stub_requests 0.1.1 → 0.1.2
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.
- checksums.yaml +4 -4
- data/.gitignore +5 -2
- data/.reek.yml +1 -0
- data/.rubocop.yml +33 -35
- data/.simplecov +14 -8
- data/.yardopts +1 -1
- data/CHANGELOG.md +4 -1
- data/README.md +19 -11
- data/Rakefile +1 -3
- data/bin/update_docs.sh +16 -0
- data/gemfiles/webmock_2.3.gemfile.lock +1 -1
- data/gemfiles/webmock_3.5.gemfile.lock +1 -1
- data/gemfiles/webmock_develop.gemfile.lock +1 -1
- data/lib/rspec/subject_as_lambda.rb +138 -0
- data/lib/stub_requests/api.rb +42 -8
- data/lib/stub_requests/argument_validation.rb +17 -6
- data/lib/stub_requests/configuration.rb +21 -0
- data/lib/stub_requests/core_ext/all.rb +4 -0
- data/lib/stub_requests/core_ext/array/extract_options.rb +32 -0
- data/lib/stub_requests/core_ext/class/attribute.rb +61 -0
- data/lib/stub_requests/core_ext/kernel/singleton_class.rb +12 -0
- data/lib/stub_requests/core_ext/module/redefine_method.rb +44 -0
- data/lib/stub_requests/core_ext/object/blank.rb +99 -155
- data/lib/stub_requests/endpoint.rb +28 -30
- data/lib/stub_requests/endpoint_registry.rb +18 -16
- data/lib/stub_requests/exceptions.rb +84 -0
- data/lib/stub_requests/hash_util.rb +2 -0
- data/lib/stub_requests/metrics/endpoint_stat.rb +97 -0
- data/lib/stub_requests/metrics/registry.rb +132 -0
- data/lib/stub_requests/metrics/stub_stat.rb +80 -0
- data/lib/stub_requests/metrics.rb +32 -0
- data/lib/stub_requests/property/validator.rb +136 -0
- data/lib/stub_requests/property.rb +99 -0
- data/lib/stub_requests/service.rb +12 -53
- data/lib/stub_requests/service_registry.rb +8 -9
- data/lib/stub_requests/stub_requests.rb +23 -51
- data/lib/stub_requests/uri/builder.rb +5 -1
- data/lib/stub_requests/uri/scheme.rb +3 -1
- data/lib/stub_requests/uri/suffix.rb +5 -0
- data/lib/stub_requests/uri/validator.rb +3 -1
- data/lib/stub_requests/uri.rb +34 -0
- data/lib/stub_requests/version.rb +1 -1
- data/lib/stub_requests/webmock/builder.rb +116 -0
- data/lib/stub_requests/webmock/stub_registry_extension.rb +46 -0
- data/lib/stub_requests.rb +21 -3
- metadata +19 -49
- data/docs/.gitkeep +0 -0
- data/docs/Array.html +0 -137
- data/docs/FalseClass.html +0 -232
- data/docs/Hash.html +0 -137
- data/docs/NilClass.html +0 -232
- data/docs/Numeric.html +0 -233
- data/docs/Object.html +0 -396
- data/docs/String.html +0 -298
- data/docs/StubRequests/API.html +0 -651
- data/docs/StubRequests/ArgumentValidation.html +0 -309
- data/docs/StubRequests/Endpoint.html +0 -1187
- data/docs/StubRequests/EndpointNotFound.html +0 -157
- data/docs/StubRequests/EndpointRegistry.html +0 -1527
- data/docs/StubRequests/Error.html +0 -153
- data/docs/StubRequests/HashUtil.html +0 -304
- data/docs/StubRequests/InvalidType.html +0 -252
- data/docs/StubRequests/InvalidUri.html +0 -252
- data/docs/StubRequests/Service.html +0 -1307
- data/docs/StubRequests/ServiceHaveEndpoints.html +0 -244
- data/docs/StubRequests/ServiceNotFound.html +0 -252
- data/docs/StubRequests/ServiceRegistry.html +0 -1031
- data/docs/StubRequests/URI/Builder.html +0 -1194
- data/docs/StubRequests/URI/Scheme.html +0 -315
- data/docs/StubRequests/URI/Suffix.html +0 -315
- data/docs/StubRequests/URI/Validator.html +0 -770
- data/docs/StubRequests/URI.html +0 -144
- data/docs/StubRequests/UriSegmentMismatch.html +0 -157
- data/docs/StubRequests/WebMockBuilder.html +0 -887
- data/docs/StubRequests.html +0 -452
- data/docs/Time.html +0 -232
- data/docs/TrueClass.html +0 -232
- data/docs/_config.yml +0 -1
- data/docs/_index.html +0 -391
- data/docs/class_list.html +0 -51
- data/docs/css/common.css +0 -1
- data/docs/css/full_list.css +0 -58
- data/docs/css/style.css +0 -496
- data/docs/file.README.html +0 -225
- data/docs/file_list.html +0 -56
- data/docs/frames.html +0 -17
- data/docs/index.html +0 -225
- data/docs/js/app.js +0 -292
- data/docs/js/full_list.js +0 -216
- data/docs/js/jquery.js +0 -4
- data/docs/method_list.html +0 -707
- data/docs/top-level-namespace.html +0 -112
- data/lib/stub_requests/webmock_builder.rb +0 -108
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Abstraction over WebMock to reduce duplication
|
5
|
+
#
|
6
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
7
|
+
# @since 0.1.0
|
8
|
+
#
|
9
|
+
module StubRequests
|
10
|
+
#
|
11
|
+
# Module Metrics contains logic for collecting metrics about {EndpointStat} and {StubStat}
|
12
|
+
#
|
13
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
14
|
+
# @since 0.1.2
|
15
|
+
#
|
16
|
+
# :reek:TooManyInstanceVariables
|
17
|
+
module Metrics
|
18
|
+
#
|
19
|
+
# Class EndpointStat provides metrics for stubbed endpoints
|
20
|
+
#
|
21
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
22
|
+
# @since 0.1.2
|
23
|
+
#
|
24
|
+
class EndpointStat
|
25
|
+
# includes "Enumerable"
|
26
|
+
# @!parse include Enumerable
|
27
|
+
include Enumerable
|
28
|
+
|
29
|
+
# @api private
|
30
|
+
include Property
|
31
|
+
|
32
|
+
#
|
33
|
+
# @!attribute [r] service_id
|
34
|
+
# @return [Symbol] the id of a {Service}
|
35
|
+
property :service_id, type: Symbol
|
36
|
+
#
|
37
|
+
# @!attribute [r] endpoint_id
|
38
|
+
# @return [Symbol] the id of an endpoint
|
39
|
+
property :endpoint_id, type: Symbol
|
40
|
+
#
|
41
|
+
# @!attribute [r] verb
|
42
|
+
# @return [String] the HTTP verb/method for this endpoint
|
43
|
+
property :verb, type: Symbol
|
44
|
+
#
|
45
|
+
# @!attribute [r] uri_template
|
46
|
+
# @return [String] the full URI template for the endpoint
|
47
|
+
property :uri_template, type: Symbol
|
48
|
+
#
|
49
|
+
# @!attribute [r] stats
|
50
|
+
# @return [Array] an array with recorded request_stubs
|
51
|
+
attr_reader :stats
|
52
|
+
|
53
|
+
#
|
54
|
+
# Initializes a new EndpointStat
|
55
|
+
#
|
56
|
+
# @param [Service] service a service
|
57
|
+
# @param [Endpoint] endpoint an endpoint
|
58
|
+
#
|
59
|
+
def initialize(service, endpoint)
|
60
|
+
@service_id = service.id
|
61
|
+
@endpoint_id = endpoint.id
|
62
|
+
@verb = endpoint.verb
|
63
|
+
@uri_template = [service.uri, endpoint.uri_template].join("/")
|
64
|
+
@stats = Concurrent::Array.new
|
65
|
+
end
|
66
|
+
|
67
|
+
def find_by(attribute:, value:)
|
68
|
+
find { |stat| stat.send(attribute) == value }
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# Required by Enumerable
|
73
|
+
#
|
74
|
+
#
|
75
|
+
# @return [Concurrent::Map<Symbol, Service>] an map with services
|
76
|
+
#
|
77
|
+
# @yield used by Enumerable
|
78
|
+
#
|
79
|
+
def each(&block)
|
80
|
+
stats.each(&block)
|
81
|
+
end
|
82
|
+
|
83
|
+
#
|
84
|
+
# Records a WebMock::RequestStub as stubbed
|
85
|
+
#
|
86
|
+
# @param [WebMock::RequestStub] request_stub <description>
|
87
|
+
#
|
88
|
+
# @return [Record]
|
89
|
+
#
|
90
|
+
def record(request_stub)
|
91
|
+
stat = StubStat.new(self, request_stub)
|
92
|
+
stats.push(stat)
|
93
|
+
stat
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Abstraction over WebMock to reduce duplication
|
5
|
+
#
|
6
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
7
|
+
# @since 0.1.0
|
8
|
+
#
|
9
|
+
module StubRequests
|
10
|
+
#
|
11
|
+
# Module Metrics contains logic for collecting metrics about {EndpointStat} and {StubStat}
|
12
|
+
#
|
13
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
14
|
+
# @since 0.1.2
|
15
|
+
#
|
16
|
+
# :reek:DataClump
|
17
|
+
module Metrics
|
18
|
+
#
|
19
|
+
# Class Registry maintains a registry of stubbed endpoints.
|
20
|
+
# Also allows provides querying capabilities for said entities.
|
21
|
+
#
|
22
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
23
|
+
# @since 0.1.2
|
24
|
+
#
|
25
|
+
class Registry
|
26
|
+
# includes "Singleton"
|
27
|
+
# @!parse include Singleton
|
28
|
+
include Singleton
|
29
|
+
# includes "Enumerable"
|
30
|
+
# @!parse include Enumerable
|
31
|
+
include Enumerable
|
32
|
+
|
33
|
+
#
|
34
|
+
# @!attribute [rw] services
|
35
|
+
# @return [Concurrent::Array<EndpointStat>] a map with stubbed endpoints
|
36
|
+
attr_reader :stats
|
37
|
+
|
38
|
+
#
|
39
|
+
# Initialize a new registry
|
40
|
+
#
|
41
|
+
#
|
42
|
+
def initialize
|
43
|
+
@stats = Concurrent::Array.new
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# Resets the map with stubbed endpoints
|
48
|
+
#
|
49
|
+
#
|
50
|
+
# @api private
|
51
|
+
def reset
|
52
|
+
stats.clear
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Required by Enumerable
|
57
|
+
#
|
58
|
+
#
|
59
|
+
# @return [Concurrent::Array<EndpointStat>] an array with stubbed endpoints
|
60
|
+
#
|
61
|
+
# @yield used by Enumerable
|
62
|
+
#
|
63
|
+
def each(&block)
|
64
|
+
stats.each(&block)
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# Records metrics about stubbed endpoints
|
69
|
+
#
|
70
|
+
#
|
71
|
+
# @param [Service] service a symbolic id of the service
|
72
|
+
# @param [Endpoint] endpoint a string with a base_uri to the service
|
73
|
+
# @param [WebMock::RequestStub] request_stub the stubbed request
|
74
|
+
#
|
75
|
+
# @return [Service] the service that was just registered
|
76
|
+
#
|
77
|
+
def record(service, endpoint, request_stub)
|
78
|
+
stat = find_or_initialize_stat(service, endpoint)
|
79
|
+
stat.record(request_stub)
|
80
|
+
|
81
|
+
stats.push(stat)
|
82
|
+
stat
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
# Mark a {StubStat} as having responded
|
87
|
+
#
|
88
|
+
# @note Called when webmock responds successfully
|
89
|
+
#
|
90
|
+
# @param [WebMock::RequestStub] request_stub the stubbed webmock request
|
91
|
+
#
|
92
|
+
# @return [void]
|
93
|
+
#
|
94
|
+
def mark_as_responded(request_stub)
|
95
|
+
return unless (stat = find_stub_stat(request_stub))
|
96
|
+
|
97
|
+
stat.mark_as_responded
|
98
|
+
end
|
99
|
+
|
100
|
+
#
|
101
|
+
# Finds a {StubStat} amongst the endpoint stubs
|
102
|
+
#
|
103
|
+
#
|
104
|
+
# @param [WebMock::RequestStub] request_stub a stubbed webmock response
|
105
|
+
#
|
106
|
+
# @return [StubStat] the stub_stat matching the request stub
|
107
|
+
#
|
108
|
+
def find_stub_stat(request_stub)
|
109
|
+
map do |endpoint|
|
110
|
+
endpoint.find_by(attribute: :request_stub, value: request_stub)
|
111
|
+
end.compact.first
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def find_or_initialize_stat(service, endpoint)
|
117
|
+
find_stat(service, endpoint) || initialize_stat(service, endpoint)
|
118
|
+
end
|
119
|
+
|
120
|
+
# :reek:UtilityFunction
|
121
|
+
# :reek:FeatureEnvy
|
122
|
+
def find_stat(service, endpoint)
|
123
|
+
find { |stat| stat.service_id == service.id && stat.endpoint_id == endpoint.id }
|
124
|
+
end
|
125
|
+
|
126
|
+
# :reek:UtilityFunction
|
127
|
+
def initialize_stat(service, endpoint)
|
128
|
+
Metrics::EndpointStat.new(service, endpoint)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Abstraction over WebMock to reduce duplication
|
5
|
+
#
|
6
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
7
|
+
# @since 0.1.0
|
8
|
+
#
|
9
|
+
module StubRequests
|
10
|
+
#
|
11
|
+
# Module Metrics contains logic for collecting metrics about {EndpointStat} and {StubStat}
|
12
|
+
#
|
13
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
14
|
+
# @since 0.1.2
|
15
|
+
#
|
16
|
+
module Metrics
|
17
|
+
#
|
18
|
+
# Class StubStat tracks the WebMock::RequestStub life cycle
|
19
|
+
#
|
20
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
21
|
+
# @since 0.1.2
|
22
|
+
#
|
23
|
+
# :reek:TooManyInstanceVariables
|
24
|
+
class StubStat
|
25
|
+
include Property
|
26
|
+
#
|
27
|
+
# @!attribute [r] verb
|
28
|
+
# @return [Symbol] a HTTP verb/method
|
29
|
+
property :verb, type: Symbol
|
30
|
+
#
|
31
|
+
# @!attribute [r] uri
|
32
|
+
# @return [String] the full URI for this endpoint
|
33
|
+
property :uri, type: String
|
34
|
+
#
|
35
|
+
# @!attribute [r] request_stub
|
36
|
+
# @return [WebMock::RequestStub] a webmock stubbed request
|
37
|
+
property :request_stub, type: WebMock::RequestStub
|
38
|
+
#
|
39
|
+
# @!attribute [r] recorded_at
|
40
|
+
# @return [Time] the time this record was recorded
|
41
|
+
property :recorded_at, type: Time
|
42
|
+
#
|
43
|
+
# @!attribute [r] recorded_from
|
44
|
+
# @return [String] the relative path to the spec that recorded it
|
45
|
+
property :recorded_from, type: String
|
46
|
+
#
|
47
|
+
# @!attribute [r] responded_at
|
48
|
+
# @return [Time] the time this stubs response was used
|
49
|
+
property :responded_at, type: Time
|
50
|
+
|
51
|
+
#
|
52
|
+
# Initialize a new Record
|
53
|
+
#
|
54
|
+
#
|
55
|
+
# @param [EndpointStat] endpoint_stat a stubbed endpoint
|
56
|
+
# @param [WebMock::RequestStub] request_stub the stubbed webmock request
|
57
|
+
#
|
58
|
+
def initialize(endpoint_stat, request_stub)
|
59
|
+
request_pattern = request_stub.request_pattern
|
60
|
+
@endpoint_stat = endpoint_stat
|
61
|
+
@verb = request_pattern.method_pattern.to_s.to_sym
|
62
|
+
@uri = request_pattern.uri_pattern.to_s
|
63
|
+
@request_stub = request_stub
|
64
|
+
@recorded_at = Time.now
|
65
|
+
@recorded_from = RSpec.current_example.metadata[:location]
|
66
|
+
@responded_at = nil
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
# Marks this record as having responded
|
71
|
+
#
|
72
|
+
#
|
73
|
+
# @return [Time] the time it was marked responded
|
74
|
+
#
|
75
|
+
def mark_as_responded
|
76
|
+
@responded_at = Time.now
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Abstraction over WebMock to reduce duplication
|
5
|
+
#
|
6
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
7
|
+
# @since 0.1.0
|
8
|
+
#
|
9
|
+
module StubRequests
|
10
|
+
#
|
11
|
+
# Module Metrics contains logic for collecting metrics about {EndpointStat} and {StubStat}
|
12
|
+
#
|
13
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
14
|
+
# @since 0.1.2
|
15
|
+
#
|
16
|
+
module Metrics
|
17
|
+
#
|
18
|
+
# Records metrics about stubbed endpoints
|
19
|
+
#
|
20
|
+
# @param [Service] service a Service
|
21
|
+
# @param [Endpoint] endpoint an Endpoint
|
22
|
+
# @param [WebMock::RequestStub] endpoint_stub the stubbed webmock request
|
23
|
+
#
|
24
|
+
# @return [EndpointStat] the stat that was recorded
|
25
|
+
#
|
26
|
+
def self.record(service, endpoint, endpoint_stub)
|
27
|
+
return unless StubRequests.config.record_metrics?
|
28
|
+
|
29
|
+
Registry.instance.record(service, endpoint, endpoint_stub)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Abstraction over WebMock to reduce duplication
|
5
|
+
#
|
6
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
7
|
+
# @since 0.1.0
|
8
|
+
#
|
9
|
+
module StubRequests
|
10
|
+
#
|
11
|
+
# Module Property provides type checked attribute definition with default value
|
12
|
+
#
|
13
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
14
|
+
# @since 0.1.2
|
15
|
+
#
|
16
|
+
module Property
|
17
|
+
#
|
18
|
+
# Class Validator provides validation for adding properties
|
19
|
+
#
|
20
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
21
|
+
# @since 0.1.2
|
22
|
+
#
|
23
|
+
class Validator
|
24
|
+
include ArgumentValidation
|
25
|
+
|
26
|
+
#
|
27
|
+
# Validates that the property can be added to the class
|
28
|
+
#
|
29
|
+
#
|
30
|
+
# @param [Symbol] name the name of the property
|
31
|
+
# @param [Class, Module] type the type of the property
|
32
|
+
# @param [Object] default the default value of the property
|
33
|
+
# @param [Hash] properties the list of currently defined properties
|
34
|
+
#
|
35
|
+
# @raise [InvalidArgumentType] when name is not a Symbol
|
36
|
+
# @raise [InvalidArgumentType] when default does not match type
|
37
|
+
# @raise [PropertyDefined] when property has already been defined
|
38
|
+
#
|
39
|
+
# @return [void]
|
40
|
+
#
|
41
|
+
# :reek:LongParameterList
|
42
|
+
def self.call(name, type, default, properties)
|
43
|
+
new(name, type, default, properties).run_validations
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# @!attribute [r] name
|
48
|
+
# @return [Symbol] the name of the property
|
49
|
+
attr_reader :name
|
50
|
+
#
|
51
|
+
# @!attribute [r] type
|
52
|
+
# @return [Class, Module] the type of the property
|
53
|
+
attr_reader :type
|
54
|
+
#
|
55
|
+
# @!attribute [r] default
|
56
|
+
# @return [Object] the default value of the property
|
57
|
+
attr_reader :default
|
58
|
+
#
|
59
|
+
# @!attribute [r] properties
|
60
|
+
# @return [Hash] the list of currently defined properties
|
61
|
+
attr_reader :properties
|
62
|
+
|
63
|
+
# Initializes a new {Validator}
|
64
|
+
#
|
65
|
+
# @param [Symbol] name the name of the property
|
66
|
+
# @param [Class, Module] type the type of the property
|
67
|
+
# @param [Object] default the default value of the property
|
68
|
+
# @param [Hash] properties the list of currently defined properties
|
69
|
+
#
|
70
|
+
# :reek:LongParameterList
|
71
|
+
def initialize(name, type, default, properties)
|
72
|
+
@name = name
|
73
|
+
@type = Array(type).flatten
|
74
|
+
@default = default
|
75
|
+
@properties = properties
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Performs all validations
|
80
|
+
#
|
81
|
+
#
|
82
|
+
# @raise [InvalidArgumentType] when name is not a Symbol
|
83
|
+
# @raise [InvalidArgumentType] when default does not match type
|
84
|
+
# @raise [PropertyDefined] when property has already been defined
|
85
|
+
#
|
86
|
+
# @return [void]
|
87
|
+
#
|
88
|
+
def run_validations
|
89
|
+
validate_undefined
|
90
|
+
validate_name
|
91
|
+
validate_default
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
#
|
97
|
+
# Validates that the name is of type Symbol
|
98
|
+
#
|
99
|
+
# @raise [InvalidArgumentType] when name is not a Symbol
|
100
|
+
#
|
101
|
+
# @return [void]
|
102
|
+
#
|
103
|
+
def validate_name
|
104
|
+
validate! :name, name, is_a: Symbol
|
105
|
+
end
|
106
|
+
|
107
|
+
#
|
108
|
+
# Validate that the default value matches the type
|
109
|
+
#
|
110
|
+
#
|
111
|
+
# @raise [InvalidArgumentType] when default does not match type
|
112
|
+
#
|
113
|
+
# @return [void]
|
114
|
+
#
|
115
|
+
def validate_default
|
116
|
+
return unless default || default.is_a?(FalseClass)
|
117
|
+
|
118
|
+
validate! :default, default, is_a: type
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# Validate that the property has not been defined
|
123
|
+
#
|
124
|
+
#
|
125
|
+
# @raise [PropertyDefined] when property has already been defined
|
126
|
+
#
|
127
|
+
# @return [void]
|
128
|
+
#
|
129
|
+
def validate_undefined
|
130
|
+
return unless (prop = properties[name])
|
131
|
+
|
132
|
+
raise PropertyDefined, name: name, type: prop[:type], default: prop[:default]
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Abstraction over WebMock to reduce duplication
|
5
|
+
#
|
6
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
7
|
+
# @since 0.1.0
|
8
|
+
#
|
9
|
+
module StubRequests
|
10
|
+
#
|
11
|
+
# Module Property provides type checked attribute definition with default value
|
12
|
+
#
|
13
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
14
|
+
# @since 0.1.2
|
15
|
+
#
|
16
|
+
module Property
|
17
|
+
include ArgumentValidation
|
18
|
+
|
19
|
+
#
|
20
|
+
# Extends the base class with the ClassMethods module
|
21
|
+
#
|
22
|
+
# @param [Class,Module] base the class where this module is included
|
23
|
+
#
|
24
|
+
# @return [void]
|
25
|
+
#
|
26
|
+
def self.included(base)
|
27
|
+
base.class_attribute :properties, default: {}
|
28
|
+
base.send(:extend, ClassMethods)
|
29
|
+
end
|
30
|
+
|
31
|
+
#
|
32
|
+
# Module ClassMethods provides class methods for {Property}
|
33
|
+
#
|
34
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
35
|
+
#
|
36
|
+
# :reek:DataClump
|
37
|
+
module ClassMethods
|
38
|
+
#
|
39
|
+
# Define property methods for the name
|
40
|
+
#
|
41
|
+
# @param [Symbol] name the name of the property
|
42
|
+
# @param [Object] type: the expected type of the property
|
43
|
+
# @param [Hash<Symbol>] **options a hash with options
|
44
|
+
# @option options [Object] :default a default value for the property
|
45
|
+
#
|
46
|
+
# @return [Object] the whatever
|
47
|
+
#
|
48
|
+
def property(name, type:, **options)
|
49
|
+
type = normalize_type(type, options)
|
50
|
+
default = options[:default]
|
51
|
+
Property::Validator.call(name, type, default, properties)
|
52
|
+
|
53
|
+
Docile.dsl_eval(self) do
|
54
|
+
define_property(name, type, default)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def normalize_type(type, **options)
|
59
|
+
type_array = Array(type)
|
60
|
+
return type_array unless (default = options[:default])
|
61
|
+
|
62
|
+
type_array.concat([default.class]).flatten.uniq
|
63
|
+
end
|
64
|
+
|
65
|
+
def define_property(name, type, default)
|
66
|
+
property_reader(name)
|
67
|
+
property_predicate(name)
|
68
|
+
property_writer(name, type)
|
69
|
+
|
70
|
+
set_property_defined(name, type, default)
|
71
|
+
end
|
72
|
+
|
73
|
+
def property_reader(name)
|
74
|
+
silence_redefinition_of_method(name.to_s)
|
75
|
+
redefine_method(name) do
|
76
|
+
instance_variable_get("@#{name}") || properties.dig(name, :default)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def property_predicate(name)
|
81
|
+
silence_redefinition_of_method("#{name}?")
|
82
|
+
redefine_method("#{name}?") do
|
83
|
+
!!public_send(name) # rubocop:disable Style/DoubleNegation
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def property_writer(name, type)
|
88
|
+
redefine_method("#{name}=") do |obj|
|
89
|
+
validate! name, obj, is_a: type
|
90
|
+
instance_variable_set("@#{name}", obj)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def set_property_defined(name, type, default)
|
95
|
+
properties[name] = { type: type, default: default }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -10,21 +10,23 @@ module StubRequests
|
|
10
10
|
#
|
11
11
|
# Class Service provides details for a registered service
|
12
12
|
#
|
13
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
14
|
+
#
|
13
15
|
class Service
|
14
|
-
include ArgumentValidation
|
15
16
|
include Comparable
|
17
|
+
include Property
|
16
18
|
|
17
19
|
# @!attribute [rw] id
|
18
20
|
# @return [EndpointRegistry] the id of the service
|
19
|
-
|
21
|
+
property :id, type: Symbol
|
20
22
|
|
21
23
|
# @!attribute [rw] uri
|
22
24
|
# @return [EndpointRegistry] the base uri to the service
|
23
|
-
|
25
|
+
property :uri, type: String
|
24
26
|
|
25
|
-
# @!attribute [rw]
|
27
|
+
# @!attribute [rw] endpoints
|
26
28
|
# @return [EndpointRegistry] a list with defined endpoints
|
27
|
-
attr_reader :
|
29
|
+
attr_reader :endpoints
|
28
30
|
|
29
31
|
#
|
30
32
|
# Initializes a new instance of a Service
|
@@ -33,28 +35,9 @@ module StubRequests
|
|
33
35
|
# @param [String] service_uri the base uri to reach the service
|
34
36
|
#
|
35
37
|
def initialize(service_id, service_uri)
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
@id = service_id
|
40
|
-
@uri = service_uri
|
41
|
-
@endpoint_registry = EndpointRegistry.new
|
42
|
-
end
|
43
|
-
|
44
|
-
#
|
45
|
-
# Registers a new endpoint or updates an existing one
|
46
|
-
#
|
47
|
-
#
|
48
|
-
# @param [Symbol] endpoint_id the id of this Endpoint
|
49
|
-
# @param [Symbol] verb a HTTP verb
|
50
|
-
# @param [String] uri_template the URI to reach the endpoint
|
51
|
-
# @param [optional, Hash<Symbol>] default_options default options
|
52
|
-
#
|
53
|
-
# @return [Endpoint] either the new endpoint or the updated one
|
54
|
-
#
|
55
|
-
# :reek:LongParameterList { max_params: 5 }
|
56
|
-
def register_endpoint(endpoint_id, verb, uri_template, default_options = {})
|
57
|
-
endpoint_registry.register(endpoint_id, verb, uri_template, default_options)
|
38
|
+
self.id = service_id
|
39
|
+
self.uri = service_uri
|
40
|
+
@endpoints = EndpointRegistry.new
|
58
41
|
end
|
59
42
|
|
60
43
|
#
|
@@ -63,31 +46,7 @@ module StubRequests
|
|
63
46
|
# @return [true,false]
|
64
47
|
#
|
65
48
|
def endpoints?
|
66
|
-
|
67
|
-
end
|
68
|
-
|
69
|
-
#
|
70
|
-
# Gets an endpoint from the {#endpoint_registry} collection
|
71
|
-
#
|
72
|
-
# @param [Symbol] endpoint_id the id of the endpoint
|
73
|
-
#
|
74
|
-
# @raise [EndpointNotFound] when the endpoint couldn't be found
|
75
|
-
#
|
76
|
-
# @return [Endpoint]
|
77
|
-
#
|
78
|
-
def get_endpoint!(endpoint_id)
|
79
|
-
endpoint_registry.get!(endpoint_id)
|
80
|
-
end
|
81
|
-
|
82
|
-
#
|
83
|
-
# Gets an endpoint from the {#endpoint_registry} collection
|
84
|
-
#
|
85
|
-
# @param [Symbol] endpoint_id the id of the endpoint
|
86
|
-
#
|
87
|
-
# @return [Endpoint, nil]
|
88
|
-
#
|
89
|
-
def get_endpoint(endpoint_id)
|
90
|
-
endpoint_registry.get(endpoint_id)
|
49
|
+
endpoints.any?
|
91
50
|
end
|
92
51
|
|
93
52
|
#
|
@@ -100,7 +59,7 @@ module StubRequests
|
|
100
59
|
+"#<#{self.class}",
|
101
60
|
+" id=#{id}",
|
102
61
|
+" uri=#{uri}",
|
103
|
-
+" endpoints=#{
|
62
|
+
+" endpoints=#{endpoints.endpoints_string}",
|
104
63
|
+">",
|
105
64
|
].join("")
|
106
65
|
end
|