pry 0.9.8pre2-java → 0.9.8pre3-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +8 -6
- data/lib/pry.rb +5 -4
- data/lib/pry/command.rb +396 -0
- data/lib/pry/command_set.rb +112 -95
- data/lib/pry/default_commands/documentation.rb +153 -82
- data/lib/pry/default_commands/easter_eggs.rb +25 -1
- data/lib/pry/default_commands/input.rb +4 -30
- data/lib/pry/default_commands/introspection.rb +69 -66
- data/lib/pry/default_commands/ls.rb +91 -94
- data/lib/pry/default_commands/shell.rb +1 -1
- data/lib/pry/helpers/base_helpers.rb +7 -2
- data/lib/pry/helpers/command_helpers.rb +29 -4
- data/lib/pry/helpers/options_helpers.rb +6 -40
- data/lib/pry/helpers/text.rb +1 -1
- data/lib/pry/method.rb +42 -4
- data/lib/pry/pry_class.rb +16 -6
- data/lib/pry/pry_instance.rb +15 -7
- data/lib/pry/version.rb +1 -1
- data/lib/pry/wrapped_module.rb +1 -1
- data/pry.gemspec +11 -11
- data/test/helper.rb +8 -12
- data/test/test_command.rb +317 -0
- data/test/test_command_set.rb +152 -18
- data/test/test_completion.rb +1 -1
- data/test/test_default_commands.rb +1 -2
- data/test/test_default_commands/test_introspection.rb +6 -6
- data/test/test_default_commands/test_ls.rb +1 -1
- data/test/test_default_commands/test_shell.rb +4 -2
- data/test/test_hooks.rb +16 -0
- data/test/test_method.rb +50 -0
- data/test/test_pry.rb +37 -39
- data/test/test_syntax_checking.rb +1 -1
- metadata +80 -75
- data/lib/pry/command_context.rb +0 -53
- data/lib/pry/command_processor.rb +0 -194
- data/test/test_command_processor.rb +0 -176
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.
|
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.
|
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
|
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
|
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"
|
data/lib/pry/command.rb
ADDED
@@ -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
|