pry 0.7.7.2-i386-mingw32 → 0.8.0-i386-mingw32
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/README.markdown +393 -195
- data/Rakefile +5 -4
- data/bin/pry +31 -39
- data/lib/pry.rb +18 -11
- data/lib/pry/command_base.rb +74 -21
- data/lib/pry/command_base_helpers.rb +241 -0
- data/lib/pry/command_helpers.rb +303 -0
- data/lib/pry/command_processor.rb +174 -0
- data/lib/pry/commands.rb +479 -260
- data/lib/pry/completion.rb +1 -1
- data/lib/pry/custom_completions.rb +6 -0
- data/lib/pry/hooks.rb +3 -7
- data/lib/pry/print.rb +10 -13
- data/lib/pry/prompts.rb +7 -2
- data/lib/pry/pry_class.rb +34 -11
- data/lib/pry/pry_instance.rb +83 -106
- data/lib/pry/version.rb +1 -1
- data/test/test.rb +126 -59
- data/test/test_helper.rb +6 -0
- metadata +112 -109
- data/lib/pry.rbc +0 -541
- data/lib/pry/#commands.rb# +0 -718
- data/lib/pry/command_base.rbc +0 -1795
- data/lib/pry/commands.rbc +0 -14430
- data/lib/pry/completion.rbc +0 -4485
- data/lib/pry/core_extensions.rbc +0 -592
- data/lib/pry/hooks.rbc +0 -649
- data/lib/pry/print.rbc +0 -400
- data/lib/pry/prompts.rbc +0 -574
- data/lib/pry/pry_class.rbc +0 -2376
- data/lib/pry/pry_instance.rbc +0 -4633
- data/lib/pry/version.rbc +0 -131
@@ -0,0 +1,303 @@
|
|
1
|
+
class Pry
|
2
|
+
class Commands < CommandBase
|
3
|
+
module CommandHelpers
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
def try_to_load_pry_doc
|
8
|
+
|
9
|
+
# YARD crashes on rbx, so do not require it
|
10
|
+
if !Object.const_defined?(:RUBY_ENGINE) || RUBY_ENGINE !~ /rbx/
|
11
|
+
require "pry-doc"
|
12
|
+
end
|
13
|
+
rescue LoadError
|
14
|
+
end
|
15
|
+
|
16
|
+
def meth_name_from_binding(b)
|
17
|
+
meth_name = b.eval('__method__')
|
18
|
+
if [:__script__, nil, :__binding__, :__binding_impl__].include?(meth_name)
|
19
|
+
nil
|
20
|
+
else
|
21
|
+
meth_name
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def set_file_and_dir_locals(file_name)
|
26
|
+
return if !target
|
27
|
+
$_file_temp = File.expand_path(file_name)
|
28
|
+
$_dir_temp = File.dirname($_file_temp)
|
29
|
+
target.eval("_file_ = $_file_temp")
|
30
|
+
target.eval("_dir_ = $_dir_temp")
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_line_numbers(lines, start_line)
|
34
|
+
line_array = lines.each_line.to_a
|
35
|
+
line_array.each_with_index.map do |line, idx|
|
36
|
+
adjusted_index = idx + start_line
|
37
|
+
if Pry.color
|
38
|
+
cindex = CodeRay.scan("#{adjusted_index}", :ruby).term
|
39
|
+
"#{cindex}: #{line}"
|
40
|
+
else
|
41
|
+
"#{idx}: #{line}"
|
42
|
+
end
|
43
|
+
end.join
|
44
|
+
end
|
45
|
+
|
46
|
+
# if start_line is not false then add line numbers starting with start_line
|
47
|
+
def render_output(should_flood, start_line, doc)
|
48
|
+
if start_line
|
49
|
+
doc = add_line_numbers(doc, start_line)
|
50
|
+
end
|
51
|
+
|
52
|
+
if should_flood
|
53
|
+
output.puts doc
|
54
|
+
else
|
55
|
+
stagger_output(doc)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def check_for_dynamically_defined_method(meth)
|
60
|
+
file, _ = meth.source_location
|
61
|
+
if file =~ /(\(.*\))|<.*>/
|
62
|
+
raise "Cannot retrieve source for dynamically defined method."
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def remove_first_word(text)
|
67
|
+
text.split.drop(1).join(' ')
|
68
|
+
end
|
69
|
+
|
70
|
+
# turn off color for duration of block
|
71
|
+
def no_color(&block)
|
72
|
+
old_color_state = Pry.color
|
73
|
+
Pry.color = false
|
74
|
+
yield
|
75
|
+
ensure
|
76
|
+
Pry.color = old_color_state
|
77
|
+
end
|
78
|
+
|
79
|
+
def code_and_code_type_for(meth)
|
80
|
+
case code_type = code_type_for(meth)
|
81
|
+
when nil
|
82
|
+
return nil
|
83
|
+
when :c
|
84
|
+
code = Pry::MethodInfo.info_for(meth).source
|
85
|
+
code = strip_comments_from_c_code(code)
|
86
|
+
when :ruby
|
87
|
+
code = strip_leading_whitespace(meth.source)
|
88
|
+
set_file_and_dir_locals(meth.source_location.first)
|
89
|
+
end
|
90
|
+
|
91
|
+
[code, code_type]
|
92
|
+
end
|
93
|
+
|
94
|
+
def doc_and_code_type_for(meth)
|
95
|
+
case code_type = code_type_for(meth)
|
96
|
+
when nil
|
97
|
+
return nil
|
98
|
+
when :c
|
99
|
+
doc = Pry::MethodInfo.info_for(meth).docstring
|
100
|
+
when :ruby
|
101
|
+
doc = meth.comment
|
102
|
+
doc = strip_leading_hash_and_whitespace_from_ruby_comments(doc)
|
103
|
+
set_file_and_dir_locals(meth.source_location.first)
|
104
|
+
end
|
105
|
+
|
106
|
+
[doc, code_type]
|
107
|
+
end
|
108
|
+
|
109
|
+
def get_method_object(meth_name, target, options)
|
110
|
+
if !meth_name
|
111
|
+
return nil
|
112
|
+
end
|
113
|
+
|
114
|
+
if options[:M]
|
115
|
+
target.eval("instance_method(:#{meth_name})")
|
116
|
+
elsif options[:m]
|
117
|
+
target.eval("method(:#{meth_name})")
|
118
|
+
else
|
119
|
+
begin
|
120
|
+
target.eval("instance_method(:#{meth_name})")
|
121
|
+
rescue
|
122
|
+
begin
|
123
|
+
target.eval("method(:#{meth_name})")
|
124
|
+
rescue
|
125
|
+
return nil
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def make_header(meth, code_type, content)
|
132
|
+
num_lines = "Number of lines: #{bold(content.each_line.count.to_s)}"
|
133
|
+
case code_type
|
134
|
+
when :ruby
|
135
|
+
file, line = meth.source_location
|
136
|
+
"\n#{bold('From:')} #{file} @ line #{line}:\n#{num_lines}\n\n"
|
137
|
+
else
|
138
|
+
file = Pry::MethodInfo.info_for(meth).file
|
139
|
+
"\n#{bold('From:')} #{file} in Ruby Core (C Method):\n#{num_lines}\n\n"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def is_a_c_method?(meth)
|
144
|
+
meth.source_location.nil?
|
145
|
+
end
|
146
|
+
|
147
|
+
def should_use_pry_doc?(meth)
|
148
|
+
Pry.has_pry_doc && is_a_c_method?(meth)
|
149
|
+
end
|
150
|
+
|
151
|
+
def code_type_for(meth)
|
152
|
+
# only C methods
|
153
|
+
if should_use_pry_doc?(meth)
|
154
|
+
info = Pry::MethodInfo.info_for(meth)
|
155
|
+
if info && info.source
|
156
|
+
code_type = :c
|
157
|
+
else
|
158
|
+
output.puts "Cannot find C method: #{meth.name}"
|
159
|
+
code_type = nil
|
160
|
+
end
|
161
|
+
else
|
162
|
+
if is_a_c_method?(meth)
|
163
|
+
output.puts "Cannot locate this method: #{meth.name}. Try `gem install pry-doc` to get access to Ruby Core documentation."
|
164
|
+
code_type = nil
|
165
|
+
else
|
166
|
+
check_for_dynamically_defined_method(meth)
|
167
|
+
code_type = :ruby
|
168
|
+
end
|
169
|
+
end
|
170
|
+
code_type
|
171
|
+
end
|
172
|
+
|
173
|
+
def file_map
|
174
|
+
{
|
175
|
+
[".c", ".h"] => :c,
|
176
|
+
[".cpp", ".hpp", ".cc", ".h", "cxx"] => :cpp,
|
177
|
+
[".rb", "Rakefile", ".irbrc", ".gemspec", ".pryrc"] => :ruby,
|
178
|
+
".py" => :python,
|
179
|
+
".diff" => :diff,
|
180
|
+
".css" => :css,
|
181
|
+
".html" => :html,
|
182
|
+
[".yaml", ".yml"] => :yaml,
|
183
|
+
".xml" => :xml,
|
184
|
+
".php" => :php,
|
185
|
+
".js" => :javascript,
|
186
|
+
".java" => :java,
|
187
|
+
".rhtml" => :rhtml,
|
188
|
+
".json" => :json
|
189
|
+
}
|
190
|
+
end
|
191
|
+
|
192
|
+
def syntax_highlight_by_file_type_or_specified(contents, file_name, file_type)
|
193
|
+
_, language_detected = file_map.find do |k, v|
|
194
|
+
Array(k).any? do |matcher|
|
195
|
+
matcher == File.extname(file_name) || matcher == File.basename(file_name)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
language_detected = file_type if file_type
|
200
|
+
CodeRay.scan(contents, language_detected).term
|
201
|
+
end
|
202
|
+
|
203
|
+
# convert negative line numbers to positive by wrapping around
|
204
|
+
# last line (as per array indexing with negative numbers)
|
205
|
+
def normalized_line_number(line_number, total_lines)
|
206
|
+
line_number < 0 ? line_number + total_lines : line_number
|
207
|
+
end
|
208
|
+
|
209
|
+
# returns the file content between the lines and the normalized
|
210
|
+
# start and end line numbers.
|
211
|
+
def read_between_the_lines(file_name, start_line, end_line)
|
212
|
+
content = File.read(File.expand_path(file_name))
|
213
|
+
lines_array = content.each_line.to_a
|
214
|
+
|
215
|
+
[lines_array[start_line..end_line].join, normalized_line_number(start_line, lines_array.size),
|
216
|
+
normalized_line_number(end_line, lines_array.size)]
|
217
|
+
end
|
218
|
+
|
219
|
+
# documentation related helpers
|
220
|
+
def strip_color_codes(str)
|
221
|
+
str.gsub(/\e\[.*?(\d)+m/, '')
|
222
|
+
end
|
223
|
+
|
224
|
+
def process_rdoc(comment, code_type)
|
225
|
+
comment = comment.dup
|
226
|
+
comment.gsub(/<code>(?:\s*\n)?(.*?)\s*<\/code>/m) { Pry.color ? CodeRay.scan($1, code_type).term : $1 }.
|
227
|
+
gsub(/<em>(?:\s*\n)?(.*?)\s*<\/em>/m) { Pry.color ? "\e[32m#{$1}\e[0m": $1 }.
|
228
|
+
gsub(/<i>(?:\s*\n)?(.*?)\s*<\/i>/m) { Pry.color ? "\e[34m#{$1}\e[0m" : $1 }.
|
229
|
+
gsub(/\B\+(\w*?)\+\B/) { Pry.color ? "\e[32m#{$1}\e[0m": $1 }.
|
230
|
+
gsub(/((?:^[ \t]+.+(?:\n+|\Z))+)/) { Pry.color ? CodeRay.scan($1, code_type).term : $1 }.
|
231
|
+
gsub(/`(?:\s*\n)?(.*?)\s*`/) { Pry.color ? CodeRay.scan($1, code_type).term : $1 }
|
232
|
+
end
|
233
|
+
|
234
|
+
def process_yardoc_tag(comment, tag)
|
235
|
+
in_tag_block = nil
|
236
|
+
output = comment.lines.map do |v|
|
237
|
+
if in_tag_block && v !~ /^\S/
|
238
|
+
strip_color_codes(strip_color_codes(v))
|
239
|
+
elsif in_tag_block
|
240
|
+
in_tag_block = false
|
241
|
+
v
|
242
|
+
else
|
243
|
+
in_tag_block = true if v =~ /^@#{tag}/
|
244
|
+
v
|
245
|
+
end
|
246
|
+
end.join
|
247
|
+
end
|
248
|
+
|
249
|
+
def process_yardoc(comment)
|
250
|
+
yard_tags = ["param", "return", "option", "yield", "attr", "attr_reader", "attr_writer",
|
251
|
+
"deprecate", "example"]
|
252
|
+
(yard_tags - ["example"]).inject(comment) { |a, v| process_yardoc_tag(a, v) }.
|
253
|
+
gsub(/^@(#{yard_tags.join("|")})/) { Pry.color ? "\e[33m#{$1}\e[0m": $1 }
|
254
|
+
end
|
255
|
+
|
256
|
+
def process_comment_markup(comment, code_type)
|
257
|
+
process_yardoc process_rdoc(comment, code_type)
|
258
|
+
end
|
259
|
+
|
260
|
+
# strip leading whitespace but preserve indentation
|
261
|
+
def strip_leading_whitespace(text)
|
262
|
+
return text if text.empty?
|
263
|
+
leading_spaces = text.lines.first[/^(\s+)/, 1]
|
264
|
+
text.gsub(/^#{leading_spaces}/, '')
|
265
|
+
end
|
266
|
+
|
267
|
+
def strip_leading_hash_and_whitespace_from_ruby_comments(comment)
|
268
|
+
comment = comment.dup
|
269
|
+
comment.gsub!(/\A\#+?$/, '')
|
270
|
+
comment.gsub!(/^\s*#/, '')
|
271
|
+
strip_leading_whitespace(comment)
|
272
|
+
end
|
273
|
+
|
274
|
+
def strip_comments_from_c_code(code)
|
275
|
+
code.sub /\A\s*\/\*.*?\*\/\s*/m, ''
|
276
|
+
end
|
277
|
+
|
278
|
+
def prompt(message, options="Yn")
|
279
|
+
opts = options.scan(/./)
|
280
|
+
optstring = opts.join("/") # case maintained
|
281
|
+
defaults = opts.select{|o| o.upcase == o }
|
282
|
+
opts = opts.map{|o| o.downcase}
|
283
|
+
|
284
|
+
raise "Error: Too many default values for the prompt: #{default.inspect}" if defaults.size > 1
|
285
|
+
|
286
|
+
default = defaults.first
|
287
|
+
|
288
|
+
loop do
|
289
|
+
response = Pry.input.readline("#{message} (#{optstring}) ").downcase
|
290
|
+
case response
|
291
|
+
when *opts
|
292
|
+
return response
|
293
|
+
when ""
|
294
|
+
return default.downcase
|
295
|
+
else
|
296
|
+
output.puts " |_ Invalid option: #{response.inspect}. Try again."
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
class Pry
|
4
|
+
class CommandProcessor
|
5
|
+
SYSTEM_COMMAND_DELIMITER = "."
|
6
|
+
SYSTEM_COMMAND_REGEX = /^#{Regexp.escape(SYSTEM_COMMAND_DELIMITER)}(.*)/
|
7
|
+
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
attr_accessor :pry_instance
|
11
|
+
|
12
|
+
def initialize(pry_instance)
|
13
|
+
@pry_instance = pry_instance
|
14
|
+
end
|
15
|
+
|
16
|
+
def_delegators :@pry_instance, :commands, :nesting, :output
|
17
|
+
|
18
|
+
# Is the string a command valid?
|
19
|
+
# @param [String] val The string passed in from the Pry prompt.
|
20
|
+
# @return [Boolean] Whether the string is a valid command.
|
21
|
+
def valid_command?(val)
|
22
|
+
system_command?(val) || pry_command?(val)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Is the string a valid system command?
|
26
|
+
# @param [String] val The string passed in from the Pry prompt.
|
27
|
+
# @return [Boolean] Whether the string is a valid system command.
|
28
|
+
def system_command?(val)
|
29
|
+
!!(SYSTEM_COMMAND_REGEX =~ val)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Is the string a valid pry command?
|
33
|
+
# A Pry command is a command that is not a system command.
|
34
|
+
# @param [String] val The string passed in from the Pry prompt.
|
35
|
+
# @return [Boolean] Whether the string is a valid Pry command.
|
36
|
+
def pry_command?(val)
|
37
|
+
!!command_matched(val).first
|
38
|
+
end
|
39
|
+
|
40
|
+
# Revaluate the string (str) and perform interpolation.
|
41
|
+
# @param [String] str The string to reevaluate with interpolation.
|
42
|
+
# @param [Binding] target The context where the string should be
|
43
|
+
# reevaluated in.
|
44
|
+
# @return [String] The reevaluated string with interpolations
|
45
|
+
# applied (if any).
|
46
|
+
def interpolate_string(str, target)
|
47
|
+
dumped_str = str.dump
|
48
|
+
dumped_str.gsub!(/\\\#\{/, '#{')
|
49
|
+
target.eval(dumped_str)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Execute a given system command.
|
53
|
+
# The commands first have interpolation applied against the
|
54
|
+
# `target` context.
|
55
|
+
# All system command are forwarded to a shell. Note that the `cd`
|
56
|
+
# command is special-cased and is converted internallly to a `Dir.chdir`
|
57
|
+
# @param [String] val The system command to execute.
|
58
|
+
# @param [Binding] target The context in which to perform string interpolation.
|
59
|
+
def execute_system_command(val, target)
|
60
|
+
SYSTEM_COMMAND_REGEX =~ val
|
61
|
+
cmd = interpolate_string($1, target)
|
62
|
+
|
63
|
+
if cmd =~ /^cd\s+(.+)/i
|
64
|
+
begin
|
65
|
+
@@cd_history ||= []
|
66
|
+
if $1 == "-"
|
67
|
+
dest = @@cd_history.pop || Dir.pwd
|
68
|
+
else
|
69
|
+
dest = File.expand_path($1)
|
70
|
+
end
|
71
|
+
|
72
|
+
@@cd_history << Dir.pwd
|
73
|
+
Dir.chdir(dest)
|
74
|
+
rescue Errno::ENOENT
|
75
|
+
output.puts "No such directory: #{dest}"
|
76
|
+
end
|
77
|
+
else
|
78
|
+
if !system(cmd)
|
79
|
+
output.puts "Error: there was a problem executing system command: #{cmd}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Tick, tock, im getting rid of this shit soon.
|
84
|
+
val.replace("")
|
85
|
+
end
|
86
|
+
|
87
|
+
# Determine whether a Pry command was matched and return command data
|
88
|
+
# and argument string.
|
89
|
+
# This method should not need to be invoked directly.
|
90
|
+
# @param [String] val The line of input.
|
91
|
+
# @return [Array] The command data and arg string pair
|
92
|
+
def command_matched(val)
|
93
|
+
_, cmd_data = commands.commands.find do |name, cmd_data|
|
94
|
+
/^#{Regexp.escape(name)}(?!\S)(?:\s+(.+))?/ =~ val
|
95
|
+
end
|
96
|
+
|
97
|
+
[cmd_data, $1]
|
98
|
+
end
|
99
|
+
|
100
|
+
# Process Pry commands. Pry commands are not Ruby methods and are evaluated
|
101
|
+
# prior to Ruby expressions.
|
102
|
+
# Commands can be modified/configured by the user: see `Pry::Commands`
|
103
|
+
# This method should not need to be invoked directly - it is called
|
104
|
+
# by `Pry#r`.
|
105
|
+
# @param [String] val The current line of input.
|
106
|
+
# @param [String] eval_string The cumulative lines of input for
|
107
|
+
# multi-line input.
|
108
|
+
# @param [Binding] target The receiver of the commands.
|
109
|
+
def process_commands(val, eval_string, target)
|
110
|
+
def val.clear() replace("") end
|
111
|
+
def eval_string.clear() replace("") end
|
112
|
+
|
113
|
+
if system_command?(val)
|
114
|
+
execute_system_command(val, target)
|
115
|
+
return
|
116
|
+
end
|
117
|
+
|
118
|
+
# no command was matched, so return to caller
|
119
|
+
return if !pry_command?(val)
|
120
|
+
|
121
|
+
val.replace interpolate_string(val, target)
|
122
|
+
cmd_data, args_string = command_matched(val)
|
123
|
+
|
124
|
+
args = args_string ? Shellwords.shellwords(args_string) : []
|
125
|
+
action = cmd_data[:action]
|
126
|
+
keep_retval = cmd_data[:keep_retval]
|
127
|
+
|
128
|
+
options = {
|
129
|
+
:val => val,
|
130
|
+
:eval_string => eval_string,
|
131
|
+
:nesting => nesting,
|
132
|
+
:commands => commands.commands
|
133
|
+
}
|
134
|
+
|
135
|
+
ret_value = execute_command(target, action, options, *args)
|
136
|
+
|
137
|
+
# return value of block only if :keep_retval is true
|
138
|
+
ret_value if keep_retval
|
139
|
+
end
|
140
|
+
|
141
|
+
# Execute a Pry command.
|
142
|
+
# This method should not need to be invoked directly.
|
143
|
+
# @param [Binding] target The target of the Pry session.
|
144
|
+
# @param [Proc] action The proc that implements the command.
|
145
|
+
# @param [Hash] options The options to set on the Commands object.
|
146
|
+
# @param [Array] args The command arguments.
|
147
|
+
def execute_command(target, action, options, *args)
|
148
|
+
|
149
|
+
# set some useful methods to be used by the action blocks
|
150
|
+
commands.opts = options
|
151
|
+
commands.target = target
|
152
|
+
commands.output = output
|
153
|
+
|
154
|
+
case action.arity <=> 0
|
155
|
+
when -1
|
156
|
+
|
157
|
+
# Use instance_exec() to make the `opts` method, etc available
|
158
|
+
ret_val = commands.instance_exec(*args, &action)
|
159
|
+
when 1, 0
|
160
|
+
|
161
|
+
# ensure that we get the right number of parameters
|
162
|
+
# since 1.8.7 complains about incorrect arity (1.9.2
|
163
|
+
# doesn't care)
|
164
|
+
args_with_corrected_arity = args.values_at *0..(action.arity - 1)
|
165
|
+
ret_val = commands.instance_exec(*args_with_corrected_arity, &action)
|
166
|
+
end
|
167
|
+
|
168
|
+
# Tick, tock, im getting rid of this shit soon.
|
169
|
+
options[:val].clear
|
170
|
+
|
171
|
+
ret_val
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|