commander-openflighthpc 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,3 @@
1
1
  module Commander
2
- VERSION = '1.2.0'.freeze
2
+ VERSION = '2.0.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: commander-openflighthpc
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alces Flight Ltd
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2019-09-23 00:00:00.000000000 Z
13
+ date: 2020-04-06 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: highline
@@ -121,12 +121,11 @@ files:
121
121
  - commander-openflighthpc.gemspec
122
122
  - lib/commander.rb
123
123
  - lib/commander/blank.rb
124
+ - lib/commander/cli.rb
124
125
  - lib/commander/command.rb
125
- - lib/commander/configure.rb
126
126
  - lib/commander/core_ext.rb
127
127
  - lib/commander/core_ext/array.rb
128
128
  - lib/commander/core_ext/object.rb
129
- - lib/commander/delegates.rb
130
129
  - lib/commander/help_formatters.rb
131
130
  - lib/commander/help_formatters/base.rb
132
131
  - lib/commander/help_formatters/terminal.rb
@@ -138,7 +137,6 @@ files:
138
137
  - lib/commander/help_formatters/terminal_compact/help.erb
139
138
  - lib/commander/help_formatters/terminal_compact/subcommand_help.erb
140
139
  - lib/commander/import.rb
141
- - lib/commander/methods.rb
142
140
  - lib/commander/patches/decimal-integer.rb
143
141
  - lib/commander/patches/help_formatter_binding.rb
144
142
  - lib/commander/patches/implicit-short-tags.rb
@@ -147,7 +145,6 @@ files:
147
145
  - lib/commander/patches/validate_inputs.rb
148
146
  - lib/commander/platform.rb
149
147
  - lib/commander/runner.rb
150
- - lib/commander/user_interaction.rb
151
148
  - lib/commander/version.rb
152
149
  - spec/command_spec.rb
153
150
  - spec/configure_spec.rb
@@ -183,4 +180,15 @@ rubygems_version: 3.0.3
183
180
  signing_key:
184
181
  specification_version: 4
185
182
  summary: The complete solution for Ruby command-line executables
186
- test_files: []
183
+ test_files:
184
+ - spec/command_spec.rb
185
+ - spec/configure_spec.rb
186
+ - spec/core_ext/array_spec.rb
187
+ - spec/core_ext/object_spec.rb
188
+ - spec/help_formatters/terminal_compact_spec.rb
189
+ - spec/help_formatters/terminal_spec.rb
190
+ - spec/methods_spec.rb
191
+ - spec/patches/validate_inputs_spec.rb
192
+ - spec/runner_spec.rb
193
+ - spec/spec_helper.rb
194
+ - spec/ui_spec.rb
@@ -1,14 +0,0 @@
1
- module Commander
2
- def configure(*configuration_opts, &configuration_block)
3
- configuration_module = Module.new
4
- configuration_module.extend Commander::Methods
5
-
6
- configuration_module.class_exec(*configuration_opts, &configuration_block)
7
-
8
- configuration_module.class_exec do
9
- run!
10
- end
11
- end
12
-
13
- module_function :configure
14
- end
@@ -1,27 +0,0 @@
1
- module Commander
2
- module Delegates
3
- %w(
4
- add_command
5
- command
6
- program
7
- error_handler
8
- run!
9
- global_option
10
- alias_command
11
- default_command
12
- always_trace!
13
- never_trace!
14
- silent_trace!
15
- ).each do |meth|
16
- eval <<-END, binding, __FILE__, __LINE__
17
- def #{meth}(*args, &block)
18
- ::Commander::Runner.instance.#{meth}(*args, &block)
19
- end
20
- END
21
- end
22
-
23
- def defined_commands(*args, &block)
24
- ::Commander::Runner.instance.commands(*args, &block)
25
- end
26
- end
27
- end
@@ -1,11 +0,0 @@
1
- module Commander
2
- module Methods
3
- include Commander::UI
4
- include Commander::UI::AskForClass
5
- include Commander::Delegates
6
-
7
- if $stdin.tty? && (cols = $terminal.output_cols) >= 40
8
- $terminal.wrap_at = cols - 5
9
- end
10
- end
11
- end
@@ -1,551 +0,0 @@
1
- require 'tempfile'
2
- require 'shellwords'
3
-
4
- module Commander
5
- ##
6
- # = User Interaction
7
- #
8
- # Commander's user interaction module mixes in common
9
- # methods which extend HighLine's functionality such
10
- # as a #password method rather than calling #ask directly.
11
-
12
- module UI
13
- module_function
14
-
15
- #--
16
- # Auto include growl when available.
17
- #++
18
-
19
- begin
20
- require 'growl'
21
- rescue LoadError
22
- # Do nothing
23
- else
24
- include Growl
25
- end
26
-
27
- ##
28
- # Ask the user for a password. Specify a custom
29
- # _message_ other than 'Password: ' or override the
30
- # default _mask_ of '*'.
31
-
32
- def password(message = 'Password: ', mask = '*')
33
- pass = ask(message) { |q| q.echo = mask }
34
- pass = password message, mask if pass.nil? || pass.empty?
35
- pass
36
- end
37
-
38
- ##
39
- # Choose from a set array of _choices_.
40
-
41
- def choose(message = nil, *choices, &block)
42
- say message if message
43
- super(*choices, &block)
44
- end
45
-
46
- ##
47
- # 'Log' an _action_ to the terminal. This is typically used
48
- # for verbose output regarding actions performed. For example:
49
- #
50
- # create path/to/file.rb
51
- # remove path/to/old_file.rb
52
- # remove path/to/old_file2.rb
53
- #
54
-
55
- def log(action, *args)
56
- say format('%15s %s', action, args.join(' '))
57
- end
58
-
59
- ##
60
- # 'Say' something using the OK color (green).
61
- #
62
- # === Examples
63
- # say_ok 'Everything is fine'
64
- # say_ok 'It is ok', 'This is ok too'
65
- #
66
-
67
- def say_ok(*args)
68
- args.each do |arg|
69
- say $terminal.color(arg, :green)
70
- end
71
- end
72
-
73
- ##
74
- # 'Say' something using the WARNING color (yellow).
75
- #
76
- # === Examples
77
- # say_warning 'This is a warning'
78
- # say_warning 'Be careful', 'Think about it'
79
- #
80
-
81
- def say_warning(*args)
82
- args.each do |arg|
83
- say $terminal.color(arg, :yellow)
84
- end
85
- end
86
-
87
- ##
88
- # 'Say' something using the ERROR color (red).
89
- #
90
- # === Examples
91
- # say_error 'Everything is not fine'
92
- # say_error 'It is not ok', 'This is not ok too'
93
- #
94
-
95
- def say_error(*args)
96
- args.each do |arg|
97
- say $terminal.color(arg, :red)
98
- end
99
- end
100
-
101
- ##
102
- # 'Say' something using the specified color
103
- #
104
- # === Examples
105
- # color 'I am blue', :blue
106
- # color 'I am bold', :bold
107
- # color 'White on Red', :white, :on_red
108
- #
109
- # === Notes
110
- # You may use:
111
- # * color: black blue cyan green magenta red white yellow
112
- # * style: blink bold clear underline
113
- # * highligh: on_<color>
114
-
115
- def color(*args)
116
- say $terminal.color(*args)
117
- end
118
-
119
- ##
120
- # Speak _message_ using _voice_ at a speaking rate of _rate_
121
- #
122
- # Voice defaults to 'Alex', which is one of the better voices.
123
- # Speaking rate defaults to 175 words per minute
124
- #
125
- # === Examples
126
- #
127
- # speak 'What is your favorite food? '
128
- # food = ask 'favorite food?: '
129
- # speak "Wow, I like #{food} too. We have so much in common."
130
- # speak "I like #{food} as well!", "Victoria", 190
131
- #
132
- # === Notes
133
- #
134
- # * MacOS only
135
- #
136
-
137
- def speak(message, voice = :Alex, rate = 175)
138
- Thread.new { applescript "say #{message.inspect} using #{voice.to_s.inspect} speaking rate #{rate}" }
139
- end
140
-
141
- ##
142
- # Converse with speech recognition.
143
- #
144
- # Currently a "poorman's" DSL to utilize applescript and
145
- # the MacOS speech recognition server.
146
- #
147
- # === Examples
148
- #
149
- # case converse 'What is the best food?', :cookies => 'Cookies', :unknown => 'Nothing'
150
- # when :cookies
151
- # speak 'o.m.g. you are awesome!'
152
- # else
153
- # case converse 'That is lame, shall I convince you cookies are the best?', :yes => 'Ok', :no => 'No', :maybe => 'Maybe another time'
154
- # when :yes
155
- # speak 'Well you see, cookies are just fantastic.'
156
- # else
157
- # speak 'Ok then, bye.'
158
- # end
159
- # end
160
- #
161
- # === Notes
162
- #
163
- # * MacOS only
164
- #
165
-
166
- def converse(prompt, responses = {})
167
- i, commands = 0, responses.map { |_key, value| value.inspect }.join(',')
168
- statement = responses.inject '' do |inner_statement, (key, value)|
169
- inner_statement <<
170
- (
171
- (i += 1) == 1 ?
172
- %(if response is "#{value}" then\n) :
173
- %(else if response is "#{value}" then\n)
174
- ) <<
175
- %(do shell script "echo '#{key}'"\n)
176
- end
177
- applescript(
178
- %(
179
- tell application "SpeechRecognitionServer"
180
- set response to listen for {#{commands}} with prompt "#{prompt}"
181
- #{statement}
182
- end if
183
- end tell
184
- )
185
- ).strip.to_sym
186
- end
187
-
188
- ##
189
- # Execute apple _script_.
190
-
191
- def applescript(script)
192
- `osascript -e "#{ script.gsub('"', '\"') }"`
193
- end
194
-
195
- ##
196
- # Normalize IO streams, allowing for redirection of
197
- # +input+ and/or +output+, for example:
198
- #
199
- # $ foo # => read from terminal I/O
200
- # $ foo in # => read from 'in' file, output to terminal output stream
201
- # $ foo in out # => read from 'in' file, output to 'out' file
202
- # $ foo < in > out # => equivalent to above (essentially)
203
- #
204
- # Optionally a +block+ may be supplied, in which case
205
- # IO will be reset once the block has executed.
206
- #
207
- # === Examples
208
- #
209
- # command :foo do |c|
210
- # c.syntax = 'foo [input] [output]'
211
- # c.when_called do |args, options|
212
- # # or io(args.shift, args.shift)
213
- # io *args
214
- # str = $stdin.gets
215
- # puts 'input was: ' + str.inspect
216
- # end
217
- # end
218
- #
219
-
220
- def io(input = nil, output = nil, &block)
221
- $stdin = File.new(input) if input
222
- $stdout = File.new(output, 'r+') if output
223
- return unless block
224
- yield
225
- reset_io
226
- end
227
-
228
- ##
229
- # Reset IO to initial constant streams.
230
-
231
- def reset_io
232
- $stdin, $stdout = STDIN, STDOUT
233
- end
234
-
235
- ##
236
- # Find an editor available in path. Optionally supply the _preferred_
237
- # editor. Returns the name as a string, nil if none is available.
238
-
239
- def available_editor(preferred = nil)
240
- [preferred, ENV['EDITOR'], 'mate -w', 'vim', 'vi', 'emacs', 'nano', 'pico']
241
- .compact
242
- .find { |name| system("hash #{name.split.first} 2>&-") }
243
- end
244
-
245
- ##
246
- # Prompt an editor for input. Optionally supply initial
247
- # _input_ which is written to the editor.
248
- #
249
- # _preferred_editor_ can be hinted.
250
- #
251
- # === Examples
252
- #
253
- # ask_editor # => prompts EDITOR with no input
254
- # ask_editor('foo') # => prompts EDITOR with default text of 'foo'
255
- # ask_editor('foo', 'mate -w') # => prompts TextMate with default text of 'foo'
256
- #
257
-
258
- def ask_editor(input = nil, preferred_editor = nil)
259
- editor = available_editor preferred_editor
260
- program = Commander::Runner.instance.program(:name).downcase rescue 'commander'
261
- tmpfile = Tempfile.new program
262
- begin
263
- tmpfile.write input if input
264
- tmpfile.close
265
- system("#{editor} #{tmpfile.path.shellescape}") ? IO.read(tmpfile.path) : nil
266
- ensure
267
- tmpfile.unlink
268
- end
269
- end
270
-
271
- ##
272
- # Enable paging of output after called.
273
-
274
- def enable_paging
275
- return unless $stdout.tty?
276
- return unless Process.respond_to? :fork
277
- read, write = IO.pipe
278
-
279
- # Kernel.fork is not supported on all platforms and configurations.
280
- # As of Ruby 1.9, `Process.respond_to? :fork` should return false on
281
- # configurations that don't support it, but versions before 1.9 don't
282
- # seem to do this reliably and instead raise a NotImplementedError
283
- # (which is rescued below).
284
-
285
- if Kernel.fork
286
- $stdin.reopen read
287
- write.close
288
- read.close
289
- Kernel.select [$stdin]
290
- ENV['LESS'] = 'FSRX' unless ENV.key? 'LESS'
291
- pager = ENV['PAGER'] || 'less'
292
- exec pager rescue exec '/bin/sh', '-c', pager
293
- else
294
- # subprocess
295
- $stdout.reopen write
296
- $stderr.reopen write if $stderr.tty?
297
- write.close
298
- read.close
299
- end
300
- rescue NotImplementedError
301
- ensure
302
- write.close if write && !write.closed?
303
- read.close if read && !read.closed?
304
- end
305
-
306
- ##
307
- # Output progress while iterating _arr_.
308
- #
309
- # === Examples
310
- #
311
- # uris = %w( http://vision-media.ca http://google.com )
312
- # progress uris, :format => "Remaining: :time_remaining" do |uri|
313
- # res = open uri
314
- # end
315
- #
316
-
317
- def progress(arr, options = {})
318
- bar = ProgressBar.new arr.length, options
319
- bar.show
320
- arr.each { |v| bar.increment yield(v) }
321
- end
322
-
323
- ##
324
- # Implements ask_for_CLASS methods.
325
-
326
- module AskForClass
327
- DEPRECATED_CONSTANTS = [:Config, :TimeoutError, :MissingSourceFile, :NIL, :TRUE, :FALSE, :Fixnum, :Bignum, :Data].freeze
328
-
329
- # define methods for common classes
330
- [Float, Integer, String, Symbol, Regexp, Array, File, Pathname].each do |klass|
331
- define_method "ask_for_#{klass.to_s.downcase}" do |prompt|
332
- $terminal.ask(prompt, klass)
333
- end
334
- end
335
-
336
- def method_missing(method_name, *arguments, &block)
337
- if method_name.to_s =~ /^ask_for_(.*)/
338
- if arguments.count != 1
339
- fail ArgumentError, "wrong number of arguments (given #{arguments.count}, expected 1)"
340
- end
341
- prompt = arguments.first
342
- requested_class = Regexp.last_match[1]
343
-
344
- # All Classes that respond to #parse
345
- # Ignore constants that trigger deprecation warnings
346
- available_classes = (Object.constants - DEPRECATED_CONSTANTS).map do |const|
347
- Object.const_get(const)
348
- end.select do |const|
349
- const.class == Class && const.respond_to?(:parse)
350
- end
351
-
352
- klass = available_classes.find { |k| k.to_s.downcase == requested_class }
353
- if klass
354
- $terminal.ask(prompt, klass)
355
- else
356
- super
357
- end
358
- else
359
- super
360
- end
361
- end
362
-
363
- def respond_to_missing?(method_name, include_private = false)
364
- method_name.to_s.start_with?('ask_for_') || super
365
- end
366
- end
367
-
368
- ##
369
- # Substitute _hash_'s keys with their associated values in _str_.
370
-
371
- def replace_tokens(str, hash) #:nodoc:
372
- hash.inject(str) do |string, (key, value)|
373
- string.gsub ":#{key}", value.to_s
374
- end
375
- end
376
-
377
- ##
378
- # = Progress Bar
379
- #
380
- # Terminal progress bar utility. In its most basic form
381
- # requires that the developer specifies when the bar should
382
- # be incremented. Note that a hash of tokens may be passed to
383
- # #increment, (or returned when using Object#progress).
384
- #
385
- # uris = %w(
386
- # http://vision-media.ca
387
- # http://yahoo.com
388
- # http://google.com
389
- # )
390
- #
391
- # bar = Commander::UI::ProgressBar.new uris.length, options
392
- # threads = []
393
- # uris.each do |uri|
394
- # threads << Thread.new do
395
- # begin
396
- # res = open uri
397
- # bar.increment :uri => uri
398
- # rescue Exception => e
399
- # bar.increment :uri => "#{uri} failed"
400
- # end
401
- # end
402
- # end
403
- # threads.each { |t| t.join }
404
- #
405
- # The Object method #progress is also available:
406
- #
407
- # progress uris, :width => 10 do |uri|
408
- # res = open uri
409
- # { :uri => uri } # Can now use :uri within :format option
410
- # end
411
- #
412
-
413
- class ProgressBar
414
- ##
415
- # Creates a new progress bar.
416
- #
417
- # === Options
418
- #
419
- # :title Title, defaults to "Progress"
420
- # :width Width of :progress_bar
421
- # :progress_str Progress string, defaults to "="
422
- # :incomplete_str Incomplete bar string, defaults to '.'
423
- # :format Defaults to ":title |:progress_bar| :percent_complete% complete "
424
- # :tokens Additional tokens replaced within the format string
425
- # :complete_message Defaults to "Process complete"
426
- #
427
- # === Tokens
428
- #
429
- # :title
430
- # :percent_complete
431
- # :progress_bar
432
- # :step
433
- # :steps_remaining
434
- # :total_steps
435
- # :time_elapsed
436
- # :time_remaining
437
- #
438
-
439
- def initialize(total, options = {})
440
- @total_steps, @step, @start_time = total, 0, Time.now
441
- @title = options.fetch :title, 'Progress'
442
- @width = options.fetch :width, 25
443
- @progress_str = options.fetch :progress_str, '='
444
- @incomplete_str = options.fetch :incomplete_str, '.'
445
- @complete_message = options.fetch :complete_message, 'Process complete'
446
- @format = options.fetch :format, ':title |:progress_bar| :percent_complete% complete '
447
- @tokens = options.fetch :tokens, {}
448
- end
449
-
450
- ##
451
- # Completion percentage.
452
-
453
- def percent_complete
454
- if @total_steps.zero?
455
- 100
456
- else
457
- @step * 100 / @total_steps
458
- end
459
- end
460
-
461
- ##
462
- # Time that has elapsed since the operation started.
463
-
464
- def time_elapsed
465
- Time.now - @start_time
466
- end
467
-
468
- ##
469
- # Estimated time remaining.
470
-
471
- def time_remaining
472
- (time_elapsed / @step) * steps_remaining
473
- end
474
-
475
- ##
476
- # Number of steps left.
477
-
478
- def steps_remaining
479
- @total_steps - @step
480
- end
481
-
482
- ##
483
- # Formatted progress bar.
484
-
485
- def progress_bar
486
- (@progress_str * (@width * percent_complete / 100)).ljust @width, @incomplete_str
487
- end
488
-
489
- ##
490
- # Generates tokens for this step.
491
-
492
- def generate_tokens
493
- {
494
- title: @title,
495
- percent_complete: percent_complete,
496
- progress_bar: progress_bar,
497
- step: @step,
498
- steps_remaining: steps_remaining,
499
- total_steps: @total_steps,
500
- time_elapsed: format('%0.2fs', time_elapsed),
501
- time_remaining: @step > 0 ? format('%0.2fs', time_remaining) : '',
502
- }.merge! @tokens
503
- end
504
-
505
- ##
506
- # Output the progress bar.
507
-
508
- def show
509
- return if finished?
510
- erase_line
511
- if completed?
512
- $terminal.say UI.replace_tokens(@complete_message, generate_tokens) if @complete_message.is_a? String
513
- else
514
- $terminal.say UI.replace_tokens(@format, generate_tokens) << ' '
515
- end
516
- end
517
-
518
- ##
519
- # Whether or not the operation is complete, and we have finished.
520
-
521
- def finished?
522
- @step == @total_steps + 1
523
- end
524
-
525
- ##
526
- # Whether or not the operation has completed.
527
-
528
- def completed?
529
- @step == @total_steps
530
- end
531
-
532
- ##
533
- # Increment progress. Optionally pass _tokens_ which
534
- # can be displayed in the output format.
535
-
536
- def increment(tokens = {})
537
- @step += 1
538
- @tokens.merge! tokens if tokens.is_a? Hash
539
- show
540
- end
541
-
542
- ##
543
- # Erase previous terminal line.
544
-
545
- def erase_line
546
- # highline does not expose the output stream
547
- $terminal.instance_variable_get('@output').print "\r\e[K"
548
- end
549
- end
550
- end
551
- end