dm-is-self_referential 1.0.0.rc1

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.
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