command_mapper 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|