pry 0.10.1 → 0.14.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +412 -11
  3. data/LICENSE +1 -1
  4. data/README.md +352 -306
  5. data/bin/pry +4 -7
  6. data/lib/pry/basic_object.rb +10 -0
  7. data/lib/pry/block_command.rb +22 -0
  8. data/lib/pry/class_command.rb +194 -0
  9. data/lib/pry/cli.rb +83 -96
  10. data/lib/pry/code/code_file.rb +37 -26
  11. data/lib/pry/code/code_range.rb +7 -5
  12. data/lib/pry/code/loc.rb +26 -13
  13. data/lib/pry/code.rb +50 -31
  14. data/lib/pry/code_object.rb +53 -28
  15. data/lib/pry/color_printer.rb +46 -35
  16. data/lib/pry/command.rb +197 -369
  17. data/lib/pry/command_set.rb +89 -114
  18. data/lib/pry/command_state.rb +31 -0
  19. data/lib/pry/commands/amend_line.rb +86 -82
  20. data/lib/pry/commands/bang.rb +18 -14
  21. data/lib/pry/commands/bang_pry.rb +15 -11
  22. data/lib/pry/commands/cat/abstract_formatter.rb +23 -18
  23. data/lib/pry/commands/cat/exception_formatter.rb +85 -72
  24. data/lib/pry/commands/cat/file_formatter.rb +56 -46
  25. data/lib/pry/commands/cat/input_expression_formatter.rb +35 -30
  26. data/lib/pry/commands/cat.rb +62 -54
  27. data/lib/pry/commands/cd.rb +40 -35
  28. data/lib/pry/commands/change_inspector.rb +29 -22
  29. data/lib/pry/commands/change_prompt.rb +48 -23
  30. data/lib/pry/commands/clear_screen.rb +20 -0
  31. data/lib/pry/commands/code_collector.rb +148 -131
  32. data/lib/pry/commands/disable_pry.rb +23 -19
  33. data/lib/pry/commands/easter_eggs.rb +23 -34
  34. data/lib/pry/commands/edit/exception_patcher.rb +21 -17
  35. data/lib/pry/commands/edit/file_and_line_locator.rb +34 -23
  36. data/lib/pry/commands/edit.rb +185 -157
  37. data/lib/pry/commands/exit.rb +40 -35
  38. data/lib/pry/commands/exit_all.rb +24 -20
  39. data/lib/pry/commands/exit_program.rb +20 -16
  40. data/lib/pry/commands/find_method.rb +168 -162
  41. data/lib/pry/commands/fix_indent.rb +16 -12
  42. data/lib/pry/commands/help.rb +140 -133
  43. data/lib/pry/commands/hist.rb +151 -149
  44. data/lib/pry/commands/import_set.rb +20 -15
  45. data/lib/pry/commands/jump_to.rb +25 -21
  46. data/lib/pry/commands/list_inspectors.rb +35 -28
  47. data/lib/pry/commands/ls/constants.rb +59 -31
  48. data/lib/pry/commands/ls/formatter.rb +42 -36
  49. data/lib/pry/commands/ls/globals.rb +38 -36
  50. data/lib/pry/commands/ls/grep.rb +17 -15
  51. data/lib/pry/commands/ls/instance_vars.rb +29 -28
  52. data/lib/pry/commands/ls/interrogatable.rb +18 -12
  53. data/lib/pry/commands/ls/jruby_hacks.rb +47 -41
  54. data/lib/pry/commands/ls/local_names.rb +26 -24
  55. data/lib/pry/commands/ls/local_vars.rb +38 -30
  56. data/lib/pry/commands/ls/ls_entity.rb +47 -52
  57. data/lib/pry/commands/ls/methods.rb +49 -51
  58. data/lib/pry/commands/ls/methods_helper.rb +46 -42
  59. data/lib/pry/commands/ls/self_methods.rb +23 -21
  60. data/lib/pry/commands/ls.rb +124 -103
  61. data/lib/pry/commands/nesting.rb +21 -17
  62. data/lib/pry/commands/play.rb +92 -82
  63. data/lib/pry/commands/pry_backtrace.rb +22 -17
  64. data/lib/pry/commands/pry_version.rb +15 -11
  65. data/lib/pry/commands/raise_up.rb +33 -27
  66. data/lib/pry/commands/reload_code.rb +60 -48
  67. data/lib/pry/commands/reset.rb +16 -12
  68. data/lib/pry/commands/ri.rb +57 -42
  69. data/lib/pry/commands/save_file.rb +45 -43
  70. data/lib/pry/commands/shell_command.rb +56 -29
  71. data/lib/pry/commands/shell_mode.rb +22 -18
  72. data/lib/pry/commands/show_doc.rb +80 -70
  73. data/lib/pry/commands/show_info.rb +194 -155
  74. data/lib/pry/commands/show_input.rb +16 -11
  75. data/lib/pry/commands/show_source.rb +110 -42
  76. data/lib/pry/commands/stat.rb +35 -31
  77. data/lib/pry/commands/switch_to.rb +21 -15
  78. data/lib/pry/commands/toggle_color.rb +20 -16
  79. data/lib/pry/commands/watch_expression/expression.rb +32 -27
  80. data/lib/pry/commands/watch_expression.rb +89 -84
  81. data/lib/pry/commands/whereami.rb +156 -141
  82. data/lib/pry/commands/wtf.rb +78 -40
  83. data/lib/pry/config/attributable.rb +22 -0
  84. data/lib/pry/config/lazy_value.rb +29 -0
  85. data/lib/pry/config/memoized_value.rb +34 -0
  86. data/lib/pry/config/value.rb +24 -0
  87. data/lib/pry/config.rb +313 -20
  88. data/lib/pry/control_d_handler.rb +28 -0
  89. data/lib/pry/core_extensions.rb +22 -9
  90. data/lib/pry/editor.rb +53 -33
  91. data/lib/pry/env.rb +18 -0
  92. data/lib/pry/exception_handler.rb +43 -0
  93. data/lib/pry/exceptions.rb +13 -17
  94. data/lib/pry/forwardable.rb +27 -0
  95. data/lib/pry/helpers/base_helpers.rb +20 -62
  96. data/lib/pry/helpers/command_helpers.rb +52 -62
  97. data/lib/pry/helpers/documentation_helpers.rb +21 -12
  98. data/lib/pry/helpers/options_helpers.rb +15 -8
  99. data/lib/pry/helpers/platform.rb +60 -0
  100. data/lib/pry/helpers/table.rb +44 -32
  101. data/lib/pry/helpers/text.rb +96 -85
  102. data/lib/pry/helpers.rb +3 -0
  103. data/lib/pry/history.rb +81 -55
  104. data/lib/pry/hooks.rb +60 -110
  105. data/lib/pry/indent.rb +72 -66
  106. data/lib/pry/input_completer.rb +199 -158
  107. data/lib/pry/input_lock.rb +7 -10
  108. data/lib/pry/inspector.rb +36 -24
  109. data/lib/pry/last_exception.rb +45 -45
  110. data/lib/pry/method/disowned.rb +19 -5
  111. data/lib/pry/method/patcher.rb +14 -8
  112. data/lib/pry/method/weird_method_locator.rb +79 -43
  113. data/lib/pry/method.rb +177 -124
  114. data/lib/pry/object_path.rb +37 -28
  115. data/lib/pry/output.rb +102 -16
  116. data/lib/pry/pager.rb +187 -174
  117. data/lib/pry/prompt.rb +213 -25
  118. data/lib/pry/pry_class.rb +106 -98
  119. data/lib/pry/pry_instance.rb +261 -224
  120. data/lib/pry/repl.rb +82 -27
  121. data/lib/pry/repl_file_loader.rb +27 -22
  122. data/lib/pry/ring.rb +89 -0
  123. data/lib/pry/slop/LICENSE +20 -0
  124. data/lib/pry/slop/commands.rb +190 -0
  125. data/lib/pry/slop/option.rb +210 -0
  126. data/lib/pry/slop.rb +672 -0
  127. data/lib/pry/syntax_highlighter.rb +26 -0
  128. data/lib/pry/system_command_handler.rb +17 -0
  129. data/lib/pry/testable/evalable.rb +24 -0
  130. data/lib/pry/testable/mockable.rb +22 -0
  131. data/lib/pry/testable/pry_tester.rb +88 -0
  132. data/lib/pry/testable/utility.rb +34 -0
  133. data/lib/pry/testable/variables.rb +52 -0
  134. data/lib/pry/testable.rb +68 -0
  135. data/lib/pry/version.rb +3 -1
  136. data/lib/pry/warning.rb +27 -0
  137. data/lib/pry/{module_candidate.rb → wrapped_module/candidate.rb} +29 -27
  138. data/lib/pry/wrapped_module.rb +67 -57
  139. data/lib/pry.rb +133 -149
  140. metadata +52 -63
  141. data/lib/pry/commands/disabled_commands.rb +0 -2
  142. data/lib/pry/commands/gem_cd.rb +0 -26
  143. data/lib/pry/commands/gem_install.rb +0 -32
  144. data/lib/pry/commands/gem_list.rb +0 -33
  145. data/lib/pry/commands/gem_open.rb +0 -29
  146. data/lib/pry/commands/gist.rb +0 -101
  147. data/lib/pry/commands/install_command.rb +0 -53
  148. data/lib/pry/commands/list_prompts.rb +0 -35
  149. data/lib/pry/commands/simple_prompt.rb +0 -22
  150. data/lib/pry/commands.rb +0 -6
  151. data/lib/pry/config/behavior.rb +0 -139
  152. data/lib/pry/config/convenience.rb +0 -25
  153. data/lib/pry/config/default.rb +0 -161
  154. data/lib/pry/history_array.rb +0 -121
  155. data/lib/pry/plugins.rb +0 -103
  156. data/lib/pry/rbx_path.rb +0 -22
  157. data/lib/pry/rubygem.rb +0 -82
  158. data/lib/pry/terminal.rb +0 -79
  159. 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