Module: DataMapper::Resource

Includes:
Assertions, Transaction, Types
Defined in:
lib/dm-core/types.rb,
lib/dm-core/resource.rb

Defined Under Namespace

Modules: Transaction

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Transaction

#transaction

Methods included from Assertions

#assert_kind_of

Instance Attribute Details

#collectionObject



424
425
426
427
428
# File 'lib/dm-core/resource.rb', line 424

def collection
  @collection ||= if query = to_query
    Collection.new(query) { |c| c << self }
  end
end

Class Method Details

.append_inclusions(*inclusions) ⇒ TrueClass, FalseClass

Appends a module for inclusion into the model class after DataMapper::Resource.

This is a useful way to extend DataMapper::Resource while still retaining a self.included method.

-

Parameters:

  • inclusion (Module)

    the module that is to be appended to the module after DataMapper::Resource

Returns:

  • (TrueClass, FalseClass)

    whether or not the inclusions have been successfully appended to the list

  • (TrueClass, FalseClass)


23
24
25
26
# File 'lib/dm-core/resource.rb', line 23

def self.append_inclusions(*inclusions)
  extra_inclusions.concat inclusions
  true
end

.descendantsObject

Return all classes that include the DataMapper::Resource module

Returns

Set

a set containing the including classes

Example

Class Foo
  include DataMapper::Resource
end

DataMapper::Resource.descendants.to_a.first == Foo

-



64
65
66
# File 'lib/dm-core/resource.rb', line 64

def self.descendants
  @descendants ||= Set.new
end

.extra_inclusionsObject



28
29
30
# File 'lib/dm-core/resource.rb', line 28

def self.extra_inclusions
  @extra_inclusions ||= []
end

.included(model) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

When Resource is included in a class this method makes sure it gets all the methods

-



37
38
39
40
41
42
43
44
45
46
47
# File 'lib/dm-core/resource.rb', line 37

def self.included(model)
  model.extend Model
  model.extend ClassMethods if defined?(ClassMethods)
  model.const_set('Resource', self) unless model.const_defined?('Resource')
  extra_inclusions.each { |inclusion| model.send(:include, inclusion) }
  descendants << model
  class << model
    @_valid_model = false
    attr_reader :_valid_model
  end
end

Instance Method Details

#attribute_dirty?(name) ⇒ Boolean

Checks if the attribute is dirty

Parameters

name<Symbol>

name of attribute

Returns

True

returns if attribute is dirty

Returns:



420
421
422
# File 'lib/dm-core/resource.rb', line 420

def attribute_dirty?(name)
  dirty_attributes.has_key?(properties[name])
end

#attribute_get(name) ⇒ Object

returns the value of the attribute. Do not read from instance variables directly, but use this method. This method handels the lazy loading the attribute and returning of defaults if nessesary.

Parameters

name<Symbol>

name attribute to lookup

Returns

<Types>

the value stored at that given attribute, nil if none, and default if necessary

Example

Class Foo
  include DataMapper::Resource

  property :first_name, String
  property :last_name, String

  def full_name
    "#{attribute_get(:first_name)} #{attribute_get(:last_name)}"
  end

  # using the shorter syntax
  def name_for_address_book
    "#{last_name}, #{first_name}"
  end
end

-



105
106
107
# File 'lib/dm-core/resource.rb', line 105

def attribute_get(name)
  properties[name].get(self)
end

#attribute_loaded?(name) ⇒ Boolean

Checks if the attribute has been loaded

Example

class Foo
  include DataMapper::Resource
  property :name, String
  property :description, Text, :lazy => false
end

Foo.new.attribute_loaded?(:description) # will return false

Returns:



332
333
334
# File 'lib/dm-core/resource.rb', line 332

def attribute_loaded?(name)
  instance_variable_defined?(properties[name].instance_variable_name)
end

#attribute_set(name, value) ⇒ Object

sets the value of the attribute and marks the attribute as dirty if it has been changed so that it may be saved. Do not set from instance variables directly, but use this method. This method handels the lazy loading the property and returning of defaults if nessesary.

Parameters

name<Symbol>

name attribute to set

value<Type>

value to store at that location

Returns

<Types>

the value stored at that given attribute, nil if none, and default if necessary

Example

Class Foo
  include DataMapper::Resource

  property :first_name, String
  property :last_name, String

  def full_name(name)
    name = name.split(' ')
    attribute_set(:first_name, name[0])
    attribute_set(:last_name, name[1])
  end

  # using the shorter syntax
  def name_from_address_book(name)
    name = name.split(', ')
    first_name = name[1]
    last_name = name[0]
  end
end

-



146
147
148
# File 'lib/dm-core/resource.rb', line 146

def attribute_set(name, value)
  properties[name].set(self, value)
end

#attributesObject

all the attributes of the model

Returns

Hash

All the (non)-lazy attributes



482
483
484
485
486
# File 'lib/dm-core/resource.rb', line 482

def attributes
  properties.map do |p|
    [p.name, send(p.getter)] if p.reader_visibility == :public
  end.compact.to_hash
end

#attributes=(values_hash) ⇒ Object

Mass assign of attributes

Parameters

value_hash <Hash>



495
496
497
498
499
500
501
502
503
504
505
# File 'lib/dm-core/resource.rb', line 495

def attributes=(values_hash)
  values_hash.each_pair do |k,v|
    setter = "#{k.to_s.sub(/\?\z/, '')}="

    if respond_to?(setter)
      send(setter, v)
    else
      raise NameError, "#{setter} is not a public property"
    end
  end
end

#destroyObject

destroy the instance, remove it from the repository

Returns

<True, False>

results of the destruction



302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'lib/dm-core/resource.rb', line 302

def destroy
  return false if new_record?
  return false unless repository.delete(to_query)

  @new_record = true
  repository.identity_map(model).delete(key)
  original_values.clear

  properties.each do |property|
    # We'll set the original value to nil as if we had a new record
    original_values[property.name] = nil if attribute_loaded?(property.name)
  end

  true
end

#dirty?Boolean

Checks if the class is dirty

Returns

True

returns if class is dirty

Returns:



406
407
408
# File 'lib/dm-core/resource.rb', line 406

def dirty?
  dirty_attributes.any?
end

#dirty_attributesObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Hash of attributes that have been marked dirty

Returns

Hash

attributes that have been marked dirty



376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
# File 'lib/dm-core/resource.rb', line 376

def dirty_attributes
  dirty_attributes = {}
  properties       = self.properties

  original_values.each do |name, old_value|
    property  = properties[name]
    new_value = property.get!(self)

    dirty = case property.track
    when :hash then old_value != new_value.hash
    else
      property.value(old_value) != property.value(new_value)
    end

    if dirty
      property.hash
      dirty_attributes[property] = property.value(new_value)
    end
  end

  dirty_attributes
end

#eql?(other) ⇒ Boolean Also known as: ==

Compares if its the same object or if attributes are equal

Parameters

other<Object>

Object to compare to

Returns

<True>

the outcome of the comparison as a boolean

-

Returns:



160
161
162
163
164
165
166
167
168
169
170
# File 'lib/dm-core/resource.rb', line 160

def eql?(other)
  return true if object_id == other.object_id
  return false unless other.kind_of?(model)
  return true if repository == other.repository && key == other.key

  properties.each do |property|
    return false if property.get!(self) != property.get!(other)
  end

  true
end

#hashObject

Computes a hash for the resource

Returns

<Integer>

the hash value of the resource

-



181
182
183
# File 'lib/dm-core/resource.rb', line 181

def hash
  model.hash + key.hash
end

#idObject

default id method to return the resource id when there is a single key, and the model was defined with a primary key named something other than id

Returns

<Array, Key> key or keys



244
245
246
247
# File 'lib/dm-core/resource.rb', line 244

def id
  key = self.key
  key.first if key.size == 1
end

#inspectObject

Inspection of the class name and the attributes

Returns

<String>

with the class name, attributes with their values

Example

>> Foo.new

> #<Foo name=nil updated_at=nil created_at=nil id=nil>

-



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/dm-core/resource.rb', line 197

def inspect
  attrs = []

  properties.each do |property|
    value = if property.lazy? && !attribute_loaded?(property.name) && !new_record?
      '<not loaded>'
    else
      send(property.getter).inspect
    end

    attrs << "#{property.name}=#{value}"
  end

  "#<#{model.name} #{attrs * ' '}>"
end

#keyObject



249
250
251
252
253
# File 'lib/dm-core/resource.rb', line 249

def key
  key_properties.map do |property|
    original_values[property.name] || property.get!(self)
  end
end

#loaded_attributesObject

fetches all the names of the attributes that have been loaded, even if they are lazy but have been called

Returns

Array

names of attributes that have been loaded

Example

class Foo
  include DataMapper::Resource
  property :name, String
  property :description, Text, :lazy => false
end

Foo.new.loaded_attributes # returns [:name]



354
355
356
# File 'lib/dm-core/resource.rb', line 354

def loaded_attributes
  properties.map{|p| p.name if attribute_loaded?(p.name)}.compact
end

#new_record?Boolean

Checks if the model has been saved

Returns

True

status if the model is new

Returns:



471
472
473
# File 'lib/dm-core/resource.rb', line 471

def new_record?
  !defined?(@new_record) || @new_record
end

#original_valuesObject

set of original values of properties

Returns

Hash

original values of properties



365
366
367
# File 'lib/dm-core/resource.rb', line 365

def original_values
  @original_values ||= {}
end

#pretty_print(pp) ⇒ Object

TODO docs



214
215
216
217
218
219
220
221
222
223
# File 'lib/dm-core/resource.rb', line 214

def pretty_print(pp)
  pp.group(1, "#<#{model.name}", ">") do
    pp.breakable
    pp.seplist(attributes.to_a) do |k_v|
      pp.text k_v[0].to_s
      pp.text " = "
      pp.pp k_v[1]
    end
  end
end

#readonly!Object



255
256
257
# File 'lib/dm-core/resource.rb', line 255

def readonly!
  @readonly = true
end

#readonly?Boolean

Returns:



259
260
261
# File 'lib/dm-core/resource.rb', line 259

def readonly?
  @readonly == true
end

#reloadObject

Reload association and all child association

Returns

self

returns the class itself



437
438
439
440
441
442
443
444
# File 'lib/dm-core/resource.rb', line 437

def reload
  unless new_record?
    reload_attributes(*loaded_attributes)
    (parent_associations + child_associations).each { |association| association.reload }
  end

  self
end

#reload_attributes(*attributes) ⇒ Object

Reload specific attributes

Parameters

*attributes<Array>

name of attribute

Returns

self

returns the class itself



456
457
458
459
460
461
462
# File 'lib/dm-core/resource.rb', line 456

def reload_attributes(*attributes)
  unless attributes.empty? || new_record?
    collection.reload(:fields => attributes)
  end

  self
end

#repositoryObject

Returns

<Repository>

the respository this resource belongs to in the context of a collection OR in the class’s context



231
232
233
# File 'lib/dm-core/resource.rb', line 231

def repository
  @repository || model.repository
end

#save(context = :default) ⇒ Object

save the instance to the data-store

Returns

<True, False>

results of the save

– #public

See Also:

  • DataMapper::Repository#save


272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
# File 'lib/dm-core/resource.rb', line 272

def save(context = :default)
  # Takes a context, but does nothing with it. This is to maintain the
  # same API through out all of dm-more. dm-validations requires a
  # context to be passed

  associations_saved = false
  child_associations.each { |a| associations_saved |= a.save }

  saved = if dirty? || (new_record? && key_properties.any? { |p| p.serial? })
    new_record? ? create : update
  end

  if saved
    original_values.clear
  end

  parent_associations.each { |a| associations_saved |= a.save }

  # We should return true if the model (or any of its associations)
  # were saved.
  (saved | associations_saved) == true
end

#to_query(query = {}) ⇒ Object

TODO: add docs



529
530
531
# File 'lib/dm-core/resource.rb', line 529

def to_query(query = {})
  model.to_query(repository, key, query) unless new_record?
end

#update_attributes(hash, *update_only) ⇒ Object

Updates attributes and saves model

Parameters

attributes<Hash> Attributes to be updated keys<Symbol, String, Array> keys of Hash to update (others won’t be updated)

Returns

<TrueClass, FalseClass> if model got saved or not

-



518
519
520
521
522
523
524
525
526
# File 'lib/dm-core/resource.rb', line 518

def update_attributes(hash, *update_only)
  unless hash.is_a?(Hash)
    raise ArgumentError, "Expecting the first parameter of " +
      "update_attributes to be a hash; got #{hash.inspect}"
  end
  loop_thru = update_only.empty? ? hash.keys : update_only
  loop_thru.each { |attr|  send("#{attr}=", hash[attr]) }
  save
end