pry 0.9.8pre7 → 0.9.8pre8

Sign up to get free protection for your applications and to get access to all the features.
@@ -59,7 +59,7 @@ class Pry
59
59
 
60
60
  alias_command(/%.?(-?\d+)?(?:\.\.(-?\d+))?/, "amend-line")
61
61
 
62
- command_class "play" do
62
+ create_command "play" do
63
63
  description "Play back a string variable or a method or a file as input. Type `play --help` for more information."
64
64
 
65
65
  banner <<-BANNER
@@ -69,73 +69,78 @@ class Pry
69
69
  if they were entered directly in the Pry REPL. Default action (no
70
70
  options) is to play the provided string variable
71
71
 
72
- e.g: `play _in_[20] --lines 1..3`
72
+ e.g: `play -i 20 --lines 1..3`
73
73
  e.g: `play -m Pry#repl --lines 1..-1`
74
74
  e.g: `play -f Rakefile --lines 5`
75
75
 
76
76
  https://github.com/pry/pry/wiki/User-Input#wiki-Play
77
77
  BANNER
78
78
 
79
+ attr_accessor :content
80
+
81
+ def setup
82
+ self.content = ""
83
+ end
84
+
79
85
  def options(opt)
80
- opt.on :l, :lines, 'The line (or range of lines) to replay.', true, :as => Range
81
- opt.on :m, :method, 'Play a method.', true
82
- opt.on :f, "file", 'The file to replay in context.', true
86
+ opt.on :m, :method, "Play a method's source.", true do |meth_name|
87
+ meth = get_method_or_raise(meth_name, target, {})
88
+ self.content << meth.source
89
+ end
90
+ opt.on :d, :doc, "Play a method's documentation.", true do |meth_name|
91
+ meth = get_method_or_raise(meth_name, target, {})
92
+ text.no_color do
93
+ self.content << process_comment_markup(meth.doc, :ruby)
94
+ end
95
+ end
96
+ opt.on :c, :command, "Play a command's source.", true do |command_name|
97
+ command = find_command(command_name)
98
+ block = Pry::Method.new(find_command(command_name).block)
99
+ self.content << block.source
100
+ end
101
+ opt.on :f, :file, "Play a file.", true do |file|
102
+ self.content << File.read(File.expand_path(file))
103
+ end
104
+ opt.on :l, :lines, "Only play a subset of lines.", :optional => true, :as => Range, :default => 1..-1
105
+ opt.on :i, :in, "Play entries from Pry's input expression history. Takes an index or range.", :optional => true,
106
+ :as => Range, :default => -5..-1 do |range|
107
+ input_expressions = _pry_.input_array[range] || []
108
+ Array(input_expressions).each { |v| self.content << v }
109
+ end
83
110
  opt.on :o, "open", 'When used with the -m switch, it plays the entire method except the last line, leaving the method definition "open". `amend-line` can then be used to modify the method.'
84
111
  end
85
112
 
86
113
  def process
87
- if opts.present?(:method)
88
- process_method
89
- elsif opts.present?(:file)
90
- process_file
91
- else
92
- process_input
93
- end
94
-
114
+ perform_play
95
115
  run "show-input" unless _pry_.complete_expression?(eval_string)
96
116
  end
97
117
 
98
- def process_method
99
- meth_name = opts[:m]
100
- meth = get_method_or_raise(meth_name, target, {}, :omit_help)
101
- return unless meth.source
102
-
103
- range = opts.present?(:lines) ? one_index_range_or_number(opts[:l]) : (0..-1)
104
- range = (0..-2) if opts.present?(:open)
105
-
106
- eval_string << Array(meth.source.each_line.to_a[range]).join
118
+ def process_non_opt
119
+ args.each do |arg|
120
+ begin
121
+ self.content << target.eval(arg)
122
+ rescue Pry::RescuableException
123
+ raise CommandError, "Prblem when evaling #{arg}."
124
+ end
125
+ end
107
126
  end
108
127
 
109
- def process_file
110
- file_name = File.expand_path(opts[:f])
128
+ def perform_play
129
+ process_non_opt
111
130
 
112
- if !File.exists?(file_name)
113
- raise CommandError, "No such file: #{opts[:f]}"
131
+ if opts.present?(:lines)
132
+ self.content = restrict_to_lines(self.content, opts[:l])
114
133
  end
115
134
 
116
- text_array = File.readlines(file_name)
117
- range = opts.present?(:lines) ? one_index_range_or_number(opts[:l]) : (0..-1)
118
- range = (0..-2) if opts.present?(:open)
119
-
120
- eval_string << Array(text_array[range]).join
121
- end
122
-
123
- def process_input
124
- if !args.first
125
- raise CommandError, "No input to play command."
135
+ if opts.present?(:open)
136
+ self.content = restrict_to_lines(self.content, 1..-2)
126
137
  end
127
138
 
128
- code = target.eval(args.first)
129
-
130
- range = opts.present?(:lines) ? one_index_range_or_number(opts[:l]) : (0..-1)
131
- range = (0..-2) if opts.present?(:open)
132
-
133
- eval_string << Array(code.each_line.to_a[range]).join
139
+ eval_string << self.content
134
140
  end
135
-
136
141
  end
137
142
 
138
- command_class "hist", "Show and replay Readline history. Aliases: history" do
143
+ create_command "hist", "Show and replay Readline history. Aliases: history" do
139
144
  banner <<-USAGE
140
145
  Usage: hist
141
146
  hist --head N
@@ -148,10 +153,10 @@ class Pry
148
153
  USAGE
149
154
 
150
155
  def options(opt)
151
- opt.on :h, :head, "Display the first N items.", :optional => true, :as => Integer
152
- opt.on :t, :tail, "Display the last N items.", :optional => true, :as => Integer
156
+ opt.on :H, :head, "Display the first N items.", :optional => true, :as => Integer
157
+ opt.on :T, :tail, "Display the last N items.", :optional => true, :as => Integer
153
158
  opt.on :s, :show, "Show the given range of lines.", :optional => true, :as => Range
154
- opt.on :g, :grep, "Show lines matching the given pattern.", true, :as => String
159
+ opt.on :G, :grep, "Show lines matching the given pattern.", true, :as => String
155
160
  opt.on :c, :clear, "Clear the current session's history."
156
161
  opt.on :r, :replay, "Replay a line or range of lines.", true, :as => Range
157
162
  opt.on :save, "Save history to a file.", true, :as => Range
@@ -230,8 +235,11 @@ class Pry
230
235
 
231
236
  def process_replay
232
237
  @history = @history.between(opts[:r])
233
- _pry_.input_stack << _pry_.input
234
- _pry_.input = StringIO.new(@history.to_s)
238
+
239
+ _pry_.input_stack.push _pry_.input
240
+ _pry_.input = StringIO.new(@history.raw)
241
+ # eval_string << "#{@history.raw}\n"
242
+ # run "show-input" unless _pry_.complete_expression?(eval_string)
235
243
  end
236
244
  end
237
245
 
@@ -5,7 +5,7 @@ class Pry
5
5
 
6
6
  Introspection = Pry::CommandSet.new do
7
7
 
8
- command_class "show-method" do
8
+ create_command "show-method" do
9
9
  description "Show the source for METH. Type `show-method --help` for more info. Aliases: $, show-source"
10
10
 
11
11
  banner <<-BANNER
@@ -33,24 +33,29 @@ class Pry
33
33
  end
34
34
 
35
35
  def process
36
- meth = method_object
37
- raise CommandError, "Could not find method source" unless meth.source
36
+ raise CommandError, "Could not find method source" unless method_object.source
38
37
 
39
- output.puts make_header(meth)
40
- output.puts "#{text.bold("Owner:")} #{meth.owner || "N/A"}"
41
- output.puts "#{text.bold("Visibility:")} #{meth.visibility}"
38
+ output.puts make_header(method_object)
39
+ output.puts "#{text.bold("Owner:")} #{method_object.owner || "N/A"}"
40
+ output.puts "#{text.bold("Visibility:")} #{method_object.visibility}"
42
41
  output.puts
43
42
 
43
+ code = Code.from_method(method_object, start_line).
44
+ with_line_numbers(use_line_numbers?)
45
+
46
+ render_output(code, opts)
47
+ end
48
+
49
+ def use_line_numbers?
50
+ opts.present?(:b) || opts.present?(:l)
51
+ end
52
+
53
+ def start_line
44
54
  if opts.present?(:'base-one')
45
- start_line = 1
55
+ 1
46
56
  else
47
- start_line = meth.source_line || 1
57
+ method_object.source_line || 1
48
58
  end
49
-
50
- code = Code.from_method(meth, start_line).
51
- with_line_numbers(opts.present?(:b) || opts.present?(:l))
52
-
53
- render_output(code, opts)
54
59
  end
55
60
  end
56
61
 
@@ -98,7 +103,7 @@ class Pry
98
103
  end
99
104
  end
100
105
 
101
- command_class "edit" do
106
+ create_command "edit" do
102
107
  description "Invoke the default editor on a file. Type `edit --help` for more info"
103
108
 
104
109
  banner <<-BANNER
@@ -219,7 +224,7 @@ class Pry
219
224
  end
220
225
  end
221
226
 
222
- command_class "edit-method" do
227
+ create_command "edit-method" do
223
228
  description "Edit a method. Type `edit-method --help` for more info."
224
229
 
225
230
  banner <<-BANNER
@@ -3,7 +3,7 @@ class Pry
3
3
 
4
4
  Ls = Pry::CommandSet.new do
5
5
 
6
- command_class "ls","Show the list of vars and methods in the current scope. Type `ls --help` for more info.",
6
+ create_command "ls","Show the list of vars and methods in the current scope. Type `ls --help` for more info.",
7
7
  :shellwords => false, :interpolate => false do
8
8
 
9
9
  def options(opt)
@@ -30,7 +30,79 @@ class Pry
30
30
  end
31
31
  alias_command "file-mode", "shell-mode"
32
32
 
33
- command_class "cat", "Show code from a file, Pry's input buffer, or the last exception." do
33
+ create_command "save-file", "Export to a file using content from the REPL." do
34
+ banner <<-USAGE
35
+ Usage: save-file [OPTIONS] [FILE]
36
+ Save REPL content to a file.
37
+ e.g: save-file -m my_method -m my_method2 ./hello.rb
38
+ e.g: save-file -i 1..10 ./hello.rb --append
39
+ e.g: save-file -c show-method ./my_command.rb
40
+ e.g: save-file -f sample_file --lines 2..10 ./output_file.rb
41
+ USAGE
42
+
43
+ attr_accessor :content
44
+ attr_accessor :file_name
45
+
46
+ def setup
47
+ self.content = ""
48
+ end
49
+
50
+ def options(opt)
51
+ opt.on :m, :method, "Save a method's source.", true do |meth_name|
52
+ meth = get_method_or_raise(meth_name, target, {})
53
+ self.content << meth.source
54
+ end
55
+ opt.on :c, :command, "Save a command's source.", true do |command_name|
56
+ command = find_command(command_name)
57
+ block = Pry::Method.new(find_command(command_name).block)
58
+ self.content << block.source
59
+ end
60
+ opt.on :f, :file, "Save a file.", true do |file|
61
+ self.content << File.read(File.expand_path(file))
62
+ end
63
+ opt.on :l, :lines, "Only save a subset of lines.", :optional => true, :as => Range, :default => 1..-1
64
+ opt.on :i, :in, "Save entries from Pry's input expression history. Takes an index or range.", :optional => true,
65
+ :as => Range, :default => -5..-1 do |range|
66
+ input_expressions = _pry_.input_array[range] || []
67
+ Array(input_expressions).each { |v| self.content << v }
68
+ end
69
+ opt.on :a, :append, "Append to the given file instead of overwriting it."
70
+ end
71
+
72
+ def process
73
+ if args.empty?
74
+ raise CommandError, "Must specify a file name."
75
+ end
76
+
77
+ self.file_name = File.expand_path(args.first)
78
+
79
+ save_file
80
+ end
81
+
82
+ def save_file
83
+ if self.content.empty?
84
+ raise CommandError, "Found no code to save."
85
+ end
86
+
87
+ File.open(file_name, mode) do |f|
88
+ if opts.present?(:lines)
89
+ f.puts restrict_to_lines(content, opts[:l])
90
+ else
91
+ f.puts content
92
+ end
93
+ end
94
+ end
95
+
96
+ def mode
97
+ if opts.present?(:append)
98
+ "a"
99
+ else
100
+ "w"
101
+ end
102
+ end
103
+ end
104
+
105
+ create_command "cat", "Show code from a file, Pry's input buffer, or the last exception." do
34
106
  banner <<-USAGE
35
107
  Usage: cat FILE
36
108
  cat --ex [STACK_INDEX]
@@ -97,6 +169,8 @@ class Pry
97
169
  ex_file = RbxPath.convert_path_to_full(ex_file)
98
170
  end
99
171
 
172
+ set_file_and_dir_locals(ex_file)
173
+
100
174
  start_line = ex_line - window_size
101
175
  start_line = 1 if start_line < 1
102
176
  end_line = ex_line + window_size
@@ -146,6 +220,7 @@ class Pry
146
220
  end
147
221
 
148
222
  file_name, line_num = file_name.split(':')
223
+ file_name = File.expand_path(file_name)
149
224
  set_file_and_dir_locals(file_name)
150
225
 
151
226
  code = yield(Pry::Code.from_file(file_name))
@@ -191,6 +191,15 @@ class Pry
191
191
  text.gsub(/^#{margin}/, '')
192
192
  end
193
193
 
194
+ # Restrict a string to the given range of lines (1-indexed)
195
+ # @param [String] content The string.
196
+ # @param [Range, Fixnum] lines The line(s) to restrict it to.
197
+ # @return [String] The resulting string.
198
+ def restrict_to_lines(content, lines)
199
+ line_range = one_index_range_or_number(lines)
200
+ Array(content.lines.to_a[line_range]).join
201
+ end
202
+
194
203
  def one_index_number(line_number)
195
204
  if line_number > 0
196
205
  line_number - 1
data/lib/pry/hooks.rb CHANGED
@@ -1,6 +1,31 @@
1
1
  class Pry
2
+
3
+ # Implements a hooks system for Pry. A hook is a callable that is
4
+ # associated with an event. A number of events are currently
5
+ # provided by Pry, these include: `:when_started`, `:before_session`, `:after_session`.
6
+ # A hook must have a name, and is connected with an event by the
7
+ # `Pry::Hooks#add_hook` method.
8
+ # @example Adding a hook for the `:before_session` event.
9
+ # Pry.config.hooks.add_hook(:before_session, :say_hi) do
10
+ # puts "hello"
11
+ # end
2
12
  class Hooks
3
13
 
14
+ # Converts a hash to a `Pry::Hooks` instance. All hooks defined
15
+ # this way are anonymous. This functionality is primarily to
16
+ # provide backwards-compatibility with the old hash-based hook
17
+ # system in Pry versions < 0.9.8
18
+ # @param [Hash] hash The hash to convert to `Pry::Hooks`.
19
+ # @return [Pry::Hooks] The resulting `Pry::Hooks` instance.
20
+ def self.from_hash(hash)
21
+ instance = new
22
+ hash.each do |k, v|
23
+ instance.add_hook(k, nil, v)
24
+ end
25
+
26
+ instance
27
+ end
28
+
4
29
  def initialize
5
30
  @hooks = {}
6
31
  end
@@ -24,14 +49,28 @@ class Pry
24
49
  @errors ||= []
25
50
  end
26
51
 
27
- # Destructively merge the contents of two `Pry:Hooks` instances.
28
- # @param [Pry::Hooks] other The `Pry::Hooks` instance to merge
52
+ # FIXME:
53
+ # This is a hack to alert people of the new API.
54
+ def [](event_name)
55
+ warn "`Pry.hooks[]` is deprecated! Please use the new `Pry::Hooks` API! http://rubydoc.info/github/pry/pry/master/Pry/Hooks"
29
56
 
57
+ get_hook(event_name, nil)
58
+ end
30
59
 
60
+ # FIXME:
61
+ # This is a hack to alert people of the new API.
62
+ def []=(event_name, callable)
63
+ warn "`Pry.hooks[]=` is deprecated! Please use the new `Pry::Hooks` API! http://rubydoc.info/github/pry/pry/master/Pry/Hooks"
31
64
 
32
- # TODO: implement by iterating over parameter and only overwriting
33
- # elements in receiver if they exist in parameter, and adding
34
- # other paramater elements to the end of the original's array
65
+ add_hook(event_name, nil, callable)
66
+ end
67
+
68
+ # Destructively merge the contents of two `Pry:Hooks` instances.
69
+ # @param [Pry::Hooks] other The `Pry::Hooks` instance to merge
70
+ # @return [Pry:Hooks] Returns the receiver.
71
+ # @example
72
+ # hooks = Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" }
73
+ # Pry::Hooks.new.merge!(hooks)
35
74
  def merge!(other)
36
75
  @hooks.merge!(other.dup.hooks) do |key, v1, v2|
37
76
  merge_arrays(v1, v2)
@@ -55,6 +94,9 @@ class Pry
55
94
  # Return a new `Pry::Hooks` instance containing a merge of the contents of two `Pry:Hooks` instances,
56
95
  # @param [Pry::Hooks] other The `Pry::Hooks` instance to merge
57
96
  # @return [Pry::Hooks] The new hash.
97
+ # @example
98
+ # hooks = Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" }
99
+ # Pry::Hooks.new.merge(hooks)
58
100
  def merge(other)
59
101
  self.dup.tap do |v|
60
102
  v.merge!(other)
@@ -66,18 +108,29 @@ class Pry
66
108
  # @param [Symbol] hook_name The name of the hook.
67
109
  # @param [#call] callable The callable.
68
110
  # @yield The block to use as the callable (if `callable` parameter not provided)
111
+ # @return [Pry:Hooks] Returns the receiver.
112
+ # @example
113
+ # Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" }
69
114
  def add_hook(event_name, hook_name, callable=nil, &block)
70
115
  @hooks[event_name] ||= []
71
116
 
72
- # do not allow duplicates
73
- raise ArgumentError, "Hook with name '#{hook_name}' already defined!" if hook_exists?(event_name, hook_name)
117
+ # do not allow duplicates, but allow multiple `nil` hooks
118
+ # (anonymous hooks)
119
+ if hook_exists?(event_name, hook_name) && !hook_name.nil?
120
+ raise ArgumentError, "Hook with name '#{hook_name}' already defined!"
121
+ end
122
+
123
+ if !block && !callable
124
+ raise ArgumentError, "Must provide a block or callable."
125
+ end
126
+
127
+ # ensure we only have one anonymous hook
128
+ @hooks[event_name].delete_if { |h, k| h.nil? } if hook_name.nil?
74
129
 
75
130
  if block
76
131
  @hooks[event_name] << [hook_name, block]
77
132
  elsif callable
78
133
  @hooks[event_name] << [hook_name, callable]
79
- else
80
- raise ArgumentError, "Must provide a block or callable."
81
134
  end
82
135
 
83
136
  self
@@ -87,6 +140,9 @@ class Pry
87
140
  # @param [Symbol] event_name The name of the event.
88
141
  # @param [Array] args The arguments to pass to each hook function.
89
142
  # @return [Object] The return value of the last executed hook.
143
+ # @example
144
+ # my_hooks = Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" }
145
+ # my_hooks.exec_hook(:before_session) #=> OUTPUT: "hi!"
90
146
  def exec_hook(event_name, *args, &block)
91
147
  @hooks[event_name] ||= []
92
148
 
@@ -107,6 +163,9 @@ class Pry
107
163
  # Return the number of hook functions registered for the `event_name` event.
108
164
  # @param [Symbol] event_name The name of the event.
109
165
  # @return [Fixnum] The number of hook functions for `event_name`.
166
+ # @example
167
+ # my_hooks = Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" }
168
+ # my_hooks.count(:before_session) #=> 1
110
169
  def hook_count(event_name)
111
170
  @hooks[event_name] ||= []
112
171
  @hooks[event_name].size
@@ -116,6 +175,9 @@ class Pry
116
175
  # @param [Symbol] event_name The name of the event.
117
176
  # @param [Symbol[ hook_name The name of the hook
118
177
  # @return [#call] The requested hook.
178
+ # @example
179
+ # my_hooks = Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" }
180
+ # my_hooks.get_hook(:before_session, :say_hi).call #=> "hi!"
119
181
  def get_hook(event_name, hook_name)
120
182
  @hooks[event_name] ||= []
121
183
  hook = @hooks[event_name].find { |current_hook_name, callable| current_hook_name == hook_name }
@@ -127,6 +189,9 @@ class Pry
127
189
  # alter the hooks, use add_hook/delete_hook for that).
128
190
  # @param [Symbol] event_name The name of the event.
129
191
  # @return [Hash] The hash of hook names / hook functions.
192
+ # @example
193
+ # my_hooks = Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" }
194
+ # my_hooks.get_hooks(:before_session) #=> {:say_hi=>#<Proc:0x00000101645e18@(pry):9>}
130
195
  def get_hooks(event_name)
131
196
  @hooks[event_name] ||= []
132
197
  Hash[@hooks[event_name]]
@@ -137,6 +202,9 @@ class Pry
137
202
  # @param [Symbol] hook_name The name of the hook.
138
203
  # to delete.
139
204
  # @return [#call] The deleted hook.
205
+ # @example
206
+ # my_hooks = Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" }
207
+ # my_hooks.delete_hook(:before_session, :say_hi)
140
208
  def delete_hook(event_name, hook_name)
141
209
  @hooks[event_name] ||= []
142
210
  deleted_callable = nil
@@ -154,16 +222,27 @@ class Pry
154
222
 
155
223
  # Clear all hooks functions for a given event.
156
224
  # @param [String] event_name The name of the event.
225
+ # @example
226
+ # my_hooks = Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" }
227
+ # my_hooks.delete_hook(:before_session)
157
228
  def delete_hooks(event_name)
158
229
  @hooks[event_name] = []
159
230
  end
160
231
 
161
232
  alias_method :clear, :delete_hooks
162
233
 
234
+ # Remove all events and hooks, clearing out the Pry::Hooks
235
+ # instance completely.
236
+ # @example
237
+ # my_hooks = Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" }
238
+ # my_hooks.clear_all
239
+ def clear_all
240
+ @hooks = {}
241
+ end
242
+
163
243
  # @param [Symbol] event_name Name of the event.
164
244
  # @param [Symbol] hook_name Name of the hook.
165
245
  # @return [Boolean] Whether the hook by the name `hook_name`
166
- # is defined for the event.
167
246
  def hook_exists?(event_name, hook_name)
168
247
  !!@hooks[event_name].find { |name, _| name == hook_name }
169
248
  end