cashier 0.4.0 → 0.4.1

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/.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