mongoid-sleeping_king_studios 0.3.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9872d41d59ce51e97ead17d8219802dd80df2069
4
- data.tar.gz: 008ca4394448aa380c101d1aad7b719ca80d7416
3
+ metadata.gz: cc9bfc29b8eaf26a12fdf6e8779468794c67d352
4
+ data.tar.gz: a927885e26c3aa375696654acc8d412b96ecc5b6
5
5
  SHA512:
6
- metadata.gz: 3a8324ecbcdc29f818bf8e2b83b82b48b1df78e1c0ad45938000acf86b388e35fb0eefb8816dfe956b6f63ae8af482aad997f61e352e1a27842060a1c1032c2c
7
- data.tar.gz: 67391ada74283759fd019872dbcb2ca97817c72f2e39c35ff52f226fd157529c4917bf436b0165f2b87bd4eabd80ebb90a6a0a5e8904c793d06494f25424e86a
6
+ metadata.gz: c2913f5069f689cbeedf2d8257096fb88a90755971ea45924771a1e8d3f09c1ed9af2acfd97e57a9e816bceb08b5a083245af455860f6888899d45f9f57b401d
7
+ data.tar.gz: a0216507421c39e39548b138cb9277a185a0fbd1db69594975e6ecf256fc3e78e4aab7655db2eb45b11584b260354f3e24b588743eb80470accb118ca044da8b
data/README.md CHANGED
@@ -5,77 +5,87 @@ documents and collections.
5
5
 
6
6
  ## The Mixins
7
7
 
8
- ### Sluggable
8
+ ### HasTree
9
9
 
10
- require 'mongoid/sleeping_king_studios/sluggable'
10
+ require 'mongoid/sleeping_king_studios/has_tree'
11
11
 
12
- Adds a slug field that automatically tracks a base attribute and stores a
13
- short, url-friendly version.
12
+ Sets up a basic tree structure by adding belongs_to :parent and has_many
13
+ :children relations, as well as some helper methods.
14
+
15
+ From 0.2.0 to 0.3.1, was Mongoid::SleepingKingStudios::Tree
14
16
 
15
17
  **How To Use:**
16
18
 
17
- class SluggableDocument
19
+ class TreeDocument
18
20
  include Mongoid::Document
19
- include Mongoid::SleepingKingStudios::Sluggable
20
-
21
- field :title, :type => String
21
+ include Mongoid::SleepingKingStudios::HasTree
22
22
 
23
- slugify :title
23
+ has_tree
24
24
  end # class
25
25
 
26
26
  #### Options
27
27
 
28
- ##### Lockable
28
+ You can pass customisation options for the generated relations into the
29
+ ::has\_tree method.
29
30
 
30
- slugify :title, :lockable => true
31
-
32
- Allows the slug to be specified manually. Adds an additional slug_lock field
33
- that is automatically set to true when #slug= is called. To resume tracking the
34
- base attribute, set :slug_lock to false.
31
+ class EvilEmployee
32
+ include Mongoid::Document
33
+ include Mongoid::SleepingKingStudios::HasTree
35
34
 
36
- ### Tree
35
+ has_tree :parent => { :relation_name => :overlord },
36
+ :children => { :relation_name => :minions, :dependent => :destroy }
37
+ end # class
37
38
 
38
- require 'mongoid/sleeping_king_studios/tree'
39
+ Available options include the standard Mongoid options for a :belongs_to and a
40
+ :has_many relationship, respectively. In addition, you can set a :relation_name
41
+ option to change the name of the created relation (see example above). The
42
+ concern will automatically update the respective :inverse_of options to match
43
+ the updated relation names.
39
44
 
40
- Sets up a basic tree structure by adding belongs_to :parent and has_many
41
- :children relations, as well as some helper methods.
45
+ #### Cache Ancestry
42
46
 
43
- **How To Use:**
47
+ Stores the chain of ancestors in an :ancestor_ids array field, and adds the
48
+ \#ancestors and #descendents scopes.
44
49
 
45
- class TreeDocument
50
+ class AncestryTree
46
51
  include Mongoid::Document
47
- include Mongoid::SleepingKingStudios::Tree
52
+ include Mongoid::SleepingKingStudios::HasTree
53
+
54
+ has_tree :cache_ancestry => true
48
55
  end # class
49
56
 
50
- #### Options
57
+ **Warning:** using this option will make many write operations much, much
58
+ slower and more resource-intensive. Do not use this option outside of
59
+ read-heavy applications with very specific requirements, e.g. a directory
60
+ structure where you must access all parent directories on each page view.
51
61
 
52
- To customise the created #parent and #children relations, you can define
53
- ::options_for_parent and ::options_for_children class methods before including
54
- the Tree concern. These methods must return a hash if defined.
62
+ ### Sluggable
55
63
 
56
- As of 0.3.1, you can change the name of the class methods used to find the
57
- customised options by setting Tree.options_for_parent_name and
58
- Tree.options_for_children_name.
64
+ require 'mongoid/sleeping_king_studios/sluggable'
59
65
 
60
- class EvilEmployee
61
- include Mongoid::Document
66
+ Adds a slug field that automatically tracks a base attribute and stores a
67
+ short, url-friendly version.
62
68
 
63
- def self.options_for_parent
64
- { :relation_name => :overlord }
65
- end # class method options_for_parent
69
+ **How To Use:**
66
70
 
67
- def self.options_for_children
68
- { :relation_name => :minions, :dependent => :destroy }
69
- end # class method options_for_children
71
+ class SluggableDocument
72
+ include Mongoid::Document
73
+ include Mongoid::SleepingKingStudios::Sluggable
74
+
75
+ field :title, :type => String
70
76
 
71
- include Mongoid::SleepingKingStudios::Tree
77
+ slugify :title
72
78
  end # class
73
79
 
74
- Available options include the default Mongoid options for a :belongs_to and a
75
- :has_many relationship, respectively. In addition, you can set a :relation_name
76
- option to change the name of the created relation (see example above). The
77
- concern will automatically update the respective :inverse_of options to match
78
- the updated relation names.
80
+ #### Options
81
+
82
+ ##### Lockable
83
+
84
+ slugify :title, :lockable => true
85
+
86
+ Allows the slug to be specified manually. Adds an additional slug_lock field
87
+ that is automatically set to true when #slug= is called. To resume tracking the
88
+ base attribute, set :slug_lock to false.
79
89
 
80
90
  ## License
81
91
 
@@ -0,0 +1,9 @@
1
+ # lib/mongoid/sleeping_king_studios/error.rb
2
+
3
+ require 'mongoid/sleeping_king_studios'
4
+
5
+ module Mongoid::SleepingKingStudios
6
+ # Base class for errors thrown by extensions in the
7
+ # Mongoid::SleepingKingStudios namespace.
8
+ class Error < StandardError; end
9
+ end # module
@@ -0,0 +1,169 @@
1
+ # lib/mongoid/sleeping_king_studios/tree.rb
2
+
3
+ require 'mongoid/sleeping_king_studios'
4
+ require 'mongoid/sleeping_king_studios/has_tree/cache_ancestry'
5
+
6
+ module Mongoid::SleepingKingStudios
7
+ # Adds a belongs_to parent relation and a has_many children relation to set
8
+ # up a basic tree structure, as well as several helper methods.
9
+ #
10
+ # @note From 0.2.0 to 0.3.1, was Mongoid::SleepingKingStudios::Tree.
11
+ #
12
+ # @example Setting up the tree:
13
+ # class SluggableDocument
14
+ # include Mongoid::Document
15
+ # include Mongoid::SleepingKingStudios::Tree
16
+ #
17
+ # has_tree
18
+ # end # class
19
+ #
20
+ # Since 0.4.1, you must call the class method ::has_tree in order to set up
21
+ # the parent and children relations. You can pass optional parameters into
22
+ # this method to customise the created relations, including the names of the
23
+ # relations.
24
+ #
25
+ # @example Setting up the tree with alternate relation names:
26
+ # class EvilEmployee
27
+ # include Mongoid::Document
28
+ # include Mongoid::SleepingKingStudios::Tree
29
+ #
30
+ # has_tree :parent => { :relation_name => 'overlord' },
31
+ # :children => { :relation_name => 'minions', :dependent => :destroy }
32
+ # end # class
33
+ #
34
+ # @since 0.2.0
35
+ module HasTree
36
+ extend ActiveSupport::Concern
37
+
38
+ # Get the valid options allowed with this concern.
39
+ #
40
+ # @return [ Array<Symbol> ] The valid options.
41
+ #
42
+ # @since 0.4.1
43
+ def self.valid_options
44
+ %i(
45
+ cache_ancestry
46
+ children
47
+ parent
48
+ ) # end Array
49
+ end # class method valid_options
50
+
51
+ # @!method parent
52
+ # Returns the parent object, or nil if the object is a root.
53
+ #
54
+ # @return [Tree, nil]
55
+
56
+ # @!method children
57
+ # Returns the list of child objects.
58
+ #
59
+ # @return [Array<Tree>]
60
+
61
+ # Class methods added to the base class via #extend.
62
+ module ClassMethods
63
+ # @overload has_tree(options = {})
64
+ # Sets up the relations necessary for the tree structure.
65
+ #
66
+ # @param [Hash] options The options for the relation and the concern as a
67
+ # whole.
68
+ # @option options [Hash] :parent ({}) The options for the parent
69
+ # relation. Supports the :relation_name option, which sets the name of
70
+ # the tree's :belongs_to relation, as well as any options normally
71
+ # supported by a :belongs_to relation.
72
+ # @option options [Hash] :children ({}) The options for the children
73
+ # relation. Supports the :relation_name options, which sets the name of
74
+ # the tree's :has_many relation, as well as any options normally
75
+ # supported by a :has_many relation.
76
+ # @option options [Boolean] :cache_ancestry (false) Stores the chain of
77
+ # ancestors in an :ancestor_ids array field. Adds the #ancestors and
78
+ # #descendents scopes.
79
+ #
80
+ # Warning: using this option will make many write operations much,
81
+ # much slower and more resource-intensive. Do not use this option
82
+ # outside of read-heavy applications with very specific requirements,
83
+ # e.g. a directory structure where you must access all parent
84
+ # directories on each page view.
85
+ #
86
+ # @see Mongoid::SleepingKingStudios::HasTree::CacheAncestry
87
+ #
88
+ # @raise [ Mongoid::Errors::InvalidOptions ] If the options are invalid.
89
+ #
90
+ # @since 0.4.0
91
+ def has_tree **options
92
+ validate_options options
93
+
94
+ # Create Relations
95
+ p_opts = { :relation_name => :parent, :class_name => self.name }
96
+ c_opts = { :relation_name => :children, :class_name => self.name }
97
+
98
+ p_opts.update(options[:parent]) if Hash === options[:parent]
99
+ c_opts.update(options[:children]) if Hash === options[:children]
100
+
101
+ p_opts.update :inverse_of => c_opts[:relation_name]
102
+ c_opts.update :inverse_of => p_opts[:relation_name]
103
+
104
+ belongs_to p_opts.delete(:relation_name), p_opts
105
+ has_many c_opts.delete(:relation_name), c_opts
106
+
107
+ options[:parent] = p_opts
108
+ options[:children] = c_opts
109
+
110
+ # Set Up Ancestry Cache
111
+ if options.has_key? :cache_ancestry
112
+ self.send :include, Mongoid::SleepingKingStudios::HasTree::CacheAncestry
113
+ self.send :cache_ancestry, **options
114
+ end # if
115
+
116
+ self
117
+ end # class method has_tree
118
+
119
+ # Returns a Criteria specifying all root objects, e.g. objects with no
120
+ # parent object.
121
+ #
122
+ # @return [Mongoid::Criteria]
123
+ def roots
124
+ where({ :parent_id => nil })
125
+ end # scope routes
126
+
127
+ private
128
+
129
+ # Determine if the provided options are valid for the concern.
130
+ #
131
+ # @param [ Hash ] options The options to check.
132
+ #
133
+ # @raise [ Mongoid::Errors::InvalidOptions ] If the options are invalid.
134
+ def validate_options options
135
+ valid_options = Mongoid::SleepingKingStudios::HasTree.valid_options
136
+ options.keys.each do |key|
137
+ if !valid_options.include?(key)
138
+ raise Mongoid::Errors::InvalidOptions.new(
139
+ :has_tree,
140
+ key,
141
+ valid_options
142
+ ) # end InvalidOptions
143
+ end # if
144
+ end # each
145
+ end # class method validate_options
146
+ end # module
147
+
148
+ # Returns the root object of the current object's tree.
149
+ #
150
+ # @return [Tree]
151
+ def root
152
+ parent ? parent.root : self
153
+ end # method root
154
+
155
+ # Returns true if the object is a leaf object, e.g. has no child objects.
156
+ #
157
+ # @return [Boolean] True if the object has no children; otherwise false.
158
+ def leaf?
159
+ children.empty?
160
+ end # method leaf?
161
+
162
+ # Returns true if the object is a root object, e.g. has no parent object.
163
+ #
164
+ # @return [Boolean] True if the object has no parent; otherwise false.
165
+ def root?
166
+ parent.nil?
167
+ end # method root?
168
+ end # module
169
+ end # module
@@ -0,0 +1,150 @@
1
+ # lib/mongoid/sleeping_king_studios/has_tree/cache_ancestry.rb
2
+
3
+ require 'mongoid/sleeping_king_studios'
4
+ require 'mongoid/sleeping_king_studios/has_tree/errors'
5
+
6
+ module Mongoid::SleepingKingStudios
7
+ module HasTree
8
+ # Adds #ancestors and #descendents methods for accessing ancestors and
9
+ # subtrees with a single read operation. Do not include this module
10
+ # directly; rather, add a :cache_ancestry => true options to the call
11
+ # to ::has_tree.
12
+ #
13
+ # @example Setting up a tree with ancestry cache:
14
+ # class SluggableDocument
15
+ # include Mongoid::Document
16
+ # include Mongoid::SleepingKingStudios::Tree
17
+ #
18
+ # has_tree :cache_ancestry => true
19
+ # end # class
20
+ #
21
+ # @since 0.5.0
22
+ module CacheAncestry
23
+ extend ActiveSupport::Concern
24
+
25
+ # @!attribute [r] ancestor_ids
26
+ # Stores the ids of the object's ancestors, starting from the root
27
+ # object of the current subtree to the object's current parent. If
28
+ # the object has no parent, returns an empty array.
29
+ #
30
+ # @return [Array] The ancestors' ids.
31
+ #
32
+ # @since 0.5.0
33
+
34
+ # Class methods added to the base class via #extend.
35
+ module ClassMethods
36
+ # @overload cache_ancestry()
37
+ # Adds the :ancestry_id field, the #ancestors and #descendents
38
+ # scopes, and redefines #parent_id= to update the :ancestry_id
39
+ # field on the object and its descendents.
40
+ #
41
+ # Do not call this method directly; rather, add a
42
+ # :cache_ancestry => true options to the call to ::has_tree.
43
+ def cache_ancestry **options
44
+ parent_name = options[:children][:inverse_of]
45
+ children_name = options[:parent][:inverse_of]
46
+
47
+ field :ancestor_ids, :type => Array, :default => []
48
+
49
+ alias_method :"set_parent_id", :"#{parent_name}_id="
50
+ private :set_parent_id
51
+ re_define_method "#{parent_name}_id=" do |value|
52
+ old_ancestor_ids = ancestor_ids.dup
53
+
54
+ set_parent_id value
55
+ new_ancestor_ids = parent ? parent.ancestor_ids + [parent.id] : []
56
+
57
+ descendents.each do |descendent|
58
+ ary = descendent.ancestor_ids.dup
59
+ ary[0..old_ancestor_ids.count] = new_ancestor_ids + [id]
60
+ descendent.update_attributes :ancestor_ids => ary
61
+ end # each
62
+
63
+ self.send :ancestor_ids=, new_ancestor_ids
64
+ end # method #{parent_name}_id=
65
+ end # class method cache_ancestry
66
+ end # module ClassMethods
67
+
68
+ # Returns an array of the current object's ancestors, from the root
69
+ # object to the current parent. If the object has no parent, returns an
70
+ # empty array. If an error is raised, consider calling #rebuild_ancestry!
71
+ #
72
+ # @raise [Mongoid::SleepingKingStudios::HasTree::Errors::MissingAncestor]
73
+ # If one or more of the ancestors is not found in the datastore (the id
74
+ # is wrong, the object is not persisted, there is a nil value in
75
+ # ancestor_ids, and so on).
76
+ #
77
+ # @return [Array] The objects' ancestors
78
+ def ancestors
79
+ self.class.find(ancestor_ids)
80
+ rescue Mongoid::Errors::DocumentNotFound, Mongoid::Errors::InvalidFind
81
+ raise Mongoid::SleepingKingStudios::HasTree::Errors::MissingAncestor.new ancestor_ids
82
+ end # method ancestors
83
+
84
+ # Returns a scope for all of the descendents of the current object, i.e.
85
+ # all objects that have the current object as an ancestor.
86
+ #
87
+ # @return [Mongoid::Criteria] The criteria for finding the descendents.
88
+ def descendents
89
+ criteria = self.class.all
90
+
91
+ ancestor_ids.each_with_index do |ancestor_id, index|
92
+ criteria = criteria.where(:"ancestor_ids.#{index}" => ancestor_id)
93
+ end # each
94
+
95
+ criteria.where(:"ancestor_ids.#{ancestor_ids.count}" => id)
96
+ end # scope descendents
97
+
98
+ # Travels up the tree using the #parent method and saves the ancestors to
99
+ # the :ancestor_ids field. This overwrites the value of :ancestor_ids on
100
+ # the current object, but not on any of its ancestors.
101
+ #
102
+ # @raise [Mongoid::SleepingKingStudios::HasTree::Errors::MissingAncestor]
103
+ # If the current object or an ancestor has an invalid #parent.
104
+ def rebuild_ancestry!
105
+ ary, object = [], self
106
+ while object.parent
107
+ ary.unshift object.parent.id
108
+ object = object.parent
109
+ end # while
110
+ self.send :ancestor_ids=, ary
111
+ rescue Mongoid::Errors::DocumentNotFound
112
+ raise Mongoid::SleepingKingStudios::HasTree::Errors::MissingAncestor.new object.parent_id
113
+ end # method rebuild_ancestry!
114
+
115
+ # Travels up the tree using the :ancestor_ids and ensures that each
116
+ # ancestor exists and is persisted to the database, and that the
117
+ # object's parent correctly matches the last value in its own
118
+ # :ancestor_ids field.
119
+ #
120
+ # @raise [Mongoid::SleepingKingStudios::HasTree::Errors::MissingAncestor]
121
+ # If any of the ancestors is not found in the datastore (the id is
122
+ # wrong, the object is not persisted, there is a nil value in
123
+ # ancestor_ids, and so on).
124
+ #
125
+ # @raise [Mongoid::SleepingKingStudios::HasTree::Errors::UnexpectedAncestor]
126
+ # If there is a mismatch between an object's #parent and the last value
127
+ # in the object's :ancestor_ids field.
128
+ def validate_ancestry!
129
+ return if ancestor_ids.empty?
130
+
131
+ ancestors = []
132
+ ancestor_ids.each_with_index do |ancestor_id, index|
133
+ begin
134
+ ancestor = self.class.find(ancestor_id)
135
+ ancestors << ancestor
136
+
137
+ if index > 0 && ancestor.parent_id != ancestor_ids[index - 1]
138
+ # If the ancestor's parent is not the same as the previous
139
+ # ancestor.
140
+ raise Mongoid::SleepingKingStudios::HasTree::Errors::UnexpectedAncestor.new ancestor.parent_id, ancestor_ids[index - 1]
141
+ end # if
142
+ rescue Mongoid::Errors::InvalidFind, Mongoid::Errors::DocumentNotFound
143
+ # If the ancestor id is nil, or the ancestor does not exist.
144
+ raise Mongoid::SleepingKingStudios::HasTree::Errors::MissingAncestor.new ancestor_id
145
+ end # begin-rescue
146
+ end # each
147
+ end # method validate_ancestry!
148
+ end # module
149
+ end # module
150
+ end # module
@@ -0,0 +1,24 @@
1
+ # lib/mongoid/sleeping_king_studios/has_tree/errors.rb
2
+
3
+ require 'mongoid/sleeping_king_studios/error'
4
+
5
+ module Mongoid::SleepingKingStudios
6
+ module HasTree
7
+ module Errors
8
+ class MissingAncestor < Mongoid::SleepingKingStudios::Error
9
+ def initialize ancestor_id
10
+ message = Array === ancestor_id ?
11
+ 'ancestors with ids' :
12
+ 'ancestor with id'
13
+ super "unable to find #{message} #{ancestor_id.inspect}"
14
+ end # constructor
15
+ end # class
16
+
17
+ class UnexpectedAncestor < Mongoid::SleepingKingStudios::Error
18
+ def initialize expected_id, received_id
19
+ super "expected ancestor with id #{expected_id.inspect}, but received id #{received_id.inspect}"
20
+ end # constructor
21
+ end # class
22
+ end # module Errors
23
+ end # module
24
+ end # module
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Mongoid
4
4
  module SleepingKingStudios
5
- VERSION = '0.3.1'
5
+ VERSION = '0.5.0'
6
6
  end # module
7
7
  end # module
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid-sleeping_king_studios
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rob "Merlin" Smith
@@ -146,8 +146,11 @@ executables: []
146
146
  extensions: []
147
147
  extra_rdoc_files: []
148
148
  files:
149
+ - lib/mongoid/sleeping_king_studios/error.rb
150
+ - lib/mongoid/sleeping_king_studios/has_tree/cache_ancestry.rb
151
+ - lib/mongoid/sleeping_king_studios/has_tree/errors.rb
152
+ - lib/mongoid/sleeping_king_studios/has_tree.rb
149
153
  - lib/mongoid/sleeping_king_studios/sluggable.rb
150
- - lib/mongoid/sleeping_king_studios/tree.rb
151
154
  - lib/mongoid/sleeping_king_studios/version.rb
152
155
  - lib/mongoid/sleeping_king_studios.rb
153
156
  - LICENSE
@@ -1,126 +0,0 @@
1
- # lib/mongoid/sleeping_king_studios/tree.rb
2
-
3
- require 'mongoid/sleeping_king_studios'
4
-
5
- module Mongoid::SleepingKingStudios
6
- # Adds a belongs_to parent relation and a has_many children relation to set
7
- # up a basic tree structure, as well as several helper methods.
8
- #
9
- # @example Setting up the tree:
10
- # class SluggableDocument
11
- # include Mongoid::Document
12
- # include Mongoid::SleepingKingStudios::Tree
13
- # end # class
14
- #
15
- # Since 0.3.0, you can customise the generated :parent and :children
16
- # relations by defining optional class methods ::options_for_parent and
17
- # ::options_for_children, which must return hashes of valid options. These
18
- # must be defined prior to including this mixin, or the default options will
19
- # be applied instead.
20
- #
21
- # In addition, you can customise the names of the relations by adding a
22
- # :relation_name key to either ::options_for hash. The concern will
23
- # automatically update the respective :inverse_of options to match the
24
- # updated relation names.
25
- #
26
- # Since 0.3.1, you can additionally customise the name of the class methods
27
- # used to determine the customised options by changing the value of
28
- # Tree.options_for_parent_name and Tree.options_for_children_name.
29
- #
30
- # @example Setting up the tree with alternate relation names:
31
- # class EvilEmployee
32
- # include Mongoid::Document
33
- #
34
- # def self.options_for_parent
35
- # { :relation_name => "overlord" }
36
- # end # class method options_for_parent
37
- #
38
- # def self.options_for_children
39
- # { :relation_name => "minions", :dependent => :destroy }
40
- # end # class method options_for_children
41
- #
42
- # include Mongoid::SleepingKingStudios::Tree
43
- # end # class
44
- #
45
- # @since 0.2.0
46
- module Tree
47
- extend ActiveSupport::Concern
48
-
49
- class << self
50
- # Gets the name of the method on the base module that is used to find
51
- # customisation options for the :parent relation.
52
- #
53
- # @return [Symbol] By default, returns :options_for_parent.
54
- #
55
- # @since 0.3.1
56
- attr_accessor :options_for_parent_name
57
-
58
- # Gets the name of the method on the base module that is used to find
59
- # customisation options for the :children relation.
60
- #
61
- # @return [Symbol] By default, returns :options_for_children.
62
- #
63
- # @since 0.3.1
64
- attr_accessor :options_for_children_name
65
- end # class << self
66
-
67
- self.options_for_parent_name = :options_for_parent
68
- self.options_for_children_name = :options_for_children
69
-
70
- # @!method parent
71
- # Returns the parent object, or nil if the object is a root.
72
- #
73
- # @return [Tree, nil]
74
-
75
- # @!method children
76
- # Returns the list of child objects.
77
- #
78
- # @return [Array<Tree>]
79
-
80
- included do |base|
81
- p_opts = { :relation_name => :parent, :class_name => base.name }
82
- c_opts = { :relation_name => :children, :class_name => base.name }
83
-
84
- p_opts.update(send Tree.options_for_parent_name) if respond_to?(Tree.options_for_parent_name)
85
- c_opts.update(send Tree.options_for_children_name) if respond_to?(Tree.options_for_children_name)
86
-
87
- p_opts.update :inverse_of => c_opts[:relation_name]
88
- c_opts.update :inverse_of => p_opts[:relation_name]
89
-
90
- belongs_to p_opts.delete(:relation_name), p_opts
91
- has_many c_opts.delete(:relation_name), c_opts
92
- end # included
93
-
94
- # Class methods added to the base class via #extend.
95
- module ClassMethods
96
- # Returns a Criteria specifying all root objects, e.g. objects with no
97
- # parent object.
98
- #
99
- # @return [Mongoid::Criteria]
100
- def roots
101
- where({ :parent_id => nil })
102
- end # scope routes
103
- end # module
104
-
105
- # Returns the root object of the current object's tree.
106
- #
107
- # @return [Tree]
108
- def root
109
- parent ? parent.root : self
110
- end # method root
111
-
112
- # Returns true if the object is a leaf object, e.g. has no child objects.
113
- #
114
- # @return [Boolean] True if the object has no children; otherwise false.
115
- def leaf?
116
- children.empty?
117
- end # method leaf?
118
-
119
- # Returns true if the object is a root object, e.g. has no parent object.
120
- #
121
- # @return [Boolean] True if the object has no parent; otherwise false.
122
- def root?
123
- parent.nil?
124
- end # method root?
125
- end # module
126
- end # module