active_remote-cached 1.1.1 → 1.2.0
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/.github/workflows/ci.yml +85 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +20 -17
- data/Appraisals +27 -0
- data/README.md +121 -0
- data/Rakefile +3 -8
- data/active_remote-cached.gemspec +31 -6
- data/lib/active_remote/cached/argument_keys.rb +61 -27
- data/lib/active_remote/cached/cache.rb +32 -6
- data/lib/active_remote/cached/version.rb +1 -1
- data/lib/active_remote/cached.rb +119 -68
- data/spec/active_remote/cached/argument_keys_spec.rb +124 -0
- data/spec/active_remote/cached/cache_spec.rb +171 -5
- data/spec/active_remote/cached_delete_methods_spec.rb +51 -4
- data/spec/active_remote/cached_exist_methods_spec.rb +75 -4
- data/spec/active_remote/cached_find_methods_spec.rb +6 -8
- data/spec/active_remote/cached_search_methods_spec.rb +57 -8
- data/spec/active_remote/cached_spec.rb +331 -0
- data/spec/spec_helper.rb +1 -0
- metadata +48 -23
data/lib/active_remote/cached.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'active_support'
|
|
2
4
|
require 'active_support/cache'
|
|
3
5
|
require 'active_support/concern'
|
|
@@ -19,7 +21,12 @@ module ActiveRemote
|
|
|
19
21
|
RUBY_AND_ACTIVE_SUPPORT_VERSION = "#{RUBY_ENGINE_VERSION}:#{ActiveSupport::VERSION::STRING}".freeze
|
|
20
22
|
|
|
21
23
|
def self.cache(cache_provider = nil)
|
|
22
|
-
|
|
24
|
+
if cache_provider
|
|
25
|
+
nested_caching = @cache_provider&.nested_caching?
|
|
26
|
+
@cache_provider = ::ActiveRemote::Cached::Cache.new(cache_provider)
|
|
27
|
+
# A new Cache starts with nested caching off, so carry the setting over.
|
|
28
|
+
@cache_provider.enable_nested_caching! if nested_caching
|
|
29
|
+
end
|
|
23
30
|
|
|
24
31
|
@cache_provider
|
|
25
32
|
end
|
|
@@ -36,6 +43,29 @@ module ActiveRemote
|
|
|
36
43
|
@cached_methods
|
|
37
44
|
end
|
|
38
45
|
|
|
46
|
+
# The options each cached finder was declared with, keyed by method name.
|
|
47
|
+
# The generated methods read this at call time. Interpolating the options
|
|
48
|
+
# into the generated source instead would require every value to have a
|
|
49
|
+
# literal form, and a value such as 5.minutes does not.
|
|
50
|
+
def cached_finder_options
|
|
51
|
+
@cached_finder_options ||= {}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# A subclass inherits the finder methods its parent defined, but not the
|
|
55
|
+
# parent registry, so the lookup walks up the superclass chain.
|
|
56
|
+
def _cached_finder_options_for(method_name)
|
|
57
|
+
klass = self
|
|
58
|
+
|
|
59
|
+
while klass.respond_to?(:cached_finder_options)
|
|
60
|
+
options = klass.cached_finder_options[method_name]
|
|
61
|
+
return options if options
|
|
62
|
+
|
|
63
|
+
klass = klass.superclass
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
{}
|
|
67
|
+
end
|
|
68
|
+
|
|
39
69
|
def cached_finders_for(*cached_finder_keys)
|
|
40
70
|
options = cached_finder_keys.extract_options!
|
|
41
71
|
|
|
@@ -103,37 +133,38 @@ module ActiveRemote
|
|
|
103
133
|
"#{::Regexp.last_match(1)}#{params.sort.join('_and_')}#{::Regexp.last_match(3)}".to_sym
|
|
104
134
|
end
|
|
105
135
|
|
|
106
|
-
# rubocop:disable Metrics/AbcSize
|
|
107
136
|
def _args_in_sorted_order(m, args)
|
|
108
137
|
regex = /cached_(?:delete|exist_search|search|exist_find|find)_by_([0-9a-zA-Z_]*)(!|\?)?/
|
|
109
138
|
|
|
110
|
-
|
|
139
|
+
called_match = m.match(regex)
|
|
140
|
+
sorted_match = _method_missing_name(m).match(regex)
|
|
111
141
|
|
|
112
|
-
|
|
113
|
-
match_2 = method_name.match(regex)
|
|
142
|
+
return args unless called_match[1] && sorted_match[1]
|
|
114
143
|
|
|
115
|
-
|
|
144
|
+
called_field_names = called_match[1].split('_and_')
|
|
145
|
+
sorted_field_names = sorted_match[1].split('_and_')
|
|
116
146
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
args_names_in_order = match_2[1].split('_and_')
|
|
147
|
+
_reorder_args(m, args, called_field_names, sorted_field_names)
|
|
148
|
+
end
|
|
120
149
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
150
|
+
def _reorder_args(m, args, called_field_names, sorted_field_names)
|
|
151
|
+
if args.size < called_field_names.size
|
|
152
|
+
raise ::ArgumentError,
|
|
153
|
+
"wrong number of arguments to #{m} (given #{args.size}, expected #{called_field_names.size})"
|
|
154
|
+
end
|
|
125
155
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
end
|
|
156
|
+
args_in_order = sorted_field_names.map do |field_name|
|
|
157
|
+
index = called_field_names.index(field_name)
|
|
158
|
+
raise ::ArgumentError, "#{m} has no argument named #{field_name}" if index.nil?
|
|
130
159
|
|
|
131
|
-
|
|
132
|
-
else
|
|
133
|
-
args
|
|
160
|
+
args[index]
|
|
134
161
|
end
|
|
162
|
+
|
|
163
|
+
# Add the options hash if the caller passed one.
|
|
164
|
+
args_in_order << args.last if args.size > called_field_names.size
|
|
165
|
+
|
|
166
|
+
args_in_order
|
|
135
167
|
end
|
|
136
|
-
# rubocop:enable Metrics/AbcSize
|
|
137
168
|
|
|
138
169
|
# rubocop:disable Metrics/AbcSize
|
|
139
170
|
def _create_cached_finder_for(cached_finder_key, options = {})
|
|
@@ -192,25 +223,41 @@ module ActiveRemote
|
|
|
192
223
|
"cached_search_by_#{arguments.sort.join('_and_')}"
|
|
193
224
|
end
|
|
194
225
|
|
|
195
|
-
def
|
|
226
|
+
def _expanded_search_args(method_arguments)
|
|
227
|
+
method_arguments.map { |method_argument| ":#{method_argument} => #{method_argument}," }.join
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# Returns the source text that builds the cache key for a generated
|
|
231
|
+
# method. The key names each field, so that two finders that take the
|
|
232
|
+
# same values do not share one cache entry.
|
|
233
|
+
def _expanded_cache_key_args(method_arguments)
|
|
234
|
+
sorted_arguments = method_arguments.sort
|
|
235
|
+
field_names = sorted_arguments.map { |argument| ":#{argument}" }.join(',')
|
|
236
|
+
|
|
237
|
+
'::ActiveRemote::Cached::ArgumentKeys.for_fields(' \
|
|
238
|
+
"[#{field_names}], [#{sorted_arguments.join(',')}], __active_remote_cached_options" \
|
|
239
|
+
').cache_key'
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def _define_cached_delete_method(method_name, *method_arguments, cached_finder_options_hash)
|
|
196
243
|
method_arguments.flatten!
|
|
197
244
|
expanded_method_args = method_arguments.join(',')
|
|
198
|
-
|
|
199
|
-
cached_methods << method_name
|
|
245
|
+
expanded_cache_key_args = _expanded_cache_key_args(method_arguments)
|
|
200
246
|
|
|
201
247
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
202
248
|
# def self.cached_delete_by_user_guid(user_guid, options = {})
|
|
203
249
|
# ::ActiveRemote::Cached.cache.delete([name, user_guid])
|
|
204
250
|
# end
|
|
205
251
|
def self.#{method_name}(#{expanded_method_args}, __active_remote_cached_options = {})
|
|
206
|
-
__active_remote_cached_options = ::ActiveRemote::Cached.default_options.merge(#{
|
|
252
|
+
__active_remote_cached_options = ::ActiveRemote::Cached.default_options.merge(_cached_finder_options_for('#{method_name}')).merge(__active_remote_cached_options)
|
|
207
253
|
namespace = __active_remote_cached_options.delete(:namespace)
|
|
254
|
+
argument_cache_key = #{expanded_cache_key_args}
|
|
208
255
|
find_cache_key = [
|
|
209
256
|
RUBY_AND_ACTIVE_SUPPORT_VERSION,
|
|
210
257
|
namespace,
|
|
211
258
|
name,
|
|
212
259
|
"#find",
|
|
213
|
-
|
|
260
|
+
argument_cache_key
|
|
214
261
|
].compact
|
|
215
262
|
|
|
216
263
|
search_cache_key = [
|
|
@@ -218,35 +265,36 @@ module ActiveRemote
|
|
|
218
265
|
namespace,
|
|
219
266
|
name,
|
|
220
267
|
"#search",
|
|
221
|
-
|
|
268
|
+
argument_cache_key
|
|
222
269
|
].compact
|
|
223
270
|
|
|
224
271
|
::ActiveRemote::Cached.cache.delete(find_cache_key)
|
|
225
272
|
::ActiveRemote::Cached.cache.delete(search_cache_key)
|
|
226
273
|
end
|
|
227
274
|
RUBY
|
|
275
|
+
|
|
276
|
+
cached_finder_options[method_name] = cached_finder_options_hash
|
|
277
|
+
cached_methods << method_name
|
|
228
278
|
end
|
|
229
279
|
|
|
230
|
-
def _define_cached_exist_find_method(method_name, *method_arguments,
|
|
280
|
+
def _define_cached_exist_find_method(method_name, *method_arguments, cached_finder_options_hash)
|
|
231
281
|
method_arguments.flatten!
|
|
232
282
|
expanded_method_args = method_arguments.join(',')
|
|
233
|
-
|
|
234
|
-
cached_methods << method_name
|
|
235
|
-
cached_methods << "#{method_name}?"
|
|
283
|
+
expanded_cache_key_args = _expanded_cache_key_args(method_arguments)
|
|
236
284
|
|
|
237
285
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
238
286
|
# def self.cached_exist_find_by_user_guid(user_guid, options = {})
|
|
239
287
|
# ::ActiveRemote::Cached.cache.exist?([name, user_guid])
|
|
240
288
|
# end
|
|
241
289
|
def self.#{method_name}(#{expanded_method_args}, __active_remote_cached_options = {})
|
|
242
|
-
__active_remote_cached_options = ::ActiveRemote::Cached.default_options.merge(#{
|
|
290
|
+
__active_remote_cached_options = ::ActiveRemote::Cached.default_options.merge(_cached_finder_options_for('#{method_name}')).merge(__active_remote_cached_options)
|
|
243
291
|
namespace = __active_remote_cached_options.delete(:namespace)
|
|
244
292
|
cache_key = [
|
|
245
293
|
RUBY_AND_ACTIVE_SUPPORT_VERSION,
|
|
246
294
|
namespace,
|
|
247
295
|
name,
|
|
248
296
|
"#find",
|
|
249
|
-
|
|
297
|
+
#{expanded_cache_key_args}
|
|
250
298
|
].compact
|
|
251
299
|
|
|
252
300
|
::ActiveRemote::Cached.cache.exist?(cache_key)
|
|
@@ -254,28 +302,30 @@ module ActiveRemote
|
|
|
254
302
|
RUBY
|
|
255
303
|
|
|
256
304
|
singleton_class.send(:alias_method, "#{method_name}?", method_name)
|
|
305
|
+
|
|
306
|
+
cached_finder_options[method_name] = cached_finder_options_hash
|
|
307
|
+
cached_methods << method_name
|
|
308
|
+
cached_methods << "#{method_name}?"
|
|
257
309
|
end
|
|
258
310
|
|
|
259
|
-
def _define_cached_exist_search_method(method_name, *method_arguments,
|
|
311
|
+
def _define_cached_exist_search_method(method_name, *method_arguments, cached_finder_options_hash)
|
|
260
312
|
method_arguments.flatten!
|
|
261
313
|
expanded_method_args = method_arguments.join(',')
|
|
262
|
-
|
|
263
|
-
cached_methods << method_name
|
|
264
|
-
cached_methods << "#{method_name}?"
|
|
314
|
+
expanded_cache_key_args = _expanded_cache_key_args(method_arguments)
|
|
265
315
|
|
|
266
316
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
267
317
|
# def self.cached_exist_search_by_user_guid(user_guid, options = {})
|
|
268
318
|
# ::ActiveRemote::Cached.cache.exist?([namespace, name, "#search", user_guid])
|
|
269
319
|
# end
|
|
270
320
|
def self.#{method_name}(#{expanded_method_args}, __active_remote_cached_options = {})
|
|
271
|
-
__active_remote_cached_options = ::ActiveRemote::Cached.default_options.merge(#{
|
|
321
|
+
__active_remote_cached_options = ::ActiveRemote::Cached.default_options.merge(_cached_finder_options_for('#{method_name}')).merge(__active_remote_cached_options)
|
|
272
322
|
namespace = __active_remote_cached_options.delete(:namespace)
|
|
273
323
|
cache_key = [
|
|
274
324
|
RUBY_AND_ACTIVE_SUPPORT_VERSION,
|
|
275
325
|
namespace,
|
|
276
326
|
name,
|
|
277
327
|
"#search",
|
|
278
|
-
|
|
328
|
+
#{expanded_cache_key_args}
|
|
279
329
|
].compact
|
|
280
330
|
|
|
281
331
|
::ActiveRemote::Cached.cache.exist?(cache_key)
|
|
@@ -283,18 +333,18 @@ module ActiveRemote
|
|
|
283
333
|
RUBY
|
|
284
334
|
|
|
285
335
|
singleton_class.send(:alias_method, "#{method_name}?", method_name)
|
|
336
|
+
|
|
337
|
+
cached_finder_options[method_name] = cached_finder_options_hash
|
|
338
|
+
cached_methods << method_name
|
|
339
|
+
cached_methods << "#{method_name}?"
|
|
286
340
|
end
|
|
287
341
|
|
|
288
|
-
def _define_cached_find_method(method_name, *method_arguments,
|
|
342
|
+
def _define_cached_find_method(method_name, *method_arguments, cached_finder_options_hash)
|
|
289
343
|
method_arguments.flatten!
|
|
290
344
|
expanded_method_args = method_arguments.join(',')
|
|
291
|
-
|
|
292
|
-
cached_methods << method_name
|
|
345
|
+
expanded_cache_key_args = _expanded_cache_key_args(method_arguments)
|
|
293
346
|
|
|
294
|
-
expanded_search_args =
|
|
295
|
-
method_arguments.each do |method_argument|
|
|
296
|
-
expanded_search_args << ":#{method_argument} => #{method_argument},"
|
|
297
|
-
end
|
|
347
|
+
expanded_search_args = _expanded_search_args(method_arguments)
|
|
298
348
|
|
|
299
349
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
300
350
|
# def self.cached_find_by_user_guid(user_guid, options = {})
|
|
@@ -309,14 +359,14 @@ module ActiveRemote
|
|
|
309
359
|
# of the result object is maintained for requests/responses
|
|
310
360
|
#
|
|
311
361
|
def self.#{method_name}(#{expanded_method_args}, __active_remote_cached_options = {})
|
|
312
|
-
__active_remote_cached_options = ::ActiveRemote::Cached.default_options.merge(#{
|
|
362
|
+
__active_remote_cached_options = ::ActiveRemote::Cached.default_options.merge(_cached_finder_options_for('#{method_name}')).merge(__active_remote_cached_options)
|
|
313
363
|
namespace = __active_remote_cached_options.delete(:namespace)
|
|
314
364
|
cache_key = [
|
|
315
365
|
RUBY_AND_ACTIVE_SUPPORT_VERSION,
|
|
316
366
|
namespace,
|
|
317
367
|
name,
|
|
318
368
|
"#find",
|
|
319
|
-
|
|
369
|
+
#{expanded_cache_key_args}
|
|
320
370
|
].compact
|
|
321
371
|
|
|
322
372
|
::ActiveRemote::Cached.cache.fetch(cache_key, __active_remote_cached_options) do
|
|
@@ -328,18 +378,17 @@ module ActiveRemote
|
|
|
328
378
|
end
|
|
329
379
|
end
|
|
330
380
|
RUBY
|
|
381
|
+
|
|
382
|
+
cached_finder_options[method_name] = cached_finder_options_hash
|
|
383
|
+
cached_methods << method_name
|
|
331
384
|
end
|
|
332
385
|
|
|
333
|
-
def _define_cached_search_method(method_name, *method_arguments,
|
|
386
|
+
def _define_cached_search_method(method_name, *method_arguments, cached_finder_options_hash)
|
|
334
387
|
method_arguments.flatten!
|
|
335
388
|
expanded_method_args = method_arguments.join(',')
|
|
336
|
-
|
|
337
|
-
cached_methods << method_name
|
|
389
|
+
expanded_cache_key_args = _expanded_cache_key_args(method_arguments)
|
|
338
390
|
|
|
339
|
-
expanded_search_args =
|
|
340
|
-
method_arguments.each do |method_argument|
|
|
341
|
-
expanded_search_args << ":#{method_argument} => #{method_argument},"
|
|
342
|
-
end
|
|
391
|
+
expanded_search_args = _expanded_search_args(method_arguments)
|
|
343
392
|
|
|
344
393
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
345
394
|
# def self.cached_search_by_user_guid(user_guid, options = {})
|
|
@@ -358,14 +407,14 @@ module ActiveRemote
|
|
|
358
407
|
# of the result object is maintained for requests/responses
|
|
359
408
|
#
|
|
360
409
|
def self.#{method_name}(#{expanded_method_args}, __active_remote_cached_options = {})
|
|
361
|
-
__active_remote_cached_options = ::ActiveRemote::Cached.default_options.merge(#{
|
|
410
|
+
__active_remote_cached_options = ::ActiveRemote::Cached.default_options.merge(_cached_finder_options_for('#{method_name}')).merge(__active_remote_cached_options)
|
|
362
411
|
namespace = __active_remote_cached_options.delete(:namespace)
|
|
363
412
|
cache_key = [
|
|
364
413
|
RUBY_AND_ACTIVE_SUPPORT_VERSION,
|
|
365
414
|
namespace,
|
|
366
415
|
name,
|
|
367
416
|
"#search",
|
|
368
|
-
|
|
417
|
+
#{expanded_cache_key_args}
|
|
369
418
|
].compact
|
|
370
419
|
|
|
371
420
|
::ActiveRemote::Cached.cache.fetch(cache_key, __active_remote_cached_options) do
|
|
@@ -377,18 +426,17 @@ module ActiveRemote
|
|
|
377
426
|
end
|
|
378
427
|
end
|
|
379
428
|
RUBY
|
|
429
|
+
|
|
430
|
+
cached_finder_options[method_name] = cached_finder_options_hash
|
|
431
|
+
cached_methods << method_name
|
|
380
432
|
end
|
|
381
433
|
|
|
382
|
-
def _define_cached_search_bang_method(method_name, *method_arguments,
|
|
434
|
+
def _define_cached_search_bang_method(method_name, *method_arguments, cached_finder_options_hash)
|
|
383
435
|
method_arguments.flatten!
|
|
384
436
|
expanded_method_args = method_arguments.join(',')
|
|
385
|
-
|
|
386
|
-
cached_methods << method_name
|
|
437
|
+
expanded_cache_key_args = _expanded_cache_key_args(method_arguments)
|
|
387
438
|
|
|
388
|
-
expanded_search_args =
|
|
389
|
-
method_arguments.each do |method_argument|
|
|
390
|
-
expanded_search_args << ":#{method_argument} => #{method_argument},"
|
|
391
|
-
end
|
|
439
|
+
expanded_search_args = _expanded_search_args(method_arguments)
|
|
392
440
|
|
|
393
441
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
394
442
|
# def self.cached_search_by_user_guid!(user_guid, options = {})
|
|
@@ -403,7 +451,7 @@ module ActiveRemote
|
|
|
403
451
|
# results = self.search(:user_guid => user_guid)
|
|
404
452
|
# end
|
|
405
453
|
#
|
|
406
|
-
# raise ::ActiveRemote::RemoteRecordNotFound
|
|
454
|
+
# raise ::ActiveRemote::RemoteRecordNotFound, self if results.nil? || results.first.nil?
|
|
407
455
|
# results
|
|
408
456
|
# end
|
|
409
457
|
# end
|
|
@@ -412,14 +460,14 @@ module ActiveRemote
|
|
|
412
460
|
# of the result object is maintained for requests/responses
|
|
413
461
|
#
|
|
414
462
|
def self.#{method_name}(#{expanded_method_args}, __active_remote_cached_options = {})
|
|
415
|
-
__active_remote_cached_options = ::ActiveRemote::Cached.default_options.merge(#{
|
|
463
|
+
__active_remote_cached_options = ::ActiveRemote::Cached.default_options.merge(_cached_finder_options_for('#{method_name}')).merge(__active_remote_cached_options)
|
|
416
464
|
namespace = __active_remote_cached_options.delete(:namespace)
|
|
417
465
|
cache_key = [
|
|
418
466
|
RUBY_AND_ACTIVE_SUPPORT_VERSION,
|
|
419
467
|
namespace,
|
|
420
468
|
name,
|
|
421
469
|
"#search",
|
|
422
|
-
|
|
470
|
+
#{expanded_cache_key_args}
|
|
423
471
|
].compact
|
|
424
472
|
|
|
425
473
|
::ActiveRemote::Cached.cache.fetch(cache_key, __active_remote_cached_options) do
|
|
@@ -431,11 +479,14 @@ module ActiveRemote
|
|
|
431
479
|
results = self.search(#{expanded_search_args})
|
|
432
480
|
end
|
|
433
481
|
|
|
434
|
-
raise ::ActiveRemote::RemoteRecordNotFound
|
|
482
|
+
raise ::ActiveRemote::RemoteRecordNotFound, self if results.nil? || results.first.nil?
|
|
435
483
|
results
|
|
436
484
|
end
|
|
437
485
|
end
|
|
438
486
|
RUBY
|
|
487
|
+
|
|
488
|
+
cached_finder_options[method_name] = cached_finder_options_hash
|
|
489
|
+
cached_methods << method_name
|
|
439
490
|
end
|
|
440
491
|
end
|
|
441
492
|
|
|
@@ -24,4 +24,128 @@ describe ::ActiveRemote::Cached::ArgumentKeys do
|
|
|
24
24
|
options = { :active_remote_cached_replace_characters => true }
|
|
25
25
|
expect(::ActiveRemote::Cached::ArgumentKeys.new('hello {}', options).cache_key).to eq('helloSPLBRB')
|
|
26
26
|
end
|
|
27
|
+
|
|
28
|
+
it 'replaces a tab when :active_remote_cached_replace_characters' do
|
|
29
|
+
options = { :active_remote_cached_replace_characters => true }
|
|
30
|
+
expect(::ActiveRemote::Cached::ArgumentKeys.new("a\tb", options).cache_key).to eq('aTBb')
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'replaces a newline when :active_remote_cached_replace_characters' do
|
|
34
|
+
options = { :active_remote_cached_replace_characters => true }
|
|
35
|
+
expect(::ActiveRemote::Cached::ArgumentKeys.new("a\nb", options).cache_key).to eq('aNLb')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# REMOVE_CHARACTERS uses [[:space:]], so both options must cover the same
|
|
39
|
+
# whitespace. A raw tab or newline in a key breaks the Memcached protocol.
|
|
40
|
+
it 'leaves no whitespace in the key under either option' do
|
|
41
|
+
argument = "a b\tc\nd\re\ff\vg"
|
|
42
|
+
|
|
43
|
+
removed = ::ActiveRemote::Cached::ArgumentKeys.new(
|
|
44
|
+
argument, :active_remote_cached_remove_characters => true
|
|
45
|
+
).cache_key
|
|
46
|
+
replaced = ::ActiveRemote::Cached::ArgumentKeys.new(
|
|
47
|
+
argument, :active_remote_cached_replace_characters => true
|
|
48
|
+
).cache_key
|
|
49
|
+
|
|
50
|
+
expect(removed).not_to match(/[[:space:]]/)
|
|
51
|
+
expect(replaced).not_to match(/[[:space:]]/)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'joins multiple arguments into one key' do
|
|
55
|
+
expect(::ActiveRemote::Cached::ArgumentKeys.new('hello', 'world', {}).cache_key).to eq('helloworld')
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'removes nil arguments from the key' do
|
|
59
|
+
expect(::ActiveRemote::Cached::ArgumentKeys.new('hello', nil, 'world', {}).cache_key).to eq('helloworld')
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'flattens nested array arguments into the key' do
|
|
63
|
+
expect(::ActiveRemote::Cached::ArgumentKeys.new(['hello', ['world']], {}).cache_key).to eq('helloworld')
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it 'returns an empty key when no arguments are given' do
|
|
67
|
+
expect(::ActiveRemote::Cached::ArgumentKeys.new({}).cache_key).to eq('')
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it 'returns the cache key from #to_s' do
|
|
71
|
+
expect(::ActiveRemote::Cached::ArgumentKeys.new('hello', {}).to_s).to eq('hello')
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it 'removes characters when both the remove and the replace option are given' do
|
|
75
|
+
options = {
|
|
76
|
+
:active_remote_cached_remove_characters => true,
|
|
77
|
+
:active_remote_cached_replace_characters => true
|
|
78
|
+
}
|
|
79
|
+
expect(::ActiveRemote::Cached::ArgumentKeys.new('hello {}', options).cache_key).to eq('hello')
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
describe '.for_fields' do
|
|
83
|
+
it 'names each field in the key' do
|
|
84
|
+
argument_keys = ::ActiveRemote::Cached::ArgumentKeys.for_fields(%i[alpha beta], %w[x y], {})
|
|
85
|
+
|
|
86
|
+
expect(argument_keys.cache_key).to eq('alpha.x/beta.y')
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it 'gives two finders with the same values two different keys' do
|
|
90
|
+
alpha_beta = ::ActiveRemote::Cached::ArgumentKeys.for_fields(%i[alpha beta], %w[x y], {})
|
|
91
|
+
gamma_delta = ::ActiveRemote::Cached::ArgumentKeys.for_fields(%i[gamma delta], %w[x y], {})
|
|
92
|
+
|
|
93
|
+
expect(alpha_beta.cache_key).not_to eq(gamma_delta.cache_key)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it 'gives a single field a different key than two fields with the same characters' do
|
|
97
|
+
one_field = ::ActiveRemote::Cached::ArgumentKeys.for_fields(%i[guid], %w[xy], {})
|
|
98
|
+
two_fields = ::ActiveRemote::Cached::ArgumentKeys.for_fields(%i[alpha beta], %w[x y], {})
|
|
99
|
+
|
|
100
|
+
expect(one_field.cache_key).not_to eq(two_fields.cache_key)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it 'joins an array value with a comma' do
|
|
104
|
+
argument_keys = ::ActiveRemote::Cached::ArgumentKeys.for_fields(%i[guid], [%w[a b]], {})
|
|
105
|
+
|
|
106
|
+
expect(argument_keys.cache_key).to eq('guid.a.b')
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it 'removes a nil inside an array value' do
|
|
110
|
+
argument_keys = ::ActiveRemote::Cached::ArgumentKeys.for_fields(%i[guid], [['a', nil, 'b']], {})
|
|
111
|
+
|
|
112
|
+
expect(argument_keys.cache_key).to eq('guid.a.b')
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it 'gives an empty value for a nil argument' do
|
|
116
|
+
argument_keys = ::ActiveRemote::Cached::ArgumentKeys.for_fields(%i[alpha beta], ['x', nil], {})
|
|
117
|
+
|
|
118
|
+
expect(argument_keys.cache_key).to eq('alpha.x/beta.')
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it 'escapes a separator inside a value' do
|
|
122
|
+
argument_keys = ::ActiveRemote::Cached::ArgumentKeys.for_fields(%i[guid], ['a/b.c%d'], {})
|
|
123
|
+
|
|
124
|
+
expect(argument_keys.cache_key).to eq('guid.a%2Fb%2Ec%25d')
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it 'keeps the separators when the remove option is given' do
|
|
128
|
+
options = { :active_remote_cached_remove_characters => true }
|
|
129
|
+
argument_keys = ::ActiveRemote::Cached::ArgumentKeys.for_fields(%i[alpha beta], ['hello {}', 'y'], options)
|
|
130
|
+
|
|
131
|
+
expect(argument_keys.cache_key).to eq('alpha.hello/beta.y')
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it 'keeps the separators when the replace option is given' do
|
|
135
|
+
options = { :active_remote_cached_replace_characters => true }
|
|
136
|
+
argument_keys = ::ActiveRemote::Cached::ArgumentKeys.for_fields(%i[alpha beta], ['hello {}', 'y'], options)
|
|
137
|
+
|
|
138
|
+
expect(argument_keys.cache_key).to eq('alpha.helloSPLBRB/beta.y')
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# #cache_key calls gsub! on an instance variable, so a second call must not
|
|
143
|
+
# replace the characters of the first result again.
|
|
144
|
+
it 'returns the same key when :active_remote_cached_replace_characters is called twice' do
|
|
145
|
+
options = { :active_remote_cached_replace_characters => true }
|
|
146
|
+
argument_keys = ::ActiveRemote::Cached::ArgumentKeys.new('hello {}', options)
|
|
147
|
+
|
|
148
|
+
expect(argument_keys.cache_key).to eq('helloSPLBRB')
|
|
149
|
+
expect(argument_keys.cache_key).to eq('helloSPLBRB')
|
|
150
|
+
end
|
|
27
151
|
end
|