mongoid-tree-rational 0.1.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/.rspec +2 -0
- data/.travis.yml +12 -0
- data/Gemfile +23 -0
- data/Guardfile +6 -0
- data/LICENSE +21 -0
- data/README.md +287 -0
- data/Rakefile +63 -0
- data/VERSION +1 -0
- data/lib/mongoid/locale/en.yml +11 -0
- data/lib/mongoid/locale/nb.yml +8 -0
- data/lib/mongoid/tree.rb +443 -0
- data/lib/mongoid/tree/ordering.rb +236 -0
- data/lib/mongoid/tree/rational_numbering.rb +805 -0
- data/lib/mongoid/tree/traversal.rb +122 -0
- data/mongoid-tree-rational.gemspec +103 -0
- data/spec/mongoid/tree/ordering_spec.rb +342 -0
- data/spec/mongoid/tree/rational_numbering_spec.rb +765 -0
- data/spec/mongoid/tree/traversal_spec.rb +177 -0
- data/spec/mongoid/tree_spec.rb +444 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/support/macros/tree_macros.rb +53 -0
- data/spec/support/models/node.rb +47 -0
- metadata +320 -0
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gem 'mongoid', ['<= 4.0', '>= 3.0']
|
4
|
+
gem 'rational_number'
|
5
|
+
|
6
|
+
group :development do
|
7
|
+
gem 'rake'
|
8
|
+
gem 'rspec'
|
9
|
+
gem 'yard'
|
10
|
+
gem 'jeweler'
|
11
|
+
gem 'guard-rspec', '>= 2.6.0'
|
12
|
+
gem 'rb-inotify', :require => false
|
13
|
+
gem 'rb-fsevent', :require => false
|
14
|
+
gem 'wdm', :platforms => [:mswin, :mingw], :require => false
|
15
|
+
gem 'hirb'
|
16
|
+
gem 'wirble'
|
17
|
+
gem 'awesome_print'
|
18
|
+
end
|
19
|
+
|
20
|
+
group :development, :test do
|
21
|
+
gem 'coveralls', :require => false
|
22
|
+
gem 'simplecov', :require => false
|
23
|
+
end
|
data/Guardfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2010-2012 Benedikt Deicke
|
2
|
+
Copyright (c) 2013 Leif Ringstad (Rational numbering additions)
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,287 @@
|
|
1
|
+
# mongoid-tree [](https://travis-ci.org/boxcms/mongoid-tree-rational) [](https://gemnasium.com/boxcms/mongoid-tree-rational) [](https://coveralls.io/r/boxcms/mongoid-tree-rational)
|
2
|
+
|
3
|
+
A tree structure for Mongoid documents using rational numbers and materialized path pattern
|
4
|
+
|
5
|
+
## Requirements
|
6
|
+
|
7
|
+
* mongoid (~> 3.0)
|
8
|
+
|
9
|
+
This version will only support mongoid 3.0+
|
10
|
+
|
11
|
+
## Install
|
12
|
+
|
13
|
+
To install mongoid_tree_rational, simply add it to your Gemfile:
|
14
|
+
|
15
|
+
gem 'mongoid-tree-rational', :require => 'mongoid/tree'
|
16
|
+
|
17
|
+
In order to get the latest development version of mongoid-tree:
|
18
|
+
|
19
|
+
gem 'mongoid-tree-rational', :git => 'git://github.com/boxcms/mongoid-tree-rational', :require => 'mongoid/tree'
|
20
|
+
|
21
|
+
You might want to remove the `:require => 'mongoid/tree'` option and explicitly `require 'mongoid/tree'` where needed and finally run
|
22
|
+
|
23
|
+
bundle install
|
24
|
+
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
class Node
|
30
|
+
include Mongoid::Document
|
31
|
+
include Mongoid::Tree
|
32
|
+
include Mongoid::Tree::RationalNumbering
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
### Utility methods
|
37
|
+
|
38
|
+
There are several utility methods that help getting to other related documents in the tree:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
Node.root
|
42
|
+
Node.roots
|
43
|
+
Node.leaves
|
44
|
+
|
45
|
+
node.root
|
46
|
+
node.parent
|
47
|
+
node.children
|
48
|
+
node.ancestors
|
49
|
+
node.ancestors_and_self
|
50
|
+
node.descendants
|
51
|
+
node.descendants_and_self
|
52
|
+
node.siblings
|
53
|
+
node.siblings_and_self
|
54
|
+
node.leaves
|
55
|
+
```
|
56
|
+
|
57
|
+
In addition it's possible to check certain aspects of the document's position in the tree:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
node.root?
|
61
|
+
node.leaf?
|
62
|
+
node.depth
|
63
|
+
node.ancestor_of?(other)
|
64
|
+
node.descendant_of?(other)
|
65
|
+
node.sibling_of?(other)
|
66
|
+
```
|
67
|
+
|
68
|
+
See `Mongoid::Tree` for more information on these methods.
|
69
|
+
|
70
|
+
|
71
|
+
### Ordering
|
72
|
+
|
73
|
+
`Mongoid::Tree` doesn't order children by default. To enable ordering of tree nodes include the `Mongoid::Tree::RationalNumbering` or the `Mongoid::Tree::Ordering` module.
|
74
|
+
|
75
|
+
|
76
|
+
#### By rational numbers
|
77
|
+
|
78
|
+
To use rational ordering, include the `Mongoid::Tree::RationalNumbering` module. This will add a `position` field to your document and provide additional utility methods:
|
79
|
+
|
80
|
+
While rational numbering requires more processing when saving, it does give the benefit of querying an entire tree in one go.
|
81
|
+
|
82
|
+
|
83
|
+
Mathematical details about rational numbers in nested trees can be found here: [http://arxiv.org/pdf/0806.3115v1.pdf](http://arxiv.org/pdf/0806.3115v1.pdf)
|
84
|
+
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
node.set_rational_number(nv,dv) # set the nv/dv directly if you have the values
|
88
|
+
# returns true/false + errors if any.
|
89
|
+
node.lower_siblings
|
90
|
+
node.higher_siblings
|
91
|
+
node.first_sibling_in_list
|
92
|
+
node.last_sibling_in_list
|
93
|
+
node.siblings_between(other_node)
|
94
|
+
|
95
|
+
node.tree # get the entire tree under the node (Triggers 1 query only! Hurray)
|
96
|
+
node.tree_and_self # # get the entire tree under the node including node
|
97
|
+
|
98
|
+
node.move_up
|
99
|
+
node.move_down
|
100
|
+
node.move_to_top
|
101
|
+
node.move_to_bottom
|
102
|
+
node.move_above(other)
|
103
|
+
node.move_below(other)
|
104
|
+
|
105
|
+
node.at_top?
|
106
|
+
node.at_bottom?
|
107
|
+
```
|
108
|
+
|
109
|
+
Example:
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
class Node
|
113
|
+
include Mongoid::Document
|
114
|
+
include Mongoid::Tree
|
115
|
+
include Mongoid::Tree::RationalNumbering
|
116
|
+
end
|
117
|
+
```
|
118
|
+
|
119
|
+
There are one additional class function
|
120
|
+
```ruby
|
121
|
+
Node.rekey_all! # Will iterate over the entire tree and rekey every single node.
|
122
|
+
# Please note that this might take a while for a large tree.
|
123
|
+
# Do this in a background worker or rake task.
|
124
|
+
end
|
125
|
+
```
|
126
|
+
|
127
|
+
You can get the entire tree in one go like this:
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
# - node_1
|
131
|
+
# - node_1_1
|
132
|
+
# - node_1_2
|
133
|
+
# - node_2
|
134
|
+
# - node_2_1
|
135
|
+
# - node_2_1_1
|
136
|
+
# - node_2_1_2
|
137
|
+
# - node_2_2
|
138
|
+
# - node_2_2_1
|
139
|
+
# - node_2_2_2
|
140
|
+
|
141
|
+
Node.all # Get the entire tree
|
142
|
+
# -> [node_1, node_1_1, node_1_2, node_2, node_2_1, node_2_1_1, node_2_1_2, node_2_2, node_2_2_1, node_2_2_2]
|
143
|
+
end
|
144
|
+
```
|
145
|
+
|
146
|
+
See `Mongoid::Tree::RationalNumbering` for more information on these methods.
|
147
|
+
|
148
|
+
#### By 0-based integer (simple)
|
149
|
+
|
150
|
+
To use simple ordering, include the `Mongoid::Tree::Ordering` module. This will add a `position` field to your document and provide additional utility methods:
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
node.lower_siblings
|
154
|
+
node.higher_siblings
|
155
|
+
node.first_sibling_in_list
|
156
|
+
node.last_sibling_in_list
|
157
|
+
|
158
|
+
node.move_up
|
159
|
+
node.move_down
|
160
|
+
node.move_to_top
|
161
|
+
node.move_to_bottom
|
162
|
+
node.move_above(other)
|
163
|
+
node.move_below(other)
|
164
|
+
|
165
|
+
node.at_top?
|
166
|
+
node.at_bottom?
|
167
|
+
```
|
168
|
+
|
169
|
+
Example:
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
class Node
|
173
|
+
include Mongoid::Document
|
174
|
+
include Mongoid::Tree
|
175
|
+
include Mongoid::Tree::Ordering
|
176
|
+
end
|
177
|
+
```
|
178
|
+
|
179
|
+
See `Mongoid::Tree::Ordering` for more information on these methods.
|
180
|
+
|
181
|
+
### Traversal
|
182
|
+
|
183
|
+
It's possible to traverse the tree using different traversal methods using the `Mongoid::Tree::Traversal` module.
|
184
|
+
|
185
|
+
Example:
|
186
|
+
|
187
|
+
```ruby
|
188
|
+
class Node
|
189
|
+
include Mongoid::Document
|
190
|
+
include Mongoid::Tree
|
191
|
+
include Mongoid::Tree::Traversal
|
192
|
+
end
|
193
|
+
|
194
|
+
node.traverse(:breadth_first) do |n|
|
195
|
+
# Do something with Node n
|
196
|
+
end
|
197
|
+
```
|
198
|
+
|
199
|
+
### Destroying
|
200
|
+
|
201
|
+
`Mongoid::Tree` does not handle destroying of nodes by default. However it provides several strategies that help you to deal with children of deleted documents. You can simply add them as `before_destroy` callbacks.
|
202
|
+
|
203
|
+
Available strategies are:
|
204
|
+
|
205
|
+
* `:nullify_children` -- Sets the children's parent_id to null
|
206
|
+
* `:move_children_to_parent` -- Moves the children to the current document's parent
|
207
|
+
* `:destroy_children` -- Destroys all children by calling their `#destroy` method (invokes callbacks)
|
208
|
+
* `:delete_descendants` -- Deletes all descendants using a database query (doesn't invoke callbacks)
|
209
|
+
|
210
|
+
Example:
|
211
|
+
|
212
|
+
```ruby
|
213
|
+
class Node
|
214
|
+
include Mongoid::Document
|
215
|
+
include Mongoid::Tree
|
216
|
+
|
217
|
+
before_destroy :nullify_children
|
218
|
+
end
|
219
|
+
```
|
220
|
+
|
221
|
+
|
222
|
+
### Callbacks
|
223
|
+
|
224
|
+
There are two callbacks that are called before and after the rearranging process. This enables you to do additional computations after the documents position in the tree is updated. See `Mongoid::Tree` for details.
|
225
|
+
|
226
|
+
Example:
|
227
|
+
|
228
|
+
```ruby
|
229
|
+
class Page
|
230
|
+
include Mongoid::Document
|
231
|
+
include Mongoid::Tree
|
232
|
+
|
233
|
+
after_rearrange :rebuild_path
|
234
|
+
|
235
|
+
field :slug
|
236
|
+
field :path
|
237
|
+
|
238
|
+
private
|
239
|
+
|
240
|
+
def rebuild_path
|
241
|
+
self.path = self.ancestors_and_self.collect(&:slug).join('/')
|
242
|
+
end
|
243
|
+
end
|
244
|
+
```
|
245
|
+
|
246
|
+
### Validations
|
247
|
+
|
248
|
+
`Mongoid::Tree` currently does not validate the document's children or parent associations by default. To explicitly enable validation for children and parent documents it's required to add a `validates_associated` validation.
|
249
|
+
|
250
|
+
Example:
|
251
|
+
|
252
|
+
```ruby
|
253
|
+
class Node
|
254
|
+
include Mongoid::Document
|
255
|
+
include Mongoid::Tree
|
256
|
+
|
257
|
+
validates_associated :parent, :children
|
258
|
+
end
|
259
|
+
```
|
260
|
+
|
261
|
+
## Build Status
|
262
|
+
|
263
|
+
mongoid-tree is on [Travis CI](http://travis-ci.org/boxcms/mongoid-tree-rational) running the specs on Ruby Head, Ruby 1.9.3, JRuby (1.9 mode), and Rubinius (1.9 mode).
|
264
|
+
|
265
|
+
## Known issues
|
266
|
+
|
267
|
+
See [github.com/boxcms/mongoid-tree-rational/issues](https://github.com/boxcms/mongoid-tree-rational/issues)
|
268
|
+
|
269
|
+
|
270
|
+
## Repository
|
271
|
+
|
272
|
+
See [github.com/boxcms/mongoid-tree-rational](https://github.com/boxcms/mongoid-tree-rational) and feel free to fork it!
|
273
|
+
|
274
|
+
|
275
|
+
## MongoMapper version
|
276
|
+
|
277
|
+
Have a look here: [github.com/leifcr/mm-tree](https://github.com/leifcr/mm-tree)
|
278
|
+
|
279
|
+
## Contributors
|
280
|
+
|
281
|
+
See a list of all contributors at [github.com/boxcms/mongoid-tree-rational/contributors](https://github.com/boxcms/mongoid-tree-rational/contributors). Thanks!
|
282
|
+
|
283
|
+
A huge thanks to [Benedikt Deicke](https://github.com/benedikt) for all the work on mongoid-tree. This rational number version is based on his work
|
284
|
+
|
285
|
+
## Copyright
|
286
|
+
|
287
|
+
See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
16
|
+
|
17
|
+
require 'jeweler'
|
18
|
+
Jeweler::Tasks.new do |gem|
|
19
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
20
|
+
gem.name = "mongoid-tree-rational"
|
21
|
+
gem.version = version
|
22
|
+
gem.homepage = "https://github.com/boxcms/mongoid-tree-rational"
|
23
|
+
gem.license = "MIT"
|
24
|
+
gem.summary = %Q{A tree structure for Mongoid documents with rational numbers}
|
25
|
+
gem.description = %Q{A tree structure for Mongoid documents using the materialized path pattern and rational number sorting.}
|
26
|
+
gem.email = "leifcr@gmail.com"
|
27
|
+
gem.authors = ['Leif Ringstad', 'Benedikt Deicke']
|
28
|
+
# dependencies defined in Gemfile
|
29
|
+
end
|
30
|
+
Jeweler::RubygemsDotOrgTasks.new
|
31
|
+
|
32
|
+
# RDoc::Task.new(:rdoc) do |rdoc|
|
33
|
+
# rdoc.rdoc_dir = 'rdoc'
|
34
|
+
# rdoc.title = "Mongoid Tree Rational #{version}"
|
35
|
+
# rdoc.options << '--line-numbers'
|
36
|
+
# rdoc.rdoc_files.include('README.rdoc')
|
37
|
+
# rdoc.rdoc_files.include('lib/**/*.rb')
|
38
|
+
# end
|
39
|
+
|
40
|
+
# Bundler::GemHelper.install_tasks
|
41
|
+
|
42
|
+
require 'rspec/core'
|
43
|
+
require 'rspec/core/rake_task'
|
44
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
45
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
46
|
+
end
|
47
|
+
|
48
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
49
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
50
|
+
spec.rcov = true
|
51
|
+
end
|
52
|
+
|
53
|
+
task :default => :spec
|
54
|
+
|
55
|
+
# YARD::Rake::YardocTask.new(:doc)
|
56
|
+
|
57
|
+
desc "Open an irb session"
|
58
|
+
task :test_console do
|
59
|
+
require 'wirble'
|
60
|
+
require 'ap'
|
61
|
+
require 'hirb'
|
62
|
+
sh "irb -rubygems -I lib -r ./spec/spec_helper.rb"
|
63
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,11 @@
|
|
1
|
+
en:
|
2
|
+
mongoid:
|
3
|
+
errors:
|
4
|
+
messages:
|
5
|
+
tree:
|
6
|
+
cyclic: "Can't be children of a descendant"
|
7
|
+
search_class_mismatch: "Mismatch between search classes. Parent: %{parent_search_class} Node: %{node_search_class}"
|
8
|
+
rational:
|
9
|
+
incorrect_parent: "Positional values doesn't match parent (check nv/dv values)"
|
10
|
+
parent_does_not_exist: "Parent does not exist. Cannot move to nv: %{nv} dv: %{dv}"
|
11
|
+
#cannot_set_parent: "Cannot set the parent"
|
@@ -0,0 +1,8 @@
|
|
1
|
+
nb:
|
2
|
+
mongoid:
|
3
|
+
errors:
|
4
|
+
messages:
|
5
|
+
tree:
|
6
|
+
cyclic: "Kan ikke være barnet av en etterkommer."
|
7
|
+
incorrect_parent_nv_dv: "Posisjonelle/rasjonelle verdier stemmer ikke (check nv/dv values)"
|
8
|
+
search_class_mismatch: "Søke klassene er ikke identiske. Forelder: %{parent_search_class} Node/barn: %{node_search_class}."
|