acts_as_ordered_tree 1.3.1 → 2.0.0.beta3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/acts_as_ordered_tree.rb +22 -100
- data/lib/acts_as_ordered_tree/adapters.rb +17 -0
- data/lib/acts_as_ordered_tree/adapters/abstract.rb +23 -0
- data/lib/acts_as_ordered_tree/adapters/postgresql.rb +150 -0
- data/lib/acts_as_ordered_tree/adapters/recursive.rb +157 -0
- data/lib/acts_as_ordered_tree/compatibility.rb +22 -0
- data/lib/acts_as_ordered_tree/compatibility/active_record/association_scope.rb +9 -0
- data/lib/acts_as_ordered_tree/compatibility/active_record/default_scoped.rb +19 -0
- data/lib/acts_as_ordered_tree/compatibility/active_record/null_relation.rb +71 -0
- data/lib/acts_as_ordered_tree/compatibility/features.rb +153 -0
- data/lib/acts_as_ordered_tree/deprecate.rb +24 -0
- data/lib/acts_as_ordered_tree/hooks.rb +38 -0
- data/lib/acts_as_ordered_tree/hooks/update.rb +86 -0
- data/lib/acts_as_ordered_tree/instance_methods.rb +92 -453
- data/lib/acts_as_ordered_tree/iterators/arranger.rb +35 -0
- data/lib/acts_as_ordered_tree/iterators/level_calculator.rb +52 -0
- data/lib/acts_as_ordered_tree/iterators/orphans_pruner.rb +58 -0
- data/lib/acts_as_ordered_tree/node.rb +78 -0
- data/lib/acts_as_ordered_tree/node/attributes.rb +48 -0
- data/lib/acts_as_ordered_tree/node/movement.rb +62 -0
- data/lib/acts_as_ordered_tree/node/movements.rb +111 -0
- data/lib/acts_as_ordered_tree/node/predicates.rb +98 -0
- data/lib/acts_as_ordered_tree/node/reloading.rb +49 -0
- data/lib/acts_as_ordered_tree/node/siblings.rb +139 -0
- data/lib/acts_as_ordered_tree/node/traversals.rb +53 -0
- data/lib/acts_as_ordered_tree/persevering_transaction.rb +93 -0
- data/lib/acts_as_ordered_tree/position.rb +143 -0
- data/lib/acts_as_ordered_tree/relation/arrangeable.rb +33 -0
- data/lib/acts_as_ordered_tree/relation/iterable.rb +41 -0
- data/lib/acts_as_ordered_tree/relation/preloaded.rb +46 -11
- data/lib/acts_as_ordered_tree/transaction/base.rb +57 -0
- data/lib/acts_as_ordered_tree/transaction/callbacks.rb +67 -0
- data/lib/acts_as_ordered_tree/transaction/create.rb +68 -0
- data/lib/acts_as_ordered_tree/transaction/destroy.rb +34 -0
- data/lib/acts_as_ordered_tree/transaction/dsl.rb +214 -0
- data/lib/acts_as_ordered_tree/transaction/factory.rb +67 -0
- data/lib/acts_as_ordered_tree/transaction/move.rb +70 -0
- data/lib/acts_as_ordered_tree/transaction/passthrough.rb +12 -0
- data/lib/acts_as_ordered_tree/transaction/reorder.rb +42 -0
- data/lib/acts_as_ordered_tree/transaction/save.rb +64 -0
- data/lib/acts_as_ordered_tree/transaction/update.rb +78 -0
- data/lib/acts_as_ordered_tree/tree.rb +148 -0
- data/lib/acts_as_ordered_tree/tree/association.rb +20 -0
- data/lib/acts_as_ordered_tree/tree/callbacks.rb +57 -0
- data/lib/acts_as_ordered_tree/tree/children_association.rb +120 -0
- data/lib/acts_as_ordered_tree/tree/columns.rb +102 -0
- data/lib/acts_as_ordered_tree/tree/deprecated_columns_accessors.rb +24 -0
- data/lib/acts_as_ordered_tree/tree/parent_association.rb +31 -0
- data/lib/acts_as_ordered_tree/tree/perseverance.rb +19 -0
- data/lib/acts_as_ordered_tree/tree/scopes.rb +56 -0
- data/lib/acts_as_ordered_tree/validators.rb +1 -1
- data/lib/acts_as_ordered_tree/version.rb +1 -1
- data/spec/acts_as_ordered_tree_spec.rb +80 -909
- data/spec/adapters/postgresql_spec.rb +14 -0
- data/spec/adapters/recursive_spec.rb +12 -0
- data/spec/adapters/shared.rb +272 -0
- data/spec/callbacks_spec.rb +177 -0
- data/spec/counter_cache_spec.rb +31 -0
- data/spec/create_spec.rb +110 -0
- data/spec/destroy_spec.rb +57 -0
- data/spec/inheritance_spec.rb +176 -0
- data/spec/move_spec.rb +94 -0
- data/spec/node/movements/concurrent_movements_spec.rb +354 -0
- data/spec/node/movements/move_higher_spec.rb +46 -0
- data/spec/node/movements/move_lower_spec.rb +46 -0
- data/spec/node/movements/move_to_child_of_spec.rb +147 -0
- data/spec/node/movements/move_to_child_with_index_spec.rb +124 -0
- data/spec/node/movements/move_to_child_with_position_spec.rb +85 -0
- data/spec/node/movements/move_to_left_of_spec.rb +120 -0
- data/spec/node/movements/move_to_right_of_spec.rb +120 -0
- data/spec/node/movements/move_to_root_spec.rb +67 -0
- data/spec/node/predicates_spec.rb +211 -0
- data/spec/node/reloading_spec.rb +42 -0
- data/spec/node/siblings_spec.rb +193 -0
- data/spec/node/traversals_spec.rb +71 -0
- data/spec/persevering_transaction_spec.rb +98 -0
- data/spec/relation/arrangeable_spec.rb +88 -0
- data/spec/relation/iterable_spec.rb +104 -0
- data/spec/relation/preloaded_spec.rb +57 -0
- data/spec/reorder_spec.rb +83 -0
- data/spec/spec_helper.rb +30 -38
- data/spec/support/db/boot.rb +22 -0
- data/spec/{db → support/db}/config.travis.yml +2 -0
- data/spec/{db → support/db}/config.yml +1 -0
- data/spec/{db → support/db}/schema.rb +9 -0
- data/spec/support/factories.rb +2 -2
- data/spec/support/matchers.rb +67 -58
- data/spec/support/models.rb +6 -14
- data/spec/support/tree_factory.rb +315 -0
- data/spec/tree/children_association_spec.rb +72 -0
- data/spec/tree/columns_spec.rb +65 -0
- data/spec/tree/scopes_spec.rb +39 -0
- metadata +161 -43
- data/lib/acts_as_ordered_tree/adapters/postgresql_adapter.rb +0 -104
- data/lib/acts_as_ordered_tree/arrangeable.rb +0 -80
- data/lib/acts_as_ordered_tree/class_methods.rb +0 -72
- data/lib/acts_as_ordered_tree/relation/base.rb +0 -26
- data/lib/acts_as_ordered_tree/tenacious_transaction.rb +0 -30
- data/spec/concurrency_support_spec.rb +0 -156
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module ActsAsOrderedTree
|
4
|
+
module Iterators
|
5
|
+
# @api private
|
6
|
+
class Arranger
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
delegate :each, :to => :arrange
|
10
|
+
|
11
|
+
def initialize(collection)
|
12
|
+
@collection = collection
|
13
|
+
@cache = Hash.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def arrange
|
17
|
+
@collection.each_with_object(Hash.new) do |node, result|
|
18
|
+
@cache[node.id] ||= node
|
19
|
+
|
20
|
+
insertion_point = result
|
21
|
+
|
22
|
+
ancestors(node).each { |a| insertion_point = (insertion_point[a] ||= {}) }
|
23
|
+
|
24
|
+
insertion_point[node] = {}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
def ancestors(node)
|
30
|
+
parent = @cache[node.ordered_tree_node.parent_id]
|
31
|
+
parent ? ancestors(parent) + [parent] : []
|
32
|
+
end
|
33
|
+
end # class Arranger
|
34
|
+
end # module Iterators
|
35
|
+
end # module ActsAsOrderedTree
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module ActsAsOrderedTree
|
4
|
+
module Iterators
|
5
|
+
# @api private
|
6
|
+
class LevelCalculator
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
def initialize(collection)
|
10
|
+
@collection = collection
|
11
|
+
@level = nil # minimal nodes level (first item level)
|
12
|
+
end
|
13
|
+
|
14
|
+
def each(&block)
|
15
|
+
return to_enum unless block_given?
|
16
|
+
|
17
|
+
if @collection.klass.ordered_tree.columns.depth?
|
18
|
+
each_with_cached_level(&block)
|
19
|
+
else
|
20
|
+
each_without_cached_level(&block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def each_with_cached_level
|
26
|
+
@collection.each { |node| yield node, node.level }
|
27
|
+
end
|
28
|
+
|
29
|
+
def each_without_cached_level
|
30
|
+
path = []
|
31
|
+
|
32
|
+
@collection.each do |node|
|
33
|
+
parent_id = node.ordered_tree_node.parent_id
|
34
|
+
|
35
|
+
@level ||= node.level
|
36
|
+
path << parent_id if path.empty?
|
37
|
+
|
38
|
+
if parent_id != path.last
|
39
|
+
# parent changed
|
40
|
+
if path.include?(parent_id) # ascend
|
41
|
+
path.pop while path.last != parent_id
|
42
|
+
else # descend
|
43
|
+
path << parent_id
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
yield node, @level + path.length - 1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end # class LevelCalculator
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module ActsAsOrderedTree
|
4
|
+
module Iterators
|
5
|
+
# @api private
|
6
|
+
class OrphansPruner
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
def initialize(collection)
|
10
|
+
@collection = collection
|
11
|
+
@cache = Hash.new
|
12
|
+
@level = nil # minimal node level
|
13
|
+
end
|
14
|
+
|
15
|
+
def each
|
16
|
+
return to_enum unless block_given?
|
17
|
+
|
18
|
+
prepare if @cache.empty?
|
19
|
+
|
20
|
+
@collection.each do |node|
|
21
|
+
if orphan?(node)
|
22
|
+
discard(node.id)
|
23
|
+
else
|
24
|
+
yield node
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
def orphan?(node)
|
31
|
+
!has_parent?(node) && node.level > @level
|
32
|
+
end
|
33
|
+
|
34
|
+
def has_parent?(node)
|
35
|
+
@cache.key?(node.ordered_tree_node.parent_id)
|
36
|
+
end
|
37
|
+
|
38
|
+
def prepare
|
39
|
+
@collection.each do |node|
|
40
|
+
@cache[node.id] = []
|
41
|
+
|
42
|
+
if has_parent?(node)
|
43
|
+
@cache[node.ordered_tree_node.parent_id] << node.id
|
44
|
+
else
|
45
|
+
@level = [@level, node.level].compact.min
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def discard(id)
|
51
|
+
if @cache.key?(id)
|
52
|
+
@cache[id].each { |k| discard(k) }
|
53
|
+
@cache.delete(id)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end # class OrphansPruner
|
57
|
+
end # module Iterators
|
58
|
+
end # module ActsAsOrderedTree
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'acts_as_ordered_tree/node/attributes'
|
4
|
+
require 'acts_as_ordered_tree/node/movements'
|
5
|
+
require 'acts_as_ordered_tree/node/predicates'
|
6
|
+
require 'acts_as_ordered_tree/node/reloading'
|
7
|
+
require 'acts_as_ordered_tree/node/siblings'
|
8
|
+
require 'acts_as_ordered_tree/node/traversals'
|
9
|
+
|
10
|
+
module ActsAsOrderedTree
|
11
|
+
# ActsAsOrderedTree::Node takes care of tree integrity when record is saved
|
12
|
+
# via usual ActiveRecord mechanism
|
13
|
+
class Node
|
14
|
+
include Attributes
|
15
|
+
include Movements
|
16
|
+
include Predicates
|
17
|
+
include Reloading
|
18
|
+
include Siblings
|
19
|
+
include Traversals
|
20
|
+
|
21
|
+
# @attr_reader [ActiveRecord::Base] original AR record, created, updated or destroyed
|
22
|
+
attr_reader :record
|
23
|
+
|
24
|
+
delegate :id, :parent, :children, :==, :to => :record
|
25
|
+
|
26
|
+
def initialize(record)
|
27
|
+
@record = record
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns scope to which record should be applied
|
31
|
+
def scope
|
32
|
+
if tree.columns.scope?
|
33
|
+
tree.base_class.where Hash[tree.columns.scope.map { |column| [column, record[column]] }]
|
34
|
+
else
|
35
|
+
tree.base_class.where(nil)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Convert node to AR::Relation
|
40
|
+
#
|
41
|
+
# @return [ActiveRecord::Relation]
|
42
|
+
def to_relation
|
43
|
+
scope.where(tree.columns.id => id)
|
44
|
+
end
|
45
|
+
|
46
|
+
# @return [ActsAsOrderedTree::Tree]
|
47
|
+
def tree
|
48
|
+
record.class.ordered_tree
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns node level value (0 for root)
|
52
|
+
#
|
53
|
+
# @return [Fixnum]
|
54
|
+
def level
|
55
|
+
case
|
56
|
+
when root? then 0
|
57
|
+
when depth_column_could_be_used? then depth
|
58
|
+
when parent_association_loaded? then parent.level + 1
|
59
|
+
# @todo move it adapters
|
60
|
+
else ancestors.size
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
# @return [Arel::Table]
|
66
|
+
def table
|
67
|
+
record.class.arel_table
|
68
|
+
end
|
69
|
+
|
70
|
+
def depth_column_could_be_used?
|
71
|
+
tree.columns.depth? && record.persisted? && !parent_id_changed? && depth?
|
72
|
+
end
|
73
|
+
|
74
|
+
def parent_association_loaded?
|
75
|
+
record.association(:parent).loaded?
|
76
|
+
end
|
77
|
+
end # class Node
|
78
|
+
end # module ActsAsOrderedTree
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'active_support/concern'
|
4
|
+
|
5
|
+
module ActsAsOrderedTree
|
6
|
+
class Node
|
7
|
+
# This module when included creates accessor to record's attributes that related to tree structure
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# class Node
|
11
|
+
# include Attributes
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# node = Node.new(record)
|
15
|
+
# node.parent_id # => record.parent_id
|
16
|
+
# node.position # => record.position
|
17
|
+
# node.position_was # => record.position_was
|
18
|
+
# # etc.
|
19
|
+
module Attributes
|
20
|
+
extend ActiveSupport::Concern
|
21
|
+
|
22
|
+
METHODS = ['', '?', ?=, '_was', '_changed?', %w(reset_ !)].freeze
|
23
|
+
|
24
|
+
included do
|
25
|
+
dynamic_attribute_accessor :position
|
26
|
+
dynamic_attribute_accessor :parent_id, :parent
|
27
|
+
dynamic_attribute_accessor :depth
|
28
|
+
dynamic_attribute_accessor :counter_cache
|
29
|
+
end
|
30
|
+
|
31
|
+
module ClassMethods
|
32
|
+
# Generates methods based on configurable record attributes
|
33
|
+
#
|
34
|
+
# @api private
|
35
|
+
def dynamic_attribute_accessor(name, column_name_accessor = name)
|
36
|
+
METHODS.each do |prefix, suffix|
|
37
|
+
prefix, suffix = suffix, prefix unless suffix
|
38
|
+
method_name = "#{prefix}#{name}#{suffix}"
|
39
|
+
|
40
|
+
define_method method_name do |*args|
|
41
|
+
record.send "#{prefix}#{tree.columns[column_name_accessor]}#{suffix}", *args
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end # module ClassMethods
|
46
|
+
end # module Attributes
|
47
|
+
end # class Node
|
48
|
+
end # module ActsAsOrderedTree
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'acts_as_ordered_tree/persevering_transaction'
|
4
|
+
|
5
|
+
module ActsAsOrderedTree
|
6
|
+
class Node
|
7
|
+
# @api private
|
8
|
+
class Movement
|
9
|
+
attr_reader :node, :options
|
10
|
+
|
11
|
+
delegate :record, :position, :position=, :to => :node
|
12
|
+
|
13
|
+
def initialize(node, target = nil, options = {}, &block)
|
14
|
+
@node, @options, @block = node, options, block
|
15
|
+
@_target = target
|
16
|
+
end
|
17
|
+
|
18
|
+
def parent=(id_or_record)
|
19
|
+
if id_or_record.is_a?(ActiveRecord::Base)
|
20
|
+
record.parent = id_or_record
|
21
|
+
else
|
22
|
+
node.parent_id = id_or_record
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def start
|
27
|
+
transaction do
|
28
|
+
record.reload
|
29
|
+
|
30
|
+
@block[self] if @block
|
31
|
+
|
32
|
+
record.save
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def target
|
37
|
+
return @target if defined?(@target)
|
38
|
+
|
39
|
+
# load target
|
40
|
+
@target = case @_target
|
41
|
+
when ActiveRecord::Base, nil
|
42
|
+
@_target.lock!
|
43
|
+
when nil
|
44
|
+
nil
|
45
|
+
else
|
46
|
+
scope = node.scope.lock
|
47
|
+
|
48
|
+
if options.fetch(:strict, false)
|
49
|
+
scope.find(@_target)
|
50
|
+
else
|
51
|
+
scope.where(:id => @_target).first
|
52
|
+
end
|
53
|
+
end.try(:ordered_tree_node)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
def transaction(&block)
|
58
|
+
PerseveringTransaction.new(record.class.connection).start(&block)
|
59
|
+
end
|
60
|
+
end # class Movement
|
61
|
+
end # class Node
|
62
|
+
end # module ActsAsOrderedTree
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'active_support/core_ext/module/aliasing'
|
4
|
+
|
5
|
+
require 'acts_as_ordered_tree/node/movement'
|
6
|
+
|
7
|
+
module ActsAsOrderedTree
|
8
|
+
class Node
|
9
|
+
# This module provides node with movement functionality
|
10
|
+
#
|
11
|
+
# Methods:
|
12
|
+
# * move_to_root
|
13
|
+
# * move_left (move_higher)
|
14
|
+
# * move_right (move_lower)
|
15
|
+
# * move_to_left_of (move_to_above_of)
|
16
|
+
# * move_to_right_of (move_to_bottom_of)
|
17
|
+
# * move_to_child_of
|
18
|
+
# * move_to_child_with_index
|
19
|
+
# * move_to_child_with_position
|
20
|
+
module Movements
|
21
|
+
# Transform node into root node
|
22
|
+
def move_to_root
|
23
|
+
movement do |to|
|
24
|
+
to.position = record.root? ? position : nil
|
25
|
+
to.parent = nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Swap node with higher sibling
|
30
|
+
def move_higher
|
31
|
+
movement { self.position -= 1 }
|
32
|
+
end
|
33
|
+
alias_method :move_left, :move_higher
|
34
|
+
|
35
|
+
# Swap node with lower sibling
|
36
|
+
def move_lower
|
37
|
+
movement { self.position += 1 }
|
38
|
+
end
|
39
|
+
alias_method :move_right, :move_lower
|
40
|
+
|
41
|
+
# Move node to above(left) of another node
|
42
|
+
#
|
43
|
+
# @param [ActiveRecord::Base, #to_i] node may be another record of ID
|
44
|
+
def move_to_above_of(node)
|
45
|
+
movement(node, :strict => true) do |to|
|
46
|
+
self.right_sibling = to.target.record
|
47
|
+
end
|
48
|
+
end
|
49
|
+
alias_method :move_to_left_of, :move_to_above_of
|
50
|
+
|
51
|
+
# Move node to bottom (right) of another node
|
52
|
+
#
|
53
|
+
# @param [ActiveRecord::Base, #to_i] node may be another record of ID
|
54
|
+
def move_to_bottom_of(node)
|
55
|
+
movement(node, :strict => true) do |to|
|
56
|
+
self.left_sibling = to.target.record
|
57
|
+
end
|
58
|
+
end
|
59
|
+
alias_method :move_to_right_of, :move_to_bottom_of
|
60
|
+
|
61
|
+
# Move node to child of another node
|
62
|
+
#
|
63
|
+
# @param [ActiveRecord::Base, #to_i] node may be another record of ID
|
64
|
+
def move_to_child_of(node)
|
65
|
+
if node
|
66
|
+
movement(node) do |to|
|
67
|
+
to.parent = node
|
68
|
+
to.position = nil if parent_id_changed?
|
69
|
+
end
|
70
|
+
else
|
71
|
+
move_to_root
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Move node to child of another node with specified index (which may be negative)
|
76
|
+
#
|
77
|
+
# @param [ActiveRecord::Base, Fixnum] node
|
78
|
+
# @param [#to_i] index
|
79
|
+
def move_to_child_with_index(node, index)
|
80
|
+
index = index.to_i
|
81
|
+
|
82
|
+
if index >= 0
|
83
|
+
move_to_child_with_position node, index + 1
|
84
|
+
elsif node
|
85
|
+
movement(node, :strict => true) do |to|
|
86
|
+
to.parent = node
|
87
|
+
to.position = to.target.children.size + index + 1
|
88
|
+
end
|
89
|
+
else
|
90
|
+
move_to_child_with_position nil, scope.roots.size + index + 1
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Move node to child of another node with specified position
|
95
|
+
#
|
96
|
+
# @param [ActiveRecord::Base, Fixnum] node
|
97
|
+
# @param [Integer, nil] position
|
98
|
+
def move_to_child_with_position(node, position)
|
99
|
+
movement(node) do |to|
|
100
|
+
to.parent = node
|
101
|
+
to.position = position
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
def movement(target = nil, options = {}, &block)
|
107
|
+
Movement.new(self, target, options, &block).start
|
108
|
+
end
|
109
|
+
end # module Movements
|
110
|
+
end # class Node
|
111
|
+
end # module ActsAsOrderedTree
|