cache_money_millionaire 0.0.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 ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cache_money_millionaire.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 John Koht
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # CacheMoneyMillionaire
2
+
3
+ Rails ActiveRecord Query Caching like a Millionaire
4
+
5
+ CacheMoneyMillionaire is a simple Ruby gem that extends Rail's basic find, save and touch methods to create, set and update cache keys for ActiveRecord models.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'cache_money_millionaire'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install cache_money_millionaire
20
+
21
+ ## Usage
22
+
23
+ In order to get started, make sure you add the initializer:
24
+
25
+ # config/initializers/cache_money_millionaire.rb
26
+ CacheMoneyMillionaire.configure do |config|
27
+ config.cacheable = true
28
+ config.expires_in = 30.days
29
+ end
30
+
31
+ Caching will only occur if the config.cacheable AND your Rails application is set to perform_caching. Please note that development environments have caching turned off, so if you want to test locally, make sure you update your development.rb.
32
+
33
+ That's it! Everything else is automatic!
34
+
35
+ ### Skip Caching
36
+
37
+ If you want, you can ignore the cached version when fetching a model, to do so, simple do:
38
+
39
+ # Get a fresh copy of the record by bypassing the cached version
40
+ Post.find(3, cache: false)
41
+
42
+ ### ActiveRecord Collection and Array Helper
43
+
44
+ There are two active record patches for the ActiveRecord Collections and Array. These allow you to call .cache_key on a collection or an array and receive an MD5 hash for caching:
45
+
46
+ # Cache key for all posts
47
+ Post.published.all.cache_key
48
+ # => "ba6a3c1d35e7c7d1b4acdcd5330f8891"
49
+
50
+ # Cache key for paginated post collection
51
+ Post.published.page(params[:page]).per(20)
52
+ # => "b7ff80c902b673c03b5f195dcf3e492e"
53
+
54
+ # Cache key for Arrays
55
+ tags = Post.find(3).tags
56
+ tags.cache_key
57
+ # => "9d72ecf5ab79e30cfe67fe5ee0b03aa9"
58
+
59
+ ## Contributing
60
+
61
+ 1. Fork it
62
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
63
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
64
+ 4. Push to the branch (`git push origin my-new-feature`)
65
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cache_money_millionaire/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "cache_money_millionaire"
8
+ spec.version = CacheMoneyMillionaire::VERSION
9
+ spec.authors = ["John Koht"]
10
+ spec.email = ["john@kohactive.com"]
11
+ spec.description = "Rails ActiveRecord Query Caching like a Millionaire"
12
+ spec.summary = "Rails ActiveRecord Query Caching like a Millionaire"
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ end
@@ -0,0 +1,30 @@
1
+ module CacheMoneyMillionaire
2
+ module Config
3
+
4
+ VALID_OPTION_KEYS = [
5
+ :cacheable,
6
+ :expires_in
7
+ ]
8
+
9
+ attr_accessor *VALID_OPTION_KEYS
10
+
11
+ def configure
12
+ yield self
13
+ self
14
+ end
15
+
16
+ def options
17
+ options = {}
18
+ VALID_OPTION_KEYS.each{ |pname| options[pname] = send(pname) }
19
+ options
20
+ end
21
+
22
+ # Is the application cacheable? We'll only perform caching if the perform_caching
23
+ # setting is true
24
+ def cacheable?
25
+ Rails.application.config.action_controller.perform_caching and options[:cacheable]
26
+ #true
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,62 @@
1
+ module ActiveRecord
2
+ class Base
3
+
4
+ # Include the CacheMoneyMillionaire module
5
+ extend CacheMoneyMillionaire
6
+
7
+
8
+ # Extend the find method for ActiveRecord
9
+ # This method will create or fetch a record by a cache key. If the record exists in cache
10
+ # then we fetch it, otherwise, we'll create a cache key for it and store it in memory
11
+ # To ignore cache, pass cache: false as a parameter
12
+
13
+ def self.find *args
14
+ # extract the options and see if the :cache: option was passed, and set the skip_cache
15
+ # variable based on it's validity. Then we'll remove from the arguments and pass
16
+ # the original arguments back into our hash
17
+ options = args.extract_options!
18
+ cache = options.delete(:cache) || true
19
+ args.push(options)
20
+
21
+ # If it's cacheable and cache isn't set to false, then let's CacheMoneyMillionaire this bitch!
22
+ # We set the cache key to the object class name and id, i.e. Post 3, User 109, etc.
23
+ if CacheMoneyMillionaire.cacheable? and cache
24
+ model = Rails.cache.fetch (Digest::MD5.hexdigest "#{self} #{args[0]}"), expires_in: CacheMoneyMillionaire.options[:expires_in] do
25
+ super *args
26
+ end
27
+ else
28
+ # if no caching, then let's just ignore and call typical .find method
29
+ super *args
30
+ end
31
+ end
32
+
33
+
34
+ # Extend the save method for ActiveRecord
35
+ # When an object is saved, let's update the cache key (the one we created above) so we can
36
+ # invalidate our stale cache
37
+ def save *args
38
+ self.rewrite_cache
39
+ super
40
+ end
41
+
42
+
43
+ # Extend the touch method for ActiveRecord
44
+ # Similar to the save method extention, we'll just hijack the touch method and update the
45
+ # cache key value with our updated data
46
+ def touch
47
+ super
48
+ self.rewrite_cache
49
+ end
50
+
51
+ # rewrite the cache for this model
52
+ def rewrite_cache
53
+ if CacheMoneyMillionaire.cacheable?
54
+ cache_key = Digest::MD5.hexdigest "#{self.class.name} #{self.id}"
55
+ Rails.cache.write cache_key, self
56
+ else
57
+ false
58
+ end
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,30 @@
1
+ # CacheKey Patch
2
+ # Add cache_key methods to Arrays and ActiveRecord collections which allows us to
3
+ # easily cache sets of data without any problems.
4
+
5
+ # example: Posts.all.cache_key
6
+ # example: Posts.published.page(params[:page]).per(20).cache_key
7
+
8
+ # This is great for HTTP caching in the controller, here's a quick example:
9
+ # @posts = Post.scoped.published.page(params[:page]).per(10)
10
+ # if stale?(etag: @posts.cache_key, last_modified: @posts.maximum(:updated_at), public: true)
11
+ # ...
12
+ # end
13
+
14
+
15
+ # Extend Array to include a cache_key method
16
+ class Array
17
+ def cache_key
18
+ Digest::MD5.hexdigest "#{self.count}-#{self.inspect}"
19
+ end
20
+ end
21
+
22
+
23
+ # Extend ActiveRecord::Base Collections to include a cache_key method
24
+ module ActiveRecord
25
+ class Base
26
+ def self.cache_key
27
+ Digest::MD5.hexdigest "#{scoped.maximum(:updated_at).try(:to_i)}-#{scoped.count}"
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,6 @@
1
+ module CacheMoneyMillionaire
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ module CacheMoneyMillionaire
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,20 @@
1
+ require "cache_money_millionaire/version"
2
+ require "cache_money_millionaire/config"
3
+ require "cache_money_millionaire/rails/active_record_patch"
4
+ require "cache_money_millionaire/rails/cache_key_patch"
5
+
6
+ module CacheMoneyMillionaire
7
+
8
+ extend Config
9
+
10
+ class << self
11
+ def initialize attrs={}
12
+ puts "initialize..."
13
+ attrs = CacheMoneyMillionaire.options.merge(attrs)
14
+ Config::VALID_OPTION_KEYS.each do |key|
15
+ instance_variable_set("@#{key}".to_sym, attrs[key])
16
+ end
17
+ end
18
+ end
19
+
20
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cache_money_millionaire
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - John Koht
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: Rails ActiveRecord Query Caching like a Millionaire
47
+ email:
48
+ - john@kohactive.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - Gemfile
55
+ - LICENSE.txt
56
+ - README.md
57
+ - Rakefile
58
+ - cache_money_millionaire.gemspec
59
+ - lib/cache_money_millionaire.rb
60
+ - lib/cache_money_millionaire/config.rb
61
+ - lib/cache_money_millionaire/rails/active_record_patch.rb
62
+ - lib/cache_money_millionaire/rails/cache_key_patch.rb
63
+ - lib/cache_money_millionaire/rails/engine.rb
64
+ - lib/cache_money_millionaire/version.rb
65
+ homepage: ''
66
+ licenses:
67
+ - MIT
68
+ post_install_message:
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ! '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubyforge_project:
86
+ rubygems_version: 1.8.25
87
+ signing_key:
88
+ specification_version: 3
89
+ summary: Rails ActiveRecord Query Caching like a Millionaire
90
+ test_files: []