pry 0.9.7.4-i386-mswin32 → 0.9.8-i386-mswin32

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 (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