sod 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/README.adoc +51 -60
- data/lib/sod/graph/loader.rb +1 -1
- data/lib/sod/graph/runner.rb +12 -1
- data/lib/sod/refines/{option_parsers.rb → option_parser.rb} +4 -4
- data/sod.gemspec +3 -2
- data.tar.gz.sig +0 -0
- metadata +20 -6
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c85d0a0011997592a071b7238743f7bd3fbaa8f82c91ace66199412030c35185
|
4
|
+
data.tar.gz: cedce56c426c4e6ca1f02fea043ef6f83d76aada4430bd4d41df16579b1c47e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 11de476bc015d7563655dd99b34b532aa638bfe97384b7e7f00837903248ad8ac294b61c65eaa0cd22c509645817e9e49c49a01c057dbb8ef68226c692e761ba
|
7
|
+
data.tar.gz: 3a8a383dfd4eaf2df98c1f93b8ecd7a53c722e4f4d716f6ac396dca8a76b0c56fed023473195d76b622098952037a57d55826383c2122536acce1468795560cb
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/README.adoc
CHANGED
@@ -292,23 +292,43 @@ With the above in mind, let's look at a few examples of what you can do when you
|
|
292
292
|
|
293
293
|
===== Booleans
|
294
294
|
|
295
|
-
Boolean
|
295
|
+
Boolean are long alases only, use `[no-]` syntax after the double dashes, and provide the boolean value for use within your action. Here's a minimal implementation:
|
296
296
|
|
297
297
|
[source,ruby]
|
298
298
|
----
|
299
|
-
class
|
299
|
+
class Action < Sod::Action
|
300
300
|
on "--[no-]run"
|
301
301
|
|
302
|
-
def call(
|
302
|
+
def call(boolean) = puts boolean
|
303
|
+
end
|
304
|
+
|
305
|
+
cli = Sod.new { on Action }
|
306
|
+
|
307
|
+
cli.call %w[--run] # "true"
|
308
|
+
cli.call %w[--no-run] # "false"
|
309
|
+
----
|
310
|
+
|
311
|
+
Because a value is always provided when using a boolean flag, you can make it a required positional parameter via your method definition (i.e. `call(boolean)`). You don't need to worry about type safety because {option_parser_link} will pass in `true` or `false` as you can see from the output above.
|
312
|
+
|
313
|
+
===== Flags
|
314
|
+
|
315
|
+
Flags are similar to _Booleans_ but take _no arguments_ and allow short or long aliases. When a flag is supplied, the action is _enabled_ which means you can execute custom functionality. Otherwise, when a flag isn't supplied (i.e. default), then the action is _disabled_ and nothing happens.
|
316
|
+
|
317
|
+
[source,ruby]
|
318
|
+
----
|
319
|
+
class Action < Sod::Action
|
320
|
+
on %w[-m --max]
|
321
|
+
|
322
|
+
def call(*) = puts "Maximum enabled."
|
303
323
|
end
|
304
324
|
|
305
|
-
cli = Sod.new { on
|
325
|
+
cli = Sod.new { on Action }
|
306
326
|
|
307
|
-
cli.call %w[--
|
308
|
-
cli.call
|
327
|
+
cli.call %w[--max] # "Maximum enabled."
|
328
|
+
cli.call # Nothing happens.
|
309
329
|
----
|
310
330
|
|
311
|
-
|
331
|
+
Since `#call` expects an argument, you can use `call(+*+)` for the method signature to ignore all arguments since you don't need them.
|
312
332
|
|
313
333
|
===== Arguments
|
314
334
|
|
@@ -316,13 +336,13 @@ Arguments inform {option_parser_link} how to parse values as either _optional_ o
|
|
316
336
|
|
317
337
|
[source,ruby]
|
318
338
|
----
|
319
|
-
class
|
339
|
+
class Action < Sod::Action
|
320
340
|
on %w[-e --echo], argument: "[TEXT]"
|
321
341
|
|
322
342
|
def call(text = nil) = puts "Got: #{text}"
|
323
343
|
end
|
324
344
|
|
325
|
-
cli = Sod.new { on
|
345
|
+
cli = Sod.new { on Action }
|
326
346
|
|
327
347
|
cli.call %w[-e] # "Got: "
|
328
348
|
cli.call %w[--echo] # "Got: "
|
@@ -334,13 +354,13 @@ The method definition of `call(text = nil)` is important because if you call the
|
|
334
354
|
|
335
355
|
[source,ruby]
|
336
356
|
----
|
337
|
-
class
|
357
|
+
class Action < Sod::Action
|
338
358
|
on %w[-e --echo], argument: "TEXT"
|
339
359
|
|
340
360
|
def call(text) = puts "Got: #{text}"
|
341
361
|
end
|
342
362
|
|
343
|
-
cli = Sod.new { on
|
363
|
+
cli = Sod.new { on Action }
|
344
364
|
|
345
365
|
cli.call %w[-e] # "🛑 Missing argument: -e"
|
346
366
|
cli.call %w[--echo] # "🛑 Missing argument: --echo"
|
@@ -348,10 +368,10 @@ cli.call %w[-e hi] # "Got: hi"
|
|
348
368
|
cli.call %w[--echo hi] # "Got: hi"
|
349
369
|
----
|
350
370
|
|
351
|
-
There are
|
371
|
+
There are three major differences between a _required_ and _optional_ argument:
|
352
372
|
|
353
373
|
* The argument is required because it's not wrapped in brackets.
|
354
|
-
* The method definition requires a `text`
|
374
|
+
* The method definition requires a parameter (i.e. `text` in the above example).
|
355
375
|
* You get an error when not providing an argument.
|
356
376
|
|
357
377
|
===== Types
|
@@ -360,13 +380,13 @@ Types are optional but worth having when you need the safety check. Here's a min
|
|
360
380
|
|
361
381
|
[source,ruby]
|
362
382
|
----
|
363
|
-
class
|
383
|
+
class Action < Sod::Action
|
364
384
|
on %w[-e --echo], argument: "NUMBER", type: Float
|
365
385
|
|
366
386
|
def call(number) = puts "Got: #{number}"
|
367
387
|
end
|
368
388
|
|
369
|
-
cli = Sod.new { on
|
389
|
+
cli = Sod.new { on Action }
|
370
390
|
|
371
391
|
cli.call %w[--echo 123] # "Got: 123.0"
|
372
392
|
cli.call %w[--echo 1.5] # "Got: 1.5"
|
@@ -381,13 +401,13 @@ Allows give you the ability to define what is acceptable as input and need to ma
|
|
381
401
|
|
382
402
|
[source,ruby]
|
383
403
|
----
|
384
|
-
class
|
404
|
+
class Action < Sod::Action
|
385
405
|
on %w[-e --echo], argument: "TEXT", allow: %w[hi hello]
|
386
406
|
|
387
407
|
def call(text) = puts "Got: #{text}"
|
388
408
|
end
|
389
409
|
|
390
|
-
cli = Sod.new { on
|
410
|
+
cli = Sod.new { on Action }
|
391
411
|
|
392
412
|
cli.call %w[--echo hi] # "Got: hi"
|
393
413
|
cli.call %w[--echo hello] # "Got: hello"
|
@@ -398,56 +418,25 @@ Here you can see the first two examples pass while the last one fails because `"
|
|
398
418
|
|
399
419
|
===== Defaults
|
400
420
|
|
401
|
-
Defaults are not
|
421
|
+
Defaults are not supported by {option_parser_link} but are handy for documentation purposes and within your implementation as fallback values. Here's a minimal example:
|
402
422
|
|
403
423
|
[source,ruby]
|
404
424
|
----
|
405
|
-
class
|
425
|
+
class Action < Sod::Action
|
406
426
|
on %w[-e --echo], argument: "[TEXT]", default: "fallback"
|
407
427
|
|
408
|
-
def call(text =
|
428
|
+
def call(text = default) = puts "Got: #{text}"
|
409
429
|
end
|
410
430
|
|
411
|
-
cli = Sod.new { on
|
431
|
+
cli = Sod.new { on Action }
|
412
432
|
|
413
433
|
cli.call %w[--echo] # "Got: fallback"
|
414
434
|
cli.call %w[--echo hi] # "Got: hi"
|
415
435
|
----
|
416
436
|
|
417
|
-
Notice how the default is printed when no value is given but is overwritten when an actual value is supplied.
|
418
|
-
|
419
|
-
[source,ruby]
|
420
|
-
----
|
421
|
-
def call(text = default) = puts "Got: #{text}"
|
422
|
-
----
|
423
|
-
|
424
|
-
...you'd not be wrong. In fact, if you initialized and called the action, you'd get what you'd expect:
|
425
|
-
|
426
|
-
[source,ruby]
|
427
|
-
----
|
428
|
-
demo = Demo.new
|
429
|
-
|
430
|
-
demo.call # "Got: fallback"
|
431
|
-
demo.call "hi" # "Got: hi"
|
432
|
-
----
|
433
|
-
|
434
|
-
The reason the above is a problem is because {option_parser_link} ignores _optional_ parameters and all keywords. Here's the fully modified example:
|
435
|
-
|
436
|
-
[source,ruby]
|
437
|
-
----
|
438
|
-
class Demo < Sod::Action
|
439
|
-
on %w[-e --echo], argument: "[TEXT]", default: "fallback"
|
440
|
-
|
441
|
-
def call(text = default) = puts "Got: #{text}"
|
442
|
-
end
|
437
|
+
Notice how the default is printed when no value is given but is overwritten when an actual value is supplied.
|
443
438
|
|
444
|
-
|
445
|
-
|
446
|
-
cli.call %w[--echo] # "Got: "
|
447
|
-
cli.call %w[--echo hi] # "Got: hi"
|
448
|
-
----
|
449
|
-
|
450
|
-
Notice how there is surprising behavior with the first result (i.e. an empty string). This is because when {option_parser_link} completely ignores the value of the _optional_ parameter. I've logged an link:https://github.com/ruby/optparse/issues/55[issue] if you want to know more. For now, be aware of this quirk as it can be confusing if you are not familiar with {option_parser_link}.
|
439
|
+
💡 If you need to lazy compute a default value, then use the block syntax instead.
|
451
440
|
|
452
441
|
===== Examples
|
453
442
|
|
@@ -464,7 +453,7 @@ class Echo < Sod::Action
|
|
464
453
|
|
465
454
|
default { "hello" }
|
466
455
|
|
467
|
-
def call(text =
|
456
|
+
def call(text = default) = puts text
|
468
457
|
end
|
469
458
|
|
470
459
|
cli = Sod.new :demo, banner: "Demo 0.0.0: A demonstration" do
|
@@ -737,7 +726,9 @@ class Demo < Sod::Command
|
|
737
726
|
end
|
738
727
|
----
|
739
728
|
|
740
|
-
One major difference between _reusable_ and _inline_ commands is that _reusable_ commands allow you implement a `#call` method. This method is optional, so if you don't need it, you don't have to implement it. However, if you do, this means you can process the input from your actions. This method is called _after_ the option parser has parsed all command line input for your actions which gives you a handy way to process all collected input via a single command.
|
729
|
+
One major difference between _reusable_ and _inline_ commands is that _reusable_ commands allow you implement a `#call` method. This method is optional, so if you don't need it, you don't have to implement it. However, if you do, this means you can process the input from your actions. This method is called _after_ the option parser has parsed all command line input for your actions which gives you a handy way to process all collected input via a single command.
|
730
|
+
|
731
|
+
💡 This is how the {rubysmith_link}, {gemsmith_link}, and {hanamismith_link} gems all build new Ruby projects for you based on the actions passed to them via the CLI.
|
741
732
|
|
742
733
|
==== Initialization
|
743
734
|
|
@@ -775,7 +766,7 @@ context = Sod::Context.new defaults_path: "path/to/defaults.yml", version_label:
|
|
775
766
|
context = Sod::Context[defaults_path: "path/to/defaults.yml", version_label: "Demo 0.0.0"]
|
776
767
|
----
|
777
768
|
|
778
|
-
Once you have an instance, you can use
|
769
|
+
Once you have an instance, you can use as follows:
|
779
770
|
|
780
771
|
[source,ruby]
|
781
772
|
----
|
@@ -805,7 +796,7 @@ end
|
|
805
796
|
|
806
797
|
Types are a way to extend default {option_parser_link} functionality. Here are a few types -- not provided by {option_parser_link} -- worth knowing about:
|
807
798
|
|
808
|
-
|
799
|
+
===== Pathname
|
809
800
|
|
810
801
|
Provided by this gem and must be manually required since it's disabled by default. Example:
|
811
802
|
|
@@ -821,7 +812,7 @@ end
|
|
821
812
|
|
822
813
|
With the above, you'll always get a link:https://rubyapi.org/o/s?q=Pathname[Pathname] instance as input to your action.
|
823
814
|
|
824
|
-
|
815
|
+
===== Version
|
825
816
|
|
826
817
|
Provided via the {versionaire_link} gem which gives you a `Version` type when dealing with link:https://semver.org[semantic versions]. Here's how to leverage it:
|
827
818
|
|
@@ -835,7 +826,7 @@ class Demo < Sod::Action
|
|
835
826
|
end
|
836
827
|
----
|
837
828
|
|
838
|
-
|
829
|
+
===== Custom
|
839
830
|
|
840
831
|
Creating a custom type requires minimal effort and can be implemented in only a few files:
|
841
832
|
|
data/lib/sod/graph/loader.rb
CHANGED
data/lib/sod/graph/runner.rb
CHANGED
@@ -6,7 +6,7 @@ module Sod
|
|
6
6
|
class Runner
|
7
7
|
include Import[:client, :logger]
|
8
8
|
|
9
|
-
using Refines::
|
9
|
+
using Refines::OptionParser
|
10
10
|
|
11
11
|
HELP_PATTERN = /
|
12
12
|
\A # Start of string.
|
@@ -48,6 +48,8 @@ module Sod
|
|
48
48
|
usage(*arguments)
|
49
49
|
else
|
50
50
|
parser, node = registry.fetch lineage, client
|
51
|
+
alter_callback_for parser
|
52
|
+
|
51
53
|
parser.order! arguments, command: node do |command|
|
52
54
|
lineage.concat(" ", command).tap(&:strip!)
|
53
55
|
visit arguments
|
@@ -55,6 +57,15 @@ module Sod
|
|
55
57
|
end
|
56
58
|
end
|
57
59
|
|
60
|
+
# :reek:FeatureEnvy
|
61
|
+
def alter_callback_for parser
|
62
|
+
parser.define_singleton_method :callback! do |function, max_arity, *positionals|
|
63
|
+
return function.call if function.arity == -1 && positionals.empty?
|
64
|
+
|
65
|
+
super(function, max_arity, *positionals)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
58
69
|
def usage(*arguments)
|
59
70
|
commands = arguments.grep_v help_pattern
|
60
71
|
commands = lineage.split if commands.empty?
|
@@ -5,10 +5,10 @@ require "optparse"
|
|
5
5
|
module Sod
|
6
6
|
module Refines
|
7
7
|
# Provides additional enhancements to the option parser primitive.
|
8
|
-
module
|
9
|
-
refine OptionParser do
|
10
|
-
def order!(argument = default_argv, into: nil, command: nil, &)
|
11
|
-
super(argument, into:, &)
|
8
|
+
module OptionParser
|
9
|
+
refine ::OptionParser do
|
10
|
+
def order!(argument = default_argv, into: nil, command: nil, **, &)
|
11
|
+
super(argument, into:, **, &)
|
12
12
|
command.call if command
|
13
13
|
end
|
14
14
|
|
data/sod.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = "sod"
|
5
|
-
spec.version = "0.
|
5
|
+
spec.version = "0.14.0"
|
6
6
|
spec.authors = ["Brooke Kuhlmann"]
|
7
7
|
spec.email = ["brooke@alchemists.io"]
|
8
8
|
spec.homepage = "https://alchemists.io/projects/sod"
|
@@ -26,7 +26,8 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.add_dependency "cogger", "~> 0.21"
|
27
27
|
spec.add_dependency "containable", "~> 0.2"
|
28
28
|
spec.add_dependency "infusible", "~> 3.8"
|
29
|
-
spec.add_dependency "
|
29
|
+
spec.add_dependency "optparse", "~> 0.5"
|
30
|
+
spec.add_dependency "refinements", "~> 12.7"
|
30
31
|
spec.add_dependency "tone", "~> 1.0"
|
31
32
|
spec.add_dependency "zeitwerk", "~> 2.6"
|
32
33
|
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sod
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brooke Kuhlmann
|
@@ -35,7 +35,7 @@ cert_chain:
|
|
35
35
|
3n5C8/6Zh9DYTkpcwPSuIfAga6wf4nXc9m6JAw8AuMLaiWN/r/2s4zJsUHYERJEu
|
36
36
|
gZGm4JqtuSg8pYjPeIJxS960owq+SfuC+jxqmRA54BisFCv/0VOJi7tiJVY=
|
37
37
|
-----END CERTIFICATE-----
|
38
|
-
date: 2024-
|
38
|
+
date: 2024-08-11 00:00:00.000000000 Z
|
39
39
|
dependencies:
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: cogger
|
@@ -79,20 +79,34 @@ dependencies:
|
|
79
79
|
- - "~>"
|
80
80
|
- !ruby/object:Gem::Version
|
81
81
|
version: '3.8'
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: optparse
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0.5'
|
89
|
+
type: :runtime
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0.5'
|
82
96
|
- !ruby/object:Gem::Dependency
|
83
97
|
name: refinements
|
84
98
|
requirement: !ruby/object:Gem::Requirement
|
85
99
|
requirements:
|
86
100
|
- - "~>"
|
87
101
|
- !ruby/object:Gem::Version
|
88
|
-
version: '12.
|
102
|
+
version: '12.7'
|
89
103
|
type: :runtime
|
90
104
|
prerelease: false
|
91
105
|
version_requirements: !ruby/object:Gem::Requirement
|
92
106
|
requirements:
|
93
107
|
- - "~>"
|
94
108
|
- !ruby/object:Gem::Version
|
95
|
-
version: '12.
|
109
|
+
version: '12.7'
|
96
110
|
- !ruby/object:Gem::Dependency
|
97
111
|
name: tone
|
98
112
|
requirement: !ruby/object:Gem::Requirement
|
@@ -153,7 +167,7 @@ files:
|
|
153
167
|
- lib/sod/prefabs/commands/config.rb
|
154
168
|
- lib/sod/presenters/action.rb
|
155
169
|
- lib/sod/presenters/node.rb
|
156
|
-
- lib/sod/refines/
|
170
|
+
- lib/sod/refines/option_parser.rb
|
157
171
|
- lib/sod/shell.rb
|
158
172
|
- lib/sod/types/pathname.rb
|
159
173
|
- sod.gemspec
|
@@ -183,7 +197,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
183
197
|
- !ruby/object:Gem::Version
|
184
198
|
version: '0'
|
185
199
|
requirements: []
|
186
|
-
rubygems_version: 3.5.
|
200
|
+
rubygems_version: 3.5.17
|
187
201
|
signing_key:
|
188
202
|
specification_version: 4
|
189
203
|
summary: A domain specific language for creating composable command line interfaces.
|
metadata.gz.sig
CHANGED
Binary file
|