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
@@ -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
 
@@ -119,7 +92,7 @@ describe "ls" do
119
92
  describe "when no arguments given" do
120
93
  describe "when at the top-level" do
121
94
  # rubinius has a bug that means local_variables of "main" aren't reported inside eval()
122
- unless defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /rbx/
95
+ unless Pry::Helpers::BaseHelpers.rbx?
123
96
  it "should show local variables" do
124
97
  mock_pry("ls").should =~ /_pry_/
125
98
  mock_pry("arbitrar = 1", "ls").should =~ /arbitrar/
@@ -1,18 +1,243 @@
1
1
  require 'helper'
2
2
 
3
3
  describe "Pry::DefaultCommands::Shell" do
4
+ describe "save-file" do
5
+ before do
6
+ @tf = Tempfile.new(["pry", ".py"])
7
+ @path = @tf.path
8
+ end
9
+
10
+ after do
11
+ @tf.close(true)
12
+ end
13
+
14
+ describe "-f" do
15
+ it 'should save a file to a file' do
16
+ f = Tempfile.new(["pry", ".py"])
17
+ path = f.path
18
+ f.write ":cute_horse"
19
+
20
+ redirect_pry_io(InputTester.new("save-file -f #{path} #{@path}",
21
+ "exit-all")) do
22
+ Pry.start(@o)
23
+ end
24
+ File.read(@path).should == File.read(path)
25
+
26
+ f.close(true)
27
+ end
28
+ end
29
+
30
+ describe "-i" do
31
+ it 'should save input expressions to a file (single expression)' do
32
+ redirect_pry_io(InputTester.new(":horse_nostrils",
33
+ "save-file -i 1 #{@path}",
34
+ "exit-all")) do
35
+ Pry.start(@o)
36
+ end
37
+ File.read(@path).should == ":horse_nostrils\n"
38
+ end
39
+
40
+ it 'should save input expressions to a file (range)' do
41
+ redirect_pry_io(InputTester.new(":horse_nostrils",
42
+ ":sucking_up_all_the_oxygen",
43
+ "save-file -i 1..2 #{@path}",
44
+ "exit-all")) do
45
+ Pry.start(@o)
46
+ end
47
+ File.read(@path).should == ":horse_nostrils\n:sucking_up_all_the_oxygen\n"
48
+ end
49
+ end
50
+
51
+ describe "-m" do
52
+ before do
53
+ @o = Object.new
54
+ def @o.baby
55
+ :baby
56
+ end
57
+ def @o.bang
58
+ :bang
59
+ end
60
+ end
61
+
62
+ describe "single method" do
63
+ it 'should save a method to a file' do
64
+ redirect_pry_io(InputTester.new("save-file #{@path} -m baby",
65
+ "exit-all")) do
66
+ Pry.start(@o)
67
+ end
68
+ File.read(@path).should == Pry::Method.from_obj(@o, :baby).source
69
+ end
70
+
71
+ it 'should save a method to a file truncated by --lines' do
72
+ redirect_pry_io(InputTester.new("save-file #{@path} -m baby --lines 2..4",
73
+ "exit-all")) do
74
+ Pry.start(@o)
75
+ end
76
+
77
+ # must add 1 as first line of method is 1
78
+ File.read(@path).should == Pry::Method.from_obj(@o, :baby).source.lines.to_a[1..5].join
79
+ end
80
+ end
81
+
82
+ describe "multiple method" do
83
+ it 'should save multiple methods to a file' do
84
+ redirect_pry_io(InputTester.new("save-file #{@path} -m baby -m bang",
85
+ "exit-all")) do
86
+ Pry.start(@o)
87
+ end
88
+ File.read(@path).should == Pry::Method.from_obj(@o, :baby).source +
89
+ Pry::Method.from_obj(@o, :bang).source
90
+ end
91
+
92
+ it 'should save multiple methods to a file trucated by --lines' do
93
+ redirect_pry_io(InputTester.new("save-file #{@path} -m baby -m bang --lines 2..-2",
94
+ "exit-all")) do
95
+ Pry.start(@o)
96
+ end
97
+
98
+ # must add 1 as first line of method is 1
99
+ File.read(@path).should == (Pry::Method.from_obj(@o, :baby).source +
100
+ Pry::Method.from_obj(@o, :bang).source).lines.to_a[1..-2].join
101
+ end
102
+
103
+ it 'should save multiple methods to a file trucated by --lines 1 (single parameter, not range)' do
104
+ redirect_pry_io(InputTester.new("save-file #{@path} -m baby -m bang --lines 1",
105
+ "exit-all")) do
106
+ Pry.start(@o)
107
+ end
108
+
109
+ # must add 1 as first line of method is 1
110
+ File.read(@path).should == (Pry::Method.from_obj(@o, :baby).source +
111
+ Pry::Method.from_obj(@o, :bang).source).lines.to_a[0]
112
+ end
113
+
114
+ end
115
+
116
+ end
117
+
118
+ describe "overwrite by default (no --append)" do
119
+ it 'should overwrite specified file with new input' do
120
+ redirect_pry_io(InputTester.new(":horse_nostrils",
121
+ "save-file -i 1 #{@path}",
122
+ "exit-all")) do
123
+ Pry.start(@o)
124
+ end
125
+
126
+ redirect_pry_io(InputTester.new(":sucking_up_all_the_oxygen",
127
+ "save-file -i 1 #{@path}",
128
+ "exit-all")) do
129
+ Pry.start(@o)
130
+ end
131
+
132
+ File.read(@path).should == ":sucking_up_all_the_oxygen\n"
133
+ end
134
+
135
+ end
136
+
137
+ describe "--append" do
138
+ it 'should append to end of specified file' do
139
+ redirect_pry_io(InputTester.new(":horse_nostrils",
140
+ "save-file -i 1 #{@path}",
141
+ "exit-all")) do
142
+ Pry.start(@o)
143
+ end
144
+
145
+ redirect_pry_io(InputTester.new(":sucking_up_all_the_oxygen",
146
+ "save-file -i 1 #{@path} -a",
147
+ "exit-all")) do
148
+ Pry.start(@o)
149
+ end
150
+
151
+ File.read(@path).should == ":horse_nostrils\n:sucking_up_all_the_oxygen\n"
152
+ end
153
+ end
154
+
155
+ describe "-c" do
156
+ it 'should save a command to a file' do
157
+ redirect_pry_io(InputTester.new("save-file #{@path} -c show-method",
158
+ "exit-all")) do
159
+ Pry.start(@o)
160
+ end
161
+ cmd = Pry::Method.new(Pry.commands.find_command("show-method").block)
162
+ File.read(@path).should == Pry::Code.from_method(cmd).to_s
163
+ end
164
+ end
165
+
166
+ describe "combined options" do
167
+ before do
168
+ @o = Object.new
169
+ def @o.baby
170
+ :baby
171
+ end
172
+ end
173
+
174
+ it 'should save input cache and a method to a file (in that order)' do
175
+ redirect_pry_io(InputTester.new(":horse_nostrils",
176
+ "save-file -i 1 -m baby #{@path}",
177
+ "exit-all")) do
178
+ Pry.start(@o)
179
+ end
180
+ File.read(@path).should == ":horse_nostrils\n" + Pry::Method.from_obj(@o, :baby).source
181
+ end
182
+
183
+ it 'should select a portion to save using --lines' do
184
+ redirect_pry_io(InputTester.new(":horse_nostrils",
185
+ "save-file -i 1 -m baby #{@path} --lines 2..-2",
186
+ "exit-all")) do
187
+ Pry.start(@o)
188
+ end
189
+ File.read(@path).should == (":horse_nostrils\n" + Pry::Method.from_obj(@o, :baby).source).lines.to_a[1..-2].join
190
+ end
191
+ end
192
+ end
193
+
4
194
  describe "cat" do
5
195
 
6
196
  describe "on receiving a file that does not exist" do
7
197
  it 'should display an error message' do
8
- mock_pry("cat supercalifragilicious66").should =~ /Could not find file/
198
+ mock_pry("cat supercalifragilicious66").should =~ /Cannot open/
199
+ end
200
+ end
201
+
202
+ describe "with --in" do
203
+ it 'should display the last few expressions with indices' do
204
+ output = mock_pry("10", "20", "cat --in")
205
+ output.should =~ /^1:/
206
+ output.should =~ /^ 10/
207
+ output.should =~ /^2:/
208
+ output.should =~ /^ 20/
209
+ end
210
+ end
211
+
212
+ describe "with --in 1" do
213
+ it 'should display the first expression with no index' do
214
+ output = mock_pry("10", "20", "cat --in 1")
215
+ output.should.not =~ /^\d+:/
216
+ output.should =~ /^10/
217
+ end
218
+ end
219
+
220
+ describe "with --in -1" do
221
+ it 'should display the last expression with no index' do
222
+ output = mock_pry("10", "20", "cat --in -1")
223
+ output.should.not =~ /^\d+:/
224
+ output.should =~ /^20/
225
+ end
226
+ end
227
+
228
+ describe "with --in 1..2" do
229
+ it 'should display the given range with indices, omitting nils' do
230
+ output = mock_pry("10", "20", "cat --ex", ":hello", "cat --in 1..4")
231
+ output.should =~ /^1:/
232
+ output.should.not =~ /^3:/
233
+ output.should =~ /^ :hello/
9
234
  end
10
235
  end
11
236
 
12
237
  # this doesnt work so well on rbx due to differences in backtrace
13
238
  # so we currently skip rbx until we figure out a workaround
14
239
  describe "with --ex" do
15
- if !rbx?
240
+ if !Pry::Helpers::BaseHelpers.rbx?
16
241
  it 'cat --ex should correctly display code that generated exception even if raised in repl' do
17
242
  mock_pry("this raises error", "cat --ex").should =~ /\d+:(\s*) this raises error/
18
243
  end
@@ -30,7 +255,7 @@ describe "Pry::DefaultCommands::Shell" do
30
255
  temp_file do |f|
31
256
  f << "bt number 1"
32
257
  f.flush
33
- pry_instance.last_exception = MockPryException.new("#{f.path}:1", "x", "x")
258
+ pry_instance.last_exception = mock_exception("#{f.path}:1", "x", "x")
34
259
  pry_instance.rep(self)
35
260
  end
36
261
 
@@ -43,7 +268,7 @@ describe "Pry::DefaultCommands::Shell" do
43
268
  temp_file do |f|
44
269
  f << "bt number 1"
45
270
  f.flush
46
- pry_instance.last_exception = MockPryException.new("#{f.path}:1", "x", "x")
271
+ pry_instance.last_exception = mock_exception("#{f.path}:1", "x", "x")
47
272
  pry_instance.rep(self)
48
273
  end
49
274
 
@@ -56,37 +281,37 @@ describe "Pry::DefaultCommands::Shell" do
56
281
  temp_file do |f|
57
282
  f << "bt number 2"
58
283
  f.flush
59
- pry_instance.last_exception = MockPryException.new("x", "#{f.path}:1", "x")
284
+ pry_instance.last_exception = mock_exception("x", "#{f.path}:1", "x")
60
285
  pry_instance.rep(self)
61
286
  end
62
287
 
63
288
  str_output.string.should =~ /bt number 2/
64
289
  end
65
290
 
66
- it 'should cat third level of backtrace when --ex 2 used ' do
291
+ it 'should cat third level of backtrace when --ex 2 used' do
67
292
  pry_instance = Pry.new(:input => StringIO.new("cat --ex 2"), :output => str_output = StringIO.new)
68
293
 
69
294
  temp_file do |f|
70
295
  f << "bt number 3"
71
296
  f.flush
72
- pry_instance.last_exception = MockPryException.new("x", "x", "#{f.path}:1")
297
+ pry_instance.last_exception = mock_exception("x", "x", "#{f.path}:1")
73
298
  pry_instance.rep(self)
74
299
  end
75
300
 
76
301
  str_output.string.should =~ /bt number 3/
77
302
  end
78
303
 
79
- it 'should show error when backtrace level out of bounds ' do
304
+ it 'should show error when backtrace level out of bounds' do
80
305
  pry_instance = Pry.new(:input => StringIO.new("cat --ex 3"), :output => str_output = StringIO.new)
81
- pry_instance.last_exception = MockPryException.new("x", "x", "x")
306
+ pry_instance.last_exception = mock_exception("x", "x", "x")
82
307
  pry_instance.rep(self)
83
- str_output.string.should =~ /No Exception or Exception has no associated file/
308
+ str_output.string.should =~ /out of bounds/
84
309
  end
85
310
 
86
311
  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
312
  temp_files = []
88
313
  3.times do |i|
89
- temp_files << Tempfile.new(['tmp', '*.rb'])
314
+ temp_files << Tempfile.new(['pry', '*.rb'])
90
315
  temp_files.last << "bt number #{i}"
91
316
  temp_files.last.flush
92
317
  end
@@ -94,7 +319,7 @@ describe "Pry::DefaultCommands::Shell" do
94
319
  pry_instance = Pry.new(:input => StringIO.new("cat --ex\n" * 4),
95
320
  :output => (str_output = StringIO.new))
96
321
 
97
- pry_instance.last_exception = MockPryException.new(*temp_files.map { |f| "#{f.path}:1" })
322
+ pry_instance.last_exception = mock_exception(*temp_files.map { |f| "#{f.path}:1" })
98
323
 
99
324
  3.times do |i|
100
325
  pry_instance.rep(self)
@@ -105,7 +330,9 @@ describe "Pry::DefaultCommands::Shell" do
105
330
  pry_instance.rep(self)
106
331
  str_output.string.should =~ /bt number 0/
107
332
 
108
- temp_files.each(&:close)
333
+ temp_files.each do |file|
334
+ file.close(true)
335
+ end
109
336
  end
110
337
 
111
338
  end
@@ -0,0 +1,490 @@
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 "Pry::Hooks#merge" do
57
+ describe "merge!" do
58
+ it 'should merge in the Pry::Hooks' do
59
+ h1 = Pry::Hooks.new.add_hook(:test_hook, :testing) {}
60
+ h2 = Pry::Hooks.new
61
+
62
+ h2.merge!(h1)
63
+ h2.get_hook(:test_hook, :testing).should == h1.get_hook(:test_hook, :testing)
64
+ end
65
+
66
+ it 'should not share merged elements with original' do
67
+ h1 = Pry::Hooks.new.add_hook(:test_hook, :testing) {}
68
+ h2 = Pry::Hooks.new
69
+
70
+ h2.merge!(h1)
71
+ h2.add_hook(:test_hook, :testing2) {}
72
+ h2.get_hook(:test_hook, :testing2).should.not == h1.get_hook(:test_hook, :testing2)
73
+ end
74
+
75
+ it 'should NOT overwrite hooks belonging to shared event in receiver' do
76
+ h1 = Pry::Hooks.new.add_hook(:test_hook, :testing) {}
77
+ callable = proc {}
78
+ h2 = Pry::Hooks.new.add_hook(:test_hook, :testing2, callable)
79
+
80
+ h2.merge!(h1)
81
+ h2.get_hook(:test_hook, :testing2).should == callable
82
+ end
83
+
84
+ it 'should overwrite identical hook in receiver' do
85
+ callable1 = proc { :one }
86
+ h1 = Pry::Hooks.new.add_hook(:test_hook, :testing, callable1)
87
+ callable2 = proc { :two }
88
+ h2 = Pry::Hooks.new.add_hook(:test_hook, :testing, callable2)
89
+
90
+ h2.merge!(h1)
91
+ h2.get_hook(:test_hook, :testing).should == callable1
92
+ h2.hook_count(:test_hook).should == 1
93
+ end
94
+
95
+ it 'should preserve hook order' do
96
+ name = ""
97
+ h1 = Pry::Hooks.new
98
+ h1.add_hook(:test_hook, :testing3) { name << "h" }
99
+ h1.add_hook(:test_hook, :testing4) { name << "n" }
100
+
101
+ h2 = Pry::Hooks.new
102
+ h2.add_hook(:test_hook, :testing1) { name << "j" }
103
+ h2.add_hook(:test_hook, :testing2) { name << "o" }
104
+
105
+ h2.merge!(h1)
106
+ h2.exec_hook(:test_hook)
107
+
108
+ name.should == "john"
109
+ end
110
+
111
+ describe "merge" do
112
+ it 'should return a fresh, independent instance' do
113
+ h1 = Pry::Hooks.new.add_hook(:test_hook, :testing) {}
114
+ h2 = Pry::Hooks.new
115
+
116
+ h3 = h2.merge(h1)
117
+ h3.should.not == h1
118
+ h3.should.not == h2
119
+ end
120
+
121
+ it 'should contain hooks from original instance' do
122
+ h1 = Pry::Hooks.new.add_hook(:test_hook, :testing) {}
123
+ h2 = Pry::Hooks.new.add_hook(:test_hook2, :testing) {}
124
+
125
+ h3 = h2.merge(h1)
126
+ h3.get_hook(:test_hook, :testing).should == h1.get_hook(:test_hook, :testing)
127
+ h3.get_hook(:test_hook2, :testing).should == h2.get_hook(:test_hook2, :testing)
128
+ end
129
+
130
+ it 'should not affect original instances when new hooks are added' do
131
+ h1 = Pry::Hooks.new.add_hook(:test_hook, :testing) {}
132
+ h2 = Pry::Hooks.new.add_hook(:test_hook2, :testing) {}
133
+
134
+ h3 = h2.merge(h1)
135
+ h3.add_hook(:test_hook3, :testing) {}
136
+
137
+ h1.get_hook(:test_hook3, :testing).should == nil
138
+ h2.get_hook(:test_hook3, :testing).should == nil
139
+ end
140
+ end
141
+
142
+ end
143
+ end
144
+
145
+ describe "dupping a Pry::Hooks instance" do
146
+ it 'should share hooks with original' do
147
+ @hooks.add_hook(:test_hook, :testing) do
148
+ :none_such
149
+ end
150
+
151
+ hooks_dup = @hooks.dup
152
+ hooks_dup.get_hook(:test_hook, :testing).should == @hooks.get_hook(:test_hook, :testing)
153
+ end
154
+
155
+ it 'adding a new event to dupped instance should not affect original' do
156
+ @hooks.add_hook(:test_hook, :testing) { :none_such }
157
+ hooks_dup = @hooks.dup
158
+
159
+ hooks_dup.add_hook(:other_test_hook, :testing) { :okay_man }
160
+
161
+ hooks_dup.get_hook(:other_test_hook, :testing).should.not == @hooks.get_hook(:other_test_hook, :testing)
162
+ end
163
+
164
+ it 'adding a new hook to dupped instance should not affect original' do
165
+ @hooks.add_hook(:test_hook, :testing) { :none_such }
166
+ hooks_dup = @hooks.dup
167
+
168
+ hooks_dup.add_hook(:test_hook, :testing2) { :okay_man }
169
+
170
+ hooks_dup.get_hook(:test_hook, :testing2).should.not == @hooks.get_hook(:test_hook, :testing2)
171
+ end
172
+
173
+ end
174
+
175
+ describe "getting hooks" do
176
+ describe "get_hook" do
177
+ it 'should return the correct requested hook' do
178
+ run = false
179
+ fun = false
180
+ @hooks.add_hook(:test_hook, :my_name) { run = true }
181
+ @hooks.add_hook(:test_hook, :my_name2) { fun = true }
182
+ @hooks.get_hook(:test_hook, :my_name).call
183
+ run.should == true
184
+ fun.should == false
185
+ end
186
+
187
+ it 'should return nil if hook does not exist' do
188
+ @hooks.get_hook(:test_hook, :my_name).should == nil
189
+ end
190
+ end
191
+
192
+ describe "get_hooks" do
193
+ it 'should return a hash of hook names/hook functions for an event' do
194
+ hook1 = proc { 1 }
195
+ hook2 = proc { 2 }
196
+ @hooks.add_hook(:test_hook, :my_name1, hook1)
197
+ @hooks.add_hook(:test_hook, :my_name2, hook2)
198
+ hash = @hooks.get_hooks(:test_hook)
199
+ hash.size.should == 2
200
+ hash[:my_name1].should == hook1
201
+ hash[:my_name2].should == hook2
202
+ end
203
+
204
+ it 'should return an empty hash if no hooks defined' do
205
+ @hooks.get_hooks(:test_hook).should == {}
206
+ end
207
+ end
208
+ end
209
+
210
+ describe "clearing all hooks for an event" do
211
+ it 'should clear all hooks' do
212
+ @hooks.add_hook(:test_hook, :my_name) { }
213
+ @hooks.add_hook(:test_hook, :my_name2) { }
214
+ @hooks.add_hook(:test_hook, :my_name3) { }
215
+ @hooks.clear(:test_hook)
216
+ @hooks.hook_count(:test_hook).should == 0
217
+ end
218
+ end
219
+
220
+ describe "deleting a hook" do
221
+ it 'should successfully delete a hook' do
222
+ @hooks.add_hook(:test_hook, :my_name) {}
223
+ @hooks.delete_hook(:test_hook, :my_name)
224
+ @hooks.hook_count(:test_hook).should == 0
225
+ end
226
+
227
+ it 'should return the deleted hook' do
228
+ run = false
229
+ @hooks.add_hook(:test_hook, :my_name) { run = true }
230
+ @hooks.delete_hook(:test_hook, :my_name).call
231
+ run.should == true
232
+ end
233
+
234
+ it 'should return nil if hook does not exist' do
235
+ @hooks.delete_hook(:test_hook, :my_name).should == nil
236
+ end
237
+ end
238
+
239
+ describe "executing a hook" do
240
+ it 'should execute block hook' do
241
+ run = false
242
+ @hooks.add_hook(:test_hook, :my_name) { run = true }
243
+ @hooks.exec_hook(:test_hook)
244
+ run.should == true
245
+ end
246
+
247
+ it 'should execute proc hook' do
248
+ run = false
249
+ @hooks.add_hook(:test_hook, :my_name, proc { run = true })
250
+ @hooks.exec_hook(:test_hook)
251
+ run.should == true
252
+ end
253
+
254
+ it 'should execute a general callable hook' do
255
+ callable = Object.new.tap do |obj|
256
+ obj.instance_variable_set(:@test_var, nil)
257
+ class << obj
258
+ attr_accessor :test_var
259
+ def call() @test_var = true; end
260
+ end
261
+ end
262
+
263
+ @hooks.add_hook(:test_hook, :my_name, callable)
264
+ @hooks.exec_hook(:test_hook)
265
+ callable.test_var.should == true
266
+ end
267
+
268
+ it 'should execute all hooks for an event if more than one is defined' do
269
+ x = nil
270
+ y = nil
271
+ @hooks.add_hook(:test_hook, :my_name1) { y = true }
272
+ @hooks.add_hook(:test_hook, :my_name2) { x = true }
273
+ @hooks.exec_hook(:test_hook)
274
+ x.should == true
275
+ y.should == true
276
+ end
277
+
278
+ it 'should execute hooks in order' do
279
+ array = []
280
+ @hooks.add_hook(:test_hook, :my_name1) { array << 1 }
281
+ @hooks.add_hook(:test_hook, :my_name2) { array << 2 }
282
+ @hooks.add_hook(:test_hook, :my_name3) { array << 3 }
283
+ @hooks.exec_hook(:test_hook)
284
+ array.should == [1, 2, 3]
285
+ end
286
+
287
+ it 'return value of exec_hook should be that of last executed hook' do
288
+ @hooks.add_hook(:test_hook, :my_name1) { 1 }
289
+ @hooks.add_hook(:test_hook, :my_name2) { 2 }
290
+ @hooks.add_hook(:test_hook, :my_name3) { 3 }
291
+ @hooks.exec_hook(:test_hook).should == 3
292
+ end
293
+
294
+ it 'should add exceptions to the errors array' do
295
+ @hooks.add_hook(:test_hook, :foo1) { raise 'one' }
296
+ @hooks.add_hook(:test_hook, :foo2) { raise 'two' }
297
+ @hooks.add_hook(:test_hook, :foo3) { raise 'three' }
298
+ @hooks.exec_hook(:test_hook)
299
+ @hooks.errors.map(&:message).should == ['one', 'two', 'three']
300
+ end
301
+
302
+ it 'should return the last exception raised as the return value' do
303
+ @hooks.add_hook(:test_hook, :foo1) { raise 'one' }
304
+ @hooks.add_hook(:test_hook, :foo2) { raise 'two' }
305
+ @hooks.add_hook(:test_hook, :foo3) { raise 'three' }
306
+ @hooks.exec_hook(:test_hook).should == @hooks.errors.last
307
+ end
308
+ end
309
+
310
+ describe "integration tests" do
311
+ describe "when_started hook" do
312
+ it 'should yield options to the hook' do
313
+ options = nil
314
+ Pry.config.hooks.add_hook(:when_started, :test_hook) { |target, opt, _| options = opt }
315
+
316
+ redirect_pry_io(StringIO.new("exit"), out=StringIO.new) do
317
+ Pry.start binding, :hello => :baby
318
+ end
319
+ options[:hello].should == :baby
320
+
321
+ Pry.config.hooks.delete_hook(:when_started, :test_hook)
322
+ end
323
+
324
+ describe "target" do
325
+
326
+ it 'should yield the target, as a binding ' do
327
+ b = nil
328
+ Pry.config.hooks.add_hook(:when_started, :test_hook) { |target, opt, _| b = target }
329
+
330
+ redirect_pry_io(StringIO.new("exit"), out=StringIO.new) do
331
+ Pry.start 5, :hello => :baby
332
+ end
333
+
334
+ b.is_a?(Binding).should == true
335
+ Pry.config.hooks.delete_hook(:when_started, :test_hook)
336
+ end
337
+
338
+ it 'should yield the target to the hook' do
339
+ b = nil
340
+ Pry.config.hooks.add_hook(:when_started, :test_hook) { |target, opt, _| b = target }
341
+
342
+ redirect_pry_io(StringIO.new("exit"), out=StringIO.new) do
343
+ Pry.start 5, :hello => :baby
344
+ end
345
+
346
+ b.eval('self').should == 5
347
+ Pry.config.hooks.delete_hook(:when_started, :test_hook)
348
+ end
349
+ end
350
+
351
+ it 'should allow overriding of target (and binding_stack)' do
352
+ options = nil
353
+ o = Object.new
354
+ class << o; attr_accessor :value; end
355
+
356
+ Pry.config.hooks.add_hook(:when_started, :test_hook) { |target, opt, _pry_| _pry_.binding_stack = [Pry.binding_for(o)] }
357
+
358
+ redirect_pry_io(InputTester.new("@value = true","exit-all")) do
359
+ Pry.start binding, :hello => :baby
360
+ end
361
+
362
+ o.value.should == true
363
+ Pry.config.hooks.delete_hook(:when_started, :test_hook)
364
+ end
365
+
366
+ end
367
+
368
+ describe "after_session hook" do
369
+ it 'should always run, even if uncaught exception bubbles out of repl' do
370
+ o = OpenStruct.new
371
+ o.great_escape = Class.new(StandardError)
372
+
373
+ old_ew = Pry.config.exception_whitelist
374
+ Pry.config.exception_whitelist << o.great_escape
375
+
376
+ array = [1, 2, 3, 4, 5]
377
+
378
+ begin
379
+ redirect_pry_io(StringIO.new("raise great_escape"), out=StringIO.new) do
380
+ Pry.start o, :hooks => Pry::Hooks.new.add_hook(:after_session, :cleanup) { array = nil }
381
+ end
382
+ rescue => ex
383
+ exception = ex
384
+ end
385
+
386
+ # ensure that an exception really was raised and it broke out
387
+ # of the repl
388
+ exception.is_a?(o.great_escape).should == true
389
+
390
+ # check that after_session hook ran
391
+ array.should == nil
392
+
393
+ # cleanup after test
394
+ Pry.config.exception_whitelist = old_ew
395
+ end
396
+
397
+ describe "exceptions" do
398
+ before do
399
+ Pry.config.hooks.add_hook(:after_eval, :baddums){ raise "Baddums" }
400
+ Pry.config.hooks.add_hook(:after_eval, :simbads){ raise "Simbads" }
401
+ end
402
+
403
+ after do
404
+ Pry.config.hooks.delete_hook(:after_eval, :baddums)
405
+ Pry.config.hooks.delete_hook(:after_eval, :simbads)
406
+ end
407
+ it "should not raise exceptions" do
408
+ lambda{
409
+ mock_pry("1", "2", "3")
410
+ }.should.not.raise
411
+ end
412
+
413
+ it "should print out a notice for each exception raised" do
414
+ mock_pry("1").should =~ /after_eval hook failed: RuntimeError: Baddums\n.*after_eval hook failed: RuntimeError: Simbads/m
415
+ end
416
+ end
417
+ end
418
+ end
419
+
420
+ describe "anonymous hooks" do
421
+ it 'should allow adding of hook without a name' do
422
+ @hooks.add_hook(:test_hook, nil) {}
423
+ @hooks.hook_count(:test_hook).should == 1
424
+ end
425
+
426
+ it 'should only allow one anonymous hook to exist' do
427
+ @hooks.add_hook(:test_hook, nil) { }
428
+ @hooks.add_hook(:test_hook, nil) { }
429
+ @hooks.hook_count(:test_hook).should == 1
430
+ end
431
+
432
+ it 'should execute most recently added anonymous hook' do
433
+ x = nil
434
+ y = nil
435
+ @hooks.add_hook(:test_hook, nil) { y = 1 }
436
+ @hooks.add_hook(:test_hook, nil) { x = 2 }
437
+ @hooks.exec_hook(:test_hook)
438
+ y.should == nil
439
+ x.should == 2
440
+ end
441
+ end
442
+
443
+ describe "deprecated hash-based API" do
444
+ after do
445
+ Pry.config.hooks.clear_all if Pry.config.hooks
446
+ end
447
+
448
+ describe "Pry.config.hooks" do
449
+ it 'should allow a hash-assignment' do
450
+ Pry.config.hooks = { :before_session => proc { :hello } }
451
+ Pry.config.hooks.get_hook(:before_session, nil).call.should == :hello
452
+ end
453
+
454
+ describe "Pry.config.hooks[]" do
455
+ it 'should return the only anonymous hook' do
456
+ Pry.config.hooks = { :before_session => proc { :hello } }
457
+ Pry.config.hooks[:before_session].call.should == :hello
458
+ end
459
+
460
+ it 'should add an anonymous hook when using Pry.config.hooks[]=' do
461
+ Pry.config.hooks[:before_session] = proc { :bing }
462
+ Pry.config.hooks.hook_count(:before_session).should == 1
463
+ end
464
+
465
+ it 'should add overwrite previous anonymous hooks with new one when calling Pry.config.hooks[]= multiple times' do
466
+ x = nil
467
+ Pry.config.hooks[:before_session] = proc { x = 1 }
468
+ Pry.config.hooks[:before_session] = proc { x = 2 }
469
+
470
+ Pry.config.hooks.exec_hook(:before_session)
471
+ Pry.config.hooks.hook_count(:before_session).should == 1
472
+ x.should == 2
473
+ end
474
+ end
475
+ end
476
+
477
+ describe "Pry.start" do
478
+ it 'should accept a hash for :hooks parameter' do
479
+
480
+ redirect_pry_io(InputTester.new("exit-all"), out=StringIO.new) do
481
+ Pry.start binding, :hooks => { :before_session => proc { |output, _, _| output.puts 'hello friend' } }
482
+ end
483
+
484
+ out.string.should =~ /hello friend/
485
+ end
486
+
487
+ end
488
+ end
489
+
490
+ end