def_cache 0.1.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 +15 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/Guardfile +13 -0
- data/LICENSE.txt +22 -0
- data/README.md +103 -0
- data/Rakefile +5 -0
- data/def_cache.gemspec +35 -0
- data/lib/def_cache/cache_handler.rb +98 -0
- data/lib/def_cache/class_methods.rb +70 -0
- data/lib/def_cache/version.rb +3 -0
- data/lib/def_cache.rb +15 -0
- data/spec/lib/def_cache/cache_handler_spec.rb +107 -0
- data/spec/lib/def_cache/class_methods_spec.rb +140 -0
- data/spec/lib/def_cache_spec.rb +21 -0
- data/spec/spec_helper.rb +16 -0
- metadata +236 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
Njg0YzFlNjJkYWE0N2M5ZmFlMTE1ZmJkNjgwY2E5NjI5M2M3Mjc2MA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NTY1ZTcwODU3NGU0Zjg0MDhmZDVlOTg2ZjNjNTI1YTgzMDdkZmY1OA==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NDBjMGIxZWJiY2MwMTNiMDA1Y2QzODk4ODE4NGNjZDVkZjkxNDVlYzJjY2U5
|
10
|
+
MTgzZjgyYTE2ZTNjYmYxN2RmN2UzMTE1YTBhNTEyODg0ZDdhNTZlZGFlOTcx
|
11
|
+
NjBhYTBjYWM3ZWJiYThjNjI0MmYzYjkzMjIwZTU4MWEwODRhYzc=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZDQxMjZlNDRhMzEyNzg1YmRlMWQ5OTgyNjA4NTI3M2Y5MDM4Y2FmM2M2Mzc3
|
14
|
+
OTI5NWZiYjFmNjY5OTY2NGIyM2EyZWJiMDhhNGU3NDdlOWYzNjcyYjBmMWM2
|
15
|
+
MTQwNWM2OGQ4ZjRjZjAzZWRkOTk5ZmQ1YjcyMzg2ZjY4YWFhYTg=
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'bundler' do
|
5
|
+
watch('Gemfile')
|
6
|
+
watch(/^.+\.gemspec/)
|
7
|
+
end
|
8
|
+
|
9
|
+
guard :rspec do
|
10
|
+
watch(%r{^spec/.+_spec\.rb$})
|
11
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
12
|
+
watch('spec/spec_helper.rb') { "spec" }
|
13
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Jason Waldrip
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
# DefCache
|
2
|
+
|
3
|
+
[](http://allthebadges.io/jwaldrip/def_cache/badge_fury)
|
4
|
+
[](http://allthebadges.io/jwaldrip/def_cache/gemnasium)
|
5
|
+
[](http://allthebadges.io/jwaldrip/def_cache/travis)
|
6
|
+
[](http://allthebadges.io/jwaldrip/def_cache/coveralls)
|
7
|
+
[](http://allthebadges.io/jwaldrip/def_cache/code_climate)
|
8
|
+
|
9
|
+
A gem for dynamically caching methods in your classes
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
gem 'def_cache'
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install funky_cache
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
### Basic
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
|
31
|
+
class MyClass
|
32
|
+
include DefCache
|
33
|
+
|
34
|
+
cache_method :my_foo_method
|
35
|
+
|
36
|
+
def my_foo_method(bar, baz)
|
37
|
+
"hello world"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
```
|
42
|
+
|
43
|
+
### With Cache Options
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
|
47
|
+
class MyClass
|
48
|
+
include DefCache
|
49
|
+
|
50
|
+
cache_method :my_foo_method, expires_in: 30.minutes
|
51
|
+
|
52
|
+
def my_foo_method(bar, baz)
|
53
|
+
"hello world"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
```
|
58
|
+
|
59
|
+
### With Dynamic Keys
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
|
63
|
+
class MyClass
|
64
|
+
include DefCache
|
65
|
+
|
66
|
+
cache_method :my_foo_method, keys: [:dyno_key]
|
67
|
+
|
68
|
+
def my_foo_method(bar, baz)
|
69
|
+
"hello world"
|
70
|
+
end
|
71
|
+
|
72
|
+
def dyno_key
|
73
|
+
"value of key"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
```
|
78
|
+
|
79
|
+
### With a custom store
|
80
|
+
|
81
|
+
***defaults to Rails.cache in rails or :memory_store in ruby***
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
|
85
|
+
class MyClass
|
86
|
+
include DefCache
|
87
|
+
|
88
|
+
cache_method :my_foo_method, with: :redis_store
|
89
|
+
|
90
|
+
def my_foo_method(bar, baz)
|
91
|
+
"hello world"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
```
|
96
|
+
|
97
|
+
## Contributing
|
98
|
+
|
99
|
+
1. Fork it
|
100
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
101
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
102
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
103
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/def_cache.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'def_cache/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "def_cache"
|
8
|
+
spec.version = DefCache::VERSION
|
9
|
+
spec.authors = ["Jason Waldrip"]
|
10
|
+
spec.email = ["jason@waldrip.net"]
|
11
|
+
spec.description = 'An agnostic ActiveSupport::Cache helper to enable easy caching of methods inside your classes.'
|
12
|
+
spec.summary = 'An agnostic ActiveSupport::Cache helper to enable easy caching of methods inside your classes.'
|
13
|
+
spec.homepage = "https://github.com/jwaldrip/funky_cache"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "activesupport", '>= 3.2'
|
22
|
+
spec.add_dependency "method_source"
|
23
|
+
|
24
|
+
spec.add_development_dependency "yard"
|
25
|
+
spec.add_development_dependency "rspec"
|
26
|
+
spec.add_development_dependency "pry"
|
27
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
28
|
+
spec.add_development_dependency "rake"
|
29
|
+
spec.add_development_dependency "guard"
|
30
|
+
spec.add_development_dependency "guard-rspec"
|
31
|
+
spec.add_development_dependency "guard-bundler"
|
32
|
+
spec.add_development_dependency "simplecov"
|
33
|
+
spec.add_development_dependency "coveralls"
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
class DefCache::CacheHandler
|
2
|
+
|
3
|
+
delegate :lookup_store, to: ActiveSupport::Cache
|
4
|
+
attr_reader :method_name, :instance, :keys, :cache_store, :cache_options, :miss_method
|
5
|
+
|
6
|
+
def initialize(method, instance, options={})
|
7
|
+
cached_target, punctuation = method.to_s.sub(/([?!=])$/, ''), $1
|
8
|
+
@cache_options = options.except(:with, :keys)
|
9
|
+
@logger = options[:logger]
|
10
|
+
@cache_store = fetch_store options[:with]
|
11
|
+
@miss_method = "#{cached_target}_without_cache#{punctuation}"
|
12
|
+
@method_name = method
|
13
|
+
@keys = Array.wrap(options[:keys]) || []
|
14
|
+
@instance = instance
|
15
|
+
end
|
16
|
+
|
17
|
+
def cache_key(*values)
|
18
|
+
key_values = keys.map { |key| instance.send(key) || '*' }
|
19
|
+
[instance_cache_key, *key_values, method_name, *values].select(&:present?).join('/')
|
20
|
+
end
|
21
|
+
|
22
|
+
def instance_method
|
23
|
+
instance.method(miss_method)
|
24
|
+
end
|
25
|
+
|
26
|
+
def instance_cache_key
|
27
|
+
instance.cache_key
|
28
|
+
rescue NoMethodError
|
29
|
+
instance.class.name
|
30
|
+
end
|
31
|
+
|
32
|
+
def logger
|
33
|
+
@logger ||= defined?(Rails) ? Rails.logger : Logger.new(STDOUT)
|
34
|
+
end
|
35
|
+
|
36
|
+
def method_cache_key(*args, &block)
|
37
|
+
params = instance_method.parameters.each_with_index do |(req, param), n|
|
38
|
+
send "#{req}_parameter_key", param, args[n], &block
|
39
|
+
end.compact.join(',')
|
40
|
+
cache_key *params
|
41
|
+
end
|
42
|
+
|
43
|
+
def index_cache_key
|
44
|
+
cache_key(:__index__)
|
45
|
+
end
|
46
|
+
|
47
|
+
def index
|
48
|
+
cache_store.fetch(index_cache_key){[]}
|
49
|
+
end
|
50
|
+
|
51
|
+
def remove_reference(cache_key)
|
52
|
+
new_index = index.delete(cache_key)
|
53
|
+
cache_store.write index_cache_key, new_index
|
54
|
+
end
|
55
|
+
|
56
|
+
def add_reference(cache_key)
|
57
|
+
unless index.include? cache_key
|
58
|
+
logger.info "adding cache ref: #{cache_key}"
|
59
|
+
new_index = index << cache_key
|
60
|
+
cache_store.write index_cache_key, new_index
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def flush!
|
65
|
+
index.each do |subkey|
|
66
|
+
logger.info "removing cache ref: #{subkey}"
|
67
|
+
cache_store.delete subkey
|
68
|
+
remove_reference subkey
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private :lookup_store
|
73
|
+
|
74
|
+
def fetch_store(store, options = {})
|
75
|
+
(store.is_a?(Symbol) ? lookup_store(store, options) : store) || default_store
|
76
|
+
end
|
77
|
+
|
78
|
+
def default_store
|
79
|
+
defined?(Rails) ? Rails.cache : ActiveSupport::Cache.lookup_store(:memory_store)
|
80
|
+
end
|
81
|
+
|
82
|
+
def req_parameter_key(param, value)
|
83
|
+
"#{param}=#{value.inspect}"
|
84
|
+
end
|
85
|
+
|
86
|
+
def opt_parameter_key(param, value)
|
87
|
+
"#{param}=#{value.inspect}" if value.present?
|
88
|
+
end
|
89
|
+
|
90
|
+
def rest_parameter_key(param, values)
|
91
|
+
"*#{param}=#{values.map(&:inspect)}" if values.present?
|
92
|
+
end
|
93
|
+
|
94
|
+
def block_parameter_key(param, value, &block)
|
95
|
+
"&#{param}(#{Digest::MD5.hexdigest(block.source)})" if block_given?
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module DefCache::ClassMethods
|
2
|
+
|
3
|
+
protected
|
4
|
+
|
5
|
+
# Add method(s) to be cached
|
6
|
+
def cache_method(*methods)
|
7
|
+
options = methods.extract_options!
|
8
|
+
methods.each do |method|
|
9
|
+
define_cache_method method, options
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
# Define the cache_method
|
16
|
+
def define_cache_method(method, options={})
|
17
|
+
stub_cache_method_original(method)
|
18
|
+
define_cache_handler_method(method, options)
|
19
|
+
define_cache_with_method(method)
|
20
|
+
cached_methods_just_added << method
|
21
|
+
alias_method_chain method, :cache
|
22
|
+
end
|
23
|
+
|
24
|
+
# Define cache with method
|
25
|
+
def define_cache_with_method(method)
|
26
|
+
target, punctuation = method.to_s.sub(/([?!=])$/, ''), $1
|
27
|
+
class_eval <<-RUBY
|
28
|
+
def #{target}_with_cache#{punctuation}(*args, &block)
|
29
|
+
handler = cache_handler_for_#{method}
|
30
|
+
handler.cache_store.fetch(handler.cache_key, handler.cache_options) do
|
31
|
+
handler.add_reference(handler.cache_key)
|
32
|
+
#{target}_without_cache#{punctuation} *args, &block
|
33
|
+
end
|
34
|
+
rescue MethodSource::SourceNotFoundError => e
|
35
|
+
warn e
|
36
|
+
#{target}_without_cache#{punctuation} *args, &block
|
37
|
+
end unless method_defined? :#{target}_with_cache#{punctuation}
|
38
|
+
RUBY
|
39
|
+
end
|
40
|
+
|
41
|
+
# Define cache handler method
|
42
|
+
def define_cache_handler_method(method, options = {})
|
43
|
+
define_method "cache_handler_for_#{method}" do
|
44
|
+
eval <<-RUBY
|
45
|
+
@cache_handler_for_#{method} ||= DefCache::CacheHandler.new(:#{method}, self, options)
|
46
|
+
RUBY
|
47
|
+
end unless method_defined? "cache_handler_for_#{method}"
|
48
|
+
end
|
49
|
+
|
50
|
+
# Define an empty method to avoid alias method chain errors
|
51
|
+
def stub_cache_method_original(method)
|
52
|
+
class_eval <<-RUBY
|
53
|
+
def #{method}
|
54
|
+
raise NoMethodError, "undefined method `#{method}' for #{self}"
|
55
|
+
end unless method_defined? :#{method}
|
56
|
+
RUBY
|
57
|
+
end
|
58
|
+
|
59
|
+
# Relink the original method if it is redefined
|
60
|
+
def method_added(method)
|
61
|
+
define_cache_method(method) if !cached_methods_just_added.delete(method) && method_defined?("#{method}_with_cache")
|
62
|
+
super
|
63
|
+
end
|
64
|
+
|
65
|
+
# A collection for just added methods
|
66
|
+
def cached_methods_just_added
|
67
|
+
@cached_methods_added ||= []
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
data/lib/def_cache.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "def_cache/version"
|
2
|
+
require "active_support/all"
|
3
|
+
|
4
|
+
module DefCache
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
extend ActiveSupport::Autoload
|
7
|
+
|
8
|
+
autoload :ClassMethods
|
9
|
+
autoload :CacheHandler
|
10
|
+
|
11
|
+
def flush_method_cache!
|
12
|
+
methods.select { |m| m.to_s.include? 'cache_handler_for_' }.each { |m| send(m).flush! }
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DefCache::CacheHandler do
|
4
|
+
|
5
|
+
let(:method_name){ nil }
|
6
|
+
let(:options){{}}
|
7
|
+
let(:klass){ stub_const 'SampleClass', Class.new { include DefCache } }
|
8
|
+
let(:instance){ klass.new }
|
9
|
+
before(:each){ klass.send(:cache_method, method_name) if method_name }
|
10
|
+
subject(:handler){ DefCache::CacheHandler.new(method_name, instance, options) }
|
11
|
+
|
12
|
+
describe '.new' do
|
13
|
+
context 'with defaults' do
|
14
|
+
let(:method_name){ :foo! }
|
15
|
+
let(:options){ { foo: :bar, baz: :raz } }
|
16
|
+
|
17
|
+
its(:cache_options){ should eq options.except(:with, :keys) }
|
18
|
+
its(:cache_store){ should be_a ActiveSupport::Cache::Store }
|
19
|
+
its(:miss_method){ should eq 'foo_without_cache!' }
|
20
|
+
its(:method_name){ should eq method_name }
|
21
|
+
its(:keys){ should be_empty }
|
22
|
+
its(:instance){ should eq instance }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#cache_key' do
|
27
|
+
let(:method_name){ :raz }
|
28
|
+
let(:keys){ [:foo, :bar, :baz] }
|
29
|
+
let(:options){ { keys: keys } }
|
30
|
+
before(:each) { keys.each { |key| allow(instance).to receive(key).and_return(SecureRandom.hex) } }
|
31
|
+
|
32
|
+
it 'should call each key on the instance' do
|
33
|
+
keys.each { |key| expect(instance).to receive(key) }
|
34
|
+
handler.cache_key
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should return the proper key' do
|
38
|
+
handler.cache_key(:test).should eq [klass.name, *keys.map { |k| instance.send(k) }, method_name, :test].join('/')
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#instance_method' do
|
44
|
+
let(:method_name){ :foo }
|
45
|
+
it 'should be the proper method' do
|
46
|
+
handler.instance_method.should be_a Method
|
47
|
+
handler.instance_method.name.should eq :foo_without_cache
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#instance_cache_key' do
|
52
|
+
pending
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '#logger' do
|
56
|
+
pending
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#method_cache_key' do
|
60
|
+
pending
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '#index_cache_key' do
|
64
|
+
pending
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '#index' do
|
68
|
+
pending
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '#remove_reference' do
|
72
|
+
pending
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#add_reference' do
|
76
|
+
pending
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#flush!' do
|
80
|
+
pending
|
81
|
+
end
|
82
|
+
|
83
|
+
describe '#fetch_store' do
|
84
|
+
pending
|
85
|
+
end
|
86
|
+
|
87
|
+
describe '#default_store' do
|
88
|
+
pending
|
89
|
+
end
|
90
|
+
|
91
|
+
describe '#req_parameter_key' do
|
92
|
+
pending
|
93
|
+
end
|
94
|
+
|
95
|
+
describe '#opt_parameter_key' do
|
96
|
+
pending
|
97
|
+
end
|
98
|
+
|
99
|
+
describe '#rest_parameter_key' do
|
100
|
+
pending
|
101
|
+
end
|
102
|
+
|
103
|
+
describe '#block_parameter_key' do
|
104
|
+
pending
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DefCache::ClassMethods do
|
4
|
+
|
5
|
+
subject(:klass) { stub_const 'SampleClass', Class.new { extend DefCache::ClassMethods } }
|
6
|
+
|
7
|
+
describe '.cache_method' do
|
8
|
+
it 'should call .define_cache_method for each method with the passed options' do
|
9
|
+
methods = [:foo, :bar, :baz]
|
10
|
+
options = { option: :value }
|
11
|
+
methods.each do |method|
|
12
|
+
expect(klass).to receive(:define_cache_method).with(method, options)
|
13
|
+
end
|
14
|
+
klass.send :cache_method, *methods, options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '.define_cache_method' do
|
19
|
+
it 'should call .stub_cache_method_original with the method' do
|
20
|
+
expect(klass).to receive(:stub_cache_method_original).at_least(:once).with(:foo).and_call_original
|
21
|
+
klass.send :define_cache_method, :foo
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should call .define_cache_handler_method with the method' do
|
25
|
+
options = { option: :value }
|
26
|
+
expect(klass).to receive(:define_cache_handler_method).at_least(:once).with(:foo, options).and_call_original
|
27
|
+
klass.send :define_cache_handler_method, :foo, options
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should call .define_cache_with_method' do
|
31
|
+
expect(klass).to receive(:define_cache_with_method).at_least(:once).with(:foo).and_call_original
|
32
|
+
klass.send :define_cache_method, :foo
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should call alias_method_chain with the method and :cache' do
|
36
|
+
expect(klass).to receive(:alias_method_chain).at_least(:once).with(:foo, :cache).and_call_original
|
37
|
+
klass.send :define_cache_method, :foo
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '.define_cache_with_method' do
|
42
|
+
it 'should define the cache with method' do
|
43
|
+
expect(klass).to receive(:method_added).with(:foo_with_cache)
|
44
|
+
klass.send :define_cache_with_method, :foo
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'if the method is already defined' do
|
48
|
+
it 'should not define the method' do
|
49
|
+
klass.send(:define_method, :foo_with_cache) { 'value' }
|
50
|
+
expect(klass).to_not receive(:method_added).with(:foo_with_cache)
|
51
|
+
klass.send :define_cache_with_method, :foo
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#cache_with_method' do
|
57
|
+
let(:instance) { klass.new }
|
58
|
+
|
59
|
+
before(:each) do
|
60
|
+
klass.send :cache_method, :foo, with: :memory_store, logger: Logger.new('/dev/null')
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should cache miss once' do
|
64
|
+
expect(instance).to receive(:foo_without_cache).exactly(:once)
|
65
|
+
2.times { instance.foo }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '.define_cache_handler_method' do
|
70
|
+
it 'should define the cache handler method' do
|
71
|
+
expect(klass).to receive(:method_added).with(:cache_handler_for_foo)
|
72
|
+
klass.send :define_cache_handler_method, :foo
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should create a cache handler with the proper options' do
|
76
|
+
options = { foo: :bar }
|
77
|
+
klass.send :define_cache_handler_method, :foo, options
|
78
|
+
instance = klass.new
|
79
|
+
expect(DefCache::CacheHandler).to receive(:new).with :foo, instance, options
|
80
|
+
instance.cache_handler_for_foo
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should define a method that returns a cache handler' do
|
84
|
+
options = { foo: :bar }
|
85
|
+
klass.send :define_cache_handler_method, :foo, options
|
86
|
+
instance = klass.new
|
87
|
+
handler = instance.cache_handler_for_foo
|
88
|
+
handler.should be_a DefCache::CacheHandler
|
89
|
+
handler.instance.should eq instance
|
90
|
+
handler.cache_options.should eq options
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'if the method is already defined' do
|
94
|
+
it 'should not define the method' do
|
95
|
+
klass.send(:define_method, :cache_handler_for_foo) { 'value' }
|
96
|
+
expect(klass).to_not receive(:method_added).with(:cache_handler_for_foo)
|
97
|
+
klass.send :define_cache_handler_method, :foo
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe '.stub_cache_method_original' do
|
103
|
+
it 'should stub the original method' do
|
104
|
+
expect(klass).to receive(:method_added).with(:foo)
|
105
|
+
klass.send :stub_cache_method_original, :foo
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should define a method that raises an error' do
|
109
|
+
klass.send :stub_cache_method_original, :foo
|
110
|
+
expect { klass.new.foo }.to raise_error NoMethodError
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'if the method is already defined' do
|
114
|
+
it 'should not stub the method' do
|
115
|
+
klass.send(:define_method, :foo) { 'value' }
|
116
|
+
expect(klass).to_not receive(:method_added).with(:foo)
|
117
|
+
klass.send :stub_cache_method_original, :foo
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe '.method_added' do
|
123
|
+
context 'if the with cache method is defined' do
|
124
|
+
before(:each) { klass.send(:define_method, :foo_with_cache) { 'value' } }
|
125
|
+
it 'should call define_cache_method' do
|
126
|
+
expect(klass).to receive(:define_cache_method).with(:foo)
|
127
|
+
klass.send(:method_added, :foo)
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'if the method has just been added' do
|
131
|
+
it 'should call define_cache_method' do
|
132
|
+
klass.send(:cached_methods_just_added) << :foo
|
133
|
+
expect(klass).to_not receive(:define_cache_method).with(:foo)
|
134
|
+
klass.send(:method_added, :foo)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DefCache do
|
4
|
+
|
5
|
+
let(:klass){ stub_const 'SampleClass', Class.new { include DefCache } }
|
6
|
+
subject(:instance){ klass.new }
|
7
|
+
|
8
|
+
describe '#flush_method_cache!' do
|
9
|
+
before do
|
10
|
+
klass.send :cache_method, :foo, :bar
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should call flush on the handlers' do
|
14
|
+
[:foo, :bar].each do |m|
|
15
|
+
expect(instance.send "cache_handler_for_#{m}").to receive(:flush!)
|
16
|
+
end
|
17
|
+
instance.flush_method_cache!
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
require 'coveralls'
|
3
|
+
|
4
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
5
|
+
SimpleCov::Formatter::HTMLFormatter,
|
6
|
+
Coveralls::SimpleCov::Formatter
|
7
|
+
]
|
8
|
+
SimpleCov.start
|
9
|
+
|
10
|
+
require 'def_cache'
|
11
|
+
|
12
|
+
RSpec.configure do |config|
|
13
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
14
|
+
config.run_all_when_everything_filtered = true
|
15
|
+
config.filter_run :focus
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,236 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: def_cache
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jason Waldrip
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-09-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: method_source
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: yard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: bundler
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.3'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.3'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rake
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ! '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: guard
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ! '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: guard-rspec
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ! '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: guard-bundler
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ! '>='
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ! '>='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: simplecov
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ! '>='
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ! '>='
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: coveralls
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ! '>='
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
description: An agnostic ActiveSupport::Cache helper to enable easy caching of methods
|
182
|
+
inside your classes.
|
183
|
+
email:
|
184
|
+
- jason@waldrip.net
|
185
|
+
executables: []
|
186
|
+
extensions: []
|
187
|
+
extra_rdoc_files: []
|
188
|
+
files:
|
189
|
+
- .gitignore
|
190
|
+
- .rspec
|
191
|
+
- .travis.yml
|
192
|
+
- Gemfile
|
193
|
+
- Guardfile
|
194
|
+
- LICENSE.txt
|
195
|
+
- README.md
|
196
|
+
- Rakefile
|
197
|
+
- def_cache.gemspec
|
198
|
+
- lib/def_cache.rb
|
199
|
+
- lib/def_cache/cache_handler.rb
|
200
|
+
- lib/def_cache/class_methods.rb
|
201
|
+
- lib/def_cache/version.rb
|
202
|
+
- spec/lib/def_cache/cache_handler_spec.rb
|
203
|
+
- spec/lib/def_cache/class_methods_spec.rb
|
204
|
+
- spec/lib/def_cache_spec.rb
|
205
|
+
- spec/spec_helper.rb
|
206
|
+
homepage: https://github.com/jwaldrip/funky_cache
|
207
|
+
licenses:
|
208
|
+
- MIT
|
209
|
+
metadata: {}
|
210
|
+
post_install_message:
|
211
|
+
rdoc_options: []
|
212
|
+
require_paths:
|
213
|
+
- lib
|
214
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
215
|
+
requirements:
|
216
|
+
- - ! '>='
|
217
|
+
- !ruby/object:Gem::Version
|
218
|
+
version: '0'
|
219
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
220
|
+
requirements:
|
221
|
+
- - ! '>='
|
222
|
+
- !ruby/object:Gem::Version
|
223
|
+
version: '0'
|
224
|
+
requirements: []
|
225
|
+
rubyforge_project:
|
226
|
+
rubygems_version: 2.0.6
|
227
|
+
signing_key:
|
228
|
+
specification_version: 4
|
229
|
+
summary: An agnostic ActiveSupport::Cache helper to enable easy caching of methods
|
230
|
+
inside your classes.
|
231
|
+
test_files:
|
232
|
+
- spec/lib/def_cache/cache_handler_spec.rb
|
233
|
+
- spec/lib/def_cache/class_methods_spec.rb
|
234
|
+
- spec/lib/def_cache_spec.rb
|
235
|
+
- spec/spec_helper.rb
|
236
|
+
has_rdoc:
|