Class: Units::Measure

Inherits:
Object
  • Object
show all
Includes:
ModalSupport::BracketConstructor, ModalSupport::StateEquivalent
Defined in:
lib/units/measure.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Measure

Returns a new instance of Measure.



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

def initialize(*args)
  if args.size==0
    mag = 1.0
    units = {}
  elsif args.size==1
    case args.first
    when Numeric
      mag = args.first
      units = {}
    else
      mag = 1.0
      units = args.first
    end
  elsif args.size==2
    mag, units = args
  else
    raise ArgumentError, "wrong number of arguments (#{args.size} for 0, 1 or 2)"
  end

  @magnitude = mag # rename to value?
  case units
  when Symbol
    uinfo = Units.unit(units)
    if uinfo
      if uinfo.dim
        @units = {uinfo.dim=>[units,1]}
      else
        @magnitude *= uinfo.factor
        @units = {}
      end
    else
      raise ArgumentError,"Invalid symbol for Measure definition: #{units.inspect} "
    end
  when Measure
    @magnitude *= units.magnitude
    @units = units.units
  else
    @units = units
  end
end

Instance Attribute Details

#magnitudeObject (readonly)

Returns the value of attribute magnitude.



51
52
53
# File 'lib/units/measure.rb', line 51

def magnitude
  @magnitude
end

#unitsObject (readonly)

Returns the value of attribute units.



51
52
53
# File 'lib/units/measure.rb', line 51

def units
  @units
end

Class Method Details

.combine(units, dim, unit, mult) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/units/measure.rb', line 115

def self.combine(units, dim, unit, mult)
  factor = 1
  if units[dim]
    u,m = units[dim]
    if u!=unit
      factor *= Units.conversion_factor(unit, u)**mult
    end
    units[dim] = [u, m+mult]
  else
    units[dim] = [unit, mult]
  end
  factor
end

Instance Method Details

#*(other) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/units/measure.rb', line 138

def *(other)
  other = Units.units(other) if other.kind_of?(String)
  case other
  when Numeric
    mag = self.magnitude*other
    units = self.units
  else
    mag = self.magnitude*other.magnitude
    units = {}
    (self.units.keys | other.units.keys).each do |dim|
      other_u = other.units[dim] || [nil,0]
      this_u = self.units[dim] || [other_u.first,0]
      # mag *= Units.conversion_factor(this_u.first, other_u.first) if other_u.first
      mult = this_u.last+other_u.last
      mag *= Units.conversion_factor(other_u.first, this_u.first)**(other_u.last) if other_u.first
      units[dim] = [this_u.first, mult]
    end
  end
  units.reject!{|dim,(u,m)| m==0}
  Measure.new(mag, units)
end

#**(n) ⇒ Object

Raises:

  • (ArgumentError)


170
171
172
173
174
175
176
177
# File 'lib/units/measure.rb', line 170

def **(n)
  raise ArgumentError,"Only integer powers are allowed for magnitudes" unless n.kind_of?(Integer)
  units = @units.dup
  units.each_pair do |dim, (u, m)|
    units[dim] = [u, m*n]
  end
  Measure.new @magnitude, units
end

#+(other) ⇒ Object



160
161
162
163
# File 'lib/units/measure.rb', line 160

def +(other)
  other = Units.units(other) if other.kind_of?(String)
  Measure.new self.magnitude+other.to(self.units).magnitude, self.units
end

#-(other) ⇒ Object



165
166
167
168
# File 'lib/units/measure.rb', line 165

def -(other)
  other = Units.units(other) if other.kind_of?(String)
  self + (-other)
end

#-@Object



188
189
190
# File 'lib/units/measure.rb', line 188

def -@
  Measure.new(-@magnitude, units)
end

#/(other) ⇒ Object



129
130
131
132
# File 'lib/units/measure.rb', line 129

def /(other)
  other = Units.units(other) if other.kind_of?(String)
  self * (other.kind_of?(Numeric) ? 1.0/other : other.inverse)
end

#abrObject

more natural concise text representation If a block is passed, it is used to format the numeric magnitudes (Float numbers) (e.g., for localization)

Units.units{3*m/(2*s)}.abr{|v| v.to_s.tr('.',',') } # => "1,5 m/s"


70
71
72
73
74
75
76
77
78
79
# File 'lib/units/measure.rb', line 70

def abr
  txt = self.to_s.gsub('**','^').tr('*',' ')
  if block_given?
    txt.gsub!(/[+-]?((\d+_?)*\d+(\.(\d+_?)*\d+)?|\.(\d+_?)*\d+)([eE][+-]?(\d+_?)*\d+)?/) do
      v = $&.to_f
      yield v
    end
  end
  txt
end

#baseObject

decompose to base units



111
112
113
# File 'lib/units/measure.rb', line 111

def base
  detailed_units true
end

#coerce(other) ⇒ Object



240
241
242
243
# File 'lib/units/measure.rb', line 240

def coerce(other)
  # other = Units.units(other) if other.kind_of?(String)
  [Measure[other], self]
end

#describeObject

more verbose description (not grammatically perfect)



61
62
63
64
65
# File 'lib/units/measure.rb', line 61

def describe
  return @magnitude.to_s if magnitude?
  u_descr = Units.units_descr(@units, true)
  "#{@magnitude} #{u_descr}"
end

#detailed_units(all_levels = false) ⇒ Object

decompose compound units



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/units/measure.rb', line 82

def detailed_units(all_levels = false)
  mag = @magnitude
  prev_units = self.units
  units = {}
  loop do
    compound = false
    prev_units.each_pair do |dim, (unit,mul)|
      ud = Units.unit(unit)
      if ud.decomposition
        compound = true
        mag *= ud.decomposition.magnitude
        ud.decomposition.units.each_pair do |d, (u,m)|
          mag *= self.class.combine(units, d, u, m*mul)
        end
      else
        mag *= self.class.combine(units, dim, unit, mul)
      end
    end
    if all_levels && compound
      prev_units = units
      units = {}
    else
      break
    end
  end
  Measure.new mag, units
end

#dimensionObject

dimension (quantity)



250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/units/measure.rb', line 250

def dimension
  q = nil
  u = self.base.si_units
  SI_UNITS.each_pair do |dim, unit|
    unit = Measure.new(1.0, unit) unless unit.kind_of?(Measure)
    if unit.base.si_units == u
      q = dim
      break
    end
  end
  q
end

#dimensionless?Boolean

Returns:

  • (Boolean)


263
264
265
# File 'lib/units/measure.rb', line 263

def dimensionless?
  base.units.reject{|d,(u,m)| m==0}.empty?
end

#in(other, mode = :absolute) ⇒ Object



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/units/measure.rb', line 192

def in(other, mode=:absolute)
  other = Units.units(other) if other.kind_of?(String)
  other = Measure.new(1.0, other) unless other.kind_of?(Measure)
  other = other.base
  this = self.base
  dims = this.units.keys | other.units.keys
  mag = this.magnitude/other.magnitude
  dims.each do |dim|
    if !this.units[dim] || !other.units[dim] ||
       (this.units[dim].last != other.units[dim].last)
      raise "Inconsistent units #{Units.units_descr(this.units)} #{Units.units_descr(other.units)}"
    end
    this_u, mult = this.units[dim]
    other_u = other.units[dim].first
    mag *= Units.conversion_factor(this_u, other_u)**mult
  end
  if mode!=:relative && dims.size==1 && this.units[dims.first].last==1
    # consider "level" conversion for biased units (otherwise consider interval or difference values)
    mag += Units.conversion_bias(this.units[dims.first].first, other.units[dims.first].first)
  end
  mag
end

#inspectObject



134
135
136
# File 'lib/units/measure.rb', line 134

def inspect
  "Units::Measure[#{@magnitude.inspect}, #{@units.inspect}]"
end

#inverseObject



179
180
181
182
183
184
185
186
# File 'lib/units/measure.rb', line 179

def inverse
  #Measure.new(1.0/@magnitude, @units.map_hash{|unit,mult| [unit, -mult]})
  units = {}
  @units.each_pair do |dim, (unit, mult)|
    units[dim] = [unit, -mult]
  end
  Measure.new(1.0/@magnitude, units)
end

#magnitude?Boolean

less strict dimensionless condition (e.g. an angle is not a pure magnitude in this sense)

Returns:

  • (Boolean)


268
269
270
# File 'lib/units/measure.rb', line 268

def magnitude?
  self.units.reject{|d,(u,m)| m==0}.empty?
end

#si_unitsObject



221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/units/measure.rb', line 221

def si_units
  units = {}
  @units.each_pair do |dim, (unit, mult)|
    si_unit = SI_UNITS[dim]
    if si_unit.kind_of?(Measure)
      si_unit.units.each_pair do |d, (u,m)|
        self.class.combine(units, d, u, m*mult)
      end
    else
      self.class.combine(units, dim, si_unit, mult)
    end
  end
  units
end

#to(units, mode = :absolute) ⇒ Object



215
216
217
218
219
# File 'lib/units/measure.rb', line 215

def to(units, mode=:absolute)
  units = Units.units(units) if units.kind_of?(String)
  units = units.u if units.kind_of?(Measure)
  Measure.new self.in(units, mode), units
end

#to_sObject

represent in text using Ruby notation



54
55
56
57
58
# File 'lib/units/measure.rb', line 54

def to_s
  return @magnitude.to_s if magnitude?
  u_descr = Units.units_descr(@units)
  "#{@magnitude}*#{u_descr}"
end

#to_siObject



236
237
238
# File 'lib/units/measure.rb', line 236

def to_si
  to(si_units)
end

#uObject

dimension? unit? only_units? strip_units? units_measure?



245
246
247
# File 'lib/units/measure.rb', line 245

def u # dimension? unit? only_units? strip_units? units_measure?
  Measure.new(1.0, self.units)
end