hanami-cli 0.0.0 → 0.1.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/.travis.yml +19 -0
- data/CHANGELOG.md +14 -0
- data/Gemfile +9 -2
- data/README.md +412 -6
- data/Rakefile +19 -2
- data/hanami-cli.gemspec +6 -1
- data/lib/hanami/cli.rb +120 -4
- data/lib/hanami/cli/banner.rb +121 -0
- data/lib/hanami/cli/command.rb +365 -0
- data/lib/hanami/cli/command_registry.rb +184 -0
- data/lib/hanami/cli/option.rb +125 -0
- data/lib/hanami/cli/parser.rb +123 -0
- data/lib/hanami/cli/program_name.rb +19 -0
- data/lib/hanami/cli/registry.rb +122 -0
- data/lib/hanami/cli/usage.rb +88 -0
- data/lib/hanami/cli/version.rb +3 -2
- metadata +59 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f875978b7f89336681b8bd5a565c983bfb958ff3
|
4
|
+
data.tar.gz: 1c96e142ccf87d61f9832c15df06ae2f1d6e6f2c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 998f3111282c4df19b87bbc918e35517c47f680234ae5e2bd4372c8a7280b6a8012a12b11ff17d302e0f7e21ec007f9216d77c4542631eb9910c4ab48636b34e
|
7
|
+
data.tar.gz: a9dc63d4465bfcaa132937f36c7825249ed0dcbe4cd6799f4bde5a567f8d3fc90c23ee9f02e4636ec9f4bd439dbdc910db68eead6dc3e3113cada80a9e150897
|
data/.gitignore
CHANGED
data/.rspec
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
language: ruby
|
2
|
+
sudo: false
|
3
|
+
cache: bundler
|
4
|
+
before_install:
|
5
|
+
- gem update --system
|
6
|
+
- rvm @global do gem uninstall bundler -a -x
|
7
|
+
- rvm @global do gem install bundler -v 1.14.6
|
8
|
+
script: 'bundle exec rake --trace'
|
9
|
+
rvm:
|
10
|
+
- 2.3.4
|
11
|
+
- 2.4.1
|
12
|
+
- ruby-head
|
13
|
+
- jruby-9.1.8.0
|
14
|
+
- jruby-head
|
15
|
+
|
16
|
+
matrix:
|
17
|
+
allow_failures:
|
18
|
+
- rvm: ruby-head
|
19
|
+
- rvm: jruby-head
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Hanami::CLI
|
2
|
+
General purpose Command Line Interface (CLI) framework for Ruby
|
3
|
+
|
4
|
+
## v0.1.0.beta1 - 2017-08-11
|
5
|
+
### Added
|
6
|
+
- [Alfonso Uceda, Luca Guidi] Commands banner and usage
|
7
|
+
- [Alfonso Uceda] Added support for subcommands
|
8
|
+
- [Alfonso Uceda] Validations for arguments and options
|
9
|
+
- [Alfonso Uceda] Commands arguments and options
|
10
|
+
- [Alfonso Uceda] Commands description
|
11
|
+
- [Alfonso Uceda, Oana Sipos] Commands aliases
|
12
|
+
- [Luca Guidi] Exit on unknown command
|
13
|
+
- [Luca Guidi, Alfonso Uceda, Oana Sipos] Command lookup
|
14
|
+
- [Luca Guidi, Tim Riley] Trie based registry to register commands and allow third-parties to override/add commands
|
data/Gemfile
CHANGED
@@ -1,4 +1,11 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
|
-
|
3
|
-
# Specify your gem's dependencies in hanami-cli.gemspec
|
4
2
|
gemspec
|
3
|
+
|
4
|
+
unless ENV['TRAVIS']
|
5
|
+
gem 'byebug', require: false, platforms: :mri
|
6
|
+
gem 'yard', require: false
|
7
|
+
end
|
8
|
+
|
9
|
+
gem 'hanami-utils', '1.1.0.beta1', require: false, git: 'https://github.com/hanami/utils.git', branch: 'develop'
|
10
|
+
|
11
|
+
gem 'rubocop', '0.49.1', require: false
|
data/README.md
CHANGED
@@ -1,15 +1,189 @@
|
|
1
|
-
# Hanami::
|
1
|
+
# Hanami::CLI
|
2
2
|
|
3
|
-
|
3
|
+
General purpose Command Line Interface (CLI) framework for Ruby.
|
4
4
|
|
5
|
-
|
5
|
+
:warning: **This is a general framework for Ruby (aka `thor` gem replacement), NOT the implementation of the `hanami` CLI commands** :warning:
|
6
|
+
|
7
|
+
## Features
|
8
|
+
|
9
|
+
### Registration
|
10
|
+
|
11
|
+
For a given _command name_, you can register a corresponding _command object_ (aka command).
|
12
|
+
|
13
|
+
Example: for `foo hi` _command name_ there is the corresponding `Foo::CLI::Hello` _command object_.
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
#!/usr/bin/env ruby
|
17
|
+
require "bundler/setup"
|
18
|
+
require "hanami/cli"
|
19
|
+
|
20
|
+
module Foo
|
21
|
+
module CLI
|
22
|
+
module Commands
|
23
|
+
extend Hanami::CLI::Registry
|
24
|
+
|
25
|
+
class Hello < Hanami::CLI::Command
|
26
|
+
def call(*)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Version < Hanami::CLI::Command
|
34
|
+
def call(*)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
Foo::CLI::Commands.register "hi", Foo::CLI::Commands::Hello
|
39
|
+
Foo::CLI::Commands.register "v", Version
|
40
|
+
|
41
|
+
Hanami::CLI.new(Foo::CLI::Commands).call
|
42
|
+
```
|
43
|
+
|
44
|
+
**Please note:** there is NOT a convention between the _command name_ and the _command object_ class.
|
45
|
+
The manual _registration_ assigns a _command object_ to a _command name_.
|
46
|
+
|
47
|
+
### Commands as objects
|
48
|
+
|
49
|
+
A command is a subclass of `Hanami::CLI::Command` and it MUST respond to `#call(*)`.
|
50
|
+
|
51
|
+
### Subcommands
|
52
|
+
|
53
|
+
There is nothing special in subcommands: they are just _command objects_ registered under a **nested** _command name_.
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
#!/usr/bin/env ruby
|
57
|
+
require "bundler/setup"
|
58
|
+
require "hanami/cli"
|
59
|
+
|
60
|
+
module Foo
|
61
|
+
module CLI
|
62
|
+
module Commands
|
63
|
+
extend Hanami::CLI::Registry
|
64
|
+
|
65
|
+
module Generate
|
66
|
+
class Configuration < Hanami::CLI::Command
|
67
|
+
def call(*)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
Foo::CLI::Commands.register "generate configuration", Foo::CLI::Commands::Generate::Configuration
|
76
|
+
|
77
|
+
Hanami::CLI.new(Foo::CLI::Commands).call
|
78
|
+
```
|
79
|
+
|
80
|
+
### Arguments
|
81
|
+
|
82
|
+
An argument is a token passed after the _command name_.
|
83
|
+
For instance, given the `foo greet` command, when an user types `foo greet Luca`, then `Luca` is considered an argument.
|
84
|
+
A command can accept none or many arguments.
|
85
|
+
An argument can be declared as _required_.
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
#!/usr/bin/env ruby
|
89
|
+
require "bundler/setup"
|
90
|
+
require "hanami/cli"
|
91
|
+
|
92
|
+
module Foo
|
93
|
+
module CLI
|
94
|
+
module Commands
|
95
|
+
extend Hanami::CLI::Registry
|
96
|
+
|
97
|
+
class Greet < Hanami::CLI::Command
|
98
|
+
argument :name, required: true, desc: "The name of the person to greet"
|
99
|
+
argument :age, desc: "The age of the person to greet"
|
100
|
+
|
101
|
+
def call(name:, age: nil, **)
|
102
|
+
result = "Hello, #{name}."
|
103
|
+
result = "#{result} You are #{age} years old." unless age.nil?
|
104
|
+
|
105
|
+
puts result
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
register "greet", Greet
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
Hanami::CLI.new(Foo::CLI::Commands).call
|
115
|
+
```
|
116
|
+
|
117
|
+
```shell
|
118
|
+
% foo greet Luca
|
119
|
+
Hello, Luca.
|
120
|
+
```
|
121
|
+
|
122
|
+
```shell
|
123
|
+
% foo greet Luca 35
|
124
|
+
Hello, Luca. You are 35 years old.
|
125
|
+
```
|
126
|
+
|
127
|
+
```shell
|
128
|
+
% foo greet
|
129
|
+
ERROR: "foo greet" was called with no arguments
|
130
|
+
Usage: "foo greet NAME"
|
131
|
+
```
|
132
|
+
|
133
|
+
### Option
|
134
|
+
|
135
|
+
An option is a named argument that is passed after the _command name_ **and** the arguments.
|
136
|
+
|
137
|
+
For instance, given the `foo request` command, when an user types `foo request --mode=http2`, then `--mode=http2` is considered an option.
|
138
|
+
A command can accept none or many options.
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
#!/usr/bin/env ruby
|
142
|
+
require "bundler/setup"
|
143
|
+
require "hanami/cli"
|
144
|
+
|
145
|
+
module Foo
|
146
|
+
module CLI
|
147
|
+
module Commands
|
148
|
+
extend Hanami::CLI::Registry
|
149
|
+
|
150
|
+
class Request < Hanami::CLI::Command
|
151
|
+
option :mode, default: "http", values: %w[http http2], desc: "The request mode"
|
152
|
+
|
153
|
+
def call(**options)
|
154
|
+
puts "Performing a request (mode: #{options.fetch(:mode)})"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
register "request", Request
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
Hanami::CLI.new(Foo::CLI::Commands).call
|
164
|
+
```
|
165
|
+
|
166
|
+
```shell
|
167
|
+
% foo request
|
168
|
+
Performing a request (mode: http)
|
169
|
+
```
|
170
|
+
|
171
|
+
```shell
|
172
|
+
% foo request --mode=http2
|
173
|
+
Performing a request (mode: http2)
|
174
|
+
```
|
175
|
+
|
176
|
+
```shell
|
177
|
+
% foo request --mode=unknown
|
178
|
+
Error: Invalid param provided
|
179
|
+
```
|
6
180
|
|
7
181
|
## Installation
|
8
182
|
|
9
183
|
Add this line to your application's Gemfile:
|
10
184
|
|
11
185
|
```ruby
|
12
|
-
gem
|
186
|
+
gem "hanami-cli"
|
13
187
|
```
|
14
188
|
|
15
189
|
And then execute:
|
@@ -22,7 +196,232 @@ Or install it yourself as:
|
|
22
196
|
|
23
197
|
## Usage
|
24
198
|
|
25
|
-
|
199
|
+
Imagine to build a CLI executable `foo` for your Ruby project.
|
200
|
+
|
201
|
+
```ruby
|
202
|
+
#!/usr/bin/env ruby
|
203
|
+
require "bundler/setup"
|
204
|
+
require "hanami/cli"
|
205
|
+
|
206
|
+
module Foo
|
207
|
+
module CLI
|
208
|
+
module Commands
|
209
|
+
extend Hanami::CLI::Registry
|
210
|
+
|
211
|
+
class Version < Hanami::CLI::Command
|
212
|
+
desc "Print version"
|
213
|
+
|
214
|
+
def call(*)
|
215
|
+
puts "1.0.0"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
class Echo < Hanami::CLI::Command
|
220
|
+
desc "Print input"
|
221
|
+
|
222
|
+
argument :input, desc: "Input to print"
|
223
|
+
|
224
|
+
example [
|
225
|
+
" # Prints 'wuh?'",
|
226
|
+
"hello, folks # Prints 'hello, folks'"
|
227
|
+
]
|
228
|
+
|
229
|
+
def call(input: nil, **)
|
230
|
+
if input.nil?
|
231
|
+
puts "wuh?"
|
232
|
+
else
|
233
|
+
puts input
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
class Start < Hanami::CLI::Command
|
239
|
+
desc "Start Foo machinery"
|
240
|
+
|
241
|
+
argument :root, required: true, desc: "Root directory"
|
242
|
+
|
243
|
+
example [
|
244
|
+
"path/to/root # Start Foo at root directory"
|
245
|
+
]
|
246
|
+
|
247
|
+
def call(root:, **)
|
248
|
+
puts "started - root: #{root}"
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
class Stop < Hanami::CLI::Command
|
253
|
+
desc "Stop Foo machinery"
|
254
|
+
|
255
|
+
option :graceful, type: :boolean, default: true, desc: "Graceful stop"
|
256
|
+
|
257
|
+
def call(**options)
|
258
|
+
puts "stopped - graceful: #{options.fetch(:graceful)}"
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
module Generate
|
263
|
+
class Configuration < Hanami::CLI::Command
|
264
|
+
desc "Generate configuration"
|
265
|
+
|
266
|
+
def call(*)
|
267
|
+
puts "generated configuration"
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
class Test < Hanami::CLI::Command
|
272
|
+
desc "Generate tests"
|
273
|
+
|
274
|
+
option :framework, default: "minitest", values: %w[minitest rspec]
|
275
|
+
|
276
|
+
def call(framework:, **)
|
277
|
+
puts "generated tests - framework: #{framework}"
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
register "version", Version, aliases: ["v", "-v", "--version"]
|
283
|
+
register "echo", Echo
|
284
|
+
register "start", Start
|
285
|
+
register "stop", Stop
|
286
|
+
|
287
|
+
register "generate", aliases: ["g"] do |prefix|
|
288
|
+
prefix.register "config", Generate::Configuration
|
289
|
+
prefix.register "test", Generate::Test
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
Hanami::CLI.new(Foo::CLI::Commands).call
|
296
|
+
```
|
297
|
+
|
298
|
+
Let's have a look at the command line usage.
|
299
|
+
|
300
|
+
### Available commands
|
301
|
+
|
302
|
+
```shell
|
303
|
+
% foo
|
304
|
+
Commands:
|
305
|
+
foo echo [INPUT] # Print input
|
306
|
+
foo generate [SUBCOMMAND]
|
307
|
+
foo start ROOT # Start Foo machinery
|
308
|
+
foo stop # Stop Foo machinery
|
309
|
+
foo version # Print version
|
310
|
+
```
|
311
|
+
|
312
|
+
### Help
|
313
|
+
|
314
|
+
```shell
|
315
|
+
% foo echo --help
|
316
|
+
Command:
|
317
|
+
foo echo
|
318
|
+
|
319
|
+
Usage:
|
320
|
+
foo echo [INPUT]
|
321
|
+
|
322
|
+
Description:
|
323
|
+
Print input
|
324
|
+
|
325
|
+
Arguments:
|
326
|
+
INPUT # Input to print
|
327
|
+
|
328
|
+
Options:
|
329
|
+
--help, -h # Print this help
|
330
|
+
|
331
|
+
Examples:
|
332
|
+
foo echo # Prints 'wuh?'
|
333
|
+
foo echo hello, folks # Prints 'hello, folks'
|
334
|
+
```
|
335
|
+
|
336
|
+
### Optional arguments
|
337
|
+
|
338
|
+
```shell
|
339
|
+
% foo echo
|
340
|
+
wuh?
|
341
|
+
|
342
|
+
% foo echo hello
|
343
|
+
hello
|
344
|
+
```
|
345
|
+
|
346
|
+
### Required arguments
|
347
|
+
|
348
|
+
```shell
|
349
|
+
% foo start .
|
350
|
+
started - root: .
|
351
|
+
```
|
352
|
+
|
353
|
+
```shell
|
354
|
+
% foo start
|
355
|
+
ERROR: "foo start" was called with no arguments
|
356
|
+
Usage: "foo start ROOT"
|
357
|
+
```
|
358
|
+
|
359
|
+
### Options
|
360
|
+
|
361
|
+
```shell
|
362
|
+
% foo generate test
|
363
|
+
generated tests - framework: minitest
|
364
|
+
```
|
365
|
+
|
366
|
+
```shell
|
367
|
+
% foo generate test --framework=rspec
|
368
|
+
generated tests - framework: rspec
|
369
|
+
```
|
370
|
+
|
371
|
+
```shell
|
372
|
+
% foo generate test --framework=unknown
|
373
|
+
Error: Invalid param provided
|
374
|
+
```
|
375
|
+
|
376
|
+
### Boolean options
|
377
|
+
|
378
|
+
```shell
|
379
|
+
% foo stop
|
380
|
+
stopped - graceful: true
|
381
|
+
```
|
382
|
+
|
383
|
+
```shell
|
384
|
+
% foo stop --no-graceful
|
385
|
+
stopped - graceful: false
|
386
|
+
```
|
387
|
+
|
388
|
+
### Subcommands
|
389
|
+
|
390
|
+
```shell
|
391
|
+
% foo generate
|
392
|
+
Commands:
|
393
|
+
foo generate config # Generate configuration
|
394
|
+
foo generate test # Generate tests
|
395
|
+
```
|
396
|
+
|
397
|
+
### Aliases
|
398
|
+
|
399
|
+
```shell
|
400
|
+
% foo version
|
401
|
+
1.0.0
|
402
|
+
```
|
403
|
+
|
404
|
+
```shell
|
405
|
+
% foo v
|
406
|
+
1.0.0
|
407
|
+
```
|
408
|
+
|
409
|
+
```shell
|
410
|
+
% foo -v
|
411
|
+
1.0.0
|
412
|
+
```
|
413
|
+
|
414
|
+
```shell
|
415
|
+
% foo --version
|
416
|
+
1.0.0
|
417
|
+
```
|
418
|
+
|
419
|
+
### Subcommand aliases
|
420
|
+
|
421
|
+
```shell
|
422
|
+
% foo g config
|
423
|
+
generated configuration
|
424
|
+
```
|
26
425
|
|
27
426
|
## Development
|
28
427
|
|
@@ -32,5 +431,12 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
32
431
|
|
33
432
|
## Contributing
|
34
433
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
434
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/hanami/cli.
|
435
|
+
|
436
|
+
## Alternatives
|
437
|
+
|
438
|
+
* [thor](http://whatisthor.com/)
|
439
|
+
|
440
|
+
## Copyright
|
36
441
|
|
442
|
+
Copyright © 2017 Luca Guidi – Released under MIT License
|