A collection of helper methods and resolvers for relations.

Methods
Attributes
[RW] options The parameters of this relation.
Public Class methods
enchant(klass)

Perform relation enchanting on this class.

     # File lib/og/relation.rb, line 257
257:   def enchant(klass)
258:     # update inherited relations.
259: 
260:     for r in klass.relations
261:       r[:owner_class] = klass 
262:     end
263: 
264:     # enchant.
265: 
266:     for r in klass.relations
267:       r.enchant() unless r.polymorphic_marker?
268:     end
269: 
270:     klass.each_schema_child do |child|
271:       #FIXME: Probably the relation classes should be passed a manager when they enchant...
272:       child.class.__send__(:attr_accessor, :ogmanager)
273:       child.instance_variable_set('@ogmanager', klass.ogmanager)
274: 
275:       Relation::enchant(child)
276:     end
277:   end
new(args, options = {})

A generalized initialize method for all relations. Contains common setup code.

    # File lib/og/relation.rb, line 26
26:   def initialize(args, options = {})
27:     @options = options
28:     @options.update(args.pop) if args.last.is_a?(Hash)
29: 
30:     target_name = if collection
31:       :target_plural_name
32:     else
33:       :target_singular_name
34:     end
35: 
36:     # Check that all needed options are provided.
37: 
38:     if args.empty? or (not (args.last.is_a?(Class) or args.last.is_a?(Symbol)))
39:       raise 'Class of target not defined' 
40:     end
41: 
42:     # Try to set the target class. Checks for class and 
43:     # class symbol.
44: 
45:     if args.last.to_s.capitalized?
46:       @options[:target_class] = args.pop
47:     end
48: 
49:     # Try to set the target name.
50: 
51:     if args.last.is_a? Symbol
52:       @options[target_name] = args.pop
53:     end
54: 
55:     # Inflect target_class if not provided.
56:     @options[:target_class] ||= @options[target_name].to_s.singular.camelize.intern
57:   end
resolve(klass, action = :resolve_polymorphic)

General resolve method.

     # File lib/og/relation.rb, line 249
249:   def resolve(klass, action = :resolve_polymorphic)
250:     for r in klass.relations
251:       r.send(action)
252:     end
253:   end
resolve_names(klass)

Resolve the names of the relations.

     # File lib/og/relation.rb, line 225
225:   def resolve_names(klass)
226:     for r in klass.relations
227:       target_name = if r.collection
228:         :target_plural_name
229:       else
230:         :target_singular_name 
231:       end
232: 
233:       # Inflect the relation name.
234: 
235:       unless r[target_name]
236:         r[target_name] = if r.collection
237:           r.target_class.to_s.demodulize.underscore.downcase.plural.to_sym 
238:         else
239:           r.target_class.to_s.demodulize.underscore.downcase.to_sym
240:         end
241:       end
242: 
243:       r[:name] = r[target_name]
244:     end
245:   end
resolve_polymorphic_markers(klass)

If the target class is just an Object mark this class (self) as a polymorphic parent class. This class acts as template to generate customized versions of this class.

For example:

class Comment

   belongs_to :parent, Object # <= polymorphic
   ...

end

     # File lib/og/relation.rb, line 170
170:   def resolve_polymorphic_markers(klass)
171:     for r in klass.relations
172:       if r.polymorphic_marker?
173:         r.owner_class.ann(:self, :polymorphic => r.owner_class)
174:       end
175:     end
176:   end
resolve_polymorphic_relations(klass)

Resolve polymorphic relations. If the target class is polymorphic, create a specialized version of that class (the target) enclosed in the owner namespace.

For example:

class Article

  has_many :comments
  ...

end

generates:

class Article::Comment < Comment end

     # File lib/og/relation.rb, line 195
195:   def resolve_polymorphic_relations(klass)
196:     generated = []
197:     
198:     for r in klass.relations
199:       if r.polymorphic?
200:         target_dm = r.target_class.to_s.demodulize
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]
214:       end
215:     end
216:     
217:     return generated
218:   end
resolve_targets(klass)
     # File lib/og/relation.rb, line 147
147:   def resolve_targets(klass)
148:     for r in klass.relations
149:       if r.target_class.is_a? Symbol
150:         if klass = symbol_to_class(r.target_class, r.owner_class)
151:           r.options[:target_class] = klass
152:         else
153:           Logger.error "Cannot resolve target class '#{r.target_class}' for relation '#{r}' of class '#{r.owner_class}'!"
154:         end
155:       end
156:     end
157:   end
symbol_to_class(sym, owner_class)

To avoid forward declarations, references to undefined (at the time of the creation of the relation) classes are stored as symbols. These symbols are resolved by this method.

First attempts to find a class in the form:

owner_class::class (ie, Article::Category)

then a class of the form:

class (ie, ::Category)

     # File lib/og/relation.rb, line 134
134:   def symbol_to_class(sym, owner_class)
135:     owner_class = owner_class.name
136:     
137:     begin
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
144:   end
Public Instance methods
[](key)

Get an option.

    # File lib/og/relation.rb, line 61
61:   def [](key)
62:     @options[key]
63:   end
[]=(key, val)

Set an option.

    # File lib/og/relation.rb, line 67
67:   def []=(key, val)
68:     @options[key] = val
69:   end
enchant()

This method is implemented in subclasses.

    # File lib/og/relation.rb, line 93
93:   def enchant
94:   end
method_missing(sym, *args)

Access the hash values as methods.

     # File lib/og/relation.rb, line 103
103:   def method_missing(sym, *args)
104:     return @options[sym]
105:   end
polymorphic?()

Is this a polymorphic relation ?

    # File lib/og/relation.rb, line 79
79:   def polymorphic?
80:     # hack fix!
81:     return false unless target_class.is_a?(Class)
82:     return target_class.ann(:self, :polymorphic)
83:   end
polymorphic_marker?()

Is this a polymorphic marker?

    # File lib/og/relation.rb, line 73
73:   def polymorphic_marker?
74:     target_class == Object
75:   end
resolve_polymorphic()

Resolve a polymorphic target class. Overrided in subclasses.

    # File lib/og/relation.rb, line 88
88:   def resolve_polymorphic
89:   end
to_s()
    # File lib/og/relation.rb, line 96
96:   def to_s
97:     self.class.to_s.underscore
98:     # @options[:target_name]
99:   end