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 +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
|