pry 0.10.0.pre2-universal-mswin32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +702 -0
  3. data/LICENSE +25 -0
  4. data/README.md +406 -0
  5. data/bin/pry +16 -0
  6. data/lib/pry.rb +161 -0
  7. data/lib/pry/cli.rb +220 -0
  8. data/lib/pry/code.rb +346 -0
  9. data/lib/pry/code/code_file.rb +103 -0
  10. data/lib/pry/code/code_range.rb +71 -0
  11. data/lib/pry/code/loc.rb +92 -0
  12. data/lib/pry/code_object.rb +172 -0
  13. data/lib/pry/color_printer.rb +55 -0
  14. data/lib/pry/command.rb +692 -0
  15. data/lib/pry/command_set.rb +443 -0
  16. data/lib/pry/commands.rb +6 -0
  17. data/lib/pry/commands/amend_line.rb +99 -0
  18. data/lib/pry/commands/bang.rb +20 -0
  19. data/lib/pry/commands/bang_pry.rb +17 -0
  20. data/lib/pry/commands/cat.rb +62 -0
  21. data/lib/pry/commands/cat/abstract_formatter.rb +27 -0
  22. data/lib/pry/commands/cat/exception_formatter.rb +77 -0
  23. data/lib/pry/commands/cat/file_formatter.rb +67 -0
  24. data/lib/pry/commands/cat/input_expression_formatter.rb +43 -0
  25. data/lib/pry/commands/cd.rb +41 -0
  26. data/lib/pry/commands/change_inspector.rb +27 -0
  27. data/lib/pry/commands/change_prompt.rb +26 -0
  28. data/lib/pry/commands/code_collector.rb +165 -0
  29. data/lib/pry/commands/disable_pry.rb +27 -0
  30. data/lib/pry/commands/disabled_commands.rb +2 -0
  31. data/lib/pry/commands/easter_eggs.rb +112 -0
  32. data/lib/pry/commands/edit.rb +195 -0
  33. data/lib/pry/commands/edit/exception_patcher.rb +25 -0
  34. data/lib/pry/commands/edit/file_and_line_locator.rb +36 -0
  35. data/lib/pry/commands/exit.rb +42 -0
  36. data/lib/pry/commands/exit_all.rb +29 -0
  37. data/lib/pry/commands/exit_program.rb +23 -0
  38. data/lib/pry/commands/find_method.rb +193 -0
  39. data/lib/pry/commands/fix_indent.rb +19 -0
  40. data/lib/pry/commands/gem_cd.rb +26 -0
  41. data/lib/pry/commands/gem_install.rb +32 -0
  42. data/lib/pry/commands/gem_list.rb +33 -0
  43. data/lib/pry/commands/gem_open.rb +29 -0
  44. data/lib/pry/commands/gist.rb +101 -0
  45. data/lib/pry/commands/help.rb +164 -0
  46. data/lib/pry/commands/hist.rb +180 -0
  47. data/lib/pry/commands/import_set.rb +22 -0
  48. data/lib/pry/commands/install_command.rb +53 -0
  49. data/lib/pry/commands/jump_to.rb +29 -0
  50. data/lib/pry/commands/list_inspectors.rb +35 -0
  51. data/lib/pry/commands/list_prompts.rb +35 -0
  52. data/lib/pry/commands/ls.rb +114 -0
  53. data/lib/pry/commands/ls/constants.rb +47 -0
  54. data/lib/pry/commands/ls/formatter.rb +49 -0
  55. data/lib/pry/commands/ls/globals.rb +48 -0
  56. data/lib/pry/commands/ls/grep.rb +21 -0
  57. data/lib/pry/commands/ls/instance_vars.rb +39 -0
  58. data/lib/pry/commands/ls/interrogatable.rb +18 -0
  59. data/lib/pry/commands/ls/jruby_hacks.rb +49 -0
  60. data/lib/pry/commands/ls/local_names.rb +35 -0
  61. data/lib/pry/commands/ls/local_vars.rb +39 -0
  62. data/lib/pry/commands/ls/ls_entity.rb +70 -0
  63. data/lib/pry/commands/ls/methods.rb +57 -0
  64. data/lib/pry/commands/ls/methods_helper.rb +46 -0
  65. data/lib/pry/commands/ls/self_methods.rb +32 -0
  66. data/lib/pry/commands/nesting.rb +25 -0
  67. data/lib/pry/commands/play.rb +103 -0
  68. data/lib/pry/commands/pry_backtrace.rb +25 -0
  69. data/lib/pry/commands/pry_version.rb +17 -0
  70. data/lib/pry/commands/raise_up.rb +32 -0
  71. data/lib/pry/commands/reload_code.rb +62 -0
  72. data/lib/pry/commands/reset.rb +18 -0
  73. data/lib/pry/commands/ri.rb +60 -0
  74. data/lib/pry/commands/save_file.rb +61 -0
  75. data/lib/pry/commands/shell_command.rb +48 -0
  76. data/lib/pry/commands/shell_mode.rb +25 -0
  77. data/lib/pry/commands/show_doc.rb +83 -0
  78. data/lib/pry/commands/show_info.rb +195 -0
  79. data/lib/pry/commands/show_input.rb +17 -0
  80. data/lib/pry/commands/show_source.rb +50 -0
  81. data/lib/pry/commands/simple_prompt.rb +22 -0
  82. data/lib/pry/commands/stat.rb +40 -0
  83. data/lib/pry/commands/switch_to.rb +23 -0
  84. data/lib/pry/commands/toggle_color.rb +24 -0
  85. data/lib/pry/commands/watch_expression.rb +105 -0
  86. data/lib/pry/commands/watch_expression/expression.rb +38 -0
  87. data/lib/pry/commands/whereami.rb +190 -0
  88. data/lib/pry/commands/wtf.rb +57 -0
  89. data/lib/pry/config.rb +24 -0
  90. data/lib/pry/config/behavior.rb +139 -0
  91. data/lib/pry/config/convenience.rb +26 -0
  92. data/lib/pry/config/default.rb +165 -0
  93. data/lib/pry/core_extensions.rb +131 -0
  94. data/lib/pry/editor.rb +133 -0
  95. data/lib/pry/exceptions.rb +77 -0
  96. data/lib/pry/helpers.rb +5 -0
  97. data/lib/pry/helpers/base_helpers.rb +113 -0
  98. data/lib/pry/helpers/command_helpers.rb +156 -0
  99. data/lib/pry/helpers/documentation_helpers.rb +75 -0
  100. data/lib/pry/helpers/options_helpers.rb +27 -0
  101. data/lib/pry/helpers/table.rb +109 -0
  102. data/lib/pry/helpers/text.rb +107 -0
  103. data/lib/pry/history.rb +125 -0
  104. data/lib/pry/history_array.rb +121 -0
  105. data/lib/pry/hooks.rb +230 -0
  106. data/lib/pry/indent.rb +406 -0
  107. data/lib/pry/input_completer.rb +242 -0
  108. data/lib/pry/input_lock.rb +132 -0
  109. data/lib/pry/inspector.rb +27 -0
  110. data/lib/pry/last_exception.rb +61 -0
  111. data/lib/pry/method.rb +546 -0
  112. data/lib/pry/method/disowned.rb +53 -0
  113. data/lib/pry/method/patcher.rb +125 -0
  114. data/lib/pry/method/weird_method_locator.rb +186 -0
  115. data/lib/pry/module_candidate.rb +136 -0
  116. data/lib/pry/object_path.rb +82 -0
  117. data/lib/pry/output.rb +50 -0
  118. data/lib/pry/pager.rb +234 -0
  119. data/lib/pry/plugins.rb +103 -0
  120. data/lib/pry/prompt.rb +26 -0
  121. data/lib/pry/pry_class.rb +375 -0
  122. data/lib/pry/pry_instance.rb +654 -0
  123. data/lib/pry/rbx_path.rb +22 -0
  124. data/lib/pry/repl.rb +202 -0
  125. data/lib/pry/repl_file_loader.rb +74 -0
  126. data/lib/pry/rubygem.rb +82 -0
  127. data/lib/pry/terminal.rb +79 -0
  128. data/lib/pry/test/helper.rb +170 -0
  129. data/lib/pry/version.rb +3 -0
  130. data/lib/pry/wrapped_module.rb +373 -0
  131. metadata +248 -0
@@ -0,0 +1,692 @@
1
+ require 'delegate'
2
+ require 'pry/helpers/documentation_helpers'
3
+
4
+ class Pry
5
+
6
+ # The super-class of all commands, new commands should be created by calling
7
+ # {Pry::CommandSet#command} which creates a BlockCommand or {Pry::CommandSet#create_command}
8
+ # which creates a ClassCommand. Please don't use this class directly.
9
+ class Command
10
+ extend Helpers::DocumentationHelpers
11
+ extend CodeObject::Helpers
12
+
13
+ # represents a void return value for a command
14
+ VOID_VALUE = Object.new
15
+
16
+ # give it a nice inspect
17
+ def VOID_VALUE.inspect() "void" end
18
+
19
+ # Properties of the command itself (as passed as arguments to
20
+ # {CommandSet#command} or {CommandSet#create_command}).
21
+ class << self
22
+ attr_writer :block
23
+ attr_writer :description
24
+ attr_writer :command_options
25
+ attr_writer :match
26
+
27
+ def match(arg=nil)
28
+ if arg
29
+ @command_options ||= default_options(arg)
30
+ @command_options[:listing] = arg.is_a?(String) ? arg : arg.inspect
31
+ @match = arg
32
+ end
33
+ @match ||= nil
34
+ end
35
+
36
+ # Define or get the command's description
37
+ def description(arg=nil)
38
+ @description = arg if arg
39
+ @description ||= nil
40
+ end
41
+
42
+ # Define or get the command's options
43
+ def command_options(arg=nil)
44
+ @command_options ||= default_options(match)
45
+ @command_options.merge!(arg) if arg
46
+ @command_options
47
+ end
48
+ # backward compatibility
49
+ alias_method :options, :command_options
50
+ alias_method :options=, :command_options=
51
+
52
+ # Define or get the command's banner
53
+ def banner(arg=nil)
54
+ @banner = arg if arg
55
+ @banner || description
56
+ end
57
+
58
+ def block
59
+ @block || instance_method(:process)
60
+ end
61
+
62
+ def source
63
+ file, line = block.source_location
64
+ strip_leading_whitespace(Pry::Code.from_file(file).expression_at(line))
65
+ end
66
+
67
+ def doc
68
+ new.help
69
+ end
70
+
71
+ def source_location
72
+ block.source_location
73
+ end
74
+
75
+ def source_file
76
+ Array(block.source_location).first
77
+ end
78
+ alias_method :file, :source_file
79
+
80
+ def source_line
81
+ Array(block.source_location).last
82
+ end
83
+ alias_method :line, :source_line
84
+
85
+ def default_options(match)
86
+ {
87
+ :requires_gem => [],
88
+ :keep_retval => false,
89
+ :argument_required => false,
90
+ :interpolate => true,
91
+ :shellwords => true,
92
+ :listing => (String === match ? match : match.inspect),
93
+ :use_prefix => true,
94
+ :takes_block => false
95
+ }
96
+ end
97
+ end
98
+
99
+ # Make those properties accessible to instances
100
+ def name; self.class.name; end
101
+ def match; self.class.match; end
102
+ def description; self.class.description; end
103
+ def block; self.class.block; end
104
+ def command_options; self.class.options; end
105
+ def command_name; self.class.command_name; end
106
+ def source; self.class.source; end
107
+ def source_location; self.class.source_location; end
108
+
109
+ class << self
110
+ def name
111
+ super.to_s == "" ? "#<class(Pry::Command #{match.inspect})>" : super
112
+ end
113
+
114
+ def inspect
115
+ name
116
+ end
117
+
118
+ def command_name
119
+ self.options[:listing]
120
+ end
121
+
122
+ # Create a new command with the given properties.
123
+ # @param [String, Regex] match The thing that triggers this command
124
+ # @param [String] description The description to appear in `help`
125
+ # @param [Hash] options Behavioral options (see {Pry::CommandSet#command})
126
+ # @param [Module] helpers A module of helper functions to be included.
127
+ # @yield optional, used for BlockCommands
128
+ # @return [Class] (a subclass of {Pry::Command})
129
+ def subclass(match, description, options, helpers, &block)
130
+ klass = Class.new(self)
131
+ klass.send(:include, helpers)
132
+ klass.match = match
133
+ klass.description = description
134
+ klass.command_options = options
135
+ klass.block = block
136
+ klass
137
+ end
138
+
139
+ # Should this command be called for the given line?
140
+ # @param [String] val A line input at the REPL
141
+ # @return [Boolean]
142
+ def matches?(val)
143
+ command_regex =~ val
144
+ end
145
+
146
+ # How well does this command match the given line?
147
+ #
148
+ # Higher scores are better because they imply that this command matches
149
+ # the line more closely.
150
+ #
151
+ # The score is calculated by taking the number of characters at the start
152
+ # of the string that are used only to identify the command, not as part of
153
+ # the arguments.
154
+ #
155
+ # @example
156
+ # /\.(.*)/.match_score(".foo") #=> 1
157
+ # /\.*(.*)/.match_score("...foo") #=> 3
158
+ # 'hi'.match_score("hi there") #=> 2
159
+ #
160
+ # @param [String] val A line input at the REPL
161
+ # @return [Fixnum]
162
+ def match_score(val)
163
+ if command_regex =~ val
164
+ Regexp.last_match.size > 1 ? Regexp.last_match.begin(1) : Regexp.last_match.end(0)
165
+ else
166
+ -1
167
+ end
168
+ end
169
+
170
+ # Store hooks to be run before or after the command body.
171
+ # @see {Pry::CommandSet#before_command}
172
+ # @see {Pry::CommandSet#after_command}
173
+ def hooks
174
+ @hooks ||= {:before => [], :after => []}
175
+ end
176
+
177
+ def command_regex
178
+ pr = Pry.respond_to?(:config) ? Pry.config.command_prefix : ""
179
+ prefix = convert_to_regex(pr)
180
+ prefix = "(?:#{prefix})?" unless options[:use_prefix]
181
+
182
+ /^#{prefix}#{convert_to_regex(match)}(?!\S)/
183
+ end
184
+
185
+ def convert_to_regex(obj)
186
+ case obj
187
+ when String
188
+ Regexp.escape(obj)
189
+ else
190
+ obj
191
+ end
192
+ end
193
+
194
+ # The group in which the command should be displayed in "help" output.
195
+ # This is usually auto-generated from directory naming, but it can be
196
+ # manually overridden if necessary.
197
+ # Group should not be changed once it is initialized.
198
+ def group(name=nil)
199
+ @group ||= if name
200
+ name
201
+ else
202
+ case Pry::Method(block).source_file
203
+ when %r{/pry/.*_commands/(.*).rb}
204
+ $1.capitalize.gsub(/_/, " ")
205
+ when %r{(pry-\w+)-([\d\.]+([\w\.]+)?)}
206
+ name, version = $1, $2
207
+ "#{name.to_s} (v#{version.to_s})"
208
+ when /pryrc/
209
+ "~/.pryrc"
210
+ else
211
+ "(other)"
212
+ end
213
+ end
214
+ end
215
+ end
216
+
217
+ # Properties of one execution of a command (passed by {Pry#run_command} as a hash of
218
+ # context and expanded in `#initialize`
219
+ attr_accessor :output
220
+ attr_accessor :target
221
+ attr_accessor :captures
222
+ attr_accessor :eval_string
223
+ attr_accessor :arg_string
224
+ attr_accessor :context
225
+ attr_accessor :command_set
226
+ attr_accessor :_pry_
227
+
228
+ # The block we pass *into* a command so long as `:takes_block` is
229
+ # not equal to `false`
230
+ # @example
231
+ # my-command | do
232
+ # puts "block content"
233
+ # end
234
+ attr_accessor :command_block
235
+
236
+ # Run a command from another command.
237
+ # @param [String] command_string The string that invokes the command
238
+ # @param [Array] args Further arguments to pass to the command
239
+ # @example
240
+ # run "show-input"
241
+ # @example
242
+ # run ".ls"
243
+ # @example
244
+ # run "amend-line", "5", 'puts "hello world"'
245
+ def run(command_string, *args)
246
+ command_string = _pry_.config.command_prefix.to_s + command_string
247
+ complete_string = "#{command_string} #{args.join(" ")}".rstrip
248
+ command_set.process_line(complete_string, context)
249
+ end
250
+
251
+ def commands
252
+ command_set.to_hash
253
+ end
254
+
255
+ def text
256
+ Pry::Helpers::Text
257
+ end
258
+
259
+ def void
260
+ VOID_VALUE
261
+ end
262
+
263
+ include Pry::Helpers::BaseHelpers
264
+ include Pry::Helpers::CommandHelpers
265
+
266
+ # Instantiate a command, in preparation for calling it.
267
+ # @param [Hash] context The runtime context to use with this command.
268
+ def initialize(context={})
269
+ self.context = context
270
+ self.target = context[:target]
271
+ self.output = context[:output]
272
+ self.eval_string = context[:eval_string]
273
+ self.command_set = context[:command_set]
274
+ self._pry_ = context[:pry_instance]
275
+ end
276
+
277
+ # @return [Object] The value of `self` inside the `target` binding.
278
+ def target_self; target.eval('self'); end
279
+
280
+ # @return [Hash] Pry commands can store arbitrary state
281
+ # here. This state persists between subsequent command invocations.
282
+ # All state saved here is unique to the command, it does not
283
+ # need to be namespaced.
284
+ # @example
285
+ # state.my_state = "my state" # this will not conflict with any
286
+ # # `state.my_state` used in another command.
287
+ def state
288
+ _pry_.command_state[match] ||= Pry::Config.from_hash({})
289
+ end
290
+
291
+ # Revaluate the string (str) and perform interpolation.
292
+ # @param [String] str The string to reevaluate with interpolation.
293
+ #
294
+ # @return [String] The reevaluated string with interpolations
295
+ # applied (if any).
296
+ def interpolate_string(str)
297
+ dumped_str = str.dump
298
+ if dumped_str.gsub!(/\\\#\{/, '#{')
299
+ target.eval(dumped_str)
300
+ else
301
+ str
302
+ end
303
+ end
304
+
305
+ # Display a warning if a command collides with a local/method in
306
+ # the current scope.
307
+ def check_for_command_collision(command_match, arg_string)
308
+ collision_type = target.eval("defined?(#{command_match})")
309
+ collision_type ||= 'local-variable' if arg_string.match(%r{\A\s*[-+*/%&|^]*=})
310
+
311
+ if collision_type
312
+ output.puts "#{text.bold('WARNING:')} Calling Pry command '#{command_match}', which conflicts with a #{collision_type}.\n\n"
313
+ end
314
+ rescue Pry::RescuableException
315
+ end
316
+
317
+ # Extract necessary information from a line that Command.matches? this
318
+ # command.
319
+ #
320
+ # Returns an array of four elements:
321
+ #
322
+ # ```
323
+ # [String] the portion of the line that matched with the Command match
324
+ # [String] a string of all the arguments (i.e. everything but the match)
325
+ # [Array] the captures caught by the command_regex
326
+ # [Array] the arguments obtained by splitting the arg_string
327
+ # ```
328
+ #
329
+ # @param [String] val The line of input
330
+ # @return [Array]
331
+ def tokenize(val)
332
+ val.replace(interpolate_string(val)) if command_options[:interpolate]
333
+
334
+ self.class.command_regex =~ val
335
+
336
+ # please call Command.matches? before Command#call_safely
337
+ raise CommandError, "fatal: called a command which didn't match?!" unless Regexp.last_match
338
+ captures = Regexp.last_match.captures
339
+ pos = Regexp.last_match.end(0)
340
+
341
+ arg_string = val[pos..-1]
342
+
343
+ # remove the one leading space if it exists
344
+ arg_string.slice!(0) if arg_string.start_with?(" ")
345
+
346
+ # process and pass a block if one is found
347
+ pass_block(arg_string) if command_options[:takes_block]
348
+
349
+ if arg_string
350
+ args = command_options[:shellwords] ? Shellwords.shellwords(arg_string) : arg_string.split(" ")
351
+ else
352
+ args = []
353
+ end
354
+
355
+ [val[0..pos].rstrip, arg_string, captures, args]
356
+ end
357
+
358
+ # Process a line that Command.matches? this command.
359
+ # @param [String] line The line to process
360
+ # @return [Object, Command::VOID_VALUE]
361
+ def process_line(line)
362
+ command_match, arg_string, captures, args = tokenize(line)
363
+
364
+ check_for_command_collision(command_match, arg_string) if Pry.config.collision_warning
365
+
366
+ self.arg_string = arg_string
367
+ self.captures = captures
368
+
369
+ call_safely(*(captures + args))
370
+ end
371
+
372
+ # Pass a block argument to a command.
373
+ # @param [String] arg_string The arguments (as a string) passed to the command.
374
+ # We inspect these for a '| do' or a '| {' and if we find it we use it
375
+ # to start a block input sequence. Once we have a complete
376
+ # block, we save it to an accessor that can be retrieved from the command context.
377
+ # Note that if we find the '| do' or '| {' we delete this and the
378
+ # elements following it from `arg_string`.
379
+ def pass_block(arg_string)
380
+ # Workaround for weird JRuby bug where rindex in this case can return nil
381
+ # even when there's a match.
382
+ arg_string.scan(/\| *(?:do|\{)/)
383
+ block_index = $~ && $~.offset(0)[0]
384
+
385
+ return if !block_index
386
+
387
+ block_init_string = arg_string.slice!(block_index..-1)[1..-1]
388
+ prime_string = "proc #{block_init_string}\n"
389
+
390
+ if !Pry::Code.complete_expression?(prime_string)
391
+ block_string = _pry_.r(target, prime_string)
392
+ else
393
+ block_string = prime_string
394
+ end
395
+
396
+ begin
397
+ self.command_block = target.eval(block_string)
398
+ rescue Pry::RescuableException
399
+ raise CommandError, "Incomplete block definition."
400
+ end
401
+ end
402
+
403
+ private :pass_block
404
+
405
+ # Run the command with the given `args`.
406
+ #
407
+ # This is a public wrapper around `#call` which ensures all preconditions
408
+ # are met.
409
+ #
410
+ # @param [Array<String>] args The arguments to pass to this command.
411
+ # @return [Object] The return value of the `#call` method, or
412
+ # {Command::VOID_VALUE}.
413
+ def call_safely(*args)
414
+ unless dependencies_met?
415
+ gems_needed = Array(command_options[:requires_gem])
416
+ gems_not_installed = gems_needed.select { |g| !Rubygem.installed?(g) }
417
+ output.puts "\nThe command '#{command_name}' is #{text.bold("unavailable")} because it requires the following gems to be installed: #{(gems_not_installed.join(", "))}"
418
+ output.puts "-"
419
+ output.puts "Type `install-command #{command_name}` to install the required gems and activate this command."
420
+ return void
421
+ end
422
+
423
+ if command_options[:argument_required] && args.empty?
424
+ raise CommandError, "The command '#{command_name}' requires an argument."
425
+ end
426
+
427
+ ret = call_with_hooks(*args)
428
+ command_options[:keep_retval] ? ret : void
429
+ end
430
+
431
+ # Are all the gems required to use this command installed?
432
+ #
433
+ # @return Boolean
434
+ def dependencies_met?
435
+ @dependencies_met ||= command_dependencies_met?(command_options)
436
+ end
437
+
438
+ # Generate completions for this command
439
+ #
440
+ # @param [String] search The line typed so far
441
+ # @return [Array<String>] Completion words
442
+ def complete(search)
443
+ []
444
+ end
445
+
446
+ private
447
+
448
+ # Run the `#call` method and all the registered hooks.
449
+ # @param [Array<String>] args The arguments to `#call`
450
+ # @return [Object] The return value from `#call`
451
+ def call_with_hooks(*args)
452
+ self.class.hooks[:before].each do |block|
453
+ instance_exec(*args, &block)
454
+ end
455
+
456
+ ret = call(*args)
457
+
458
+ self.class.hooks[:after].each do |block|
459
+ ret = instance_exec(*args, &block)
460
+ end
461
+
462
+ ret
463
+ end
464
+
465
+ # Fix the number of arguments we pass to a block to avoid arity warnings.
466
+ # @param [Fixnum] arity The arity of the block
467
+ # @param [Array] args The arguments to pass
468
+ # @return [Array] A (possibly shorter) array of the arguments to pass
469
+ def correct_arg_arity(arity, args)
470
+ case
471
+ when arity < 0
472
+ args
473
+ when arity == 0
474
+ []
475
+ when arity > 0
476
+ args.values_at(*(0..(arity - 1)).to_a)
477
+ end
478
+ end
479
+ end
480
+
481
+ # A super-class for Commands that are created with a single block.
482
+ #
483
+ # This class ensures that the block is called with the correct number of arguments
484
+ # and the right context.
485
+ #
486
+ # Create subclasses using {Pry::CommandSet#command}.
487
+ class BlockCommand < Command
488
+ # backwards compatibility
489
+ alias_method :opts, :context
490
+
491
+ # Call the block that was registered with this command.
492
+ # @param [Array<String>] args The arguments passed
493
+ # @return [Object] The return value of the block
494
+ def call(*args)
495
+ instance_exec(*correct_arg_arity(block.arity, args), &block)
496
+ end
497
+
498
+ def help
499
+ "#{command_options[:listing].to_s.ljust(18)} #{description}"
500
+ end
501
+ end
502
+
503
+ # A super-class of Commands with structure.
504
+ #
505
+ # This class implements the bare-minimum functionality that a command should
506
+ # have, namely a --help switch, and then delegates actual processing to its
507
+ # subclasses.
508
+ #
509
+ # Create subclasses using {Pry::CommandSet#create_command}, and override the
510
+ # `options(opt)` method to set up an instance of Slop, and the `process`
511
+ # method to actually run the command. If necessary, you can also override
512
+ # `setup` which will be called before `options`, for example to require any
513
+ # gems your command needs to run, or to set up state.
514
+ class ClassCommand < Command
515
+ class << self
516
+
517
+ # Ensure that subclasses inherit the options, description and
518
+ # match from a ClassCommand super class.
519
+ def inherited(klass)
520
+ klass.match match
521
+ klass.description description
522
+ klass.command_options options
523
+ end
524
+
525
+ def source
526
+ source_object.source
527
+ end
528
+
529
+ def doc
530
+ new.help
531
+ end
532
+
533
+ def source_location
534
+ source_object.source_location
535
+ end
536
+
537
+ def source_file
538
+ source_object.source_file
539
+ end
540
+ alias_method :file, :source_file
541
+
542
+ def source_line
543
+ source_object.source_line
544
+ end
545
+ alias_method :line, :source_line
546
+
547
+ private
548
+
549
+ # The object used to extract the source for the command.
550
+ #
551
+ # This should be a `Pry::Method(block)` for a command made with `create_command`
552
+ # and a `Pry::WrappedModule(self)` for a command that's a standard class.
553
+ # @return [Pry::WrappedModule, Pry::Method]
554
+ def source_object
555
+ @source_object ||= if name =~ /^[A-Z]/
556
+ Pry::WrappedModule(self)
557
+ else
558
+ Pry::Method(block)
559
+ end
560
+ end
561
+ end
562
+
563
+ attr_accessor :opts
564
+ attr_accessor :args
565
+
566
+ # Set up `opts` and `args`, and then call `process`.
567
+ #
568
+ # This method will display help if necessary.
569
+ #
570
+ # @param [Array<String>] args The arguments passed
571
+ # @return [Object] The return value of `process` or VOID_VALUE
572
+ def call(*args)
573
+ setup
574
+
575
+ self.opts = slop
576
+ self.args = self.opts.parse!(args)
577
+
578
+ if opts.present?(:help)
579
+ output.puts slop.help
580
+ void
581
+ else
582
+ process(*correct_arg_arity(method(:process).arity, args))
583
+ end
584
+ end
585
+
586
+ # Return the help generated by Slop for this command.
587
+ def help
588
+ slop.help
589
+ end
590
+
591
+ # Return an instance of Slop that can parse either subcommands or the
592
+ # options that this command accepts.
593
+ def slop
594
+ Slop.new do |opt|
595
+ opt.banner(unindent(self.class.banner))
596
+ subcommands(opt)
597
+ options(opt)
598
+ opt.on :h, :help, 'Show this message.'
599
+ end
600
+ end
601
+
602
+ # Generate shell completions
603
+ # @param [String] search The line typed so far
604
+ # @return [Array<String>] the words to complete
605
+ def complete(search)
606
+ slop.map do |opt|
607
+ [opt.long && "--#{opt.long} " || opt.short && "-#{opt.short}"]
608
+ end.flatten(1).compact + super
609
+ end
610
+
611
+ # A method called just before `options(opt)` as part of `call`.
612
+ #
613
+ # This method can be used to set up any context your command needs to run,
614
+ # for example requiring gems, or setting default values for options.
615
+ #
616
+ # @example
617
+ # def setup
618
+ # require 'gist'
619
+ # @action = :method
620
+ # end
621
+ def setup; end
622
+
623
+ # A method to setup Slop commands so it can parse the subcommands your
624
+ # command expects. If you need to set up default values, use `setup`
625
+ # instead.
626
+ #
627
+ # @example A minimal example
628
+ # def subcommands(cmd)
629
+ # cmd.command :download do |opt|
630
+ # description 'Downloads a content from a server'
631
+ #
632
+ # opt.on :verbose, 'Use verbose output'
633
+ #
634
+ # run do |options, arguments|
635
+ # ContentDownloader.download(options, arguments)
636
+ # end
637
+ # end
638
+ # end
639
+ #
640
+ # @example Define the invokation block anywhere you want
641
+ # def subcommands(cmd)
642
+ # cmd.command :download do |opt|
643
+ # description 'Downloads a content from a server'
644
+ #
645
+ # opt.on :verbose, 'Use verbose output'
646
+ # end
647
+ # end
648
+ #
649
+ # def process
650
+ # # Perform calculations...
651
+ # opts.fetch_command(:download).run do |options, arguments|
652
+ # ContentDownloader.download(options, arguments)
653
+ # end
654
+ # # More calculations...
655
+ # end
656
+ def subcommands(cmd); end
657
+
658
+ # A method to setup Slop so it can parse the options your command expects.
659
+ #
660
+ # @note Please don't do anything side-effecty in the main part of this
661
+ # method, as it may be called by Pry at any time for introspection reasons.
662
+ # If you need to set up default values, use `setup` instead.
663
+ #
664
+ # @example
665
+ # def options(opt)
666
+ # opt.banner "Gists methods or classes"
667
+ # opt.on(:c, :class, "gist a class") do
668
+ # @action = :class
669
+ # end
670
+ # end
671
+ def options(opt); end
672
+
673
+ # The actual body of your command should go here.
674
+ #
675
+ # The `opts` mehod can be called to get the options that Slop has passed,
676
+ # and `args` gives the remaining, unparsed arguments.
677
+ #
678
+ # The return value of this method is discarded unless the command was
679
+ # created with `:keep_retval => true`, in which case it is returned to the
680
+ # repl.
681
+ #
682
+ # @example
683
+ # def process
684
+ # if opts.present?(:class)
685
+ # gist_class
686
+ # else
687
+ # gist_method
688
+ # end
689
+ # end
690
+ def process; raise CommandError, "command '#{command_name}' not implemented" end
691
+ end
692
+ end