mongoid-sleeping_king_studios 0.3.1 → 0.5.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/README.md +53 -43
- data/lib/mongoid/sleeping_king_studios/error.rb +9 -0
- data/lib/mongoid/sleeping_king_studios/has_tree.rb +169 -0
- data/lib/mongoid/sleeping_king_studios/has_tree/cache_ancestry.rb +150 -0
- data/lib/mongoid/sleeping_king_studios/has_tree/errors.rb +24 -0
- data/lib/mongoid/sleeping_king_studios/version.rb +1 -1
- metadata +5 -2
- data/lib/mongoid/sleeping_king_studios/tree.rb +0 -126
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc9bfc29b8eaf26a12fdf6e8779468794c67d352
|
4
|
+
data.tar.gz: a927885e26c3aa375696654acc8d412b96ecc5b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
###
|
8
|
+
### HasTree
|
9
9
|
|
10
|
-
require 'mongoid/sleeping_king_studios/
|
10
|
+
require 'mongoid/sleeping_king_studios/has_tree'
|
11
11
|
|
12
|
-
|
13
|
-
|
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
|
19
|
+
class TreeDocument
|
18
20
|
include Mongoid::Document
|
19
|
-
include Mongoid::SleepingKingStudios::
|
20
|
-
|
21
|
-
field :title, :type => String
|
21
|
+
include Mongoid::SleepingKingStudios::HasTree
|
22
22
|
|
23
|
-
|
23
|
+
has_tree
|
24
24
|
end # class
|
25
25
|
|
26
26
|
#### Options
|
27
27
|
|
28
|
-
|
28
|
+
You can pass customisation options for the generated relations into the
|
29
|
+
::has\_tree method.
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
35
|
+
has_tree :parent => { :relation_name => :overlord },
|
36
|
+
:children => { :relation_name => :minions, :dependent => :destroy }
|
37
|
+
end # class
|
37
38
|
|
38
|
-
|
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
|
-
|
41
|
-
:children relations, as well as some helper methods.
|
45
|
+
#### Cache Ancestry
|
42
46
|
|
43
|
-
|
47
|
+
Stores the chain of ancestors in an :ancestor_ids array field, and adds the
|
48
|
+
\#ancestors and #descendents scopes.
|
44
49
|
|
45
|
-
class
|
50
|
+
class AncestryTree
|
46
51
|
include Mongoid::Document
|
47
|
-
include Mongoid::SleepingKingStudios::
|
52
|
+
include Mongoid::SleepingKingStudios::HasTree
|
53
|
+
|
54
|
+
has_tree :cache_ancestry => true
|
48
55
|
end # class
|
49
56
|
|
50
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
61
|
-
|
66
|
+
Adds a slug field that automatically tracks a base attribute and stores a
|
67
|
+
short, url-friendly version.
|
62
68
|
|
63
|
-
|
64
|
-
{ :relation_name => :overlord }
|
65
|
-
end # class method options_for_parent
|
69
|
+
**How To Use:**
|
66
70
|
|
67
|
-
|
68
|
-
|
69
|
-
|
71
|
+
class SluggableDocument
|
72
|
+
include Mongoid::Document
|
73
|
+
include Mongoid::SleepingKingStudios::Sluggable
|
74
|
+
|
75
|
+
field :title, :type => String
|
70
76
|
|
71
|
-
|
77
|
+
slugify :title
|
72
78
|
end # class
|
73
79
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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
|
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.
|
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
|