pry 0.3.0 → 0.4.0pre1
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/CHANGELOG +10 -0
- data/README.markdown +442 -29
- data/lib/pry.rb +10 -247
- data/lib/pry/command_base.rb +114 -0
- data/lib/pry/commands.rb +115 -0
- data/lib/pry/completion.rb +202 -0
- data/lib/pry/core_extensions.rb +47 -0
- data/lib/pry/hooks.rb +8 -0
- data/lib/pry/print.rb +15 -0
- data/lib/pry/prompts.rb +24 -0
- data/lib/pry/pry_class.rb +109 -0
- data/lib/pry/pry_instance.rb +309 -0
- data/lib/pry/version.rb +1 -1
- data/test/test.rb +528 -0
- data/test/test_helper.rb +38 -0
- metadata +21 -15
- data/lib/pry/input.rb +0 -22
- data/lib/pry/output.rb +0 -100
data/lib/pry.rb
CHANGED
@@ -4,254 +4,17 @@
|
|
4
4
|
direc = File.dirname(__FILE__)
|
5
5
|
|
6
6
|
require "method_source"
|
7
|
+
require "readline"
|
7
8
|
require "#{direc}/pry/version"
|
8
|
-
require "#{direc}/pry/
|
9
|
-
require "#{direc}/pry/
|
9
|
+
require "#{direc}/pry/hooks"
|
10
|
+
require "#{direc}/pry/print"
|
11
|
+
require "#{direc}/pry/command_base"
|
12
|
+
require "#{direc}/pry/commands"
|
13
|
+
require "#{direc}/pry/prompts"
|
14
|
+
require "#{direc}/pry/completion"
|
15
|
+
require "#{direc}/pry/core_extensions"
|
16
|
+
require "#{direc}/pry/pry_class"
|
17
|
+
require "#{direc}/pry/pry_instance"
|
10
18
|
|
11
|
-
class Pry
|
12
|
-
def self.start(target=TOPLEVEL_BINDING)
|
13
|
-
new.repl(target)
|
14
|
-
end
|
15
19
|
|
16
|
-
def self.view(obj)
|
17
|
-
case obj
|
18
|
-
when String, Array, Hash, Symbol, nil
|
19
|
-
obj.inspect
|
20
|
-
else
|
21
|
-
obj.to_s
|
22
|
-
end
|
23
|
-
end
|
24
20
|
|
25
|
-
# class accessors
|
26
|
-
class << self
|
27
|
-
attr_reader :nesting
|
28
|
-
attr_accessor :last_result
|
29
|
-
attr_accessor :default_prompt, :wait_prompt
|
30
|
-
end
|
31
|
-
|
32
|
-
self.default_prompt = proc do |v, nest|
|
33
|
-
if nest == 0
|
34
|
-
"pry(#{Pry.view(v)})> "
|
35
|
-
else
|
36
|
-
"pry(#{Pry.view(v)}):#{Pry.view(nest)}> "
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
self.wait_prompt = proc do |v, nest|
|
41
|
-
if nest == 0
|
42
|
-
"pry(#{Pry.view(v)})* "
|
43
|
-
else
|
44
|
-
"pry(#{Pry.view(v)}):#{Pry.view(nest)}* "
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
attr_accessor :input, :output
|
49
|
-
attr_accessor :default_prompt, :wait_prompt
|
50
|
-
attr_reader :last_result
|
51
|
-
|
52
|
-
def initialize(input = Input.new, output = Output.new)
|
53
|
-
@input = input
|
54
|
-
@output = output
|
55
|
-
|
56
|
-
@default_prompt = Pry.default_prompt
|
57
|
-
@wait_prompt = Pry.wait_prompt
|
58
|
-
end
|
59
|
-
|
60
|
-
@nesting = []
|
61
|
-
|
62
|
-
def @nesting.level
|
63
|
-
last.is_a?(Array) ? last.first : nil
|
64
|
-
end
|
65
|
-
|
66
|
-
def nesting
|
67
|
-
self.class.nesting
|
68
|
-
end
|
69
|
-
|
70
|
-
def nesting=(v)
|
71
|
-
self.class.nesting = v
|
72
|
-
end
|
73
|
-
|
74
|
-
# loop
|
75
|
-
def repl(target=TOPLEVEL_BINDING)
|
76
|
-
target = binding_for(target)
|
77
|
-
target_self = target.eval('self')
|
78
|
-
output.session_start(target_self)
|
79
|
-
|
80
|
-
nesting_level = nesting.size
|
81
|
-
|
82
|
-
# Make sure _ exists
|
83
|
-
target.eval("_ = Pry.last_result")
|
84
|
-
|
85
|
-
break_level = catch(:breakout) do
|
86
|
-
nesting << [nesting.size, target_self]
|
87
|
-
loop do
|
88
|
-
rep(target)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
nesting.pop
|
93
|
-
output.session_end(target_self)
|
94
|
-
|
95
|
-
# we only enter here if :breakout has been thrown
|
96
|
-
if nesting_level != break_level
|
97
|
-
throw :breakout, break_level
|
98
|
-
end
|
99
|
-
|
100
|
-
target_self
|
101
|
-
end
|
102
|
-
|
103
|
-
# print
|
104
|
-
def rep(target=TOPLEVEL_BINDING)
|
105
|
-
target = binding_for(target)
|
106
|
-
output.print re(target)
|
107
|
-
end
|
108
|
-
|
109
|
-
# eval
|
110
|
-
def re(target=TOPLEVEL_BINDING)
|
111
|
-
target = binding_for(target)
|
112
|
-
Pry.last_result = target.eval r(target)
|
113
|
-
target.eval("_ = Pry.last_result")
|
114
|
-
rescue SystemExit => e
|
115
|
-
exit
|
116
|
-
rescue Exception => e
|
117
|
-
e
|
118
|
-
end
|
119
|
-
|
120
|
-
# read
|
121
|
-
def r(target=TOPLEVEL_BINDING)
|
122
|
-
target = binding_for(target)
|
123
|
-
eval_string = ""
|
124
|
-
loop do
|
125
|
-
val = input.read(prompt(eval_string, target, nesting.level))
|
126
|
-
eval_string += "#{val.chomp}\n"
|
127
|
-
process_commands(val, eval_string, target)
|
128
|
-
|
129
|
-
break eval_string if valid_expression?(eval_string)
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
def process_commands(val, eval_string, target)
|
134
|
-
def eval_string.clear() replace("") end
|
135
|
-
|
136
|
-
case val
|
137
|
-
when "exit_program", "quit_program"
|
138
|
-
output.exit_program
|
139
|
-
exit
|
140
|
-
when "!"
|
141
|
-
output.refresh
|
142
|
-
eval_string.clear
|
143
|
-
when "help"
|
144
|
-
output.show_help
|
145
|
-
eval_string.clear
|
146
|
-
when "nesting"
|
147
|
-
output.show_nesting(nesting)
|
148
|
-
eval_string.clear
|
149
|
-
when "status"
|
150
|
-
output.show_status(nesting, target)
|
151
|
-
eval_string.clear
|
152
|
-
when "exit_all"
|
153
|
-
throw(:breakout, 0)
|
154
|
-
when "exit", "quit", "back", /^cd\s*\.\./
|
155
|
-
output.exit
|
156
|
-
throw(:breakout, nesting.level)
|
157
|
-
when "ls"
|
158
|
-
output.ls(target)
|
159
|
-
eval_string.clear
|
160
|
-
when /^cat\s+(.+)/
|
161
|
-
var = $~.captures.first
|
162
|
-
output.cat(target, var)
|
163
|
-
eval_string.clear
|
164
|
-
when /^cd\s+(.+)/
|
165
|
-
obj = $~.captures.first
|
166
|
-
target.eval("#{obj}.pry")
|
167
|
-
eval_string.clear
|
168
|
-
when /^show_doc\s*(.+)/
|
169
|
-
meth_name = ($~.captures).first
|
170
|
-
doc = target.eval("method(:#{meth_name})").comment
|
171
|
-
output.show_doc doc
|
172
|
-
eval_string.clear
|
173
|
-
when /^show_idoc\s*(.+)/
|
174
|
-
meth_name = ($~.captures).first
|
175
|
-
doc = target.eval("instance_method(:#{meth_name})").comment
|
176
|
-
output.show_doc doc
|
177
|
-
eval_string.clear
|
178
|
-
when /^show_method\s*(.+)/
|
179
|
-
meth_name = ($~.captures).first
|
180
|
-
code = target.eval("method(:#{meth_name})").source
|
181
|
-
output.show_method code
|
182
|
-
eval_string.clear
|
183
|
-
when /^show_instance_method\s*(.+)/, /^show_imethod\s*(.+)/
|
184
|
-
meth_name = ($~.captures).first
|
185
|
-
code = target.eval("instance_method(:#{meth_name})").source
|
186
|
-
output.show_method code
|
187
|
-
eval_string.clear
|
188
|
-
when /^jump_to\s*(\d*)/
|
189
|
-
break_level = ($~.captures).first.to_i
|
190
|
-
output.jump_to(break_level)
|
191
|
-
|
192
|
-
case break_level
|
193
|
-
when nesting.level
|
194
|
-
output.warn_already_at_level(nesting.level)
|
195
|
-
eval_string.clear
|
196
|
-
when (0...nesting.level)
|
197
|
-
throw(:breakout, break_level + 1)
|
198
|
-
else
|
199
|
-
output.err_invalid_nest_level(break_level,
|
200
|
-
nesting.level - 1)
|
201
|
-
eval_string.clear
|
202
|
-
end
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
def prompt(eval_string, target, nest)
|
207
|
-
target_self = target.eval('self')
|
208
|
-
|
209
|
-
if eval_string.empty?
|
210
|
-
default_prompt.call(target_self, nest)
|
211
|
-
else
|
212
|
-
wait_prompt.call(target_self, nest)
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
if RUBY_VERSION =~ /1.9/
|
217
|
-
require 'ripper'
|
218
|
-
|
219
|
-
def valid_expression?(code)
|
220
|
-
!!Ripper::SexpBuilder.new(code).parse
|
221
|
-
end
|
222
|
-
|
223
|
-
else
|
224
|
-
require 'ruby_parser'
|
225
|
-
|
226
|
-
def valid_expression?(code)
|
227
|
-
RubyParser.new.parse(code)
|
228
|
-
rescue Racc::ParseError, SyntaxError
|
229
|
-
false
|
230
|
-
else
|
231
|
-
true
|
232
|
-
end
|
233
|
-
|
234
|
-
end
|
235
|
-
|
236
|
-
def binding_for(target)
|
237
|
-
if target.is_a?(Binding)
|
238
|
-
target
|
239
|
-
else
|
240
|
-
if target == TOPLEVEL_BINDING.eval('self')
|
241
|
-
TOPLEVEL_BINDING
|
242
|
-
else
|
243
|
-
target.instance_eval { binding }
|
244
|
-
end
|
245
|
-
end
|
246
|
-
end
|
247
|
-
|
248
|
-
module ObjectExtensions
|
249
|
-
def pry(target=self)
|
250
|
-
Pry.start(target)
|
251
|
-
end
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
class Object
|
256
|
-
include Pry::ObjectExtensions
|
257
|
-
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
class Pry
|
2
|
+
|
3
|
+
# Basic command functionality. All user-defined commands must
|
4
|
+
# inherit from this class. It provides the `command` method.
|
5
|
+
class CommandBase
|
6
|
+
class << self
|
7
|
+
attr_accessor :commands
|
8
|
+
attr_accessor :command_info
|
9
|
+
attr_accessor :opts, :output, :target
|
10
|
+
|
11
|
+
# private because we want to force function style invocation. We require
|
12
|
+
# that the location where the block is defined has the `opts`
|
13
|
+
# method in scope.
|
14
|
+
private
|
15
|
+
|
16
|
+
# Defines a new Pry command.
|
17
|
+
# @param [String, Array] names The name of the command (or array of
|
18
|
+
# command name aliases).
|
19
|
+
# @param [String] description A description of the command.
|
20
|
+
# @yield The action to perform. The parameters in the block
|
21
|
+
# determines the parameters the command will receive. All
|
22
|
+
# parameters passed into the block will be strings. Successive
|
23
|
+
# command parameters are separated by whitespace at the Pry prompt.
|
24
|
+
# @example
|
25
|
+
# class MyCommands < Pry::CommandBase
|
26
|
+
# command "greet", "Greet somebody" do |name|
|
27
|
+
# puts "Good afternoon #{name.capitalize}!"
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# # From pry:
|
32
|
+
# # pry(main)> _pry_.commands = MyCommands
|
33
|
+
# # pry(main)> greet john
|
34
|
+
# # Good afternoon John!
|
35
|
+
# # pry(main)> help greet
|
36
|
+
# # Greet somebody
|
37
|
+
def command(names, description="No description.", &block)
|
38
|
+
@commands ||= {}
|
39
|
+
|
40
|
+
Array(names).each do |name|
|
41
|
+
commands[name] = { :description => description, :action => block }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Delete a command or an array of commands.
|
46
|
+
# Useful when inheriting from another command set and pruning
|
47
|
+
# those commands down to the ones you want.
|
48
|
+
# @param [Array<String>] names The command name or array
|
49
|
+
# of command names you want to delete
|
50
|
+
# @example Deleteing inherited commands
|
51
|
+
# class MyCommands < Pry::Commands
|
52
|
+
# delete "show_method", "show_imethod", "show_doc", "show_idoc"
|
53
|
+
# end
|
54
|
+
# Pry.commands = MyCommands
|
55
|
+
def delete(*names)
|
56
|
+
names.each { |name| commands.delete(name) }
|
57
|
+
end
|
58
|
+
|
59
|
+
# Execute a command (this enables commands to call other commands).
|
60
|
+
# @param [String] name The command to execute
|
61
|
+
# @param [Array] args The parameters to pass to the command.
|
62
|
+
# @example Wrap one command with another
|
63
|
+
# class MyCommands < Pry::Commands
|
64
|
+
# command "ls2" do
|
65
|
+
# output.puts "before ls"
|
66
|
+
# run "ls"
|
67
|
+
# output.puts "after ls"
|
68
|
+
# end
|
69
|
+
# end
|
70
|
+
def run(name, *args)
|
71
|
+
action = opts[:commands][name][:action]
|
72
|
+
instance_exec(*args, &action)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Import commands from another command object.
|
76
|
+
# @param [Pry::CommandBase] klass The class to import from (must
|
77
|
+
# be a subclass of `Pry::CommandBase`)
|
78
|
+
# @param [Array<String>] names The commands to import.
|
79
|
+
# @example
|
80
|
+
# class MyCommands < Pry::CommandBase
|
81
|
+
# import_from Pry::Commands, "ls", "show_method", "cd"
|
82
|
+
# end
|
83
|
+
def import_from(klass, *names)
|
84
|
+
imported_hash = Hash[klass.commands.select { |k, v| names.include?(k) }]
|
85
|
+
commands.merge!(imported_hash)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
command "help", "This menu." do |cmd|
|
90
|
+
command_info = opts[:commands]
|
91
|
+
param = cmd
|
92
|
+
|
93
|
+
if !param
|
94
|
+
output.puts "Command list:"
|
95
|
+
output.puts "--"
|
96
|
+
command_info.each do |k, data|
|
97
|
+
output.puts "#{k}".ljust(18) + data[:description] if !data[:description].empty?
|
98
|
+
end
|
99
|
+
else
|
100
|
+
if command_info[param]
|
101
|
+
output.puts command_info[param][:description]
|
102
|
+
else
|
103
|
+
output.puts "No info for command: #{param}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Ensures that commands can be inherited
|
109
|
+
def self.inherited(klass)
|
110
|
+
klass.commands = commands.dup
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
data/lib/pry/commands.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
direc = File.dirname(__FILE__)
|
2
|
+
require "#{direc}/command_base"
|
3
|
+
|
4
|
+
class Pry
|
5
|
+
|
6
|
+
# Default commands used by Pry.
|
7
|
+
class Commands < CommandBase
|
8
|
+
|
9
|
+
command "!", "Refresh the REPL" do
|
10
|
+
output.puts "Refreshed REPL"
|
11
|
+
opts[:eval_string].clear
|
12
|
+
end
|
13
|
+
|
14
|
+
command "!pry", "Start a Pry session on current self; this even works mid-expression." do
|
15
|
+
Pry.start(target)
|
16
|
+
end
|
17
|
+
|
18
|
+
command ["exit_program", "quit_program"], "End the current program." do
|
19
|
+
exit
|
20
|
+
end
|
21
|
+
|
22
|
+
command "nesting", "Show nesting information." do
|
23
|
+
out = output
|
24
|
+
nesting = opts[:nesting]
|
25
|
+
|
26
|
+
out.puts "Nesting status:"
|
27
|
+
out.puts "--"
|
28
|
+
nesting.each do |level, obj|
|
29
|
+
if level == 0
|
30
|
+
out.puts "#{level}. #{Pry.view(obj)} (Pry top level)"
|
31
|
+
else
|
32
|
+
out.puts "#{level}. #{Pry.view(obj)}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
command "status", "Show status information." do
|
38
|
+
out = output
|
39
|
+
nesting = opts[:nesting]
|
40
|
+
|
41
|
+
out.puts "Status:"
|
42
|
+
out.puts "--"
|
43
|
+
out.puts "Receiver: #{Pry.view(target.eval('self'))}"
|
44
|
+
out.puts "Nesting level: #{nesting.level}"
|
45
|
+
out.puts "Local variables: #{Pry.view(target.eval('local_variables'))}"
|
46
|
+
out.puts "Pry instance: #{Pry.active_instance}"
|
47
|
+
out.puts "Last result: #{Pry.view(Pry.last_result)}"
|
48
|
+
end
|
49
|
+
|
50
|
+
command "exit_all", "End all nested Pry sessions." do
|
51
|
+
throw(:breakout, 0)
|
52
|
+
end
|
53
|
+
|
54
|
+
command "ls", "Show the list of vars in the current scope." do
|
55
|
+
output.puts "#{Pry.view(target.eval('local_variables + instance_variables'))}"
|
56
|
+
end
|
57
|
+
|
58
|
+
command "cat", "Show output of <var>.inspect." do |obj|
|
59
|
+
out = output
|
60
|
+
out.puts target.eval("#{obj}.inspect")
|
61
|
+
end
|
62
|
+
|
63
|
+
command "cd", "Start a Pry session on <var> (use `cd ..` to go back)" do |obj|
|
64
|
+
throw(:breakout, opts[:nesting].level) if obj == ".."
|
65
|
+
target.eval("#{obj}.pry")
|
66
|
+
end
|
67
|
+
|
68
|
+
command "show_doc", "Show the comments above <methname>" do |meth_name|
|
69
|
+
doc = target.eval("method(:#{meth_name})").comment
|
70
|
+
output.puts doc
|
71
|
+
end
|
72
|
+
|
73
|
+
command "show_idoc", "Show the comments above instance method <methname>" do |meth_name|
|
74
|
+
doc = target.eval("instance_method(:#{meth_name})").comment
|
75
|
+
output.puts doc
|
76
|
+
end
|
77
|
+
|
78
|
+
command "show_method", "Show sourcecode for method <methname>." do |meth_name|
|
79
|
+
doc = target.eval("method(:#{meth_name})").source
|
80
|
+
output.puts doc
|
81
|
+
end
|
82
|
+
|
83
|
+
command "show_imethod", "Show sourcecode for instance method <methname>." do |meth_name|
|
84
|
+
doc = target.eval("instance_method(:#{meth_name})").source
|
85
|
+
output.puts doc
|
86
|
+
end
|
87
|
+
|
88
|
+
command "jump_to", "Jump to a Pry session further up the stack, exiting all sessions below." do |break_level|
|
89
|
+
break_level = break_level.to_i
|
90
|
+
nesting = opts[:nesting]
|
91
|
+
|
92
|
+
case break_level
|
93
|
+
when nesting.level
|
94
|
+
output.puts "Already at nesting level #{nesting.level}"
|
95
|
+
when (0...nesting.level)
|
96
|
+
throw(:breakout, break_level + 1)
|
97
|
+
else
|
98
|
+
max_nest_level = nesting.level - 1
|
99
|
+
output.puts "Invalid nest level. Must be between 0 and #{max_nest_level}. Got #{break_level}."
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
command "ls_methods", "List all methods defined on class of receiver." do
|
104
|
+
output.puts "#{Pry.view(target.eval('public_methods(false) + private_methods(false) + protected_methods(false)'))}"
|
105
|
+
end
|
106
|
+
|
107
|
+
command "ls_imethods", "List all instance methods defined on class of receiver." do
|
108
|
+
output.puts "#{Pry.view(target.eval('public_instance_methods(false) + private_instance_methods(false) + protected_instance_methods(false)'))}"
|
109
|
+
end
|
110
|
+
|
111
|
+
command ["exit", "quit", "back"], "End the current Pry session." do
|
112
|
+
throw(:breakout, opts[:nesting].level)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|