mongo_mapper_tree 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Joel Junström, Oktavilla
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,44 @@
1
+ = mongo_mapper_tree
2
+
3
+ This is an modernized version of mongo_mapper_acts_as_tree (https://github.com/ramdiv/mongo_mapper_acts_as_tree)
4
+ In it's essence it's an implementation of a tree structure for MongoMapper, think acts as tree but for mongodb.
5
+
6
+
7
+ == Installation
8
+
9
+ Install as gem
10
+
11
+ gem install mongo_mapper_tree
12
+
13
+ == Usage
14
+
15
+ Enable the tree functionality by declaring acts_as_tree on your model
16
+
17
+ class Category
18
+ include MongoMapper::Document
19
+ plugin MongoMapper::Plugins::Tree
20
+
21
+ key :name, String
22
+ end
23
+
24
+ This adds class_attributes called parent_id_field, path_field, depth_field, tree_order and tree_search_class.
25
+
26
+ parent_id_field, path_field and depth_field overrides the default field names
27
+ tree_order controls the order (format :field_name.[asc|desc])
28
+ tree_search_class expects a Class that is a MongoMapper::Document to be used for search
29
+
30
+ Check test_tree.rb and test_search_class.rb for examples.
31
+
32
+ == Note on Patches/Pull Requests
33
+
34
+ * Fork the project.
35
+ * Make your feature addition or bug fix.
36
+ * Add tests for it. This is important so I don't break it in a
37
+ future version unintentionally.
38
+ * Commit, do not mess with rakefile, version, or history.
39
+ (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)
40
+ * Send me a pull request. Bonus points for topic branches.
41
+
42
+ == Copyright
43
+
44
+ Copyright (c) 2011 Joel Junström. See LICENSE for details.
data/lib/locale/en.yml ADDED
@@ -0,0 +1,5 @@
1
+ en:
2
+ mongo_mapper:
3
+ errors:
4
+ messages:
5
+ cyclic: "Can't be children of a descendant"
@@ -0,0 +1,160 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Tree
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ def roots
9
+ self.where(parent_id_field => nil).sort(tree_order).all
10
+ end
11
+ end
12
+
13
+ module InstanceMethods
14
+ def tree_search_class
15
+ self.class.tree_search_class
16
+ end
17
+
18
+ def will_save_tree
19
+ if parent && self.descendants.include?(parent)
20
+ errors.add(:base, :cyclic)
21
+ end
22
+ end
23
+
24
+ def fix_position(opts = {})
25
+ if parent.nil?
26
+ self[parent_id_field] = nil
27
+ self[path_field] = []
28
+ self[depth_field] = 0
29
+ elsif !!opts[:force] || self.changes.include?(parent_id_field)
30
+ @_will_move = true
31
+ self[path_field] = parent[path_field] + [parent._id]
32
+ self[depth_field] = parent[depth_field] + 1
33
+ end
34
+ end
35
+
36
+ def fix_position!
37
+ fix_position(:force => true)
38
+ save
39
+ end
40
+
41
+ def root?
42
+ self[parent_id_field].nil?
43
+ end
44
+
45
+ def root
46
+ self[path_field].first.nil? ? self : tree_search_class.find(self[path_field].first)
47
+ end
48
+
49
+ def ancestors
50
+ return [] if root?
51
+ tree_search_class.find(self[path_field])
52
+ end
53
+
54
+ def self_and_ancestors
55
+ ancestors << self
56
+ end
57
+
58
+ def siblings
59
+ tree_search_class.where({
60
+ :_id => { "$ne" => self._id },
61
+ parent_id_field => self[parent_id_field]
62
+ }).sort(tree_order).all
63
+ end
64
+
65
+ def self_and_siblings
66
+ tree_search_class.where({
67
+ parent_id_field => self[parent_id_field]
68
+ }).sort(tree_order).all
69
+ end
70
+
71
+ def children
72
+ tree_search_class.where(parent_id_field => self._id).sort(tree_order).all
73
+ end
74
+
75
+ def descendants
76
+ return [] if new_record?
77
+ tree_search_class.where(path_field => self._id).sort(tree_order).all
78
+ end
79
+
80
+ def self_and_descendants
81
+ [self] + self.descendants
82
+ end
83
+
84
+ def is_ancestor_of?(other)
85
+ other[path_field].include?(self._id)
86
+ end
87
+
88
+ def is_or_is_ancestor_of?(other)
89
+ (other == self) or is_ancestor_of?(other)
90
+ end
91
+
92
+ def is_descendant_of?(other)
93
+ self[path_field].include?(other._id)
94
+ end
95
+
96
+ def is_or_is_descendant_of?(other)
97
+ (other == self) or is_descendant_of?(other)
98
+ end
99
+
100
+ def is_sibling_of?(other)
101
+ (other != self) and (other[parent_id_field] == self[parent_id_field])
102
+ end
103
+
104
+ def is_or_is_sibling_of?(other)
105
+ (other == self) or is_sibling_of?(other)
106
+ end
107
+
108
+ def move_children
109
+ if @_will_move
110
+ @_will_move = false
111
+ self.children.each do |child|
112
+ child.fix_position!
113
+ end
114
+ @_will_move = true
115
+ end
116
+ end
117
+
118
+ def destroy_descendants
119
+ tree_search_class.destroy(self.descendants.map(&:_id))
120
+ end
121
+ end
122
+
123
+ included do
124
+ # Tree search class will be used as the base from which to
125
+ # find tree objects. This is handy should you have a tree of objects that are of different types, but
126
+ # might be related through single table inheritance.
127
+ #
128
+ # self.tree_search_class = Shape
129
+ #
130
+ # In the above example, you could have a working tree ofShape, Circle and Square types (assuming
131
+ # Circle and Square were subclasses of Shape). If you want to do the same thing and you don't provide
132
+ # tree_search_class, nesting mixed types will not work.
133
+ class_attribute :tree_search_class
134
+ self.tree_search_class ||= self
135
+
136
+ class_attribute :parent_id_field
137
+ self.parent_id_field ||= "parent_id"
138
+
139
+ class_attribute :path_field
140
+ self.path_field ||= "path"
141
+
142
+ class_attribute :depth_field
143
+ self.depth_field ||= "depth"
144
+
145
+ class_attribute :tree_order
146
+
147
+ key parent_id_field, ObjectId
148
+ key path_field, Array, :default => [], :index => true
149
+ key depth_field, Integer, :default => 0
150
+
151
+ belongs_to :parent, :class => tree_search_class
152
+
153
+ validate :will_save_tree
154
+ after_validation :fix_position
155
+ after_save :move_children
156
+ before_destroy :destroy_descendants
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,4 @@
1
+ # encoding: UTF-8
2
+ require 'mongo_mapper'
3
+ I18n.load_path << File.expand_path('../locale/en.yml', __FILE__)
4
+ require 'mongo_mapper/plugins/tree'
data/lib/version.rb ADDED
@@ -0,0 +1,4 @@
1
+ # encoding: UTF-8
2
+ module MongoMapperTree
3
+ Version = '0.0.1'
4
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,41 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'database_cleaner'
5
+
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
8
+ require 'mongo_mapper_tree'
9
+
10
+ MongoMapper.database = "mongo_mapper_tree-test"
11
+
12
+ Dir["#{File.dirname(__FILE__)}/models/*.rb"].each {|file| require file}
13
+
14
+ DatabaseCleaner.strategy = :truncation
15
+
16
+ class Test::Unit::TestCase
17
+ # Drop all collections after each test case.
18
+ def setup
19
+ DatabaseCleaner.start
20
+ end
21
+
22
+ def teardown
23
+ DatabaseCleaner.clean
24
+ end
25
+
26
+ # Make sure that each test case has a teardown
27
+ # method to clear the db after each test.
28
+ def inherited(base)
29
+ base.define_method setup do
30
+ super
31
+ end
32
+
33
+ base.define_method teardown do
34
+ super
35
+ end
36
+ end
37
+
38
+ def eql_arrays?(first, second)
39
+ first.collect(&:_id).to_set == second.collect(&:_id).to_set
40
+ end
41
+ end
@@ -0,0 +1,6 @@
1
+ class Category
2
+ include MongoMapper::Document
3
+ plugin MongoMapper::Plugins::Tree
4
+
5
+ key :name, String
6
+ end
@@ -0,0 +1,9 @@
1
+ class OrderedCategory
2
+ include MongoMapper::Document
3
+ plugin MongoMapper::Plugins::Tree
4
+
5
+ key :name, String
6
+ key :value, Integer
7
+
8
+ self.tree_order = :value.asc
9
+ end
@@ -0,0 +1,10 @@
1
+ class Shape
2
+ include MongoMapper::Document
3
+ plugin MongoMapper::Plugins::Tree
4
+ self.tree_search_class = Shape
5
+
6
+ key :name, String
7
+ end
8
+
9
+ class Circle < Shape; end
10
+ class Square < Shape; end
@@ -0,0 +1,26 @@
1
+ require 'helper'
2
+ class TestMongomapperActsAsTree < Test::Unit::TestCase
3
+ context "Ordered tree" do
4
+ setup do
5
+ @root_1 = OrderedCategory.create(:name => "Root 1", :value => 2)
6
+ @child_1 = OrderedCategory.create(:name => "Child 1", :parent => @root_1, :value => 1)
7
+ @child_2 = OrderedCategory.create(:name => "Child 2", :parent => @root_1, :value => 9)
8
+ @child_2_1 = OrderedCategory.create(:name => "Child 2.1", :parent => @child_2, :value => 2)
9
+ @child_3 = OrderedCategory.create(:name => "Child 3", :parent => @root_1, :value => 5)
10
+ @root_2 = OrderedCategory.create(:name => "Root 2", :value => 1)
11
+ end
12
+
13
+ should "be in order" do
14
+ assert_equal OrderedCategory.roots, [@root_2, @root_1]
15
+
16
+ assert_equal @root_1.children, [@child_1, @child_3, @child_2]
17
+
18
+ assert_equal @root_1.descendants, [@child_1, @child_2_1, @child_3, @child_2]
19
+ assert_equal @root_1.self_and_descendants, [@root_1, @child_1, @child_2_1, @child_3, @child_2]
20
+
21
+ assert_equal @child_2.siblings, [@child_1, @child_3]
22
+ assert_equal @child_2.self_and_siblings, [@child_1, @child_3, @child_2]
23
+ assert_equal @root_1.self_and_siblings, [@root_2, @root_1]
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,90 @@
1
+ require 'helper'
2
+
3
+ class TestSearchScope < Test::Unit::TestCase
4
+ context "Simple, mixed type tree" do
5
+ setup do
6
+ shape = Shape.create(:name => "Root")
7
+ Circle.create(:name => "Circle", :parent => shape)
8
+ Square.create(:name => "Square", :parent => shape)
9
+ end
10
+
11
+ setup do
12
+ # We are loading from the database here because this process proves the point. If we never did it this
13
+ # way, there would be no reason to change the code.
14
+ @shape, @circle, @square = Shape.first, Circle.first, Square.first
15
+ end
16
+
17
+ should "return circle and square as children of shape" do
18
+ assert_equal [@circle, @square], @shape.children
19
+ end
20
+
21
+ should("return shape as parent of circle") { assert_equal @shape, @circle.parent }
22
+ should("return shape as parent of square") { assert_equal @shape, @square.parent }
23
+
24
+ should("return square as exclusive sibling of circle") { assert_equal [@square], @circle.siblings }
25
+ should "return self and square as inclusive siblings of circle" do
26
+ assert_equal [@circle, @square], @circle.self_and_siblings
27
+ end
28
+
29
+ should("return circle as exclusive sibling of square") { assert_equal [@circle], @square.siblings }
30
+ should "return self and circle as inclusive siblings of square" do
31
+ assert_equal [@circle, @square], @square.self_and_siblings
32
+ end
33
+
34
+ should "return circle and square as exclusive descendants of shape" do
35
+ assert_equal [@circle, @square], @shape.descendants
36
+ end
37
+ should "return shape, circle and square as inclusive descendants of shape" do
38
+ assert_equal [@shape, @circle, @square], @shape.self_and_descendants
39
+ end
40
+
41
+ should("return shape as exclusive ancestor of circle") { assert_equal [@shape], @circle.ancestors }
42
+ should "return self and shape as inclusive ancestors of circle" do
43
+ assert_equal [@shape, @circle], @circle.self_and_ancestors
44
+ end
45
+
46
+ should("return shape as exclusive ancestor of square") { assert_equal [@shape], @square.ancestors }
47
+ should "return self and shape as inclusive ancestors of square" do
48
+ assert_equal [@shape, @square], @square.self_and_ancestors
49
+ end
50
+
51
+ should("return shape as root of circle") { assert_equal @shape, @square.root }
52
+ should("return shape as root of square") { assert_equal @shape, @circle.root }
53
+ end
54
+
55
+ context "A tree with mixed types on either side of a branch" do
56
+ setup do
57
+ shape = Shape.create(:name => "Root")
58
+ circle = Circle.create(:name => "Circle", :parent => shape)
59
+ Square.create(:name => "Square", :parent => circle)
60
+ end
61
+
62
+ setup do
63
+ @shape, @circle, @square = Shape.first, Circle.first, Square.first
64
+ end
65
+
66
+ should("return circle as child of shape") { assert_equal [@circle], @shape.children }
67
+ should("return square as child of circle") { assert_equal [@square], @circle.children }
68
+ should("return circle as parent of square") { assert_equal @circle, @square.parent }
69
+ should("return shape as parent of circle") { assert_equal @shape, @circle.parent }
70
+
71
+ should "return circle and square as descendants of shape" do
72
+ assert_equal [@circle, @square], @shape.descendants
73
+ end
74
+
75
+ should("return square as descendant of circle") { assert_equal [@square], @circle.descendants }
76
+
77
+ should "return shape and circle as ancestors of square" do
78
+ assert_equal [@shape, @circle], @square.ancestors
79
+ end
80
+
81
+ should("return shape as ancestor of circle") { assert_equal [@shape], @circle.ancestors }
82
+
83
+ should "destroy descendants of shape" do
84
+ @shape.destroy_descendants
85
+ assert_nil Shape.find(@circle._id)
86
+ assert_nil Shape.find(@square._id)
87
+ end
88
+ end
89
+
90
+ end # TestSearchScope
data/test/test_tree.rb ADDED
@@ -0,0 +1,157 @@
1
+ require 'helper'
2
+ class TestMongomapperActsAsTree < Test::Unit::TestCase
3
+ context "Tree" do
4
+ setup do
5
+ @root_1 = Category.create(:name => "Root 1")
6
+ @child_1 = Category.create(:name => "Child 1", :parent => @root_1)
7
+ @child_2 = Category.create(:name => "Child 2", :parent => @root_1)
8
+ @child_2_1 = Category.create(:name => "Child 2.1", :parent => @child_2)
9
+ @child_3 = Category.create(:name => "Child 3", :parent => @root_1)
10
+ @root_2 = Category.create(:name => "Root 2")
11
+ end
12
+
13
+ should "create node from id " do
14
+ assert Category.create(:name => "Child 2.2", :parent_id => @root_1.id).parent == @root_1
15
+ end
16
+
17
+ should "have roots" do
18
+ assert eql_arrays?(Category.roots, [@root_1, @root_2])
19
+ end
20
+
21
+ context "node" do
22
+ should "have a root" do
23
+ assert_equal @root_1.root, @root_1
24
+ assert_not_equal @root_1.root, @root_2.root
25
+ assert_equal @root_1, @child_2_1.root
26
+ end
27
+
28
+ should "have ancestors" do
29
+ assert_equal @root_1.ancestors, []
30
+ assert_equal @child_2_1.ancestors, [@root_1, @child_2]
31
+ assert_equal @root_1.self_and_ancestors, [@root_1]
32
+ assert_equal @child_2_1.self_and_ancestors, [@root_1, @child_2, @child_2_1]
33
+ end
34
+
35
+ should "have siblings" do
36
+ assert eql_arrays?(@root_1.siblings, [@root_2])
37
+ assert eql_arrays?(@child_2.siblings, [@child_1, @child_3])
38
+ assert eql_arrays?(@child_2_1.siblings, [])
39
+ assert eql_arrays?(@root_1.self_and_siblings, [@root_1, @root_2])
40
+ assert eql_arrays?(@child_2.self_and_siblings, [@child_1, @child_2, @child_3])
41
+ assert eql_arrays?(@child_2_1.self_and_siblings, [@child_2_1])
42
+ end
43
+
44
+ should "set depth" do
45
+ assert_equal 0, @root_1.depth
46
+ assert_equal 1, @child_1.depth
47
+ assert_equal 2, @child_2_1.depth
48
+ end
49
+
50
+ should "have children" do
51
+ assert @child_2_1.children.empty?
52
+ assert eql_arrays?(@root_1.children, [@child_1, @child_2, @child_3])
53
+ end
54
+
55
+ should "have descendants" do
56
+ assert eql_arrays?(@root_1.descendants, [@child_1, @child_2, @child_3, @child_2_1])
57
+ assert eql_arrays?(@child_2.descendants, [@child_2_1])
58
+ assert @child_2_1.descendants.empty?
59
+ assert eql_arrays?(@root_1.self_and_descendants, [@root_1, @child_1, @child_2, @child_3, @child_2_1])
60
+ assert eql_arrays?(@child_2.self_and_descendants, [@child_2, @child_2_1])
61
+ assert eql_arrays?(@child_2_1.self_and_descendants, [@child_2_1])
62
+ end
63
+
64
+ should "be able to tell if ancestor" do
65
+ assert @root_1.is_ancestor_of?(@child_1)
66
+ assert ! @root_2.is_ancestor_of?(@child_2_1)
67
+ assert ! @child_2.is_ancestor_of?(@child_2)
68
+
69
+ assert @root_1.is_or_is_ancestor_of?(@child_1)
70
+ assert ! @root_2.is_or_is_ancestor_of?(@child_2_1)
71
+ assert @child_2.is_or_is_ancestor_of?(@child_2)
72
+ end
73
+
74
+ should "be able to tell if descendant" do
75
+ assert ! @root_1.is_descendant_of?(@child_1)
76
+ assert @child_1.is_descendant_of?(@root_1)
77
+ assert ! @child_2.is_descendant_of?(@child_2)
78
+
79
+ assert ! @root_1.is_or_is_descendant_of?(@child_1)
80
+ assert @child_1.is_or_is_descendant_of?(@root_1)
81
+ assert @child_2.is_or_is_descendant_of?(@child_2)
82
+ end
83
+
84
+ should "be able to tell if sibling" do
85
+ assert ! @root_1.is_sibling_of?(@child_1)
86
+ assert ! @child_1.is_sibling_of?(@child_1)
87
+ assert ! @child_2.is_sibling_of?(@child_2)
88
+
89
+ assert ! @root_1.is_or_is_sibling_of?(@child_1)
90
+ assert @child_1.is_or_is_sibling_of?(@child_2)
91
+ assert @child_2.is_or_is_sibling_of?(@child_2)
92
+ end
93
+
94
+ context "when moving" do
95
+ should "recalculate path and depth" do
96
+ @child_3.parent = @child_2
97
+ @child_3.save
98
+
99
+ assert @child_2.is_or_is_ancestor_of?(@child_3)
100
+ assert @child_3.is_or_is_descendant_of?(@child_2)
101
+ assert @child_2.children.include?(@child_3)
102
+ assert @child_2.descendants.include?(@child_3)
103
+ assert @child_2_1.is_or_is_sibling_of?(@child_3)
104
+ assert_equal 2, @child_3.depth
105
+ end
106
+
107
+ should "move children on save" do
108
+ @child_2.parent = @root_2
109
+
110
+ assert ! @root_2.is_or_is_ancestor_of?(@child_2_1)
111
+ assert ! @child_2_1.is_or_is_descendant_of?(@root_2)
112
+ assert ! @root_2.descendants.include?(@child_2_1)
113
+
114
+ @child_2.save
115
+ @child_2_1.reload
116
+
117
+ assert @root_2.is_or_is_ancestor_of?(@child_2_1)
118
+ assert @child_2_1.is_or_is_descendant_of?(@root_2)
119
+ assert @root_2.descendants.include?(@child_2_1)
120
+ end
121
+
122
+ should "check against cyclic graph" do
123
+ @root_1.parent = @child_2_1
124
+ assert ! @root_1.valid?
125
+ assert_equal I18n.t(:'mongo_mapper.errors.messages.cyclic'), @root_1.errors[:base].first
126
+ end
127
+
128
+ should "be able to become root" do
129
+ @child_2.parent = nil
130
+ @child_2.save
131
+ @child_2.reload
132
+ assert_nil @child_2.parent
133
+ @child_2_1.reload
134
+ assert (@child_2_1.path == [@child_2.id])
135
+ end
136
+
137
+ end
138
+
139
+ should "destroy descendants when destroyed" do
140
+ @child_2.destroy
141
+ assert_nil Category.find(@child_2_1._id)
142
+ end
143
+ end
144
+
145
+ context "root node" do
146
+ should "not have a parent" do
147
+ assert_nil @root_1.parent
148
+ end
149
+ end
150
+
151
+ context "child_node" do
152
+ should "have a parent" do
153
+ assert_equal @child_2, @child_2_1.parent
154
+ end
155
+ end
156
+ end
157
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mongo_mapper_tree
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - "Joel Junstr\xC3\xB6m"
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-08-05 00:00:00 +02:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: mongo_mapper
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: 0.9.1
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: shoulda
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: "2.10"
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: *id002
38
+ description: An Acts As Tree like implementation for MongoMapper based on mongo_mapper_acts_as_tree
39
+ email:
40
+ - joel.junstrom@oktavilla.se
41
+ executables: []
42
+
43
+ extensions: []
44
+
45
+ extra_rdoc_files: []
46
+
47
+ files:
48
+ - lib/locale/en.yml
49
+ - lib/mongo_mapper/plugins/tree.rb
50
+ - lib/mongo_mapper_tree.rb
51
+ - lib/version.rb
52
+ - test/helper.rb
53
+ - test/models/category.rb
54
+ - test/models/ordered_category.rb
55
+ - test/models/shapes.rb
56
+ - test/test_order.rb
57
+ - test/test_search_class.rb
58
+ - test/test_tree.rb
59
+ - LICENSE
60
+ - README.rdoc
61
+ has_rdoc: true
62
+ homepage: http://github.com/Oktavilla/mongo_mapper_tree
63
+ licenses: []
64
+
65
+ post_install_message:
66
+ rdoc_options: []
67
+
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: -4220793794743588163
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ hash: -4220793794743588163
85
+ segments:
86
+ - 0
87
+ version: "0"
88
+ requirements: []
89
+
90
+ rubyforge_project:
91
+ rubygems_version: 1.6.2
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: An Acts As Tree like implementation for MongoMapper
95
+ test_files:
96
+ - test/helper.rb
97
+ - test/models/category.rb
98
+ - test/models/ordered_category.rb
99
+ - test/models/shapes.rb
100
+ - test/test_order.rb
101
+ - test/test_search_class.rb
102
+ - test/test_tree.rb