pry 0.9.3pre1-i386-mswin32 → 0.9.4-i386-mswin32

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