cache_crispies 0.1.0 → 0.1.1
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/lib/cache_crispies.rb +11 -3
- data/lib/cache_crispies/attribute.rb +40 -5
- data/lib/cache_crispies/base.rb +68 -13
- data/lib/cache_crispies/collection.rb +16 -1
- data/lib/cache_crispies/condition.rb +16 -4
- data/lib/cache_crispies/controller.rb +16 -1
- data/lib/cache_crispies/hash_builder.rb +11 -1
- data/lib/cache_crispies/memoizer.rb +11 -1
- data/lib/cache_crispies/plan.rb +39 -1
- data/lib/cache_crispies/version.rb +5 -2
- data/spec/attribute_spec.rb +2 -2
- data/spec/collection_spec.rb +1 -3
- data/spec/memoizer_spec.rb +0 -2
- data/spec/plan_spec.rb +19 -1
- data/spec/spec_helper.rb +6 -87
- metadata +15 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af451e5837f96664e141a147df118fbfffb7ee4fedc71cd5e6c34438b9069461
|
4
|
+
data.tar.gz: ffe23f3217c50b5c6bbbd183127a2274b6c4afb59ad93e50a271c880d20968f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8208c9ef13c4f66e9d64c7b8a5394e7d2907b894ff4ca6617357ca785ede999048d3ef4ffc00d900a30e5ac284401a5b145fb2271764f878d16603017ac08d1
|
7
|
+
data.tar.gz: 167cf43b28151ec4d6c65c0badfcbe73a871f7a102bc916f04eb0e889069843e518db1a608da31c854096a60843bd50a69ab99a2b4b784a89ce1d5ecd5e549fe
|
data/lib/cache_crispies.rb
CHANGED
@@ -1,12 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_support/dependencies'
|
2
4
|
require 'oj'
|
3
5
|
|
6
|
+
# The top level namespace module for the gem
|
4
7
|
module CacheCrispies
|
5
|
-
|
6
|
-
|
8
|
+
# A prefix used in building cache key. This should be extra insurance against
|
9
|
+
# key conflicts and also provides an easy way to search for keys in Redis.
|
10
|
+
CACHE_KEY_PREFIX = 'cache-crispies'
|
11
|
+
|
12
|
+
# The string to use to join parts of the cache keys together
|
13
|
+
CACHE_KEY_SEPARATOR = '+'
|
7
14
|
|
8
15
|
require 'cache_crispies/version'
|
9
16
|
|
17
|
+
# Use autoload for better Rails development
|
10
18
|
autoload :Attribute, 'cache_crispies/attribute'
|
11
19
|
autoload :Base, 'cache_crispies/base'
|
12
20
|
autoload :Collection, 'cache_crispies/collection'
|
@@ -15,4 +23,4 @@ module CacheCrispies
|
|
15
23
|
autoload :Memoizer, 'cache_crispies/memoizer'
|
16
24
|
autoload :Controller, 'cache_crispies/controller'
|
17
25
|
autoload :Plan, 'cache_crispies/plan'
|
18
|
-
end
|
26
|
+
end
|
@@ -1,8 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CacheCrispies
|
4
|
+
# Reperesents a single serialized attribute in a serializer. It's generated
|
5
|
+
# by a call to either {CacheCrispies::Base.serialize} or
|
6
|
+
# {CacheCrispies::Base.merge}.
|
2
7
|
class Attribute
|
3
|
-
|
8
|
+
# Represents an invalid option passed in the to: argument
|
9
|
+
class InvalidCoercionType < ArgumentError; end
|
4
10
|
|
5
|
-
|
11
|
+
# Initializes a new CacheCrispies::Attribute instance
|
12
|
+
#
|
13
|
+
# @param key [Symbol] the JSON key for this attribute
|
14
|
+
# @param from [Symbol] the method on the model to call to get the value
|
15
|
+
# @param with [CacheCrispies::Base] a serializer to use to serialize the
|
16
|
+
# @param to [Class, Symbol] the data type to coerce the value into
|
17
|
+
# @param nesting [Array<Symbol>] the JSON keys this attribute will be
|
18
|
+
# nested inside
|
19
|
+
# @param conditions [Array<CacheCrispies::Condition>] the show_if condition
|
20
|
+
# blocks this attribute is nested inside. These will be evaluated for
|
21
|
+
# thruthiness and must all be true for this attribute to reneder.
|
22
|
+
# argument's value
|
23
|
+
def initialize(
|
24
|
+
key,
|
25
|
+
from: nil, with: nil, to: nil, nesting: [], conditions: []
|
26
|
+
)
|
6
27
|
@key = key
|
7
28
|
@method_name = from || key || :itself
|
8
29
|
@serializer = with
|
@@ -11,8 +32,22 @@ module CacheCrispies
|
|
11
32
|
@conditions = Array(conditions)
|
12
33
|
end
|
13
34
|
|
14
|
-
attr_reader
|
35
|
+
attr_reader(
|
36
|
+
:method_name,
|
37
|
+
:key,
|
38
|
+
:serializer,
|
39
|
+
:coerce_to,
|
40
|
+
:nesting,
|
41
|
+
:conditions
|
42
|
+
)
|
15
43
|
|
44
|
+
# Gets the value of the attribute for the given model and options
|
45
|
+
#
|
46
|
+
# @param model [Object] typically ActiveRecord::Base, but could be anything
|
47
|
+
# @param options [Hash] any optional values from the serializer instance
|
48
|
+
# @return the value for the attribute for the given model and options
|
49
|
+
# @raise [InvalidCoercionType] when an invalid argument is passed in the
|
50
|
+
# to: argument
|
16
51
|
def value_for(model, options)
|
17
52
|
value = model.public_send(method_name)
|
18
53
|
|
@@ -51,7 +86,7 @@ module CacheCrispies
|
|
51
86
|
!!value
|
52
87
|
else
|
53
88
|
raise(
|
54
|
-
|
89
|
+
InvalidCoercionType,
|
55
90
|
"#{coerce_to} has no registered coercion strategy"
|
56
91
|
)
|
57
92
|
end
|
@@ -63,4 +98,4 @@ module CacheCrispies
|
|
63
98
|
).public_send(method_name)
|
64
99
|
end
|
65
100
|
end
|
66
|
-
end
|
101
|
+
end
|
data/lib/cache_crispies/base.rb
CHANGED
@@ -1,50 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'digest'
|
2
4
|
require 'rails'
|
3
5
|
|
4
6
|
module CacheCrispies
|
7
|
+
# The Base class that all serializer classes should inherit from
|
5
8
|
class Base
|
6
9
|
attr_reader :model, :options
|
7
10
|
|
11
|
+
# Define class-level instance variables and their default values when the
|
12
|
+
# class is inherited by another class. This is not meant to be called
|
13
|
+
# directly. It is called internally by Ruby.
|
14
|
+
#
|
15
|
+
# @param other [Class] the inheriting child class
|
16
|
+
# @return [void]
|
17
|
+
def self.inherited(other)
|
18
|
+
other.instance_variable_set(:@attributes, [])
|
19
|
+
other.instance_variable_set(:@nesting, [])
|
20
|
+
other.instance_variable_set(:@conditions, [])
|
21
|
+
end
|
22
|
+
|
23
|
+
class << self
|
24
|
+
attr_reader :attributes
|
25
|
+
end
|
26
|
+
delegate :attributes, to: :class
|
27
|
+
|
28
|
+
# Initializes a new instance of CacheCrispies::Base, or really, it should
|
29
|
+
# always be a subclass of CacheCrispies::Base.
|
30
|
+
#
|
31
|
+
# @param model [Object] typically ActiveRecord::Base, but could be anything
|
32
|
+
# @param options [Hash] any optional custom values you want to be
|
33
|
+
# accessible in your subclass.
|
8
34
|
def initialize(model, options = {})
|
9
35
|
@model = model
|
10
36
|
@options = options
|
11
37
|
end
|
12
38
|
|
39
|
+
# Renders the serializer instance to a JSON-ready Hash
|
40
|
+
#
|
41
|
+
# @return [Hash] a JSON-ready hash
|
13
42
|
def as_json
|
14
43
|
HashBuilder.new(self).call
|
15
44
|
end
|
16
45
|
|
46
|
+
# Whether or not this serializer class should allow caching of results.
|
47
|
+
# It is set to false by default, but can be overridden in child classes.
|
48
|
+
#
|
49
|
+
# @return [Boolean]
|
17
50
|
def self.do_caching?
|
18
51
|
false
|
19
52
|
end
|
20
53
|
|
54
|
+
# A JSON key to use as a root key on a non-collection serializable. by
|
55
|
+
# default it's the name of the class without the "Serializer" part. But it
|
56
|
+
# can be overridden in a subclass to be anything.
|
57
|
+
#
|
58
|
+
# @return [Symbol] a symbol to be used as a key for a JSON-ready Hash
|
21
59
|
def self.key
|
22
60
|
to_s.demodulize.chomp('Serializer').underscore.to_sym
|
23
61
|
end
|
24
62
|
|
63
|
+
# A JSON key to use as a root key on a collection-type serializable. By
|
64
|
+
# deafult it's the plural version of .key, but it can be overridden in a
|
65
|
+
# subclass to be anything.
|
66
|
+
#
|
67
|
+
# @return [Symbol] a symbol to be used as a key for a JSON-ready Hash
|
25
68
|
def self.collection_key
|
26
69
|
return nil unless key
|
27
70
|
|
28
71
|
key.to_s.pluralize.to_sym
|
29
72
|
end
|
30
73
|
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
74
|
+
# An array of strings that should be added to the cache key for an instance
|
75
|
+
# of this serializer. Typically you'd add in the #cache_key or string value
|
76
|
+
# for any extra models or data passed in through the options hash here. But
|
77
|
+
# it could also contain any custom logic about how to construct a cache
|
78
|
+
# key. This method is meant to be overridden in subclasses.
|
79
|
+
#
|
80
|
+
# @example cache based off models provided in options
|
81
|
+
# def self.cache_key_addons(options)
|
82
|
+
# [options[:current_user].cache_key]
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# @example time-based caching
|
86
|
+
# def self.cache_key_addons(_options)
|
87
|
+
# [Date.today.to_s]
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# @param options [Hash] the options hash passed to the serializer, will be
|
91
|
+
# passed in here as well so you can refernce it if needed.
|
92
|
+
# @return [Array<String>]
|
34
93
|
def self.cache_key_addons(_options = {})
|
35
94
|
[]
|
36
95
|
end
|
37
96
|
|
97
|
+
# Return a cache key string for the serializer class to be included in the
|
98
|
+
# cache key for the instances. The key includes the name of the class, and
|
99
|
+
# a digest of the contents of the main class file.
|
100
|
+
#
|
101
|
+
# @return [String] a cache key for the class
|
38
102
|
def self.cache_key_base
|
39
103
|
# TODO: we may need to get a cache key from nested serializers as well :(
|
40
104
|
@cache_key_base ||= "#{self}-#{file_hash}"
|
41
105
|
end
|
42
106
|
|
43
|
-
def self.attributes
|
44
|
-
@attributes || []
|
45
|
-
end
|
46
|
-
delegate :attributes, to: :class
|
47
|
-
|
48
107
|
private
|
49
108
|
|
50
109
|
def self.file_hash
|
@@ -63,7 +122,6 @@ module CacheCrispies
|
|
63
122
|
private_class_method :path
|
64
123
|
|
65
124
|
def self.nest_in(key, &block)
|
66
|
-
@nesting ||= []
|
67
125
|
@nesting << key
|
68
126
|
|
69
127
|
block.call
|
@@ -73,7 +131,6 @@ module CacheCrispies
|
|
73
131
|
private_class_method :nest_in
|
74
132
|
|
75
133
|
def self.show_if(condition_proc, &block)
|
76
|
-
@conditions ||= []
|
77
134
|
@conditions << Condition.new(condition_proc)
|
78
135
|
|
79
136
|
block.call
|
@@ -83,8 +140,6 @@ module CacheCrispies
|
|
83
140
|
private_class_method :show_if
|
84
141
|
|
85
142
|
def self.serialize(*attribute_names, from: nil, with: nil, to: nil)
|
86
|
-
@attributes ||= []
|
87
|
-
|
88
143
|
attribute_names.flatten.map { |att| att&.to_sym }.map do |attrib|
|
89
144
|
current_nesting = Array(@nesting).dup
|
90
145
|
current_conditions = Array(@conditions).dup
|
@@ -107,4 +162,4 @@ module CacheCrispies
|
|
107
162
|
end
|
108
163
|
private_class_method :merge
|
109
164
|
end
|
110
|
-
end
|
165
|
+
end
|
@@ -1,13 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rails'
|
2
4
|
|
3
5
|
module CacheCrispies
|
6
|
+
# Handles rendering and possibly caching a collection of models using a
|
7
|
+
# Serializer
|
4
8
|
class Collection
|
9
|
+
# Initializes a new instance of CacheCrispies::Collection
|
10
|
+
#
|
11
|
+
# @param colleciton [Object] typically an enumerable containing instances of
|
12
|
+
# ActiveRecord::Base, but could be any enumerable
|
13
|
+
# @param serializer [CacheCrispies::Base] a class inheriting from
|
14
|
+
# CacheCrispies::Base
|
15
|
+
# @param options [Hash] any optional values from the serializer instance
|
5
16
|
def initialize(collection, serializer, options = {})
|
6
17
|
@collection = collection
|
7
18
|
@serializer = serializer
|
8
19
|
@options = options
|
9
20
|
end
|
10
21
|
|
22
|
+
# Renders the collection to a JSON-ready Hash trying to cache the hash
|
23
|
+
# along the way
|
24
|
+
#
|
25
|
+
# @return [Hash] the JSON-ready Hash
|
11
26
|
def as_json
|
12
27
|
if serializer.do_caching? && collection.respond_to?(:cache_key)
|
13
28
|
cached_json
|
@@ -40,4 +55,4 @@ module CacheCrispies
|
|
40
55
|
end
|
41
56
|
end
|
42
57
|
end
|
43
|
-
end
|
58
|
+
end
|
@@ -1,17 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CacheCrispies
|
2
|
-
# Represents an instance of a conditional built by a
|
4
|
+
# Represents an instance of a conditional built by a
|
5
|
+
# {CacheCrispies::Base.show_if} call
|
3
6
|
class Condition
|
7
|
+
# Returns a new instance of Condition
|
8
|
+
#
|
9
|
+
# @param block [Proc] a block containing the logic for the condition
|
4
10
|
def initialize(block)
|
5
11
|
@block = block
|
6
12
|
end
|
7
13
|
|
8
|
-
#
|
9
|
-
#
|
14
|
+
# A system-wide unique ID used for memoizaiton
|
15
|
+
#
|
16
|
+
# @eturn [Integer] the unique ID for this condition
|
10
17
|
def uid
|
11
18
|
# Just reusing the block's object_id seems to make sense
|
12
19
|
block.object_id
|
13
20
|
end
|
14
21
|
|
22
|
+
# Test the truthiness of the condition against a model and options
|
23
|
+
#
|
24
|
+
# @param model [Object] typically ActiveRecord::Base, but could be anything
|
25
|
+
# @param options [Hash] any optional values from the serializer instance
|
26
|
+
# @return [Boolean] the condition's truthiness
|
15
27
|
def true_for?(model, options = {})
|
16
28
|
!!case block.arity
|
17
29
|
when 0
|
@@ -27,4 +39,4 @@ module CacheCrispies
|
|
27
39
|
|
28
40
|
attr_reader :block
|
29
41
|
end
|
30
|
-
end
|
42
|
+
end
|
@@ -1,9 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CacheCrispies
|
4
|
+
# A Rails concern designed to be used in Rails controllers to provide access to
|
5
|
+
# the #cache_render method
|
2
6
|
module Controller
|
3
7
|
extend ActiveSupport::Concern
|
4
8
|
|
9
|
+
# The serialization mode that should be used with the oj gem
|
5
10
|
OJ_MODE = :rails
|
6
11
|
|
12
|
+
# Renders the provided cacheable object to JSON using the provided
|
13
|
+
# serializer
|
14
|
+
#
|
15
|
+
# @param serializer [CacheCrispies::Base] a class inheriting from
|
16
|
+
# CacheCrispies::Base
|
17
|
+
# @param cacheable [Object] can be any object. But is typically a Rails
|
18
|
+
# model inheriting from ActiveRecord::Base
|
19
|
+
# @param options [Hash] any hash of custom options that should be passed
|
20
|
+
# to the serializer instance
|
21
|
+
# @return [void]
|
7
22
|
def cache_render(serializer, cacheable, options = {})
|
8
23
|
plan = CacheCrispies::Plan.new(serializer, cacheable, options)
|
9
24
|
|
@@ -23,4 +38,4 @@ module CacheCrispies
|
|
23
38
|
render json: Oj.dump(plan.wrap(serializer_json), mode: OJ_MODE)
|
24
39
|
end
|
25
40
|
end
|
26
|
-
end
|
41
|
+
end
|
@@ -1,10 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CacheCrispies
|
4
|
+
# Builds out a JSON-ready Hash using the attributes in a Serializer
|
2
5
|
class HashBuilder
|
6
|
+
# Initializes a new instance of CacheCrispies::HashBuilder
|
7
|
+
#
|
8
|
+
# @param serializer [CacheCrispies::Base] an instance of a subclass of
|
9
|
+
# CacheCrispies::Base
|
3
10
|
def initialize(serializer)
|
4
11
|
@serializer = serializer
|
5
12
|
@condition_results = Memoizer.new
|
6
13
|
end
|
7
14
|
|
15
|
+
# Builds the Hash
|
16
|
+
#
|
17
|
+
# @return [Hash]
|
8
18
|
def call
|
9
19
|
hash = {}
|
10
20
|
|
@@ -58,4 +68,4 @@ module CacheCrispies
|
|
58
68
|
attribute.value_for(target, serializer.options)
|
59
69
|
end
|
60
70
|
end
|
61
|
-
end
|
71
|
+
end
|
@@ -1,9 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CacheCrispies
|
4
|
+
# Simple class to handle memoizing values by a key. This really just provides
|
5
|
+
# a bit of wrapper around doing this yourself with a hash.
|
2
6
|
class Memoizer
|
3
7
|
def initialize
|
4
8
|
@cache = {}
|
5
9
|
end
|
6
10
|
|
11
|
+
# Fetches a cached value for the given key, if it exists. Otherwise it calls
|
12
|
+
# the block and caches that value
|
13
|
+
#
|
14
|
+
# @param key [Object] the value to use as a cache key
|
15
|
+
# @yield the value to cache and return if there is a cache miss
|
16
|
+
# @return [Object] either the cached value or the block's value
|
7
17
|
def fetch(key, &_block)
|
8
18
|
# Avoid ||= because we need to memoize falsey values.
|
9
19
|
return cache[key] if cache.key?(key)
|
@@ -15,4 +25,4 @@ module CacheCrispies
|
|
15
25
|
|
16
26
|
attr_reader :cache
|
17
27
|
end
|
18
|
-
end
|
28
|
+
end
|
data/lib/cache_crispies/plan.rb
CHANGED
@@ -1,7 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CacheCrispies
|
4
|
+
# Represents a plan on how to cache a given cacheable with a given serializer
|
2
5
|
class Plan
|
3
6
|
attr_reader :serializer, :cacheable, :options
|
4
7
|
|
8
|
+
# Initializes a new instance of CacheCrispies::Plan
|
9
|
+
#
|
10
|
+
# @param serializer [CacheCrispies::Base] a class inheriting from
|
11
|
+
# CacheCrispies::Base
|
12
|
+
# @param cacheable [Object] typically ActiveRecord::Base or an enumerable
|
13
|
+
# containing instances of ActiveRecord::Base, but could be anything
|
14
|
+
# @param options [Hash] any optional values from the serializer instance
|
5
15
|
def initialize(serializer, cacheable, options = {})
|
6
16
|
@serializer = serializer
|
7
17
|
@cacheable = cacheable
|
@@ -9,14 +19,30 @@ module CacheCrispies
|
|
9
19
|
@options = options
|
10
20
|
end
|
11
21
|
|
22
|
+
# Whether or not the cacheable should be treated like a collection
|
23
|
+
#
|
24
|
+
# @return [Boolean] true if cacheable is a collection
|
12
25
|
def collection?
|
13
26
|
cacheable.respond_to?(:each)
|
14
27
|
end
|
15
28
|
|
29
|
+
# Returns the cache_key in a format suitable for an ETag header
|
30
|
+
#
|
31
|
+
# @return [String] an MD5 digest of cache_key
|
16
32
|
def etag
|
17
33
|
Digest::MD5.hexdigest(cache_key)
|
18
34
|
end
|
19
35
|
|
36
|
+
# Returns a string of cache keys for all dependent objects. Changes to any
|
37
|
+
# of keys should bust the overall key for this plan. The key consists of:
|
38
|
+
# - a global key for this gem
|
39
|
+
# - the serializers class name
|
40
|
+
# - a digest of the contents of the of serializer class file
|
41
|
+
# - any addon keys the serializer may define
|
42
|
+
# - the #cache_key method on the cacheable (ActiveRecord provides this by
|
43
|
+
# default)
|
44
|
+
#
|
45
|
+
# @return [String] a suitable cache key
|
20
46
|
def cache_key
|
21
47
|
@cache_key ||=
|
22
48
|
[
|
@@ -27,6 +53,11 @@ module CacheCrispies
|
|
27
53
|
].flatten.compact.join(CACHE_KEY_SEPARATOR)
|
28
54
|
end
|
29
55
|
|
56
|
+
# Caches the contents of the block, if the plan is cacheable, otherwise
|
57
|
+
# calls yields to the block directly
|
58
|
+
#
|
59
|
+
# @yield calls the block that should return a value to be cached
|
60
|
+
# @return whatever the provided block returns
|
30
61
|
def cache
|
31
62
|
if cache?
|
32
63
|
Rails.cache.fetch(cache_key) { yield }
|
@@ -35,6 +66,13 @@ module CacheCrispies
|
|
35
66
|
end
|
36
67
|
end
|
37
68
|
|
69
|
+
# Wraps a value in a JSON key/object. Returns json_hash directly if there
|
70
|
+
# is no key.
|
71
|
+
#
|
72
|
+
# @param json_hash [Hash, Array, Object] typically a JSON-ready Hash or
|
73
|
+
# Array, but could be anything really
|
74
|
+
# @return [Hash, Object] will return a hash with a single key of #key,
|
75
|
+
# unless there is no #key, then returns the json_hash directly.
|
38
76
|
def wrap(json_hash)
|
39
77
|
return json_hash unless key?
|
40
78
|
|
@@ -65,4 +103,4 @@ module CacheCrispies
|
|
65
103
|
Digest::MD5.hexdigest(addons.join('|'))
|
66
104
|
end
|
67
105
|
end
|
68
|
-
end
|
106
|
+
end
|
data/spec/attribute_spec.rb
CHANGED
@@ -151,9 +151,9 @@ describe CacheCrispies::Attribute do
|
|
151
151
|
let(:to) { OpenStruct }
|
152
152
|
|
153
153
|
it 'raises an exception' do
|
154
|
-
expect { subject }.to raise_exception CacheCrispies::Attribute::
|
154
|
+
expect { subject }.to raise_exception CacheCrispies::Attribute::InvalidCoercionType
|
155
155
|
end
|
156
156
|
end
|
157
157
|
end
|
158
158
|
end
|
159
|
-
end
|
159
|
+
end
|
data/spec/collection_spec.rb
CHANGED
@@ -20,9 +20,7 @@ describe CacheCrispies::Collection do
|
|
20
20
|
let(:uncacheable_models) { [model1, model2] }
|
21
21
|
let(:cacheable_models) {
|
22
22
|
[model1, model2].tap do |models|
|
23
|
-
def models.cache_key
|
24
|
-
'cereals-key'
|
25
|
-
end
|
23
|
+
def models.cache_key() end
|
26
24
|
end
|
27
25
|
}
|
28
26
|
let(:collection) { cacheable_models }
|
data/spec/memoizer_spec.rb
CHANGED
@@ -3,8 +3,6 @@ require 'spec_helper'
|
|
3
3
|
describe CacheCrispies::Memoizer do
|
4
4
|
describe '#fetch' do
|
5
5
|
it 'only calls the block once per key' do
|
6
|
-
block = -> {}
|
7
|
-
|
8
6
|
expect { |block| subject.fetch 1, &block }.to yield_with_no_args
|
9
7
|
expect { |block| subject.fetch 1, &block }.to_not yield_with_no_args
|
10
8
|
expect { |block| subject.fetch 2, &block }.to yield_with_no_args
|
data/spec/plan_spec.rb
CHANGED
@@ -49,7 +49,10 @@ describe CacheCrispies::Plan do
|
|
49
49
|
end
|
50
50
|
|
51
51
|
describe '#etag' do
|
52
|
-
|
52
|
+
it 'generates an MD5 digest of the cache_key' do
|
53
|
+
expect(subject).to receive(:cache_key).and_return 'foo'
|
54
|
+
expect(subject.etag).to eq Digest::MD5::hexdigest('foo')
|
55
|
+
end
|
53
56
|
end
|
54
57
|
|
55
58
|
describe '#cache_key' do
|
@@ -104,6 +107,21 @@ describe CacheCrispies::Plan do
|
|
104
107
|
end
|
105
108
|
|
106
109
|
describe '#cache' do
|
110
|
+
context 'when the plan is not cacheable' do
|
111
|
+
it "doesn't cache the results" do
|
112
|
+
expect(Rails).to_not receive(:cache)
|
113
|
+
subject.cache {}
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'when the plan is not cacheable' do
|
118
|
+
it "doesn't cache the results" do
|
119
|
+
expect(subject).to receive(:cache?).and_return true
|
120
|
+
expect(subject).to receive(:cache_key).and_return 'bar'
|
121
|
+
expect(Rails).to receive_message_chain(:cache, :fetch).with('bar')
|
122
|
+
subject.cache {}
|
123
|
+
end
|
124
|
+
end
|
107
125
|
end
|
108
126
|
|
109
127
|
describe '#wrap' do
|
data/spec/spec_helper.rb
CHANGED
@@ -1,102 +1,21 @@
|
|
1
|
-
require '
|
1
|
+
require 'simplecov'
|
2
|
+
SimpleCov.start
|
2
3
|
|
4
|
+
require 'byebug'
|
3
5
|
require_relative '../lib/cache_crispies'
|
4
6
|
|
5
|
-
# This file was generated by the `rspec --init` command. Conventionally, all
|
6
|
-
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
7
|
-
# The generated `.rspec` file contains `--require spec_helper` which will cause
|
8
|
-
# this file to always be loaded, without a need to explicitly require it in any
|
9
|
-
# files.
|
10
|
-
#
|
11
|
-
# Given that it is always loaded, you are encouraged to keep this file as
|
12
|
-
# light-weight as possible. Requiring heavyweight dependencies from this file
|
13
|
-
# will add to the boot time of your test suite on EVERY test run, even for an
|
14
|
-
# individual file that may not need all of that loaded. Instead, consider making
|
15
|
-
# a separate helper file that requires the additional dependencies and performs
|
16
|
-
# the additional setup, and require it from the spec files that actually need
|
17
|
-
# it.
|
18
|
-
#
|
19
|
-
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
20
7
|
RSpec.configure do |config|
|
21
|
-
# rspec-expectations config goes here. You can use an alternate
|
22
|
-
# assertion/expectation library such as wrong or the stdlib/minitest
|
23
|
-
# assertions if you prefer.
|
24
8
|
config.expect_with :rspec do |expectations|
|
25
|
-
# This option will default to `true` in RSpec 4. It makes the `description`
|
26
|
-
# and `failure_message` of custom matchers include text for helper methods
|
27
|
-
# defined using `chain`, e.g.:
|
28
|
-
# be_bigger_than(2).and_smaller_than(4).description
|
29
|
-
# # => "be bigger than 2 and smaller than 4"
|
30
|
-
# ...rather than:
|
31
|
-
# # => "be bigger than 2"
|
32
9
|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
33
10
|
end
|
34
11
|
|
35
|
-
# rspec-mocks config goes here. You can use an alternate test double
|
36
|
-
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
37
12
|
config.mock_with :rspec do |mocks|
|
38
|
-
# Prevents you from mocking or stubbing a method that does not exist on
|
39
|
-
# a real object. This is generally recommended, and will default to
|
40
|
-
# `true` in RSpec 4.
|
41
13
|
mocks.verify_partial_doubles = true
|
42
14
|
end
|
43
15
|
|
44
|
-
# This option will default to `:apply_to_host_groups` in RSpec 4 (and will
|
45
|
-
# have no way to turn it off -- the option exists only for backwards
|
46
|
-
# compatibility in RSpec 3). It causes shared context metadata to be
|
47
|
-
# inherited by the metadata hash of host groups and examples, rather than
|
48
|
-
# triggering implicit auto-inclusion in groups with matching metadata.
|
49
16
|
config.shared_context_metadata_behavior = :apply_to_host_groups
|
50
17
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
# # you care about by tagging them with `:focus` metadata. When nothing
|
55
|
-
# # is tagged with `:focus`, all examples get run. RSpec also provides
|
56
|
-
# # aliases for `it`, `describe`, and `context` that include `:focus`
|
57
|
-
# # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
|
58
|
-
# config.filter_run_when_matching :focus
|
59
|
-
#
|
60
|
-
# # Allows RSpec to persist some state between runs in order to support
|
61
|
-
# # the `--only-failures` and `--next-failure` CLI options. We recommend
|
62
|
-
# # you configure your source control system to ignore this file.
|
63
|
-
# config.example_status_persistence_file_path = "spec/examples.txt"
|
64
|
-
#
|
65
|
-
# # Limits the available syntax to the non-monkey patched syntax that is
|
66
|
-
# # recommended. For more details, see:
|
67
|
-
# # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
|
68
|
-
# # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
69
|
-
# # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
|
70
|
-
# config.disable_monkey_patching!
|
71
|
-
#
|
72
|
-
# # This setting enables warnings. It's recommended, but in some cases may
|
73
|
-
# # be too noisy due to issues in dependencies.
|
74
|
-
# config.warnings = true
|
75
|
-
#
|
76
|
-
# # Many RSpec users commonly either run the entire suite or an individual
|
77
|
-
# # file, and it's useful to allow more verbose output when running an
|
78
|
-
# # individual spec file.
|
79
|
-
# if config.files_to_run.one?
|
80
|
-
# # Use the documentation formatter for detailed output,
|
81
|
-
# # unless a formatter has already been configured
|
82
|
-
# # (e.g. via a command-line flag).
|
83
|
-
# config.default_formatter = "doc"
|
84
|
-
# end
|
85
|
-
#
|
86
|
-
# # Print the 10 slowest examples and example groups at the
|
87
|
-
# # end of the spec run, to help surface which specs are running
|
88
|
-
# # particularly slow.
|
89
|
-
# config.profile_examples = 10
|
90
|
-
#
|
91
|
-
# # Run specs in random order to surface order dependencies. If you find an
|
92
|
-
# # order dependency and want to debug it, you can fix the order by providing
|
93
|
-
# # the seed, which is printed after each run.
|
94
|
-
# # --seed 1234
|
95
|
-
# config.order = :random
|
96
|
-
#
|
97
|
-
# # Seed global randomization in this process using the `--seed` CLI option.
|
98
|
-
# # Setting this allows you to use `--seed` to deterministically reproduce
|
99
|
-
# # test failures related to randomization by passing the same `--seed` value
|
100
|
-
# # as the one that triggered the failure.
|
101
|
-
# Kernel.srand config.seed
|
18
|
+
config.warnings = true
|
19
|
+
config.order = :random
|
20
|
+
Kernel.srand config.seed
|
102
21
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cache_crispies
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Crownoble
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 3.8.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.17'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.17'
|
83
97
|
description:
|
84
98
|
email: adam@codenoble.com
|
85
99
|
executables: []
|