ramdiv-mongo_mapper_acts_as_tree 0.0.0
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 +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +46 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/lib/mongo_mapper_acts_as_tree.rb +177 -0
- data/ramdiv-mongo_mapper_acts_as_tree.gemspec +63 -0
- data/test/helper.rb +32 -0
- data/test/models/category.rb +11 -0
- data/test/models/ordered_category.rb +12 -0
- data/test/test_order.rb +28 -0
- data/test/test_tree.rb +139 -0
- metadata +91 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Jakob Vidmar
|
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,46 @@
|
|
1
|
+
= mongo_mapper-acts_as_tree
|
2
|
+
|
3
|
+
This is an implementation of a tree structure for MongoMapper.
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
Install as gem
|
8
|
+
|
9
|
+
gem install ramdiv-mongo_mapper_acts_as_tree
|
10
|
+
|
11
|
+
== Usage
|
12
|
+
|
13
|
+
Enable the tree functionality by declaring acts_as_tree on your model
|
14
|
+
|
15
|
+
class Category
|
16
|
+
include MongoMapper::Document
|
17
|
+
include MongoMapper::Acts::Tree
|
18
|
+
|
19
|
+
key :name, String
|
20
|
+
|
21
|
+
acts_as_tree
|
22
|
+
end
|
23
|
+
|
24
|
+
The method accepts :parent_id_field, :path_field, :depth_field, :order as a hash.
|
25
|
+
|
26
|
+
:parent_id_field, :path_field, :depth_field => override the default field names
|
27
|
+
:order => control the order (format "_field-name_ _[asc|desc]_")
|
28
|
+
|
29
|
+
Check the test_tree.rb for examples.
|
30
|
+
|
31
|
+
== !WARNING!
|
32
|
+
|
33
|
+
This is not production-ready code. Bugs are to be expected.
|
34
|
+
== Note on Patches/Pull Requests
|
35
|
+
|
36
|
+
* Fork the project.
|
37
|
+
* Make your feature addition or bug fix.
|
38
|
+
* Add tests for it. This is important so I don't break it in a
|
39
|
+
future version unintentionally.
|
40
|
+
* Commit, do not mess with rakefile, version, or history.
|
41
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
42
|
+
* Send me a pull request. Bonus points for topic branches.
|
43
|
+
|
44
|
+
== Copyright
|
45
|
+
|
46
|
+
Copyright (c) 2009 Jakob Vidmar. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "ramdiv-mongo_mapper_acts_as_tree"
|
8
|
+
gem.summary = %Q{ActsAsTree plugin for MongoMapper}
|
9
|
+
gem.description = %Q{Port of the old, venerable ActsAsTree with a bit of a twist}
|
10
|
+
gem.email = "jakob.vidmar@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/ramdiv/mongo_mapper_acts_as_tree"
|
12
|
+
gem.authors = ["Jakob Vidmar"]
|
13
|
+
gem.add_dependency("mongo_mapper", ">= 0.6.8")
|
14
|
+
|
15
|
+
gem.add_development_dependency "shoulda", ">=2.10.2"
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'rake/testtask'
|
23
|
+
Rake::TestTask.new(:test) do |test|
|
24
|
+
test.libs << 'lib' << 'test'
|
25
|
+
test.pattern = 'test/**/test_*.rb'
|
26
|
+
test.verbose = true
|
27
|
+
end
|
28
|
+
|
29
|
+
begin
|
30
|
+
require 'rcov/rcovtask'
|
31
|
+
Rcov::RcovTask.new do |test|
|
32
|
+
test.libs << 'test'
|
33
|
+
test.pattern = 'test/**/test_*.rb'
|
34
|
+
test.verbose = true
|
35
|
+
end
|
36
|
+
rescue LoadError
|
37
|
+
task :rcov do
|
38
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
task :test => :check_dependencies
|
43
|
+
|
44
|
+
task :default => :test
|
45
|
+
|
46
|
+
require 'rake/rdoctask'
|
47
|
+
Rake::RDocTask.new do |rdoc|
|
48
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
49
|
+
|
50
|
+
rdoc.rdoc_dir = 'rdoc'
|
51
|
+
rdoc.title = "mongo_mapper_acts_as_tree #{version}"
|
52
|
+
rdoc.rdoc_files.include('README*')
|
53
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
54
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require "mongo_mapper"
|
2
|
+
|
3
|
+
module MongoMapper
|
4
|
+
module Acts
|
5
|
+
module Tree
|
6
|
+
def self.included(model)
|
7
|
+
model.class_eval do
|
8
|
+
extend InitializerMethods
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module InitializerMethods
|
13
|
+
def acts_as_tree(options = {})
|
14
|
+
options = {
|
15
|
+
:parent_id_field => "parent_id",
|
16
|
+
:path_field => "path",
|
17
|
+
:depth_field => "depth"
|
18
|
+
}.merge(options)
|
19
|
+
|
20
|
+
write_inheritable_attribute :acts_as_tree_options, options
|
21
|
+
class_inheritable_reader :acts_as_tree_options
|
22
|
+
|
23
|
+
include InstanceMethods
|
24
|
+
include Fields
|
25
|
+
extend Fields
|
26
|
+
extend ClassMethods
|
27
|
+
|
28
|
+
key parent_id_field, String
|
29
|
+
key path_field, String, :default => ""
|
30
|
+
key depth_field, Integer, :default => 0
|
31
|
+
|
32
|
+
after_save :move_children
|
33
|
+
before_save :will_save_tree
|
34
|
+
# before_destroy :destroy_descendants
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module ClassMethods
|
39
|
+
def roots
|
40
|
+
self.find(:all, :conditions => {parent_id_field => nil}, :order => tree_order)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
module InstanceMethods
|
45
|
+
def ==(other)
|
46
|
+
return true if other.equal?(self)
|
47
|
+
return true if other.instance_of?(self.class) and other._id == self._id
|
48
|
+
false
|
49
|
+
end
|
50
|
+
|
51
|
+
def parent=(var)
|
52
|
+
var = self.find(var) if var.is_a? String
|
53
|
+
|
54
|
+
if self.descendents.include? var
|
55
|
+
@_cyclic = true
|
56
|
+
else
|
57
|
+
@_parent = var
|
58
|
+
fix_position
|
59
|
+
@_will_move = true
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def will_save_tree
|
64
|
+
!@_cyclic
|
65
|
+
end
|
66
|
+
|
67
|
+
def fix_position
|
68
|
+
if parent.nil?
|
69
|
+
self[parent_id_field] = nil
|
70
|
+
self[path_field] = ""
|
71
|
+
self[depth_field] = 0
|
72
|
+
else
|
73
|
+
self[parent_id_field] = parent.id
|
74
|
+
self[path_field] = parent[path_field] + ":" + parent.id.to_s
|
75
|
+
self[depth_field] = parent[depth_field] + 1
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def parent
|
80
|
+
@_parent or (self[parent_id_field] ? self.class.find(self[parent_id_field]) : nil)
|
81
|
+
end
|
82
|
+
|
83
|
+
def root?
|
84
|
+
self[parent_id_field].nil?
|
85
|
+
end
|
86
|
+
|
87
|
+
def root
|
88
|
+
self.class.find(self[path_field].split(":")[1]) or self
|
89
|
+
end
|
90
|
+
|
91
|
+
def ancestors
|
92
|
+
return [] if root?
|
93
|
+
self.class.find(self[path_field].split(":")[1..-1].collect{|i| Mongo::ObjectID.from_string(i)})
|
94
|
+
end
|
95
|
+
|
96
|
+
def self_and_ancestors
|
97
|
+
ancestors << self
|
98
|
+
end
|
99
|
+
|
100
|
+
def siblings
|
101
|
+
self.class.find(:all, :conditions => {:_id => {"$ne" => self._id}, parent_id_field => self[parent_id_field]}, :order => tree_order)
|
102
|
+
end
|
103
|
+
|
104
|
+
def self_and_siblings
|
105
|
+
self.class.find(:all, :conditions => {parent_id_field => self[parent_id_field]}, :order => tree_order)
|
106
|
+
end
|
107
|
+
|
108
|
+
def children
|
109
|
+
self.class.find(:all, :conditions => {parent_id_field => self._id.to_s}, :order => tree_order)
|
110
|
+
end
|
111
|
+
|
112
|
+
def descendents
|
113
|
+
return [] if new_record?
|
114
|
+
sorting_options = tree_order.split(",").map(&:strip).map(&:split).map{|item| [item[0], ((item[1].nil? or item[1].downcase == "asc") ? "asc" : "desc")]}.flatten
|
115
|
+
self.class.collection.find({path_field => /#{self._id}/}, {:sort => sorting_options}).map{|i| self.class.new(i)} or []
|
116
|
+
end
|
117
|
+
|
118
|
+
def self_and_descendents
|
119
|
+
[self] + self.descendents
|
120
|
+
end
|
121
|
+
|
122
|
+
def is_ancestor_of?(other)
|
123
|
+
!(other[path_field] =~ /#{self._id}/).nil?
|
124
|
+
end
|
125
|
+
|
126
|
+
def is_or_is_ancestor_of?(other)
|
127
|
+
(other == self) or is_ancestor_of?(other)
|
128
|
+
end
|
129
|
+
|
130
|
+
def is_descendant_of?(other)
|
131
|
+
!(self[path_field] =~ /#{other._id}/).nil?
|
132
|
+
end
|
133
|
+
|
134
|
+
def is_or_is_descendant_of?(other)
|
135
|
+
(other == self) or is_descendant_of?(other)
|
136
|
+
end
|
137
|
+
|
138
|
+
def is_sibling_of?(other)
|
139
|
+
(other != self) and (other[parent_id_field] == self[parent_id_field])
|
140
|
+
end
|
141
|
+
|
142
|
+
def is_or_is_sibling_of?(other)
|
143
|
+
(other == self) or is_sibling_of?(other)
|
144
|
+
end
|
145
|
+
|
146
|
+
def move_children
|
147
|
+
if @_will_move
|
148
|
+
@_will_move = false
|
149
|
+
for child in self.children
|
150
|
+
child.fix_position
|
151
|
+
child.save
|
152
|
+
end
|
153
|
+
@_will_move = true
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
module Fields
|
159
|
+
def parent_id_field
|
160
|
+
acts_as_tree_options[:parent_id_field]
|
161
|
+
end
|
162
|
+
|
163
|
+
def path_field
|
164
|
+
acts_as_tree_options[:path_field]
|
165
|
+
end
|
166
|
+
|
167
|
+
def depth_field
|
168
|
+
acts_as_tree_options[:depth_field]
|
169
|
+
end
|
170
|
+
|
171
|
+
def tree_order
|
172
|
+
acts_as_tree_options[:order] or ""
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,63 @@
|
|
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{ramdiv-mongo_mapper_acts_as_tree}
|
8
|
+
s.version = "0.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Jakob Vidmar"]
|
12
|
+
s.date = %q{2009-12-20}
|
13
|
+
s.description = %q{Port of the old, venerable ActsAsTree with a bit of a twist}
|
14
|
+
s.email = %q{jakob.vidmar@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"lib/mongo_mapper_acts_as_tree.rb",
|
27
|
+
"ramdiv-mongo_mapper_acts_as_tree.gemspec",
|
28
|
+
"test/helper.rb",
|
29
|
+
"test/models/category.rb",
|
30
|
+
"test/models/ordered_category.rb",
|
31
|
+
"test/test_order.rb",
|
32
|
+
"test/test_tree.rb"
|
33
|
+
]
|
34
|
+
s.homepage = %q{http://github.com/ramdiv/mongo_mapper_acts_as_tree}
|
35
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
36
|
+
s.require_paths = ["lib"]
|
37
|
+
s.rubygems_version = %q{1.3.5}
|
38
|
+
s.summary = %q{ActsAsTree plugin for MongoMapper}
|
39
|
+
s.test_files = [
|
40
|
+
"test/helper.rb",
|
41
|
+
"test/models/category.rb",
|
42
|
+
"test/models/ordered_category.rb",
|
43
|
+
"test/test_order.rb",
|
44
|
+
"test/test_tree.rb"
|
45
|
+
]
|
46
|
+
|
47
|
+
if s.respond_to? :specification_version then
|
48
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
49
|
+
s.specification_version = 3
|
50
|
+
|
51
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
52
|
+
s.add_runtime_dependency(%q<mongo_mapper>, [">= 0.6.8"])
|
53
|
+
s.add_development_dependency(%q<shoulda>, [">= 2.10.2"])
|
54
|
+
else
|
55
|
+
s.add_dependency(%q<mongo_mapper>, [">= 0.6.8"])
|
56
|
+
s.add_dependency(%q<shoulda>, [">= 2.10.2"])
|
57
|
+
end
|
58
|
+
else
|
59
|
+
s.add_dependency(%q<mongo_mapper>, [">= 0.6.8"])
|
60
|
+
s.add_dependency(%q<shoulda>, [">= 2.10.2"])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
data/test/helper.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'shoulda'
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
6
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
7
|
+
require 'mongo_mapper'
|
8
|
+
|
9
|
+
MongoMapper.database = "acts_as_tree-test"
|
10
|
+
|
11
|
+
Dir["#{File.dirname(__FILE__)}/models/*.rb"].each {|file| require file}
|
12
|
+
|
13
|
+
class Test::Unit::TestCase
|
14
|
+
# Drop all columns after each test case.
|
15
|
+
def teardown
|
16
|
+
MongoMapper.database.collections.each do |coll|
|
17
|
+
coll.remove
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Make sure that each test case has a teardown
|
22
|
+
# method to clear the db after each test.
|
23
|
+
def inherited(base)
|
24
|
+
base.define_method teardown do
|
25
|
+
super
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def eql_arrays?(first, second)
|
30
|
+
first.collect(&:_id).to_set == second.collect(&:_id).to_set
|
31
|
+
end
|
32
|
+
end
|
data/test/test_order.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
class TestMongomapperActsAsTree < Test::Unit::TestCase
|
5
|
+
context "Ordered tree" do
|
6
|
+
setup do
|
7
|
+
@root_1 = OrderedCategory.create(:name => "Root 1", :value => 2)
|
8
|
+
@child_1 = OrderedCategory.create(:name => "Child 1", :parent => @root_1, :value => 1)
|
9
|
+
@child_2 = OrderedCategory.create(:name => "Child 2", :parent => @root_1, :value => 9)
|
10
|
+
@child_2_1 = OrderedCategory.create(:name => "Child 2.1", :parent => @child_2, :value => 2)
|
11
|
+
@child_3 = OrderedCategory.create(:name => "Child 3", :parent => @root_1, :value => 5)
|
12
|
+
@root_2 = OrderedCategory.create(:name => "Root 2", :value => 1)
|
13
|
+
end
|
14
|
+
|
15
|
+
should "be in order" do
|
16
|
+
assert_equal OrderedCategory.roots, [@root_2, @root_1]
|
17
|
+
|
18
|
+
assert_equal @root_1.children, [@child_1, @child_3, @child_2]
|
19
|
+
|
20
|
+
assert_equal @root_1.descendents, [@child_1, @child_2_1, @child_3, @child_2]
|
21
|
+
assert_equal @root_1.self_and_descendents, [@root_1, @child_1, @child_2_1, @child_3, @child_2]
|
22
|
+
|
23
|
+
assert_equal @child_2.siblings, [@child_1, @child_3]
|
24
|
+
assert_equal @child_2.self_and_siblings, [@child_1, @child_3, @child_2]
|
25
|
+
assert_equal @root_1.self_and_siblings, [@root_2, @root_1]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/test/test_tree.rb
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
class TestMongomapperActsAsTree < Test::Unit::TestCase
|
5
|
+
context "Tree" do
|
6
|
+
setup do
|
7
|
+
@root_1 = Category.create(:name => "Root 1")
|
8
|
+
@child_1 = Category.create(:name => "Child 1", :parent => @root_1)
|
9
|
+
@child_2 = Category.create(:name => "Child 2", :parent => @root_1)
|
10
|
+
@child_2_1 = Category.create(:name => "Child 2.1", :parent => @child_2)
|
11
|
+
@child_3 = Category.create(:name => "Child 3", :parent => @root_1)
|
12
|
+
@root_2 = Category.create(:name => "Root 2")
|
13
|
+
end
|
14
|
+
|
15
|
+
should "have roots" do
|
16
|
+
assert eql_arrays?(Category.roots, [@root_1, @root_2])
|
17
|
+
end
|
18
|
+
|
19
|
+
context "node" do
|
20
|
+
should "have a root" do
|
21
|
+
assert_equal @root_1.root, @root_1
|
22
|
+
assert_not_equal @root_1.root, @root_2.root
|
23
|
+
assert_equal @root_1, @child_2_1.root
|
24
|
+
end
|
25
|
+
|
26
|
+
should "have ancestors" do
|
27
|
+
assert_equal @root_1.ancestors, []
|
28
|
+
assert_equal @child_2_1.ancestors, [@root_1, @child_2]
|
29
|
+
assert_equal @root_1.self_and_ancestors, [@root_1]
|
30
|
+
assert_equal @child_2_1.self_and_ancestors, [@root_1, @child_2, @child_2_1]
|
31
|
+
end
|
32
|
+
|
33
|
+
should "have siblings" do
|
34
|
+
assert eql_arrays?(@root_1.siblings, [@root_2])
|
35
|
+
assert eql_arrays?(@child_2.siblings, [@child_1, @child_3])
|
36
|
+
assert eql_arrays?(@child_2_1.siblings, [])
|
37
|
+
assert eql_arrays?(@root_1.self_and_siblings, [@root_1, @root_2])
|
38
|
+
assert eql_arrays?(@child_2.self_and_siblings, [@child_1, @child_2, @child_3])
|
39
|
+
assert eql_arrays?(@child_2_1.self_and_siblings, [@child_2_1])
|
40
|
+
end
|
41
|
+
|
42
|
+
should "set depth" do
|
43
|
+
assert_equal 0, @root_1.depth
|
44
|
+
assert_equal 1, @child_1.depth
|
45
|
+
assert_equal 2, @child_2_1.depth
|
46
|
+
end
|
47
|
+
|
48
|
+
should "have children" do
|
49
|
+
assert @child_2_1.children.empty?
|
50
|
+
assert eql_arrays?(@root_1.children, [@child_1, @child_2, @child_3])
|
51
|
+
end
|
52
|
+
|
53
|
+
should "have descendents" do
|
54
|
+
assert eql_arrays?(@root_1.descendents, [@child_1, @child_2, @child_3, @child_2_1])
|
55
|
+
assert eql_arrays?(@child_2.descendents, [@child_2_1])
|
56
|
+
assert @child_2_1.descendents.empty?
|
57
|
+
assert eql_arrays?(@root_1.self_and_descendents, [@root_1, @child_1, @child_2, @child_3, @child_2_1])
|
58
|
+
assert eql_arrays?(@child_2.self_and_descendents, [@child_2, @child_2_1])
|
59
|
+
assert eql_arrays?(@child_2_1.self_and_descendents, [@child_2_1])
|
60
|
+
end
|
61
|
+
|
62
|
+
should "be able to tell if ancestor" do
|
63
|
+
assert @root_1.is_ancestor_of?(@child_1)
|
64
|
+
assert !@root_2.is_ancestor_of?(@child_2_1)
|
65
|
+
assert !@child_2.is_ancestor_of?(@child_2)
|
66
|
+
|
67
|
+
assert @root_1.is_or_is_ancestor_of?(@child_1)
|
68
|
+
assert !@root_2.is_or_is_ancestor_of?(@child_2_1)
|
69
|
+
assert @child_2.is_or_is_ancestor_of?(@child_2)
|
70
|
+
end
|
71
|
+
|
72
|
+
should "be able to tell if descendent" do
|
73
|
+
assert !@root_1.is_descendant_of?(@child_1)
|
74
|
+
assert @child_1.is_descendant_of?(@root_1)
|
75
|
+
assert !@child_2.is_descendant_of?(@child_2)
|
76
|
+
|
77
|
+
assert !@root_1.is_or_is_descendant_of?(@child_1)
|
78
|
+
assert @child_1.is_or_is_descendant_of?(@root_1)
|
79
|
+
assert @child_2.is_or_is_descendant_of?(@child_2)
|
80
|
+
end
|
81
|
+
|
82
|
+
should "be able to tell if sibling" do
|
83
|
+
assert !@root_1.is_sibling_of?(@child_1)
|
84
|
+
assert !@child_1.is_sibling_of?(@child_1)
|
85
|
+
assert !@child_2.is_sibling_of?(@child_2)
|
86
|
+
|
87
|
+
assert !@root_1.is_or_is_sibling_of?(@child_1)
|
88
|
+
assert @child_1.is_or_is_sibling_of?(@child_2)
|
89
|
+
assert @child_2.is_or_is_sibling_of?(@child_2)
|
90
|
+
end
|
91
|
+
|
92
|
+
context "when moving" do
|
93
|
+
should "recalculate path and depth" do
|
94
|
+
@child_3.parent = @child_2
|
95
|
+
@child_3.save
|
96
|
+
|
97
|
+
assert @child_2.is_or_is_ancestor_of?(@child_3)
|
98
|
+
assert @child_3.is_or_is_descendant_of?(@child_2)
|
99
|
+
assert @child_2.children.include?(@child_3)
|
100
|
+
assert @child_2.descendents.include?(@child_3)
|
101
|
+
assert @child_2_1.is_or_is_sibling_of?(@child_3)
|
102
|
+
assert_equal 2, @child_3.depth
|
103
|
+
end
|
104
|
+
|
105
|
+
should "move children on save" do
|
106
|
+
@child_2.parent = @root_2
|
107
|
+
|
108
|
+
assert !@root_2.is_or_is_ancestor_of?(@child_2_1)
|
109
|
+
assert !@child_2_1.is_or_is_descendant_of?(@root_2)
|
110
|
+
assert !@root_2.descendents.include?(@child_2_1)
|
111
|
+
|
112
|
+
@child_2.save
|
113
|
+
@child_2_1.reload
|
114
|
+
|
115
|
+
assert @root_2.is_or_is_ancestor_of?(@child_2_1)
|
116
|
+
assert @child_2_1.is_or_is_descendant_of?(@root_2)
|
117
|
+
assert @root_2.descendents.include?(@child_2_1)
|
118
|
+
end
|
119
|
+
|
120
|
+
should "check agains cyclic graph" do
|
121
|
+
@root_1.parent = @child_2_1
|
122
|
+
assert !@root_1.save
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context "root node" do
|
128
|
+
should "not have a parent" do
|
129
|
+
assert_nil @root_1.parent
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context "child_node" do
|
134
|
+
should "have a parent" do
|
135
|
+
assert_equal @child_2, @child_2_1.parent
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ramdiv-mongo_mapper_acts_as_tree
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jakob Vidmar
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-20 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: mongo_mapper
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.6.8
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: shoulda
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.10.2
|
34
|
+
version:
|
35
|
+
description: Port of the old, venerable ActsAsTree with a bit of a twist
|
36
|
+
email: jakob.vidmar@gmail.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- LICENSE
|
43
|
+
- README.rdoc
|
44
|
+
files:
|
45
|
+
- .document
|
46
|
+
- .gitignore
|
47
|
+
- LICENSE
|
48
|
+
- README.rdoc
|
49
|
+
- Rakefile
|
50
|
+
- VERSION
|
51
|
+
- lib/mongo_mapper_acts_as_tree.rb
|
52
|
+
- ramdiv-mongo_mapper_acts_as_tree.gemspec
|
53
|
+
- test/helper.rb
|
54
|
+
- test/models/category.rb
|
55
|
+
- test/models/ordered_category.rb
|
56
|
+
- test/test_order.rb
|
57
|
+
- test/test_tree.rb
|
58
|
+
has_rdoc: true
|
59
|
+
homepage: http://github.com/ramdiv/mongo_mapper_acts_as_tree
|
60
|
+
licenses: []
|
61
|
+
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options:
|
64
|
+
- --charset=UTF-8
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: "0"
|
72
|
+
version:
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
version:
|
79
|
+
requirements: []
|
80
|
+
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.3.5
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: ActsAsTree plugin for MongoMapper
|
86
|
+
test_files:
|
87
|
+
- test/helper.rb
|
88
|
+
- test/models/category.rb
|
89
|
+
- test/models/ordered_category.rb
|
90
|
+
- test/test_order.rb
|
91
|
+
- test/test_tree.rb
|