scoped_cache_keys 0.1.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/.travis.yml +5 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +47 -0
- data/Rakefile +22 -0
- data/Readme.md +37 -0
- data/lib/scoped_cache_keys/version.rb +3 -0
- data/lib/scoped_cache_keys.rb +23 -0
- data/scoped_cache_keys.gemspec +12 -0
- data/spec/scoped_cache_keys_spec.rb +97 -0
- data/spec/spec_helper.rb +22 -0
- metadata +74 -0
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
scoped_cache_keys (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
activemodel (3.2.3)
|
10
|
+
activesupport (= 3.2.3)
|
11
|
+
builder (~> 3.0.0)
|
12
|
+
activerecord (3.2.3)
|
13
|
+
activemodel (= 3.2.3)
|
14
|
+
activesupport (= 3.2.3)
|
15
|
+
arel (~> 3.0.2)
|
16
|
+
tzinfo (~> 0.3.29)
|
17
|
+
activesupport (3.2.3)
|
18
|
+
i18n (~> 0.6)
|
19
|
+
multi_json (~> 1.0)
|
20
|
+
arel (3.0.2)
|
21
|
+
builder (3.0.0)
|
22
|
+
diff-lcs (1.1.3)
|
23
|
+
i18n (0.6.0)
|
24
|
+
multi_json (1.3.4)
|
25
|
+
rake (0.9.2)
|
26
|
+
rspec (2.6.0)
|
27
|
+
rspec-core (~> 2.6.0)
|
28
|
+
rspec-expectations (~> 2.6.0)
|
29
|
+
rspec-mocks (~> 2.6.0)
|
30
|
+
rspec-core (2.6.4)
|
31
|
+
rspec-expectations (2.6.0)
|
32
|
+
diff-lcs (~> 1.1.2)
|
33
|
+
rspec-mocks (2.6.0)
|
34
|
+
sqlite3 (1.3.6)
|
35
|
+
timecop (0.3.5)
|
36
|
+
tzinfo (0.3.33)
|
37
|
+
|
38
|
+
PLATFORMS
|
39
|
+
ruby
|
40
|
+
|
41
|
+
DEPENDENCIES
|
42
|
+
activerecord
|
43
|
+
rake
|
44
|
+
rspec (~> 2)
|
45
|
+
scoped_cache_keys!
|
46
|
+
sqlite3
|
47
|
+
timecop
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
|
3
|
+
task :default do
|
4
|
+
sh "rspec spec/"
|
5
|
+
end
|
6
|
+
|
7
|
+
# extracted from https://github.com/grosser/project_template
|
8
|
+
rule /^version:bump:.*/ do |t|
|
9
|
+
sh "git status | grep 'nothing to commit'" # ensure we are not dirty
|
10
|
+
index = ['major', 'minor','patch'].index(t.name.split(':').last)
|
11
|
+
file = 'lib/scoped_cache_keys/version.rb'
|
12
|
+
|
13
|
+
version_file = File.read(file)
|
14
|
+
old_version, *version_parts = version_file.match(/(\d+)\.(\d+)\.(\d+)/).to_a
|
15
|
+
version_parts[index] = version_parts[index].to_i + 1
|
16
|
+
version_parts[2] = 0 if index < 2 # remove patch for minor
|
17
|
+
version_parts[1] = 0 if index < 1 # remove minor for major
|
18
|
+
new_version = version_parts * '.'
|
19
|
+
File.open(file,'w'){|f| f.write(version_file.sub(old_version, new_version)) }
|
20
|
+
|
21
|
+
sh "bundle && git add #{file} Gemfile.lock && git commit -m 'bump version to #{new_version}'"
|
22
|
+
end
|
data/Readme.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
Add scoped_cache_key / expire_scoped_cache_key to your models for caching/sweeping of model-related caches.
|
2
|
+
|
3
|
+
Install
|
4
|
+
=======
|
5
|
+
sudo gem install scoped_cache_keys
|
6
|
+
Or
|
7
|
+
|
8
|
+
rails plugin install git://github.com/grosser/scoped_cache_keys.git
|
9
|
+
|
10
|
+
Usage
|
11
|
+
=====
|
12
|
+
|
13
|
+
Gives you a key that will change whenever expire_scoped_cache_key is called.
|
14
|
+
|
15
|
+
<% cache user.scoped_cache_key :products do %>
|
16
|
+
... user.products.each ...
|
17
|
+
<% end %>
|
18
|
+
|
19
|
+
<% cache "something-else-" + user.scoped_cache_key :products %>
|
20
|
+
... will also be expired ...
|
21
|
+
<% end %>
|
22
|
+
|
23
|
+
# app/sweepers/product_sweeper.rb
|
24
|
+
class ProductSweeper < ActionController::Caching::Sweeper
|
25
|
+
observe Product
|
26
|
+
|
27
|
+
def after_save(record)
|
28
|
+
record.user.expire_scoped_cache_key :products
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
Author
|
33
|
+
======
|
34
|
+
[Zendesk](http://zendesk.com)<br/>
|
35
|
+
michael@grosser.it<br/>
|
36
|
+
License: MIT<br/>
|
37
|
+
[](http://travis-ci.org/grosser/scoped_cache_keys)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'scoped_cache_keys/version'
|
2
|
+
|
3
|
+
module ScopedCacheKeys
|
4
|
+
def scoped_cache_key(scope)
|
5
|
+
base_key = Rails.cache.fetch(build_scoped_cache_key([scope])){ Time.now.to_f }
|
6
|
+
build_scoped_cache_key [scope, base_key]
|
7
|
+
end
|
8
|
+
|
9
|
+
def expire_scoped_cache_key(scope)
|
10
|
+
Rails.cache.delete(build_scoped_cache_key(scope))
|
11
|
+
end
|
12
|
+
|
13
|
+
def touch_if_necessary
|
14
|
+
raise "#{self.class} has no updated_at" unless respond_to? :updated_at=
|
15
|
+
touch if updated_at < 1.second.ago
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def build_scoped_cache_key(*scopes)
|
21
|
+
"#{self.class.table_name}/#{id}/#{scopes.join('/')}"
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
2
|
+
name = "scoped_cache_keys"
|
3
|
+
require "#{name}/version"
|
4
|
+
|
5
|
+
Gem::Specification.new name, ScopedCacheKeys::VERSION do |s|
|
6
|
+
s.summary = "Add scoped_cache_key / expire_scoped_cache_key to your models for caching/sweeping of model-related caches + touch_if_necessary"
|
7
|
+
s.authors = ["Michael Grosser"]
|
8
|
+
s.email = "michael@grosser.it"
|
9
|
+
s.homepage = "http://github.com/grosser/#{name}"
|
10
|
+
s.files = `git ls-files`.split("\n")
|
11
|
+
s.license = 'MIT'
|
12
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# create tables
|
4
|
+
ActiveRecord::Schema.define(:version => 1) do
|
5
|
+
create_table :users do |t|
|
6
|
+
t.timestamp :updated_at
|
7
|
+
end
|
8
|
+
|
9
|
+
create_table :products do |t|
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# setup models
|
14
|
+
class User < ActiveRecord::Base
|
15
|
+
include ScopedCacheKeys
|
16
|
+
end
|
17
|
+
|
18
|
+
class Product < ActiveRecord::Base
|
19
|
+
include ScopedCacheKeys
|
20
|
+
end
|
21
|
+
|
22
|
+
describe ScopedCacheKeys do
|
23
|
+
let(:user){ User.create! }
|
24
|
+
|
25
|
+
before do
|
26
|
+
Rails.cache.clear
|
27
|
+
end
|
28
|
+
|
29
|
+
it "has a VERSION" do
|
30
|
+
ScopedCacheKeys::VERSION.should =~ /^[\.\da-z]+$/
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#scoped_cache_key" do
|
34
|
+
it "is scoped by id" do
|
35
|
+
Timecop.freeze "2011-01-01"
|
36
|
+
user.scoped_cache_key(:foo).should_not == User.create!.scoped_cache_key(:foo)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "stays the same" do
|
40
|
+
user.scoped_cache_key(:foo).should == user.scoped_cache_key(:foo)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "does not depend on updated_at" do
|
44
|
+
expect{
|
45
|
+
user.updated_at = 1.week.ago
|
46
|
+
}.to_not change{ user.scoped_cache_key(:foo) }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#expire_scoped_cache_key" do
|
51
|
+
it "expires a specific scope" do
|
52
|
+
expect{
|
53
|
+
user.expire_scoped_cache_key :foo
|
54
|
+
}.to change{ user.scoped_cache_key(:foo) }
|
55
|
+
end
|
56
|
+
|
57
|
+
it "does not expire other keys" do
|
58
|
+
expect{
|
59
|
+
user.expire_scoped_cache_key :bar
|
60
|
+
}.to_not change{ user.scoped_cache_key(:foo) }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "#touch_if_necessary" do
|
65
|
+
context "with a model that has updated_at" do
|
66
|
+
let(:model) do
|
67
|
+
user = User.create!
|
68
|
+
user.update_attribute(:updated_at, 1.month.ago)
|
69
|
+
user
|
70
|
+
end
|
71
|
+
|
72
|
+
it "increments updated_at" do
|
73
|
+
expect{
|
74
|
+
model.touch_if_necessary
|
75
|
+
}.to change{ model.reload.updated_at.to_i }
|
76
|
+
end
|
77
|
+
|
78
|
+
it "does not update updated_at if it thinks the model is fresh" do
|
79
|
+
model.touch_if_necessary
|
80
|
+
expect{
|
81
|
+
model.class.update(model.id, :updated_at => 1.month.ago)
|
82
|
+
model.touch_if_necessary
|
83
|
+
}.to change{ model.reload.updated_at.to_i }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "with a model that does not have updated_at" do
|
88
|
+
let(:model){ Product.create! }
|
89
|
+
|
90
|
+
it "raises" do
|
91
|
+
expect{
|
92
|
+
model.touch_if_necessary
|
93
|
+
}.to raise_error
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
$LOAD_PATH.unshift 'lib'
|
2
|
+
require 'scoped_cache_keys'
|
3
|
+
|
4
|
+
require 'active_record'
|
5
|
+
require 'timecop'
|
6
|
+
|
7
|
+
ActiveRecord::Base.establish_connection(
|
8
|
+
:adapter => "sqlite3",
|
9
|
+
:database => ":memory:"
|
10
|
+
)
|
11
|
+
|
12
|
+
module Rails
|
13
|
+
def self.cache
|
14
|
+
@cache ||= ActiveSupport::Cache::MemoryStore.new
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
RSpec.configure do |config|
|
19
|
+
config.before do
|
20
|
+
Timecop.return
|
21
|
+
end
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: scoped_cache_keys
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Michael Grosser
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-05-04 00:00:00 Z
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description:
|
22
|
+
email: michael@grosser.it
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files: []
|
28
|
+
|
29
|
+
files:
|
30
|
+
- .travis.yml
|
31
|
+
- Gemfile
|
32
|
+
- Gemfile.lock
|
33
|
+
- Rakefile
|
34
|
+
- Readme.md
|
35
|
+
- lib/scoped_cache_keys.rb
|
36
|
+
- lib/scoped_cache_keys/version.rb
|
37
|
+
- scoped_cache_keys.gemspec
|
38
|
+
- spec/scoped_cache_keys_spec.rb
|
39
|
+
- spec/spec_helper.rb
|
40
|
+
homepage: http://github.com/grosser/scoped_cache_keys
|
41
|
+
licenses:
|
42
|
+
- MIT
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
hash: 3
|
54
|
+
segments:
|
55
|
+
- 0
|
56
|
+
version: "0"
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
hash: 3
|
63
|
+
segments:
|
64
|
+
- 0
|
65
|
+
version: "0"
|
66
|
+
requirements: []
|
67
|
+
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 1.8.24
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: Add scoped_cache_key / expire_scoped_cache_key to your models for caching/sweeping of model-related caches + touch_if_necessary
|
73
|
+
test_files: []
|
74
|
+
|