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