command_mapper 0.2.0 → 0.2.1
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/ChangeLog.md +11 -0
- data/README.md +15 -3
- data/examples/grep.rb +62 -0
- data/lib/command_mapper/arg.rb +4 -0
- data/lib/command_mapper/argument.rb +6 -0
- data/lib/command_mapper/command.rb +59 -29
- data/lib/command_mapper/option.rb +8 -0
- data/lib/command_mapper/option_value.rb +22 -0
- data/lib/command_mapper/types/enum.rb +8 -0
- data/lib/command_mapper/types/hex.rb +6 -0
- data/lib/command_mapper/types/input_dir.rb +2 -0
- data/lib/command_mapper/types/input_file.rb +2 -0
- data/lib/command_mapper/types/input_path.rb +2 -0
- data/lib/command_mapper/types/key_value.rb +10 -0
- data/lib/command_mapper/types/key_value_list.rb +2 -0
- data/lib/command_mapper/types/list.rb +10 -0
- data/lib/command_mapper/types/map.rb +10 -1
- data/lib/command_mapper/types/num.rb +7 -1
- data/lib/command_mapper/types/str.rb +10 -1
- data/lib/command_mapper/types/type.rb +4 -0
- data/lib/command_mapper/version.rb +1 -1
- data/spec/commnad_spec.rb +20 -0
- data/spec/option_value_spec.rb +28 -0
- data/spec/types/map_spec.rb +2 -2
- data/spec/types/num_spec.rb +6 -6
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: abc51ed8c1f7edf0484053eb62854a56b13dce9d5e3ea7b3373799c4b7a1d4fb
|
4
|
+
data.tar.gz: 0e7945e79e57cb99a4448b4eafef1237e9cc5e06d4523e13efd68b2767106a2f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea9449f43ab086e941cc011dffd778cea4d356a2a9171aef5496e9a4593f62ca3ba68356d455cc510046ee926970c290c065b76bf445ba843a317f60c0fbbd31
|
7
|
+
data.tar.gz: 5979c264d481d50be2fed8ca17a19cb59b4c522303ff4d5cdf14164195b9b27fd6589ebe5b8e0b06276494f5298c6898fb297a97a606ca10d5fb916dbe1d568d
|
data/ChangeLog.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
### 0.2.1 / 2022-04-22
|
2
|
+
|
3
|
+
* Properly validate in {CommandMapper::OptionValue#validate} when an option,
|
4
|
+
who's value is not required, is given `true`.
|
5
|
+
* Omit `nil` arguments from {CommandMapper::Command#command_argv} if the
|
6
|
+
argument is not required.
|
7
|
+
* Improve validation error message for {CommandMapper::Types::Num} when
|
8
|
+
initialized with a `range:` value.
|
9
|
+
* Improve validation error message for {CommandMapper::Types::Map} and
|
10
|
+
{CommandMapper::Types::Enum}.
|
11
|
+
|
1
12
|
### 0.2.0 / 2022-04-18
|
2
13
|
|
3
14
|
* Added {CommandMapper::Command.spawn} and
|
data/README.md
CHANGED
@@ -21,9 +21,9 @@ allow safely and securely executing commands.
|
|
21
21
|
* [Str][CommandMapper::Types::Str]: string values
|
22
22
|
* [Num][CommandMapper::Types::Num]: numeric values
|
23
23
|
* [Hex][CommandMapper::Types::Hex]: hexadecimal values
|
24
|
-
* [Map][CommandMapper::Types::Map]: maps
|
25
|
-
`
|
26
|
-
|
24
|
+
* [Map][CommandMapper::Types::Map]: maps Ruby values to other String values.
|
25
|
+
* `Map::YesNo`: maps `true`/`false` to `yes`/`no`.
|
26
|
+
* `Map::EnabledDisabled`: Maps `true`/`false` to `enabled`/`disabled`.
|
27
27
|
* [Enum][CommandMapper::Types::Enum]: maps a finite set of Symbols to a
|
28
28
|
finite set of Strings (aka `--opt={foo|bar|baz}` values).
|
29
29
|
* [List][CommandMapper::Types::List]: comma-separated list
|
@@ -314,6 +314,18 @@ Grep.run do |grep|
|
|
314
314
|
end
|
315
315
|
```
|
316
316
|
|
317
|
+
Overriding the command name:
|
318
|
+
|
319
|
+
```ruby
|
320
|
+
Grep.run(..., command_name: 'grep2')
|
321
|
+
```
|
322
|
+
|
323
|
+
Specifying the direct path to the command:
|
324
|
+
|
325
|
+
```ruby
|
326
|
+
Grep.run(..., command_path: '/path/to/grep')
|
327
|
+
```
|
328
|
+
|
317
329
|
### Capturing output
|
318
330
|
|
319
331
|
```ruby
|
data/examples/grep.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'command_mapper/command'
|
2
|
+
|
3
|
+
#
|
4
|
+
# Represents the `grep` command
|
5
|
+
#
|
6
|
+
class Grep < CommandMapper::Command
|
7
|
+
|
8
|
+
command "grep" do
|
9
|
+
option "--extended-regexp"
|
10
|
+
option "--fixed-strings"
|
11
|
+
option "--basic-regexp"
|
12
|
+
option "--perl-regexp"
|
13
|
+
option "--regexp", equals: true, value: true
|
14
|
+
option "--file", name: :patterns_file, equals: true, value: true
|
15
|
+
option "--ignore-case"
|
16
|
+
option "--no-ignore-case"
|
17
|
+
option "--word-regexp"
|
18
|
+
option "--line-regexp"
|
19
|
+
option "--null-data"
|
20
|
+
option "--no-messages"
|
21
|
+
option "--invert-match"
|
22
|
+
option "--version"
|
23
|
+
option "--help"
|
24
|
+
option "--max-count", equals: true, value: {type: Num.new}
|
25
|
+
option "--byte-offset"
|
26
|
+
option "--line-number"
|
27
|
+
option "--line-buffered"
|
28
|
+
option "--with-filename"
|
29
|
+
option "--no-filename"
|
30
|
+
option "--label", equals: true, value: true
|
31
|
+
option "--only-matching"
|
32
|
+
option "--quiet"
|
33
|
+
option "--binary-files", equals: true, value: true
|
34
|
+
option "--text"
|
35
|
+
option "-I", name: :binary
|
36
|
+
option "--directories", equals: true, value: true
|
37
|
+
option "--devices", equals: true, value: true
|
38
|
+
option "--recursive"
|
39
|
+
option "--dereference-recursive"
|
40
|
+
option "--include", equals: true, value: true
|
41
|
+
option "--exclude", equals: true, value: true
|
42
|
+
option "--exclude-from", equals: true, value: true
|
43
|
+
option "--exclude-dir", equals: true, value: true
|
44
|
+
option "--files-without-match", value: true
|
45
|
+
option "--files-with-matches"
|
46
|
+
option "--count"
|
47
|
+
option "--initial-tab"
|
48
|
+
option "--null"
|
49
|
+
option "--before-context", equals: true, value: {type: Num.new}
|
50
|
+
option "--after-context", equals: true, value: {type: Num.new}
|
51
|
+
option "--context", equals: true, value: {type: Num.new}
|
52
|
+
option "--group-separator", equals: true, value: true
|
53
|
+
option "--no-group-separator"
|
54
|
+
option "--color", equals: :optional, value: {required: false}
|
55
|
+
option "--colour", equals: :optional, value: {required: false}
|
56
|
+
option "--binary"
|
57
|
+
|
58
|
+
argument :patterns
|
59
|
+
argument :file, required: false, repeats: true
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
data/lib/command_mapper/arg.rb
CHANGED
@@ -24,6 +24,8 @@ module CommandMapper
|
|
24
24
|
# @raise [ArgumentError]
|
25
25
|
# The `type` keyword argument was given a `nil` value.
|
26
26
|
#
|
27
|
+
# @api private
|
28
|
+
#
|
27
29
|
def initialize(required: true, type: Types::Str.new)
|
28
30
|
@required = required
|
29
31
|
|
@@ -62,6 +64,8 @@ module CommandMapper
|
|
62
64
|
# Returns true if the value is valid, or `false` and a validation error
|
63
65
|
# message if the value is not compatible.
|
64
66
|
#
|
67
|
+
# @api semipublic
|
68
|
+
#
|
65
69
|
def validate(value)
|
66
70
|
if value.nil?
|
67
71
|
if required?
|
@@ -30,6 +30,8 @@ module CommandMapper
|
|
30
30
|
# @raise [ArgumentError]
|
31
31
|
# The given `type:` must not be `false` or `nil`.
|
32
32
|
#
|
33
|
+
# @api private
|
34
|
+
#
|
33
35
|
def initialize(name, required: true, type: Types::Str.new, repeats: false)
|
34
36
|
super(required: required, type: type)
|
35
37
|
|
@@ -56,6 +58,8 @@ module CommandMapper
|
|
56
58
|
# Returns true if the value is valid, or `false` and a validation error
|
57
59
|
# message if the value is not compatible.
|
58
60
|
#
|
61
|
+
# @api semipublic
|
62
|
+
#
|
59
63
|
def validate(value)
|
60
64
|
if repeats?
|
61
65
|
values = case value
|
@@ -101,6 +105,8 @@ module CommandMapper
|
|
101
105
|
# @raise [ArgumentError]
|
102
106
|
# The given value was incompatible with the argument.
|
103
107
|
#
|
108
|
+
# @api semipublic
|
109
|
+
#
|
104
110
|
def argv(argv=[],value)
|
105
111
|
valid, message = validate(value)
|
106
112
|
|
@@ -5,6 +5,11 @@ require 'command_mapper/option'
|
|
5
5
|
require 'shellwords'
|
6
6
|
|
7
7
|
module CommandMapper
|
8
|
+
#
|
9
|
+
# Base class for all mapped commands.
|
10
|
+
#
|
11
|
+
# @api public
|
12
|
+
#
|
8
13
|
class Command
|
9
14
|
|
10
15
|
include Types
|
@@ -24,16 +29,6 @@ module CommandMapper
|
|
24
29
|
# @return [Hash{String => String}]
|
25
30
|
attr_reader :command_env
|
26
31
|
|
27
|
-
# The option values to execute the command with.
|
28
|
-
#
|
29
|
-
# @return [Hash{String => Object}]
|
30
|
-
attr_reader :command_options
|
31
|
-
|
32
|
-
# The argument values to execute the command with.
|
33
|
-
#
|
34
|
-
# @return [Hash{String => Object}]
|
35
|
-
attr_reader :command_arguments
|
36
|
-
|
37
32
|
# The subcommand's options and arguments.
|
38
33
|
#
|
39
34
|
# @return [Command, nil]
|
@@ -51,7 +46,7 @@ module CommandMapper
|
|
51
46
|
# @param [String, nil] command_path
|
52
47
|
# Overrides the command with a custom path to the command.
|
53
48
|
#
|
54
|
-
# @param [Hash{String => String}]
|
49
|
+
# @param [Hash{String => String}] command_env
|
55
50
|
# Custom environment variables to pass to the command.
|
56
51
|
#
|
57
52
|
# @param [Hash{Symbol => Object}] kwargs
|
@@ -94,12 +89,16 @@ module CommandMapper
|
|
94
89
|
# Initializes and runs the command.
|
95
90
|
#
|
96
91
|
# @param [Hash{Symbol => Object}] params
|
97
|
-
# The option values.
|
92
|
+
# The option and argument values.
|
98
93
|
#
|
99
|
-
# @
|
94
|
+
# @param [Hash{Symbol => Object}] kwargs
|
95
|
+
# Additional keywords arguments. These will be used to populate
|
96
|
+
# {#options} and {#arguments}, along with `params`.
|
97
|
+
#
|
98
|
+
# @yield [command]
|
100
99
|
# The newly initialized command.
|
101
100
|
#
|
102
|
-
# @yieldparam [Command]
|
101
|
+
# @yieldparam [Command] command
|
103
102
|
#
|
104
103
|
# @return [Boolean, nil]
|
105
104
|
#
|
@@ -113,12 +112,16 @@ module CommandMapper
|
|
113
112
|
# PID of the process.
|
114
113
|
#
|
115
114
|
# @param [Hash{Symbol => Object}] params
|
116
|
-
# The option values.
|
115
|
+
# The option and argument values.
|
117
116
|
#
|
118
|
-
# @
|
117
|
+
# @param [Hash{Symbol => Object}] kwargs
|
118
|
+
# Additional keywords arguments. These will be used to populate
|
119
|
+
# {#options} and {#arguments}, along with `params`.
|
120
|
+
#
|
121
|
+
# @yield [command]
|
119
122
|
# The newly initialized command.
|
120
123
|
#
|
121
|
-
# @yieldparam [Command]
|
124
|
+
# @yieldparam [Command] command
|
122
125
|
#
|
123
126
|
# @return [Integer]
|
124
127
|
# The PID of the new command process.
|
@@ -138,12 +141,16 @@ module CommandMapper
|
|
138
141
|
# output.
|
139
142
|
#
|
140
143
|
# @param [Hash{Symbol => Object}] params
|
141
|
-
# The option values.
|
144
|
+
# The option and argument values.
|
142
145
|
#
|
143
|
-
# @
|
146
|
+
# @param [Hash{Symbol => Object}] kwargs
|
147
|
+
# Additional keywords arguments. These will be used to populate
|
148
|
+
# {#options} and {#arguments}, along with `params`.
|
149
|
+
#
|
150
|
+
# @yield [command]
|
144
151
|
# The newly initialized command.
|
145
152
|
#
|
146
|
-
# @yieldparam [Command]
|
153
|
+
# @yieldparam [Command] command
|
147
154
|
#
|
148
155
|
# @return [String]
|
149
156
|
# The stdout output of the command.
|
@@ -157,12 +164,19 @@ module CommandMapper
|
|
157
164
|
# Initializes and executes the command and returns an IO object to it.
|
158
165
|
#
|
159
166
|
# @param [Hash{Symbol => Object}] params
|
160
|
-
# The option values.
|
167
|
+
# The option and argument values.
|
161
168
|
#
|
162
|
-
# @
|
169
|
+
# @param [String] mode
|
170
|
+
# The IO "mode" to open the IO pipe in.
|
171
|
+
#
|
172
|
+
# @param [Hash{Symbol => Object}] kwargs
|
173
|
+
# Additional keywords arguments. These will be used to populate
|
174
|
+
# {#options} and {#arguments}, along with `params`.
|
175
|
+
#
|
176
|
+
# @yield [command]
|
163
177
|
# The newly initialized command.
|
164
178
|
#
|
165
|
-
# @yieldparam [Command]
|
179
|
+
# @yieldparam [Command] command
|
166
180
|
#
|
167
181
|
# @return [IO]
|
168
182
|
#
|
@@ -175,15 +189,15 @@ module CommandMapper
|
|
175
189
|
# Initializes and runs the command through `sudo`.
|
176
190
|
#
|
177
191
|
# @param [Hash{Symbol => Object}] params
|
178
|
-
# The option values.
|
192
|
+
# The option and argument values.
|
179
193
|
#
|
180
194
|
# @param [Hash{Symbol => Object}] kwargs
|
181
195
|
# Additional keyword arguments for {#initialize}.
|
182
196
|
#
|
183
|
-
# @yield [
|
197
|
+
# @yield [command]
|
184
198
|
# The newly initialized command.
|
185
199
|
#
|
186
|
-
# @yieldparam [Command]
|
200
|
+
# @yieldparam [Command] command
|
187
201
|
#
|
188
202
|
# @return [Boolean, nil]
|
189
203
|
#
|
@@ -360,6 +374,7 @@ module CommandMapper
|
|
360
374
|
# All defined options.
|
361
375
|
#
|
362
376
|
# @return [Hash{Symbol => Argument}]
|
377
|
+
# The mapping of argument names and {Argument} objects.
|
363
378
|
#
|
364
379
|
# @api semipublic
|
365
380
|
#
|
@@ -438,7 +453,8 @@ module CommandMapper
|
|
438
453
|
#
|
439
454
|
# All defined subcommands.
|
440
455
|
#
|
441
|
-
# @return [Hash{Symbol => Command}]
|
456
|
+
# @return [Hash{Symbol => Command.class}]
|
457
|
+
# The mapping of subcommand names and subcommand classes.
|
442
458
|
#
|
443
459
|
# @api semipublic
|
444
460
|
#
|
@@ -535,8 +551,10 @@ module CommandMapper
|
|
535
551
|
# Gets the value of an option or an argument.
|
536
552
|
#
|
537
553
|
# @param [Symbol] name
|
554
|
+
# The name of the option, argument, or subcommand.
|
538
555
|
#
|
539
556
|
# @return [Object]
|
557
|
+
# The value of the option, argument, or subcommand.
|
540
558
|
#
|
541
559
|
# @raise [ArgumentError]
|
542
560
|
# The given name was not match any option or argument.
|
@@ -555,10 +573,13 @@ module CommandMapper
|
|
555
573
|
# Sets an option or an argument with the given name.
|
556
574
|
#
|
557
575
|
# @param [Symbol] name
|
576
|
+
# The name of the option, argument, or subcommand.
|
558
577
|
#
|
559
578
|
# @param [Object] value
|
579
|
+
# The new value for the option, argument, or subcommand.
|
560
580
|
#
|
561
581
|
# @return [Object]
|
582
|
+
# The new value for the option, argument, or subcommand.
|
562
583
|
#
|
563
584
|
# @raise [ArgumentError]
|
564
585
|
# The given name was not match any option or argument.
|
@@ -575,6 +596,7 @@ module CommandMapper
|
|
575
596
|
# Returns an Array of command-line arguments for the command.
|
576
597
|
#
|
577
598
|
# @return [Array<String>]
|
599
|
+
# The formatted command-line arguments.
|
578
600
|
#
|
579
601
|
# @raise [ArgumentReqired]
|
580
602
|
# A required argument was not set.
|
@@ -597,8 +619,10 @@ module CommandMapper
|
|
597
619
|
self.class.arguments.each do |name,argument|
|
598
620
|
value = self[name]
|
599
621
|
|
600
|
-
if value.nil?
|
601
|
-
|
622
|
+
if value.nil?
|
623
|
+
if argument.required?
|
624
|
+
raise(ArgumentRequired,"argument #{name} is required")
|
625
|
+
end
|
602
626
|
else
|
603
627
|
argument.argv(additional_args,value)
|
604
628
|
end
|
@@ -639,6 +663,8 @@ module CommandMapper
|
|
639
663
|
# Runs the command.
|
640
664
|
#
|
641
665
|
# @return [Boolean, nil]
|
666
|
+
# Indicates whether the command exited successfully or not.
|
667
|
+
# `nil` indicates the command could not be found.
|
642
668
|
#
|
643
669
|
def run_command
|
644
670
|
Kernel.system(@command_env,*command_argv)
|
@@ -674,6 +700,7 @@ module CommandMapper
|
|
674
700
|
# Executes the command and returns an IO object to it.
|
675
701
|
#
|
676
702
|
# @return [IO]
|
703
|
+
# The IO object for the command's `STDIN`.
|
677
704
|
#
|
678
705
|
def popen_command(mode=nil)
|
679
706
|
if mode then IO.popen(@command_env,command_argv,mode)
|
@@ -688,6 +715,8 @@ module CommandMapper
|
|
688
715
|
# Additional keyword arguments for {Sudo#initialize}.
|
689
716
|
#
|
690
717
|
# @return [Boolean, nil]
|
718
|
+
# Indicates whether the command exited successfully or not.
|
719
|
+
# `nil` indicates the command could not be found.
|
691
720
|
#
|
692
721
|
def sudo_command(**sudo_kwargs,&block)
|
693
722
|
sudo_params = sudo_kwargs.merge(command: command_argv)
|
@@ -718,6 +747,7 @@ module CommandMapper
|
|
718
747
|
# The method name.
|
719
748
|
#
|
720
749
|
# @return [Boolean]
|
750
|
+
# Indicates that the method name is also an intenral method name.
|
721
751
|
#
|
722
752
|
def self.is_internal_method?(name)
|
723
753
|
Command.instance_methods(false).include?(name.to_sym)
|
@@ -51,6 +51,8 @@ module CommandMapper
|
|
51
51
|
# Specifies that the value should be appended to the option's flag
|
52
52
|
# (ex: `-Fvalue`).
|
53
53
|
#
|
54
|
+
# @api private
|
55
|
+
#
|
54
56
|
def initialize(flag, name: nil, value: nil, repeats: false,
|
55
57
|
# formatting options
|
56
58
|
equals: nil,
|
@@ -81,6 +83,8 @@ module CommandMapper
|
|
81
83
|
# Could not infer the name from the given option flag or was not given a
|
82
84
|
# valid option flag.
|
83
85
|
#
|
86
|
+
# @api private
|
87
|
+
#
|
84
88
|
def self.infer_name_from_flag(flag)
|
85
89
|
if flag.start_with?('--')
|
86
90
|
name = flag[2..-1]
|
@@ -146,6 +150,8 @@ module CommandMapper
|
|
146
150
|
# Returns true if the value is valid, or `false` and a validation error
|
147
151
|
# message if the value is not compatible.
|
148
152
|
#
|
153
|
+
# @api semipublic
|
154
|
+
#
|
149
155
|
def validate(value)
|
150
156
|
if accepts_value?
|
151
157
|
if repeats?
|
@@ -173,6 +179,8 @@ module CommandMapper
|
|
173
179
|
# @raise [ArgumentError]
|
174
180
|
# The given value was incompatible with the option.
|
175
181
|
#
|
182
|
+
# @api semipublic
|
183
|
+
#
|
176
184
|
def argv(argv=[],value)
|
177
185
|
valid, message = validate(value)
|
178
186
|
|
@@ -6,6 +6,26 @@ module CommandMapper
|
|
6
6
|
#
|
7
7
|
class OptionValue < Arg
|
8
8
|
|
9
|
+
#
|
10
|
+
# Validates whether a given value is compatible with the option {#type}.
|
11
|
+
#
|
12
|
+
# @param [Object] value
|
13
|
+
# The given value to validate.
|
14
|
+
#
|
15
|
+
# @return [true, (false, String)]
|
16
|
+
# Returns true if the value is valid, or `false` and a validation error
|
17
|
+
# message if the value is not compatible.
|
18
|
+
#
|
19
|
+
# @api semipublic
|
20
|
+
#
|
21
|
+
def validate(value)
|
22
|
+
if !required? && value == true
|
23
|
+
return true
|
24
|
+
else
|
25
|
+
super(value)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
9
29
|
#
|
10
30
|
# Formats a value using the options {#type}.
|
11
31
|
#
|
@@ -15,6 +35,8 @@ module CommandMapper
|
|
15
35
|
# @return [String]
|
16
36
|
# The formatted value.
|
17
37
|
#
|
38
|
+
# @api semipublic
|
39
|
+
#
|
18
40
|
def format(value)
|
19
41
|
@type.format(value)
|
20
42
|
end
|
@@ -2,9 +2,17 @@ require 'command_mapper/types/map'
|
|
2
2
|
|
3
3
|
module CommandMapper
|
4
4
|
module Types
|
5
|
+
#
|
6
|
+
# Represents a mapping of Ruby values to their String equivalents.
|
7
|
+
#
|
5
8
|
class Enum < Map
|
6
9
|
|
10
|
+
# The values of the enum.
|
11
|
+
#
|
7
12
|
# @return [Array<Object>]
|
13
|
+
#
|
14
|
+
# @api semipublic
|
15
|
+
#
|
8
16
|
attr_reader :values
|
9
17
|
|
10
18
|
#
|
@@ -27,6 +27,8 @@ module CommandMapper
|
|
27
27
|
#
|
28
28
|
# @return [Boolean]
|
29
29
|
#
|
30
|
+
# @api semipublic
|
31
|
+
#
|
30
32
|
def leading_zero?
|
31
33
|
@leading_zero
|
32
34
|
end
|
@@ -41,6 +43,8 @@ module CommandMapper
|
|
41
43
|
# Returns true if the value is valid, or `false` and a validation error
|
42
44
|
# message if the value is not compatible.
|
43
45
|
#
|
46
|
+
# @api semipublic
|
47
|
+
#
|
44
48
|
def validate(value)
|
45
49
|
case value
|
46
50
|
when String
|
@@ -69,6 +73,8 @@ module CommandMapper
|
|
69
73
|
# @return [String]
|
70
74
|
# The formatted numeric value.
|
71
75
|
#
|
76
|
+
# @api semipublic
|
77
|
+
#
|
72
78
|
def format(value)
|
73
79
|
case value
|
74
80
|
when String
|
@@ -11,16 +11,22 @@ module CommandMapper
|
|
11
11
|
# The separator String between the key and value.
|
12
12
|
#
|
13
13
|
# @return [String]
|
14
|
+
#
|
15
|
+
# @api semipublic
|
14
16
|
attr_reader :separator
|
15
17
|
|
16
18
|
# The key's type.
|
17
19
|
#
|
18
20
|
# @return [Type]
|
21
|
+
#
|
22
|
+
# @api semipublic
|
19
23
|
attr_reader :key
|
20
24
|
|
21
25
|
# The value's type.
|
22
26
|
#
|
23
27
|
# @return [Type]
|
28
|
+
#
|
29
|
+
# @api semipublic
|
24
30
|
attr_reader :value
|
25
31
|
|
26
32
|
#
|
@@ -63,6 +69,8 @@ module CommandMapper
|
|
63
69
|
# Returns true if the value is valid, or `false` and a validation error
|
64
70
|
# message if the value is not compatible.
|
65
71
|
#
|
72
|
+
# @api semipublic
|
73
|
+
#
|
66
74
|
def validate(value)
|
67
75
|
case value
|
68
76
|
when Hash
|
@@ -113,6 +121,8 @@ module CommandMapper
|
|
113
121
|
# @return [String]
|
114
122
|
# The formatted key-value pair.
|
115
123
|
#
|
124
|
+
# @api semipublic
|
125
|
+
#
|
116
126
|
def format(value)
|
117
127
|
case value
|
118
128
|
when Hash, Array
|
@@ -11,11 +11,15 @@ module CommandMapper
|
|
11
11
|
# The seperator character.
|
12
12
|
#
|
13
13
|
# @return [String]
|
14
|
+
#
|
15
|
+
# @api semipublic
|
14
16
|
attr_reader :separator
|
15
17
|
|
16
18
|
# The list element type.
|
17
19
|
#
|
18
20
|
# @return [Type]
|
21
|
+
#
|
22
|
+
# @api semipublic
|
19
23
|
attr_reader :type
|
20
24
|
|
21
25
|
#
|
@@ -43,6 +47,8 @@ module CommandMapper
|
|
43
47
|
#
|
44
48
|
# @return [Boolean]
|
45
49
|
#
|
50
|
+
# @api semipublic
|
51
|
+
#
|
46
52
|
def allow_empty?
|
47
53
|
@allow_empty
|
48
54
|
end
|
@@ -57,6 +63,8 @@ module CommandMapper
|
|
57
63
|
# Returns true if the value is valid, or `false` and a validation error
|
58
64
|
# message if the value is not compatible.
|
59
65
|
#
|
66
|
+
# @api semipublic
|
67
|
+
#
|
60
68
|
def validate(value)
|
61
69
|
values = Array(value)
|
62
70
|
|
@@ -86,6 +94,8 @@ module CommandMapper
|
|
86
94
|
# @return [String]
|
87
95
|
# The formatted list.
|
88
96
|
#
|
97
|
+
# @api semipublic
|
98
|
+
#
|
89
99
|
def format(value)
|
90
100
|
Array(value).map(&@type.method(:format)).join(@separator)
|
91
101
|
end
|
@@ -2,11 +2,16 @@ require 'command_mapper/types/type'
|
|
2
2
|
|
3
3
|
module CommandMapper
|
4
4
|
module Types
|
5
|
+
#
|
6
|
+
# Represents a mapping of Ruby values to other String values.
|
7
|
+
#
|
5
8
|
class Map < Type
|
6
9
|
|
7
10
|
# The map of values to Strings.
|
8
11
|
#
|
9
12
|
# @return [Hash{Object => String}]
|
13
|
+
#
|
14
|
+
# @api semipublic
|
10
15
|
attr_reader :map
|
11
16
|
|
12
17
|
#
|
@@ -47,9 +52,11 @@ module CommandMapper
|
|
47
52
|
# Returns true if the value is valid, or `false` and a validation error
|
48
53
|
# message if the value is not compatible.
|
49
54
|
#
|
55
|
+
# @api semipublic
|
56
|
+
#
|
50
57
|
def validate(value)
|
51
58
|
unless (@map.has_key?(value) || @map.has_value?(value))
|
52
|
-
return [false, "unknown value (#{value.inspect})"]
|
59
|
+
return [false, "unknown value (#{value.inspect}) must be #{@map.keys.map(&:inspect).join(', ')}, or #{@map.values.map(&:inspect).join(', ')}"]
|
53
60
|
end
|
54
61
|
|
55
62
|
return true
|
@@ -67,6 +74,8 @@ module CommandMapper
|
|
67
74
|
# @raise [KeyError]
|
68
75
|
# The given value is not a key or value in the map.
|
69
76
|
#
|
77
|
+
# @api semipublic
|
78
|
+
#
|
70
79
|
def format(value)
|
71
80
|
if @map.has_key?(value)
|
72
81
|
super(@map[value])
|
@@ -10,6 +10,8 @@ module CommandMapper
|
|
10
10
|
# The optional range of acceptable numbers.
|
11
11
|
#
|
12
12
|
# @return [Range, nil]
|
13
|
+
#
|
14
|
+
# @api semipublic
|
13
15
|
attr_reader :range
|
14
16
|
|
15
17
|
#
|
@@ -32,6 +34,8 @@ module CommandMapper
|
|
32
34
|
# Returns true if the value is valid, or `false` and a validation error
|
33
35
|
# message if the value is not compatible.
|
34
36
|
#
|
37
|
+
# @api semipublic
|
38
|
+
#
|
35
39
|
def validate(value)
|
36
40
|
case value
|
37
41
|
when Integer
|
@@ -48,7 +52,7 @@ module CommandMapper
|
|
48
52
|
|
49
53
|
if @range
|
50
54
|
unless @range.include?(value.to_i)
|
51
|
-
return [false, "
|
55
|
+
return [false, "(#{value.inspect}) not within the range of acceptable values (#{range.inspect})"]
|
52
56
|
end
|
53
57
|
end
|
54
58
|
|
@@ -64,6 +68,8 @@ module CommandMapper
|
|
64
68
|
# @return [String]
|
65
69
|
# The formatted numeric value.
|
66
70
|
#
|
71
|
+
# @api semipublic
|
72
|
+
#
|
67
73
|
def format(value)
|
68
74
|
case value
|
69
75
|
when Integer, String then value.to_s
|
@@ -2,6 +2,9 @@ require 'command_mapper/types/type'
|
|
2
2
|
|
3
3
|
module CommandMapper
|
4
4
|
module Types
|
5
|
+
#
|
6
|
+
# Represents an arbitrary string value.
|
7
|
+
#
|
5
8
|
class Str < Type
|
6
9
|
#
|
7
10
|
# Initializes the value.
|
@@ -22,6 +25,8 @@ module CommandMapper
|
|
22
25
|
#
|
23
26
|
# @return [Boolean]
|
24
27
|
#
|
28
|
+
# @api semipublic
|
29
|
+
#
|
25
30
|
def allow_empty?
|
26
31
|
@allow_empty
|
27
32
|
end
|
@@ -31,6 +36,8 @@ module CommandMapper
|
|
31
36
|
#
|
32
37
|
# @return [Boolean]
|
33
38
|
#
|
39
|
+
# @api semipublic
|
40
|
+
#
|
34
41
|
def allow_blank?
|
35
42
|
@allow_blank
|
36
43
|
end
|
@@ -42,7 +49,7 @@ module CommandMapper
|
|
42
49
|
# The given value to validate.
|
43
50
|
#
|
44
51
|
# @return [true, (false, String)]
|
45
|
-
# Returns true if the
|
52
|
+
# Returns true if the value is considered valid, or false and a
|
46
53
|
# validation message if the value is not valid.
|
47
54
|
# * If `nil` is given and a value is required, then `false` will be
|
48
55
|
# returned.
|
@@ -51,6 +58,8 @@ module CommandMapper
|
|
51
58
|
# * If an empty value is given and blank values are not allowed, then
|
52
59
|
# `false` will be returned.
|
53
60
|
#
|
61
|
+
# @api semipublic
|
62
|
+
#
|
54
63
|
def validate(value)
|
55
64
|
case value
|
56
65
|
when nil
|
@@ -50,6 +50,8 @@ module CommandMapper
|
|
50
50
|
#
|
51
51
|
# argument :ports, required: true, type: PortRange.new
|
52
52
|
#
|
53
|
+
# @api semipublic
|
54
|
+
#
|
53
55
|
class Type
|
54
56
|
|
55
57
|
#
|
@@ -96,6 +98,8 @@ module CommandMapper
|
|
96
98
|
# @raise [ArgumentError]
|
97
99
|
# The given type value was not a {Type}, `Hash`, or `nil`,
|
98
100
|
#
|
101
|
+
# @api semipublic
|
102
|
+
#
|
99
103
|
def self.Type(value)
|
100
104
|
case value
|
101
105
|
when Type then value
|
data/spec/commnad_spec.rb
CHANGED
@@ -1163,6 +1163,26 @@ describe CommandMapper::Command do
|
|
1163
1163
|
}.to raise_error(ArgumentRequired,"argument arg2 is required")
|
1164
1164
|
end
|
1165
1165
|
end
|
1166
|
+
|
1167
|
+
context "but the command has un-required arguments that repeat" do
|
1168
|
+
module TestCommand
|
1169
|
+
class CommandWithUnRequiredRepeatingArguments < CommandMapper::Command
|
1170
|
+
command "test" do
|
1171
|
+
argument :arg1, required: false
|
1172
|
+
argument :arg2, required: false, repeats: true
|
1173
|
+
argument :arg3, required: false
|
1174
|
+
end
|
1175
|
+
end
|
1176
|
+
end
|
1177
|
+
|
1178
|
+
let(:command_class) { TestCommand::CommandWithUnRequiredRepeatingArguments }
|
1179
|
+
|
1180
|
+
subject { command_class.new(arg1: nil, arg2: nil, arg3: nil) }
|
1181
|
+
|
1182
|
+
it "must omit the un-required repeating arguments that are not set" do
|
1183
|
+
expect(subject.command_argv).to eq([subject.class.command_name])
|
1184
|
+
end
|
1185
|
+
end
|
1166
1186
|
end
|
1167
1187
|
|
1168
1188
|
context "when the command is initialized with the command_path: keyword" do
|
data/spec/option_value_spec.rb
CHANGED
@@ -1,8 +1,36 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'command_mapper/option_value'
|
3
|
+
require 'command_mapper/types/num'
|
3
4
|
require 'command_mapper/types/list'
|
4
5
|
|
5
6
|
describe CommandMapper::OptionValue do
|
7
|
+
describe "#validate" do
|
8
|
+
let(:type) { Types::Num.new }
|
9
|
+
|
10
|
+
subject { described_class.new(type: type) }
|
11
|
+
|
12
|
+
context "when the option value is not required" do
|
13
|
+
subject do
|
14
|
+
described_class.new(type: type, required: false)
|
15
|
+
end
|
16
|
+
|
17
|
+
context "and given a value of true" do
|
18
|
+
it "must return true" do
|
19
|
+
expect(subject.validate(true)).to be(true)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "otherwise" do
|
25
|
+
it "must validate the value using #type.validate" do
|
26
|
+
expect(subject.validate('1234')).to be(true)
|
27
|
+
expect(subject.validate('foo')).to eq(
|
28
|
+
[false, "contains non-numeric characters (\"foo\")"]
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
6
34
|
describe "#format" do
|
7
35
|
let(:type) { Types::List.new }
|
8
36
|
|
data/spec/types/map_spec.rb
CHANGED
@@ -41,9 +41,9 @@ describe CommandMapper::Types::Map do
|
|
41
41
|
context "when given a value that is not in the map" do
|
42
42
|
let(:value) { 42 }
|
43
43
|
|
44
|
-
it "must return [false, \"unknown value (...)
|
44
|
+
it "must return [false, \"unknown value (...) must be ..., or ...\"]" do
|
45
45
|
expect(subject.validate(value)).to eq(
|
46
|
-
[false, "unknown value (#{value.inspect})"]
|
46
|
+
[false, "unknown value (#{value.inspect}) must be #{subject.map.keys.map(&:inspect).join(', ')}, or #{subject.map.values.map(&:inspect).join(', ')}"]
|
47
47
|
)
|
48
48
|
end
|
49
49
|
end
|
data/spec/types/num_spec.rb
CHANGED
@@ -44,9 +44,9 @@ describe CommandMapper::Types::Num do
|
|
44
44
|
context "but the value is not within the range of values" do
|
45
45
|
let(:value) { 0 }
|
46
46
|
|
47
|
-
it "must return [false, \"
|
47
|
+
it "must return [false, \"(...) not within the range of acceptable values (...)\"]" do
|
48
48
|
expect(subject.validate(value)).to eq(
|
49
|
-
[false, "
|
49
|
+
[false, "(#{value.inspect}) not within the range of acceptable values (#{range.inspect})"]
|
50
50
|
)
|
51
51
|
end
|
52
52
|
end
|
@@ -77,9 +77,9 @@ describe CommandMapper::Types::Num do
|
|
77
77
|
context "but the value is not within the range of values" do
|
78
78
|
let(:value) { '0' }
|
79
79
|
|
80
|
-
it "must return [false, \"
|
80
|
+
it "must return [false, \"(...) not within the range of acceptable values (...)\"]" do
|
81
81
|
expect(subject.validate(value)).to eq(
|
82
|
-
[false, "
|
82
|
+
[false, "(#{value.inspect}) not within the range of acceptable values (#{range.inspect})"]
|
83
83
|
)
|
84
84
|
end
|
85
85
|
end
|
@@ -132,9 +132,9 @@ describe CommandMapper::Types::Num do
|
|
132
132
|
context "but the value is not within the range of values" do
|
133
133
|
let(:value) { 0.0 }
|
134
134
|
|
135
|
-
it "must return [false, \"
|
135
|
+
it "must return [false, \"(...) not within the range of acceptable values (...)\"]" do
|
136
136
|
expect(subject.validate(value)).to eq(
|
137
|
-
[false, "
|
137
|
+
[false, "(#{value.inspect}) not within the range of acceptable values (#{range.inspect})"]
|
138
138
|
)
|
139
139
|
end
|
140
140
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: command_mapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Postmodern
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-04-
|
11
|
+
date: 2022-04-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -45,6 +45,7 @@ files:
|
|
45
45
|
- README.md
|
46
46
|
- Rakefile
|
47
47
|
- commnad_mapper.gemspec
|
48
|
+
- examples/grep.rb
|
48
49
|
- gemspec.yml
|
49
50
|
- lib/command_mapper.rb
|
50
51
|
- lib/command_mapper/arg.rb
|