dm-polymorphic 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README +51 -0
- data/Rakefile +60 -0
- data/TODO +0 -0
- data/lib/associations.rb +24 -0
- data/lib/dm-polymorphic.rb +46 -0
- data/lib/tester.rb +50 -0
- data/lib/types.rb +7 -0
- data/spec/dm-polymorphic_spec.rb +121 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +31 -0
- metadata +76 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Daniel Neighman
|
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
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
Please see wiki for discussion.
|
2
|
+
|
3
|
+
The DM polymorphic gem mimics AR style polymorphism. It has been decided that DM will not follow this path, since it
|
4
|
+
really isn't very nice on the DB and there are other ways, that do not require DBA to cry to achieve the same result.
|
5
|
+
|
6
|
+
That being said this is still useful for those ppl wishing to convert rails apps over.
|
7
|
+
|
8
|
+
One Massive Caveat is that using this you will get n+1 calls to the db atm if you do Comments#commentable for example. It needs a proxy object if anyone cares to write one.
|
9
|
+
|
10
|
+
This is highly experimental software, use it at your own risk.
|
11
|
+
|
12
|
+
==== Example Usage.
|
13
|
+
|
14
|
+
class Comment
|
15
|
+
include DataMapper::Resource
|
16
|
+
|
17
|
+
is :polymorphic, :commentable
|
18
|
+
|
19
|
+
property :id, Integer, :serial => true
|
20
|
+
property :text, String
|
21
|
+
end
|
22
|
+
|
23
|
+
class Post
|
24
|
+
include DataMapper::Resource
|
25
|
+
|
26
|
+
property :id, Integer, :serial => true
|
27
|
+
property :name, String
|
28
|
+
|
29
|
+
has n, :comments, :polymorphically => :commentable
|
30
|
+
end
|
31
|
+
|
32
|
+
class Article
|
33
|
+
include DataMapper::Resource
|
34
|
+
|
35
|
+
property :id, Integer, :serial => true
|
36
|
+
property :name, String
|
37
|
+
|
38
|
+
has n, :comments, :polymorphically => :commentable
|
39
|
+
end
|
40
|
+
|
41
|
+
This will then provide the following methods
|
42
|
+
|
43
|
+
Comment#commentable
|
44
|
+
Comment#post
|
45
|
+
Comment#article
|
46
|
+
Post#comments
|
47
|
+
Article#comments
|
48
|
+
|
49
|
+
What is needed is a
|
50
|
+
Comment.commentables or something method so there is a nice proxy to avoid having all the loading issues.
|
51
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "spec"
|
3
|
+
require "rake/clean"
|
4
|
+
require "rake/gempackagetask"
|
5
|
+
require "spec/rake/spectask"
|
6
|
+
require "pathname"
|
7
|
+
|
8
|
+
CLEAN.include "{log,pkg}/"
|
9
|
+
|
10
|
+
spec = Gem::Specification.new do |s|
|
11
|
+
s.name = "dm-polymorphic"
|
12
|
+
s.version = "0.10.0"
|
13
|
+
s.platform = Gem::Platform::RUBY
|
14
|
+
s.has_rdoc = true
|
15
|
+
s.extra_rdoc_files = %w[ README LICENSE TODO ]
|
16
|
+
s.summary = "DataMapper plugin enabling simple ActiveRecord style polymorphism"
|
17
|
+
s.description = s.summary
|
18
|
+
s.author = "Daniel Neighman, Wayne E. Seguin, Ripta Pasay"
|
19
|
+
s.email = "has.sox@gmail.com, wayneeseguin@gmail.com, github@r8y.org"
|
20
|
+
s.homepage = "http://github.com/hassox/dm-polymorphic"
|
21
|
+
s.require_path = "lib"
|
22
|
+
s.files = FileList[ "{lib,spec}/**/*.rb", "spec/spec.opts", "Rakefile", *s.extra_rdoc_files ]
|
23
|
+
s.add_dependency("dm-core", ">=#{s.version}")
|
24
|
+
end
|
25
|
+
|
26
|
+
task :default => [ :spec ]
|
27
|
+
|
28
|
+
WIN32 = (RUBY_PLATFORM =~ /win32|mingw|cygwin/) rescue nil
|
29
|
+
SUDO = WIN32 ? "" : ("sudo" unless ENV["SUDOLESS"])
|
30
|
+
|
31
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
32
|
+
pkg.gem_spec = spec
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Install #{spec.name} #{spec.version} (default ruby)"
|
36
|
+
task :install => [ :package ] do
|
37
|
+
sh "#{SUDO} gem install pkg/#{spec.name}-#{spec.version} --no-update-sources", :verbose => false
|
38
|
+
end
|
39
|
+
|
40
|
+
namespace :jruby do
|
41
|
+
desc "Install #{spec.name} #{spec.version} with JRuby"
|
42
|
+
task :install => [ :package ] do
|
43
|
+
sh %{#{SUDO} jruby -S gem install --local pkg/#{spec.name}-#{spec.version} --no-update-sources}, :verbose => false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
desc "Run specifications"
|
48
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
49
|
+
t.spec_opts << "--options" << "spec/spec.opts" if File.exists?("spec/spec.opts")
|
50
|
+
t.spec_files = Pathname.glob(Pathname.new(__FILE__).dirname + "spec/**/*_spec.rb")
|
51
|
+
|
52
|
+
begin
|
53
|
+
t.rcov = ENV.has_key?("NO_RCOV") ? ENV["NO_RCOV"] != "true" : true
|
54
|
+
t.rcov_opts << "--exclude" << "spec"
|
55
|
+
t.rcov_opts << "--text-summary"
|
56
|
+
t.rcov_opts << "--sort" << "coverage" << "--sort-reverse"
|
57
|
+
rescue Exception
|
58
|
+
# rcov not installed
|
59
|
+
end
|
60
|
+
end
|
data/TODO
ADDED
File without changes
|
data/lib/associations.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Model
|
3
|
+
module Relationship
|
4
|
+
|
5
|
+
alias_method :has_without_polymorphism, :has
|
6
|
+
|
7
|
+
def has(cardinality, name, opts = {})
|
8
|
+
if interface = opts.delete(:polymorphically)
|
9
|
+
# get the child model
|
10
|
+
child_model_name = opts.fetch(:class_name, Extlib::Inflection.classify(name))
|
11
|
+
child_klass = Extlib::Inflection.constantize(child_model_name)
|
12
|
+
belongs_to_name = Extlib::Inflection.underscore(Extlib::Inflection.demodulize(self.name))
|
13
|
+
|
14
|
+
# Setup the has with the right stuff
|
15
|
+
has_without_polymorphism cardinality, name, :child_key => [:"#{interface}_id"], :"#{interface}_class" => self
|
16
|
+
child_klass.belongs_to :"#{belongs_to_name}", :child_key => [:"#{interface}_id"], :"#{interface}_class" => self
|
17
|
+
else
|
18
|
+
has_without_polymorphism(cardinality, name, opts)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "pathname"
|
3
|
+
|
4
|
+
gem "dm-core", ">=0.10.0"
|
5
|
+
require "dm-core"
|
6
|
+
|
7
|
+
|
8
|
+
module DataMapper
|
9
|
+
module Is
|
10
|
+
module Polymorphic
|
11
|
+
|
12
|
+
def is_polymorphic(name, id_type=String)
|
13
|
+
self.class_eval <<-EOS, __FILE__, __LINE__
|
14
|
+
property :"#{name}_class", Klass
|
15
|
+
property :"#{name}_id", #{id_type}
|
16
|
+
|
17
|
+
def #{name}
|
18
|
+
return nil if self.#{name}_class.nil? || self.#{name}_class == NilClass
|
19
|
+
return nil if self.#{name}_id.nil?
|
20
|
+
if (self.#{name}_class.class == Class)
|
21
|
+
self.#{name}_class.get(self.#{name}_id)
|
22
|
+
else
|
23
|
+
klass = Kernel.const_get(self.#{name}_class.to_s)
|
24
|
+
if klass.ancestors.include? DataMapper::Resource
|
25
|
+
klass.get(self.#{name}_id)
|
26
|
+
else
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def #{name}=(entity)
|
33
|
+
self.#{name}_class = entity.class
|
34
|
+
self.#{name}_id = entity.id
|
35
|
+
end
|
36
|
+
EOS
|
37
|
+
end
|
38
|
+
|
39
|
+
end # Polymophic
|
40
|
+
end # Is
|
41
|
+
end
|
42
|
+
|
43
|
+
DataMapper::Model.append_extensions DataMapper::Is::Polymorphic
|
44
|
+
|
45
|
+
require Pathname(__FILE__).dirname.expand_path / "associations.rb"
|
46
|
+
require Pathname(__FILE__).dirname.expand_path / "types.rb"
|
data/lib/tester.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "dm-polymorphic")
|
2
|
+
|
3
|
+
DataMapper::Logger.new(STDOUT, :debug)
|
4
|
+
DataMapper.setup(:default, 'sqlite3::memory:')
|
5
|
+
|
6
|
+
class Comment
|
7
|
+
include DataMapper::Resource
|
8
|
+
|
9
|
+
is :polymorphic, :commentable
|
10
|
+
|
11
|
+
property :id, Integer, :serial => true
|
12
|
+
property :text, String
|
13
|
+
end
|
14
|
+
|
15
|
+
class Post
|
16
|
+
include DataMapper::Resource
|
17
|
+
|
18
|
+
property :id, Integer, :serial => true
|
19
|
+
property :name, String
|
20
|
+
|
21
|
+
has n, :comments, :polymorphically => :commentable
|
22
|
+
end
|
23
|
+
|
24
|
+
class Article
|
25
|
+
include DataMapper::Resource
|
26
|
+
|
27
|
+
property :id, Integer, :serial => true
|
28
|
+
property :name, String
|
29
|
+
|
30
|
+
has n, :comments, :polymorphically => :commentable
|
31
|
+
end
|
32
|
+
|
33
|
+
Comment.auto_migrate!
|
34
|
+
Post.auto_migrate!
|
35
|
+
Article.auto_migrate!
|
36
|
+
|
37
|
+
post1 = Post.create(:name => "post1")
|
38
|
+
article1 = Article.create(:name => "article1")
|
39
|
+
post2 = Post.create(:name => "post2")
|
40
|
+
article2 = Article.create(:name => "article2")
|
41
|
+
|
42
|
+
%w(one two three four five six seven eight nine ten).each_with_index do |text, index|
|
43
|
+
[post1, post2, article1, article2].each do |item|
|
44
|
+
item.comments << Comment.new(:text => text)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
Comment.all.each do |c|
|
49
|
+
puts "COMMENT: #{c.text} - #{c.commentable}"
|
50
|
+
end
|
data/lib/types.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/spec_helper"
|
2
|
+
|
3
|
+
DataMapper::Logger.new(STDOUT, :debug)
|
4
|
+
|
5
|
+
if HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
|
6
|
+
describe "DataMapper::Polymorphic" do
|
7
|
+
|
8
|
+
class Comment
|
9
|
+
include DataMapper::Resource
|
10
|
+
|
11
|
+
is :polymorphic, :commentable
|
12
|
+
|
13
|
+
property :id, Serial
|
14
|
+
property :text, String
|
15
|
+
end
|
16
|
+
|
17
|
+
class Post
|
18
|
+
include DataMapper::Resource
|
19
|
+
|
20
|
+
property :id, Serial
|
21
|
+
property :name, String
|
22
|
+
|
23
|
+
has n, :comments, :polymorphically => :commentable
|
24
|
+
end
|
25
|
+
|
26
|
+
class Article
|
27
|
+
include DataMapper::Resource
|
28
|
+
|
29
|
+
property :id, Serial
|
30
|
+
property :name, String
|
31
|
+
|
32
|
+
has n, :comments, :polymorphically => :commentable
|
33
|
+
end
|
34
|
+
|
35
|
+
before :each do
|
36
|
+
Comment.auto_migrate!
|
37
|
+
Post.auto_migrate!
|
38
|
+
Article.auto_migrate!
|
39
|
+
end
|
40
|
+
|
41
|
+
[Article, Post].each do |klass|
|
42
|
+
it "should create an associated object for #{klass}" do
|
43
|
+
item = klass.create(:name => "item1")
|
44
|
+
item.reload
|
45
|
+
item.comments.create(:text => "A Comment")
|
46
|
+
item.reload
|
47
|
+
item.comments(:text => "A Comment").should have(1).item
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should add the comment with the << syntax for #{klass}" do
|
51
|
+
item = klass.create(:name => "item2")
|
52
|
+
c = Comment.new(:text => "comment2")
|
53
|
+
item.comments << c
|
54
|
+
c.save
|
55
|
+
item.reload
|
56
|
+
item.comments(:text => "comment2").should have(1).item
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should not add the comment with the << syntax for #{klass} if comment was not saved" do
|
60
|
+
item = klass.create(:name => "item2a")
|
61
|
+
c = Comment.new(:text => "comment2a")
|
62
|
+
item.comments << c
|
63
|
+
item.reload
|
64
|
+
item.comments(:text => "comment2a").should have(0).item
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should access all the comments from the post for #{klass}" do
|
68
|
+
item = klass.create(:name => "item3")
|
69
|
+
c1 = Comment.new(:text => "comment3")
|
70
|
+
c2 = Comment.new(:text => "comment4")
|
71
|
+
[c1,c2].each{|c| item.comments << c}
|
72
|
+
item.comments.save
|
73
|
+
item.reload
|
74
|
+
item.comments.should have(2).items
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should access the post from the comment for #{klass}" do
|
78
|
+
item = klass.create(:name => "item4")
|
79
|
+
c = Comment.new(:text => "comment5")
|
80
|
+
item.comments << c
|
81
|
+
item.save
|
82
|
+
c.send(Extlib::Inflection.underscore(klass.name).to_sym).should == item
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should access the commentable from the comment for #{klass}" do
|
86
|
+
item = klass.create(:name => "item5")
|
87
|
+
c = Comment.new(:text => "comment6")
|
88
|
+
item.comments << c
|
89
|
+
c.save
|
90
|
+
item.reload; c.reload
|
91
|
+
c.commentable.should == item
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# it "should only make one query to each Model" do
|
96
|
+
# post1 = Post.create(:name => "post1")
|
97
|
+
# article1 = Article.create(:name => "article1")
|
98
|
+
# post2 = Post.create(:name => "post2")
|
99
|
+
# article2 = Article.create(:name => "article2")
|
100
|
+
#
|
101
|
+
# %w(one two three four five six seven eight nine ten).each_with_index do |text, index|
|
102
|
+
# [post1, post2, article1, article2].each do |item|
|
103
|
+
# item.comments.create(:text => text)
|
104
|
+
# end
|
105
|
+
# end
|
106
|
+
#
|
107
|
+
# Post.all.each do |c|
|
108
|
+
# puts "COMMENT: #{c.text} - #{c.commentable_class}"
|
109
|
+
# end
|
110
|
+
#
|
111
|
+
# Post.should_receive(:all).once
|
112
|
+
# Article.should_receive(:all).once.and_return(Article.comments)
|
113
|
+
#
|
114
|
+
# Comment.all.each do |comment|
|
115
|
+
# [Post, Article].should include(comment.commentable.class)
|
116
|
+
# end
|
117
|
+
# end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "pathname"
|
3
|
+
|
4
|
+
gem "dm-core", ">=0.10.0"
|
5
|
+
require "dm-core"
|
6
|
+
|
7
|
+
spec_dir_path = Pathname(__FILE__).dirname.expand_path
|
8
|
+
require spec_dir_path.parent + "lib/dm-polymorphic"
|
9
|
+
|
10
|
+
def load_driver(name, default_uri)
|
11
|
+
return false if ENV["ADAPTER"] != name.to_s
|
12
|
+
|
13
|
+
lib = "do_#{name}"
|
14
|
+
|
15
|
+
begin
|
16
|
+
gem lib, ">=0.10.0"
|
17
|
+
require lib
|
18
|
+
DataMapper.setup(name, ENV["#{name.to_s.upcase}_SPEC_URI"] || default_uri)
|
19
|
+
DataMapper::Repository.adapters[:default] = DataMapper::Repository.adapters[name]
|
20
|
+
true
|
21
|
+
rescue Gem::LoadError => e
|
22
|
+
warn "Could not load #{lib}: #{e}"
|
23
|
+
false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
ENV["ADAPTER"] ||= "sqlite3"
|
28
|
+
|
29
|
+
HAS_SQLITE3 = load_driver(:sqlite3, "sqlite3::memory:")
|
30
|
+
HAS_MYSQL = load_driver(:mysql, "mysql://localhost/dm_core_test")
|
31
|
+
HAS_POSTGRES = load_driver(:postgres, "postgres://postgres@localhost/dm_core_test")
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dm-polymorphic
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.10.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daniel Neighman, Wayne E. Seguin, Ripta Pasay
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-03 00:00:00 -04: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.10.0
|
24
|
+
version:
|
25
|
+
description: DataMapper plugin enabling simple ActiveRecord style polymorphism
|
26
|
+
email: has.sox@gmail.com, wayneeseguin@gmail.com, github@r8y.org
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- README
|
33
|
+
- LICENSE
|
34
|
+
- TODO
|
35
|
+
files:
|
36
|
+
- lib/associations.rb
|
37
|
+
- lib/dm-polymorphic.rb
|
38
|
+
- lib/tester.rb
|
39
|
+
- lib/types.rb
|
40
|
+
- spec/dm-polymorphic_spec.rb
|
41
|
+
- spec/spec_helper.rb
|
42
|
+
- spec/spec.opts
|
43
|
+
- Rakefile
|
44
|
+
- README
|
45
|
+
- LICENSE
|
46
|
+
- TODO
|
47
|
+
has_rdoc: true
|
48
|
+
homepage: http://github.com/hassox/dm-polymorphic
|
49
|
+
licenses: []
|
50
|
+
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
version:
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: "0"
|
67
|
+
version:
|
68
|
+
requirements: []
|
69
|
+
|
70
|
+
rubyforge_project:
|
71
|
+
rubygems_version: 1.3.2
|
72
|
+
signing_key:
|
73
|
+
specification_version: 3
|
74
|
+
summary: DataMapper plugin enabling simple ActiveRecord style polymorphism
|
75
|
+
test_files: []
|
76
|
+
|