scoped_cache_keys 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ script: "bundle exec rake"
2
+ rvm:
3
+ - ree
4
+ - 1.9.2
5
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source :rubygems
2
+ gemspec
3
+
4
+ gem 'rake'
5
+ gem 'rspec', '~>2'
6
+ gem 'activerecord'
7
+ gem 'sqlite3'
8
+ gem 'timecop'
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
+ [![Build Status](https://secure.travis-ci.org/grosser/scoped_cache_keys.png)](http://travis-ci.org/grosser/scoped_cache_keys)
@@ -0,0 +1,3 @@
1
+ module ScopedCacheKeys
2
+ VERSION = '0.1.0'
3
+ end
@@ -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
@@ -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
+