simple_scripting 0.11.1 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd6f01ad9ea507d97ac4024fa8e78feb1093e67f75b16d4ac5c5db79354caf18
4
- data.tar.gz: a0a1ad4b67822086544890b54590af03a2877a7210f3198109d605a6fa772d57
3
+ metadata.gz: 0a31e06185c711924565be44455735e02e55b31a98fc6782a101214cf9d37266
4
+ data.tar.gz: 2fa2139a689a85e1703604a3da2be186ac8596b9b17c0bc2af4c8c8244c8ad4d
5
5
  SHA512:
6
- metadata.gz: 2ee276b4af46f3746523f9ed11d7b11b4097f65c7139709506363708f1e6303ec1ead4d48c182f480918597272f2c1af92af6620920dad296967540c5b14105c
7
- data.tar.gz: 9059bae5453cc7e64eeea88c8279167020bd7cae0c1b67337c4bf83acb055a0ab04b75c746e7c0ea6d2a9184a8b1df5af0754dcfff55a8ad8e9e2b2409c8fe59
6
+ metadata.gz: bbf4a7477108d85b62922592eedbc550f0896ca75265385c219c052636d0c45628cd93ca59603649f9ee9227cf00fdf2526732918efb0ab7d55fe62d4b158196
7
+ data.tar.gz: b754caa9b812a0d7a5882d5bc2c67b0e72a276da9385a2be70d423838f00da711a182fb1f9b67c4072176c73a9d4020acb3b2070fba54f83615edd830cc5aa5c
@@ -7,9 +7,19 @@ module SimpleScripting
7
7
  # The fact that the following errors don't descend from OptionParser::InvalidOption is somewhat
8
8
  # annoying, however, there should be no practical problem.
9
9
  #
10
- class InvalidCommand < StandardError; end
11
10
  class ArgumentError < StandardError; end
12
11
 
12
+ class InvalidCommand < StandardError
13
+
14
+ attr_reader :valid_commands
15
+
16
+ def initialize(message, valid_commands)
17
+ super(message)
18
+ @valid_commands = valid_commands
19
+ end
20
+
21
+ end
22
+
13
23
  class ExitWithCommandsHelpPrinting < Struct.new(:commands_definition)
14
24
  # Note that :long_help is not used.
15
25
  def print_help(output, long_help)
@@ -61,12 +71,18 @@ module SimpleScripting
61
71
  exit_data.print_help(output, @long_help)
62
72
 
63
73
  nil # to be used with the 'decode(...) || exit' pattern
64
- rescue SimpleScripting::Argv::ArgumentError, SimpleScripting::Argv::InvalidCommand, OptionParser::InvalidOption => error
65
- if raise_errors
66
- raise
67
- else
68
- output.puts "Command error!: #{error.message}"
69
- end
74
+ rescue SimpleScripting::Argv::ArgumentError, OptionParser::InvalidOption => error
75
+ raise if raise_errors
76
+
77
+ output.puts "Command error!: #{error.message}"
78
+ rescue SimpleScripting::Argv::InvalidCommand => error
79
+ raise if raise_errors
80
+
81
+ output.puts <<~MESSAGE
82
+ Command error!: #{error.message}"
83
+
84
+ Valid commands: #{error.valid_commands.join(", ")}
85
+ MESSAGE
70
86
  ensure
71
87
  @long_help = nil
72
88
  end
@@ -129,13 +145,13 @@ module SimpleScripting
129
145
 
130
146
  command = command_for_check
131
147
 
132
- raise InvalidCommand.new("Missing command") if command.nil?
148
+ raise InvalidCommand.new("Missing command!", commands_definition.keys) if command.nil?
133
149
 
134
150
  command_params_definition = commands_definition[command]
135
151
 
136
152
  case command_params_definition
137
153
  when nil
138
- raise InvalidCommand.new("Invalid command: #{command}")
154
+ raise InvalidCommand.new("Invalid command: #{command}", commands_definition.keys)
139
155
  when Hash
140
156
  commands_stack << command
141
157
 
@@ -210,14 +226,25 @@ module SimpleScripting
210
226
  # DEFINITIONS PROCESSING ###############################
211
227
 
212
228
  def process_option_definition!(param_definition, parser_opts, result)
229
+ # Work on a copy; in at least one case (data type definition), we perform destructive
230
+ # operations.
231
+ #
232
+ param_definition = param_definition.dup
233
+
213
234
  if param_definition[1] && param_definition[1].start_with?('--')
214
- key = param_definition[1].split(' ')[0][2 .. -1].tr('-', '_').to_sym
235
+ raw_key, key_argument = param_definition[1].split(' ')
236
+ key = raw_key[2 .. -1].tr('-', '_').to_sym
237
+
238
+ if key_argument&.include?(',')
239
+ param_definition.insert(2, Array)
240
+ end
215
241
  else
216
242
  key = param_definition[0][1 .. -1].to_sym
217
243
  end
218
244
 
219
245
  parser_opts.on(*param_definition) do |value|
220
- result[key] = value || true
246
+ raise "Unexpected (nil; likely programmatic error) value for param definition #{param_definition}" if value.nil?
247
+ result[key] = value
221
248
  end
222
249
  end
223
250
 
@@ -1,5 +1,5 @@
1
1
  module SimpleScripting
2
2
 
3
- VERSION = "0.11.1"
3
+ VERSION = "0.13.0"
4
4
 
5
5
  end
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.platform = Gem::Platform::RUBY
11
11
  s.required_ruby_version = '>= 2.3.0'
12
12
  s.authors = ["Saverio Miroddi"]
13
- s.date = "2019-03-31"
13
+ s.date = "2022-07-21"
14
14
  s.email = ["saverio.pub2@gmail.com"]
15
15
  s.homepage = "https://github.com/saveriomiroddi/simple_scripting"
16
16
  s.summary = "Library for simplifying some typical scripting functionalities."
@@ -2,497 +2,512 @@ require_relative '../../lib/simple_scripting/argv.rb'
2
2
 
3
3
  require 'stringio'
4
4
 
5
- describe SimpleScripting::Argv do
6
-
7
- let(:output_buffer) do
8
- StringIO.new
9
- end
10
-
11
- describe 'Basic functionality' do
12
-
13
- let(:decoder_params) {[
14
- ['-a' ],
15
- ['-b', '"-b" description'],
16
- ['-c', '--c-switch' ],
17
- ['-d', '--d-switch', '"-d" description'],
18
- ['-e', '--e-switch VALUE' ],
19
- ['-f', '--f-switch VALUE', '"-f" description'],
20
- 'mandatory',
21
- '[optional]',
22
- long_help: 'This is the long help!',
23
- output: output_buffer,
24
- ]}
25
-
26
- context 'help' do
27
-
28
- it 'should print help automatically by default' do
29
- decoder_params.last[:arguments] = ['-h']
30
-
31
- return_value = described_class.decode(*decoder_params)
32
-
33
- expected_output = <<~OUTPUT
34
- Usage: rspec [options] <mandatory> [<optional>]
35
- -a
36
- -b "-b" description
37
- -c, --c-switch
38
- -d, --d-switch "-d" description
39
- -e, --e-switch VALUE
40
- -f, --f-switch VALUE "-f" description
41
- -h, --help Help
42
-
43
- This is the long help!
44
- OUTPUT
45
-
46
- expect(output_buffer.string).to eql(expected_output)
47
- expect(return_value).to be(nil)
48
- end
49
-
50
- it 'should not interpret the --help argument, and not print the help, on auto_help: false' do
51
- decoder_params.last.merge!(
52
- arguments: ['--help', 'm_arg'],
53
- auto_help: false
54
- )
55
-
56
- actual_result = described_class.decode(*decoder_params)
57
-
58
- expected_result = {
59
- help: true,
60
- mandatory: 'm_arg',
61
- }
62
-
63
- expect(output_buffer.string).to eql('')
64
- expect(actual_result).to eql(expected_result)
65
- end
66
-
67
- it "should check all the options/arguments when --help is passed, raising an error when they're not correct" do
68
- decoder_params.last.merge!(
69
- arguments: ['--help'],
70
- auto_help: false,
71
- raise_errors: true,
72
- )
73
-
74
- decoding = -> { described_class.decode(*decoder_params) }
5
+ module SimpleScripting
6
+ describe Argv do
7
+ let(:output_buffer) do
8
+ StringIO.new
9
+ end
75
10
 
76
- expect(decoding).to raise_error(SimpleScripting::Argv::ArgumentError, "Missing mandatory argument(s)")
77
- end
11
+ describe 'Basic functionality' do
12
+ let(:decoder_params) {[
13
+ ['-a' ],
14
+ ['-b', '"-b" description'],
15
+ ['-c', '--c-switch VAL1,VAL2' ],
16
+ ['-d', '--d-switch', '"-d" description'],
17
+ ['-e', '--e-switch VALUE' ],
18
+ ['-f', '--f-switch VALUE', '"-f" description'],
19
+ 'mandatory',
20
+ '[optional]',
21
+ long_help: 'This is the long help!',
22
+ output: output_buffer,
23
+ ]}
78
24
 
79
- end # context 'help'
25
+ context 'help' do
26
+ it 'should print help automatically by default' do
27
+ decoder_params.last[:arguments] = ['-h']
80
28
 
81
- it "should implement basic switches and arguments (all set)" do
82
- decoder_params.last[:arguments] = ['-a', '-b', '-c', '-d', '-ev_swt', '-fv_swt', 'm_arg', 'o_arg']
29
+ return_value = described_class.decode(*decoder_params)
83
30
 
84
- actual_result = described_class.decode(*decoder_params)
31
+ expected_output = <<~OUTPUT
32
+ Usage: rspec [options] <mandatory> [<optional>]
33
+ -a
34
+ -b "-b" description
35
+ -c, --c-switch VAL1,VAL2
36
+ -d, --d-switch "-d" description
37
+ -e, --e-switch VALUE
38
+ -f, --f-switch VALUE "-f" description
39
+ -h, --help Help
85
40
 
86
- expected_result = {
87
- a: true,
88
- b: true,
89
- c_switch: true,
90
- d_switch: true,
91
- e_switch: 'v_swt',
92
- f_switch: 'v_swt',
93
- mandatory: 'm_arg',
94
- optional: 'o_arg',
95
- }
41
+ This is the long help!
42
+ OUTPUT
96
43
 
97
- expect(actual_result).to eql(expected_result)
98
- end
44
+ expect(output_buffer.string).to eql(expected_output)
45
+ expect(return_value).to be(nil)
46
+ end
99
47
 
100
- it "should implement basic switches and arguments (no optional argument)" do
101
- decoder_params.last[:arguments] = ['m_arg']
48
+ it 'should not interpret the --help argument, and not print the help, on auto_help: false' do
49
+ decoder_params.last.merge!(
50
+ arguments: ['--help', 'm_arg'],
51
+ auto_help: false
52
+ )
102
53
 
103
- actual_result = described_class.decode(*decoder_params)
54
+ actual_result = described_class.decode(*decoder_params)
104
55
 
105
- expected_result = {
106
- mandatory: 'm_arg',
107
- }
56
+ expected_result = {
57
+ help: true,
58
+ mandatory: 'm_arg',
59
+ }
108
60
 
109
- expect(actual_result).to eql(expected_result)
110
- end
61
+ expect(output_buffer.string).to eql('')
62
+ expect(actual_result).to eql(expected_result)
63
+ end
111
64
 
112
- context "multiple optional arguments" do
65
+ it "should check all the options/arguments when --help is passed, raising an error when they're not correct" do
66
+ decoder_params.last.merge!(
67
+ arguments: ['--help'],
68
+ auto_help: false,
69
+ raise_errors: true,
70
+ )
113
71
 
114
- let(:decoder_params) {[
115
- '[optional1]',
116
- '[optional2]',
117
- output: output_buffer,
118
- ]}
72
+ expect {
73
+ described_class.decode(*decoder_params)
74
+ }.to raise_error(Argv::ArgumentError, "Missing mandatory argument(s)")
75
+ end
76
+ end # context 'help'
119
77
 
120
- it "should correctly decode a single argument passed" do
121
- decoder_params.last[:arguments] = ['o_arg1']
78
+ it "should implement basic switches, with conversion, and arguments (all set)" do
79
+ decoder_params.last[:arguments] = ['-a', '-b', '-c', 'a,b,c', '-d', '-ev_swt', '-fv_swt', 'm_arg', 'o_arg']
122
80
 
123
81
  actual_result = described_class.decode(*decoder_params)
124
82
 
125
83
  expected_result = {
126
- optional1: 'o_arg1',
84
+ a: true,
85
+ b: true,
86
+ c_switch: %w(a b c),
87
+ d_switch: true,
88
+ e_switch: 'v_swt',
89
+ f_switch: 'v_swt',
90
+ mandatory: 'm_arg',
91
+ optional: 'o_arg',
127
92
  }
128
93
 
129
94
  expect(actual_result).to eql(expected_result)
130
95
  end
131
96
 
132
- it "should correctly decode all arguments passed" do
133
- decoder_params.last[:arguments] = ['o_arg1', 'o_arg2']
97
+ it "should implement basic switches and arguments (no optional argument)" do
98
+ decoder_params.last[:arguments] = ['m_arg']
134
99
 
135
100
  actual_result = described_class.decode(*decoder_params)
136
101
 
137
102
  expected_result = {
138
- optional1: 'o_arg1',
139
- optional2: 'o_arg2',
103
+ mandatory: 'm_arg',
140
104
  }
141
105
 
142
106
  expect(actual_result).to eql(expected_result)
143
107
  end
144
108
 
145
- end
146
-
147
- context "error handling" do
148
-
149
- # All the other UTs use error raising, for convenience.
150
- it "should print the error, with a previx, by default, instead of raising an error" do
151
- decoder_params.last[:arguments] = []
152
-
153
- actual_result = described_class.decode(*decoder_params)
154
-
155
- # Returning nil is an important specification, as it's part of the Argv protocol of doing
156
- # so in case of problem/exit.
157
- expect(actual_result).to be(nil)
158
-
159
- expect(output_buffer.string).to eql("Command error!: Missing mandatory argument(s)\n")
160
- end
161
-
162
- it "should raise an error when mandatory arguments are missing" do
163
- decoder_params.last.merge!(
164
- arguments: [],
165
- raise_errors: true,
166
- )
109
+ context "booleans" do
110
+ VALID_BOOLS = {
111
+ 'false' => false,
112
+ 'true' => true,
113
+ }
167
114
 
168
- decoding = -> { described_class.decode(*decoder_params) }
115
+ INVALID_BOOLS = %w[falx FALSE TRUE]
169
116
 
170
- expect(decoding).to raise_error(SimpleScripting::Argv::ArgumentError, "Missing mandatory argument(s)")
171
- end
117
+ VALID_BOOLS.each do |user_value, decoded_value|
118
+ it "should decode a #{decoded_value} value" do
119
+ decoder_params = [
120
+ ["-b", "--mybool VAL", TrueClass],
121
+ output: output_buffer,
122
+ arguments: ['--mybool', 'false']
123
+ ]
172
124
 
173
- it "should raise an error when there are too many arguments" do
174
- decoder_params.last.merge!(
175
- arguments: ['arg1', 'arg2', 'excessive_arg'],
176
- raise_errors: true,
177
- )
125
+ actual_result = described_class.decode(*decoder_params)
178
126
 
179
- decoding = -> { described_class.decode(*decoder_params) }
127
+ expected_result = {
128
+ mybool: false
129
+ }
180
130
 
181
- expect(decoding).to raise_error(SimpleScripting::Argv::ArgumentError, "Too many arguments")
131
+ expect(actual_result).to eql(expected_result)
132
+ end
133
+ end # context "booleans"
134
+
135
+ INVALID_BOOLS.each do |value|
136
+ it "should raise an error on invalid bool #{value.inspect}" do
137
+ decoder_params = [
138
+ ["-b", "--mybool VAL", TrueClass],
139
+ output: output_buffer,
140
+ arguments: ['--mybool', value],
141
+ raise_errors: true,
142
+ ]
143
+
144
+ expect {
145
+ described_class.decode(*decoder_params)
146
+ }.to raise_error(OptionParser::InvalidArgument)
147
+ end
148
+ end
182
149
  end
183
150
 
184
- end # context "error handling"
185
-
186
- end # describe 'Basic functionality'
187
-
188
- describe 'Varargs' do
189
-
190
- describe '(mandatory)' do
191
-
192
- context 'as only parameter' do
193
-
151
+ context "multiple optional arguments" do
194
152
  let(:decoder_params) {[
195
- '*varargs',
153
+ '[optional1]',
154
+ '[optional2]',
196
155
  output: output_buffer,
197
- arguments: ['varval1', 'varval2'],
198
156
  ]}
199
157
 
200
- it "should be decoded" do
158
+ it "should correctly decode a single argument passed" do
159
+ decoder_params.last[:arguments] = ['o_arg1']
160
+
201
161
  actual_result = described_class.decode(*decoder_params)
202
162
 
203
163
  expected_result = {
204
- varargs: ['varval1', 'varval2'],
164
+ optional1: 'o_arg1',
205
165
  }
206
166
 
207
167
  expect(actual_result).to eql(expected_result)
208
168
  end
209
169
 
210
- end
211
-
212
- context 'followed by varargs' do
170
+ it "should correctly decode all arguments passed" do
171
+ decoder_params.last[:arguments] = ['o_arg1', 'o_arg2']
213
172
 
214
- let(:decoder_params) {[
215
- 'mandatory',
216
- '*varargs',
217
- output: output_buffer,
218
- arguments: ['mandval', 'varval1', 'varval2']
219
- ]}
220
-
221
- it "should be decoded" do
222
173
  actual_result = described_class.decode(*decoder_params)
223
174
 
224
175
  expected_result = {
225
- mandatory: 'mandval',
226
- varargs: ['varval1', 'varval2'],
176
+ optional1: 'o_arg1',
177
+ optional2: 'o_arg2',
227
178
  }
228
179
 
229
180
  expect(actual_result).to eql(expected_result)
230
181
  end
231
-
232
182
  end
233
183
 
234
184
  context "error handling" do
185
+ # All the other UTs use error raising, for convenience.
186
+ it "should print the error, with a previx, by default, instead of raising an error" do
187
+ decoder_params.last[:arguments] = []
235
188
 
236
- let(:decoder_params) {[
237
- '*varargs',
238
- output: output_buffer,
239
- arguments: [],
240
- ]}
241
-
242
- it "should raise an error when they are not specified" do
243
- decoder_params.last[:raise_errors] = true
189
+ actual_result = described_class.decode(*decoder_params)
244
190
 
245
- decoding = -> { described_class.decode(*decoder_params) }
191
+ # Returning nil is an important specification, as it's part of the Argv protocol of doing
192
+ # so in case of problem/exit.
193
+ expect(actual_result).to be(nil)
246
194
 
247
- expect(decoding).to raise_error(SimpleScripting::Argv::ArgumentError, "Missing mandatory argument(s)")
195
+ expect(output_buffer.string).to eql("Command error!: Missing mandatory argument(s)\n")
248
196
  end
249
197
 
250
- end # context "error handling"
251
-
252
- end # describe '(mandatory)'
253
-
254
- describe '(optional)' do
255
-
256
- let(:decoder_params) {[
257
- '[*varargs]',
258
- output: output_buffer,
259
- ]}
260
-
261
- it "should be decoded" do
262
- decoder_params.last[:arguments] = ['varval1', 'varval2']
263
-
264
- actual_result = described_class.decode(*decoder_params)
265
-
266
- expected_result = {
267
- varargs: ['varval1', 'varval2'],
268
- }
269
-
270
- expect(actual_result).to eql(expected_result)
271
- end
272
-
273
- it "should be allowed not to be specified" do
274
- decoder_params.last[:arguments] = []
198
+ it "should raise an error when mandatory arguments are missing" do
199
+ decoder_params.last.merge!(
200
+ arguments: [],
201
+ raise_errors: true,
202
+ )
275
203
 
276
- actual_result = described_class.decode(*decoder_params)
204
+ expect {
205
+ described_class.decode(*decoder_params)
206
+ }.to raise_error(Argv::ArgumentError, "Missing mandatory argument(s)")
207
+ end
277
208
 
278
- expected_result = {
279
- varargs: [],
280
- }
209
+ it "should raise an error when there are too many arguments" do
210
+ decoder_params.last.merge!(
211
+ arguments: ['arg1', 'arg2', 'excessive_arg'],
212
+ raise_errors: true,
213
+ )
281
214
 
282
- expect(actual_result).to eql(expected_result)
283
- end
215
+ expect {
216
+ described_class.decode(*decoder_params)
217
+ }.to raise_error(Argv::ArgumentError, "Too many arguments")
218
+ end
219
+ end # context "error handling"
220
+ end # describe 'Basic functionality'
284
221
 
285
- end # describe '(optional)'
222
+ describe 'Varargs' do
223
+ describe '(mandatory)' do
224
+ context 'as only parameter' do
225
+ let(:decoder_params) {[
226
+ '*varargs',
227
+ output: output_buffer,
228
+ arguments: ['varval1', 'varval2'],
229
+ ]}
286
230
 
287
- end # describe 'Varargs'
231
+ it "should be decoded" do
232
+ actual_result = described_class.decode(*decoder_params)
288
233
 
289
- describe 'Commands' do
234
+ expected_result = {
235
+ varargs: ['varval1', 'varval2'],
236
+ }
290
237
 
291
- describe 'regular case' do
238
+ expect(actual_result).to eql(expected_result)
239
+ end
240
+ end
292
241
 
293
- let(:decoder_params) {{
294
- 'command1' => [
295
- 'arg1',
296
- long_help: 'This is the long help.'
297
- ],
298
- 'command2' => [
299
- 'arg2'
300
- ],
301
- output: output_buffer,
302
- }}
242
+ context 'followed by varargs' do
243
+ let(:decoder_params) {[
244
+ 'mandatory',
245
+ '*varargs',
246
+ output: output_buffer,
247
+ arguments: ['mandval', 'varval1', 'varval2']
248
+ ]}
303
249
 
304
- it 'should be decoded' do
305
- decoder_params[:arguments] = ['command1', 'value1']
250
+ it "should be decoded" do
251
+ actual_result = described_class.decode(*decoder_params)
306
252
 
307
- actual_result = described_class.decode(decoder_params)
253
+ expected_result = {
254
+ mandatory: 'mandval',
255
+ varargs: ['varval1', 'varval2'],
256
+ }
308
257
 
309
- expected_result = ['command1', arg1: 'value1']
258
+ expect(actual_result).to eql(expected_result)
259
+ end
260
+ end
310
261
 
311
- expect(actual_result).to eql(expected_result)
312
- end
262
+ context "error handling" do
263
+ let(:decoder_params) {[
264
+ '*varargs',
265
+ output: output_buffer,
266
+ arguments: [],
267
+ ]}
313
268
 
314
- context "error handling" do
269
+ it "should raise an error when they are not specified" do
270
+ decoder_params.last[:raise_errors] = true
315
271
 
316
- it "should raise an error on invalid command" do
317
- decoder_params.merge!(
318
- arguments: ['pizza'],
319
- raise_errors: true,
320
- )
272
+ expect {
273
+ described_class.decode(*decoder_params)
274
+ }.to raise_error(Argv::ArgumentError, "Missing mandatory argument(s)")
275
+ end
276
+ end # context "error handling"
277
+ end # describe '(mandatory)'
321
278
 
322
- decoding = -> { described_class.decode(decoder_params) }
279
+ describe '(optional)' do
280
+ let(:decoder_params) {[
281
+ '[*varargs]',
282
+ output: output_buffer,
283
+ ]}
323
284
 
324
- expect(decoding).to raise_error(SimpleScripting::Argv::InvalidCommand, "Invalid command: pizza")
325
- end
285
+ it "should be decoded" do
286
+ decoder_params.last[:arguments] = ['varval1', 'varval2']
326
287
 
327
- it "should raise a specific error message on missing command" do
328
- decoder_params.merge!(
329
- arguments: [],
330
- raise_errors: true,
331
- )
288
+ actual_result = described_class.decode(*decoder_params)
332
289
 
333
- decoding = -> { described_class.decode(decoder_params) }
290
+ expected_result = {
291
+ varargs: ['varval1', 'varval2'],
292
+ }
334
293
 
335
- expect(decoding).to raise_error(SimpleScripting::Argv::InvalidCommand, "Missing command")
294
+ expect(actual_result).to eql(expected_result)
336
295
  end
337
296
 
338
- end # context "error handling"
339
-
340
- context "help" do
341
-
342
- it 'should implement the commands help' do
343
- decoder_params[:arguments] = ['-h']
297
+ it "should be allowed not to be specified" do
298
+ decoder_params.last[:arguments] = []
344
299
 
345
- described_class.decode(decoder_params)
346
-
347
- expected_output = <<~OUTPUT
348
- Valid commands:
300
+ actual_result = described_class.decode(*decoder_params)
349
301
 
350
- command1, command2
351
- OUTPUT
302
+ expected_result = {
303
+ varargs: [],
304
+ }
352
305
 
353
- expect(output_buffer.string).to eql(expected_output)
306
+ expect(actual_result).to eql(expected_result)
354
307
  end
308
+ end # describe '(optional)'
309
+ end # describe 'Varargs'
355
310
 
356
- it "should display the command given command's help" do
357
- decoder_params[:arguments] = ['command1', '-h']
311
+ describe 'Commands' do
312
+ describe 'regular case' do
313
+ let(:decoder_params) {{
314
+ 'command1' => [
315
+ 'arg1',
316
+ long_help: 'This is the long help.'
317
+ ],
318
+ 'command2' => [
319
+ 'arg2'
320
+ ],
321
+ output: output_buffer,
322
+ }}
358
323
 
359
- described_class.decode(decoder_params)
324
+ it 'should be decoded' do
325
+ decoder_params[:arguments] = ['command1', 'value1']
360
326
 
361
- expected_output = <<~OUTPUT
362
- Usage: rspec command1 [options] <arg1>
363
- -h, --help Help
327
+ actual_result = described_class.decode(decoder_params)
364
328
 
365
- This is the long help.
366
- OUTPUT
329
+ expected_result = ['command1', arg1: 'value1']
367
330
 
368
- expect(output_buffer.string).to eql(expected_output)
331
+ expect(actual_result).to eql(expected_result)
369
332
  end
370
333
 
371
- context 'auto_help: false' do
372
-
373
- it 'should not interpret the --help argument, and not print the help' do
334
+ context "error handling" do
335
+ it "should raise an error on invalid command" do
374
336
  decoder_params.merge!(
375
- arguments: ['-h'],
376
- auto_help: false,
337
+ arguments: ['pizza'],
338
+ raise_errors: true,
377
339
  )
378
340
 
379
- actual_result = described_class.decode(decoder_params)
380
-
381
- expected_result = {
382
- help: true,
383
- }
384
-
385
- expect(actual_result).to eql(expected_result)
341
+ expect {
342
+ described_class.decode(decoder_params)
343
+ }.to raise_error(an_instance_of(Argv::InvalidCommand).and having_attributes(
344
+ message: "Invalid command: pizza",
345
+ valid_commands: ["command1", "command2"],
346
+ ))
386
347
  end
387
348
 
388
- it 'should ignore and not return all the other arguments' do
349
+ it "should raise a specific error message on missing command" do
389
350
  decoder_params.merge!(
390
- arguments: ['-h', 'pizza'],
391
- auto_help: false,
351
+ arguments: [],
352
+ raise_errors: true,
392
353
  )
393
354
 
394
- actual_result = described_class.decode(decoder_params)
395
-
396
- expected_result = {
397
- help: true,
398
- }
399
-
400
- expect(actual_result).to eql(expected_result)
355
+ expect {
356
+ described_class.decode(decoder_params)
357
+ }.to raise_error(an_instance_of(Argv::InvalidCommand).and having_attributes(
358
+ message: "Missing command!",
359
+ valid_commands: ["command1", "command2"],
360
+ ))
401
361
  end
362
+ end # context "error handling"
402
363
 
403
- end # context 'auto_help: false'
364
+ context "help" do
365
+ it 'should implement the commands help' do
366
+ decoder_params[:arguments] = ['-h']
404
367
 
405
- end # context 'help'
368
+ described_class.decode(decoder_params)
406
369
 
407
- end # describe 'regular case'
370
+ expected_output = <<~OUTPUT
371
+ Valid commands:
408
372
 
409
- describe 'Nested commands' do
373
+ command1, command2
374
+ OUTPUT
410
375
 
411
- let(:decoder_params) {{
412
- 'command1' => {
413
- 'nested1a' => [
414
- 'arg1',
415
- long_help: 'nested1a long help.'
416
- ],
417
- 'nested1b' => [
418
- 'arg1b'
419
- ],
420
- },
421
- 'command2' => [
422
- 'arg2'
423
- ],
424
- output: output_buffer
425
- }}
376
+ expect(output_buffer.string).to eql(expected_output)
377
+ end
426
378
 
427
- it 'should be decoded (two levels)' do
428
- decoder_params[:arguments] = ['command1', 'nested1a', 'value1']
379
+ it "should display the command given command's help" do
380
+ decoder_params[:arguments] = ['command1', '-h']
429
381
 
430
- actual_result = described_class.decode(decoder_params)
382
+ described_class.decode(decoder_params)
431
383
 
432
- expected_result = ['command1.nested1a', arg1: 'value1']
384
+ expected_output = <<~OUTPUT
385
+ Usage: rspec command1 [options] <arg1>
386
+ -h, --help Help
433
387
 
434
- expect(actual_result).to eql(expected_result)
435
- end
388
+ This is the long help.
389
+ OUTPUT
436
390
 
437
- it 'should be decoded (one level)' do
438
- decoder_params[:arguments] = ['command2', 'value2']
391
+ expect(output_buffer.string).to eql(expected_output)
392
+ end
439
393
 
440
- actual_result = described_class.decode(decoder_params)
394
+ context 'auto_help: false' do
395
+ it 'should not interpret the --help argument, and not print the help' do
396
+ decoder_params.merge!(
397
+ arguments: ['-h'],
398
+ auto_help: false,
399
+ )
400
+
401
+ actual_result = described_class.decode(decoder_params)
402
+
403
+ expected_result = {
404
+ help: true,
405
+ }
406
+
407
+ expect(actual_result).to eql(expected_result)
408
+ end
409
+
410
+ it 'should ignore and not return all the other arguments' do
411
+ decoder_params.merge!(
412
+ arguments: ['-h', 'pizza'],
413
+ auto_help: false,
414
+ )
415
+
416
+ actual_result = described_class.decode(decoder_params)
417
+
418
+ expected_result = {
419
+ help: true,
420
+ }
421
+
422
+ expect(actual_result).to eql(expected_result)
423
+ end
424
+ end # context 'auto_help: false'
425
+ end # context 'help'
426
+ end # describe 'regular case'
427
+
428
+ describe 'Nested commands' do
429
+ let(:decoder_params) {{
430
+ 'command1' => {
431
+ 'nested1a' => [
432
+ 'arg1',
433
+ long_help: 'nested1a long help.'
434
+ ],
435
+ 'nested1b' => [
436
+ 'arg1b'
437
+ ],
438
+ },
439
+ 'command2' => [
440
+ 'arg2'
441
+ ],
442
+ output: output_buffer
443
+ }}
441
444
 
442
- expected_result = ['command2', arg2: 'value2']
445
+ it 'should be decoded (two levels)' do
446
+ decoder_params[:arguments] = ['command1', 'nested1a', 'value1']
443
447
 
444
- expect(actual_result).to eql(expected_result)
445
- end
448
+ actual_result = described_class.decode(decoder_params)
446
449
 
447
- it 'should print the command1 help' do
448
- decoder_params[:arguments] = ['command1', '-h']
450
+ expected_result = ['command1.nested1a', arg1: 'value1']
449
451
 
450
- actual_result = described_class.decode(decoder_params)
452
+ expect(actual_result).to eql(expected_result)
453
+ end
451
454
 
452
- expected_output = <<~OUTPUT
453
- Valid commands:
455
+ it 'should be decoded (one level)' do
456
+ decoder_params[:arguments] = ['command2', 'value2']
454
457
 
455
- nested1a, nested1b
456
- OUTPUT
458
+ actual_result = described_class.decode(decoder_params)
457
459
 
458
- expect(output_buffer.string).to eql(expected_output)
459
- end
460
+ expected_result = ['command2', arg2: 'value2']
460
461
 
461
- it 'should print the nested1a help, and long help' do
462
- decoder_params[:arguments] = ['command1', 'nested1a', '-h']
462
+ expect(actual_result).to eql(expected_result)
463
+ end
463
464
 
464
- actual_result = described_class.decode(decoder_params)
465
+ it 'should print the command1 help' do
466
+ decoder_params[:arguments] = ['command1', '-h']
467
+
468
+ actual_result = described_class.decode(decoder_params)
465
469
 
466
- expected_output = <<~OUTPUT
467
- Usage: rspec command1 nested1a [options] <arg1>
468
- -h, --help Help
470
+ expected_output = <<~OUTPUT
471
+ Valid commands:
469
472
 
470
- nested1a long help.
471
- OUTPUT
473
+ nested1a, nested1b
474
+ OUTPUT
472
475
 
473
- expect(output_buffer.string).to eql(expected_output)
474
- end
475
- end # describe 'Nested commands'
476
+ expect(output_buffer.string).to eql(expected_output)
477
+ end
476
478
 
477
- end # describe 'Commands'
479
+ it 'should print the nested1a help, and long help' do
480
+ decoder_params[:arguments] = ['command1', 'nested1a', '-h']
478
481
 
479
- # Special case.
480
- #
481
- describe 'No definitions given' do
482
+ actual_result = described_class.decode(decoder_params)
482
483
 
483
- let(:decoder_params) {{
484
- output: output_buffer,
485
- }}
484
+ expected_output = <<~OUTPUT
485
+ Usage: rspec command1 nested1a [options] <arg1>
486
+ -h, --help Help
486
487
 
487
- it 'should avoid options being interpreted as definitions' do
488
- decoder_params[:arguments] = ['pizza']
489
- decoder_params[:raise_errors] = true
488
+ nested1a long help.
489
+ OUTPUT
490
490
 
491
- decoding = -> { described_class.decode(decoder_params) }
491
+ expect(output_buffer.string).to eql(expected_output)
492
+ end
493
+ end # describe 'Nested commands'
494
+ end # describe 'Commands'
492
495
 
493
- expect(decoding).to raise_error(SimpleScripting::Argv::ArgumentError, "Too many arguments")
494
- end
496
+ # Special case.
497
+ #
498
+ describe 'No definitions given' do
499
+ let(:decoder_params) {{
500
+ output: output_buffer,
501
+ }}
495
502
 
496
- end # describe 'No definitions given'
503
+ it 'should avoid options being interpreted as definitions' do
504
+ decoder_params[:arguments] = ['pizza']
505
+ decoder_params[:raise_errors] = true
497
506
 
498
- end
507
+ expect {
508
+ described_class.decode(decoder_params)
509
+ }.to raise_error(Argv::ArgumentError, "Too many arguments")
510
+ end
511
+ end # describe 'No definitions given'
512
+ end # describe Argv
513
+ end # module SimpleScripting
@@ -4,7 +4,6 @@ require 'tempfile'
4
4
  require 'tmpdir'
5
5
 
6
6
  module SimpleScripting::ConfigurationSpecHelper
7
-
8
7
  def with_tempfile(config_content)
9
8
  tempfile = Tempfile.new('ss_config_test')
10
9
  tempfile.write(config_content)
@@ -14,11 +13,9 @@ module SimpleScripting::ConfigurationSpecHelper
14
13
  ensure
15
14
  tempfile.unlink
16
15
  end
17
-
18
16
  end
19
17
 
20
18
  describe SimpleScripting::Configuration do
21
-
22
19
  include SimpleScripting::ConfigurationSpecHelper
23
20
 
24
21
  let(:configuration_text) {"
@@ -56,9 +53,9 @@ g2_key=bang
56
53
 
57
54
  it "should raise an error when required keys are missing" do
58
55
  with_tempfile(configuration_text) do |config_file|
59
- error_call = -> { described_class.load(config_file: config_file, required: %w(abspath_key missing_key group1)) }
60
-
61
- expect(error_call).to raise_error(RuntimeError, "Missing required configuration key(s): missing_key, group1")
56
+ expect {
57
+ described_class.load(config_file: config_file, required: %w(abspath_key missing_key group1))
58
+ }.to raise_error(RuntimeError, "Missing required configuration key(s): missing_key, group1")
62
59
  end
63
60
  end
64
61
 
@@ -73,5 +70,4 @@ g2_key=bang
73
70
  File.delete(temp_config_file)
74
71
  end
75
72
  end
76
-
77
- end
73
+ end # describe SimpleScripting::Configuration
@@ -3,7 +3,6 @@
3
3
  require_relative '../../lib/simple_scripting/tab_completion.rb'
4
4
 
5
5
  describe SimpleScripting::TabCompletion do
6
-
7
6
  include TabCompletionCustomRSpecMatchers
8
7
 
9
8
  let(:output_buffer) {
@@ -45,9 +44,7 @@ describe SimpleScripting::TabCompletion do
45
44
  subject { described_class.new(switches_definition, output: output_buffer) }
46
45
 
47
46
  context "with a correct configuration" do
48
-
49
47
  context "standard cases" do
50
-
51
48
  # Note that the conversion of mandatory to optional argument is defined by most of the cases.
52
49
  #
53
50
  STANDARD_CASES = {
@@ -79,11 +76,9 @@ describe SimpleScripting::TabCompletion do
79
76
  expect(symbolic_commandline_options).to complete_with(expected_entries)
80
77
  end
81
78
  end
82
-
83
79
  end # context "standard cases"
84
80
 
85
81
  context "suffix management" do
86
-
87
82
  SUFFIX_CASES = {
88
83
  "arg1<tab>v" => %w(arg1v1 arg1v2), # the execution target of the test suite doesn't
89
84
  "arg1<tab>x" => %w(), # ignore the suffix; programmer-defined
@@ -97,11 +92,9 @@ describe SimpleScripting::TabCompletion do
97
92
  expect(symbolic_commandline_options).to complete_with(expected_entries)
98
93
  end
99
94
  end
100
-
101
95
  end # context "suffix management"
102
96
 
103
97
  context "escaped cases" do
104
-
105
98
  ESCAPED_CASES = {
106
99
  "\ <tab>" => [" _argv1spc"],
107
100
  '\-<tab>' => %w(), # this is the result of typing `command "\-<tab>`
@@ -111,7 +104,6 @@ describe SimpleScripting::TabCompletion do
111
104
  ESCAPED_CASES.each do |symbolic_commandline_options, _|
112
105
  it "should output the entries for #{symbolic_commandline_options.inspect}"
113
106
  end
114
-
115
107
  end # context "escaped cases"
116
108
 
117
109
  it "should support multiple values for an option"
@@ -119,11 +111,9 @@ describe SimpleScripting::TabCompletion do
119
111
  it "should keep parsing also when --help is passed" do
120
112
  expect("--help a<tab>").to complete_with(%w(arg1v1 arg1v2))
121
113
  end
122
-
123
114
  end # context "with a correct configuration"
124
115
 
125
116
  context "with an incorrect configuration" do
126
-
127
117
  INCORRECT_CASES = [
128
118
  "a b <tab>", # too many args
129
119
  "-O<tab>", # no values for this option
@@ -134,7 +124,5 @@ describe SimpleScripting::TabCompletion do
134
124
  expect(symbolic_commandline_options).to not_complete
135
125
  end
136
126
  end
137
-
138
127
  end # context "with an incorrect configuration"
139
-
140
128
  end # describe SimpleScripting::TabCompletion
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_scripting
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.1
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Saverio Miroddi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-31 00:00:00.000000000 Z
11
+ date: 2022-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parseconfig
@@ -99,8 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
99
  - !ruby/object:Gem::Version
100
100
  version: '0'
101
101
  requirements: []
102
- rubyforge_project:
103
- rubygems_version: 2.7.8
102
+ rubygems_version: 3.1.6
104
103
  signing_key:
105
104
  specification_version: 4
106
105
  summary: Library for simplifying some typical scripting functionalities.