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
@@ -0,0 +1,202 @@
|
|
1
|
+
# taken from irb
|
2
|
+
|
3
|
+
require "readline"
|
4
|
+
|
5
|
+
class Pry
|
6
|
+
|
7
|
+
# Implements tab completion for Readline in Pry
|
8
|
+
module InputCompleter
|
9
|
+
|
10
|
+
if Readline.respond_to?("basic_word_break_characters=")
|
11
|
+
Readline.basic_word_break_characters= " \t\n\"\\'`><=;|&{("
|
12
|
+
end
|
13
|
+
|
14
|
+
Readline.completion_append_character = nil
|
15
|
+
|
16
|
+
ReservedWords = [
|
17
|
+
"BEGIN", "END",
|
18
|
+
"alias", "and",
|
19
|
+
"begin", "break",
|
20
|
+
"case", "class",
|
21
|
+
"def", "defined", "do",
|
22
|
+
"else", "elsif", "end", "ensure",
|
23
|
+
"false", "for",
|
24
|
+
"if", "in",
|
25
|
+
"module",
|
26
|
+
"next", "nil", "not",
|
27
|
+
"or",
|
28
|
+
"redo", "rescue", "retry", "return",
|
29
|
+
"self", "super",
|
30
|
+
"then", "true",
|
31
|
+
"undef", "unless", "until",
|
32
|
+
"when", "while",
|
33
|
+
"yield",
|
34
|
+
]
|
35
|
+
|
36
|
+
Operators = ["%", "&", "*", "**", "+", "-", "/",
|
37
|
+
"<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>",
|
38
|
+
"[]", "[]=", "^", "!", "!=", "!~"]
|
39
|
+
|
40
|
+
# Return a new completion proc for use by Readline.
|
41
|
+
# @param [Binding] target The current binding context.
|
42
|
+
# @param [Array<String>] commands The array of Pry commands.
|
43
|
+
def self.build_completion_proc(target, commands=[""])
|
44
|
+
proc do |input|
|
45
|
+
bind = target
|
46
|
+
|
47
|
+
case input
|
48
|
+
when /^(\/[^\/]*\/)\.([^.]*)$/
|
49
|
+
# Regexp
|
50
|
+
receiver = $1
|
51
|
+
message = Regexp.quote($2)
|
52
|
+
|
53
|
+
candidates = Regexp.instance_methods.collect{|m| m.to_s}
|
54
|
+
select_message(receiver, message, candidates)
|
55
|
+
|
56
|
+
when /^([^\]]*\])\.([^.]*)$/
|
57
|
+
# Array
|
58
|
+
receiver = $1
|
59
|
+
message = Regexp.quote($2)
|
60
|
+
|
61
|
+
candidates = Array.instance_methods.collect{|m| m.to_s}
|
62
|
+
select_message(receiver, message, candidates)
|
63
|
+
|
64
|
+
when /^([^\}]*\})\.([^.]*)$/
|
65
|
+
# Proc or Hash
|
66
|
+
receiver = $1
|
67
|
+
message = Regexp.quote($2)
|
68
|
+
|
69
|
+
candidates = Proc.instance_methods.collect{|m| m.to_s}
|
70
|
+
candidates |= Hash.instance_methods.collect{|m| m.to_s}
|
71
|
+
select_message(receiver, message, candidates)
|
72
|
+
|
73
|
+
when /^(:[^:.]*)$/
|
74
|
+
# Symbol
|
75
|
+
if Symbol.respond_to?(:all_symbols)
|
76
|
+
sym = $1
|
77
|
+
candidates = Symbol.all_symbols.collect{|s| ":" + s.id2name}
|
78
|
+
candidates.grep(/^#{sym}/)
|
79
|
+
else
|
80
|
+
[]
|
81
|
+
end
|
82
|
+
|
83
|
+
when /^::([A-Z][^:\.\(]*)$/
|
84
|
+
# Absolute Constant or class methods
|
85
|
+
receiver = $1
|
86
|
+
candidates = Object.constants.collect{|m| m.to_s}
|
87
|
+
candidates.grep(/^#{receiver}/).collect{|e| "::" + e}
|
88
|
+
|
89
|
+
when /^([A-Z].*)::([^:.]*)$/
|
90
|
+
# Constant or class methods
|
91
|
+
receiver = $1
|
92
|
+
message = Regexp.quote($2)
|
93
|
+
begin
|
94
|
+
candidates = eval("#{receiver}.constants.collect{|m| m.to_s}", bind)
|
95
|
+
candidates |= eval("#{receiver}.methods.collect{|m| m.to_s}", bind)
|
96
|
+
rescue Exception
|
97
|
+
candidates = []
|
98
|
+
end
|
99
|
+
candidates.grep(/^#{message}/).collect{|e| receiver + "::" + e}
|
100
|
+
|
101
|
+
when /^(:[^:.]+)\.([^.]*)$/
|
102
|
+
# Symbol
|
103
|
+
receiver = $1
|
104
|
+
message = Regexp.quote($2)
|
105
|
+
|
106
|
+
candidates = Symbol.instance_methods.collect{|m| m.to_s}
|
107
|
+
select_message(receiver, message, candidates)
|
108
|
+
|
109
|
+
when /^(-?(0[dbo])?[0-9_]+(\.[0-9_]+)?([eE]-?[0-9]+)?)\.([^.]*)$/
|
110
|
+
# Numeric
|
111
|
+
receiver = $1
|
112
|
+
message = Regexp.quote($5)
|
113
|
+
|
114
|
+
begin
|
115
|
+
candidates = eval(receiver, bind).methods.collect{|m| m.to_s}
|
116
|
+
rescue Exception
|
117
|
+
candidates = []
|
118
|
+
end
|
119
|
+
select_message(receiver, message, candidates)
|
120
|
+
|
121
|
+
when /^(-?0x[0-9a-fA-F_]+)\.([^.]*)$/
|
122
|
+
# Numeric(0xFFFF)
|
123
|
+
receiver = $1
|
124
|
+
message = Regexp.quote($2)
|
125
|
+
|
126
|
+
begin
|
127
|
+
candidates = eval(receiver, bind).methods.collect{|m| m.to_s}
|
128
|
+
rescue Exception
|
129
|
+
candidates = []
|
130
|
+
end
|
131
|
+
select_message(receiver, message, candidates)
|
132
|
+
|
133
|
+
when /^(\$[^.]*)$/
|
134
|
+
regmessage = Regexp.new(Regexp.quote($1))
|
135
|
+
candidates = global_variables.collect{|m| m.to_s}.grep(regmessage)
|
136
|
+
|
137
|
+
when /^([^."].*)\.([^.]*)$/
|
138
|
+
# variable
|
139
|
+
receiver = $1
|
140
|
+
message = Regexp.quote($2)
|
141
|
+
|
142
|
+
gv = eval("global_variables", bind).collect{|m| m.to_s}
|
143
|
+
lv = eval("local_variables", bind).collect{|m| m.to_s}
|
144
|
+
cv = eval("self.class.constants", bind).collect{|m| m.to_s}
|
145
|
+
|
146
|
+
if (gv | lv | cv).include?(receiver) or /^[A-Z]/ =~ receiver && /\./ !~ receiver
|
147
|
+
# foo.func and foo is local var. OR
|
148
|
+
# Foo::Bar.func
|
149
|
+
begin
|
150
|
+
candidates = eval("#{receiver}.methods", bind).collect{|m| m.to_s}
|
151
|
+
rescue Exception
|
152
|
+
candidates = []
|
153
|
+
end
|
154
|
+
else
|
155
|
+
# func1.func2
|
156
|
+
candidates = []
|
157
|
+
ObjectSpace.each_object(Module){|m|
|
158
|
+
begin
|
159
|
+
name = m.name
|
160
|
+
rescue Exception
|
161
|
+
name = ""
|
162
|
+
end
|
163
|
+
next if name != "IRB::Context" and
|
164
|
+
/^(IRB|SLex|RubyLex|RubyToken)/ =~ name
|
165
|
+
candidates.concat m.instance_methods(false).collect{|x| x.to_s}
|
166
|
+
}
|
167
|
+
candidates.sort!
|
168
|
+
candidates.uniq!
|
169
|
+
end
|
170
|
+
select_message(receiver, message, candidates)
|
171
|
+
|
172
|
+
when /^\.([^.]*)$/
|
173
|
+
# unknown(maybe String)
|
174
|
+
|
175
|
+
receiver = ""
|
176
|
+
message = Regexp.quote($1)
|
177
|
+
|
178
|
+
candidates = String.instance_methods(true).collect{|m| m.to_s}
|
179
|
+
select_message(receiver, message, candidates)
|
180
|
+
|
181
|
+
else
|
182
|
+
candidates = eval("methods | private_methods | local_variables | self.class.constants", bind).collect{|m| m.to_s}
|
183
|
+
|
184
|
+
(candidates|ReservedWords|commands).grep(/^#{Regexp.quote(input)}/)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def self.select_message(receiver, message, candidates)
|
190
|
+
candidates.grep(/^#{message}/).collect do |e|
|
191
|
+
case e
|
192
|
+
when /^[a-zA-Z_]/
|
193
|
+
receiver + "." + e
|
194
|
+
when /^[0-9]/
|
195
|
+
when *Operators
|
196
|
+
#receiver + " " + e
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class Pry
|
2
|
+
module ObjectExtensions
|
3
|
+
|
4
|
+
# Start a Pry REPL.
|
5
|
+
# This method differs from `Pry.start` in that it does not
|
6
|
+
# support an options hash. Also, when no parameter is provided, the Pry
|
7
|
+
# session will start on the implied receiver rather than on
|
8
|
+
# top-level (as in the case of `Pry.start`).
|
9
|
+
# It has two forms of invocation. In the first form no parameter
|
10
|
+
# should be provided and it will start a pry session on the
|
11
|
+
# receiver. In the second form it should be invoked without an
|
12
|
+
# explicit receiver and one parameter; this will start a Pry
|
13
|
+
# session on the parameter.
|
14
|
+
# @param [Object, Binding] target The receiver of the Pry session.
|
15
|
+
# @example First form
|
16
|
+
# "dummy".pry
|
17
|
+
# @example Second form
|
18
|
+
# pry "dummy"
|
19
|
+
# @example Start a Pry session on current self (whatever that is)
|
20
|
+
# pry
|
21
|
+
def pry(target=self)
|
22
|
+
Pry.start(target)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return a binding object for the receiver.
|
26
|
+
def __binding__
|
27
|
+
if is_a?(Module)
|
28
|
+
return class_eval "binding"
|
29
|
+
end
|
30
|
+
|
31
|
+
unless respond_to? :__binding_impl__
|
32
|
+
self.class.class_eval <<-EXTRA
|
33
|
+
def __binding_impl__
|
34
|
+
binding
|
35
|
+
end
|
36
|
+
EXTRA
|
37
|
+
end
|
38
|
+
|
39
|
+
__binding_impl__
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# bring the extensions into Object
|
45
|
+
class Object
|
46
|
+
include Pry::ObjectExtensions
|
47
|
+
end
|
data/lib/pry/hooks.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
class Pry
|
2
|
+
|
3
|
+
# The default hooks - display messages when beginning and ending Pry sessions.
|
4
|
+
DEFAULT_HOOKS = {
|
5
|
+
:before_session => proc { |out, obj| out.puts "Beginning Pry session for #{Pry.view(obj)}" },
|
6
|
+
:after_session => proc { |out, obj| out.puts "Ending Pry session for #{Pry.view(obj)}" }
|
7
|
+
}
|
8
|
+
end
|
data/lib/pry/print.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
class Pry
|
2
|
+
|
3
|
+
# The default print object - only show first line of backtrace and
|
4
|
+
# prepend output with `=>`
|
5
|
+
DEFAULT_PRINT = proc do |output, value|
|
6
|
+
case value
|
7
|
+
when Exception
|
8
|
+
output.puts "#{value.class}: #{value.message}"
|
9
|
+
output.puts "from #{value.backtrace.first}"
|
10
|
+
else
|
11
|
+
output.puts "=> #{Pry.view(value)}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
data/lib/pry/prompts.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
class Pry
|
2
|
+
|
3
|
+
# The default prompt; includes the target and nesting level
|
4
|
+
DEFAULT_PROMPT = [
|
5
|
+
proc do |target_self, nest_level|
|
6
|
+
if nest_level == 0
|
7
|
+
"pry(#{Pry.view(target_self)})> "
|
8
|
+
else
|
9
|
+
"pry(#{Pry.view(target_self)}):#{Pry.view(nest_level)}> "
|
10
|
+
end
|
11
|
+
end,
|
12
|
+
|
13
|
+
proc do |target_self, nest_level|
|
14
|
+
if nest_level == 0
|
15
|
+
"pry(#{Pry.view(target_self)})* "
|
16
|
+
else
|
17
|
+
"pry(#{Pry.view(target_self)}):#{Pry.view(nest_level)}* "
|
18
|
+
end
|
19
|
+
end
|
20
|
+
]
|
21
|
+
|
22
|
+
# A simple prompt - doesn't display target or nesting level
|
23
|
+
SIMPLE_PROMPT = [proc { "pry> " }, proc { "pry* " }]
|
24
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'readline'
|
2
|
+
|
3
|
+
# @author John Mair (banisterfiend)
|
4
|
+
class Pry
|
5
|
+
|
6
|
+
# class accessors
|
7
|
+
class << self
|
8
|
+
|
9
|
+
# Get nesting data.
|
10
|
+
# This method should not need to be accessed directly.
|
11
|
+
# @return [Array] The unparsed nesting information.
|
12
|
+
attr_reader :nesting
|
13
|
+
|
14
|
+
# Get last value evaluated by Pry.
|
15
|
+
# This method should not need to be accessed directly.
|
16
|
+
# @return [Object] The last result.
|
17
|
+
attr_accessor :last_result
|
18
|
+
|
19
|
+
# Get the active Pry instance that manages the active Pry session.
|
20
|
+
# This method should not need to be accessed directly.
|
21
|
+
# @return [Pry] The active Pry instance.
|
22
|
+
attr_accessor :active_instance
|
23
|
+
|
24
|
+
# Get/Set the object to use for input by default by all Pry instances.
|
25
|
+
# @return [#readline] The object to use for input by default by all
|
26
|
+
# Pry instances.
|
27
|
+
attr_accessor :input
|
28
|
+
|
29
|
+
# Get/Set the object to use for output by default by all Pry instances.
|
30
|
+
# @return [#puts] The object to use for output by default by all
|
31
|
+
# Pry instances.
|
32
|
+
attr_accessor :output
|
33
|
+
|
34
|
+
# Get/Set the object to use for commands by default by all Pry instances.
|
35
|
+
# @return [Pry::CommandBase] The object to use for commands by default by all
|
36
|
+
# Pry instances.
|
37
|
+
attr_accessor :commands
|
38
|
+
|
39
|
+
# Get/Set the Proc to use for printing by default by all Pry
|
40
|
+
# instances.
|
41
|
+
# This is the 'print' component of the REPL.
|
42
|
+
# @return [Proc] The Proc to use for printing by default by all
|
43
|
+
# Pry instances.
|
44
|
+
attr_accessor :print
|
45
|
+
|
46
|
+
# Get/Set the Hash that defines Pry hooks used by default by all Pry
|
47
|
+
# instances.
|
48
|
+
# @return [Hash] The hooks used by default by all Pry instances.
|
49
|
+
# @example
|
50
|
+
# Pry.hooks :before_session => proc { puts "hello" },
|
51
|
+
# :after_session => proc { puts "goodbye" }
|
52
|
+
attr_accessor :hooks
|
53
|
+
|
54
|
+
# Get the array of Procs to be used for the prompts by default by
|
55
|
+
# all Pry instances.
|
56
|
+
# @return [Array<Proc>] The array of Procs to be used for the
|
57
|
+
# prompts by default by all Pry instances.
|
58
|
+
attr_accessor :prompt
|
59
|
+
end
|
60
|
+
|
61
|
+
# Start a Pry REPL.
|
62
|
+
# @param [Object, Binding] target The receiver of the Pry session
|
63
|
+
# @param [Hash] options
|
64
|
+
# @option options (see Pry#initialize)
|
65
|
+
# @example
|
66
|
+
# Pry.start(Object.new, :input => MyInput.new)
|
67
|
+
def self.start(target=TOPLEVEL_BINDING, options={})
|
68
|
+
new(options).repl(target)
|
69
|
+
end
|
70
|
+
|
71
|
+
# A custom version of `Kernel#inspect`.
|
72
|
+
# This method should not need to be accessed directly.
|
73
|
+
# @param obj The object to view.
|
74
|
+
# @return [String] The string representation of `obj`.
|
75
|
+
def self.view(obj)
|
76
|
+
case obj
|
77
|
+
when String, Hash, Array, Symbol, nil
|
78
|
+
obj.inspect
|
79
|
+
else
|
80
|
+
obj.to_s
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Set all the configurable options back to their default values
|
85
|
+
def self.reset_defaults
|
86
|
+
@input = Readline
|
87
|
+
@output = $stdout
|
88
|
+
|
89
|
+
# FIXME
|
90
|
+
@commands = Pry::Commands
|
91
|
+
@prompt = DEFAULT_PROMPT
|
92
|
+
@print = DEFAULT_PRINT
|
93
|
+
@hooks = DEFAULT_HOOKS
|
94
|
+
end
|
95
|
+
|
96
|
+
self.reset_defaults
|
97
|
+
|
98
|
+
@nesting = []
|
99
|
+
def @nesting.level
|
100
|
+
last.is_a?(Array) ? last.first : nil
|
101
|
+
end
|
102
|
+
|
103
|
+
# Return all active Pry sessions.
|
104
|
+
# @return [Array<Pry>] Active Pry sessions.
|
105
|
+
def self.sessions
|
106
|
+
# last element in nesting array is the pry instance
|
107
|
+
nesting.map(&:last)
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,309 @@
|
|
1
|
+
require 'readline'
|
2
|
+
|
3
|
+
class Pry
|
4
|
+
|
5
|
+
# The list of configuration options.
|
6
|
+
ConfigOptions = [:input, :output, :commands, :print,
|
7
|
+
:prompt, :hooks]
|
8
|
+
|
9
|
+
attr_accessor *ConfigOptions
|
10
|
+
|
11
|
+
# Create a new `Pry` object.
|
12
|
+
# @param [Hash] options The optional configuration parameters.
|
13
|
+
# @option options [#readline] :input The object to use for input.
|
14
|
+
# @option options [#puts] :output The object to use for output.
|
15
|
+
# @option options [Pry::CommandBase] :commands The object to use for
|
16
|
+
# commands. (see commands.rb)
|
17
|
+
# @option options [Hash] :hooks The defined hook Procs (see hooks.rb)
|
18
|
+
# @option options [Array<Proc>] :default_prompt The array of Procs
|
19
|
+
# to use for the prompts. (see prompts.rb)
|
20
|
+
# @option options [Proc] :print The Proc to use for the 'print'
|
21
|
+
# component of the REPL. (see print.rb)
|
22
|
+
def initialize(options={})
|
23
|
+
|
24
|
+
h = {}
|
25
|
+
ConfigOptions.each { |v| h[v] = Pry.send(v) }
|
26
|
+
default_options = h
|
27
|
+
default_options.merge!(options)
|
28
|
+
|
29
|
+
ConfigOptions.each do |key|
|
30
|
+
instance_variable_set("@#{key}", default_options[key])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Get nesting data.
|
35
|
+
# This method should not need to be accessed directly.
|
36
|
+
# @return [Array] The unparsed nesting information.
|
37
|
+
def nesting
|
38
|
+
self.class.nesting
|
39
|
+
end
|
40
|
+
|
41
|
+
# Set nesting data.
|
42
|
+
# This method should not need to be accessed directly.
|
43
|
+
# @param v nesting data.
|
44
|
+
def nesting=(v)
|
45
|
+
self.class.nesting = v
|
46
|
+
end
|
47
|
+
|
48
|
+
# Return parent of current Pry session.
|
49
|
+
# @return [Pry] The parent of the current Pry session.
|
50
|
+
def parent
|
51
|
+
idx = Pry.sessions.index(self)
|
52
|
+
|
53
|
+
if idx > 0
|
54
|
+
Pry.sessions[idx - 1]
|
55
|
+
else
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Execute the hook `hook_name`, if it is defined.
|
61
|
+
# @param [Symbol] hook_name The hook to execute
|
62
|
+
# @param [Array] args The arguments to pass to the hook.
|
63
|
+
def exec_hook(hook_name, *args, &block)
|
64
|
+
hooks[hook_name].call(*args, &block) if hooks[hook_name]
|
65
|
+
end
|
66
|
+
|
67
|
+
# Start a read-eval-print-loop.
|
68
|
+
# If no parameter is given, default to top-level (main).
|
69
|
+
# @param [Object, Binding] target The receiver of the Pry session
|
70
|
+
# @return [Object] The target of the Pry session
|
71
|
+
# @example
|
72
|
+
# Pry.new.repl(Object.new)
|
73
|
+
def repl(target=TOPLEVEL_BINDING)
|
74
|
+
target = binding_for(target)
|
75
|
+
target_self = target.eval('self')
|
76
|
+
|
77
|
+
exec_hook :before_session, output, target_self
|
78
|
+
|
79
|
+
# cannot rely on nesting.level as
|
80
|
+
# nesting.level changes with new sessions
|
81
|
+
nesting_level = nesting.size
|
82
|
+
|
83
|
+
Pry.active_instance = self
|
84
|
+
|
85
|
+
# Make sure special locals exist
|
86
|
+
target.eval("_pry_ = Pry.active_instance")
|
87
|
+
target.eval("_ = Pry.last_result")
|
88
|
+
|
89
|
+
break_level = catch(:breakout) do
|
90
|
+
nesting.push [nesting.size, target_self, self]
|
91
|
+
loop do
|
92
|
+
rep(target)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
nesting.pop
|
97
|
+
|
98
|
+
exec_hook :after_session, output, target_self
|
99
|
+
|
100
|
+
# keep throwing until we reach the desired nesting level
|
101
|
+
if nesting_level != break_level
|
102
|
+
throw :breakout, break_level
|
103
|
+
end
|
104
|
+
|
105
|
+
target_self
|
106
|
+
end
|
107
|
+
|
108
|
+
# Perform a read-eval-print.
|
109
|
+
# If no parameter is given, default to top-level (main).
|
110
|
+
# @param [Object, Binding] target The receiver of the read-eval-print
|
111
|
+
# @example
|
112
|
+
# Pry.new.rep(Object.new)
|
113
|
+
def rep(target=TOPLEVEL_BINDING)
|
114
|
+
target = binding_for(target)
|
115
|
+
print.call output, re(target)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Perform a read-eval
|
119
|
+
# If no parameter is given, default to top-level (main).
|
120
|
+
# @param [Object, Binding] target The receiver of the read-eval-print
|
121
|
+
# @return [Object] The result of the eval or an `Exception` object in case of error.
|
122
|
+
# @example
|
123
|
+
# Pry.new.re(Object.new)
|
124
|
+
def re(target=TOPLEVEL_BINDING)
|
125
|
+
target = binding_for(target)
|
126
|
+
|
127
|
+
if input == Readline
|
128
|
+
# Readline tab completion
|
129
|
+
Readline.completion_proc = Pry::InputCompleter.build_completion_proc(target, commands.commands.keys)
|
130
|
+
end
|
131
|
+
|
132
|
+
# eval the expression and save to last_result
|
133
|
+
Pry.last_result = target.eval r(target)
|
134
|
+
|
135
|
+
# save the pry instance to active_instance
|
136
|
+
Pry.active_instance = self
|
137
|
+
|
138
|
+
# define locals _pry_ and _ (active instance and last expression)
|
139
|
+
target.eval("_pry_ = Pry.active_instance")
|
140
|
+
target.eval("_ = Pry.last_result")
|
141
|
+
rescue SystemExit => e
|
142
|
+
exit
|
143
|
+
rescue Exception => e
|
144
|
+
e
|
145
|
+
end
|
146
|
+
|
147
|
+
# Perform a read.
|
148
|
+
# If no parameter is given, default to top-level (main).
|
149
|
+
# This is a multi-line read; so the read continues until a valid
|
150
|
+
# Ruby expression is received.
|
151
|
+
# Pry commands are also accepted here and operate on the target.
|
152
|
+
# @param [Object, Binding] target The receiver of the read.
|
153
|
+
# @return [String] The Ruby expression.
|
154
|
+
# @example
|
155
|
+
# Pry.new.r(Object.new)
|
156
|
+
def r(target=TOPLEVEL_BINDING)
|
157
|
+
target = binding_for(target)
|
158
|
+
eval_string = ""
|
159
|
+
|
160
|
+
loop do
|
161
|
+
current_prompt = select_prompt(eval_string.empty?, target.eval('self'))
|
162
|
+
|
163
|
+
val = readline(current_prompt)
|
164
|
+
val.chomp!
|
165
|
+
|
166
|
+
process_commands(val, eval_string, target)
|
167
|
+
eval_string << "#{val}\n"
|
168
|
+
|
169
|
+
break eval_string if valid_expression?(eval_string)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# Process Pry commands. Pry commands are not Ruby methods and are evaluated
|
174
|
+
# prior to Ruby expressions.
|
175
|
+
# Commands can be modified/configured by the user: see `Pry::Commands`
|
176
|
+
# This method should not need to be invoked directly - it is called
|
177
|
+
# by `Pry#r`.
|
178
|
+
# @param [String] val The current line of input.
|
179
|
+
# @param [String] eval_string The cumulative lines of input for
|
180
|
+
# multi-line input.
|
181
|
+
# @param [Binding] target The receiver of the commands.
|
182
|
+
def process_commands(val, eval_string, target)
|
183
|
+
def val.clear() replace("") end
|
184
|
+
def eval_string.clear() replace("") end
|
185
|
+
|
186
|
+
pattern, data = commands.commands.find do |name, data|
|
187
|
+
/^#{name}(?!\S)(?:\s+(.+))?/ =~ val
|
188
|
+
end
|
189
|
+
|
190
|
+
if pattern
|
191
|
+
args_string = $1
|
192
|
+
args = args_string ? args_string.split : []
|
193
|
+
action = data[:action]
|
194
|
+
|
195
|
+
options = {
|
196
|
+
:val => val,
|
197
|
+
:eval_string => eval_string,
|
198
|
+
:nesting => nesting,
|
199
|
+
:commands => commands.commands
|
200
|
+
}
|
201
|
+
|
202
|
+
# set some useful methods to be used by the action blocks
|
203
|
+
commands.opts = options
|
204
|
+
commands.target = target
|
205
|
+
commands.output = output
|
206
|
+
|
207
|
+
case action.arity <=> 0
|
208
|
+
when -1
|
209
|
+
|
210
|
+
# Use instance_exec() to make the `opts` method, etc available
|
211
|
+
commands.instance_exec(*args, &action)
|
212
|
+
when 1, 0
|
213
|
+
|
214
|
+
# ensure that we get the right number of parameters
|
215
|
+
# since 1.8.7 complains about incorrect arity (1.9.2
|
216
|
+
# doesn't care)
|
217
|
+
args_with_corrected_arity = args.values_at *0..(action.arity - 1)
|
218
|
+
commands.instance_exec(*args_with_corrected_arity, &action)
|
219
|
+
end
|
220
|
+
|
221
|
+
val.clear
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# Returns the next line of input to be used by the pry instance.
|
226
|
+
# This method should not need to be invoked directly.
|
227
|
+
# @param [String] current_prompt The prompt to use for input.
|
228
|
+
# @return [String] The next line of input.
|
229
|
+
def readline(current_prompt="> ")
|
230
|
+
|
231
|
+
if input == Readline
|
232
|
+
|
233
|
+
# Readline must be treated differently
|
234
|
+
# as it has a second parameter.
|
235
|
+
input.readline(current_prompt, true)
|
236
|
+
else
|
237
|
+
if input.method(:readline).arity == 1
|
238
|
+
input.readline(current_prompt)
|
239
|
+
else
|
240
|
+
input.readline
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
# Returns the appropriate prompt to use.
|
246
|
+
# This method should not need to be invoked directly.
|
247
|
+
# @param [Boolean] first_line Whether this is the first line of input
|
248
|
+
# (and not multi-line input).
|
249
|
+
# @param [Object] target_self The receiver of the Pry session.
|
250
|
+
# @return [String] The prompt.
|
251
|
+
def select_prompt(first_line, target_self)
|
252
|
+
|
253
|
+
if first_line
|
254
|
+
Array(prompt).first.call(target_self, nesting.level)
|
255
|
+
else
|
256
|
+
Array(prompt).last.call(target_self, nesting.level)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
if RUBY_VERSION =~ /1.9/
|
261
|
+
require 'ripper'
|
262
|
+
|
263
|
+
# Determine if a string of code is a valid Ruby expression.
|
264
|
+
# Ruby 1.9 uses Ripper, Ruby 1.8 uses RubyParser.
|
265
|
+
# @param [String] code The code to validate.
|
266
|
+
# @return [Boolean] Whether or not the code is a valid Ruby expression.
|
267
|
+
# @example
|
268
|
+
# valid_expression?("class Hello") #=> false
|
269
|
+
# valid_expression?("class Hello; end") #=> true
|
270
|
+
def valid_expression?(code)
|
271
|
+
!!Ripper::SexpBuilder.new(code).parse
|
272
|
+
end
|
273
|
+
|
274
|
+
else
|
275
|
+
require 'ruby_parser'
|
276
|
+
|
277
|
+
# Determine if a string of code is a valid Ruby expression.
|
278
|
+
# Ruby 1.9 uses Ripper, Ruby 1.8 uses RubyParser.
|
279
|
+
# @param [String] code The code to validate.
|
280
|
+
# @return [Boolean] Whether or not the code is a valid Ruby expression.
|
281
|
+
# @example
|
282
|
+
# valid_expression?("class Hello") #=> false
|
283
|
+
# valid_expression?("class Hello; end") #=> true
|
284
|
+
def valid_expression?(code)
|
285
|
+
RubyParser.new.parse(code)
|
286
|
+
rescue Racc::ParseError, SyntaxError
|
287
|
+
false
|
288
|
+
else
|
289
|
+
true
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
# Return a `Binding` object for `target` or return `target` if it is
|
294
|
+
# already a `Binding`.
|
295
|
+
# In the case where `target` is top-level then return `TOPLEVEL_BINDING`
|
296
|
+
# @param [Object] target The object to get a `Binding` object for.
|
297
|
+
# @return [Binding] The `Binding` object.
|
298
|
+
def binding_for(target)
|
299
|
+
if target.is_a?(Binding)
|
300
|
+
target
|
301
|
+
else
|
302
|
+
if target == TOPLEVEL_BINDING.eval('self')
|
303
|
+
TOPLEVEL_BINDING
|
304
|
+
else
|
305
|
+
target.__binding__
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|