static_record_cache 0.2.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.
@@ -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