class ActiveRecord::AttributeAssignment::MultiparameterAttribute

:nodoc:

def blank_date_parameter?

exists. The caller is responsible to handle the case of this returning true.
positions instead of missing ones, and does not raise in case one blank position
than the validate_required_parameters! method, since it just checks for blank
Checks whether some blank date parameter exists. Note that this is different
def blank_date_parameter?
  (1..3).any? { |position| values[position].blank? }
end

def extract_max_param(upper_cap = 100)

def extract_max_param(upper_cap = 100)
  [values.keys.max, upper_cap].min
end

def initialize(object, name, values)

def initialize(object, name, values)
  @object = object
  @name   = name
  @values = values
end

def instantiate_time_object(set_values)

def instantiate_time_object(set_values)
  if object.class.send(:create_time_zone_conversion_attribute?, name, cast_type)
    Time.zone.local(*set_values)
  else
    Time.send(object.class.default_timezone, *set_values)
  end
end

def read_date

def read_date
  return if blank_date_parameter?
  set_values = values.values_at(1,2,3)
  begin
    Date.new(*set_values)
  rescue ArgumentError # if Date.new raises an exception on an invalid date
    instantiate_time_object(set_values).to_date # we instantiate Time object and convert it back to a date thus using Time's logic in handling invalid dates
  end
end

def read_other

def read_other
  max_position = extract_max_param
  positions    = (1..max_position)
  validate_required_parameters!(positions)
  values.slice(*positions)
end

def read_time

def read_time
  # If column is a :time (and not :date or :datetime) there is no need to validate if
  # there are year/month/day fields
  if cast_type.type == :time
    # if the column is a time set the values to their defaults as January 1, 1970, but only if they're nil
    { 1 => 1970, 2 => 1, 3 => 1 }.each do |key,value|
      values[key] ||= value
    end
  else
    # else column is a timestamp, so if Date bits were not provided, error
    validate_required_parameters!([1,2,3])
    # If Date bits were provided but blank, then return nil
    return if blank_date_parameter?
  end
  max_position = extract_max_param(6)
  set_values   = values.values_at(*(1..max_position))
  # If Time bits are not there, then default to 0
  (3..5).each { |i| set_values[i] = set_values[i].presence || 0 }
  instantiate_time_object(set_values)
end

def read_value

def read_value
  return if values.values.compact.empty?
  @cast_type = object.type_for_attribute(name)
  klass = cast_type.klass
  if klass == Time
    read_time
  elsif klass == Date
    read_date
  else
    read_other
  end
end

def validate_required_parameters!(positions)

If some position is not provided, it errors out a missing parameter exception.
def validate_required_parameters!(positions)
  if missing_parameter = positions.detect { |position| !values.key?(position) }
    raise ArgumentError.new("Missing Parameter - #{name}(#{missing_parameter})")
  end
end