Class: Measure
- Inherits:
-
Object
show all
- Defined in:
- lib/measure.rb,
lib/measure/length.rb,
lib/measure/weight.rb,
lib/measure/version.rb
Overview
- Author
-
Kenta Murata
- Copyright
-
Copyright © 2008 Kenta Murata
- License
-
LGPL version 3.0
Defined Under Namespace
Modules: VERSION
Classes: CompatibilityError, InvalidUnitError, UnitRedefinitionError
Constant Summary
collapse
- @@units =
[]
- @@dimension_map =
{}
- @@conversion_map =
{}
- @@alias_map =
{}
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
Constructor Details
#initialize(value, unit) ⇒ Measure
199
200
201
202
|
# File 'lib/measure.rb', line 199
def initialize(value, unit)
@value, @unit = value, unit
return nil
end
|
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args) ⇒ Object
395
396
397
398
399
400
401
|
# File 'lib/measure.rb', line 395
def method_missing(name, *args)
if /^as_(\w+)/.match(name.to_s)
unit = $1.to_sym
return convert(unit)
end
return saved_method_missing(name, *args)
end
|
Instance Attribute Details
#unit ⇒ Object
Returns the value of attribute unit.
204
205
206
|
# File 'lib/measure.rb', line 204
def unit
@unit
end
|
#value ⇒ Object
Returns the value of attribute value.
204
205
206
|
# File 'lib/measure.rb', line 204
def value
@value
end
|
Class Method Details
.clear_units ⇒ Object
67
68
69
70
71
72
73
|
# File 'lib/measure.rb', line 67
def clear_units
@@units.clear
@@dimension_map.clear
@@conversion_map.clear
@@alias_map.clear
return nil
end
|
.conversion_map ⇒ Object
18
19
20
|
# File 'lib/measure.rb', line 18
def conversion_map
@@conversion_map
end
|
.define_alias(unit, base) ⇒ Object
Also known as:
def_alias
Defines an alias. Measure::UnitRedefinitionError is raised when the alias is redefined. Measure::InvalidUnitError is raised when the base unit is not defined.
114
115
116
117
118
119
|
# File 'lib/measure.rb', line 114
def define_alias(unit, base)
if self.has_unit?(unit)
raise UnitRedefinitionError, "unit [#{unit}] is already defined"
end
@@alias_map[unit] = resolve_alias base
end
|
.define_conversion(origin, conversion) ⇒ Object
Also known as:
def_conversion
127
128
129
130
131
132
133
134
135
|
# File 'lib/measure.rb', line 127
def define_conversion(origin, conversion)
origin = resolve_alias origin
@@conversion_map[origin] ||= {}
conversion.each {|target, conv|
target = resolve_alias target
@@conversion_map[origin][target] = conv
}
return nil
end
|
.define_unit(unit, dimension = 1) ⇒ Object
Also known as:
def_unit
Defines a unit. The default dimension is 1. Measure::UnitRedefinitionError is raised when the unit is redefined.
95
96
97
98
99
100
101
102
103
104
105
|
# File 'lib/measure.rb', line 95
def define_unit(unit, dimension=1)
if @@units.include?(unit)
if self.dimension(unit) != dimension
raise UnitRedefinitionError, "unit [#{unit}] is already defined"
end
else
@@units << unit
@@dimension_map[unit] = dimension
return self
end
end
|
.dimension(unit) ⇒ Object
Also known as:
dim
155
156
157
|
# File 'lib/measure.rb', line 155
def dimension(unit)
return @@dimension_map[resolve_alias(unit)]
end
|
.direct_compatible?(u1, u2) ⇒ Boolean
Test direct compatibility between two units, u1 and u2.
51
52
53
54
55
56
57
58
59
60
61
62
|
# File 'lib/measure.rb', line 51
def direct_compatible?(u1, u2)
u1 = resolve_alias u1
u2 = resolve_alias u2
return true if u1 == u2
if @@conversion_map.has_key? u1 and @@conversion_map[u1].has_key? u2
return true
end
if @@conversion_map.has_key? u2 and @@conversion_map[u2].has_key? u1
return true unless Proc === @@conversion_map[u2][u1]
end
return false
end
|
.find_conversion_route(u1, u2) ⇒ Object
Also known as:
find_multi_hop_conversion
160
161
162
163
164
165
166
167
168
169
170
171
|
# File 'lib/measure.rb', line 160
def find_conversion_route(u1, u2)
visited = []
queue = [[u1]]
while route = queue.shift
next if visited.include? route.last
visited.push route.last
return route if route.last == u2
neighbors(route.last).each{|u|
queue.push(route + [u]) unless visited.include? u }
end
return nil
end
|
.has_unit?(unit) ⇒ Boolean
22
23
24
25
26
27
28
29
|
# File 'lib/measure.rb', line 22
def has_unit?(unit)
begin
unit = resolve_alias unit
return @@units.include?(unit)
rescue InvalidUnitError
return false
end
end
|
.num_units ⇒ Object
The number of defined units.
87
88
89
|
# File 'lib/measure.rb', line 87
def num_units
return @@units.length + @@alias_map.length
end
|
.resolve_alias(unit) ⇒ Object
Resolves an alias and returns the entity. The returned unit is NOT invalid always. InvalidUnitError is raised if a given unit is undefined.
36
37
38
39
40
41
42
43
44
45
46
|
# File 'lib/measure.rb', line 36
def resolve_alias(unit)
return unit if @@units.include? unit
unless @@alias_map.has_key? unit
raise InvalidUnitError, "unit `#{unit}' is undefined"
end
while @@alias_map.has_key? unit
unit = @@alias_map[unit]
end
return unit
end
|
.undefine_unit(unit) ⇒ Object
139
140
141
142
143
144
145
146
147
148
149
150
|
# File 'lib/measure.rb', line 139
def undefine_unit(unit)
if @@units.include? unit
@@conversion_map.delete unit
@@conversion_map.each {|k, v| v.delete unit }
@@units.delete unit
return true
elsif @@alias_map.has_key? unit
@@alias_map.delete unit
return true
end
return false
end
|
.units(dimension = nil) ⇒ Object
Returns defined units. If dimension is specified, returning units are of only the dimension.
79
80
81
82
|
# File 'lib/measure.rb', line 79
def units(dimension=nil)
return @@units.dup if dimension.nil?
@@dimension_map.select {|k, v| v == dimension }.collect{|k, v| k }
end
|
Instance Method Details
#*(other) ⇒ Object
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
|
# File 'lib/measure.rb', line 287
def *(other)
case other
when Measure
return other * self.value if self.unit == 1
return Measure(self.value * other.value, self.unit) if other.unit == 1
raise NotImplementedError, "this feature has not implemented yet"
when Numeric
return Measure(self.value * other, self.unit)
else
check_coercable other
a, b = other.coerce self
return a * b
end
end
|
#+(other) ⇒ Object
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
|
# File 'lib/measure.rb', line 247
def +(other)
case other
when Measure
if self.unit == other.unit
return Measure(self.value + other.value, self.unit)
elsif Measure.dim(self.unit) == Measure.dim(other.unit)
return Measure(self.value + other.convert(self.unit).value, self.unit)
else
raise TypeError, "incompatible dimensions: " +
"#{Measure.dim(self.unit)} and #{Measure.dim(other.unit)}"
end
when Numeric
return Measure(self.value + other, self.unit)
else
check_coercable other
a, b = other.coerce self
return a + b
end
end
|
#-(other) ⇒ Object
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
|
# File 'lib/measure.rb', line 267
def -(other)
case other
when Measure
if self.unit == other.unit
return Measure(self.value - other.value, self.unit)
elsif Measure.dim(self.unit) == Measure.dim(other.unit)
return Measure(self.value - other.convert(self.unit).value, self.unit)
else
raise TypeError, "incompatible dimensions: " +
"#{Measure.dim(self.unit)} and #{Measure.dim(other.unit)}"
end
when Numeric
return Measure(self.value - other, self.unit)
else
check_coerecable other
a, b = other.coerce self
return a - b
end
end
|
#/(other) ⇒ Object
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
|
# File 'lib/measure.rb', line 310
def /(other)
case other
when Measure
raise NotImplementedError, "this feature has not implemented yet"
when Numeric
return Measure(self.value / other, self.unit)
else
check_coercable other
a, b = other.coerce self
return a / b
end
end
|
#<(other) ⇒ Object
206
207
208
209
210
211
212
213
214
215
216
217
218
219
|
# File 'lib/measure.rb', line 206
def <(other)
case other
when Measure
if self.unit == other.unit
return self.value < other.value
else
return self < other.convert(self.value)
end
when Numeric
return self.value < other
else
raise ArgumentError, 'unable to compare with #{other.inspect}'
end
end
|
#==(other) ⇒ Object
236
237
238
239
240
241
242
243
244
245
|
# File 'lib/measure.rb', line 236
def ==(other)
return self.value == other.value if self.unit == other.unit
if Measure.direct_compatible? self.unit, other.unit
return self == other.convert(self.unit)
elsif Measure.direct_compatible? other.unit, self.unit
return self.convert(other.unit) == other
else
return false
end
end
|
#>(other) ⇒ Object
221
222
223
224
225
226
227
228
229
230
231
232
233
234
|
# File 'lib/measure.rb', line 221
def >(other)
case other
when Measure
if self.unit == other.unit
return self.value > other.value
else
return self > other.convert(self.value)
end
when Numeric
return self.value > other
else
raise ArgumentError, 'unable to compare with #{other.inspect}'
end
end
|
#abs ⇒ Object
338
339
340
|
# File 'lib/measure.rb', line 338
def abs
return Measure(self.value.abs, self.unit)
end
|
#coerce(other) ⇒ Object
329
330
331
332
333
334
335
336
|
# File 'lib/measure.rb', line 329
def coerce(other)
case other
when Numeric
return [Measure(other, 1), self]
else
raise TypeError, "#{other.class} can't convert into #{self.class}"
end
end
|
#convert(unit) ⇒ Object
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
|
# File 'lib/measure.rb', line 350
def convert(unit)
return self if unit == self.unit
to_unit = Measure.resolve_alias unit
raise InvalidUnitError, "unknown unit: #{unit}" unless Measure.has_unit? unit
from_unit = Measure.resolve_alias self.unit
if Measure.direct_compatible? from_unit, to_unit
if @@conversion_map.has_key? from_unit and @@conversion_map[from_unit].has_key? to_unit
conv = @@conversion_map[from_unit][to_unit]
case conv
when Proc
value = conv[self.value]
else
value = self.value * conv
end
else
value = self.value / @@conversion_map[to_unit][from_unit].to_f
end
elsif route = Measure.find_multi_hop_conversion(from_unit, to_unit)
u1 = route.shift
value = self.value
while u2 = route.shift
if @@conversion_map.has_key? u1 and @@conversion_map[u1].has_key? u2
conv = @@conversion_map[u1][u2]
case conv
when Proc
value = conv[vaule]
else
value *= conv
end
else
value /= @@conversion_map[u2][u1].to_f
end
u1 = u2
end
else
raise CompatibilityError, "units not compatible: #{self.unit} and #{unit}"
end
return Measure.new(value, unit)
end
|
#saved_method_missing ⇒ Object
392
|
# File 'lib/measure.rb', line 392
alias saved_method_missing method_missing
|
#to_a ⇒ Object
346
347
348
|
# File 'lib/measure.rb', line 346
def to_a
return [self.value, self.unit]
end
|
#to_s ⇒ Object
342
343
344
|
# File 'lib/measure.rb', line 342
def to_s
return "#{self.value} [#{self.unit}]"
end
|