Skip to content

Commit a9166f4

Browse files
committed
Introduce ChildConfiguration to point to global configuration
This should solve issues where hooks that were added via OpenapiFirst::Test have not been called
1 parent 88a1c1f commit a9166f4

10 files changed

Lines changed: 70 additions & 29 deletions

File tree

lib/openapi_first.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
require_relative 'openapi_first/errors'
66
require_relative 'openapi_first/registry'
77
require_relative 'openapi_first/configuration'
8+
require_relative 'openapi_first/child_configuration'
89
require_relative 'openapi_first/definition'
910
require_relative 'openapi_first/version'
1011
require_relative 'openapi_first/middlewares/response_validation'
@@ -29,7 +30,8 @@ def self.configuration
2930
# @return [Configuration]
3031
# @yield [Configuration]
3132
def self.configure
32-
yield configuration
33+
@configuration = Configuration.new
34+
yield @configuration if block_given?
3335
end
3436

3537
ERROR_RESPONSES = {} # rubocop:disable Style/MutableConstant

lib/openapi_first/builder.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def build_parameter_schema(parameters)
125125
end
126126

127127
Schema::Hash.new(schemas, required:, configuration: schemer_configuration,
128-
after_property_validation: config.hooks[:after_request_parameter_property_validation])
128+
after_property_validation: config.after_request_parameter_property_validation)
129129
end
130130

131131
def build_requests(path:, request_method:, operation_object:, parameters:)
@@ -139,7 +139,7 @@ def build_requests(path:, request_method:, operation_object:, parameters:)
139139
content_objects.map do |content_type, content_object|
140140
content_schema = content_object['schema'].schema(
141141
configuration: schemer_configuration,
142-
after_property_validation: config.hooks[:after_request_body_property_validation]
142+
after_property_validation: config.after_request_body_property_validation
143143
)
144144
Request.new(path:, request_method:, parameters:,
145145
operation_object: operation_object.resolved,
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# frozen_string_literal: true
2+
3+
module OpenapiFirst
4+
# A subclass to configuration that points to its parent
5+
class ChildConfiguration < Configuration
6+
def initialize(parent:)
7+
super()
8+
@parent = parent
9+
@request_validation_error_response = parent.request_validation_error_response
10+
@request_validation_raise_error = parent.request_validation_raise_error
11+
@response_validation_raise_error = parent.response_validation_raise_error
12+
@path = parent.path
13+
end
14+
15+
private attr_reader :parent
16+
17+
HOOKS.each do |hook|
18+
define_method(hook) do |&block|
19+
return hooks[hook].chain(parent.hooks[hook]) if block.nil?
20+
21+
hooks[hook] << block
22+
block
23+
end
24+
end
25+
end
26+
end

lib/openapi_first/configuration.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ def register(path_or_definition, as: :default)
2525
attr_reader :request_validation_error_response, :hooks
2626
attr_accessor :request_validation_raise_error, :response_validation_raise_error, :path
2727

28-
def clone
29-
copy = super
30-
copy.instance_variable_set(:@hooks, @hooks&.transform_values(&:clone))
31-
copy
28+
def child
29+
ChildConfiguration.new(parent: self)
3230
end
3331

3432
HOOKS.each do |hook|
3533
define_method(hook) do |&block|
34+
return hooks[hook] if block.nil?
35+
3636
hooks[hook] << block
3737
block
3838
end

lib/openapi_first/definition.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def validate_request(request, raise_error: false)
7373
else
7474
route.request_definition.validate(request, route_params: route.params)
7575
end.tap do |validated|
76-
@config.hooks[:after_request_validation].each { |hook| hook.call(validated, self) }
76+
@config.after_request_validation.each { |hook| hook.call(validated, self) }
7777
raise validated.error.exception(validated) if validated.error && raise_error
7878
end
7979
end
@@ -95,7 +95,7 @@ def validate_response(rack_request, rack_response, raise_error: false)
9595
else
9696
response_match.response.validate(rack_response)
9797
end
98-
@config.hooks[:after_response_validation]&.each { |hook| hook.call(validated, rack_request, self) }
98+
@config.after_response_validation&.each { |hook| hook.call(validated, rack_request, self) }
9999
raise validated.error.exception(validated) if raise_error && validated.invalid?
100100

101101
validated

lib/openapi_first/test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,8 @@ def self.raise_response_error?(invalid_response)
130130

131131
def self.uninstall
132132
configuration = OpenapiFirst.configuration
133-
configuration.hooks[:after_request_validation].delete(@after_request_validation)
134-
configuration.hooks[:after_response_validation].delete(@after_response_validation)
133+
configuration.after_request_validation.delete(@after_request_validation)
134+
configuration.after_response_validation.delete(@after_response_validation)
135135
definitions.clear
136136
@configuration = nil
137137
@installed = nil

spec/configuration_spec.rb

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
# frozen_string_literal: true
22

33
RSpec.describe OpenapiFirst::Configuration do
4-
describe '#after' do
4+
describe '#after_...' do
55
it 'adds a hook' do
66
config = OpenapiFirst::Configuration.new
77
called = []
88
config.after_request_validation do |request|
99
called << request
1010
end
1111

12-
config.hooks[:after_request_validation].each { |hook| hook.call('request') }
12+
config.after_request_validation.each { |hook| hook.call('request') }
1313
expect(called).to eq(%w[request])
1414
end
1515

@@ -18,7 +18,7 @@
1818
config.after_request_validation { _1 }
1919
config.after_request_validation { _1 }
2020

21-
expect(config.hooks[:after_request_validation].size).to eq(2)
21+
expect(config.after_request_validation.size).to eq(2)
2222
end
2323
end
2424

@@ -54,22 +54,34 @@
5454
end
5555
end
5656

57-
describe '#clone' do
57+
describe '#child' do
5858
it 'clones actions' do
5959
config = OpenapiFirst::Configuration.new
6060
config.after_request_validation { |request| request }
61-
expect(config.hooks[:after_request_validation].size).to eq(1)
62-
cloned = config.clone
61+
expect(config.after_request_validation.size).to eq(1)
62+
cloned = config.child
6363
cloned.after_request_validation { |request| request }
64-
expect(cloned.hooks[:after_request_validation].size).to eq(2)
65-
expect(config.hooks[:after_request_validation].size).to eq(1)
64+
expect(cloned.after_request_validation.size).to eq(2)
65+
expect(config.after_request_validation.size).to eq(1)
6666
end
6767

6868
it 'clones empty configs' do
6969
config = OpenapiFirst::Configuration.new
70-
expect(config.hooks.values.all?(&:empty?)).to be(true)
71-
cloned = config.clone
72-
expect(cloned.hooks.values.all?(&:empty?)).to be(true)
70+
expect(config.after_request_validation.to_a).to be_empty
71+
cloned = config.child
72+
expect(cloned.after_request_validation.to_a).to be_empty
73+
end
74+
75+
it 'allows adding hooks to the parent config after cloning' do
76+
parent = OpenapiFirst::Configuration.new
77+
parent.after_request_validation { |request| request }
78+
79+
child = parent.child
80+
81+
expect(child.after_request_validation.size).to eq(1)
82+
parent.after_request_validation { |request| request }
83+
expect(parent.after_request_validation.size).to eq(2)
84+
expect(child.after_request_validation.size).to eq(2)
7385
end
7486
end
7587
end

spec/hooks_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def build_request(path, method: 'GET', body: nil)
1616
config.after_request_validation(&myproc)
1717
end
1818
definition.validate_request(build_request('/pets?limit=24'))
19-
definition.config.hooks[:after_request_validation].delete(myproc)
19+
definition.config.after_request_validation.delete(myproc)
2020
definition.validate_request(build_request('/pets?limit=24'))
2121

2222
expect(called).to eq([['listPets', true]])

spec/spec_helper.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
end
2929

3030
config.after(:each) do
31+
OpenapiFirst.configure
3132
OpenapiFirst::Test.definitions.clear
3233
OpenapiFirst.definitions.clear
3334
OpenapiFirst::Test.uninstall

spec/test_spec.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -379,17 +379,17 @@ def call(_env)
379379
it 'installs global hooks' do
380380
described_class.install
381381

382-
hooks = OpenapiFirst.configuration.hooks
383-
expect(hooks[:after_request_validation]).not_to be_empty
384-
expect(hooks[:after_response_validation]).not_to be_empty
382+
config = OpenapiFirst.configuration
383+
expect(config.after_request_validation).not_to be_empty
384+
expect(config.after_response_validation).not_to be_empty
385385
end
386386

387387
it 'does not install hooks multiple times' do
388388
2.times { described_class.install }
389389

390-
hooks = OpenapiFirst.configuration.hooks
391-
expect(hooks[:after_request_validation].count).to eq(1)
392-
expect(hooks[:after_response_validation].count).to eq(1)
390+
config = OpenapiFirst.configuration
391+
expect(config.after_request_validation.count).to eq(1)
392+
expect(config.after_response_validation.count).to eq(1)
393393
end
394394
end
395395

0 commit comments

Comments
 (0)