command_mapper 0.1.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ruby.yml +27 -0
  3. data/.gitignore +10 -0
  4. data/.rspec +1 -0
  5. data/.yardopts +1 -0
  6. data/ChangeLog.md +25 -0
  7. data/Gemfile +15 -0
  8. data/LICENSE.txt +20 -0
  9. data/README.md +369 -0
  10. data/Rakefile +12 -0
  11. data/commnad_mapper.gemspec +61 -0
  12. data/gemspec.yml +23 -0
  13. data/lib/command_mapper/arg.rb +75 -0
  14. data/lib/command_mapper/argument.rb +142 -0
  15. data/lib/command_mapper/command.rb +606 -0
  16. data/lib/command_mapper/exceptions.rb +19 -0
  17. data/lib/command_mapper/option.rb +282 -0
  18. data/lib/command_mapper/option_value.rb +21 -0
  19. data/lib/command_mapper/sudo.rb +73 -0
  20. data/lib/command_mapper/types/enum.rb +35 -0
  21. data/lib/command_mapper/types/hex.rb +82 -0
  22. data/lib/command_mapper/types/input_dir.rb +35 -0
  23. data/lib/command_mapper/types/input_file.rb +35 -0
  24. data/lib/command_mapper/types/input_path.rb +29 -0
  25. data/lib/command_mapper/types/key_value.rb +131 -0
  26. data/lib/command_mapper/types/key_value_list.rb +45 -0
  27. data/lib/command_mapper/types/list.rb +90 -0
  28. data/lib/command_mapper/types/map.rb +64 -0
  29. data/lib/command_mapper/types/num.rb +50 -0
  30. data/lib/command_mapper/types/str.rb +85 -0
  31. data/lib/command_mapper/types/type.rb +102 -0
  32. data/lib/command_mapper/types.rb +6 -0
  33. data/lib/command_mapper/version.rb +4 -0
  34. data/lib/command_mapper.rb +2 -0
  35. data/spec/arg_spec.rb +137 -0
  36. data/spec/argument_spec.rb +513 -0
  37. data/spec/commnad_spec.rb +1175 -0
  38. data/spec/exceptions_spec.rb +14 -0
  39. data/spec/option_spec.rb +882 -0
  40. data/spec/option_value_spec.rb +17 -0
  41. data/spec/spec_helper.rb +6 -0
  42. data/spec/sudo_spec.rb +24 -0
  43. data/spec/types/enum_spec.rb +31 -0
  44. data/spec/types/hex_spec.rb +158 -0
  45. data/spec/types/input_dir_spec.rb +30 -0
  46. data/spec/types/input_file_spec.rb +34 -0
  47. data/spec/types/input_path_spec.rb +32 -0
  48. data/spec/types/key_value_list_spec.rb +100 -0
  49. data/spec/types/key_value_spec.rb +272 -0
  50. data/spec/types/list_spec.rb +143 -0
  51. data/spec/types/map_spec.rb +62 -0
  52. data/spec/types/num_spec.rb +90 -0
  53. data/spec/types/str_spec.rb +232 -0
  54. data/spec/types/type_spec.rb +59 -0
  55. metadata +118 -0
@@ -0,0 +1,272 @@
1
+ require 'spec_helper'
2
+ require 'command_mapper/types/key_value'
3
+ require 'command_mapper/types/num'
4
+ require 'command_mapper/types/list'
5
+
6
+ describe CommandMapper::Types::KeyValue do
7
+ describe "#initialize" do
8
+ it "must default #separator to '='" do
9
+ expect(subject.separator).to eq('=')
10
+ end
11
+
12
+ it "must initialize #key" do
13
+ expect(subject.key).to be_kind_of(CommandMapper::Types::Str)
14
+ end
15
+
16
+ it "must require a non-empty 'key' value by default" do
17
+ expect(subject.key.allow_empty?).to be(false)
18
+ end
19
+
20
+ it "must initialize #value" do
21
+ expect(subject.value).to be_kind_of(CommandMapper::Types::Str)
22
+ end
23
+
24
+ it "must require a non-empty 'value' value by default" do
25
+ expect(subject.value.allow_empty?).to be(false)
26
+ end
27
+
28
+ context "when given the separator: keyword" do
29
+ let(:separator) { ':' }
30
+
31
+ subject { described_class.new(separator: separator) }
32
+
33
+ it "must set #separator" do
34
+ expect(subject.separator).to eq(separator)
35
+ end
36
+ end
37
+
38
+ context "when given key: nil" do
39
+ it do
40
+ expect {
41
+ described_class.new(key: nil)
42
+ }.to raise_error(ArgumentError,"key: keyword cannot be nil")
43
+ end
44
+ end
45
+
46
+ context "when given value: nil" do
47
+ it do
48
+ expect {
49
+ described_class.new(value: nil)
50
+ }.to raise_error(ArgumentError,"value: keyword cannot be nil")
51
+ end
52
+ end
53
+ end
54
+
55
+ describe "#validate" do
56
+ context "when given a Hash" do
57
+ context "but it's empty" do
58
+ let(:hash) { {} }
59
+
60
+ it "must return [false, \"cannot be empty\"]" do
61
+ expect(subject.validate(hash)).to eq(
62
+ [false, "cannot be empty"]
63
+ )
64
+ end
65
+ end
66
+
67
+ context "and the Hash contains only one key:value pair" do
68
+ let(:key) { "foo" }
69
+ let(:value) { "bar" }
70
+ let(:hash) { {key => value} }
71
+
72
+ it "must return true" do
73
+ expect(subject.validate(hash)).to be(true)
74
+ end
75
+
76
+ context "when #key is a custom Types::Type object" do
77
+ let(:key_type) { Types::Num.new }
78
+ let(:key) { "foo" }
79
+
80
+ subject { described_class.new(key: key_type) }
81
+
82
+ it "must validate the key value using #key.validate" do
83
+ expect(subject.validate(hash)).to eq(
84
+ [false, "key contains non-numeric characters (#{key.inspect})"]
85
+ )
86
+ end
87
+ end
88
+
89
+ context "when #value is a custom Types::Type object" do
90
+ let(:value_type) { Types::Num.new }
91
+ let(:value) { "foo" }
92
+
93
+ subject { described_class.new(value: value_type) }
94
+
95
+ it "must validate the key value using #key.validate" do
96
+ expect(subject.validate(hash)).to eq(
97
+ [false, "value contains non-numeric characters (#{value.inspect})"]
98
+ )
99
+ end
100
+ end
101
+ end
102
+
103
+ context "but the Hash contains more than one pair" do
104
+ let(:hash) { {"foo" => "bar", "baz" => "qux"} }
105
+
106
+ it "must return [false, \"cannot contain multiple key:value pairs (...)\"]" do
107
+ expect(subject.validate(hash)).to eq(
108
+ [false, "cannot contain multiple key:value pairs (#{hash.inspect})"]
109
+ )
110
+ end
111
+ end
112
+ end
113
+
114
+ context "when given an Array" do
115
+ context "but the Array is empty" do
116
+ let(:array) { [] }
117
+
118
+ it "must return [false, \"must contain two elements (...)\"]" do
119
+ expect(subject.validate(array)).to eq(
120
+ [false, "must contain two elements (#{array.inspect})"]
121
+ )
122
+ end
123
+ end
124
+
125
+ context "and the Array contains only one elemnet" do
126
+ let(:array) { ["foo"] }
127
+
128
+ it "must return true" do
129
+ expect(subject.validate(array)).to eq(
130
+ [false, "must contain two elements (#{array.inspect})"]
131
+ )
132
+ end
133
+ end
134
+
135
+ context "and the Array contains only two elements" do
136
+ let(:key) { "foo" }
137
+ let(:value) { "bar" }
138
+ let(:array) { [key, value] }
139
+
140
+ it "must return true" do
141
+ expect(subject.validate(array)).to be(true)
142
+ end
143
+
144
+ context "when #key is a custom Types::Type object" do
145
+ let(:key_type) { Types::Num.new }
146
+ let(:key) { "foo" }
147
+
148
+ subject { described_class.new(key: key_type) }
149
+
150
+ it "must validate the key value using #key.validate" do
151
+ expect(subject.validate(array)).to eq(
152
+ [false, "key contains non-numeric characters (#{key.inspect})"]
153
+ )
154
+ end
155
+ end
156
+
157
+ context "when #value is a custom Types::Type object" do
158
+ let(:value_type) { Types::Num.new }
159
+ let(:value) { "foo" }
160
+
161
+ subject { described_class.new(value: value_type) }
162
+
163
+ it "must validate the key value using #key.validate" do
164
+ expect(subject.validate(array)).to eq(
165
+ [false, "value contains non-numeric characters (#{value.inspect})"]
166
+ )
167
+ end
168
+ end
169
+ end
170
+
171
+ context "but the Array contains more than two elements" do
172
+ let(:array) { ["foo", "bar", "baz"] }
173
+
174
+ it "must return [false, \"cannot contain more than two elements (...)\"]" do
175
+ expect(subject.validate(array)).to eq(
176
+ [false, "cannot contain more than two elements (#{array.inspect})"]
177
+ )
178
+ end
179
+ end
180
+ end
181
+ end
182
+
183
+ describe "#format" do
184
+ context "when given a Hash" do
185
+ let(:key) { "foo" }
186
+ let(:value) { "bar" }
187
+ let(:hash) { {key => value} }
188
+
189
+ it "must format the hash'es key and value into a key=value pair" do
190
+ expect(subject.format(hash)).to eq("#{key}=#{value}")
191
+ end
192
+
193
+ context "when initialized with a custom key: keyword argument" do
194
+ subject { described_class.new(key: Types::Num.new) }
195
+
196
+ let(:key) { 42 }
197
+
198
+ it "must format the key using #key.format" do
199
+ expect(subject.format(hash)).to eq("#{key}=#{value}")
200
+ end
201
+ end
202
+
203
+ context "when initialized with a custom key: keyword argument" do
204
+ subject { described_class.new(value: Types::List.new) }
205
+
206
+ let(:value) { %w[bar baz] }
207
+
208
+ it "must format the value using #value.format" do
209
+ expect(subject.format(hash)).to eq("#{key}=#{value.join(',')}")
210
+ end
211
+ end
212
+
213
+ context "when initialized with a custom separator" do
214
+ let(:separator) { ':' }
215
+
216
+ subject { described_class.new(separator: separator) }
217
+
218
+ it "must use the custom separator" do
219
+ expect(subject.format(hash)).to eq("#{key}#{separator}#{value}")
220
+ end
221
+ end
222
+ end
223
+
224
+ context "when given an Array" do
225
+ let(:key) { "foo" }
226
+ let(:value) { "bar" }
227
+ let(:array) { [key, value] }
228
+
229
+ it "must format the array's first and second elements into a key=value pair" do
230
+ expect(subject.format(array)).to eq("#{key}=#{value}")
231
+ end
232
+
233
+ context "when initialized with a custom key: keyword argument" do
234
+ subject { described_class.new(key: Types::Num.new) }
235
+
236
+ let(:key) { 42 }
237
+
238
+ it "must format the key using #key.format" do
239
+ expect(subject.format(array)).to eq("#{key}=#{value}")
240
+ end
241
+ end
242
+
243
+ context "when initialized with a custom key: keyword argument" do
244
+ subject { described_class.new(value: Types::List.new) }
245
+
246
+ let(:value) { %w[bar baz] }
247
+
248
+ it "must format the value using #value.format" do
249
+ expect(subject.format(array)).to eq("#{key}=#{value.join(',')}")
250
+ end
251
+ end
252
+
253
+ context "when initialized with a custom separator" do
254
+ let(:separator) { ':' }
255
+
256
+ subject { described_class.new(separator: separator) }
257
+
258
+ it "must use the custom separator" do
259
+ expect(subject.format(array)).to eq("#{key}#{separator}#{value}")
260
+ end
261
+ end
262
+ end
263
+
264
+ context "when another kind of Object is given" do
265
+ let(:value) { 42 }
266
+
267
+ it "must return the String version of that object" do
268
+ expect(subject.format(value)).to eq(value.to_s)
269
+ end
270
+ end
271
+ end
272
+ end
@@ -0,0 +1,143 @@
1
+ require 'spec_helper'
2
+ require 'command_mapper/types/list'
3
+ require 'command_mapper/types/num'
4
+
5
+ describe CommandMapper::Types::List do
6
+ describe "#initialize" do
7
+ it "must default #separator to ','" do
8
+ expect(subject.separator).to eq(',')
9
+ end
10
+
11
+ context "when given the separator: keyword" do
12
+ let(:separator) { ':' }
13
+
14
+ subject { described_class.new(separator: separator) }
15
+
16
+ it "must set #separator" do
17
+ expect(subject.separator).to eq(separator)
18
+ end
19
+ end
20
+
21
+ context "when given type: keyword argument" do
22
+ context "and it's a Types::Type object" do
23
+ let(:type) { Types::Num.new }
24
+
25
+ subject { described_class.new(type: type) }
26
+
27
+ it "must set a custom #type" do
28
+ expect(subject.type).to eq(type)
29
+ end
30
+ end
31
+
32
+ context "but it's nil" do
33
+ it do
34
+ expect {
35
+ described_class.new(type: nil)
36
+ }.to raise_error(ArgumentError,"type: keyword cannot be nil")
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ describe "#validate" do
43
+ context "when given a single value" do
44
+ let(:value) { "foo" }
45
+
46
+ it "must return true" do
47
+ expect(subject.validate(value)).to be(true)
48
+ end
49
+
50
+ context "but the value is nil" do
51
+ let(:value) { nil }
52
+
53
+ it "must return [false, \"cannot be empty\"]" do
54
+ expect(subject.validate(value)).to eq(
55
+ [false, "cannot be empty"]
56
+ )
57
+ end
58
+
59
+ context "when #allow_empty? is true" do
60
+ subject { described_class.new(allow_empty: true) }
61
+
62
+ it "must return true" do
63
+ expect(subject.validate(value)).to be(true)
64
+ end
65
+ end
66
+ end
67
+
68
+ context "and the value is invalid" do
69
+ let(:value) { "" }
70
+
71
+ it "must return the validation error from #type.validate" do
72
+ expect(subject.validate(value)).to eq(
73
+ [false, "element does not allow an empty value"]
74
+ )
75
+ end
76
+ end
77
+ end
78
+
79
+ context "when given multiple values" do
80
+ let(:values) { %w[foo bar baz] }
81
+
82
+ it "must return true" do
83
+ expect(subject.validate(values)).to be(true)
84
+ end
85
+
86
+ context "but the value is []" do
87
+ let(:value) { [] }
88
+
89
+ it "must return [false, \"cannot be empty\"]" do
90
+ expect(subject.validate(value)).to eq(
91
+ [false, "cannot be empty"]
92
+ )
93
+ end
94
+
95
+ context "when #allow_empty? is true" do
96
+ subject { described_class.new(allow_empty: true) }
97
+
98
+ it "must return true" do
99
+ expect(subject.validate(value)).to be(true)
100
+ end
101
+ end
102
+ end
103
+
104
+ context "but one of the values is invalid" do
105
+ let(:values) { ["foo", nil, "bar"] }
106
+
107
+ it "must return the validation error from #type.validate" do
108
+ expect(subject.validate(values)).to eq(
109
+ [false, "element cannot be nil"]
110
+ )
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ describe "#format" do
117
+ context "when given a single value" do
118
+ let(:value) { "foo" }
119
+
120
+ it "must return the String version of that value" do
121
+ expect(subject.format(value)).to eq(value.to_s)
122
+ end
123
+ end
124
+
125
+ context "when given multiple values" do
126
+ let(:values) { %w[foo bar baz] }
127
+
128
+ it "must join the values with ','" do
129
+ expect(subject.format(values)).to eq(values.join(','))
130
+ end
131
+
132
+ context "when initialized with a custom separator" do
133
+ let(:separator) { ':' }
134
+
135
+ subject { described_class.new(separator: separator) }
136
+
137
+ it "must join the values with #separator" do
138
+ expect(subject.format(values)).to eq(values.join(subject.separator))
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+ require 'command_mapper/types/map'
3
+
4
+ describe CommandMapper::Types::Map do
5
+ let(:map) { {1 => 'one', 2 => 'two'} }
6
+
7
+ subject { described_class.new(map) }
8
+
9
+ describe "#initialize" do
10
+ it "must initialize #map" do
11
+ expect(subject.map).to eq(map)
12
+ end
13
+ end
14
+
15
+ describe ".[]" do
16
+ subject { described_class[map] }
17
+
18
+ it "must create a new Map with the given values" do
19
+ expect(subject).to be_kind_of(described_class)
20
+ expect(subject.map).to eq(map)
21
+ end
22
+ end
23
+
24
+ describe "#validate" do
25
+ context "when given a value that's in the map" do
26
+ let(:value) { 2 }
27
+
28
+ it "must return true" do
29
+ expect(subject.validate(value)).to be(true)
30
+ end
31
+ end
32
+ context "when given a value that is not in the map" do
33
+ let(:value) { 42 }
34
+
35
+ it "must return [false, \"unknown value (...)\"]" do
36
+ expect(subject.validate(value)).to eq(
37
+ [false, "unknown value (#{value.inspect})"]
38
+ )
39
+ end
40
+ end
41
+ end
42
+
43
+ describe "#format" do
44
+ context "when given a value that's in the map" do
45
+ let(:value) { 2 }
46
+
47
+ it "must return the corresponding mapped value" do
48
+ expect(subject.format(value)).to eq(map[value])
49
+ end
50
+ end
51
+
52
+ context "when given a value that is not in the map" do
53
+ let(:value) { 42 }
54
+
55
+ it "must return the String version of the value" do
56
+ expect {
57
+ subject.format(value)
58
+ }.to raise_error(KeyError)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,90 @@
1
+ require 'spec_helper'
2
+ require 'command_mapper/types/num'
3
+
4
+ describe CommandMapper::Types::Num do
5
+ describe "#validate" do
6
+ context "when given an Integer" do
7
+ let(:value) { 1 }
8
+
9
+ it "must return true" do
10
+ expect(subject.validate(value)).to be(true)
11
+ end
12
+ end
13
+
14
+ context "when given a String" do
15
+ context "and it contains only digits" do
16
+ let(:value) { "0123456789" }
17
+
18
+ it "must return true" do
19
+ expect(subject.validate(value)).to be(true)
20
+ end
21
+
22
+ context "and the String contains a newline" do
23
+ let(:value) { "01234\n56789" }
24
+
25
+ it "must return [false, \"contains non-numeric characters (...)\"]" do
26
+ expect(subject.validate(value)).to eq(
27
+ [false, "contains non-numeric characters (#{value.inspect})"]
28
+ )
29
+ end
30
+ end
31
+ end
32
+
33
+ context "and it contains non-digits" do
34
+ let(:value) { "12abc34" }
35
+
36
+ it "must return [false, \"contains non-numeric characters (...)\"]" do
37
+ expect(subject.validate(value)).to eq(
38
+ [false, "contains non-numeric characters (#{value.inspect})"]
39
+ )
40
+ end
41
+ end
42
+ end
43
+
44
+ context "when given another type of Object" do
45
+ context "but it defines a #to_i method" do
46
+ let(:value) { 1.0 }
47
+
48
+ it "must return true" do
49
+ expect(subject.validate(value)).to be(true)
50
+ end
51
+ end
52
+
53
+ context "but it does not define a #to_i method" do
54
+ let(:value) { Object.new }
55
+
56
+ it "must return [false, \"value cannot be converted into an Integer\"]" do
57
+ expect(subject.validate(value)).to eq(
58
+ [false, "cannot be converted into an Integer (#{value.inspect})"]
59
+ )
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ describe "#format" do
66
+ context "when given a String" do
67
+ let(:value) { "1234567890" }
68
+
69
+ it "must return the same String" do
70
+ expect(subject.format(value)).to eq(value)
71
+ end
72
+ end
73
+
74
+ context "when given an Intger" do
75
+ let(:value) { 1234567890 }
76
+
77
+ it "must convert the Integer into a String" do
78
+ expect(subject.format(value)).to eq(value.to_s)
79
+ end
80
+ end
81
+
82
+ context "when given another type of Object" do
83
+ let(:value) { 1.0 }
84
+
85
+ it "must call #to_i then #to_s" do
86
+ expect(subject.format(value)).to eq(value.to_i.to_s)
87
+ end
88
+ end
89
+ end
90
+ end