pry 0.9.6.2 → 0.9.7
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/CHANGELOG +19 -1
- data/CONTRIBUTORS +22 -16
- data/Rakefile +12 -6
- data/bin/pry +15 -12
- data/lib/pry.rb +39 -28
- data/lib/pry/command_context.rb +1 -0
- data/lib/pry/command_processor.rb +9 -2
- data/lib/pry/command_set.rb +7 -0
- data/lib/pry/config.rb +8 -0
- data/lib/pry/default_commands/basic.rb +7 -10
- data/lib/pry/default_commands/context.rb +36 -26
- data/lib/pry/default_commands/documentation.rb +31 -123
- data/lib/pry/default_commands/gems.rb +9 -4
- data/lib/pry/default_commands/input.rb +21 -11
- data/lib/pry/default_commands/introspection.rb +79 -88
- data/lib/pry/default_commands/ls.rb +165 -176
- data/lib/pry/default_commands/shell.rb +8 -8
- data/lib/pry/extended_commands/experimental.rb +1 -5
- data/lib/pry/extended_commands/user_command_api.rb +17 -5
- data/lib/pry/helpers.rb +1 -0
- data/lib/pry/helpers/base_helpers.rb +5 -1
- data/lib/pry/helpers/command_helpers.rb +22 -241
- data/lib/pry/helpers/options_helpers.rb +58 -0
- data/lib/pry/helpers/text.rb +10 -4
- data/lib/pry/history.rb +1 -1
- data/lib/pry/indent.rb +205 -0
- data/lib/pry/method.rb +412 -0
- data/lib/pry/pry_class.rb +56 -15
- data/lib/pry/pry_instance.rb +63 -16
- data/lib/pry/rbx_method.rb +20 -0
- data/lib/pry/rbx_path.rb +34 -0
- data/lib/pry/version.rb +1 -1
- data/pry.gemspec +16 -16
- data/test/helper.rb +8 -4
- data/test/test_command_helpers.rb +1 -69
- data/test/test_command_set.rb +29 -28
- data/test/test_default_commands/test_documentation.rb +23 -10
- data/test/test_default_commands/test_introspection.rb +58 -13
- data/test/test_default_commands/test_ls.rb +148 -0
- data/test/test_indent.rb +234 -0
- data/test/test_input_stack.rb +13 -0
- data/test/test_method.rb +291 -0
- data/test/test_pry.rb +10 -1
- metadata +82 -65
@@ -4,226 +4,215 @@ class Pry
|
|
4
4
|
Ls = Pry::CommandSet.new do
|
5
5
|
|
6
6
|
helpers do
|
7
|
-
def should_trim?(target, options)
|
8
|
-
if target.eval('self').is_a? Module
|
9
|
-
options[:e] || target.eval('self') >= Object
|
10
|
-
else
|
11
|
-
options[:e]
|
12
|
-
end
|
13
|
-
end
|
14
7
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
8
|
+
# http://ruby.runpaint.org/globals, and running "puts global_variables.inspect".
|
9
|
+
BUILTIN_GLOBALS = %w($" $$ $* $, $-0 $-F $-I $-K $-W $-a $-d $-i $-l $-p $-v $-w $. $/ $\\
|
10
|
+
$: $; $< $= $> $0 $ARGV $CONSOLE $DEBUG $DEFAULT_INPUT $DEFAULT_OUTPUT
|
11
|
+
$FIELD_SEPARATOR $FILENAME $FS $IGNORECASE $INPUT_LINE_NUMBER
|
12
|
+
$INPUT_RECORD_SEPARATOR $KCODE $LOADED_FEATURES $LOAD_PATH $NR $OFS
|
13
|
+
$ORS $OUTPUT_FIELD_SEPARATOR $OUTPUT_RECORD_SEPARATOR $PID $PROCESS_ID
|
14
|
+
$PROGRAM_NAME $RS $VERBOSE $deferr $defout $stderr $stdin $stdout)
|
15
|
+
|
16
|
+
# $SAFE and $? are thread-local, the exception stuff only works in a rescue clause,
|
17
|
+
# everything else is basically a local variable with a $ in its name.
|
18
|
+
PSEUDO_GLOBALS = %w($! $' $& $` $@ $? $+ $_ $~ $1 $2 $3 $4 $5 $6 $7 $8 $9
|
19
|
+
$CHILD_STATUS $SAFE $ERROR_INFO $ERROR_POSITION $LAST_MATCH_INFO
|
20
|
+
$LAST_PAREN_MATCH $LAST_READ_LINE $MATCH $POSTMATCH $PREMATCH)
|
21
|
+
|
22
|
+
# Get all the methods that we'll want to output
|
23
|
+
def all_methods(obj, opts)
|
24
|
+
opts.M? ? Pry::Method.all_from_class(obj) : Pry::Method.all_from_obj(obj)
|
21
25
|
end
|
22
26
|
|
23
|
-
def
|
24
|
-
|
25
|
-
"local variables" => Pry.config.ls.local_var_color,
|
26
|
-
"instance variables" => Pry.config.ls.instance_var_color,
|
27
|
-
"class variables" => Pry.config.ls.class_var_color,
|
28
|
-
"global variables" => Pry.config.ls.global_var_color,
|
29
|
-
"just singleton methods" => Pry.config.ls.method_color,
|
30
|
-
"public methods" => Pry.config.ls.method_color,
|
31
|
-
"private methods" => Pry.config.ls.method_color,
|
32
|
-
"protected methods" => Pry.config.ls.method_color,
|
33
|
-
"public instance methods" => Pry.config.ls.instance_method_color,
|
34
|
-
"private instance methods" => Pry.config.ls.instance_method_color,
|
35
|
-
"protected instance methods" => Pry.config.ls.instance_method_color,
|
36
|
-
"constants" => Pry.config.ls.constant_color
|
37
|
-
}
|
27
|
+
def resolution_order(obj, opts)
|
28
|
+
opts.M? ? Pry::Method.instance_resolution_order(obj) : Pry::Method.resolution_order(obj)
|
38
29
|
end
|
39
|
-
end
|
40
|
-
|
41
|
-
command "ls", "Show the list of vars and methods in the current scope. Type `ls --help` for more info." do |*args|
|
42
|
-
options = {}
|
43
|
-
# Set target local to the default -- note that we can set a different target for
|
44
|
-
# ls if we like: e.g ls my_var
|
45
|
-
target = target()
|
46
|
-
|
47
|
-
OptionParser.new do |opts|
|
48
|
-
opts.banner = %{Usage: ls [OPTIONS] [VAR]\n\
|
49
|
-
List information about VAR (the current context by default).
|
50
|
-
Shows local and instance variables by default.
|
51
|
-
--
|
52
|
-
}
|
53
|
-
opts.on("-g", "--globals", "Display global variables.") do
|
54
|
-
options[:g] = true
|
55
|
-
end
|
56
30
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end
|
72
|
-
|
73
|
-
opts.on("-m", "--methods", "Display methods (public methods by default).") do
|
74
|
-
options[:m] = true
|
75
|
-
end
|
76
|
-
|
77
|
-
opts.on("-M", "--instance-methods", "Display instance methods (only relevant to classes and modules).") do
|
78
|
-
options[:M] = true
|
79
|
-
end
|
80
|
-
|
81
|
-
opts.on("-P", "--public", "Display public methods (with -m).") do
|
82
|
-
options[:P] = true
|
83
|
-
end
|
84
|
-
|
85
|
-
opts.on("-r", "--protected", "Display protected methods (with -m).") do
|
86
|
-
options[:r] = true
|
87
|
-
end
|
88
|
-
|
89
|
-
opts.on("-p", "--private", "Display private methods (with -m).") do
|
90
|
-
options[:p] = true
|
91
|
-
end
|
92
|
-
|
93
|
-
opts.on("-j", "--just-singletons", "Display just the singleton methods (with -m).") do
|
94
|
-
options[:j] = true
|
95
|
-
end
|
96
|
-
|
97
|
-
opts.on("-s", "--super", "Include superclass entries excluding Object (relevant to constant and methods options).") do
|
98
|
-
options[:s] = true
|
31
|
+
# Get the name of the klass for pretty display in the title column of ls -m
|
32
|
+
# as there can only ever be one singleton class of a non-class, we just call
|
33
|
+
# that "self".
|
34
|
+
def class_name(klass)
|
35
|
+
if klass == klass.ancestors.first
|
36
|
+
(klass.name || "") == "" ? klass.to_s : klass.name
|
37
|
+
elsif klass.ancestors.include?(Module)
|
38
|
+
begin
|
39
|
+
"#{class_name(ObjectSpace.each_object(klass).detect{ |x| class << x; self; end == klass })}.self"
|
40
|
+
rescue # ObjectSpace is not enabled by default in jruby
|
41
|
+
klass.to_s.sub(/#<Class:(.*)>/, '\1.self')
|
42
|
+
end
|
43
|
+
else
|
44
|
+
"self"
|
99
45
|
end
|
46
|
+
end
|
100
47
|
|
101
|
-
|
102
|
-
|
103
|
-
|
48
|
+
# Get a lambda that can be used with .take_while to prevent over-eager
|
49
|
+
# traversal of the Object's ancestry graph.
|
50
|
+
def below_ceiling(obj, opts)
|
51
|
+
ceiling = if opts.q?
|
52
|
+
[opts.M? ? obj.ancestors[1] : obj.class.ancestors[1]] + Pry.config.ls.ceiling
|
53
|
+
elsif opts.v?
|
54
|
+
[]
|
55
|
+
else
|
56
|
+
Pry.config.ls.ceiling.dup
|
57
|
+
end
|
58
|
+
|
59
|
+
lambda { |klass| !ceiling.include?(klass) }
|
60
|
+
end
|
104
61
|
|
105
|
-
|
106
|
-
|
62
|
+
# Format and colourise a list of methods.
|
63
|
+
def format_methods(methods)
|
64
|
+
methods.sort_by(&:name).map do |method|
|
65
|
+
if method.name == 'method_missing'
|
66
|
+
color(:method_missing, 'method_missing')
|
67
|
+
elsif method.visibility == :private
|
68
|
+
color(:private_method, method.name)
|
69
|
+
elsif method.visibility == :protected
|
70
|
+
color(:protected_method, method.name)
|
71
|
+
else
|
72
|
+
color(:public_method, method.name)
|
73
|
+
end
|
107
74
|
end
|
75
|
+
end
|
108
76
|
|
109
|
-
|
110
|
-
|
111
|
-
|
77
|
+
def format_variables(type, vars)
|
78
|
+
vars.sort_by(&:downcase).map{ |var| color(type, var) }
|
79
|
+
end
|
112
80
|
|
113
|
-
|
114
|
-
|
81
|
+
def format_constants(mod, constants)
|
82
|
+
constants.sort_by(&:downcase).map do |name|
|
83
|
+
if const = (!mod.autoload?(name) && mod.const_get(name) rescue nil)
|
84
|
+
if (const < Exception rescue false)
|
85
|
+
color(:exception_constant, name)
|
86
|
+
elsif (Module === mod.const_get(name) rescue false)
|
87
|
+
color(:class_constant, name)
|
88
|
+
else
|
89
|
+
color(:constant, name)
|
90
|
+
end
|
91
|
+
end
|
115
92
|
end
|
93
|
+
end
|
116
94
|
|
117
|
-
|
118
|
-
|
95
|
+
def format_globals(globals)
|
96
|
+
globals.sort_by(&:downcase).map do |name|
|
97
|
+
if PSEUDO_GLOBALS.include?(name)
|
98
|
+
color(:pseudo_global, name)
|
99
|
+
elsif BUILTIN_GLOBALS.include?(name)
|
100
|
+
color(:builtin_global, name)
|
101
|
+
else
|
102
|
+
color(:global_var, name)
|
103
|
+
end
|
119
104
|
end
|
105
|
+
end
|
120
106
|
|
121
|
-
|
122
|
-
|
123
|
-
|
107
|
+
def format_locals(locals)
|
108
|
+
locals.sort_by(&:downcase).map do |name|
|
109
|
+
if _pry_.special_locals.include?(name.to_sym)
|
110
|
+
color(:pry_var, name)
|
111
|
+
else
|
112
|
+
color(:local_var, name)
|
113
|
+
end
|
124
114
|
end
|
125
|
-
end.order(args) do |new_target|
|
126
|
-
target = Pry.binding_for(target.eval("#{new_target}")) if !options[:h]
|
127
115
|
end
|
128
116
|
|
129
|
-
#
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
options.merge!({
|
135
|
-
:l => true,
|
136
|
-
:i => true,
|
137
|
-
:k => true
|
138
|
-
}) if options.empty? || (options.size == 1 && options[:v]) || (options.size == 1 && options[:grep])
|
117
|
+
# Add a new section to the output. Outputs nothing if the section would be empty.
|
118
|
+
def output_section(heading, body)
|
119
|
+
return if body.compact.empty?
|
120
|
+
output.puts "#{text.bold(color(:heading, heading))}: #{body.compact.join(Pry.config.ls.separator)}"
|
121
|
+
end
|
139
122
|
|
140
|
-
|
123
|
+
# Color output based on config.ls.*_color
|
124
|
+
def color(type, str)
|
125
|
+
text.send(Pry.config.ls.send(:"#{type}_color"), str)
|
126
|
+
end
|
127
|
+
end
|
141
128
|
|
129
|
+
command "ls", "Show the list of vars and methods in the current scope. Type `ls --help` for more info.",
|
130
|
+
:shellwords => false, :interpolate => false do |*args|
|
142
131
|
|
143
|
-
|
144
|
-
|
132
|
+
opts = Slop.parse!(args, :strict => true) do |opt|
|
133
|
+
opt.banner unindent <<-USAGE
|
134
|
+
Usage: ls [-m|-M|-p|-pM] [-q|-v] [-c|-i] [Object]
|
135
|
+
ls [-g] [-l]
|
145
136
|
|
146
|
-
|
147
|
-
target_self = target.eval('self')
|
137
|
+
ls shows you which methods, constants and variables are accessible to Pry. By default it shows you the local variables defined in the current shell, and any public methods or instance variables defined on the current object.
|
148
138
|
|
149
|
-
|
150
|
-
# interpolating in the string)
|
151
|
-
options[:s] = !!options[:s]
|
139
|
+
The colours used are configurable using Pry.config.ls.*_color, and the separator is Pry.config.ls.separator.
|
152
140
|
|
153
|
-
|
154
|
-
|
141
|
+
Pry.config.ls.ceiling is used to hide methods defined higher up in the inheritance chain, this is by default set to [Object, Module, Class] so that methods defined on all Objects are omitted. The -v flag can be used to ignore this setting and show all methods, while the -q can be used to set the ceiling much lower and show only methods defined on the object or its direct class.
|
142
|
+
USAGE
|
155
143
|
|
156
|
-
|
157
|
-
|
158
|
-
info["instance variables"] = [Array(target.eval("instance_variables")).sort, i += 1] if options[:i] || options[:a]
|
144
|
+
opt.on :m, "methods", "Show public methods defined on the Object (default)"
|
145
|
+
opt.on :M, "module", "Show methods defined in a Module or Class"
|
159
146
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
Array(target.eval("self.class.class_variables")).sort
|
164
|
-
end, i += 1] if options[:k] || options[:a]
|
147
|
+
opt.on :p, "ppp", "Show public, protected (in yellow) and private (in green) methods"
|
148
|
+
opt.on :q, "quiet", "Show only methods defined on object.singleton_class and object.class"
|
149
|
+
opt.on :v, "verbose", "Show methods and constants on all super-classes (ignores Pry.config.ls.ceiling)"
|
165
150
|
|
166
|
-
|
151
|
+
opt.on :g, "globals", "Show global variables, including those builtin to Ruby (in cyan)"
|
152
|
+
opt.on :l, "locals", "Show locals, including those provided by Pry (in red)"
|
167
153
|
|
168
|
-
|
154
|
+
opt.on :c, "constants", "Show constants, highlighting classes (in blue), and exceptions (in purple)"
|
169
155
|
|
170
|
-
|
156
|
+
opt.on :i, "ivars", "Show instance variables (in blue) and class variables (in bright blue)"
|
171
157
|
|
172
|
-
|
158
|
+
opt.on :G, "grep", "Filter output by regular expression", :optional => false
|
173
159
|
|
174
|
-
|
160
|
+
opt.on :h, "help", "Show help"
|
161
|
+
end
|
175
162
|
|
176
|
-
|
163
|
+
next output.puts(opts) if opts.h?
|
177
164
|
|
178
|
-
|
165
|
+
obj = args.empty? ? target_self : target.eval(args.join(" "))
|
179
166
|
|
180
|
-
|
167
|
+
# exclude -q, -v and --grep because they don't specify what the user wants to see.
|
168
|
+
has_opts = (opts.m? || opts.M? || opts.p? || opts.g? || opts.l? || opts.c? || opts.i?)
|
181
169
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
end
|
170
|
+
show_methods = opts.m? || opts.M? || opts.p? || !has_opts
|
171
|
+
show_constants = opts.c? || (!has_opts && Module === obj)
|
172
|
+
show_ivars = opts.i? || !has_opts
|
173
|
+
show_locals = opts.l? || (!has_opts && args.empty?)
|
187
174
|
|
188
|
-
|
189
|
-
target.eval("self.class.constants(#{csuper})")).uniq.sort, i += 1] if options[:c] || options[:a]
|
175
|
+
grep_regex, grep = [Regexp.new(opts[:G] || "."), lambda{ |x| x.grep(grep_regex) }]
|
190
176
|
|
191
|
-
|
177
|
+
raise Pry::CommandError, "-l does not make sense with a specified Object" if opts.l? && !args.empty?
|
178
|
+
raise Pry::CommandError, "-g does not make sense with a specified Object" if opts.g? && !args.empty?
|
179
|
+
raise Pry::CommandError, "-q does not make sense with -v" if opts.q? && opts.v?
|
180
|
+
raise Pry::CommandError, "-M only makes sense with a Module or a Class" if opts.M? && !(Module === obj)
|
181
|
+
raise Pry::CommandError, "-c only makes sense with a Module or a Class" if opts.c? && !args.empty? && !(Module === obj)
|
192
182
|
|
193
|
-
# verbose output?
|
194
|
-
if options[:v]
|
195
|
-
# verbose
|
196
183
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
filtered_list = v.first.grep options[:grep]
|
201
|
-
text << text().send(ls_color_map[k], (filtered_list.join(Pry.config.ls.separator)))
|
202
|
-
text << "\n\n"
|
203
|
-
end
|
204
|
-
end
|
184
|
+
if opts.g?
|
185
|
+
output_section("global variables", grep[format_globals(target.eval("global_variables"))])
|
186
|
+
end
|
205
187
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
188
|
+
if show_constants
|
189
|
+
mod = Module === obj ? obj : Object
|
190
|
+
constants = mod.constants
|
191
|
+
constants -= (mod.ancestors - [mod]).map(&:constants).flatten unless opts.v?
|
192
|
+
output_section("constants", grep[format_constants(mod, constants)])
|
193
|
+
end
|
211
194
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
list = list.each { |k, v| text << text().send(ls_color_map[k], v.first.join(Pry.config.ls.separator)); text << Pry.config.ls.separator }
|
195
|
+
if show_methods
|
196
|
+
# methods is a hash {Module/Class => [Pry::Methods]}
|
197
|
+
methods = all_methods(obj, opts).select{ |method| opts.p? || method.visibility == :public }.group_by(&:owner)
|
216
198
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
end
|
224
|
-
end
|
199
|
+
# reverse the resolution order so that the most useful information appears right by the prompt
|
200
|
+
resolution_order(obj, opts).take_while(&below_ceiling(obj, opts)).reverse.each do |klass|
|
201
|
+
methods_here = format_methods((methods[klass] || []).select{ |m| m.name =~ grep_regex })
|
202
|
+
output_section "#{class_name(klass)} methods", methods_here
|
203
|
+
end
|
204
|
+
end
|
225
205
|
|
206
|
+
if show_ivars
|
207
|
+
klass = (Module === obj ? obj : obj.class)
|
208
|
+
output_section("instance variables", format_variables(:instance_var, grep[obj.__send__(:instance_variables)]))
|
209
|
+
output_section("class variables", format_variables(:class_var, grep[klass.__send__(:class_variables)]))
|
210
|
+
end
|
226
211
|
|
212
|
+
if show_locals
|
213
|
+
output_section("locals", format_locals(grep[target.eval("local_variables")]))
|
214
|
+
end
|
215
|
+
end
|
227
216
|
end
|
228
217
|
end
|
229
218
|
end
|
@@ -9,7 +9,7 @@ class Pry
|
|
9
9
|
begin
|
10
10
|
Dir.chdir File.expand_path(dest)
|
11
11
|
rescue Errno::ENOENT
|
12
|
-
|
12
|
+
raise CommandError, "No such directory: #{dest}"
|
13
13
|
end
|
14
14
|
else
|
15
15
|
Pry.config.system.call(output, cmd, _pry_)
|
@@ -61,8 +61,8 @@ class Pry
|
|
61
61
|
start_line = (ex_line - 1) - window_size
|
62
62
|
start_line = start_line < 0 ? 0 : start_line
|
63
63
|
end_line = (ex_line - 1) + window_size
|
64
|
-
if ex_file &&
|
65
|
-
file_name =
|
64
|
+
if ex_file && RbxPath.is_core_path?(ex_file)
|
65
|
+
file_name = RbxPath.convert_path_to_full(ex_file)
|
66
66
|
else
|
67
67
|
file_name = ex_file
|
68
68
|
end
|
@@ -79,22 +79,22 @@ class Pry
|
|
79
79
|
next if opts.help?
|
80
80
|
|
81
81
|
if opts.ex?
|
82
|
-
|
82
|
+
if file_name.nil?
|
83
|
+
raise CommandError, "No Exception or Exception has no associated file."
|
84
|
+
end
|
83
85
|
else
|
84
86
|
file_name = args.shift
|
85
87
|
end
|
86
88
|
|
87
89
|
if !file_name
|
88
|
-
|
89
|
-
next
|
90
|
+
raise CommandError, "Must provide a file name."
|
90
91
|
end
|
91
92
|
|
92
93
|
begin
|
93
94
|
contents, _, _ = read_between_the_lines(file_name, start_line, end_line)
|
94
95
|
contents = syntax_highlight_by_file_type_or_specified(contents, file_name, opts[:type])
|
95
96
|
rescue Errno::ENOENT
|
96
|
-
|
97
|
-
next
|
97
|
+
raise CommandError, "Could not find file: #{file_name}"
|
98
98
|
end
|
99
99
|
|
100
100
|
if opts.l?
|
@@ -4,11 +4,7 @@ class Pry
|
|
4
4
|
Experimental = Pry::CommandSet.new do
|
5
5
|
|
6
6
|
command "reload-method", "Reload the source specifically for a method", :requires_gem => "method_reload" do |meth_name|
|
7
|
-
|
8
|
-
output.puts "Invalid method name: #{meth_name}."
|
9
|
-
next
|
10
|
-
end
|
11
|
-
|
7
|
+
meth = get_method_or_raise(meth_name, target, {}, :omit_help)
|
12
8
|
meth.reload
|
13
9
|
end
|
14
10
|
end
|