commander-tool 1.0.1 → 1.0.2

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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/commander-tool.rb +128 -66
  3. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5496f2b9238097da058b066f97a541fff53522c6121de06cc0b1571bdd494e19
4
- data.tar.gz: 4a3f35031685414b72c956c7bb78e32fd3bace54909e3694ae417159802b0723
3
+ metadata.gz: fc12456920e61c887d63c3224bbabe9b8c8850df925733a917c782da347ad2a6
4
+ data.tar.gz: fc30d88eac1a17c0effd957e5e1fc1cdcada2e83eda493087e2421b568e2ea88
5
5
  SHA512:
6
- metadata.gz: 29c6b2246ef33bf14e01048d7f3a7df42da6d36080c33a00ba9834936a2c91e9d78214d3dc75590706265f066270db42293499245cc1f21460d1afa0871d2022
7
- data.tar.gz: b4270d0872210a3287049f7a41de8d743859e30ccf2406d26471183dae922daba1809b78abe06856e3154a5ab21c3f88abcbc586bb705a1b1b7b9cdfaa656a2c
6
+ metadata.gz: f830e16aad8121ad5a59cf0a2f4ebf9ce8835e0c06ae2589e845137a06f4dc04f0bff5af628c467d25c04da944f11d393e9da67d025166035bb563819eccc24c
7
+ data.tar.gz: 759a7318b4a23153c992a3a5fb2422b3fd31efb6c2632cf38f2b279430aa92e7bf2fa539db240f07cceebe9fa4284d43dceeaf89c9325f51224001cdb49fc521
@@ -1,14 +1,14 @@
1
1
  require "did_you_mean"
2
2
 
3
3
  class Commander
4
- VERSION = "1.0.1"
4
+ VERSION = "1.0.2"
5
5
 
6
6
  class Command
7
7
  attr_reader :name, :description, :options, :block, :subcommands
8
8
 
9
9
  def initialize(name, description = "", &block)
10
10
  @name = name.to_s
11
- @description = description
11
+ @description = description.to_s
12
12
  @options = []
13
13
  @subcommands = {}
14
14
  @block = block
@@ -34,12 +34,21 @@ class Commander
34
34
  attr_reader :switches, :description, :key
35
35
 
36
36
  def initialize(switches, description = "")
37
- @switches = switches
38
- @description = description
37
+ @switches = Array(switches).map(&:to_s)
38
+ @description = description.to_s
39
+
40
+ long =
41
+ @switches.find { |s| s.start_with?("--") }
42
+
43
+ short =
44
+ @switches.find { |s| s.start_with?("-") }
39
45
 
40
46
  @key =
41
- switches.find { |s| s.start_with?("--") }&.sub(/^--/, "")&.tr("-", "_") ||
42
- switches.find { |s| s.start_with?("-") }&.sub(/^-/, "")
47
+ if long
48
+ long.sub(/\A--/, "").tr("-", "_")
49
+ elsif short
50
+ short.sub(/\A-/, "").tr("-", "_")
51
+ end
43
52
  end
44
53
 
45
54
  def matches?(arg)
@@ -48,8 +57,8 @@ class Commander
48
57
 
49
58
  def value_required?
50
59
  @description.include?("<") ||
51
- @description.include?("argument") ||
52
- @description.include?("value")
60
+ @description.match?(/\bargument\b/i) ||
61
+ @description.match?(/\bvalue\b/i)
53
62
  end
54
63
  end
55
64
 
@@ -70,27 +79,61 @@ class Commander
70
79
  end
71
80
 
72
81
  def parse(args = ARGV)
73
- global_options, remaining = parse_options(
74
- args,
75
- @global_options
76
- )
82
+ args = Array(args).dup
83
+
84
+ if args.empty?
85
+ print_usage
86
+ return
87
+ end
77
88
 
78
- command_name = remaining.shift
89
+ if args.first == "--version" || args.first == "-v"
90
+ puts "Commander CLI v#{VERSION}"
91
+ return
92
+ end
79
93
 
80
- if command_name.nil?
81
- handle_no_command(global_options)
94
+ if args.first == "--help" || args.first == "-h"
95
+ print_usage
82
96
  return
83
97
  end
84
98
 
85
- command = @commands[command_name]
99
+ # Find the first registered top-level command.
100
+ command_index = nil
101
+ command = nil
102
+
103
+ args.each_with_index do |arg, index|
104
+ next if arg.start_with?("-")
105
+
106
+ if @commands.key?(arg)
107
+ command_index = index
108
+ command = @commands[arg]
109
+ break
110
+ end
111
+ end
86
112
 
87
113
  unless command
88
- raise_unknown_command(command_name)
114
+ name = args.find { |arg| !arg.start_with?("-") }
115
+
116
+ if name
117
+ raise_unknown_command(name)
118
+ else
119
+ raise_unknown_option(args.first, @global_options)
120
+ end
89
121
  end
90
122
 
123
+ # Only arguments BEFORE the command belong to global options.
124
+ global_args = args[0...command_index]
125
+
126
+ # Everything AFTER the command belongs to that command.
127
+ command_args = args[(command_index + 1)..] || []
128
+
129
+ global_options, = parse_options(
130
+ global_args,
131
+ @global_options
132
+ )
133
+
91
134
  parse_command(
92
135
  command,
93
- remaining,
136
+ command_args,
94
137
  global_options
95
138
  )
96
139
  end
@@ -98,6 +141,8 @@ class Commander
98
141
  private
99
142
 
100
143
  def parse_command(command, args, inherited_options)
144
+ args = args.dup
145
+
101
146
  if command.has_subcommands?
102
147
  subcommand_name = args.shift
103
148
 
@@ -106,6 +151,11 @@ class Commander
106
151
  return
107
152
  end
108
153
 
154
+ if subcommand_name == "--help" || subcommand_name == "-h"
155
+ print_command_help(command)
156
+ return
157
+ end
158
+
109
159
  subcommand = command.subcommands[subcommand_name]
110
160
 
111
161
  unless subcommand
@@ -116,7 +166,10 @@ class Commander
116
166
  end
117
167
 
118
168
  command_options, command_args =
119
- parse_options(args, command.options)
169
+ parse_options(
170
+ args,
171
+ command.options
172
+ )
120
173
 
121
174
  combined_options =
122
175
  inherited_options.merge(command_options)
@@ -138,7 +191,10 @@ class Commander
138
191
  end
139
192
 
140
193
  command_options, command_args =
141
- parse_options(args, command.options)
194
+ parse_options(
195
+ args,
196
+ command.options
197
+ )
142
198
 
143
199
  combined_options =
144
200
  inherited_options.merge(command_options)
@@ -152,6 +208,7 @@ class Commander
152
208
  def parse_options(args, available_options)
153
209
  parsed = {}
154
210
  remaining = []
211
+
155
212
  i = 0
156
213
 
157
214
  while i < args.length
@@ -162,37 +219,41 @@ class Commander
162
219
  break
163
220
  end
164
221
 
165
- if arg.start_with?("-")
166
- option = available_options.find do |opt|
167
- opt.matches?(arg)
222
+ unless arg.start_with?("-")
223
+ remaining << arg
224
+ i += 1
225
+ next
226
+ end
227
+
228
+ option =
229
+ available_options.find do |candidate|
230
+ candidate.matches?(arg)
168
231
  end
169
232
 
233
+ unless option
170
234
  raise_unknown_option(
171
235
  arg,
172
236
  available_options
173
- ) unless option
237
+ )
238
+ end
174
239
 
175
- next_arg = args[i + 1]
240
+ next_arg = args[i + 1]
176
241
 
177
- if option.value_required?
178
- if next_arg.nil? ||
179
- next_arg.start_with?("-")
180
- raise_missing_argument(arg)
181
- end
242
+ if option.value_required?
243
+ if next_arg.nil? || next_arg.start_with?("-")
244
+ raise_missing_argument(arg)
245
+ end
182
246
 
183
- parsed[option.key.to_sym] = next_arg
184
- i += 2
185
- elsif next_arg &&
186
- !next_arg.start_with?("-")
247
+ parsed[option.key.to_sym] = next_arg
248
+ i += 2
249
+ else
250
+ if next_arg && !next_arg.start_with?("-")
187
251
  parsed[option.key.to_sym] = next_arg
188
252
  i += 2
189
253
  else
190
254
  parsed[option.key.to_sym] = true
191
255
  i += 1
192
256
  end
193
- else
194
- remaining << arg
195
- i += 1
196
257
  end
197
258
  end
198
259
 
@@ -204,26 +265,29 @@ class Commander
204
265
  end
205
266
 
206
267
  def raise_unknown_command(name)
207
- corrector = DidYouMean::SpellChecker.new(
208
- dictionary: @commands.keys
209
- )
268
+ corrector =
269
+ DidYouMean::SpellChecker.new(
270
+ dictionary: @commands.keys
271
+ )
210
272
 
211
273
  suggestions = corrector.correct(name)
212
274
 
213
- message = "error: unknown command '#{name}'"
275
+ message =
276
+ "error: unknown command '#{name}'"
214
277
 
215
278
  unless suggestions.empty?
216
- message += "\n\nDid you mean?\n"
217
- message += suggestions.map { |s| "\t#{s}" }.join("\n")
279
+ message << "\n\nDid you mean?\n"
280
+ message << suggestions.map { |s| "\t#{s}" }.join("\n")
218
281
  end
219
282
 
220
283
  abort message
221
284
  end
222
285
 
223
286
  def raise_unknown_subcommand(name, command)
224
- corrector = DidYouMean::SpellChecker.new(
225
- dictionary: command.subcommands.keys
226
- )
287
+ corrector =
288
+ DidYouMean::SpellChecker.new(
289
+ dictionary: command.subcommands.keys
290
+ )
227
291
 
228
292
  suggestions = corrector.correct(name)
229
293
 
@@ -231,41 +295,35 @@ class Commander
231
295
  "error: unknown command '#{name}'"
232
296
 
233
297
  unless suggestions.empty?
234
- message += "\n\nDid you mean?\n"
235
- message += suggestions.map { |s| "\t#{s}" }.join("\n")
298
+ message << "\n\nDid you mean?\n"
299
+ message << suggestions.map { |s| "\t#{s}" }.join("\n")
236
300
  end
237
301
 
238
302
  abort message
239
303
  end
240
304
 
241
305
  def raise_unknown_option(name, options)
242
- switches = options.flat_map(&:switches)
306
+ switches =
307
+ options.flat_map(&:switches)
243
308
 
244
- corrector = DidYouMean::SpellChecker.new(
245
- dictionary: switches
246
- )
309
+ corrector =
310
+ DidYouMean::SpellChecker.new(
311
+ dictionary: switches
312
+ )
247
313
 
248
314
  suggestions = corrector.correct(name)
249
315
 
250
- message = "error: unknown option '#{name}'"
316
+ message =
317
+ "error: unknown option '#{name}'"
251
318
 
252
319
  unless suggestions.empty?
253
- message += "\n\nDid you mean?\n"
254
- message += suggestions.map { |s| "\t#{s}" }.join("\n")
320
+ message << "\n\nDid you mean?\n"
321
+ message << suggestions.map { |s| "\t#{s}" }.join("\n")
255
322
  end
256
323
 
257
324
  abort message
258
325
  end
259
326
 
260
- def handle_no_command(options)
261
- if options[:version] || options[:v]
262
- puts "Commander CLI v#{VERSION}"
263
- return
264
- end
265
-
266
- print_usage
267
- end
268
-
269
327
  def print_usage
270
328
  puts "Usage: <command> [options]"
271
329
  puts
@@ -288,8 +346,12 @@ class Commander
288
346
  def print_command_help(command)
289
347
  puts "Usage: #{command.name} <subcommand> [options]"
290
348
  puts
291
- puts command.description unless command.description.empty?
292
- puts
349
+
350
+ unless command.description.empty?
351
+ puts command.description
352
+ puts
353
+ end
354
+
293
355
  puts "Commands:"
294
356
 
295
357
  command.subcommands.each_value do |subcommand|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: commander-tool
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jjjm