dm-counter-cache 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ === 0.9.8 / 2008-12-07
2
+
3
+ * Initial commit
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Saimon Moore
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.
@@ -0,0 +1,13 @@
1
+ History.txt
2
+ LICENSE
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ TODO
7
+ lib/dm-counter-cache.rb
8
+ lib/dm-counter-cache/version.rb
9
+ spec/integration/dm-counter-cache_spec.rb
10
+ spec/spec.opts
11
+ spec/spec_helper.rb
12
+ tasks/install.rb
13
+ tasks/spec.rb
@@ -0,0 +1,23 @@
1
+ == README
2
+
3
+ DataMapper::CounterCacheable automates the dec/incrementing of association counter fields. This is
4
+ similar to counter caches in ActiveRecord.
5
+
6
+ Example:
7
+
8
+ class Post
9
+ include DataMapper::Resource
10
+
11
+ has n :comments
12
+
13
+ property :id, Integer, :serial => true
14
+ property :comments_count, Integer, :default => 0
15
+ end
16
+
17
+ class Comment
18
+ include DataMapper::Resource
19
+ include DataMapper::CounterCacheable
20
+
21
+ belongs_to :post, :counter_cache => true
22
+
23
+ end
@@ -0,0 +1,28 @@
1
+ require 'pathname'
2
+ require 'rubygems'
3
+ require 'hoe'
4
+
5
+ ROOT = Pathname(__FILE__).dirname.expand_path
6
+ JRUBY = RUBY_PLATFORM =~ /java/
7
+ WINDOWS = Gem.win_platform?
8
+ SUDO = (WINDOWS || JRUBY) ? '' : ('sudo' unless ENV['SUDOLESS'])
9
+
10
+ require ROOT + 'lib/dm-counter-cache/version'
11
+
12
+ AUTHOR = 'Saimon Moore'
13
+ EMAIL = 'saimonmoore [a] gmail [d] com'
14
+ GEM_NAME = 'dm-counter-cache'
15
+ GEM_VERSION = DataMapper::CounterCacheable::VERSION
16
+ GEM_DEPENDENCIES = [['dm-core', "~>#{GEM_VERSION}"]]
17
+ GEM_CLEAN = %w[ log pkg coverage ]
18
+ GEM_EXTRAS = { :has_rdoc => true, :extra_rdoc_files => %w[ README.txt LICENSE TODO History.txt ] }
19
+
20
+ PROJECT_NAME = 'datamapper'
21
+ PROJECT_URL = "http://github.com/saimonmoore/dm-counter-cache/tree/master/#{GEM_NAME}"
22
+ PROJECT_DESCRIPTION = PROJECT_SUMMARY = 'DataMapper plugin for for counter caches ala ActiveRecord'
23
+
24
+ [ ROOT, ROOT.parent ].each do |dir|
25
+ Pathname.glob(dir.join('tasks/**/*.rb').to_s).each { |f| require f }
26
+ end
27
+
28
+ require 'tasks/hoe'
data/TODO ADDED
File without changes
@@ -0,0 +1,92 @@
1
+ module DataMapper
2
+ # CounterCacheable allows you to transparently maintain counts on collection association of this model on the parent model.
3
+ # You can also specify a custom counter cache column by providing a column name instead of a true/false value
4
+ # to this option (e.g., :counter_cache => :my_custom_counter.)
5
+ module CounterCacheable
6
+
7
+ def self.included(klass)
8
+ DataMapper::Associations::ManyToOne.module_eval {
9
+ extend DataMapper::CounterCacheable::ClassMethods
10
+
11
+ (class << self; self; end).class_eval do
12
+ unless method_defined?(:setup_without_counter_caching)
13
+ alias_method :setup_without_counter_caching, :setup
14
+ alias_method :setup, :setup_with_counter_caching
15
+ end
16
+ end
17
+
18
+ }
19
+ end
20
+
21
+ module ClassMethods
22
+
23
+ def setup_with_counter_caching(name, model, options = {})
24
+ counter_cache_attribute = options.delete(:counter_cache)
25
+ relationship = setup_without_counter_caching(name, model, options)
26
+
27
+ if counter_cache_attribute
28
+ case counter_cache_attribute
29
+ when String, Symbol
30
+ counter_cache_attribute = counter_cache_attribute.to_s
31
+ else
32
+ counter_cache_attribute = "#{model.storage_name}_count".to_s
33
+ end
34
+
35
+ model.class_eval <<-EOS, __FILE__, __LINE__
36
+ unless method_defined?(:increment_counter_cache_for_#{name})
37
+ after :create, :increment_counter_cache_for_#{name}
38
+ after :destroy, :decrement_counter_cache_for_#{name}
39
+
40
+ def increment_counter_cache_for_#{name}
41
+ return unless ::#{relationship.parent_model}.properties.has_property?(:#{counter_cache_attribute})
42
+ if self.#{name} && self.class == #{model.name}
43
+ self.#{name}.update_attributes(:#{counter_cache_attribute} => self.#{name}.reload.#{counter_cache_attribute}.succ)
44
+ end
45
+ end
46
+
47
+ def decrement_counter_cache_for_#{name}
48
+ return unless ::#{relationship.parent_model}.properties.has_property?(:#{counter_cache_attribute})
49
+ if self.#{name} && self.class == #{model.name}
50
+ self.#{name}.update_attributes(:#{counter_cache_attribute} => self.#{name}.reload.#{counter_cache_attribute} - 1)
51
+ end
52
+ end
53
+ end
54
+
55
+ EOS
56
+ end
57
+
58
+ relationship
59
+ end
60
+
61
+ end # ClassMethods
62
+
63
+ end # CounterCacheable
64
+ end # DataMapper
65
+
66
+ if $0 == __FILE__
67
+ require 'rubygems'
68
+
69
+ gem 'dm-core', '~>0.9.8'
70
+ require 'dm-core'
71
+
72
+ FileUtils.touch(File.join(Dir.pwd, "migration_test.db"))
73
+ DataMapper.setup(:default, "sqlite3://#{Dir.pwd}/migration_test.db")
74
+
75
+ class Post
76
+ include DataMapper::Resource
77
+
78
+ property :id, Integer, :serial => true
79
+ has n, :comments
80
+ end
81
+ Post.auto_migrate!
82
+
83
+ class Comment
84
+ include DataMapper::Resource
85
+ include DataMapper::CounterCacheable
86
+
87
+ belongs_to :post, :counter_cache => true
88
+ end
89
+ Comments.auto_migrate!
90
+
91
+ Post.create.comments.create
92
+ end
@@ -0,0 +1,5 @@
1
+ module DataMapper
2
+ module CounterCacheable
3
+ VERSION = '0.9.8'
4
+ end
5
+ end
@@ -0,0 +1,87 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
+
4
+ describe DataMapper::CounterCacheable do
5
+ before :all do
6
+ class Post
7
+ include DataMapper::Resource
8
+
9
+ property :id, Integer, :serial => true
10
+ property :comments_count, Integer, :default => 0
11
+ has n, :comments
12
+ end
13
+
14
+ class Comment
15
+ include DataMapper::Resource
16
+ include DataMapper::CounterCacheable
17
+
18
+ property :id, Integer, :serial => true
19
+ belongs_to :post, :counter_cache => true
20
+
21
+ end
22
+
23
+ class User
24
+ include DataMapper::Resource
25
+
26
+ property :id, Integer, :serial => true
27
+ property :groups_count, Integer, :default => 0
28
+
29
+ has n, :group_memberships
30
+ has n, :groups, :through => :group_memberships, :class_name => "Group", :remote_name => :group, :parent_key => [:id], :child_key => [:user_id]
31
+ end
32
+
33
+ class Group
34
+ include DataMapper::Resource
35
+
36
+ property :id, Integer, :serial => true
37
+ property :members_count, Integer, :default => 0
38
+ has n, :group_memberships
39
+ has n, :members, :through => :group_memberships, :class_name => "User", :remote_name => :user, :parent_key => [:id], :child_key => [:group_id]
40
+ end
41
+
42
+ class GroupMembership
43
+ include DataMapper::Resource
44
+ include DataMapper::CounterCacheable
45
+
46
+ property :id, Serial
47
+
48
+ belongs_to :group, :counter_cache => :members_count
49
+ belongs_to :member, :class_name => "User", :child_key => [:user_id], :counter_cache => :groups_count
50
+ end
51
+
52
+ GroupMembership.auto_migrate!
53
+ User.auto_migrate!
54
+ Group.auto_migrate!
55
+ Comment.auto_migrate!
56
+ Post.auto_migrate!
57
+ end
58
+
59
+ before(:each) do
60
+ @post = Post.create
61
+ @user = User.create
62
+ @group = Group.create
63
+ end
64
+
65
+ it "should increment comments_count" do
66
+ @post.comments.create
67
+ @post.reload.comments_count.should == 1
68
+
69
+ @user.group_memberships.create(:group => @group)
70
+ @user.reload.groups_count.should == 1
71
+ @group.reload.members_count.should == 1
72
+ end
73
+
74
+ it "should decrement comments_count" do
75
+ comment1 = @post.comments.create
76
+ comment2 = @post.comments.create
77
+ comment2.destroy
78
+ @post.reload.comments_count.should == 1
79
+
80
+ gm1 = @user.group_memberships.create(:group => @group)
81
+ gm2 = @user.group_memberships.create(:group => @group)
82
+ gm2.destroy
83
+ @user.reload.groups_count.should == 1
84
+ @group.reload.members_count.should == 1
85
+ end
86
+
87
+ end
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,29 @@
1
+ require 'pathname'
2
+ require 'rubygems'
3
+
4
+ gem 'rspec', '~>1.1.11'
5
+ require 'spec'
6
+
7
+ gem 'dm-core', '~>0.9.8'
8
+ require 'dm-core'
9
+
10
+ require Pathname(__FILE__).dirname.parent.expand_path + 'lib/dm-counter-cache'
11
+
12
+ def load_driver(name, default_uri)
13
+ return false if ENV['ADAPTER'] != name.to_s
14
+
15
+ begin
16
+ DataMapper.setup(name, ENV["#{name.to_s.upcase}_SPEC_URI"] || default_uri)
17
+ DataMapper::Repository.adapters[:default] = DataMapper::Repository.adapters[name]
18
+ true
19
+ rescue LoadError => e
20
+ warn "Could not load do_#{name}: #{e}"
21
+ false
22
+ end
23
+ end
24
+
25
+ ENV['ADAPTER'] ||= 'sqlite3'
26
+
27
+ HAS_SQLITE3 = load_driver(:sqlite3, 'sqlite3::memory:')
28
+ HAS_MYSQL = load_driver(:mysql, 'mysql://localhost/dm_core_test')
29
+ HAS_POSTGRES = load_driver(:postgres, 'postgres://postgres@localhost/dm_core_test')
@@ -0,0 +1,13 @@
1
+ def sudo_gem(cmd)
2
+ sh "#{SUDO} #{RUBY} -S gem #{cmd}", :verbose => false
3
+ end
4
+
5
+ desc "Install #{GEM_NAME} #{GEM_VERSION}"
6
+ task :install => [ :package ] do
7
+ sudo_gem "install --local pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources"
8
+ end
9
+
10
+ desc "Uninstall #{GEM_NAME} #{GEM_VERSION}"
11
+ task :uninstall => [ :clobber ] do
12
+ sudo_gem "uninstall #{GEM_NAME} -v#{GEM_VERSION} -Ix"
13
+ end
@@ -0,0 +1,25 @@
1
+ begin
2
+ gem 'rspec', '~>1.1.11'
3
+ require 'spec'
4
+ require 'spec/rake/spectask'
5
+
6
+ task :default => [ :spec ]
7
+
8
+ desc 'Run specifications'
9
+ Spec::Rake::SpecTask.new(:spec) do |t|
10
+ t.spec_opts << '--options' << 'spec/spec.opts' if File.exists?('spec/spec.opts')
11
+ t.spec_files = Pathname.glob((ROOT + 'spec/**/*_spec.rb').to_s)
12
+
13
+ begin
14
+ gem 'rcov', '~>0.8'
15
+ t.rcov = JRUBY ? false : (ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true)
16
+ t.rcov_opts << '--exclude' << 'spec'
17
+ t.rcov_opts << '--text-summary'
18
+ t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
19
+ rescue LoadError
20
+ # rcov not installed
21
+ end
22
+ end
23
+ rescue LoadError
24
+ # rspec not installed
25
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dm-counter-cache
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.8
5
+ platform: ruby
6
+ authors:
7
+ - Saimon Moore
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-05 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: dm-core
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: 0.9.8
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: hoe
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.8.2
34
+ version:
35
+ description: DataMapper plugin for for counter caches ala ActiveRecord
36
+ email:
37
+ - saimonmoore [a] gmail [d] com
38
+ executables: []
39
+
40
+ extensions: []
41
+
42
+ extra_rdoc_files:
43
+ - README.txt
44
+ - LICENSE
45
+ - TODO
46
+ - History.txt
47
+ files:
48
+ - History.txt
49
+ - LICENSE
50
+ - Manifest.txt
51
+ - README.txt
52
+ - Rakefile
53
+ - TODO
54
+ - lib/dm-counter-cache.rb
55
+ - lib/dm-counter-cache/version.rb
56
+ - spec/integration/dm-counter-cache_spec.rb
57
+ - spec/spec.opts
58
+ - spec/spec_helper.rb
59
+ - tasks/install.rb
60
+ - tasks/spec.rb
61
+ has_rdoc: true
62
+ homepage: http://github.com/saimonmoore/dm-counter-cache/tree/master/dm-counter-cache
63
+ post_install_message:
64
+ rdoc_options:
65
+ - --main
66
+ - README.txt
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: "0"
74
+ version:
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: "0"
80
+ version:
81
+ requirements: []
82
+
83
+ rubyforge_project: datamapper
84
+ rubygems_version: 1.3.1
85
+ signing_key:
86
+ specification_version: 2
87
+ summary: DataMapper plugin for for counter caches ala ActiveRecord
88
+ test_files: []
89
+