command_mapper 0.1.0 → 0.1.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 +9 -0
- data/README.md +31 -14
- data/lib/command_mapper/arg.rb +2 -0
- data/lib/command_mapper/argument.rb +1 -0
- data/lib/command_mapper/option.rb +3 -0
- data/lib/command_mapper/option_value.rb +2 -0
- data/lib/command_mapper/types/enum.rb +2 -0
- data/lib/command_mapper/types/hex.rb +5 -0
- data/lib/command_mapper/types/input_dir.rb +3 -0
- data/lib/command_mapper/types/input_file.rb +3 -0
- data/lib/command_mapper/types/input_path.rb +3 -0
- data/lib/command_mapper/types/key_value.rb +4 -1
- data/lib/command_mapper/types/key_value_list.rb +1 -1
- data/lib/command_mapper/types/list.rb +5 -0
- data/lib/command_mapper/types/map.rb +18 -2
- data/lib/command_mapper/types/num.rb +5 -0
- data/lib/command_mapper/types/type.rb +9 -1
- data/lib/command_mapper/types.rb +6 -0
- data/lib/command_mapper/version.rb +1 -1
- data/spec/commnad_spec.rb +4 -0
- data/spec/types/map_spec.rb +20 -3
- data/spec/types_spec.rb +48 -0
- 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: 4db5d03aecac93251d259d3b776a33706bc328208a9fb58c4a96966d87128ed8
|
4
|
+
data.tar.gz: bc67f06449dc8b0b7c5061c55a315112dcf3fab2bf548314e4f20a6b2dbdd67f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e99f9216620e3847fc8e250d0c05d549f547396eef01a519d332cd3927cd86c71ed26e862fda84f26f28570e180f76eb1fb9117729a737bcf718de33f2d0886
|
7
|
+
data.tar.gz: a3766529ada1866b7736e905d3ba65511eea1b2e9679b9edad99e57089285159a307beb726ee7b1f2f2c02e6eb6d34d569d86babb3f79dc3be54527e834fbacd
|
data/ChangeLog.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
### 0.1.1 / 2021-11-29
|
2
|
+
|
3
|
+
* Fixed a bug where {CommandMapper::Types::Num}, {CommandMapper::Types::Hex},
|
4
|
+
{CommandMapper::Types::Enum}, {CommandMapper::Types::InputPath},
|
5
|
+
{CommandMapper::Types::InputFile}, and {CommandMapper::Types::InputDir} were
|
6
|
+
not being required by default.
|
7
|
+
* Allow {CommandMapper::Types::Map} to accept values that have already been
|
8
|
+
mapped to a String.
|
9
|
+
|
1
10
|
### 0.1.0 / 2021-11-25
|
2
11
|
|
3
12
|
* Initial release:
|
data/README.md
CHANGED
@@ -18,21 +18,26 @@ allow safely and securely executing commands.
|
|
18
18
|
* Supports defining commands as Ruby classes.
|
19
19
|
* Supports mapping in options and additional arguments.
|
20
20
|
* Supports common option types:
|
21
|
-
*
|
22
|
-
*
|
23
|
-
*
|
24
|
-
*
|
25
|
-
(aka `--opt=yes|no` or
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
*
|
30
|
-
(aka `--opt
|
31
|
-
*
|
21
|
+
* [Str][CommandMapper::Types::Str]: string values
|
22
|
+
* [Num][CommandMapper::Types::Num]: numeric values
|
23
|
+
* [Hex][CommandMapper::Types::Hex]: hexadecimal values
|
24
|
+
* [Map][CommandMapper::Types::Map]: maps `true`/`false` to `yes`/`no`, or
|
25
|
+
`enabled`/`disabled` (aka `--opt=yes|no` or
|
26
|
+
`--opt=enabled|disabled` values).
|
27
|
+
* [Enum][CommandMapper::Types::Enum]: maps a finite set of Symbols to a
|
28
|
+
finite set of Strings (aka `--opt={foo|bar|baz}` values).
|
29
|
+
* [List][CommandMapper::Types::List]: comma-separated list
|
30
|
+
(aka `--opt VALUE,...`).
|
31
|
+
* [KeyValue][CommandMapper::Types::KeyValue]: maps a Hash or Array to
|
32
|
+
key:value Strings (aka `--opt KEY:VALUE` or `--opt KEY=VALUE` values).
|
33
|
+
* [KeyValueList][CommandMapper::Types::KeyValueList]: a key-value list
|
32
34
|
(aka `--opt KEY:VALUE,...` or `--opt KEY=VALUE;...` values).
|
33
|
-
*
|
34
|
-
|
35
|
-
*
|
35
|
+
* [InputPath][CommandMapper::Types::InputPath]: a path to a pre-existing
|
36
|
+
file or directory
|
37
|
+
* [InputFile][CommandMapper::Types::InputFile]: a path to a pre-existing
|
38
|
+
file
|
39
|
+
* [InputDir][CommandMapper::Types::InputDir]: a path to a pre-existing
|
40
|
+
directory
|
36
41
|
* Supports mapping in sub-commands.
|
37
42
|
* Allows running the command via `IO.popen` to read the command's output.
|
38
43
|
* Allows running commands with additional environment variables.
|
@@ -40,6 +45,18 @@ allow safely and securely executing commands.
|
|
40
45
|
* Allows running commands via `sudo`.
|
41
46
|
* Prevents command injection and option injection.
|
42
47
|
|
48
|
+
[CommandMapper::Types::Str]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/Str
|
49
|
+
[CommandMapper::Types::Num]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/Num
|
50
|
+
[CommandMapper::Types::Hex]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/Hex
|
51
|
+
[CommandMapper::Types::Map]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/Map
|
52
|
+
[CommandMapper::Types::Enum]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/Enum
|
53
|
+
[CommandMapper::Types::List]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/List
|
54
|
+
[CommandMapper::Types::KeyValue]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/KeyValue
|
55
|
+
[CommandMapper::Types::KeyValueList]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/KeyValueList
|
56
|
+
[CommandMapper::Types::InputPath]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/InputPath
|
57
|
+
[CommandMapper::Types::InputFile]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/InputFile
|
58
|
+
[CommandMapper::Types::InputDir]: https://rubydoc.info/gems/command_mapper/CommandMapper/Types/InputDir
|
59
|
+
|
43
60
|
## Examples
|
44
61
|
|
45
62
|
```ruby
|
data/lib/command_mapper/arg.rb
CHANGED
@@ -18,6 +18,7 @@ module CommandMapper
|
|
18
18
|
# Specifies whether the argument is required or can be omitted.
|
19
19
|
#
|
20
20
|
# @param [Types::Type, Hash, nil] type
|
21
|
+
# The type of the arg's value.
|
21
22
|
#
|
22
23
|
# @raise [ArgumentError]
|
23
24
|
# The `type` keyword argument was given a `nil` value.
|
@@ -54,6 +55,7 @@ module CommandMapper
|
|
54
55
|
# Validates whether a given value is compatible with the arg.
|
55
56
|
#
|
56
57
|
# @param [Object] value
|
58
|
+
# The given value to validate.
|
57
59
|
#
|
58
60
|
# @return [true, (false, String)]
|
59
61
|
# Returns true if the value is valid, or `false` and a validation error
|
@@ -50,6 +50,7 @@ module CommandMapper
|
|
50
50
|
# Validates whether a given value is compatible with the arg.
|
51
51
|
#
|
52
52
|
# @param [Array<Object>, Object] value
|
53
|
+
# The given value to validate.
|
53
54
|
#
|
54
55
|
# @return [true, (false, String)]
|
55
56
|
# Returns true if the value is valid, or `false` and a validation error
|
@@ -113,6 +113,7 @@ module CommandMapper
|
|
113
113
|
# Validates whether the given value is compatible with the option.
|
114
114
|
#
|
115
115
|
# @param [Array<Object>, Object] value
|
116
|
+
# The given value to validate.
|
116
117
|
#
|
117
118
|
# @return [true, (false, String)]
|
118
119
|
# Returns true if the value is valid, or `false` and a validation error
|
@@ -175,6 +176,7 @@ module CommandMapper
|
|
175
176
|
# Validates a value when the option can be repeated.
|
176
177
|
#
|
177
178
|
# @param [Array<Object>, Object] value
|
179
|
+
# The given value to validate.
|
178
180
|
#
|
179
181
|
# @return [true, (false, String)]
|
180
182
|
# Returns true if the value is valid, or `false` and a validation error
|
@@ -208,6 +210,7 @@ module CommandMapper
|
|
208
210
|
# Validates a value when the option does not accept a value.
|
209
211
|
#
|
210
212
|
# @param [Array<Object>, Object] value
|
213
|
+
# The given value to validate.
|
211
214
|
#
|
212
215
|
# @return [true, (false, String)]
|
213
216
|
# Returns true if the value is valid, or `false` and a validation error
|
@@ -33,8 +33,11 @@ module CommandMapper
|
|
33
33
|
# Validates a value.
|
34
34
|
#
|
35
35
|
# @param [String, Integer, Object] value
|
36
|
+
# The given value to validate.
|
36
37
|
#
|
37
38
|
# @return [true, (false, String)]
|
39
|
+
# Returns true if the value is valid, or `false` and a validation error
|
40
|
+
# message if the value is not compatible.
|
38
41
|
#
|
39
42
|
def validate(value)
|
40
43
|
case value
|
@@ -53,8 +56,10 @@ module CommandMapper
|
|
53
56
|
# Formats the value.
|
54
57
|
#
|
55
58
|
# @param [#to_i] value
|
59
|
+
# The given numeric value.
|
56
60
|
#
|
57
61
|
# @return [String]
|
62
|
+
# The formatted numeric value.
|
58
63
|
#
|
59
64
|
def format(value)
|
60
65
|
case value
|
@@ -11,8 +11,11 @@ module CommandMapper
|
|
11
11
|
# Validates whether the directory exists.
|
12
12
|
#
|
13
13
|
# @param [Object] value
|
14
|
+
# The given value to validate.
|
14
15
|
#
|
15
16
|
# @return [true, (false, String)]
|
17
|
+
# Returns true if the value is valid, or `false` and a validation error
|
18
|
+
# message if the value is not compatible.
|
16
19
|
#
|
17
20
|
def validate(value)
|
18
21
|
valid, message = super(value)
|
@@ -11,8 +11,11 @@ module CommandMapper
|
|
11
11
|
# Validates the file exists.
|
12
12
|
#
|
13
13
|
# @param [Object] value
|
14
|
+
# The given value to validate.
|
14
15
|
#
|
15
16
|
# @return [true, (false, String)]
|
17
|
+
# Returns true if the value is valid, or `false` and a validation error
|
18
|
+
# message if the value is not compatible.
|
16
19
|
#
|
17
20
|
def validate(value)
|
18
21
|
valid, message = super(value)
|
@@ -11,8 +11,11 @@ module CommandMapper
|
|
11
11
|
# Validates whether the path exists or not.
|
12
12
|
#
|
13
13
|
# @param [Object] value
|
14
|
+
# The given value to validate.
|
14
15
|
#
|
15
16
|
# @return [true, (false, String)]
|
17
|
+
# Returns true if the value is valid, or `false` and a validation error
|
18
|
+
# message if the value is not compatible.
|
16
19
|
#
|
17
20
|
def validate(value)
|
18
21
|
unless value.empty?
|
@@ -57,8 +57,11 @@ module CommandMapper
|
|
57
57
|
# Valides the given value.
|
58
58
|
#
|
59
59
|
# @param [Object] value
|
60
|
+
# The given value to validate.
|
60
61
|
#
|
61
62
|
# @return [true, (false, String)]
|
63
|
+
# Returns true if the value is valid, or `false` and a validation error
|
64
|
+
# message if the value is not compatible.
|
62
65
|
#
|
63
66
|
def validate(value)
|
64
67
|
case value
|
@@ -105,7 +108,7 @@ module CommandMapper
|
|
105
108
|
# Formats a value into a key-value pair.
|
106
109
|
#
|
107
110
|
# @param [Hash, Array, #to_s] value
|
108
|
-
# The given value.
|
111
|
+
# The given value to format.
|
109
112
|
#
|
110
113
|
# @return [String]
|
111
114
|
# The formatted key-value pair.
|
@@ -51,8 +51,11 @@ module CommandMapper
|
|
51
51
|
# Validates the value.
|
52
52
|
#
|
53
53
|
# @param [Object] value
|
54
|
+
# The given value to validate.
|
54
55
|
#
|
55
56
|
# @return [true, (false, String)]
|
57
|
+
# Returns true if the value is valid, or `false` and a validation error
|
58
|
+
# message if the value is not compatible.
|
56
59
|
#
|
57
60
|
def validate(value)
|
58
61
|
values = Array(value)
|
@@ -78,8 +81,10 @@ module CommandMapper
|
|
78
81
|
# Formats the value into a list.
|
79
82
|
#
|
80
83
|
# @param [Object] value
|
84
|
+
# The given value to format.
|
81
85
|
#
|
82
86
|
# @return [String]
|
87
|
+
# The formatted list.
|
83
88
|
#
|
84
89
|
def format(value)
|
85
90
|
Array(value).map(&@type.method(:format)).join(@separator)
|
@@ -39,24 +39,40 @@ module CommandMapper
|
|
39
39
|
# Validates a value.
|
40
40
|
#
|
41
41
|
# @param [Object] value
|
42
|
+
# The given value to validate.
|
42
43
|
#
|
43
44
|
# @return [true, (false, String)]
|
45
|
+
# Returns true if the value is valid, or `false` and a validation error
|
46
|
+
# message if the value is not compatible.
|
44
47
|
#
|
45
48
|
def validate(value)
|
46
|
-
unless @map.has_key?(value)
|
49
|
+
unless (@map.has_key?(value) || @map.has_value?(value))
|
47
50
|
return [false, "unknown value (#{value.inspect})"]
|
48
51
|
end
|
49
52
|
|
50
53
|
return true
|
51
54
|
end
|
52
55
|
|
56
|
+
#
|
57
|
+
# Maps a value.
|
53
58
|
#
|
54
59
|
# @param [Object] value
|
60
|
+
# The given value.
|
55
61
|
#
|
56
62
|
# @return [String]
|
63
|
+
# The mapped value.
|
64
|
+
#
|
65
|
+
# @raise [KeyError]
|
66
|
+
# The given value is not a key or value in the map.
|
57
67
|
#
|
58
68
|
def format(value)
|
59
|
-
|
69
|
+
if @map.has_key?(value)
|
70
|
+
super(@map[value])
|
71
|
+
elsif @map.has_value?(value)
|
72
|
+
super(value)
|
73
|
+
else
|
74
|
+
raise(KeyError,"value (#{value.inspect}) is not a key or value in the map: #{@map.inspect}")
|
75
|
+
end
|
60
76
|
end
|
61
77
|
|
62
78
|
end
|
@@ -11,8 +11,11 @@ module CommandMapper
|
|
11
11
|
# Validates a value.
|
12
12
|
#
|
13
13
|
# @param [String, Integer] value
|
14
|
+
# The given value to validate.
|
14
15
|
#
|
15
16
|
# @return [true, (false, String)]
|
17
|
+
# Returns true if the value is valid, or `false` and a validation error
|
18
|
+
# message if the value is not compatible.
|
16
19
|
#
|
17
20
|
def validate(value)
|
18
21
|
case value
|
@@ -35,8 +38,10 @@ module CommandMapper
|
|
35
38
|
# Formats a numeric value.
|
36
39
|
#
|
37
40
|
# @param [String, Integer, #to_i] value
|
41
|
+
# The given value to format.
|
38
42
|
#
|
39
43
|
# @return [String]
|
44
|
+
# The formatted numeric value.
|
40
45
|
#
|
41
46
|
def format(value)
|
42
47
|
case value
|
@@ -56,8 +56,11 @@ module CommandMapper
|
|
56
56
|
# The default `validate` method for all types.
|
57
57
|
#
|
58
58
|
# @param [Object]
|
59
|
+
# The given value to format.
|
59
60
|
#
|
60
61
|
# @return [true, (false, String)]
|
62
|
+
# Returns true if the value is valid, or `false` and a validation error
|
63
|
+
# message if the value is not compatible.
|
61
64
|
#
|
62
65
|
def validate(value)
|
63
66
|
true
|
@@ -67,6 +70,7 @@ module CommandMapper
|
|
67
70
|
# The default `format` method for all types.
|
68
71
|
#
|
69
72
|
# @param [#to_s] value
|
73
|
+
# The given value to format.
|
70
74
|
#
|
71
75
|
# @return [String]
|
72
76
|
# The String version of the value.
|
@@ -83,10 +87,14 @@ module CommandMapper
|
|
83
87
|
# Converts a value into a {Type} object.
|
84
88
|
#
|
85
89
|
# @param [Type, Hash, nil] value
|
90
|
+
# The type value or `Hash` of keyword arguments.
|
86
91
|
#
|
87
|
-
# @return [Type]
|
92
|
+
# @return [Type, Str]
|
93
|
+
# The type object or a new {Str} type object if a `Hash` of keyword
|
94
|
+
# arguments is given.
|
88
95
|
#
|
89
96
|
# @raise [ArgumentError]
|
97
|
+
# The given type value was not a {Type}, `Hash`, or `nil`,
|
90
98
|
#
|
91
99
|
def self.Type(value)
|
92
100
|
case value
|
data/lib/command_mapper/types.rb
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
require 'command_mapper/types/type'
|
2
2
|
require 'command_mapper/types/str'
|
3
|
+
require 'command_mapper/types/num'
|
4
|
+
require 'command_mapper/types/hex'
|
3
5
|
require 'command_mapper/types/map'
|
6
|
+
require 'command_mapper/types/enum'
|
4
7
|
require 'command_mapper/types/list'
|
5
8
|
require 'command_mapper/types/key_value'
|
6
9
|
require 'command_mapper/types/key_value_list'
|
10
|
+
require 'command_mapper/types/input_path'
|
11
|
+
require 'command_mapper/types/input_file'
|
12
|
+
require 'command_mapper/types/input_dir'
|
data/spec/commnad_spec.rb
CHANGED
data/spec/types/map_spec.rb
CHANGED
@@ -22,13 +22,22 @@ describe CommandMapper::Types::Map do
|
|
22
22
|
end
|
23
23
|
|
24
24
|
describe "#validate" do
|
25
|
-
context "when given a value that's in the map" do
|
25
|
+
context "when given a value that's a key in the map" do
|
26
26
|
let(:value) { 2 }
|
27
27
|
|
28
28
|
it "must return true" do
|
29
29
|
expect(subject.validate(value)).to be(true)
|
30
30
|
end
|
31
31
|
end
|
32
|
+
|
33
|
+
context "when given a value that's a value in the map" do
|
34
|
+
let(:value) { "two" }
|
35
|
+
|
36
|
+
it "must return true" do
|
37
|
+
expect(subject.validate(value)).to be(true)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
32
41
|
context "when given a value that is not in the map" do
|
33
42
|
let(:value) { 42 }
|
34
43
|
|
@@ -41,7 +50,7 @@ describe CommandMapper::Types::Map do
|
|
41
50
|
end
|
42
51
|
|
43
52
|
describe "#format" do
|
44
|
-
context "when given a value that's in the map" do
|
53
|
+
context "when given a value that's a key in the map" do
|
45
54
|
let(:value) { 2 }
|
46
55
|
|
47
56
|
it "must return the corresponding mapped value" do
|
@@ -49,13 +58,21 @@ describe CommandMapper::Types::Map do
|
|
49
58
|
end
|
50
59
|
end
|
51
60
|
|
61
|
+
context "when given a value that's a value in the map" do
|
62
|
+
let(:value) { "two" }
|
63
|
+
|
64
|
+
it "must return the value" do
|
65
|
+
expect(subject.format(value)).to eq(value)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
52
69
|
context "when given a value that is not in the map" do
|
53
70
|
let(:value) { 42 }
|
54
71
|
|
55
72
|
it "must return the String version of the value" do
|
56
73
|
expect {
|
57
74
|
subject.format(value)
|
58
|
-
}.to raise_error(KeyError)
|
75
|
+
}.to raise_error(KeyError,"value (#{value.inspect}) is not a key or value in the map: #{map.inspect}")
|
59
76
|
end
|
60
77
|
end
|
61
78
|
end
|
data/spec/types_spec.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'command_mapper/types'
|
3
|
+
|
4
|
+
describe CommandMapper::Types do
|
5
|
+
it "must define a Str type" do
|
6
|
+
expect(subject.const_defined?('Str')).to be(true)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "must define a Num type" do
|
10
|
+
expect(subject.const_defined?('Num')).to be(true)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "must define a Hex type" do
|
14
|
+
expect(subject.const_defined?('Hex')).to be(true)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "must define a Map type" do
|
18
|
+
expect(subject.const_defined?('Map')).to be(true)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "must define a Enum type" do
|
22
|
+
expect(subject.const_defined?('Enum')).to be(true)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "must define a List type" do
|
26
|
+
expect(subject.const_defined?('List')).to be(true)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "must define a KeyValue type" do
|
30
|
+
expect(subject.const_defined?('KeyValue')).to be(true)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "must define a KeyValueList type" do
|
34
|
+
expect(subject.const_defined?('KeyValueList')).to be(true)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "must define a InputPath type" do
|
38
|
+
expect(subject.const_defined?('InputPath')).to be(true)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "must define a InputFile type" do
|
42
|
+
expect(subject.const_defined?('InputFile')).to be(true)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "must define a InputDir type" do
|
46
|
+
expect(subject.const_defined?('InputDir')).to be(true)
|
47
|
+
end
|
48
|
+
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.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Postmodern
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-11-
|
11
|
+
date: 2021-11-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -87,6 +87,7 @@ files:
|
|
87
87
|
- spec/types/num_spec.rb
|
88
88
|
- spec/types/str_spec.rb
|
89
89
|
- spec/types/type_spec.rb
|
90
|
+
- spec/types_spec.rb
|
90
91
|
homepage: https://github.com/postmodern/command_mapper.rb#readme
|
91
92
|
licenses:
|
92
93
|
- MIT
|