lib/active_data/model/attributable.rb in active_data-0.0.1 vs lib/active_data/model/attributable.rb in active_data-0.1.0

- old
+ new

@@ -1,63 +1,46 @@ -require 'active_data/model/serializable' - module ActiveData module Model module Attributable - include Serializable extend ActiveSupport::Concern included do class_attribute :_attributes, :instance_reader => false, :instance_writer => false self._attributes = ActiveSupport::HashWithIndifferentAccess.new + extend generated_class_attributes_methods + include generated_instance_attributes_methods + delegate :attribute_default, :to => 'self.class' end module ClassMethods - def attribute name, options = {}, &block - default = options.is_a?(Hash) ? options[:default] : options - type = options.is_a?(Hash) ? normalize_type(options[:type]) : String - self._attributes = self._attributes.merge(name => { - default: (block || default), - type: type - }) - - define_method name do - read_attribute(name) + def build_attribute name, options = {}, &block + klass = case options[:type].to_s + when 'Localized' + ActiveData::Attributes::Localized + else + ActiveData::Attributes::Base end - define_method "#{name}_before_type_cast" do - read_attribute_before_type_cast(name) - end - define_method "#{name}?" do - read_attribute(name).present? - end - define_method "#{name}=" do |value| - write_attribute(name, value) - end + klass.new name, options, &block + end - if options.is_a?(Hash) && options[:in] - define_singleton_method "#{name}_values" do - options[:in].dup - end - 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 normalize_type type - case type - when String, Symbol then - type.to_s.camelize.safe_constantize - when nil then - String - else - type - end + def generated_class_attributes_methods + @generated_class_attributes_methods ||= Module.new end - def attribute_default name - default = _attributes[name][:default] - default.respond_to?(:call) ? default.call : default + def generated_instance_attributes_methods + @generated_instance_attributes_methods ||= Module.new end def initialize_attributes _attributes.inject(ActiveSupport::HashWithIndifferentAccess.new) do |result, (name, value)| result[name] = nil @@ -65,21 +48,26 @@ end end end def read_attribute name - @attributes[name].nil? ? attribute_default(name) : @attributes[name] + attribute = self.class._attributes[name] + source = @attributes[name].nil? ? attribute.default_value(self) : @attributes[name] + attribute.type_cast source end alias_method :[], :read_attribute + def has_attribute? name + @attributes.key? name + end + def read_attribute_before_type_cast name - deserialize(send(name)) + @attributes[name] end def write_attribute name, value - type = self.class._attributes[name][:type] - @attributes[name] = serialize(value, type) + @attributes[name] = value end alias_method :[]=, :write_attribute def attributes Hash[attribute_names.map { |name| [name, send(name)] }] @@ -102,14 +90,25 @@ def update_attributes attributes self.attributes = attributes end + def reverse_update_attributes attributes + reverse_assign_attributes(attributes) + end + private def assign_attributes attributes (attributes.presence || {}).each do |(name, value)| send("#{name}=", value) if 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