pry 0.9.8pre2 → 0.9.8pre3

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -19,9 +19,9 @@ def apply_spec_defaults(s)
19
19
  s.executables = ['pry']
20
20
  s.files = `git ls-files`.split("\n")
21
21
  s.test_files = `git ls-files -- test/*`.split("\n")
22
- s.add_dependency('coderay', '~> 0.9')
22
+ s.add_dependency('coderay', '~> 1.0.5')
23
23
  s.add_dependency('slop', ['>= 2.4.1', '< 3'])
24
- s.add_dependency('method_source','~> 0.6')
24
+ s.add_dependency('method_source','~> 0.7')
25
25
  s.add_development_dependency('bacon', '~> 1.1')
26
26
  s.add_development_dependency('open4', '~> 1.3')
27
27
  s.add_development_dependency('rake', '~> 0.9')
@@ -29,9 +29,9 @@ end
29
29
 
30
30
  def check_dependencies
31
31
  require 'bundler'
32
-
33
- ENV["BUNDLE_GEMFILE"] = File.expand_path("../Gemfile", __FILE__)
34
32
  Bundler.definition.missing_specs
33
+
34
+ eval('nil', TOPLEVEL_BINDING, '<main>') # workaround for issue #395
35
35
  rescue LoadError
36
36
  # if Bundler isn't installed, we'll just assume your setup is ok.
37
37
  rescue Bundler::GemNotFound
@@ -65,6 +65,9 @@ task :profile do
65
65
  Pry.start(TOPLEVEL_BINDING, :input => StringIO.new('exit'))
66
66
  end
67
67
 
68
+ desc "Build the gemspec file"
69
+ task :gemspec => "ruby:gemspec"
70
+
68
71
  namespace :ruby do
69
72
  spec = Gem::Specification.new do |s|
70
73
  apply_spec_defaults(s)
@@ -76,7 +79,6 @@ namespace :ruby do
76
79
  pkg.need_tar = false
77
80
  end
78
81
 
79
- desc "Generate gemspec file"
80
82
  task :gemspec do
81
83
  File.open("#{spec.name}.gemspec", "w") do |f|
82
84
  f << spec.to_ruby
@@ -114,7 +116,7 @@ end
114
116
  end
115
117
 
116
118
  desc "build all platform gems at once"
117
- task :gems => [:clean, :rmgems, 'ruby:gem', 'mswin32:gem', 'mingw32:gem', 'jruby:gem']
119
+ task :gems => [:clean, :rmgems, :gemspec, 'ruby:gem', 'mswin32:gem', 'mingw32:gem', 'jruby:gem']
118
120
 
119
121
  desc "remove all platform gems"
120
122
  task :rmgems => ['ruby:clobber_package']
data/lib/pry.rb CHANGED
@@ -13,7 +13,7 @@ class Pry
13
13
  file = target.eval('__FILE__')
14
14
 
15
15
  # /unknown/ for rbx
16
- if file !~ /(\(.*\))|<.*>/ && file !~ /__unknown__/ && file != "" && file != "-e"
16
+ if file !~ /(\(.*\))|<.*>/ && file !~ /__unknown__/ && file != "" && file != "-e" || file == Pry.eval_path
17
17
  _pry_.run_command("whereami 5", "", target)
18
18
  end
19
19
  end
@@ -157,8 +157,9 @@ require "stringio"
157
157
  require "coderay"
158
158
  require "optparse"
159
159
  require "slop"
160
+ require "rbconfig"
160
161
 
161
- if RUBY_PLATFORM =~ /jruby/
162
+ if Pry::Helpers::BaseHelpers.jruby?
162
163
  begin
163
164
  require 'ffi'
164
165
  rescue LoadError
@@ -166,7 +167,7 @@ if RUBY_PLATFORM =~ /jruby/
166
167
  end
167
168
  end
168
169
 
169
- if RUBY_PLATFORM =~ /mswin/ || RUBY_PLATFORM =~ /mingw/
170
+ if Pry::Helpers::BaseHelpers.windows?
170
171
  begin
171
172
  require 'win32console'
172
173
  rescue LoadError
@@ -183,9 +184,9 @@ require "pry/wrapped_module"
183
184
  require "pry/history_array"
184
185
  require "pry/helpers"
185
186
  require "pry/history"
187
+ require "pry/command"
186
188
  require "pry/command_set"
187
189
  require "pry/commands"
188
- require "pry/command_context"
189
190
  require "pry/custom_completions"
190
191
  require "pry/completion"
191
192
  require "pry/plugins"
@@ -0,0 +1,396 @@
1
+ class Pry
2
+
3
+ # The super-class of all commands, new commands should be created by calling
4
+ # {Pry::CommandSet#command} which creates a BlockCommand or {Pry::CommandSet#command_class}
5
+ # which creates a ClassCommand. Please don't use this class directly.
6
+ class Command
7
+
8
+ # represents a void return value for a command
9
+ VOID_VALUE = Object.new
10
+
11
+ # give it a nice inspect
12
+ def VOID_VALUE.inspect() "void" end
13
+
14
+ # Properties of the command itself (as passed as arguments to
15
+ # {CommandSet#command} or {CommandSet#command_class}).
16
+ class << self
17
+ attr_accessor :name
18
+ attr_accessor :description
19
+ attr_accessor :options
20
+ attr_accessor :block
21
+ end
22
+
23
+ # Make those properties accessible to instances
24
+ def name; self.class.name; end
25
+ def description; self.class.description; end
26
+ def block; self.class.block; end
27
+ def command_options; self.class.options; end
28
+ def command_name; command_options[:listing]; end
29
+
30
+ class << self
31
+ def inspect
32
+ "#<class(Pry::Command #{name.inspect})>"
33
+ end
34
+
35
+ # Create a new command with the given properties.
36
+ #
37
+ # @param String name the name of the command
38
+ # @param String description the description to appear in {help}
39
+ # @param Hash options behavioural options (@see {Pry::CommandSet#command})
40
+ # @param Module helpers a module of helper functions to be included.
41
+ # @param Proc &block (optional, a block, used for BlockCommands)
42
+ #
43
+ # @return Class (a subclass of Pry::Command)
44
+ #
45
+ def subclass(name, description, options, helpers, &block)
46
+ klass = Class.new(self)
47
+ klass.send(:include, helpers)
48
+ klass.name = name
49
+ klass.description = description
50
+ klass.options = options
51
+ klass.block = block
52
+ klass
53
+ end
54
+
55
+ # Should this command be called for the given line?
56
+ #
57
+ # @param String a line input at the REPL
58
+ # @return Boolean
59
+ def matches?(val)
60
+ command_regex =~ val
61
+ end
62
+
63
+ # Store hooks to be run before or after the command body.
64
+ # @see {Pry::CommandSet#before_command}
65
+ # @see {Pry::CommandSet#after_command}
66
+ def hooks
67
+ @hooks ||= {:before => [], :after => []}
68
+ end
69
+
70
+ def command_regex
71
+ prefix = convert_to_regex(Pry.config.command_prefix)
72
+ prefix = "(?:#{prefix})?" unless options[:use_prefix]
73
+
74
+ /^#{prefix}#{convert_to_regex(name)}(?!\S)/
75
+ end
76
+
77
+ def convert_to_regex(obj)
78
+ case obj
79
+ when String
80
+ Regexp.escape(obj)
81
+ else
82
+ obj
83
+ end
84
+ end
85
+ end
86
+
87
+
88
+ # Properties of one execution of a command (passed by {Pry#run_command} as a hash of
89
+ # context and expanded in {#initialize}
90
+ attr_accessor :output
91
+ attr_accessor :target
92
+ attr_accessor :captures
93
+ attr_accessor :eval_string
94
+ attr_accessor :arg_string
95
+ attr_accessor :context
96
+ attr_accessor :command_set
97
+ attr_accessor :_pry_
98
+
99
+ # Run a command from another command.
100
+ # @param [String] command_string The string that invokes the command
101
+ # @param [Array] args Further arguments to pass to the command
102
+ # @example
103
+ # run "show-input"
104
+ # @example
105
+ # run ".ls"
106
+ # @example
107
+ # run "amend-line", "5", 'puts "hello world"'
108
+ def run(command_string, *args)
109
+ complete_string = "#{command_string} #{args.join(" ")}"
110
+ command_set.process_line(complete_string, context)
111
+ end
112
+
113
+ def commands
114
+ command_set.commands
115
+ end
116
+
117
+ def text
118
+ Pry::Helpers::Text
119
+ end
120
+
121
+ def void
122
+ VOID_VALUE
123
+ end
124
+
125
+ include Pry::Helpers::BaseHelpers
126
+ include Pry::Helpers::CommandHelpers
127
+
128
+
129
+ # Instantiate a command, in preparation for calling it.
130
+ #
131
+ # @param Hash context The runtime context to use with this command.
132
+ def initialize(context={})
133
+ self.context = context
134
+ self.target = context[:target]
135
+ self.output = context[:output]
136
+ self.eval_string = context[:eval_string]
137
+ self.command_set = context[:command_set]
138
+ self._pry_ = context[:pry_instance]
139
+ end
140
+
141
+ # The value of {self} inside the {target} binding.
142
+ def target_self; target.eval('self'); end
143
+
144
+ # Revaluate the string (str) and perform interpolation.
145
+ # @param [String] str The string to reevaluate with interpolation.
146
+ #
147
+ # @return [String] The reevaluated string with interpolations
148
+ # applied (if any).
149
+ def interpolate_string(str)
150
+ dumped_str = str.dump
151
+ if dumped_str.gsub!(/\\\#\{/, '#{')
152
+ target.eval(dumped_str)
153
+ else
154
+ str
155
+ end
156
+ end
157
+
158
+ # Display a warning if a command collides with a local/method in
159
+ # the current scope.
160
+ # @param [String] command_name_match The name of the colliding command.
161
+ # @param [Binding] target The current binding context.
162
+ def check_for_command_name_collision(command_name_match)
163
+ if collision_type = target.eval("defined?(#{command_name_match})")
164
+ output.puts "#{Pry::Helpers::Text.bold('WARNING:')} Command name collision with a #{collision_type}: '#{command_name_match}'\n\n"
165
+ end
166
+ rescue Pry::RescuableException
167
+ end
168
+
169
+ # Extract necessary information from a line that Command.matches? this command.
170
+ #
171
+ # @param String the line of input
172
+ # @return [
173
+ # String the command name used, or portion of line that matched the command_regex
174
+ # String a string of all the arguments (i.e. everything but the name)
175
+ # Array the captures caught by the command_regex
176
+ # Array args the arguments got by splitting the arg_string
177
+ # ]
178
+ def tokenize(val)
179
+ val.replace(interpolate_string(val)) if command_options[:interpolate]
180
+
181
+ self.class.command_regex =~ val
182
+
183
+ # please call Command.matches? before Command#call_safely
184
+ raise CommandError, "fatal: called a command which didn't match?!" unless Regexp.last_match
185
+ captures = Regexp.last_match.captures
186
+ pos = Regexp.last_match.end(0)
187
+
188
+ arg_string = val[pos..-1]
189
+
190
+ # remove the one leading space if it exists
191
+ arg_string.slice!(0) if arg_string.start_with?(" ")
192
+
193
+ if arg_string
194
+ args = command_options[:shellwords] ? Shellwords.shellwords(arg_string) : arg_string.split(" ")
195
+ else
196
+ args = []
197
+ end
198
+
199
+ [val[0..pos].rstrip, arg_string, captures, args]
200
+ end
201
+
202
+ # Process a line that Command.matches? this command.
203
+ #
204
+ # @param String the line to process
205
+ # @return Object or Command::VOID_VALUE
206
+ def process_line(line)
207
+ command_name, arg_string, captures, args = tokenize(line)
208
+
209
+ check_for_command_name_collision(command_name) if Pry.config.collision_warning
210
+
211
+ self.arg_string = arg_string
212
+ self.captures = captures
213
+
214
+ call_safely(*(captures + args))
215
+ end
216
+
217
+ # Run the command with the given {args}.
218
+ #
219
+ # This is a public wrapper around {#call} which ensures all preconditions are met.
220
+ #
221
+ # @param *[String] the arguments to pass to this command.
222
+ # @return Object the return value of the {#call} method, or Command::VOID_VALUE
223
+ def call_safely(*args)
224
+ unless dependencies_met?
225
+ gems_needed = Array(command_options[:requires_gem])
226
+ gems_not_installed = gems_needed.select { |g| !gem_installed?(g) }
227
+ output.puts "\nThe command '#{name}' is #{Helpers::Text.bold("unavailable")} because it requires the following gems to be installed: #{(gems_not_installed.join(", "))}"
228
+ output.puts "-"
229
+ output.puts "Type `install-command #{name}` to install the required gems and activate this command."
230
+ return void
231
+ end
232
+
233
+ if command_options[:argument_required] && args.empty?
234
+ raise CommandError, "The command '#{name}' requires an argument."
235
+ end
236
+
237
+ ret = call_with_hooks(*args)
238
+ command_options[:keep_retval] ? ret : void
239
+ end
240
+
241
+ # Are all the gems required to use this command installed?
242
+ #
243
+ # @return Boolean
244
+ def dependencies_met?
245
+ @dependencies_met ||= command_dependencies_met?(command_options)
246
+ end
247
+
248
+ private
249
+
250
+ # Run the {#call} method and all the registered hooks.
251
+ #
252
+ # @param *String the arguments to #{call}
253
+ # @return Object the return value from #{call}
254
+ def call_with_hooks(*args)
255
+ self.class.hooks[:before].each do |block|
256
+ instance_exec(*args, &block)
257
+ end
258
+
259
+ ret = call *args
260
+
261
+ self.class.hooks[:after].each do |block|
262
+ ret = instance_exec(*args, &block)
263
+ end
264
+
265
+ ret
266
+ end
267
+ end
268
+
269
+ # A super-class for Commands that are created with a single block.
270
+ #
271
+ # This class ensures that the block is called with the correct number of arguments
272
+ # and the right context.
273
+ #
274
+ # Create subclasses using {Pry::CommandSet#command}.
275
+ class BlockCommand < Command
276
+ # backwards compatibility
277
+ alias_method :opts, :context
278
+
279
+ def call(*args)
280
+ instance_exec(*correct_arg_arity(block.arity, args), &block)
281
+ end
282
+
283
+ def correct_arg_arity(arity, args)
284
+ case
285
+ when arity < 0
286
+ args
287
+ when arity == 0
288
+ []
289
+ when arity > 0
290
+ args.values_at *(0..(arity - 1)).to_a
291
+ end
292
+ end
293
+
294
+ def help; description; end
295
+ end
296
+
297
+ # A super-class ofr Commands with structure.
298
+ #
299
+ # This class implements the bare-minimum functionality that a command should have,
300
+ # namely a --help switch, and then delegates actual processing to its subclasses.
301
+ #
302
+ # Create subclasses using {Pry::CommandSet#command_class}, and override the {options(opt)} method
303
+ # to set up an instance of Slop, and the {process} method to actually run the command. If
304
+ # necessary, you can also override {setup} which will be called before {options}, for example to
305
+ # require any gems your command needs to run, or to set up state.
306
+ class ClassCommand < Command
307
+ class << self
308
+ def banner(arg=nil)
309
+ @banner = arg if arg
310
+ @banner || description
311
+ end
312
+ end
313
+
314
+ attr_accessor :opts
315
+ attr_accessor :args
316
+
317
+ # Set up {opts} and {args}, and then call {process}
318
+ #
319
+ # This function will display help if necessary.
320
+ #
321
+ # @param *String the arguments passed
322
+ # @return Object the return value of {process} or VOID_VALUE
323
+ def call(*args)
324
+ setup
325
+
326
+ self.opts = slop
327
+ self.args = self.opts.parse!(args)
328
+
329
+ if opts.present?(:help)
330
+ output.puts slop.help
331
+ void
332
+ else
333
+ process
334
+ end
335
+ end
336
+
337
+ # Return the help generated by Slop for this command.
338
+ def help
339
+ slop.help
340
+ end
341
+
342
+ # Return an instance of Slop that can parse the options that this command accepts.
343
+ def slop
344
+ Slop.new do |opt|
345
+ opt.banner(unindent(self.class.banner))
346
+ options(opt)
347
+ opt.on(:h, :help, "Show this message.")
348
+ end
349
+ end
350
+
351
+ # A function called just before {options(opt)} as part of {call}.
352
+ #
353
+ # This function can be used to set up any context your command needs to run, for example
354
+ # requiring gems, or setting default values for options.
355
+ #
356
+ # @example
357
+ # def setup;
358
+ # require 'gist'
359
+ # @action = :method
360
+ # end
361
+ def setup; end
362
+
363
+ # A function to setup Slop so it can parse the options your command expects.
364
+ #
365
+ # NOTE: please don't do anything side-effecty in the main part of this method,
366
+ # as it may be called by Pry at any time for introspection reasons. If you need
367
+ # to set up default values, use {setup} instead.
368
+ #
369
+ # @example
370
+ # def options(opt)
371
+ # opt.banner "Gists methods or classes"
372
+ # opt.on(:c, :class, "gist a class") do
373
+ # @action = :class
374
+ # end
375
+ # end
376
+ def options(opt); end
377
+
378
+ # The actual body of your command should go here.
379
+ #
380
+ # The {opts} mehod can be called to get the options that Slop has passed,
381
+ # and {args} gives the remaining, unparsed arguments.
382
+ #
383
+ # The return value of this method is discarded unless the command was created
384
+ # with :keep_retval => true, in which case it is returned to the repl.
385
+ #
386
+ # @example
387
+ # def process
388
+ # if opts.present?(:class)
389
+ # gist_class
390
+ # else
391
+ # gist_method
392
+ # end
393
+ # end
394
+ def process; raise CommandError, "command '#{name}' not implemented" end
395
+ end
396
+ end