cache_it 0.0.1
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 +5 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +20 -0
- data/README +23 -0
- data/Rakefile +21 -0
- data/cache_it.gemspec +21 -0
- data/init.rb +2 -0
- data/install.rb +1 -0
- data/lib/cache_it/version.rb +3 -0
- data/lib/cache_it.rb +228 -0
- data/spec/cache_it_spec.rb +232 -0
- data/uninstall.rb +1 -0
- metadata +76 -0
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Rodrigo Vanegas
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
cache_it
|
2
|
+
========
|
3
|
+
|
4
|
+
Cache for ActiveRecord objects, backed by ActiveSupport::CacheStore of your choice. Cache-money was
|
5
|
+
not yet ported to Rails 3 so I rolled my own.
|
6
|
+
|
7
|
+
|
8
|
+
Example
|
9
|
+
=======
|
10
|
+
|
11
|
+
class User < ActiveRecord::Base
|
12
|
+
cache_it do |c|
|
13
|
+
c.index :first, :last
|
14
|
+
c.index :email
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
user = User.cache_it_find :first => "Joe", :last => "Schmoe"
|
19
|
+
user = User.cache_it_find :email => "joe@example.com"
|
20
|
+
user.age = 30
|
21
|
+
user.cache_it_write
|
22
|
+
|
23
|
+
Copyright (c) 2011 Rodrigo Vanegas, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rspec/core/rake_task'
|
2
|
+
require 'bundler'
|
3
|
+
|
4
|
+
Bundler::GemHelper.install_tasks
|
5
|
+
|
6
|
+
desc 'Default: run specs.'
|
7
|
+
task :default => :spec
|
8
|
+
|
9
|
+
desc "Run specs"
|
10
|
+
RSpec::Core::RakeTask.new do |t|
|
11
|
+
t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
|
12
|
+
# Put spec opts in a file named .rspec in root
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Generate code coverage"
|
16
|
+
RSpec::Core::RakeTask.new(:coverage) do |t|
|
17
|
+
t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
|
18
|
+
t.rcov = true
|
19
|
+
t.rcov_opts = ['--exclude', 'spec']
|
20
|
+
end
|
21
|
+
|
data/cache_it.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "cache_it/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "cache_it"
|
7
|
+
s.version = CacheIt::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Rodrigo Vanegas"]
|
10
|
+
s.email = ["rvanegas@gmail.com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{ActiveRecord caching}
|
13
|
+
s.description = %q{Integrates ActiveRecord with cache stores provided by Rails.cache, incluing memcached}
|
14
|
+
|
15
|
+
s.rubyforge_project = "cache_it"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
end
|
data/init.rb
ADDED
data/install.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Install hook code here
|
data/lib/cache_it.rb
ADDED
@@ -0,0 +1,228 @@
|
|
1
|
+
|
2
|
+
module ActiveRecord
|
3
|
+
class Base
|
4
|
+
#
|
5
|
+
# First time called, configures \cache_it for this ActiveRecord model.
|
6
|
+
# Subsequent calls returns a delegate to access class methods.
|
7
|
+
#
|
8
|
+
# Examples:
|
9
|
+
#
|
10
|
+
# class Foo < ActiveRecord::Base
|
11
|
+
# cache_it :first, :last
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# class Foo < ActiveRecord::Base
|
15
|
+
# cache_it do |c|
|
16
|
+
# c.index :first, :last
|
17
|
+
# c.index :email
|
18
|
+
# c.counters :points
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
def self.cache_it(*index)
|
23
|
+
if self.class_variable_defined? :@@cache_it
|
24
|
+
raise ArgumentError, "cannot reconfigure" if index.present? or block_given?
|
25
|
+
else
|
26
|
+
raise ArgumentError, "use block or args" if index.present? and block_given?
|
27
|
+
config = CacheIt::Config.new self
|
28
|
+
config.index *index if config and index.present?
|
29
|
+
yield config if config and block_given?
|
30
|
+
self.class_exec do
|
31
|
+
# Returns delegate to access instance methods
|
32
|
+
def cache_it
|
33
|
+
@cache_it ||= CacheIt::InstanceDelegate.new self
|
34
|
+
end
|
35
|
+
end
|
36
|
+
delegate = CacheIt::ClassDelegate.new self, config
|
37
|
+
self.class_variable_set "@@cache_it", delegate
|
38
|
+
end
|
39
|
+
self.class_variable_get "@@cache_it"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Cache for ActiveRecord objects, backed by ActiveSupport::CacheStore of your choice.
|
46
|
+
#
|
47
|
+
# ==Usage
|
48
|
+
#
|
49
|
+
# # migration
|
50
|
+
# create_table :users do |t|
|
51
|
+
# t.string :first
|
52
|
+
# t.string :last
|
53
|
+
# t.string :email
|
54
|
+
# t.integer :age
|
55
|
+
# t.integer :points
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# class User < ActiveRecord::Base
|
59
|
+
# cache_it do |c|
|
60
|
+
# c.index :first, :last
|
61
|
+
# c.index :email
|
62
|
+
# c.counters :points
|
63
|
+
# end
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# user = User.cache_it.find(:first => "Joe", :last => "Schmoe")
|
67
|
+
# user = User.cache_it.find(:email => "joe@example.com")
|
68
|
+
# user.age = 30
|
69
|
+
# user.cache_it_write
|
70
|
+
#
|
71
|
+
module CacheIt
|
72
|
+
class InstanceDelegate
|
73
|
+
def initialize(base)
|
74
|
+
@base = base
|
75
|
+
end
|
76
|
+
|
77
|
+
def write
|
78
|
+
expires_in = @base.class.cache_it.config.expires_in
|
79
|
+
val = {:attributes => @base.attributes}
|
80
|
+
keys.each {|key| Rails.cache.write(key, val, :expires_in => expires_in)}
|
81
|
+
stale_keys.each {|key| Rails.cache.delete(key)}
|
82
|
+
init_counters
|
83
|
+
end
|
84
|
+
|
85
|
+
def increment(counter, amount = 1)
|
86
|
+
counter = counter.to_s
|
87
|
+
unless @base.class.cache_it.config.counters.include? counter
|
88
|
+
raise ArgumentError, "#{counter} is not a counter"
|
89
|
+
end
|
90
|
+
primary_key = @base.class.primary_key
|
91
|
+
if key = @base.class.cache_it.key({primary_key => @base[primary_key]}, :counter => counter)
|
92
|
+
@base[counter] = Rails.cache.increment(key, amount, :raw => true)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def delete
|
97
|
+
keys(attributes_before_changes).each {|key| Rails.cache.delete(key)}
|
98
|
+
end
|
99
|
+
|
100
|
+
def init_counters
|
101
|
+
primary_key = @base.class.primary_key
|
102
|
+
@base.class.cache_it.config.counters.map do |counter|
|
103
|
+
counter_key = @base.class.cache_it.key({primary_key => @base[primary_key]}, :counter => counter)
|
104
|
+
@base[counter] = Rails.cache.fetch(counter_key, :raw => true) { @base[counter] }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
def attributes_before_changes
|
110
|
+
result = Hash.new
|
111
|
+
@base.attributes.each do |k,v|
|
112
|
+
result[k] = @base.changes.include?(k) ? @base.changes[k].first : v
|
113
|
+
end
|
114
|
+
return result
|
115
|
+
end
|
116
|
+
|
117
|
+
def keys(attrs = @base.attributes)
|
118
|
+
@base.class.cache_it.config.indexes.map do |index|
|
119
|
+
@base.class.cache_it.key attrs.select {|attr| index.include? attr}
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def stale_keys
|
124
|
+
keys(attributes_before_changes) - keys(@base.attributes)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class ClassDelegate
|
129
|
+
def initialize(base, config)
|
130
|
+
@base = base
|
131
|
+
@config = config
|
132
|
+
@base.after_save Proc.new { cache_it.write }
|
133
|
+
@base.after_destroy Proc.new { cache_it.delete }
|
134
|
+
end
|
135
|
+
|
136
|
+
def key(attrs, options = {})
|
137
|
+
attrs = attrs.stringify_keys
|
138
|
+
index = attrs.keys.sort
|
139
|
+
raise ArgumentError, "index not available" unless @config.indexes.include? index
|
140
|
+
if options[:counter]
|
141
|
+
raise ArgumentError, "not a counter" unless @config.counters.include? options[:counter]
|
142
|
+
end
|
143
|
+
key = ["CacheIt.v1", @base.name]
|
144
|
+
key.push options[:counter] if options[:counter]
|
145
|
+
key.push index.map{|name| [name, attrs[name]]}.to_json
|
146
|
+
return key.join(":")
|
147
|
+
end
|
148
|
+
|
149
|
+
def find(attrs, options = {})
|
150
|
+
unless obj = read(attrs, options)
|
151
|
+
obj = @base.where(attrs).first
|
152
|
+
obj.cache_it.write if obj
|
153
|
+
end
|
154
|
+
return obj
|
155
|
+
end
|
156
|
+
|
157
|
+
def read(attrs, options = {})
|
158
|
+
key = key(attrs)
|
159
|
+
obj = nil
|
160
|
+
if val = Rails.cache.read(key)
|
161
|
+
attributes = val[:attributes]
|
162
|
+
obj = @base.new
|
163
|
+
obj.send :attributes=, attributes, false
|
164
|
+
obj.instance_variable_set("@new_record", false) if obj.id
|
165
|
+
obj.cache_it.init_counters unless options[:skip_counters]
|
166
|
+
end
|
167
|
+
return obj
|
168
|
+
end
|
169
|
+
|
170
|
+
def config
|
171
|
+
@config
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
class Config
|
176
|
+
def initialize(model)
|
177
|
+
@model = model
|
178
|
+
@indexes ||= [[@model.primary_key]]
|
179
|
+
@counters ||= []
|
180
|
+
end
|
181
|
+
|
182
|
+
def index(*index)
|
183
|
+
return nil unless index.present?
|
184
|
+
index = index.map {|n|n.to_s}.sort
|
185
|
+
unless index.all? {|n| @model.column_names.include? n}
|
186
|
+
raise ArgumentError, "index must be list of column names"
|
187
|
+
end
|
188
|
+
@indexes.push index unless @indexes.include? index
|
189
|
+
validate
|
190
|
+
return nil
|
191
|
+
end
|
192
|
+
|
193
|
+
def indexes
|
194
|
+
@indexes
|
195
|
+
end
|
196
|
+
|
197
|
+
def counters(*counters)
|
198
|
+
return @counters unless counters.present?
|
199
|
+
counters = counters.map {|n|n.to_s}
|
200
|
+
unless counters.all? {|n| @model.columns_hash[n].try(:type) == :integer}
|
201
|
+
raise ArgumentError, "counters must be column names for integer attributes"
|
202
|
+
end
|
203
|
+
counters.each do |name|
|
204
|
+
@counters.push name unless @counters.include? name
|
205
|
+
end
|
206
|
+
validate
|
207
|
+
return nil
|
208
|
+
end
|
209
|
+
|
210
|
+
def expires_in(expires_in = nil, &block)
|
211
|
+
unless expires_in or block_given?
|
212
|
+
@expires_in.respond_to?(:call) ? @expires_in.call : @expires_in
|
213
|
+
else
|
214
|
+
raise ArgumentError, "use block or args" if expires_in and block_given?
|
215
|
+
@expires_in = expires_in || block
|
216
|
+
return nil
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
private
|
221
|
+
def validate
|
222
|
+
if @indexes.flatten.any? {|name| @counters.include? name}
|
223
|
+
raise "cannot use column for both index and counter"
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
@@ -0,0 +1,232 @@
|
|
1
|
+
|
2
|
+
require 'ruby-debug'
|
3
|
+
Debugger.start
|
4
|
+
|
5
|
+
require 'sqlite3'
|
6
|
+
require 'active_record'
|
7
|
+
require File.expand_path(File.dirname(__FILE__) + '/../lib/cache_it.rb')
|
8
|
+
|
9
|
+
class MockCache
|
10
|
+
def initialize
|
11
|
+
clear
|
12
|
+
end
|
13
|
+
|
14
|
+
def write(key, val, options = {})
|
15
|
+
@hash[key] = val
|
16
|
+
end
|
17
|
+
|
18
|
+
def read(key)
|
19
|
+
@hash[key]
|
20
|
+
end
|
21
|
+
|
22
|
+
def fetch(key, options = {})
|
23
|
+
if @hash.has_key?(key)
|
24
|
+
@hash[key]
|
25
|
+
elsif block_given?
|
26
|
+
@hash[key] = yield
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def increment(key, amount = 1, options = {})
|
31
|
+
@hash[key] = @hash[key].to_s.to_i + amount
|
32
|
+
end
|
33
|
+
|
34
|
+
def delete(key)
|
35
|
+
@hash.delete(key)
|
36
|
+
end
|
37
|
+
|
38
|
+
def clear
|
39
|
+
@hash = Hash.new
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe MockCache do
|
44
|
+
it "writes and reads" do
|
45
|
+
subject.read("foo").should== nil
|
46
|
+
subject.write("foo", 1)
|
47
|
+
subject.read("foo").should== 1
|
48
|
+
end
|
49
|
+
|
50
|
+
it "fetches" do
|
51
|
+
subject.read("foo").should== nil
|
52
|
+
subject.fetch("foo", 1){ 1 }.should== 1
|
53
|
+
subject.read("foo").should== 1
|
54
|
+
subject.fetch("foo", 1).should== 1
|
55
|
+
end
|
56
|
+
|
57
|
+
it "increments" do
|
58
|
+
subject.read("foo").should== nil
|
59
|
+
subject.increment("foo")
|
60
|
+
subject.increment("foo", 2)
|
61
|
+
subject.write("foo", 1)
|
62
|
+
subject.increment("foo")
|
63
|
+
subject.increment("foo", 2)
|
64
|
+
subject.read("foo").should== 4
|
65
|
+
end
|
66
|
+
|
67
|
+
it "deletes" do
|
68
|
+
subject.read("foo").should== nil
|
69
|
+
subject.write("foo", 1)
|
70
|
+
subject.read("foo").should== 1
|
71
|
+
subject.delete("foo")
|
72
|
+
subject.read("foo").should== nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ":memory:")
|
77
|
+
|
78
|
+
silence_stream(STDOUT) do
|
79
|
+
ActiveRecord::Schema.define(:version => 1) do
|
80
|
+
create_table :users do |t|
|
81
|
+
t.string :code
|
82
|
+
t.string :name
|
83
|
+
t.integer :points, :default => 0
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class Rails
|
89
|
+
@@cache = MockCache.new
|
90
|
+
def self.cache
|
91
|
+
@@cache
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class User < ActiveRecord::Base
|
96
|
+
cache_it do |c|
|
97
|
+
c.index :code
|
98
|
+
c.index :name
|
99
|
+
c.counters :points
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe CacheIt do
|
104
|
+
context "User" do
|
105
|
+
before do
|
106
|
+
User.delete_all
|
107
|
+
Rails.cache.clear
|
108
|
+
@u = User.create(:code => "x", :name => "joe")
|
109
|
+
end
|
110
|
+
|
111
|
+
it "reads" do
|
112
|
+
User.cache_it.read(:name => "joe").should== @u
|
113
|
+
end
|
114
|
+
|
115
|
+
it "writes" do
|
116
|
+
@u.name = "jane"
|
117
|
+
@u.cache_it.write
|
118
|
+
User.cache_it.read(:name => "jane").should== @u
|
119
|
+
User.find_by_sql("select * from users where id = #{@u.id}").first.name.should== "joe"
|
120
|
+
@u.save!
|
121
|
+
User.find_by_sql("select * from users where id = #{@u.id}").first.name.should== "jane"
|
122
|
+
end
|
123
|
+
|
124
|
+
it "increments" do
|
125
|
+
@u.cache_it.increment(:points)
|
126
|
+
@u.points.should== 1
|
127
|
+
User.find_by_sql("select * from users where name = 'joe'").first.points.should== 0
|
128
|
+
@u.save!
|
129
|
+
User.find_by_sql("select * from users where name = 'joe'").first.points.should== 1
|
130
|
+
end
|
131
|
+
|
132
|
+
it "deletes stale keys" do
|
133
|
+
@u.code = "y"
|
134
|
+
@u.save!
|
135
|
+
User.cache_it.read(:code => "x").should== nil
|
136
|
+
end
|
137
|
+
|
138
|
+
it "deletes stale keys on destroy" do
|
139
|
+
@u.code = "y"
|
140
|
+
@u.destroy
|
141
|
+
User.cache_it.read(:code => "x").should== nil
|
142
|
+
end
|
143
|
+
|
144
|
+
it "syncs counters" do
|
145
|
+
@u.cache_it.increment(:points)
|
146
|
+
@u2 = User.cache_it.read(:name => "joe")
|
147
|
+
@u2.points.should== 1
|
148
|
+
@u2.cache_it.increment(:points)
|
149
|
+
@u3 = User.cache_it.read({:name => "joe"}, :skip_counters => true)
|
150
|
+
@u3.points.should== 0
|
151
|
+
@u4 = User.cache_it.read(:name => "joe")
|
152
|
+
@u4.points.should== 2
|
153
|
+
end
|
154
|
+
|
155
|
+
it "nil for read of unknown keys" do
|
156
|
+
User.cache_it.read(:name => "dave").should== nil
|
157
|
+
end
|
158
|
+
|
159
|
+
it "flags set right" do
|
160
|
+
@u2 = User.cache_it.read(:name => "joe")
|
161
|
+
@u2.new_record?.should== false
|
162
|
+
@u2.persisted?.should== true
|
163
|
+
end
|
164
|
+
|
165
|
+
it "doesn't accept unknown index" do
|
166
|
+
expect { User.cache_it.read(:points => 10) }.to raise_error(/index not available/)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context "config" do
|
171
|
+
before do
|
172
|
+
@users_class = Class.new ActiveRecord::Base
|
173
|
+
@users_class.set_table_name "users"
|
174
|
+
end
|
175
|
+
|
176
|
+
it "can't use same column for both index and counter" do
|
177
|
+
expect do
|
178
|
+
@users_class.cache_it do |c|
|
179
|
+
c.index :name, :points
|
180
|
+
c.counters :points
|
181
|
+
end
|
182
|
+
end.to raise_error(/cannot use column/)
|
183
|
+
end
|
184
|
+
|
185
|
+
it "can use arg" do
|
186
|
+
expect do
|
187
|
+
@users_class.cache_it :code
|
188
|
+
end.to_not raise_error
|
189
|
+
end
|
190
|
+
|
191
|
+
it "can't use arg and block" do
|
192
|
+
expect do
|
193
|
+
@users_class.cache_it(:code) {|c| c.index :name}
|
194
|
+
end.to raise_error(/block or args/)
|
195
|
+
end
|
196
|
+
|
197
|
+
it "accepts constant for expires" do
|
198
|
+
expect do
|
199
|
+
@users_class.cache_it {|c| c.expires_in 3}
|
200
|
+
end.to_not raise_error
|
201
|
+
end
|
202
|
+
|
203
|
+
it "accepts proc for expires" do
|
204
|
+
expect do
|
205
|
+
@users_class.cache_it {|c| c.expires_in { 3 }}
|
206
|
+
end.to_not raise_error
|
207
|
+
end
|
208
|
+
|
209
|
+
it "counter must be integer column" do
|
210
|
+
expect do
|
211
|
+
@users_class.cache_it {|c| c.counters :name}
|
212
|
+
end.to raise_error(/must be column names for integer/)
|
213
|
+
end
|
214
|
+
|
215
|
+
it "counter must be existing column" do
|
216
|
+
expect do
|
217
|
+
@users_class.cache_it {|c| c.counters :not_a_column}
|
218
|
+
end.to raise_error(/must be column names for integer/)
|
219
|
+
end
|
220
|
+
|
221
|
+
it "each class gets its own config" do
|
222
|
+
@users_class2 = Class.new ActiveRecord::Base
|
223
|
+
@users_class2.set_table_name "users"
|
224
|
+
@users_class2.cache_it.config.should_not== @users_class.cache_it.config
|
225
|
+
end
|
226
|
+
|
227
|
+
it "cannot config twice" do
|
228
|
+
expect {@users_class.cache_it :name}.to_not raise_error
|
229
|
+
expect {@users_class.cache_it :code}.to raise_error
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
data/uninstall.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Uninstall hook code here
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cache_it
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Rodrigo Vanegas
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-04-11 00:00:00 -07:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: Integrates ActiveRecord with cache stores provided by Rails.cache, incluing memcached
|
22
|
+
email:
|
23
|
+
- rvanegas@gmail.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- .gitignore
|
32
|
+
- Gemfile
|
33
|
+
- MIT-LICENSE
|
34
|
+
- README
|
35
|
+
- Rakefile
|
36
|
+
- cache_it.gemspec
|
37
|
+
- init.rb
|
38
|
+
- install.rb
|
39
|
+
- lib/cache_it.rb
|
40
|
+
- lib/cache_it/version.rb
|
41
|
+
- spec/cache_it_spec.rb
|
42
|
+
- uninstall.rb
|
43
|
+
has_rdoc: true
|
44
|
+
homepage: ""
|
45
|
+
licenses: []
|
46
|
+
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
segments:
|
66
|
+
- 0
|
67
|
+
version: "0"
|
68
|
+
requirements: []
|
69
|
+
|
70
|
+
rubyforge_project: cache_it
|
71
|
+
rubygems_version: 1.3.7
|
72
|
+
signing_key:
|
73
|
+
specification_version: 3
|
74
|
+
summary: ActiveRecord caching
|
75
|
+
test_files: []
|
76
|
+
|