コマンドラインオプションをパースするコードをコマンドラインオプションから生成するツールをつくった/fukuokago14_flagen

 コマンドラインオプションをパースするコードをコマンドラインオプションから生成するツールをつくった/fukuokago14_flagen

Cd3d2cb2dadf5488935fe0ddaea7938a?s=128

monochromegane

October 25, 2019
Tweet

Transcript

  1. ࡾ୐༔հ / Pepabo R&D Institute, GMO Pepabo, Inc. 2019.10.25 Fukuoka.go#14+Umeda.go

    ίϚϯυϥΠϯΦϓγϣϯΛύʔε͢ ΔίʔυΛίϚϯυϥΠϯΦϓγϣϯ ͔Βੜ੒͢ΔπʔϧΛͭͬͨ͘
  2. 1SJODJQBMFOHJOFFS :VTVLF.*:",&!NPOPDISPNFHBOF 1FQBCP3%*OTUJUVUF (.01FQBCP *OD IUUQTCMPHNPOPDISPNFHBOFDPN

  3. GopherCon 2019 3 :VTVLF.JZBLF 0QUJNJ[BUJPOGPS/VNCFSPGHPSPVUJOFT6TJOH'FFECBDL$POUSPM  (PQIFS$PO.BSSJPUU.BSRVJT4BO%JFHP.BSJOB $BMJGPSOJB +VMZ

  4. 1. ͸͡Ίʹ 2. ίϚϯυϥΠϯΦϓγϣϯΛύʔε͢ΔίʔυΛίϚϯ υϥΠϯΦϓγϣϯ͔Βੜ੒͢Δ 3. ·ͱΊ 4 ໨࣍

  5. 1. ͸͡Ίʹ

  6. • ίϚϯυϥΠϯϓϩάϥϜͷڍಈΛ࣮ߦ࣌ʹมߋͤ͞ΔͨΊʹ֎෦͔ΒҾ਺΍ ΦϓγϣϯΛࢦఆ͢Δ • ୯ͳΔจࣈྻͰ͋ΔͨΊɺίϚϯυϥΠϯϓϩάϥϜͰ͸͜ΕΒͷղੳॲཧΛ ߦ͍ɺ಺෦ͷม਺΁ͱ֨ೲ͢Δ • ࠷΋୯७ͳ΋ͷͰ͋Ε͹ɺۭന۠੾Γ (cp src

    dest) • Ґஔ͕ҙຯΛ͕࣋ͭ׳श͸͋ΕͲɺ͜ͷؔ܎ੑ͸໌֬Ͱ͸ͳ͍ • Ґஔʹґଘ͠ͳ͍Φϓγϣϯܗࣜ (cp -r, head -n 10…) • ϢʔβϑϨϯυϦʔͰ͋Δ͕ղੳॲཧ͸΍΍ෳࡶʹͳΔ 6 ίϚϯυϥΠϯҾ਺ͱΦϓγϣϯ
  7. • ίϚϯυϥΠϯΦϓγϣϯͷղੳॲཧ͸ݴޠඪ४ͷ΋ͷ΍ϥΠϒϥϦ͔Βͨ͘ ͞Μఏڙ͞Ε͍ͯΔʢflag, getopts, argparse, optparse…ʣ • શ෦Λ֮͑Δͷ͸೉͍͠ͷͰɺݴޠ΍ϥΠϒϥϦ͝ͱʹυΩϡϝϯτΛࢀর͠ ͳ͕Β࣮૷͢Δ •

    Ͳ͏ͯ͠΋͕͔͔࣌ؒΔ • ఆܕॲཧͰ͋Δ͜ͱ͔Βɺߟ͑͏ΔύλʔϯΛهड़ͨ͠ϘΠϥʔςϯϓϨʔτ Λ४උ͢Δ • ൚༻తͳϘΠϥʔςϯϓϨʔτ͸Ͳ͏ͯ͠΋ฤूՕॴ͕ଟ͘ͳΔʢΦϓγϣ ϯ໊ɺม਺໊ɺσϑΥϧτ஋…ʣ 7 ίϚϯυϥΠϯΦϓγϣϯ
  8. 8 ίϚϯυϥΠϯΦϓγϣϯղੳͷ՝୊ͷ੔ཧ $ mycli --dist erlang -e k/l --lambda 1.5

    -k 1 -v 1. ίϚϯυϥΠϯΦϓγϣϯͷܗࣜΛݕ౼͢Δ 2. ࣮૷͢Δ 1. υΩϡϝϯτͷࢀরͱ࣮૷ 2. ϘΠϥʔςϯϓϨʔτͷίϐʔͱฤू 3. ຊདྷͷॲཧͷ࣮૷
  9. 9 ίϚϯυϥΠϯΦϓγϣϯղੳͷ՝୊ͷ੔ཧ $ mycli --dist erlang -e k/l --lambda 1.5

    -k 1 -v 1. ίϚϯυϥΠϯΦϓγϣϯͷܗࣜΛݕ౼͢Δ 2. ࣮૷͢Δ 1. υΩϡϝϯτͷࢀরͱ࣮૷ 2. ϘΠϥʔςϯϓϨʔτͷίϐʔͱฤू 3. ຊདྷͷॲཧͷ࣮૷ ͜͜ͷ࣌ؒΛݶΓͳ͘ θϩʹ͚͍ۙͮͨ
  10. 2. ίϚϯυϥΠϯΦϓγϣϯΛύʔε͢ΔίʔυΛ ίϚϯυϥΠϯΦϓγϣϯ͔Βੜ੒͢Δ

  11. • A command line option parser generator (Flag-gen). • https://github.com/monochromegane/flagen

    • ࣮ࡍʹ࢖͏ࡍͷίϚϯυϥΠϯΦϓγϣϯ͔ΒɺʮͦͷʯίϚϯυϥΠϯΦϓ γϣϯΛղੳ͢ΔϘΠϥʔςϯϓϨʔτΛੜ੒͢Δ • ࢖͍ํΛࢥ͍ු͔΂Δͱ࣮૷͕Ͱ͖͍ͯΔʂʂ 11 flagen
  12. Usage $ flagen YOUR_TEMPLATE YOUR_COMMAND_LINE_OPTIONS... 12 • ςϯϓϨʔτͱ࣮ࡍʹ࢖͏࣌ͷίϚϯυϥΠϯΦϓγϣϯΛ౉͚ͩ͢ • ϓϦηοτͷςϯϓϨʔτͱͯ͠ɺGoɺRubyɺPythonɺShellΛఏڙ

    • ϑΝΠϧύεΛࢦఆ͢Ε͹ಠࣗςϯϓϨʔτ΋ར༻Մೳʢޙड़ʣ
  13. Example of Go (preset template) 13 $ flagen go --dist

    erlang -e k/l --lambda 1.5 -k 1 -v var ( dist string e string lambda float64 k int v bool ) func init() { flag.StringVar(&dist, "dist", "erlang", "usage of dist") flag.StringVar(&e, "e", "k/l", "usage of e") flag.Float64Var(&lambda, "lambda", 1.5, "usage of lambda") flag.IntVar(&k, "k", 1, "usage of k") flag.BoolVar(&v, "v", false, "usage of v") } ίϚϯυϥΠϯΦϓγϣϯ໊͔Βม਺໊Λੜ੒ ίϚϯυϥΠϯΦϓγϣϯ஋͔ΒܕΛਪଌ ࣮ࡍʹ࢖༻͢ΔίϚϯυϥΠϯΦϓγϣϯ͔Β ίϚϯυϥΠϯͷղੳॲཧΛੜ੒
  14. Example of Python (preset template) 14 $ flagen py --dist

    erlang -e k/l --lambda 1.5 -k 1 -v import argparse parser = argparse.ArgumentParser() parser.add_argument("--dist", default="erlang", help="Help of dist") parser.add_argument("-e", default="k/l", help="Help of e") parser.add_argument("--lambda", type=float, default=1.5, help="Help of lambda") parser.add_argument("-k", type=int, default=1, help="Help of k") parser.add_argument("-v", action="store_false", help="Help of v") args = parser.parse_args() ϋϚΓ͕ͪͳ1ZUIPOͷCPPMͷσϑΥϧτ஋ͷઃఆ΋ ϘΠϥʔςϯϓϨʔτͳͷͰେৎ෉
  15. Example of Ruby (preset template) 15 $ flagen rb --dist

    erlang -e k/l --lambda 1.5 -k 1 -v require 'optparse' opts = { dist: 'erlang', e: 'k/l', lambda: 1.5, k: 1, v: false, } OptionParser.new do |op| op.on('--dist [VALUE]', 'Desc of dist') {|v| opts[:dist] = v } op.on('-e [VALUE]', 'Desc of e') {|v| opts[:e] = v } op.on('--lambda [VALUE]', 'Desc of lambda') {|v| opts[:lambda] = v.to_f } op.on('-k [VALUE]', 'Desc of k') {|v| opts[:k] = v.to_i } op.on('-v', 'Desc of v') {|v| opts[:v] = v } op.parse!(ARGV) end
  16. Example of Shell (preset template) 16 $ flagen sh --dist

    erlang -e k/l --lambda 1.5 -k 1 -v E="k/l" K="1" V="FALSE" while getopts e:k:v OPT do case $OPT in "e" ) E="$OPTARG";; "k" ) K="$OPTARG";; "v" ) V="TRUE";; esac done shift `expr $OPTIND - 1` HFUPQUT͸ҰจࣈͷҾ਺͚ͩѻ͑ΔͷͰ௕͍Φϓγϣϯ͸ແࢹ
  17. • ΋ͪΖΜflagen͸ಠࣗςϯϓϨʔτ΋࢖͑Δ • ςϯϓϨʔτ͸Goͷtext/templateΛ࢖ͬͯॲཧ • `.Flags`ʹΦϓγϣϯͷղੳ݁Ռ • NameͱValueΛ࣋ͭ • Value͸͞ΒʹTypeͱGetΛ࣋ͭ

    • `.Args`ʹ࢒ΓͷҾ਺ 17 Template
  18. Template

  19. Template {{ range $flag := .Flags -}} {{ $flag.Name }}={{

    $flag.Value.Get}}({{ $flag.Value.Type }}) {{ end }} 19 $ flagen my.tmpl --dist erlang -e k/l --lambda 1.5 -k 1 -v dist=erlang(string) e=k/l(string) lambda=1.5(float) k=1(int) v=false(bool)
  20. Template (Functions) {{ range $flag := .Flags -}} {{ ToCamel

    $flag.Name }}={{ $flag.Value.Get}} {{ end }} 20 Dist=erlang E=k/l Lambda=1.5 K=1 V=false
  21. Collaboration

  22. • flagenΛΤσΟλͱ࿈ܞ͢Δ • ྫ͑͹VimͰ͸ҎԼʹΑΓɺΧʔιϧҐஔʹ݁ՌΛૠೖ͢Δ͜ͱ͕Ͱ͖Δɻ ʢಈతͳίʔυεχϖοτͱͯ͠ͷར༻ʣ 22 Collaboration :r!flagen YOUR_TEMPLATE YOUR_COMMAND_LINE_OPTIONS...

  23. • flagenΛࣗલͷϘΠϥʔςϯϓϨʔτπʔϧͱ࿈ܞ͢Δ • πʔϧ͕GoͰ͋Ε͹ɺflagenΛϥΠϒϥϦͱͯ͠ར༻͢Δ͜ͱ͕Ͱ͖Δ 23 Collaboration tmpl, err := flagen.NewTemplate(args[0])

    if err != nil { return err } return tmpl.Execute(outStream, args[1:]) ςϯϓϨʔτΛࢦఆ ग़ྗઌͱ ίϚϯυϥΠϯΦϓγϣϯΛࢦఆ 4FFBMTP<(PEPD> IUUQTHPEPDPSHHJUIVCDPNNPOPDISPNFHBOFqBHFO 
  24. Workaround

  25. • ᐆດͳϑϥά • flagen͸Φϓγϣϯʹ஋͕ࢦఆ͞Ε͍ͯͳ͍ͱ͖ʹboolͩͱݟͳͨ͢Ίɺ boolϑϥάͰऴΘͬͯҾ਺͕͋Δ৔߹ʹ൑அ͕͔ͭͳ͍ • ૝ఆͲ͓Γʹ͢ΔͨΊʹ͸஋ͱͯ͠true or falseΛड͚औΔ͜ͱΛ໌ࣔ͢Δ 25

    Workarounds - Ambiguous flag $ flagen TEMPLATE --bool-flag arg1 $ flagen TEMPLATE --bool-flag=false arg1
  26. Implementation of template

  27. • ExampleςετΛ༻ҙͯ͠ग़ྗ݁ՌΛςετ͢Δ΂͠ • Godocʹྫ͕ग़ྗ͞ΕΔͷͰศར • ग़ྗ༗ແͷ੾Γ෼͚͸ with action͕ศར 27 ςϯϓϨʔτͷ࣮૷

  28. 3. ·ͱΊ

  29. • ༷ʑͳ࣮૷͕ఏڙ͞Ε͍ͯΔίϚϯυϥΠϯΦϓγϣϯͷղੳॲཧΛར༻ܗࣜ ͔Βಈతʹੜ੒͢ΔδΣωϨʔλʔͱͯ͠flagenΛͭͬͨ͘ • ͍͔ͭ͘ͷݴޠͷςϯϓϨʔτΛ༻ҙͯ͠ΤσΟλͱ࿈ܞͤ͞Δ͜ͱͰCLI։ ൃͷޮ཰͕վળͨ͠ • flagenࣗମͷΦϓγϣϯͱͯ͠prefixͳͲΛఏڙ͢Ε͹ߏ଄ମͱͷ૬ੑ΋Α͘ ͳΓͦ͏ (hoge.nameͷΑ͏ͳ࢖͍ํ)

    • ςϯϓϨʔτ௥ՃͷϓϧϦΫΤετ΍ΠγϡʔͳͲ͓଴͍ͪͯ͠·͢ • https://github.com/monochromegane/flagen 29 ·ͱΊ
  30. None