module DataMapper::Model::Property

Public Class Methods

extended(model) click to toggle source
# File lib/dm-core/model/property.rb, line 9
def self.extended(model)
  model.instance_variable_set(:@properties,               {})
  model.instance_variable_set(:@field_naming_conventions, {})
end

Public Instance Methods

field_naming_convention(repository_name = default_storage_name) click to toggle source

Gets the field naming conventions for this resource in the given Repository

@param [String, Symbol] repository_name

the name of the Repository for which the field naming convention
will be retrieved

@return [#call]

The naming convention for the given Repository

@api public

# File lib/dm-core/model/property.rb, line 159
def field_naming_convention(repository_name = default_storage_name)
  @field_naming_conventions[repository_name] ||= repository(repository_name).adapter.field_naming_convention
end
inherited(model) click to toggle source
Calls superclass method
# File lib/dm-core/model/property.rb, line 15
def inherited(model)
  model.instance_variable_set(:@properties,               {})
  model.instance_variable_set(:@field_naming_conventions, @field_naming_conventions.dup)

  @properties.each do |repository_name, properties|
    model_properties = model.properties(repository_name)
    properties.each { |property| model_properties << property }
  end

  super
end
key(repository_name = default_repository_name) click to toggle source

Gets the list of key fields for this Model in repository_name

@param [String] repository_name

The name of the Repository for which the key is to be reported

@return [Array]

The list of key fields for this Model in +repository_name+

@api public

# File lib/dm-core/model/property.rb, line 140
def key(repository_name = default_repository_name)
  properties(repository_name).key
end
key_conditions(repository, key) click to toggle source

@api private

# File lib/dm-core/model/property.rb, line 177
def key_conditions(repository, key)
  Hash[ self.key(repository.name).zip(key.nil? ? [] : key) ]
end
properties(repository_name = default_repository_name) click to toggle source

Gets a list of all properties that have been defined on this Model in the requested repository

@param [Symbol, String] repository_name

The name of the repository to use. Uses the default Repository
if none is specified.

@return [PropertySet]

A list of Properties defined on this Model in the given Repository

@api public

# File lib/dm-core/model/property.rb, line 116
def properties(repository_name = default_repository_name)
  # TODO: create PropertySet#copy that will copy the properties, but assign the
  # new Relationship objects to a supplied repository and model.  dup does not really
  # do what is needed
  repository_name = repository_name.to_sym

  default_repository_name = self.default_repository_name

  @properties[repository_name] ||= if repository_name == default_repository_name
    PropertySet.new
  else
    properties(default_repository_name).dup
  end
end
properties_with_subclasses(repository_name = default_repository_name) click to toggle source

@api private

# File lib/dm-core/model/property.rb, line 164
def properties_with_subclasses(repository_name = default_repository_name)
  properties = properties(repository_name).dup

  descendants.each do |model|
    model.properties(repository_name).each do |property|
      properties << property
    end
  end

  properties
end
property(name, type, options = {}) click to toggle source

Defines a Property on the Resource

@param [Symbol] name

the name for which to call this property

@param [Class] type

the ruby type to define this property as

@param [Hash(Symbol => String)] options

a hash of available options

@return [Property]

the created Property

@see Property

@api public

# File lib/dm-core/model/property.rb, line 42
def property(name, type, options = {})
  if TrueClass == type
    raise "#{type} is deprecated, use Boolean instead at #{caller[2]}"
  elsif BigDecimal == type
    raise "#{type} is deprecated, use Decimal instead at #{caller[2]}"
  end

  # if the type can be found within Property then
  # use that class rather than the primitive
  unless klass = DataMapper::Property.determine_class(type)
    raise ArgumentError, "+type+ was #{type.inspect}, which is not a supported type"
  end

  property = klass.new(self, name, options)

  repository_name = self.repository_name
  properties      = properties(repository_name)

  properties << property

  # Add property to the other mappings as well if this is for the default
  # repository.

  if repository_name == default_repository_name
    other_repository_properties = DataMapper::Ext::Hash.except(@properties, default_repository_name)

    other_repository_properties.each do |other_repository_name, properties|
      next if properties.named?(name)

      # make sure the property is created within the correct repository scope
      DataMapper.repository(other_repository_name) do
        properties << klass.new(self, name, options)
      end
    end
  end

  # Add the property to the lazy_loads set for this resources repository
  # only.
  # TODO Is this right or should we add the lazy contexts to all
  # repositories?
  if property.lazy?
    context = options.fetch(:lazy, :default)
    context = :default if context == true

    Array(context).each do |context|
      properties.lazy_context(context) << property
    end
  end

  # add the property to the child classes only if the property was
  # added after the child classes' properties have been copied from
  # the parent
  descendants.each do |descendant|
    descendant.properties(repository_name) << property
  end

  create_reader_for(property)
  create_writer_for(property)

  # FIXME: explicit return needed for YARD to parse this properly
  return property
end
serial(repository_name = default_repository_name) click to toggle source

@api public

# File lib/dm-core/model/property.rb, line 145
def serial(repository_name = default_repository_name)
  key(repository_name).detect { |property| property.serial? }
end

Private Instance Methods

create_reader_for(property) click to toggle source

defines the reader method for the property

@api private

# File lib/dm-core/model/property.rb, line 200
      def create_reader_for(property)
        name                   = property.name.to_s
        reader_visibility      = property.reader_visibility
        instance_variable_name = property.instance_variable_name
        property_module.module_eval "          #{reader_visibility}
          def #{name}
            return #{instance_variable_name} if defined?(#{instance_variable_name})
            property = properties[#{name.inspect}]
            #{instance_variable_name} = property ? persistence_state.get(property) : nil
          end
", __FILE__, __LINE__ + 1

        boolean_reader_name = "#{name}?"

        if property.kind_of?(DataMapper::Property::Boolean)
          property_module.module_eval "            #{reader_visibility}
            def #{boolean_reader_name}
              #{name}
            end
", __FILE__, __LINE__ + 1
        end
      end
create_writer_for(property) click to toggle source

defines the setter for the property

@api private

# File lib/dm-core/model/property.rb, line 228
      def create_writer_for(property)
        name              = property.name
        writer_visibility = property.writer_visibility

        writer_name = "#{name}="
        property_module.module_eval "          #{writer_visibility}
          def #{writer_name}(value)
            property = properties[#{name.inspect}]
            value    = property.typecast(value)
            self.persistence_state = persistence_state.set(property, value)
            persistence_state.get(property)
          end
", __FILE__, __LINE__ + 1
      end
method_missing(method, *args, &block) click to toggle source

@api public

Calls superclass method
# File lib/dm-core/model/property.rb, line 245
def method_missing(method, *args, &block)
  if property = properties(repository_name)[method]
    return property
  end

  super
end
property_module() click to toggle source

Defines the anonymous module that is used to add properties. 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/property.rb, line 187
def property_module
  @property_module ||= begin
    mod = Module.new
    class_eval do
      include mod
    end
    mod
  end
end