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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. data/.gitignore +2 -3
  2. data/CHANGELOG +43 -0
  3. data/README.markdown +3 -1
  4. data/Rakefile +51 -32
  5. data/bin/pry +2 -80
  6. data/lib/pry.rb +33 -26
  7. data/lib/pry/cli.rb +152 -0
  8. data/lib/pry/code.rb +351 -0
  9. data/lib/pry/command.rb +422 -0
  10. data/lib/pry/command_set.rb +259 -129
  11. data/lib/pry/commands.rb +0 -1
  12. data/lib/pry/config.rb +43 -9
  13. data/lib/pry/default_commands/context.rb +109 -92
  14. data/lib/pry/default_commands/documentation.rb +174 -63
  15. data/lib/pry/default_commands/easter_eggs.rb +26 -2
  16. data/lib/pry/default_commands/gems.rb +65 -37
  17. data/lib/pry/default_commands/input.rb +175 -243
  18. data/lib/pry/default_commands/introspection.rb +173 -112
  19. data/lib/pry/default_commands/ls.rb +96 -114
  20. data/lib/pry/default_commands/shell.rb +175 -70
  21. data/lib/pry/helpers/base_helpers.rb +7 -2
  22. data/lib/pry/helpers/command_helpers.rb +71 -77
  23. data/lib/pry/helpers/options_helpers.rb +10 -41
  24. data/lib/pry/helpers/text.rb +24 -4
  25. data/lib/pry/history.rb +55 -17
  26. data/lib/pry/history_array.rb +2 -0
  27. data/lib/pry/hooks.rb +252 -0
  28. data/lib/pry/indent.rb +9 -5
  29. data/lib/pry/method.rb +149 -50
  30. data/lib/pry/plugins.rb +12 -4
  31. data/lib/pry/pry_class.rb +69 -26
  32. data/lib/pry/pry_instance.rb +187 -115
  33. data/lib/pry/version.rb +1 -1
  34. data/lib/pry/wrapped_module.rb +73 -0
  35. data/man/pry.1 +195 -0
  36. data/man/pry.1.html +204 -0
  37. data/man/pry.1.ronn +141 -0
  38. data/pry.gemspec +29 -32
  39. data/test/helper.rb +32 -36
  40. data/test/test_cli.rb +78 -0
  41. data/test/test_code.rb +201 -0
  42. data/test/test_command.rb +327 -0
  43. data/test/test_command_integration.rb +512 -0
  44. data/test/test_command_set.rb +338 -12
  45. data/test/test_completion.rb +1 -1
  46. data/test/test_default_commands.rb +1 -2
  47. data/test/test_default_commands/test_context.rb +27 -5
  48. data/test/test_default_commands/test_documentation.rb +20 -8
  49. data/test/test_default_commands/test_input.rb +84 -45
  50. data/test/test_default_commands/test_introspection.rb +74 -17
  51. data/test/test_default_commands/test_ls.rb +9 -36
  52. data/test/test_default_commands/test_shell.rb +240 -13
  53. data/test/test_hooks.rb +490 -0
  54. data/test/test_indent.rb +2 -0
  55. data/test/test_method.rb +60 -0
  56. data/test/test_pry.rb +29 -904
  57. data/test/test_pry_defaults.rb +380 -0
  58. data/test/test_pry_history.rb +24 -24
  59. data/test/test_syntax_checking.rb +63 -0
  60. data/test/test_wrapped_module.rb +71 -0
  61. metadata +50 -39
  62. data/lib/pry/command_context.rb +0 -53
  63. data/lib/pry/command_processor.rb +0 -181
  64. data/lib/pry/extended_commands/user_command_api.rb +0 -65
  65. data/test/test_command_processor.rb +0 -176
@@ -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