Module: MongoMapper::Plugins::MultiParameterAttributes

Extended by:
ActiveSupport::Concern
Defined in:
lib/mm-multi-parameter-attributes.rb

Instance Method Summary collapse

Instance Method Details

#assign_multiparameter_attributes(pairs) ⇒ Object

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



34
35
36
37
38
# File 'lib/mm-multi-parameter-attributes.rb', line 34

def assign_multiparameter_attributes(pairs)
  execute_callstack_for_multiparameter_attributes(
    extract_callstack_for_multiparameter_attributes(pairs)
  )
end

#attributes=(new_attributes) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/mm-multi-parameter-attributes.rb', line 9

def attributes=(new_attributes)
  return if new_attributes.nil?

  multi_parameter_attributes = []
  normal_attributes = {}

  new_attributes.each do |k, v|
    if k.to_s.include?("(")
      multi_parameter_attributes << [ k.to_s, v ]
    else
      normal_attributes[k] = v
    end
  end

  assign_multiparameter_attributes(multi_parameter_attributes)

  super(normal_attributes)
end

#execute_callstack_for_multiparameter_attributes(callstack) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/mm-multi-parameter-attributes.rb', line 40

def execute_callstack_for_multiparameter_attributes(callstack)
  callstack.each do |name, values_with_empty_parameters|
    # in order to allow a date to be set without a year, we must keep the empty values.
    # Otherwise, we wouldn't be able to distinguish it from a date with an empty day.
    values = values_with_empty_parameters.reject(&:blank?)

    if values.any?

      key = self.class.keys[name]
      raise ArgumentError, "Unknown key #{name}" if key.nil?
      klass = key.type

      value = if Time == klass
                Time.zone.local(*valid_datetime_values(values_with_empty_parameters))
              elsif Date == klass
                values = valid_datetime_values(values_with_empty_parameters)
                begin
                  Date.new(*values)
                rescue ArgumentError => ex # if Date.new raises an exception on an invalid date
                  Time.zone.local(*values).to_date # we instantiate Time object and convert it back to a date thus using Time's logic in handling invalid dates
                end
              else
                klass.new(*values_with_empty_parameters)
              end
    else
      value = nil
    end
    writer_method = "#{name}="
    if respond_to?(writer_method)
      self.send(writer_method, value)
    else
      self[name.to_s] = value
    end
  end
end

#extract_callstack_for_multiparameter_attributes(pairs) ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/mm-multi-parameter-attributes.rb', line 85

def extract_callstack_for_multiparameter_attributes(pairs)
  attributes = { }

  for pair in pairs
    multiparameter_name, value = pair
    attribute_name = multiparameter_name.split("(").first
    attributes[attribute_name] = [] unless attributes.include?(attribute_name)

    attributes[attribute_name] << [ find_parameter_position(multiparameter_name), value ]
  end

  attributes.each { |name, values| attributes[name] = values.sort_by{ |v| v.first }.collect { |v| v.last } }
end

#find_parameter_position(multiparameter_name) ⇒ Object



99
100
101
# File 'lib/mm-multi-parameter-attributes.rb', line 99

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

#valid_datetime_values(values) ⇒ Object

Ensures that values for date are set to now if blank (as month and say cannot be 0) and that all values are converted to integers



77
78
79
80
81
82
83
# File 'lib/mm-multi-parameter-attributes.rb', line 77

def valid_datetime_values(values)
  now = Time.zone.now
  values[0] = now.year if values[0].blank?
  values[1] = now.month if values[1].blank?
  values[2] = now.day if values[2].blank?
  values.map(&:to_i)
end