flagpole_sitta 0.7.3 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -147,6 +147,14 @@ This also means if your just showing objects in an index you don't even have to
147
147
 
148
148
  :index_only => true, tells the helper to not bother trying to associated this cache with anyone item in particular.
149
149
 
150
+ You could also pass it :scope which will add a 'scope' to a :models_in_index cache, which will cause the cache to only be destroyed if an object with in its 'scope' is create, updated or destroyed. Like :model and :route_id for each model there must be a corresponding route_id. If you don't want a scope on every model then just do something like the following
151
+
152
+ - cache_sitta :models_in_index => [Blog, Setting], :scope => [@scope, nil] :index_only => true, :section => "body" do
153
+
154
+ The 'scope' can only be arguments for a where call. Which means it will either be a hash, record object, string, or an array.
155
+
156
+ Scopes should be used sparling because in order to verify them on save they require a call to the database, and while it boils down to a call by id, they can still add up if you don't pay attention.
157
+
150
158
  == existence_hash
151
159
 
152
160
  If you might have already figured out the overall strategy of this gem has a weakness. Namely how do you deal with instances where, the object being routed to doesn't exist. See if your not querying the database until your already in the view then you can't exactly redirect with out some crazy stuff going on. You could put some if statements in your view to show a 404 if the objects are nil, but the issue with that is that you would still end up with a bunch of pointless caches. This can all be avoided by creating a 'hash' in the cache which you can use to check for the existence of an object. This 'hash' too is updated on save/destory. Also the hash really isn't hash but rather a bunch of cache keys held together by a flag key. Lets use the page example from above.
@@ -166,27 +174,21 @@ A quick note you only actually have to pass :route_id once if your using both ca
166
174
 
167
175
  class PagesController < ApplicationController
168
176
 
169
- if Page.get_existence_hash(params[:url])
170
-
171
- def show
177
+ def show
172
178
 
173
- @page_call = lambda {
179
+ if Page.get_existence_hash(params[:url])
180
+ calls_sitta :name => "page", :section => "body" do
174
181
  if params[:url]
175
182
  @page = Page.find_by_url params[:url]
176
183
  else
177
184
  @page = Page.find_by_url 'home'
178
185
  end
179
- }
180
-
181
- @body_calls = [
182
- ['page', @page_call]
183
- ]
184
-
186
+ end
187
+ else
188
+ redirect_to :action => 'home'
189
+ flash[:notice] = "The Page you are looking for doesn't exist"
185
190
  end
186
191
 
187
- else
188
- redirect_to :action => 'home'
189
- flash[:notice] = "The Page you are looking for doesn't exist"
190
192
  end
191
193
 
192
194
  end
@@ -1,11 +1,11 @@
1
1
  module FlagpoleSittaHelper
2
2
 
3
- def update_index_array_cache model, key
4
- model.try(:update_array_cache, key)
3
+ def update_index_array_cache model, key, scope=nil
4
+ model.try(:update_array_cache, key, :scope => scope)
5
5
  end
6
6
 
7
7
  def update_show_array_cache model, key, route_id
8
- model.try(:update_array_cache, key, route_id)
8
+ model.try(:update_array_cache, key, :route_id => route_id)
9
9
  end
10
10
 
11
11
  ##
@@ -55,9 +55,13 @@ module FlagpoleSittaHelper
55
55
  #That way your caching each possible version of the page
56
56
  #instead of just one.
57
57
  #
58
- #:calls_args
59
- #Any args you want to pass to your calls. Can only take one argument.
60
- #The best idea is to pass an option hash.
58
+ #:scope which will add a 'scope' to a :models_in_index cache,
59
+ #which will cause the cache to only be destroyed if an object with in its 'scope' is create,
60
+ #updated or destroyed. Like :model and :route_id for each model there must be a corresponding route_id.
61
+ #If you don't want a scope on every model then just make the index model's scope nil.
62
+ #The 'scope' can only be arguments for a where call. Which means it will either be a hash or an array.
63
+ #Scopes should be used sparling because in order to verify them on save they require a call to the database,
64
+ #and while it boils down to a call by id, they can still add up if you don't pay attention.
61
65
  def cache_sitta options={}, &block
62
66
 
63
67
  if options[:route_id].class.eql?(Array)
@@ -120,11 +124,7 @@ module FlagpoleSittaHelper
120
124
  if calls
121
125
  calls.each do |c|
122
126
  if instance_variable_get("@#{c[0]}").nil?
123
- if options[:calls_args] && (c.parameters.length > 0)
124
- instance_variable_set("@#{c[0]}", c[1].call(options[:calls_args]))
125
- else
126
- instance_variable_set("@#{c[0]}", c[1].call())
127
- end
127
+ instance_variable_set("@#{c[0]}", c[1].call())
128
128
  end
129
129
  end
130
130
  end
@@ -142,13 +142,17 @@ module FlagpoleSittaHelper
142
142
  #any of the model types involved are updated.
143
143
 
144
144
  if options[:models_in_index].class.eql?(Array)
145
- options[:models_in_index].each do |m|
146
- processed_m = m.respond_to?(:constantize) ? m.constantize : m
147
- update_index_array_cache(processed_m, key)
145
+ options[:models_in_index].each_index do |i|
146
+ m = options[:models_in_index][i]
147
+ if options[:scope]
148
+ scope = options[:scope][i]
149
+ end
150
+ processed_model = m.respond_to?(:constantize) ? m.constantize : m
151
+ update_index_array_cache(processed_model, key, scope)
148
152
  end
149
153
  elsif options[:models_in_index]
150
154
  processed_model = options[:models_in_index].respond_to?(:constantize) ? options[:models_in_index].constantize : options[:models_in_index]
151
- update_index_array_cache(options[:models_in_index], key)
155
+ update_index_array_cache(processed_model, key, options[:scope])
152
156
  end
153
157
 
154
158
  #AR - Create a link between each declared object and the cache.
@@ -10,6 +10,7 @@ module FlagpoleSitta
10
10
 
11
11
  included do
12
12
  before_save :cache_sitta_save
13
+ after_save :cache_sitta_after_save
13
14
  before_destroy :cache_sitta_destory
14
15
  end
15
16
 
@@ -40,9 +41,9 @@ module FlagpoleSitta
40
41
  end
41
42
 
42
43
  #Updates the 'array' in the cache.
43
- def update_array_cache key, route_id = nil
44
+ def update_array_cache key, options={}
44
45
 
45
- mid_key = mid_key_gen route_id
46
+ mid_key = mid_key_gen options[:route_id]
46
47
 
47
48
  clazz = self
48
49
 
@@ -50,14 +51,14 @@ module FlagpoleSitta
50
51
 
51
52
  #AR - If it doesn't exist start the process of creating it
52
53
  if flag.nil?
53
- flag = initialize_array_cache route_id
54
+ flag = initialize_array_cache options[:route_id]
54
55
  end
55
56
 
56
57
  #AR - update the array's end point
57
58
  flag[:space] = flag[:space] + 1
58
59
 
59
60
  #AR - write out the new index at the end of the array
60
- Rails.cache.write("#{clazz}/#{mid_key}/#{flag[:space]}", {:key => key})
61
+ Rails.cache.write("#{clazz}/#{mid_key}/#{flag[:space]}", {:key => key, :scope => options[:scope]})
61
62
 
62
63
  #AR - update flag in the cache
63
64
  Rails.cache.write("#{clazz}/#{mid_key}/Flag", flag)
@@ -72,19 +73,16 @@ module FlagpoleSitta
72
73
  clazz = self
73
74
 
74
75
  flag = Rails.cache.read("#{clazz}/#{mid_key}/Flag")
75
-
76
- #AR - If it doesn't exist start the process of creating it
77
- if flag.nil?
78
- flag = initialize_array_cache route_id
79
- end
80
76
 
81
77
  #AR - If there aren't any index do nothing.
82
78
  #Else wise loop through every index.
83
79
  #If it actually does exist then yield.
84
- for i in 0..flag[:space] do
85
- hash = Rails.cache.read("#{clazz}/#{mid_key}/#{i}")
86
- if hash
87
- yield hash[:key]
80
+ if flag
81
+ for i in 0..flag[:space] do
82
+ hash = Rails.cache.read("#{clazz}/#{mid_key}/#{i}")
83
+ if hash
84
+ yield hash
85
+ end
88
86
  end
89
87
  end
90
88
 
@@ -93,19 +91,32 @@ module FlagpoleSitta
93
91
  end
94
92
 
95
93
  #Nukes all corresponding caches for a given array.
96
- def destroy_array_cache route_id = nil
94
+ def destroy_array_cache options={}
97
95
 
98
- mid_key = mid_key_gen route_id
96
+ mid_key = mid_key_gen options[:route_id]
99
97
 
100
98
  clazz = self
101
99
 
102
- each_cache route_id do |key|
103
- if key.present?
104
- Rails.cache.delete(key)
100
+ i = 0
101
+
102
+ each_cache options[:route_id] do |hash|
103
+ if hash.present?
104
+ if hash[:scope].nil? || options[:obj].in_scope(hash[:scope])
105
+ Rails.cache.delete(hash[:key])
106
+ else
107
+ Rails.cache.write("#{clazz}/#{mid_key}/#{i}", hash)
108
+ i = i + 1
109
+ end
105
110
  end
106
111
  end
107
112
 
108
- Rails.cache.delete("#{clazz}/#{mid_key}/Flag")
113
+ if i == 0
114
+ Rails.cache.delete("#{clazz}/#{mid_key}/Flag")
115
+ else
116
+ flag = Rails.cache.read("#{clazz}/#{mid_key}/Flag")
117
+ flag[:space => (i - 1)]
118
+ Rails.cache.write("#{clazz}/#{mid_key}/Flag", flag)
119
+ end
109
120
  end
110
121
 
111
122
  end
@@ -114,6 +125,10 @@ module FlagpoleSitta
114
125
  self.cache_work(true)
115
126
  end
116
127
 
128
+ def cache_sitta_after_save
129
+ self.post_cache_work
130
+ end
131
+
117
132
  def cache_sitta_destory
118
133
  self.cache_work(false)
119
134
  end
@@ -128,15 +143,15 @@ module FlagpoleSitta
128
143
  while(clazz.respond_to? :destroy_array_cache)
129
144
 
130
145
  #AR - Clear all caches related to the old route_id
131
- clazz.destroy_array_cache(self.try(:send, ("#{clazz.route_id}_was")).to_s)
146
+ clazz.destroy_array_cache(:route_id => self.try(:send, ("#{clazz.route_id}_was")).to_s)
132
147
  #AR - Clear all caches related to the new route_id just in case
133
- clazz.destroy_array_cache(self.try(:send, ("#{clazz.route_id}")).to_s)
148
+ clazz.destroy_array_cache(:route_id => self.try(:send, ("#{clazz.route_id}")).to_s)
134
149
  #AR - If the new and old are the same All that will happen on the second call is that
135
150
  #it will write the flag out and then destroy it. A very tiny bit of work
136
151
  #for a great amount of extra protection.
137
152
 
138
153
  # AR - Remember to include models_in_index in your helper call in the corresponding index cache.
139
- clazz.destroy_array_cache
154
+ clazz.destroy_array_cache(:obj => self)
140
155
 
141
156
  clazz = clazz.superclass
142
157
  end
@@ -146,11 +161,33 @@ module FlagpoleSitta
146
161
 
147
162
  end
148
163
 
164
+ #Sense the current in_scope requires the object to be in the database, this has to be called in case the new version that has been
165
+ #saved fits into any cache's scope. The above call to clear index caches is basically the object_was call, while this is just the call
166
+ #for the update object.
167
+ def post_cache_work
168
+ original_clazz = self.class
169
+ clazz = original_clazz
170
+
171
+ while(clazz.respond_to? :destroy_array_cache)
172
+ # AR - Remember to include models_in_index in your helper call in the corresponding index cache.
173
+ clazz.destroy_array_cache(:obj => self)
174
+
175
+ clazz = clazz.superclass
176
+ end
177
+
178
+ end
179
+
149
180
  #AR - For Safety this will not recurse upwards for the extra cache maintenance
150
181
  def extra_cache_maintenance alive
151
182
  method = (@_cache_extra_maintance || Proc.new{})
152
183
  method.call
153
184
  end
154
185
 
186
+ def in_scope scope
187
+
188
+ self.class.where(scope).exists?(self.id)
189
+
190
+ end
191
+
155
192
  end
156
193
  end
@@ -9,4 +9,4 @@ module FlagpoleSitta
9
9
  app.middleware.use ::ActionDispatch::Static, "#{root}/public"
10
10
  end
11
11
  end
12
- end
12
+ end
@@ -27,8 +27,8 @@ module FlagpoleSitta
27
27
  i = 0
28
28
  superclazz.find_each do |m|
29
29
  #Route ID is the key. The POS is used to emulate an array, along with the length stored in the flag.
30
- Rails.cache.write("#{superclazz}/ExistenceHash/#{m.send(m.class.route_id).to_s}", {:type => m.has_attribute?('type') ? m.type : m.class, :pos => i, :num => 0})
31
- Rails.cache.write("#{superclazz}/ExistenceHash/#{i}", {:key => m.send(m.class.route_id).to_s})
30
+ Rails.cache.write("#{superclazz}/ExistenceHash/#{m.class}/#{m.send(m.class.route_id).to_s}", {:type => m.has_attribute?('type') ? m.type : m.class, :pos => i, :num => 0})
31
+ Rails.cache.write("#{superclazz}/ExistenceHash/#{i}", {:key => m.send(m.class.route_id).to_s, :type => m.class})
32
32
  i = i + 1
33
33
  end
34
34
 
@@ -39,6 +39,8 @@ module FlagpoleSitta
39
39
  #Gets a value from the 'hash' in the cache given a key.
40
40
  def get_existence_hash key
41
41
 
42
+ clazz = self
43
+
42
44
  superclazz = get_super_with_existence_hash
43
45
  #Try to find the hash
44
46
  flag = Rails.cache.read("#{superclazz}/ExistenceHash/Flag")
@@ -47,12 +49,14 @@ module FlagpoleSitta
47
49
  initialize_existence_hash
48
50
  end
49
51
 
50
- Rails.cache.read("#{superclazz}/ExistenceHash/#{key}")
52
+ Rails.cache.read("#{superclazz}/ExistenceHash/#{clazz}/#{key}")
51
53
 
52
54
  end
53
55
 
54
56
  #Increments a value from the 'hash' in the cache given a key.
55
57
  def increment_existence_hash key
58
+
59
+ clazz = self
56
60
 
57
61
  superclazz = get_super_with_existence_hash
58
62
  #Try to find the hash
@@ -61,7 +65,7 @@ module FlagpoleSitta
61
65
  #Update the hash key if it exists
62
66
  if hash
63
67
  hash[:num] = hash[:num] + 1
64
- Rails.cache.write("#{superclazz}/ExistenceHash/#{key}", hash)
68
+ Rails.cache.write("#{superclazz}/ExistenceHash/#{clazz}/#{key}", hash)
65
69
  end
66
70
 
67
71
  #Return the value
@@ -72,6 +76,8 @@ module FlagpoleSitta
72
76
  #Goes through each entry in the hash returning a key and value
73
77
  def each_existence_hash &block
74
78
 
79
+ clazz = self
80
+
75
81
  superclazz = get_super_with_existence_hash
76
82
 
77
83
  flag = Rails.cache.read("#{superclazz}/ExistenceHash/Flag")
@@ -85,8 +91,8 @@ module FlagpoleSitta
85
91
 
86
92
  value = Rails.cache.read("#{superclazz}/ExistenceHash/#{i}")
87
93
 
88
- if value.present?
89
- hash = Rails.cache.read("#{superclazz}/ExistenceHash/#{value[:key]}")
94
+ if value.present? && value[:type].eql?(clazz)
95
+ hash = Rails.cache.read("#{superclazz}/ExistenceHash/#{value[:type]}/#{value[:key]}")
90
96
  yield value[:key], hash
91
97
  end
92
98
 
@@ -129,6 +135,7 @@ module FlagpoleSitta
129
135
 
130
136
  #Updates the 'hash' on save of any of its records.
131
137
  def update_existence_hash alive
138
+ clazz = self.class
132
139
  superclazz = self.class.get_super_with_existence_hash
133
140
 
134
141
  #Old key is where it was, and new is where it is going.
@@ -151,13 +158,13 @@ module FlagpoleSitta
151
158
  hash = {:type => self.has_attribute?('type') ? self.type : self.class, :num => 0, :pos => flag[:space]}
152
159
  else
153
160
  hash = self.class.get_existence_hash(self.send("#{self.class.route_id}_was"))
154
- Rails.cache.delete("#{superclazz}/ExistenceHash/#{old_key}")
161
+ Rails.cache.delete("#{superclazz}/ExistenceHash/#{clazz}/#{old_key}")
155
162
  end
156
163
 
157
164
  #If the record is not being destroyed add new route_id to existence hash
158
165
  if alive
159
- Rails.cache.write("#{superclazz}/ExistenceHash/#{new_key}", hash)
160
- Rails.cache.write("#{superclazz}/ExistenceHash/#{hash[:pos]}", {:key => new_key})
166
+ Rails.cache.write("#{superclazz}/ExistenceHash/#{clazz}/#{new_key}", hash)
167
+ Rails.cache.write("#{superclazz}/ExistenceHash/#{hash[:pos]}", {:key => new_key, :type => clazz})
161
168
  #The following check is needed if for some reason someone does destroy on a none saved record.
162
169
  elsif !self.new_record?
163
170
  if hash[:pos] == flag[:space]
@@ -1,3 +1,3 @@
1
1
  module FlagpoleSitta
2
- VERSION = "0.7.3"
2
+ VERSION = "0.8.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flagpole_sitta
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.3
4
+ version: 0.8.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-24 00:00:00.000000000 Z
12
+ date: 2012-07-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: dalli