Upgrade to Pro — share decks privately, control downloads, hide ads and more …

swift-argument-parserで
簡単 CLI ツール作り

swift-argument-parserで
簡単 CLI ツール作り

21e251d97f836f77e7dce83fcaf6daff?s=128

ry-itto

July 18, 2020
Tweet

More Decks by ry-itto

Other Decks in Programming

Transcript

  1. swift-argument-parserͰ ؆୯ CLI πʔϧ࡞Γ Zli × DMM ߹ಉLT ry-itto 2020/07/18

    1
  2. ࣗݾ঺հ • ҏ౻྇໵(@ry-itto) • iOS • B4 • Χϐόϥ͕޷͖ 2

    ͜Μͳ͜ͱ΍ͬͯ·ͨ͠ˠ
  3. ࣗݾ঺հʢଓ͖ʣ ʬ͋ͭ͠ʭChannel ΛΈΔ͜ͱΛ೔՝ʹͯ͠·͢ ௒༊͞ΕΔͷͰҰճ͸Έͯ΄͍͠ ↑͓͢͢Ίͷಈը (https://www.youtube.com/watch?v=4tieUdeYHHY)

  4. swift-argument-parser ͱ͸ʁʁ • Apple ެࣜͷϥΠϒϥϦ • CLI πʔϧΛ࢖͏࣌ʹΑ͋͘ΔΦϓγϣϯͱ͔ɺίϚϯυͷαϒίϚ ϯυͱ͔Λѻ͏΋ͷ •

    PropertyWrapper Λ͏·͍͜ͱ࢖͍ͬͯΔ • help ͕͍͍ײ͡ʹͳΔ 4
  5. ॾ஫ҙ • ࠓճ͸ swift-argument-parser ʹ͍ͭͯͷΈઆ໌͠·͢ • SPM ͰίϚϯυϥΠϯ πʔϧΛ࡞Δํ๏ͳͲ͸ݴ͍·ͤΜ 5

  6. ϛχϚϜͳ ࢖͍ํ struct SampleCommand: ParsableCommand { func run() throws {

    print("sample") } } SampleCommand.main() 1. ParsableCommand ʹ४ڌ ͨ͠Ϋϥε/ߏ଄ମΛ༻ҙ ͢Δ 2. run() ϝιουΛ࣮૷͢Δ 3. main() ΛݺͿ 6
  7. ͪΐͬͱԠ༻ import ArgumentParser struct SampleCommand: ParsableCommand { @Argument() var context:

    String @Flag() var upper: Bool = false @Option( name: .shortAndLong, help: "Repeating context" ) var repeatTimes: Int? mutating func run() throws { if upper { self.context = context.uppercased() } if let repeatTimes = repeatTimes { self.context = String(repeating: context, count: repeatTimes) } print(context) } } SampleCommand.main() echo ίϚϯυͷΑ͏ͳ΋ͷɻ • @Argument • @Flag • @Option ͕ग़͖ͯͨ 7
  8. ͪΐͬͱԠ༻ @Argument • ίϚϯυʹର͢ΔҾ਺ • σϑΥϧτ஋Λ༩͓͑ͯ͘ͱࢦఆ ͠ͳͯ͘΋ಈ࡞͢Δ • ΠχγϟϥΠβ͸ҎԼ̎ͭͳͲ͕ ༻ҙ͞Ε͍ͯΔ

    • @Argument(help:transform:) • @Argument(wrappedValue:parsing:help:trans form:) • ෳ਺ͷҾ਺ʹ΋ରԠ͍ͯ͠Δ 8
  9. ͪΐͬͱԠ༻ @Flag • ϑϥάɻ (ls -a ͷ -a ͱ͔ͷΠϝʔ δ)

    • ྫͷΑ͏ʹ Bool Ͱͷ੾Γସ͑΋ Ͱ͖Δ͕ɺenum Ͱ΋͍͚Δ • ↓ΠχγϟϥΠβͰΑ͘࢖͍ͦ͏ • @Flag(name:help:) 9
  10. @Flag (͓·͚) import ArgumentParser enum OutputCase: EnumerableFlag { case upper

    case lower case natural } struct SampleCommand: ParsableCommand { @Argument() var context: String @Flag() var outputCase: OutputCase = .natural @Option( name: .shortAndLong, help: "Repeating context" ) var repeatTimes: Int? mutating func run() throws { switch outputCase { case .upper: self.context = context.uppercased() case .lower: self.context = context.lowercased() case .natural: break } if let repeatTimes = repeatTimes { self.context = String(repeating: context, count: repeatTimes) } print(context) } } SampleCommand.main() enum Ͱॻ͍ͨόʔδϣϯ (lower ΋ͨͯ͠Έͨ) 10
  11. ͪΐͬͱԠ༻ @Option • git commit -m <commit- message> ͷΠϝʔδ •

    σϑΥϧτ஋Λ༩͑Δ·ͨ͸Φϓ γϣφϧܕʹ͠ͳ͍ͱඞਢͷΦϓ γϣϯʹͳͬͯ͠·͏ 11
  12. ͪΐͬͱԠ༻ > ./.build/debug/SampleCommand --help USAGE: sample-command <context> [--upper] [--repeat- times

    <repeat-times>] ARGUMENTS: <context> OPTIONS: --upper -r, --repeat-times <repeat-times> Repeating context -h, --help Show help information. —help
  13. ͪΐͬͱԠ༻ ࢖ͬͯΈΔ :yosasou: 13

  14. αϒίϚϯυ import ArgumentParser struct SampleSubCommands: ParsableCommand { static var configuration:

    CommandConfiguration = .init( subcommands: [Sum.self, Average.self], defaultSubcommand: Sum.self ) } struct Sum: ParsableCommand { @Argument() var numbers: [Int] = [] mutating func run() throws { print(numbers.reduce(0, +)) } } struct Average: ParsableCommand { @Argument() var numbers: [Int] = [] func validate() throws { if numbers.count == 0 { throw ValidationError("Please specify numbers.") } } mutating func run() throws { print(numbers.reduce(0, +) / numbers.count) } } SampleSubCommands.main()
  15. αϒίϚϯυ > ./.build/debug/SampleSubCommands --help USAGE: sample-sub-commands <subcommand> OPTIONS: -h, --help

    Show help information. SUBCOMMANDS: sum (default) average See 'sample-sub-commands help <subcommand>' for detailed help. --help
  16. αϒίϚϯυ ࡞Γํ • ParsableCommand ʹ४ڌͨ͠Ϋ ϥε/ߏ଄ମ Λ༻ҙ • configuration Λఆٛͯ͠ɺҾ਺

    ͷ subcommands ʹ࡞ͬͨαϒί ϚϯυΛೖΕΔ • defaultSubcommand Λࢦఆ͢Δ ͜ͱͰɺsubcommand ໊Λࢦఆ ͠ͳͯ͘΋ྑ͘ͳΔ
  17. αϒίϚϯυ ࢖ͬͯΈΔ

  18. εϥΠυ಺ʹग़͖ͯͨιʔείʔυ ↓ʹஔ͍ͯ·͢ github.com/ry-itto-playground/SampleCommand

  19. ࡞ͬͯΈͨ΋ͷͷ঺հ (⭐͍ͩ͘͞) AtCoderSwiftCLI (github.com/ry-itto/AtCoderSwiftCLI) • cargo-atcoder ͷ Swift ൛ΛΠϝʔδ •

    ఏग़ػೳ͸࡞ͬͯΈͯΔ్த • brew ͰམͱͤΔΑ͏ʹͯ͠ͳ͍ͷͰ mint ͔ɺखಈϏϧυͰ 19