activeentity 0.0.1.beta1
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 +7 -0
- data/MIT-LICENSE +42 -0
- data/README.md +145 -0
- data/Rakefile +29 -0
- data/lib/active_entity.rb +73 -0
- data/lib/active_entity/aggregations.rb +276 -0
- data/lib/active_entity/associations.rb +146 -0
- data/lib/active_entity/associations/embedded/association.rb +134 -0
- data/lib/active_entity/associations/embedded/builder/association.rb +100 -0
- data/lib/active_entity/associations/embedded/builder/collection_association.rb +69 -0
- data/lib/active_entity/associations/embedded/builder/embedded_in.rb +38 -0
- data/lib/active_entity/associations/embedded/builder/embeds_many.rb +13 -0
- data/lib/active_entity/associations/embedded/builder/embeds_one.rb +16 -0
- data/lib/active_entity/associations/embedded/builder/singular_association.rb +28 -0
- data/lib/active_entity/associations/embedded/collection_association.rb +188 -0
- data/lib/active_entity/associations/embedded/collection_proxy.rb +310 -0
- data/lib/active_entity/associations/embedded/embedded_in_association.rb +31 -0
- data/lib/active_entity/associations/embedded/embeds_many_association.rb +15 -0
- data/lib/active_entity/associations/embedded/embeds_one_association.rb +19 -0
- data/lib/active_entity/associations/embedded/singular_association.rb +35 -0
- data/lib/active_entity/attribute_assignment.rb +85 -0
- data/lib/active_entity/attribute_decorators.rb +90 -0
- data/lib/active_entity/attribute_methods.rb +330 -0
- data/lib/active_entity/attribute_methods/before_type_cast.rb +78 -0
- data/lib/active_entity/attribute_methods/primary_key.rb +98 -0
- data/lib/active_entity/attribute_methods/query.rb +35 -0
- data/lib/active_entity/attribute_methods/read.rb +47 -0
- data/lib/active_entity/attribute_methods/serialization.rb +90 -0
- data/lib/active_entity/attribute_methods/time_zone_conversion.rb +91 -0
- data/lib/active_entity/attribute_methods/write.rb +63 -0
- data/lib/active_entity/attributes.rb +165 -0
- data/lib/active_entity/base.rb +303 -0
- data/lib/active_entity/coders/json.rb +15 -0
- data/lib/active_entity/coders/yaml_column.rb +50 -0
- data/lib/active_entity/core.rb +281 -0
- data/lib/active_entity/define_callbacks.rb +17 -0
- data/lib/active_entity/enum.rb +234 -0
- data/lib/active_entity/errors.rb +80 -0
- data/lib/active_entity/gem_version.rb +17 -0
- data/lib/active_entity/inheritance.rb +278 -0
- data/lib/active_entity/integration.rb +78 -0
- data/lib/active_entity/locale/en.yml +45 -0
- data/lib/active_entity/model_schema.rb +115 -0
- data/lib/active_entity/nested_attributes.rb +592 -0
- data/lib/active_entity/readonly_attributes.rb +47 -0
- data/lib/active_entity/reflection.rb +441 -0
- data/lib/active_entity/serialization.rb +25 -0
- data/lib/active_entity/store.rb +242 -0
- data/lib/active_entity/translation.rb +24 -0
- data/lib/active_entity/type.rb +73 -0
- data/lib/active_entity/type/date.rb +9 -0
- data/lib/active_entity/type/date_time.rb +9 -0
- data/lib/active_entity/type/decimal_without_scale.rb +15 -0
- data/lib/active_entity/type/hash_lookup_type_map.rb +25 -0
- data/lib/active_entity/type/internal/timezone.rb +17 -0
- data/lib/active_entity/type/json.rb +30 -0
- data/lib/active_entity/type/modifiers/array.rb +72 -0
- data/lib/active_entity/type/registry.rb +92 -0
- data/lib/active_entity/type/serialized.rb +71 -0
- data/lib/active_entity/type/text.rb +11 -0
- data/lib/active_entity/type/time.rb +21 -0
- data/lib/active_entity/type/type_map.rb +62 -0
- data/lib/active_entity/type/unsigned_integer.rb +17 -0
- data/lib/active_entity/validate_embedded_association.rb +305 -0
- data/lib/active_entity/validations.rb +50 -0
- data/lib/active_entity/validations/absence.rb +25 -0
- data/lib/active_entity/validations/associated.rb +60 -0
- data/lib/active_entity/validations/length.rb +26 -0
- data/lib/active_entity/validations/presence.rb +68 -0
- data/lib/active_entity/validations/subset.rb +76 -0
- data/lib/active_entity/validations/uniqueness_in_embedding.rb +99 -0
- data/lib/active_entity/version.rb +10 -0
- data/lib/tasks/active_entity_tasks.rake +6 -0
- metadata +155 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveEntity
|
4
|
+
module ReadonlyAttributes
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
class_attribute :_attr_readonly, instance_accessor: false, default: []
|
9
|
+
end
|
10
|
+
|
11
|
+
def disable_readonly!
|
12
|
+
@_readonly_enabled = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def enable_readonly!
|
16
|
+
@_readonly_enabled = true
|
17
|
+
end
|
18
|
+
|
19
|
+
def enable_readonly
|
20
|
+
return unless block_given?
|
21
|
+
|
22
|
+
disable_readonly!
|
23
|
+
yield self
|
24
|
+
enable_readonly!
|
25
|
+
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
def _readonly_enabled
|
30
|
+
@_readonly_enabled
|
31
|
+
end
|
32
|
+
alias readonly_enabled? _readonly_enabled
|
33
|
+
|
34
|
+
module ClassMethods
|
35
|
+
# Attributes listed as readonly will be used to create a new record but update operations will
|
36
|
+
# ignore these fields.
|
37
|
+
def attr_readonly(*attributes)
|
38
|
+
self._attr_readonly = Set.new(attributes.map(&:to_s)) + (_attr_readonly || [])
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns an array of all the attributes that have been specified as readonly.
|
42
|
+
def readonly_attributes
|
43
|
+
_attr_readonly
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,441 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/string/filters"
|
4
|
+
require "concurrent/map"
|
5
|
+
|
6
|
+
module ActiveEntity
|
7
|
+
# = Active Entity Reflection
|
8
|
+
module Reflection # :nodoc:
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
included do
|
12
|
+
class_attribute :_reflections, instance_writer: false, default: {}
|
13
|
+
class_attribute :aggregate_reflections, instance_writer: false, default: {}
|
14
|
+
end
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def create(macro, name, scope, options, ar_or_ae)
|
18
|
+
reflection = reflection_class_for(macro).new(name, scope, options, ar_or_ae)
|
19
|
+
options[:through] ? ThroughReflection.new(reflection) : reflection
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_reflection(ar_or_ae, name, reflection)
|
23
|
+
ar_or_ae.clear_reflections_cache
|
24
|
+
name = name.to_s
|
25
|
+
ar_or_ae._reflections = ar_or_ae._reflections.except(name).merge!(name => reflection)
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_aggregate_reflection(ae, name, reflection)
|
29
|
+
ae.aggregate_reflections = ae.aggregate_reflections.merge(name.to_s => reflection)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def reflection_class_for(macro)
|
34
|
+
case macro
|
35
|
+
when :composed_of
|
36
|
+
AggregateReflection
|
37
|
+
when :embedded_in
|
38
|
+
EmbeddedInReflection
|
39
|
+
when :embeds_one
|
40
|
+
EmbedsOneReflection
|
41
|
+
when :embeds_many
|
42
|
+
EmbedsManyReflection
|
43
|
+
else
|
44
|
+
raise "Unsupported Macro: #{macro}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# \Reflection enables the ability to examine the associations and aggregations of
|
50
|
+
# Active Entity classes and objects. This information, for example,
|
51
|
+
# can be used in a form builder that takes an Active Entity object
|
52
|
+
# and creates input fields for all of the attributes depending on their type
|
53
|
+
# and displays the associations to other objects.
|
54
|
+
#
|
55
|
+
# MacroReflection class has info for AggregateReflection and AssociationReflection
|
56
|
+
# classes.
|
57
|
+
module ClassMethods
|
58
|
+
# Returns an array of AggregateReflection objects for all the aggregations in the class.
|
59
|
+
def reflect_on_all_aggregations
|
60
|
+
aggregate_reflections.values
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns the AggregateReflection object for the named +aggregation+ (use the symbol).
|
64
|
+
#
|
65
|
+
# Account.reflect_on_aggregation(:balance) # => the balance AggregateReflection
|
66
|
+
#
|
67
|
+
def reflect_on_aggregation(aggregation)
|
68
|
+
aggregate_reflections[aggregation.to_s]
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns a Hash of name of the reflection as the key and an AssociationReflection as the value.
|
72
|
+
#
|
73
|
+
# Account.reflections # => {"balance" => AggregateReflection}
|
74
|
+
#
|
75
|
+
def reflections
|
76
|
+
@__reflections ||= begin
|
77
|
+
ref = {}
|
78
|
+
|
79
|
+
_reflections.each do |name, reflection|
|
80
|
+
parent_reflection = reflection.parent_reflection
|
81
|
+
|
82
|
+
if parent_reflection
|
83
|
+
parent_name = parent_reflection.name
|
84
|
+
ref[parent_name.to_s] = parent_reflection
|
85
|
+
else
|
86
|
+
ref[name] = reflection
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
ref
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns an array of AssociationReflection objects for all the
|
95
|
+
# associations in the class. If you only want to reflect on a certain
|
96
|
+
# association type, pass in the symbol (<tt>:has_many</tt>, <tt>:has_one</tt>,
|
97
|
+
# <tt>:belongs_to</tt>) as the first parameter.
|
98
|
+
#
|
99
|
+
# Example:
|
100
|
+
#
|
101
|
+
# Account.reflect_on_all_associations # returns an array of all associations
|
102
|
+
# Account.reflect_on_all_associations(:has_many) # returns an array of all has_many associations
|
103
|
+
#
|
104
|
+
def reflect_on_all_associations(macro = nil)
|
105
|
+
association_reflections = reflections.values
|
106
|
+
association_reflections.select! { |reflection| reflection.macro == macro } if macro
|
107
|
+
association_reflections
|
108
|
+
end
|
109
|
+
|
110
|
+
# Returns the AssociationReflection object for the +association+ (use the symbol).
|
111
|
+
#
|
112
|
+
# Account.reflect_on_association(:owner) # returns the owner AssociationReflection
|
113
|
+
# Invoice.reflect_on_association(:line_items).macro # returns :has_many
|
114
|
+
#
|
115
|
+
def reflect_on_association(association)
|
116
|
+
reflections[association.to_s]
|
117
|
+
end
|
118
|
+
|
119
|
+
def _reflect_on_association(association) #:nodoc:
|
120
|
+
_reflections[association.to_s]
|
121
|
+
end
|
122
|
+
|
123
|
+
def clear_reflections_cache # :nodoc:
|
124
|
+
@__reflections = nil
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Holds all the methods that are shared between MacroReflection and ThroughReflection.
|
129
|
+
#
|
130
|
+
# AbstractReflection
|
131
|
+
# MacroReflection
|
132
|
+
# AggregateReflection
|
133
|
+
# AssociationReflection
|
134
|
+
# HasManyReflection
|
135
|
+
# HasOneReflection
|
136
|
+
# BelongsToReflection
|
137
|
+
# HasAndBelongsToManyReflection
|
138
|
+
# ThroughReflection
|
139
|
+
# PolymorphicReflection
|
140
|
+
# RuntimeReflection
|
141
|
+
|
142
|
+
class AbstractReflection
|
143
|
+
def embedded?
|
144
|
+
false
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
class AbstractEmbeddedReflection < AbstractReflection # :nodoc:
|
149
|
+
def embedded?
|
150
|
+
true
|
151
|
+
end
|
152
|
+
|
153
|
+
def through_reflection?
|
154
|
+
false
|
155
|
+
end
|
156
|
+
|
157
|
+
# Returns a new, unsaved instance of the associated class. +attributes+ will
|
158
|
+
# be passed to the class's constructor.
|
159
|
+
def build_association(attributes, &block)
|
160
|
+
klass.new(attributes, &block)
|
161
|
+
end
|
162
|
+
|
163
|
+
# Returns the class name for the macro.
|
164
|
+
#
|
165
|
+
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
|
166
|
+
# <tt>has_many :clients</tt> returns <tt>'Client'</tt>
|
167
|
+
def class_name
|
168
|
+
@class_name ||= (options[:class_name] || derive_class_name).to_s
|
169
|
+
end
|
170
|
+
|
171
|
+
def inverse_of
|
172
|
+
return unless inverse_name
|
173
|
+
|
174
|
+
@inverse_of ||= klass._reflect_on_association inverse_name
|
175
|
+
end
|
176
|
+
|
177
|
+
def check_validity_of_inverse!
|
178
|
+
if has_inverse? && inverse_of.nil?
|
179
|
+
raise InverseOfAssociationNotFoundError.new(self)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
protected
|
184
|
+
def actual_source_reflection # FIXME: this is a horrible name
|
185
|
+
self
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Base class for AggregateReflection and AssociationReflection. Objects of
|
190
|
+
# AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
|
191
|
+
class MacroEmbeddedReflection < AbstractEmbeddedReflection
|
192
|
+
# Returns the name of the macro.
|
193
|
+
#
|
194
|
+
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>:balance</tt>
|
195
|
+
# <tt>has_many :clients</tt> returns <tt>:clients</tt>
|
196
|
+
attr_reader :name
|
197
|
+
|
198
|
+
# Returns the hash of options used for the macro.
|
199
|
+
#
|
200
|
+
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>{ class_name: "Money" }</tt>
|
201
|
+
# <tt>has_many :clients</tt> returns <tt>{}</tt>
|
202
|
+
attr_reader :options
|
203
|
+
|
204
|
+
attr_reader :active_entity
|
205
|
+
|
206
|
+
def initialize(name, scope, options, active_entity)
|
207
|
+
@name = name
|
208
|
+
@scope = scope
|
209
|
+
@options = options
|
210
|
+
@active_entity = active_entity
|
211
|
+
@klass = options[:anonymous_class]
|
212
|
+
end
|
213
|
+
|
214
|
+
# Returns the class for the macro.
|
215
|
+
#
|
216
|
+
# <tt>composed_of :balance, class_name: 'Money'</tt> returns the Money class
|
217
|
+
# <tt>has_many :clients</tt> returns the Client class
|
218
|
+
#
|
219
|
+
# class Company < ActiveEntity::Base
|
220
|
+
# has_many :clients
|
221
|
+
# end
|
222
|
+
#
|
223
|
+
# Company.reflect_on_association(:clients).klass
|
224
|
+
# # => Client
|
225
|
+
#
|
226
|
+
# <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
|
227
|
+
# a new association object. Use +build_association+ or +create_association+
|
228
|
+
# instead. This allows plugins to hook into association object creation.
|
229
|
+
def klass
|
230
|
+
@klass ||= compute_class(class_name)
|
231
|
+
end
|
232
|
+
|
233
|
+
def compute_class(name)
|
234
|
+
name.constantize
|
235
|
+
end
|
236
|
+
|
237
|
+
# Returns +true+ if +self+ and +other_aggregation+ have the same +name+ attribute, +active_entity+ attribute,
|
238
|
+
# and +other_aggregation+ has an options hash assigned to it.
|
239
|
+
def ==(other_aggregation)
|
240
|
+
super ||
|
241
|
+
other_aggregation.kind_of?(self.class) &&
|
242
|
+
name == other_aggregation.name &&
|
243
|
+
!other_aggregation.options.nil? &&
|
244
|
+
active_entity == other_aggregation.active_entity
|
245
|
+
end
|
246
|
+
|
247
|
+
private
|
248
|
+
def derive_class_name
|
249
|
+
name.to_s.camelize
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
# Holds all the metadata about an aggregation as it was specified in the
|
254
|
+
# Active Entity class.
|
255
|
+
class AggregateReflection < MacroEmbeddedReflection #:nodoc:
|
256
|
+
def mapping
|
257
|
+
mapping = options[:mapping] || [name, name]
|
258
|
+
mapping.first.is_a?(Array) ? mapping : [mapping]
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
# Holds all the metadata about an association as it was specified in the
|
263
|
+
# Active Entity class.
|
264
|
+
class EmbeddedAssociationReflection < MacroEmbeddedReflection #:nodoc:
|
265
|
+
def compute_class(name)
|
266
|
+
active_entity.send(:compute_type, name)
|
267
|
+
end
|
268
|
+
|
269
|
+
attr_reader :type
|
270
|
+
attr_accessor :parent_reflection # Reflection
|
271
|
+
|
272
|
+
def initialize(name, scope, options, active_entity)
|
273
|
+
super
|
274
|
+
@constructable = calculate_constructable(macro, options)
|
275
|
+
|
276
|
+
if options[:class_name] && options[:class_name].class == Class
|
277
|
+
raise ArgumentError, "A class was passed to `:class_name` but we are expecting a string."
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
def constructable? # :nodoc:
|
282
|
+
@constructable
|
283
|
+
end
|
284
|
+
|
285
|
+
def check_validity!
|
286
|
+
check_validity_of_inverse!
|
287
|
+
end
|
288
|
+
|
289
|
+
def nested?
|
290
|
+
false
|
291
|
+
end
|
292
|
+
|
293
|
+
def has_inverse?
|
294
|
+
inverse_name
|
295
|
+
end
|
296
|
+
|
297
|
+
# Returns the macro type.
|
298
|
+
#
|
299
|
+
# <tt>has_many :clients</tt> returns <tt>:has_many</tt>
|
300
|
+
def macro; raise NotImplementedError; end
|
301
|
+
|
302
|
+
# Returns whether or not this association reflection is for a collection
|
303
|
+
# association. Returns +true+ if the +macro+ is either +has_many+ or
|
304
|
+
# +has_and_belongs_to_many+, +false+ otherwise.
|
305
|
+
def collection?
|
306
|
+
false
|
307
|
+
end
|
308
|
+
|
309
|
+
# Returns whether or not the association should be validated as part of
|
310
|
+
# the parent's validation.
|
311
|
+
#
|
312
|
+
# Unless you explicitly disable validation with
|
313
|
+
# <tt>validate: false</tt>, validation will take place when:
|
314
|
+
#
|
315
|
+
# * you explicitly enable validation; <tt>validate: true</tt>
|
316
|
+
# * you use autosave; <tt>autosave: true</tt>
|
317
|
+
# * the association is a +has_many+ association
|
318
|
+
def validate?
|
319
|
+
!!options[:validate]
|
320
|
+
end
|
321
|
+
|
322
|
+
# Returns +true+ if +self+ is a +belongs_to+ reflection.
|
323
|
+
def embedded_in?; false; end
|
324
|
+
|
325
|
+
# Returns +true+ if +self+ is a +has_one+ reflection.
|
326
|
+
def embeds_one?; false; end
|
327
|
+
|
328
|
+
def association_class; raise NotImplementedError; end
|
329
|
+
|
330
|
+
VALID_AUTOMATIC_INVERSE_MACROS = [:embeds_many, :embeds_one, :embedded_in]
|
331
|
+
|
332
|
+
def extensions
|
333
|
+
Array(options[:extend])
|
334
|
+
end
|
335
|
+
|
336
|
+
private
|
337
|
+
|
338
|
+
def calculate_constructable(_macro, _options)
|
339
|
+
true
|
340
|
+
end
|
341
|
+
|
342
|
+
# Attempts to find the inverse association name automatically.
|
343
|
+
# If it cannot find a suitable inverse association name, it returns
|
344
|
+
# +nil+.
|
345
|
+
def inverse_name
|
346
|
+
unless defined?(@inverse_name)
|
347
|
+
@inverse_name = options.fetch(:inverse_of) { automatic_inverse_of }
|
348
|
+
end
|
349
|
+
|
350
|
+
@inverse_name
|
351
|
+
end
|
352
|
+
|
353
|
+
# returns either +nil+ or the inverse association name that it finds.
|
354
|
+
def automatic_inverse_of
|
355
|
+
return unless can_find_inverse_of_automatically?(self)
|
356
|
+
|
357
|
+
inverse_name_candidates =
|
358
|
+
begin
|
359
|
+
active_entity_name = active_entity.name.demodulize
|
360
|
+
[active_entity_name, ActiveSupport::Inflector.pluralize(active_entity_name)]
|
361
|
+
end
|
362
|
+
|
363
|
+
inverse_name_candidates.map! do |candidate|
|
364
|
+
ActiveSupport::Inflector.underscore(candidate).to_sym
|
365
|
+
end
|
366
|
+
|
367
|
+
inverse_name_candidates.detect do |inverse_name|
|
368
|
+
begin
|
369
|
+
reflection = klass._reflect_on_association(inverse_name)
|
370
|
+
rescue NameError
|
371
|
+
# Give up: we couldn't compute the klass type so we won't be able
|
372
|
+
# to find any associations either.
|
373
|
+
reflection = false
|
374
|
+
end
|
375
|
+
|
376
|
+
valid_inverse_reflection?(reflection)
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
# Checks if the inverse reflection that is returned from the
|
381
|
+
# +automatic_inverse_of+ method is a valid reflection. We must
|
382
|
+
# make sure that the reflection's active_entity name matches up
|
383
|
+
# with the current reflection's klass name.
|
384
|
+
def valid_inverse_reflection?(reflection)
|
385
|
+
reflection &&
|
386
|
+
klass <= reflection.active_entity &&
|
387
|
+
can_find_inverse_of_automatically?(reflection)
|
388
|
+
end
|
389
|
+
|
390
|
+
# Checks to see if the reflection doesn't have any options that prevent
|
391
|
+
# us from being able to guess the inverse automatically. First, the
|
392
|
+
# <tt>inverse_of</tt> option cannot be set to false. Second, we must
|
393
|
+
# have <tt>has_many</tt>, <tt>has_one</tt>, <tt>belongs_to</tt> associations.
|
394
|
+
# Third, we must not have options such as <tt>:foreign_key</tt>
|
395
|
+
# which prevent us from correctly guessing the inverse association.
|
396
|
+
#
|
397
|
+
# Anything with a scope can additionally ruin our attempt at finding an
|
398
|
+
# inverse, so we exclude reflections with scopes.
|
399
|
+
def can_find_inverse_of_automatically?(reflection)
|
400
|
+
reflection.options[:inverse_of] != false &&
|
401
|
+
VALID_AUTOMATIC_INVERSE_MACROS.include?(reflection.macro)
|
402
|
+
end
|
403
|
+
|
404
|
+
def derive_class_name
|
405
|
+
class_name = name.to_s
|
406
|
+
class_name = class_name.singularize if collection?
|
407
|
+
class_name.camelize
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
class EmbedsManyReflection < EmbeddedAssociationReflection # :nodoc:
|
412
|
+
def macro; :embeds_many; end
|
413
|
+
|
414
|
+
def collection?; true; end
|
415
|
+
|
416
|
+
def association_class
|
417
|
+
Associations::Embedded::EmbedsManyAssociation
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
class EmbedsOneReflection < EmbeddedAssociationReflection # :nodoc:
|
422
|
+
def macro; :embeds_one; end
|
423
|
+
|
424
|
+
def embeds_one?; true; end
|
425
|
+
|
426
|
+
def association_class
|
427
|
+
Associations::Embedded::EmbedsOneAssociation
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
class EmbeddedInReflection < EmbeddedAssociationReflection # :nodoc:
|
432
|
+
def macro; :embedded_in; end
|
433
|
+
|
434
|
+
def embedded_in?; true; end
|
435
|
+
|
436
|
+
def association_class
|
437
|
+
Associations::Embedded::EmbeddedInAssociation
|
438
|
+
end
|
439
|
+
end
|
440
|
+
end
|
441
|
+
end
|