# Class: Measure

Inherits:
Object
• Object
show all
Defined in:
lib/measure.rb

## Overview

Measure represents a decimal value and a unit. It depends on nomenclatures Unit and Dimension.

## Constant Summary collapse

@@dimensions =
Nomen.find_or_initialize(:dimensions)
@@units =
Nomen.find_or_initialize(:units)

## Instance Attribute Summary collapse

Returns the value of attribute unit.

Returns the value of attribute value.

## Class Method Summary collapse

• Returns the dimension of the given unit.

• Returns the units of same dimension of the given unit.

• Lists all units.

## Instance Method Summary collapse

• Test if the other measure is equal to self.

• Returns the dimension of a other.

• Returns self of its value.

• Returns opposite of its value.

• Returns if self is less than other.

• Returns if self is less than or equal to other.

• Returns if self is greater than other.

• Test if the other measure is equal to self.

• Returns if self is greater than other.

• Returns if self is greater than or equal to other.

• #convert(unit) ⇒ Object (also: #in)

Returns a new measure in the given unit.

• #convert!(unit) ⇒ Object (also: #in!)

Converts measure inline without instanciating a new Measure.

• Returns the dimension of a measure.

• constructor

Ways to instanciate a measure: \$ Measure.new(55.23, 'kilogram') \$ Measure.new(55.23, :kilogram) \$ Measure.new('55.23 kilogram') \$ Measure.new('55.23kilogram') \$ Measure.new('55.23 kg') \$ Measure.new('55.23kg') \$ 55.23.in_kilogram \$ 55.23.in(:kilogram) \$ 55.23.in('kilogram').

• #localize(options = {}) ⇒ Object (also: #l)

Localize a measure FIXME: Measure l10n must be configurable in translation files.

• Returns the unit from the nomenclature.

• Return BigDecimal value.

• Return Float value.

• Test if measure is null.

## Constructor Details

### #initialize(*args) ⇒ Measure

Ways to instanciate a measure: \$ Measure.new(55.23, 'kilogram') \$ Measure.new(55.23, :kilogram) \$ Measure.new('55.23 kilogram') \$ Measure.new('55.23kilogram') \$ Measure.new('55.23 kg') \$ Measure.new('55.23kg') \$ 55.23.in_kilogram \$ 55.23.in(:kilogram) \$ 55.23.in('kilogram')

 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 86 87 # File 'lib/measure.rb', line 53 def initialize(*args) value = nil unit = nil if args.size == 1 expr = args.shift.to_s.gsub(/[[:space:]]+/, ' ').strip unless expr =~ /\A-?([\,\.]\d+|\d+([\,\.]\d+)?)\s*[^\s]+\z/ raise InvalidExpression, "#{expr} cannot be parsed." end unit = expr.gsub(/\A-?([\,\.]\d+|\d+([\,\.]\d+)?)\s*/, '').strip value = expr[0..-(1 + unit.size)].strip.to_d elsif args.size == 2 value = args.shift unit = args.shift else raise ArgumentError, "wrong number of arguments (#{args.size} for 1 or 2)" end value = 0 if value.blank? unless value.is_a? Numeric raise ArgumentError, "Value can't be converted to float: #{value.inspect}" end @value = value.to_r unit = unit.name.to_s if unit.is_a?(Nomen::Item) @unit = unit.to_s unless @@units.items[@unit] units = @@units.where(symbol: @unit) if units.size > 1 raise AmbiguousUnit, "The unit #{@unit} match with too many units: #{units.map(&:name).to_sentence}." elsif units.size.zero? # fail ArgumentError, "Unknown unit: #{unit.inspect}" @unit = 'unity' else @unit = units.first.name.to_s end end end

## Instance Attribute Details

Returns the value of attribute unit

 13 14 15 # File 'lib/measure.rb', line 13 def unit @unit end

Returns the value of attribute value

 13 14 15 # File 'lib/measure.rb', line 13 def value @value end

## Class Method Details

### .dimension(unit) ⇒ Object

Returns the dimension of the given unit

 38 39 40 # File 'lib/measure.rb', line 38 def dimension(unit) @@units[unit].dimension.to_sym end

### .siblings(unit) ⇒ Object

Returns the units of same dimension of the given unit

 33 34 35 # File 'lib/measure.rb', line 33 def siblings(unit) units(dimension(unit)) end

### .units(dimension = nil) ⇒ Object

Lists all units. Can be filtered on a given dimension

 22 23 24 25 26 27 28 29 30 # File 'lib/measure.rb', line 22 def units(dimension = nil) return @@units.all unless dimension unless @@dimensions.all.include?(dimension.to_s) raise ArgumentError, "Unknown dimension #{dimension.inspect}" end @@units.items.select do |_n, i| i.dimension.to_s == dimension.to_s end.keys.map(&:to_sym) end

## Instance Method Details

### #!=(other) ⇒ Object

Test if the other measure is equal to self

 131 132 133 134 # File 'lib/measure.rb', line 131 def !=(other) return true unless other.is_a?(Measure) to_r != other.to_r(unit) end

### #*(numeric_or_measure) ⇒ Object

 216 217 218 219 220 221 222 223 224 225 226 # File 'lib/measure.rb', line 216 def *(numeric_or_measure) if numeric_or_measure.is_a? Numeric self.class.new(@value * numeric_or_measure.to_r, unit) elsif numeric_or_measure.is_a? Measure # Find matching dimension # Convert raise NotImplementedError else raise ArgumentError, 'Only numerics and measures can be multiplicated to a measure' end end

### #+(other) ⇒ Object

Returns the dimension of a other

 192 193 194 195 196 197 # File 'lib/measure.rb', line 192 def +(other) unless other.is_a?(Measure) raise ArgumentError, 'Only measure can be added to another measure' end self.class.new(@value + other.to_r(unit), unit) end

### #[email protected] ⇒ Object

Returns self of its value

 212 213 214 # File 'lib/measure.rb', line 212 def [email protected] self end

### #-(other) ⇒ Object

 199 200 201 202 203 204 # File 'lib/measure.rb', line 199 def -(other) unless other.is_a?(Measure) raise ArgumentError, 'Only measure can be substracted to another measure' end self.class.new(@value - other.to_r(unit), unit) end

### #[email protected] ⇒ Object

Returns opposite of its value

 207 208 209 # File 'lib/measure.rb', line 207 def [email protected] self.class.new(-value, unit) end

### #/(numeric_or_measure) ⇒ Object

 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 # File 'lib/measure.rb', line 228 def /(numeric_or_measure) if numeric_or_measure.is_a? Numeric self.class.new(@value / numeric_or_measure.to_r, unit) elsif numeric_or_measure.is_a? Measure # Find matching dimension # Convert if dimension == numeric_or_measure.dimension to_d / numeric_or_measure.to_d(unit) else raise NotImplementedError end else raise ArgumentError, 'Only numerics and measures can divide to a measure' end end

### #<(other) ⇒ Object

Returns if self is less than other

 143 144 145 146 147 148 # File 'lib/measure.rb', line 143 def <(other) unless other.is_a?(Measure) raise ArgumentError, 'Only measure can be compared to another measure' end to_r < other.to_r(unit) end

### #<=(other) ⇒ Object

Returns if self is less than or equal to other

 159 160 161 162 163 164 # File 'lib/measure.rb', line 159 def <=(other) unless other.is_a?(Measure) raise ArgumentError, 'Only measure can be compared to another measure' end to_r <= other.to_r(unit) end

### #<=>(other) ⇒ Object

Returns if self is greater than other

 175 176 177 178 179 180 # File 'lib/measure.rb', line 175 def <=>(other) unless other.is_a?(Measure) raise ArgumentError, 'Only measure can be compared to another measure' end to_r <=> other.to_r(unit) end

### #==(other) ⇒ Object

Test if the other measure is equal to self

 137 138 139 140 # File 'lib/measure.rb', line 137 def ==(other) return false unless other.is_a?(Measure) to_r == other.to_r(unit) end

### #>(other) ⇒ Object

Returns if self is greater than other

 151 152 153 154 155 156 # File 'lib/measure.rb', line 151 def >(other) unless other.is_a?(Measure) raise ArgumentError, 'Only measure can be compared to another measure' end to_r > other.to_r(unit) end

### #>=(other) ⇒ Object

Returns if self is greater than or equal to other

 167 168 169 170 171 172 # File 'lib/measure.rb', line 167 def >=(other) unless other.is_a?(Measure) raise ArgumentError, 'Only measure can be compared to another measure' end to_r >= other.to_r(unit) end

### #convert(unit) ⇒ ObjectAlso known as: in

Returns a new measure in the given unit

 94 95 96 # File 'lib/measure.rb', line 94 def convert(unit) Measure.new(to_r(unit), unit) end

### #convert!(unit) ⇒ ObjectAlso known as: in!

Converts measure inline without instanciating a new Measure

 100 101 102 103 104 # File 'lib/measure.rb', line 100 def convert!(unit) @value = to_r(unit) @unit = unit.to_s self end

### #dimension ⇒ Object

Returns the dimension of a measure

 126 127 128 # File 'lib/measure.rb', line 126 def dimension self.class.dimension(unit) end

### #hash ⇒ Object

 89 90 91 # File 'lib/measure.rb', line 89 def hash [@value, @unit].hash end

### #inspect ⇒ Object

 117 118 119 # File 'lib/measure.rb', line 117 def inspect "#{@value.to_f} #{@unit}" end

### #localize(options = {}) ⇒ ObjectAlso known as: l

Localize a measure FIXME: Measure l10n must be configurable in translation files.

 277 278 279 # File 'lib/measure.rb', line 277 def localize(options = {}) "#{value.to_f.localize(options)} #{@@units.items[unit].symbol}" end

### #nomenclature_unit ⇒ Object

Returns the unit from the nomenclature

 283 284 285 # File 'lib/measure.rb', line 283 def nomenclature_unit @@units[unit] end

### #nonzero? ⇒ Boolean

Returns:

• (Boolean)
 187 188 189 # File 'lib/measure.rb', line 187 def nonzero? zero? ? nil : self end

### #round(ndigits = 0) ⇒ Object

 113 114 115 # File 'lib/measure.rb', line 113 def round(ndigits = 0) Measure.new(to_d.round(ndigits), unit) end

### #to_d(unit = nil, precision = 16) ⇒ Object

Return BigDecimal value

 271 272 273 # File 'lib/measure.rb', line 271 def to_d(unit = nil, precision = 16) to_r(unit, precision).to_d(precision) end

### #to_f(unit = nil, precision = 16) ⇒ Object

Return Float value

 266 267 268 # File 'lib/measure.rb', line 266 def to_f(unit = nil, precision = 16) to_r(unit, precision).to_f end

### #to_r(other_unit = nil, precision = 16) ⇒ Object

 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 # File 'lib/measure.rb', line 244 def to_r(other_unit = nil, precision = 16) if other_unit.nil? value else other_unit = other_unit.name if other_unit.is_a?(Nomen::Item) unless @@units[other_unit] raise ArgumentError, "Unknown unit: #{other_unit.inspect}" end if @@units[unit.to_s].dimension != @@units[other_unit.to_s].dimension raise IncompatibleDimensions, "Measure can't be converted from one dimension (#{@@units[unit].dimension}) to an other (#{@@units[other_unit].dimension})" end return value if unit.to_s == other_unit.to_s # Reduce to base ref = @@units[unit] reduced = ((ref.a * value.to_d(precision)) / ref.d) + ref.b # Coeff to dest ref = @@units[other_unit] (ref.d * ((reduced - ref.b) / ref.a)).to_r end end

### #to_s ⇒ Object

 121 122 123 # File 'lib/measure.rb', line 121 def to_s inspect end

### #zero? ⇒ Boolean

Test if measure is null

Returns:

• (Boolean)
 183 184 185 # File 'lib/measure.rb', line 183 def zero? @value.zero? end