stub_requests 0.1.9 → 0.1.10

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/.reek.yml +5 -9
  3. data/.rubocop.yml +1 -0
  4. data/CHANGELOG.md +23 -0
  5. data/README.md +9 -9
  6. data/Rakefile +7 -5
  7. data/lib/stub_requests.rb +30 -16
  8. data/lib/stub_requests/api.rb +45 -26
  9. data/lib/stub_requests/callback.rb +3 -1
  10. data/lib/stub_requests/callback_registry.rb +9 -55
  11. data/lib/stub_requests/concerns/argument_validation.rb +47 -0
  12. data/lib/stub_requests/concerns/property.rb +114 -0
  13. data/lib/stub_requests/concerns/property/validator.rb +137 -0
  14. data/lib/stub_requests/concerns/register_verb.rb +110 -0
  15. data/lib/stub_requests/configuration.rb +19 -2
  16. data/lib/stub_requests/dsl.rb +5 -6
  17. data/lib/stub_requests/dsl/method_definition.rb +2 -8
  18. data/lib/stub_requests/endpoint.rb +22 -23
  19. data/lib/stub_requests/endpoint_registry.rb +157 -0
  20. data/lib/stub_requests/exceptions.rb +28 -10
  21. data/lib/stub_requests/request_stub.rb +29 -14
  22. data/lib/stub_requests/service.rb +55 -7
  23. data/lib/stub_requests/service_registry.rb +30 -79
  24. data/lib/stub_requests/stub_registry.rb +22 -80
  25. data/lib/stub_requests/stub_requests.rb +8 -5
  26. data/lib/stub_requests/uri.rb +0 -17
  27. data/lib/stub_requests/utils/fuzzy.rb +70 -0
  28. data/lib/stub_requests/version.rb +1 -1
  29. data/lib/stub_requests/webmock/builder.rb +9 -51
  30. data/lib/stub_requests/webmock/stub_registry_extension.rb +1 -1
  31. data/lib/tasks/changelog.rake +1 -7
  32. data/stub_requests.gemspec +1 -0
  33. data/update_docs.sh +2 -2
  34. metadata +27 -8
  35. data/lib/stub_requests/argument_validation.rb +0 -48
  36. data/lib/stub_requests/endpoint_stub.rb +0 -89
  37. data/lib/stub_requests/endpoints.rb +0 -246
  38. data/lib/stub_requests/hash_util.rb +0 -32
  39. data/lib/stub_requests/observable.rb +0 -18
  40. data/lib/stub_requests/property.rb +0 -112
  41. data/lib/stub_requests/property/validator.rb +0 -135
@@ -0,0 +1,114 @@
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
+ module Concerns
11
+ #
12
+ # Module Property provides type checked attribute definition with default value
13
+ #
14
+ # @author Mikael Henriksson <mikael@zoolutions.se>
15
+ # @since 0.1.2
16
+ #
17
+ module Property
18
+ include ArgumentValidation
19
+
20
+ #
21
+ # Extends the base class with the ClassMethods module
22
+ #
23
+ # @param [Class,Module] base the class where this module is included
24
+ #
25
+ # @return [void]
26
+ #
27
+ def self.included(base)
28
+ base.class_attribute :properties, default: {}
29
+ base.send(:extend, ClassMethods)
30
+ end
31
+
32
+ #
33
+ # Module ClassMethods provides class methods for {Property}
34
+ #
35
+ # @author Mikael Henriksson <mikael@zoolutions.se>
36
+ #
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 [void]
47
+ #
48
+ def property(name, type:, **options)
49
+ type = normalize_type(type, options)
50
+ default = options[:default]
51
+ 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
+ # @api private
59
+ def normalize_type(type, **options)
60
+ type_array = Array(type)
61
+ return type_array unless (default = options[:default])
62
+
63
+ type_array.concat([default.class]).flatten.uniq
64
+ end
65
+
66
+ # @api private
67
+ def define_property(name, type, default)
68
+ property_reader(name, default)
69
+ property_predicate(name)
70
+ property_writer(name, type)
71
+
72
+ set_property_default(name, default)
73
+ set_property_defined(name, type, default)
74
+ end
75
+
76
+ # @api private
77
+ def property_reader(name, default)
78
+ invar = "@#{name}"
79
+ silence_redefinition_of_method(name.to_s)
80
+ redefine_method(name) do
81
+ instance_variable_set(invar, default) unless instance_variable_defined?(invar)
82
+ instance_variable_get(invar)
83
+ end
84
+ end
85
+
86
+ # @api private
87
+ def property_predicate(name)
88
+ silence_redefinition_of_method("#{name}?")
89
+ redefine_method("#{name}?") do
90
+ !!public_send(name) # rubocop:disable Style/DoubleNegation
91
+ end
92
+ end
93
+
94
+ # @api private
95
+ def property_writer(name, type)
96
+ redefine_method("#{name}=") do |obj|
97
+ validate! name: name, value: obj, type: type
98
+ instance_variable_set("@#{name}", obj)
99
+ end
100
+ end
101
+
102
+ def set_property_default(name, default)
103
+ instance_variable_set("@#{name}", default)
104
+ end
105
+
106
+ # @api private
107
+ def set_property_defined(name, type, default)
108
+ self.properties ||= {}
109
+ properties[name] = { type: type, default: default }
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,137 @@
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
+ module Concerns
11
+ #
12
+ # Module Property provides type checked attribute definition with default value
13
+ #
14
+ # @author Mikael Henriksson <mikael@zoolutions.se>
15
+ # @since 0.1.2
16
+ #
17
+ module Property
18
+ #
19
+ # Class Validator provides validation for adding properties
20
+ #
21
+ # @author Mikael Henriksson <mikael@zoolutions.se>
22
+ # @since 0.1.2
23
+ #
24
+ class Validator
25
+ include ArgumentValidation
26
+
27
+ #
28
+ # Validates that the property can be added to the class
29
+ #
30
+ #
31
+ # @param [Symbol] name the name of the property
32
+ # @param [Class, Module] type the type of the property
33
+ # @param [Object] default the default value of the property
34
+ # @param [Hash] properties the list of currently defined properties
35
+ #
36
+ # @raise [InvalidArgumentType] when name is not a Symbol
37
+ # @raise [InvalidArgumentType] when default does not match type
38
+ # @raise [PropertyDefined] when property has already been defined
39
+ #
40
+ # @return [void]
41
+ #
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
+ def initialize(name, type, default = nil, properties = {})
71
+ @type = Array(type).flatten
72
+ @default = default
73
+ @name = name
74
+ @properties = properties || {}
75
+ end
76
+
77
+ #
78
+ # Performs all validations
79
+ #
80
+ #
81
+ # @raise [InvalidArgumentType] when name is not a Symbol
82
+ # @raise [InvalidArgumentType] when default does not match type
83
+ # @raise [PropertyDefined] when property has already been defined
84
+ #
85
+ # @return [void]
86
+ #
87
+ def run_validations
88
+ validate_undefined
89
+ validate_name
90
+ validate_default
91
+ end
92
+
93
+ private
94
+
95
+ #
96
+ # Validates that the name is of type Symbol
97
+ #
98
+ # @raise [InvalidArgumentType] when name is not a Symbol
99
+ #
100
+ # @return [void]
101
+ #
102
+ def validate_name
103
+ validate! name: :name, value: name, type: Symbol
104
+ end
105
+
106
+ #
107
+ # Validate that the default value matches the type
108
+ #
109
+ #
110
+ # @raise [InvalidArgumentType] when default does not match type
111
+ #
112
+ # @return [void]
113
+ #
114
+ def validate_default
115
+ return unless default || default.is_a?(FalseClass)
116
+
117
+ validate! name: :default, value: default, type: type
118
+ end
119
+
120
+ #
121
+ # Validate that the property has not been defined
122
+ #
123
+ #
124
+ # @raise [PropertyDefined] when property has already been defined
125
+ #
126
+ # @return [void]
127
+ #
128
+ def validate_undefined
129
+ return unless properties
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
137
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StubRequests
4
+ module Concerns
5
+ #
6
+ # Module RegisterVerb provides <description>
7
+ # @since 0.1.10
8
+ #
9
+ #
10
+ # @author Mikael Henriksson <mikael@zoolutions.se>
11
+ #
12
+ module RegisterVerb
13
+ #
14
+ # Convenience wrapper for register
15
+ #
16
+ #
17
+ # @example **Register a get endpoint**
18
+ # . get("documents/:id", as: :documents_show)
19
+ #
20
+ # @param [String] path the path to the endpoint
21
+ # @param [Symbol] as the id of the endpoint
22
+ #
23
+ # @return [Endpoint] the registered endpoint
24
+ #
25
+ def any(path, as:) # rubocop:disable Naming/UncommunicativeMethodParamName
26
+ register(as, __method__, path)
27
+ end
28
+
29
+ #
30
+ # Convenience wrapper for register
31
+ #
32
+ #
33
+ # @example **Register a get endpoint**
34
+ # . get("documents/:id", as: :documents_show)
35
+ #
36
+ # @param [String] path the path to the endpoint
37
+ # @param [Symbol] as the id of the endpoint
38
+ #
39
+ # @return [Endpoint] the registered endpoint
40
+ #
41
+ def get(path, as:) # rubocop:disable Naming/UncommunicativeMethodParamName
42
+ register(as, __method__, path)
43
+ end
44
+
45
+ #
46
+ # Register a :post endpoint
47
+ #
48
+ #
49
+ # @example **Register a post endpoint**
50
+ # . post("documents", as: :documents_create)
51
+ #
52
+ # @param [String] path the path to the endpoint
53
+ # @param [Symbol] as the id of the endpoint
54
+ #
55
+ # @return [Endpoint] the registered endpoint
56
+ #
57
+ def post(path, as:) # rubocop:disable Naming/UncommunicativeMethodParamName
58
+ register(as, __method__, path)
59
+ end
60
+
61
+ #
62
+ # Register a :patch endpoint
63
+ #
64
+ #
65
+ # @example **Register a patch endpoint**
66
+ # . patch("documents/:id", as: :documents_update)
67
+ #
68
+ # @param [String] path the path to the endpoint
69
+ # @param [Symbol] as the id of the endpoint
70
+ #
71
+ # @return [Endpoint] the registered endpoint
72
+ #
73
+ def patch(path, as:) # rubocop:disable Naming/UncommunicativeMethodParamName
74
+ register(as, __method__, path)
75
+ end
76
+
77
+ #
78
+ # Register a :put endpoint
79
+ #
80
+ #
81
+ # @example **Register a put endpoint**
82
+ # . put("documents/:id", as: :documents_update)
83
+ #
84
+ # @param [String] path the path to the endpoint
85
+ # @param [Symbol] as the id of the endpoint
86
+ #
87
+ # @return [Endpoint] the registered endpoint
88
+ #
89
+ def put(path, as:) # rubocop:disable Naming/UncommunicativeMethodParamName
90
+ register(as, __method__, path)
91
+ end
92
+
93
+ #
94
+ # Register a :delete endpoint
95
+ #
96
+ #
97
+ # @example **Register a delete endpoint**
98
+ # . delete("documents/:id", as: :documents_destroy)
99
+ #
100
+ # @param [String] path the path to the endpoint
101
+ # @param [Symbol] as the id of the endpoint
102
+ #
103
+ # @return [Endpoint] the registered endpoint
104
+ #
105
+ def delete(path, as:) # rubocop:disable Naming/UncommunicativeMethodParamName
106
+ register(as, __method__, path)
107
+ end
108
+ end
109
+ end
110
+ end
@@ -14,8 +14,25 @@ module StubRequests
14
14
  # @since 0.1.2
15
15
  #
16
16
  class Configuration
17
- include Property
17
+ # includes "Concerns::Property"
18
+ # @!parse include Concerns::Property
19
+ include Concerns::Property
18
20
 
19
- property :record_metrics, type: [TrueClass, FalseClass], default: false
21
+ #
22
+ # @!attribute [rw] record_stubs
23
+ # @return [Hash] record_stubs set to true to keep track of stubs
24
+ property :record_stubs, type: [TrueClass, FalseClass], default: false
25
+ #
26
+ # @!attribute [rw] jaro_options
27
+ # @return [Hash] options to use for jaro winkler
28
+ property :jaro_options, type: Hash, default: {
29
+ weight: 0.1,
30
+ threshold: 0.7,
31
+ ignore_case: true,
32
+ }
33
+ #
34
+ # @!attribute [rw] logger
35
+ # @return [Logger] any object that responds to the standard logger methods
36
+ property :logger, type: Logger
20
37
  end
21
38
  end
@@ -29,15 +29,15 @@ module StubRequests
29
29
  # Stubs.instance_methods #=> [:stub_documents_show, :stub_documents_index, :stub_documents_create]
30
30
  # module Stubs
31
31
  # def stub_documents_show(id:, &block)
32
- # stub_endpoint(:documents, :show, id: id, &block)
32
+ # stub_endpoint(:documents_show, id: id, &block)
33
33
  # end
34
34
  #
35
35
  # def stub_documents_index(&block)
36
- # stub_endpoint(:documents, :index, &block)
36
+ # stub_endpoint(:documents_index, &block)
37
37
  # end
38
38
  #
39
39
  # def stub_documents_create(&block)
40
- # stub_endpoint(:documents, :create, &block)
40
+ # stub_endpoint(:documents_create, &block)
41
41
  # end
42
42
  # end
43
43
  #
@@ -90,9 +90,8 @@ module StubRequests
90
90
  # @param [Module] receiver the receiver of the stub methods
91
91
  #
92
92
  def initialize(service_id, receiver: nil)
93
- @service = StubRequests::ServiceRegistry.instance.find!(service_id)
93
+ @endpoints = StubRequests::EndpointRegistry[service_id]
94
94
  @receiver = receiver
95
- @endpoints = service.endpoints.endpoints.values
96
95
  end
97
96
 
98
97
  #
@@ -123,7 +122,7 @@ module StubRequests
123
122
 
124
123
  def method_definitions
125
124
  @method_definitions ||= endpoints.map do |endpoint|
126
- MethodDefinition.new(service.id, endpoint.id, endpoint.route_params)
125
+ MethodDefinition.new(endpoint.id, endpoint.route_params)
127
126
  end
128
127
  end
129
128
  end
@@ -13,10 +13,6 @@ module StubRequests
13
13
  # @return [String]
14
14
  BLOCK_ARG = "&block"
15
15
 
16
- #
17
- # @!attribute [r] service_id
18
- # @return [Symbol] the id of a registered service
19
- attr_reader :service_id
20
16
  #
21
17
  # @!attribute [r] endpoint_id
22
18
  # @return [Symbol] the id of a registered endpoint
@@ -29,12 +25,10 @@ module StubRequests
29
25
  #
30
26
  # Initialize a new endpoint of {MethodDefinition}
31
27
  #
32
- # @param [Symbol] service_id the id of a registered service
33
28
  # @param [Symbol] endpoint_id the id of a registered endpoint
34
29
  # @param [Array<Symbol>] route_params the route parameter keys
35
30
  #
36
- def initialize(service_id, endpoint_id, route_params)
37
- @service_id = service_id
31
+ def initialize(endpoint_id, route_params)
38
32
  @endpoint_id = endpoint_id
39
33
  @route_params = route_params
40
34
  end
@@ -52,7 +46,7 @@ module StubRequests
52
46
  def to_s
53
47
  <<~METHOD
54
48
  def #{name}(#{keywords})
55
- StubRequests.stub_endpoint(:#{service_id}, :#{endpoint_id}, #{arguments})
49
+ StubRequests.stub_endpoint(:#{endpoint_id}, #{arguments})
56
50
  end
57
51
  METHOD
58
52
  end