lib/active_data/model/attributable.rb in active_data-0.1.0 vs lib/active_data/model/attributable.rb in active_data-0.2.0
- old
+ new
@@ -3,70 +3,73 @@
module Attributable
extend ActiveSupport::Concern
included do
class_attribute :_attributes, :instance_reader => false, :instance_writer => false
- self._attributes = ActiveSupport::HashWithIndifferentAccess.new
+ self._attributes = {}
- extend generated_class_attributes_methods
- include generated_instance_attributes_methods
-
delegate :attribute_default, :to => 'self.class'
end
module ClassMethods
+ def attribute name, options = {}, &block
+ attribute = build_attribute(name, options, &block)
+ self._attributes = _attributes.merge(attribute.name => attribute)
+
+ attribute.generate_instance_methods generated_instance_attributes_methods
+ attribute.generate_class_methods generated_class_attributes_methods
+ attribute
+ end
+
def build_attribute name, options = {}, &block
klass = case options[:type].to_s
when 'Localized'
ActiveData::Attributes::Localized
else
ActiveData::Attributes::Base
end
klass.new name, options, &block
end
- def attribute name, options = {}, &block
- attribute = build_attribute(name, options, &block)
- self._attributes = _attributes.merge(attribute.name => attribute)
-
- attribute.generate_instance_methods generated_instance_attributes_methods
- attribute.generate_singleton_methods generated_class_attributes_methods
- attribute
- end
-
def generated_class_attributes_methods
- @generated_class_attributes_methods ||= Module.new
+ @generated_class_attributes_methods ||= Module.new.tap { |proxy| extend proxy }
end
def generated_instance_attributes_methods
- @generated_instance_attributes_methods ||= Module.new
+ @generated_instance_attributes_methods ||= Module.new.tap { |proxy| include proxy }
end
def initialize_attributes
- _attributes.inject(ActiveSupport::HashWithIndifferentAccess.new) do |result, (name, value)|
- result[name] = nil
- result
- end
+ Hash[_attributes.map { |(name, _)| [name, nil] }]
end
end
def read_attribute name
- attribute = self.class._attributes[name]
- source = @attributes[name].nil? ? attribute.default_value(self) : @attributes[name]
- attribute.type_cast source
+ name = name.to_sym
+ if attributes_cache.key? name
+ attributes_cache[name]
+ else
+ attribute = self.class._attributes[name]
+ value = attribute.type_cast @attributes[name]
+ use_default = attribute.default_blank? && value.blank? || value.nil?
+
+ attributes_cache[name] = use_default ? attribute.default_value(self) : value
+ end
end
alias_method :[], :read_attribute
def has_attribute? name
- @attributes.key? name
+ @attributes.key? name.to_sym
end
def read_attribute_before_type_cast name
- @attributes[name]
+ @attributes[name.to_sym]
end
def write_attribute name, value
+ name = name.to_sym
+ attributes_cache.delete name
@attributes[name] = value
end
alias_method :[]=, :write_attribute
def attributes
@@ -85,32 +88,35 @@
end
def attributes= attributes
assign_attributes(attributes)
end
+ alias_method :update_attributes, :attributes=
- def update_attributes attributes
- self.attributes = attributes
+ def write_attributes attributes
+ attributes.each { |(name, value)| send("#{name}=", value) }
end
def reverse_update_attributes attributes
reverse_assign_attributes(attributes)
end
private
+ def attributes_cache
+ @attributes_cache ||= {}
+ end
+
def assign_attributes attributes
(attributes.presence || {}).each do |(name, value)|
- send("#{name}=", value) if respond_to?("#{name}=")
+ send("#{name}=", value) if has_attribute?(name) || respond_to?("#{name}=")
end
- self.attributes
end
def reverse_assign_attributes attributes
(attributes.presence || {}).each do |(name, value)|
send("#{name}=", value) if respond_to?("#{name}=") && respond_to?(name) && send(name).blank?
end
- self.attributes
end
end
end
end