shadow_model 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: af8efdd8209465e2f3160872a3ebd70d13386b66
4
+ data.tar.gz: 5a95826af5c3f28814fa974c5348972ce0d475ba
5
+ SHA512:
6
+ metadata.gz: 57371ab38d192ab2eefc309ddf9d24fa7020e627196016371e58c930e26cbdf508b776c40e714a3d937187b8e07a8820943f18ce4a86a6e19d6fb57d5e352ee5
7
+ data.tar.gz: 5187008742137a1ca9f641f2946adbf01bdd9d2e69e726fee007fd9684fc956368944e9147e2cdcaec044c301bb80126b27efe2f0d03c9b6ff0f07d05f071f0f
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2013 Weihu Chen
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # ShadowModel
2
+
3
+ A rails plugin use redis to cache models data.
4
+
5
+ [![Build Status](https://travis-ci.org/cctiger36/shadow_model.png?branch=master)](https://travis-ci.org/cctiger36/shadow_model)
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'shadow_model'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ ## Usage
18
+
19
+ Add this to your model class, then the models will be cached with the assigned attributes and methods after the model saved or updated.
20
+
21
+ shadow_model attribute_or_method1, attribute_or_method2, ..., options
22
+
23
+ And use this to retrieve the model from redis.
24
+
25
+ YourModelClass.find_by_shadow(primary_key)
26
+
27
+ ### options
28
+
29
+ <table>
30
+ <tr>
31
+ <td>expiration</td><td>Set the timeout of each cache.</td>
32
+ <tr>
33
+ </tr>
34
+ <td>&nbsp;&nbsp;update_expiration</td><td>Reset cache expiration after model updated.</td>
35
+ </tr>
36
+ </tr>
37
+ <td>expireat</td><td>Set the absolute timeout timestamp of each cache.</td>
38
+ </tr>
39
+ </table>
40
+
41
+ ## Example
42
+
43
+ # == Schema Information
44
+ #
45
+ # Table name: players
46
+ #
47
+ # id :integer not null, primary key
48
+ # name :string(255)
49
+ # stamina :integer
50
+ # created_at :datetime not null
51
+ # updated_at :datetime not null
52
+
53
+ class Player < ActiveRecord::Base
54
+ shadow_model :name, :stamina, :cacheable_method, expiration: 30.minutes
55
+
56
+ def cacheable_method
57
+ "result to cache"
58
+ end
59
+ end
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ desc 'Default: run specs'
5
+ task :default => :spec
6
+
7
+ require 'rspec/core/rake_task'
8
+ RSpec::Core::RakeTask.new do |t|
9
+ t.pattern = "spec/**/*_spec.rb"
10
+ end
11
+
12
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,19 @@
1
+ require 'active_support'
2
+ require 'active_record'
3
+ require 'shadow_model/version'
4
+
5
+ module ShadowModel
6
+ extend ActiveSupport::Concern
7
+
8
+ autoload :Extension, 'shadow_model/extension'
9
+
10
+ module ClassMethods
11
+ def shadow_model(*args)
12
+ options = args.last.is_a?(Hash) ? args.pop : {}
13
+ self.send :include, ShadowModel::Extension
14
+ set_shadow_keys(args, options)
15
+ end
16
+ end
17
+ end
18
+
19
+ ActiveRecord::Base.send :include, ShadowModel
@@ -0,0 +1,128 @@
1
+ module ShadowModel
2
+ module Extension
3
+ def self.included(base)
4
+ base.class_eval <<-RUBY
5
+ mattr_accessor :shadow_options
6
+ extend ClassMethods
7
+ after_save :update_shadow_cache
8
+ RUBY
9
+ end
10
+
11
+ def shadow_model?
12
+ @shadow_model
13
+ end
14
+
15
+ def shadow_model=(value)
16
+ @shadow_model = value
17
+ end
18
+
19
+ def shadow_cache_key
20
+ @shadow_cache_key ||= self.class.build_shadow_cache_key(self[self.class.primary_key])
21
+ end
22
+
23
+ def shadow_data
24
+ @shadow_data ||= self.class.find_shadow_data(self[self.class.primary_key])
25
+ end
26
+
27
+ def shadow_data=(data)
28
+ @shadow_data = data
29
+ end
30
+
31
+ def clear_shadow_data
32
+ Redis.current.del(shadow_cache_key)
33
+ end
34
+
35
+ def build_shadow_data
36
+ Marshal.dump(self.class.shadow_keys.inject({}) { |data, attr| data[attr] = send(attr); data })
37
+ end
38
+
39
+ def update_shadow_cache
40
+ Redis.current.set(shadow_cache_key, build_shadow_data)
41
+ update_expiration
42
+ end
43
+
44
+ def update_expiration
45
+ if self.class.shadow_options[:expiration].present?
46
+ if self.class.shadow_options[:update_expiration] || shadow_ttl < 0
47
+ Redis.current.expire(shadow_cache_key, self.class.shadow_options[:expiration])
48
+ end
49
+ elsif self.class.shadow_options[:expireat].present?
50
+ Redis.current.expireat(shadow_cache_key, self.class.shadow_options[:expireat].to_i) if shadow_ttl < 0
51
+ end
52
+ end
53
+
54
+ def shadow_ttl
55
+ Redis.current.ttl(shadow_cache_key)
56
+ end
57
+
58
+ module ClassMethods
59
+ def set_shadow_keys(args, options = {})
60
+ @shadow_attributes ||= []
61
+ @shadow_methods ||= []
62
+ self.shadow_options = options
63
+ args.each do |arg|
64
+ if self.attribute_names.include?(arg.to_s)
65
+ @shadow_attributes << arg.to_sym
66
+ else
67
+ @shadow_methods << arg.to_sym
68
+ end
69
+ end
70
+ @shadow_attributes.each { |attr| define_shadow_attributes(attr) }
71
+ end
72
+
73
+ def shadow_keys
74
+ @shadow_attributes + @shadow_methods
75
+ end
76
+
77
+ def method_added(method_name)
78
+ define_shadow_methods(method_name)
79
+ end
80
+
81
+ def define_shadow_attributes(attribute_name)
82
+ self.class_eval <<-RUBY
83
+ def #{attribute_name}_without_shadow
84
+ self.read_attribute(:#{attribute_name})
85
+ end
86
+
87
+ def #{attribute_name}
88
+ shadow_model? ? shadow_data[:#{attribute_name}] : #{attribute_name}_without_shadow
89
+ end
90
+ RUBY
91
+ end
92
+
93
+ def define_shadow_methods(method_name)
94
+ if self.shadow_keys.include?(method_name.to_sym) && !self.instance_methods.include?("#{method_name}_without_shadow".to_sym)
95
+ self.class_eval <<-RUBY
96
+ def #{method_name}_with_shadow
97
+ shadow_model? ? shadow_data[:#{method_name}] : #{method_name}_without_shadow
98
+ end
99
+ alias_method_chain :#{method_name}, :shadow
100
+ RUBY
101
+ end
102
+ end
103
+
104
+ def find_by_shadow(id)
105
+ if shadow_data = find_shadow_data(id)
106
+ instance = self.new
107
+ instance.shadow_model = true
108
+ instance.shadow_data = shadow_data
109
+ instance.readonly!
110
+ instance
111
+ else
112
+ instance = self.find(id)
113
+ instance.update_shadow_cache
114
+ find_by_shadow(id)
115
+ end
116
+ end
117
+
118
+ def find_shadow_data(id)
119
+ data = Redis.current.get(build_shadow_cache_key(id))
120
+ data ? Marshal.load(data) : nil
121
+ end
122
+
123
+ def build_shadow_cache_key(id)
124
+ "#{self.name.tableize}:Shadow:#{id}"
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,3 @@
1
+ module ShadowModel
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: shadow_model
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Weihu Chen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-09-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 3.1.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 3.1.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: redis
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 3.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: 3.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: sqlite3
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: factory_girl_rails
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: A rails plugin use reids to cache models data.
84
+ email:
85
+ - cctiger36@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - lib/shadow_model/extension.rb
91
+ - lib/shadow_model/version.rb
92
+ - lib/shadow_model.rb
93
+ - MIT-LICENSE
94
+ - Rakefile
95
+ - README.md
96
+ homepage: https://github.com/cctiger36/shadow_model
97
+ licenses:
98
+ - MIT
99
+ metadata: {}
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - '>='
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubyforge_project:
116
+ rubygems_version: 2.0.6
117
+ signing_key:
118
+ specification_version: 4
119
+ summary: rails model cache with redis
120
+ test_files: []