module ActiveRecord::AttributeAssignment

def _assign_attribute(k, v)

def _assign_attribute(k, v)
  public_send("#{k}=", v)
rescue NoMethodError
  if respond_to?("#{k}=")
    raise
  else
    raise UnknownAttributeError.new(self, k)
  end
end

def assign_attributes(new_attributes)

exception is raised.
of this method is +false+ an ActiveModel::ForbiddenAttributesError
If the passed hash responds to permitted? method and the return value

keys matching the attribute names (which again matches the column names).
Allows you to set all the attributes by passing in a hash of attributes with
def assign_attributes(new_attributes)
  if !new_attributes.respond_to?(:stringify_keys)
    raise ArgumentError, "When assigning attributes, you must pass a hash as an argument."
  end
  return if new_attributes.blank?
  attributes                  = new_attributes.stringify_keys
  multi_parameter_attributes  = []
  nested_parameter_attributes = []
  attributes = sanitize_for_mass_assignment(attributes)
  attributes.each do |k, v|
    if k.include?("(")
      multi_parameter_attributes << [ k, v ]
    elsif v.is_a?(Hash)
      nested_parameter_attributes << [ k, v ]
    else
      _assign_attribute(k, v)
    end
  end
  assign_nested_parameter_attributes(nested_parameter_attributes) unless nested_parameter_attributes.empty?
  assign_multiparameter_attributes(multi_parameter_attributes) unless multi_parameter_attributes.empty?
end

def assign_multiparameter_attributes(pairs)

f for Float. If all the values for a given attribute are empty, the attribute will be set to +nil+.
parentheses to have the parameters typecasted before they're used in the constructor. Use i for Fixnum and
written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the
So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate
by calling new on the column type or aggregation type (through composed_of) object with these parameters.
Instantiates objects for all attribute classes that needs more than one constructor parameter. This is done
def assign_multiparameter_attributes(pairs)
  execute_callstack_for_multiparameter_attributes(
    extract_callstack_for_multiparameter_attributes(pairs)
  )
end

def assign_nested_parameter_attributes(pairs)

Assign any deferred nested attributes after the base attributes have been set.
def assign_nested_parameter_attributes(pairs)
  pairs.each { |k, v| _assign_attribute(k, v) }
end

def execute_callstack_for_multiparameter_attributes(callstack)

def execute_callstack_for_multiparameter_attributes(callstack)
  errors = []
  callstack.each do |name, values_with_empty_parameters|
    begin
      send("#{name}=", MultiparameterAttribute.new(self, name, values_with_empty_parameters).read_value)
    rescue => ex
      errors << AttributeAssignmentError.new("error on assignment #{values_with_empty_parameters.values.inspect} to #{name} (#{ex.message})", ex, name)
    end
  end
  unless errors.empty?
    error_descriptions = errors.map { |ex| ex.message }.join(",")
    raise MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes [#{error_descriptions}]"
  end
end

def extract_callstack_for_multiparameter_attributes(pairs)

def extract_callstack_for_multiparameter_attributes(pairs)
  attributes = {}
  pairs.each do |(multiparameter_name, value)|
    attribute_name = multiparameter_name.split("(").first
    attributes[attribute_name] ||= {}
    parameter_value = value.empty? ? nil : type_cast_attribute_value(multiparameter_name, value)
    attributes[attribute_name][find_parameter_position(multiparameter_name)] ||= parameter_value
  end
  attributes
end

def find_parameter_position(multiparameter_name)

def find_parameter_position(multiparameter_name)
  multiparameter_name.scan(/\(([0-9]*).*\)/).first.first.to_i
end

def type_cast_attribute_value(multiparameter_name, value)

def type_cast_attribute_value(multiparameter_name, value)
  multiparameter_name =~ /\([0-9]*([if])\)/ ? value.send("to_" + $1) : value
end