pry 0.9.3pre1-i386-mingw32 → 0.9.4-i386-mingw32

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 (43) hide show
  1. data/CHANGELOG +53 -0
  2. data/CONTRIBUTORS +13 -0
  3. data/README.markdown +4 -2
  4. data/Rakefile +17 -3
  5. data/TODO +22 -0
  6. data/lib/pry.rb +102 -24
  7. data/lib/pry/command_context.rb +12 -0
  8. data/lib/pry/command_processor.rb +50 -19
  9. data/lib/pry/command_set.rb +17 -7
  10. data/lib/pry/completion.rb +6 -6
  11. data/lib/pry/config.rb +6 -2
  12. data/lib/pry/default_commands/basic.rb +8 -4
  13. data/lib/pry/default_commands/context.rb +84 -36
  14. data/lib/pry/default_commands/documentation.rb +50 -30
  15. data/lib/pry/default_commands/easter_eggs.rb +5 -0
  16. data/lib/pry/default_commands/input.rb +20 -16
  17. data/lib/pry/default_commands/introspection.rb +61 -77
  18. data/lib/pry/default_commands/ls.rb +22 -14
  19. data/lib/pry/default_commands/shell.rb +32 -17
  20. data/lib/pry/extended_commands/user_command_api.rb +32 -1
  21. data/lib/pry/helpers/base_helpers.rb +21 -9
  22. data/lib/pry/helpers/command_helpers.rb +99 -17
  23. data/lib/pry/helpers/text.rb +12 -11
  24. data/lib/pry/history.rb +61 -0
  25. data/lib/pry/plugins.rb +19 -8
  26. data/lib/pry/pry_class.rb +49 -60
  27. data/lib/pry/pry_instance.rb +122 -119
  28. data/lib/pry/version.rb +1 -1
  29. data/pry.gemspec +15 -14
  30. data/test/helper.rb +31 -0
  31. data/test/test_command_processor.rb +8 -87
  32. data/test/test_command_set.rb +40 -2
  33. data/test/test_completion.rb +26 -0
  34. data/test/test_default_commands/test_context.rb +185 -1
  35. data/test/test_default_commands/test_documentation.rb +10 -0
  36. data/test/test_default_commands/test_input.rb +39 -13
  37. data/test/test_default_commands/test_introspection.rb +11 -1
  38. data/test/test_default_commands/test_shell.rb +18 -0
  39. data/test/test_pry.rb +217 -47
  40. data/test/test_pry_history.rb +84 -0
  41. data/test/test_pry_output.rb +44 -0
  42. data/test/test_special_locals.rb +35 -0
  43. metadata +83 -77
@@ -18,18 +18,6 @@ describe "Pry::CommandProcessor" do
18
18
 
19
19
  valid = @command_processor.valid_command? "blah"
20
20
  valid.should == false
21
-
22
-
23
- a = "test-command"
24
-
25
- # not passing in a binding so 'a' shouldn't exist and no command
26
- # will be matched
27
- valid = @command_processor.valid_command?('#{a}')
28
- valid.should == false
29
-
30
- # passing in the optional binding (against which interpolation is performed)
31
- valid = @command_processor.valid_command? '#{a}', binding
32
- valid.should == true
33
21
  end
34
22
 
35
23
  it 'should correctly match a simple string command' do
@@ -168,88 +156,21 @@ describe "Pry::CommandProcessor" do
168
156
  pos.should == sample_text.size
169
157
  end
170
158
 
171
- it 'should correctly match a command whose name is interpolated' do
172
- @pry.commands.command("blah") {}
173
- a = "bl"
174
- b = "ah"
175
- command, captures, pos = @command_processor.command_matched '#{a}#{b}', binding
176
-
177
- command.name.should == "blah"
178
- captures.should == []
179
- pos.should == command.name.length
180
- end
181
-
182
- it 'should correctly match a regex command and interpolation should not break the regex' do
183
- regex_command_name = /blah(\d)/
184
- @pry.commands.command(regex_command_name) {}
185
-
186
- sample_text = "blah5"
187
- a = "5"
188
- command, captures, pos = @command_processor.command_matched 'blah#{a}', binding
189
-
190
- command.name.should == regex_command_name
191
- captures.should == ["5"]
192
- pos.should == sample_text.size
193
- end
194
-
195
- it 'should NOT match a regex command that is interpolated when :interpolate => false' do
196
- regex_command_name = /blah(\d)/
197
- @pry.commands.command(regex_command_name, "", :interpolate => false) {}
198
-
199
- sample_text = "blah5"
200
- a = "5"
201
- command, captures, pos = @command_processor.command_matched 'blah#{a}', binding
202
-
203
- command.should == nil
204
- end
205
-
206
- it 'should correctly match a regex command and interpolation should not break the regex where entire regex command is interpolated' do
207
- regex_command_name = /blah(\d)/
208
- @pry.commands.command(regex_command_name) {}
209
-
210
- sample_text = "blah5"
211
- a = "bl"
212
- b = "ah"
213
- c = "5"
214
-
215
- command, captures, pos = @command_processor.command_matched '#{a}#{b}#{c}', binding
216
-
217
- command.name.should == regex_command_name
218
- captures.should == ["5"]
219
- pos.should == sample_text.size
220
- end
221
-
222
- it 'should NOT match a regex command where entire regex command is interpolated and :interpolate => false' do
223
- regex_command_name = /blah(\d)/
224
- @pry.commands.command(regex_command_name, "", :interpolate => false) {}
225
-
226
- sample_text = "blah5"
227
- a = "bl"
228
- b = "ah"
229
- c = "5"
230
-
231
- command, captures, pos = @command_processor.command_matched '#{a}#{b}#{c}', binding
232
- command.should == nil
233
- end
234
-
235
- it 'should NOT match a command whose name is interpolated when :interpolate => false' do
159
+ it 'should not interpolate commands that have :interpolate => false (interpolate_string should *not* be called)' do
236
160
  @pry.commands.command("boast", "", :interpolate => false) {}
237
- a = "boa"
238
- b = "st"
239
161
 
240
162
  # remember to use '' instead of "" when testing interpolation or
241
163
  # you'll cause yourself incredible confusion
242
- command, captures, pos = @command_processor.command_matched '#{a}#{b}', binding
243
-
244
- command.should == nil
164
+ lambda { @command_processor.command_matched('boast #{c}', binding) }.should.not.raise NameError
245
165
  end
246
166
 
167
+ it 'should only execute the contents of an interpolation once' do
168
+ $obj = 'a'
247
169
 
248
- it 'commands that have :interpolate => false should not be interpolated (interpolate_string should *not* be called)' do
249
- @pry.commands.command("boast", "", :interpolate => false) {}
170
+ redirect_pry_io(InputTester.new('cat #{$obj.succ!}'), StringIO.new) do
171
+ Pry.new.rep
172
+ end
250
173
 
251
- # remember to use '' instead of "" when testing interpolation or
252
- # you'll cause yourself incredible confusion
253
- lambda { @command_processor.command_matched('boast #{c}', binding) }.should.not.raise NameError
174
+ $obj.should == 'b'
254
175
  end
255
176
  end
@@ -112,9 +112,9 @@ describe Pry::CommandSet do
112
112
  @set.commands['foo'].description.should == 'baz'
113
113
  end
114
114
 
115
- it 'should return nil for commands by default' do
115
+ it 'should return Pry::CommandContext::VOID_VALUE for commands by default' do
116
116
  @set.command('foo') { 3 }
117
- @set.run_command(nil, 'foo').should == nil
117
+ @set.run_command(nil, 'foo').should == Pry::CommandContext::VOID_VALUE
118
118
  end
119
119
 
120
120
  it 'should be able to keep return values' do
@@ -122,6 +122,11 @@ describe Pry::CommandSet do
122
122
  @set.run_command(nil, 'foo').should == 3
123
123
  end
124
124
 
125
+ it 'should be able to keep return values, even if return value is nil' do
126
+ @set.command('foo', '', :keep_retval => true) { nil }
127
+ @set.run_command(nil, 'foo').should == nil
128
+ end
129
+
125
130
  it 'should be able to have its own helpers' do
126
131
  @set.command('foo') do
127
132
  should.respond_to :my_helper
@@ -187,4 +192,37 @@ describe Pry::CommandSet do
187
192
  @set.command 'foo', "", :listing => 'bar' do;end
188
193
  @set.commands['foo'].options[:listing].should == 'bar'
189
194
  end
195
+
196
+ it "should provide a 'help' command" do
197
+ context = Pry::CommandContext.new
198
+ context.command_set = @set
199
+ context.output = StringIO.new
200
+
201
+ lambda {
202
+ @set.run_command(context, 'help')
203
+ }.should.not.raise
204
+ end
205
+
206
+ it "should sort the output of the 'help' command" do
207
+ @set.command 'foo', "Fooerizes" do; end
208
+ @set.command 'goo', "Gooerizes" do; end
209
+ @set.command 'moo', "Mooerizes" do; end
210
+ @set.command 'boo', "Booerizes" do; end
211
+
212
+ context = Pry::CommandContext.new
213
+ context.command_set = @set
214
+ context.output = StringIO.new
215
+
216
+ @set.run_command(context, 'help')
217
+
218
+ doc = context.output.string
219
+
220
+ order = [doc.index("boo"),
221
+ doc.index("foo"),
222
+ doc.index("goo"),
223
+ doc.index("help"),
224
+ doc.index("moo")]
225
+
226
+ order.should == order.sort
227
+ end
190
228
  end
@@ -0,0 +1,26 @@
1
+ require 'helper'
2
+
3
+ describe Pry::InputCompleter do
4
+
5
+ before do
6
+ # The AMQP gem has some classes like this:
7
+ # pry(main)> AMQP::Protocol::Test::ContentOk.name
8
+ # => :content_ok
9
+ module SymbolyName
10
+ def self.name; :symboly_name; end
11
+ end
12
+ end
13
+
14
+ after do
15
+ Object.remove_const :SymbolyName
16
+ end
17
+
18
+ # another jruby hack :((
19
+ if !jruby?
20
+ it "should not crash if there's a Module that has a symbolic name." do
21
+ completer = Pry::InputCompleter.build_completion_proc(Pry.binding_for(Object.new))
22
+ lambda{ completer.call "a.to_s." }.should.not.raise Exception
23
+ end
24
+ end
25
+ end
26
+
@@ -1,6 +1,104 @@
1
1
  require 'helper'
2
2
 
3
3
  describe "Pry::DefaultCommands::Context" do
4
+ describe "exit-all" do
5
+ it 'should break out of the repl loop of Pry instance (returning target of session)' do
6
+ redirect_pry_io(InputTester.new("exit-all"), StringIO.new) do
7
+ Pry.new.repl(0).should == 0
8
+ end
9
+ end
10
+
11
+ it 'should break out of the repl loop of Pry instance wth a user specified value' do
12
+ redirect_pry_io(InputTester.new("exit-all 'message'"), StringIO.new) do
13
+ Pry.new.repl(0).should == 'message'
14
+ end
15
+ end
16
+
17
+ it 'should break of the repl loop even if multiple bindings still on stack' do
18
+ ins = nil
19
+ redirect_pry_io(InputTester.new("cd 1", "cd 2", "exit-all 'message'"), StringIO.new) do
20
+ ins = Pry.new.tap { |v| v.repl(0).should == 'message' }
21
+ end
22
+ end
23
+
24
+ it 'binding_stack should be empty after breaking out of the repl loop' do
25
+ ins = nil
26
+ redirect_pry_io(InputTester.new("cd 1", "cd 2", "exit-all"), StringIO.new) do
27
+ ins = Pry.new.tap { |v| v.repl(0) }
28
+ end
29
+
30
+ ins.binding_stack.empty?.should == true
31
+ end
32
+ end
33
+
34
+ describe "exit" do
35
+ it 'should pop a binding with exit' do
36
+ b = Pry.binding_for(:outer)
37
+ b.eval("x = :inner")
38
+
39
+ redirect_pry_io(InputTester.new("cd x", "$inner = self;", "exit", "$outer = self", "exit-all"), StringIO.new) do
40
+ b.pry
41
+ end
42
+ $inner.should == :inner
43
+ $outer.should == :outer
44
+ end
45
+
46
+ it 'should break out of the repl loop of Pry instance when binding_stack has only one binding with exit' do
47
+ Pry.start(0, :input => StringIO.new("exit")).should == 0
48
+ end
49
+
50
+ it 'should break out of the repl loop of Pry instance when binding_stack has only one binding with exit, and return user-given value' do
51
+ Pry.start(0, :input => StringIO.new("exit :john")).should == :john
52
+ end
53
+ end
54
+
55
+ describe "jump-to" do
56
+ it 'should jump to the proper binding index in the stack' do
57
+ outp = StringIO.new
58
+ redirect_pry_io(InputTester.new("cd 1", "cd 2", "jump-to 1", "$blah = self", "exit-all"), outp) do
59
+ Pry.start(0)
60
+ end
61
+
62
+ $blah.should == 1
63
+ end
64
+
65
+ it 'should print error when trying to jump to a non-existent binding index' do
66
+ outp = StringIO.new
67
+ redirect_pry_io(InputTester.new("cd 1", "cd 2", "jump-to 100", "exit-all"), outp) do
68
+ Pry.start(0)
69
+ end
70
+
71
+ outp.string.should =~ /Invalid nest level/
72
+ end
73
+
74
+ it 'should print error when trying to jump to the same binding index' do
75
+ outp = StringIO.new
76
+ redirect_pry_io(InputTester.new("cd 1", "cd 2", "jump-to 2", "exit-all"), outp) do
77
+ Pry.new.repl(0)
78
+ end
79
+
80
+ outp.string.should =~ /Already/
81
+ end
82
+ end
83
+
84
+ describe "exit-program" do
85
+ it 'should raise SystemExit' do
86
+ redirect_pry_io(InputTester.new("exit-program"), StringIO.new) do
87
+ lambda { Pry.new.repl(0).should == 0 }.should.raise SystemExit
88
+ end
89
+ end
90
+
91
+ it 'should exit the program with the provided value' do
92
+ redirect_pry_io(InputTester.new("exit-program 66"), StringIO.new) do
93
+ begin
94
+ Pry.new.repl(0)
95
+ rescue SystemExit => e
96
+ e.status.should == 66
97
+ end
98
+ end
99
+ end
100
+ end
101
+
4
102
  describe "cd" do
5
103
  after do
6
104
  $obj = nil
@@ -28,6 +126,10 @@ describe "Pry::DefaultCommands::Context" do
28
126
  $outer.should == :outer
29
127
  end
30
128
 
129
+ it 'should break out of the repl loop of Pry instance when binding_stack has only one binding with cd ..' do
130
+ Pry.start(0, :input => StringIO.new("cd ..")).should == 0
131
+ end
132
+
31
133
  it 'should break out to outer-most session with cd /' do
32
134
  b = Pry.binding_for(:outer)
33
135
  b.eval("x = :inner")
@@ -40,9 +142,91 @@ describe "Pry::DefaultCommands::Context" do
40
142
  $outer.should == :outer
41
143
  end
42
144
 
43
- it 'should start a session on TOPLEVEL_BINDING with cd ::' do
145
+ it 'should break out to outer-most session with just cd (no args)' do
44
146
  b = Pry.binding_for(:outer)
147
+ b.eval("x = :inner")
148
+
149
+ redirect_pry_io(InputTester.new("cd x", "$inner = self;", "cd 5", "$five = self", "cd", "$outer = self", "exit-all"), StringIO.new) do
150
+ b.pry
151
+ end
152
+ $inner.should == :inner
153
+ $five.should == 5
154
+ $outer.should == :outer
155
+ end
156
+
157
+ it 'should cd into an object and its ivar using cd obj/@ivar syntax' do
158
+ $obj = Object.new
159
+ $obj.instance_variable_set(:@x, 66)
160
+
161
+ redirect_pry_io(InputTester.new("cd $obj/@x", "$result = _pry_.binding_stack.dup", "exit-all"), StringIO.new) do
162
+ Pry.start
163
+ end
164
+ $result.size.should == 3
165
+ $result[1].eval('self').should == $obj
166
+ $result[2].eval('self').should == 66
167
+ end
45
168
 
169
+ it 'should cd into an object and its ivar using cd obj/@ivar/ syntax (note following /)' do
170
+ $obj = Object.new
171
+ $obj.instance_variable_set(:@x, 66)
172
+
173
+ redirect_pry_io(InputTester.new("cd $obj/@x/", "$result = _pry_.binding_stack.dup", "exit-all"), StringIO.new) do
174
+ Pry.start
175
+ end
176
+ $result.size.should == 3
177
+ $result[1].eval('self').should == $obj
178
+ $result[2].eval('self').should == 66
179
+ end
180
+
181
+ it 'should cd into previous object and its local using cd ../local syntax' do
182
+ $obj = Object.new
183
+ $obj.instance_variable_set(:@x, 66)
184
+
185
+ redirect_pry_io(InputTester.new("cd $obj", "local = :local", "cd @x", "cd ../local", "$result = _pry_.binding_stack.dup", "exit-all"), StringIO.new) do
186
+ Pry.start
187
+ end
188
+ $result.size.should == 3
189
+ $result[1].eval('self').should == $obj
190
+ $result[2].eval('self').should == :local
191
+ end
192
+
193
+ it 'should cd into an object and its ivar and back again using cd obj/@ivar/.. syntax' do
194
+ $obj = Object.new
195
+ $obj.instance_variable_set(:@x, 66)
196
+
197
+ redirect_pry_io(InputTester.new("cd $obj/@x/..", "$result = _pry_.binding_stack.dup", "exit-all"), StringIO.new) do
198
+ Pry.start
199
+ end
200
+ $result.size.should == 2
201
+ $result[1].eval('self').should == $obj
202
+ end
203
+
204
+ it 'should cd into an object and its ivar and back and then into another ivar using cd obj/@ivar/../@y syntax' do
205
+ $obj = Object.new
206
+ $obj.instance_variable_set(:@x, 66)
207
+ $obj.instance_variable_set(:@y, 79)
208
+
209
+ redirect_pry_io(InputTester.new("cd $obj/@x/../@y", "$result = _pry_.binding_stack.dup", "exit-all"), StringIO.new) do
210
+ Pry.start
211
+ end
212
+ $result.size.should == 3
213
+ $result[1].eval('self').should == $obj
214
+ $result[2].eval('self').should == 79
215
+ end
216
+
217
+ it 'should cd back to top-level and then into another ivar using cd /@ivar/ syntax' do
218
+ $obj = Object.new
219
+ $obj.instance_variable_set(:@x, 66)
220
+ TOPLEVEL_BINDING.eval('@z = 20')
221
+
222
+ redirect_pry_io(InputTester.new("cd $obj/@x/", "cd /@z", "$result = _pry_.binding_stack.dup", "exit-all"), StringIO.new) do
223
+ Pry.start
224
+ end
225
+ $result.size.should == 2
226
+ $result[1].eval('self').should == 20
227
+ end
228
+
229
+ it 'should start a session on TOPLEVEL_BINDING with cd ::' do
46
230
  redirect_pry_io(InputTester.new("cd ::", "$obj = self", "exit-all"), StringIO.new) do
47
231
  5.pry
48
232
  end
@@ -10,6 +10,16 @@ describe "Pry::DefaultCommands::Documentation" do
10
10
 
11
11
  str_output.string.should =~ /sample doc/
12
12
  end
13
+
14
+ it 'should output multiple methods\' documentation' do
15
+ str_output = StringIO.new
16
+ redirect_pry_io(InputTester.new("show-doc sample_method another_sample_method", "exit-all"), str_output) do
17
+ pry
18
+ end
19
+
20
+ str_output.string.should =~ /sample doc/
21
+ str_output.string.should =~ /another sample doc/
22
+ end
13
23
 
14
24
  it 'should output a method\'s documentation if inside method without needing to use method name' do
15
25
  $str_output = StringIO.new
@@ -2,7 +2,7 @@ require 'helper'
2
2
 
3
3
  describe "Pry::DefaultCommands::Input" do
4
4
 
5
- describe "amend-line-N" do
5
+ describe "amend-line" do
6
6
  it 'should correctly amend the last line of input when no line number specified ' do
7
7
  str_output = StringIO.new
8
8
  redirect_pry_io(InputTester.new("def hello", "puts :bing", "amend-line puts :blah", "show-input", "exit-all"), str_output) do
@@ -104,7 +104,7 @@ describe "Pry::DefaultCommands::Input" do
104
104
 
105
105
  it 'should correctly amend the specified range of lines, using negative numbers in range' do
106
106
  str_output = StringIO.new
107
- redirect_pry_io(InputTester.new("def hello", "puts :bing", "puts :bang", "puts :boast", "puts :heart", "amend-line-2..-2 puts :bong", "show-input", "exit-all"), str_output) do
107
+ redirect_pry_io(InputTester.new("def hello", "puts :bing", "puts :bang", "puts :boast", "puts :heart", "amend-line 2..-2 puts :bong", "show-input", "exit-all"), str_output) do
108
108
  pry
109
109
  end
110
110
  str_output.string.should =~ /\d+: def hello\n\d+: puts :bong\n\d+: puts :heart/
@@ -150,19 +150,24 @@ describe "Pry::DefaultCommands::Input" do
150
150
  end
151
151
 
152
152
  describe "play" do
153
- it 'should play a string of code (with no args)' do
154
- redirect_pry_io(InputTester.new("play :test_string", "exit-all"), str_output = StringIO.new) do
155
- pry
153
+ it 'should play a string variable (with no args)' do
154
+ b = binding
155
+ b.eval('x = "\"hello\""')
156
+ redirect_pry_io(InputTester.new("play x", "exit-all"), str_output = StringIO.new) do
157
+ Pry.start b, :hooks => {}
156
158
  end
157
- str_output.string.should =~ /:test_string/
159
+ str_output.string.should =~ /hello/
158
160
  end
159
161
 
160
- it 'should play an interpolated string of code (with no args)' do
161
- $obj = ":test_string_interpolated"
162
- redirect_pry_io(InputTester.new('play #{$obj}', "exit-all"), str_output = StringIO.new) do
163
- pry
162
+ it 'should play a string variable (with no args) using --lines to select what to play' do
163
+ b = binding
164
+ b.eval('x = "\"hello\"\n\"goodbye\"\n\"love\""')
165
+ redirect_pry_io(InputTester.new("play x --lines 1", "exit-all"), str_output = StringIO.new) do
166
+ Pry.start b, :hooks => {}
164
167
  end
165
- str_output.string.should =~ /:test_string_interpolated/
168
+ str_output.string.should =~ /hello/
169
+ str_output.string.should.not =~ /love/
170
+ str_output.string.should.not =~ /goodbye/
166
171
  end
167
172
 
168
173
  it 'should play a method with the -m switch (a single line)' do
@@ -202,8 +207,8 @@ describe "Pry::DefaultCommands::Input" do
202
207
  end
203
208
 
204
209
  before do
205
- Readline::HISTORY.shift until Readline::HISTORY.empty?
206
- @hist = Readline::HISTORY
210
+ Pry.history.clear
211
+ @hist = Pry.history
207
212
  end
208
213
 
209
214
  it 'should display the correct history' do
@@ -321,6 +326,27 @@ describe "Pry::DefaultCommands::Input" do
321
326
  str_output.string.each_line.count.should == 4
322
327
  str_output.string.should =~ /b\n\d+:.*c\n\d+:.*d/
323
328
  end
329
+
330
+ it "should not contain duplicated lines" do
331
+ str_output = StringIO.new
332
+ redirect_pry_io(InputTester.new("3", "_ += 1", "_ += 1", "hist", "exit-all", :history => @hist), str_output) do
333
+ pry
334
+ end
335
+
336
+ str_output.string.each_line.grep(/_ \+= 1/).count.should == 1
337
+ end
338
+
339
+ it "should not contain duplicated lines" do
340
+ str_output = StringIO.new
341
+ redirect_pry_io(InputTester.new(":place_holder", "2 + 2", "", "", "3 + 3", "hist", "exit-all", :history => @hist), str_output) do
342
+ pry
343
+ end
344
+
345
+ a = str_output.string.each_line.to_a.index{|line| line.include?("2 + 2") }
346
+ b = str_output.string.each_line.to_a.index{|line| line.include?("3 + 3") }
347
+
348
+ (a + 1).should == b
349
+ end
324
350
  end
325
351
 
326
352