Class: Measure
- Inherits:
-
Object
show all
- Defined in:
- lib/measure.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
138
139
140
141
|
# File 'lib/measure.rb', line 138
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
329
330
331
332
333
334
335
|
# File 'lib/measure.rb', line 329
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.
143
144
145
|
# File 'lib/measure.rb', line 143
def unit
@unit
end
|
#value ⇒ Object
Returns the value of attribute value.
143
144
145
|
# File 'lib/measure.rb', line 143
def value
@value
end
|
Class Method Details
.clear_units ⇒ Object
39
40
41
42
43
44
45
|
# File 'lib/measure.rb', line 39
def clear_units
@@units.clear
@@dimension_map.clear
@@conversion_map.clear
@@alias_map.clear
return nil
end
|
.compatible?(u1, u2) ⇒ Boolean
28
29
30
31
32
33
34
35
36
37
|
# File 'lib/measure.rb', line 28
def compatible?(u1, u2)
u1 = resolve_alias u1
raise InvalidUnitError, "unknown unit: #{u1}" unless self.defined? u1
u2 = resolve_alias u2
raise InvalidUnitError, "unknown unit: #{u2}" unless self.defined? u2
return true if u1 == u2
return true if @@conversion_map.has_key? u1 and @@conversion_map[u1].has_key? u2
return true if @@conversion_map.has_key? u2 and @@conversion_map[u2].has_key? u1
return false
end
|
.conversion_map ⇒ Object
18
19
20
|
# File 'lib/measure.rb', line 18
def conversion_map
@@conversion_map
end
|
.define_alias(unit, base) ⇒ Object
67
68
69
70
71
72
73
|
# File 'lib/measure.rb', line 67
def define_alias(unit, base)
if self.defined?(unit)
raise UnitRedefinitionError, "unit [#{unit}] is already defined"
end
raise InvalidUnitError, "unknown unit: #{base}" unless self.defined? base
@@alias_map[unit] = base
end
|
.define_conversion(base, conversion) ⇒ Object
75
76
77
78
79
80
81
82
83
84
85
|
# File 'lib/measure.rb', line 75
def define_conversion(base, conversion)
base = resolve_alias base
raise InvalidUnitError, "unknown unit: #{base}" unless self.defined? base
@@conversion_map[base] ||= {}
conversion.each {|unit, factor|
unit = resolve_alias unit
raise InvalidUnitError, "unknown unit: #{unit}" unless self.defined? unit
@@conversion_map[base][unit] = factor
}
return nil
end
|
.define_unit(unit, dimension = 1) ⇒ Object
56
57
58
59
60
61
62
63
64
65
|
# File 'lib/measure.rb', line 56
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
end
end
|
.dimension(unit) ⇒ Object
Also known as:
dim
87
88
89
|
# File 'lib/measure.rb', line 87
def dimension(unit)
return @@dimension_map[resolve_alias unit]
end
|
.find_multi_hop_conversion(u1, u2) ⇒ Object
99
100
101
102
103
104
105
106
107
108
109
110
|
# File 'lib/measure.rb', line 99
def find_multi_hop_conversion(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
Also known as:
defined?
22
23
24
25
|
# File 'lib/measure.rb', line 22
def has_unit?(unit)
unit = resolve_alias unit
return @@units.include? unit
end
|
.num_units ⇒ Object
52
53
54
|
# File 'lib/measure.rb', line 52
def num_units
return @@units.length
end
|
.resolve_alias(unit) ⇒ Object
92
93
94
95
96
97
|
# File 'lib/measure.rb', line 92
def resolve_alias(unit)
while @@alias_map.has_key? unit
unit = @@alias_map[unit]
end
return unit
end
|
.units(dimension = nil) ⇒ Object
47
48
49
50
|
# File 'lib/measure.rb', line 47
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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
|
# File 'lib/measure.rb', line 226
def *(other)
case other
when Measure
return other * self.value if self.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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
# File 'lib/measure.rb', line 186
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
|
# File 'lib/measure.rb', line 206
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
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
|
# File 'lib/measure.rb', line 248
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
# File 'lib/measure.rb', line 145
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
175
176
177
178
179
180
181
182
183
184
|
# File 'lib/measure.rb', line 175
def ==(other)
return self.value == other.value if self.unit == other.unit
if Measure.compatible? self.unit, other.unit
return self == other.convert(self.unit)
elsif Measure.compatible? other.unit, self.unit
return self.convert(other.unit) == other
else
return false
end
end
|
#>(other) ⇒ Object
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
# File 'lib/measure.rb', line 160
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
276
277
278
|
# File 'lib/measure.rb', line 276
def abs
return Measure(self.value.abs, self.unit)
end
|
#coerce(other) ⇒ Object
267
268
269
270
271
272
273
274
|
# File 'lib/measure.rb', line 267
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
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
|
# File 'lib/measure.rb', line 296
def convert(unit)
return self if unit == self.unit
to_unit = Measure.resolve_alias unit
raise InvalidUnitError, "unknown unit: #{unit}" unless Measure.defined? unit
from_unit = Measure.resolve_alias self.unit
if Measure.compatible? from_unit, to_unit
if @@conversion_map.has_key? from_unit and @@conversion_map[from_unit].has_key? to_unit
value = self.value * @@conversion_map[from_unit][to_unit]
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
value *= @@conversion_map[u1][u2]
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
326
|
# File 'lib/measure.rb', line 326
alias saved_method_missing method_missing
|
#to_a ⇒ Object
292
293
294
|
# File 'lib/measure.rb', line 292
def to_a
return [self.value, self.unit]
end
|
#to_f ⇒ Object
288
289
290
|
# File 'lib/measure.rb', line 288
def to_f
return self.value.to_f
end
|
#to_i ⇒ Object
284
285
286
|
# File 'lib/measure.rb', line 284
def to_i
return self.value.to_i
end
|
#to_s ⇒ Object
280
281
282
|
# File 'lib/measure.rb', line 280
def to_s
return "#{self.value} [#{self.unit}]"
end
|