pry 0.9.7.4 → 0.9.8pre2

Sign up to get free protection for your applications and to get access to all the features.
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