acts_as_ordered_tree 1.3.1 → 2.0.0.beta3
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/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
|