pry 0.10.3 → 0.14.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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +439 -16
- data/LICENSE +1 -1
- data/README.md +362 -302
- data/bin/pry +4 -7
- data/lib/pry/basic_object.rb +10 -0
- data/lib/pry/block_command.rb +22 -0
- data/lib/pry/class_command.rb +194 -0
- data/lib/pry/cli.rb +84 -97
- data/lib/pry/code/code_file.rb +37 -26
- data/lib/pry/code/code_range.rb +7 -5
- data/lib/pry/code/loc.rb +26 -13
- data/lib/pry/code.rb +42 -31
- data/lib/pry/code_object.rb +53 -28
- data/lib/pry/color_printer.rb +46 -35
- data/lib/pry/command.rb +197 -369
- data/lib/pry/command_set.rb +89 -114
- data/lib/pry/command_state.rb +31 -0
- data/lib/pry/commands/amend_line.rb +86 -82
- data/lib/pry/commands/bang.rb +18 -14
- data/lib/pry/commands/bang_pry.rb +15 -11
- data/lib/pry/commands/cat/abstract_formatter.rb +23 -18
- data/lib/pry/commands/cat/exception_formatter.rb +85 -72
- data/lib/pry/commands/cat/file_formatter.rb +56 -46
- data/lib/pry/commands/cat/input_expression_formatter.rb +35 -30
- data/lib/pry/commands/cat.rb +62 -54
- data/lib/pry/commands/cd.rb +40 -35
- data/lib/pry/commands/change_inspector.rb +29 -22
- data/lib/pry/commands/change_prompt.rb +48 -23
- data/lib/pry/commands/clear_screen.rb +20 -0
- data/lib/pry/commands/code_collector.rb +148 -131
- data/lib/pry/commands/disable_pry.rb +23 -19
- data/lib/pry/commands/easter_eggs.rb +23 -34
- data/lib/pry/commands/edit/exception_patcher.rb +21 -17
- data/lib/pry/commands/edit/file_and_line_locator.rb +34 -23
- data/lib/pry/commands/edit.rb +185 -157
- data/lib/pry/commands/exit.rb +40 -35
- data/lib/pry/commands/exit_all.rb +24 -20
- data/lib/pry/commands/exit_program.rb +20 -16
- data/lib/pry/commands/find_method.rb +168 -162
- data/lib/pry/commands/fix_indent.rb +16 -12
- data/lib/pry/commands/help.rb +140 -133
- data/lib/pry/commands/hist.rb +151 -149
- data/lib/pry/commands/import_set.rb +20 -15
- data/lib/pry/commands/jump_to.rb +25 -21
- data/lib/pry/commands/list_inspectors.rb +35 -28
- data/lib/pry/commands/ls/constants.rb +59 -31
- data/lib/pry/commands/ls/formatter.rb +42 -36
- data/lib/pry/commands/ls/globals.rb +38 -36
- data/lib/pry/commands/ls/grep.rb +17 -15
- data/lib/pry/commands/ls/instance_vars.rb +29 -28
- data/lib/pry/commands/ls/interrogatable.rb +18 -12
- data/lib/pry/commands/ls/jruby_hacks.rb +47 -41
- data/lib/pry/commands/ls/local_names.rb +26 -24
- data/lib/pry/commands/ls/local_vars.rb +38 -30
- data/lib/pry/commands/ls/ls_entity.rb +47 -52
- data/lib/pry/commands/ls/methods.rb +49 -51
- data/lib/pry/commands/ls/methods_helper.rb +46 -42
- data/lib/pry/commands/ls/self_methods.rb +23 -21
- data/lib/pry/commands/ls.rb +124 -103
- data/lib/pry/commands/nesting.rb +21 -17
- data/lib/pry/commands/play.rb +92 -82
- data/lib/pry/commands/pry_backtrace.rb +22 -17
- data/lib/pry/commands/pry_version.rb +15 -11
- data/lib/pry/commands/raise_up.rb +33 -27
- data/lib/pry/commands/reload_code.rb +60 -48
- data/lib/pry/commands/reset.rb +16 -12
- data/lib/pry/commands/ri.rb +57 -42
- data/lib/pry/commands/save_file.rb +45 -43
- data/lib/pry/commands/shell_command.rb +56 -29
- data/lib/pry/commands/shell_mode.rb +22 -18
- data/lib/pry/commands/show_doc.rb +80 -70
- data/lib/pry/commands/show_info.rb +194 -155
- data/lib/pry/commands/show_input.rb +16 -11
- data/lib/pry/commands/show_source.rb +110 -42
- data/lib/pry/commands/stat.rb +35 -31
- data/lib/pry/commands/switch_to.rb +21 -15
- data/lib/pry/commands/toggle_color.rb +20 -16
- data/lib/pry/commands/watch_expression/expression.rb +32 -27
- data/lib/pry/commands/watch_expression.rb +89 -84
- data/lib/pry/commands/whereami.rb +156 -141
- data/lib/pry/commands/wtf.rb +78 -40
- data/lib/pry/config/attributable.rb +22 -0
- data/lib/pry/config/lazy_value.rb +29 -0
- data/lib/pry/config/memoized_value.rb +34 -0
- data/lib/pry/config/value.rb +24 -0
- data/lib/pry/config.rb +310 -20
- data/lib/pry/control_d_handler.rb +28 -0
- data/lib/pry/core_extensions.rb +22 -9
- data/lib/pry/editor.rb +56 -34
- data/lib/pry/env.rb +18 -0
- data/lib/pry/exception_handler.rb +43 -0
- data/lib/pry/exceptions.rb +13 -18
- data/lib/pry/forwardable.rb +27 -0
- data/lib/pry/helpers/base_helpers.rb +20 -62
- data/lib/pry/helpers/command_helpers.rb +52 -62
- data/lib/pry/helpers/documentation_helpers.rb +21 -12
- data/lib/pry/helpers/options_helpers.rb +15 -8
- data/lib/pry/helpers/platform.rb +55 -0
- data/lib/pry/helpers/table.rb +44 -32
- data/lib/pry/helpers/text.rb +96 -85
- data/lib/pry/helpers.rb +3 -0
- data/lib/pry/history.rb +81 -55
- data/lib/pry/hooks.rb +60 -110
- data/lib/pry/indent.rb +74 -68
- data/lib/pry/input_completer.rb +199 -158
- data/lib/pry/input_lock.rb +7 -10
- data/lib/pry/inspector.rb +36 -24
- data/lib/pry/last_exception.rb +45 -45
- data/lib/pry/method/disowned.rb +19 -5
- data/lib/pry/method/patcher.rb +14 -8
- data/lib/pry/method/weird_method_locator.rb +79 -45
- data/lib/pry/method.rb +178 -124
- data/lib/pry/object_path.rb +37 -28
- data/lib/pry/output.rb +102 -16
- data/lib/pry/pager.rb +187 -174
- data/lib/pry/prompt.rb +213 -25
- data/lib/pry/pry_class.rb +119 -98
- data/lib/pry/pry_instance.rb +261 -224
- data/lib/pry/repl.rb +83 -29
- data/lib/pry/repl_file_loader.rb +27 -22
- data/lib/pry/ring.rb +89 -0
- data/lib/pry/slop/LICENSE +20 -0
- data/lib/pry/slop/commands.rb +190 -0
- data/lib/pry/slop/option.rb +210 -0
- data/lib/pry/slop.rb +672 -0
- data/lib/pry/syntax_highlighter.rb +26 -0
- data/lib/pry/system_command_handler.rb +17 -0
- data/lib/pry/testable/evalable.rb +24 -0
- data/lib/pry/testable/mockable.rb +22 -0
- data/lib/pry/testable/pry_tester.rb +88 -0
- data/lib/pry/testable/utility.rb +34 -0
- data/lib/pry/testable/variables.rb +52 -0
- data/lib/pry/testable.rb +68 -0
- data/lib/pry/version.rb +3 -1
- data/lib/pry/warning.rb +20 -0
- data/lib/pry/{module_candidate.rb → wrapped_module/candidate.rb} +35 -32
- data/lib/pry/wrapped_module.rb +68 -63
- data/lib/pry.rb +133 -149
- metadata +58 -69
- data/lib/pry/commands/disabled_commands.rb +0 -2
- data/lib/pry/commands/gem_cd.rb +0 -26
- data/lib/pry/commands/gem_install.rb +0 -32
- data/lib/pry/commands/gem_list.rb +0 -33
- data/lib/pry/commands/gem_open.rb +0 -29
- data/lib/pry/commands/gist.rb +0 -101
- data/lib/pry/commands/install_command.rb +0 -53
- data/lib/pry/commands/list_prompts.rb +0 -35
- data/lib/pry/commands/simple_prompt.rb +0 -22
- data/lib/pry/commands.rb +0 -6
- data/lib/pry/config/behavior.rb +0 -139
- data/lib/pry/config/convenience.rb +0 -25
- data/lib/pry/config/default.rb +0 -161
- data/lib/pry/history_array.rb +0 -121
- data/lib/pry/plugins.rb +0 -103
- data/lib/pry/rbx_path.rb +0 -22
- data/lib/pry/rubygem.rb +0 -82
- data/lib/pry/terminal.rb +0 -79
- data/lib/pry/test/helper.rb +0 -170
data/lib/pry/slop.rb
ADDED
@@ -0,0 +1,672 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Pry
|
4
|
+
# rubocop:disable Metrics/ClassLength
|
5
|
+
class Slop
|
6
|
+
require_relative 'slop/option'
|
7
|
+
require_relative 'slop/commands'
|
8
|
+
include Enumerable
|
9
|
+
VERSION = '3.4.0'.freeze
|
10
|
+
|
11
|
+
# The main Error class, all Exception classes inherit from this class.
|
12
|
+
class Error < StandardError; end
|
13
|
+
|
14
|
+
# Raised when an option argument is expected but none are given.
|
15
|
+
class MissingArgumentError < Error; end
|
16
|
+
|
17
|
+
# Raised when an option is expected/required but not present.
|
18
|
+
class MissingOptionError < Error; end
|
19
|
+
|
20
|
+
# Raised when an argument does not match its intended match constraint.
|
21
|
+
class InvalidArgumentError < Error; end
|
22
|
+
|
23
|
+
# Raised when an invalid option is found and the strict flag is enabled.
|
24
|
+
class InvalidOptionError < Error; end
|
25
|
+
|
26
|
+
# Raised when an invalid command is found and the strict flag is enabled.
|
27
|
+
class InvalidCommandError < Error; end
|
28
|
+
|
29
|
+
# Returns a default Hash of configuration options this Slop instance uses.
|
30
|
+
DEFAULT_OPTIONS = {
|
31
|
+
strict: false,
|
32
|
+
help: false,
|
33
|
+
banner: nil,
|
34
|
+
ignore_case: false,
|
35
|
+
autocreate: false,
|
36
|
+
arguments: false,
|
37
|
+
optional_arguments: false,
|
38
|
+
multiple_switches: true,
|
39
|
+
longest_flag: 0
|
40
|
+
}.freeze
|
41
|
+
|
42
|
+
class << self
|
43
|
+
# items - The Array of items to extract options from (default: ARGV).
|
44
|
+
# config - The Hash of configuration options to send to Slop.new().
|
45
|
+
# block - An optional block used to add options.
|
46
|
+
#
|
47
|
+
# Examples:
|
48
|
+
#
|
49
|
+
# Slop.parse(ARGV, :help => true) do
|
50
|
+
# on '-n', '--name', 'Your username', :argument => true
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# Returns a new instance of Slop.
|
54
|
+
def parse(items = ARGV, config = {}, &block)
|
55
|
+
parse! items.dup, config, &block
|
56
|
+
end
|
57
|
+
|
58
|
+
# items - The Array of items to extract options from (default: ARGV).
|
59
|
+
# config - The Hash of configuration options to send to Slop.new().
|
60
|
+
# block - An optional block used to add options.
|
61
|
+
#
|
62
|
+
# Returns a new instance of Slop.
|
63
|
+
def parse!(items = ARGV, config = {}, &block)
|
64
|
+
if items.is_a?(Hash) && config.empty?
|
65
|
+
config = items
|
66
|
+
items = ARGV
|
67
|
+
end
|
68
|
+
slop = Pry::Slop.new config, &block
|
69
|
+
slop.parse! items
|
70
|
+
slop
|
71
|
+
end
|
72
|
+
|
73
|
+
# Build a Slop object from a option specification.
|
74
|
+
#
|
75
|
+
# This allows you to design your options via a simple String rather
|
76
|
+
# than programatically. Do note though that with this method, you're
|
77
|
+
# unable to pass any advanced options to the on() method when creating
|
78
|
+
# options.
|
79
|
+
#
|
80
|
+
# string - The optspec String
|
81
|
+
# config - A Hash of configuration options to pass to Slop.new
|
82
|
+
#
|
83
|
+
# Examples:
|
84
|
+
#
|
85
|
+
# opts = Slop.optspec(<<-SPEC)
|
86
|
+
# ruby foo.rb [options]
|
87
|
+
# ---
|
88
|
+
# n,name= Your name
|
89
|
+
# a,age= Your age
|
90
|
+
# A,auth Sign in with auth
|
91
|
+
# p,passcode= Your secret pass code
|
92
|
+
# SPEC
|
93
|
+
#
|
94
|
+
# opts.fetch_option(:name).description #=> "Your name"
|
95
|
+
#
|
96
|
+
# Returns a new instance of Slop.
|
97
|
+
def optspec(string, config = {})
|
98
|
+
config[:banner], optspec = string.split(/^--+$/, 2) if string[/^--+$/]
|
99
|
+
lines = optspec.split("\n").reject(&:empty?)
|
100
|
+
opts = Slop.new(config)
|
101
|
+
|
102
|
+
lines.each do |line|
|
103
|
+
opt, description = line.split(' ', 2)
|
104
|
+
short, long = opt.split(',').map { |s| s.sub(/\A--?/, '') }
|
105
|
+
opt = opts.on(short, long, description)
|
106
|
+
|
107
|
+
if long && long.end_with?('=')
|
108
|
+
long.sub!(/\=$/, '')
|
109
|
+
opt.config[:argument] = true
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
opts
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# The Hash of configuration options for this Slop instance.
|
118
|
+
attr_reader :config
|
119
|
+
|
120
|
+
# The Array of Slop::Option objects tied to this Slop instance.
|
121
|
+
attr_reader :options
|
122
|
+
|
123
|
+
# Create a new instance of Slop and optionally build options via a block.
|
124
|
+
#
|
125
|
+
# config - A Hash of configuration options.
|
126
|
+
# block - An optional block used to specify options.
|
127
|
+
def initialize(config = {}, &block)
|
128
|
+
@config = DEFAULT_OPTIONS.merge(config)
|
129
|
+
@options = []
|
130
|
+
@commands = {}
|
131
|
+
@trash = []
|
132
|
+
@triggered_options = []
|
133
|
+
@unknown_options = []
|
134
|
+
@callbacks = {}
|
135
|
+
@separators = {}
|
136
|
+
@runner = nil
|
137
|
+
|
138
|
+
if block_given?
|
139
|
+
block.arity == 1 ? yield(self) : instance_eval(&block)
|
140
|
+
end
|
141
|
+
|
142
|
+
return unless config[:help]
|
143
|
+
|
144
|
+
on('-h', '--help', 'Display this help message.', tail: true) do
|
145
|
+
warn help
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# Is strict mode enabled?
|
150
|
+
#
|
151
|
+
# Returns true if strict mode is enabled, false otherwise.
|
152
|
+
def strict?
|
153
|
+
config[:strict]
|
154
|
+
end
|
155
|
+
|
156
|
+
# Set the banner.
|
157
|
+
#
|
158
|
+
# banner - The String to set the banner.
|
159
|
+
def banner=(banner)
|
160
|
+
config[:banner] = banner
|
161
|
+
end
|
162
|
+
|
163
|
+
# Get or set the banner.
|
164
|
+
#
|
165
|
+
# banner - The String to set the banner.
|
166
|
+
#
|
167
|
+
# Returns the banner String.
|
168
|
+
def banner(banner = nil)
|
169
|
+
config[:banner] = banner if banner
|
170
|
+
config[:banner]
|
171
|
+
end
|
172
|
+
|
173
|
+
# Set the description (used for commands).
|
174
|
+
#
|
175
|
+
# desc - The String to set the description.
|
176
|
+
def description=(desc)
|
177
|
+
config[:description] = desc
|
178
|
+
end
|
179
|
+
|
180
|
+
# Get or set the description (used for commands).
|
181
|
+
#
|
182
|
+
# desc - The String to set the description.
|
183
|
+
#
|
184
|
+
# Returns the description String.
|
185
|
+
def description(desc = nil)
|
186
|
+
config[:description] = desc if desc
|
187
|
+
config[:description]
|
188
|
+
end
|
189
|
+
|
190
|
+
# Add a new command.
|
191
|
+
#
|
192
|
+
# command - The Symbol or String used to identify this command.
|
193
|
+
# options - A Hash of configuration options (see Slop::new)
|
194
|
+
#
|
195
|
+
# Returns a new instance of Slop mapped to this command.
|
196
|
+
def command(command, options = {}, &block)
|
197
|
+
@commands[command.to_s] = Pry::Slop.new(options, &block)
|
198
|
+
end
|
199
|
+
|
200
|
+
# Parse a list of items, executing and gathering options along the way.
|
201
|
+
#
|
202
|
+
# items - The Array of items to extract options from (default: ARGV).
|
203
|
+
# block - An optional block which when used will yield non options.
|
204
|
+
#
|
205
|
+
# Returns an Array of original items.
|
206
|
+
def parse(items = ARGV, &block)
|
207
|
+
parse! items.dup, &block
|
208
|
+
items
|
209
|
+
end
|
210
|
+
|
211
|
+
# Parse a list of items, executing and gathering options along the way.
|
212
|
+
# unlike parse() this method will remove any options and option arguments
|
213
|
+
# from the original Array.
|
214
|
+
#
|
215
|
+
# items - The Array of items to extract options from (default: ARGV).
|
216
|
+
# block - An optional block which when used will yield non options.
|
217
|
+
#
|
218
|
+
# Returns an Array of original items with options removed.
|
219
|
+
def parse!(items = ARGV, &block)
|
220
|
+
if items.empty? && @callbacks[:empty]
|
221
|
+
@callbacks[:empty].each { |cb| cb.call(self) }
|
222
|
+
return items
|
223
|
+
end
|
224
|
+
|
225
|
+
if (cmd = @commands[items[0]])
|
226
|
+
return cmd.parse! items[1..-1]
|
227
|
+
end
|
228
|
+
|
229
|
+
items.each_with_index do |item, index|
|
230
|
+
@trash << index && break if item == '--'
|
231
|
+
autocreate(items, index) if config[:autocreate]
|
232
|
+
process_item(items, index, &block) unless @trash.include?(index)
|
233
|
+
end
|
234
|
+
items.reject!.with_index { |_item, index| @trash.include?(index) }
|
235
|
+
|
236
|
+
missing_options = options.select { |opt| opt.required? && opt.count < 1 }
|
237
|
+
if missing_options.any?
|
238
|
+
raise MissingOptionError,
|
239
|
+
"Missing required option(s): #{missing_options.map(&:key).join(', ')}"
|
240
|
+
end
|
241
|
+
|
242
|
+
if @unknown_options.any?
|
243
|
+
raise InvalidOptionError, "Unknown options #{@unknown_options.join(', ')}"
|
244
|
+
end
|
245
|
+
|
246
|
+
if @triggered_options.empty? && @callbacks[:no_options]
|
247
|
+
@callbacks[:no_options].each { |cb| cb.call(self) }
|
248
|
+
end
|
249
|
+
|
250
|
+
@runner.call(self, items) if @runner.respond_to?(:call)
|
251
|
+
|
252
|
+
items
|
253
|
+
end
|
254
|
+
|
255
|
+
# Add an Option.
|
256
|
+
#
|
257
|
+
# objects - An Array with an optional Hash as the last element.
|
258
|
+
#
|
259
|
+
# Examples:
|
260
|
+
#
|
261
|
+
# on '-u', '--username=', 'Your username'
|
262
|
+
# on :v, :verbose, 'Enable verbose mode'
|
263
|
+
#
|
264
|
+
# Returns the created instance of Slop::Option.
|
265
|
+
def on(*objects, &block)
|
266
|
+
option = build_option(objects, &block)
|
267
|
+
options << option
|
268
|
+
option
|
269
|
+
end
|
270
|
+
alias option on
|
271
|
+
alias opt on
|
272
|
+
|
273
|
+
# Fetch an options argument value.
|
274
|
+
#
|
275
|
+
# key - The Symbol or String option short or long flag.
|
276
|
+
#
|
277
|
+
# Returns the Object value for this option, or nil.
|
278
|
+
def [](key)
|
279
|
+
option = fetch_option(key)
|
280
|
+
option.value if option
|
281
|
+
end
|
282
|
+
alias get []
|
283
|
+
|
284
|
+
# Returns a new Hash with option flags as keys and option values as values.
|
285
|
+
#
|
286
|
+
# include_commands - If true, merge options from all sub-commands.
|
287
|
+
def to_hash(include_commands = false)
|
288
|
+
hash = Hash[options.map { |opt| [opt.key.to_sym, opt.value] }]
|
289
|
+
if include_commands
|
290
|
+
@commands.each { |cmd, opts| hash.merge!(cmd.to_sym => opts.to_hash) }
|
291
|
+
end
|
292
|
+
hash
|
293
|
+
end
|
294
|
+
alias to_h to_hash
|
295
|
+
|
296
|
+
# Enumerable interface. Yields each Slop::Option.
|
297
|
+
def each(&block)
|
298
|
+
options.each(&block)
|
299
|
+
end
|
300
|
+
|
301
|
+
# Specify code to be executed when these options are parsed.
|
302
|
+
#
|
303
|
+
# callable - An object responding to a call method.
|
304
|
+
#
|
305
|
+
# yields - The instance of Slop parsing these options
|
306
|
+
# An Array of unparsed arguments
|
307
|
+
#
|
308
|
+
# Example:
|
309
|
+
#
|
310
|
+
# Slop.parse do
|
311
|
+
# on :v, :verbose
|
312
|
+
#
|
313
|
+
# run do |opts, args|
|
314
|
+
# puts "Arguments: #{args.inspect}" if opts.verbose?
|
315
|
+
# end
|
316
|
+
# end
|
317
|
+
def run(callable = nil, &block)
|
318
|
+
@runner = callable || block
|
319
|
+
return if @runner.respond_to?(:call)
|
320
|
+
|
321
|
+
raise ArgumentError, "You must specify a callable object or a block to #run"
|
322
|
+
end
|
323
|
+
|
324
|
+
# Check for an options presence.
|
325
|
+
#
|
326
|
+
# Examples:
|
327
|
+
#
|
328
|
+
# opts.parse %w( --foo )
|
329
|
+
# opts.present?(:foo) #=> true
|
330
|
+
# opts.present?(:bar) #=> false
|
331
|
+
#
|
332
|
+
# Returns true if all of the keys are present in the parsed arguments.
|
333
|
+
def present?(*keys)
|
334
|
+
keys.all? { |key| (opt = fetch_option(key)) && opt.count > 0 }
|
335
|
+
end
|
336
|
+
|
337
|
+
# Override this method so we can check if an option? method exists.
|
338
|
+
#
|
339
|
+
# Returns true if this option key exists in our list of options.
|
340
|
+
def respond_to_missing?(method_name, include_all = false)
|
341
|
+
options.any? { |o| o.key == method_name.to_s.chop } || super
|
342
|
+
end
|
343
|
+
|
344
|
+
# Fetch a list of options which were missing from the parsed list.
|
345
|
+
#
|
346
|
+
# Examples:
|
347
|
+
#
|
348
|
+
# opts = Slop.new do
|
349
|
+
# on :n, :name=
|
350
|
+
# on :p, :password=
|
351
|
+
# end
|
352
|
+
#
|
353
|
+
# opts.parse %w[ --name Lee ]
|
354
|
+
# opts.missing #=> ['password']
|
355
|
+
#
|
356
|
+
# Returns an Array of Strings representing missing options.
|
357
|
+
def missing
|
358
|
+
(options - @triggered_options).map(&:key)
|
359
|
+
end
|
360
|
+
|
361
|
+
# Fetch a Slop::Option object.
|
362
|
+
#
|
363
|
+
# key - The Symbol or String option key.
|
364
|
+
#
|
365
|
+
# Examples:
|
366
|
+
#
|
367
|
+
# opts.on(:foo, 'Something fooey', :argument => :optional)
|
368
|
+
# opt = opts.fetch_option(:foo)
|
369
|
+
# opt.class #=> Slop::Option
|
370
|
+
# opt.accepts_optional_argument? #=> true
|
371
|
+
#
|
372
|
+
# Returns an Option or nil if none were found.
|
373
|
+
def fetch_option(key)
|
374
|
+
options.find { |option| [option.long, option.short].include?(clean(key)) }
|
375
|
+
end
|
376
|
+
|
377
|
+
# Fetch a Slop object associated with this command.
|
378
|
+
#
|
379
|
+
# command - The String or Symbol name of the command.
|
380
|
+
#
|
381
|
+
# Examples:
|
382
|
+
#
|
383
|
+
# opts.command :foo do
|
384
|
+
# on :v, :verbose, 'Enable verbose mode'
|
385
|
+
# end
|
386
|
+
#
|
387
|
+
# # ruby run.rb foo -v
|
388
|
+
# opts.fetch_command(:foo).verbose? #=> true
|
389
|
+
def fetch_command(command)
|
390
|
+
@commands[command.to_s]
|
391
|
+
end
|
392
|
+
|
393
|
+
# Add a callback.
|
394
|
+
#
|
395
|
+
# label - The Symbol identifier to attach this callback.
|
396
|
+
#
|
397
|
+
# Returns nothing.
|
398
|
+
def add_callback(label, &block)
|
399
|
+
(@callbacks[label] ||= []) << block
|
400
|
+
end
|
401
|
+
|
402
|
+
# Add string separators between options.
|
403
|
+
#
|
404
|
+
# text - The String text to print.
|
405
|
+
def separator(text)
|
406
|
+
if @separators[options.size]
|
407
|
+
@separators[options.size] << "\n#{text}"
|
408
|
+
else
|
409
|
+
@separators[options.size] = text
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
# Print a handy Slop help string.
|
414
|
+
#
|
415
|
+
# Returns the banner followed by available option help strings.
|
416
|
+
def to_s
|
417
|
+
heads = options.reject(&:tail?)
|
418
|
+
tails = (options - heads)
|
419
|
+
opts = (heads + tails).select(&:help).map(&:to_s)
|
420
|
+
optstr = opts.each_with_index.map do |o, i|
|
421
|
+
(str = @separators[i + 1]) ? [o, str].join("\n") : o
|
422
|
+
end.join("\n")
|
423
|
+
|
424
|
+
if @commands.any?
|
425
|
+
optstr << "\n" unless optstr.empty?
|
426
|
+
optstr << "\nAvailable commands:\n\n"
|
427
|
+
optstr << commands_to_help
|
428
|
+
optstr << "\n\nSee `<command> --help` for more information on a specific command."
|
429
|
+
end
|
430
|
+
|
431
|
+
banner = config[:banner]
|
432
|
+
banner ||= "Usage: #{File.basename($PROGRAM_NAME, '.*')}" \
|
433
|
+
"#{' [command]' if @commands.any?} [options]"
|
434
|
+
if banner
|
435
|
+
"#{banner}\n#{@separators[0] ? "#{@separators[0]}\n" : ''}#{optstr}"
|
436
|
+
else
|
437
|
+
optstr
|
438
|
+
end
|
439
|
+
end
|
440
|
+
alias help to_s
|
441
|
+
|
442
|
+
private
|
443
|
+
|
444
|
+
# Convenience method for present?(:option).
|
445
|
+
#
|
446
|
+
# Examples:
|
447
|
+
#
|
448
|
+
# opts.parse %( --verbose )
|
449
|
+
# opts.verbose? #=> true
|
450
|
+
# opts.other? #=> false
|
451
|
+
#
|
452
|
+
# Returns true if this option is present. If this method does not end
|
453
|
+
# with a ? character it will instead call super().
|
454
|
+
def method_missing(method, *args, &block)
|
455
|
+
meth = method.to_s
|
456
|
+
if meth.end_with?('?')
|
457
|
+
meth = meth.chop
|
458
|
+
present?(meth) || present?(meth.tr('_', '-'))
|
459
|
+
else
|
460
|
+
super
|
461
|
+
end
|
462
|
+
end
|
463
|
+
|
464
|
+
# Process a list item, figure out if it's an option, execute any
|
465
|
+
# callbacks, assign any option arguments, and do some sanity checks.
|
466
|
+
#
|
467
|
+
# items - The Array of items to process.
|
468
|
+
# index - The current Integer index of the item we want to process.
|
469
|
+
# block - An optional block which when passed will yield non options.
|
470
|
+
#
|
471
|
+
# Returns nothing.
|
472
|
+
def process_item(items, index, &block)
|
473
|
+
return unless (item = items[index])
|
474
|
+
|
475
|
+
option, argument = extract_option(item) if item.start_with?('-')
|
476
|
+
|
477
|
+
if option
|
478
|
+
option.count += 1 unless item.start_with?('--no-')
|
479
|
+
option.count += 1 if option.key[0, 3] == "no-"
|
480
|
+
@trash << index
|
481
|
+
@triggered_options << option
|
482
|
+
|
483
|
+
if option.expects_argument?
|
484
|
+
argument ||= items.at(index + 1)
|
485
|
+
|
486
|
+
if !argument || argument =~ /\A--?[a-zA-Z][a-zA-Z0-9_-]*\z/
|
487
|
+
raise MissingArgumentError, "#{option.key} expects an argument"
|
488
|
+
end
|
489
|
+
|
490
|
+
execute_option(option, argument, index, item)
|
491
|
+
elsif option.accepts_optional_argument?
|
492
|
+
argument ||= items.at(index + 1)
|
493
|
+
|
494
|
+
if argument && argument =~ /\A([^\-?]|-\d)+/
|
495
|
+
execute_option(option, argument, index, item)
|
496
|
+
else
|
497
|
+
option.call(nil)
|
498
|
+
end
|
499
|
+
elsif config[:multiple_switches] && argument
|
500
|
+
execute_multiple_switches(option, argument, index)
|
501
|
+
else
|
502
|
+
option.value = option.count > 0
|
503
|
+
option.call(nil)
|
504
|
+
end
|
505
|
+
else
|
506
|
+
@unknown_options << item if strict? && item =~ /\A--?/
|
507
|
+
yield(item) if block && !@trash.include?(index)
|
508
|
+
end
|
509
|
+
end
|
510
|
+
|
511
|
+
# Execute an option, firing off callbacks and assigning arguments.
|
512
|
+
#
|
513
|
+
# option - The Slop::Option object found by #process_item.
|
514
|
+
# argument - The argument Object to assign to this option.
|
515
|
+
# index - The current Integer index of the object we're processing.
|
516
|
+
# item - The optional String item we're processing.
|
517
|
+
#
|
518
|
+
# Returns nothing.
|
519
|
+
def execute_option(option, argument, index, item = nil)
|
520
|
+
unless option
|
521
|
+
if config[:multiple_switches] && strict?
|
522
|
+
raise InvalidOptionError, "Unknown option -#{item}"
|
523
|
+
end
|
524
|
+
|
525
|
+
return
|
526
|
+
end
|
527
|
+
|
528
|
+
if argument
|
529
|
+
unless item && item.end_with?("=#{argument}")
|
530
|
+
@trash << index + 1 unless option.argument_in_value
|
531
|
+
end
|
532
|
+
option.value = argument
|
533
|
+
else
|
534
|
+
option.value = option.count > 0
|
535
|
+
end
|
536
|
+
|
537
|
+
if option.match? && !argument.match(option.config[:match])
|
538
|
+
raise InvalidArgumentError, "#{argument} is an invalid argument"
|
539
|
+
end
|
540
|
+
|
541
|
+
option.call(option.value)
|
542
|
+
end
|
543
|
+
|
544
|
+
# Execute a `-abc` type option where a, b and c are all options. This
|
545
|
+
# method is only executed if the multiple_switches argument is true.
|
546
|
+
#
|
547
|
+
# option - The first Option object.
|
548
|
+
# argument - The argument to this option. (Split into multiple Options).
|
549
|
+
# index - The index of the current item being processed.
|
550
|
+
#
|
551
|
+
# Returns nothing.
|
552
|
+
def execute_multiple_switches(option, argument, index)
|
553
|
+
execute_option(option, nil, index)
|
554
|
+
argument.split('').each do |key|
|
555
|
+
next unless (opt = fetch_option(key))
|
556
|
+
|
557
|
+
opt.count += 1
|
558
|
+
execute_option(opt, nil, index, key)
|
559
|
+
end
|
560
|
+
end
|
561
|
+
|
562
|
+
# Extract an option from a flag.
|
563
|
+
#
|
564
|
+
# flag - The flag key used to extract an option.
|
565
|
+
#
|
566
|
+
# Returns an Array of [option, argument].
|
567
|
+
def extract_option(flag)
|
568
|
+
option = fetch_option(flag)
|
569
|
+
option ||= fetch_option(flag.downcase) if config[:ignore_case]
|
570
|
+
option ||= fetch_option(flag.gsub(/([^-])-/, '\1_'))
|
571
|
+
|
572
|
+
unless option
|
573
|
+
case flag
|
574
|
+
when /\A--?([^=]+)=(.+)\z/, /\A-([a-zA-Z])(.+)\z/, /\A--no-(.+)\z/
|
575
|
+
option = fetch_option(Regexp.last_match(1))
|
576
|
+
argument = Regexp.last_match(2) || false
|
577
|
+
option.argument_in_value = true if option
|
578
|
+
end
|
579
|
+
end
|
580
|
+
|
581
|
+
[option, argument]
|
582
|
+
end
|
583
|
+
|
584
|
+
# Autocreate an option on the fly. See the :autocreate Slop config option.
|
585
|
+
#
|
586
|
+
# items - The Array of items we're parsing.
|
587
|
+
# index - The current Integer index for the item we're processing.
|
588
|
+
#
|
589
|
+
# Returns nothing.
|
590
|
+
def autocreate(items, index)
|
591
|
+
flag = items[index]
|
592
|
+
return if fetch_option(flag) || @trash.include?(index)
|
593
|
+
|
594
|
+
option = build_option(Array(flag))
|
595
|
+
argument = items[index + 1]
|
596
|
+
option.config[:argument] = (argument && argument !~ /\A--?/)
|
597
|
+
option.config[:autocreated] = true
|
598
|
+
options << option
|
599
|
+
end
|
600
|
+
|
601
|
+
# Build an option from a list of objects.
|
602
|
+
#
|
603
|
+
# objects - An Array of objects used to build this option.
|
604
|
+
#
|
605
|
+
# Returns a new instance of Slop::Option.
|
606
|
+
def build_option(objects, &block)
|
607
|
+
config = {}
|
608
|
+
config[:argument] = true if @config[:arguments]
|
609
|
+
config[:optional_argument] = true if @config[:optional_arguments]
|
610
|
+
|
611
|
+
if objects.last.is_a?(Hash)
|
612
|
+
config.merge!(objects.last)
|
613
|
+
objects.pop
|
614
|
+
end
|
615
|
+
short = extract_short_flag(objects, config)
|
616
|
+
long = extract_long_flag(objects, config)
|
617
|
+
desc = objects[0].respond_to?(:to_str) ? objects.shift : nil
|
618
|
+
|
619
|
+
Option.new(self, short, long, desc, config, &block)
|
620
|
+
end
|
621
|
+
|
622
|
+
# Extract the short flag from an item.
|
623
|
+
#
|
624
|
+
# objects - The Array of objects passed from #build_option.
|
625
|
+
# config - The Hash of configuration options built in #build_option.
|
626
|
+
def extract_short_flag(objects, config)
|
627
|
+
flag = clean(objects.first)
|
628
|
+
|
629
|
+
if flag.size == 2 && flag.end_with?('=')
|
630
|
+
config[:argument] ||= true
|
631
|
+
flag.chop!
|
632
|
+
end
|
633
|
+
|
634
|
+
return unless flag.size == 1
|
635
|
+
|
636
|
+
objects.shift
|
637
|
+
flag
|
638
|
+
end
|
639
|
+
|
640
|
+
# Extract the long flag from an item.
|
641
|
+
#
|
642
|
+
# objects - The Array of objects passed from #build_option.
|
643
|
+
# config - The Hash of configuration options built in #build_option.
|
644
|
+
def extract_long_flag(objects, config)
|
645
|
+
flag = objects.first.to_s
|
646
|
+
return unless flag =~ /\A(?:--?)?[a-zA-Z][a-zA-Z0-9_-]+\=?\??\z/
|
647
|
+
|
648
|
+
config[:argument] ||= true if flag.end_with?('=')
|
649
|
+
config[:optional_argument] = true if flag.end_with?('=?')
|
650
|
+
objects.shift
|
651
|
+
clean(flag).sub(/\=\??\z/, '')
|
652
|
+
end
|
653
|
+
|
654
|
+
# Remove any leading -- characters from a string.
|
655
|
+
#
|
656
|
+
# object - The Object we want to cast to a String and clean.
|
657
|
+
#
|
658
|
+
# Returns the newly cleaned String with leading -- characters removed.
|
659
|
+
def clean(object)
|
660
|
+
object.to_s.sub(/\A--?/, '')
|
661
|
+
end
|
662
|
+
|
663
|
+
def commands_to_help
|
664
|
+
padding = 0
|
665
|
+
@commands.each { |c, _| padding = c.size if c.size > padding }
|
666
|
+
@commands.map do |cmd, opts|
|
667
|
+
" #{cmd}#{' ' * (padding - cmd.size)} #{opts.description}"
|
668
|
+
end.join("\n")
|
669
|
+
end
|
670
|
+
end
|
671
|
+
# rubocop:enable Metrics/ClassLength
|
672
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'coderay'
|
4
|
+
|
5
|
+
class Pry
|
6
|
+
# @api private
|
7
|
+
# @since v0.13.0
|
8
|
+
class SyntaxHighlighter
|
9
|
+
def self.highlight(code, language = :ruby)
|
10
|
+
tokenize(code, language).term
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.tokenize(code, language = :ruby)
|
14
|
+
CodeRay.scan(code, language)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.keyword_token_color
|
18
|
+
CodeRay::Encoders::Terminal::TOKEN_COLORS[:keyword]
|
19
|
+
end
|
20
|
+
|
21
|
+
# Sets comment token to blue (black by default), so it's more legible.
|
22
|
+
def self.overwrite_coderay_comment_token!
|
23
|
+
CodeRay::Encoders::Terminal::TOKEN_COLORS[:comment][:self] = "\e[1;34m"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Pry
|
4
|
+
# @api private
|
5
|
+
# @since v0.13.0
|
6
|
+
module SystemCommandHandler
|
7
|
+
class << self
|
8
|
+
def default(output, command, _pry_instance)
|
9
|
+
return if Kernel.system(command)
|
10
|
+
|
11
|
+
output.puts(
|
12
|
+
"Error: there was a problem executing system command: #{command}"
|
13
|
+
)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|