stub_requests 0.1.9 → 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
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