pry 0.10.4-java → 0.11.0-java
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 +4 -4
- data/CHANGELOG.md +52 -18
- data/LICENSE +1 -1
- data/README.md +32 -31
- data/bin/pry +3 -7
- data/lib/pry.rb +4 -4
- data/lib/pry/basic_object.rb +6 -0
- data/lib/pry/cli.rb +39 -34
- data/lib/pry/code.rb +6 -1
- data/lib/pry/code/code_file.rb +8 -2
- data/lib/pry/code_object.rb +23 -0
- data/lib/pry/color_printer.rb +20 -11
- data/lib/pry/command.rb +40 -16
- data/lib/pry/command_set.rb +9 -2
- data/lib/pry/commands/cat/exception_formatter.rb +11 -10
- data/lib/pry/commands/cat/file_formatter.rb +7 -3
- data/lib/pry/commands/code_collector.rb +16 -14
- data/lib/pry/commands/easter_eggs.rb +9 -9
- data/lib/pry/commands/edit.rb +7 -3
- data/lib/pry/commands/edit/file_and_line_locator.rb +1 -1
- data/lib/pry/commands/find_method.rb +1 -1
- data/lib/pry/commands/gem_open.rb +1 -1
- data/lib/pry/commands/gem_readme.rb +25 -0
- data/lib/pry/commands/gem_search.rb +40 -0
- data/lib/pry/commands/hist.rb +2 -2
- data/lib/pry/commands/jump_to.rb +7 -7
- data/lib/pry/commands/ls.rb +3 -1
- data/lib/pry/commands/ls/constants.rb +12 -1
- data/lib/pry/commands/ls/formatter.rb +1 -0
- data/lib/pry/commands/ls/jruby_hacks.rb +2 -2
- data/lib/pry/commands/ls/self_methods.rb +2 -0
- data/lib/pry/commands/play.rb +2 -2
- data/lib/pry/commands/reload_code.rb +2 -2
- data/lib/pry/commands/ri.rb +4 -0
- data/lib/pry/commands/shell_command.rb +34 -8
- data/lib/pry/commands/show_info.rb +10 -2
- data/lib/pry/commands/watch_expression/expression.rb +1 -1
- data/lib/pry/commands/whereami.rb +7 -6
- data/lib/pry/config.rb +3 -16
- data/lib/pry/config/behavior.rb +140 -49
- data/lib/pry/config/default.rb +21 -33
- data/lib/pry/config/memoization.rb +44 -0
- data/lib/pry/core_extensions.rb +12 -2
- data/lib/pry/editor.rb +1 -1
- data/lib/pry/exceptions.rb +1 -1
- data/lib/pry/forwardable.rb +23 -0
- data/lib/pry/helpers/base_helpers.rb +6 -10
- data/lib/pry/helpers/documentation_helpers.rb +1 -0
- data/lib/pry/helpers/options_helpers.rb +1 -1
- data/lib/pry/helpers/text.rb +69 -75
- data/lib/pry/history.rb +22 -1
- data/lib/pry/history_array.rb +1 -1
- data/lib/pry/hooks.rb +48 -107
- data/lib/pry/indent.rb +6 -2
- data/lib/pry/input_completer.rb +138 -120
- data/lib/pry/last_exception.rb +2 -2
- data/lib/pry/method.rb +15 -15
- data/lib/pry/method/disowned.rb +1 -0
- data/lib/pry/method/patcher.rb +0 -3
- data/lib/pry/output.rb +37 -38
- data/lib/pry/pager.rb +11 -8
- data/lib/pry/plugins.rb +20 -5
- data/lib/pry/pry_class.rb +30 -4
- data/lib/pry/pry_instance.rb +8 -6
- data/lib/pry/repl.rb +38 -8
- data/lib/pry/repl_file_loader.rb +1 -1
- data/lib/pry/rubygem.rb +3 -1
- data/lib/pry/slop.rb +661 -0
- data/lib/pry/slop/LICENSE +20 -0
- data/lib/pry/slop/commands.rb +196 -0
- data/lib/pry/slop/option.rb +208 -0
- data/lib/pry/terminal.rb +16 -5
- data/lib/pry/test/helper.rb +12 -3
- data/lib/pry/version.rb +1 -1
- data/lib/pry/wrapped_module.rb +7 -7
- data/lib/pry/{module_candidate.rb → wrapped_module/candidate.rb} +7 -13
- metadata +14 -19
data/lib/pry/pager.rb
CHANGED
@@ -14,11 +14,12 @@ class Pry::Pager
|
|
14
14
|
end
|
15
15
|
|
16
16
|
# Send the given text through the best available pager (if `Pry.config.pager` is
|
17
|
-
# enabled).
|
18
|
-
#
|
19
|
-
#
|
20
|
-
# @param [String] text
|
21
|
-
#
|
17
|
+
# enabled). If you want to send text through in chunks as you generate it, use `open`
|
18
|
+
# to get a writable object instead.
|
19
|
+
#
|
20
|
+
# @param [String] text
|
21
|
+
# Text to run through a pager.
|
22
|
+
#
|
22
23
|
def page(text)
|
23
24
|
open do |pager|
|
24
25
|
pager << text
|
@@ -27,7 +28,6 @@ class Pry::Pager
|
|
27
28
|
|
28
29
|
# Yields a pager object (`NullPager`, `SimplePager`, or `SystemPager`). All
|
29
30
|
# pagers accept output with `#puts`, `#print`, `#write`, and `#<<`.
|
30
|
-
# @param [IO] output (`$stdout`) An object to send output to.
|
31
31
|
def open
|
32
32
|
pager = best_available
|
33
33
|
yield pager
|
@@ -48,7 +48,6 @@ class Pry::Pager
|
|
48
48
|
# `#print`, `#write`, and `#<<`. You must call `#close` when you're done
|
49
49
|
# writing output to a pager, and you must rescue `Pry::Pager::StopPaging`.
|
50
50
|
# These requirements can be avoided by using `.open` instead.
|
51
|
-
# @param [#<<] output ($stdout) An object to send output to.
|
52
51
|
def best_available
|
53
52
|
if !_pry_.config.pager
|
54
53
|
NullPager.new(_pry_.output)
|
@@ -139,7 +138,11 @@ class Pry::Pager
|
|
139
138
|
if @system_pager.nil?
|
140
139
|
@system_pager = begin
|
141
140
|
pager_executable = default_pager.split(' ').first
|
142
|
-
|
141
|
+
if Pry::Helpers::BaseHelpers.windows? || Pry::Helpers::BaseHelpers.windows_ansi?
|
142
|
+
`where #{pager_executable}`
|
143
|
+
else
|
144
|
+
`which #{pager_executable}`
|
145
|
+
end
|
143
146
|
$?.success?
|
144
147
|
rescue
|
145
148
|
false
|
data/lib/pry/plugins.rb
CHANGED
@@ -60,6 +60,16 @@ class Pry
|
|
60
60
|
|
61
61
|
alias active? active
|
62
62
|
alias enabled? enabled
|
63
|
+
|
64
|
+
def supported?
|
65
|
+
pry_version = Gem::Version.new(VERSION)
|
66
|
+
spec.dependencies.each do |dependency|
|
67
|
+
if dependency.name == "pry"
|
68
|
+
return dependency.requirement.satisfied_by?(pry_version)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
true
|
72
|
+
end
|
63
73
|
end
|
64
74
|
|
65
75
|
def initialize
|
@@ -68,11 +78,11 @@ class Pry
|
|
68
78
|
|
69
79
|
# Find all installed Pry plugins and store them in an internal array.
|
70
80
|
def locate_plugins
|
71
|
-
|
72
|
-
(Gem::Specification.respond_to?(:each) ? Gem::Specification : Gem.source_index.find_name('')).each do |gem|
|
81
|
+
gem_list.each do |gem|
|
73
82
|
next if gem.name !~ PRY_PLUGIN_PREFIX
|
74
83
|
plugin_name = gem.name.split('-', 2).last
|
75
|
-
|
84
|
+
plugin = Plugin.new(plugin_name, gem.name, gem, false)
|
85
|
+
@plugins << plugin.tap(&:enable!) if plugin.supported? && !plugin_located?(plugin)
|
76
86
|
end
|
77
87
|
@plugins
|
78
88
|
end
|
@@ -95,8 +105,13 @@ class Pry
|
|
95
105
|
end
|
96
106
|
|
97
107
|
private
|
98
|
-
def
|
99
|
-
@plugins.any? { |
|
108
|
+
def plugin_located?(plugin)
|
109
|
+
@plugins.any? { |existing| existing.gem_name == plugin.gem_name }
|
110
|
+
end
|
111
|
+
|
112
|
+
def gem_list
|
113
|
+
Gem.refresh
|
114
|
+
Gem::Specification.respond_to?(:each) ? Gem::Specification : Gem.source_index.find_name('')
|
100
115
|
end
|
101
116
|
end
|
102
117
|
|
data/lib/pry/pry_class.rb
CHANGED
@@ -5,7 +5,7 @@ class Pry
|
|
5
5
|
LOCAL_RC_FILE = "./.pryrc"
|
6
6
|
|
7
7
|
class << self
|
8
|
-
extend Forwardable
|
8
|
+
extend Pry::Forwardable
|
9
9
|
attr_accessor :custom_completions
|
10
10
|
attr_accessor :current_line
|
11
11
|
attr_accessor :line_buffer
|
@@ -32,6 +32,21 @@ class Pry
|
|
32
32
|
def history
|
33
33
|
@history ||= History.new
|
34
34
|
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# @example
|
38
|
+
# Pry.configure do |config|
|
39
|
+
# config.eager_load! # optional
|
40
|
+
# config.input = # ..
|
41
|
+
# config.foo = 2
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# @yield [config]
|
45
|
+
# Yields a block with {Pry.config} as its argument.
|
46
|
+
#
|
47
|
+
def configure
|
48
|
+
yield config
|
49
|
+
end
|
35
50
|
end
|
36
51
|
|
37
52
|
#
|
@@ -81,7 +96,7 @@ class Pry
|
|
81
96
|
expanded = Pathname.new(File.expand_path(file)).realpath.to_s
|
82
97
|
# For rbx 1.9 mode [see rubinius issue #2165]
|
83
98
|
File.exist?(expanded) ? expanded : nil
|
84
|
-
rescue Errno::ENOENT
|
99
|
+
rescue Errno::ENOENT, Errno::EACCES
|
85
100
|
nil
|
86
101
|
end
|
87
102
|
|
@@ -124,6 +139,11 @@ you can add "Pry.config.windows_console_warning = false" to your .pryrc.
|
|
124
139
|
# note these have to be loaded here rather than in pry_instance as
|
125
140
|
# we only want them loaded once per entire Pry lifetime.
|
126
141
|
load_rc_files
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.final_session_setup
|
145
|
+
return if @session_finalized
|
146
|
+
@session_finalized = true
|
127
147
|
load_plugins if Pry.config.should_load_plugins
|
128
148
|
load_requires if Pry.config.should_load_requires
|
129
149
|
load_history if Pry.config.history.should_load
|
@@ -141,6 +161,9 @@ you can add "Pry.config.windows_console_warning = false" to your .pryrc.
|
|
141
161
|
# Pry.start(Object.new, :input => MyInput.new)
|
142
162
|
def self.start(target=nil, options={})
|
143
163
|
return if ENV['DISABLE_PRY']
|
164
|
+
if ENV['FAIL_PRY']
|
165
|
+
raise 'You have FAIL_PRY set to true, which results in Pry calls failing'
|
166
|
+
end
|
144
167
|
options = options.to_hash
|
145
168
|
|
146
169
|
if in_critical_section?
|
@@ -150,8 +173,8 @@ you can add "Pry.config.windows_console_warning = false" to your .pryrc.
|
|
150
173
|
end
|
151
174
|
|
152
175
|
options[:target] = Pry.binding_for(target || toplevel_binding)
|
153
|
-
options[:hooks] = Pry::Hooks.from_hash options.delete(:hooks) if options.key?(:hooks)
|
154
176
|
initial_session_setup
|
177
|
+
final_session_setup
|
155
178
|
|
156
179
|
# Unless we were given a backtrace, save the current one
|
157
180
|
if options[:backtrace].nil?
|
@@ -233,7 +256,7 @@ you can add "Pry.config.windows_console_warning = false" to your .pryrc.
|
|
233
256
|
# @param [String] command_string The Pry command (including arguments,
|
234
257
|
# if any).
|
235
258
|
# @param [Hash] options Optional named parameters.
|
236
|
-
# @return [
|
259
|
+
# @return [nil]
|
237
260
|
# @option options [Object, Binding] :target The object to run the
|
238
261
|
# command under. Defaults to `TOPLEVEL_BINDING` (main).
|
239
262
|
# @option options [Boolean] :show_output Whether to show command
|
@@ -258,6 +281,7 @@ you can add "Pry.config.windows_console_warning = false" to your .pryrc.
|
|
258
281
|
|
259
282
|
pry = Pry.new(:output => output, :target => target, :commands => options[:commands])
|
260
283
|
pry.eval command_string
|
284
|
+
nil
|
261
285
|
end
|
262
286
|
|
263
287
|
def self.default_editor_for_platform
|
@@ -306,6 +330,8 @@ Readline version #{Readline::VERSION} detected - will not auto_resize! correctly
|
|
306
330
|
# Set all the configurable options back to their default values
|
307
331
|
def self.reset_defaults
|
308
332
|
@initial_session = true
|
333
|
+
@session_finalized = nil
|
334
|
+
|
309
335
|
self.config = Pry::Config.new Pry::Config::Default.new
|
310
336
|
self.cli = false
|
311
337
|
self.current_line = 1
|
data/lib/pry/pry_instance.rb
CHANGED
@@ -16,7 +16,7 @@
|
|
16
16
|
# This will show a list of available commands and their usage. For more
|
17
17
|
# information about Pry you can refer to the following resources:
|
18
18
|
#
|
19
|
-
# * http://
|
19
|
+
# * http://pryrepl.org/
|
20
20
|
# * https://github.com/pry/pry
|
21
21
|
# * the IRC channel, which is #pry on the Freenode network
|
22
22
|
#
|
@@ -124,7 +124,7 @@ class Pry
|
|
124
124
|
#
|
125
125
|
# Generate completions.
|
126
126
|
#
|
127
|
-
# @param [String]
|
127
|
+
# @param [String] str
|
128
128
|
# What the user has typed so far
|
129
129
|
#
|
130
130
|
# @return [Array<String>]
|
@@ -269,7 +269,7 @@ class Pry
|
|
269
269
|
@suppress_output = false
|
270
270
|
inject_sticky_locals!
|
271
271
|
begin
|
272
|
-
if !process_command_safely(line
|
272
|
+
if !process_command_safely(line)
|
273
273
|
@eval_string << "#{line.chomp}\n" if !line.empty? || !@eval_string.empty?
|
274
274
|
end
|
275
275
|
rescue RescuableException => e
|
@@ -373,7 +373,7 @@ class Pry
|
|
373
373
|
# serialize something in the user's program, let's not assume we can serialize
|
374
374
|
# the exception either.
|
375
375
|
begin
|
376
|
-
output.puts "(pry) output error: #{e.inspect}"
|
376
|
+
output.puts "(pry) output error: #{e.inspect}\n#{e.backtrace.join("\n")}"
|
377
377
|
rescue RescuableException => e
|
378
378
|
if last_result_is_exception?
|
379
379
|
output.puts "(pry) output error: failed to show exception"
|
@@ -400,12 +400,14 @@ class Pry
|
|
400
400
|
# @param [String] val The line to process.
|
401
401
|
# @return [Boolean] `true` if `val` is a command, `false` otherwise
|
402
402
|
def process_command(val)
|
403
|
+
val = val.lstrip if /^\s\S/ !~ val
|
403
404
|
val = val.chomp
|
404
405
|
result = commands.process_line(val,
|
405
406
|
:target => current_binding,
|
406
407
|
:output => output,
|
407
408
|
:eval_string => @eval_string,
|
408
|
-
:pry_instance => self
|
409
|
+
:pry_instance => self,
|
410
|
+
:hooks => hooks
|
409
411
|
)
|
410
412
|
|
411
413
|
# set a temporary (just so we can inject the value we want into eval_string)
|
@@ -433,7 +435,7 @@ class Pry
|
|
433
435
|
# @return [Boolean] `true` if `val` is a command, `false` otherwise
|
434
436
|
def process_command_safely(val)
|
435
437
|
process_command(val)
|
436
|
-
rescue CommandError, Slop::InvalidOptionError, MethodSource::SourceNotFoundError => e
|
438
|
+
rescue CommandError, Pry::Slop::InvalidOptionError, MethodSource::SourceNotFoundError => e
|
437
439
|
Pry.last_internal_error = e
|
438
440
|
output.puts "Error: #{e.message}"
|
439
441
|
true
|
data/lib/pry/repl.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
|
-
require 'forwardable'
|
2
|
-
|
3
1
|
class Pry
|
4
2
|
class REPL
|
5
|
-
extend Forwardable
|
3
|
+
extend Pry::Forwardable
|
6
4
|
def_delegators :@pry, :input, :output
|
7
5
|
|
8
6
|
# @return [Pry] The instance of {Pry} that the user is controlling.
|
@@ -23,6 +21,8 @@ class Pry
|
|
23
21
|
@pry = pry
|
24
22
|
@indent = Pry::Indent.new
|
25
23
|
|
24
|
+
@readline_output = nil
|
25
|
+
|
26
26
|
if options[:target]
|
27
27
|
@pry.push_binding options[:target]
|
28
28
|
end
|
@@ -168,20 +168,21 @@ class Pry
|
|
168
168
|
# @return [String?] The next line of input, or `nil` on <Ctrl-D>.
|
169
169
|
def read_line(current_prompt)
|
170
170
|
handle_read_errors do
|
171
|
-
if
|
171
|
+
if coolline_available?
|
172
172
|
input.completion_proc = proc do |cool|
|
173
173
|
completions = @pry.complete cool.completed_word
|
174
174
|
completions.compact
|
175
175
|
end
|
176
176
|
elsif input.respond_to? :completion_proc=
|
177
|
-
input.completion_proc = proc do |
|
178
|
-
@pry.complete
|
177
|
+
input.completion_proc = proc do |inp|
|
178
|
+
@pry.complete inp
|
179
179
|
end
|
180
180
|
end
|
181
181
|
|
182
|
-
if
|
182
|
+
if readline_available?
|
183
|
+
set_readline_output
|
183
184
|
input_readline(current_prompt, false) # false since we'll add it manually
|
184
|
-
elsif
|
185
|
+
elsif coolline_available?
|
185
186
|
input_readline(current_prompt)
|
186
187
|
else
|
187
188
|
if input.method(:readline).arity == 1
|
@@ -198,5 +199,34 @@ class Pry
|
|
198
199
|
input.readline(*args)
|
199
200
|
end
|
200
201
|
end
|
202
|
+
|
203
|
+
def readline_available?
|
204
|
+
defined?(Readline) && input == Readline
|
205
|
+
end
|
206
|
+
|
207
|
+
def coolline_available?
|
208
|
+
defined?(Coolline) && input.is_a?(Coolline)
|
209
|
+
end
|
210
|
+
|
211
|
+
# If `$stdout` is not a tty, it's probably a pipe.
|
212
|
+
# @example
|
213
|
+
# # `piping?` returns `false`
|
214
|
+
# % pry
|
215
|
+
# [1] pry(main)
|
216
|
+
#
|
217
|
+
# # `piping?` returns `true`
|
218
|
+
# % pry | tee log
|
219
|
+
def piping?
|
220
|
+
return false unless $stdout.respond_to?(:tty?)
|
221
|
+
!$stdout.tty? && $stdin.tty? && !Pry::Helpers::BaseHelpers.windows?
|
222
|
+
end
|
223
|
+
|
224
|
+
# @return [void]
|
225
|
+
def set_readline_output
|
226
|
+
return if @readline_output
|
227
|
+
if piping?
|
228
|
+
@readline_output = (Readline.output = Pry.config.output)
|
229
|
+
end
|
230
|
+
end
|
201
231
|
end
|
202
232
|
end
|
data/lib/pry/repl_file_loader.rb
CHANGED
@@ -13,7 +13,7 @@ class Pry
|
|
13
13
|
class REPLFileLoader
|
14
14
|
def initialize(file_name)
|
15
15
|
full_name = File.expand_path(file_name)
|
16
|
-
raise RuntimeError, "No such file: #{full_name}" if !File.
|
16
|
+
raise RuntimeError, "No such file: #{full_name}" if !File.exist?(full_name)
|
17
17
|
|
18
18
|
define_additional_commands
|
19
19
|
@content = File.read(full_name)
|
data/lib/pry/rubygem.rb
CHANGED
@@ -57,7 +57,9 @@ class Pry
|
|
57
57
|
# @param [String] name
|
58
58
|
# @return [void]
|
59
59
|
def install(name)
|
60
|
-
|
60
|
+
require 'rubygems/dependency_installer'
|
61
|
+
gem_config = Gem.configuration['gem']
|
62
|
+
gemrc_opts = (gem_config.nil? ? "" : gem_config.split(' '))
|
61
63
|
destination = if gemrc_opts.include?('--user-install')
|
62
64
|
Gem.user_dir
|
63
65
|
elsif File.writable?(Gem.dir)
|
data/lib/pry/slop.rb
ADDED
@@ -0,0 +1,661 @@
|
|
1
|
+
class Pry::Slop
|
2
|
+
require_relative 'slop/option'
|
3
|
+
require_relative 'slop/commands'
|
4
|
+
include Enumerable
|
5
|
+
VERSION = '3.4.0'
|
6
|
+
|
7
|
+
# The main Error class, all Exception classes inherit from this class.
|
8
|
+
class Error < StandardError; end
|
9
|
+
|
10
|
+
# Raised when an option argument is expected but none are given.
|
11
|
+
class MissingArgumentError < Error; end
|
12
|
+
|
13
|
+
# Raised when an option is expected/required but not present.
|
14
|
+
class MissingOptionError < Error; end
|
15
|
+
|
16
|
+
# Raised when an argument does not match its intended match constraint.
|
17
|
+
class InvalidArgumentError < Error; end
|
18
|
+
|
19
|
+
# Raised when an invalid option is found and the strict flag is enabled.
|
20
|
+
class InvalidOptionError < Error; end
|
21
|
+
|
22
|
+
# Raised when an invalid command is found and the strict flag is enabled.
|
23
|
+
class InvalidCommandError < Error; end
|
24
|
+
|
25
|
+
# Returns a default Hash of configuration options this Slop instance uses.
|
26
|
+
DEFAULT_OPTIONS = {
|
27
|
+
:strict => false,
|
28
|
+
:help => false,
|
29
|
+
:banner => nil,
|
30
|
+
:ignore_case => false,
|
31
|
+
:autocreate => false,
|
32
|
+
:arguments => false,
|
33
|
+
:optional_arguments => false,
|
34
|
+
:multiple_switches => true,
|
35
|
+
:longest_flag => 0
|
36
|
+
}
|
37
|
+
|
38
|
+
class << self
|
39
|
+
|
40
|
+
# items - The Array of items to extract options from (default: ARGV).
|
41
|
+
# config - The Hash of configuration options to send to Slop.new().
|
42
|
+
# block - An optional block used to add options.
|
43
|
+
#
|
44
|
+
# Examples:
|
45
|
+
#
|
46
|
+
# Slop.parse(ARGV, :help => true) do
|
47
|
+
# on '-n', '--name', 'Your username', :argument => true
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# Returns a new instance of Slop.
|
51
|
+
def parse(items = ARGV, config = {}, &block)
|
52
|
+
parse! items.dup, config, &block
|
53
|
+
end
|
54
|
+
|
55
|
+
# items - The Array of items to extract options from (default: ARGV).
|
56
|
+
# config - The Hash of configuration options to send to Slop.new().
|
57
|
+
# block - An optional block used to add options.
|
58
|
+
#
|
59
|
+
# Returns a new instance of Slop.
|
60
|
+
def parse!(items = ARGV, config = {}, &block)
|
61
|
+
config, items = items, ARGV if items.is_a?(Hash) && config.empty?
|
62
|
+
slop = Pry::Slop.new config, &block
|
63
|
+
slop.parse! items
|
64
|
+
slop
|
65
|
+
end
|
66
|
+
|
67
|
+
# Build a Slop object from a option specification.
|
68
|
+
#
|
69
|
+
# This allows you to design your options via a simple String rather
|
70
|
+
# than programatically. Do note though that with this method, you're
|
71
|
+
# unable to pass any advanced options to the on() method when creating
|
72
|
+
# options.
|
73
|
+
#
|
74
|
+
# string - The optspec String
|
75
|
+
# config - A Hash of configuration options to pass to Slop.new
|
76
|
+
#
|
77
|
+
# Examples:
|
78
|
+
#
|
79
|
+
# opts = Slop.optspec(<<-SPEC)
|
80
|
+
# ruby foo.rb [options]
|
81
|
+
# ---
|
82
|
+
# n,name= Your name
|
83
|
+
# a,age= Your age
|
84
|
+
# A,auth Sign in with auth
|
85
|
+
# p,passcode= Your secret pass code
|
86
|
+
# SPEC
|
87
|
+
#
|
88
|
+
# opts.fetch_option(:name).description #=> "Your name"
|
89
|
+
#
|
90
|
+
# Returns a new instance of Slop.
|
91
|
+
def optspec(string, config = {})
|
92
|
+
config[:banner], optspec = string.split(/^--+$/, 2) if string[/^--+$/]
|
93
|
+
lines = optspec.split("\n").reject(&:empty?)
|
94
|
+
opts = Slop.new(config)
|
95
|
+
|
96
|
+
lines.each do |line|
|
97
|
+
opt, description = line.split(' ', 2)
|
98
|
+
short, long = opt.split(',').map { |s| s.sub(/\A--?/, '') }
|
99
|
+
opt = opts.on(short, long, description)
|
100
|
+
|
101
|
+
if long && long.end_with?('=')
|
102
|
+
long.sub!(/\=$/, '')
|
103
|
+
opt.config[:argument] = true
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
opts
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
# The Hash of configuration options for this Slop instance.
|
113
|
+
attr_reader :config
|
114
|
+
|
115
|
+
# The Array of Slop::Option objects tied to this Slop instance.
|
116
|
+
attr_reader :options
|
117
|
+
|
118
|
+
# Create a new instance of Slop and optionally build options via a block.
|
119
|
+
#
|
120
|
+
# config - A Hash of configuration options.
|
121
|
+
# block - An optional block used to specify options.
|
122
|
+
def initialize(config = {}, &block)
|
123
|
+
@config = DEFAULT_OPTIONS.merge(config)
|
124
|
+
@options = []
|
125
|
+
@commands = {}
|
126
|
+
@trash = []
|
127
|
+
@triggered_options = []
|
128
|
+
@unknown_options = []
|
129
|
+
@callbacks = {}
|
130
|
+
@separators = {}
|
131
|
+
@runner = nil
|
132
|
+
|
133
|
+
if block_given?
|
134
|
+
block.arity == 1 ? yield(self) : instance_eval(&block)
|
135
|
+
end
|
136
|
+
|
137
|
+
if config[:help]
|
138
|
+
on('-h', '--help', 'Display this help message.', :tail => true) do
|
139
|
+
$stderr.puts help
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Is strict mode enabled?
|
145
|
+
#
|
146
|
+
# Returns true if strict mode is enabled, false otherwise.
|
147
|
+
def strict?
|
148
|
+
config[:strict]
|
149
|
+
end
|
150
|
+
|
151
|
+
# Set the banner.
|
152
|
+
#
|
153
|
+
# banner - The String to set the banner.
|
154
|
+
def banner=(banner)
|
155
|
+
config[:banner] = banner
|
156
|
+
end
|
157
|
+
|
158
|
+
# Get or set the banner.
|
159
|
+
#
|
160
|
+
# banner - The String to set the banner.
|
161
|
+
#
|
162
|
+
# Returns the banner String.
|
163
|
+
def banner(banner = nil)
|
164
|
+
config[:banner] = banner if banner
|
165
|
+
config[:banner]
|
166
|
+
end
|
167
|
+
|
168
|
+
# Set the description (used for commands).
|
169
|
+
#
|
170
|
+
# desc - The String to set the description.
|
171
|
+
def description=(desc)
|
172
|
+
config[:description] = desc
|
173
|
+
end
|
174
|
+
|
175
|
+
# Get or set the description (used for commands).
|
176
|
+
#
|
177
|
+
# desc - The String to set the description.
|
178
|
+
#
|
179
|
+
# Returns the description String.
|
180
|
+
def description(desc = nil)
|
181
|
+
config[:description] = desc if desc
|
182
|
+
config[:description]
|
183
|
+
end
|
184
|
+
|
185
|
+
# Add a new command.
|
186
|
+
#
|
187
|
+
# command - The Symbol or String used to identify this command.
|
188
|
+
# options - A Hash of configuration options (see Slop::new)
|
189
|
+
#
|
190
|
+
# Returns a new instance of Slop mapped to this command.
|
191
|
+
def command(command, options = {}, &block)
|
192
|
+
@commands[command.to_s] = Pry::Slop.new(options, &block)
|
193
|
+
end
|
194
|
+
|
195
|
+
# Parse a list of items, executing and gathering options along the way.
|
196
|
+
#
|
197
|
+
# items - The Array of items to extract options from (default: ARGV).
|
198
|
+
# block - An optional block which when used will yield non options.
|
199
|
+
#
|
200
|
+
# Returns an Array of original items.
|
201
|
+
def parse(items = ARGV, &block)
|
202
|
+
parse! items.dup, &block
|
203
|
+
items
|
204
|
+
end
|
205
|
+
|
206
|
+
# Parse a list of items, executing and gathering options along the way.
|
207
|
+
# unlike parse() this method will remove any options and option arguments
|
208
|
+
# from the original Array.
|
209
|
+
#
|
210
|
+
# items - The Array of items to extract options from (default: ARGV).
|
211
|
+
# block - An optional block which when used will yield non options.
|
212
|
+
#
|
213
|
+
# Returns an Array of original items with options removed.
|
214
|
+
def parse!(items = ARGV, &block)
|
215
|
+
if items.empty? && @callbacks[:empty]
|
216
|
+
@callbacks[:empty].each { |cb| cb.call(self) }
|
217
|
+
return items
|
218
|
+
end
|
219
|
+
|
220
|
+
if cmd = @commands[items[0]]
|
221
|
+
return cmd.parse! items[1..-1]
|
222
|
+
end
|
223
|
+
|
224
|
+
items.each_with_index do |item, index|
|
225
|
+
@trash << index && break if item == '--'
|
226
|
+
autocreate(items, index) if config[:autocreate]
|
227
|
+
process_item(items, index, &block) unless @trash.include?(index)
|
228
|
+
end
|
229
|
+
items.reject!.with_index { |item, index| @trash.include?(index) }
|
230
|
+
|
231
|
+
missing_options = options.select { |opt| opt.required? && opt.count < 1 }
|
232
|
+
if missing_options.any?
|
233
|
+
raise MissingOptionError,
|
234
|
+
"Missing required option(s): #{missing_options.map(&:key).join(', ')}"
|
235
|
+
end
|
236
|
+
|
237
|
+
if @unknown_options.any?
|
238
|
+
raise InvalidOptionError, "Unknown options #{@unknown_options.join(', ')}"
|
239
|
+
end
|
240
|
+
|
241
|
+
if @triggered_options.empty? && @callbacks[:no_options]
|
242
|
+
@callbacks[:no_options].each { |cb| cb.call(self) }
|
243
|
+
end
|
244
|
+
|
245
|
+
@runner.call(self, items) if @runner.respond_to?(:call)
|
246
|
+
|
247
|
+
items
|
248
|
+
end
|
249
|
+
|
250
|
+
# Add an Option.
|
251
|
+
#
|
252
|
+
# objects - An Array with an optional Hash as the last element.
|
253
|
+
#
|
254
|
+
# Examples:
|
255
|
+
#
|
256
|
+
# on '-u', '--username=', 'Your username'
|
257
|
+
# on :v, :verbose, 'Enable verbose mode'
|
258
|
+
#
|
259
|
+
# Returns the created instance of Slop::Option.
|
260
|
+
def on(*objects, &block)
|
261
|
+
option = build_option(objects, &block)
|
262
|
+
options << option
|
263
|
+
option
|
264
|
+
end
|
265
|
+
alias option on
|
266
|
+
alias opt on
|
267
|
+
|
268
|
+
# Fetch an options argument value.
|
269
|
+
#
|
270
|
+
# key - The Symbol or String option short or long flag.
|
271
|
+
#
|
272
|
+
# Returns the Object value for this option, or nil.
|
273
|
+
def [](key)
|
274
|
+
option = fetch_option(key)
|
275
|
+
option.value if option
|
276
|
+
end
|
277
|
+
alias get []
|
278
|
+
|
279
|
+
# Returns a new Hash with option flags as keys and option values as values.
|
280
|
+
#
|
281
|
+
# include_commands - If true, merge options from all sub-commands.
|
282
|
+
def to_hash(include_commands = false)
|
283
|
+
hash = Hash[options.map { |opt| [opt.key.to_sym, opt.value] }]
|
284
|
+
if include_commands
|
285
|
+
@commands.each { |cmd, opts| hash.merge!(cmd.to_sym => opts.to_hash) }
|
286
|
+
end
|
287
|
+
hash
|
288
|
+
end
|
289
|
+
alias to_h to_hash
|
290
|
+
|
291
|
+
# Enumerable interface. Yields each Slop::Option.
|
292
|
+
def each(&block)
|
293
|
+
options.each(&block)
|
294
|
+
end
|
295
|
+
|
296
|
+
# Specify code to be executed when these options are parsed.
|
297
|
+
#
|
298
|
+
# callable - An object responding to a call method.
|
299
|
+
#
|
300
|
+
# yields - The instance of Slop parsing these options
|
301
|
+
# An Array of unparsed arguments
|
302
|
+
#
|
303
|
+
# Example:
|
304
|
+
#
|
305
|
+
# Slop.parse do
|
306
|
+
# on :v, :verbose
|
307
|
+
#
|
308
|
+
# run do |opts, args|
|
309
|
+
# puts "Arguments: #{args.inspect}" if opts.verbose?
|
310
|
+
# end
|
311
|
+
# end
|
312
|
+
def run(callable = nil, &block)
|
313
|
+
@runner = callable || block
|
314
|
+
unless @runner.respond_to?(:call)
|
315
|
+
raise ArgumentError, "You must specify a callable object or a block to #run"
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
# Check for an options presence.
|
320
|
+
#
|
321
|
+
# Examples:
|
322
|
+
#
|
323
|
+
# opts.parse %w( --foo )
|
324
|
+
# opts.present?(:foo) #=> true
|
325
|
+
# opts.present?(:bar) #=> false
|
326
|
+
#
|
327
|
+
# Returns true if all of the keys are present in the parsed arguments.
|
328
|
+
def present?(*keys)
|
329
|
+
keys.all? { |key| (opt = fetch_option(key)) && opt.count > 0 }
|
330
|
+
end
|
331
|
+
|
332
|
+
# Override this method so we can check if an option? method exists.
|
333
|
+
#
|
334
|
+
# Returns true if this option key exists in our list of options.
|
335
|
+
def respond_to_missing?(method_name, include_all=false)
|
336
|
+
options.any? { |o| o.key == method_name.to_s.chop } || super
|
337
|
+
end
|
338
|
+
|
339
|
+
# Fetch a list of options which were missing from the parsed list.
|
340
|
+
#
|
341
|
+
# Examples:
|
342
|
+
#
|
343
|
+
# opts = Slop.new do
|
344
|
+
# on :n, :name=
|
345
|
+
# on :p, :password=
|
346
|
+
# end
|
347
|
+
#
|
348
|
+
# opts.parse %w[ --name Lee ]
|
349
|
+
# opts.missing #=> ['password']
|
350
|
+
#
|
351
|
+
# Returns an Array of Strings representing missing options.
|
352
|
+
def missing
|
353
|
+
(options - @triggered_options).map(&:key)
|
354
|
+
end
|
355
|
+
|
356
|
+
# Fetch a Slop::Option object.
|
357
|
+
#
|
358
|
+
# key - The Symbol or String option key.
|
359
|
+
#
|
360
|
+
# Examples:
|
361
|
+
#
|
362
|
+
# opts.on(:foo, 'Something fooey', :argument => :optional)
|
363
|
+
# opt = opts.fetch_option(:foo)
|
364
|
+
# opt.class #=> Slop::Option
|
365
|
+
# opt.accepts_optional_argument? #=> true
|
366
|
+
#
|
367
|
+
# Returns an Option or nil if none were found.
|
368
|
+
def fetch_option(key)
|
369
|
+
options.find { |option| [option.long, option.short].include?(clean(key)) }
|
370
|
+
end
|
371
|
+
|
372
|
+
# Fetch a Slop object associated with this command.
|
373
|
+
#
|
374
|
+
# command - The String or Symbol name of the command.
|
375
|
+
#
|
376
|
+
# Examples:
|
377
|
+
#
|
378
|
+
# opts.command :foo do
|
379
|
+
# on :v, :verbose, 'Enable verbose mode'
|
380
|
+
# end
|
381
|
+
#
|
382
|
+
# # ruby run.rb foo -v
|
383
|
+
# opts.fetch_command(:foo).verbose? #=> true
|
384
|
+
def fetch_command(command)
|
385
|
+
@commands[command.to_s]
|
386
|
+
end
|
387
|
+
|
388
|
+
# Add a callback.
|
389
|
+
#
|
390
|
+
# label - The Symbol identifier to attach this callback.
|
391
|
+
#
|
392
|
+
# Returns nothing.
|
393
|
+
def add_callback(label, &block)
|
394
|
+
(@callbacks[label] ||= []) << block
|
395
|
+
end
|
396
|
+
|
397
|
+
# Add string separators between options.
|
398
|
+
#
|
399
|
+
# text - The String text to print.
|
400
|
+
def separator(text)
|
401
|
+
if @separators[options.size]
|
402
|
+
@separators[options.size] << "\n#{text}"
|
403
|
+
else
|
404
|
+
@separators[options.size] = text
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
# Print a handy Slop help string.
|
409
|
+
#
|
410
|
+
# Returns the banner followed by available option help strings.
|
411
|
+
def to_s
|
412
|
+
heads = options.reject(&:tail?)
|
413
|
+
tails = (options - heads)
|
414
|
+
opts = (heads + tails).select(&:help).map(&:to_s)
|
415
|
+
optstr = opts.each_with_index.map { |o, i|
|
416
|
+
(str = @separators[i + 1]) ? [o, str].join("\n") : o
|
417
|
+
}.join("\n")
|
418
|
+
|
419
|
+
if @commands.any?
|
420
|
+
optstr << "\n" if !optstr.empty?
|
421
|
+
optstr << "\nAvailable commands:\n\n"
|
422
|
+
optstr << commands_to_help
|
423
|
+
optstr << "\n\nSee `<command> --help` for more information on a specific command."
|
424
|
+
end
|
425
|
+
|
426
|
+
banner = config[:banner]
|
427
|
+
banner = "Usage: #{File.basename($0, '.*')}#{' [command]' if @commands.any?} [options]" if banner.nil?
|
428
|
+
if banner
|
429
|
+
"#{banner}\n#{@separators[0] ? "#{@separators[0]}\n" : ''}#{optstr}"
|
430
|
+
else
|
431
|
+
optstr
|
432
|
+
end
|
433
|
+
end
|
434
|
+
alias help to_s
|
435
|
+
|
436
|
+
private
|
437
|
+
|
438
|
+
# Convenience method for present?(:option).
|
439
|
+
#
|
440
|
+
# Examples:
|
441
|
+
#
|
442
|
+
# opts.parse %( --verbose )
|
443
|
+
# opts.verbose? #=> true
|
444
|
+
# opts.other? #=> false
|
445
|
+
#
|
446
|
+
# Returns true if this option is present. If this method does not end
|
447
|
+
# with a ? character it will instead call super().
|
448
|
+
def method_missing(method, *args, &block)
|
449
|
+
meth = method.to_s
|
450
|
+
if meth.end_with?('?')
|
451
|
+
meth.chop!
|
452
|
+
present?(meth) || present?(meth.gsub('_', '-'))
|
453
|
+
else
|
454
|
+
super
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
# Process a list item, figure out if it's an option, execute any
|
459
|
+
# callbacks, assign any option arguments, and do some sanity checks.
|
460
|
+
#
|
461
|
+
# items - The Array of items to process.
|
462
|
+
# index - The current Integer index of the item we want to process.
|
463
|
+
# block - An optional block which when passed will yield non options.
|
464
|
+
#
|
465
|
+
# Returns nothing.
|
466
|
+
def process_item(items, index, &block)
|
467
|
+
return unless item = items[index]
|
468
|
+
option, argument = extract_option(item) if item.start_with?('-')
|
469
|
+
|
470
|
+
if option
|
471
|
+
option.count += 1 unless item.start_with?('--no-')
|
472
|
+
option.count += 1 if option.key[0, 3] == "no-"
|
473
|
+
@trash << index
|
474
|
+
@triggered_options << option
|
475
|
+
|
476
|
+
if option.expects_argument?
|
477
|
+
argument ||= items.at(index + 1)
|
478
|
+
|
479
|
+
if !argument || argument =~ /\A--?[a-zA-Z][a-zA-Z0-9_-]*\z/
|
480
|
+
raise MissingArgumentError, "#{option.key} expects an argument"
|
481
|
+
end
|
482
|
+
|
483
|
+
execute_option(option, argument, index, item)
|
484
|
+
elsif option.accepts_optional_argument?
|
485
|
+
argument ||= items.at(index + 1)
|
486
|
+
|
487
|
+
if argument && argument =~ /\A([^\-?]|-\d)+/
|
488
|
+
execute_option(option, argument, index, item)
|
489
|
+
else
|
490
|
+
option.call(nil)
|
491
|
+
end
|
492
|
+
elsif config[:multiple_switches] && argument
|
493
|
+
execute_multiple_switches(option, argument, index)
|
494
|
+
else
|
495
|
+
option.value = option.count > 0
|
496
|
+
option.call(nil)
|
497
|
+
end
|
498
|
+
else
|
499
|
+
@unknown_options << item if strict? && item =~ /\A--?/
|
500
|
+
block.call(item) if block && !@trash.include?(index)
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
# Execute an option, firing off callbacks and assigning arguments.
|
505
|
+
#
|
506
|
+
# option - The Slop::Option object found by #process_item.
|
507
|
+
# argument - The argument Object to assign to this option.
|
508
|
+
# index - The current Integer index of the object we're processing.
|
509
|
+
# item - The optional String item we're processing.
|
510
|
+
#
|
511
|
+
# Returns nothing.
|
512
|
+
def execute_option(option, argument, index, item = nil)
|
513
|
+
if !option
|
514
|
+
if config[:multiple_switches] && strict?
|
515
|
+
raise InvalidOptionError, "Unknown option -#{item}"
|
516
|
+
end
|
517
|
+
return
|
518
|
+
end
|
519
|
+
|
520
|
+
if argument
|
521
|
+
unless item && item.end_with?("=#{argument}")
|
522
|
+
@trash << index + 1 unless option.argument_in_value
|
523
|
+
end
|
524
|
+
option.value = argument
|
525
|
+
else
|
526
|
+
option.value = option.count > 0
|
527
|
+
end
|
528
|
+
|
529
|
+
if option.match? && !argument.match(option.config[:match])
|
530
|
+
raise InvalidArgumentError, "#{argument} is an invalid argument"
|
531
|
+
end
|
532
|
+
|
533
|
+
option.call(option.value)
|
534
|
+
end
|
535
|
+
|
536
|
+
# Execute a `-abc` type option where a, b and c are all options. This
|
537
|
+
# method is only executed if the multiple_switches argument is true.
|
538
|
+
#
|
539
|
+
# option - The first Option object.
|
540
|
+
# argument - The argument to this option. (Split into multiple Options).
|
541
|
+
# index - The index of the current item being processed.
|
542
|
+
#
|
543
|
+
# Returns nothing.
|
544
|
+
def execute_multiple_switches(option, argument, index)
|
545
|
+
execute_option(option, nil, index)
|
546
|
+
argument.split('').each do |key|
|
547
|
+
next unless opt = fetch_option(key)
|
548
|
+
opt.count += 1
|
549
|
+
execute_option(opt, nil, index, key)
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
# Extract an option from a flag.
|
554
|
+
#
|
555
|
+
# flag - The flag key used to extract an option.
|
556
|
+
#
|
557
|
+
# Returns an Array of [option, argument].
|
558
|
+
def extract_option(flag)
|
559
|
+
option = fetch_option(flag)
|
560
|
+
option ||= fetch_option(flag.downcase) if config[:ignore_case]
|
561
|
+
option ||= fetch_option(flag.gsub(/([^-])-/, '\1_'))
|
562
|
+
|
563
|
+
unless option
|
564
|
+
case flag
|
565
|
+
when /\A--?([^=]+)=(.+)\z/, /\A-([a-zA-Z])(.+)\z/, /\A--no-(.+)\z/
|
566
|
+
option, argument = fetch_option($1), ($2 || false)
|
567
|
+
option.argument_in_value = true if option
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
[option, argument]
|
572
|
+
end
|
573
|
+
|
574
|
+
# Autocreate an option on the fly. See the :autocreate Slop config option.
|
575
|
+
#
|
576
|
+
# items - The Array of items we're parsing.
|
577
|
+
# index - The current Integer index for the item we're processing.
|
578
|
+
#
|
579
|
+
# Returns nothing.
|
580
|
+
def autocreate(items, index)
|
581
|
+
flag = items[index]
|
582
|
+
if !fetch_option(flag) && !@trash.include?(index)
|
583
|
+
option = build_option(Array(flag))
|
584
|
+
argument = items[index + 1]
|
585
|
+
option.config[:argument] = (argument && argument !~ /\A--?/)
|
586
|
+
option.config[:autocreated] = true
|
587
|
+
options << option
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
# Build an option from a list of objects.
|
592
|
+
#
|
593
|
+
# objects - An Array of objects used to build this option.
|
594
|
+
#
|
595
|
+
# Returns a new instance of Slop::Option.
|
596
|
+
def build_option(objects, &block)
|
597
|
+
config = {}
|
598
|
+
config[:argument] = true if @config[:arguments]
|
599
|
+
config[:optional_argument] = true if @config[:optional_arguments]
|
600
|
+
|
601
|
+
if objects.last.is_a?(Hash)
|
602
|
+
config.merge!(objects.last)
|
603
|
+
objects.pop
|
604
|
+
end
|
605
|
+
short = extract_short_flag(objects, config)
|
606
|
+
long = extract_long_flag(objects, config)
|
607
|
+
desc = objects[0].respond_to?(:to_str) ? objects.shift : nil
|
608
|
+
|
609
|
+
Option.new(self, short, long, desc, config, &block)
|
610
|
+
end
|
611
|
+
|
612
|
+
# Extract the short flag from an item.
|
613
|
+
#
|
614
|
+
# objects - The Array of objects passed from #build_option.
|
615
|
+
# config - The Hash of configuration options built in #build_option.
|
616
|
+
def extract_short_flag(objects, config)
|
617
|
+
flag = clean(objects.first)
|
618
|
+
|
619
|
+
if flag.size == 2 && flag.end_with?('=')
|
620
|
+
config[:argument] ||= true
|
621
|
+
flag.chop!
|
622
|
+
end
|
623
|
+
|
624
|
+
if flag.size == 1
|
625
|
+
objects.shift
|
626
|
+
flag
|
627
|
+
end
|
628
|
+
end
|
629
|
+
|
630
|
+
# Extract the long flag from an item.
|
631
|
+
#
|
632
|
+
# objects - The Array of objects passed from #build_option.
|
633
|
+
# config - The Hash of configuration options built in #build_option.
|
634
|
+
def extract_long_flag(objects, config)
|
635
|
+
flag = objects.first.to_s
|
636
|
+
if flag =~ /\A(?:--?)?[a-zA-Z][a-zA-Z0-9_-]+\=?\??\z/
|
637
|
+
config[:argument] ||= true if flag.end_with?('=')
|
638
|
+
config[:optional_argument] = true if flag.end_with?('=?')
|
639
|
+
objects.shift
|
640
|
+
clean(flag).sub(/\=\??\z/, '')
|
641
|
+
end
|
642
|
+
end
|
643
|
+
|
644
|
+
# Remove any leading -- characters from a string.
|
645
|
+
#
|
646
|
+
# object - The Object we want to cast to a String and clean.
|
647
|
+
#
|
648
|
+
# Returns the newly cleaned String with leading -- characters removed.
|
649
|
+
def clean(object)
|
650
|
+
object.to_s.sub(/\A--?/, '')
|
651
|
+
end
|
652
|
+
|
653
|
+
def commands_to_help
|
654
|
+
padding = 0
|
655
|
+
@commands.each { |c, _| padding = c.size if c.size > padding }
|
656
|
+
@commands.map do |cmd, opts|
|
657
|
+
" #{cmd}#{' ' * (padding - cmd.size)} #{opts.description}"
|
658
|
+
end.join("\n")
|
659
|
+
end
|
660
|
+
|
661
|
+
end
|