cashier 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,9 @@
1
+ spec/dummy/log
1
2
  spec/dummy/tmp/pids
2
3
  spec/dummy/tmp/cache
3
4
  Gemfile.lock
5
+ .rvmrc
6
+ coverage*
7
+ .tags
8
+ .tags_sorted_by_file
9
+ .rspec
data/README.md CHANGED
@@ -29,10 +29,22 @@ caches_action :tag => proc {|c|
29
29
  "users/#{c.current_user.id}/dashboard"
30
30
  }
31
31
 
32
- # in your sweeper, in your observers, in your resque jobs...wherever
32
+ # in your sweeper, in your observers, in your Resque jobs...wherever
33
33
  Cashier.expire 'complicated-action'
34
34
  Cashier.expire 'tag1', 'tag2', 'tag3', 'tag4'
35
35
 
36
+ # It integrates smoothly with Rails.cache as well, not just the views
37
+ Rails.cache.fetch("user_1", :tag => ["users"]) { User.find(1) }
38
+ Rails.cache.fetch("user_2", :tag => ["users"]) { User.find(2) }
39
+ Rails.cache.fetch("user_3", :tag => ["users"]) { User.find(3) }
40
+ Rails.cache.fetch("admins", :tag => ["users"]) { User.where(role: "Admin").all }
41
+
42
+ # You can then expire all your users
43
+ Cashier.expire "users"
44
+
45
+ # You can also use Rails.cache.write
46
+ Rails.cache.write("foo", "bar", :tag => ["some_tag"])
47
+
36
48
  # what's cached
37
49
  Cashier.tags
38
50
 
@@ -77,19 +89,19 @@ Cashier has 2 adapters for the tags storing, `:cache_store` or `:redis_store`.
77
89
 
78
90
  #### Setting an adapter for working with the cache as the tags storage
79
91
 
80
- `config/initializers/cashier.rb`
81
-
82
92
  ```ruby
83
- Cachier.adapter = :cache_store
93
+ # config/environment/production.rb
94
+
95
+ config.cashier.adapter = :cache_store
96
+ # or config.cashier.adapter = :redis_store
84
97
  ```
85
98
 
86
99
  #### Setting an adapter for working with Redis as the tags storage
87
100
 
88
- `config/initializers/cashier.rb`
89
101
 
90
102
  ```ruby
91
- Cashier.adapter = :redis_store
92
- Cashier.adapter.redis = Redis.new(:host => '127.0.0.1', :port => '3697')
103
+ # config/environment/production.rb
104
+ config.cashier.adapter.redis = Redis.new(:host => '127.0.0.1', :port => '3697') # or Resque.redis or any existing redis connection
93
105
  ```
94
106
 
95
107
  ### Why Redis?
@@ -118,54 +130,54 @@ Benchmark.measure do
118
130
  end
119
131
  end
120
132
  ```
121
-
122
133
  Using the Redis adapter, the same piece of code takes 0.8 seconds, quite the difference :)
123
134
 
124
- ## Testing
125
135
 
126
- Use can use cashier to test caching as well. First things first:
136
+ ### Notifications
127
137
 
128
- ```ruby
129
- # test.rb
138
+ Cashier will send out events when things happen inside the library.
139
+ The events are sent out through `ActiveSupport::Notifications` so you can pretty much subscribe to the events from anywhere you want.
130
140
 
131
- config.application_controller.perform_caching = true
132
- ```
133
-
134
- I've also included some Rspec Matchers and a cucumber helper for testing
135
- caching. The rspec matchers can be used like this:
141
+ Here are the way you can subscribe to the events and use the data from them.
136
142
 
137
143
  ```ruby
138
- describe "get index" do
139
- include Cashier::Matchers
140
-
141
- it "should cache the action" do
142
- get :index
143
- 'some-tag'.should be_cached
144
- end
145
- end
144
+ # Subscribe to the store fragment event, this is fired every time cashier will call the "store_fragment" method
145
+ # payload[:data] will be something like this: ["key", ["tag1", "tag2", "tag3"]]
146
+ ActiveSupport::Notifications.subscribe("store_fragment.cashier") do |name, start, finish, id, payload|
147
+
148
+ end
149
+
150
+ # Subscribe to the clear event. (no data)
151
+ ActiveSupport::Notifications.subscribe("clear.cashier") do |name, start, finish, id, payload|
152
+
153
+ end
154
+
155
+ # Subscribe to the delete_cache_key event
156
+ # this event will fire every time there's a Rails.cache.delete with the key
157
+ # payload[:data] will be the key name that's been deleted from the cache
158
+ ActiveSupport::Notifications.subscribe("delete_cache_key.cashier") do |name, start, finish, id, payload|
159
+
160
+ end
161
+
162
+ # Subscribe to the o_write_cache_key event
163
+ # this event will fire every time there's a Rails.cache.write with the key
164
+ # payload[:data] will be the key name that's been written to the cache
165
+ ActiveSupport::Notifications.subscribe("write_cache_key.cashier") do |name, start, finish, id, payload|
166
+
167
+ end
146
168
  ```
147
169
 
148
- Testing w/cucumber is more involved.
149
-
150
- ```ruby
151
- # features/support/cashier.rb
152
- require 'cashier/cucumber'
153
- ```
170
+ ### Notifications use case
171
+ At [Gogobot](http://www.gogobot.com) we have a plugin to invalidate the external CDN cache on full pages for logged out users.
172
+ The usage is pretty unlimited.
154
173
 
155
- is an example of a possible step
156
-
157
- ```ruby
158
- Then /the dashboard should be cached/ do
159
- "dashboard".should be_cached
160
- end
161
- ```
162
- Including `cashier/cucumber` will also wipe the cache before every
163
- scenario.
174
+ If you think we're missing a notification, please do open an issue or be awesome and do it yourself and open a pull request.
164
175
 
165
176
  ## Contributors
166
177
 
167
- * [adman65](http://twitter.com/adman65) - Initial Implementation
178
+ * [twinturbo](http://twitter.com/adman65) - Initial Implementation
168
179
  * [KensoDev](http://twitter.com/kensodev) - Adding Redis support (Again \o/)
180
+ * [KensoDev](http://twitter.com/kensodev) - Adding plugins support for callback methods
169
181
 
170
182
  ## Contributing to Cashier
171
183
 
@@ -1,132 +1,152 @@
1
1
  module Cashier
2
- extend self
3
2
 
4
3
  CACHE_KEY = 'cashier-tags'
5
4
 
6
- def adapter
7
- if @@adapter == :cache_store
8
- Cashier::Adapters::CacheStore
9
- else
10
- Cashier::Adapters::RedisStore
5
+ class << self
6
+
7
+ # Public: whether the module will perform caching or not. this is being set in the application layer .perform_caching configuration
8
+ #
9
+ # Examples
10
+ #
11
+ # Cashier.perform_caching?
12
+ # # => true
13
+ #
14
+ def perform_caching?
15
+ ::ApplicationController.perform_caching
11
16
  end
12
- end
13
-
14
- # Public: set the adapter the Cashier module will use to store the keys
15
- #
16
- # cache_adapter - :cache_store / :redis_store
17
- #
18
- # Examples
19
- #
20
- # Cashier.adapter = :redis_store
21
- #
22
- def adapter=(cache_adapter)
23
- @@adapter = cache_adapter
24
- end
25
17
 
26
- # Public: whether the module will perform caching or not. this is being set in the application layer .perform_caching configuration
27
- #
28
- # Examples
29
- #
30
- # Cashier.perform_caching?
31
- # # => true
32
- #
33
- def perform_caching?
34
- ::ApplicationController.perform_caching
35
- end
36
-
37
- # Public: store a fragment with an array of tags for this fragment.
38
- #
39
- # fragment - cached fragment.
40
- # tags - array of tags you want to assign this fragments.
41
- #
42
- # Examples
43
- #
44
- # Cachier.store_fragment('foo', 'tag1', 'tag2', 'tag3')
45
- #
46
- def store_fragment(fragment, *tags)
47
- return unless perform_caching?
48
-
49
- tags.each do |tag|
50
- # store the fragment
51
- adapter.store_fragment_in_tag(fragment, tag)
18
+ # Public: store a fragment with an array of tags for this fragment.
19
+ #
20
+ # fragment - cached fragment.
21
+ # tags - array of tags you want to assign this fragments.
22
+ #
23
+ # Examples
24
+ #
25
+ # Cachier.store_fragment('foo', 'tag1', 'tag2', 'tag3')
26
+ #
27
+ def store_fragment(fragment, *tags)
28
+ return unless perform_caching?
29
+
30
+ tags = tags.flatten
31
+
32
+ ActiveSupport::Notifications.instrument("store_fragment.cashier", :data => [fragment, tags]) do
33
+ tags.each do |tag|
34
+ # store the fragment
35
+ adapter.store_fragment_in_tag(fragment, tag)
36
+ end
37
+
38
+ # now store the tag for book keeping
39
+ adapter.store_tags(tags)
40
+ end
52
41
  end
53
42
 
54
- # now store the tag for book keeping
55
- adapter.store_tags(tags)
56
- end
57
-
58
- # Public: expire tags. expiring the keys 'assigned' to the tags you expire and removes the tags from the tags list
59
- #
60
- # tags - array of tags to expire.
61
- #
62
- # Examples
63
- #
64
- # Cashier.expire('tag1', 'tag2')
65
- #
66
- def expire(*tags)
67
- return unless perform_caching?
68
-
69
- # delete them from the cache
70
- tags.each do |tag|
71
- fragment_keys = adapter.get_fragments_for_tag(tag)
72
-
73
- fragment_keys.each do |fragment_key|
74
- Rails.cache.delete(fragment_key)
43
+ # Public: expire tags. expiring the keys 'assigned' to the tags you expire and removes the tags from the tags list
44
+ #
45
+ # tags - array of tags to expire.
46
+ #
47
+ # Examples
48
+ #
49
+ # Cashier.expire('tag1', 'tag2')
50
+ #
51
+ def expire(*tags)
52
+ return unless perform_caching?
53
+
54
+ ActiveSupport::Notifications.instrument("expire.cashier", :data => tags) do
55
+ # delete them from the cache
56
+ tags.each do |tag|
57
+ fragment_keys = adapter.get_fragments_for_tag(tag)
58
+
59
+ fragment_keys.each do |fragment_key|
60
+ Rails.cache.delete(fragment_key)
61
+ end
62
+
63
+ adapter.delete_tag(tag)
64
+ end
65
+
66
+ # now remove them from the list
67
+ # of stored tags
68
+ adapter.remove_tags(tags)
75
69
  end
70
+ end
76
71
 
77
- adapter.delete_tag(tag)
72
+ # Public: returns the array of tags stored in the tags store.
73
+ #
74
+ #
75
+ # Examples
76
+ #
77
+ # Cashier.tags
78
+ # # => ['tag1', 'tag2']
79
+ #
80
+ def tags
81
+ adapter.tags
78
82
  end
79
83
 
80
- # now remove them from the list
81
- # of stored tags
82
- adapter.remove_tags(tags)
83
- end
84
+ # Public: clears the tags.
85
+ #
86
+ #
87
+ # Examples
88
+ #
89
+ # Cashier.clear
90
+ #
91
+ def clear
92
+ ActiveSupport::Notifications.instrument("clear.cashier") do
93
+ adapter.clear
94
+ end
95
+ end
84
96
 
85
- # Public: returns the array of tags stored in the tags store.
86
- #
87
- #
88
- # Examples
89
- #
90
- # Cashier.tags
91
- # # => ['tag1', 'tag2']
92
- #
93
- def tags
94
- adapter.tags
95
- end
97
+ # Public: get all the keys names as an array.
98
+ #
99
+ #
100
+ # Examples
101
+ #
102
+ # Cachier.keys
103
+ # # => ['key1', 'key2', 'key3']
104
+ #
105
+ def keys
106
+ adapter.keys
107
+ end
96
108
 
97
- # Public: clears the tags.
98
- #
99
- #
100
- # Examples
101
- #
102
- # Cashier.clear
103
- #
104
- def clear
105
- adapter.clear
106
- end
109
+ # Public: get all the keys for a specific tag as an array.
110
+ #
111
+ #
112
+ # Examples
113
+ #
114
+ # Cashier.tags_for('tag1')
115
+ # # => ['key1', 'key2', 'key3']
116
+ #
117
+ def keys_for(tag)
118
+ adapter.get_fragments_for_tag(tag)
119
+ end
107
120
 
108
- # Public: get all the keys names as an array.
109
- #
110
- #
111
- # Examples
112
- #
113
- # Cachier.keys
114
- # # => ['key1', 'key2', 'key3']
115
- #
116
- def keys
117
- adapter.keys
118
- end
121
+ # Public: adapter which is used by cashier.
122
+ #
123
+ # Examples
124
+ #
125
+ # Cashier.adapter
126
+ # # => Cashier::Adapters::CacheStore
127
+ #
128
+ # Cashier.adapter
129
+ # # => Cashier::Adapters::RedisStore
130
+ #
131
+ def adapter
132
+ if @@adapter == :cache_store
133
+ Cashier::Adapters::CacheStore
134
+ else
135
+ Cashier::Adapters::RedisStore
136
+ end
137
+ end
119
138
 
120
- # Public: get all the keys for a specific tag as an array.
121
- #
122
- #
123
- # Examples
124
- #
125
- # Cashier.tags_for('tag1')
126
- # # => ['key1', 'key2', 'key3']
127
- #
128
- def keys_for(tag)
129
- adapter.get_fragments_for_tag(tag)
139
+ # Public: set the adapter the Cashier module will use to store the keys
140
+ #
141
+ # cache_adapter - :cache_store / :redis_store
142
+ #
143
+ # Examples
144
+ #
145
+ # Cashier.adapter = :redis_store
146
+ #
147
+ def adapter=(cache_adapter)
148
+ @@adapter = cache_adapter
149
+ end
130
150
  end
131
151
  end
132
152
 
@@ -134,3 +154,9 @@ require 'rails'
134
154
  require 'cashier/railtie'
135
155
  require 'cashier/adapters/cache_store'
136
156
  require 'cashier/adapters/redis_store'
157
+
158
+ # Connect cashier up to the low level Rails cache.
159
+ ActiveSupport::Notifications.subscribe("cache_write.active_support") do |*args|
160
+ payload = ActiveSupport::Notifications::Event.new(*args).payload
161
+ Cashier.store_fragment payload[:key], payload[:tag] if payload[:tag]
162
+ end
@@ -42,4 +42,4 @@ module Cashier
42
42
  end
43
43
  end
44
44
  end
45
- end
45
+ end
@@ -1,9 +1,9 @@
1
1
  module Cashier
2
- class Railtie < Rails::Railtie
3
- initializer 'cashier.initialize' do
4
- ActiveSupport.on_load(:action_controller) do
5
- require 'cashier/application_controller'
6
- end
2
+ class Railtie < ::Rails::Railtie
3
+ config.cashier = Cashier
4
+
5
+ initializer "cashier.active_support.cache.instrumentation" do |app|
6
+ ActiveSupport::Cache::Store.instrument = true
7
7
  end
8
8
  end
9
- end
9
+ end
@@ -1,3 +1,3 @@
1
1
  module Cashier
2
- VERSION = "0.4.0"
2
+ VERSION = "0.4.1"
3
3
  end
@@ -0,0 +1,38 @@
1
+ require "spec_helper"
2
+
3
+ describe "Rails cache integration" do
4
+ subject { Rails.cache }
5
+ let(:cashier) { Cashier }
6
+
7
+ it "should ensure that cache operations are instrumented" do
8
+ ActiveSupport::Cache::Store.instrument.should be_true
9
+ end
10
+
11
+ context "write" do
12
+ it "should write to cashier when I call Rails.cache.write with tags" do
13
+ cashier.should_receive(:store_fragment).with("foo", ["some_tag"])
14
+ subject.write("foo", "bar", :tag => ["some_tag"])
15
+ end
16
+
17
+ it "shuld not write to cashier when I call Rails.cache.write without tags" do
18
+ cashier.should_not_receive(:store_fragment)
19
+ subject.write("foo", "bar")
20
+ end
21
+
22
+ it "should not fail when I don't pass in any options" do
23
+ expect { subject.write("foo", "bar", nil) }.to_not raise_error
24
+ end
25
+ end
26
+
27
+ context "fetch" do
28
+ it "should write to cashier when I call Rails.cache.fetch with tags" do
29
+ cashier.should_receive(:store_fragment).with("foo", ["some_tag"])
30
+ subject.fetch("foo", :tag => ["some_tag"]) { "bar" }
31
+ end
32
+
33
+ it "shuld not write to cashier when I call Rails.cache.fetch without tags" do
34
+ cashier.should_not_receive(:store_fragment)
35
+ subject.fetch("foo") { "bar" }
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Rails configuration" do
4
+ it "should be configuration through rails" do
5
+ Rails.application.config.cashier.adapter = :redis_store
6
+
7
+ Cashier.adapter.should == Cashier::Adapters::RedisStore
8
+ end
9
+ end
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe Cashier::Adapters::CacheStore do
4
4
  subject { Cashier::Adapters::CacheStore }
5
5
  let(:cache) { Rails.cache }
6
-
6
+
7
7
  it "should store the fragment in a tag" do
8
8
  subject.store_fragment_in_tag('fragment-key', 'dashboard')
9
9
  cache.fetch('dashboard').should eql(['fragment-key'])
@@ -62,7 +62,6 @@ describe Cashier::Adapters::CacheStore do
62
62
 
63
63
  context "keys" do
64
64
  it "should return the list of keys" do
65
-
66
65
  subject.store_tags(['dashboard', 'settings', 'email'])
67
66
 
68
67
  subject.store_fragment_in_tag('key1', 'dashboard')
@@ -72,4 +71,4 @@ describe Cashier::Adapters::CacheStore do
72
71
  subject.keys.should eql(%w(key1 key2 key3))
73
72
  end
74
73
  end
75
- end
74
+ end
@@ -1,112 +1,134 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "Cashier" do
4
- context "Tags store adapters" do
5
- subject { Cashier }
4
+ before(:each) do
5
+ Cashier.adapter = :cache_store
6
+ end
6
7
 
7
- it "should allow me to set the keys adapter" do
8
- subject.respond_to?(:adapter=).should be_true
9
- end
8
+ subject { Cashier }
9
+
10
+ let(:adapter) { Cashier.adapter }
11
+
12
+ describe "#store_fragment" do
13
+ it "should write the tag to the cache" do
14
+ adapter.should_receive(:store_fragment_in_tag).with('fragment-key', 'dashboard')
15
+ adapter.should_receive(:store_tags).with(["dashboard"])
10
16
 
11
- it "shold allow to get the adapter" do
12
- subject.respond_to?(:adapter).should be_true
17
+ subject.store_fragment('fragment-key', 'dashboard')
13
18
  end
14
- end
15
19
 
16
- context "Cashier adapters communication through the interface" do
17
- before(:each) do
18
- Cashier.adapter = :cache_store
20
+ it "should flatten tags" do
21
+ adapter.should_receive(:store_fragment_in_tag).with('fragment-key', 'dashboard')
22
+ adapter.should_receive(:store_tags).with(["dashboard"])
23
+
24
+ subject.store_fragment('fragment-key', ['dashboard'])
19
25
  end
20
- subject { Cashier }
21
- let(:adapter) { Cashier.adapter }
22
26
 
23
- describe "#store_fragment" do
24
- it "should write the tag to the cache" do
25
- adapter.should_receive(:store_fragment_in_tag).with('fragment-key', 'dashboard')
26
- adapter.should_receive(:store_tags).with(["dashboard"])
27
+ it "should store the tag for book keeping" do
28
+ adapter.should_receive(:store_fragment_in_tag).with('fragment-key', 'dashboard')
29
+ adapter.should_receive(:store_fragment_in_tag).with('fragment-key', 'settings')
27
30
 
28
- subject.store_fragment('fragment-key', 'dashboard')
29
- end
31
+ adapter.should_receive(:store_tags).with(["dashboard", "settings"])
30
32
 
31
- it "should store the tag for book keeping" do
32
- adapter.should_receive(:store_fragment_in_tag).with('fragment-key', 'dashboard')
33
- adapter.should_receive(:store_fragment_in_tag).with('fragment-key', 'settings')
33
+ subject.store_fragment('fragment-key', 'dashboard', 'settings')
34
+ end
35
+ end
34
36
 
35
- adapter.should_receive(:store_tags).with(["dashboard", "settings"])
37
+ describe "Cashier notifications" do
38
+ let(:notification_system) { ActiveSupport::Notifications }
39
+
40
+ it "should raise a callback when I call store_fragment" do
41
+ notification_system.should_receive(:instrument).with("store_fragment.cashier", :data => ["foo", ["bar"]])
42
+ subject.store_fragment("foo", "bar")
43
+ end
36
44
 
37
- subject.store_fragment('fragment-key', 'dashboard', 'settings')
38
- end
45
+ it "should raise a callback method when I call clear" do
46
+ notification_system.should_receive(:instrument).with("clear.cashier")
47
+ subject.clear
39
48
  end
40
49
 
41
- describe "#expire" do
42
- before do
43
- subject.store_fragment('fragment-key', 'dashboard')
44
- end
50
+ it "should raise a callback method when I call expire" do
51
+ notification_system.should_receive(:instrument).with("expire.cashier", :data => ["some_tag"])
52
+ subject.expire("some_tag")
53
+ end
54
+ end
55
+
56
+ describe "#expire" do
57
+ before do
58
+ subject.store_fragment('fragment-key', 'dashboard')
59
+ end
45
60
 
46
- it "should remove delete the fragment key" do
47
- adapter.should_receive(:get_fragments_for_tag).with('dashboard').and_return(["fragment-key"])
48
- adapter.should_receive(:delete_tag).with('dashboard')
49
- adapter.should_receive(:remove_tags).with(['dashboard'])
61
+ it "should remove delete the fragment key" do
62
+ adapter.should_receive(:get_fragments_for_tag).with('dashboard').and_return(["fragment-key"])
63
+ adapter.should_receive(:delete_tag).with('dashboard')
64
+ adapter.should_receive(:remove_tags).with(['dashboard'])
50
65
 
51
- subject.expire('dashboard')
52
- end
66
+ subject.expire('dashboard')
67
+ end
53
68
 
54
- it "should remove the tag" do
55
- adapter.should_receive(:get_fragments_for_tag).with('dashboard').and_return([])
56
- adapter.should_receive(:delete_tag).with('dashboard')
57
- adapter.should_receive(:remove_tags).with(['dashboard'])
69
+ it "should remove the tag" do
70
+ adapter.should_receive(:get_fragments_for_tag).with('dashboard').and_return([])
71
+ adapter.should_receive(:delete_tag).with('dashboard')
72
+ adapter.should_receive(:remove_tags).with(['dashboard'])
58
73
 
59
- subject.expire('dashboard')
60
- end
74
+ subject.expire('dashboard')
75
+ end
61
76
 
62
- it "should remove the tag from the list of tracked tags" do
63
- adapter.should_receive(:get_fragments_for_tag).with('dashboard').and_return(['fragment-key'])
64
- adapter.should_receive(:delete_tag).with('dashboard')
77
+ it "should remove the tag from the list of tracked tags" do
78
+ adapter.should_receive(:get_fragments_for_tag).with('dashboard').and_return(['fragment-key'])
79
+ adapter.should_receive(:delete_tag).with('dashboard')
65
80
 
66
- subject.expire('dashboard')
67
- end
81
+ subject.expire('dashboard')
68
82
  end
83
+ end
69
84
 
70
- describe "#tags" do
71
- it "should return a list of active tags" do
72
- subject.store_fragment('key1', 'dashboard')
73
- subject.store_fragment('key2', 'settings')
74
- subject.store_fragment('key3', 'email')
85
+ describe "#tags" do
86
+ it "should return a list of active tags" do
87
+ subject.store_fragment('key1', 'dashboard')
88
+ subject.store_fragment('key2', 'settings')
89
+ subject.store_fragment('key3', 'email')
75
90
 
76
- subject.tags.should eql(%w(dashboard settings email))
77
- end
91
+ subject.tags.should eql(%w(dashboard settings email))
78
92
  end
93
+ end
79
94
 
80
- describe '#clear' do
81
- before(:each) do
82
- subject.store_fragment('key1', 'dashboard')
83
- subject.store_fragment('key2', 'settings')
84
- subject.store_fragment('key3', 'email')
85
- end
95
+ describe '#clear' do
96
+ before(:each) do
97
+ subject.store_fragment('key1', 'dashboard')
98
+ subject.store_fragment('key2', 'settings')
99
+ subject.store_fragment('key3', 'email')
100
+ end
86
101
 
87
- it "should expire all tags" do
88
- adapter.should_receive(:clear)
89
- subject.clear
90
- end
102
+ it "should expire all tags" do
103
+ adapter.should_receive(:clear)
104
+ subject.clear
105
+ end
91
106
 
92
- it "should clear the list of tracked tags" do
93
- subject.clear
94
- adapter.tags.should == []
95
- end
107
+ it "should clear the list of tracked tags" do
108
+ subject.clear
109
+ adapter.tags.should == []
96
110
  end
111
+ end
97
112
 
98
- describe '#keys' do
99
- it "should return an array of all the tracked keys" do
100
- adapter.should_receive(:keys).and_return(%w(key1 key2 key3))
101
- subject.keys.should eql(%w(key1 key2 key3))
102
- end
113
+ describe '#keys' do
114
+ it "should return an array of all the tracked keys" do
115
+ adapter.should_receive(:keys).and_return(%w(key1 key2 key3))
116
+ subject.keys.should eql(%w(key1 key2 key3))
103
117
  end
118
+ end
104
119
 
105
- describe '#keys_for' do
106
- it "should return an array of all the keys for the tag" do
107
- adapter.should_receive(:get_fragments_for_tag).with('dashboard').and_return(%w(key1 key2 key3))
108
- subject.keys_for('dashboard').should eql(%w(key1 key2 key3))
109
- end
120
+ describe '#keys_for' do
121
+ it "should return an array of all the keys for the tag" do
122
+ adapter.should_receive(:get_fragments_for_tag).with('dashboard').and_return(%w(key1 key2 key3))
123
+ subject.keys_for('dashboard').should eql(%w(key1 key2 key3))
110
124
  end
111
125
  end
126
+
127
+ it "should allow me to set the adapter" do
128
+ subject.respond_to?(:adapter=).should be_true
129
+ end
130
+
131
+ it "shold allow to get the adapter" do
132
+ subject.respond_to?(:adapter).should be_true
133
+ end
112
134
  end
@@ -1,5 +1,6 @@
1
1
  require 'simplecov'
2
2
  require 'redis'
3
+ require 'dalli'
3
4
 
4
5
  SimpleCov.start
5
6
 
@@ -28,8 +29,11 @@ RSpec.configure do |config|
28
29
  "port" => 6397,
29
30
  "dir" => Rails.root.join('tmp', 'cache'),
30
31
  }.map { |k, v| "#{k} #{v}" }.join('\n')
32
+
31
33
  `echo '#{redis_options}' | redis-server -`
32
34
 
35
+ sleep 0.25
36
+
33
37
  Cashier::Adapters::RedisStore.redis = Redis.new(:host => '127.0.0.1', :port => 6397)
34
38
  end
35
39
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cashier
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-16 00:00:00.000000000 Z
12
+ date: 2012-12-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
16
- requirement: &70172278921700 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,15 @@ dependencies:
21
21
  version: '3.0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70172278921700
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '3.0'
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: rspec
27
- requirement: &70172278920840 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ! '>='
@@ -32,10 +37,15 @@ dependencies:
32
37
  version: '0'
33
38
  type: :development
34
39
  prerelease: false
35
- version_requirements: *70172278920840
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: rspec-rails
38
- requirement: &70172278920180 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
51
  - - ! '>='
@@ -43,10 +53,15 @@ dependencies:
43
53
  version: '0'
44
54
  type: :development
45
55
  prerelease: false
46
- version_requirements: *70172278920180
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
47
62
  - !ruby/object:Gem::Dependency
48
63
  name: dalli
49
- requirement: &70172278919320 !ruby/object:Gem::Requirement
64
+ requirement: !ruby/object:Gem::Requirement
50
65
  none: false
51
66
  requirements:
52
67
  - - ! '>='
@@ -54,10 +69,15 @@ dependencies:
54
69
  version: '0'
55
70
  type: :development
56
71
  prerelease: false
57
- version_requirements: *70172278919320
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
58
78
  - !ruby/object:Gem::Dependency
59
79
  name: simplecov
60
- requirement: &70172278918460 !ruby/object:Gem::Requirement
80
+ requirement: !ruby/object:Gem::Requirement
61
81
  none: false
62
82
  requirements:
63
83
  - - ! '>='
@@ -65,10 +85,15 @@ dependencies:
65
85
  version: '0'
66
86
  type: :development
67
87
  prerelease: false
68
- version_requirements: *70172278918460
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
69
94
  - !ruby/object:Gem::Dependency
70
95
  name: redis
71
- requirement: &70172278917740 !ruby/object:Gem::Requirement
96
+ requirement: !ruby/object:Gem::Requirement
72
97
  none: false
73
98
  requirements:
74
99
  - - ~>
@@ -76,7 +101,12 @@ dependencies:
76
101
  version: 2.2.0
77
102
  type: :development
78
103
  prerelease: false
79
- version_requirements: *70172278917740
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: 2.2.0
80
110
  description: Associate different cached content with a tag, then expire by tag instead
81
111
  of key
82
112
  email:
@@ -94,12 +124,10 @@ files:
94
124
  - lib/cashier.rb
95
125
  - lib/cashier/adapters/cache_store.rb
96
126
  - lib/cashier/adapters/redis_store.rb
97
- - lib/cashier/application_controller.rb
98
127
  - lib/cashier/cucumber.rb
99
128
  - lib/cashier/matchers.rb
100
129
  - lib/cashier/railtie.rb
101
130
  - lib/cashier/version.rb
102
- - spec/controllers/application_controller_spec.rb
103
131
  - spec/dummy/.gitignore
104
132
  - spec/dummy/Gemfile
105
133
  - spec/dummy/Gemfile.lock
@@ -144,8 +172,10 @@ files:
144
172
  - spec/dummy/test/performance/browsing_test.rb
145
173
  - spec/dummy/test/test_helper.rb
146
174
  - spec/dummy/vendor/plugins/.gitkeep
147
- - spec/lib/adapters/cache_store_spec.rb
148
- - spec/lib/adapters/redis_store_spec.rb
175
+ - spec/integration/rails_cache_integration_spec.rb
176
+ - spec/integration/rails_configuration_spec.rb
177
+ - spec/lib/cashier/adapters/cache_store_spec.rb
178
+ - spec/lib/cashier/adapters/redis_store_spec.rb
149
179
  - spec/lib/cashier_spec.rb
150
180
  - spec/spec_helper.rb
151
181
  homepage: https://github.com/threadedlabs/cashier
@@ -162,7 +192,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
162
192
  version: '0'
163
193
  segments:
164
194
  - 0
165
- hash: 1935489588722938674
195
+ hash: 2649723664706912496
166
196
  required_rubygems_version: !ruby/object:Gem::Requirement
167
197
  none: false
168
198
  requirements:
@@ -171,15 +201,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
171
201
  version: '0'
172
202
  segments:
173
203
  - 0
174
- hash: 1935489588722938674
204
+ hash: 2649723664706912496
175
205
  requirements: []
176
206
  rubyforge_project:
177
- rubygems_version: 1.8.11
207
+ rubygems_version: 1.8.24
178
208
  signing_key:
179
209
  specification_version: 3
180
210
  summary: Tag based caching for Rails using Redis or Memcached
181
211
  test_files:
182
- - spec/controllers/application_controller_spec.rb
183
212
  - spec/dummy/.gitignore
184
213
  - spec/dummy/Gemfile
185
214
  - spec/dummy/Gemfile.lock
@@ -224,7 +253,9 @@ test_files:
224
253
  - spec/dummy/test/performance/browsing_test.rb
225
254
  - spec/dummy/test/test_helper.rb
226
255
  - spec/dummy/vendor/plugins/.gitkeep
227
- - spec/lib/adapters/cache_store_spec.rb
228
- - spec/lib/adapters/redis_store_spec.rb
256
+ - spec/integration/rails_cache_integration_spec.rb
257
+ - spec/integration/rails_configuration_spec.rb
258
+ - spec/lib/cashier/adapters/cache_store_spec.rb
259
+ - spec/lib/cashier/adapters/redis_store_spec.rb
229
260
  - spec/lib/cashier_spec.rb
230
261
  - spec/spec_helper.rb
@@ -1,28 +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
- class ApplicationController < ActionController::Base
15
- def write_fragment_with_tagged_key(key, content, options = nil)
16
- if options && options[:tag] && Cashier.perform_caching?
17
- tags = case options[:tag].class.to_s
18
- when 'Proc', 'Lambda'
19
- options[:tag].call(self)
20
- else
21
- options[:tag]
22
- end
23
- Cashier.store_fragment fragment_cache_key(key), *tags
24
- end
25
- write_fragment_without_tagged_key(key, content, options)
26
- end
27
- alias_method_chain :write_fragment, :tagged_key
28
- end
@@ -1,23 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ApplicationController do
4
- it "should be able to tag framgents" do
5
- Cashier.should_receive(:store_fragment).with('views/key', 'tag')
6
- controller.write_fragment('key', 'content', :tag => 'tag')
7
- end
8
-
9
- it "should be able write a fragment with multiple tags" do
10
- Cashier.should_receive(:store_fragment).with('views/key', 'tag1', 'tag2')
11
- controller.write_fragment('key', 'content', :tag => %w(tag1 tag2))
12
- end
13
-
14
- it "should able to create a tag with a proc" do
15
- Cashier.should_receive(:store_fragment).with('views/key', 'tag')
16
- controller.write_fragment('key', 'content', :tag => proc {|c| 'tag' })
17
- end
18
-
19
- it "should able to create a tag with a lambda" do
20
- Cashier.should_receive(:store_fragment).with('views/key', 'tag')
21
- controller.write_fragment('key', 'content', :tag => lambda {|c| 'tag' })
22
- end
23
- end