Module: Measured::Rails::ActiveRecord::ClassMethods

Defined in:
lib/measured/rails/active_record.rb

Instance Method Summary collapse

Instance Method Details

#measured(measured_class, *fields) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/measured/rails/active_record.rb', line 6

def measured(measured_class, *fields)
  options = fields.extract_options!
  options = {}.merge(options)

  measured_class = measured_class.constantize if measured_class.is_a?(String)
  unless measured_class.is_a?(Class) && measured_class.ancestors.include?(Measured::Measurable)
    raise Measured::Rails::Error, "Expecting #{ measured_class } to be a subclass of Measured::Measurable"
  end

  options[:class] = measured_class

  fields.map(&:to_sym).each do |field|
    raise Measured::Rails::Error, "The field #{ field } has already been measured" if measured_fields.key?(field)

    measured_fields[field] = options

    unit_field_name = if options[:unit_field_name]
      measured_fields[field][:unit_field_name] = options[:unit_field_name].to_s
    else
      "#{ field }_unit"
    end

    value_field_name = if options[:value_field_name]
      measured_fields[field][:value_field_name] = options[:value_field_name].to_s
    else
      "#{ field }_value"
    end

    # Reader to retrieve measured object
    define_method(field) do
      value = public_send(value_field_name)
      unit = public_send(unit_field_name)

      return nil unless value && unit

      instance = instance_variable_get("@measured_#{ field }") if instance_variable_defined?("@measured_#{ field }")
      new_instance = begin
        measured_class.new(value, unit)
      rescue Measured::UnitError
        nil
      end

      if instance == new_instance
        instance
      else
        instance_variable_set("@measured_#{ field }", new_instance)
      end
    end

    # Writer to assign measured object
    define_method("#{ field }=") do |incoming|
      if incoming.is_a?(measured_class)
        instance_variable_set("@measured_#{ field }", incoming)
        precision = self.column_for_attribute(value_field_name).precision
        scale = self.column_for_attribute(value_field_name).scale
        rounded_to_scale_value = incoming.value.round(scale)

        max = self.class.measured_fields[field][:max_on_assignment]
        if max && rounded_to_scale_value > max
          rounded_to_scale_value = max
        elsif rounded_to_scale_value.to_i.to_s.length > (precision - scale)
          raise Measured::Rails::Error, "The value #{rounded_to_scale_value} being set for column '#{value_field_name}' has too many significant digits. Please ensure it has no more than #{precision - scale} significant digits."
        end

        public_send("#{ value_field_name }=", rounded_to_scale_value)
        public_send("#{ unit_field_name }=", incoming.unit.name)
      else
        instance_variable_set("@measured_#{ field }", nil)
        public_send("#{ value_field_name}=", nil)
        public_send("#{ unit_field_name }=", nil)
      end
    end

    # Writer to override unit assignment
    redefine_method("#{ unit_field_name }=") do |incoming|
      unit_name = measured_class.unit_system.unit_for(incoming).try!(:name)
      write_attribute(unit_field_name, unit_name || incoming)
    end
  end
end

#measured_fieldsObject



87
88
89
# File 'lib/measured/rails/active_record.rb', line 87

def measured_fields
  @measured_fields ||= {}
end