cashier 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/.gitignore +3 -42
  2. data/README.md +183 -0
  3. data/Rakefile +1 -5
  4. data/cashier.gemspec +8 -11
  5. data/lib/cashier.rb +93 -35
  6. data/lib/cashier/adapters/cache_store.rb +45 -0
  7. data/lib/cashier/adapters/redis_store.rb +46 -0
  8. data/lib/cashier/application_controller.rb +28 -0
  9. data/lib/cashier/matchers.rb +0 -1
  10. data/lib/cashier/railtie.rb +4 -3
  11. data/lib/cashier/version.rb +1 -1
  12. data/spec/{application_controller_spec.rb → controllers/application_controller_spec.rb} +0 -8
  13. data/spec/{test_app → dummy}/.gitignore +0 -0
  14. data/spec/{test_app → dummy}/Gemfile +0 -0
  15. data/spec/{test_app → dummy}/README +0 -0
  16. data/spec/{test_app → dummy}/Rakefile +0 -0
  17. data/spec/{test_app → dummy}/app/controllers/application_controller.rb +0 -0
  18. data/spec/{test_app → dummy}/app/controllers/home_controller.rb +0 -0
  19. data/spec/{test_app → dummy}/app/helpers/application_helper.rb +0 -0
  20. data/spec/{test_app → dummy}/app/helpers/home_helper.rb +0 -0
  21. data/spec/{test_app → dummy}/app/views/home/index.html.erb +0 -0
  22. data/spec/{test_app → dummy}/app/views/layouts/application.html.erb +0 -0
  23. data/spec/{test_app → dummy}/config.ru +0 -0
  24. data/spec/{test_app → dummy}/config/application.rb +0 -4
  25. data/spec/{test_app → dummy}/config/boot.rb +0 -0
  26. data/spec/{test_app → dummy}/config/environment.rb +0 -0
  27. data/spec/{test_app → dummy}/config/environments/development.rb +0 -3
  28. data/spec/{test_app → dummy}/config/environments/production.rb +0 -3
  29. data/spec/{test_app → dummy}/config/environments/test.rb +1 -6
  30. data/spec/{test_app → dummy}/config/initializers/backtrace_silencers.rb +0 -0
  31. data/spec/{test_app → dummy}/config/initializers/inflections.rb +0 -0
  32. data/spec/{test_app → dummy}/config/initializers/mime_types.rb +0 -0
  33. data/spec/{test_app → dummy}/config/initializers/secret_token.rb +0 -0
  34. data/spec/{test_app → dummy}/config/initializers/session_store.rb +0 -0
  35. data/spec/{test_app → dummy}/config/locales/en.yml +0 -0
  36. data/spec/{test_app → dummy}/config/routes.rb +0 -0
  37. data/spec/{test_app → dummy}/db/seeds.rb +0 -0
  38. data/spec/{test_app → dummy}/lib/tasks/.gitkeep +0 -0
  39. data/spec/{test_app → dummy}/public/404.html +0 -0
  40. data/spec/{test_app → dummy}/public/422.html +0 -0
  41. data/spec/{test_app → dummy}/public/500.html +0 -0
  42. data/spec/{test_app → dummy}/public/favicon.ico +0 -0
  43. data/spec/{test_app → dummy}/public/images/rails.png +0 -0
  44. data/spec/{test_app → dummy}/public/javascripts/application.js +0 -0
  45. data/spec/{test_app → dummy}/public/javascripts/controls.js +0 -0
  46. data/spec/{test_app → dummy}/public/javascripts/dragdrop.js +0 -0
  47. data/spec/{test_app → dummy}/public/javascripts/effects.js +0 -0
  48. data/spec/{test_app → dummy}/public/javascripts/prototype.js +0 -0
  49. data/spec/{test_app → dummy}/public/javascripts/rails.js +0 -0
  50. data/spec/{test_app → dummy}/public/robots.txt +0 -0
  51. data/spec/{test_app → dummy}/public/stylesheets/.gitkeep +0 -0
  52. data/spec/{test_app → dummy}/script/rails +0 -0
  53. data/spec/{test_app → dummy}/test/performance/browsing_test.rb +0 -0
  54. data/spec/{test_app → dummy}/test/test_helper.rb +0 -0
  55. data/spec/{test_app → dummy}/vendor/plugins/.gitkeep +0 -0
  56. data/spec/lib/adapters/cache_store_spec.rb +75 -0
  57. data/spec/lib/adapters/redis_store_spec.rb +89 -0
  58. data/spec/lib/cashier_spec.rb +112 -0
  59. data/spec/spec_helper.rb +34 -8
  60. metadata +179 -214
  61. data/..gemspec +0 -21
  62. data/.infinity_test +0 -19
  63. data/.rvmrc +0 -1
  64. data/Gemfile.lock +0 -118
  65. data/lib/cashier/controller_helper.rb +0 -34
  66. data/readme.md +0 -120
  67. data/spec/cashier_spec.rb +0 -89
  68. data/spec/test_app/Gemfile.lock +0 -73
  69. data/spec/test_app/config/database.yml +0 -22
data/..gemspec DELETED
@@ -1,21 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "./version"
4
-
5
- Gem::Specification.new do |s|
6
- s.name = "."
7
- s.version = .::VERSION
8
- s.platform = Gem::Platform::RUBY
9
- s.authors = ["TODO: Write your name"]
10
- s.email = ["TODO: Write your email address"]
11
- s.homepage = ""
12
- s.summary = %q{TODO: Write a gem summary}
13
- s.description = %q{TODO: Write a gem description}
14
-
15
- s.rubyforge_project = "."
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/.infinity_test DELETED
@@ -1,19 +0,0 @@
1
- infinity_test do
2
- notifications :growl
3
-
4
- use :test_framework => :rspec
5
-
6
- before_run do
7
- clear :terminal
8
- end
9
-
10
- heuristics do
11
- add('lib/(.+)\.rb') do |file|
12
- run :all => :tests
13
- end
14
-
15
- add('rails_app') do |file|
16
- run :all => :tests
17
- end
18
- end
19
- end
data/.rvmrc DELETED
@@ -1 +0,0 @@
1
- rvm use 1.9.2@cashier
data/Gemfile.lock DELETED
@@ -1,118 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- cashier (0.2.0)
5
-
6
- GEM
7
- remote: http://rubygems.org/
8
- specs:
9
- abstract (1.0.0)
10
- actionmailer (3.0.4)
11
- actionpack (= 3.0.4)
12
- mail (~> 2.2.15)
13
- actionpack (3.0.4)
14
- activemodel (= 3.0.4)
15
- activesupport (= 3.0.4)
16
- builder (~> 2.1.2)
17
- erubis (~> 2.6.6)
18
- i18n (~> 0.4)
19
- rack (~> 1.2.1)
20
- rack-mount (~> 0.6.13)
21
- rack-test (~> 0.5.7)
22
- tzinfo (~> 0.3.23)
23
- activemodel (3.0.4)
24
- activesupport (= 3.0.4)
25
- builder (~> 2.1.2)
26
- i18n (~> 0.4)
27
- activerecord (3.0.4)
28
- activemodel (= 3.0.4)
29
- activesupport (= 3.0.4)
30
- arel (~> 2.0.2)
31
- tzinfo (~> 0.3.23)
32
- activeresource (3.0.4)
33
- activemodel (= 3.0.4)
34
- activesupport (= 3.0.4)
35
- activesupport (3.0.4)
36
- archive-tar-minitar (0.5.2)
37
- arel (2.0.8)
38
- builder (2.1.2)
39
- columnize (0.3.2)
40
- diff-lcs (1.1.2)
41
- erubis (2.6.6)
42
- abstract (>= 1.0.0)
43
- i18n (0.5.0)
44
- infinity_test (1.0.2)
45
- notifiers (>= 1.1.0)
46
- watchr (>= 0.7)
47
- linecache19 (0.5.11)
48
- ruby_core_source (>= 0.1.4)
49
- mail (2.2.15)
50
- activesupport (>= 2.3.6)
51
- i18n (>= 0.4.0)
52
- mime-types (~> 1.16)
53
- treetop (~> 1.4.8)
54
- memcache-client (1.8.5)
55
- mime-types (1.16)
56
- notifiers (1.1.0)
57
- polyglot (0.3.1)
58
- rack (1.2.1)
59
- rack-mount (0.6.13)
60
- rack (>= 1.0.0)
61
- rack-test (0.5.7)
62
- rack (>= 1.0)
63
- rails (3.0.4)
64
- actionmailer (= 3.0.4)
65
- actionpack (= 3.0.4)
66
- activerecord (= 3.0.4)
67
- activeresource (= 3.0.4)
68
- activesupport (= 3.0.4)
69
- bundler (~> 1.0)
70
- railties (= 3.0.4)
71
- railties (3.0.4)
72
- actionpack (= 3.0.4)
73
- activesupport (= 3.0.4)
74
- rake (>= 0.8.7)
75
- thor (~> 0.14.4)
76
- rake (0.8.7)
77
- rspec (2.5.0)
78
- rspec-core (~> 2.5.0)
79
- rspec-expectations (~> 2.5.0)
80
- rspec-mocks (~> 2.5.0)
81
- rspec-core (2.5.1)
82
- rspec-expectations (2.5.0)
83
- diff-lcs (~> 1.1.2)
84
- rspec-mocks (2.5.0)
85
- rspec-rails (2.5.0)
86
- actionpack (~> 3.0)
87
- activesupport (~> 3.0)
88
- railties (~> 3.0)
89
- rspec (~> 2.5.0)
90
- ruby-debug-base19 (0.11.24)
91
- columnize (>= 0.3.1)
92
- linecache19 (>= 0.5.11)
93
- ruby_core_source (>= 0.1.4)
94
- ruby-debug19 (0.11.6)
95
- columnize (>= 0.3.1)
96
- linecache19 (>= 0.5.11)
97
- ruby-debug-base19 (>= 0.11.19)
98
- ruby_core_source (0.1.4)
99
- archive-tar-minitar (>= 0.5.2)
100
- sqlite3 (1.3.3)
101
- thor (0.14.6)
102
- treetop (1.4.9)
103
- polyglot (>= 0.3.1)
104
- tzinfo (0.3.24)
105
- watchr (0.7)
106
-
107
- PLATFORMS
108
- ruby
109
-
110
- DEPENDENCIES
111
- cashier!
112
- infinity_test
113
- memcache-client
114
- rails
115
- rspec
116
- rspec-rails
117
- ruby-debug19
118
- sqlite3
@@ -1,34 +0,0 @@
1
- # Hooks into ApplicationController's write_fragment method.
2
- # write_fragment is used for action and fragment caching.
3
- # Create an alias method chain to call our customer method
4
- # which stores the associated key with the tag in a
5
- # Redis Set. Then we can expire all those keys from anywhere
6
- # in the code using Rails.cache.delete
7
- #
8
- # I use alias_method_chain instead of calling 'super'
9
- # because there is a very rare case where someone
10
- # may have redfined 'write_fragment' in their own
11
- # controllers. Using an alias method chain
12
- # keeps those methods intact.
13
-
14
- module Cashier
15
- module ControllerHelper
16
- def self.included(klass)
17
- klass.class_eval do
18
- def write_fragment_with_tagged_key(key, content, options = nil)
19
- if options && options[:tag] && Cashier.perform_caching?
20
- tags = case options[:tag].class.to_s
21
- when 'Proc', 'Lambda'
22
- options[:tag].call(self)
23
- else
24
- options[:tag]
25
- end
26
- Cashier.store_fragment fragment_cache_key(key), *tags
27
- end
28
- write_fragment_without_tagged_key(key, content, options)
29
- end
30
- alias_method_chain :write_fragment, :tagged_key
31
- end
32
- end
33
- end
34
- end
data/readme.md DELETED
@@ -1,120 +0,0 @@
1
- # Cashier: Tag Based Caching for Rails
2
-
3
- Manage your cache keys with tags, forget about keys!
4
-
5
- ## What Is It?
6
-
7
- # in your view
8
- cache @some_record, :tag => 'some-component'
9
-
10
- # in another view
11
- cache @some_releated_record, :tag => 'some-component'
12
-
13
- # can have multiple tags
14
- cache @something, :tag => ['dashboard', 'settings'] # can expire from either tag
15
-
16
- # in an observer
17
- Cashier.expire 'some-component' # don't worry about keys! Much easier to sweep with confidence
18
-
19
- # in your controller
20
- caches_action :tag => 'complicated-action', :cache_path => proc { |c|
21
- # huge complicated mess of parameters
22
- c.params
23
- }
24
-
25
- # need to access the controller?
26
- caches_action :tag => proc {|c|
27
- # c is the controller
28
- "users/#{c.current_user.id}/dashboard"
29
- }
30
-
31
- # in your sweeper, in your observers, in your resque jobs...wherever
32
- Cashier.expire 'complicated-action'
33
- Cashier.expire 'tag1', 'tag2', 'tag3', 'tag4'
34
-
35
- # what's cached
36
- Cashier.tags
37
-
38
- # sweep all stored keys
39
- Cashier.clear
40
-
41
- ## How it Came About
42
-
43
- I work on an application that involves all sorts of caching. I try to use action caching whenever I possible.
44
- I had an index action that had maybe ~20 different combination of filters and sorting. If you want to use
45
- action caching you have to create a **unique** key for every combination. This created a nice 6 nested loop
46
- to expire the cache. Once you had pagination, then you have even more combinations of possible cache keys.
47
- I needed a better solution. I wanted to expire things logically as a viewed them on the page. IE, if
48
- a record was added, I wanted to say "expire that page". Problem was that page contained ~1000 different keys.
49
- So I needed something to store the keys for me and associate them with tags. That's exactly what cashier does.
50
- Cache associate individual cache keys with a tag, then expire them all at once. This took my 7 layer loop
51
- down to one line of code. It's also made managing the cache throught my application much easier.
52
-
53
- ## Why Tag Based Caching is Useful
54
-
55
- 1. You don't worry about keys. How many times have you created a complicated key for a fragment or action
56
- then messed up when you tried to expire the cache
57
- 2. Associate your cached content into groups of related content. If you have records that are closely associated
58
- or displayed together, then you can tag them and expire them at once.
59
- 3. **Expire cached content from anywhere.** If you've done any serious development, you know that Rails caching
60
- does not work (easily) outside the scope of an HTTP request. If you have background jobs that manipulate data
61
- or potentially invalidate cached data, you know how much of a pain it is to say `expire_fragment` in some random code.
62
- 4. Don't do anything differently! All you have to do is pass `:tag => 'something'` into `cache` (in the view) or `caches_action`
63
- in the controller.
64
-
65
- ## How it Works
66
-
67
- Cashier hooks into Rails' `expire_fragment` method using `alias_method_chain` to run some code that captures the key
68
- and tag then stores that in the rails cache. **No external processes are
69
- needed. All tag/fragment information is stored in the Rails.cache.**
70
-
71
- ## Configuration
72
-
73
- **if you're using Rails 3, there is no configuration.** If you're using
74
- Rails 2, include `Cashier::ControllerHelper` into ApplicationController
75
- like so:
76
-
77
- require 'cashier'
78
-
79
- class ApplicationController
80
- include Cashier::ControllerHelper
81
- end
82
-
83
- ## Testing
84
-
85
- I've also included some Rspec Matchers and a cucumber helper for testing
86
- caching. The rspec matchers can be used like this:
87
-
88
- describe "get index" do
89
- it "should cache the action" do
90
- get :index
91
- 'some-tag'.should be_cached
92
- end
93
- end
94
-
95
- Testing w/cucumber is more involved. **Make sure you set perform_caching = true in test.rb**
96
- Then require `cashier/cucumber` to use the matchers in your steps. Here
97
- is an example of a possible step
98
-
99
- Then /the dashboard should be cached/ do
100
- "dashboard".should be_cached
101
- end
102
-
103
- Including `cashier/cucumber` will also wipe the cache before every
104
- scenario.
105
-
106
- ## Contributing to Cashier
107
-
108
- * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
109
- * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
110
- * Fork the project
111
- * Start a feature/bugfix branch
112
- * Commit and push until you are happy with your contribution
113
- * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
114
- * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
115
-
116
- ## Copyright
117
-
118
- Copyright (c) 2010 Adam Hawkins. See LICENSE.txt for
119
- further details.
120
-
data/spec/cashier_spec.rb DELETED
@@ -1,89 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
-
3
- describe "Cashier" do
4
- subject { Cashier }
5
-
6
- let(:cache) { Rails.cache }
7
-
8
- describe "#store_fragment" do
9
- it "should write the tag to the cache" do
10
- subject.store_fragment('fragment-key', 'dashboard')
11
-
12
- cache.fetch('dashboard').should eql(['fragment-key'])
13
- end
14
-
15
- it "should store the tag for book keeping" do
16
- subject.store_fragment('fragment-key', 'dashboard', 'settings')
17
- cache.fetch(Cashier::CACHE_KEY).should eql(%w(dashboard settings))
18
- end
19
- end
20
-
21
- describe "#expire" do
22
- before do
23
- subject.store_fragment('fragment-key', 'dashboard')
24
- end
25
-
26
- it "should remove delete the fragment key" do
27
- subject.expire('dashboard')
28
- Rails.cache.fetch('fragment-key').should be_nil
29
- end
30
-
31
- it "should remove the tag" do
32
- subject.expire('dashboard')
33
- Rails.cache.fetch('dashboard').should be_nil
34
- end
35
-
36
- it "should remove the tag from the list of tracked tags" do
37
- subject.expire('dashboard')
38
- Rails.cache.fetch(Cashier::CACHE_KEY).should eql([])
39
- end
40
- end
41
-
42
- describe "#tags" do
43
- it "should return a list of active tags" do
44
- subject.store_fragment('key1', 'dashboard')
45
- subject.store_fragment('key2', 'settings')
46
- subject.store_fragment('key3', 'email')
47
-
48
- subject.tags.should eql(%w(dashboard settings email))
49
- end
50
- end
51
-
52
- describe '#clear' do
53
- before(:each) do
54
- subject.store_fragment('key1', 'dashboard')
55
- subject.store_fragment('key2', 'settings')
56
- subject.store_fragment('key3', 'email')
57
- end
58
-
59
- it "should expire all tags" do
60
- subject.should_receive(:expire).with('dashboard','settings','email')
61
- subject.clear
62
- end
63
-
64
- it "should clear the list of tracked tags" do
65
- subject.clear
66
- cache.fetch(Cashier::CACHE_KEY).should be_nil
67
- end
68
- end
69
-
70
- describe '#keys' do
71
- it "should return an array of all the tracked keys" do
72
- subject.store_fragment('key1', 'dashboard')
73
- subject.store_fragment('key2', 'settings')
74
- subject.store_fragment('key3', 'email')
75
-
76
- subject.keys.should eql(%w(key1 key2 key3))
77
- end
78
- end
79
-
80
- describe '#keys_for' do
81
- it "should return an array of all the keys for the tag" do
82
- subject.store_fragment('key1', 'dashboard')
83
- subject.store_fragment('key2', 'dashboard')
84
- subject.store_fragment('key3', 'dashboard')
85
-
86
- subject.keys_for('dashboard').should eql(%w(key1 key2 key3))
87
- end
88
- end
89
- end
@@ -1,73 +0,0 @@
1
- GEM
2
- remote: http://rubygems.org/
3
- specs:
4
- abstract (1.0.0)
5
- actionmailer (3.0.4)
6
- actionpack (= 3.0.4)
7
- mail (~> 2.2.15)
8
- actionpack (3.0.4)
9
- activemodel (= 3.0.4)
10
- activesupport (= 3.0.4)
11
- builder (~> 2.1.2)
12
- erubis (~> 2.6.6)
13
- i18n (~> 0.4)
14
- rack (~> 1.2.1)
15
- rack-mount (~> 0.6.13)
16
- rack-test (~> 0.5.7)
17
- tzinfo (~> 0.3.23)
18
- activemodel (3.0.4)
19
- activesupport (= 3.0.4)
20
- builder (~> 2.1.2)
21
- i18n (~> 0.4)
22
- activerecord (3.0.4)
23
- activemodel (= 3.0.4)
24
- activesupport (= 3.0.4)
25
- arel (~> 2.0.2)
26
- tzinfo (~> 0.3.23)
27
- activeresource (3.0.4)
28
- activemodel (= 3.0.4)
29
- activesupport (= 3.0.4)
30
- activesupport (3.0.4)
31
- arel (2.0.8)
32
- builder (2.1.2)
33
- erubis (2.6.6)
34
- abstract (>= 1.0.0)
35
- i18n (0.5.0)
36
- mail (2.2.15)
37
- activesupport (>= 2.3.6)
38
- i18n (>= 0.4.0)
39
- mime-types (~> 1.16)
40
- treetop (~> 1.4.8)
41
- mime-types (1.16)
42
- polyglot (0.3.1)
43
- rack (1.2.1)
44
- rack-mount (0.6.13)
45
- rack (>= 1.0.0)
46
- rack-test (0.5.7)
47
- rack (>= 1.0)
48
- rails (3.0.4)
49
- actionmailer (= 3.0.4)
50
- actionpack (= 3.0.4)
51
- activerecord (= 3.0.4)
52
- activeresource (= 3.0.4)
53
- activesupport (= 3.0.4)
54
- bundler (~> 1.0)
55
- railties (= 3.0.4)
56
- railties (3.0.4)
57
- actionpack (= 3.0.4)
58
- activesupport (= 3.0.4)
59
- rake (>= 0.8.7)
60
- thor (~> 0.14.4)
61
- rake (0.8.7)
62
- sqlite3 (1.3.3)
63
- thor (0.14.6)
64
- treetop (1.4.9)
65
- polyglot (>= 0.3.1)
66
- tzinfo (0.3.24)
67
-
68
- PLATFORMS
69
- ruby
70
-
71
- DEPENDENCIES
72
- rails (= 3.0.4)
73
- sqlite3