pry 0.9.7.4-i386-mingw32 → 0.9.8-i386-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/.gitignore +2 -3
  2. data/CHANGELOG +43 -0
  3. data/README.markdown +3 -1
  4. data/Rakefile +51 -32
  5. data/bin/pry +2 -80
  6. data/lib/pry.rb +33 -26
  7. data/lib/pry/cli.rb +152 -0
  8. data/lib/pry/code.rb +351 -0
  9. data/lib/pry/command.rb +422 -0
  10. data/lib/pry/command_set.rb +259 -129
  11. data/lib/pry/commands.rb +0 -1
  12. data/lib/pry/config.rb +43 -9
  13. data/lib/pry/default_commands/context.rb +109 -92
  14. data/lib/pry/default_commands/documentation.rb +174 -63
  15. data/lib/pry/default_commands/easter_eggs.rb +26 -2
  16. data/lib/pry/default_commands/gems.rb +65 -37
  17. data/lib/pry/default_commands/input.rb +175 -243
  18. data/lib/pry/default_commands/introspection.rb +173 -112
  19. data/lib/pry/default_commands/ls.rb +96 -114
  20. data/lib/pry/default_commands/shell.rb +175 -70
  21. data/lib/pry/helpers/base_helpers.rb +7 -2
  22. data/lib/pry/helpers/command_helpers.rb +71 -77
  23. data/lib/pry/helpers/options_helpers.rb +10 -41
  24. data/lib/pry/helpers/text.rb +24 -4
  25. data/lib/pry/history.rb +55 -17
  26. data/lib/pry/history_array.rb +2 -0
  27. data/lib/pry/hooks.rb +252 -0
  28. data/lib/pry/indent.rb +9 -5
  29. data/lib/pry/method.rb +149 -50
  30. data/lib/pry/plugins.rb +12 -4
  31. data/lib/pry/pry_class.rb +69 -26
  32. data/lib/pry/pry_instance.rb +187 -115
  33. data/lib/pry/version.rb +1 -1
  34. data/lib/pry/wrapped_module.rb +73 -0
  35. data/man/pry.1 +195 -0
  36. data/man/pry.1.html +204 -0
  37. data/man/pry.1.ronn +141 -0
  38. data/pry.gemspec +29 -32
  39. data/test/helper.rb +32 -36
  40. data/test/test_cli.rb +78 -0
  41. data/test/test_code.rb +201 -0
  42. data/test/test_command.rb +327 -0
  43. data/test/test_command_integration.rb +512 -0
  44. data/test/test_command_set.rb +338 -12
  45. data/test/test_completion.rb +1 -1
  46. data/test/test_default_commands.rb +1 -2
  47. data/test/test_default_commands/test_context.rb +27 -5
  48. data/test/test_default_commands/test_documentation.rb +20 -8
  49. data/test/test_default_commands/test_input.rb +84 -45
  50. data/test/test_default_commands/test_introspection.rb +74 -17
  51. data/test/test_default_commands/test_ls.rb +9 -36
  52. data/test/test_default_commands/test_shell.rb +240 -13
  53. data/test/test_hooks.rb +490 -0
  54. data/test/test_indent.rb +2 -0
  55. data/test/test_method.rb +60 -0
  56. data/test/test_pry.rb +29 -904
  57. data/test/test_pry_defaults.rb +380 -0
  58. data/test/test_pry_history.rb +24 -24
  59. data/test/test_syntax_checking.rb +63 -0
  60. data/test/test_wrapped_module.rb +71 -0
  61. metadata +50 -39
  62. data/lib/pry/command_context.rb +0 -53
  63. data/lib/pry/command_processor.rb +0 -181
  64. data/lib/pry/extended_commands/user_command_api.rb +0 -65
  65. data/test/test_command_processor.rb +0 -176
@@ -28,104 +28,209 @@ class Pry
28
28
  _pry_.instance_eval(&Pry::FILE_COMPLETIONS)
29
29
  end
30
30
  end
31
-
32
31
  alias_command "file-mode", "shell-mode"
33
32
 
34
- command "cat", "Show output of file FILE. Type `cat --help` for more information." do |*args|
35
- start_line = 0
36
- end_line = -1
37
- file_name = nil
38
- bt_index = 0
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
39
49
 
40
- opts = Slop.parse!(args) do |opt|
41
- opt.on :s, :start, "Start line (defaults to start of file)Line 1 is the first line.", true, :as => Integer do |line|
42
- start_line = line - 1
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))
43
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
44
71
 
45
- opt.on :e, :end, "End line (defaults to end of file). Line -1 is the last line", true, :as => Integer do |line|
46
- end_line = line - 1
72
+ def process
73
+ if args.empty?
74
+ raise CommandError, "Must specify a file name."
47
75
  end
48
76
 
49
- opt.on :ex, "Show a window of N lines either side of the last exception (defaults to 5).", :optional => true, :as => Integer do |bt_index_arg|
50
- window_size = Pry.config.exception_window_size || 5
51
- ex = _pry_.last_exception
52
- next if !ex
53
- if bt_index_arg
54
- bt_index = bt_index_arg
55
- else
56
- bt_index = ex.bt_index
57
- end
58
- ex.bt_index = (bt_index + 1) % ex.backtrace.size
59
-
60
- ex_file, ex_line = ex.bt_source_location_for(bt_index)
61
- start_line = (ex_line - 1) - window_size
62
- start_line = start_line < 0 ? 0 : start_line
63
- end_line = (ex_line - 1) + window_size
64
- if ex_file && RbxPath.is_core_path?(ex_file)
65
- file_name = RbxPath.convert_path_to_full(ex_file)
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])
66
90
  else
67
- file_name = ex_file
91
+ f.puts content
68
92
  end
69
93
  end
94
+ end
70
95
 
71
- opt.on :l, "line-numbers", "Show line numbers."
72
- opt.on :t, :type, "The specific file type for syntax higlighting (e.g ruby, python)", true, :as => Symbol
73
- opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
74
- opt.on :h, :help, "This message." do
75
- output.puts opt
96
+ def mode
97
+ if opts.present?(:append)
98
+ "a"
99
+ else
100
+ "w"
76
101
  end
77
102
  end
103
+ end
78
104
 
79
- next if opts.help?
105
+ create_command "cat", "Show code from a file, Pry's input buffer, or the last exception." do
106
+ banner <<-USAGE
107
+ Usage: cat FILE
108
+ cat --ex [STACK_INDEX]
109
+ cat --in [INPUT_INDEX_OR_RANGE]
80
110
 
81
- if opts.ex?
82
- if file_name.nil?
83
- raise CommandError, "No Exception or Exception has no associated file."
84
- end
85
- else
86
- file_name = args.shift
87
- end
111
+ cat is capable of showing part or all of a source file, the context of the
112
+ last exception, or an expression from Pry's input history.
113
+
114
+ cat --ex defaults to showing the lines surrounding the location of the last
115
+ exception. Invoking it more than once travels up the exception's backtrace,
116
+ and providing a number shows the context of the given index of the backtrace.
117
+ USAGE
88
118
 
89
- if !file_name
90
- raise CommandError, "Must provide a file name."
119
+ def options(opt)
120
+ opt.on :ex, "Show the context of the last exception.", :optional => true, :as => Integer
121
+ opt.on :i, :in, "Show one or more entries from Pry's expression history.", :optional => true, :as => Range, :default => -5..-1
122
+
123
+ opt.on :s, :start, "Starting line (defaults to the first line).", :optional => true, :as => Integer
124
+ opt.on :e, :end, "Ending line (defaults to the last line).", :optional => true, :as => Integer
125
+ opt.on :l, :'line-numbers', "Show line numbers."
126
+ opt.on :t, :type, "The file type for syntax highlighting (e.g., 'ruby' or 'python').", true, :as => Symbol
127
+
128
+ opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
91
129
  end
92
130
 
93
- begin
94
- contents, _, _ = read_between_the_lines(file_name, start_line, end_line)
95
- 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}"
131
+ def process
132
+ 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
140
+
141
+ output = handler.call do |code|
142
+ code.code_type = opts[:type] || :ruby
143
+
144
+ code.between(opts[:start] || 1, opts[:end] || -1).
145
+ with_line_numbers(opts.present?(:'line-numbers') || opts.present?(:ex))
146
+ end
147
+
148
+ render_output(output, opts)
98
149
  end
99
150
 
100
- if opts.l?
101
- contents = text.with_line_numbers contents, start_line + 1
151
+ def process_ex
152
+ window_size = Pry.config.default_window_size || 5
153
+ ex = _pry_.last_exception
154
+
155
+ raise CommandError, "No exception found." unless ex
156
+
157
+ if opts[:ex].nil?
158
+ bt_index = ex.bt_index
159
+ ex.inc_bt_index
160
+ else
161
+ bt_index = opts[:ex]
162
+ end
163
+
164
+ ex_file, ex_line = ex.bt_source_location_for(bt_index)
165
+
166
+ raise CommandError, "The given backtrace level is out of bounds." unless ex_file
167
+
168
+ if RbxPath.is_core_path?(ex_file)
169
+ ex_file = RbxPath.convert_path_to_full(ex_file)
170
+ end
171
+
172
+ set_file_and_dir_locals(ex_file)
173
+
174
+ start_line = ex_line - window_size
175
+ start_line = 1 if start_line < 1
176
+ end_line = ex_line + window_size
177
+
178
+ header = unindent <<-HEADER
179
+ #{text.bold 'Exception:'} #{ex.class}: #{ex.message}
180
+ --
181
+ #{text.bold('From:')} #{ex_file} @ line #{ex_line} @ #{text.bold("level: #{bt_index}")} of backtrace (of #{ex.backtrace.size - 1}).
182
+
183
+ HEADER
184
+
185
+ code = yield(Pry::Code.from_file(ex_file).
186
+ between(start_line, end_line).
187
+ with_marker(ex_line))
188
+
189
+ "#{header}#{code}"
102
190
  end
103
191
 
104
- # add the arrow pointing to line that caused the exception
105
- if opts.ex?
106
- ex_file, ex_line = _pry_.last_exception.bt_source_location_for(bt_index)
107
- contents = text.with_line_numbers contents, start_line + 1, :bright_red
192
+ def process_in
193
+ normalized_range = absolute_index_range(opts[:i], _pry_.input_array.length)
194
+ input_items = _pry_.input_array[normalized_range] || []
108
195
 
109
- contents = contents.lines.each_with_index.map do |line, idx|
110
- l = idx + start_line
111
- if l == (ex_line - 1)
112
- " =>#{line}"
113
- else
114
- " #{line}"
196
+ zipped_items = normalized_range.zip(input_items).reject { |_, s| s.nil? || s == "" }
197
+
198
+ unless zipped_items.length > 0
199
+ raise CommandError, "No expressions found."
200
+ end
201
+
202
+ if zipped_items.length > 1
203
+ contents = ""
204
+ zipped_items.each do |i, s|
205
+ contents << "#{text.bold(i.to_s)}:\n"
206
+ contents << yield(Pry::Code(s).with_indentation(2)).to_s
115
207
  end
116
- end.join
208
+ else
209
+ contents = yield(Pry::Code(zipped_items.first.last))
210
+ end
117
211
 
118
- # header for exceptions
119
- output.puts "\n#{Pry::Helpers::Text.bold('Exception:')} #{_pry_.last_exception.class}: #{_pry_.last_exception.message}\n--"
120
- output.puts "#{Pry::Helpers::Text.bold('From:')} #{ex_file} @ line #{ex_line} @ #{text.bold('level: ')} #{bt_index} of backtrace (of #{_pry_.last_exception.backtrace.size - 1}).\n\n"
212
+ contents
121
213
  end
122
214
 
123
- set_file_and_dir_locals(file_name)
215
+ def process_file
216
+ file_name = args.shift
217
+
218
+ unless file_name
219
+ raise CommandError, "Must provide a filename, --in, or --ex."
220
+ end
221
+
222
+ file_name, line_num = file_name.split(':')
223
+ file_name = File.expand_path(file_name)
224
+ set_file_and_dir_locals(file_name)
124
225
 
125
- if opts.f?
126
- output.puts contents
127
- else
128
- stagger_output(contents)
226
+ code = yield(Pry::Code.from_file(file_name))
227
+
228
+ if line_num
229
+ code = code.around(line_num.to_i,
230
+ Pry.config.default_window_size || 7)
231
+ end
232
+
233
+ code
129
234
  end
130
235
  end
131
236
  end
@@ -91,14 +91,19 @@ class Pry
91
91
  27
92
92
  end
93
93
 
94
+ # have fun on the Windows platform.
95
+ def windows?
96
+ RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
97
+ end
98
+
94
99
  # are we on Jruby platform?
95
100
  def jruby?
96
- defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/
101
+ RbConfig::CONFIG['ruby_install_name'] == 'jruby'
97
102
  end
98
103
 
99
104
  # are we on rbx platform?
100
105
  def rbx?
101
- defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /rbx/
106
+ RbConfig::CONFIG['ruby_install_name'] == 'rbx'
102
107
  end
103
108
 
104
109
  # a simple pager for systems without `less`. A la windows.
@@ -6,26 +6,21 @@ class Pry
6
6
 
7
7
  module_function
8
8
 
9
- # if start_line is not false then add line numbers starting with start_line
10
- def render_output(should_flood, start_line, text, color=:blue)
11
- if start_line
12
- text = Pry::Helpers::Text.with_line_numbers text, start_line, color
13
- end
14
-
15
- if should_flood
16
- output.puts text
17
- else
18
- stagger_output(text)
19
- end
20
- end
21
-
22
9
  # Open a temp file and yield it to the block, closing it after
23
10
  # @return [String] The path of the temp file
24
- def temp_file
25
- file = Tempfile.new(["tmp", ".rb"])
11
+ def temp_file(ext='.rb')
12
+ file = Tempfile.new(['pry', ext])
26
13
  yield file
27
14
  ensure
28
- file.close
15
+ file.close(true) if file
16
+ end
17
+
18
+ def render_output(str, opts={})
19
+ if opts[:flood]
20
+ output.puts str
21
+ else
22
+ stagger_output str
23
+ end
29
24
  end
30
25
 
31
26
  def get_method_or_raise(name, target, opts={}, omit_help=false)
@@ -34,14 +29,14 @@ class Pry
34
29
  if name && !meth
35
30
  command_error("The method '#{name}' could not be found.", omit_help)
36
31
  elsif !meth
37
- command_error("No method name given, and context is not a method.", omit_help)
32
+ command_error("No method name given, and context is not a method.", omit_help, NonMethodContextError)
38
33
  end
39
34
 
40
35
  (opts[:super] || 0).times do
41
36
  if meth.super
42
37
  meth = meth.super
43
38
  else
44
- command_error("The method '#{meth.name}' is not defined in a superclass of '#{class_name(meth.owner)}'.", omit_help)
39
+ command_error("'#{meth.name_with_owner}' has no super method.", omit_help)
45
40
  end
46
41
  end
47
42
 
@@ -49,9 +44,9 @@ class Pry
49
44
  meth
50
45
  end
51
46
 
52
- def command_error(message, omit_help)
47
+ def command_error(message, omit_help, klass=CommandError)
53
48
  message += " Type `#{command_name} --help` for help." unless omit_help
54
- raise CommandError, message
49
+ raise klass, message
55
50
  end
56
51
 
57
52
  def make_header(meth, content=meth.source)
@@ -66,60 +61,6 @@ class Pry
66
61
  header << "#{Pry::Helpers::Text.bold("Number of lines:")} #{content.each_line.count.to_s}\n"
67
62
  end
68
63
 
69
- def file_map
70
- {
71
- [".c", ".h"] => :c,
72
- [".cpp", ".hpp", ".cc", ".h", "cxx"] => :cpp,
73
- [".rb", "Rakefile", ".irbrc", ".gemspec", ".pryrc"] => :ruby,
74
- ".py" => :python,
75
- ".diff" => :diff,
76
- ".css" => :css,
77
- ".html" => :html,
78
- [".yaml", ".yml"] => :yaml,
79
- ".xml" => :xml,
80
- ".php" => :php,
81
- ".js" => :javascript,
82
- ".java" => :java,
83
- ".rhtml" => :rhtml,
84
- ".json" => :json
85
- }
86
- end
87
-
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)
92
- end
93
- end
94
-
95
- language_detected = file_type if file_type
96
- if Pry.color
97
- CodeRay.scan(contents, language_detected).term
98
- else
99
- contents
100
- end
101
- end
102
-
103
- # convert negative line numbers to positive by wrapping around
104
- # last line (as per array indexing with negative numbers)
105
- def normalized_line_number(line_number, total_lines)
106
- line_number < 0 ? line_number + total_lines : line_number
107
- end
108
-
109
- # returns the file content between the lines and the normalized
110
- # start and end line numbers.
111
- def read_between_the_lines(file_name, start_line, end_line)
112
- if file_name == Pry.eval_path
113
- content = Pry.line_buffer.drop(1).join
114
- else
115
- content = File.read(File.expand_path(file_name))
116
- end
117
- lines_array = content.each_line.to_a
118
-
119
- [lines_array[start_line..end_line].join, normalized_line_number(start_line, lines_array.size),
120
- normalized_line_number(end_line, lines_array.size)]
121
- end
122
-
123
64
  def process_rdoc(comment, code_type)
124
65
  comment = comment.dup
125
66
  comment.gsub(/<code>(?:\s*\n)?(.*?)\s*<\/code>/m) { Pry.color ? CodeRay.scan($1, code_type).term : $1 }.
@@ -157,6 +98,7 @@ class Pry
157
98
  end
158
99
 
159
100
  def invoke_editor(file, line)
101
+ raise CommandError, "Please set Pry.config.editor or export $EDITOR" unless Pry.config.editor
160
102
  if Pry.config.editor.respond_to?(:call)
161
103
  editor_invocation = Pry.config.editor.call(file, line)
162
104
  else
@@ -176,14 +118,16 @@ class Pry
176
118
  # Note we dont want to use Pry.config.system here as that
177
119
  # may be invoked non-interactively (i.e via Open4), whereas we want to
178
120
  # ensure the editor is always interactive
179
- system(editor_invocation)
121
+ system(editor_invocation) or raise CommandError, "`#{editor_invocation}` gave exit status: #{$?.exitstatus}"
180
122
  end
181
123
  end
182
124
 
183
125
  # Return the syntax for a given editor for starting the editor
184
126
  # and moving to a particular line within that file
185
127
  def start_line_syntax_for_editor(file_name, line_number)
186
- file_name = file_name.gsub(/\//, '\\') if RUBY_PLATFORM =~ /mswin|mingw/
128
+ if windows?
129
+ file_name = file_name.gsub(/\//, '\\')
130
+ end
187
131
 
188
132
  # special case for 1st line
189
133
  return file_name if line_number <= 1
@@ -198,7 +142,7 @@ class Pry
198
142
  when /^jedit/
199
143
  "#{file_name} +line:#{line_number}"
200
144
  else
201
- if RUBY_PLATFORM =~ /mswin|mingw/
145
+ if windows?
202
146
  "#{file_name}"
203
147
  else
204
148
  "+#{line_number} #{file_name}"
@@ -247,6 +191,56 @@ class Pry
247
191
  text.gsub(/^#{margin}/, '')
248
192
  end
249
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
+
203
+ def one_index_number(line_number)
204
+ if line_number > 0
205
+ line_number - 1
206
+ else
207
+ line_number
208
+ end
209
+ end
210
+
211
+ # convert a 1-index range to a 0-indexed one
212
+ def one_index_range(range)
213
+ Range.new(one_index_number(range.begin), one_index_number(range.end))
214
+ end
215
+
216
+ def one_index_range_or_number(range_or_number)
217
+ case range_or_number
218
+ when Range
219
+ one_index_range(range_or_number)
220
+ else
221
+ one_index_number(range_or_number)
222
+ end
223
+ end
224
+
225
+ def absolute_index_number(line_number, array_length)
226
+ if line_number >= 0
227
+ line_number
228
+ else
229
+ [array_length + line_number, 0].max
230
+ end
231
+ end
232
+
233
+ def absolute_index_range(range_or_number, array_length)
234
+ case range_or_number
235
+ when Range
236
+ a = absolute_index_number(range_or_number.begin, array_length)
237
+ b = absolute_index_number(range_or_number.end, array_length)
238
+ else
239
+ a = b = absolute_index_number(range_or_number, array_length)
240
+ end
241
+
242
+ Range.new(a, b)
243
+ end
250
244
  end
251
245
 
252
246
  end