vcr 2.0.0.beta2 → 2.0.0.rc1

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 (91) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +0 -2
  3. data/CHANGELOG.md +22 -1
  4. data/CONTRIBUTING.md +46 -0
  5. data/Gemfile +1 -9
  6. data/README.md +8 -2
  7. data/Rakefile +12 -1
  8. data/cucumber.yml +8 -9
  9. data/features/.nav +10 -4
  10. data/features/cassettes/format.feature +1 -1
  11. data/features/cassettes/no_cassette.feature +8 -11
  12. data/features/configuration/allow_http_connections_when_no_cassette.feature +4 -4
  13. data/features/configuration/filter_sensitive_data.feature +3 -0
  14. data/features/configuration/hook_into.feature +4 -8
  15. data/features/configuration/ignore_request.feature +191 -0
  16. data/features/getting_started.md +38 -21
  17. data/features/hooks/after_http_request.feature +44 -0
  18. data/features/hooks/around_http_request.feature +56 -0
  19. data/features/hooks/before_http_request.feature +44 -0
  20. data/features/hooks/before_playback.feature +181 -0
  21. data/features/hooks/before_record.feature +172 -0
  22. data/features/middleware/faraday.feature +7 -3
  23. data/features/record_modes/none.feature +2 -1
  24. data/features/record_modes/once.feature +2 -1
  25. data/features/request_matching/body.feature +2 -2
  26. data/features/request_matching/custom_matcher.feature +2 -2
  27. data/features/request_matching/headers.feature +2 -2
  28. data/features/request_matching/host.feature +2 -2
  29. data/features/request_matching/identical_request_sequence.feature +2 -2
  30. data/features/request_matching/method.feature +2 -2
  31. data/features/request_matching/path.feature +2 -2
  32. data/features/request_matching/playback_repeats.feature +2 -1
  33. data/features/request_matching/uri.feature +2 -2
  34. data/features/support/env.rb +21 -12
  35. data/features/test_frameworks/cucumber.feature +9 -4
  36. data/features/test_frameworks/{rspec.feature → rspec_macro.feature} +7 -7
  37. data/features/test_frameworks/rspec_metadata.feature +90 -0
  38. data/lib/vcr.rb +1 -1
  39. data/lib/vcr/cassette.rb +3 -3
  40. data/lib/vcr/cassette/http_interaction_list.rb +13 -9
  41. data/lib/vcr/cassette/migrator.rb +1 -1
  42. data/lib/vcr/configuration.rb +37 -0
  43. data/lib/vcr/errors.rb +172 -6
  44. data/lib/vcr/library_hooks.rb +4 -6
  45. data/lib/vcr/library_hooks/excon.rb +23 -11
  46. data/lib/vcr/library_hooks/fakeweb.rb +85 -24
  47. data/lib/vcr/library_hooks/faraday.rb +30 -2
  48. data/lib/vcr/library_hooks/typhoeus.rb +25 -3
  49. data/lib/vcr/library_hooks/webmock.rb +25 -36
  50. data/lib/vcr/middleware/faraday.rb +23 -5
  51. data/lib/vcr/request_handler.rb +12 -1
  52. data/lib/vcr/request_ignorer.rb +12 -1
  53. data/lib/vcr/request_matcher_registry.rb +1 -9
  54. data/lib/vcr/structs.rb +32 -2
  55. data/lib/vcr/test_frameworks/rspec.rb +28 -0
  56. data/lib/vcr/util/hooks.rb +12 -4
  57. data/lib/vcr/util/version_checker.rb +2 -0
  58. data/lib/vcr/version.rb +1 -1
  59. data/spec/fixtures/cassette_spec/example.yml +1 -1
  60. data/spec/fixtures/{fake_example.com_responses.yml → fake_example_responses.yml} +0 -0
  61. data/spec/monkey_patches.rb +1 -1
  62. data/spec/spec_helper.rb +3 -1
  63. data/spec/support/http_library_adapters.rb +4 -3
  64. data/spec/support/shared_example_groups/hook_into_http_library.rb +194 -12
  65. data/spec/support/shared_example_groups/request_hooks.rb +58 -0
  66. data/spec/support/shared_example_groups/version_checking.rb +5 -0
  67. data/spec/support/sinatra_app.rb +17 -9
  68. data/spec/support/vcr_stub_helpers.rb +17 -0
  69. data/spec/vcr/cassette/http_interaction_list_spec.rb +28 -29
  70. data/spec/vcr/cassette/migrator_spec.rb +6 -7
  71. data/spec/vcr/cassette_spec.rb +5 -5
  72. data/spec/vcr/configuration_spec.rb +51 -32
  73. data/spec/vcr/deprecations_spec.rb +0 -8
  74. data/spec/vcr/errors_spec.rb +129 -0
  75. data/spec/vcr/library_hooks/excon_spec.rb +21 -4
  76. data/spec/vcr/library_hooks/fakeweb_spec.rb +71 -3
  77. data/spec/vcr/library_hooks/faraday_spec.rb +45 -0
  78. data/spec/vcr/library_hooks/typhoeus_spec.rb +31 -1
  79. data/spec/vcr/library_hooks/webmock_spec.rb +26 -3
  80. data/spec/vcr/middleware/faraday_spec.rb +84 -1
  81. data/spec/vcr/request_ignorer_spec.rb +16 -0
  82. data/spec/vcr/request_matcher_registry_spec.rb +0 -26
  83. data/spec/vcr/structs_spec.rb +61 -1
  84. data/spec/vcr/test_frameworks/rspec_spec.rb +32 -0
  85. data/spec/vcr/util/hooks_spec.rb +73 -63
  86. data/spec/vcr_spec.rb +2 -2
  87. data/vcr.gemspec +5 -5
  88. metadata +51 -31
  89. data/features/configuration/hooks.feature +0 -270
  90. data/features/configuration/ignore_hosts.feature +0 -61
  91. data/features/configuration/ignore_localhost.feature +0 -97
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+ require 'vcr/library_hooks/faraday'
3
+
4
+ describe "Faraday hook" do
5
+ it 'inserts the VCR middleware just before the adapter' do
6
+ conn = Faraday.new(:url => 'http://sushi.com') do |builder|
7
+ builder.request :url_encoded
8
+ builder.request :json
9
+ builder.response :logger
10
+ builder.adapter :net_http
11
+ end
12
+
13
+ conn.builder.lock!
14
+ conn.builder.handlers.last(2).map(&:klass).should eq([
15
+ VCR::Middleware::Faraday,
16
+ Faraday::Adapter::NetHttp
17
+ ])
18
+ end
19
+
20
+ it 'handles the case where no adapter is declared' do
21
+ conn = Faraday.new
22
+
23
+ conn.builder.lock!
24
+ conn.builder.handlers.last(2).map(&:klass).should eq([
25
+ VCR::Middleware::Faraday,
26
+ Faraday::Adapter::NetHttp
27
+ ])
28
+ end
29
+
30
+ it 'does nothing if the VCR middleware has already been included' do
31
+ conn = Faraday.new(:url => 'http://sushi.com') do |builder|
32
+ builder.use VCR::Middleware::Faraday
33
+ builder.use Faraday::Response::Logger
34
+ builder.use Faraday::Adapter::NetHttp
35
+ end
36
+
37
+ conn.builder.lock!
38
+ conn.builder.handlers.map(&:klass).should eq([
39
+ VCR::Middleware::Faraday,
40
+ Faraday::Response::Logger,
41
+ Faraday::Adapter::NetHttp
42
+ ])
43
+ end
44
+ end
45
+
@@ -1,7 +1,35 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "Typhoeus hook", :with_monkey_patches => :typhoeus do
4
- it_behaves_like 'a hook into an HTTP library', 'typhoeus'
4
+ after(:each) do
5
+ ::Typhoeus::Hydra.clear_stubs
6
+ end
7
+
8
+ def disable_real_connections
9
+ ::Typhoeus::Hydra.allow_net_connect = false
10
+ ::Typhoeus::Hydra::NetConnectNotAllowedError
11
+ end
12
+
13
+ def enable_real_connections
14
+ ::Typhoeus::Hydra.allow_net_connect = true
15
+ end
16
+
17
+ def directly_stub_request(method, url, response_body)
18
+ response = ::Typhoeus::Response.new(:code => 200, :body => response_body)
19
+ ::Typhoeus::Hydra.stub(method, url).and_return(response)
20
+ end
21
+
22
+ it_behaves_like 'a hook into an HTTP library', :typhoeus, 'typhoeus'
23
+
24
+ def stub_callback_registration
25
+ # stub the callback registration methods so we don't get a second
26
+ # callback registered when we load the typhoeus file below.
27
+ # Note that we have to use `stub!`, not `stub` because
28
+ # Typhoeus::Hydra defines its own stub method...so to use RSpec's,
29
+ # we use stub!
30
+ ::Typhoeus::Hydra.stub!(:after_request_before_on_complete)
31
+ ::Typhoeus::Hydra.stub!(:register_stub_finder)
32
+ end
5
33
 
6
34
  it_performs('version checking', 'Typhoeus',
7
35
  :valid => %w[ 0.3.2 0.3.10 ],
@@ -18,6 +46,8 @@ describe "Typhoeus hook", :with_monkey_patches => :typhoeus do
18
46
  end
19
47
 
20
48
  describe "VCR.configuration.after_library_hooks_loaded hook", :disable_warnings do
49
+ before(:each) { stub_callback_registration }
50
+
21
51
  it 'disables the webmock typhoeus adapter so it does not conflict with our typhoeus hook' do
22
52
  load "vcr/library_hooks/typhoeus.rb" # to re-add the hook since it's cleared by each test
23
53
  ::WebMock::HttpLibAdapters::TyphoeusAdapter.should_receive(:disable!)
@@ -1,8 +1,25 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "WebMock hook", :with_monkey_patches => :webmock do
4
+ after(:each) do
5
+ ::WebMock.reset!
6
+ end
7
+
8
+ def disable_real_connections
9
+ ::WebMock.disable_net_connect!
10
+ ::WebMock::NetConnectNotAllowedError
11
+ end
12
+
13
+ def enable_real_connections
14
+ ::WebMock.allow_net_connect!
15
+ end
16
+
17
+ def directly_stub_request(method, url, response_body)
18
+ ::WebMock.stub_request(method, url).to_return(:body => response_body)
19
+ end
20
+
4
21
  %w[net/http patron httpclient em-http-request curb typhoeus].each do |lib|
5
- it_behaves_like 'a hook into an HTTP library', lib do
22
+ it_behaves_like 'a hook into an HTTP library', :webmock, lib do
6
23
  if lib == 'net/http'
7
24
  def normalize_request_headers(headers)
8
25
  headers.merge(DEFAULT_REQUEST_HEADERS)
@@ -12,10 +29,16 @@ describe "WebMock hook", :with_monkey_patches => :webmock do
12
29
  end
13
30
 
14
31
  it_performs('version checking', 'WebMock',
15
- :valid => %w[ 1.7.0 1.7.99 ],
16
- :too_low => %w[ 0.9.9 0.9.10 0.1.30 1.0.30 1.6.9 ],
32
+ :valid => %w[ 1.7.8 1.7.10 1.7.99 ],
33
+ :too_low => %w[ 0.9.9 0.9.10 0.1.30 1.0.30 1.7.7 ],
17
34
  :too_high => %w[ 1.8.0 1.10.0 2.0.0 ]
18
35
  ) do
36
+
37
+ def stub_callback_registration
38
+ ::WebMock.stub(:after_request)
39
+ ::WebMock.stub(:globally_stub_request)
40
+ end
41
+
19
42
  def stub_version(version)
20
43
  WebMock.stub(:version).and_return(version)
21
44
  end
@@ -1,8 +1,9 @@
1
1
  require 'spec_helper'
2
+ require 'vcr/library_hooks/faraday'
2
3
 
3
4
  describe VCR::Middleware::Faraday do
4
5
  %w[ typhoeus net_http patron ].each do |lib|
5
- it_behaves_like 'a hook into an HTTP library', "faraday (w/ #{lib})",
6
+ it_behaves_like 'a hook into an HTTP library', :faraday, "faraday (w/ #{lib})",
6
7
  :status_message_not_exposed,
7
8
  :does_not_support_rotating_responses,
8
9
  :not_disableable
@@ -22,4 +23,86 @@ describe VCR::Middleware::Faraday do
22
23
  ::Faraday::VERSION = version
23
24
  end
24
25
  end
26
+
27
+ context 'when making parallel requests' do
28
+ include VCRStubHelpers
29
+ let(:parallel_manager) { ::Faraday::Adapter::Typhoeus.setup_parallel_manager }
30
+ let(:connection) { ::Faraday.new { |b| b.adapter :typhoeus } }
31
+
32
+ shared_examples_for "exclusive library hook" do
33
+ let(:request_url) { "http://localhost:#{VCR::SinatraApp.port}/" }
34
+
35
+ def make_request
36
+ connection.in_parallel(parallel_manager) { connection.get(request_url) }
37
+ end
38
+
39
+ it 'makes the faraday middleware exclusively enabled for the duration of the request' do
40
+ VCR.library_hooks.should_not be_disabled(:fakeweb)
41
+
42
+ hook_called = false
43
+ VCR.configuration.after_http_request do
44
+ hook_called = true
45
+ VCR.library_hooks.should be_disabled(:fakeweb)
46
+ end
47
+
48
+ make_request
49
+ VCR.library_hooks.should_not be_disabled(:fakeweb)
50
+ hook_called.should be_true
51
+ end
52
+ end
53
+
54
+ context 'for an ignored request' do
55
+ before(:each) { VCR.configuration.ignore_request { true } }
56
+ it_behaves_like "exclusive library hook"
57
+ end
58
+
59
+ context 'for a stubbed request' do
60
+ it_behaves_like "exclusive library hook" do
61
+ before(:each) do
62
+ stub_requests([http_interaction(request_url)], [:method, :uri])
63
+ end
64
+ end
65
+ end
66
+
67
+ context 'for a recorded request' do
68
+ let!(:inserted_cassette) { VCR.insert_cassette('new_cassette') }
69
+ before(:each) { VCR.should_receive(:record_http_interaction) }
70
+ it_behaves_like "exclusive library hook"
71
+ end
72
+
73
+ context 'for a disallowed request' do
74
+ it_behaves_like "exclusive library hook" do
75
+ undef make_request
76
+ def make_request
77
+ expect {
78
+ connection.in_parallel(parallel_manager) { connection.get(request_url) }
79
+ }.to raise_error(VCR::Errors::UnhandledHTTPRequestError)
80
+ end
81
+ end
82
+ end
83
+
84
+ it_behaves_like "request hooks", :faraday do
85
+ let!(:inserted_cassette) { VCR.insert_cassette('new_cassette') }
86
+
87
+ undef make_request
88
+ def make_request(disabled = false)
89
+ response = nil
90
+ connection.in_parallel(parallel_manager) do
91
+ response = connection.get(request_url)
92
+ end
93
+ response
94
+ end
95
+
96
+ it 'can be used to eject a cassette after the request is recorded' do
97
+ VCR.configuration.after_http_request { |request| VCR.eject_cassette }
98
+
99
+ VCR.should_receive(:record_http_interaction) do |interaction|
100
+ VCR.current_cassette.should be(inserted_cassette)
101
+ end
102
+
103
+ make_request
104
+ VCR.current_cassette.should be_nil
105
+ end
106
+ end
107
+ end if defined?(::Typhoeus)
25
108
  end
@@ -49,6 +49,22 @@ module VCR
49
49
  it_behaves_like "#ignore?", "http://#{host}/foo", false
50
50
  end
51
51
  end
52
+
53
+ context 'when a custom ignore_request hook has been set' do
54
+ before(:each) do
55
+ subject.ignore_request do |request|
56
+ URI(request.uri).port == 5
57
+ end
58
+ end
59
+
60
+ it 'ignores requests for which the block returns true' do
61
+ subject.ignore?(request('http://foo.com:5/bar')).should be_true
62
+ end
63
+
64
+ it 'does not ignore requests for which the block returns false' do
65
+ subject.ignore?(request('http://foo.com:6/bar')).should be_false
66
+ end
67
+ end
52
68
  end
53
69
  end
54
70
 
@@ -168,32 +168,6 @@ module VCR
168
168
  request_with(:uri => 'http://foo2.com/bar?baz=7')
169
169
  ).should be_false
170
170
  end
171
-
172
- it 'does not consider the standard HTTP port' do
173
- subject[:uri].matches?(
174
- request_with(:uri => 'http://foo.com:80/bar?baz=7'),
175
- request_with(:uri => 'http://foo.com/bar?baz=7')
176
- ).should be_true
177
- end
178
-
179
- it 'does not consider the standard HTTPS port' do
180
- subject[:uri].matches?(
181
- request_with(:uri => 'https://foo.com/bar?baz=7'),
182
- request_with(:uri => 'https://foo.com:443/bar?baz=7')
183
- ).should be_true
184
- end
185
-
186
- it 'considers non-standard ports' do
187
- subject[:uri].matches?(
188
- request_with(:uri => 'http://foo.com:79/bar?baz=7'),
189
- request_with(:uri => 'http://foo.com:78/bar?baz=7')
190
- ).should be_false
191
-
192
- subject[:uri].matches?(
193
- request_with(:uri => 'https://foo.com:442/bar?baz=7'),
194
- request_with(:uri => 'https://foo.com:441/bar?baz=7')
195
- ).should be_false
196
- end
197
171
  end
198
172
 
199
173
  describe ":host" do
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+
1
3
  require 'yaml'
2
4
  require 'vcr/structs'
3
5
 
@@ -222,7 +224,7 @@ module VCR
222
224
  end
223
225
 
224
226
  it 'replaces sensitive text in the request URI' do
225
- subject.request.uri.should eq('http://example-AAA.com:80/AAA/')
227
+ subject.request.uri.should eq('http://example-AAA.com/AAA/')
226
228
  end
227
229
  end
228
230
  end
@@ -244,8 +246,59 @@ module VCR
244
246
  m.call.should eq(described_class)
245
247
  end
246
248
  end
249
+
250
+ it 'gets normalized to a lowercase symbol' do
251
+ VCR::Request.new("GET").method.should eq(:get)
252
+ VCR::Request.new(:GET).method.should eq(:get)
253
+ VCR::Request.new(:get).method.should eq(:get)
254
+ VCR::Request.new("get").method.should eq(:get)
255
+ end
256
+ end
257
+
258
+ describe "#uri" do
259
+ def uri_for(uri)
260
+ VCR::Request.new(:get, uri).uri
261
+ end
262
+
263
+ it 'removes the default http port' do
264
+ uri_for("http://foo.com:80/bar").should eq("http://foo.com/bar")
265
+ end
266
+
267
+ it 'removes the default https port' do
268
+ uri_for("https://foo.com:443/bar").should eq("https://foo.com/bar")
269
+ end
270
+
271
+ it 'does not remove a non-standard http port' do
272
+ uri_for("http://foo.com:81/bar").should eq("http://foo.com:81/bar")
273
+ end
274
+
275
+ it 'does not remove a non-standard https port' do
276
+ uri_for("https://foo.com:442/bar").should eq("https://foo.com:442/bar")
277
+ end
247
278
  end
248
279
 
280
+ describe "#fiber_aware" do
281
+ it 'adds a #proceed method that yields in a fiber' do
282
+ fiber = Fiber.new do |request|
283
+ request.proceed
284
+ :done
285
+ end
286
+
287
+ fiber.resume(subject.fiber_aware).should be_nil
288
+ fiber.resume.should eq(:done)
289
+ end
290
+
291
+ it 'can be cast to a proc' do
292
+ request = subject.fiber_aware
293
+ request.should_receive(:proceed)
294
+ lambda(&request).call
295
+ end
296
+
297
+ it 'returns the request' do
298
+ subject.fiber_aware.should be(subject)
299
+ end
300
+ end if RUBY_VERSION > '1.9'
301
+
249
302
  it_behaves_like 'a header normalizer' do
250
303
  def with_headers(headers)
251
304
  described_class.new(:get, 'http://example.com/', nil, headers)
@@ -301,6 +354,13 @@ module VCR
301
354
  inst.update_content_length_header
302
355
  }.to change { inst.headers[header] }.from(['3']).to(['0'])
303
356
  end
357
+
358
+ it 'sets the header according to RFC 2616 based on the number of bytes (not the number of characters)' do
359
+ inst = instance('aؼ', '2') # the second char is a double byte char
360
+ expect {
361
+ inst.update_content_length_header
362
+ }.to change { inst.headers[header] }.from(['2']).to(['3'])
363
+ end
304
364
  end
305
365
  end
306
366
  end
@@ -1,5 +1,37 @@
1
1
  require 'spec_helper'
2
2
 
3
+ RSpec.configure do |config|
4
+ config.before(:suite) do
5
+ VCR.configuration.configure_rspec_metadata!
6
+ end
7
+ end
8
+
9
+ describe VCR::RSpec::Metadata, :skip_vcr_reset do
10
+ before(:all) { VCR.reset! }
11
+ after(:each) { VCR.reset! }
12
+
13
+ context 'an example group', :vcr do
14
+ context 'with a nested example group' do
15
+ it 'uses a cassette for any examples' do
16
+ VCR.current_cassette.name.split('/').should eq([
17
+ 'VCR::RSpec::Metadata',
18
+ 'an example group',
19
+ 'with a nested example group',
20
+ 'uses a cassette for any examples'
21
+ ])
22
+ end
23
+ end
24
+ end
25
+
26
+ it 'allows the cassette name to be overriden', :vcr => { :cassette_name => 'foo' } do
27
+ VCR.current_cassette.name.should eq('foo')
28
+ end
29
+
30
+ it 'allows the cassette options to be set', :vcr => { :match_requests_on => [:method] } do
31
+ VCR.current_cassette.match_requests_on.should eq([:method])
32
+ end
33
+ end
34
+
3
35
  describe VCR::RSpec::Macros do
4
36
  extend described_class
5
37
 
@@ -17,76 +17,86 @@ describe VCR::Hooks do
17
17
  it 'clears all hooks' do
18
18
  subject.before_foo { invocations << :callback }
19
19
  subject.clear_hooks
20
- subject.invoke_hook(:before_foo, nil)
20
+ subject.invoke_hook(:before_foo)
21
21
  invocations.should be_empty
22
22
  end
23
23
  end
24
24
 
25
25
  describe '#invoke_hook(:before_foo)' do
26
- context 'with a tag argument' do
27
- it 'invokes each of the :before_foo callbacks with a matching tag' do
28
- subject.before_foo(:green) { invocations << :callback_1 }
29
- subject.before_foo(:green) { invocations << :callback_2 }
30
-
31
- invocations.should be_empty
32
- subject.invoke_hook(:before_foo, :green)
33
- invocations.should eq([:callback_1, :callback_2])
34
- end
35
-
36
- it 'invokes each of the :before_foo callbacks with no tag' do
37
- subject.before_foo { invocations << :no_tag_1 }
38
- subject.before_foo { invocations << :no_tag_2 }
39
-
40
- subject.invoke_hook(:before_foo, :green)
41
- invocations.should eq([:no_tag_1, :no_tag_2])
42
- end
43
-
44
- it 'does not invoke any callbacks with a different tag' do
45
- subject.before_foo(:blue) { invocations << :blue_callback }
46
- subject.invoke_hook(:before_foo, :green)
47
- invocations.should be_empty
48
- end
26
+ it 'maps the return value of each callback' do
27
+ subject.before_foo { 17 }
28
+ subject.before_foo { 12 }
29
+ subject.invoke_hook(:before_foo).should eq([17, 12])
49
30
  end
50
31
 
51
- context 'without a tag argument' do
52
- it 'invokes each of the :before_foo callbacks' do
53
- subject.before_foo { invocations << :callback_1 }
54
- subject.before_foo { invocations << :callback_2 }
55
-
56
- invocations.should be_empty
57
- subject.invoke_hook(:before_foo, nil)
58
- invocations.should eq([:callback_1, :callback_2])
59
- end
60
-
61
- it 'does not invoke :before_bar callbacks' do
62
- subject.before_bar { invocations << :bar_callback }
63
- subject.invoke_hook(:before_foo, nil)
64
- invocations.should be_empty
65
- end
66
-
67
- it 'does not invoke any tagged callbacks' do
68
- subject.before_foo(:blue) { invocations << :blue_callback }
69
- subject.invoke_hook(:before_foo, nil)
70
- invocations.should be_empty
71
- end
72
-
73
- it 'passes along the provided arguments to the callback' do
74
- subject.before_foo(&lambda { |a, b| invocations << [a, b] })
75
- subject.invoke_hook(:before_foo, nil, :arg1, :arg2)
76
- invocations.flatten.should eq([:arg1, :arg2])
77
- end
78
-
79
- it 'only passes along 1 argument when the block accepts only 1 arguments' do
80
- subject.before_foo(&lambda { |a| invocations << a })
81
- subject.invoke_hook(:before_foo, nil, :arg1, :arg2)
82
- invocations.flatten.should eq([:arg1])
83
- end
84
-
85
- it 'passes along all arguments when the block accepts a variable number of args' do
86
- subject.before_foo(&lambda { |*a| invocations << a })
87
- subject.invoke_hook(:before_foo, nil, :arg1, :arg2)
88
- invocations.flatten.should eq([:arg1, :arg2])
89
- end
32
+ it 'invokes each of the :before_foo callbacks' do
33
+ subject.before_foo { invocations << :callback_1 }
34
+ subject.before_foo { invocations << :callback_2 }
35
+
36
+ invocations.should be_empty
37
+ subject.invoke_hook(:before_foo)
38
+ invocations.should eq([:callback_1, :callback_2])
39
+ end
40
+
41
+ it 'does not invoke :before_bar callbacks' do
42
+ subject.before_bar { invocations << :bar_callback }
43
+ subject.invoke_hook(:before_foo)
44
+ invocations.should be_empty
45
+ end
46
+
47
+ it 'does not invoke any tagged callbacks' do
48
+ subject.before_foo(:blue) { invocations << :blue_callback }
49
+ subject.invoke_hook(:before_foo)
50
+ invocations.should be_empty
51
+ end
52
+
53
+ it 'passes along the provided arguments to the callback' do
54
+ subject.before_foo(&lambda { |a, b| invocations << [a, b] })
55
+ subject.invoke_hook(:before_foo, :arg1, :arg2)
56
+ invocations.flatten.should eq([:arg1, :arg2])
57
+ end
58
+
59
+ it 'only passes along 1 argument when the block accepts only 1 arguments' do
60
+ subject.before_foo(&lambda { |a| invocations << a })
61
+ subject.invoke_hook(:before_foo, :arg1, :arg2)
62
+ invocations.flatten.should eq([:arg1])
63
+ end
64
+
65
+ it 'passes along all arguments when the block accepts a variable number of args' do
66
+ subject.before_foo(&lambda { |*a| invocations << a })
67
+ subject.invoke_hook(:before_foo, :arg1, :arg2)
68
+ invocations.flatten.should eq([:arg1, :arg2])
69
+ end
70
+ end
71
+
72
+ describe "#invoke_tagged_hook(:before_foo, tag)" do
73
+ it 'invokes each of the :before_foo callbacks with a matching tag' do
74
+ subject.before_foo(:green) { invocations << :callback_1 }
75
+ subject.before_foo(:green) { invocations << :callback_2 }
76
+
77
+ invocations.should be_empty
78
+ subject.invoke_tagged_hook(:before_foo, :green)
79
+ invocations.should eq([:callback_1, :callback_2])
80
+ end
81
+
82
+ it 'invokes each of the :before_foo callbacks with no tag' do
83
+ subject.before_foo { invocations << :no_tag_1 }
84
+ subject.before_foo { invocations << :no_tag_2 }
85
+
86
+ subject.invoke_hook(:before_foo, :green)
87
+ invocations.should eq([:no_tag_1, :no_tag_2])
88
+ end
89
+
90
+ it 'does not invoke any callbacks with a different tag' do
91
+ subject.before_foo(:blue) { invocations << :blue_callback }
92
+ subject.invoke_tagged_hook(:before_foo, :green)
93
+ invocations.should be_empty
94
+ end
95
+
96
+ it 'passes along the provided arguments to the callback' do
97
+ subject.before_foo(:green, &lambda { |a, b| invocations << [a, b] })
98
+ subject.invoke_tagged_hook(:before_foo, :green, :arg1, :arg2)
99
+ invocations.flatten.should eq([:arg1, :arg2])
90
100
  end
91
101
  end
92
102
  end