shellopts 2.0.10 → 2.0.13

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: 812078e64c677a6aff78081e25a04b81be3b3a1fe9496709838e2abb80573b4a
4
- data.tar.gz: 92c14741c409697f543820d656683b9552d4c6c7ce5c29b01a30677a174549c2
3
+ metadata.gz: 8dd7a731b489dbf650e15549d9768469ae9d6c47c6dba3ae79f4d956fea069ab
4
+ data.tar.gz: 4b71aff7ba350d4616a136580857a6acd840141ed0b7463034518dcf4ae4dada
5
5
  SHA512:
6
- metadata.gz: 3b1ac7453a534a50cf250e489688aa82ad1928220a615b9e4f7076c27b588d19a7b355e866f3e3cc789fd2259bb2e5de14ac92e905b7b033528c11be26564356
7
- data.tar.gz: d50433ec49a4bf67fd9947d2028ed81be9c8310e7410d93c691e2cd59ed36ef622937c861ef1f4608e7ef5869804cd0f1a4197abf03fd4c2d96cef4985d5dab4
6
+ metadata.gz: bb5792606dd91f46b95fe786b509fd079697c87fd603c667e49740b365cafafa0cdc7b49a0a86c72cd014f9c2d88cdf74f096422e6099403042d8c34d35044b3
7
+ data.tar.gz: d7f2637649b474741b70dd9334e25107586fe52eb4e4f9a289453699f334488fed60322a676ad20fcab2f0c993785ccdef89be4397055028e75d79795766b972
data/lib/ext/array.rb CHANGED
@@ -41,7 +41,9 @@ module Ext
41
41
 
42
42
  module Wrap
43
43
  refine ::Array do
44
- # Concatenate strings into lines that are at most +width+ characters wide
44
+ # Concatenate array of words into lines that are at most +width+
45
+ # characters wide. +curr+ is the initial number of characters already
46
+ # used on the first line
45
47
  def wrap(width, curr = 0)
46
48
  lines = [[]]
47
49
  curr -= 1 # Simplifies conditions below
@@ -1,12 +1,5 @@
1
1
  require 'terminfo'
2
2
 
3
- # TODO: Move to ext/indented_io.rb
4
- module IndentedIO
5
- class IndentedIO
6
- def margin() combined_indent.size end
7
- end
8
- end
9
-
10
3
  module ShellOpts
11
4
  module Grammar
12
5
  class Node
@@ -216,7 +209,10 @@ module ShellOpts
216
209
  BRIEF_COL1_MAX_WIDTH = 40
217
210
 
218
211
  # Minimum width of second column in brief option and command lists
219
- BRIEF_COL2_MAX_WIDTH = 50
212
+ BRIEF_COL2_MIN_WIDTH = 30
213
+
214
+ # Maximum width of second column in brief option and command lists
215
+ BRIEF_COL2_MAX_WIDTH = 70
220
216
 
221
217
  # Indent to use in help output
222
218
  HELP_INDENT = 4
@@ -226,29 +222,21 @@ module ShellOpts
226
222
 
227
223
  # Usage string in error messages
228
224
  def self.usage(subject)
229
- subject = Grammar::Command.command(subject)
230
- @command_prefix = subject.ancestors.map { |node| node.name + " " }.join
225
+ command = Grammar::Command.command(subject)
226
+ @command_prefix = command.ancestors.map { |node| node.name + " " }.join
231
227
  setup_indent(1) {
232
228
  print lead = "#{USAGE_STRING}: "
233
- indent(lead.size, ' ', bol: false) { subject.puts_usage }
229
+ indent(lead.size, ' ', bol: false) { command.puts_usage }
234
230
  }
235
231
  end
236
232
 
237
- # # TODO
238
- # def self.usage=(usage_lambda)
239
- # end
240
-
241
233
  # When the user gives a -h option
242
- def self.brief(command)
243
- command = Grammar::Command.command(command)
234
+ def self.brief(subject)
235
+ command = Grammar::Command.command(subject)
244
236
  @command_prefix = command.ancestors.map { |node| node.name + " " }.join
245
237
  setup_indent(BRIEF_INDENT) { command.puts_brief }
246
238
  end
247
239
 
248
- # # TODO
249
- # def self.brief=(brief_lambda)
250
- # end
251
-
252
240
  # When the user gives a --help option
253
241
  def self.help(subject)
254
242
  subject = Grammar::Command.command(subject)
@@ -262,18 +250,6 @@ module ShellOpts
262
250
  obj.is_a?(Grammar::Command) ? obj : obj.__grammar__
263
251
  end
264
252
 
265
- # # TODO
266
- # def self.help_w_lambda(program)
267
- # if @help_lambda
268
- # #
269
- # else
270
- # program = Grammar::Command.command(program)
271
- # setup_indent(HELP_INDENT) { program.puts_descr }
272
- # end
273
- # end
274
- #
275
- # def self.help=(help_lambda) @help_lambda end
276
-
277
253
  def self.puts_columns(widths, fields)
278
254
  l = []
279
255
  first_width, second_width = *widths
@@ -284,40 +260,47 @@ module ShellOpts
284
260
  puts first
285
261
  indent(first_width + BRIEF_COL_SEP, ' ') { puts second.wrap(second_width) } if second
286
262
  elsif second
287
- printf "%-#{first_width + BRIEF_COL_SEP}s", first
288
- indent(first_width, bol: false) { puts second.wrap(second_width) }
263
+ indent_size = first_width + BRIEF_COL_SEP
264
+ printf "%-#{indent_size}s", first
265
+ indent(indent_size, ' ', bol: false) { puts second.wrap(second_width) }
289
266
  else
290
267
  puts first
291
268
  end
292
269
  end
293
270
  end
294
271
 
272
+ # Returns a tuple of [first-column-width, second-column-width]. +width+ is
273
+ # the maximum width of the colunms and the BRIEF_COL_SEP separator.
274
+ # +fields+ is an array of [subject-string, descr-text] tuples where the
275
+ # descr is an array of words
295
276
  def self.compute_columns(width, fields)
296
- first_max = [
297
- (fields.map { |first, _| first.size } + [BRIEF_COL1_MIN_WIDTH]).max,
298
- BRIEF_COL1_MAX_WIDTH
299
- ].min
300
- second_max = fields.map { |_, second| second ? second&.map(&:size).sum + second.size - 1: 0 }.max
301
-
302
- if first_max + BRIEF_COL_SEP + second_max <= width
303
- first_width = first_max
304
- second_width = second_max
305
- elsif first_max + BRIEF_COL_SEP + BRIEF_COL2_MAX_WIDTH <= width
306
- first_width = first_max
307
- second_width = width - first_width - BRIEF_COL_SEP
277
+ first_max =
278
+ fields.map { |first, _| first.size }.select { |size| size <= BRIEF_COL1_MAX_WIDTH }.max ||
279
+ BRIEF_COL1_MIN_WIDTH
280
+ second_max = fields.map { |_, second| second ? second&.map(&:size).sum + second.size - 1 : 0 }.max
281
+ first_width = [[first_max, BRIEF_COL1_MIN_WIDTH].max, BRIEF_COL1_MAX_WIDTH].min
282
+ rest = width - first_width - BRIEF_COL_SEP
283
+ second_min = [BRIEF_COL2_MIN_WIDTH, second_max].min
284
+ if rest < second_min
285
+ first_width = [first_max, width - second_min - BRIEF_COL_SEP].max
286
+ second_width = [width - first_width - BRIEF_COL_SEP, BRIEF_COL2_MIN_WIDTH].max
308
287
  else
309
- first_width = [width - BRIEF_COL_SEP - BRIEF_COL2_MAX_WIDTH, BRIEF_COL1_MAX_WIDTH].min
310
- second_width = BRIEF_COL2_MAX_WIDTH
288
+ second_width = [[rest, BRIEF_COL2_MIN_WIDTH].max, BRIEF_COL2_MAX_WIDTH].min
311
289
  end
312
-
313
290
  [first_width, second_width]
314
291
  end
315
292
 
316
293
  def self.width()
317
294
  @width ||= TermInfo.screen_width - MARGIN_RIGHT
295
+ @width
296
+ end
297
+
298
+ # Used in rspec
299
+ def self.width=(width)
300
+ @width = width
318
301
  end
319
302
 
320
- def self.rest() width - $stdout.margin end
303
+ def self.rest() width - $stdout.tab end
321
304
 
322
305
  private
323
306
  # TODO Get rid of?
@@ -45,12 +45,12 @@ module ShellOpts
45
45
 
46
46
  # These names can't be used as option or command names
47
47
  RESERVED_OPTION_NAMES = %w(
48
- is_a instance_eval instance_exec method_missing singleton_method_added
48
+ is_a to_h instance_eval instance_exec method_missing singleton_method_added
49
49
  singleton_method_removed singleton_method_undefined
50
50
  )
51
51
 
52
- # These methods can be overridden by an option or a command (the value is not used -
53
- # this is just for informational purposes)
52
+ # These methods can be overridden by an option or a command (this constant
53
+ # is not used - it is just for informational purposes)
54
54
  OVERRIDEABLE_METHOD_NAMES = %w(
55
55
  subcommand subcommand! supercommand!
56
56
  )
@@ -96,6 +96,19 @@ module ShellOpts
96
96
  end
97
97
  end
98
98
 
99
+ # Returns a hash of the given options if defined. Returns all options if no
100
+ # options are given
101
+ def to_h(*keys)
102
+ keys = ::Kernel::Array(keys).flatten
103
+ if keys.empty?
104
+ @__option_values__
105
+ else
106
+ keys.map { |key|
107
+ @__option_values__.key?(key) ? [key, @__option_values__[key]] : nil
108
+ }.compact.to_h
109
+ end
110
+ end
111
+
99
112
  # Subcommand identifier or nil if not present. #subcommand is often used in
100
113
  # case statement to branch out to code that handles the given subcommand:
101
114
  #
@@ -1,3 +1,3 @@
1
1
  module ShellOpts
2
- VERSION = "2.0.10"
2
+ VERSION = "2.0.13"
3
3
  end
data/lib/shellopts.rb CHANGED
@@ -192,23 +192,23 @@ module ShellOpts
192
192
  #
193
193
  # #error is supposed to be used when the user made an error and the usage
194
194
  # is written to help correcting the error
195
- #
196
195
  def error(subject = nil, message)
197
- saved = $stdout
198
- $stdout = $stderr
199
196
  $stderr.puts "#{name}: #{message}"
200
- Formatter.usage(grammar)
201
- exit 1
202
- ensure
203
- $stdout = saved
197
+ saved = $stdout
198
+ begin
199
+ $stdout = $stderr
200
+ Formatter.usage(grammar)
201
+ exit 1
202
+ ensure
203
+ $stdout = saved
204
+ end
204
205
  end
205
206
 
206
207
  # Write error message to standard error and terminate program with status 1
207
208
  #
208
- # #failure is supposed to be used the used specified the correct arguments
209
- # but something went wrong during processing. Since the used didn't cause
210
- # the problem, only the error message is written
211
- #
209
+ # #failure doesn't print the program usage because is supposed to be used
210
+ # when the user specified the correct arguments but something else went
211
+ # wrong during processing
212
212
  def failure(message)
213
213
  $stderr.puts "#{name}: #{message}"
214
214
  exit 1
@@ -222,7 +222,6 @@ module ShellOpts
222
222
 
223
223
  # Print help for the given subject or the full documentation if +subject+
224
224
  # is nil. Clears the screen beforehand if :clear is true
225
- #
226
225
  def help(subject = nil, clear: true)
227
226
  node = (subject ? @grammar[subject] : @grammar) or
228
227
  raise ArgumentError, "No such command: '#{subject&.sub(".", " ")}'"
@@ -333,7 +332,17 @@ module ShellOpts
333
332
  def self.instance=(instance) @instance = instance end
334
333
  def self.shellopts() instance end
335
334
 
336
- forward_self_to :instance, :error, :failure
335
+ def self.error(subject = nil, message)
336
+ instance.error(subject, message) if instance? # Never returns
337
+ $stderr.puts "#{File.basename($PROGRAM_NAME)}: #{message}"
338
+ exit 1
339
+ end
340
+
341
+ def self.failure(message)
342
+ instance.failure(message) if instance?
343
+ $stderr.puts "#{File.basename($PROGRAM_NAME)}: #{message}"
344
+ exit 1
345
+ end
337
346
 
338
347
  # The Include module brings the reporting methods into the namespace when
339
348
  # included
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shellopts
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.10
4
+ version: 2.0.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Claus Rasmussen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-03-08 00:00:00.000000000 Z
11
+ date: 2022-04-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: forward_to