forked from mongodb/mongoid
/
proxy.rb
146 lines (132 loc) · 4.37 KB
/
proxy.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# encoding: utf-8
module Mongoid # :nodoc:
module Relations #:nodoc:
# This class is the superclass for all relation proxy objects, and contains
# common behaviour for all of them.
class Proxy
include Threaded::Lifecycle
# We undefine most methods to get them sent through to the target.
instance_methods.each do |method|
undef_method(method) unless
method =~ /(^__|^send$|^object_id$|^extend$|^respond_to\?$|^tap$)/
end
attr_accessor :base, :loaded, :metadata, :target
# Backwards compatibility with Mongoid beta releases.
delegate :klass, :to => :metadata
delegate :bind_one, :unbind_one, :to => :binding
delegate :collection_name, :to => :base
# Convenience for setting the target and the metadata properties since
# all proxies will need to do this.
#
# @example Initialize the proxy.
# proxy.init(person, name, metadata)
#
# @param [ Document ] base The base document on the proxy.
# @param [ Document, Array<Document> ] target The target of the proxy.
# @param [ Metadata ] metadata The relation's metadata.
#
# @since 2.0.0.rc.1
def init(base, target, metadata)
@base, @target, @metadata = base, target, metadata
yield(self) if block_given?
extend metadata.extension if metadata.extension?
end
# The default substitutable object for a relation proxy is the clone of
# the target.
#
# @example Get the substitutable.
# proxy.substitutable
#
# @return [ Object ] A clone of the target.
#
# @since 2.1.6
def substitutable
target
end
protected
# Get the collection from the root of the hierarchy.
#
# @example Get the collection.
# relation.collection
#
# @return [ Collection ] The root's collection.
#
# @since 2.0.0
def collection
root = base._root
root.collection unless root.embedded?
end
# Return a new document for the type of class we want to instantiate.
# If the type is provided use that, otherwise the klass from the
# metadata.
#
# @example Get an instantiated document.
# proxy.instantiated(Person)
#
# @param [ Class ] type The type of class to instantiate.
#
# @return [ Document ] The freshly created document.
#
# @since 2.0.0.rc.1
def instantiated(type = nil)
type ? type.new : metadata.klass.new
end
# Takes the supplied document and sets the metadata on it.
#
# @example Set the metadata.
# proxt.characterize_one(name)
#
# @param [ Document ] document The document to set on.
#
# @since 2.0.0.rc.4
def characterize_one(document)
document.metadata = metadata unless document.metadata
end
# Default behavior of method missing should be to delegate all calls
# to the target of the proxy. This can be overridden in special cases.
#
# @param [ String, Symbol ] name The name of the method.
# @param [ Array ] *args The arguments passed to the method.
def method_missing(name, *args, &block)
target.send(name, *args, &block)
end
# When the base document illegally references an embedded document this
# error will get raised.
#
# @example Raise the error.
# relation.raise_mixed
#
# @raise [ Errors::MixedRelations ] The error.
#
# @since 2.0.0
def raise_mixed
raise Errors::MixedRelations.new(base.class, metadata.klass)
end
# When the base is not yet saved and the user calls create or create!
# on the relation, this error will get raised.
#
# @example Raise the error.
# relation.raise_unsaved(post)
#
# @param [ Document ] doc The child document getting created.
#
# @raise [ Errors::UnsavedDocument ] The error.
#
# @since 2.0.0.rc.6
def raise_unsaved(doc)
raise Errors::UnsavedDocument.new(base, doc)
end
# Get the class of the root document in the hierarchy.
#
# @example Get the root's class.
# proxy.root_class
#
# @return [ Class ] The root class.
#
# @since 2.1.8
def root_class
@root_class ||= base._root.class
end
end
end
end