eymiha_units 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. data/gem_package.rb +4 -4
  2. data/html/classes/Eymiha/AmbiguousUnitsException.html +119 -0
  3. data/html/classes/Eymiha/MissingUnitsException.html +119 -0
  4. data/html/classes/Eymiha/NumericWithUnits.html +867 -0
  5. data/html/classes/Eymiha/NumericWithUnits.src/M000021.html +18 -0
  6. data/html/classes/Eymiha/NumericWithUnits.src/M000022.html +18 -0
  7. data/html/classes/Eymiha/NumericWithUnits.src/M000023.html +18 -0
  8. data/html/classes/Eymiha/NumericWithUnits.src/M000024.html +30 -0
  9. data/html/classes/Eymiha/NumericWithUnits.src/M000025.html +30 -0
  10. data/html/classes/Eymiha/NumericWithUnits.src/M000027.html +18 -0
  11. data/html/classes/Eymiha/NumericWithUnits.src/M000028.html +20 -0
  12. data/html/classes/Eymiha/NumericWithUnits.src/M000029.html +32 -0
  13. data/html/classes/Eymiha/NumericWithUnits.src/M000030.html +18 -0
  14. data/html/classes/Eymiha/NumericWithUnits.src/M000031.html +30 -0
  15. data/html/classes/Eymiha/NumericWithUnits.src/M000032.html +30 -0
  16. data/html/classes/Eymiha/NumericWithUnits.src/M000033.html +22 -0
  17. data/html/classes/Eymiha/NumericWithUnits.src/M000034.html +22 -0
  18. data/html/classes/Eymiha/NumericWithUnits.src/M000035.html +32 -0
  19. data/html/classes/Eymiha/NumericWithUnits.src/M000036.html +32 -0
  20. data/html/classes/Eymiha/NumericWithUnits.src/M000037.html +18 -0
  21. data/html/classes/Eymiha/NumericWithUnits.src/M000038.html +18 -0
  22. data/html/classes/Eymiha/NumericWithUnits.src/M000039.html +24 -0
  23. data/html/classes/Eymiha/NumericWithUnits.src/M000040.html +26 -0
  24. data/html/classes/Eymiha/NumericWithUnits.src/M000041.html +18 -0
  25. data/html/classes/Eymiha/NumericWithUnits.src/M000042.html +18 -0
  26. data/html/classes/Eymiha/NumericWithUnits.src/M000043.html +18 -0
  27. data/html/classes/Eymiha/NumericWithUnits.src/M000044.html +20 -0
  28. data/html/classes/Eymiha/NumericWithUnits.src/M000045.html +18 -0
  29. data/html/classes/Eymiha/NumericWithUnits.src/M000046.html +25 -0
  30. data/html/classes/Eymiha/NumericWithUnits.src/M000047.html +18 -0
  31. data/html/classes/Eymiha/NumericWithUnits.src/M000048.html +19 -0
  32. data/html/classes/Eymiha/Units.html +378 -0
  33. data/html/classes/Eymiha/Units.src/M000052.html +18 -0
  34. data/html/classes/Eymiha/Units.src/M000053.html +18 -0
  35. data/html/classes/Eymiha/Units.src/M000054.html +20 -0
  36. data/html/classes/Eymiha/Units.src/M000055.html +30 -0
  37. data/html/classes/Eymiha/Units.src/M000056.html +33 -0
  38. data/html/classes/Eymiha/Units.src/M000057.html +18 -0
  39. data/html/classes/Eymiha/Units.src/M000058.html +21 -0
  40. data/html/classes/Eymiha/Units.src/M000059.html +18 -0
  41. data/html/classes/Eymiha/Units.src/M000060.html +18 -0
  42. data/html/classes/Eymiha/Units.src/M000061.html +18 -0
  43. data/html/classes/Eymiha/Units.src/M000062.html +18 -0
  44. data/html/classes/Eymiha/Units.src/M000063.html +18 -0
  45. data/html/classes/Eymiha/Units.src/M000064.html +28 -0
  46. data/html/classes/Eymiha/UnitsException.html +119 -0
  47. data/html/classes/Eymiha/UnitsHash.html +351 -0
  48. data/html/classes/Eymiha/UnitsHash.src/M000002.html +18 -0
  49. data/html/classes/Eymiha/UnitsHash.src/M000003.html +26 -0
  50. data/html/classes/Eymiha/UnitsHash.src/M000004.html +25 -0
  51. data/html/classes/Eymiha/UnitsHash.src/M000005.html +18 -0
  52. data/html/classes/Eymiha/UnitsHash.src/M000006.html +18 -0
  53. data/html/classes/Eymiha/UnitsHash.src/M000007.html +18 -0
  54. data/html/classes/Eymiha/UnitsHash.src/M000008.html +22 -0
  55. data/html/classes/Eymiha/UnitsHash.src/M000010.html +21 -0
  56. data/html/classes/Eymiha/UnitsHash.src/M000011.html +19 -0
  57. data/html/classes/Eymiha/UnitsHash.src/M000012.html +27 -0
  58. data/html/classes/Eymiha/UnitsHash.src/M000013.html +18 -0
  59. data/html/classes/Eymiha/UnitsMeasure.html +302 -0
  60. data/html/classes/Eymiha/UnitsMeasure.src/M000014.html +23 -0
  61. data/html/classes/Eymiha/UnitsMeasure.src/M000015.html +18 -0
  62. data/html/classes/Eymiha/UnitsMeasure.src/M000016.html +18 -0
  63. data/html/classes/Eymiha/UnitsMeasure.src/M000017.html +18 -0
  64. data/html/classes/Eymiha/UnitsMeasure.src/M000018.html +18 -0
  65. data/html/classes/Eymiha/UnitsMeasure.src/M000019.html +18 -0
  66. data/html/classes/Eymiha/UnitsMeasure.src/M000020.html +18 -0
  67. data/html/classes/Eymiha/UnitsSystem.html +196 -0
  68. data/html/classes/Eymiha/UnitsSystem.src/M000050.html +31 -0
  69. data/html/classes/Eymiha/UnitsSystem.src/M000051.html +18 -0
  70. data/html/classes/Eymiha/UnitsUnit.html +166 -0
  71. data/html/classes/Eymiha/UnitsUnit.src/M000049.html +18 -0
  72. data/html/classes/Eymiha.html +143 -0
  73. data/html/classes/Numeric.html +182 -0
  74. data/html/classes/Numeric.src/M000001.html +50 -0
  75. data/html/created.rid +1 -0
  76. data/html/files/lib/eymiha/units/definitions/area_rb.html +101 -0
  77. data/html/files/lib/eymiha/units/definitions/length_rb.html +101 -0
  78. data/html/files/lib/eymiha/units/definitions/mass_rb.html +101 -0
  79. data/html/files/lib/eymiha/units/definitions/measures_rb.html +113 -0
  80. data/html/files/lib/eymiha/units/definitions/time_rb.html +101 -0
  81. data/html/files/lib/eymiha/units/definitions/velocity_rb.html +101 -0
  82. data/html/files/lib/eymiha/units/definitions/volume_rb.html +101 -0
  83. data/html/files/lib/eymiha/units/numeric_rb.html +116 -0
  84. data/html/files/lib/eymiha/units/numeric_with_units_rb.html +109 -0
  85. data/html/files/lib/eymiha/units/object_rb.html +108 -0
  86. data/html/files/lib/eymiha/units/units_exception_rb.html +101 -0
  87. data/html/files/lib/eymiha/units/units_hash_rb.html +108 -0
  88. data/html/files/lib/eymiha/units/units_measure_rb.html +109 -0
  89. data/html/files/lib/eymiha/units/units_rb.html +115 -0
  90. data/html/files/lib/eymiha/units/units_system_rb.html +109 -0
  91. data/html/files/lib/eymiha/units/units_unit_rb.html +109 -0
  92. data/html/files/lib/eymiha/units_rb.html +115 -0
  93. data/html/fr_class_index.html +37 -0
  94. data/html/fr_file_index.html +43 -0
  95. data/html/fr_method_index.html +90 -0
  96. data/html/index.html +24 -0
  97. data/html/rdoc-style.css +208 -0
  98. data/lib/{units → eymiha/units}/definitions/area.rb +0 -0
  99. data/lib/{units → eymiha/units}/definitions/length.rb +0 -0
  100. data/lib/{units → eymiha/units}/definitions/mass.rb +0 -0
  101. data/lib/eymiha/units/definitions/measures.rb +6 -0
  102. data/lib/{units → eymiha/units}/definitions/time.rb +0 -0
  103. data/lib/{units → eymiha/units}/definitions/velocity.rb +0 -0
  104. data/lib/{units → eymiha/units}/definitions/volume.rb +0 -0
  105. data/lib/{units → eymiha/units}/numeric.rb +4 -3
  106. data/lib/eymiha/units/numeric_with_units.rb +640 -0
  107. data/lib/{units → eymiha/units}/object.rb +1 -1
  108. data/lib/eymiha/units/units.rb +234 -0
  109. data/lib/eymiha/units/units_exception.rb +18 -0
  110. data/lib/eymiha/units/units_hash.rb +118 -0
  111. data/lib/eymiha/units/units_measure.rb +95 -0
  112. data/lib/eymiha/units/units_system.rb +89 -0
  113. data/lib/eymiha/units/units_unit.rb +63 -0
  114. data/lib/eymiha/units.rb +4 -0
  115. data/test/tc_definitions.rb +1 -1
  116. data/test/tc_formatting.rb +2 -2
  117. data/test/tc_formatting_derived.rb +2 -2
  118. data/test/tc_measure_create.rb +2 -2
  119. data/test/tc_measure_derive.rb +2 -2
  120. data/test/tc_system_create.rb +2 -2
  121. data/test/tc_unit_ambiguity.rb +2 -2
  122. data/test/tc_unit_arithmetic.rb +2 -2
  123. data/test/tc_unit_create.rb +2 -2
  124. data/test/tc_unit_derive.rb +2 -2
  125. data/test/tc_unit_equality.rb +2 -2
  126. data/test/tc_unit_forward_reference.rb +2 -2
  127. data/test/tc_unit_greek.rb +2 -2
  128. data/test/tc_unit_hash.rb +2 -2
  129. data/test/tc_unit_identifiers.rb +2 -2
  130. data/test/tc_unit_rank.rb +2 -2
  131. data/test/tc_uses_1.rb +2 -2
  132. data/test/tc_uses_2.rb +2 -2
  133. metadata +190 -86
  134. data/lib/units/definitions/measures.rb +0 -6
  135. data/lib/units/numeric_with_units.rb +0 -635
  136. data/lib/units/units.rb +0 -229
  137. data/lib/units/units_exception.rb +0 -14
  138. data/lib/units/units_hash.rb +0 -112
  139. data/lib/units/units_measure.rb +0 -91
  140. data/lib/units/units_system.rb +0 -85
  141. data/lib/units/units_unit.rb +0 -60
  142. data/lib/units.rb +0 -4
@@ -1,635 +0,0 @@
1
- require 'units/units'
2
- require 'set'
3
-
4
- # A NumericWithUnits is the intersection of a Numeric and a UnitsHash.
5
- #
6
- # Unit-sensitive coding is made much easier using an object that transparently
7
- # adds units to a common everyday Numerics. Everything that can be done to a
8
- # Numeric is still there, but explicit and implicit unit conversions are present
9
- # in all of the operations.
10
- #
11
- # With this, numbers with units can be created easily. For example,
12
- #
13
- # 2.feet # a length of 2 feet
14
- # 5.inches^2 # an area of 5 square inches
15
- # 44.5.ft/sec # a velocity of 44.5 feet per second
16
- #
17
- # This should provide a good starting point for using the Units framework. Also
18
- # pay attention to the examples given in the method documentation; some of the
19
- # dynamic features of the framework are exposed in them.
20
- class NumericWithUnits
21
-
22
- include Comparable
23
-
24
- @@debug = false
25
-
26
- def self.debug=(value)
27
- @@debug = value
28
- end
29
-
30
- # A Numeric containing the numeric part of the instance
31
- attr_accessor :numeric
32
- # A UnitsHash containing the units part of the instance
33
- attr_accessor :unit
34
- attr_accessor :original # :nodoc:
35
-
36
- # Returns a new NumericWithUnits instance whose numeric part is set to
37
- # numeric and whose units part is set to a units hash for the unit raised
38
- # to the provided power.
39
- def initialize(numeric,unit,power=1)
40
- @numeric, @unit = numeric, units_hash(unit)**power
41
- end
42
-
43
- def units_hash(unit) # :nodoc:
44
- (unit.kind_of? UnitsHash) ? unit : UnitsHash.new(unit)
45
- end
46
-
47
- # Returns a String representation of the instance, using the named format
48
- # if provided.
49
- #
50
- # 15.5.minutes.to_s # 15.5 minutes
51
- # 15.5.minutes.to_seconds.to_s # 930.0 seconds
52
- # 15.5.minutes.in_seconds.to_s # 930.0 seconds
53
- # 15.5.minutes.seconds.to_s # 930.0 seconds
54
- # (15.5.minutes+1).seconds.to_s # 990.0 seconds
55
- # (15.5.minutes.seconds+1).to_s # 931.0 seconds
56
- # 10.feet_per_minute.to_s # 10 ft / min
57
- # seconds_per_hour.to_s # 3600.0
58
- # 14.5.inches.to_s(:feet_inches_and_32s) # "1 foot 2-16/32 inches"
59
- def to_s(format = nil)
60
- format == nil ? "#{numeric} #{unit.to_s(numeric)}" : self.format(format)
61
- end
62
-
63
- def promote_original # :nodoc:
64
- @numeric, @unit = original.numeric, original.unit
65
- end
66
-
67
- # Compares the numeric and units parts of the instance with the value. If
68
- # the value is a Numeric, the units are assumed to match. If the
69
- # UnitsMeasures don't match, a UnitsException is raised.
70
- #
71
- # 2.ft <=> 1.yd # -1
72
- # 3.ft <=> 1.yd # 0
73
- # 4.ft <=> 1.yd # 1
74
- # 4.ft <=> 3.5 # 1
75
- # 4.ft <=> 2.minutes # UnitsException
76
- def <=>(value)
77
- if derived?
78
- reduce <=> value
79
- elsif value.kind_of? NumericWithUnits
80
- if value.derived?
81
- self <=> value.reduce
82
- else
83
- align(value).numeric <=> value.numeric
84
- end
85
- elsif value.kind_of? Numeric
86
- numeric <=> value
87
- else
88
- raise UnitsException.new("units mismatch")
89
- end
90
- end
91
-
92
- # Returns true if the value and the instance are within a distance epsilon
93
- # of each other. If the value is a Numeric, the units are assumed to match.
94
- # If the UnitsMeasures don't match, a UnitsException is raised.
95
- #
96
- # 1.ft.approximately_equals? 0.33.yd # false
97
- # 1.ft.approximately_equals? 0.333333.yd # true
98
- def approximately_equals?(value,epsilon=Numeric.epsilon)
99
- if derived?
100
- reduce.approximately_equals?(value,epsilon)
101
- elsif value.kind_of? NumericWithUnits
102
- if value.derived?
103
- approximately_equals?(value.reduce,epsilon)
104
- else
105
- align(value).numeric.approximately_equals?(value.numeric,epsilon)
106
- end
107
- elsif value.kind_of? Numeric
108
- numeric.approximately_equals?(value,epsilon)
109
- else
110
- raise UnitsException.new("units mismatch")
111
- end
112
- end
113
-
114
- alias :=~ :approximately_equals?
115
-
116
- # Unary plus returns a copy of the instance.
117
- def +@
118
- clone
119
- end
120
-
121
- # Unary minus returns a copy of the instance with its numeric part negated.
122
- def -@
123
- value = clone
124
- value.numeric = -(value.numeric)
125
- value
126
- end
127
-
128
- # Returns a new NumericWithUnits containing the sum of the instance and
129
- # the value. If the value is a Numeric, the units are assumed to match.
130
- # If the UnitsMeasures don't match, a UnitsException is raised.
131
- #
132
- # 6.inches + 1.foot # 18 inches
133
- # 6.inches + 1 # 7 inches
134
- # 6.inches + 1.sec # UnitsException
135
- def +(value)
136
- if derived?
137
- reduce+value
138
- elsif value.kind_of? NumericWithUnits
139
- if value.derived?
140
- self+value.reduce
141
- else
142
- aligned_value = align(value)
143
- aligned_value.numeric += value.numeric
144
- aligned_value
145
- end
146
- elsif value.kind_of? Numeric
147
- NumericWithUnits.new(numeric+value,unit)
148
- else
149
- raise UnitsException.new("units mismatch")
150
- end
151
- end
152
-
153
- # Returns a new NumericWithUnits containing the difference between the
154
- # instance and the value. If the value is a Numeric, the units are assumed
155
- # to match. If the UnitsMeasures don't match, a UnitsException is raised.
156
- #
157
- # 6.inches - 1.foot # -6 inches
158
- # 6.inches - 1 # 5 inches
159
- # 6.inches - 1.sec # UnitsException
160
- def -(value)
161
- self + (-value)
162
- end
163
-
164
- # Returns a new NumericWithUnits containing the product of the instance and
165
- # the value. The units of the two factors are merged. If the value is not a
166
- # Numeric nor NumericWithUnits, a UnitsException is thrown.
167
- #
168
- # 6.in * 2.ft # 1 foot^2
169
- # 6.in * 2 # 12 inches
170
- # 6.in * 2.sec # 12 ft sec
171
- # 6.in * "hello" # UnitsException
172
- def *(value)
173
- if derived?
174
- reduce*value
175
- elsif value.kind_of? NumericWithUnits
176
- if value.derived?
177
- self*value.reduce
178
- else
179
- extend(value,1)
180
- end
181
- elsif value.kind_of? Numeric
182
- NumericWithUnits.new(numeric*value,unit)
183
- else
184
- raise UnitsException.new("units mismatch")
185
- end
186
- end
187
-
188
- # Returns a new NumericWithUnits containing the value of the instance divided
189
- # by the value. The units of the result are the units of the instance merged
190
- # with the recipricol of the units of the value. If the value is neither a
191
- # Numeric nor NumericWithUnits, a UnitsException is thrown.
192
- #
193
- # 6.in / 2.ft # 0.25
194
- # 6.in / 2 # 3 inches
195
- # 6.in / 2.sec # 3 ft / sec
196
- # 6.in / "hello" # UnitsException
197
- def /(value)
198
- if derived?
199
- reduce/value
200
- elsif value.kind_of? NumericWithUnits
201
- if value.derived?
202
- self/value.reduce
203
- else
204
- extend(value,-1)
205
- end
206
- elsif value.kind_of? Numeric
207
- NumericWithUnits.new(numeric/value,unit)
208
- else
209
- raise UnitsException.new("units mismatch")
210
- end
211
- end
212
-
213
- # Returns a new NumericWithUnits containing the numeric and units parts of
214
- # the instance both raised to the valueth power. If the value is not
215
- # a Numeric, a UnitsException is thrown.
216
- #
217
- # 6.in ** 3 # 216 in^3
218
- # 6.in ** 3.in # UnitsException
219
- def **(value)
220
- if (value.kind_of? Numeric) && !(value.kind_of? NumericWithUnits)
221
- extend(nil,value)
222
- else
223
- raise UnitsException.new("units mismatch")
224
- end
225
- end
226
-
227
- # Returns a new NumericWithUnits containing the numeric and units parts of
228
- # the instance with just the units raised to the valueth power. If the value
229
- # is not a Numeric, a UnitsException is thrown.
230
- #
231
- # 6.in ^ 3 # 6 in^3
232
- # 6.in ^ 3.in # UnitsException
233
- def ^(value)
234
- if (value.kind_of? Numeric) && !(value.kind_of? NumericWithUnits)
235
- NumericWithUnits.new(numeric,unit,value)
236
- else
237
- raise UnitsException.new("units mismatch")
238
- end
239
- end
240
-
241
- # Returns a new NumericWithUnits containing the numeric part of the instance
242
- # modulo the numeric part of the value, with the units part equal to the
243
- # instance's units part. If the value is a Numeric, the units are assumed
244
- # to match. If the UnitsMeasures don't match, a UnitsException is raised.
245
- #
246
- # 30.in % 2.ft # 0.5 feet
247
- # 5.in % 2.3 # 0.4 inches
248
- # 5.in % 2.sec # UnitsException
249
- def %(value)
250
- if derived?
251
- reduce%value
252
- elsif value.kind_of? NumericWithUnits
253
- if value.derived?
254
- self%value.reduce
255
- else
256
- aligned_value = align(value)
257
- aligned_value.numeric = aligned_value.numeric % value.numeric
258
- aligned_value
259
- end
260
- elsif value.kind_of? Numeric
261
- NumericWithUnits.new(numeric % value,unit)
262
- else
263
- raise UnitsException.new("units mismatch")
264
- end
265
- end
266
-
267
- # Returns a new NumericWithUnits containing the numeric part of the value
268
- # modulo the numeric part of the instance, with the units part equal to the
269
- # instance's units part. If the value is a Numeric, the units are assumed
270
- # to match. If the UnitsMeasures don't match, a UnitsException is raised.
271
- #
272
- # 30.in % 2.ft # 24 inches
273
- # 5.in % 2.3 # 2.3 inches
274
- # 5.in % 2.sec # UnitsException
275
- def inv_mod(value)
276
- if derived?
277
- reduce.inv_mod value
278
- elsif value.kind_of? NumericWithUnits
279
- if value.derived?
280
- self.inv_mod value.reduce
281
- else
282
- aligned_value = align(value)
283
- aligned_value.numeric = value.numeric % aligned_value.numeric
284
- aligned_value
285
- end
286
- elsif value.kind_of? Numeric
287
- NumericWithUnits.new(value % numeric,unit)
288
- else
289
- raise UnitsException.new("units mismatch")
290
- end
291
- end
292
-
293
- def can_align(target,exact=true) # :nodoc:
294
- ru, tru = reduce.unit, target.reduce.unit
295
- !exact || (ru == tru)
296
- end
297
-
298
- def reduce_power(p,f,type) # :nodoc:
299
- if type == :whole_powers
300
- pa = p.abs
301
- (p == 0) ? [p,f,0] : (pa < f) ? [p, f, pa/p] : [p, f, p/f]
302
- else
303
- (p == 0) ? [p,f,0] : [p, f, (1.0*p)/f]
304
- end
305
- end
306
-
307
- def common_power(ps) # :nodoc:
308
- ps.values.collect {|a| a[2]}.inject {|p,e| p.abs < e.abs ? p : e}
309
- end
310
-
311
- def revise_power(rp,p) # :nodoc:
312
- [rp[0], rp[1], p, rp[0]-p*rp[1]]
313
- end
314
-
315
- # Sets and returns the type of exponentiation merging during alignment.
316
- def self.derived_align_type=(type)
317
- @@derived_align_type = type
318
- end
319
-
320
- # Returns the type of exponentiation merging during alignment.
321
- # * :whole_powers require exponents to have integer values
322
- # * :fractional_powers allow exponents to have rational values
323
- def self.derived_align_type
324
- @@derived_align_type
325
- end
326
-
327
- @@derived_align_type = :whole_powers
328
-
329
- # Returns a new NumericWithUnits whose value is equivalent to that of the
330
- # instance, but whose units are aligned to the target, according to the
331
- # value of derived_align_type. If all is true, then the UnitsMeasure of the
332
- # instance and the target must match exactly, or else a UnitsException is
333
- # raised.
334
- #
335
- # (80.miles_per_hour).align(1.min,false) # 1.3333333 mi / min
336
- def align(target,all=true,type=@@derived_align_type)
337
- if target.kind_of? Array
338
- piece_align(target)
339
- elsif !derived? && !target.derived?
340
- simple_align(target,all)
341
- else
342
- power_align(target,all,type)
343
- end
344
- end
345
-
346
- def simple_align(target,all=true) # :nodoc:
347
- puts "simple align #{self} #{target}" if @@debug
348
- factor = 1
349
- target_unit = UnitsHash.new
350
- unit.each do |tu,tv|
351
- su = target.unit.keys.select {|u|
352
- u.units_measure.equal? tu.units_measure }
353
- if tu.equals.kind_of? Array
354
- m = tu.equals.select{|u| u.unit[su[0]]}
355
- m = tu.equals.collect{|u|
356
- u.align(1.unite(su[0]))}.compact if m.size == 0
357
- factor *= (m[0].numeric)**tv
358
- target_unit[su[0]] = tv
359
- else
360
- if su.size == 1
361
- e = su[0].equals
362
- if e.kind_of? Array
363
- m = e.select{|u|
364
- u.unit[tu]}
365
- m = e.equals.collect{|u|
366
- u.align(1.unite(su[0]))}.compact if m.size == 0
367
- factor *= (1.0/m[0].numeric)**tv
368
- else
369
- factor *= (1.0*tu.equals.numeric/e.numeric)**tv
370
- end
371
- target_unit[su[0]] = tv
372
- else
373
- target_unit[tu] = tv
374
- end
375
- end
376
- end
377
- raise UnitsException.new("units mismatch") if
378
- all && (target.unit != target_unit)
379
- nwu = NumericWithUnits.new(numeric*factor,target_unit)
380
- puts " simple_align returning #{nwu}" if @@debug
381
- nwu
382
- end
383
-
384
- def power_align(target,all=true,type=@@derived_align_type) # :nodoc:
385
- puts "power_align #{self} #{target}" if @@debug
386
- raise UnitsException.new("units mismatch") unless can_align(target,all)
387
- factor = 1
388
- target_unit = UnitsHash.new
389
- unit_reduce = reduce
390
- puts " unit_reduce #{unit_reduce}" if @@debug
391
- target.unit.each do |tu,tv|
392
- t_u = {}
393
- tt_u = {}
394
- tu_reduce = tu.equals.reduce
395
- found = tu_reduce.unit.each do |ttu,ttv|
396
- su = unit_reduce.unit.keys.select {|u|
397
- u.units_measure.equal? ttu.units_measure }
398
- break false if su.size == 0
399
- tt_u[ttu] = reduce_power(unit_reduce.unit[ttu],ttv,type)
400
- end
401
- if found
402
- cp = common_power(tt_u)
403
- puts " cp #{cp}" if @@debug
404
- tt_u.each {|k,v| tt_u[k] = revise_power(v,cp)}
405
- t_u[tu] = tv**cp
406
- t_factor = tu_reduce.numeric**cp
407
- puts " t_factor #{t_factor}" if @@debug
408
- target_unit[tu] = cp
409
- puts " tu.equals.numeric**cp #{tu.equals.numeric**cp}" if @@debug
410
- factor *= t_factor/(tu.equals.numeric**cp)
411
- puts " factor #{factor}" if @@debug
412
- tt_u.each {|k,v|
413
- unit_reduce.numeric /= t_factor
414
- unit_reduce.unit[k] = v[3]}
415
- end
416
- end
417
- puts " unit_reduce #{unit_reduce}" if @@debug
418
- unit_redux = unit_reduce.simple_align(self,false)
419
- puts " unit_redux #{unit_redux}" if @@debug
420
- result_unit = target_unit.merge(unit_redux)
421
- raise UnitsException.new("units mismatch") if
422
- all && (target.unit != result_unit)
423
- nwu = NumericWithUnits.new(factor*unit_redux.numeric,result_unit)
424
- puts " power_align returning #{nwu}" if @@debug
425
- nwu
426
- end
427
-
428
- def piece_align(pieces,type=@@derived_align_type) # :nodoc:
429
- puts "piece_align #{self} #{pieces}" if @@debug
430
- factor = 1
431
- target_unit = UnitsHash.new
432
- unit_reduce = reduce
433
- pieces.each do |p|
434
- p.unit.each do |tu,tv|
435
- t_u = {}
436
- tt_u = {}
437
- tu_reduce = tu.equals.reduce
438
- found = tu_reduce.unit.each do |ttu,ttv|
439
- su = unit_reduce.unit.keys.select {|u|
440
- u.units_measure.equal? ttu.units_measure }
441
- break false if su.size == 0
442
- tt_u[ttu] = reduce_power(unit_reduce.unit[ttu],ttv,type)
443
- end
444
- if found
445
- tt_u.each {|k,v| tt_u[k] = revise_power(v,tv)}
446
- t_u[tu] = tv
447
- t_factor = tu_reduce.numeric**tv
448
- target_unit[tu] = tv
449
- factor *= t_factor/(tu.equals.numeric**tv)
450
- tt_u.each {|k,v|
451
- unit_reduce.numeric /= t_factor
452
- unit_reduce.unit[k] = v[3]}
453
- end
454
- end
455
- end
456
- raise UnitsException.new("units mismatch") if unit_reduce.unit.has_units?
457
- nwu = NumericWithUnits.new(factor*unit_reduce.numeric,target_unit)
458
- puts " piece_align returning #{nwu}" if @@debug
459
- nwu
460
- end
461
-
462
- # Returns a new NumericWithUnits whose value is extended by raising it to the
463
- # power, or by multiplying it by units raised to the power.
464
- #
465
- # 7.miles.extend(nil,2) # 49 mi^2
466
- # 5.feet.extend(10.ft,2) # 500 ft^3
467
- def extend(units,power)
468
- if !units
469
- NumericWithUnits.new(numeric**power,unit**power)
470
- else
471
- value = align(units,false)
472
- extended_numeric = value.numeric*(units.numeric**power)
473
- extended_unit = value.unit.merge(units,power)
474
- (extended_unit.size == 0)? extended_numeric :
475
- NumericWithUnits.new(extended_numeric,extended_unit)
476
- end
477
- end
478
-
479
- def NumericWithUnits.commutative_operator(op,old,calc) # :nodoc:
480
- ([] <<
481
- "alias :old_#{old} :#{op}" <<
482
- "def #{op}(value)" <<
483
- " (value.kind_of? NumericWithUnits) ? #{calc} : old_#{old}(value)" <<
484
- "end").
485
- join("\r\n")
486
- end
487
-
488
- def NumericWithUnits.create_commutative_operators(klasses) # :nodoc:
489
- commutative_operators ||=
490
- ([] <<
491
- commutative_operator( "*", "multiply", "value * self" ) <<
492
- commutative_operator( "/", "divide", "(value**-1) * self" ) <<
493
- commutative_operator( "+", "add", "value + self" ) <<
494
- commutative_operator( "-", "subtract", "(-value) + self" ) <<
495
- commutative_operator( "%", "modulo", "value.inv_mod(self)" ) <<
496
- commutative_operator( "<=>", "compare", "-(value <=> self)" ) <<
497
- commutative_operator( ">", "gt", "(value < self)" ) <<
498
- commutative_operator( "<", "lt", "(value > self)" ) <<
499
- commutative_operator( ">=", "gteq", "(value <= self)" ) <<
500
- commutative_operator( "<=", "lteq", "(value >= self)" ) <<
501
- commutative_operator( "==", "eq", "(value == self)" ) <<
502
- commutative_operator( "=~", "approxeq", "(value =~ self)" )).
503
- join("\r\n")
504
- klasses.each { |klass| klass.class_eval commutative_operators }
505
- end
506
-
507
- def method_missing(method,*args) # :nodoc:
508
- begin
509
- s = method.to_s
510
- ms = s.split '_'
511
- if ms[0] == 'to'
512
- convert! s.gsub(/^to_/,"")
513
- elsif ms[0] == 'in'
514
- convert s.gsub(/^in_/,"")
515
- elsif ms.select{|e| e == 'per'}.size > 0
516
- convert_per method
517
- else
518
- convert s
519
- end
520
- rescue Exception
521
- value = numeric.send(method,*args)
522
- if (value.kind_of? String)
523
- "#{value} #{unit.to_s(numeric)}"
524
- else
525
- NumericWithUnits.new(value,unit)
526
- end
527
- end
528
- end
529
-
530
- def convert_per method # :nodoc:
531
- ps = method.to_s.split '_per_'
532
- raise UnitsException.new('invalid per method') if ps.size != 2
533
- numerator = 1.unite(ps[0])
534
- numerator_units = Set.new numerator.unit.keys
535
- denominator = 1.unite(ps[1])
536
- denominator_units = Set.new denominator.unit.keys
537
- positives = unit.keys.collect{|k| unit[k] > 0 ? k : nil}.compact!
538
- negatives = unit.keys.collect{|k| unit[k] < 0 ? k : nil}.compact!
539
- numerator_positives =
540
- Set.new 1.unite(positives).align(numerator,false).unit.keys
541
- numerator_negatives =
542
- Set.new 1.unite(negatives).align(numerator,false).unit.keys
543
- denominator_positives =
544
- Set.new 1.unite(positives).align(denominator,false).unit.keys
545
- denominator_negatives =
546
- Set.new 1.unite(negatives).align(denominator,false).unit.keys
547
- if (numerator_units == numerator_positives) &&
548
- (denominator_units == denominator_negatives)
549
- convert(ps[0]+'_and_'+ps[1])
550
- elsif (numerator_units == numerator_negatives) &&
551
- (denominator_units == denominator_positives)
552
- convert(ps[0]+'_and_'+ps[1])**-1
553
- else
554
- raise UnitsException.new('invalid per units')
555
- end
556
- end
557
-
558
- alias :old_kind_of? :kind_of?
559
-
560
- # Returns true if the instance or it's numeric part is a kind of klass.
561
- #
562
- # 28.feet.kind_of? String # false
563
- # 28.feet.kind_of? NumericWithUnits # true
564
- # 28.feet.kind_of? Numeric # true
565
- # 28.feet.kind_of? Integer # true
566
- # 28.feet.kind_of? Float # false
567
- # 28.0.feet.kind_of? Float # true
568
- #
569
- # Note while NumericWithUnits actually descends from Object, it acts as if it
570
- # is inherited from the class of the numeric part of the instance, since it
571
- # forwards any unknown method calls to it. In this way the duck really is a
572
- # duck.
573
- def kind_of?(klass)
574
- (numeric.kind_of? klass)? true : old_kind_of?(klass)
575
- end
576
-
577
- # Returns a new NumericWithUnits whose numeric part is the target of the
578
- # Numeric's unite method.
579
- #
580
- # 28.ft^2.unite("seconds") # 28 seconds
581
- def unite(target_unit=nil,power=1,measure=nil)
582
- numeric.unite(target_unit,power,measure)
583
- end
584
-
585
- # Returns a copy of the instance converted to the target_units. Note that
586
- # the conversion is only with respect to the UnitsMeasures of the
587
- # target_units - the remainder of the units will remain unconverted.
588
- def convert(target_units=nil)
589
- target_units ? align(1.unite(target_units),false) : clone
590
- end
591
-
592
- # Converts the instance itself.
593
- def convert!(target_units=nil)
594
- result = convert(target_units)
595
- self.numeric, self.unit = result.numeric, result.unit
596
- self
597
- end
598
-
599
- # Returns the UnitsMeasures in the units part of the instance.
600
- def measure
601
- unit.measure
602
- end
603
-
604
- # Returns a String formatted using the named format defined in the instance's
605
- # measure. Raises a UnitsException if either the unit part of the instance
606
- # has no defined UnitsMeasure or a format with the given name does not exist
607
- # in that UnitsMeasure.
608
- def format(name=nil)
609
- if name == nil
610
- to_s
611
- else
612
- raise UnitsException.new("system not explicit") if (measure == nil)
613
- format = measure.formats[name]
614
- raise UnitsException.new("missing format") if format == nil
615
- format.call(self)
616
- end
617
- end
618
-
619
- # Returns true if a component of unit part of the instance has a derived
620
- # UnitsMeasure.
621
- def derived?
622
- unit.derived?
623
- end
624
-
625
- # Return a new NumericWithUnits that is equivalent to the instance but whose
626
- # unit contains no derived UnitMeasures.
627
- def reduce
628
- puts "reduce unit.reduce #{unit.reduce}" if @@debug
629
- numeric * unit.reduce
630
- end
631
-
632
- end
633
-
634
-
635
- NumericWithUnits.create_commutative_operators [ Fixnum, Bignum, Float ]