command_mapper 0.2.0 → 0.3.0
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 +15 -0
- data/README.md +19 -5
- data/{commnad_mapper.gemspec → command_mapper.gemspec} +0 -0
- data/examples/grep.rb +62 -0
- data/gemspec.yml +2 -2
- 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/dec.rb +84 -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 +5 -1
- data/lib/command_mapper/types.rb +1 -0
- data/lib/command_mapper/version.rb +1 -1
- data/spec/commnad_spec.rb +25 -5
- data/spec/option_value_spec.rb +28 -0
- data/spec/types/dec_spec.rb +180 -0
- data/spec/types/input_dir_spec.rb +13 -9
- data/spec/types/map_spec.rb +2 -2
- data/spec/types/num_spec.rb +6 -6
- metadata +9 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 254468c58bbee95ac037609a4ddefc34c026240b4933a37038df1bade5b7487e
|
4
|
+
data.tar.gz: 1fe51a7d6ad09b0b51c753bee28632e70292bfa9e9938896e22183c0327f48ae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c1fc9b041fafa2d92300bcbf312e8b1d848450bd4691b6b0eea57fb401a8d20b8a73613328c69cc5d323e9b42313ecc2f3e66b8bcfff14454a8cdb5bd5db5467
|
7
|
+
data.tar.gz: 62fd74bd469bff9620c94a8c0710f6d309bb0611af7e58664fa7d04808ee40b14d3b076fb8143a6fdbd409a0fd35fb12682e535c30b41ed616200dc7be982bd2
|
data/ChangeLog.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
### 0.3.0 / 2022-11-11
|
2
|
+
|
3
|
+
* Added {CommandMapper::Types::Dec}.
|
4
|
+
|
5
|
+
### 0.2.1 / 2022-04-22
|
6
|
+
|
7
|
+
* Properly validate in {CommandMapper::OptionValue#validate} when an option,
|
8
|
+
who's value is not required, is given `true`.
|
9
|
+
* Omit `nil` arguments from {CommandMapper::Command#command_argv} if the
|
10
|
+
argument is not required.
|
11
|
+
* Improve validation error message for {CommandMapper::Types::Num} when
|
12
|
+
initialized with a `range:` value.
|
13
|
+
* Improve validation error message for {CommandMapper::Types::Map} and
|
14
|
+
{CommandMapper::Types::Enum}.
|
15
|
+
|
1
16
|
### 0.2.0 / 2022-04-18
|
2
17
|
|
3
18
|
* Added {CommandMapper::Command.spawn} and
|
data/README.md
CHANGED
@@ -10,8 +10,8 @@
|
|
10
10
|
|
11
11
|
## Description
|
12
12
|
|
13
|
-
Command Mapper maps
|
14
|
-
allow safely and securely executing commands.
|
13
|
+
Command Mapper maps an external command's options and arguments to Class
|
14
|
+
attributes to allow safely and securely executing commands.
|
15
15
|
|
16
16
|
## Features
|
17
17
|
|
@@ -20,10 +20,11 @@ allow safely and securely executing commands.
|
|
20
20
|
* Supports common option types:
|
21
21
|
* [Str][CommandMapper::Types::Str]: string values
|
22
22
|
* [Num][CommandMapper::Types::Num]: numeric values
|
23
|
+
* [Dec][CommandMapper::Types::Dec]: decimal values
|
23
24
|
* [Hex][CommandMapper::Types::Hex]: hexadecimal values
|
24
|
-
* [Map][CommandMapper::Types::Map]: maps
|
25
|
-
`
|
26
|
-
|
25
|
+
* [Map][CommandMapper::Types::Map]: maps Ruby values to other String values.
|
26
|
+
* `Map::YesNo`: maps `true`/`false` to `yes`/`no`.
|
27
|
+
* `Map::EnabledDisabled`: Maps `true`/`false` to `enabled`/`disabled`.
|
27
28
|
* [Enum][CommandMapper::Types::Enum]: maps a finite set of Symbols to a
|
28
29
|
finite set of Strings (aka `--opt={foo|bar|baz}` values).
|
29
30
|
* [List][CommandMapper::Types::List]: comma-separated list
|
@@ -50,6 +51,7 @@ allow safely and securely executing commands.
|
|
50
51
|
|
51
52
|
[CommandMapper::Types::Str]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/Str
|
52
53
|
[CommandMapper::Types::Num]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/Num
|
54
|
+
[CommandMapper::Types::Dec]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/Dec
|
53
55
|
[CommandMapper::Types::Hex]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/Hex
|
54
56
|
[CommandMapper::Types::Map]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/Map
|
55
57
|
[CommandMapper::Types::Enum]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/Enum
|
@@ -314,6 +316,18 @@ Grep.run do |grep|
|
|
314
316
|
end
|
315
317
|
```
|
316
318
|
|
319
|
+
Overriding the command name:
|
320
|
+
|
321
|
+
```ruby
|
322
|
+
Grep.run(..., command_name: 'grep2')
|
323
|
+
```
|
324
|
+
|
325
|
+
Specifying the direct path to the command:
|
326
|
+
|
327
|
+
```ruby
|
328
|
+
Grep.run(..., command_path: '/path/to/grep')
|
329
|
+
```
|
330
|
+
|
317
331
|
### Capturing output
|
318
332
|
|
319
333
|
```ruby
|
File without changes
|
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/gemspec.yml
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
name: command_mapper
|
2
2
|
summary: Safe and secure execution of commands.
|
3
3
|
description:
|
4
|
-
Command Mapper maps
|
5
|
-
and securely executing commands.
|
4
|
+
Command Mapper maps an external command's arguments to Class attributes to
|
5
|
+
allow safely and securely executing commands.
|
6
6
|
|
7
7
|
license: MIT
|
8
8
|
authors: Postmodern
|
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
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'command_mapper/types/type'
|
2
|
+
|
3
|
+
module CommandMapper
|
4
|
+
module Types
|
5
|
+
#
|
6
|
+
# Represents a decimal value (ex: `1.5`).
|
7
|
+
#
|
8
|
+
# @since 0.3.0
|
9
|
+
#
|
10
|
+
class Dec < Type
|
11
|
+
|
12
|
+
# The optional range of acceptable decimal numbers.
|
13
|
+
#
|
14
|
+
# @return [Range<Float,Float>, nil]
|
15
|
+
#
|
16
|
+
# @api semipublic
|
17
|
+
attr_reader :range
|
18
|
+
|
19
|
+
#
|
20
|
+
# Initializes the decimal type.
|
21
|
+
#
|
22
|
+
# @param [Range<Float,Float>] range
|
23
|
+
# Specifies the range of acceptable numbers.
|
24
|
+
#
|
25
|
+
def initialize(range: nil)
|
26
|
+
@range = range
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Validates a value.
|
31
|
+
#
|
32
|
+
# @param [String, Numeric] value
|
33
|
+
# The given value to validate.
|
34
|
+
#
|
35
|
+
# @return [true, (false, String)]
|
36
|
+
# Returns true if the value is valid, or `false` and a validation error
|
37
|
+
# message if the value is not compatible.
|
38
|
+
#
|
39
|
+
# @api semipublic
|
40
|
+
#
|
41
|
+
def validate(value)
|
42
|
+
case value
|
43
|
+
when Float
|
44
|
+
# no-op
|
45
|
+
when String
|
46
|
+
unless value =~ /\A\d+(?:\.\d+)?\z/
|
47
|
+
return [false, "contains non-decimal characters (#{value.inspect})"]
|
48
|
+
end
|
49
|
+
else
|
50
|
+
unless value.respond_to?(:to_f)
|
51
|
+
return [false, "cannot be converted into a Float (#{value.inspect})"]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
if @range
|
56
|
+
unless @range.include?(value.to_f)
|
57
|
+
return [false, "(#{value.inspect}) not within the range of acceptable values (#{range.inspect})"]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
return true
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Formats a decimal value.
|
66
|
+
#
|
67
|
+
# @param [String, Float, #to_f] value
|
68
|
+
# The given value to format.
|
69
|
+
#
|
70
|
+
# @return [String]
|
71
|
+
# The formatted decimal value.
|
72
|
+
#
|
73
|
+
# @api semipublic
|
74
|
+
#
|
75
|
+
def format(value)
|
76
|
+
case value
|
77
|
+
when Float, String then value.to_s
|
78
|
+
else value.to_f.to_s
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
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
|