static_record_cache 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +138 -0
- data/Rakefile +44 -0
- data/VERSION +1 -0
- data/init.rb +2 -0
- data/install.rb +1 -0
- data/lib/acts_as_static_record.rb +517 -0
- data/lib/static_active_record_context.rb +60 -0
- data/lib/static_record_cache.rb +5 -0
- data/static_record_cache.gemspec +70 -0
- data/tasks/static_record_cache_tasks.rake +4 -0
- data/test/acts_as_static_record_test.rb +146 -0
- data/test/db/schema.rb +20 -0
- data/test/fixtures/carriers.yml +65 -0
- data/test/fixtures/phone_numbers.yml +36 -0
- data/test/models/carrier.rb +28 -0
- data/test/models/context_carrier.rb +5 -0
- data/test/models/phone_number.rb +5 -0
- data/test/static_active_record_context_test.rb +54 -0
- data/test/test_helper.rb +99 -0
- data/uninstall.rb +1 -0
- metadata +91 -0
@@ -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,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,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
|