quantitymanager 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (236) hide show
  1. data/doc/classes/Array.html +159 -0
  2. data/doc/classes/Array.src/M000001.html +21 -0
  3. data/doc/classes/Array.src/M000002.html +19 -0
  4. data/doc/classes/Array.src/M000040.html +21 -0
  5. data/doc/classes/Array.src/M000041.html +19 -0
  6. data/doc/classes/CalculatorTest.html +332 -0
  7. data/doc/classes/CalculatorTest.src/M000022.html +33 -0
  8. data/doc/classes/CalculatorTest.src/M000023.html +28 -0
  9. data/doc/classes/CalculatorTest.src/M000024.html +25 -0
  10. data/doc/classes/CalculatorTest.src/M000025.html +34 -0
  11. data/doc/classes/CalculatorTest.src/M000026.html +27 -0
  12. data/doc/classes/CalculatorTest.src/M000027.html +28 -0
  13. data/doc/classes/CalculatorTest.src/M000028.html +26 -0
  14. data/doc/classes/CalculatorTest.src/M000029.html +25 -0
  15. data/doc/classes/CalculatorTest.src/M000030.html +26 -0
  16. data/doc/classes/CalculatorTest.src/M000031.html +31 -0
  17. data/doc/classes/CalculatorTest.src/M000032.html +23 -0
  18. data/doc/classes/CalculatorTest.src/M000033.html +23 -0
  19. data/doc/classes/CalculatorTest.src/M000034.html +32 -0
  20. data/doc/classes/CalculatorTest.src/M000035.html +20 -0
  21. data/doc/classes/CompasedUnitTest.html +279 -0
  22. data/doc/classes/CompasedUnitTest.src/M000001.html +32 -0
  23. data/doc/classes/CompasedUnitTest.src/M000002.html +31 -0
  24. data/doc/classes/CompasedUnitTest.src/M000003.html +28 -0
  25. data/doc/classes/CompasedUnitTest.src/M000004.html +28 -0
  26. data/doc/classes/CompasedUnitTest.src/M000005.html +31 -0
  27. data/doc/classes/CompasedUnitTest.src/M000006.html +23 -0
  28. data/doc/classes/CompasedUnitTest.src/M000007.html +30 -0
  29. data/doc/classes/CompasedUnitTest.src/M000008.html +24 -0
  30. data/doc/classes/CompasedUnitTest.src/M000009.html +27 -0
  31. data/doc/classes/CompasedUnitTest.src/M000010.html +24 -0
  32. data/doc/classes/Configuration.html +184 -0
  33. data/doc/classes/Configuration.src/M000003.html +19 -0
  34. data/doc/classes/Configuration.src/M000004.html +18 -0
  35. data/doc/classes/Configuration.src/M000005.html +18 -0
  36. data/doc/classes/Configuration.src/M000006.html +24 -0
  37. data/doc/classes/Configuration.src/M000042.html +19 -0
  38. data/doc/classes/Configuration.src/M000043.html +18 -0
  39. data/doc/classes/Configuration.src/M000044.html +18 -0
  40. data/doc/classes/Configuration.src/M000045.html +24 -0
  41. data/doc/classes/ConfigurationTest.html +182 -0
  42. data/doc/classes/ConfigurationTest.src/M000065.html +31 -0
  43. data/doc/classes/ConfigurationTest.src/M000066.html +27 -0
  44. data/doc/classes/ConfigurationTest.src/M000067.html +35 -0
  45. data/doc/classes/ConfigurationTest.src/M000068.html +24 -0
  46. data/doc/classes/CustomUnitConversionTest.html +212 -0
  47. data/doc/classes/CustomUnitConversionTest.src/M000052.html +31 -0
  48. data/doc/classes/CustomUnitConversionTest.src/M000053.html +25 -0
  49. data/doc/classes/CustomUnitConversionTest.src/M000054.html +20 -0
  50. data/doc/classes/CustomUnitConversionTest.src/M000055.html +26 -0
  51. data/doc/classes/CustomUnitConversionTest.src/M000056.html +26 -0
  52. data/doc/classes/CustomUnitConversionTest.src/M000057.html +24 -0
  53. data/doc/classes/Numeric.html +125 -0
  54. data/doc/classes/QuantifiableTest.html +189 -0
  55. data/doc/classes/QuantifiableTest.src/M000036.html +24 -0
  56. data/doc/classes/QuantifiableTest.src/M000037.html +26 -0
  57. data/doc/classes/QuantifiableTest.src/M000038.html +41 -0
  58. data/doc/classes/QuantifiableTest.src/M000039.html +23 -0
  59. data/doc/classes/Quantity/Calculable.html +213 -0
  60. data/doc/classes/Quantity/Calculable.src/M000010.html +18 -0
  61. data/doc/classes/Quantity/Calculable.src/M000011.html +18 -0
  62. data/doc/classes/Quantity/Calculable.src/M000012.html +18 -0
  63. data/doc/classes/Quantity/Calculable.src/M000013.html +18 -0
  64. data/doc/classes/Quantity/Calculable.src/M000014.html +21 -0
  65. data/doc/classes/Quantity/Calculable.src/M000015.html +18 -0
  66. data/doc/classes/Quantity/Calculable.src/M000072.html +18 -0
  67. data/doc/classes/Quantity/Calculable.src/M000073.html +18 -0
  68. data/doc/classes/Quantity/Calculable.src/M000074.html +18 -0
  69. data/doc/classes/Quantity/Calculable.src/M000075.html +18 -0
  70. data/doc/classes/Quantity/Calculable.src/M000076.html +21 -0
  71. data/doc/classes/Quantity/Calculable.src/M000077.html +18 -0
  72. data/doc/classes/Quantity/Calculator.html +240 -0
  73. data/doc/classes/Quantity/Calculator.src/M000021.html +20 -0
  74. data/doc/classes/Quantity/Calculator.src/M000022.html +18 -0
  75. data/doc/classes/Quantity/Calculator.src/M000023.html +26 -0
  76. data/doc/classes/Quantity/Calculator.src/M000024.html +23 -0
  77. data/doc/classes/Quantity/Calculator.src/M000025.html +31 -0
  78. data/doc/classes/Quantity/Calculator.src/M000026.html +25 -0
  79. data/doc/classes/Quantity/Calculator.src/M000083.html +20 -0
  80. data/doc/classes/Quantity/Calculator.src/M000084.html +18 -0
  81. data/doc/classes/Quantity/Calculator.src/M000085.html +26 -0
  82. data/doc/classes/Quantity/Calculator.src/M000086.html +23 -0
  83. data/doc/classes/Quantity/Calculator.src/M000087.html +31 -0
  84. data/doc/classes/Quantity/Calculator.src/M000088.html +25 -0
  85. data/doc/classes/Quantity/Measurable.html +153 -0
  86. data/doc/classes/Quantity/Measurable.src/M000008.html +18 -0
  87. data/doc/classes/Quantity/Measurable.src/M000009.html +18 -0
  88. data/doc/classes/Quantity/Measurable.src/M000070.html +18 -0
  89. data/doc/classes/Quantity/Measurable.src/M000071.html +18 -0
  90. data/doc/classes/Quantity/OperationInfo.html +184 -0
  91. data/doc/classes/Quantity/OperationInfo.src/M000027.html +24 -0
  92. data/doc/classes/Quantity/OperationInfo.src/M000028.html +21 -0
  93. data/doc/classes/Quantity/OperationInfo.src/M000089.html +24 -0
  94. data/doc/classes/Quantity/OperationInfo.src/M000090.html +21 -0
  95. data/doc/classes/Quantity/Quantifiable.html +131 -0
  96. data/doc/classes/Quantity/Quantifiable.src/M000007.html +18 -0
  97. data/doc/classes/Quantity/Quantifiable.src/M000069.html +18 -0
  98. data/doc/classes/Quantity/Quantity.html +211 -0
  99. data/doc/classes/Quantity/Quantity.src/M000016.html +20 -0
  100. data/doc/classes/Quantity/Quantity.src/M000017.html +20 -0
  101. data/doc/classes/Quantity/Quantity.src/M000018.html +20 -0
  102. data/doc/classes/Quantity/Quantity.src/M000078.html +20 -0
  103. data/doc/classes/Quantity/Quantity.src/M000079.html +20 -0
  104. data/doc/classes/Quantity/Quantity.src/M000080.html +20 -0
  105. data/doc/classes/Quantity/QuantityInfo.html +179 -0
  106. data/doc/classes/Quantity/QuantityInfo.src/M000019.html +19 -0
  107. data/doc/classes/Quantity/QuantityInfo.src/M000020.html +18 -0
  108. data/doc/classes/Quantity/QuantityInfo.src/M000081.html +19 -0
  109. data/doc/classes/Quantity/QuantityInfo.src/M000082.html +18 -0
  110. data/doc/classes/Quantity.html +121 -0
  111. data/doc/classes/QuantityTest.html +220 -0
  112. data/doc/classes/QuantityTest.src/M000046.html +32 -0
  113. data/doc/classes/QuantityTest.src/M000047.html +33 -0
  114. data/doc/classes/QuantityTest.src/M000048.html +27 -0
  115. data/doc/classes/QuantityTest.src/M000049.html +20 -0
  116. data/doc/classes/QuantityTest.src/M000050.html +22 -0
  117. data/doc/classes/QuantityTest.src/M000051.html +20 -0
  118. data/doc/classes/SimpleUnitTest.html +234 -0
  119. data/doc/classes/SimpleUnitTest.src/M000058.html +24 -0
  120. data/doc/classes/SimpleUnitTest.src/M000059.html +25 -0
  121. data/doc/classes/SimpleUnitTest.src/M000060.html +21 -0
  122. data/doc/classes/SimpleUnitTest.src/M000061.html +20 -0
  123. data/doc/classes/SimpleUnitTest.src/M000062.html +26 -0
  124. data/doc/classes/SimpleUnitTest.src/M000063.html +21 -0
  125. data/doc/classes/SimpleUnitTest.src/M000064.html +18 -0
  126. data/doc/classes/SpecParserTest.html +174 -0
  127. data/doc/classes/SpecParserTest.src/M000019.html +25 -0
  128. data/doc/classes/SpecParserTest.src/M000020.html +32 -0
  129. data/doc/classes/SpecParserTest.src/M000021.html +31 -0
  130. data/doc/classes/Test.html +101 -0
  131. data/doc/classes/Unit/Comparable.html +156 -0
  132. data/doc/classes/Unit/Comparable.src/M000030.html +22 -0
  133. data/doc/classes/Unit/Comparable.src/M000031.html +22 -0
  134. data/doc/classes/Unit/Comparable.src/M000092.html +22 -0
  135. data/doc/classes/Unit/Comparable.src/M000093.html +22 -0
  136. data/doc/classes/Unit/ComposedUnit.html +301 -0
  137. data/doc/classes/Unit/ComposedUnit.src/M000044.html +22 -0
  138. data/doc/classes/Unit/ComposedUnit.src/M000045.html +25 -0
  139. data/doc/classes/Unit/ComposedUnit.src/M000046.html +25 -0
  140. data/doc/classes/Unit/ComposedUnit.src/M000047.html +22 -0
  141. data/doc/classes/Unit/ComposedUnit.src/M000048.html +29 -0
  142. data/doc/classes/Unit/ComposedUnit.src/M000049.html +24 -0
  143. data/doc/classes/Unit/ComposedUnit.src/M000050.html +25 -0
  144. data/doc/classes/Unit/ComposedUnit.src/M000051.html +18 -0
  145. data/doc/classes/Unit/ComposedUnit.src/M000107.html +22 -0
  146. data/doc/classes/Unit/ComposedUnit.src/M000108.html +25 -0
  147. data/doc/classes/Unit/ComposedUnit.src/M000109.html +25 -0
  148. data/doc/classes/Unit/ComposedUnit.src/M000110.html +22 -0
  149. data/doc/classes/Unit/ComposedUnit.src/M000111.html +29 -0
  150. data/doc/classes/Unit/ComposedUnit.src/M000112.html +24 -0
  151. data/doc/classes/Unit/ComposedUnit.src/M000113.html +25 -0
  152. data/doc/classes/Unit/ComposedUnit.src/M000114.html +18 -0
  153. data/doc/classes/Unit/Optimizer.html +152 -0
  154. data/doc/classes/Unit/Optimizer.src/M000042.html +44 -0
  155. data/doc/classes/Unit/Optimizer.src/M000043.html +18 -0
  156. data/doc/classes/Unit/Optimizer.src/M000105.html +44 -0
  157. data/doc/classes/Unit/Optimizer.src/M000106.html +18 -0
  158. data/doc/classes/Unit/Parser.html +176 -0
  159. data/doc/classes/Unit/Parser.src/M000039.html +18 -0
  160. data/doc/classes/Unit/Parser.src/M000040.html +25 -0
  161. data/doc/classes/Unit/Parser.src/M000041.html +19 -0
  162. data/doc/classes/Unit/Parser.src/M000102.html +18 -0
  163. data/doc/classes/Unit/Parser.src/M000103.html +25 -0
  164. data/doc/classes/Unit/Parser.src/M000104.html +19 -0
  165. data/doc/classes/Unit/SimpleUnit.html +287 -0
  166. data/doc/classes/Unit/SimpleUnit.src/M000032.html +20 -0
  167. data/doc/classes/Unit/SimpleUnit.src/M000033.html +20 -0
  168. data/doc/classes/Unit/SimpleUnit.src/M000034.html +20 -0
  169. data/doc/classes/Unit/SimpleUnit.src/M000035.html +20 -0
  170. data/doc/classes/Unit/SimpleUnit.src/M000036.html +18 -0
  171. data/doc/classes/Unit/SimpleUnit.src/M000037.html +21 -0
  172. data/doc/classes/Unit/SimpleUnit.src/M000038.html +18 -0
  173. data/doc/classes/Unit/SimpleUnit.src/M000094.html +20 -0
  174. data/doc/classes/Unit/SimpleUnit.src/M000095.html +20 -0
  175. data/doc/classes/Unit/SimpleUnit.src/M000096.html +20 -0
  176. data/doc/classes/Unit/SimpleUnit.src/M000097.html +20 -0
  177. data/doc/classes/Unit/SimpleUnit.src/M000098.html +18 -0
  178. data/doc/classes/Unit/SimpleUnit.src/M000099.html +21 -0
  179. data/doc/classes/Unit/SimpleUnit.src/M000100.html +18 -0
  180. data/doc/classes/Unit/SymbolConverter.html +131 -0
  181. data/doc/classes/Unit/SymbolConverter.src/M000029.html +24 -0
  182. data/doc/classes/Unit/SymbolConverter.src/M000091.html +24 -0
  183. data/doc/classes/Unit/TestCase.html +146 -0
  184. data/doc/classes/Unit/TestCase.src/M000101.html +24 -0
  185. data/doc/classes/Unit.html +120 -0
  186. data/doc/classes/UnitOptemizerTest.html +249 -0
  187. data/doc/classes/UnitOptemizerTest.src/M000011.html +31 -0
  188. data/doc/classes/UnitOptemizerTest.src/M000012.html +25 -0
  189. data/doc/classes/UnitOptemizerTest.src/M000013.html +27 -0
  190. data/doc/classes/UnitOptemizerTest.src/M000014.html +27 -0
  191. data/doc/classes/UnitOptemizerTest.src/M000015.html +27 -0
  192. data/doc/classes/UnitOptemizerTest.src/M000016.html +26 -0
  193. data/doc/classes/UnitOptemizerTest.src/M000017.html +23 -0
  194. data/doc/classes/UnitOptemizerTest.src/M000018.html +22 -0
  195. data/doc/created.rid +1 -0
  196. data/doc/files/config/default_configuration_rb.html +108 -0
  197. data/doc/files/quantity_rb.html +113 -0
  198. data/doc/files/test/all_tests_rb.html +108 -0
  199. data/doc/files/test/test_helper_rb.html +110 -0
  200. data/doc/files/test/unit/calculator_test_rb.html +109 -0
  201. data/doc/files/test/unit/composed_unit_test_rb.html +101 -0
  202. data/doc/files/test/unit/configuration_test_rb.html +109 -0
  203. data/doc/files/test/unit/custom_conversion_test_rb.html +109 -0
  204. data/doc/files/test/unit/quantifiable_test_rb.html +101 -0
  205. data/doc/files/test/unit/quantity_test_rb.html +101 -0
  206. data/doc/files/test/unit/simple_unit_test_rb.html +101 -0
  207. data/doc/files/test/unit/unit_optimizer_test_rb.html +101 -0
  208. data/doc/files/test/unit/unit_spec_parser_test_rb.html +101 -0
  209. data/doc/files/unitmanager/calculator_rb.html +101 -0
  210. data/doc/files/unitmanager/configuration_rb.html +101 -0
  211. data/doc/files/unitmanager/quantity_rb.html +101 -0
  212. data/doc/files/unitmanager/simple_unit_rb.html +108 -0
  213. data/doc/files/unitmanager/unit_composition_rb.html +101 -0
  214. data/doc/fr_class_index.html +44 -0
  215. data/doc/fr_file_index.html +33 -0
  216. data/doc/fr_method_index.html +77 -0
  217. data/doc/index.html +24 -0
  218. data/lib/config/default_configuration.rb +115 -0
  219. data/lib/quantity.rb +34 -0
  220. data/lib/unitmanager/calculator.rb +195 -0
  221. data/lib/unitmanager/configuration.rb +26 -0
  222. data/lib/unitmanager/quantity.rb +167 -0
  223. data/lib/unitmanager/simple_unit.rb +155 -0
  224. data/lib/unitmanager/unit_composition.rb +217 -0
  225. data/test/all_tests.rb +8 -0
  226. data/test/calculator_test.rb +194 -0
  227. data/test/composed_unit_test.rb +169 -0
  228. data/test/configuration_test.rb +70 -0
  229. data/test/custom_conversion_test.rb +90 -0
  230. data/test/quantifiable_test.rb +73 -0
  231. data/test/quantity_test.rb +79 -0
  232. data/test/simple_unit_test.rb +59 -0
  233. data/test/test_helper.rb +18 -0
  234. data/test/unit_optimizer_test.rb +104 -0
  235. data/test/unit_spec_parser_test.rb +50 -0
  236. metadata +307 -0
@@ -0,0 +1,155 @@
1
+ #Extension to standard Array class.
2
+ #Added functionality to compare array content regardless element order.
3
+ class Array
4
+ def contains?(other_array)
5
+ copy = dup
6
+ other_array.each {|item|
7
+ return false unless i = copy.index(item)
8
+ copy[i] = nil
9
+ }
10
+ true
11
+ end
12
+
13
+ def same?(other_array)
14
+ length == other_array.length &&
15
+ contains?(other_array)
16
+ end
17
+
18
+ end
19
+
20
+ module Unit
21
+
22
+ class BaseUnit
23
+
24
+ class << self
25
+
26
+ def once (*methods) #:nodoc:
27
+ methods.each {|method|
28
+
29
+ module_eval <<-"end;"
30
+ alias_method :__#{method.to_i}__ , :#{method.to_s}
31
+
32
+ def #{method.to_s}(*args, &block)
33
+ if defined? @__#{method.to_i}__
34
+ @__#{method.to_i}__
35
+ else
36
+ @__#{method.to_i}__ ||= __#{method.to_i}__(*args, &block)
37
+ end
38
+ end
39
+ private :__#{method.to_i}__
40
+
41
+ end;
42
+
43
+ }
44
+ end
45
+
46
+ private :once
47
+ end
48
+
49
+ # This method allows to retrieve symbolic portions of the unit definition.
50
+ # Supported values are:
51
+ # :dividends - returns an array of symbols representing dividend part of
52
+ # unit definition.
53
+ # :divisors - returns an array of symbols representing divisor part of
54
+ # unit definition.
55
+ # :string - string representation of the unit of measure.
56
+ def [] (symbol)
57
+ unit_sym[symbol]
58
+ end
59
+ end
60
+
61
+ # Adds comparing capabilities to unit implementations
62
+ module Comparable
63
+
64
+ #Two units are compatible if they have same hierarchy base
65
+ #Example :cm is compatible with :in, since they both based on :mm
66
+ def compatible? (other)
67
+ return false if other == nil
68
+ return false unless other.respond_to?(:h_base)
69
+
70
+ h_base[:dividends].same?(other.h_base[:dividends]) &&
71
+ h_base[:divisors].same?(other.h_base[:divisors])
72
+ end
73
+
74
+ def contains? (other)
75
+ return false if other == nil
76
+ return false unless other.respond_to?(:h_base)
77
+
78
+ h_base[:dividends].contains?(other.h_base[:dividends]) &&
79
+ h_base[:divisors].contains?(other.h_base[:divisors])
80
+ end
81
+ end
82
+
83
+
84
+ # Implementation of what is called ‘simple unit of measure’.
85
+ # This is a linear unit which is optionally based on some other
86
+ # simple unit with linear coefficient.
87
+ # Example: :cm is based on :mm with coefficient equal 10.
88
+ # In other words X cm = 10 * Y mm.
89
+ class SimpleUnit < BaseUnit
90
+
91
+ include Unit::Comparable
92
+ # include Unit::Singleton
93
+
94
+ attr_reader :unit, :coefficient, :based_on
95
+
96
+ @@EMPTY_UNIT = SimpleUnit.new()
97
+
98
+ def initialize (args = {})
99
+ @unit = args[:unit]
100
+ @based_on = args[:based_on] || nil
101
+ @coefficient = args[:coefficient] || 1
102
+ end
103
+
104
+ def to_base(value)
105
+ value = @based_on.to_base(value) if derived?
106
+
107
+ value *= @coefficient
108
+ end
109
+
110
+ def from_base(value)
111
+ value = @based_on.from_base(value) if derived?
112
+
113
+ value /= @coefficient
114
+ end
115
+
116
+ # Returns unit representing hierarchy base for the given unit.
117
+ # The Hierarchy is the "based on" chain.
118
+ def h_base
119
+ derived? ? @based_on.h_base : self
120
+ end
121
+
122
+ def dividend
123
+ @unit
124
+ end
125
+
126
+ def divisor
127
+ @@EMPTY_UNIT
128
+ end
129
+
130
+ # Two Simple units are equal if they have same symbol,
131
+ # based on the same unit with the same coefficient
132
+ def ==(other)
133
+ return false if other == nil
134
+ return false unless other.kind_of?(self.class)
135
+
136
+ unit == other.unit && based_on == other.based_on && coefficient == other.coefficient
137
+ end
138
+
139
+ def eql?(other)
140
+ self == other
141
+ end
142
+
143
+ private
144
+ def derived?
145
+ @based_on != nil
146
+ end
147
+
148
+ def unit_sym
149
+ {:dividends => [@unit], :divisors => [], :string => @unit.to_s}
150
+ end
151
+
152
+ once :unit_sym
153
+ end
154
+
155
+ end
@@ -0,0 +1,217 @@
1
+ module Unit
2
+
3
+ module SymbolConverter
4
+
5
+ def convert(symbols)
6
+ units = []
7
+ symbols.each {|symbol|
8
+ unit = @units[symbol]
9
+ raise "Invalid Unit Name: #{symbol.to_s}" if unit.nil?
10
+ units << unit
11
+ }
12
+ return units
13
+ end
14
+
15
+ end
16
+
17
+
18
+ # Implementation of what is called ‘composed unit of measure’.
19
+ # This is a result of performing multiplication or division of
20
+ # quantities with simple units.
21
+ # Example: 1 lb per in or 70 mi per hour
22
+ class ComposedUnit < BaseUnit
23
+
24
+ include Unit::Comparable
25
+
26
+ attr_reader :dividends, :divisors, :coefficient
27
+
28
+ def initialize(params)
29
+ params = Optimizer.process(params)
30
+
31
+ @coefficient = params[:coefficient] || 1
32
+ @dividends = params[:dividends] || []
33
+ @divisors = params[:divisors] || []
34
+ end
35
+
36
+ def to_base(value)
37
+ value * to_base_coef
38
+ end
39
+
40
+ def from_base(value)
41
+ value * from_base_coef
42
+ end
43
+
44
+ # Returns unit representing hierarchy base for the given unit.
45
+ # The Hierarchy is the "based on" chain.
46
+ def h_base
47
+ ComposedUnit.new({ :coefficient => 1.0,
48
+ :dividends => Optimizer.base(@dividends),
49
+ :divisors => Optimizer.base(@divisors) })
50
+ end
51
+
52
+ def dividend
53
+ ComposedUnit.new({:dividends => @dividends})
54
+ end
55
+
56
+ def divisor
57
+ ComposedUnit.new({:divisors => @divisors})
58
+ end
59
+
60
+ def reverse
61
+ ComposedUnit.new({
62
+ :coefficient => 1.0 / coefficient,
63
+ :dividends => @divisors.collect{|unit| unit },
64
+ :divisors => @dividends.collect{|unit| unit }
65
+ })
66
+ end
67
+
68
+ # Two composed units are equal if their coefficients are the same
69
+ # and units contain same set of dividends and divisors.
70
+ def ==(other)
71
+ return false if other == nil
72
+ return false unless other.kind_of?(self.class)
73
+
74
+ result = (coefficient == other.coefficient) &&
75
+ dividends.same?(other.dividends) &&
76
+ divisors.same?(other.divisors)
77
+
78
+ return result
79
+ end
80
+
81
+ def eql?(other)
82
+ self == other
83
+ end
84
+
85
+ private
86
+
87
+ def collect(array)
88
+ result = []
89
+
90
+ array.each {|item| result += (yield(item) || []) }
91
+
92
+ return result
93
+ end
94
+
95
+ def to_base_coef
96
+ coef = @coefficient
97
+ @dividends.each {|unit| coef *= unit.to_base(1.0) }
98
+ @divisors.each {|unit| coef /= unit.to_base(1.0) }
99
+ coef
100
+ end
101
+
102
+ def from_base_coef
103
+ coef = @coefficient
104
+ @dividends.each {|unit| coef *= unit.from_base(1.0) }
105
+ @divisors.each {|unit| coef /= unit.from_base(1.0) }
106
+ coef
107
+ end
108
+
109
+ def unit_string
110
+ buffer = {:dividends => [], :divisors => []}
111
+
112
+ @dividends.each{|unit|
113
+ if unit[:string]
114
+ strings = unit[:string].split(/\//)
115
+ buffer[:dividends] << strings[0]
116
+ buffer[:divisors] << strings[1]
117
+ end
118
+ }
119
+
120
+ @divisors.each{|unit|
121
+ if unit[:string]
122
+ strings = unit[:string].split(/\//)
123
+ buffer[:dividends] << strings[1]
124
+ buffer[:divisors] << strings[0]
125
+ end
126
+ }
127
+
128
+ unit_string = buffer[:dividends].empty? ? '' : buffer[:dividends].compact.join('*')
129
+
130
+ buffer[:divisors].compact!
131
+ unit_string << "/" << buffer[:divisors].join('*') unless buffer[:divisors].empty?
132
+
133
+ unit_string
134
+ end
135
+
136
+
137
+ def unit_sym
138
+ {
139
+ :dividends =>
140
+ collect(@dividends){|unit| unit[:dividends]} +
141
+ collect(@divisors){|unit| unit[:divisors]},
142
+ :divisors =>
143
+ collect(@divisors){|unit| unit[:dividends]} +
144
+ collect(@dividends){|unit| unit[:divisors]},
145
+ :string => unit_string
146
+ }
147
+ end
148
+
149
+ once :unit_sym, :to_base_coef, :from_base_coef, :h_base, :dividend, :divisor, :reverse, :unit_string
150
+ end
151
+
152
+
153
+ class Parser
154
+ include SymbolConverter
155
+
156
+ def initialize(units)
157
+ @units = units
158
+ end
159
+
160
+ def to_units(unit_spec)
161
+
162
+ operands = unit_spec.split(/\//)
163
+ raise "Invalid Number of Operands in : #{unit_spec}" if operands.size > 2
164
+
165
+ {
166
+ :dividends => convert(parse_operand_symbols(operands[0])),
167
+ :divisors => convert(parse_operand_symbols(operands[1]))
168
+ }
169
+ end
170
+
171
+ def parse_operand_symbols(string)
172
+ operands = string.nil? ? [] : string.split(/\*/)
173
+ operands.collect{|name| name.to_sym}
174
+ end
175
+
176
+ end
177
+
178
+
179
+ class Optimizer
180
+
181
+ def Optimizer.process(params)
182
+ raise "Incoming parameter has to respond to [] method" unless params.respond_to?(:[])
183
+
184
+ #initialize local values
185
+ coefficient = params[:coefficient] || 1
186
+ dividends = [] + (params[:dividends] || [])
187
+ divisors = [] + (params[:divisors] || [])
188
+
189
+ #create arrays of unit hierarchy bases..
190
+ base_dividends = base(dividends)
191
+ base_divisors = base(divisors)
192
+
193
+ #try to find matching units and optimize them
194
+ base_dividends.each_index { | i |
195
+ if index = base_divisors.index(base_dividends[i])
196
+ coefficient *= dividends[i].to_base(1.0)
197
+ coefficient /= divisors[index].to_base(1.0)
198
+
199
+ #set 'used' units to nil, so they won't be used again
200
+ dividends[i] = divisors[index] = base_divisors[index] = nil
201
+ end
202
+ }
203
+
204
+ return {
205
+ :coefficient => coefficient,
206
+ :dividends => dividends.compact,
207
+ :divisors => divisors.compact
208
+ }
209
+ end
210
+
211
+ def Optimizer.base(units)
212
+ units.collect {| item | item.h_base}
213
+ end
214
+
215
+ end
216
+
217
+ end
data/test/all_tests.rb ADDED
@@ -0,0 +1,8 @@
1
+ dir = File.dirname(__FILE__)
2
+
3
+ require dir + "/test_helper"
4
+
5
+ unit_tests = Dir[dir + "/../test/*test.rb"]
6
+ unit_tests.each{|test|
7
+ require test
8
+ }
@@ -0,0 +1,194 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ include Unit
4
+ include Quantity
5
+
6
+ class CalculatorTest < Test::Unit::TestCase
7
+
8
+ def setup
9
+
10
+ @units = {}
11
+ @units[:mm] = SimpleUnit.new(:unit => :mm)
12
+ @units[:cm] = SimpleUnit.new(:unit => :cm, :based_on => @units[:mm], :coefficient => 10)
13
+ @units[:m] = SimpleUnit.new(:unit => :m, :based_on => @units[:cm], :coefficient => 100)
14
+
15
+ @units[:g] = SimpleUnit.new(:unit => :g)
16
+ @units[:kg] = SimpleUnit.new(:unit => :kg, :based_on => @units[:g], :coefficient => 1000.0)
17
+ @units[:oz] = SimpleUnit.new(:unit => :oz, :based_on => @units[:g], :coefficient => 28.349523125)
18
+ @units[:lb] = SimpleUnit.new(:unit => :lb, :based_on => @units[:oz], :coefficient => 16)
19
+ @units[:mg] = SimpleUnit.new(:unit => :mg, :based_on => @units[:g], :coefficient => 0.001)
20
+
21
+ @units[:sec] = SimpleUnit.new(:unit => :sec)
22
+
23
+ @calc = Calculator.new(@units)
24
+
25
+ end
26
+
27
+
28
+ def test_quantity_creation
29
+ qty = @calc.quantity(45.897, :mm)
30
+
31
+ assert_in_delta(45.897, qty.value, 0.0001)
32
+ assert_equal([:mm], qty[:dividends])
33
+ assert_equal([], qty[:divisors])
34
+
35
+
36
+ qty = @calc.quantity(57.345, "mm/lb")
37
+ assert_in_delta(57.345, qty.value, 0.0001)
38
+ assert_equal([:mm], qty[:dividends])
39
+ assert_equal([:lb], qty[:divisors])
40
+ end
41
+
42
+ def test_calculator_expression_method
43
+ qty = @calc.exp {5.lb}
44
+ assert(qty.kind_of?(Quantity))
45
+
46
+ qty = @calc.exp {12.mm + 34.7.cm}
47
+ assert(qty.kind_of?(Quantity))
48
+
49
+ qty = @calc.quantity(45, :cm)
50
+ assert_equal(qty, @calc.exp(:cm) {qty})
51
+ end
52
+
53
+ def test_convert_to
54
+
55
+ qty = @calc.quantity(45, :cm)
56
+
57
+ base = @calc.exp(1.mm) {qty}
58
+
59
+ assert_in_delta(450.0, base.value, 0.0001)
60
+ assert_equal([:mm], base[:dividends])
61
+
62
+ base = @calc.exp(:mm) {qty}
63
+
64
+ assert_in_delta(450.0, base.value, 0.0001)
65
+ assert_equal([:mm], base[:dividends])
66
+
67
+ base = @calc.exp("mm") {qty}
68
+
69
+ assert_in_delta(450.0, base.value, 0.0001)
70
+ assert_equal([:mm], base[:dividends])
71
+ end
72
+
73
+ def test_complex_conver_to
74
+ @calc.add_unit :unit => :km, :based_on => :m, :coefficient => 1000
75
+ @calc.add_unit :unit => :in, :based_on => :cm, :coefficient => 2.54
76
+ @calc.add_unit :unit => :ft, :based_on => :in, :coefficient => 12
77
+ @calc.add_unit :unit => :yd, :based_on => :ft, :coefficient => 3
78
+ @calc.add_unit :unit => :mi, :based_on => :yd, :coefficient => 1760
79
+ @calc.add_unit :unit => :min, :based_on => :sec, :coefficient => 60
80
+ @calc.add_unit :unit => :hour, :based_on => :min, :coefficient => 60
81
+
82
+ qty = @calc.exp(1.km/1.hour) {70.mi / 1.hour}
83
+ assert_in_delta(112.654, qty.value, 0.0001)
84
+ end
85
+
86
+ def test_reverse_unit_conversion
87
+ @calc.add_unit :unit => :km, :based_on => :m, :coefficient => 1000
88
+ @calc.add_unit :unit => :L
89
+ @calc.add_unit :unit => :gal, :based_on => :L, :coefficient => 3.785332
90
+ @calc.add_unit :unit => :in, :based_on => :cm, :coefficient => 2.54
91
+ @calc.add_unit :unit => :ft, :based_on => :in, :coefficient => 12
92
+ @calc.add_unit :unit => :yd, :based_on => :ft, :coefficient => 3
93
+ @calc.add_unit :unit => :mi, :based_on => :yd, :coefficient => 1760
94
+
95
+ qty = @calc.exp(1.mi/1.gal) {5.5.L/100.km}
96
+ assert_in_delta(42.765, qty.value, 0.001)
97
+
98
+ end
99
+
100
+ def test_simple_same_base_add
101
+
102
+ qty = @calc.exp(:cm){2.m + 17.8.cm}
103
+
104
+ assert_in_delta(217.8, qty.value, 0.0001)
105
+ assert_equal([:cm], qty[:dividends])
106
+
107
+ assert_raise(RuntimeError) {
108
+ @calc.exp(:cm){2.m + 17.8}
109
+ }
110
+ end
111
+
112
+ def test_simple_same_base_subtract
113
+ qty = @calc.exp(:cm){2.m - 20.cm}
114
+
115
+ assert_in_delta(180, qty.value, 0.0001)
116
+ assert_equal([:cm], qty[:dividends])
117
+
118
+ assert_raise(RuntimeError) {
119
+ @calc.exp(:cm){2.m - 5.7}
120
+ }
121
+ end
122
+
123
+ def test_simple_multiply
124
+ qty = @calc.exp(1.cm * 1.oz) {10.m * 5.lb}
125
+
126
+ assert_in_delta(80000, qty.value, 0.0001)
127
+ assert_equal([:cm, :oz], qty[:dividends])
128
+
129
+ qty = @calc.exp(:m) {10.m * 5}
130
+
131
+ assert_in_delta(50, qty.value, 0.0001)
132
+ assert_equal([:m], qty[:dividends])
133
+ end
134
+
135
+ def test_simple_divide
136
+ qty = @calc.exp(1.cm / 1.oz) {10.m / 5.lb}
137
+
138
+ assert_in_delta(12.5, qty.value, 0.0001)
139
+ assert_equal([:cm], qty[:dividends])
140
+ assert_equal([:oz], qty[:divisors])
141
+
142
+ qty = @calc.exp(:m) {10.m / 5}
143
+
144
+ assert_in_delta(2, qty.value, 0.0001)
145
+ assert_equal([:m], qty[:dividends])
146
+
147
+ qty = @calc.exp {25.6.lb / 0}
148
+ assert_in_delta(0, qty.value, 0.0001)
149
+ assert_equal([:g], qty[:dividends])
150
+ end
151
+
152
+ def test_string_unit_spec
153
+ qty = @calc.exp("cm/oz") {10.m / 5.lb}
154
+
155
+ assert_in_delta(12.5, qty.value, 0.0001)
156
+ assert_equal([:cm], qty[:dividends])
157
+ assert_equal([:oz], qty[:divisors])
158
+
159
+ end
160
+
161
+ def test_different_calculation_approaches
162
+ qty = @calc.exp(:m) {25.cm + 15.8.mm + 10.m}
163
+
164
+ result = @calc.exp(:m){ 35.cm + qty }
165
+ assert_in_delta(10.6158, result.value, 0.001)
166
+
167
+ assert_in_delta(1076.58, (15.cm + result)[:value], 0.001)
168
+ end
169
+
170
+ def test_add_unit
171
+ assert_nothing_raised(RuntimeError) {
172
+ @calc.add_unit({:unit=> :V})
173
+ qty = @calc.quantity(15, :V)
174
+ assert_equal("V", qty[:string])
175
+ @calc.add_unit({:unit => :mV, :based_on => :V, :coefficient => 0.001})
176
+
177
+ qty = @calc.quantity(15, :mV)
178
+ assert_equal("mV", qty[:string])
179
+ assert_equal([:V], qty.unit.h_base[:dividends])
180
+ }
181
+
182
+ assert_raise(RuntimeError) {
183
+ @calc.add_unit :unit => :mW, :based_on => :W, :coefficient => 0.001
184
+ }
185
+
186
+ end
187
+
188
+ def test_add_existing_unit
189
+ assert_raise(RuntimeError) {
190
+ @calc.add_unit :unit => :cm, :based_on => :mm, :coefficient => 10
191
+ }
192
+ end
193
+
194
+ end