Class: Og::Relation
- Inherits:
-
Object
- Object
- Og::Relation
- Defined in:
- lib/og/relation.rb,
lib/og/relation.rb
Overview
A collection of helper methods and resolvers for relations.
Instance Attribute Summary collapse
-
#options ⇒ Object
The parameters of this relation.
Class Method Summary collapse
-
.enchant(klass) ⇒ Object
Perform relation enchanting on this class.
-
.resolve(klass, action = :resolve_polymorphic) ⇒ Object
General resolve method.
-
.resolve_names(klass) ⇒ Object
Resolve the names of the relations.
-
.resolve_polymorphic_markers(klass) ⇒ Object
If the target class is just an Object mark this class (self) as a polymorphic parent class.
-
.resolve_polymorphic_relations(klass) ⇒ Object
Resolve polymorphic relations.
- .resolve_targets(klass) ⇒ Object
-
.symbol_to_class(sym, owner_class) ⇒ Object
(also: resolve_symbol)
To avoid forward declarations, references to undefined (at the time of the creation of the relation) classes are stored as symbols.
Instance Method Summary collapse
-
#[](key) ⇒ Object
Get an option.
-
#[]=(key, val) ⇒ Object
Set an option.
-
#enchant ⇒ Object
This method is implemented in subclasses.
-
#initialize(args, options = {}) ⇒ Relation
constructor
A generalized initialize method for all relations.
-
#method_missing(sym, *args) ⇒ Object
Access the hash values as methods.
-
#polymorphic? ⇒ Boolean
Is this a polymorphic relation ?.
-
#polymorphic_marker? ⇒ Boolean
Is this a polymorphic marker?.
-
#resolve_polymorphic ⇒ Object
Resolve a polymorphic target class.
- #to_s ⇒ Object
Constructor Details
#initialize(args, options = {}) ⇒ Relation
A generalized initialize method for all relations. Contains common setup code.
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 |
# File 'lib/og/relation.rb', line 25 def initialize(args, = {}) @options = @options.update(args.pop) if args.last.is_a?(Hash) target_name = if collection :target_plural_name else :target_singular_name end # Check that all needed options are provided. if args.empty? or (not (args.last.is_a?(Class) or args.last.is_a?(Symbol))) raise 'Class of target not defined' end # Try to set the target class. Checks for class and # class symbol. if args.last.to_s.capitalized? @options[:target_class] = args.pop end # Try to set the target name. if args.last.is_a? Symbol @options[target_name] = args.pop end # Inflect target_class if not provided. @options[:target_class] ||= @options[target_name].to_s.singular.camelize.intern end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(sym, *args) ⇒ Object
Access the hash values as methods.
103 104 105 |
# File 'lib/og/relation.rb', line 103 def method_missing(sym, *args) return @options[sym] end |
Instance Attribute Details
#options ⇒ Object
The parameters of this relation.
20 21 22 |
# File 'lib/og/relation.rb', line 20 def @options end |
Class Method Details
.enchant(klass) ⇒ Object
Perform relation enchanting on this class.
257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/og/relation.rb', line 257 def enchant(klass) # update inherited relations. for r in klass.relations r[:owner_class] = klass end # enchant. for r in klass.relations r.enchant() unless r.polymorphic_marker? end end |
.resolve(klass, action = :resolve_polymorphic) ⇒ Object
General resolve method.
249 250 251 252 253 |
# File 'lib/og/relation.rb', line 249 def resolve(klass, action = :resolve_polymorphic) for r in klass.relations r.send(action) end end |
.resolve_names(klass) ⇒ Object
Resolve the names of the relations. – For the target name it uses the demodulized class name. ++
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/og/relation.rb', line 225 def resolve_names(klass) for r in klass.relations target_name = if r.collection :target_plural_name else :target_singular_name end # Inflect the relation name. unless r[target_name] r[target_name] = if r.collection r.target_class.to_s.demodulize.underscore.downcase.plural.to_sym else r.target_class.to_s.demodulize.underscore.downcase.to_sym end end r[:name] = r[target_name] end end |
.resolve_polymorphic_markers(klass) ⇒ Object
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
170 171 172 173 174 175 176 |
# File 'lib/og/relation.rb', line 170 def resolve_polymorphic_markers(klass) for r in klass.relations if r.polymorphic_marker? r.owner_class.ann :self, :polymorphic => r.owner_class end end end |
.resolve_polymorphic_relations(klass) ⇒ Object
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
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/og/relation.rb', line 195 def resolve_polymorphic_relations(klass) generated = [] for r in klass.relations if r.polymorphic? target_dm = r.target_class.to_s.demodulize # Replace the target class by either creating or getting the # polymorphic child if it already exists. r[:target_class] = if r.owner_class.constants.include?(target_dm) r.owner_class.const_get(target_dm) else r.owner_class.const_set(target_dm, Class.new(r.target_class)) end r.resolve_polymorphic generated << r[:target_class] end end return generated end |
.resolve_targets(klass) ⇒ Object
147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/og/relation.rb', line 147 def resolve_targets(klass) for r in klass.relations if r.target_class.is_a? Symbol if klass = symbol_to_class(r.target_class, r.owner_class) r.[:target_class] = klass else Logger.error "Cannot resolve target class '#{r.target_class}' for relation '#{r}' of class '#{r.owner_class}'!" end end end end |
.symbol_to_class(sym, owner_class) ⇒ Object Also known as: resolve_symbol
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) – The lookup is handled automatically by the #constant Facets method. ++
134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/og/relation.rb', line 134 def symbol_to_class(sym, owner_class) owner_class = owner_class.name begin c = "#{owner_class}::#{sym}" const = constant(c) owner_class = owner_class.to_s.scan(/^(.*)::(?:[^:])*$/) end while const.class != Class && !owner_class.empty? return const.class == Class ? const : nil end |
Instance Method Details
#[](key) ⇒ Object
Get an option.
61 62 63 |
# File 'lib/og/relation.rb', line 61 def [](key) @options[key] end |
#[]=(key, val) ⇒ Object
Set an option.
67 68 69 |
# File 'lib/og/relation.rb', line 67 def []=(key, val) @options[key] = val end |
#enchant ⇒ Object
This method is implemented in subclasses.
93 94 |
# File 'lib/og/relation.rb', line 93 def enchant end |
#polymorphic? ⇒ Boolean
Is this a polymorphic relation ?
79 80 81 82 83 |
# File 'lib/og/relation.rb', line 79 def polymorphic? # hack fix! return false unless target_class.is_a?(Class) target_class.ann.self[:polymorphic] end |
#polymorphic_marker? ⇒ Boolean
Is this a polymorphic marker?
73 74 75 |
# File 'lib/og/relation.rb', line 73 def polymorphic_marker? target_class == Object end |
#resolve_polymorphic ⇒ Object
Resolve a polymorphic target class. Overrided in subclasses.
88 89 |
# File 'lib/og/relation.rb', line 88 def resolve_polymorphic end |
#to_s ⇒ Object
96 97 98 99 |
# File 'lib/og/relation.rb', line 96 def to_s self.class.to_s.underscore # @options[:target_name] end |