flagpole_sitta 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/.gitignore +7 -0
  2. data/Gemfile +8 -0
  3. data/Gemfile.lock +38 -0
  4. data/README.rdoc +121 -0
  5. data/Rakefile +29 -0
  6. data/app/helpers/flagpole_sitta_helper.rb +169 -0
  7. data/flagpole_sitta.gemspec +23 -0
  8. data/lib/flagpole_sitta/bracket_retrieval.rb +83 -0
  9. data/lib/flagpole_sitta/cache_sitta.rb +198 -0
  10. data/lib/flagpole_sitta/config_sitta.rb +35 -0
  11. data/lib/flagpole_sitta/engine.rb +12 -0
  12. data/lib/flagpole_sitta/existance_hash.rb +164 -0
  13. data/lib/flagpole_sitta/version.rb +3 -0
  14. data/lib/flagpole_sitta.rb +20 -0
  15. data/test/dummy/Rakefile +7 -0
  16. data/test/dummy/app/controllers/application_controller.rb +3 -0
  17. data/test/dummy/app/helpers/application_helper.rb +2 -0
  18. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  19. data/test/dummy/config/application.rb +45 -0
  20. data/test/dummy/config/boot.rb +10 -0
  21. data/test/dummy/config/database.yml +22 -0
  22. data/test/dummy/config/environment.rb +5 -0
  23. data/test/dummy/config/environments/development.rb +26 -0
  24. data/test/dummy/config/environments/production.rb +49 -0
  25. data/test/dummy/config/environments/test.rb +35 -0
  26. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  27. data/test/dummy/config/initializers/inflections.rb +10 -0
  28. data/test/dummy/config/initializers/mime_types.rb +5 -0
  29. data/test/dummy/config/initializers/secret_token.rb +7 -0
  30. data/test/dummy/config/initializers/session_store.rb +8 -0
  31. data/test/dummy/config/locales/en.yml +5 -0
  32. data/test/dummy/config/routes.rb +58 -0
  33. data/test/dummy/config.ru +4 -0
  34. data/test/dummy/public/404.html +26 -0
  35. data/test/dummy/public/422.html +26 -0
  36. data/test/dummy/public/500.html +26 -0
  37. data/test/dummy/public/favicon.ico +0 -0
  38. data/test/dummy/public/javascripts/application.js +2 -0
  39. data/test/dummy/public/javascripts/controls.js +965 -0
  40. data/test/dummy/public/javascripts/dragdrop.js +974 -0
  41. data/test/dummy/public/javascripts/effects.js +1123 -0
  42. data/test/dummy/public/javascripts/prototype.js +6001 -0
  43. data/test/dummy/public/javascripts/rails.js +202 -0
  44. data/test/dummy/public/stylesheets/.gitkeep +0 -0
  45. data/test/dummy/script/rails +6 -0
  46. data/test/flagpole_sitta_test.rb +7 -0
  47. data/test/integration/navigation_test.rb +7 -0
  48. data/test/support/integration_case.rb +5 -0
  49. data/test/test_helper.rb +22 -0
  50. metadata +116 -0
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ .bundle/
2
+ log/*.log
3
+ pkg/
4
+ test/dummy/db/*.sqlite3
5
+ test/dummy/log/*.log
6
+ test/dummy/tmp/
7
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "capybara", ">= 0.4.0"
4
+ gem "sqlite3"
5
+
6
+ # To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+)
7
+ # gem 'ruby-debug'
8
+ # gem 'ruby-debug19'
data/Gemfile.lock ADDED
@@ -0,0 +1,38 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ addressable (2.2.8)
5
+ capybara (1.1.2)
6
+ mime-types (>= 1.16)
7
+ nokogiri (>= 1.3.3)
8
+ rack (>= 1.0.0)
9
+ rack-test (>= 0.5.4)
10
+ selenium-webdriver (~> 2.0)
11
+ xpath (~> 0.1.4)
12
+ childprocess (0.3.3)
13
+ ffi (~> 1.0.6)
14
+ ffi (1.0.11)
15
+ libwebsocket (0.1.3)
16
+ addressable
17
+ mime-types (1.19)
18
+ multi_json (1.3.6)
19
+ nokogiri (1.5.5)
20
+ rack (1.4.1)
21
+ rack-test (0.6.1)
22
+ rack (>= 1.0)
23
+ rubyzip (0.9.9)
24
+ selenium-webdriver (2.24.0)
25
+ childprocess (>= 0.2.5)
26
+ libwebsocket (~> 0.1.3)
27
+ multi_json (~> 1.0)
28
+ rubyzip
29
+ sqlite3 (1.3.6)
30
+ xpath (0.1.4)
31
+ nokogiri (~> 1.3)
32
+
33
+ PLATFORMS
34
+ ruby
35
+
36
+ DEPENDENCIES
37
+ capybara (>= 0.4.0)
38
+ sqlite3
data/README.rdoc ADDED
@@ -0,0 +1,121 @@
1
+ = FlagpoleSitta
2
+
3
+ I had visions, I was in them,
4
+
5
+ I was looking into the mirror
6
+
7
+ To see a little bit clearer
8
+
9
+ The rottenness and evil in me.
10
+
11
+ ♫~♫~♫~♫~♫~♫~♫~♫~♫~♫~♫~♫~♫~♫~♫~♫~♫~♫~♫~♫~♫~♫~♫
12
+
13
+ == Preface
14
+
15
+ ===This gem should be considered in early beta and highly unstable. Do not use in a production app!
16
+
17
+ This gem was inspired in part by the song Flagpole Sitta by Harvey Danger. So if you like the gem and are wanting to help out please either donate your time and submits some patches, or donate to the band who wrote the song. They put there last two albums out there all open source like, only asking that those that could donate after downloading. While your donating, if you choose to do so, don't be afraid to download there albums, its good stuff!
18
+
19
+ http://www.harveydanger.com/contribute.php
20
+
21
+ Another note on a personal level, I have some learning disabilities that make it so I frequently make grammar mistake, and once and a while just drop random articles out of my sentences. All this only happens when writing. So if something doesn't make sense in the docs don't be afraid to point it out or submit a patch. Because to me it all looks right.....
22
+
23
+ This gem has also only so far been tested with memcache using the Dalli adapter. File System caching and memory caching are not recommended.Redis/Memcache are defiantly suggested and strongly encouraged for this gem.
24
+
25
+ == Installation
26
+
27
+ For now add the following line to your gemfile
28
+
29
+ gem 'flagpole_sitta', :git => "git://github.com/rovermicrover/FlagpoleSitta.git"
30
+
31
+ Then bundle install.
32
+
33
+ == About
34
+
35
+ Flagpole Sitta is a gem that main purpose is to make it easier to effectively fragment cache in dynamic fashions in Rails.
36
+
37
+ When ever a cache is created it is associated with any model and/or record you tell it to be from the view helper method. When that model and/or record is updated all it's associated cache's are cleared.
38
+
39
+ Flagpole also expects you to put all your database calls into Procs/Lamdbas. This makes it so that your database calls wont have to happen unless your cache hasn't been created. Thus speeding up response time and reducing database traffic.
40
+
41
+ For a simple application you could do something like this.
42
+
43
+ === PageModel
44
+
45
+ cache_sitta :route_id => "url"
46
+
47
+ === PagesController
48
+
49
+ def show
50
+
51
+ @page_call = lambda {
52
+ if params[:url]
53
+ @page = Page.find_by_url params[:url]
54
+ else
55
+ @page = Page.find_by_url 'home'
56
+ end
57
+ }
58
+
59
+ @body_calls = [
60
+ ['page', @page_call]
61
+ ]
62
+
63
+ end
64
+
65
+ === show.haml for Pages
66
+
67
+ - cache_sitta :model => Page, :route_id => params[:url], :section => "body" do
68
+ = @page.content.try(:html_safe)
69
+
70
+ First off lets look at @body_calls. The if you don't provide cache_sitta :calls, then it will look for @#{:section}_calls. So in this case it will look for @body_calls.
71
+
72
+ Second off @body_calls is an array of arrays. This is because you can have multiple calls, and each call must be given a target instance variable ('page') and a call object (@page_call). So in this instance the cache_sitta helper will do
73
+
74
+ @page = @page_call.call
75
+
76
+ You can also pass your calls options by providing :calls_args to the helper. You must though set up your calls to expect an options hash.
77
+
78
+ :route_id and :model must be provide so that the cache can be associated with the correct object, and the cache clear when its supposed to.
79
+
80
+ :route_id must also be a unquie field on the model, other wise the cache won't connect properly to the object.
81
+
82
+ For an index page you could do something like the following for a simple app.
83
+
84
+ === BlogModel
85
+
86
+ cache_sitta :route_id => "url"
87
+
88
+ === BlogsController
89
+
90
+ def index
91
+
92
+ @blogs_call = lambda {
93
+ @blogs = Blog.all
94
+ }
95
+
96
+ @body_calls = [
97
+ ['blogs', @blogs_call]
98
+ ]
99
+
100
+ end
101
+
102
+ === index.haml for Blogs
103
+
104
+ - cache_sitta :models_in_index => Blog, :index_only => true, :section => "body" do
105
+ - @blogs.each do |blog|
106
+ = blog.title
107
+ etc
108
+ etc
109
+
110
+ First notice you don't have to pass :route_id if you pass :index_only => true. And you don't have to pass :model if you pass :models_in_index.
111
+
112
+ :models_in_index tells the helper which Model to associated with the index, so if any objects in that model update the index cache gets nuked.
113
+
114
+ :index_only => true, tells the helper to not bother trying to associated this cache with anyone item in particular.
115
+
116
+ == Footer
117
+
118
+ More examples to come in the wiki, and in the coming example app.
119
+
120
+ ===This gem should be considered in early beta and highly unstable. Do not use in a production app!
121
+
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ # encoding: UTF-8
2
+ require 'rubygems'
3
+ begin
4
+ require 'bundler/setup'
5
+ rescue LoadError
6
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ end
8
+
9
+ require 'rake'
10
+ require 'rake/rdoctask'
11
+
12
+ require 'rake/testtask'
13
+
14
+ Rake::TestTask.new(:test) do |t|
15
+ t.libs << 'lib'
16
+ t.libs << 'test'
17
+ t.pattern = 'test/**/*_test.rb'
18
+ t.verbose = false
19
+ end
20
+
21
+ task :default => :test
22
+
23
+ Rake::RDocTask.new(:rdoc) do |rdoc|
24
+ rdoc.rdoc_dir = 'rdoc'
25
+ rdoc.title = 'FlagpoleSitta'
26
+ rdoc.options << '--line-numbers' << '--inline-source'
27
+ rdoc.rdoc_files.include('README.rdoc')
28
+ rdoc.rdoc_files.include('lib/**/*.rb')
29
+ end
@@ -0,0 +1,169 @@
1
+ module FlagpoleSittaHelper
2
+
3
+ def update_index_array_cache model, key
4
+ model.try(:update_index_array_cache, key)
5
+ end
6
+
7
+ def update_show_array_cache model, key, route_id
8
+ model.try(:update_show_array_cache, key, route_id)
9
+ end
10
+
11
+ #AR - cache_sitta helper
12
+
13
+ #NOTE This is not safe for .builder xml files.
14
+
15
+ #Options are for cache_sitta
16
+
17
+ #key_args, passed to route_id if its a proc or lamdba
18
+ #all args must be passed in this manner if proc or lamdba
19
+ #so start your proc or lamdba with |options = {}|
20
+
21
+ #call_args, passed to call_path if its a proc of lamdba
22
+ #all args must be passed in this manner if proc or lamdba
23
+ #so start your proc or lamdba with |options = {}|
24
+
25
+ #models_in_index
26
+ #Use this if the fragment you are rendering is an index
27
+ #pass it all the different types of models/classes could be
28
+ #included in the index. All the include classes must have cache
29
+ #sitta enabled. The cache for the used index pages will then be
30
+ #wiped clear when anyone of these models/classes has an object
31
+ #created or updated.
32
+ def cache_sitta options={}, &block
33
+
34
+ #AR - If its a string, then just use that value, other wise it
35
+ #assumes that the route_id is a proc or lamdba and call its
36
+ #with the provide args.
37
+
38
+ if options[:route_id_args]
39
+ options[:route_id] = options[:route_id].call(options[:route_id_args])
40
+ elsif options[:route_id].class.eql?(Proc)
41
+ options[:route_id] = options[:route_id].call()
42
+ end
43
+
44
+ if options[:route_id].class.eql?(Array)
45
+ main_route_id = options[:route_id][0]
46
+ else
47
+ main_route_id = options[:route_id]
48
+ end
49
+
50
+
51
+ #Use subroute idea if the view can differ on things like current day, or any type of passed params that can effect how
52
+ #the page will look.
53
+ if options[:sub_route_id_args]
54
+ options[:sub_route_id] = options[:sub_route_id].call(options[:sub_route_id_args])
55
+ elsif options[:sub_route_id_args].class.eql?(Proc)
56
+ options[:sub_route_id] = options[:sub_route_id].call()
57
+ end
58
+
59
+ if options[:model]
60
+ if options[:model_args]
61
+ options[:model] = options[:model].call(options[:model_args])
62
+ elsif options[:model].class.eql?(Proc)
63
+ options[:model] = options[:model].call()
64
+ end
65
+
66
+ if options[:model].class.eql?(Array)
67
+ main_model = options[:model][0]
68
+ else
69
+ main_model = options[:model]
70
+ end
71
+
72
+ elsif params[:model]
73
+
74
+ main_model = params[:model]
75
+
76
+ elsif options[:models_in_index]
77
+
78
+ if options[:models_in_index].class.eql?(Array)
79
+ main_model = options[:models_in_index][0]
80
+ else
81
+ main_model = options[:models_in_index]
82
+ end
83
+
84
+ end
85
+
86
+ main_model = main_model.respond_to?(:constantize) ? main_model.constantize : main_model
87
+
88
+ action = options[:action] || params[:action]
89
+
90
+ key = "views/#{main_model}/#{action}"
91
+
92
+ key = key + (main_route_id ? ('/' + main_route_id) : '')
93
+
94
+ key = key + (options[:sub_route_id] ? ('/' + options[:sub_route_id]) : '')
95
+
96
+ key = key + (options[:section] ? ('/' + options[:section]) : '')
97
+
98
+ calls = instance_variable_get(
99
+ "@" + (options[:section] ? options[:section] : 'body') + "_calls"
100
+ )
101
+
102
+ if content = Rails.cache.read(key)
103
+ #Do nothing the content is ready to render
104
+ else
105
+ #NOTE This is not safe for .builder xml files, and using capture here is why.
106
+ #Its either this or a really complicated hack, from the rails source code, which
107
+ #at the moment I don't feel comfortable using. Waiting for an official solution for
108
+ #the ability to use capture with .builders.
109
+ content = capture do
110
+ #AR - If call_path is an array render each one, other
111
+ #wise just render call_path, because it must
112
+ #be a string or array by this point or something went
113
+ #terribly terribly wrong.
114
+
115
+ if calls
116
+ calls.each do |c|
117
+ if instance_variable_get("@#{c[0]}").nil?
118
+ if options[:calls_args]
119
+ instance_variable_set("@#{c[0]}", c[1].call(options[:calls_args]))
120
+ else
121
+ instance_variable_set("@#{c[0]}", c[1].call())
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ yield
128
+
129
+ end
130
+
131
+ #AR - If the cache is an index or includes an index
132
+ #then models_in_index should be passed with all the
133
+ #models that could show up in the index.
134
+ #Then on save of any model include here this index will be cleared.
135
+ #This can also be used for fragments where there are just so many objects,
136
+ #that while its not an index, there isn't a clear way expect to nuke it when
137
+ #any of the model types involved are updated.
138
+
139
+ if options[:models_in_index].class.eql?(Array)
140
+ options[:models_in_index].each do |m|
141
+ processed_m = m.respond_to?(:constantize) ? m.constantize : m
142
+ update_index_array_cache(processed_m, key)
143
+ end
144
+ elsif options[:models_in_index]
145
+ processed_model = options[:models_in_index].respond_to?(:constantize) ? options[:models_in_index].constantize : options[:models_in_index]
146
+ update_index_array_cache(options[:models_in_index], key)
147
+ end
148
+
149
+ #AR - Create a link between each declared object and the cache.
150
+
151
+ if !options[:index_only] && options[:route_id]
152
+ if options[:route_id].class.eql?(Array) && options[:model].class.eql?(Array)
153
+ options[:model].each_index do |i|
154
+ update_show_array_cache(options[:model][i], key, options[:route_id][i])
155
+ end
156
+ else
157
+ update_show_array_cache(main_model, key, main_route_id)
158
+ end
159
+ end
160
+
161
+ Rails.cache.write(key, content)
162
+
163
+ end
164
+
165
+ safe_concat content
166
+
167
+ end
168
+
169
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path("../lib/flagpole_sitta/version", __FILE__)
2
+
3
+ # Provide a simple gemspec so you can easily use your enginex
4
+ # project in your rails apps through git.
5
+ Gem::Specification.new do |s|
6
+ s.name = "flagpole_sitta"
7
+ s.version = FlagpoleSitta::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Andrew Rove (Rover)"]
10
+ s.email = ["rovermicrover@gmail.com"]
11
+ s.homepage = "https://github.com/rovermicrover/FlagpoleSitta"
12
+ s.summary = "FlagpoleSitta a gem for effective dynamic caching"
13
+ s.description = "Flagpole Sitta is a gem that main purpose is to make it easier to effectively fragment cache in dynamic fashions.\n When ever a cache is created it is associated with any model and/or record you tell it to be from the helper method. When that model and/or record is updated all it's associated cache's are cleared.\n Flagpole also expects you to put all your database calls into Procs/Lamdbas. This makes it so that your database calls wont have to happen unless your cache hasn't been created. Thus speeding up response time and reducing database traffic."
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
17
+ s.require_path = 'lib'
18
+
19
+ #add dependecy here and in the engine file as a required.
20
+
21
+ s.add_dependency('dalli')
22
+
23
+ end
@@ -0,0 +1,83 @@
1
+ module FlagpoleSitta
2
+ module BracketRetrieval
3
+
4
+ extend ActiveSupport::Concern
5
+
6
+ #When forcing a call back into a class from a module you must do it inside an include block
7
+ included do
8
+ validates_uniqueness_of (@_key_field || "name").to_sym
9
+ validates_presence_of (@_key_field || "name").to_sym
10
+ before_save :br_update_save
11
+ before_destroy :br_update_destroy
12
+ end
13
+
14
+ def br_update_save
15
+ self.br_update(true)
16
+ end
17
+
18
+ def br_update_destroy
19
+ self.br_update(false)
20
+ end
21
+
22
+ def br_update alive
23
+ downcased = self.class.name.downcase
24
+ #Checks to make sure Controller Caching is on
25
+ if Rails.application.config.action_controller.perform_caching
26
+ Rails.cache.delete("#{downcased}/#{self.send(self.class.key_field + "_was")}")
27
+ Rails.cache.write("#{downcased}/#{self.send(self.class.key_field)}", self.send(self.class.value_field))
28
+ end
29
+ end
30
+
31
+ module ClassMethods
32
+
33
+ #Will look up the object chain till it finds what it was set to, or not set too.
34
+ def safe_content?
35
+ result = @_safe_content || (self.superclass.respond_to?(:safe_content?) ? self.superclass.safe_content? : nil) || false
36
+ end
37
+
38
+ #Will look up the object chain till it finds what it was set to, or not set too.
39
+ def key_field
40
+ result = @_key_field || (self.superclass.respond_to?(:key_field) ? self.superclass.key_field : nil) || "name"
41
+ end
42
+
43
+ #Will look up the object chain till it finds what it was set to, or not set too.
44
+ def value_field
45
+ result = @_value_field || (self.superclass.respond_to?(:value_field) ? self.superclass.value_field : nil) || "content"
46
+ end
47
+
48
+ def default_value
49
+ result = @_default_value || (self.superclass.respond_to?(:default_value) ? self.superclass.default_value : nil) || ""
50
+ end
51
+
52
+ def [] key
53
+ downcased = self.to_s.downcase
54
+ #If its in cache return that, unless blank, then return nil
55
+ #elsif the object is in the database put it into the cache
56
+ #then return it.
57
+ #else create the corresponding object as blank, and return nil.
58
+ #The last line there is why this extension should never be used
59
+ #with user generated content.
60
+ if value = Rails.cache.read("#{downcased}/#{key}") || Rails.cache.exist?("#{downcased}/#{key}")
61
+ if value.present?
62
+ value = self.safe_content? ? value.html_safe : value
63
+ else
64
+ #Always return nil even if the return value is blank.
65
+ #Also if its blank we don't want to try to create it again
66
+ #thus the reason for this odd nested if statement.
67
+ value = nil
68
+ end
69
+ elsif obj = self.send("find_by_#{self.key_field}", key)
70
+ value = obj.send(self.value_field)
71
+ Rails.cache.write("#{downcased}/#{key}", value)
72
+ value = value && self.safe_content? ? value.html_safe : value
73
+ else
74
+ rec = self.create(self.key_field.to_sym => key, self.value_field.to_sym => self.default_value)
75
+ Rails.cache.write("#{downcased}/#{key}", rec.send(self.value_field))
76
+ value = nil
77
+ end
78
+ value
79
+ end
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,198 @@
1
+ module FlagpoleSitta
2
+ module CacheSitta
3
+ extend ActiveSupport::Concern
4
+
5
+ #When forcing a call back into a class from a module you must do it inside an include block
6
+ included do
7
+ before_save :cache_sitta_save
8
+ before_destroy :cache_sitta_destory
9
+ end
10
+
11
+ module ClassMethods
12
+
13
+ def initialize_index_array_cache
14
+
15
+ clazz = self
16
+
17
+ flag = {:space => - 1}
18
+
19
+ Rails.cache.write("#{clazz}/IndexArray/Flag", flag)
20
+
21
+ flag
22
+
23
+ end
24
+
25
+ def update_index_array_cache key
26
+
27
+ clazz = self
28
+
29
+ flag = Rails.cache.read("#{clazz}/IndexArray/Flag")
30
+
31
+ #AR - If it doesn't exist start the process of creating it
32
+ if flag.nil?
33
+ flag = initialize_index_array_cache
34
+ end
35
+
36
+ #AR - update the array's end point
37
+ flag[:space] = flag[:space] + 1
38
+
39
+ #AR - write out the new index at the end of the array
40
+ Rails.cache.write("#{clazz}/IndexArray/#{flag[:space]}", {:key => key})
41
+
42
+ #AR - update flag in the cache
43
+ Rails.cache.write("#{clazz}/IndexArray/Flag", flag)
44
+
45
+ end
46
+
47
+ def each_index_cache &block
48
+
49
+ clazz = self
50
+
51
+ flag = Rails.cache.read("#{clazz}/IndexArray/Flag")
52
+
53
+ #AR - If it doesn't exist start the process of creating it
54
+ if flag.nil?
55
+ flag = initialize_index_array_cache
56
+ end
57
+
58
+ #AR - If there aren't any index do nothing.
59
+ #Else wise loop through every index.
60
+ #If it actually does exist then yield.
61
+ for i in 0..flag[:space] do
62
+ hash = Rails.cache.read("#{clazz}/IndexArray/#{i}")
63
+ if hash
64
+ yield hash[:key]
65
+ end
66
+ end
67
+
68
+ nil
69
+
70
+ end
71
+
72
+ def destroy_index_array_cache
73
+
74
+ clazz = self
75
+
76
+ each_index_cache do |key|
77
+ Rails.cache.delete(key)
78
+ end
79
+
80
+ Rails.cache.delete("#{clazz}/IndexArray/Flag")
81
+ end
82
+
83
+ def initialize_show_array_cache route_id
84
+
85
+ clazz = self
86
+
87
+ #AR - Its negative one to stop the for loops in the each method if its empty
88
+ flag = {:space => - 1}
89
+
90
+ Rails.cache.write("#{clazz}/#{route_id}/ShowArray/Flag", flag)
91
+
92
+ flag
93
+
94
+ end
95
+
96
+ def update_show_array_cache key, route_id
97
+
98
+ clazz = self
99
+
100
+ flag = Rails.cache.read("#{clazz}/#{route_id}/ShowArray/Flag")
101
+
102
+ #AR - If it doesn't exist start the process of creating it
103
+ if flag.nil?
104
+ flag = initialize_show_array_cache(route_id)
105
+ end
106
+
107
+ #AR - Update the array's end point
108
+ flag[:space] = flag[:space] + 1
109
+
110
+ #AR - Write out the new index at the end of the array
111
+ Rails.cache.write("#{clazz}/#{route_id}/ShowArray/#{flag[:space]}", {:key => key})
112
+
113
+ #AR - Update flag in the cache
114
+ Rails.cache.write("#{clazz}/#{route_id}/ShowArray/Flag", flag)
115
+
116
+ end
117
+
118
+ def each_show_cache route_id, &block
119
+
120
+ clazz = self
121
+
122
+ flag = Rails.cache.read("#{clazz}/#{route_id}/ShowArray/Flag")
123
+
124
+ #AR - If it doesn't exist start the process of creating it
125
+ if flag.nil?
126
+ flag = initialize_show_array_cache(route_id)
127
+ end
128
+
129
+ #AR - If there aren't any shows caches do nothing, this happens when space is -1.
130
+ #Else wise loop through every caches.
131
+ #If it actually does exist then yield.
132
+ for i in 0..flag[:space] do
133
+ hash = Rails.cache.read("#{clazz}/#{route_id}/ShowArray/#{i}")
134
+ if hash
135
+ yield hash[:key]
136
+ end
137
+ end
138
+
139
+ nil
140
+
141
+ end
142
+
143
+ def destroy_show_array_cache route_id
144
+
145
+ clazz = self
146
+
147
+ each_show_cache route_id do |k|
148
+ Rails.cache.delete(k)
149
+ end
150
+
151
+ Rails.cache.delete("#{clazz}/#{route_id}/ShowArray/Flag")
152
+ end
153
+
154
+ end
155
+
156
+ def cache_sitta_save
157
+ self.cache_work(true)
158
+ end
159
+
160
+ def cache_sitta_destory
161
+ self.cache_work(false)
162
+ end
163
+
164
+ def cache_work(alive)
165
+ original_clazz = self.class
166
+ # Also have to go through all its super objects till the super objects aren't cache sittaed
167
+ # this is because the new updated object for a sub class, could have also been in a cache for
168
+ # said sub class, but also in a cache for its super.
169
+ clazz = original_clazz
170
+ while(clazz.respond_to? :destroy_show_array_cache)
171
+
172
+ #AR - Clear all caches related to the old route_id
173
+ clazz.destroy_show_array_cache(self.try(:send, ("#{clazz.route_id}_was")).to_s)
174
+ #AR - Clear all caches related to the new route_id just in case
175
+ clazz.destroy_show_array_cache(self.try(:send, ("#{clazz.route_id}")).to_s)
176
+ #AR - If the new and old are the same All that will happen on the second call is that
177
+ #it will write the flag out and then destroy it. A very tiny bit of work
178
+ #for a great amount of extra protection.
179
+
180
+ # AR - Remember to include models_in_index in your helper call in the corresponding index cache.
181
+ clazz.destroy_index_array_cache
182
+
183
+ clazz = clazz.superclass
184
+ end
185
+
186
+ #AR - For Safety this will not recurse upwards for the extra cache maintenance
187
+ extra_cache_maintenance(alive)
188
+
189
+ end
190
+
191
+ #AR - For Safety this will not recurse upwards for the extra cache maintenance
192
+ def extra_cache_maintenance alive
193
+ method = (@_cache_extra_maintance || Proc.new{})
194
+ method.call
195
+ end
196
+
197
+ end
198
+ end