Included Modules

Class Index [+]

Quicksearch

DataMapper::Model::Relationship

Public Class Methods

extended(model) click to toggle source

Initializes relationships hash for extended model class.

When model calls has n, has 1 or belongs_to, relationships are stored in that hash: keys are repository names and values are relationship sets.

@api private

    # File lib/dm-core/model/relationship.rb, line 19
19:       def self.extended(model)
20:         model.instance_variable_set(:@relationships, {})
21:       end

Public Instance Methods

belongs_to(name, *args) click to toggle source

A shorthand, clear syntax for defining many-to-one resource relationships.

 * belongs_to :user                              # many to one user
 * belongs_to :friend, :model => 'User'          # many to one friend
 * belongs_to :reference, :repository => :pubmed # association for repository other than default

@param name [Symbol]

  the name that the association will be referenced by

@param *args [Model, Hash] model and/or options hash

@option *args :model[Model, String] The name of the class to associate with, if omitted

  then the association name is assumed to match the class name

@option *args :repository[Symbol] name of child model repository

@return [Association::Relationship] The association created

  should not be accessed directly

@api public

     # File lib/dm-core/model/relationship.rb, line 156
156:       def belongs_to(name, *args)
157:         name       = name.to_sym
158:         model_name = self.name
159:         model      = extract_model(args)
160:         options    = extract_options(args)
161: 
162:         if options.key?(:through)
163:           raise "#{model_name}#belongs_to with :through is deprecated, use 'has 1, :#{name}, #{options.inspect}' in #{model_name} instead (#{caller.first})"
164:         elsif options.key?(:model) && model
165:           raise ArgumentError, 'should not specify options[:model] if passing the model in the third argument'
166:         end
167: 
168:         assert_valid_options(options)
169: 
170:         model ||= options.delete(:model)
171: 
172:         repository_name = repository.name
173: 
174:         # TODO: change to source_repository_name and target_respository_name
175:         options[:child_repository_name]  = repository_name
176:         options[:parent_repository_name] = options.delete(:repository)
177: 
178:         relationship = Associations::ManyToOne::Relationship.new(name, self, model, options)
179: 
180:         relationships(repository_name) << relationship
181: 
182:         descendants.each do |descendant|
183:           descendant.relationships(repository_name) << relationship
184:         end
185: 
186:         create_relationship_reader(relationship)
187:         create_relationship_writer(relationship)
188: 
189:         relationship
190:       end
has(cardinality, name, *args) click to toggle source

A shorthand, clear syntax for defining one-to-one, one-to-many and many-to-many resource relationships.

 * has 1,    :friend                             # one friend
 * has n,    :friends                            # many friends
 * has 1..3, :friends                            # many friends (at least 1, at most 3)
 * has 3,    :friends                            # many friends (exactly 3)
 * has 1,    :friend,  'User'                    # one friend with the class User
 * has 3,    :friends, :through => :friendships  # many friends through the friendships relationship

@param cardinality [Integer, Range, Infinity]

  cardinality that defines the association type and constraints

@param name [Symbol]

  the name that the association will be referenced by

@param *args [Model, Hash] model and/or options hash

@option *args :through[Symbol] A association that this join should go through to form

  a many-to-many association

@option *args :model[Model, String] The name of the class to associate with, if omitted

  then the association name is assumed to match the class name

@option *args :repository[Symbol] name of child model repository

@return [Association::Relationship] the relationship that was

  created to reflect either a one-to-one, one-to-many or many-to-many
  relationship

@raise [ArgumentError] if the cardinality was not understood. Should be a

  Integer, Range or Infinity(n)

@api public

     # File lib/dm-core/model/relationship.rb, line 96
 96:       def has(cardinality, name, *args)
 97:         name    = name.to_sym
 98:         model   = extract_model(args)
 99:         options = extract_options(args)
100: 
101:         min, max = extract_min_max(cardinality)
102:         options.update(:min => min, :max => max)
103: 
104:         assert_valid_options(options)
105: 
106:         if options.key?(:model) && model
107:           raise ArgumentError, 'should not specify options[:model] if passing the model in the third argument'
108:         end
109: 
110:         model ||= options.delete(:model)
111: 
112:         repository_name = repository.name
113: 
114:         # TODO: change to :target_respository_name and :source_repository_name
115:         options[:child_repository_name]  = options.delete(:repository)
116:         options[:parent_repository_name] = repository_name
117: 
118:         klass = if max > 1
119:           options.key?(:through) ? Associations::ManyToMany::Relationship : Associations::OneToMany::Relationship
120:         else
121:           Associations::OneToOne::Relationship
122:         end
123: 
124:         relationship = klass.new(name, model, self, options)
125: 
126:         relationships(repository_name) << relationship
127: 
128:         descendants.each do |descendant|
129:           descendant.relationships(repository_name) << relationship
130:         end
131: 
132:         create_relationship_reader(relationship)
133:         create_relationship_writer(relationship)
134: 
135:         relationship
136:       end
inherited(model) click to toggle source

When DataMapper model is inherited, relationships of parent are duplicated and copied to subclass model

@api private

    # File lib/dm-core/model/relationship.rb, line 27
27:       def inherited(model)
28:         model.instance_variable_set(:@relationships, {})
29: 
30:         @relationships.each do |repository_name, relationships|
31:           model_relationships = model.relationships(repository_name)
32:           relationships.each { |relationship| model_relationships << relationship }
33:         end
34: 
35:         super
36:       end
n() click to toggle source

Used to express unlimited cardinality of association, see has

@api public

    # File lib/dm-core/model/relationship.rb, line 63
63:       def n
64:         Infinity
65:       end
relationships(repository_name = default_repository_name) click to toggle source

Returns copy of relationships set in given repository.

@param [Symbol] repository_name

  Name of the repository for which relationships set is returned

@return [RelationshipSet] relationships set for given repository

@api semipublic

    # File lib/dm-core/model/relationship.rb, line 45
45:       def relationships(repository_name = default_repository_name)
46:         # TODO: create RelationshipSet#copy that will copy the relationships, but assign the
47:         # new Relationship objects to a supplied repository and model.  dup does not really
48:         # do what is needed
49: 
50:         default_repository_name = self.default_repository_name
51: 
52:         @relationships[repository_name] ||= if repository_name == default_repository_name
53:           RelationshipSet.new
54:         else
55:           relationships(default_repository_name).dup
56:         end
57:       end

Private Instance Methods

assert_valid_options(options) click to toggle source

Validates options of association method like belongs_to or has: verifies types of cardinality bounds, repository, association class, keys and possible values of :through option.

@api private

     # File lib/dm-core/model/relationship.rb, line 250
250:       def assert_valid_options(options)
251:         # TODO: update to match Query#assert_valid_options
252:         #   - perform options normalization elsewhere
253: 
254:         if options.key?(:min) && options.key?(:max)
255:           min = options[:min]
256:           max = options[:max]
257: 
258:           min = min.to_int unless min == Infinity
259:           max = max.to_int unless max == Infinity
260: 
261:           if min == Infinity && max == Infinity
262:             raise ArgumentError, 'Cardinality may not be n..n.  The cardinality specifies the min/max number of results from the association'
263:           elsif min > max
264:             raise ArgumentError, "Cardinality min (#{min}) cannot be larger than the max (#{max})"
265:           elsif min < 0
266:             raise ArgumentError, "Cardinality min much be greater than or equal to 0, but was #{min}"
267:           elsif max < 1
268:             raise ArgumentError, "Cardinality max much be greater than or equal to 1, but was #{max}"
269:           end
270:         end
271: 
272:         if options.key?(:repository)
273:           options[:repository] = options[:repository].to_sym
274:         end
275: 
276:         if options.key?(:class_name)
277:           raise "+options[:class_name]+ is deprecated, use :model instead (#{caller[1]})"
278:         elsif options.key?(:remote_name)
279:           raise "+options[:remote_name]+ is deprecated, use :via instead (#{caller[1]})"
280:         end
281: 
282:         if options.key?(:through)
283:           assert_kind_of 'options[:through]', options[:through], Symbol, Module
284:         end
285: 
286:         [ :via, :inverse ].each do |key|
287:           if options.key?(key)
288:             assert_kind_of "options[#{key.inspect}]", options[key], Symbol, Associations::Relationship
289:           end
290:         end
291: 
292:         # TODO: deprecate :child_key and :parent_key in favor of :source_key and
293:         # :target_key (will mean something different for each relationship)
294: 
295:         [ :child_key, :parent_key ].each do |key|
296:           if options.key?(key)
297:             options[key] = Array(options[key])
298:           end
299:         end
300: 
301:         if options.key?(:limit)
302:           raise ArgumentError, '+options[:limit]+ should not be specified on a relationship'
303:         end
304:       end
create_relationship_reader(relationship) click to toggle source

Dynamically defines reader method

@api private

     # File lib/dm-core/model/relationship.rb, line 323
323:       def create_relationship_reader(relationship)
324:         name        = relationship.name
325:         reader_name = name.to_s
326: 
327:         return if method_defined?(reader_name)
328: 
329:         reader_visibility = relationship.reader_visibility
330: 
331:         relationship_module.module_eval           #{reader_visibility}          def #{reader_name}(query = nil)            # TODO: when no query is passed in, return the results from            #       the ivar directly. This will require that the ivar            #       actually hold the resource/collection, and in the case            #       of 1:1, the underlying collection is hidden in a            #       private ivar, and the resource is in a known ivar            persistence_state.get(relationships[#{name.inspect}], query)          end, __FILE__, __LINE__ + 1
332:       end
create_relationship_writer(relationship) click to toggle source

Dynamically defines writer method

@api private

     # File lib/dm-core/model/relationship.rb, line 348
348:       def create_relationship_writer(relationship)
349:         name        = relationship.name
350:         writer_name = "#{name}="
351: 
352:         return if method_defined?(writer_name)
353: 
354:         writer_visibility = relationship.writer_visibility
355: 
356:         relationship_module.module_eval           #{writer_visibility}          def #{writer_name}(target)            relationship = relationships[#{name.inspect}]            self.persistence_state = persistence_state.set(relationship, target)            persistence_state.get(relationship)          end, __FILE__, __LINE__ + 1
357:       end
extract_min_max(cardinality) click to toggle source

A support method for converting Integer, Range or Infinity values into two values representing the minimum and maximum cardinality of the association

@return [Array] A pair of integers, min and max

@api private

     # File lib/dm-core/model/relationship.rb, line 235
235:       def extract_min_max(cardinality)
236:         case cardinality
237:           when Integer  then [ cardinality,       cardinality      ]
238:           when Range    then [ cardinality.first, cardinality.last ]
239:           when Infinity then [ 0,                 Infinity         ]
240:           else
241:             assert_kind_of 'options', options, Integer, Range, Infinity.class
242:         end
243:       end
extract_model(args) click to toggle source

Extract the model from an Array of arguments

@param [Array(Model, String, Hash)]

  The arguments passed to an relationship declaration

@return [Model, #]

  target model for the association

@api private

     # File lib/dm-core/model/relationship.rb, line 203
203:       def extract_model(args)
204:         model = args.first
205: 
206:         if model.kind_of?(Model)
207:           model
208:         elsif model.respond_to?(:to_str)
209:           model.to_str
210:         else
211:           nil
212:         end
213:       end
extract_options(args) click to toggle source

Extract the model from an Array of arguments

@param [Array(Model, String, Hash)]

  The arguments passed to an relationship declaration

@return [Hash]

  options for the association

@api private

     # File lib/dm-core/model/relationship.rb, line 224
224:       def extract_options(args)
225:         options = args.last
226:         options.respond_to?(:to_hash) ? options.to_hash.dup : {}
227:       end
method_missing(method, *args, &block) click to toggle source

@api public

     # File lib/dm-core/model/relationship.rb, line 367
367:       def method_missing(method, *args, &block)
368:         if relationship = relationships(repository_name)[method]
369:           return Query::Path.new([ relationship ])
370:         end
371: 
372:         super
373:       end
relationship_module() click to toggle source

Defines the anonymous module that is used to add relationships. Using a single module here prevents having a very large number of anonymous modules, where each property has their own module. @api private

     # File lib/dm-core/model/relationship.rb, line 310
310:       def relationship_module
311:         @relationship_module ||= begin
312:           mod = Module.new
313:           class_eval do
314:             include mod
315:           end
316:           mod
317:         end
318:       end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.