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
@@ -2,9 +2,9 @@ require 'helper'
2
2
 
3
3
  describe "Pry::DefaultCommands::Context" do
4
4
  describe "exit-all" do
5
- it 'should break out of the repl loop of Pry instance (returning target of session)' do
5
+ it 'should break out of the repl loop of Pry instance and return nil' do
6
6
  redirect_pry_io(InputTester.new("exit-all"), StringIO.new) do
7
- Pry.new.repl(0).should == 0
7
+ Pry.new.repl(0).should == nil
8
8
  end
9
9
  end
10
10
 
@@ -31,6 +31,21 @@ describe "Pry::DefaultCommands::Context" do
31
31
  end
32
32
  end
33
33
 
34
+ describe "whereami" do
35
+ it 'should work with methods that have been undefined' do
36
+ class Cor
37
+ def blimey!
38
+ Cor.send :undef_method, :blimey!
39
+ # using [.] so the regex doesn't match itself
40
+ mock_pry(binding, 'whereami').should =~ /self[.]blimey!/
41
+ end
42
+ end
43
+
44
+ Cor.new.blimey!
45
+ Object.remove_const(:Cor)
46
+ end
47
+ end
48
+
34
49
  describe "exit" do
35
50
  it 'should pop a binding with exit' do
36
51
  b = Pry.binding_for(:outer)
@@ -44,7 +59,7 @@ describe "Pry::DefaultCommands::Context" do
44
59
  end
45
60
 
46
61
  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
62
+ Pry.start(0, :input => StringIO.new("exit")).should == nil
48
63
  end
49
64
 
50
65
  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
@@ -127,7 +142,7 @@ describe "Pry::DefaultCommands::Context" do
127
142
  end
128
143
 
129
144
  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
145
+ Pry.start(0, :input => StringIO.new("cd ..")).should == nil
131
146
  end
132
147
 
133
148
  it 'should break out to outer-most session with cd /' do
@@ -154,7 +154,7 @@ describe "Pry::DefaultCommands::Input" do
154
154
  b = binding
155
155
  b.eval('x = "\"hello\""')
156
156
  redirect_pry_io(InputTester.new("play x", "exit-all"), str_output = StringIO.new) do
157
- Pry.start b, :hooks => {}
157
+ Pry.start b, :hooks => Pry::Hooks.new
158
158
  end
159
159
  str_output.string.should =~ /hello/
160
160
  end
@@ -163,7 +163,7 @@ describe "Pry::DefaultCommands::Input" do
163
163
  b = binding
164
164
  b.eval('x = "\"hello\"\n\"goodbye\"\n\"love\""')
165
165
  redirect_pry_io(InputTester.new("play x --lines 1", "exit-all"), str_output = StringIO.new) do
166
- Pry.start b, :hooks => {}
166
+ Pry.start b, :hooks => Pry::Hooks.new
167
167
  end
168
168
  str_output.string.should =~ /hello/
169
169
  str_output.string.should.not =~ /love/
@@ -48,7 +48,7 @@ describe "Pry::DefaultCommands::Introspection" do
48
48
  end
49
49
 
50
50
  it "should reload the file if it is a ruby file" do
51
- tf = Tempfile.new(["tmp", ".rb"])
51
+ tf = Tempfile.new(["pry", ".rb"])
52
52
  path = tf.path
53
53
 
54
54
  mock_pry("edit #{path}", "$rand").should =~ /#{@rand}/
@@ -57,7 +57,7 @@ describe "Pry::DefaultCommands::Introspection" do
57
57
  end
58
58
 
59
59
  it "should not reload the file if it is not a ruby file" do
60
- tf = Tempfile.new(["tmp", ".py"])
60
+ tf = Tempfile.new(["pry", ".py"])
61
61
  path = tf.path
62
62
 
63
63
  mock_pry("edit #{path}", "$rand").should.not =~ /#{@rand}/
@@ -66,7 +66,7 @@ describe "Pry::DefaultCommands::Introspection" do
66
66
  end
67
67
 
68
68
  it "should not reload a ruby file if -n is given" do
69
- tf = Tempfile.new(["tmp", ".rb"])
69
+ tf = Tempfile.new(["pry", ".rb"])
70
70
  path = tf.path
71
71
 
72
72
  mock_pry("edit -n #{path}", "$rand").should.not =~ /#{@rand}/
@@ -75,7 +75,7 @@ describe "Pry::DefaultCommands::Introspection" do
75
75
  end
76
76
 
77
77
  it "should reload a non-ruby file if -r is given" do
78
- tf = Tempfile.new(["tmp", ".pryrc"])
78
+ tf = Tempfile.new(["pry", ".pryrc"])
79
79
  path = tf.path
80
80
 
81
81
  mock_pry("edit -r #{path}", "$rand").should =~ /#{@rand}/
@@ -87,7 +87,7 @@ describe "Pry::DefaultCommands::Introspection" do
87
87
 
88
88
  describe "with --ex" do
89
89
  before do
90
- @tf = Tempfile.new(["tmp", ".rb"])
90
+ @tf = Tempfile.new(["pry", ".rb"])
91
91
  @path = @tf.path
92
92
  @tf << "1\n2\nraise RuntimeError"
93
93
  @tf.flush
@@ -254,6 +254,10 @@ describe "Pry::DefaultCommands::Introspection" do
254
254
  str_output.string.should =~ /def sample/
255
255
  end
256
256
 
257
+ it 'should output help' do
258
+ mock_pry('show-method -h').should =~ /Usage: show-method/
259
+ end
260
+
257
261
  it 'should output a method\'s source with line numbers' do
258
262
  str_output = StringIO.new
259
263
  redirect_pry_io(InputTester.new("show-method -l sample_method", "exit-all"), str_output) do
@@ -316,6 +320,59 @@ describe "Pry::DefaultCommands::Introspection" do
316
320
  str_output.string.should =~ /Mr flibble/
317
321
  end
318
322
 
323
+ it "should find instance methods with -M" do
324
+ c = Class.new{ def moo; "ve over!"; end }
325
+ mock_pry(binding, "cd c","show-method -M moo").should =~ /ve over/
326
+ end
327
+
328
+ it "should not find instance methods with -m" do
329
+ c = Class.new{ def moo; "ve over!"; end }
330
+ mock_pry(binding, "cd c", "show-method -m moo").should =~ /could not be found/
331
+ end
332
+
333
+ it "should find normal methods with -m" do
334
+ c = Class.new{ def self.moo; "ve over!"; end }
335
+ mock_pry(binding, "cd c", "show-method -m moo").should =~ /ve over/
336
+ end
337
+
338
+ it "should not find normal methods with -M" do
339
+ c = Class.new{ def self.moo; "ve over!"; end }
340
+ mock_pry(binding, "cd c", "show-method -M moo").should =~ /could not be found/
341
+ end
342
+
343
+ it "should find normal methods with no -M or -m" do
344
+ c = Class.new{ def self.moo; "ve over!"; end }
345
+ mock_pry(binding, "cd c", "show-method moo").should =~ /ve over/
346
+ end
347
+
348
+ it "should find instance methods with no -M or -m" do
349
+ c = Class.new{ def moo; "ve over!"; end }
350
+ mock_pry(binding, "cd c", "show-method moo").should =~ /ve over/
351
+ end
352
+
353
+ it "should find super methods" do
354
+ class Foo
355
+ def foo(*bars)
356
+ :super_wibble
357
+ end
358
+ end
359
+ o = Foo.new
360
+ Object.remove_const(:Foo)
361
+ def o.foo(*bars)
362
+ :wibble
363
+ end
364
+
365
+ mock_pry(binding, "show-method --super o.foo").should =~ /:super_wibble/
366
+
367
+ end
368
+
369
+ it "should not raise an exception when a non-extant super method is requested" do
370
+ o = Object.new
371
+ def o.foo(*bars); end
372
+
373
+ mock_pry(binding, "show-method --super o.foo").should =~ /'self.foo' has no super method/
374
+ end
375
+
319
376
  # dynamically defined method source retrieval is only supported in
320
377
  # 1.9 - where Method#source_location is native
321
378
  if RUBY_VERSION =~ /1.9/
@@ -364,7 +421,7 @@ describe "Pry::DefaultCommands::Introspection" do
364
421
  describe "edit-method" do
365
422
  describe "on a method defined in a file" do
366
423
  before do
367
- @tempfile = Tempfile.new(['tmp', '*.rb'])
424
+ @tempfile = Tempfile.new(['pry', '*.rb'])
368
425
  @tempfile.puts <<-EOS
369
426
  module A
370
427
  def a
@@ -1,38 +1,5 @@
1
1
  require 'helper'
2
2
  describe "ls" do
3
- describe "class_name" do
4
- extend Pry::DefaultCommands::Ls.helper_module
5
- it "should use the name of the class if it exists" do
6
- class_name(Object).should == "Object"
7
- end
8
-
9
- it "should use the name of the module if it exists" do
10
- class_name(Kernel).should == "Kernel"
11
- end
12
-
13
- it "should use Foo.self for singleton classes of classes" do
14
- class_name(class << Object; self; end).should == "Object.self"
15
- end
16
-
17
- it "should use Foo.self for singleton methods of modules" do
18
- class_name(class << Kernel; self; end).should == "Kernel.self"
19
- end
20
-
21
- it "should default to the .to_s if that's not possible" do
22
- cls = Class.new
23
- class_name(cls).should == cls.to_s
24
- end
25
-
26
- it "should default to .to_s.self" do
27
- cls = Class.new
28
- class_name(class << cls; self; end).should == "#{cls.to_s}.self"
29
- end
30
-
31
- it "should just be self for singleton classes of normal objects" do
32
- class_name(class << "hi"; self; end).should == "self"
33
- end
34
- end
35
-
36
3
  describe "below ceiling" do
37
4
  it "should stop before Object by default" do
38
5
  mock_pry("cd Class.new{ def goo; end }.new", "ls").should.not =~ /Object/
@@ -55,7 +22,13 @@ describe "ls" do
55
22
  end
56
23
  end
57
24
 
58
- describe "methods" do
25
+ describe "help" do
26
+ it 'should show help with -h' do
27
+ mock_pry("ls -h").should =~ /Usage: ls/
28
+ end
29
+ end
30
+
31
+ describe "methods" do
59
32
  it "should show public methods by default" do
60
33
  mock_pry("ls Class.new{ def goo; end }.new").should =~ /goo/
61
34
  end
@@ -77,7 +50,7 @@ describe "ls" do
77
50
  it "should work for objects with an overridden method method" do
78
51
  require 'net/http'
79
52
  # This doesn't actually touch the network, promise!
80
- mock_pry("ls Net::HTTP::Get.new('localhost')").should =~ /Net::HTTPGenericRequest methods/
53
+ mock_pry("ls Net::HTTP::Get.new('localhost')").should =~ /Net::HTTPGenericRequest#methods/
81
54
  end
82
55
  end
83
56
 
@@ -9,6 +9,41 @@ describe "Pry::DefaultCommands::Shell" do
9
9
  end
10
10
  end
11
11
 
12
+ describe "with --in" do
13
+ it 'should display the last few expressions with indices' do
14
+ output = mock_pry("10", "20", "cat --in")
15
+ output.should =~ /^1:/
16
+ output.should =~ /^ 10/
17
+ output.should =~ /^2:/
18
+ output.should =~ /^ 20/
19
+ end
20
+ end
21
+
22
+ describe "with --in 1" do
23
+ it 'should display the first expression with no index' do
24
+ output = mock_pry("10", "20", "cat --in 1")
25
+ output.should.not =~ /^\d+:/
26
+ output.should =~ /^10/
27
+ end
28
+ end
29
+
30
+ describe "with --in -1" do
31
+ it 'should display the last expression with no index' do
32
+ output = mock_pry("10", "20", "cat --in -1")
33
+ output.should.not =~ /^\d+:/
34
+ output.should =~ /^20/
35
+ end
36
+ end
37
+
38
+ describe "with --in 1..2" do
39
+ it 'should display the given range with indices, omitting nils' do
40
+ output = mock_pry("10", "20", "cat --ex", ":hello", "cat --in 1..4")
41
+ output.should =~ /^1:/
42
+ output.should.not =~ /^3:/
43
+ output.should =~ /^ :hello/
44
+ end
45
+ end
46
+
12
47
  # this doesnt work so well on rbx due to differences in backtrace
13
48
  # so we currently skip rbx until we figure out a workaround
14
49
  describe "with --ex" do
@@ -86,7 +121,7 @@ describe "Pry::DefaultCommands::Shell" do
86
121
  it 'each successive cat --ex should show the next level of backtrace, and going past the final level should return to the first' do
87
122
  temp_files = []
88
123
  3.times do |i|
89
- temp_files << Tempfile.new(['tmp', '*.rb'])
124
+ temp_files << Tempfile.new(['pry', '*.rb'])
90
125
  temp_files.last << "bt number #{i}"
91
126
  temp_files.last.flush
92
127
  end
@@ -0,0 +1,175 @@
1
+ require 'helper'
2
+
3
+ describe Pry::Hooks do
4
+ before do
5
+ @hooks = Pry::Hooks.new
6
+ end
7
+
8
+ describe "adding a new hook" do
9
+ it 'should not execute hook while adding it' do
10
+ run = false
11
+ @hooks.add_hook(:test_hook, :my_name) { run = true }
12
+ run.should == false
13
+ end
14
+
15
+ it 'should not allow adding of a hook with a duplicate name' do
16
+ @hooks.add_hook(:test_hook, :my_name) {}
17
+
18
+ lambda { @hooks.add_hook(:test_hook, :my_name) {} }.should.raise ArgumentError
19
+ end
20
+
21
+ it 'should create a new hook with a block' do
22
+ @hooks.add_hook(:test_hook, :my_name) { }
23
+ @hooks.hook_count(:test_hook).should == 1
24
+ end
25
+
26
+ it 'should create a new hook with a callable' do
27
+ @hooks.add_hook(:test_hook, :my_name, proc { })
28
+ @hooks.hook_count(:test_hook).should == 1
29
+ end
30
+
31
+ it 'should use block if given both block and callable' do
32
+ run = false
33
+ foo = false
34
+ @hooks.add_hook(:test_hook, :my_name, proc { foo = true }) { run = true }
35
+ @hooks.hook_count(:test_hook).should == 1
36
+ @hooks.exec_hook(:test_hook)
37
+ run.should == true
38
+ foo.should == false
39
+ end
40
+
41
+ it 'should raise if not given a block or any other object' do
42
+ lambda { @hooks.add_hook(:test_hook, :my_name) }.should.raise ArgumentError
43
+ end
44
+
45
+ it 'should create multiple hooks for an event' do
46
+ @hooks.add_hook(:test_hook, :my_name) {}
47
+ @hooks.add_hook(:test_hook, :my_name2) {}
48
+ @hooks.hook_count(:test_hook).should == 2
49
+ end
50
+
51
+ it 'should return a count of 0 for an empty hook' do
52
+ @hooks.hook_count(:test_hook).should == 0
53
+ end
54
+ end
55
+
56
+ describe "getting hooks" do
57
+ describe "get_hook" do
58
+ it 'should return the correct requested hook' do
59
+ run = false
60
+ fun = false
61
+ @hooks.add_hook(:test_hook, :my_name) { run = true }
62
+ @hooks.add_hook(:test_hook, :my_name2) { fun = true }
63
+ @hooks.get_hook(:test_hook, :my_name).call
64
+ run.should == true
65
+ fun.should == false
66
+ end
67
+
68
+ it 'should return nil if hook does not exist' do
69
+ @hooks.get_hook(:test_hook, :my_name).should == nil
70
+ end
71
+ end
72
+
73
+ describe "get_hooks" do
74
+ it 'should return a hash of hook names/hook functions for an event' do
75
+ hook1 = proc { 1 }
76
+ hook2 = proc { 2 }
77
+ @hooks.add_hook(:test_hook, :my_name1, hook1)
78
+ @hooks.add_hook(:test_hook, :my_name2, hook2)
79
+ hash = @hooks.get_hooks(:test_hook)
80
+ hash.size.should == 2
81
+ hash[:my_name1].should == hook1
82
+ hash[:my_name2].should == hook2
83
+ end
84
+
85
+ it 'should return an empty hash if no hooks defined' do
86
+ @hooks.get_hooks(:test_hook).should == {}
87
+ end
88
+ end
89
+ end
90
+
91
+ describe "clearing all hooks for an event" do
92
+ it 'should clear all hooks' do
93
+ @hooks.add_hook(:test_hook, :my_name) { }
94
+ @hooks.add_hook(:test_hook, :my_name2) { }
95
+ @hooks.add_hook(:test_hook, :my_name3) { }
96
+ @hooks.clear(:test_hook)
97
+ @hooks.hook_count(:test_hook).should == 0
98
+ end
99
+ end
100
+
101
+ describe "deleting a hook" do
102
+ it 'should successfully delete a hook' do
103
+ @hooks.add_hook(:test_hook, :my_name) {}
104
+ @hooks.delete_hook(:test_hook, :my_name)
105
+ @hooks.hook_count(:test_hook).should == 0
106
+ end
107
+
108
+ it 'should return the deleted hook' do
109
+ run = false
110
+ @hooks.add_hook(:test_hook, :my_name) { run = true }
111
+ @hooks.delete_hook(:test_hook, :my_name).call
112
+ run.should == true
113
+ end
114
+
115
+ it 'should return nil if hook does not exist' do
116
+ @hooks.delete_hook(:test_hook, :my_name).should == nil
117
+ end
118
+ end
119
+
120
+ describe "executing a hook" do
121
+ it 'should execute block hook' do
122
+ run = false
123
+ @hooks.add_hook(:test_hook, :my_name) { run = true }
124
+ @hooks.exec_hook(:test_hook)
125
+ run.should == true
126
+ end
127
+
128
+ it 'should execute proc hook' do
129
+ run = false
130
+ @hooks.add_hook(:test_hook, :my_name, proc { run = true })
131
+ @hooks.exec_hook(:test_hook)
132
+ run.should == true
133
+ end
134
+
135
+ it 'should execute a general callable hook' do
136
+ callable = Object.new.tap do |obj|
137
+ obj.instance_variable_set(:@test_var, nil)
138
+ class << obj
139
+ attr_accessor :test_var
140
+ def call() @test_var = true; end
141
+ end
142
+ end
143
+
144
+ @hooks.add_hook(:test_hook, :my_name, callable)
145
+ @hooks.exec_hook(:test_hook)
146
+ callable.test_var.should == true
147
+ end
148
+
149
+ it 'should execute all hooks for an event if more than one is defined' do
150
+ x = nil
151
+ y = nil
152
+ @hooks.add_hook(:test_hook, :my_name1) { y = true }
153
+ @hooks.add_hook(:test_hook, :my_name2) { x = true }
154
+ @hooks.exec_hook(:test_hook)
155
+ x.should == true
156
+ y.should == true
157
+ end
158
+
159
+ it 'should execute hooks in order' do
160
+ array = []
161
+ @hooks.add_hook(:test_hook, :my_name1) { array << 1 }
162
+ @hooks.add_hook(:test_hook, :my_name2) { array << 2 }
163
+ @hooks.add_hook(:test_hook, :my_name3) { array << 3 }
164
+ @hooks.exec_hook(:test_hook)
165
+ array.should == [1, 2, 3]
166
+ end
167
+
168
+ it 'return value of exec_hook should be that of last executed hook' do
169
+ @hooks.add_hook(:test_hook, :my_name1) { 1 }
170
+ @hooks.add_hook(:test_hook, :my_name2) { 2 }
171
+ @hooks.add_hook(:test_hook, :my_name3) { 3 }
172
+ @hooks.exec_hook(:test_hook).should == 3
173
+ end
174
+ end
175
+ end