module Modis::Attribute::ClassMethods

Attributes

attributes[RW]
attributes_with_defaults[RW]

Public Instance Methods

attribute(name, type, options = {}) click to toggle source
# File lib/modis/attribute.rb, line 32
      def attribute(name, type, options = {})
        name = name.to_s
        raise AttributeError, "Attribute with name '#{name}' has already been specified." if attributes.key?(name)

        type_classes = Array(type).map do |t|
          raise UnsupportedAttributeType, t unless TYPES.key?(t)

          TYPES[t]
        end.flatten

        attributes[name] = options.update(type: type)
        attributes_with_defaults[name] = options[:default]
        define_attribute_methods([name])

        value_coercion = type == :timestamp ? 'value = Time.new(*value) if value && value.is_a?(Array) && value.count == 7' : nil
        predicate = type_classes.map { |cls| "value.is_a?(#{cls.name})" }.join(' || ')

        type_check = <<-RUBY
        if value && !(#{predicate})
          raise Modis::AttributeCoercionError, "Received value of type '\#{value.class}', expected '#{type_classes.join("', '")}' for attribute '#{name}'."
        end
        RUBY

        class_eval <<-RUBY, __FILE__, __LINE__ + 1
          def #{name}
            attributes['#{name}']
          end

          def #{name}=(value)
            #{value_coercion}

            # ActiveSupport's Time#<=> does not perform well when comparing with NilClass.
            if (value.nil? ^ attributes['#{name}'].nil?) || (value != attributes['#{name}'])
              #{type_check}
              #{name}_will_change!
              attributes['#{name}'] = value
            end
          end
        RUBY
      end
bootstrap_attributes(parent = nil) click to toggle source
# File lib/modis/attribute.rb, line 21
def bootstrap_attributes(parent = nil)
  class << self
    attr_accessor :attributes, :attributes_with_defaults
  end

  self.attributes = parent ? parent.attributes.dup : {}
  self.attributes_with_defaults = parent ? parent.attributes_with_defaults.dup : {}

  attribute :id, :integer unless parent
end