cache-machine 0.1.10 → 0.2.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.
Files changed (38) hide show
  1. data/.gitignore +3 -1
  2. data/.travis.yml +6 -0
  3. data/Gemfile +0 -2
  4. data/Gemfile.lock +0 -2
  5. data/README.md +258 -0
  6. data/VERSION +1 -1
  7. data/cache-machine.gemspec +7 -22
  8. data/db/.gitignore +1 -0
  9. data/lib/cache-machine.rb +6 -2
  10. data/lib/cache_machine/adapter.rb +127 -0
  11. data/lib/cache_machine/adapters/rails.rb +58 -0
  12. data/lib/cache_machine/cache.rb +34 -85
  13. data/lib/cache_machine/cache/associations.rb +29 -0
  14. data/lib/cache_machine/cache/class_timestamp.rb +31 -0
  15. data/lib/cache_machine/cache/collection.rb +131 -0
  16. data/lib/cache_machine/cache/map.rb +97 -241
  17. data/lib/cache_machine/cache/mapper.rb +135 -0
  18. data/lib/cache_machine/cache/resource.rb +108 -0
  19. data/lib/cache_machine/cache/scope.rb +24 -0
  20. data/lib/cache_machine/cache/timestamp_builder.rb +58 -0
  21. data/lib/cache_machine/helpers/cache_helper.rb +3 -3
  22. data/lib/cache_machine/logger.rb +9 -8
  23. data/lib/cache_machine/railtie.rb +11 -0
  24. data/lib/cache_machine/tasks.rb +10 -0
  25. data/spec/fixtures.rb +11 -6
  26. data/spec/lib/cache_machine/adapters/rails_spec.rb +149 -0
  27. data/spec/lib/cache_machine/cache/associations_spec.rb +32 -0
  28. data/spec/lib/cache_machine/cache/class_timestam_spec.rb +29 -0
  29. data/spec/lib/cache_machine/cache/collection_spec.rb +106 -0
  30. data/spec/lib/cache_machine/cache/map_spec.rb +34 -0
  31. data/spec/lib/cache_machine/cache/mapper_spec.rb +61 -0
  32. data/spec/lib/cache_machine/cache/resource_spec.rb +86 -0
  33. data/spec/lib/cache_machine/cache/scope_spec.rb +50 -0
  34. data/spec/lib/cache_machine/cache/timestamp_builder_spec.rb +52 -0
  35. data/spec/spec_helper.rb +9 -3
  36. metadata +35 -61
  37. data/README.rdoc +0 -186
  38. data/spec/lib/cache_machine_spec.rb +0 -161
@@ -0,0 +1,50 @@
1
+ require "spec_helper"
2
+
3
+ describe CacheMachine::Cache::Scope do
4
+ let(:cacher_under_scope_one) { Cacher.create :name => 'one' }
5
+ let(:cacher_under_scope_two) { Cacher.create :name => 'two' }
6
+ let(:cacher_outside_scope ) { Cacher.create :name => 'tree' }
7
+
8
+ let(:join_under_scope_one) { Join.create :cacher => cacher_under_scope_one }
9
+ let(:join_under_scope_two) { Join.create :cacher => cacher_under_scope_two }
10
+ let(:join_outside_scope) { Join.create :cacher => cacher_outside_scope }
11
+
12
+ before :each do
13
+ CacheMachine::Cache::Mapper.new do
14
+ resource Cacher, :scopes => :test_scope do
15
+ collection :joins, :scopes => :test_scope
16
+ end
17
+ end
18
+ end
19
+
20
+ it "works" do
21
+ Cacher.should respond_to(:cache_scopes)
22
+ Cacher.should respond_to(:under_cache_scopes)
23
+ end
24
+
25
+ describe "::under_cache_scopes" do
26
+ context "for resources" do
27
+ before :each do
28
+ cacher_under_scope_one
29
+ cacher_under_scope_two
30
+ cacher_outside_scope
31
+ end
32
+
33
+ it "works" do
34
+ Cacher.under_cache_scopes.all.should =~ [cacher_under_scope_one, cacher_under_scope_two]
35
+ end
36
+ end
37
+
38
+ context "for collections" do
39
+ before :each do
40
+ join_under_scope_one
41
+ join_under_scope_two
42
+ join_outside_scope
43
+ end
44
+
45
+ it "works" do
46
+ Join.under_cache_scopes.all.should =~ [join_under_scope_one, join_under_scope_two]
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ describe CacheMachine::Cache::TimestampBuilder do
4
+ describe "::define_timestamp" do
5
+ before :each do
6
+ Cacher.stamp = 0
7
+ Cacher.define_timestamp(:test_timestamp) { stamp }
8
+ end
9
+
10
+ it "works" do
11
+ Cacher.should respond_to :resource_test_timestamp
12
+ Cacher.should respond_to :test_timestamp
13
+ Object.should_not respond_to :test_timestamp
14
+ end
15
+
16
+ it "returns current time value if cache is clear" do
17
+ Time.stub("now").and_return 1
18
+ Cacher.test_timestamp.should == "1"
19
+ end
20
+
21
+ context "key" do
22
+ it "works" do
23
+ CacheMachine::Cache::timestamps_adapter.should_receive(:fetch_timestamp).with(Cacher.timestamp_key_of("test_timestamp"))
24
+ CacheMachine::Cache::timestamps_adapter.should_receive(:fetch_timestamp).with(Cacher.timestamp_key_of("test_timestamp_0_stamp"), {})
25
+ Cacher.test_timestamp
26
+ end
27
+
28
+ it "changes value" do
29
+ Cacher.stamp = 1
30
+
31
+ CacheMachine::Cache::timestamps_adapter.should_receive(:fetch_timestamp).with(Cacher.timestamp_key_of("test_timestamp"))
32
+ CacheMachine::Cache::timestamps_adapter.should_receive(:fetch_timestamp).with(Cacher.timestamp_key_of("test_timestamp_1_stamp"), {})
33
+ Cacher.test_timestamp
34
+ end
35
+ end
36
+
37
+ it "returns value from cache" do
38
+ Cacher.test_timestamp
39
+ CacheMachine::Cache::timestamps_adapter.should_not_receive(:reset_timestamp)
40
+ Cacher.test_timestamp
41
+ end
42
+
43
+ it "expires old timestamp" do
44
+ Cacher.test_timestamp
45
+ CacheMachine::Cache::timestamps_adapter.should_receive(:reset_timestamp).with("Cacher~test_timestamp~ts")
46
+ CacheMachine::Cache::timestamps_adapter.should_receive(:reset_timestamp).with("Cacher~test_timestamp_0_stamp~ts")
47
+
48
+ Cacher.stamp = 1
49
+ Cacher.test_timestamp
50
+ end
51
+ end
52
+ end
@@ -8,8 +8,14 @@ require "cache-machine"
8
8
  RSpec.configure { |config| config.mock_with :rspec }
9
9
 
10
10
  ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => "db/sqlite3.test.db")
11
- CacheMachine::Logger.level = :info
12
- CacheMachine::Cache.formats = [:ehtml, :json]
13
- ActiveRecord::Base.logger = Logger.new(STDOUT)
11
+
12
+ CacheMachine::Logger.level = :info
14
13
 
15
14
  Object.const_set "RAILS_CACHE", ActiveSupport::Cache.lookup_store(:memory_store) # You can set memcached
15
+
16
+ ::Rails.cache.clear
17
+
18
+ ActiveRecord::Base.logger = Logger.new(nil)
19
+ CacheMachine::Logger.logger = Logger.new(nil)
20
+
21
+ require 'fixtures'
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cache-machine
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
9
- - 10
10
- version: 0.1.10
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Sergei Zinin
@@ -16,8 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2011-10-22 00:00:00 +08:00
20
- default_executable:
19
+ date: 2012-03-05 00:00:00 Z
21
20
  dependencies:
22
21
  - !ruby/object:Gem::Dependency
23
22
  name: rails
@@ -27,44 +26,16 @@ dependencies:
27
26
  requirements:
28
27
  - - ">="
29
28
  - !ruby/object:Gem::Version
30
- hash: 3
29
+ hash: 5
31
30
  segments:
32
- - 0
33
- version: "0"
31
+ - 3
32
+ version: "3"
34
33
  type: :runtime
35
34
  version_requirements: *id001
36
- - !ruby/object:Gem::Dependency
37
- name: activemodel
38
- prerelease: false
39
- requirement: &id002 !ruby/object:Gem::Requirement
40
- none: false
41
- requirements:
42
- - - ">="
43
- - !ruby/object:Gem::Version
44
- hash: 3
45
- segments:
46
- - 0
47
- version: "0"
48
- type: :runtime
49
- version_requirements: *id002
50
- - !ruby/object:Gem::Dependency
51
- name: activesupport
52
- prerelease: false
53
- requirement: &id003 !ruby/object:Gem::Requirement
54
- none: false
55
- requirements:
56
- - - ">="
57
- - !ruby/object:Gem::Version
58
- hash: 3
59
- segments:
60
- - 0
61
- version: "0"
62
- type: :runtime
63
- version_requirements: *id003
64
35
  - !ruby/object:Gem::Dependency
65
36
  name: bundler
66
37
  prerelease: false
67
- requirement: &id004 !ruby/object:Gem::Requirement
38
+ requirement: &id002 !ruby/object:Gem::Requirement
68
39
  none: false
69
40
  requirements:
70
41
  - - ~>
@@ -76,52 +47,55 @@ dependencies:
76
47
  - 0
77
48
  version: 1.0.0
78
49
  type: :development
79
- version_requirements: *id004
80
- - !ruby/object:Gem::Dependency
81
- name: jeweler
82
- prerelease: false
83
- requirement: &id005 !ruby/object:Gem::Requirement
84
- none: false
85
- requirements:
86
- - - ~>
87
- - !ruby/object:Gem::Version
88
- hash: 11
89
- segments:
90
- - 1
91
- - 6
92
- - 2
93
- version: 1.6.2
94
- type: :development
95
- version_requirements: *id005
50
+ version_requirements: *id002
96
51
  description: A Ruby on Rails framework to support cache management based on explicitely modeled caching dependencies.
97
- email: kgoslar@partyearth.com
52
+ email: szinin@partyearth.com
98
53
  executables: []
99
54
 
100
55
  extensions: []
101
56
 
102
57
  extra_rdoc_files:
103
58
  - LICENSE.txt
104
- - README.rdoc
59
+ - README.md
105
60
  files:
106
61
  - .gitignore
62
+ - .travis.yml
107
63
  - Gemfile
108
64
  - Gemfile.lock
109
65
  - LICENSE.txt
110
- - README.rdoc
66
+ - README.md
111
67
  - Rakefile
112
68
  - VERSION
113
69
  - cache-machine.gemspec
70
+ - db/.gitignore
114
71
  - lib/cache-machine.rb
72
+ - lib/cache_machine/adapter.rb
73
+ - lib/cache_machine/adapters/rails.rb
115
74
  - lib/cache_machine/cache.rb
75
+ - lib/cache_machine/cache/associations.rb
76
+ - lib/cache_machine/cache/class_timestamp.rb
77
+ - lib/cache_machine/cache/collection.rb
116
78
  - lib/cache_machine/cache/map.rb
79
+ - lib/cache_machine/cache/mapper.rb
80
+ - lib/cache_machine/cache/resource.rb
81
+ - lib/cache_machine/cache/scope.rb
82
+ - lib/cache_machine/cache/timestamp_builder.rb
117
83
  - lib/cache_machine/helpers.rb
118
84
  - lib/cache_machine/helpers/cache_helper.rb
119
85
  - lib/cache_machine/logger.rb
120
86
  - lib/cache_machine/railtie.rb
87
+ - lib/cache_machine/tasks.rb
121
88
  - spec/fixtures.rb
122
- - spec/lib/cache_machine_spec.rb
89
+ - spec/lib/cache_machine/adapters/rails_spec.rb
90
+ - spec/lib/cache_machine/cache/associations_spec.rb
91
+ - spec/lib/cache_machine/cache/class_timestam_spec.rb
92
+ - spec/lib/cache_machine/cache/collection_spec.rb
93
+ - spec/lib/cache_machine/cache/map_spec.rb
94
+ - spec/lib/cache_machine/cache/mapper_spec.rb
95
+ - spec/lib/cache_machine/cache/resource_spec.rb
96
+ - spec/lib/cache_machine/cache/scope_spec.rb
97
+ - spec/lib/cache_machine/cache/timestamp_builder_spec.rb
123
98
  - spec/spec_helper.rb
124
- has_rdoc: true
125
99
  homepage: http://github.com/partyearth/cache-machine
126
100
  licenses:
127
101
  - MIT
@@ -151,7 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
151
125
  requirements: []
152
126
 
153
127
  rubyforge_project:
154
- rubygems_version: 1.5.0
128
+ rubygems_version: 1.8.10
155
129
  signing_key:
156
130
  specification_version: 3
157
131
  summary: A Ruby on Rails framework to support cache management based on explicitely modeled caching dependencies.
@@ -1,186 +0,0 @@
1
- = cache-machine
2
- http://img195.imageshack.us/img195/5371/cachemachinefinal2.png
3
-
4
- An ActiveRecord mixin that helps managing cached content in a Ruby on Rails application with complex data update dependencies.
5
-
6
- Cache Machine provides
7
- * high-level methods for accessing cached content using page names, numbers, time stamps etc,
8
- * a DSL to describe update dependencies between the data models underlying the cached content,
9
- * automatic cache invalidation based on those explicitly modeled data update dependencies.
10
-
11
- You will find Cache Machine useful if you:
12
- * use Memcache to cache fragments of a web site that contain data from a variety of underlying data models
13
- * anytime one of the underlying data models changes, all the cached page fragments in which this data model occurs - and only those - need to be invalidated/updated
14
- * you have many data models, cached fragments, and many data models used inside each cached fragment
15
-
16
- Cache Machine depends only on the Rails.cache API and is thereby library agnostic.
17
-
18
- = Usage
19
-
20
- # Fetch cache of venues collection on model_instance.
21
- @neighborhood.fetch_cache_of(:venues) { venues }
22
-
23
- # Specify format.
24
- @neighborhood.fetch_cache_of(:venues, :format => :json) { venues.to_json }
25
-
26
- # Paginated content.
27
- @neighborhood.fetch_cache_of(:venues, :page => 2) { venues.paginate(:page => 2) }
28
-
29
- In you target model define <b>cache map</b>:
30
-
31
- cache_map :venues => [:hotspots, :today_events],
32
- :cities => [:venues],
33
- :streets => :hotspots,
34
- :users
35
-
36
- This example shows you how changes of one collection affect on invalidation process.
37
- For each record of your target model:
38
- - Cache for <b>users</b> collection associated with object of your target model is invalidated when changing (_add_, _remove_, _update_) the _users_ collection
39
- - Cache for <b>venues</b> collection associated with object of your target model is invalidated when changing the _venues_ collection associated with that object
40
- - Cache for <b>venues</b> collection associated with object of your target model is invalidated when changing the _cities_ collection. In this case machine automatically invalidates _hotspots_ and _today_events_
41
- - Cache for <b>cities</b> collection associated with object of your target model is invalidated when changing the _cities_ collection
42
- - Cache for <b>hotspots</b> collection is invalidated when changing the _venues_ collection
43
- - Cache for <b>hotspots</b> collection is invalidated when changing the _streets_ collection
44
- - Cache for <b>hotspots</b> collection is invalidated when changing the _cities_ collection
45
- - Cache for <b>today_events</b> collection is invalidated when changing the _venues_ collection
46
- - Cache for <b>today_events</b> collection is invalidated when changing the _cities_ collection
47
- <b>Cache map may contain any name, whatever you want. But invalidation process starts only when ActiveRecord collection is changed.</b>
48
-
49
- == Custom cache invalidation
50
-
51
- === Using timestamps
52
- Suppose you need to reset cache of _schedule_of_events_ every day.
53
-
54
- @lady_gaga.fetch_cache_of :schedule_of_events, :timestamp => lambda { Date.today } do
55
- @lady_gaga.events.where(:date.gt => Date.today)
56
- end
57
-
58
- === Using Cache Machine timestamps
59
- Suppose you need to reset cache of _tweets_ every 10 minutes.
60
-
61
- class LadyGagaPerformer < ActiveRecord::Base
62
- define_timestamp :tweets_timestamp, :expires_in => 10.minutes
63
- end
64
-
65
- #...
66
-
67
- # Somewhere
68
- @lady_gaga.fetch_cache_of :tweets, :timestamp => :tweets_timestamp do
69
- TwitterApi.fetch_tweets_for @lady_gaga
70
- end
71
-
72
- Suppose you need custom timestamp value.
73
-
74
- class LadyGagaPerformer < ActiveRecord::Base
75
- define_timestamp(:tweets_timestamp) { Time.now.to_i + self.id }
76
- end
77
-
78
- #...
79
-
80
- # Somewhere
81
- @lady_gaga.fetch_cache_of :tweets, :timestamp => :tweets_timestamp do
82
- TwitterApi.fetch_tweets_for @lady_gaga
83
- end
84
-
85
- Note what timestamp declarations work in object scope. Lets take an example:
86
-
87
- class LadyGagaPerformer < ActiveRecord::Base
88
- define_timestamp (:tweets_timestamp) { tweets.last.updated_at.to_i }
89
-
90
- has_many :tweets
91
- end
92
-
93
- class Tweet < ActiveRecord::Base
94
- belongs_to :lady_gaga_performer
95
- end
96
-
97
- === Using methods as timestamps
98
- Suppose you have your own really custom cache key.
99
-
100
- class LadyGagaPerformer < ActiveRecord::Base
101
- def my_custom_cache_key
102
- rand(100) + rand(1000) + rand(10000)
103
- end
104
- end
105
-
106
- #...
107
-
108
- # Somewere
109
- @lady_gaga.fetch_cache_of(:something, :timestamp => :my_custom_cache_key) { '...' }
110
-
111
- === Using class timestamps
112
- Suppose you need to fetch cached content of one of your collections.
113
- Rails.cache.fetch(MyModel.timestamped_key) { '...' }
114
-
115
- Want to see collection timestamp?
116
- MyModel.timestamp
117
-
118
- === Manual cache invalidation
119
- # For classes.
120
- MyModel.reset_timestamp
121
-
122
- # For collections.
123
- @lady_gaga.delete_cache_of :events
124
-
125
- # For timestamps.
126
- @lady_gaga.reset_timestamp_of :events
127
-
128
- # You can reset all associated caches using map.
129
- @lady_gaga.delete_all_caches
130
-
131
- == Cache formats
132
- Cache Machine invalidates cache using a couple of keys with the different formats.
133
- Default formats are:
134
- - EHTML
135
- - HTML
136
- - JSON
137
- - XML
138
-
139
- This means you call 5 times for cache invalidation (1 time without specifying format) with different keys. Sometimes it is too much. Cache machine allows you to set your own formats. Just place in your environment config or in initializer the following:
140
- CacheMachine::Cache.formats = [:doc, :pdf]
141
-
142
- Or if you do not want to use formats at all:
143
- CacheMachine::Cache.formats = nil
144
-
145
- Then use:
146
-
147
- @lady_gaga.fetch_cache_of(:new_songs, :format => :doc) { "LaLaLa".to_doc }
148
- @lady_gaga.fetch_cache_of(:new_songs, :format => :pdf) { "GaGaGa".to_pdf }
149
-
150
- Cache Machine will invalidate cache for each format you specified in config.
151
-
152
- == Working with paginated content
153
- Suppose you installed WillPaginate gem and want to cache each page with fetched results separately.
154
- class TweetsController < ApplicationController
155
-
156
- def index
157
- @tweets = @lady_gaga.fetch_cache_of(:tweets, :page => params[:page]) do
158
- Tweet.all.paginate(:page => params[:page])
159
- end
160
- end
161
- end
162
-
163
- Cache Machine will use <tt>:page</tt> as a part of cache key and will invalidate each page on any change in associated collection.
164
-
165
- == ActionView helper
166
- From examples above:
167
- <%= cache_for @lady_gaga, :updoming_events do %>
168
- <p>Don't hide yourself in regret
169
- Just love yourself and you're set</p>
170
- <% end %>
171
- <tt>cache_for</tt> method automatically sets EHTML format on cache key.
172
-
173
-
174
- == Contributing to cache-machine
175
-
176
- * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
177
- * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
178
- * Fork the project
179
- * Start a feature/bugfix branch
180
- * Commit and push until you are happy with your contribution
181
- * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
182
- * 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.
183
-
184
- == Copyright
185
-
186
- Copyright (c) 2011 PartyEarth LLC. See LICENSE.txt for details.