Module: M9t::Base

Included in:
Direction, Distance, Pressure, Speed, Temperature
Defined in:
lib/m9t/base.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object

define conversion instance methods as required



117
118
119
120
121
122
123
124
# File 'lib/m9t/base.rb', line 117

def method_missing(name, *args, &block)
  to = extract_to(name)
  if to && legal_conversion?(to)
    define_conversion(to)
    return send(name)
  end
  super
end

Instance Attribute Details

#optionsObject (readonly)

Returns the value of attribute options.



109
110
111
# File 'lib/m9t/base.rb', line 109

def options
  @options
end

#valueObject (readonly) Also known as: to_f

Returns the value of attribute value.



109
110
111
# File 'lib/m9t/base.rb', line 109

def value
  @value
end

Class Method Details

.add_options(klass) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/m9t/base.rb', line 69

def self.add_options(klass)
  klass.instance_eval do
    # Make sure derived classes get the extra methods
    def inherited(sub) #:nodoc:
      sub.instance_eval do
        M9t::Base.add_options(sub)
      end
    end

    # Returns the class's current options - see the specific class for
    # defaults
    def options
      @options
    end

    # Reloads the class"s default options
    def reset_options!
      @options = self::DEFAULT_OPTIONS.clone
    end

    # The name used for i18n translations
    #  M9t::Distance => "distance"
    def measurement_name
      name.split("::")[-1].downcase
    end

    def default_unit
      self::DEFAULT_OPTIONS[:units]
    end

    reset_options!
  end
end

.generate_conversions(klass) ⇒ 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
# File 'lib/m9t/base.rb', line 6

def self.generate_conversions(klass)
  klass.instance_eval do
    def convert(from, to, value)
      value / self::CONVERSIONS[from] * self::CONVERSIONS[to]
    end

    # Define class conversion methods as required
    def method_missing(name, *args, &block)
      from, to = extract_from_and_to(name)
      if from
        if legal_conversion?(from, to)
          define_conversion(from, to)
          return send(name, args[0])
        end
      end
      if legal_constructor?(name)
        define_constructor(name)
        return send(name, args[0])
      end
      super
    end

    def respond_to?(name, _include_all = false)
      from, to = extract_from_and_to(name)
      return true if from && legal_conversion?(from, to)
      legal_constructor?(name)
    end

    private

    def extract_from_and_to(name)
      name.to_s.scan(/^(\w+)_to_(\w+)$/)[0]
    end

    def legal_conversion?(from, to)
      self::CONVERSIONS.include?(from.to_sym) &&
        self::CONVERSIONS.include?(to.to_sym)
    end

    def define_conversion(from, to)
      self.class.instance_exec do
        define_method("#{from}_to_#{to}") do |value|
          convert(from.to_sym, to.to_sym, value)
        end
      end
    end

    def legal_constructor?(name)
      self::CONVERSIONS.include?(name.to_sym)
    end

    # Define klass.unit(value) which converts the parameter
    # from the unit and returns an instance
    def define_constructor(name)
      self.class.instance_exec do
        define_method(name.to_sym) do |*args|
          new(args[0].to_f / self::CONVERSIONS[name])
        end
      end
    end
  end
end

.included(base) ⇒ Object

Adds methods for handling options



104
105
106
107
# File 'lib/m9t/base.rb', line 104

def self.included(base) #:nodoc:
  M9t::Base.add_options(base)
  M9t::Base.generate_conversions(base)
end

Instance Method Details

#initialize(value) ⇒ Object



112
113
114
# File 'lib/m9t/base.rb', line 112

def initialize(value)
  @value = value.to_f
end

#respond_to?(name, _include_all = false) ⇒ Boolean

Returns:

  • (Boolean)


126
127
128
129
130
# File 'lib/m9t/base.rb', line 126

def respond_to?(name, _include_all = false)
  to = extract_to(name)
  return true if to && legal_conversion?(to)
  super
end

#to_s(options = {}) ⇒ Object

Returns the string representation of the measurement, taking into account locale, desired units and abbreviation.



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/m9t/base.rb', line 134

def to_s(options = {})
  options = self.class.options.merge(options)
  unless self.class::CONVERSIONS.include?(options[:units])
    units_error(options[:units])
  end
  value_in_units = send("to_#{options[:units]}")
  localized_value = I18n.localize_float(
    value_in_units, format: "%0.#{options[:precision]}f"
  )

  key = i18n_key(options)
  unit = I18n.t(key, count: value_in_units)

  "#{localized_value}%s#{unit}" % (options[:abbreviated] ? "" : " ")
end