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.
- 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
|