cached_attr 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ cache_attr
2
+ ==========
3
+
4
+ Make a ruby object attribute cacheable
@@ -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
@@ -0,0 +1,12 @@
1
+ require 'bundler/setup'
2
+ require 'rspec/autorun'
3
+ require 'simplecov'
4
+
5
+ unless ENV['COVERAGE'] == 'no'
6
+ require 'simplecov'
7
+ SimpleCov.start do
8
+ add_filter "/spec/"
9
+ end
10
+ end
11
+
12
+ require 'cached_attr'
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