Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
swift-argument-parserで 簡単 CLI ツール作り
Search
ry-itto
July 18, 2020
Programming
180
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
swift-argument-parserで 簡単 CLI ツール作り
ry-itto
July 18, 2020
More Decks by ry-itto
See All by ry-itto
決定版!?OSSアプリプロジェクトでのBeta版アプリ配布の方法「Xcode Cloud + TestFlight」
ryitto
0
410
CA.swift#14
ryitto
3
5.9k
Data Essentials in SwiftUI
ryitto
1
540
Composable Architecture
ryitto
0
810
CollectionViewの 新しいレイアウトの作り方
ryitto
0
79
Swift5.1 SwiftUI
ryitto
0
150
Other Decks in Programming
See All in Programming
{ Android | Kotlin } Gradle Plugin in 2026
ryunen344
1
250
AI時代に学ぶ 好きなルール 嫌いなルール Linter編
shorty5121
0
760
Gmail/Google DriveをトリガーにAIエージェントを動かそう! / Run AI agents with Gmail/Google Drive as triggers!
har1101
3
460
Loosening the Reins: Go Generics Get More Flexible
kuro_kurorrr
0
360
Cloudflare is Agents
chimame
0
190
DroidKaigi 2026 「個人開発という実験場: Android エンジニアが手にする4つの自由」
slashnephy
0
190
Seeing Through Serverless: Observability for AWS Lambda with ADOT and CloudWatch Application Signals
seike460
PRO
1
100
承認済みなのに差戻しできてしまうバグ、型で潰せます
shinchit
0
130
Vibes Containers 〜AIで変わるコンテナ設計と運用〜
tkikuc
0
230
ソフトウェアラスタライザ
fadis
1
770
ソフトウェアエンジニアにとっての生成AI - 特性を知って使い倒す / generative ai for software enginner
kishida
7
2.3k
XHTMLが残したもの
yosuke_furukawa
PRO
1
360
Featured
See All Featured
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
2.7k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
254
22k
First, design no harm
axbom
PRO
2
1.3k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.9k
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
500
Odyssey Design
rkendrick25
PRO
2
790
Why Our Code Smells
bkeepers
PRO
340
58k
Why You Should Never Use an ORM
jnunemaker
PRO
61
10k
Java REST API Framework Comparison - PWX 2021
mraible
34
9.7k
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
510
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
590
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.3k
Transcript
swift-argument-parserͰ ؆୯ CLI πʔϧ࡞Γ Zli × DMM ߹ಉLT ry-itto 2020/07/18
1
ࣗݾհ • ҏ౻྇(@ry-itto) • iOS • B4 • Χϐόϥ͕͖ 2
͜Μͳ͜ͱͬͯ·ͨ͠ˠ
ࣗݾհʢଓ͖ʣ ʬ͋ͭ͠ʭChannel ΛΈΔ͜ͱΛ՝ʹͯ͠·͢ ༊͞ΕΔͷͰҰճΈͯ΄͍͠ ↑͓͢͢Ίͷಈը (https://www.youtube.com/watch?v=4tieUdeYHHY)
swift-argument-parser ͱʁʁ • Apple ެࣜͷϥΠϒϥϦ • CLI πʔϧΛ͏࣌ʹΑ͋͘ΔΦϓγϣϯͱ͔ɺίϚϯυͷαϒίϚ ϯυͱ͔Λѻ͏ͷ •
PropertyWrapper Λ͏·͍͜ͱ͍ͬͯΔ • help ͕͍͍ײ͡ʹͳΔ 4
ॾҙ • ࠓճ swift-argument-parser ʹ͍ͭͯͷΈઆ໌͠·͢ • SPM ͰίϚϯυϥΠϯ πʔϧΛ࡞Δํ๏ͳͲݴ͍·ͤΜ 5
ϛχϚϜͳ ͍ํ struct SampleCommand: ParsableCommand { func run() throws {
print("sample") } } SampleCommand.main() 1. ParsableCommand ʹ४ڌ ͨ͠Ϋϥε/ߏମΛ༻ҙ ͢Δ 2. run() ϝιουΛ࣮͢Δ 3. main() ΛݺͿ 6
ͪΐͬͱԠ༻ 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
ͪΐͬͱԠ༻ @Argument • ίϚϯυʹର͢ΔҾ • σϑΥϧτΛ༩͓͑ͯ͘ͱࢦఆ ͠ͳͯ͘ಈ࡞͢Δ • ΠχγϟϥΠβҎԼ̎ͭͳͲ͕ ༻ҙ͞Ε͍ͯΔ
• @Argument(help:transform:) • @Argument(wrappedValue:parsing:help:trans form:) • ෳͷҾʹରԠ͍ͯ͠Δ 8
ͪΐͬͱԠ༻ @Flag • ϑϥάɻ (ls -a ͷ -a ͱ͔ͷΠϝʔ δ)
• ྫͷΑ͏ʹ Bool ͰͷΓସ͑ Ͱ͖Δ͕ɺenum Ͱ͍͚Δ • ↓ΠχγϟϥΠβͰΑ͍ͦ͘͏ • @Flag(name:help:) 9
@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
ͪΐͬͱԠ༻ @Option • git commit -m <commit- message> ͷΠϝʔδ •
σϑΥϧτΛ༩͑Δ·ͨΦϓ γϣφϧܕʹ͠ͳ͍ͱඞਢͷΦϓ γϣϯʹͳͬͯ͠·͏ 11
ͪΐͬͱԠ༻ > ./.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
ͪΐͬͱԠ༻ ͬͯΈΔ :yosasou: 13
αϒίϚϯυ 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()
αϒίϚϯυ > ./.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
αϒίϚϯυ ࡞Γํ • ParsableCommand ʹ४ڌͨ͠Ϋ ϥε/ߏମ Λ༻ҙ • configuration Λఆٛͯ͠ɺҾ
ͷ subcommands ʹ࡞ͬͨαϒί ϚϯυΛೖΕΔ • defaultSubcommand Λࢦఆ͢Δ ͜ͱͰɺsubcommand ໊Λࢦఆ ͠ͳͯ͘ྑ͘ͳΔ
αϒίϚϯυ ͬͯΈΔ
εϥΠυʹग़͖ͯͨιʔείʔυ ↓ʹஔ͍ͯ·͢ github.com/ry-itto-playground/SampleCommand
࡞ͬͯΈͨͷͷհ (⭐͍ͩ͘͞) AtCoderSwiftCLI (github.com/ry-itto/AtCoderSwiftCLI) • cargo-atcoder ͷ Swift ൛ΛΠϝʔδ •
ఏग़ػೳ࡞ͬͯΈͯΔ్த • brew ͰམͱͤΔΑ͏ʹͯ͠ͳ͍ͷͰ mint ͔ɺखಈϏϧυͰ 19