og 0.31.0 → 0.40.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.
- data/doc/{AUTHORS → CONTRIBUTORS} +26 -10
- data/doc/LICENSE +2 -3
- data/doc/RELEASES +56 -7
- data/doc/tutorial.txt +15 -15
- data/lib/glue/cacheable.rb +2 -5
- data/lib/glue/hierarchical.rb +1 -4
- data/lib/glue/optimistic_locking.rb +0 -2
- data/lib/glue/orderable.rb +79 -75
- data/lib/glue/revisable.rb +19 -24
- data/lib/glue/searchable.rb +0 -2
- data/lib/glue/taggable.rb +31 -29
- data/lib/glue/timestamped.rb +4 -2
- data/lib/og.rb +50 -29
- data/lib/og/adapter.rb +19 -0
- data/lib/og/adapter/mysql.rb +212 -0
- data/lib/og/adapter/mysql/override.rb +34 -0
- data/lib/og/adapter/mysql/script.rb +15 -0
- data/lib/og/adapter/mysql/utils.rb +40 -0
- data/lib/og/adapter/postgresql.rb +231 -0
- data/lib/og/adapter/postgresql/override.rb +117 -0
- data/lib/og/adapter/postgresql/script.rb +15 -0
- data/lib/og/adapter/postgresql/utils.rb +35 -0
- data/lib/og/adapter/sqlite.rb +132 -0
- data/lib/og/adapter/sqlite/override.rb +33 -0
- data/lib/og/adapter/sqlite/script.rb +15 -0
- data/lib/og/collection.rb +35 -7
- data/lib/og/{evolution.rb → dump.rb} +4 -5
- data/lib/og/entity.rb +102 -173
- data/lib/og/entity/clone.rb +119 -0
- data/lib/og/errors.rb +0 -2
- data/lib/og/manager.rb +85 -37
- data/lib/og/relation.rb +52 -34
- data/lib/og/relation/belongs_to.rb +0 -2
- data/lib/og/relation/has_many.rb +27 -4
- data/lib/og/relation/joins_many.rb +41 -14
- data/lib/og/relation/many_to_many.rb +10 -0
- data/lib/og/relation/refers_to.rb +22 -5
- data/lib/og/store.rb +80 -86
- data/lib/og/store/sql.rb +710 -713
- data/lib/og/store/sql/evolution.rb +119 -0
- data/lib/og/store/sql/join.rb +155 -0
- data/lib/og/store/sql/utils.rb +149 -0
- data/lib/og/test/assertions.rb +1 -3
- data/lib/og/test/testcase.rb +0 -2
- data/lib/og/types.rb +2 -5
- data/lib/og/validation.rb +6 -9
- data/test/{og/mixin → glue}/tc_hierarchical.rb +3 -13
- data/test/glue/tc_og_paginate.rb +47 -0
- data/test/{og/mixin → glue}/tc_optimistic_locking.rb +2 -12
- data/test/{og/mixin → glue}/tc_orderable.rb +15 -23
- data/test/glue/tc_orderable2.rb +47 -0
- data/test/glue/tc_revisable.rb +3 -3
- data/test/{og/mixin → glue}/tc_taggable.rb +20 -10
- data/test/{og/mixin → glue}/tc_timestamped.rb +2 -12
- data/test/glue/tc_webfile.rb +36 -0
- data/test/og/CONFIG.rb +8 -11
- data/test/og/multi_validations_model.rb +14 -0
- data/test/og/store/tc_filesys.rb +3 -1
- data/test/og/store/tc_kirby.rb +16 -13
- data/test/og/store/tc_sti.rb +11 -11
- data/test/og/store/tc_sti2.rb +79 -0
- data/test/og/tc_build.rb +41 -0
- data/test/og/tc_cacheable.rb +3 -2
- data/test/og/tc_has_many.rb +96 -0
- data/test/og/tc_inheritance.rb +6 -4
- data/test/og/tc_joins_many.rb +93 -0
- data/test/og/tc_multi_validations.rb +5 -7
- data/test/og/tc_multiple.rb +7 -6
- data/test/og/tc_override.rb +13 -7
- data/test/og/tc_primary_key.rb +30 -0
- data/test/og/tc_relation.rb +8 -14
- data/test/og/tc_reldelete.rb +163 -0
- data/test/og/tc_reverse.rb +17 -14
- data/test/og/tc_scoped.rb +3 -11
- data/test/og/tc_setup.rb +13 -11
- data/test/og/tc_store.rb +21 -28
- data/test/og/tc_validation2.rb +2 -2
- data/test/og/tc_validation_loop.rb +17 -15
- metadata +109 -103
- data/INSTALL +0 -91
- data/ProjectInfo +0 -51
- data/README +0 -177
- data/doc/config.txt +0 -28
- data/examples/README +0 -23
- data/examples/mysql_to_psql.rb +0 -71
- data/examples/run.rb +0 -271
- data/lib/glue/tree.rb +0 -218
- data/lib/og/store/alpha/filesys.rb +0 -110
- data/lib/og/store/alpha/memory.rb +0 -295
- data/lib/og/store/alpha/sqlserver.rb +0 -256
- data/lib/og/store/kirby.rb +0 -490
- data/lib/og/store/mysql.rb +0 -415
- data/lib/og/store/psql.rb +0 -875
- data/lib/og/store/sqlite.rb +0 -348
- data/lib/og/store/sqlite2.rb +0 -241
- data/setup.rb +0 -1585
- data/test/og/tc_sti_find.rb +0 -35
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'og/entity'
|
2
|
+
|
3
|
+
# Add cloning functionality to entities.
|
4
|
+
#--
|
5
|
+
# WARNING, gmosx: I haven't tested this extensively,
|
6
|
+
# this is a donated patch.
|
7
|
+
#++
|
8
|
+
|
9
|
+
module EntityMixin
|
10
|
+
|
11
|
+
def og_clone(*args)
|
12
|
+
Og::Entity.clone(self,*args)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
class Entity
|
18
|
+
|
19
|
+
class << self
|
20
|
+
|
21
|
+
# Entity copying support. Eventually this should all
|
22
|
+
# be eval'd in at enchanting stage for the minor
|
23
|
+
# speed increase.
|
24
|
+
# TODO: Convert to enchantments on objects
|
25
|
+
|
26
|
+
# Accepts source object, destination and ignore.
|
27
|
+
# Source and destination are self explanatory; ignore
|
28
|
+
# is a list of properties not to copy (i.e.
|
29
|
+
# :create_time,:update_time).
|
30
|
+
# By default sets the class variables directly on the
|
31
|
+
# remote model instance, if you set use_setter_method to
|
32
|
+
# true, uses create_time= style copying tactics,
|
33
|
+
|
34
|
+
def copy_properties(source, destination, ignore = [], use_setter_method = false)
|
35
|
+
property_copier(source, destination, ignore, use_setter_method, false)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Copies relations of one record to another. Only copies
|
39
|
+
# has_one, refers_to, belongs_to relationships as
|
40
|
+
# has_many requires modifying of other objects and
|
41
|
+
# cannot be copied (by design). If you think you need to copy
|
42
|
+
# these relations, what you need is a joins_many relationship
|
43
|
+
# which can be copied.
|
44
|
+
|
45
|
+
def copy_inferior_relations(source, destination, ignore = [])
|
46
|
+
real_ignore = Array.new
|
47
|
+
|
48
|
+
# Map relation symbols to foreign keys.
|
49
|
+
|
50
|
+
ignore.each do |symbol|
|
51
|
+
source.class.relations.reject{|r| [Og::JoinsMany, Og::ManyToMany, Og::HasMany].include?(r.class)}.each do |relation|
|
52
|
+
if relation.name == symbol.to_s
|
53
|
+
real_ignore << relation.foreign_key.to_sym
|
54
|
+
break
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Use instance variable property copier method.
|
60
|
+
|
61
|
+
property_copier(source, destination, real_ignore, false, true)
|
62
|
+
end
|
63
|
+
|
64
|
+
def copy_equal_relations(source, destination, ignore = [])
|
65
|
+
source.class.relations.reject{|r| not [Og::JoinsMany, Og::ManyToMany].include?(r.class)}.each do |relation|
|
66
|
+
next if relation.name == nil or ignore.include?(relation.name)
|
67
|
+
source.send(relation.name).each do |related|
|
68
|
+
destination.send(relation.name).send(:<<, related)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Copies all relations *except* HasMany which is impossible
|
74
|
+
# to copy. Use a JoinsMany relation instead if you need a
|
75
|
+
# copyable HasMany (which is irrational).
|
76
|
+
|
77
|
+
def copy_relations(source, destination, ignore = [])
|
78
|
+
copy_inferior_relations(source, destination, ignore)
|
79
|
+
copy_equal_relations(source, destination, ignore)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Clones an object in every possible way (cannot copy
|
83
|
+
# HasMany but can copy all others - BelongsTo, etc).
|
84
|
+
# Provide a source object as first arguments, the rest
|
85
|
+
# (if any) are passed along to the initialize constructor
|
86
|
+
# when calling new to make the copied object.
|
87
|
+
|
88
|
+
def clone(source,*args)
|
89
|
+
destination = source.class.new(*args)
|
90
|
+
copy_properties(source, destination, [], false)
|
91
|
+
# Must save here to copy join tables.
|
92
|
+
destination.save!
|
93
|
+
copy_relations(source, destination, [])
|
94
|
+
destination.save!
|
95
|
+
destination
|
96
|
+
end
|
97
|
+
|
98
|
+
# Does the work of clone_properties and copy_inferior_relations.
|
99
|
+
# Syntax is the same with one extra field to tell the
|
100
|
+
# routine what it is copying.
|
101
|
+
|
102
|
+
def property_copier(source,destination,ignore,use_setter_method,relations)
|
103
|
+
primary_key_symbol = source.class.primary_key.symbol
|
104
|
+
source.class.properties.to_a.each do |symbol, property|
|
105
|
+
next if primary_key_symbol == symbol or ignore.include?(symbol) or
|
106
|
+
(relations and not property.relation) or (not relations and property.relation)
|
107
|
+
|
108
|
+
variable = "@#{symbol}"
|
109
|
+
if use_setter_method
|
110
|
+
destination.send("#{symbol}=".to_sym,source.instance_variable_get(variable))
|
111
|
+
else
|
112
|
+
destination.instance_variable_set(variable, source.instance_variable_get(variable))
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
data/lib/og/errors.rb
CHANGED
data/lib/og/manager.rb
CHANGED
@@ -3,6 +3,7 @@ require 'facet/class/descendents'
|
|
3
3
|
|
4
4
|
require 'og/entity'
|
5
5
|
require 'og/store'
|
6
|
+
require 'og/adapter'
|
6
7
|
|
7
8
|
module Og
|
8
9
|
|
@@ -58,16 +59,24 @@ class Manager
|
|
58
59
|
|
59
60
|
attr_accessor :cache
|
60
61
|
|
62
|
+
# Initialize the manager.
|
63
|
+
#
|
64
|
+
# === Options
|
65
|
+
#
|
66
|
+
# :store, :adapter = the adapter/store to use as backend.
|
67
|
+
|
61
68
|
def initialize(options)
|
62
69
|
@options = options
|
63
70
|
@entities = {}
|
64
71
|
|
65
|
-
@store_class =
|
66
|
-
@store_class.
|
67
|
-
|
68
|
-
init_store
|
72
|
+
@store_class = Adapter.for_name(options[:adapter] || options[:store])
|
73
|
+
@store_class.allocate.destroy_db(options) if Og.destroy_schema || options[:destroy]
|
74
|
+
|
75
|
+
init_store()
|
69
76
|
end
|
70
77
|
|
78
|
+
# Initialize a store.
|
79
|
+
|
71
80
|
def initialize_store
|
72
81
|
if @pool
|
73
82
|
close_store
|
@@ -77,9 +86,11 @@ class Manager
|
|
77
86
|
@pool = Pool.new
|
78
87
|
(options[:connection_count] || 5).times do
|
79
88
|
@pool << @store_class.new(@options)
|
89
|
+
@pool.last.ogmanager = self
|
80
90
|
end
|
81
91
|
else
|
82
92
|
@store = @store_class.new(@options)
|
93
|
+
@store.ogmanager = self
|
83
94
|
end
|
84
95
|
end
|
85
96
|
alias :init_store :initialize_store
|
@@ -87,7 +98,7 @@ class Manager
|
|
87
98
|
# used when changing thread_safe mode
|
88
99
|
|
89
100
|
def close_store
|
90
|
-
|
101
|
+
unless @pool
|
91
102
|
@store.close
|
92
103
|
else
|
93
104
|
@pool.each { |s| s.close }
|
@@ -103,10 +114,22 @@ class Manager
|
|
103
114
|
thread = Thread.current
|
104
115
|
|
105
116
|
unless st = thread[:og_store] and st.is_a?(@store_class)
|
106
|
-
if 0 == @pool.size
|
107
|
-
initialize_store
|
117
|
+
if 0 == @pool.size
|
118
|
+
initialize_store
|
108
119
|
end
|
109
|
-
st = @pool.pop
|
120
|
+
st = @pool.pop
|
121
|
+
thread[:og_store] = st
|
122
|
+
end
|
123
|
+
|
124
|
+
if st.ogmanager != self
|
125
|
+
# This normally shound't happen, there is a leftover store.
|
126
|
+
# Just return it to the original store and go on.
|
127
|
+
st.ogmanager.put_store
|
128
|
+
|
129
|
+
if 0 == @pool.size
|
130
|
+
initialize_store
|
131
|
+
end
|
132
|
+
st = @pool.pop
|
110
133
|
thread[:og_store] = st
|
111
134
|
end
|
112
135
|
|
@@ -125,6 +148,12 @@ class Manager
|
|
125
148
|
thread = Thread.current
|
126
149
|
|
127
150
|
if conn = thread[:og_store]
|
151
|
+
|
152
|
+
# store released to the wrong manager?
|
153
|
+
if conn.ogmanager != self
|
154
|
+
return conn.ogmanager.put_store
|
155
|
+
end
|
156
|
+
|
128
157
|
thread[:og_store] = nil
|
129
158
|
return @pool.push(conn)
|
130
159
|
end
|
@@ -140,21 +169,39 @@ class Manager
|
|
140
169
|
# Manage a class. Converts the class to an Entity.
|
141
170
|
|
142
171
|
def manage(klass)
|
143
|
-
return if managed?(klass) or
|
172
|
+
return if managed?(klass) or (!manageable?(klass))
|
144
173
|
|
145
174
|
info = EntityInfo.new(klass)
|
146
175
|
|
176
|
+
# Check if the class has a :text key.
|
177
|
+
|
178
|
+
for a in klass.serializable_attributes
|
179
|
+
anno = klass.ann(a)
|
180
|
+
if anno[:key]
|
181
|
+
klass.ann.self[:text_key] = a
|
182
|
+
break
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
147
186
|
# DON'T DO THIS!!!
|
187
|
+
#--
|
188
|
+
# gmosx: this is used though, dont remove without recoding
|
189
|
+
# some stuff.
|
190
|
+
#++
|
148
191
|
|
149
192
|
klass.module_eval %{
|
150
193
|
def ==(other)
|
151
|
-
other.instance_of?(#{klass}) ? @#{klass.primary_key
|
194
|
+
other.instance_of?(#{klass}) ? @#{klass.primary_key} == other.#{klass.primary_key} : false
|
152
195
|
end
|
153
196
|
}
|
154
197
|
|
155
198
|
klass.class.send(:attr_accessor, :ogmanager)
|
156
199
|
klass.instance_variable_set '@ogmanager', self
|
157
200
|
|
201
|
+
# FIXME: move somewhere else.
|
202
|
+
|
203
|
+
klass.define_force_methods
|
204
|
+
|
158
205
|
Relation.enchant(klass)
|
159
206
|
|
160
207
|
# ensure that the superclass is managed before the
|
@@ -162,7 +209,8 @@ class Manager
|
|
162
209
|
|
163
210
|
manage(klass.superclass) if manageable?(klass.superclass)
|
164
211
|
|
165
|
-
#
|
212
|
+
# Perform store related enchanting.
|
213
|
+
|
166
214
|
store.enchant(klass, self); put_store
|
167
215
|
|
168
216
|
# Call special class enchanting code.
|
@@ -175,12 +223,15 @@ class Manager
|
|
175
223
|
# Is this class manageable by Og?
|
176
224
|
#
|
177
225
|
# Unmanageable classes include classes:
|
178
|
-
# * without
|
226
|
+
# * without serializable attributes
|
179
227
|
# * explicitly marked as Unmanageable (is Og::Unamanageable)
|
180
228
|
# * are polymorphic_parents (ie thay are used to spawn polymorphic relations)
|
181
229
|
|
182
230
|
def manageable?(klass)
|
183
|
-
klass.respond_to?(:
|
231
|
+
(klass.respond_to?(:serializable_attributes)) and
|
232
|
+
(!klass.serializable_attributes.empty?) and
|
233
|
+
(!Og.unmanageable_classes.include?(klass)) and
|
234
|
+
(!klass.polymorphic_parent?)
|
184
235
|
end
|
185
236
|
|
186
237
|
# Is the class managed by Og?
|
@@ -203,7 +254,6 @@ class Manager
|
|
203
254
|
def manageable_classes
|
204
255
|
classes = []
|
205
256
|
|
206
|
-
# for c in Property.classes
|
207
257
|
ObjectSpace.each_object(Class) do |c|
|
208
258
|
if manageable?(c)
|
209
259
|
classes << c
|
@@ -216,17 +266,27 @@ class Manager
|
|
216
266
|
# Manage a collection of classes.
|
217
267
|
|
218
268
|
def manage_classes(*classes)
|
219
|
-
classes
|
220
|
-
classes
|
269
|
+
classes.flatten!
|
270
|
+
classes.compact!
|
271
|
+
|
272
|
+
mc = self.class.managed_classes
|
273
|
+
|
274
|
+
classes = manageable_classes.flatten if classes.empty?
|
275
|
+
classes = classes.reject { |c| mc.member?(c) || !manageable?(c) }
|
276
|
+
|
277
|
+
sc = @store_class.allocate
|
221
278
|
|
279
|
+
classes.each { |c| sc.force_primary_key(c) }
|
222
280
|
classes.each { |c| Relation.resolve_targets(c) }
|
223
281
|
classes.each { |c| Relation.resolve_polymorphic_markers(c) }
|
224
|
-
|
225
|
-
|
282
|
+
|
226
283
|
# The polymorpic resolution step creates more manageable classes.
|
227
|
-
|
228
|
-
classes
|
229
|
-
|
284
|
+
|
285
|
+
classes += classes.map {|c| Relation.resolve_polymorphic_relations(c) }
|
286
|
+
|
287
|
+
classes.flatten!
|
288
|
+
|
289
|
+
classes = classes.reject { |c| !c or self.class.managed?(c) }
|
230
290
|
|
231
291
|
Logger.debug "Og manageable classes: #{classes.inspect}" if $DBG
|
232
292
|
|
@@ -234,8 +294,10 @@ class Manager
|
|
234
294
|
classes.each { |c| Relation.resolve_names(c) }
|
235
295
|
classes.each { |c| manage(c) }
|
236
296
|
end
|
237
|
-
|
297
|
+
alias manage_class manage_classes
|
238
298
|
|
299
|
+
# Do not manage the given classes.
|
300
|
+
|
239
301
|
def unmanage_classes(*classes)
|
240
302
|
classes = manageable_classes.flatten if classes.empty?
|
241
303
|
|
@@ -243,7 +305,7 @@ class Manager
|
|
243
305
|
@entities.delete_if { |k, v| v.klass == c }
|
244
306
|
end
|
245
307
|
end
|
246
|
-
|
308
|
+
alias unmanage_class unmanage_classes
|
247
309
|
|
248
310
|
# Allows functionality that requires a store is finalized
|
249
311
|
# to be implemented. A vastly superior method of constructing
|
@@ -258,20 +320,6 @@ class Manager
|
|
258
320
|
store.post_setup if store.respond_to?(:post_setup)
|
259
321
|
end
|
260
322
|
|
261
|
-
# Dump a nice name for this store.
|
262
|
-
=begin
|
263
|
-
def to_s
|
264
|
-
if store = get_store
|
265
|
-
store.to_s
|
266
|
-
else
|
267
|
-
'Uninitialized'
|
268
|
-
end
|
269
|
-
end
|
270
|
-
=end
|
271
323
|
end
|
272
324
|
|
273
325
|
end
|
274
|
-
|
275
|
-
# * George Moschovitis <gm@navel.gr>
|
276
|
-
# * Guillaume Pierronnet <guillaume.pierronnet@laposte.net>
|
277
|
-
# * Rob Pitt
|
data/lib/og/relation.rb
CHANGED
@@ -2,7 +2,8 @@ require 'facet/kernel/constant'
|
|
2
2
|
require 'facet/string/capitalized'
|
3
3
|
require 'facet/ormsupport'
|
4
4
|
require 'facet/inheritor'
|
5
|
-
|
5
|
+
|
6
|
+
require 'facets/core/module/class_extension'
|
6
7
|
|
7
8
|
module Og
|
8
9
|
|
@@ -53,9 +54,6 @@ class Relation
|
|
53
54
|
# Inflect target_class if not provided.
|
54
55
|
|
55
56
|
@options[:target_class] ||= @options[target_name].to_s.singular.camelize.intern
|
56
|
-
|
57
|
-
# FIXME: this is a hack!
|
58
|
-
# setup() rescue nil
|
59
57
|
end
|
60
58
|
|
61
59
|
# Get an option.
|
@@ -79,6 +77,8 @@ class Relation
|
|
79
77
|
# Is this a polymorphic relation ?
|
80
78
|
|
81
79
|
def polymorphic?
|
80
|
+
# hack fix!
|
81
|
+
return false unless target_class.is_a?(Class)
|
82
82
|
target_class.ann.self[:polymorphic]
|
83
83
|
end
|
84
84
|
|
@@ -116,23 +116,31 @@ class Relation
|
|
116
116
|
# (at the time of the creation of the relation) classes are
|
117
117
|
# stored as symbols. These symbols are resolved by this
|
118
118
|
# method.
|
119
|
+
#
|
120
|
+
# First attempts to find a class in the form:
|
121
|
+
#
|
122
|
+
# owner_class::class
|
123
|
+
# (ie, Article::Category)
|
124
|
+
#
|
125
|
+
# then a class of the form:
|
126
|
+
#
|
127
|
+
# class
|
128
|
+
# (ie, ::Category)
|
119
129
|
#--
|
120
|
-
#
|
130
|
+
# The lookup is handled automatically by the #constant Facets
|
131
|
+
# method.
|
121
132
|
#++
|
122
|
-
|
133
|
+
|
123
134
|
def symbol_to_class(sym, owner_class)
|
124
|
-
|
125
|
-
|
126
|
-
c.gsub!(/::[^:]*$/, '::')
|
127
|
-
c << sym.to_s
|
135
|
+
owner_class = owner_class.name
|
136
|
+
|
128
137
|
begin
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
end
|
138
|
+
c = "#{owner_class}::#{sym}"
|
139
|
+
const = constant(c)
|
140
|
+
owner_class = owner_class.to_s.scan(/^(.*)::(?:[^:])*$/)
|
141
|
+
end while const.class != Class && !owner_class.empty?
|
142
|
+
|
143
|
+
return const.class == Class ? const : nil
|
136
144
|
end
|
137
145
|
alias_method :resolve_symbol, :symbol_to_class
|
138
146
|
|
@@ -175,32 +183,45 @@ class Relation
|
|
175
183
|
# For example:
|
176
184
|
#
|
177
185
|
# class Article
|
178
|
-
# has_many
|
186
|
+
# has_many :comments
|
179
187
|
# ...
|
180
188
|
# end
|
189
|
+
#
|
190
|
+
# generates:
|
191
|
+
#
|
192
|
+
# class Article::Comment < Comment
|
193
|
+
# end
|
181
194
|
|
182
195
|
def resolve_polymorphic_relations(klass)
|
196
|
+
generated = []
|
197
|
+
|
183
198
|
for r in klass.relations
|
184
199
|
if r.polymorphic?
|
185
|
-
|
186
200
|
target_dm = r.target_class.to_s.demodulize
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
201
|
+
|
202
|
+
# Replace the target class by either creating or getting the
|
203
|
+
# polymorphic child if it already exists.
|
204
|
+
|
205
|
+
r[:target_class] = if r.owner_class.constants.include?(target_dm)
|
206
|
+
r.owner_class.const_get(target_dm)
|
207
|
+
else
|
208
|
+
r.owner_class.const_set(target_dm, Class.new(r.target_class))
|
209
|
+
end
|
210
|
+
|
211
|
+
r.resolve_polymorphic
|
212
|
+
|
213
|
+
generated << r[:target_class]
|
196
214
|
end
|
197
|
-
|
198
|
-
r.resolve_polymorphic
|
199
215
|
end
|
216
|
+
|
217
|
+
return generated
|
200
218
|
end
|
201
219
|
|
202
220
|
# Resolve the names of the relations.
|
203
|
-
|
221
|
+
#--
|
222
|
+
# For the target name it uses the demodulized class name.
|
223
|
+
#++
|
224
|
+
|
204
225
|
def resolve_names(klass)
|
205
226
|
for r in klass.relations
|
206
227
|
target_name = if r.collection
|
@@ -243,7 +264,6 @@ class Relation
|
|
243
264
|
# enchant.
|
244
265
|
|
245
266
|
for r in klass.relations
|
246
|
-
# p "=== #{klass} : #{r.class} : #{r.name}"
|
247
267
|
r.enchant() unless r.polymorphic_marker?
|
248
268
|
end
|
249
269
|
|
@@ -328,5 +348,3 @@ module RelationDSL
|
|
328
348
|
end
|
329
349
|
|
330
350
|
end
|
331
|
-
|
332
|
-
# * George Moschovitis <gm@navel.gr>
|