pry 0.9.7.4 → 0.9.8pre2

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.
Files changed (49) hide show
  1. data/.gitignore +1 -3
  2. data/README.markdown +3 -1
  3. data/Rakefile +48 -31
  4. data/bin/pry +2 -80
  5. data/lib/pry.rb +17 -20
  6. data/lib/pry/cli.rb +152 -0
  7. data/lib/pry/command_processor.rb +13 -0
  8. data/lib/pry/command_set.rb +102 -9
  9. data/lib/pry/config.rb +28 -6
  10. data/lib/pry/default_commands/context.rb +9 -8
  11. data/lib/pry/default_commands/documentation.rb +55 -13
  12. data/lib/pry/default_commands/easter_eggs.rb +1 -1
  13. data/lib/pry/default_commands/input.rb +25 -25
  14. data/lib/pry/default_commands/introspection.rb +19 -18
  15. data/lib/pry/default_commands/ls.rb +23 -38
  16. data/lib/pry/default_commands/shell.rb +47 -15
  17. data/lib/pry/helpers/command_helpers.rb +28 -6
  18. data/lib/pry/helpers/options_helpers.rb +7 -4
  19. data/lib/pry/helpers/text.rb +23 -3
  20. data/lib/pry/history.rb +55 -17
  21. data/lib/pry/history_array.rb +2 -0
  22. data/lib/pry/hooks.rb +108 -0
  23. data/lib/pry/indent.rb +9 -5
  24. data/lib/pry/method.rb +99 -50
  25. data/lib/pry/plugins.rb +10 -2
  26. data/lib/pry/pry_class.rb +48 -20
  27. data/lib/pry/pry_instance.rb +106 -91
  28. data/lib/pry/version.rb +1 -1
  29. data/lib/pry/wrapped_module.rb +73 -0
  30. data/man/pry.1 +195 -0
  31. data/man/pry.1.html +204 -0
  32. data/man/pry.1.ronn +141 -0
  33. data/pry.gemspec +21 -24
  34. data/test/helper.rb +12 -3
  35. data/test/test_cli.rb +78 -0
  36. data/test/test_command_set.rb +193 -1
  37. data/test/test_default_commands/test_context.rb +19 -4
  38. data/test/test_default_commands/test_input.rb +2 -2
  39. data/test/test_default_commands/test_introspection.rb +63 -6
  40. data/test/test_default_commands/test_ls.rb +8 -35
  41. data/test/test_default_commands/test_shell.rb +36 -1
  42. data/test/test_hooks.rb +175 -0
  43. data/test/test_indent.rb +2 -0
  44. data/test/test_method.rb +10 -0
  45. data/test/test_pry.rb +35 -34
  46. data/test/test_pry_history.rb +24 -24
  47. data/test/test_syntax_checking.rb +47 -0
  48. data/test/test_wrapped_module.rb +71 -0
  49. metadata +40 -34
@@ -32,13 +32,13 @@ class Pry
32
32
  end
33
33
 
34
34
  start_line = false
35
- if opts.b?
35
+ if opts.present?(:'base-one')
36
36
  start_line = 1
37
- elsif opts.l?
37
+ elsif opts.present?(:'line-numbers')
38
38
  start_line = meth.source_line || 1
39
39
  end
40
40
 
41
- render_output(opts.flood?, start_line, code)
41
+ render_output(opts.present?(:flood), start_line, code)
42
42
  end
43
43
 
44
44
  alias_command "show-source", "show-method"
@@ -61,7 +61,7 @@ class Pry
61
61
  end
62
62
  end
63
63
 
64
- next if opts.help?
64
+ next if opts.present?(:help)
65
65
 
66
66
  command_name = args.shift
67
67
  if !command_name
@@ -84,11 +84,11 @@ class Pry
84
84
  end
85
85
 
86
86
  start_line = false
87
- if opts.l?
87
+ if opts.present?(:'line-numbers')
88
88
  start_line = block.source_line || 1
89
89
  end
90
90
 
91
- render_output(opts.flood?, opts.l? ? block.source_line : false, code)
91
+ render_output(opts.present?(:flood), opts.present?(:'line-numbers') ? block.source_line : false, code)
92
92
  code
93
93
  else
94
94
  raise CommandError, "No such command: #{command_name}."
@@ -114,18 +114,18 @@ class Pry
114
114
  output.puts opt
115
115
  end
116
116
  end
117
- next if opts.h?
117
+ next if opts.present?(:help)
118
118
 
119
- if [opts.ex?, opts.t?, opts.i?, !args.empty?].count(true) > 1
119
+ if [opts.present?(:ex), opts.present?(:temp), opts.present?(:in), !args.empty?].count(true) > 1
120
120
  raise CommandError, "Only one of --ex, --temp, --in and FILE may be specified."
121
121
  end
122
122
 
123
123
  # edit of local code, eval'd within pry.
124
- if !opts.ex? && args.empty?
124
+ if !opts.present?(:ex) && args.empty?
125
125
 
126
- content = if opts.t?
126
+ content = if opts.present?(:temp)
127
127
  ""
128
- elsif opts.i?
128
+ elsif opts.present?(:in)
129
129
  case opts[:i]
130
130
  when Range
131
131
  (_pry_.input_array[opts[:i]] || []).join
@@ -146,7 +146,7 @@ class Pry
146
146
  f.puts(content)
147
147
  f.flush
148
148
  invoke_editor(f.path, line)
149
- if !opts.n?
149
+ if !opts.present?(:'no-reload')
150
150
  silence_warnings do
151
151
  eval_string.replace(File.read(f.path))
152
152
  end
@@ -155,7 +155,7 @@ class Pry
155
155
 
156
156
  # edit of remote code, eval'd at top-level
157
157
  else
158
- if opts.ex?
158
+ if opts.present?(:ex)
159
159
  if _pry_.last_exception.nil?
160
160
  raise CommandError, "No exception found."
161
161
  end
@@ -186,12 +186,12 @@ class Pry
186
186
  line = file_name.sub!(/:(\d+)$/, "") ? $1.to_i : 1
187
187
  end
188
188
 
189
- line = opts[:l].to_i if opts.l?
189
+ line = opts[:l].to_i if opts.present?(:line)
190
190
 
191
191
  invoke_editor(file_name, line)
192
192
  set_file_and_dir_locals(file_name)
193
193
 
194
- if opts.r? || ((opts.ex? || file_name.end_with?(".rb")) && !opts.n?)
194
+ if opts.present?(:reload) || ((opts.present?(:ex) || file_name.end_with?(".rb")) && !opts.present?(:'no-reload'))
195
195
  silence_warnings do
196
196
  TOPLEVEL_BINDING.eval(File.read(file_name), file_name)
197
197
  end
@@ -222,7 +222,7 @@ class Pry
222
222
  raise CommandError, "No editor set!\nEnsure that #{text.bold("Pry.config.editor")} is set to your editor of choice."
223
223
  end
224
224
 
225
- if opts.p? || meth.dynamically_defined?
225
+ if opts.present?(:patch) || meth.dynamically_defined?
226
226
  lines = meth.source.lines.to_a
227
227
 
228
228
  if ((original_name = meth.original_name) &&
@@ -256,7 +256,7 @@ class Pry
256
256
 
257
257
  invoke_editor(file, opts["no-jump"] ? 0 : line)
258
258
  silence_warnings do
259
- load file if !opts.n? && !Pry.config.disable_auto_reload
259
+ load file if !opts.present?(:'no-jump') && !Pry.config.disable_auto_reload
260
260
  end
261
261
  end
262
262
  end
@@ -269,7 +269,8 @@ class Pry
269
269
  target.eval("alias #{temp_name} #{meth_name}")
270
270
  yield
271
271
  target.eval("alias #{meth_name} #{temp_name}")
272
- target.eval("undef #{temp_name}")
272
+ ensure
273
+ target.eval("undef #{temp_name}") rescue nil
273
274
  end
274
275
  end
275
276
  end
@@ -21,36 +21,19 @@ class Pry
21
21
 
22
22
  # Get all the methods that we'll want to output
23
23
  def all_methods(obj, opts)
24
- opts.M? ? Pry::Method.all_from_class(obj) : Pry::Method.all_from_obj(obj)
24
+ opts.present?(:'instance-methods') ? Pry::Method.all_from_class(obj) : Pry::Method.all_from_obj(obj)
25
25
  end
26
26
 
27
27
  def resolution_order(obj, opts)
28
- opts.M? ? Pry::Method.instance_resolution_order(obj) : Pry::Method.resolution_order(obj)
29
- end
30
-
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"
45
- end
28
+ opts.present?(:'instance-methods') ? Pry::Method.instance_resolution_order(obj) : Pry::Method.resolution_order(obj)
46
29
  end
47
30
 
48
31
  # Get a lambda that can be used with .take_while to prevent over-eager
49
32
  # traversal of the Object's ancestry graph.
50
33
  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?
34
+ ceiling = if opts.present?(:quiet)
35
+ [opts.present?(:'instance-methods') ? obj.ancestors[1] : obj.class.ancestors[1]] + Pry.config.ls.ceiling
36
+ elsif opts.present?(:verbose)
54
37
  []
55
38
  else
56
39
  Pry.config.ls.ceiling.dup
@@ -142,7 +125,7 @@ class Pry
142
125
  USAGE
143
126
 
144
127
  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"
128
+ opt.on :M, "instance-methods", "Show methods defined in a Module or Class"
146
129
 
147
130
  opt.on :p, "ppp", "Show public, protected (in yellow) and private (in green) methods"
148
131
  opt.on :q, "quiet", "Show only methods defined on object.singleton_class and object.class"
@@ -160,46 +143,48 @@ class Pry
160
143
  opt.on :h, "help", "Show help"
161
144
  end
162
145
 
163
- next output.puts(opts) if opts.h?
146
+ next output.puts(opts.to_s) if opts.present?(:help)
164
147
 
165
148
  obj = args.empty? ? target_self : target.eval(args.join(" "))
166
149
 
167
150
  # 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?)
151
+ has_opts = (opts.present?(:methods) || opts.present?(:'instance-methods') || opts.present?(:ppp) ||
152
+ opts.present?(:globals) || opts.present?(:locals) || opts.present?(:constants) ||
153
+ opts.present?(:ivars))
169
154
 
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?)
155
+ show_methods = opts.present?(:methods) || opts.present?(:'instance-methods') || opts.present?(:ppp) || !has_opts
156
+ show_constants = opts.present?(:constants) || (!has_opts && Module === obj)
157
+ show_ivars = opts.present?(:ivars) || !has_opts
158
+ show_locals = opts.present?(:locals) || (!has_opts && args.empty?)
174
159
 
175
160
  grep_regex, grep = [Regexp.new(opts[:G] || "."), lambda{ |x| x.grep(grep_regex) }]
176
161
 
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)
162
+ raise Pry::CommandError, "-l does not make sense with a specified Object" if opts.present?(:locals) && !args.empty?
163
+ raise Pry::CommandError, "-g does not make sense with a specified Object" if opts.present?(:globals) && !args.empty?
164
+ raise Pry::CommandError, "-q does not make sense with -v" if opts.present?(:quiet) && opts.present?(:verbose)
165
+ raise Pry::CommandError, "-M only makes sense with a Module or a Class" if opts.present?(:'instance-methods') && !(Module === obj)
166
+ raise Pry::CommandError, "-c only makes sense with a Module or a Class" if opts.present?(:constants) && !args.empty? && !(Module === obj)
182
167
 
183
168
 
184
- if opts.g?
169
+ if opts.present?(:globals)
185
170
  output_section("global variables", grep[format_globals(target.eval("global_variables"))])
186
171
  end
187
172
 
188
173
  if show_constants
189
174
  mod = Module === obj ? obj : Object
190
175
  constants = mod.constants
191
- constants -= (mod.ancestors - [mod]).map(&:constants).flatten unless opts.v?
176
+ constants -= (mod.ancestors - [mod]).map(&:constants).flatten unless opts.present?(:verbose)
192
177
  output_section("constants", grep[format_constants(mod, constants)])
193
178
  end
194
179
 
195
180
  if show_methods
196
181
  # methods is a hash {Module/Class => [Pry::Methods]}
197
- methods = all_methods(obj, opts).select{ |method| opts.p? || method.visibility == :public }.group_by(&:owner)
182
+ methods = all_methods(obj, opts).select{ |method| opts.present?(:ppp) || method.visibility == :public }.group_by(&:owner)
198
183
 
199
184
  # reverse the resolution order so that the most useful information appears right by the prompt
200
185
  resolution_order(obj, opts).take_while(&below_ceiling(obj, opts)).reverse.each do |klass|
201
186
  methods_here = format_methods((methods[klass] || []).select{ |m| m.name =~ grep_regex })
202
- output_section "#{class_name(klass)} methods", methods_here
187
+ output_section "#{Pry::WrappedModule.new(klass).method_prefix}methods", methods_here
203
188
  end
204
189
  end
205
190
 
@@ -31,7 +31,7 @@ class Pry
31
31
 
32
32
  alias_command "file-mode", "shell-mode"
33
33
 
34
- command "cat", "Show output of file FILE. Type `cat --help` for more information." do |*args|
34
+ command "cat", "Show code from a file or Pry's input buffer. Type `cat --help` for more information." do |*args|
35
35
  start_line = 0
36
36
  end_line = -1
37
37
  file_name = nil
@@ -68,6 +68,8 @@ class Pry
68
68
  end
69
69
  end
70
70
 
71
+ opt.on :i, :in, "Show entries from Pry's input expression history. Takes an index or range.", :optional => true, :as => Range, :default => -5..-1
72
+
71
73
  opt.on :l, "line-numbers", "Show line numbers."
72
74
  opt.on :t, :type, "The specific file type for syntax higlighting (e.g ruby, python)", true, :as => Symbol
73
75
  opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
@@ -76,9 +78,9 @@ class Pry
76
78
  end
77
79
  end
78
80
 
79
- next if opts.help?
81
+ next if opts.present?(:help)
80
82
 
81
- if opts.ex?
83
+ if opts.present?(:ex)
82
84
  if file_name.nil?
83
85
  raise CommandError, "No Exception or Exception has no associated file."
84
86
  end
@@ -86,23 +88,53 @@ class Pry
86
88
  file_name = args.shift
87
89
  end
88
90
 
89
- if !file_name
90
- raise CommandError, "Must provide a file name."
91
- end
91
+ if opts.present?(:in)
92
+ normalized_range = absolute_index_range(opts[:i], _pry_.input_array.length)
93
+ input_items = _pry_.input_array[normalized_range] || []
94
+
95
+ zipped_items = normalized_range.zip(input_items).reject { |_, s| s.nil? || s == "" }
96
+
97
+ unless zipped_items.length > 0
98
+ raise CommandError, "No expressions found."
99
+ end
100
+
101
+ if opts[:i].is_a?(Range)
102
+ contents = ""
103
+
104
+ zipped_items.each do |i, s|
105
+ contents << "#{text.bold(i.to_s)}:\n"
106
+
107
+ code = syntax_highlight_by_file_type_or_specified(s, nil, :ruby)
108
+
109
+ if opts.present?(:'line-numbers')
110
+ contents << text.indent(text.with_line_numbers(code, 1), 2)
111
+ else
112
+ contents << text.indent(code, 2)
113
+ end
114
+ end
115
+ else
116
+ contents = syntax_highlight_by_file_type_or_specified(zipped_items.first.last, nil, :ruby)
117
+ end
118
+ else
119
+ unless file_name
120
+ raise CommandError, "Must provide a file name."
121
+ end
122
+
123
+ begin
124
+ contents, _, _ = read_between_the_lines(file_name, start_line, end_line)
125
+ rescue Errno::ENOENT
126
+ raise CommandError, "Could not find file: #{file_name}"
127
+ end
92
128
 
93
- begin
94
- contents, _, _ = read_between_the_lines(file_name, start_line, end_line)
95
129
  contents = syntax_highlight_by_file_type_or_specified(contents, file_name, opts[:type])
96
- rescue Errno::ENOENT
97
- raise CommandError, "Could not find file: #{file_name}"
98
- end
99
130
 
100
- if opts.l?
101
- contents = text.with_line_numbers contents, start_line + 1
131
+ if opts.present?(:'line-numbers')
132
+ contents = text.with_line_numbers contents, start_line + 1
133
+ end
102
134
  end
103
135
 
104
136
  # add the arrow pointing to line that caused the exception
105
- if opts.ex?
137
+ if opts.present?(:ex)
106
138
  ex_file, ex_line = _pry_.last_exception.bt_source_location_for(bt_index)
107
139
  contents = text.with_line_numbers contents, start_line + 1, :bright_red
108
140
 
@@ -122,7 +154,7 @@ class Pry
122
154
 
123
155
  set_file_and_dir_locals(file_name)
124
156
 
125
- if opts.f?
157
+ if opts.present?(:flood)
126
158
  output.puts contents
127
159
  else
128
160
  stagger_output(contents)
@@ -22,7 +22,7 @@ class Pry
22
22
  # Open a temp file and yield it to the block, closing it after
23
23
  # @return [String] The path of the temp file
24
24
  def temp_file
25
- file = Tempfile.new(["tmp", ".rb"])
25
+ file = Tempfile.new(['pry', '.rb'])
26
26
  yield file
27
27
  ensure
28
28
  file.close
@@ -41,7 +41,7 @@ class Pry
41
41
  if meth.super
42
42
  meth = meth.super
43
43
  else
44
- command_error("The method '#{meth.name}' is not defined in a superclass of '#{class_name(meth.owner)}'.", omit_help)
44
+ command_error("'#{meth.name_with_owner}' has no super method.", omit_help)
45
45
  end
46
46
  end
47
47
 
@@ -86,13 +86,16 @@ class Pry
86
86
  end
87
87
 
88
88
  def syntax_highlight_by_file_type_or_specified(contents, file_name, file_type)
89
- _, language_detected = file_map.find do |k, v|
90
- Array(k).any? do |matcher|
91
- matcher == File.extname(file_name) || matcher == File.basename(file_name)
89
+ if file_type
90
+ language_detected = file_type
91
+ else
92
+ _, language_detected = file_map.find do |k, v|
93
+ Array(k).any? do |matcher|
94
+ matcher == File.extname(file_name) || matcher == File.basename(file_name)
95
+ end
92
96
  end
93
97
  end
94
98
 
95
- language_detected = file_type if file_type
96
99
  if Pry.color
97
100
  CodeRay.scan(contents, language_detected).term
98
101
  else
@@ -247,6 +250,25 @@ class Pry
247
250
  text.gsub(/^#{margin}/, '')
248
251
  end
249
252
 
253
+ def absolute_index_number(line_number, array_length)
254
+ if line_number >= 0
255
+ line_number
256
+ else
257
+ [array_length + line_number, 0].max
258
+ end
259
+ end
260
+
261
+ def absolute_index_range(range_or_number, array_length)
262
+ case range_or_number
263
+ when Range
264
+ a = absolute_index_number(range_or_number.begin, array_length)
265
+ b = absolute_index_number(range_or_number.end, array_length)
266
+ else
267
+ a = b = absolute_index_number(range_or_number, array_length)
268
+ end
269
+
270
+ Range.new(a, b)
271
+ end
250
272
  end
251
273
 
252
274
  end
@@ -22,7 +22,7 @@ class Pry
22
22
  yield opt
23
23
 
24
24
  opt.on :h, :help, "This message" do
25
- output.puts opt
25
+ output.puts opt.to_s
26
26
  throw :command_done
27
27
  end
28
28
  end
@@ -47,11 +47,14 @@ class Pry
47
47
 
48
48
  # Add the derived :method_object option to a used Slop instance.
49
49
  def process_method_object_options(args, opts)
50
- opts[:instance] = opts['instance-methods'] if opts.m?
51
50
  # TODO: de-hack when we upgrade Slop: https://github.com/injekt/slop/pull/30
52
- opts.options[:super].force_argument_value opts.options[:super].count if opts.super?
51
+ opts.options[:super].force_argument_value opts.options[:super].count if opts.present?(:super)
53
52
 
54
- get_method_or_raise(args.empty? ? nil : args.join(" "), @method_target, opts.to_hash(true))
53
+ get_method_or_raise(args.empty? ? nil : args.join(" "), @method_target,
54
+ :super => opts[:super],
55
+ :instance => opts.present?(:'instance-methods') && !opts.present?(:'methods'),
56
+ :methods => opts.present?(:'methods') && !opts.present?(:'instance-methods')
57
+ )
55
58
  end
56
59
  end
57
60
  end
@@ -61,11 +61,23 @@ class Pry
61
61
  # @param [Proc]
62
62
  # @return [void]
63
63
  def no_color &block
64
- boolean = Pry.color
65
- Pry.color = false
64
+ boolean = Pry.config.color
65
+ Pry.config.color = false
66
66
  yield
67
67
  ensure
68
- Pry.color = boolean
68
+ Pry.config.color = boolean
69
+ end
70
+
71
+ # Executes _block_ with _Pry.config.pager_ set to false.
72
+ #
73
+ # @param [Proc]
74
+ # @return [void]
75
+ def no_pager &block
76
+ boolean = Pry.config.pager
77
+ Pry.config.pager = false
78
+ yield
79
+ ensure
80
+ Pry.config.pager = boolean
69
81
  end
70
82
 
71
83
  # Returns _text_ in a numbered list, beginning at _offset_.
@@ -81,6 +93,14 @@ class Pry
81
93
  "#{self.send(color, adjusted_index)}: #{line}"
82
94
  end.join
83
95
  end
96
+
97
+ # Returns _text_ indented by _chars_ spaces.
98
+ #
99
+ # @param [String] text
100
+ # @param [Fixnum] chars
101
+ def indent(text, chars)
102
+ text.lines.map { |l| "#{' ' * chars}#{l}" }.join
103
+ end
84
104
  end
85
105
 
86
106
  end