cached_attr 0.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.
- data/README.md +4 -0
- data/lib/cached_attr.rb +115 -0
- data/spec/cached_attr_spec.rb +47 -0
- data/spec/spec_helper.rb +12 -0
- metadata +100 -0
data/README.md
ADDED
data/lib/cached_attr.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
# This module implements attributes whose reader method executes once, and the returned value is cached for later use.
|
2
|
+
# This might be handy for expensive operations.
|
3
|
+
#
|
4
|
+
# An example, given the following method:
|
5
|
+
#
|
6
|
+
# def object_to_get
|
7
|
+
# if @object_to_get.nil?
|
8
|
+
# @object_to_get = [code_to_retrieve_object]
|
9
|
+
# end
|
10
|
+
# @object_to_get
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# ...the cached attribute format would be:
|
14
|
+
#
|
15
|
+
# cache_attr :object_to_get do
|
16
|
+
# [code_to_retrieve_object]
|
17
|
+
# end
|
18
|
+
module CachedAttr
|
19
|
+
|
20
|
+
def self.included(base)
|
21
|
+
base.extend(ClassMethods)
|
22
|
+
end
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
|
26
|
+
# Defines an attribute on the including class.
|
27
|
+
#
|
28
|
+
# @param name [Symbol] the name of the attribute
|
29
|
+
# @param options [Hash] options
|
30
|
+
# @option options :writer if set to true, also define a writer method for the property
|
31
|
+
# @option options :ttl the time to live for a value. Ignored if nil or false
|
32
|
+
# @option options :method the method to call if no block is given
|
33
|
+
def cached_attr(name, options = {}, &block)
|
34
|
+
default_opts = {
|
35
|
+
:writer => false,
|
36
|
+
:method => false,
|
37
|
+
:ttl => false
|
38
|
+
}
|
39
|
+
opts = default_opts.merge(options)
|
40
|
+
|
41
|
+
class_eval do
|
42
|
+
internal_retrieve_method = "__internal_retrieve_#{name}".to_sym
|
43
|
+
define_method(internal_retrieve_method) do
|
44
|
+
if block.nil?
|
45
|
+
val = self.send(opts[:method])
|
46
|
+
else
|
47
|
+
val = self.instance_exec(&block)
|
48
|
+
end
|
49
|
+
cached_attributes_store[name][:invoke_count] += 1
|
50
|
+
val
|
51
|
+
end
|
52
|
+
internal_init_method = "__internal_init_#{name}".to_sym
|
53
|
+
define_method(internal_init_method) do |val = nil|
|
54
|
+
unless cached_attributes_store.has_key?(name)
|
55
|
+
cached_attributes_store[name] = {:call_count => 0, :invoke_count => 0}
|
56
|
+
if val.nil?
|
57
|
+
cached_attributes_store[name][:value] = self.send(internal_retrieve_method)
|
58
|
+
cached_attributes_store[name][:expires] = Time.now + opts[:ttl] if opts[:ttl]
|
59
|
+
|
60
|
+
else
|
61
|
+
cached_attributes_store[name][:value] = val
|
62
|
+
end
|
63
|
+
end
|
64
|
+
cached_attributes_store[name]
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
define_method("_#{name}_reset!".to_sym) do
|
69
|
+
cached_attributes_store.delete(name)
|
70
|
+
end
|
71
|
+
|
72
|
+
define_method("_#{name}_expires".to_sym) do
|
73
|
+
self.send(internal_init_method)[:expires]
|
74
|
+
end
|
75
|
+
|
76
|
+
define_method("_#{name}_call_count".to_sym) do
|
77
|
+
self.send(internal_init_method)[:call_count]
|
78
|
+
end
|
79
|
+
|
80
|
+
define_method("_#{name}_invoke_count".to_sym) do
|
81
|
+
self.send(internal_init_method)[:invoke_count]
|
82
|
+
end
|
83
|
+
|
84
|
+
define_method(name) do
|
85
|
+
|
86
|
+
cache_val = self.send(internal_init_method)
|
87
|
+
|
88
|
+
if opts[:ttl] && cache_val[:expires] && Time.now > cache_val[:expires]
|
89
|
+
cache_val[:value] = self.send(internal_retrieve_method)
|
90
|
+
cache_val[:expires] = Time.now + opts[:ttl]
|
91
|
+
end
|
92
|
+
|
93
|
+
cache_val[:call_count] = cached_attributes_store[name][:call_count] + 1
|
94
|
+
cache_val[:value]
|
95
|
+
end
|
96
|
+
|
97
|
+
if opts[:writer]
|
98
|
+
define_method("#{name}=") do |val|
|
99
|
+
self.send(internal_init_method, val)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
#private
|
109
|
+
|
110
|
+
# The store of cached properties
|
111
|
+
def cached_attributes_store
|
112
|
+
@cached_attributes_store ||= {}
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CachedAttr do
|
4
|
+
|
5
|
+
it "simple case" do
|
6
|
+
t = Test.new
|
7
|
+
5.times do
|
8
|
+
t.one.should == "1"
|
9
|
+
end
|
10
|
+
t._one_call_count.should == 5
|
11
|
+
t._one_invoke_count.should == 1
|
12
|
+
end
|
13
|
+
|
14
|
+
it "using TTL" do
|
15
|
+
t = Test.new
|
16
|
+
t.two.should == "2"
|
17
|
+
t._two_invoke_count.should == 1
|
18
|
+
sleep(3)
|
19
|
+
t.two.should == "2"
|
20
|
+
t._two_invoke_count.should == 2
|
21
|
+
end
|
22
|
+
|
23
|
+
it "using method call" do
|
24
|
+
t = Test.new
|
25
|
+
t.three.should == "3"
|
26
|
+
end
|
27
|
+
|
28
|
+
class Test
|
29
|
+
include CachedAttr
|
30
|
+
|
31
|
+
cached_attr :one do
|
32
|
+
"1"
|
33
|
+
end
|
34
|
+
|
35
|
+
cached_attr :two, :ttl => 2 do
|
36
|
+
"2"
|
37
|
+
end
|
38
|
+
|
39
|
+
cached_attr :three, :method => :three_impl
|
40
|
+
|
41
|
+
def three_impl
|
42
|
+
"3"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cached_attr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jerphaes van Blijenburgh
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-10-23 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: simplecov
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - '='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.7.1
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.7.1
|
62
|
+
description: Cacheable Ruby attributes
|
63
|
+
email:
|
64
|
+
- jerphaes@gmail.com
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- lib/cached_attr.rb
|
70
|
+
- README.md
|
71
|
+
- spec/cached_attr_spec.rb
|
72
|
+
- spec/spec_helper.rb
|
73
|
+
homepage: http://github.com/jerphaes/cache_attr
|
74
|
+
licenses:
|
75
|
+
- Apache License 2.0
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 1.9.2
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ! '>='
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
requirements: []
|
93
|
+
rubyforge_project:
|
94
|
+
rubygems_version: 1.8.25
|
95
|
+
signing_key:
|
96
|
+
specification_version: 3
|
97
|
+
summary: Cacheable Ruby attributes
|
98
|
+
test_files:
|
99
|
+
- spec/cached_attr_spec.rb
|
100
|
+
- spec/spec_helper.rb
|