pry 0.9.8.2 → 0.9.8.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/CHANGELOG +8 -0
  2. data/README.markdown +20 -13
  3. data/Rakefile +1 -1
  4. data/lib/pry.rb +1 -2
  5. data/lib/pry/command.rb +88 -2
  6. data/lib/pry/command_set.rb +15 -85
  7. data/lib/pry/commands.rb +12 -8
  8. data/lib/pry/default_commands/cd.rb +58 -0
  9. data/lib/pry/default_commands/commands.rb +62 -0
  10. data/lib/pry/default_commands/context.rb +48 -165
  11. data/lib/pry/default_commands/editing.rb +385 -0
  12. data/lib/pry/default_commands/help.rb +127 -0
  13. data/lib/pry/default_commands/hist.rb +116 -0
  14. data/lib/pry/default_commands/{shell.rb → input_and_output.rb} +137 -15
  15. data/lib/pry/default_commands/introspection.rb +79 -232
  16. data/lib/pry/default_commands/ls.rb +4 -2
  17. data/lib/pry/default_commands/{basic.rb → misc.rb} +1 -14
  18. data/lib/pry/default_commands/navigating_pry.rb +114 -0
  19. data/lib/pry/helpers/base_helpers.rb +15 -3
  20. data/lib/pry/helpers/command_helpers.rb +16 -0
  21. data/lib/pry/history.rb +12 -4
  22. data/lib/pry/method.rb +2 -2
  23. data/lib/pry/pry_class.rb +7 -1
  24. data/lib/pry/pry_instance.rb +6 -0
  25. data/lib/pry/rbx_path.rb +6 -18
  26. data/lib/pry/version.rb +1 -1
  27. data/pry.gemspec +8 -8
  28. data/test/helper.rb +8 -0
  29. data/test/test_command.rb +256 -2
  30. data/test/test_command_integration.rb +2 -13
  31. data/test/test_command_set.rb +13 -23
  32. data/test/test_default_commands/test_help.rb +57 -0
  33. data/test/test_default_commands/test_introspection.rb +23 -0
  34. data/test/test_pry.rb +11 -0
  35. metadata +13 -9
  36. data/lib/pry/default_commands/documentation.rb +0 -209
  37. data/lib/pry/default_commands/input.rb +0 -247
  38. data/test/test_default_commands.rb +0 -58
@@ -0,0 +1,127 @@
1
+ class Pry
2
+ module DefaultCommands
3
+ Help = Pry::CommandSet.new do
4
+ create_command "help" do |cmd|
5
+ description "Show a list of commands. Type `help <foo>` for information about <foo>."
6
+
7
+ banner <<-BANNER
8
+ Usage: help [ COMMAND ]
9
+
10
+ With no arguments, help lists all the available commands in the current
11
+ command-set along with their description.
12
+
13
+ When given a command name as an argument, shows the help for that command.
14
+ BANNER
15
+
16
+ # We only want to show commands that have descriptions, so that the
17
+ # easter eggs don't show up.
18
+ def visible_commands
19
+ visible = {}
20
+ commands.each do |key, command|
21
+ visible[key] = command if command.description && !command.description.empty?
22
+ end
23
+ visible
24
+ end
25
+
26
+ # Get a hash of available commands grouped by the "group" name.
27
+ def command_groups
28
+ visible_commands.values.group_by(&:group)
29
+ end
30
+
31
+ def process
32
+ if args.empty?
33
+ display_index(command_groups)
34
+ else
35
+ display_search(args.first)
36
+ end
37
+ end
38
+
39
+ # Display the index view, with headings and short descriptions per command.
40
+ #
41
+ # @param Hash[String => Array[Commands]]
42
+ def display_index(groups)
43
+ help_text = []
44
+
45
+ groups.keys.sort_by(&method(:group_sort_key)).each do |key|
46
+ commands = groups[key].sort_by{ |command| command.options[:listing].to_s }
47
+
48
+ unless commands.empty?
49
+ help_text << "#{text.bold(key)}\n" + commands.map do |command|
50
+ " #{command.options[:listing].to_s.ljust(18)} #{command.description}"
51
+ end.join("\n")
52
+ end
53
+ end
54
+
55
+ stagger_output(help_text.join("\n\n"))
56
+ end
57
+
58
+ # Display help for an individual command or group.
59
+ #
60
+ # @param String The string to search for.
61
+ def display_search(search)
62
+ if command = command_set.find_command_for_help(search)
63
+ display_command(command)
64
+ else
65
+ groups = search_hash(search, command_groups)
66
+
67
+ if groups.size > 0
68
+ display_index(groups)
69
+ return
70
+ end
71
+
72
+ filtered = search_hash(search, visible_commands)
73
+ raise CommandError, "No help found for '#{args.first}'" if filtered.empty?
74
+
75
+ if filtered.size == 1
76
+ display_command(filtered.values.first)
77
+ else
78
+ display_index({"'#{search}' commands" => filtered.values})
79
+ end
80
+ end
81
+ end
82
+
83
+ # Display help for an individual command.
84
+ #
85
+ # @param [Pry::Command]
86
+ def display_command(command)
87
+ stagger_output command.new.help
88
+ end
89
+
90
+ # Find a subset of a hash that matches the user's search term.
91
+ #
92
+ # If there's an exact match a Hash of one element will be returned,
93
+ # otherwise a sub-Hash with every key that matches the search will
94
+ # be returned.
95
+ #
96
+ # @param [String] the search term
97
+ # @param [Hash] the hash to search
98
+ def search_hash(search, hash)
99
+ matching = {}
100
+
101
+ hash.each_pair do |key, value|
102
+ next unless key.is_a?(String)
103
+ if normalize(key) == normalize(search)
104
+ return {key => value}
105
+ elsif normalize(key).start_with?(normalize(search))
106
+ matching[key] = value
107
+ end
108
+ end
109
+
110
+ matching
111
+ end
112
+
113
+ # Clean search terms to make it easier to search group names
114
+ #
115
+ # @param String
116
+ # @return String
117
+ def normalize(key)
118
+ key.downcase.gsub(/pry\W+/, '')
119
+ end
120
+
121
+ def group_sort_key(group_name)
122
+ [%w(Help Context Editing Introspection Input_and_output Navigating_pry Gems Basic Commands).index(group_name.gsub(' ', '_')) || 99, group_name]
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,116 @@
1
+ class Pry
2
+ module DefaultCommands
3
+ Hist = Pry::CommandSet.new do
4
+
5
+ create_command "hist", "Show and replay Readline history. Aliases: history" do
6
+ group "Editing"
7
+ banner <<-USAGE
8
+ Usage: hist
9
+ hist --head N
10
+ hist --tail N
11
+ hist --show START..END
12
+ hist --grep PATTERN
13
+ hist --clear
14
+ hist --replay START..END
15
+ hist --save [START..END] FILE
16
+ USAGE
17
+
18
+ def options(opt)
19
+ opt.on :H, :head, "Display the first N items.", :optional => true, :as => Integer
20
+ opt.on :T, :tail, "Display the last N items.", :optional => true, :as => Integer
21
+ opt.on :s, :show, "Show the given range of lines.", :optional => true, :as => Range
22
+ opt.on :G, :grep, "Show lines matching the given pattern.", true, :as => String
23
+ opt.on :c, :clear, "Clear the current session's history."
24
+ opt.on :r, :replay, "Replay a line or range of lines.", true, :as => Range
25
+ opt.on :save, "Save history to a file.", true, :as => Range
26
+
27
+ opt.on :e, :'exclude-pry', "Exclude Pry commands from the history."
28
+ opt.on :n, :'no-numbers', "Omit line numbers."
29
+ opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
30
+ end
31
+
32
+ def process
33
+ @history = Pry::Code(Pry.history.to_a)
34
+
35
+ @history = case
36
+ when opts.present?(:head)
37
+ @history.between(1, opts[:head] || 10)
38
+ when opts.present?(:tail)
39
+ @history.between(-(opts[:tail] || 10), -1)
40
+ when opts.present?(:show)
41
+ @history.between(opts[:show])
42
+ else
43
+ @history
44
+ end
45
+
46
+ if opts.present?(:grep)
47
+ @history = @history.grep(opts[:grep])
48
+ end
49
+
50
+ if opts.present?(:'exclude-pry')
51
+ @history = @history.select { |l, ln| !command_set.valid_command?(l) }
52
+ end
53
+
54
+ if opts.present?(:save)
55
+ process_save
56
+ elsif opts.present?(:clear)
57
+ process_clear
58
+ elsif opts.present?(:replay)
59
+ process_replay
60
+ else
61
+ process_display
62
+ end
63
+ end
64
+
65
+ def process_display
66
+ unless opts.present?(:'no-numbers')
67
+ @history = @history.with_line_numbers
68
+ end
69
+
70
+ render_output(@history, opts)
71
+ end
72
+
73
+ def process_save
74
+ case opts[:save]
75
+ when Range
76
+ @history = @history.between(opts[:save])
77
+
78
+ unless args.first
79
+ raise CommandError, "Must provide a file name."
80
+ end
81
+
82
+ file_name = File.expand_path(args.first)
83
+ when String
84
+ file_name = File.expand_path(opts[:save])
85
+ end
86
+
87
+ output.puts "Saving history in #{file_name}..."
88
+
89
+ File.open(file_name, 'w') { |f| f.write(@history.to_s) }
90
+
91
+ output.puts "History saved."
92
+ end
93
+
94
+ def process_clear
95
+ Pry.history.clear
96
+ output.puts "History cleared."
97
+ end
98
+
99
+ def process_replay
100
+ @history = @history.between(opts[:r])
101
+
102
+ _pry_.input_stack.push _pry_.input
103
+ _pry_.input = StringIO.new(@history.raw)
104
+ # eval_string << "#{@history.raw}\n"
105
+ # run "show-input" unless _pry_.complete_expression?(eval_string)
106
+ end
107
+ end
108
+
109
+ alias_command "history", "hist"
110
+
111
+
112
+
113
+
114
+ end
115
+ end
116
+ end
@@ -1,9 +1,10 @@
1
+ require 'tempfile'
2
+
1
3
  class Pry
2
4
  module DefaultCommands
3
5
 
4
- Shell = Pry::CommandSet.new do
5
-
6
- command(/\.(.*)/, "All text following a '.' is forwarded to the shell.", :listing => ".<shell command>", :use_prefix => false) do |cmd|
6
+ InputAndOutput = Pry::CommandSet.new do
7
+ command(/\.(.*)/, "All text following a '.' is forwarded to the shell.", :listing => ".<shell command>", :use_prefix => false, :takes_block => true) do |cmd|
7
8
  if cmd =~ /^cd\s+(.+)/i
8
9
  dest = $1
9
10
  begin
@@ -12,7 +13,13 @@ class Pry
12
13
  raise CommandError, "No such directory: #{dest}"
13
14
  end
14
15
  else
15
- Pry.config.system.call(output, cmd, _pry_)
16
+ pass_block(cmd)
17
+
18
+ if command_block
19
+ command_block.call `#{cmd}`
20
+ else
21
+ Pry.config.system.call(output, cmd, _pry_)
22
+ end
16
23
  end
17
24
  end
18
25
 
@@ -30,6 +37,122 @@ class Pry
30
37
  end
31
38
  alias_command "file-mode", "shell-mode"
32
39
 
40
+ create_command "gist", "Gist a method or expression history to github.", :requires_gem => "gist", :shellwords => false do
41
+ banner <<-USAGE
42
+ Usage: gist [OPTIONS] [METH]
43
+ Gist method (doc or source) or input expression to github.
44
+ Ensure the `gist` gem is properly working before use. http://github.com/defunkt/gist for instructions.
45
+ e.g: gist -m my_method
46
+ e.g: gist -d my_method
47
+ e.g: gist -i 1..10
48
+ e.g: gist -c show-method
49
+ e.g: gist -m hello_world --lines 2..-2
50
+ USAGE
51
+
52
+ attr_accessor :content
53
+ attr_accessor :code_type
54
+
55
+ def setup
56
+ require 'gist'
57
+ self.content = ""
58
+ self.code_type = :ruby
59
+ end
60
+
61
+ def options(opt)
62
+ opt.on :m, :method, "Gist a method's source.", true do |meth_name|
63
+ meth = get_method_or_raise(meth_name, target, {})
64
+ self.content << meth.source
65
+ self.code_type = meth.source_type
66
+ end
67
+ opt.on :d, :doc, "Gist a method's documentation.", true do |meth_name|
68
+ meth = get_method_or_raise(meth_name, target, {})
69
+ text.no_color do
70
+ self.content << process_comment_markup(meth.doc, self.code_type)
71
+ end
72
+ self.code_type = :plain
73
+ end
74
+ opt.on :c, :command, "Gist a command's source.", true do |command_name|
75
+ command = find_command(command_name)
76
+ block = Pry::Method.new(find_command(command_name).block)
77
+ self.content << block.source
78
+ end
79
+ opt.on :f, :file, "Gist a file.", true do |file|
80
+ self.content << File.read(File.expand_path(file))
81
+ end
82
+ opt.on :p, :public, "Create a public gist (default: false)", :default => false
83
+ opt.on :l, :lines, "Only gist a subset of lines.", :optional => true, :as => Range, :default => 1..-1
84
+ opt.on :i, :in, "Gist entries from Pry's input expression history. Takes an index or range.", :optional => true,
85
+ :as => Range, :default => -5..-1 do |range|
86
+ range = convert_to_range(range)
87
+ input_expressions = _pry_.input_array[range] || []
88
+ Array(input_expressions).each_with_index do |code, index|
89
+ corrected_index = index + range.first
90
+ if code && code != ""
91
+ self.content << code
92
+ if code !~ /;\Z/
93
+ self.content << "#{comment_expression_result_for_gist(Pry.config.gist.inspecter.call(_pry_.output_array[corrected_index]))}"
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ def process
101
+ perform_gist
102
+ end
103
+
104
+ def perform_gist
105
+ type_map = { :ruby => "rb", :c => "c", :plain => "plain" }
106
+
107
+ if self.content =~ /\A\s*\z/
108
+ raise CommandError, "Found no code to gist."
109
+ end
110
+
111
+ # prevent Gist from exiting the session on error
112
+ begin
113
+ extname = opts.present?(:file) ? ".#{gist_file_extension(opts[:f])}" : ".#{type_map[self.code_type]}"
114
+
115
+ if opts.present?(:lines)
116
+ self.content = restrict_to_lines(content, opts[:l])
117
+ end
118
+
119
+ link = Gist.write([:extension => extname,
120
+ :input => self.content],
121
+ !opts[:p])
122
+ rescue SystemExit
123
+ end
124
+
125
+ if link
126
+ Gist.copy(link)
127
+ output.puts "Gist created at #{link} and added to clipboard."
128
+ end
129
+ end
130
+
131
+ def gist_file_extension(file_name)
132
+ file_name.split(".").last
133
+ end
134
+
135
+ def convert_to_range(n)
136
+ if !n.is_a?(Range)
137
+ (n..n)
138
+ else
139
+ n
140
+ end
141
+ end
142
+
143
+ def comment_expression_result_for_gist(result)
144
+ content = ""
145
+ result.lines.each_with_index do |line, index|
146
+ if index == 0
147
+ content << "# => #{line}"
148
+ else
149
+ content << "# #{line}"
150
+ end
151
+ end
152
+ content
153
+ end
154
+ end
155
+
33
156
  create_command "save-file", "Export to a file using content from the REPL." do
34
157
  banner <<-USAGE
35
158
  Usage: save-file [OPTIONS] [FILE]
@@ -130,13 +253,13 @@ class Pry
130
253
 
131
254
  def process
132
255
  handler = case
133
- when opts.present?(:ex)
134
- method :process_ex
135
- when opts.present?(:in)
136
- method :process_in
137
- else
138
- method :process_file
139
- end
256
+ when opts.present?(:ex)
257
+ method :process_ex
258
+ when opts.present?(:in)
259
+ method :process_in
260
+ else
261
+ method :process_file
262
+ end
140
263
 
141
264
  output = handler.call do |code|
142
265
  code.code_type = opts[:type] || :ruby
@@ -183,8 +306,8 @@ class Pry
183
306
  HEADER
184
307
 
185
308
  code = yield(Pry::Code.from_file(ex_file).
186
- between(start_line, end_line).
187
- with_marker(ex_line))
309
+ between(start_line, end_line).
310
+ with_marker(ex_line))
188
311
 
189
312
  "#{header}#{code}"
190
313
  end
@@ -233,8 +356,7 @@ class Pry
233
356
  code
234
357
  end
235
358
  end
236
- end
237
359
 
360
+ end
238
361
  end
239
362
  end
240
-
@@ -5,8 +5,80 @@ class Pry
5
5
 
6
6
  Introspection = Pry::CommandSet.new do
7
7
 
8
+ create_command "show-doc", "Show the comments above METH. Aliases: \?", :shellwords => false do |*args|
9
+ banner <<-BANNER
10
+ Usage: show-doc [OPTIONS] [METH]
11
+ Show the comments above method METH. Tries instance methods first and then methods by default.
12
+ e.g show-doc hello_method
13
+ BANNER
14
+
15
+ def options(opt)
16
+ method_options(opt)
17
+ opt.on :l, "line-numbers", "Show line numbers."
18
+ opt.on :b, "base-one", "Show line numbers but start numbering at 1 (useful for `amend-line` and `play` commands)."
19
+ opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
20
+ end
21
+
22
+ def process
23
+ meth = method_object
24
+ raise Pry::CommandError, "No documentation found." if meth.doc.nil? || meth.doc.empty?
25
+
26
+ doc = process_comment_markup(meth.doc, meth.source_type)
27
+ output.puts make_header(meth, doc)
28
+ output.puts "#{text.bold("Owner:")} #{meth.owner || "N/A"}"
29
+ output.puts "#{text.bold("Visibility:")} #{meth.visibility}"
30
+ output.puts "#{text.bold("Signature:")} #{meth.signature}"
31
+ output.puts
32
+
33
+ if opts.present?(:b) || opts.present?(:l)
34
+ doc = Code.new(doc, start_line, :text).
35
+ with_line_numbers(true)
36
+ end
37
+
38
+ render_output(doc, opts)
39
+ end
40
+
41
+ def start_line
42
+ if opts.present?(:'base-one')
43
+ 1
44
+ else
45
+ (method_object.source_line - method_object.doc.lines.count) || 1
46
+ end
47
+ end
48
+
49
+ end
50
+
51
+ alias_command "?", "show-doc"
52
+
53
+ create_command "stat", "View method information and set _file_ and _dir_ locals.", :shellwords => false do |*args|
54
+ banner <<-BANNER
55
+ Usage: stat [OPTIONS] [METH]
56
+ Show method information for method METH and set _file_ and _dir_ locals.
57
+ e.g: stat hello_method
58
+ BANNER
59
+
60
+ def options(opt)
61
+ method_options(opt)
62
+ end
63
+
64
+ def process
65
+ meth = method_object
66
+ output.puts unindent <<-EOS
67
+ Method Information:
68
+ --
69
+ Name: #{meth.name}
70
+ Owner: #{meth.owner ? meth.owner : "Unknown"}
71
+ Visibility: #{meth.visibility}
72
+ Type: #{meth.is_a?(::Method) ? "Bound" : "Unbound"}
73
+ Arity: #{meth.arity}
74
+ Method Signature: #{meth.signature}
75
+ Source Location: #{meth.source_location ? meth.source_location.join(":") : "Not found."}
76
+ EOS
77
+ end
78
+ end
79
+
8
80
  create_command "show-method" do
9
- description "Show the source for METH. Type `show-method --help` for more info. Aliases: $, show-source"
81
+ description "Show the source for METH. Aliases: $, show-source"
10
82
 
11
83
  banner <<-BANNER
12
84
  Usage: show-method [OPTIONS] [METH]
@@ -62,7 +134,7 @@ class Pry
62
134
  alias_command "show-source", "show-method"
63
135
  alias_command "$", "show-method"
64
136
 
65
- command "show-command", "Show the source for CMD. Type `show-command --help` for more info." do |*args|
137
+ command "show-command", "Show the source for CMD." do |*args|
66
138
  target = target()
67
139
 
68
140
  opts = Slop.parse!(args) do |opt|
@@ -103,244 +175,19 @@ class Pry
103
175
  end
104
176
  end
105
177
 
106
- create_command "edit" do
107
- description "Invoke the default editor on a file. Type `edit --help` for more info"
108
-
178
+ create_command "ri", "View ri documentation. e.g `ri Array#each`" do
109
179
  banner <<-BANNER
110
- Usage: edit [--no-reload|--reload] [--line LINE] [--temp|--ex|FILE[:LINE]|--in N]
111
-
112
- Open a text editor. When no FILE is given, edits the pry input buffer.
113
- Ensure Pry.config.editor is set to your editor of choice.
114
-
115
- e.g: `edit sample.rb`
116
- e.g: `edit sample.rb --line 105`
117
- e.g: `edit --ex`
180
+ Usage: ri [spec]
181
+ e.g. ri Array#each
118
182
 
119
- https://github.com/pry/pry/wiki/Editor-integration#wiki-Edit_command
183
+ Relies on the ri executable being available. See also: show-doc.
120
184
  BANNER
121
185
 
122
- def options(opt)
123
- opt.on :e, :ex, "Open the file that raised the most recent exception (_ex_.file)", :optional => true, :as => Integer
124
- opt.on :i, :in, "Open a temporary file containing the Nth line of _in_. N may be a range.", :optional => true, :as => Range, :default => -1..-1
125
- opt.on :t, :temp, "Open an empty temporary file"
126
- opt.on :l, :line, "Jump to this line in the opened file", true, :as => Integer
127
- opt.on :n, :"no-reload", "Don't automatically reload the edited code"
128
- opt.on :c, :"current", "Open the current __FILE__ and at __LINE__ (as returned by `whereami`)."
129
- opt.on :r, :reload, "Reload the edited code immediately (default for ruby files)"
130
- end
131
-
132
186
  def process
133
- if [opts.present?(:ex), opts.present?(:temp), opts.present?(:in), !args.empty?].count(true) > 1
134
- raise CommandError, "Only one of --ex, --temp, --in and FILE may be specified."
135
- end
136
-
137
- if !opts.present?(:ex) && !opts.present?(:current) && args.empty?
138
- # edit of local code, eval'd within pry.
139
- process_local_edit
140
- else
141
- # edit of remote code, eval'd at top-level
142
- process_remote_edit
143
- end
144
- end
145
-
146
- def process_i
147
- case opts[:i]
148
- when Range
149
- (_pry_.input_array[opts[:i]] || []).join
150
- when Fixnum
151
- _pry_.input_array[opts[:i]] || ""
152
- else
153
- return output.puts "Not a valid range: #{opts[:i]}"
154
- end
155
- end
156
-
157
- def process_local_edit
158
- content = case
159
- when opts.present?(:temp)
160
- ""
161
- when opts.present?(:in)
162
- process_i
163
- when eval_string.strip != ""
164
- eval_string
165
- else
166
- _pry_.input_array.reverse_each.find{ |x| x && x.strip != "" } || ""
167
- end
168
-
169
- line = content.lines.count
170
-
171
- temp_file do |f|
172
- f.puts(content)
173
- f.flush
174
- invoke_editor(f.path, line)
175
- if !opts.present?(:'no-reload') && !Pry.config.disable_auto_reload
176
- silence_warnings do
177
- eval_string.replace(File.read(f.path))
178
- end
179
- end
180
- end
181
- end
182
-
183
- def process_remote_edit
184
- if opts.present?(:ex)
185
- if _pry_.last_exception.nil?
186
- raise CommandError, "No exception found."
187
- end
188
-
189
- ex = _pry_.last_exception
190
- bt_index = opts[:ex].to_i
191
-
192
- ex_file, ex_line = ex.bt_source_location_for(bt_index)
193
- if ex_file && RbxPath.is_core_path?(ex_file)
194
- file_name = RbxPath.convert_path_to_full(ex_file)
195
- else
196
- file_name = ex_file
197
- end
198
-
199
- line = ex_line
200
-
201
- if file_name.nil?
202
- raise CommandError, "Exception has no associated file."
203
- end
204
-
205
- if Pry.eval_path == file_name
206
- raise CommandError, "Cannot edit exceptions raised in REPL."
207
- end
208
- elsif opts.present?(:current)
209
- file_name = target.eval("__FILE__")
210
- line = target.eval("__LINE__")
211
- else
212
-
213
- # break up into file:line
214
- file_name = File.expand_path(args.first)
215
- line = file_name.sub!(/:(\d+)$/, "") ? $1.to_i : 1
216
- end
217
-
218
- if not_a_real_file?(file_name)
219
- raise CommandError, "#{file_name} is not a valid file name, cannot edit!"
220
- end
221
-
222
- line = opts[:l].to_i if opts.present?(:line)
223
-
224
- invoke_editor(file_name, line)
225
- set_file_and_dir_locals(file_name)
226
-
227
- if opts.present?(:reload) || ((opts.present?(:ex) || file_name.end_with?(".rb")) && !opts.present?(:'no-reload')) && !Pry.config.disable_auto_reload
228
- silence_warnings do
229
- TOPLEVEL_BINDING.eval(File.read(file_name), file_name)
230
- end
231
- end
187
+ run ".ri", *args
232
188
  end
233
189
  end
234
190
 
235
- create_command "edit-method" do
236
- description "Edit a method. Type `edit-method --help` for more info."
237
-
238
- banner <<-BANNER
239
- Usage: edit-method [OPTIONS] [METH]
240
-
241
- Edit the method METH in an editor.
242
- Ensure Pry.config.editor is set to your editor of choice.
243
-
244
- e.g: `edit-method hello_method`
245
- e.g: `edit-method Pry#rep`
246
- e.g: `edit-method`
247
-
248
- https://github.com/pry/pry/wiki/Editor-integration#wiki-Edit_method
249
- BANNER
250
-
251
- command_options :shellwords => false
252
-
253
- def options(opt)
254
- method_options(opt)
255
- opt.on :n, "no-reload", "Do not automatically reload the method's file after editing."
256
- opt.on "no-jump", "Do not fast forward editor to first line of method."
257
- opt.on :p, :patch, "Instead of editing the method's file, try to edit in a tempfile and apply as a monkey patch."
258
- end
259
-
260
- def process
261
- if !Pry.config.editor
262
- raise CommandError, "No editor set!\nEnsure that #{text.bold("Pry.config.editor")} is set to your editor of choice."
263
- end
264
-
265
- begin
266
- @method = method_object
267
- rescue NonMethodContextError => err
268
- end
269
-
270
- if opts.present?(:patch) || (@method && @method.dynamically_defined?)
271
- if err
272
- raise err # can't patch a non-method
273
- end
274
-
275
- process_patch
276
- else
277
- if err && !File.exist?(target.eval('__FILE__'))
278
- raise err # can't edit a non-file
279
- end
280
-
281
- process_file
282
- end
283
- end
284
-
285
- def process_patch
286
- lines = @method.source.lines.to_a
287
-
288
- if ((original_name = @method.original_name) &&
289
- lines[0] =~ /^def (?:.*?\.)?#{original_name}(?=[\(\s;]|$)/)
290
- lines[0] = "def #{original_name}#{$'}"
291
- else
292
- raise CommandError, "Pry can only patch methods created with the `def` keyword."
293
- end
294
-
295
- temp_file do |f|
296
- f.puts lines.join
297
- f.flush
298
- invoke_editor(f.path, 0)
299
-
300
- if @method.alias?
301
- with_method_transaction(original_name, @method.owner) do
302
- Pry.new(:input => StringIO.new(File.read(f.path))).rep(@method.owner)
303
- Pry.binding_for(@method.owner).eval("alias #{@method.name} #{original_name}")
304
- end
305
- else
306
- Pry.new(:input => StringIO.new(File.read(f.path))).rep(@method.owner)
307
- end
308
- end
309
- end
310
-
311
- def process_file
312
- file, line = extract_file_and_line
313
-
314
- invoke_editor(file, opts["no-jump"] ? 0 : line)
315
- silence_warnings do
316
- load file unless opts.present?(:'no-reload') || Pry.config.disable_auto_reload
317
- end
318
- end
319
-
320
- protected
321
- def extract_file_and_line
322
- if @method
323
- if @method.source_type == :c
324
- raise CommandError, "Can't edit a C method."
325
- else
326
- [@method.source_file, @method.source_line]
327
- end
328
- else
329
- [target.eval('__FILE__'), target.eval('__LINE__')]
330
- end
331
- end
332
-
333
- def with_method_transaction(meth_name, target=TOPLEVEL_BINDING)
334
- target = Pry.binding_for(target)
335
- temp_name = "__pry_#{meth_name}__"
336
-
337
- target.eval("alias #{temp_name} #{meth_name}")
338
- yield
339
- target.eval("alias #{meth_name} #{temp_name}")
340
- ensure
341
- target.eval("undef #{temp_name}") rescue nil
342
- end
343
- end
344
191
  end
345
192
  end
346
193
  end