static_record_cache 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,60 @@
1
+ # ==StaticActiveRecordContext
2
+ # Simple module to extends technoweenie's rad ActiveRecordContext plugin
3
+ # http://svn.techno-weenie.net/projects/plugins/active_record_context/
4
+ # to permanently cache active record data for the life of the class
5
+ #
6
+ # As with active_record_context, only finds based on ids are cache hits, however
7
+ # id finders are the majority of calls from associations. If cache hits on
8
+ # fields and methods are needed, refer to acts_as_static_record[link:files/acts_as_static_record_rb.html]
9
+ #
10
+ # class TelephoneCarriers < ActiveRecord::Base
11
+ # extend StaticActiveRecordContext
12
+ # has_many :phone_numbers
13
+ # end
14
+ #
15
+ # The following would exercise a cache hit
16
+ # phone_number.telephone_carrier
17
+ #
18
+ #
19
+ # The static cache is available both inside and outside +with_context+ block, where as
20
+ # the cache for typical records the context is only with the block.
21
+ #
22
+ # PhoneNumber.with_context {
23
+ # PhoneNumber.find :all
24
+ # TelephoneCarriers.find :all
25
+ # }
26
+ #
27
+ # phone = PhoneNumber.find_by_id(1) # not a cache hit
28
+ # phone.telephone_carrier # cache hit
29
+ # telephone_carrier = TelephoneCarrier.find(1) # cache hit
30
+ #
31
+ # === Developers
32
+ # * Blythe Dunham http://snowgiraffe.com
33
+ #
34
+ # === Homepage
35
+ # * Rdoc: http://snowgiraffe.com/rdocs/static_record_cache/
36
+ # * Github Project: http://github.com/blythedunham/static_record_cache/tree/master
37
+ # * Install: <tt>script/plugin install git://github.com/blythedunham/static_record_cache.git</tt>
38
+ module StaticActiveRecordContext
39
+ def self.extended(base)#:nodoc
40
+ base.class_inheritable_accessor :static_record_context
41
+ end
42
+
43
+ def context_cache#:nodoc:
44
+ self.static_record_context ||= {}
45
+ end
46
+
47
+ def context_cache=(map)#:nodoc:
48
+ self.static_record_context = map unless map.nil?
49
+ end
50
+
51
+ # Reload the cache for this class only
52
+ def reload_context_cache
53
+ self.static_record_context = {}
54
+ end
55
+
56
+ # Call ActiveRecord::Base to cache the other objects
57
+ def with_context(&block)#:nodoc:
58
+ ActiveRecord::Base.with_context(&block)
59
+ end
60
+ end
@@ -0,0 +1,5 @@
1
+ require 'ostruct'
2
+ begin ; require 'active_record' ; rescue LoadError; require 'rubygems'; require 'active_record'; end
3
+
4
+ require File.join( File.dirname(__FILE__), "acts_as_static_record" )
5
+ require File.join( File.dirname(__FILE__), "static_active_record_context" )
@@ -0,0 +1,70 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{static_record_cache}
8
+ s.version = "0.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Blythe Dunham"]
12
+ s.date = %q{2009-12-31}
13
+ s.description = %q{Permanently caches subclasses of ActiveRecord in memory. }
14
+ s.email = %q{blythe@snowgiraffe.com}
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "MIT-LICENSE",
21
+ "README.rdoc",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "init.rb",
25
+ "install.rb",
26
+ "lib/acts_as_static_record.rb",
27
+ "lib/static_active_record_context.rb",
28
+ "lib/static_record_cache.rb",
29
+ "static_record_cache.gemspec",
30
+ "tasks/static_record_cache_tasks.rake",
31
+ "test/acts_as_static_record_test.rb",
32
+ "test/db/schema.rb",
33
+ "test/fixtures/carriers.yml",
34
+ "test/fixtures/phone_numbers.yml",
35
+ "test/models/carrier.rb",
36
+ "test/models/context_carrier.rb",
37
+ "test/models/phone_number.rb",
38
+ "test/static_active_record_context_test.rb",
39
+ "test/test_helper.rb",
40
+ "uninstall.rb"
41
+ ]
42
+ s.homepage = %q{http://github.com/blythedunham/static_record_cache}
43
+ s.rdoc_options = ["--charset=UTF-8"]
44
+ s.require_paths = ["lib"]
45
+ s.rubygems_version = %q{1.3.5}
46
+ s.summary = %q{Permanently caches subclasses of ActiveRecord in memory.}
47
+ s.test_files = [
48
+ "test/acts_as_static_record_test.rb",
49
+ "test/db/schema.rb",
50
+ "test/models/carrier.rb",
51
+ "test/models/context_carrier.rb",
52
+ "test/models/phone_number.rb",
53
+ "test/static_active_record_context_test.rb",
54
+ "test/test_helper.rb"
55
+ ]
56
+
57
+ if s.respond_to? :specification_version then
58
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
59
+ s.specification_version = 3
60
+
61
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
62
+ s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
63
+ else
64
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
65
+ end
66
+ else
67
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
68
+ end
69
+ end
70
+
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :static_record_cache do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,146 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class StaticActiveRecordContextTest < TestCaseSuperClass
4
+ self.fixtures :carriers, :phone_numbers
5
+
6
+
7
+ def setup
8
+ super
9
+ StaticCarrierWithKey.clear_static_record_cache
10
+ StaticCarrier.clear_static_record_cache
11
+ StaticCarrierWithNonColumnKey.clear_static_record_cache
12
+ end
13
+
14
+ def test_should_load_all_records
15
+ StaticCarrier.find :all
16
+ assert_equal Carrier.count, cache_instance(StaticCarrier)[:primary_key].size
17
+ end
18
+
19
+ def test_should_load_all_records_with_key
20
+ StaticCarrierWithKey.find :all
21
+ assert_equal Carrier.count, cache_instance(StaticCarrierWithKey)[:primary_key].size
22
+ assert_equal Carrier.count, cache_instance(StaticCarrierWithKey)[:key].size
23
+
24
+ #cached on key
25
+ cache_instance(StaticCarrierWithKey)[:key].each {|cache_key, cache_item|
26
+ assert(cache_key, cache_item.name)
27
+ }
28
+ end
29
+
30
+ def test_should_load_all_records_with_non_column_key
31
+ StaticCarrierWithNonColumnKey.find :all
32
+ assert_equal Carrier.count, cache_instance(StaticCarrierWithNonColumnKey)[:primary_key].size
33
+ assert_equal Carrier.count, cache_instance(StaticCarrierWithNonColumnKey)[:key].size
34
+
35
+ #cached on key
36
+ cache_instance(StaticCarrierWithNonColumnKey)[:key].each {|cache_key, cache_item|
37
+ assert(cache_key, cache_item.non_column)
38
+ }
39
+ end
40
+
41
+ def test_should_not_load_cache_with_conditions
42
+ StaticCarrier.find :all, :conditions => 'id is not null'
43
+ assert_nil cache_instance(StaticCarrier)
44
+ end
45
+
46
+ def test_should_load_all_when_accessing_one_record
47
+ phone = phone_numbers(:phone_number_1)
48
+ phone.static_carrier
49
+ phone.reload
50
+ assert_queries(0){
51
+ phone.static_carrier
52
+ }
53
+ assert_equal Carrier.count, cache_instance(StaticCarrier)[:primary_key].size
54
+ assert_equal 0, cache_instance(StaticCarrier)[:key].size
55
+ end
56
+
57
+ def test_should_define_method_for_non_column_key
58
+ assert StaticCarrierWithNonColumnKey.respond_to?(:find_by_non_column)
59
+
60
+ record = StaticCarrierWithNonColumnKey.find_by_non_column('NONCOLUMN: 1')
61
+ assert(1, record.to_param)
62
+ end
63
+
64
+
65
+ def test_finders_for_column_key
66
+
67
+ assert_queries(1) {
68
+ record = StaticCarrierWithKey.find_by_name_and_id('Verizon', 1)
69
+ assert(record)
70
+ assert_equal('Verizon', record.name)
71
+ assert_equal("1", record.to_param)
72
+
73
+ record = StaticCarrierWithKey.find_by_name_and_id('Verizon', 2)
74
+ assert_nil(record)
75
+ }
76
+ end
77
+
78
+ def test_finders_for_primary_key_id
79
+
80
+ StaticCarrierWithKey.find :all
81
+ assert_queries(0) {
82
+ record = StaticCarrierWithKey.find_by_id(1)
83
+ assert(record)
84
+ assert_equal('Verizon', record.name)
85
+ assert_equal("1", record.to_param)
86
+ }
87
+
88
+ assert_queries(1) {
89
+ record = StaticCarrierWithKey.find_by_id(2, :conditions => 'id = 1')
90
+ assert_nil(record)
91
+ }
92
+ end
93
+
94
+ def test_finders_for_column_key_base
95
+
96
+ StaticCarrierWithKey.find :all
97
+ assert_queries(0) {
98
+ record = StaticCarrierWithKey.find_by_name('Verizon')
99
+ assert(record)
100
+ assert_equal('Verizon', record.name)
101
+ assert_equal("1", record.to_param)
102
+ }
103
+ assert_queries(1) {
104
+ record = StaticCarrierWithKey.find_by_name('Verizondd', :conditions => 'id is not null')
105
+ assert_nil(record)
106
+ }
107
+ end
108
+
109
+
110
+ def test_finders_for_column_key_with_conditions
111
+ #load up the cache
112
+ StaticCarrierWithKey.find :all
113
+
114
+ assert_queries(1) {
115
+ #This performs one query because the conditions are not nil
116
+ record = StaticCarrierWithKey.find_by_name_and_id('Verizon', 1, :conditions => 'id is not null')
117
+ assert(record)
118
+ assert_equal('Verizon', record.name)
119
+ assert_equal("1", record.to_param)
120
+
121
+ #This should use the cache
122
+ record = StaticCarrierWithKey.find_by_name_and_id('Verizon', 1)
123
+ assert(record)
124
+ assert_equal('Verizon', record.name)
125
+ assert_equal("1", record.to_param)
126
+ }
127
+
128
+ #This should use the newly defined method and run it since there are conditions
129
+ assert_queries(1) {
130
+ #This performs one query because the conditions are not nil
131
+ record = StaticCarrierWithKey.find_by_name_and_id('Verizon', 1, :conditions => 'id is not null')
132
+ assert(record)
133
+ assert_equal('Verizon', record.name)
134
+ assert_equal("1", record.to_param)
135
+ }
136
+ end
137
+
138
+
139
+ protected
140
+
141
+ #calling static_record_cache invokes the cache
142
+ def cache_instance(klass)
143
+ klass.instance_variable_get('@static_record_cache')
144
+ end
145
+
146
+ end
data/test/db/schema.rb ADDED
@@ -0,0 +1,20 @@
1
+ ActiveRecord::Schema.define do
2
+
3
+ create_table :phone_numbers, :force => true do |t|
4
+ t.column :number, :string, :length => 20, :null => false
5
+ t.column :carrier_id, :integer, :default => nil
6
+ t.column :owner_id, :integer, :default => nil
7
+ t.column :country_code, :integer, :length => 5, :default => 1
8
+ t.column :notes, :string, :default => nil
9
+ end
10
+
11
+ add_index :phone_numbers, :number, :unique => 'true', :name => 'uk_phone_numbers_number'
12
+
13
+ create_table :carriers, :force => true do |t|
14
+ t.column :name, :string, :length => 100
15
+ t.column :email_domain, :string, :length => 100, :default => nil
16
+ t.column :options, :string, :default => nil
17
+ end
18
+ add_index :carriers, :name, :unique => 'true', :name => 'uk_carriers_name'
19
+
20
+ end
@@ -0,0 +1,65 @@
1
+ carrier_1:
2
+ id: "1"
3
+ name: Verizon
4
+ email_domain: "vtext.com"
5
+
6
+ carrier_2:
7
+ id: "2"
8
+ name: Alltel
9
+ email_domain: "message.alltel.com"
10
+
11
+ carrier_3:
12
+ id: "3"
13
+ name: mmode
14
+ email_domain: "mmode.com"
15
+
16
+ carrier_4:
17
+ id: "4"
18
+ name: Cellular One
19
+ email_domain: "mobile.celloneusa.com"
20
+
21
+ carrier_5:
22
+ id: "5"
23
+ name: AT&T (Cingular)
24
+ email_domain: "txt.att.net"
25
+
26
+ carrier_6:
27
+ id: "6"
28
+ name: Nextel
29
+ email_domain: "page.nextel.com"
30
+
31
+ carrier_7:
32
+ id: "7"
33
+ name: OmnipointPCS
34
+ email_domain: "omnipointpcs.com"
35
+
36
+ carrier_8:
37
+ id: "8"
38
+ name: Qwest
39
+ email_domain: "qwestmp.com"
40
+
41
+ carrier_9:
42
+ id: "9"
43
+ name: Sprint
44
+ email_domain: "messaging.sprintpcs.com"
45
+
46
+ carrier_10:
47
+ id: "10"
48
+ name: T-Mobile
49
+ email_domain: "tmomail.net"
50
+
51
+ carrier_11:
52
+ id: "11"
53
+ name: Virgin Mobile
54
+ email_domain: "vmobl.com"
55
+
56
+ carrier_12:
57
+ id: "12"
58
+ name: US Cellular
59
+ email_domain: "email.uscc.com"
60
+
61
+ carrier_13:
62
+ id: "13"
63
+ name: Amp'd
64
+ email_domain: "ampdpix.com"
65
+
@@ -0,0 +1,36 @@
1
+ #add 2 phones of each carrier
2
+ <% 1.upto(26) do |count| %>
3
+ phone_number_<%=count %>:
4
+ id: <%=count %>
5
+ number: <%= "120655500#{'%02d' % count}"%>
6
+ carrier_id: <%=count % 13 %>
7
+ notes: <%= "Note #{count}"%>
8
+ <% end %>
9
+
10
+
11
+ phone_number_101:
12
+ id: 101
13
+ number: 12065551111
14
+ carrier_id: 1
15
+
16
+ phone_number_201:
17
+ id: 201
18
+ number: 12065552222
19
+ carrier_id: 2
20
+
21
+ phone_number_301:
22
+ id: 301
23
+ number: 12065553333
24
+ carrier_id: 3
25
+ notes: likes grapes
26
+
27
+ phone_number_401:
28
+ id: 401
29
+ number: 12065554444
30
+ carrier_id: 4
31
+
32
+ phone_number_501:
33
+ id: 501
34
+ number: 12065555555
35
+ carrier_id: 5
36
+ notes: iPhone
@@ -0,0 +1,28 @@
1
+ class Carrier < ActiveRecord::Base
2
+ has_many :phone_numbers
3
+ end
4
+
5
+
6
+
7
+ class StaticCarrier < ActiveRecord::Base
8
+ set_table_name 'carriers'
9
+ acts_as_static_record
10
+ has_many :phone_numbers, :foreign_key => :carrier_id
11
+ end
12
+
13
+
14
+ class StaticCarrierWithKey < ActiveRecord::Base
15
+ set_table_name 'carriers'
16
+ acts_as_static_record :key => :name
17
+ has_many :phone_numbers, :foreign_key => :carrier_id
18
+ end
19
+
20
+ class StaticCarrierWithNonColumnKey < ActiveRecord::Base
21
+ set_table_name 'carriers'
22
+ acts_as_static_record :key => :non_column
23
+ has_many :phone_numbers, :foreign_key => :carrier_id
24
+
25
+ def non_column
26
+ "NONCOLUMN: " + self.to_param.to_s
27
+ end
28
+ end