dm-is-self_referential 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
6
+ .bundle
7
+ *.gem
8
+
data/Gemfile ADDED
@@ -0,0 +1,145 @@
1
+ # If you're working on more than one datamapper gem at a time, then it's
2
+ # recommended to create a local Gemfile and use this instead of the git
3
+ # sources. This will make sure that you are developing against your
4
+ # other local datamapper sources that you currently work on. Gemfile.local
5
+ # will behave identically to the standard Gemfile apart from the fact that
6
+ # it fetches the datamapper gems from local paths. This means that you can use
7
+ # the same environment variables, like ADAPTER(S) or PLUGIN(S) when running
8
+ # bundle commands. Gemfile.local is added to .gitignore, so you don't need to
9
+ # worry about accidentally checking local development paths into git.
10
+ # In order to create a local Gemfile, all you need to do is run:
11
+ #
12
+ # bundle exec rake local_gemfile
13
+ #
14
+ # This will give you a Gemfile.local file that points to your local clones of
15
+ # the various datamapper gems. It's assumed that all datamapper repo clones
16
+ # reside in the same directory. You can use the Gemfile.local like so for
17
+ # running any bundle command:
18
+ #
19
+ # BUNDLE_GEMFILE=Gemfile.local bundle foo
20
+ #
21
+ # You can also specify which adapter(s) should be part of the bundle by setting
22
+ # an environment variable. This of course also works when using the Gemfile.local
23
+ #
24
+ # bundle foo # dm-sqlite-adapter
25
+ # ADAPTER=mysql bundle foo # dm-mysql-adapter
26
+ # ADAPTERS=sqlite,mysql bundle foo # dm-sqlite-adapter and dm-mysql-adapter
27
+ #
28
+ # Of course you can also use the ADAPTER(S) variable when using the Gemfile.local
29
+ # and running specs against selected adapters.
30
+ #
31
+ # For easily working with adapters supported on your machine, it's recommended
32
+ # that you first install all adapters that you are planning to use or work on
33
+ # by doing something like
34
+ #
35
+ # ADAPTERS=sqlite,mysql,postgres bundle install
36
+ #
37
+ # This will clone the various repositories and make them available to bundler.
38
+ # Once you have them installed you can easily switch between adapters for the
39
+ # various development tasks. Running something like
40
+ #
41
+ # ADAPTER=mysql bundle exec rake spec
42
+ #
43
+ # will make sure that the dm-mysql-adapter is part of the bundle, and will be used
44
+ # when running the specs.
45
+ #
46
+ # You can also specify which plugin(s) should be part of the bundle by setting
47
+ # an environment variable. This also works when using the Gemfile.local
48
+ #
49
+ # bundle foo # dm-migrations
50
+ # PLUGINS=dm-validations bundle foo # dm-migrations and dm-validations
51
+ # PLUGINS=dm-validations,dm-types bundle foo # dm-migrations, dm-validations and dm-types
52
+ #
53
+ # Of course you can combine the PLUGIN(S) and ADAPTER(S) env vars to run specs
54
+ # for certain adapter/plugin combinations.
55
+ #
56
+ # Finally, to speed up running specs and other tasks, it's recommended to run
57
+ #
58
+ # bundle lock
59
+ #
60
+ # after running 'bundle install' for the first time. This will make 'bundle exec' run
61
+ # a lot faster compared to the unlocked version. With an unlocked bundle you would
62
+ # typically just run 'bundle install' from time to time to fetch the latest sources from
63
+ # upstream. When you locked your bundle, you need to run
64
+ #
65
+ # bundle install --relock
66
+ #
67
+ # to make sure to fetch the latest updates and then lock the bundle again. Gemfile.lock
68
+ # is added to the .gitignore file, so you don't need to worry about accidentally checking
69
+ # it into version control.
70
+
71
+ source 'http://rubygems.org'
72
+
73
+ DATAMAPPER = 'git://github.com/datamapper'
74
+ DM_VERSION = '~> 1.0.0.rc1'
75
+
76
+
77
+ group :runtime do # Runtime dependencies (as in the gemspec)
78
+
79
+ if ENV['EXTLIB']
80
+ gem 'extlib', '~> 0.9.15', :git => "#{DATAMAPPER}/extlib.git"
81
+ else
82
+ gem 'activesupport', '~> 3.0.0.beta3', :git => 'git://github.com/rails/rails.git', :require => nil
83
+ end
84
+
85
+ gem 'dm-core', DM_VERSION, :git => "#{DATAMAPPER}/dm-core.git"
86
+
87
+ end
88
+
89
+ group(:development) do # Development dependencies (as in the gemspec)
90
+
91
+ gem 'dm-validations', DM_VERSION, :git => "#{DATAMAPPER}/dm-validations.git"
92
+
93
+ gem 'rake', '~> 0.8.7'
94
+ gem 'rspec', '~> 1.3'
95
+ gem 'jeweler', '~> 1.4'
96
+
97
+ end
98
+
99
+ group :quality do # These gems contain rake tasks that check the quality of the source code
100
+
101
+ gem 'metric_fu', '~> 1.3'
102
+ gem 'rcov', '~> 0.9.7'
103
+ gem 'reek', '~> 1.2.7'
104
+ gem 'roodi', '~> 2.1'
105
+ gem 'yard', '~> 0.5'
106
+ gem 'yardstick', '~> 0.1'
107
+
108
+
109
+ end
110
+
111
+ group :datamapper do # We need this because we want to pin these dependencies to their git master sources
112
+
113
+ adapters = ENV['ADAPTER'] || ENV['ADAPTERS']
114
+ adapters = adapters.to_s.gsub(',',' ').split(' ') - ['in_memory']
115
+
116
+ unless adapters.empty?
117
+
118
+ DO_VERSION = '~> 0.10.2'
119
+ DM_DO_ADAPTERS = %w[sqlite postgres mysql oracle sqlserver]
120
+
121
+ gem 'data_objects', DO_VERSION, :git => "#{DATAMAPPER}/do.git"
122
+
123
+ adapters.each do |adapter|
124
+ if DM_DO_ADAPTERS.any? { |dm_do_adapter| dm_do_adapter =~ /#{adapter}/ }
125
+ adapter = 'sqlite3' if adapter == 'sqlite'
126
+ gem "do_#{adapter}", DO_VERSION, :git => "#{DATAMAPPER}/do.git"
127
+ end
128
+ end
129
+
130
+ gem 'dm-do-adapter', DM_VERSION, :git => "#{DATAMAPPER}/dm-do-adapter.git"
131
+
132
+ adapters.each do |adapter|
133
+ gem "dm-#{adapter}-adapter", DM_VERSION, :git => "#{DATAMAPPER}/dm-#{adapter}-adapter.git"
134
+ end
135
+
136
+ end
137
+
138
+ plugins = ENV['PLUGINS'] || ENV['PLUGIN']
139
+ plugins = (plugins.to_s.gsub(',',' ').split(' ') + ['dm-migrations']).uniq
140
+
141
+ plugins.each do |plugin|
142
+ gem plugin, DM_VERSION, :git => "#{DATAMAPPER}/#{plugin}.git"
143
+ end
144
+
145
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 snusnu
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.rdoc ADDED
@@ -0,0 +1,108 @@
1
+ = dm-is-self_referential
2
+
3
+ A datamapper[http://github.com/datamapper/dm-core] plugin that allows declarative specification of self referential m:m relationships.
4
+
5
+ == Examples
6
+
7
+ class User
8
+
9
+ include DataMapper::Resource
10
+
11
+ property :id, Serial
12
+ property :name, String, :nullable => false, :unique => true, :unique_index => true
13
+
14
+ # with default options
15
+ #
16
+ # will define and thus be able to automigrate the UserToUser model
17
+ # with the following relationships established between the participating models
18
+ #
19
+ # has n, :user_children, 'UserToUser', :child_key => [ :source_id ]
20
+ # has n, :user_parents, 'UserToUser', :child_key => [ :target_id ]
21
+ #
22
+ # once dm-core has full support for the following m:m relationships built in,
23
+ # these will also get established.
24
+ #
25
+ # has n, :children, self, :through => :user_children, :via => :target
26
+ # has n, :parents , self, :through => :user_parents, :via => :source
27
+ #
28
+ # In the meantime, the following helper methods get defined
29
+ #
30
+ # def children
31
+ # children_ids = self.user_children.map { |r| r.target_id }
32
+ # self.class.all(:id => children_ids)
33
+ # end
34
+ #
35
+ # def parents
36
+ # parent_ids = self.user_parents.map { |r| r.source_id }
37
+ # self.class.all(:id => parent_ids)
38
+ # end
39
+ #
40
+ is :self_referential
41
+
42
+
43
+ # With explicit intermediate model name and default options
44
+ #
45
+ # Will define and thus be able to automigrate the Friendship model
46
+ # with the following relationships established between the participating models
47
+ #
48
+ # has n, :user_children, 'Friendship', :child_key => [ :source_id ]
49
+ # has n, :user_parents, 'Friendship', :child_key => [ :target_id ]
50
+ #
51
+ # Once dm-core has full support for the following m:m relationships built in,
52
+ # these will also get established.
53
+ #
54
+ # has n, :children, self, :through => :user_children, :via => :target
55
+ # has n, :parents , self, :through => :user_parents, :via => :source
56
+ #
57
+ # In the meantime, the following helper methods get defined
58
+ #
59
+ # def children
60
+ # children_ids = self.user_children.map { |r| r.target_id }
61
+ # self.class.all(:id => children_ids)
62
+ # end
63
+ #
64
+ # def parents
65
+ # parent_ids = self.user_parents.map { |r| r.source_id }
66
+ # self.class.all(:id => parent_ids)
67
+ # end
68
+ #
69
+ is :self_referential, :through => 'Friendship'
70
+
71
+
72
+ # With explicit intermediate model name and customized options
73
+ #
74
+ # Will define and thus be able to automigrate the UserRelationship model
75
+ # with the following relationships established between the participating models
76
+ #
77
+ # has n, :user_children, 'UserRelationship', :child_key => [ :parent_user_id ]
78
+ # has n, :user_parents, 'UserRelationship', :child_key => [ :child_user_id ]
79
+ #
80
+ # Once dm-core has full support for the following m:m relationships built in,
81
+ # these will also get established.
82
+ #
83
+ # has n, :child_users, User, :through => :user_children, :via => :child_user
84
+ # has n, :parent_users, User, :through => :user_parents, :via => :parent_user
85
+ #
86
+ # In the meantime, the following helper methods get defined
87
+ #
88
+ # def child_users
89
+ # children_ids = self.user_children.map { |r| r.target_id }
90
+ # self.class.all(:id => children_ids)
91
+ # end
92
+ #
93
+ # def parent_users
94
+ # parent_ids = self.user_parents.map { |r| r.source_id }
95
+ # self.class.all(:id => parent_ids)
96
+ # end
97
+ #
98
+ is :self_referential, :through => 'UserRelationship',
99
+ :children => :child_users,
100
+ :parents => :parent_users,
101
+ :source => :parent_user,
102
+ :target => :child_user
103
+
104
+ end
105
+
106
+ == Copyright
107
+
108
+ Copyright (c) 2009 Martin Gamsjaeger (snusnu). See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,26 @@
1
+ require 'rake'
2
+
3
+ begin
4
+
5
+ require 'jeweler'
6
+
7
+ Jeweler::Tasks.new do |gem|
8
+ gem.name = 'dm-is-self_referential'
9
+ gem.summary = 'Declaratively specify self referential m:m relationships in datamapper models'
10
+ gem.description = gem.summary
11
+ gem.email = 'gamsnjaga@gmail.com'
12
+ gem.homepage = 'http://github.com/snusnu/dm-is-self_referential'
13
+ gem.authors = [ "Martin Gamsjaeger (snusnu)" ]
14
+
15
+ gem.add_dependency 'dm-core', '~> 1.0.0.rc1'
16
+
17
+ gem.add_development_dependency 'rspec', '~> 1.3'
18
+ gem.add_development_dependency 'yard', '~> 0.5'
19
+ end
20
+
21
+ Jeweler::GemcutterTasks.new
22
+
23
+ FileList['tasks/**/*.rake'].each { |task| import task }
24
+ rescue LoadError
25
+ puts 'Jeweler (or a dependency) not available. Install it with: gem install jeweler'
26
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0.rc1
@@ -0,0 +1,69 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{dm-is-self_referential}
8
+ s.version = "1.0.0.rc1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Martin Gamsjaeger (snusnu)"]
12
+ s.date = %q{2010-05-19}
13
+ s.description = %q{Declaratively specify self referential m:m relationships in datamapper models}
14
+ s.email = %q{gamsnjaga@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "Gemfile",
23
+ "LICENSE",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "dm-is-self_referential.gemspec",
28
+ "lib/dm-is-self_referential.rb",
29
+ "spec/dm-is-self_referential_spec.rb",
30
+ "spec/rcov.opts",
31
+ "spec/spec.opts",
32
+ "spec/spec_helper.rb",
33
+ "tasks/ci.rake",
34
+ "tasks/local_gemfile.rake",
35
+ "tasks/metrics.rake",
36
+ "tasks/spec.rake",
37
+ "tasks/yard.rake",
38
+ "tasks/yardstick.rake"
39
+ ]
40
+ s.homepage = %q{http://github.com/snusnu/dm-is-self_referential}
41
+ s.rdoc_options = ["--charset=UTF-8"]
42
+ s.require_paths = ["lib"]
43
+ s.rubygems_version = %q{1.3.7}
44
+ s.summary = %q{Declaratively specify self referential m:m relationships in datamapper models}
45
+ s.test_files = [
46
+ "spec/dm-is-self_referential_spec.rb",
47
+ "spec/spec_helper.rb"
48
+ ]
49
+
50
+ if s.respond_to? :specification_version then
51
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
52
+ s.specification_version = 3
53
+
54
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
55
+ s.add_runtime_dependency(%q<dm-core>, ["~> 1.0.0.rc1"])
56
+ s.add_development_dependency(%q<rspec>, ["~> 1.3"])
57
+ s.add_development_dependency(%q<yard>, ["~> 0.5"])
58
+ else
59
+ s.add_dependency(%q<dm-core>, ["~> 1.0.0.rc1"])
60
+ s.add_dependency(%q<rspec>, ["~> 1.3"])
61
+ s.add_dependency(%q<yard>, ["~> 0.5"])
62
+ end
63
+ else
64
+ s.add_dependency(%q<dm-core>, ["~> 1.0.0.rc1"])
65
+ s.add_dependency(%q<rspec>, ["~> 1.3"])
66
+ s.add_dependency(%q<yard>, ["~> 0.5"])
67
+ end
68
+ end
69
+
@@ -0,0 +1,57 @@
1
+ require 'dm-core'
2
+
3
+ module DataMapper
4
+ module Is
5
+
6
+ module SelfReferential
7
+
8
+ def is_self_referential(options = {})
9
+ # Given 'Nested::Module::ClassName'
10
+ # deepest_context = Nested::Module::
11
+ # self_model_name = ClassName
12
+ # ---
13
+ # Given 'ClassName'
14
+ # deepest_context = "::"
15
+ # self_model_name = ClassName
16
+ deepest_context, self_model_name = (self.name =~ /^(.*::)(.*)$/) ? [$1, $2] : ["::", self.name]
17
+ sane_self_model_name = ActiveSupport::Inflector.underscore(self.name.gsub(/::/, ""))
18
+
19
+ options = {
20
+ :through => "#{deepest_context}#{self_model_name}To#{self_model_name}",
21
+ :children => :children,
22
+ :parents => :parents,
23
+ :source => :source,
24
+ :target => :target
25
+ }.merge!(options)
26
+
27
+ Object.full_const_set(options[:through], Class.new)
28
+
29
+ source_model = self
30
+ intermediate_model = Object.full_const_get(options[:through])
31
+ target_model = self
32
+
33
+ source_fk = ActiveSupport::Inflector.foreign_key(options[:source]).to_sym
34
+ target_fk = ActiveSupport::Inflector.foreign_key(options[:target]).to_sym
35
+
36
+ intermediate_model.class_eval do
37
+ include DataMapper::Resource
38
+ belongs_to options[:source], source_model, :key => true
39
+ belongs_to options[:target], target_model, :key => true
40
+ end
41
+
42
+ intermediate_children = "#{sane_self_model_name}_#{options[:children]}".to_sym
43
+ intermediate_parents = "#{sane_self_model_name}_#{options[:parents ]}".to_sym
44
+
45
+ has n, intermediate_children, intermediate_model, :child_key => [ source_fk ]
46
+ has n, intermediate_parents, intermediate_model, :child_key => [ target_fk ]
47
+
48
+ has n, options[:children], self, :through => intermediate_children, :via => :target
49
+ has n, options[:parents ], self, :through => intermediate_parents, :via => :source
50
+
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+ Model.append_extensions(Is::SelfReferential)
57
+ end
@@ -0,0 +1,258 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ class Object
4
+
5
+ def full_const_defined?(name)
6
+ !!full_const_get(name) rescue false
7
+ end
8
+
9
+ end
10
+
11
+ module RemixableHelper
12
+
13
+ def clear_remixed_models(*models)
14
+ models.each do |model|
15
+ deepest_context, removable_const = (model =~ /^(.*::)(.*)$/) ? [$1, $2] : ["Object", model]
16
+
17
+ if Object.full_const_defined?(model)
18
+ if Object.full_const_defined?(deepest_context)
19
+ deepest_context = Object.full_const_get(deepest_context)
20
+ deepest_context.send(:remove_const, removable_const)
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ alias :clear_remixed_model :clear_remixed_models
27
+
28
+ end
29
+
30
+ class User
31
+
32
+ include DataMapper::Resource
33
+
34
+ property :id, Serial
35
+ property :name, String, :required => true, :unique => true, :unique_index => true
36
+
37
+ end
38
+
39
+ module Main
40
+ class Group
41
+ include DataMapper::Resource
42
+
43
+ property :id, Serial
44
+ property :name, String, :required => true
45
+ end
46
+
47
+ class GroupHeritage
48
+ include DataMapper::Resource
49
+
50
+ property :parent_group_id, Integer, :key => true
51
+ property :child_group_id, Integer, :key => true
52
+ end
53
+ end
54
+
55
+ describe 'every self referential m:m relationship', :shared => true do
56
+
57
+ it "should establish a 1:m relationship to the intermediate model" do
58
+ relationship = @model.relationships(:default)[@intermediate_name]
59
+ relationship.is_a?(DataMapper::Associations::OneToMany::Relationship).should be_true
60
+ end
61
+
62
+ it "should establish a m:m relationship to the target model" do
63
+ relationship = @model.relationships(:default)[@target_name]
64
+ relationship.is_a?(DataMapper::Associations::ManyToMany::Relationship).should be_true
65
+ end
66
+
67
+
68
+ it "should establish a method to retrieve children for an individual parent" do
69
+ @source_instance.respond_to?(@children_accessor).should be_true
70
+ end
71
+
72
+ it "should establish a method to retrieve parents for an individual child" do
73
+ @source_instance.respond_to?(@parents_accessor).should be_true
74
+ end
75
+
76
+
77
+ it "should return a DataMapper::Collection when calling the children accessor" do
78
+ @source_instance.send(@children_accessor).is_a?(DataMapper::Collection).should be_true
79
+ end
80
+
81
+ it "should return a DataMapper::Collection when calling the parents accessor" do
82
+ @source_instance.send(@parents_accessor).is_a?(DataMapper::Collection).should be_true
83
+ end
84
+
85
+ it "should be able to return all children" do
86
+ pending_if 'M:M operations are not supported in_memory and on yaml', !SUPPORTS_M2M do
87
+ @child_1 = @model.create(:name => 'Bars')
88
+ @child_2 = @model.create(:name => 'Lisichka')
89
+ @intermediate_model.create(@intermediate_source => @source_instance, @intermediate_target => @child_1)
90
+ @intermediate_model.create(@intermediate_source => @source_instance, @intermediate_target => @child_2)
91
+ @source_instance.send(@children_accessor).size.should == 2
92
+ end
93
+ end
94
+
95
+ it "should be able to return all parents" do
96
+ pending_if 'M:M operations are not supported in_memory and on yaml', !SUPPORTS_M2M do
97
+ @parent_1 = @model.create(:name => 'Belka')
98
+ @parent_2 = @model.create(:name => 'Strelka')
99
+ @intermediate_model.create(@intermediate_target => @source_instance, @intermediate_source => @parent_1)
100
+ @intermediate_model.create(@intermediate_target => @source_instance, @intermediate_source => @parent_2)
101
+ @source_instance.send(@parents_accessor).size.should == 2
102
+ end
103
+ end
104
+
105
+ end
106
+
107
+ describe DataMapper::Is::SelfReferential do
108
+
109
+ include RemixableHelper
110
+
111
+ describe "with default options" do
112
+
113
+ before(:each) do
114
+
115
+ clear_remixed_models 'UserToUser'
116
+
117
+ User.is :self_referential
118
+ DataMapper.auto_migrate!
119
+
120
+ @model = User
121
+ @intermediate_model = UserToUser # implicitly test intermediate model generation
122
+ @intermediate_source = :source
123
+ @intermediate_target = :target
124
+ @children_accessor = :children
125
+ @parents_accessor = :parents
126
+
127
+ @intermediate_name = "user_#{@children_accessor}".to_sym
128
+ @target_name = @children_accessor
129
+
130
+ @source_instance = User.create(:name => 'Laika')
131
+
132
+ end
133
+
134
+ it_should_behave_like 'every self referential m:m relationship'
135
+
136
+ end
137
+
138
+ describe "with explict intermediate model name and default options" do
139
+
140
+ before(:each) do
141
+
142
+ clear_remixed_models 'Friendship'
143
+
144
+ User.is :self_referential, :through => 'Friendship'
145
+ DataMapper.auto_migrate!
146
+
147
+ @model = User
148
+ @intermediate_model = Friendship # implicitly test intermediate model generation
149
+ @intermediate_source = :source
150
+ @intermediate_target = :target
151
+ @children_accessor = :children
152
+ @parents_accessor = :parents
153
+
154
+ @intermediate_name = "user_#{@children_accessor}".to_sym
155
+ @target_name = @children_accessor
156
+
157
+ @source_instance = User.create(:name => 'Laika')
158
+
159
+ end
160
+
161
+ it_should_behave_like 'every self referential m:m relationship'
162
+
163
+ end
164
+
165
+ describe "with explict intermediate model name and customized options" do
166
+
167
+ before(:each) do
168
+
169
+ clear_remixed_models 'UserRelationship'
170
+
171
+ User.is :self_referential, :through => 'UserRelationship',
172
+ :children => :child_users,
173
+ :parents => :parent_users,
174
+ :source => :parent_user,
175
+ :target => :child_user
176
+
177
+ DataMapper.auto_migrate!
178
+
179
+ @model = User
180
+ @intermediate_model = UserRelationship # implicitly test intermediate model generation
181
+ @intermediate_source = :parent_user
182
+ @intermediate_target = :child_user
183
+ @children_accessor = :child_users
184
+ @parents_accessor = :parent_users
185
+
186
+ @intermediate_name = "user_#{@children_accessor}".to_sym
187
+ @target_name = @children_accessor
188
+
189
+ @source_instance = User.create(:name => 'Laika')
190
+
191
+ end
192
+
193
+ it_should_behave_like 'every self referential m:m relationship'
194
+
195
+ end
196
+
197
+ describe "with default options for nested model" do
198
+
199
+ before(:each) do
200
+
201
+ clear_remixed_models 'Main::GroupToGroup'
202
+
203
+ Main::Group.is :self_referential
204
+ DataMapper.auto_migrate!
205
+
206
+ @model = Main::Group
207
+ @intermediate_model = Main::GroupToGroup # implicitly test intermediate model generation
208
+ @intermediate_source = :source
209
+ @intermediate_target = :target
210
+ @children_accessor = :children
211
+ @parents_accessor = :parents
212
+
213
+ @intermediate_name = "main_group_#{@children_accessor}".to_sym
214
+ @target_name = @children_accessor
215
+
216
+ @source_instance = Main::Group.create(:name => 'Laika')
217
+
218
+ end
219
+
220
+ it_should_behave_like 'every self referential m:m relationship'
221
+
222
+ end
223
+
224
+
225
+ describe "with explict intermediate nested model name and customized options" do
226
+
227
+ before(:each) do
228
+
229
+ clear_remixed_models 'Main::GroupHeritage'
230
+
231
+ Main::Group.is :self_referential, :through => 'Main::GroupHeritage',
232
+ :children => :child_groups,
233
+ :parents => :parent_groups,
234
+ :source => :parent_group,
235
+ :target => :child_group
236
+
237
+ DataMapper.auto_migrate!
238
+
239
+ @model = Main::Group
240
+ @intermediate_model = Main::GroupHeritage # implicitly test intermediate model generation
241
+ @intermediate_source = :parent_group
242
+ @intermediate_target = :child_group
243
+ @children_accessor = :child_groups
244
+ @parents_accessor = :parent_groups
245
+
246
+ @intermediate_name = "main_group_#{@children_accessor}".to_sym
247
+ @target_name = @children_accessor
248
+
249
+ @source_instance = Main::Group.create(:name => 'Laika')
250
+
251
+ end
252
+
253
+ it_should_behave_like 'every self referential m:m relationship'
254
+
255
+ end
256
+
257
+
258
+ end
data/spec/rcov.opts ADDED
@@ -0,0 +1,6 @@
1
+ --exclude "spec"
2
+ --sort coverage
3
+ --callsites
4
+ --xrefs
5
+ --profile
6
+ --text-summary
data/spec/spec.opts ADDED
@@ -0,0 +1,2 @@
1
+ --format specdoc
2
+ --colour
@@ -0,0 +1,16 @@
1
+ require 'dm-core/spec/setup'
2
+ require 'dm-core/spec/lib/adapter_helpers'
3
+ require 'dm-core/spec/lib/pending_helpers'
4
+
5
+ require 'dm-is-self_referential'
6
+ require 'dm-migrations'
7
+ require 'dm-validations'
8
+
9
+ DataMapper::Spec.setup
10
+
11
+ SUPPORTS_M2M = %w[sqlite postgres mysql oracle sqlserver].include?(DataMapper::Spec.adapter_name)
12
+
13
+ Spec::Runner.configure do |config|
14
+ config.extend(DataMapper::Spec::Adapters::Helpers)
15
+ config.include(DataMapper::Spec::PendingHelpers)
16
+ end
data/tasks/ci.rake ADDED
@@ -0,0 +1 @@
1
+ task :ci => [ :verify_measurements, 'metrics:all' ]
@@ -0,0 +1,18 @@
1
+ desc "Support bundling from local source code (allows BUNDLE_GEMFILE=Gemfile.local bundle foo)"
2
+ task :local_gemfile do |t|
3
+
4
+ root = Pathname(__FILE__).dirname.parent
5
+ datamapper = root.parent
6
+
7
+ source_regex = /DATAMAPPER = 'git:\/\/github.com\/datamapper'/
8
+ gem_source_regex = /:git => \"#\{DATAMAPPER\}\/(.+?)(?:\.git)?\"/
9
+
10
+ root.join('Gemfile.local').open('w') do |f|
11
+ root.join('Gemfile').open.each do |line|
12
+ line.sub!(source_regex, "DATAMAPPER = '#{datamapper}'")
13
+ line.sub!(gem_source_regex, ':path => "#{DATAMAPPER}/\1"')
14
+ f.puts line
15
+ end
16
+ end
17
+
18
+ end
@@ -0,0 +1,36 @@
1
+ begin
2
+ require 'metric_fu'
3
+ rescue LoadError
4
+ namespace :metrics do
5
+ task :all do
6
+ abort 'metric_fu is not available. In order to run metrics:all, you must: gem install metric_fu'
7
+ end
8
+ end
9
+ end
10
+
11
+ begin
12
+ require 'reek/adapters/rake_task'
13
+
14
+ Reek::RakeTask.new do |t|
15
+ t.fail_on_error = true
16
+ t.verbose = false
17
+ t.source_files = 'lib/**/*.rb'
18
+ end
19
+ rescue LoadError
20
+ task :reek do
21
+ abort 'Reek is not available. In order to run reek, you must: gem install reek'
22
+ end
23
+ end
24
+
25
+ begin
26
+ require 'roodi'
27
+ require 'roodi_task'
28
+
29
+ RoodiTask.new do |t|
30
+ t.verbose = false
31
+ end
32
+ rescue LoadError
33
+ task :roodi do
34
+ abort 'Roodi is not available. In order to run roodi, you must: gem install roodi'
35
+ end
36
+ end
data/tasks/spec.rake ADDED
@@ -0,0 +1,38 @@
1
+ spec_defaults = lambda do |spec|
2
+ spec.pattern = 'spec/**/*_spec.rb'
3
+ spec.libs << 'lib' << 'spec'
4
+ spec.spec_opts << '--options' << 'spec/spec.opts'
5
+ end
6
+
7
+ begin
8
+ require 'spec/rake/spectask'
9
+
10
+ Spec::Rake::SpecTask.new(:spec, &spec_defaults)
11
+ rescue LoadError
12
+ task :spec do
13
+ abort 'rspec is not available. In order to run spec, you must: gem install rspec'
14
+ end
15
+ end
16
+
17
+ begin
18
+ require 'rcov'
19
+ require 'spec/rake/verify_rcov'
20
+
21
+ Spec::Rake::SpecTask.new(:rcov) do |rcov|
22
+ spec_defaults.call(rcov)
23
+ rcov.rcov = true
24
+ rcov.rcov_opts = File.read('spec/rcov.opts').split(/\s+/)
25
+ end
26
+
27
+ RCov::VerifyTask.new(:verify_rcov => :rcov) do |rcov|
28
+ rcov.threshold = 100
29
+ end
30
+ rescue LoadError
31
+ %w[ rcov verify_rcov ].each do |name|
32
+ task name do
33
+ abort "rcov is not available. In order to run #{name}, you must: gem install rcov"
34
+ end
35
+ end
36
+ end
37
+
38
+ task :default => :spec
data/tasks/yard.rake ADDED
@@ -0,0 +1,9 @@
1
+ begin
2
+ require 'yard'
3
+
4
+ YARD::Rake::YardocTask.new
5
+ rescue LoadError
6
+ task :yard do
7
+ abort 'YARD is not available. In order to run yard, you must: gem install yard'
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ begin
2
+ require 'pathname'
3
+ require 'yardstick/rake/measurement'
4
+ require 'yardstick/rake/verify'
5
+
6
+ # yardstick_measure task
7
+ Yardstick::Rake::Measurement.new
8
+
9
+ # verify_measurements task
10
+ Yardstick::Rake::Verify.new do |verify|
11
+ verify.threshold = 100
12
+ end
13
+ rescue LoadError
14
+ %w[ yardstick_measure verify_measurements ].each do |name|
15
+ task name.to_s do
16
+ abort "Yardstick is not available. In order to run #{name}, you must: gem install yardstick"
17
+ end
18
+ end
19
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dm-is-self_referential
3
+ version: !ruby/object:Gem::Version
4
+ hash: 977940574
5
+ prerelease: true
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ - rc1
11
+ version: 1.0.0.rc1
12
+ platform: ruby
13
+ authors:
14
+ - Martin Gamsjaeger (snusnu)
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2010-05-19 00:00:00 +02:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: dm-core
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ hash: 977940574
31
+ segments:
32
+ - 1
33
+ - 0
34
+ - 0
35
+ - rc1
36
+ version: 1.0.0.rc1
37
+ type: :runtime
38
+ version_requirements: *id001
39
+ - !ruby/object:Gem::Dependency
40
+ name: rspec
41
+ prerelease: false
42
+ requirement: &id002 !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ hash: 9
48
+ segments:
49
+ - 1
50
+ - 3
51
+ version: "1.3"
52
+ type: :development
53
+ version_requirements: *id002
54
+ - !ruby/object:Gem::Dependency
55
+ name: yard
56
+ prerelease: false
57
+ requirement: &id003 !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ hash: 1
63
+ segments:
64
+ - 0
65
+ - 5
66
+ version: "0.5"
67
+ type: :development
68
+ version_requirements: *id003
69
+ description: Declaratively specify self referential m:m relationships in datamapper models
70
+ email: gamsnjaga@gmail.com
71
+ executables: []
72
+
73
+ extensions: []
74
+
75
+ extra_rdoc_files:
76
+ - LICENSE
77
+ - README.rdoc
78
+ files:
79
+ - .document
80
+ - .gitignore
81
+ - Gemfile
82
+ - LICENSE
83
+ - README.rdoc
84
+ - Rakefile
85
+ - VERSION
86
+ - dm-is-self_referential.gemspec
87
+ - lib/dm-is-self_referential.rb
88
+ - spec/dm-is-self_referential_spec.rb
89
+ - spec/rcov.opts
90
+ - spec/spec.opts
91
+ - spec/spec_helper.rb
92
+ - tasks/ci.rake
93
+ - tasks/local_gemfile.rake
94
+ - tasks/metrics.rake
95
+ - tasks/spec.rake
96
+ - tasks/yard.rake
97
+ - tasks/yardstick.rake
98
+ has_rdoc: true
99
+ homepage: http://github.com/snusnu/dm-is-self_referential
100
+ licenses: []
101
+
102
+ post_install_message:
103
+ rdoc_options:
104
+ - --charset=UTF-8
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ hash: 3
113
+ segments:
114
+ - 0
115
+ version: "0"
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ">"
120
+ - !ruby/object:Gem::Version
121
+ hash: 25
122
+ segments:
123
+ - 1
124
+ - 3
125
+ - 1
126
+ version: 1.3.1
127
+ requirements: []
128
+
129
+ rubyforge_project:
130
+ rubygems_version: 1.3.7
131
+ signing_key:
132
+ specification_version: 3
133
+ summary: Declaratively specify self referential m:m relationships in datamapper models
134
+ test_files:
135
+ - spec/dm-is-self_referential_spec.rb
136
+ - spec/spec_helper.rb