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
@@ -7,103 +7,60 @@ class Pry
|
|
7
7
|
run ".ri", *args
|
8
8
|
end
|
9
9
|
|
10
|
-
command "show-doc", "Show the comments above METH. Type `show-doc --help` for more info. Aliases: \?" do |*args|
|
11
|
-
|
12
|
-
|
13
|
-
opts = Slop.parse!(args) do |opt|
|
10
|
+
command "show-doc", "Show the comments above METH. Type `show-doc --help` for more info. Aliases: \?", :shellwords => false do |*args|
|
11
|
+
opts, meth = parse_options!(args, :method_object) do |opt|
|
14
12
|
opt.banner unindent <<-USAGE
|
15
|
-
Usage: show-doc [OPTIONS] [METH
|
13
|
+
Usage: show-doc [OPTIONS] [METH]
|
16
14
|
Show the comments above method METH. Tries instance methods first and then methods by default.
|
17
15
|
e.g show-doc hello_method
|
18
16
|
USAGE
|
19
17
|
|
20
|
-
opt.on :M, "instance-methods", "Operate on instance methods."
|
21
|
-
opt.on :m, :methods, "Operate on methods."
|
22
|
-
opt.on :c, :context, "Select object context to run under.", true do |context|
|
23
|
-
target = Pry.binding_for(target.eval(context))
|
24
|
-
end
|
25
18
|
opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
|
26
|
-
opt.on :h, :help, "This message." do
|
27
|
-
output.puts opt
|
28
|
-
end
|
29
19
|
end
|
30
20
|
|
31
|
-
|
21
|
+
raise Pry::CommandError, "No documentation found." if meth.doc.nil? || meth.doc.empty?
|
32
22
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
doc, code_type = doc_and_code_type_for(meth)
|
42
|
-
next if !doc
|
43
|
-
|
44
|
-
next output.puts("No documentation found.") if doc.empty?
|
45
|
-
doc = process_comment_markup(doc, code_type)
|
46
|
-
output.puts make_header(meth, code_type, doc)
|
47
|
-
output.puts "#{text.bold("visibility: ")} #{method_visibility(meth).to_s}"
|
48
|
-
output.puts "#{text.bold("signature: ")} #{signature_for(meth)}"
|
49
|
-
output.puts
|
50
|
-
render_output(opts.flood?, false, doc)
|
51
|
-
doc
|
52
|
-
end
|
23
|
+
doc = process_comment_markup(meth.doc, meth.source_type)
|
24
|
+
output.puts make_header(meth, doc)
|
25
|
+
output.puts "#{text.bold("Owner:")} #{meth.owner || "N/A"}"
|
26
|
+
output.puts "#{text.bold("Visibility:")} #{meth.visibility}"
|
27
|
+
output.puts "#{text.bold("Signature:")} #{meth.signature}"
|
28
|
+
output.puts
|
29
|
+
render_output(opts.flood?, false, doc)
|
53
30
|
end
|
54
31
|
|
55
32
|
alias_command "?", "show-doc"
|
56
33
|
|
57
|
-
command "stat", "View method information and set _file_ and _dir_ locals. Type `stat --help` for more info." do |*args|
|
34
|
+
command "stat", "View method information and set _file_ and _dir_ locals. Type `stat --help` for more info.", :shellwords => false do |*args|
|
58
35
|
target = target()
|
59
36
|
|
60
|
-
opts =
|
37
|
+
opts, meth = parse_options!(args, :method_object) do |opt|
|
61
38
|
opt.banner unindent <<-USAGE
|
62
39
|
Usage: stat [OPTIONS] [METH]
|
63
40
|
Show method information for method METH and set _file_ and _dir_ locals.
|
64
41
|
e.g: stat hello_method
|
65
42
|
USAGE
|
66
|
-
|
67
|
-
opt.on :M, "instance-methods", "Operate on instance methods."
|
68
|
-
opt.on :m, :methods, "Operate on methods."
|
69
|
-
opt.on :c, :context, "Select object context to run under.", true do |context|
|
70
|
-
target = Pry.binding_for(target.eval(context))
|
71
|
-
end
|
72
|
-
opt.on :h, :help, "This message" do
|
73
|
-
output.puts opt
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
next if opts.help?
|
78
|
-
|
79
|
-
meth_name = args.shift
|
80
|
-
if (meth = get_method_object(meth_name, target, opts.to_hash(true))).nil?
|
81
|
-
output.puts "Invalid method name: #{meth_name}. Type `stat --help` for help"
|
82
|
-
next
|
83
|
-
end
|
84
|
-
|
85
|
-
if !is_a_c_method?(meth) && !is_a_dynamically_defined_method?(meth)
|
86
|
-
set_file_and_dir_locals(path_line_for(meth).first)
|
87
43
|
end
|
88
44
|
|
89
|
-
output.puts
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
45
|
+
output.puts unindent <<-EOS
|
46
|
+
Method Information:
|
47
|
+
--
|
48
|
+
Name: #{meth.name}
|
49
|
+
Owner: #{meth.owner ? meth.owner : "Unknown"}
|
50
|
+
Visibility: #{meth.visibility}
|
51
|
+
Type: #{meth.is_a?(::Method) ? "Bound" : "Unbound"}
|
52
|
+
Arity: #{meth.arity}
|
53
|
+
Method Signature: #{meth.signature}
|
54
|
+
Source Location: #{meth.source_location ? meth.source_location.join(":") : "Not found."}
|
55
|
+
EOS
|
99
56
|
end
|
100
57
|
|
101
|
-
command "gist-method", "Gist a method to github. Type `gist-method --help` for more info.", :requires_gem => "gist" do |*args|
|
58
|
+
command "gist-method", "Gist a method to github. Type `gist-method --help` for more info.", :requires_gem => "gist", :shellwords => false do |*args|
|
102
59
|
require 'gist'
|
103
60
|
|
104
61
|
target = target()
|
105
62
|
|
106
|
-
opts =
|
63
|
+
opts, meth = parse_options!(args, :method_object) do |opt|
|
107
64
|
opt.banner unindent <<-USAGE
|
108
65
|
Usage: gist-method [OPTIONS] [METH]
|
109
66
|
Gist the method (doc or source) to github.
|
@@ -112,29 +69,18 @@ class Pry
|
|
112
69
|
e.g: gist -d my_method
|
113
70
|
USAGE
|
114
71
|
|
115
|
-
opt.on :m, :method, "Gist a method's source."
|
116
72
|
opt.on :d, :doc, "Gist a method's documentation."
|
117
73
|
opt.on :p, :private, "Create a private gist (default: true)", :default => true
|
118
|
-
opt.on :h, :help, "This message" do
|
119
|
-
output.puts opt
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
next if opts.help?
|
124
|
-
|
125
|
-
# This needs to be extracted into its own method as it's shared
|
126
|
-
# by show-method and show-doc and stat commands
|
127
|
-
meth_name = args.shift
|
128
|
-
if (meth = get_method_object(meth_name, target, opts.to_hash(true))).nil?
|
129
|
-
output.puts "Invalid method name: #{meth_name}. Type `gist-method --help` for help"
|
130
|
-
next
|
131
74
|
end
|
132
75
|
|
133
76
|
type_map = { :ruby => "rb", :c => "c", :plain => "plain" }
|
134
77
|
if !opts.doc?
|
135
|
-
content
|
78
|
+
content = meth.source
|
79
|
+
code_type = meth.source_type
|
136
80
|
else
|
137
|
-
content
|
81
|
+
content = meth.doc
|
82
|
+
code_type = meth.source_type
|
83
|
+
|
138
84
|
text.no_color do
|
139
85
|
content = process_comment_markup(content, code_type)
|
140
86
|
end
|
@@ -147,44 +93,6 @@ class Pry
|
|
147
93
|
|
148
94
|
output.puts "Gist created at #{link}"
|
149
95
|
end
|
150
|
-
|
151
|
-
helpers do
|
152
|
-
|
153
|
-
# paraphrased from awesome_print gem
|
154
|
-
def signature_for(method)
|
155
|
-
if method.respond_to?(:parameters)
|
156
|
-
|
157
|
-
args = method.parameters.inject([]) do |arr, (type, name)|
|
158
|
-
name ||= (type == :block ? 'block' : "arg#{arr.size + 1}")
|
159
|
-
arr << case type
|
160
|
-
when :req then name.to_s
|
161
|
-
when :opt, :rest then "*#{name}"
|
162
|
-
when :block then "&#{name}"
|
163
|
-
else '?'
|
164
|
-
end
|
165
|
-
end
|
166
|
-
else
|
167
|
-
args = (1..method.arity.abs).map { |i| "arg#{i}" }
|
168
|
-
args[-1] = "*#{args[-1]}" if method.arity < 0
|
169
|
-
end
|
170
|
-
|
171
|
-
"#{method.name}(#{args.join(', ')})"
|
172
|
-
end
|
173
|
-
|
174
|
-
def method_visibility(meth)
|
175
|
-
if meth.owner.public_instance_methods.include? meth.name
|
176
|
-
:public
|
177
|
-
elsif meth.owner.protected_instance_methods.include? meth.name
|
178
|
-
:protected
|
179
|
-
elsif meth.owner.private_instance_methods.include? meth.name
|
180
|
-
:private
|
181
|
-
else
|
182
|
-
:none
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
96
|
end
|
188
|
-
|
189
97
|
end
|
190
98
|
end
|
@@ -4,14 +4,15 @@ class Pry
|
|
4
4
|
Gems = Pry::CommandSet.new do
|
5
5
|
|
6
6
|
command "gem-install", "Install a gem and refresh the gem cache.", :argument_required => true do |gem|
|
7
|
+
require 'rubygems/dependency_installer' unless defined? Gem::DependencyInstaller
|
7
8
|
begin
|
8
9
|
destination = File.writable?(Gem.dir) ? Gem.dir : Gem.user_dir
|
9
10
|
installer = Gem::DependencyInstaller.new :install_dir => destination
|
10
11
|
installer.install gem
|
11
12
|
rescue Errno::EACCES
|
12
|
-
|
13
|
+
raise CommandError, "Insufficient permissions to install `#{text.green gem}`."
|
13
14
|
rescue Gem::GemNotFoundException
|
14
|
-
|
15
|
+
raise CommandError, "Gem `#{text.green gem}` not found."
|
15
16
|
else
|
16
17
|
Gem.refresh
|
17
18
|
output.puts "Gem `#{text.green gem}` installed."
|
@@ -21,7 +22,11 @@ class Pry
|
|
21
22
|
command "gem-cd", "Change working directory to specified gem's directory.", :argument_required => true do |gem|
|
22
23
|
specs = Gem::Specification.respond_to?(:each) ? Gem::Specification.find_all_by_name(gem) : Gem.source_index.find_name(gem)
|
23
24
|
spec = specs.sort { |a,b| Gem::Version.new(b.version) <=> Gem::Version.new(a.version) }.first
|
24
|
-
|
25
|
+
if spec
|
26
|
+
Dir.chdir(spec.full_gem_path)
|
27
|
+
else
|
28
|
+
raise CommandError, "Gem `#{gem}` not found."
|
29
|
+
end
|
25
30
|
end
|
26
31
|
|
27
32
|
command "gem-list", "List/search installed gems. (Optional parameter: a regexp to limit the search)" do |pattern|
|
@@ -41,7 +46,7 @@ class Pry
|
|
41
46
|
index == 0 ? text.bright_green(spec.version.to_s) : text.green(spec.version.to_s)
|
42
47
|
end
|
43
48
|
|
44
|
-
output.puts "#{text.
|
49
|
+
output.puts "#{text.default gem} (#{versions.join ', '})"
|
45
50
|
end
|
46
51
|
end
|
47
52
|
|
@@ -33,7 +33,10 @@ class Pry
|
|
33
33
|
end
|
34
34
|
|
35
35
|
next if opts.h?
|
36
|
-
|
36
|
+
|
37
|
+
if eval_string.empty?
|
38
|
+
raise CommandError, "No input to amend."
|
39
|
+
end
|
37
40
|
|
38
41
|
replacement_line = "" if !replacement_line
|
39
42
|
input_array = eval_string.each_line.to_a
|
@@ -77,20 +80,20 @@ class Pry
|
|
77
80
|
|
78
81
|
if opts.m?
|
79
82
|
meth_name = opts[:m]
|
80
|
-
|
81
|
-
|
82
|
-
next
|
83
|
-
end
|
84
|
-
code, _ = code_and_code_type_for(meth)
|
85
|
-
next if !code
|
83
|
+
meth = get_method_or_raise(meth_name, target, {}, :omit_help)
|
84
|
+
next unless meth.source
|
86
85
|
|
87
86
|
range = opts.l? ? one_index_range_or_number(opts[:l]) : (0..-1)
|
88
87
|
range = (0..-2) if opts.o?
|
89
88
|
|
90
|
-
eval_string << Array(
|
89
|
+
eval_string << Array(meth.source.each_line.to_a[range]).join
|
91
90
|
elsif opts.f?
|
92
91
|
file_name = File.expand_path(opts[:f])
|
93
|
-
|
92
|
+
|
93
|
+
if !File.exists?(file_name)
|
94
|
+
raise CommandError, "No such file: #{opts[:f]}"
|
95
|
+
end
|
96
|
+
|
94
97
|
text_array = File.readlines(file_name)
|
95
98
|
range = opts.l? ? one_index_range_or_number(opts[:l]) : (0..-1)
|
96
99
|
range = (0..-2) if opts.o?
|
@@ -98,7 +101,10 @@ class Pry
|
|
98
101
|
_pry_.input_stack << _pry_.input
|
99
102
|
_pry_.input = StringIO.new(Array(text_array[range]).join)
|
100
103
|
else
|
101
|
-
|
104
|
+
if !args.first
|
105
|
+
raise CommandError, "No input to play command."
|
106
|
+
end
|
107
|
+
|
102
108
|
code = target.eval(args.first)
|
103
109
|
|
104
110
|
range = opts.l? ? one_index_range_or_number(opts[:l]) : (0..-1)
|
@@ -242,7 +248,11 @@ class Pry
|
|
242
248
|
case opts["save"]
|
243
249
|
when Range
|
244
250
|
hist_array = Array(history[opts["save"]])
|
245
|
-
|
251
|
+
|
252
|
+
if !args.first
|
253
|
+
raise CommandError, "Must provide a file name."
|
254
|
+
end
|
255
|
+
|
246
256
|
file_name = File.expand_path(args.first)
|
247
257
|
when String
|
248
258
|
hist_array = history
|
@@ -5,59 +5,40 @@ class Pry
|
|
5
5
|
|
6
6
|
Introspection = Pry::CommandSet.new do
|
7
7
|
|
8
|
-
command "show-method", "Show the source for METH. Type `show-method --help` for more info. Aliases: $, show-source" do |*args|
|
9
|
-
|
10
|
-
|
11
|
-
opts = Slop.parse!(args) do |opt|
|
8
|
+
command "show-method", "Show the source for METH. Type `show-method --help` for more info. Aliases: $, show-source", :shellwords => false do |*args|
|
9
|
+
opts, meth = parse_options!(args, :method_object) do |opt|
|
12
10
|
opt.banner unindent <<-USAGE
|
13
|
-
Usage: show-method [OPTIONS] [METH
|
11
|
+
Usage: show-method [OPTIONS] [METH]
|
14
12
|
Show the source for method METH. Tries instance methods first and then methods by default.
|
15
13
|
e.g: show-method hello_method
|
16
14
|
USAGE
|
17
15
|
|
18
16
|
opt.on :l, "line-numbers", "Show line numbers."
|
19
17
|
opt.on :b, "base-one", "Show line numbers but start numbering at 1 (useful for `amend-line` and `play` commands)."
|
20
|
-
|
21
|
-
opt.on :M, "instance-methods", "Operate on instance methods."
|
22
|
-
opt.on :m, :methods, "Operate on methods."
|
23
18
|
opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
|
24
|
-
opt.on :c, :context, "Select object context to run under.", true do |context|
|
25
|
-
target = Pry.binding_for(target.eval(context))
|
26
|
-
end
|
27
|
-
opt.on :h, :help, "This message." do
|
28
|
-
output.puts opt
|
29
|
-
end
|
30
19
|
end
|
31
20
|
|
32
|
-
|
33
|
-
|
34
|
-
args = [nil] if args.empty?
|
35
|
-
args.each do |method_name|
|
36
|
-
meth_name = method_name
|
37
|
-
if (meth = get_method_object(meth_name, target, opts.to_hash(true))).nil?
|
38
|
-
output.puts "Invalid method name: #{meth_name}. Type `show-method --help` for help"
|
39
|
-
next
|
40
|
-
end
|
21
|
+
raise CommandError, "Could not find method source" unless meth.source
|
41
22
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
if Pry.color
|
47
|
-
code = CodeRay.scan(code, code_type).term
|
48
|
-
end
|
49
|
-
|
50
|
-
start_line = false
|
51
|
-
if opts.l?
|
52
|
-
start_line = meth.source_location ? meth.source_location.last : 1
|
53
|
-
end
|
54
|
-
|
55
|
-
start_line = opts.b? ? 1 : start_line
|
23
|
+
output.puts make_header(meth)
|
24
|
+
output.puts "#{text.bold("Owner:")} #{meth.owner || "N/A"}"
|
25
|
+
output.puts "#{text.bold("Visibility:")} #{meth.visibility}"
|
26
|
+
output.puts
|
56
27
|
|
28
|
+
if Pry.color
|
29
|
+
code = CodeRay.scan(meth.source, meth.source_type).term
|
30
|
+
else
|
31
|
+
code = meth.source
|
32
|
+
end
|
57
33
|
|
58
|
-
|
59
|
-
|
34
|
+
start_line = false
|
35
|
+
if opts.b?
|
36
|
+
start_line = 1
|
37
|
+
elsif opts.l?
|
38
|
+
start_line = meth.source_line || 1
|
60
39
|
end
|
40
|
+
|
41
|
+
render_output(opts.flood?, start_line, code)
|
61
42
|
end
|
62
43
|
|
63
44
|
alias_command "show-source", "show-method"
|
@@ -84,31 +65,33 @@ class Pry
|
|
84
65
|
|
85
66
|
command_name = args.shift
|
86
67
|
if !command_name
|
87
|
-
|
88
|
-
next
|
68
|
+
raise CommandError, "You must provide a command name."
|
89
69
|
end
|
90
70
|
|
91
71
|
if find_command(command_name)
|
92
|
-
block = find_command(command_name).block
|
72
|
+
block = Pry::Method.new(find_command(command_name).block)
|
93
73
|
|
94
|
-
|
95
|
-
|
74
|
+
next unless block.source
|
75
|
+
set_file_and_dir_locals(block.source_file)
|
96
76
|
|
97
|
-
output.puts make_header(block
|
77
|
+
output.puts make_header(block)
|
78
|
+
output.puts
|
98
79
|
|
99
80
|
if Pry.color
|
100
|
-
code = CodeRay.scan(
|
81
|
+
code = CodeRay.scan(block.source, :ruby).term
|
82
|
+
else
|
83
|
+
code = block.source
|
101
84
|
end
|
102
85
|
|
103
86
|
start_line = false
|
104
87
|
if opts.l?
|
105
|
-
start_line = block.
|
88
|
+
start_line = block.source_line || 1
|
106
89
|
end
|
107
90
|
|
108
|
-
render_output(opts.flood?, opts.l? ? block.
|
91
|
+
render_output(opts.flood?, opts.l? ? block.source_line : false, code)
|
109
92
|
code
|
110
93
|
else
|
111
|
-
|
94
|
+
raise CommandError, "No such command: #{command_name}."
|
112
95
|
end
|
113
96
|
end
|
114
97
|
|
@@ -133,8 +116,8 @@ class Pry
|
|
133
116
|
end
|
134
117
|
next if opts.h?
|
135
118
|
|
136
|
-
if [opts.ex?, opts.t?, opts.
|
137
|
-
|
119
|
+
if [opts.ex?, opts.t?, opts.i?, !args.empty?].count(true) > 1
|
120
|
+
raise CommandError, "Only one of --ex, --temp, --in and FILE may be specified."
|
138
121
|
end
|
139
122
|
|
140
123
|
# edit of local code, eval'd within pry.
|
@@ -173,21 +156,29 @@ class Pry
|
|
173
156
|
# edit of remote code, eval'd at top-level
|
174
157
|
else
|
175
158
|
if opts.ex?
|
176
|
-
|
159
|
+
if _pry_.last_exception.nil?
|
160
|
+
raise CommandError, "No exception found."
|
161
|
+
end
|
162
|
+
|
177
163
|
ex = _pry_.last_exception
|
178
164
|
bt_index = opts[:ex].to_i
|
179
165
|
|
180
166
|
ex_file, ex_line = ex.bt_source_location_for(bt_index)
|
181
|
-
if ex_file &&
|
182
|
-
file_name =
|
167
|
+
if ex_file && RbxPath.is_core_path?(ex_file)
|
168
|
+
file_name = RbxPath.convert_path_to_full(ex_file)
|
183
169
|
else
|
184
170
|
file_name = ex_file
|
185
171
|
end
|
186
172
|
|
187
173
|
line = ex_line
|
188
|
-
next output.puts "Exception has no associated file." if file_name.nil?
|
189
|
-
next output.puts "Cannot edit exceptions raised in REPL." if Pry.eval_path == file_name
|
190
174
|
|
175
|
+
if file_name.nil?
|
176
|
+
raise CommandError, "Exception has no associated file."
|
177
|
+
end
|
178
|
+
|
179
|
+
if Pry.eval_path == file_name
|
180
|
+
raise CommandError, "Cannot edit exceptions raised in REPL."
|
181
|
+
end
|
191
182
|
else
|
192
183
|
# break up into file:line
|
193
184
|
file_name = File.expand_path(args.first)
|
@@ -208,10 +199,10 @@ class Pry
|
|
208
199
|
end
|
209
200
|
end
|
210
201
|
|
211
|
-
command "edit-method", "Edit a method. Type `edit-method --help` for more info." do |*args|
|
202
|
+
command "edit-method", "Edit a method. Type `edit-method --help` for more info.", :shellwords => false do |*args|
|
212
203
|
target = target()
|
213
204
|
|
214
|
-
opts =
|
205
|
+
opts, meth = parse_options!(args, :method_object) do |opt|
|
215
206
|
opt.banner unindent <<-USAGE
|
216
207
|
Usage: edit-method [OPTIONS] [METH]
|
217
208
|
Edit the method METH in an editor.
|
@@ -219,60 +210,49 @@ class Pry
|
|
219
210
|
e.g: edit-method hello_method
|
220
211
|
USAGE
|
221
212
|
|
222
|
-
opt.on :M, "instance-methods", "Operate on instance methods."
|
223
|
-
opt.on :m, :methods, "Operate on methods."
|
224
213
|
opt.on :n, "no-reload", "Do not automatically reload the method's file after editing."
|
225
214
|
opt.on "no-jump", "Do not fast forward editor to first line of method."
|
226
215
|
opt.on :p, :patch, "Instead of editing the method's file, try to edit in a tempfile and apply as a monkey patch."
|
227
|
-
opt.on :c, :context, "Select object context to run under.", true do |context|
|
228
|
-
target = Pry.binding_for(target.eval(context))
|
229
|
-
end
|
230
216
|
opt.on :h, :help, "This message." do
|
231
217
|
output.puts opt
|
232
218
|
end
|
233
219
|
end
|
234
220
|
|
235
|
-
next if opts.help?
|
236
|
-
|
237
221
|
if !Pry.config.editor
|
238
|
-
|
239
|
-
output.puts "Ensure that #{text.bold("Pry.config.editor")} is set to your editor of choice."
|
240
|
-
next
|
222
|
+
raise CommandError, "No editor set!\nEnsure that #{text.bold("Pry.config.editor")} is set to your editor of choice."
|
241
223
|
end
|
242
224
|
|
243
|
-
|
244
|
-
|
245
|
-
meth = get_method_object_from_target(meth_name, target, type)
|
225
|
+
if opts.p? || meth.dynamically_defined?
|
226
|
+
lines = meth.source.lines.to_a
|
246
227
|
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
end
|
251
|
-
|
252
|
-
if opts.p? || is_a_dynamically_defined_method?(meth)
|
253
|
-
code, _ = code_and_code_type_for(meth)
|
254
|
-
|
255
|
-
lines = code.lines.to_a
|
256
|
-
if lines[0] =~ /^def [^( \n]+/
|
257
|
-
lines[0] = "def #{meth_name}#{$'}"
|
228
|
+
if ((original_name = meth.original_name) &&
|
229
|
+
lines[0] =~ /^def (?:.*?\.)?#{original_name}(?=[\(\s;]|$)/)
|
230
|
+
lines[0] = "def #{original_name}#{$'}"
|
258
231
|
else
|
259
|
-
|
232
|
+
raise CommandError, "Pry can only patch methods created with the `def` keyword."
|
260
233
|
end
|
261
234
|
|
262
235
|
temp_file do |f|
|
263
236
|
f.puts lines.join
|
264
237
|
f.flush
|
265
238
|
invoke_editor(f.path, 0)
|
266
|
-
|
239
|
+
|
240
|
+
if meth.alias?
|
241
|
+
with_method_transaction(original_name, meth.owner) do
|
242
|
+
Pry.new(:input => StringIO.new(File.read(f.path))).rep(meth.owner)
|
243
|
+
Pry.binding_for(meth.owner).eval("alias #{meth.name} #{original_name}")
|
244
|
+
end
|
245
|
+
else
|
246
|
+
Pry.new(:input => StringIO.new(File.read(f.path))).rep(meth.owner)
|
247
|
+
end
|
267
248
|
end
|
268
249
|
next
|
269
250
|
end
|
270
251
|
|
271
|
-
if
|
272
|
-
|
252
|
+
if meth.source_type == :c
|
253
|
+
raise CommandError, "Can't edit a C method."
|
273
254
|
else
|
274
|
-
file, line =
|
275
|
-
set_file_and_dir_locals(file)
|
255
|
+
file, line = meth.source_file, meth.source_line
|
276
256
|
|
277
257
|
invoke_editor(file, opts["no-jump"] ? 0 : line)
|
278
258
|
silence_warnings do
|
@@ -281,6 +261,17 @@ class Pry
|
|
281
261
|
end
|
282
262
|
end
|
283
263
|
|
264
|
+
helpers do
|
265
|
+
def with_method_transaction(meth_name, target=TOPLEVEL_BINDING)
|
266
|
+
target = Pry.binding_for(target)
|
267
|
+
temp_name = "__pry_#{meth_name}__"
|
268
|
+
|
269
|
+
target.eval("alias #{temp_name} #{meth_name}")
|
270
|
+
yield
|
271
|
+
target.eval("alias #{meth_name} #{temp_name}")
|
272
|
+
target.eval("undef #{temp_name}")
|
273
|
+
end
|
274
|
+
end
|
284
275
|
end
|
285
276
|
end
|
286
277
|
end
|