database_cached_attribute 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e3ef5688041c2ebdebee855e718969bc6cd71689
4
+ data.tar.gz: 9d6ddf4d939944de4cd165123d61d3a9c8cd0e15
5
+ SHA512:
6
+ metadata.gz: dabf006f76c29f149f7a0cf8663d5f18753270c129e075ed2ca440de752f40a10c6b3a907d4c88a6ea74879638094551b7b668e5c8bd54c3e5c7e7270ec9f1a1
7
+ data.tar.gz: 523acfca93ff269e49dc7631c89a2f480647de6ad29e4734f7dbb934a67bc31b85c70680acfee13e825e89b529d3d69391b2b81c829b364aac2803257066c0da
data/.travis.yml ADDED
@@ -0,0 +1 @@
1
+ language: ruby
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Declare your gem's dependencies in database_cached_attribute.gemspec.
4
+ # Bundler will treat runtime dependencies like base dependencies, and
5
+ # development dependencies will be added by default to the :development group.
6
+ gemspec
7
+
8
+ # Declare any dependencies that are still in development here instead of in
9
+ # your gemspec. These might include edge Rails or gems from your path or
10
+ # Git. Remember to move these dependencies to your gemspec before releasing
11
+ # your gem to rubygems.org.
12
+
13
+ # To use debugger
14
+ # gem 'debugger'
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Charles Smith (github.com/twohlix/)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,6 @@
1
+ database_cached_attribute
2
+ =========================
3
+ [![Code Climate](https://codeclimate.com/github/twohlix/database_cached_attribute.png)](https://codeclimate.com/github/twohlix/database_cached_attribute)
4
+ [![Build Status](https://travis-ci.org/twohlix/database_cached_attribute.png?branch=master)](https://travis-ci.org/twohlix/database_cached_attribute)
5
+
6
+ Ruby gem that adds simple functions to invalidate single columns as a cache on an ActiveRecord models.
data/Rakefile ADDED
@@ -0,0 +1,25 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'DatabaseCachedAttribute'
12
+ rdoc.options << '--line-numbers'
13
+ #rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ Bundler::GemHelper.install_tasks
18
+
19
+ require 'rspec/core/rake_task'
20
+
21
+ RSpec::Core::RakeTask.new(:spec) do |spec|
22
+ spec.rspec_opts = '--colour'
23
+ end
24
+
25
+ task default: :spec
@@ -0,0 +1,81 @@
1
+ require 'active_support/concern'
2
+
3
+ # DatabaseCachedAttribute adds a method to add a set of easy to use cache invalidation
4
+ # methods/callbacks for specified attributes
5
+ #
6
+ # On the model where you possibly may want to cache things from this model that may
7
+ # be heavy to create:
8
+ # include DatabaseCachedAttribute
9
+ # database_cached_attribute :attribute_name, :another_attribute_name
10
+ # This will create the methods
11
+ # invalidate_attribute_name(optional_object)
12
+ # invalidate_another_attribute_name(optional_object)
13
+ # cache_attribute_name(optional_object)
14
+ # cache_another_attribute_name(optional_object)
15
+ # Which means invalidating that attribute is easy, say when you add an associated object
16
+ # has_many :things, before_add: :invalidate_attribute, before_remove: :invalidate_other_attribute
17
+ #
18
+ module DatabaseCachedAttribute
19
+ extend ActiveSupport::Concern
20
+
21
+ included do
22
+ # Cache invalidation by column
23
+ def invalidate_cache (column_name)
24
+ self[column_name.to_sym] = nil
25
+ update_cache column_name.to_sym
26
+ end
27
+
28
+ # Update cache by column
29
+ def update_cache (column_name)
30
+ save if only_change?(column_name) && persisted?
31
+ end
32
+
33
+ # Determines if the provided column name is the only change
34
+ def only_change? (column_name)
35
+ changes.length == 1 && changes.has_key?(column_name)
36
+ end
37
+
38
+ # Determines if the provided column names are the only changes
39
+ def only_changes? (*column_names)
40
+ return false if changes.length != column_names.length
41
+
42
+ column_names.each do |column_name|
43
+ return false if !changes.has_key?(column_name)
44
+ end
45
+
46
+ true
47
+ end
48
+
49
+ # Determines if the changes, if any, are only in the list of column names provided
50
+ def only_changes_in? (*column_names)
51
+ return false if changes.length > column_names.length
52
+
53
+ our_changes = changes.slice column_names
54
+ return false if our_changes.length < changes.length
55
+
56
+ true
57
+ end
58
+ end
59
+
60
+ module ClassMethods
61
+ # Sets up cache invalidation callbacks for the provided attributes
62
+ def database_cached_attribute(*attrs)
63
+ attrs.each do |attr|
64
+ define_method("invalidate_#{attr}") do |arg=nil| # default arg to allow before_blah callbacks
65
+ invalidate_cache attr.to_sym
66
+ end
67
+
68
+ define_method("only_#{attr}_changed?") do
69
+ only_change? attr.to_sym
70
+ end
71
+
72
+ define_method("cache_#{attr}") do
73
+ update_cache attr.to_sym
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+
80
+
81
+ end
@@ -0,0 +1,7 @@
1
+ module DatabaseCachedAttribute
2
+ VERSION = "0.1.0"
3
+ VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
4
+ VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
5
+ VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
6
+ VERSION_BUILD = VERSION_ARRAY[2] # :nodoc:
7
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :database_cached_attribute do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,144 @@
1
+ require 'temping'
2
+ require 'database_cached_attribute'
3
+
4
+ ActiveRecord::Base.establish_connection("sqlite3:///:memory:")
5
+
6
+ Temping.create :no_include_class do
7
+ with_columns do |t|
8
+ t.string :string_attribute
9
+ t.integer :integer_attribute
10
+ end
11
+ end
12
+ Temping.create :include_class do
13
+ include DatabaseCachedAttribute
14
+ database_cached_attribute :string_attribute
15
+ database_cached_attribute :integer_attribute
16
+
17
+ with_columns do |t|
18
+ t.string :string_attribute
19
+ t.integer :integer_attribute
20
+ end
21
+ end
22
+
23
+ describe DatabaseCachedAttribute do
24
+ # JUST INCLUDED TESTS
25
+ context "included" do
26
+ before do
27
+ @test_obj = IncludeClass.new
28
+ end
29
+
30
+ it "creates functions for invalidating cache" do
31
+ expect(@test_obj.respond_to? :invalidate_cache).to eq(true)
32
+ end
33
+
34
+ it "creates functions for saving cache" do
35
+ expect(@test_obj.respond_to? :update_cache)
36
+ end
37
+
38
+ it "using database_cached_attribute in the model adds nice functions to invalidate cache" do
39
+ expect(@test_obj.respond_to? :invalidate_string_attribute).to eq(true)
40
+ expect(@test_obj.respond_to? :invalidate_integer_attribute).to eq(true)
41
+ expect(@test_obj.respond_to? :invalidate_non_attribute).to eq(false)
42
+ end
43
+
44
+ it "using database_cached_attribute in the model adds nice functions to save caches" do
45
+ expect(@test_obj.respond_to? :cache_string_attribute).to eq(true)
46
+ expect(@test_obj.respond_to? :cache_integer_attribute).to eq(true)
47
+ expect(@test_obj.respond_to? :cache_non_attribute).to eq(false)
48
+ end
49
+ end
50
+
51
+ # NEW OBJECT TESTS
52
+ context "new objects not yet saved" do
53
+ before(:each) do
54
+ @test_obj = IncludeClass.new
55
+ @test_obj.string_attribute = "original string"
56
+ expect(@test_obj.new_record?).to eq(true)
57
+ expect(@test_obj.persisted?).to eq(false)
58
+ end
59
+
60
+ it "does not persist cache updates" do
61
+ @test_obj.cache_string_attribute
62
+ @test_obj.string_attribute = "new string"
63
+ @test_obj.cache_string_attribute
64
+ expect(@test_obj.new_record?).to eq(true)
65
+ expect(@test_obj.persisted?).to eq(false)
66
+ end
67
+
68
+ it "does not persist cache invalidations" do
69
+ @test_obj.invalidate_string_attribute
70
+ @test_obj.string_attribute = "new string"
71
+ @test_obj.invalidate_string_attribute
72
+ expect(@test_obj.new_record?).to eq(true)
73
+ expect(@test_obj.persisted?).to eq(false)
74
+ end
75
+
76
+ it "using .invalidate_attribute_name does change the data" do
77
+ expect(@test_obj.string_attribute).to eq("original string")
78
+ @test_obj.invalidate_string_attribute
79
+ expect(@test_obj.string_attribute).to eq(nil)
80
+ end
81
+
82
+ it "using .cache_attribute_name does not change the data" do
83
+ expect(@test_obj.string_attribute).to eq("original string")
84
+ @test_obj.cache_string_attribute
85
+ expect(@test_obj.string_attribute).to eq("original string")
86
+ end
87
+ end
88
+
89
+ # SAVED OBJECT TESTS
90
+ context "objects persisted in the database" do
91
+ before(:each) do
92
+ @test_obj = IncludeClass.new
93
+ @test_obj.string_attribute = "original string"
94
+ @test_obj.save
95
+ expect(@test_obj.new_record?).to eq(false)
96
+ expect(@test_obj.persisted?).to eq(true)
97
+ end
98
+
99
+ it "persists a cache invalidation" do
100
+ expect(@test_obj.string_attribute).to eq("original string")
101
+ @test_obj.invalidate_string_attribute
102
+ expect(@test_obj.string_attribute).to eq(nil)
103
+ @compare_obj = IncludeClass.last
104
+ expect(@compare_obj.id).to eq(@test_obj.id)
105
+ expect(@compare_obj.string_attribute).to eq(nil)
106
+ end
107
+
108
+ it "persists a cache update" do
109
+ expect(@test_obj.string_attribute).to eq("original string")
110
+ @test_obj.string_attribute = "new string"
111
+ @test_obj.cache_string_attribute
112
+ expect(@test_obj.string_attribute).to eq("new string")
113
+
114
+ @compare_obj = IncludeClass.last
115
+ expect(@compare_obj.id).to eq(@test_obj.id)
116
+ expect(@compare_obj.string_attribute).to eq("new string")
117
+ end
118
+
119
+ it "does not persist cache invalidation with other changes" do
120
+ expect(@test_obj.string_attribute).to eq("original string")
121
+ @test_obj.integer_attribute = 1337
122
+ @test_obj.invalidate_string_attribute
123
+ expect(@test_obj.string_attribute).to eq(nil)
124
+ @compare_obj = IncludeClass.last
125
+ expect(@compare_obj.id).to eq(@test_obj.id)
126
+ expect(@compare_obj.string_attribute).to eq("original string")
127
+ expect(@compare_obj.integer_attribute).to eq(nil)
128
+ end
129
+
130
+ it "does not persist cache updates with other changes" do
131
+ expect(@test_obj.string_attribute).to eq("original string")
132
+ @test_obj.string_attribute = "new string"
133
+ @test_obj.integer_attribute = 1337
134
+ @test_obj.cache_string_attribute
135
+ expect(@test_obj.string_attribute).to eq("new string")
136
+
137
+ @compare_obj = IncludeClass.last
138
+ expect(@compare_obj.id).to eq(@test_obj.id)
139
+ expect(@compare_obj.string_attribute).to eq("original string")
140
+ expect(@compare_obj.integer_attribute).to eq(nil)
141
+ end
142
+ end
143
+
144
+ end
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: database_cached_attribute
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Charles Smith
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-04 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: 4.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 4.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: activerecord
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '3.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '3.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activesupport
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '3.1'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '3.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
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: sqlite3
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
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: temping
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Provides simple methods on an ActiveRecord model using an ActiveRecord
112
+ concern to invalidate/save single_column caches.
113
+ email:
114
+ - twohlix@gmail.com
115
+ executables: []
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - lib/database_cached_attribute.rb
120
+ - lib/tasks/database_cached_attribute_tasks.rake
121
+ - lib/database_cached_attribute/version.rb
122
+ - LICENSE
123
+ - Rakefile
124
+ - README.md
125
+ - Gemfile
126
+ - spec/database_cached_attribute_spec.rb
127
+ - .travis.yml
128
+ homepage: http://github.com/twohlix/database_cached_attribute/
129
+ licenses:
130
+ - MIT
131
+ metadata: {}
132
+ post_install_message:
133
+ rdoc_options: []
134
+ require_paths:
135
+ - lib
136
+ required_ruby_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - '>='
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ required_rubygems_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ requirements: []
147
+ rubyforge_project:
148
+ rubygems_version: 2.0.3
149
+ signing_key:
150
+ specification_version: 4
151
+ summary: ActiveRecord Concern to make db caching on ActiveRecord Models simpler
152
+ test_files:
153
+ - spec/database_cached_attribute_spec.rb
154
+ - .travis.yml