simple_scripting 0.11.1 → 0.13.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 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.