mock_proxy 0.2.3 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/mock_proxy.rb +63 -34
- data/lib/mock_proxy/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4be99a98663982f26b85d5b18b0f4b8aeb60a889
|
4
|
+
data.tar.gz: 56eabef1a63825f91c4375960677ed0dc3a0c37c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e355f02c7587ab7b2e194db9cb3d170e5baf970bdc620a86501902344440c75d3aa1c0fbd2eac1eacf9074b9fcca90037bf2cb78b2c1ba2f5f1157bcd018d1c6
|
7
|
+
data.tar.gz: 38e6f423b030d606c29e3fc1e524027223032bfd3bb2dff2196a2a9ff33b79e3c8d978b758c37e697bf2e0b8cf6bff682ee9ff0e2b353fb42e58656ded28c1b7
|
data/lib/mock_proxy.rb
CHANGED
@@ -9,15 +9,15 @@ require 'active_support/core_ext'
|
|
9
9
|
# That would have be 5-6 lines of stubbing. If this sounds like stub_chain, you're on the right track. It was removed in
|
10
10
|
# RSpec 3 (or 2?). It's similar to that but it does things differently
|
11
11
|
# First, it doesn't require you to use it in a stub
|
12
|
-
# Second, it's use of
|
12
|
+
# Second, it's use of callbacks means you can define anything, a stub or a mock (expectation) or a spy or whatever you want
|
13
13
|
#
|
14
14
|
# To use MockProxy, initialize it with a hash. Each key is a method call. Each call either returns a new proxy or calls
|
15
|
-
# the
|
16
|
-
# a new proxy with the value as the hash. MockProxy will warn if you don't use hashes or
|
15
|
+
# the callback. If the value is a callback, it calls it immediately with the args and block. If the value is a hash, it returns
|
16
|
+
# a new proxy with the value as the hash. MockProxy will warn if you don't use hashes or callbacks and will also warn if
|
17
17
|
# you did not define all the method calls (it won't automatically return itself for methods not defined in the hash)
|
18
18
|
#
|
19
19
|
# Example use:
|
20
|
-
# let(:model_proxy) { MockProxy.new(receive_email:
|
20
|
+
# let(:model_proxy) { MockProxy.new(receive_email: callback {}, generate_email: { validate!: { send: callback { |to| email } } }) }
|
21
21
|
# before { allow(Model).to receive(:new).and_return model_proxy }
|
22
22
|
# # ...
|
23
23
|
# describe 'Model' do
|
@@ -34,13 +34,13 @@ require 'active_support/core_ext'
|
|
34
34
|
#
|
35
35
|
# Example:
|
36
36
|
# let(:model_proxy) do
|
37
|
-
# callback =
|
38
|
-
# MockProxy.merge(generator_proxy, decorate:
|
37
|
+
# callback = callback do |type|
|
38
|
+
# MockProxy.merge(generator_proxy, decorate: callback { |*args| method_call(type, *args) })
|
39
39
|
# generator_proxy
|
40
40
|
# end
|
41
41
|
# MockProxy.new(generate_email: callback)
|
42
42
|
# end
|
43
|
-
# let(:generator_proxy) { MockProxy.new(validate!: { send:
|
43
|
+
# let(:generator_proxy) { MockProxy.new(validate!: { send: callback { |to| email } }) }
|
44
44
|
#
|
45
45
|
#
|
46
46
|
# @author Geoff Lee
|
@@ -51,7 +51,7 @@ class MockProxy
|
|
51
51
|
#
|
52
52
|
# NOTE: We freeze the hash so you cannot modify it
|
53
53
|
#
|
54
|
-
# Use case: Retrieve
|
54
|
+
# Use case: Retrieve callback to mock
|
55
55
|
#
|
56
56
|
# @param [MockProxy] proxy existing proxy
|
57
57
|
# @param [String, Symbol, #to_s, Array<String, Symbol, #to_s>] key_path the chain of methods or key path. Can be a
|
@@ -79,11 +79,11 @@ class MockProxy
|
|
79
79
|
proxy
|
80
80
|
end
|
81
81
|
|
82
|
-
# Replaces the
|
82
|
+
# Replaces the callback at the specified key path, but only if there was one there before.
|
83
83
|
# Without creating new paths comes validation, including checking that this replaces an
|
84
|
-
# existing
|
84
|
+
# existing callback, sort of like mkdir (without the -p option)
|
85
85
|
#
|
86
|
-
# Use case: Replace existing stub with a new
|
86
|
+
# Use case: Replace existing stub with a new callback without creating new method chains
|
87
87
|
#
|
88
88
|
# @param [MockProxy] proxy existing proxy
|
89
89
|
# @param [String, Symbol, #to_s, Array<String, Symbol, #to_s>] key_path the chain of methods or key path. Can be a
|
@@ -94,7 +94,7 @@ class MockProxy
|
|
94
94
|
proxy
|
95
95
|
end
|
96
96
|
|
97
|
-
# Sets the
|
97
|
+
# Sets the callback at the specified key path, regardless if there was a callback there before.
|
98
98
|
# No validation comes with automatic path creation, meaning the key path will be defined
|
99
99
|
# it it hasn't already, sort of like mkdir -p
|
100
100
|
#
|
@@ -124,7 +124,7 @@ class MockProxy
|
|
124
124
|
# Wrap existing callback, calling the provided block before it
|
125
125
|
# Multiple calls to .observe will create a pyramid of callbacks, calling the observers before
|
126
126
|
# eventually calling the existing callback
|
127
|
-
new_callback =
|
127
|
+
new_callback = callback do |*args|
|
128
128
|
block.call(*args)
|
129
129
|
callback.call(*args)
|
130
130
|
end
|
@@ -134,7 +134,7 @@ class MockProxy
|
|
134
134
|
|
135
135
|
# Wraps the existing callback with your block
|
136
136
|
#
|
137
|
-
# Use case: Get full control of the existing
|
137
|
+
# Use case: Get full control of the existing callback while running custom code
|
138
138
|
#
|
139
139
|
# @param [MockProxy] proxy existing proxy
|
140
140
|
# @param [String, Symbol, #to_s, Array<String, Symbol, #to_s>] key_path the chain of methods or key path. Can be a
|
@@ -147,7 +147,7 @@ class MockProxy
|
|
147
147
|
# Wrap existing callback, calling the provided block before it
|
148
148
|
# Multiple calls to .observe will create a pyramid of callbacks, calling the observers before
|
149
149
|
# eventually calling the existing callback
|
150
|
-
new_callback =
|
150
|
+
new_callback = callback do |*args|
|
151
151
|
block.call(*args, &callback)
|
152
152
|
end
|
153
153
|
set_callback(proxy, key_path, new_callback)
|
@@ -158,8 +158,8 @@ class MockProxy
|
|
158
158
|
# @param [MockProxy] proxy existing proxy
|
159
159
|
# @param [String, Symbol, #to_s, Array<String, Symbol, #to_s>] key_path the chain of methods or key path. Can be a
|
160
160
|
# dot delimited key path or an array of method names as strings or symbols
|
161
|
-
# @return [
|
162
|
-
# @raise [ArgumentError] if
|
161
|
+
# @return [AnyObject, !Hash] if callback found at key path
|
162
|
+
# @raise [ArgumentError] if callback not found or hash found at key path
|
163
163
|
def self.get_callback(proxy, key_path)
|
164
164
|
key_paths = key_path.is_a?(Array) ? key_path.map(&:to_s) : key_path.split('.')
|
165
165
|
existing_callback_hash = proxy.instance_variable_get('@callback_hash')
|
@@ -177,12 +177,12 @@ class MockProxy
|
|
177
177
|
# @param [MockProxy] proxy existing proxy
|
178
178
|
# @param [String, Symbol, #to_s, Array<String, Symbol, #to_s>] key_path the chain of methods or key path. Can be a
|
179
179
|
# dot delimited key path or an array of method names as strings or symbols
|
180
|
-
# @return [
|
181
|
-
# @raise [ArgumentError] if
|
180
|
+
# @return [AnyObject, !Hash] if callback found at key path
|
181
|
+
# @raise [ArgumentError] if callback not found or hash found at key path
|
182
182
|
def self.get_and_validate_callback(proxy, key_path)
|
183
183
|
callback = get_callback(proxy, key_path)
|
184
|
-
return callback if
|
185
|
-
fail ArgumentError, "The existing callback tree contains the full key path you provided but continues going (i.e. no
|
184
|
+
return callback if valid_callback?(callback)
|
185
|
+
fail ArgumentError, "The existing callback tree contains the full key path you provided but continues going (i.e. no callback at exact key path). If you want to shorten the callback tree, use MockProxy.set_at. The callback tree looks like this: #{proxy.instance_variable_get('@callback_hash')}"
|
186
186
|
end
|
187
187
|
private_class_method :get_and_validate_callback
|
188
188
|
|
@@ -190,15 +190,15 @@ class MockProxy
|
|
190
190
|
# @param [MockProxy] proxy existing proxy
|
191
191
|
# @param [String, Symbol, #to_s, Array<String, Symbol, #to_s>] key_path the chain of methods or key path. Can be a
|
192
192
|
# dot delimited key path or an array of method names as strings or symbols
|
193
|
-
# @param [
|
193
|
+
# @param [AnyObject, !Hash] callback the new callback to replace the existing callback
|
194
194
|
# @param [Bool] validate true will throw error if nil at any part of key path, false to
|
195
195
|
# create key path if missing (mkdir vs mkdir -p) (Defaults: true)
|
196
|
-
# @return [MockProxy] if
|
197
|
-
# @raise [ArgumentError] if
|
198
|
-
def self.set_callback(proxy, key_path,
|
199
|
-
fail ArgumentError, '
|
200
|
-
fail ArgumentError, '
|
201
|
-
# Validate by checking if
|
196
|
+
# @return [MockProxy] if callback existed at key path
|
197
|
+
# @raise [ArgumentError] if callback not found or hash found at key path
|
198
|
+
def self.set_callback(proxy, key_path, callback, validate = true)
|
199
|
+
fail ArgumentError, 'callback must be provided' unless callback
|
200
|
+
fail ArgumentError, 'callback must have a non-hash value' unless valid_callback?(callback)
|
201
|
+
# Validate by checking if callback exists at key path
|
202
202
|
get_and_validate_callback(proxy, key_path) if validate
|
203
203
|
# Set callback at key path, validating if set
|
204
204
|
key_paths = key_path.is_a?(Array) ? key_path.map(&:to_s) : key_path.to_s.split('.')
|
@@ -208,11 +208,11 @@ class MockProxy
|
|
208
208
|
# Last key
|
209
209
|
if key_paths.last == key
|
210
210
|
# Type check value, if validate
|
211
|
-
if validate && !callback_hash[key]
|
212
|
-
fail ArgumentError, "The existing callback tree contains the full key path you provided but continues going (i.e. no
|
211
|
+
if validate && !valid_callback?(callback_hash[key])
|
212
|
+
fail ArgumentError, "The existing callback tree contains the full key path you provided but continues going (i.e. no callback at exact key path). If you want to shorten the callback tree, use MockProxy.set_at. The callback tree looks like this: #{copied_callback_hash}"
|
213
213
|
else
|
214
|
-
# Assign new
|
215
|
-
callback_hash[key] =
|
214
|
+
# Assign new callback if pass validations
|
215
|
+
callback_hash[key] = callback
|
216
216
|
end
|
217
217
|
else
|
218
218
|
# In-between keys
|
@@ -230,18 +230,47 @@ class MockProxy
|
|
230
230
|
end
|
231
231
|
private_class_method :set_callback
|
232
232
|
|
233
|
+
# @private
|
234
|
+
# Supporting not just callbacks but other values for callbacks. To make the code easier to
|
235
|
+
# read and more reliable, hashes are not a supported callback value. To return one, use
|
236
|
+
# a callback like you would normally
|
237
|
+
#
|
238
|
+
# @param [AnyObject, !Hash] callback
|
239
|
+
# @return [Boolean] true if callback is valid, false if not
|
240
|
+
def self.valid_callback?(callback)
|
241
|
+
callback && !callback.is_a?(Hash)
|
242
|
+
end
|
243
|
+
private_class_method :valid_callback?
|
244
|
+
|
245
|
+
# @private
|
246
|
+
# Supporting not just callbacks but other values for callbacks. To make the code easier to
|
247
|
+
# read and more reliable, hashes are not a supported callback value. To return one, use
|
248
|
+
# a callback like you would normally
|
249
|
+
#
|
250
|
+
# @param [#to_s => AnyObject, !Hash] callback_tree
|
251
|
+
# @return [Boolean] true if callback is valid, false if not
|
252
|
+
def self.valid_callback_tree?(callback_tree)
|
253
|
+
return false unless callback_tree.is_a?(Hash)
|
254
|
+
callback_tree.all? do |key, value|
|
255
|
+
next false unless key.responds_to?(:to_s)
|
256
|
+
value.is_a?(Hash) ? valid_callback_tree?(value) : valid_callback?(value)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
private_class_method :valid_callback_tree?
|
260
|
+
|
233
261
|
# @param [Hash] callback_hash the tree of chained method calls
|
234
262
|
def initialize(callback_hash)
|
263
|
+
valid_callback_tree?(callback_hash)
|
235
264
|
@callback_hash = callback_hash.deep_stringify_keys.freeze
|
236
265
|
end
|
237
266
|
|
238
267
|
# @private
|
239
268
|
def method_missing(name, *args, &block)
|
240
269
|
current = @callback_hash[name.to_s]
|
241
|
-
if
|
270
|
+
if MockProxy.valid_callback?(current)
|
242
271
|
current.call(*args, &block)
|
243
272
|
else
|
244
|
-
if !current
|
273
|
+
if !current
|
245
274
|
fail "Missing method #{name}. Please add this definition to your mock proxy"
|
246
275
|
end
|
247
276
|
MockProxy.new(current.freeze)
|
data/lib/mock_proxy/version.rb
CHANGED