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


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

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


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

def options
  @options
end

#valueObject (readonly) Also known as: to_f

Returns the value of attribute value


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

def value
  @value
end

Class Method Details

.add_options(klass) ⇒ Object


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
102
# File 'lib/m9t/base.rb', line 70

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


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
# File 'lib/m9t/base.rb', line 7

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


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

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

Instance Method Details

#initialize(value) ⇒ Object


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

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

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

Returns:

  • (Boolean)

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

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.


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

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