Class: Unit

Inherits:
Numeric show all
Defined in:
lib/unit/dsl.rb,
lib/unit/class.rb,
lib/unit/system.rb,
lib/unit/version.rb

Defined Under Namespace

Classes: IncompatibleUnitError, System

Constant Summary collapse

VERSION =
'0.5.0'

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(value, unit, system) ⇒ Unit

Returns a new instance of Unit.



7
8
9
10
11
12
13
# File 'lib/unit/class.rb', line 7

def initialize(value, unit, system)
  @system = system
  @value = value
  @unit = unit.dup
  @normalized = nil
  reduce!
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, system = nil) ⇒ Object



18
19
20
21
22
23
24
25
# File 'lib/unit/dsl.rb', line 18

def method_missing(name, system = nil)
  if name.to_s =~ /^in_(.*?)(!?)$/
    unit = Unit.method_name_to_unit($1)
    $2.empty? ? self.in(unit) : self.in!(unit)
  else
    super(name, system || @system)
  end
end

Class Attribute Details

.default_systemObject

Returns the value of attribute default_system.



300
301
302
# File 'lib/unit/class.rb', line 300

def default_system
  @default_system
end

Instance Attribute Details

#normalizedObject (readonly)

Returns the value of attribute normalized.



3
4
5
# File 'lib/unit/class.rb', line 3

def normalized
  @normalized
end

#systemObject (readonly)

Returns the value of attribute system.



3
4
5
# File 'lib/unit/class.rb', line 3

def system
  @system
end

#unitObject (readonly)

Returns the value of attribute unit.



3
4
5
# File 'lib/unit/class.rb', line 3

def unit
  @unit
end

#valueObject (readonly)

Returns the value of attribute value.



3
4
5
# File 'lib/unit/class.rb', line 3

def value
  @value
end

Class Method Details

.method_name_to_unit(name) ⇒ Object



14
15
16
# File 'lib/unit/dsl.rb', line 14

def self.method_name_to_unit(name)
  name.to_s.sub(/^per_/, '1/').gsub('_per_', '/').gsub('_', ' ')
end

.numeric_to_unit(object, system = nil) ⇒ Object



306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/unit/class.rb', line 306

def numeric_to_unit(object, system = nil)
  system ||= Unit.default_system
  case object
  when Unit
    raise IncompatibleUnitError, "Unit system of #{object.inspect} is incompatible with #{system.name}" if object.system != system
    object
  when Numeric
    Unit.new(object, [], system)
  else
    raise TypeError, "#{object.class} can't be coerced into Unit"
  end
end

.power_unit(unit, pow) ⇒ Object



302
303
304
# File 'lib/unit/class.rb', line 302

def power_unit(unit, pow)
  unit.map {|factor, name, exp| [factor, name, exp * pow] }
end

.to_unit(object, system = nil) ⇒ Object



319
320
321
322
323
324
325
326
327
328
329
330
331
332
# File 'lib/unit/class.rb', line 319

def to_unit(object, system = nil)
  system ||= Unit.default_system
  case object
  when String, Symbol
    unit = system.parse_unit(object.to_s)
    system.validate_unit(unit)
    Unit.new(1, unit, system)
  when Array
    system.validate_unit(object)
    Unit.new(1, object, system)
  else
    numeric_to_unit(object, system)
  end
end

Instance Method Details

#*(other) ⇒ Object



48
49
50
51
52
53
54
55
# File 'lib/unit/class.rb', line 48

def *(other)
  if Numeric === other
    other = coerce_numeric(other)
    Unit.new(other.value * self.value, other.unit + self.unit, system)
  else
    apply_through_coercion(other, __method__)
  end
end

#**(exp) ⇒ Object

Raises:

  • (TypeError)


81
82
83
84
# File 'lib/unit/class.rb', line 81

def **(exp)
  raise TypeError if Unit === exp
  Unit.new(value ** exp, Unit.power_unit(unit, exp), system)
end

#+(other) ⇒ Object



71
72
73
74
75
76
77
78
79
# File 'lib/unit/class.rb', line 71

def +(other)
  if Numeric === other
    other = coerce_numeric_compatible(other)
    a, b = self.normalize, other.normalize
    Unit.new(a.value + b.value, b.unit, system).in(self)
  else
    apply_through_coercion(other, __method__)
  end
end

#-(other) ⇒ Object



86
87
88
89
90
91
92
93
94
# File 'lib/unit/class.rb', line 86

def -(other)
  if Numeric === other
    other = coerce_numeric_compatible(other)
    a, b = self.normalize, other.normalize
    Unit.new(a.value - b.value, b.unit, system).in(self)
  else
    apply_through_coercion(other, __method__)
  end
end

#-@Object



96
97
98
# File 'lib/unit/class.rb', line 96

def -@
  Unit.new(-value, unit, system)
end

#/(other) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/unit/class.rb', line 57

def /(other)
  if Numeric === other
    other = coerce_numeric(other)
    result = if Integer === value && Integer === other.value
               other.value == 1 ? value : Rational(value, other.value)
             else
               value / other.value
             end
    Unit.new(result, unit + Unit.power_unit(other.unit, -1), system)
  else
    apply_through_coercion(other, __method__)
  end
end

#<=>(other) ⇒ Object



122
123
124
125
126
127
128
129
130
# File 'lib/unit/class.rb', line 122

def <=>(other)
  if Numeric === other
    other = coerce_numeric_compatible(other)
    a, b = self.normalize, other.normalize
    a.value <=> b.value
  else
    apply_through_coercion(other, __method__)
  end
end

#==(other) ⇒ Object



108
109
110
111
112
113
114
115
116
# File 'lib/unit/class.rb', line 108

def ==(other)
  if Numeric === other
    other = coerce_numeric(other)
    a, b = self.normalize, other.normalize
    a.value == b.value && a.unit == b.unit
  else
    apply_through_coercion(other, __method__)
  end
end

#absObject



100
101
102
# File 'lib/unit/class.rb', line 100

def abs
  Unit.new(value.abs, unit, system)
end

#approxObject



181
182
183
# File 'lib/unit/class.rb', line 181

def approx
  Unit.new(self.to_f, unit, system)
end

#coerce(other) ⇒ Object



189
190
191
# File 'lib/unit/class.rb', line 189

def coerce(other)
  [coerce_numeric(other), self]
end

#compatible?(other) ⇒ Boolean Also known as: compatible_with?

Compatible units can be added

Returns:

  • (Boolean)


140
141
142
# File 'lib/unit/class.rb', line 140

def compatible?(other)
  self.normalize.unit == Unit.to_unit(other, system).normalize.unit
end

#dimensionless?Boolean Also known as: unitless?

Number without dimension

Returns:

  • (Boolean)


133
134
135
# File 'lib/unit/class.rb', line 133

def dimensionless?
  normalize.unit.empty?
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


118
119
120
# File 'lib/unit/class.rb', line 118

def eql?(other)
  Unit === other && value.eql?(other.value) && unit == other.unit
end

#in(unit) ⇒ Object

Convert to other unit



147
148
149
150
# File 'lib/unit/class.rb', line 147

def in(unit)
  conversion = Unit.new(1, Unit.to_unit(unit, system).unit, system)
  (self / conversion).normalize * conversion
end

#in!(unit) ⇒ Object



152
153
154
155
156
157
158
159
# File 'lib/unit/class.rb', line 152

def in!(unit)
  unit = coerce_object(unit)
  result = self.in(unit)
  unless result.unit == unit.unit
    raise TypeError, "Unexpected #{result.inspect}, expected to be in #{unit.unit_string}"
  end
  result
end

#initialize_copy(other) ⇒ Object



15
16
17
18
19
20
# File 'lib/unit/class.rb', line 15

def initialize_copy(other)
  @system = other.system
  @value = other.value
  @unit = other.unit.dup
  @normalized = other.normalized
end

#inspectObject



161
162
163
# File 'lib/unit/class.rb', line 161

def inspect
  unit.empty? ? %{Unit("#{value}")} : %{Unit("#{value_string} #{unit_string('.')}")}
end

#normalizeObject

Converts to base units



23
24
25
# File 'lib/unit/class.rb', line 23

def normalize
  @normalized ||= dup.normalize!
end

#normalize!Object

Converts to base units



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/unit/class.rb', line 28

def normalize!
  if @normalized != self
    begin
      last_unit = @unit
      @unit = []
      last_unit.each do |factor, unit, exp|
        @value *= @system.factor[factor][:value] ** exp if factor != :one
        if Numeric === unit
          @unit << [:one, unit, exp]
        else
          @unit += Unit.power_unit(@system.unit[unit][:def], exp)
        end
      end
    end while last_unit != @unit
    reduce!
    @normalized = self
  end
  self
end

#round(precision = 0) ⇒ Object



185
186
187
# File 'lib/unit/class.rb', line 185

def round(precision = 0)
  Unit.new(value.round(precision), unit, system)
end

#to_fObject



177
178
179
# File 'lib/unit/class.rb', line 177

def to_f
  @value.to_f
end

#to_iObject



173
174
175
# File 'lib/unit/class.rb', line 173

def to_i
  @value.to_i
end

#to_sObject



165
166
167
# File 'lib/unit/class.rb', line 165

def to_s
  unit.empty? ? value.to_s : "#{value_string} #{unit_string}"
end

#to_texObject



169
170
171
# File 'lib/unit/class.rb', line 169

def to_tex
  unit.empty? ? value.to_s : "\SI{#{value}}{#{unit_string('.')}}"
end

#unit_string(sep = '·') ⇒ Object



205
206
207
208
# File 'lib/unit/class.rb', line 205

def unit_string(sep = '·')
  (unit_list(@unit.select {|factor, name, exp| exp >= 0 }) +
   unit_list(@unit.select {|factor, name, exp| exp < 0 })).join(sep)
end

#value_stringObject



193
194
195
196
197
198
199
200
201
202
203
# File 'lib/unit/class.rb', line 193

def value_string
  if Rational === value
    if value.denominator == 1
      value.numerator.to_s
    else
      value.inspect
    end
  else
    value.to_s
  end
end

#zero?Boolean

Returns:

  • (Boolean)


104
105
106
# File 'lib/unit/class.rb', line 104

def zero?
  value.zero?
end