fertile_forest 0.0.0 → 1.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.
- checksums.yaml +4 -4
- data/LICENSE +22 -0
- data/README.rdoc +3 -0
- data/config/routes.rb +2 -0
- data/lib/fertile_forest/engine.rb +13 -0
- data/lib/fertile_forest/modules/calculators.rb +231 -0
- data/lib/fertile_forest/modules/configs.rb +96 -0
- data/lib/fertile_forest/modules/entities.rb +233 -0
- data/lib/fertile_forest/modules/finders.rb +736 -0
- data/lib/fertile_forest/modules/reconstructers.rb +843 -0
- data/lib/fertile_forest/modules/states.rb +271 -0
- data/lib/fertile_forest/modules/utilities.rb +188 -0
- data/lib/fertile_forest/saplings.rb +330 -0
- data/lib/fertile_forest/version.rb +1 -1
- data/lib/fertile_forest.rb +7 -3
- data/lib/tasks/fertile_forest_tasks.rake +4 -0
- metadata +19 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e7fb8b7fe6a221ca6fa537152448626b03bfa453
|
4
|
+
data.tar.gz: 55da6e1a5fcb682e8e0a1cc2239df52e32bfb53f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3600025777793045fc0faaa17c1b3a150dc91bb11432589fd199b64b12f62ae4295960a6e2d5b5aa088880e6528dfb5cf7853800138ab9dc109637bf477653bf
|
7
|
+
data.tar.gz: 9eaf893afade620cbdae109ce6144b36fac204dcae85d2a18fb87b555784543c6a5b7bbb14f4e4a7a4b19deff3c8ca562174b5fb977cf7c849056569b614d623
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Stew Eucen
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
22
|
+
|
data/README.rdoc
ADDED
data/config/routes.rb
ADDED
@@ -0,0 +1,231 @@
|
|
1
|
+
#
|
2
|
+
# Calcurators methods
|
3
|
+
# Fertile Forest for Ruby: The new model for storing hierarchical data in a database.
|
4
|
+
#
|
5
|
+
# @author StewEucen
|
6
|
+
# @copyright Copyright (c) 2015 Stew Eucen (http://lab.kochlein.com)
|
7
|
+
# @license http://www.opensource.org/licenses/mit-license.php MIT License
|
8
|
+
#
|
9
|
+
# @link http://lab.kochlein.com/FertileForest
|
10
|
+
# @since File available since Release 1.0.0
|
11
|
+
# @version 1.0.0
|
12
|
+
#
|
13
|
+
module StewEucen
|
14
|
+
# Name space of Stew Eucen's Acts
|
15
|
+
module Acts
|
16
|
+
# Name space of Fertile Forest
|
17
|
+
module FertileForest
|
18
|
+
# Name space of class methods for Fertile Forest
|
19
|
+
module Table
|
20
|
+
# This module is for extending into derived class by ActiveRecord.<br>
|
21
|
+
# The caption contains "Instance Methods",
|
22
|
+
# but it means "Class Methods" of each derived class.
|
23
|
+
# @private
|
24
|
+
module Calculators
|
25
|
+
|
26
|
+
def fill_required_columns_to_append!(node)
|
27
|
+
# calculate depth and queue for appending.
|
28
|
+
# If no interval, try to scoot over queue.
|
29
|
+
if node.ff_base_id.to_i <= 0
|
30
|
+
fill_info = ff_calc_required_columns_for_appending_as_root(node)
|
31
|
+
else
|
32
|
+
fill_info = ff_calc_required_columns_for_appending_as_internal(node)
|
33
|
+
end
|
34
|
+
|
35
|
+
# When fail to calc, can not save.
|
36
|
+
# no need to set error message here.
|
37
|
+
return false if fill_info.blank?
|
38
|
+
|
39
|
+
# not need to set ff_grove, because posted node has it already.
|
40
|
+
node.ff_queue = fill_info[:ff_queue]
|
41
|
+
node.ff_depth = fill_info[:ff_depth]
|
42
|
+
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
def ff_parse_kinship(node)
|
47
|
+
ff_kinship_key = node.ff_kinship
|
48
|
+
if /true|false/i.match(ff_kinship_key)
|
49
|
+
ff_kinship_key === 'true'
|
50
|
+
else
|
51
|
+
ff_kinship_key.to_i
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Calculate depth and queue as root node to append.
|
57
|
+
# @return [Hash] Calculated queue and depth.
|
58
|
+
# @return [false] Can not calculate.
|
59
|
+
#
|
60
|
+
def ff_calc_required_columns_for_appending_as_root(node)
|
61
|
+
# can be null=zero
|
62
|
+
posted_grove = node.ff_grove.to_i
|
63
|
+
|
64
|
+
# When append as root, need to post ff_grove.
|
65
|
+
if has_grove? && posted_grove <= 0
|
66
|
+
# TODO: set error message 'append_empty_column'
|
67
|
+
return false
|
68
|
+
end
|
69
|
+
|
70
|
+
# depth is fixed value
|
71
|
+
fill_info = {ff_depth: ROOT_DEPTH}
|
72
|
+
|
73
|
+
####################################################################
|
74
|
+
#
|
75
|
+
# calculate queue
|
76
|
+
#
|
77
|
+
|
78
|
+
# get max queue in grove
|
79
|
+
last_queue = ff_get_last_queue(posted_grove) # can be nil
|
80
|
+
|
81
|
+
if last_queue.nil?
|
82
|
+
append_queue = 0
|
83
|
+
elsif QUEUE_MAX_VALUE <= last_queue
|
84
|
+
# Try to scoot over pre-nodes.
|
85
|
+
evenize_res = ff_evenize(posted_grove, nil, nil, 1) # 1: append node count
|
86
|
+
|
87
|
+
# When fail to evenize, filled all id.
|
88
|
+
if evenize_res.blank?
|
89
|
+
# TODO: set error append.canNotScootsOver'
|
90
|
+
return false
|
91
|
+
end
|
92
|
+
|
93
|
+
append_queue = evenize_res[SPROUT_VACANT_QUEUE_KEY]
|
94
|
+
elsif QUEUE_MAX_VALUE - last_queue < QUEUE_DEFAULT_INTERVAL
|
95
|
+
append_queue = QUEUE_MAX_VALUE
|
96
|
+
else
|
97
|
+
append_queue = last_queue + QUEUE_DEFAULT_INTERVAL
|
98
|
+
end
|
99
|
+
|
100
|
+
# return value
|
101
|
+
fill_info.merge({ff_queue: append_queue})
|
102
|
+
end
|
103
|
+
|
104
|
+
#
|
105
|
+
# Calculate depth and queue as internal node to append.
|
106
|
+
# (1) has space before base-node, calc median queue.
|
107
|
+
# (2) When no space befre base node, try to evenize.
|
108
|
+
# (3) can not evenize, can not append.
|
109
|
+
# @return [Hash] Calculated queue and depth.
|
110
|
+
# @return [false] Can not calculate.
|
111
|
+
#
|
112
|
+
def ff_calc_required_columns_for_appending_as_internal(node)
|
113
|
+
base_id = node.ff_base_id.to_i
|
114
|
+
grove_id = node.ff_grove.to_i
|
115
|
+
|
116
|
+
# get base node by ff_base_id
|
117
|
+
# use ff_grove for find, because grove means USER_ID
|
118
|
+
base_node = ff_required_columns_scope()
|
119
|
+
.ff_usual_conditions_scope(grove_id)
|
120
|
+
.where(id: base_id)
|
121
|
+
.first
|
122
|
+
|
123
|
+
# When has ff_base_id and the node is nothing, fail to append.
|
124
|
+
if base_node.blank?
|
125
|
+
# TODO: set errors append.baseNodeIsNull
|
126
|
+
return false
|
127
|
+
end
|
128
|
+
|
129
|
+
kinship = ff_parse_kinship(node)
|
130
|
+
is_sibling = ff_is_bool(kinship)
|
131
|
+
|
132
|
+
# depth is fixed value
|
133
|
+
fill_info = {ff_depth: base_node.ff_depth.to_i + (is_sibling ? 0 : 1)}
|
134
|
+
|
135
|
+
# pick up node for wedged node to scoot over. (can be null)
|
136
|
+
wedged_node = ff_get_wedged_node(base_node, kinship)
|
137
|
+
|
138
|
+
# When wedged node is nothing, it means last queue.
|
139
|
+
# In the case, calc appending queue is "lastQueue + INTERVAL"
|
140
|
+
|
141
|
+
if wedged_node.blank?
|
142
|
+
last_queue = ff_get_last_queue(grove_id, 0)
|
143
|
+
if last_queue < QUEUE_MAX_VALUE
|
144
|
+
if QUEUE_DEFAULT_INTERVAL <= QUEUE_MAX_VALUE - last_queue
|
145
|
+
calc_queue = last_queue + QUEUE_DEFAULT_INTERVAL
|
146
|
+
else
|
147
|
+
calc_queue = QUEUE_MAX_VALUE
|
148
|
+
end
|
149
|
+
|
150
|
+
return fill_info.merge({ff_queue: calc_queue})
|
151
|
+
end
|
152
|
+
else
|
153
|
+
#
|
154
|
+
# When got wedged node, calc median queue.
|
155
|
+
# (1) get previous node of the wedge node.
|
156
|
+
# (2) calc median queue.
|
157
|
+
#
|
158
|
+
append_queue = ff_calc_median_queue(wedged_node)
|
159
|
+
|
160
|
+
return fill_info.merge({ff_queue: append_queue}) \
|
161
|
+
if append_queue.present?
|
162
|
+
end
|
163
|
+
|
164
|
+
# When no space before wedged node, try to scoot over.
|
165
|
+
append_queue = ff_evenize_for_appending(base_node, wedged_node)
|
166
|
+
|
167
|
+
return fill_info.merge({ff_queue: append_queue}) \
|
168
|
+
if append_queue.present?
|
169
|
+
|
170
|
+
# TODO: set error message append.canNotScootsOver
|
171
|
+
false
|
172
|
+
end
|
173
|
+
|
174
|
+
def ff_calc_median_queue(wedged_node)
|
175
|
+
tail_node = ff_get_previous_node(wedged_node)
|
176
|
+
|
177
|
+
# tail_node never be null, because parent-node exists.
|
178
|
+
return nil if tail_node.blank?
|
179
|
+
|
180
|
+
tail_queue = tail_node.ff_queue
|
181
|
+
wedged_queue = wedged_node.ff_queue
|
182
|
+
|
183
|
+
return nil if wedged_queue - tail_queue <= 1
|
184
|
+
|
185
|
+
# not need to use (int)
|
186
|
+
(tail_queue + wedged_queue) / 2
|
187
|
+
end
|
188
|
+
|
189
|
+
def ff_evenize_for_appending(base_node, wedged_node)
|
190
|
+
append_node_count = 1
|
191
|
+
|
192
|
+
grove_id = base_node.ff_grove
|
193
|
+
base_queue = base_node.blank? ? nil : base_node .ff_queue
|
194
|
+
wedged_queue = wedged_node.blank? ? nil : wedged_node.ff_queue
|
195
|
+
|
196
|
+
# try to evenize all pre-nodes from this base node.
|
197
|
+
evenize_res = ff_evenize(grove_id, base_queue, wedged_queue, append_node_count)
|
198
|
+
return evenize_res[SPROUT_VACANT_QUEUE_KEY] if evenize_res.present?
|
199
|
+
|
200
|
+
# try to evenize all pre-nodes from this root node.
|
201
|
+
# {
|
202
|
+
# $rootNode = $this->root($baseNode);
|
203
|
+
# $evenizeRes = $this->_evenize($grove, $rootNode, $wedgedQueue, $appendNodeCount);
|
204
|
+
# if (!empty($evenizeRes)) {
|
205
|
+
# return $evenizeRes[self::SPROUT_VACANT_QUEUE_KEY];
|
206
|
+
# }
|
207
|
+
# }
|
208
|
+
|
209
|
+
# try to evenize all pre-nodes.
|
210
|
+
evenize_res = ff_evenize(grove_id, nil, wedged_queue, append_node_count)
|
211
|
+
return evenize_res[SPROUT_VACANT_QUEUE_KEY] if evenize_res.present?
|
212
|
+
|
213
|
+
# try to evenize all post-nodes.
|
214
|
+
evenize_res = ff_evenize(grove_id, wedged_queue, nil, append_node_count, true)
|
215
|
+
return evenize_res[SPROUT_VACANT_QUEUE_KEY] if evenize_res.present?
|
216
|
+
|
217
|
+
# can not evenize.
|
218
|
+
false
|
219
|
+
end
|
220
|
+
|
221
|
+
protected :ff_parse_kinship,
|
222
|
+
:ff_calc_required_columns_for_appending_as_root,
|
223
|
+
:ff_calc_required_columns_for_appending_as_internal,
|
224
|
+
:ff_calc_median_queue,
|
225
|
+
:ff_evenize_for_appending
|
226
|
+
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
#
|
2
|
+
# Configs methods
|
3
|
+
# Fertile Forest for Ruby: The new model for storing hierarchical data in a database.
|
4
|
+
#
|
5
|
+
# @author StewEucen
|
6
|
+
# @copyright Copyright (c) 2015 Stew Eucen (http://lab.kochlein.com)
|
7
|
+
# @license http://www.opensource.org/licenses/mit-license.php MIT License
|
8
|
+
#
|
9
|
+
# @link http://lab.kochlein.com/FertileForest
|
10
|
+
# @since File available since Release 1.0.0
|
11
|
+
# @version 1.0.0
|
12
|
+
#
|
13
|
+
module StewEucen
|
14
|
+
# Name space of Stew Eucen's Acts
|
15
|
+
module Acts
|
16
|
+
# Name space of Fertile Forest
|
17
|
+
module FertileForest
|
18
|
+
# Name space of class methods for Fertile Forest
|
19
|
+
module Table
|
20
|
+
# This module is for extending into derived class by ActiveRecord.<br>
|
21
|
+
# The caption contains "Instance Methods",
|
22
|
+
# but it means "Class Methods" of each derived class.
|
23
|
+
module Configs
|
24
|
+
|
25
|
+
#
|
26
|
+
# Exists grove field in table?
|
27
|
+
#
|
28
|
+
# @author StewEucen
|
29
|
+
# @return [Boolean] true: has grove column.
|
30
|
+
# @return [Boolean] false: no grove column.
|
31
|
+
# @since Release 1.0.0
|
32
|
+
#
|
33
|
+
def has_grove?
|
34
|
+
ff_has_column? :ff_grove
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# Exists soft-delete field in table?
|
39
|
+
#
|
40
|
+
# @author StewEucen
|
41
|
+
# @return [Boolean] true: has soft-delete column.
|
42
|
+
# @return [Boolean] false: no soft-delete column.
|
43
|
+
# @since Release 1.0.0
|
44
|
+
#
|
45
|
+
def has_soft_delete?
|
46
|
+
ff_has_column? :ff_soft_delete
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# Is enable to use soft-delete by grove field?
|
51
|
+
#
|
52
|
+
# @author StewEucen
|
53
|
+
# @return [Boolean] true: enable.
|
54
|
+
# @return [Boolean] false: disable.
|
55
|
+
# @since Release 1.0.0
|
56
|
+
#
|
57
|
+
def enable_grove_delete?
|
58
|
+
has_grove? \
|
59
|
+
&& !has_soft_delete? \
|
60
|
+
&& ff_options[:enable_grove_delete]
|
61
|
+
# Need back slashes for this writing.
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Exists field in table?
|
66
|
+
#
|
67
|
+
# @author StewEucen
|
68
|
+
# @param column [Symbol] Column symbol to check.
|
69
|
+
# @return [Boolean] true: has specified column.
|
70
|
+
# @return [Boolean] false: no specified column.
|
71
|
+
# @since Release 1.0.0
|
72
|
+
#
|
73
|
+
def ff_has_column?(column)
|
74
|
+
key = column.to_s
|
75
|
+
attribute_aliases[key] || column_names.include?(key)
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Recommended queue interval for appending node.
|
80
|
+
# Can overwrite [queue interval] at setup()/initialize().
|
81
|
+
#
|
82
|
+
# @author StewEucen
|
83
|
+
# @return [Integer] Default queue interval.
|
84
|
+
# @since Release 1.0.0
|
85
|
+
#
|
86
|
+
def ff_get_query_interval
|
87
|
+
QUEUE_DEFAULT_INTERVAL
|
88
|
+
end
|
89
|
+
|
90
|
+
protected :ff_has_column?,
|
91
|
+
:ff_get_query_interval
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,233 @@
|
|
1
|
+
#
|
2
|
+
# Fertile Forest for Ruby
|
3
|
+
# The new model for storing hierarchical data in a database.
|
4
|
+
#
|
5
|
+
# @author StewEucen
|
6
|
+
# @copyright Copyright (c) 2015 Stew Eucen (http://lab.kochlein.com)
|
7
|
+
# @license http://www.opensource.org/licenses/mit-license.php MIT License
|
8
|
+
#
|
9
|
+
# @link http://lab.kochlein.com/FertileForest
|
10
|
+
# @since File available since Release 1.0.0
|
11
|
+
# @version 1.0.0
|
12
|
+
#
|
13
|
+
module StewEucen
|
14
|
+
# Name space of Stew Eucen's Acts
|
15
|
+
module Acts
|
16
|
+
# Name space of Fertile Forest
|
17
|
+
module FertileForest
|
18
|
+
#
|
19
|
+
# Instance methods to include into derived class by ActiveRecord.
|
20
|
+
#
|
21
|
+
# @author StewEucen
|
22
|
+
# @example Include into ActiveRecord class.
|
23
|
+
# ActiveRecord::Base.send :include, StewEucen::Acts::FertileForest::Entity
|
24
|
+
# @since Release 1.0.0
|
25
|
+
#
|
26
|
+
module Entity
|
27
|
+
#
|
28
|
+
# Before save listener (must be an instance methoed).
|
29
|
+
# Transparently manages setting the required fields for FertileForestBehavior
|
30
|
+
# if the parent field is included in the parameters to be saved.
|
31
|
+
#
|
32
|
+
# @return boolean true:Continue to save./false:Abort to save.
|
33
|
+
#
|
34
|
+
def ff_before_save
|
35
|
+
# when not new record, to update.
|
36
|
+
# no need to set ff_columns (id, grove, queue, depth)
|
37
|
+
return true unless new_record?
|
38
|
+
|
39
|
+
if self.class.has_grove?
|
40
|
+
posted_grove = self.ff_grove
|
41
|
+
if posted_grove.blank?
|
42
|
+
# TODO: set_error
|
43
|
+
return false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# return value
|
48
|
+
self.class.fill_required_columns_to_append!(self)
|
49
|
+
end
|
50
|
+
|
51
|
+
def ff_before_create
|
52
|
+
end
|
53
|
+
|
54
|
+
def ff_after_save
|
55
|
+
end
|
56
|
+
|
57
|
+
def ff_before_destroy
|
58
|
+
end
|
59
|
+
|
60
|
+
protected :ff_before_save,
|
61
|
+
:ff_before_create,
|
62
|
+
:ff_after_save,
|
63
|
+
:ff_before_destroy
|
64
|
+
|
65
|
+
########################################################################
|
66
|
+
|
67
|
+
def ff_reset_values
|
68
|
+
{
|
69
|
+
parent: {0 => nil},
|
70
|
+
children: {},
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
def ff_get_options
|
75
|
+
@fertile_forest ||= ff_reset_values
|
76
|
+
end
|
77
|
+
|
78
|
+
def nest_unset_parent
|
79
|
+
ff_get_options[:parent] = {0 => nil}
|
80
|
+
end
|
81
|
+
|
82
|
+
def nest_unset_children(id = nil)
|
83
|
+
if id.blank?
|
84
|
+
ff_get_options[:children] = {}
|
85
|
+
else
|
86
|
+
ff_get_options[:children][id] = nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
##
|
91
|
+
#
|
92
|
+
# accessors
|
93
|
+
#
|
94
|
+
#
|
95
|
+
########################################################################
|
96
|
+
|
97
|
+
def nest_parent_node
|
98
|
+
ff_get_options[:parent].values.first
|
99
|
+
end
|
100
|
+
|
101
|
+
def nest_child_nodes
|
102
|
+
ff_get_options[:children]
|
103
|
+
end
|
104
|
+
|
105
|
+
def nest_parent_id
|
106
|
+
ff_get_options[:parent].keys.first
|
107
|
+
end
|
108
|
+
|
109
|
+
def nest_child_ids
|
110
|
+
ff_get_options[:children].keys
|
111
|
+
end
|
112
|
+
|
113
|
+
alias nest_parent nest_parent_node
|
114
|
+
alias nest_genitor nest_parent_node
|
115
|
+
alias nest_children nest_child_nodes
|
116
|
+
|
117
|
+
########################################################################
|
118
|
+
|
119
|
+
def nest_set_parent_id(aim_id)
|
120
|
+
ff_get_options[:parent] = {aim_id => nil} # always overwrite
|
121
|
+
end
|
122
|
+
|
123
|
+
def nest_set_child_id(aim_id)
|
124
|
+
ff_get_options[:children][aim_id] = nil
|
125
|
+
end
|
126
|
+
|
127
|
+
########################################################################
|
128
|
+
|
129
|
+
def nest_set_parent_node(aim_id, node)
|
130
|
+
ff_get_options[:parent] = {aim_id => node} \
|
131
|
+
if aim_id.present? && node.present?
|
132
|
+
end
|
133
|
+
|
134
|
+
def nest_set_child_node(aim_id, node)
|
135
|
+
ff_get_options[:children][aim_id] = node \
|
136
|
+
if aim_id.present? && node.present?
|
137
|
+
end
|
138
|
+
|
139
|
+
########################################################################
|
140
|
+
|
141
|
+
def nest_leaf?
|
142
|
+
ff_get_options[:children].blank?
|
143
|
+
end
|
144
|
+
|
145
|
+
def nest_parent?
|
146
|
+
!nest_leaf?
|
147
|
+
end
|
148
|
+
|
149
|
+
########################################################################
|
150
|
+
|
151
|
+
def trunk(range = ANCESTOR_ALL, columns = nil)
|
152
|
+
self.class.trunk(self, range, columns)
|
153
|
+
end
|
154
|
+
|
155
|
+
def ancestors(columns = nil)
|
156
|
+
self.class.ancestors(self, columns)
|
157
|
+
end
|
158
|
+
|
159
|
+
def genitor(columns = nil)
|
160
|
+
self.class.genitor(self, columns)
|
161
|
+
end
|
162
|
+
|
163
|
+
def root(columns = nil)
|
164
|
+
self.class.root(self, columns)
|
165
|
+
end
|
166
|
+
|
167
|
+
def grandparent(columns = nil)
|
168
|
+
self.class.grandparent(self, columns)
|
169
|
+
end
|
170
|
+
|
171
|
+
def subtree(range = DESCENDANTS_ALL, with_top = true, columns = nil)
|
172
|
+
self.class.subtree(self, range, with_top, columns)
|
173
|
+
end
|
174
|
+
|
175
|
+
def descendants(columns = nil)
|
176
|
+
self.class.descendants(self, columns)
|
177
|
+
end
|
178
|
+
|
179
|
+
def children(columns = nil)
|
180
|
+
self.class.children(self, columns)
|
181
|
+
end
|
182
|
+
|
183
|
+
def nth_child(nth = 0, columns = nil)
|
184
|
+
self.class.nth_child(self, nth, columns)
|
185
|
+
end
|
186
|
+
|
187
|
+
def grandchildren(columns = nil)
|
188
|
+
self.class.grandchildren(self, columns)
|
189
|
+
end
|
190
|
+
|
191
|
+
def siblings(columns = nil)
|
192
|
+
self.class.siblings(self, columns)
|
193
|
+
end
|
194
|
+
|
195
|
+
def nth_sibling(nth = 0, columns = nil)
|
196
|
+
self.class.nth_sibling(self, nth, columns)
|
197
|
+
end
|
198
|
+
|
199
|
+
def elder_sibling(columns = nil)
|
200
|
+
self.class.elder_sibling(self, columns)
|
201
|
+
end
|
202
|
+
|
203
|
+
def younger_sibling(columns = nil)
|
204
|
+
self.class.younger_sibling(self, columns)
|
205
|
+
end
|
206
|
+
|
207
|
+
def offset_sibling(offset, columns = nil)
|
208
|
+
self.class.offset_sibling(self, offset, columns)
|
209
|
+
end
|
210
|
+
|
211
|
+
def leaves(columns = nil)
|
212
|
+
self.class.leaves(self, columns)
|
213
|
+
end
|
214
|
+
|
215
|
+
def internals(columns = nil)
|
216
|
+
self.class.internals(self, columns)
|
217
|
+
end
|
218
|
+
|
219
|
+
def height
|
220
|
+
self.class.height(self)
|
221
|
+
end
|
222
|
+
|
223
|
+
def size
|
224
|
+
self.class.size(self)
|
225
|
+
end
|
226
|
+
|
227
|
+
protected :ff_reset_values,
|
228
|
+
:ff_get_options
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
end
|
233
|
+
end
|