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.
- data/doc/classes/Array.html +159 -0
- data/doc/classes/Array.src/M000001.html +21 -0
- data/doc/classes/Array.src/M000002.html +19 -0
- data/doc/classes/Array.src/M000040.html +21 -0
- data/doc/classes/Array.src/M000041.html +19 -0
- data/doc/classes/CalculatorTest.html +332 -0
- data/doc/classes/CalculatorTest.src/M000022.html +33 -0
- data/doc/classes/CalculatorTest.src/M000023.html +28 -0
- data/doc/classes/CalculatorTest.src/M000024.html +25 -0
- data/doc/classes/CalculatorTest.src/M000025.html +34 -0
- data/doc/classes/CalculatorTest.src/M000026.html +27 -0
- data/doc/classes/CalculatorTest.src/M000027.html +28 -0
- data/doc/classes/CalculatorTest.src/M000028.html +26 -0
- data/doc/classes/CalculatorTest.src/M000029.html +25 -0
- data/doc/classes/CalculatorTest.src/M000030.html +26 -0
- data/doc/classes/CalculatorTest.src/M000031.html +31 -0
- data/doc/classes/CalculatorTest.src/M000032.html +23 -0
- data/doc/classes/CalculatorTest.src/M000033.html +23 -0
- data/doc/classes/CalculatorTest.src/M000034.html +32 -0
- data/doc/classes/CalculatorTest.src/M000035.html +20 -0
- data/doc/classes/CompasedUnitTest.html +279 -0
- data/doc/classes/CompasedUnitTest.src/M000001.html +32 -0
- data/doc/classes/CompasedUnitTest.src/M000002.html +31 -0
- data/doc/classes/CompasedUnitTest.src/M000003.html +28 -0
- data/doc/classes/CompasedUnitTest.src/M000004.html +28 -0
- data/doc/classes/CompasedUnitTest.src/M000005.html +31 -0
- data/doc/classes/CompasedUnitTest.src/M000006.html +23 -0
- data/doc/classes/CompasedUnitTest.src/M000007.html +30 -0
- data/doc/classes/CompasedUnitTest.src/M000008.html +24 -0
- data/doc/classes/CompasedUnitTest.src/M000009.html +27 -0
- data/doc/classes/CompasedUnitTest.src/M000010.html +24 -0
- data/doc/classes/Configuration.html +184 -0
- data/doc/classes/Configuration.src/M000003.html +19 -0
- data/doc/classes/Configuration.src/M000004.html +18 -0
- data/doc/classes/Configuration.src/M000005.html +18 -0
- data/doc/classes/Configuration.src/M000006.html +24 -0
- data/doc/classes/Configuration.src/M000042.html +19 -0
- data/doc/classes/Configuration.src/M000043.html +18 -0
- data/doc/classes/Configuration.src/M000044.html +18 -0
- data/doc/classes/Configuration.src/M000045.html +24 -0
- data/doc/classes/ConfigurationTest.html +182 -0
- data/doc/classes/ConfigurationTest.src/M000065.html +31 -0
- data/doc/classes/ConfigurationTest.src/M000066.html +27 -0
- data/doc/classes/ConfigurationTest.src/M000067.html +35 -0
- data/doc/classes/ConfigurationTest.src/M000068.html +24 -0
- data/doc/classes/CustomUnitConversionTest.html +212 -0
- data/doc/classes/CustomUnitConversionTest.src/M000052.html +31 -0
- data/doc/classes/CustomUnitConversionTest.src/M000053.html +25 -0
- data/doc/classes/CustomUnitConversionTest.src/M000054.html +20 -0
- data/doc/classes/CustomUnitConversionTest.src/M000055.html +26 -0
- data/doc/classes/CustomUnitConversionTest.src/M000056.html +26 -0
- data/doc/classes/CustomUnitConversionTest.src/M000057.html +24 -0
- data/doc/classes/Numeric.html +125 -0
- data/doc/classes/QuantifiableTest.html +189 -0
- data/doc/classes/QuantifiableTest.src/M000036.html +24 -0
- data/doc/classes/QuantifiableTest.src/M000037.html +26 -0
- data/doc/classes/QuantifiableTest.src/M000038.html +41 -0
- data/doc/classes/QuantifiableTest.src/M000039.html +23 -0
- data/doc/classes/Quantity/Calculable.html +213 -0
- data/doc/classes/Quantity/Calculable.src/M000010.html +18 -0
- data/doc/classes/Quantity/Calculable.src/M000011.html +18 -0
- data/doc/classes/Quantity/Calculable.src/M000012.html +18 -0
- data/doc/classes/Quantity/Calculable.src/M000013.html +18 -0
- data/doc/classes/Quantity/Calculable.src/M000014.html +21 -0
- data/doc/classes/Quantity/Calculable.src/M000015.html +18 -0
- data/doc/classes/Quantity/Calculable.src/M000072.html +18 -0
- data/doc/classes/Quantity/Calculable.src/M000073.html +18 -0
- data/doc/classes/Quantity/Calculable.src/M000074.html +18 -0
- data/doc/classes/Quantity/Calculable.src/M000075.html +18 -0
- data/doc/classes/Quantity/Calculable.src/M000076.html +21 -0
- data/doc/classes/Quantity/Calculable.src/M000077.html +18 -0
- data/doc/classes/Quantity/Calculator.html +240 -0
- data/doc/classes/Quantity/Calculator.src/M000021.html +20 -0
- data/doc/classes/Quantity/Calculator.src/M000022.html +18 -0
- data/doc/classes/Quantity/Calculator.src/M000023.html +26 -0
- data/doc/classes/Quantity/Calculator.src/M000024.html +23 -0
- data/doc/classes/Quantity/Calculator.src/M000025.html +31 -0
- data/doc/classes/Quantity/Calculator.src/M000026.html +25 -0
- data/doc/classes/Quantity/Calculator.src/M000083.html +20 -0
- data/doc/classes/Quantity/Calculator.src/M000084.html +18 -0
- data/doc/classes/Quantity/Calculator.src/M000085.html +26 -0
- data/doc/classes/Quantity/Calculator.src/M000086.html +23 -0
- data/doc/classes/Quantity/Calculator.src/M000087.html +31 -0
- data/doc/classes/Quantity/Calculator.src/M000088.html +25 -0
- data/doc/classes/Quantity/Measurable.html +153 -0
- data/doc/classes/Quantity/Measurable.src/M000008.html +18 -0
- data/doc/classes/Quantity/Measurable.src/M000009.html +18 -0
- data/doc/classes/Quantity/Measurable.src/M000070.html +18 -0
- data/doc/classes/Quantity/Measurable.src/M000071.html +18 -0
- data/doc/classes/Quantity/OperationInfo.html +184 -0
- data/doc/classes/Quantity/OperationInfo.src/M000027.html +24 -0
- data/doc/classes/Quantity/OperationInfo.src/M000028.html +21 -0
- data/doc/classes/Quantity/OperationInfo.src/M000089.html +24 -0
- data/doc/classes/Quantity/OperationInfo.src/M000090.html +21 -0
- data/doc/classes/Quantity/Quantifiable.html +131 -0
- data/doc/classes/Quantity/Quantifiable.src/M000007.html +18 -0
- data/doc/classes/Quantity/Quantifiable.src/M000069.html +18 -0
- data/doc/classes/Quantity/Quantity.html +211 -0
- data/doc/classes/Quantity/Quantity.src/M000016.html +20 -0
- data/doc/classes/Quantity/Quantity.src/M000017.html +20 -0
- data/doc/classes/Quantity/Quantity.src/M000018.html +20 -0
- data/doc/classes/Quantity/Quantity.src/M000078.html +20 -0
- data/doc/classes/Quantity/Quantity.src/M000079.html +20 -0
- data/doc/classes/Quantity/Quantity.src/M000080.html +20 -0
- data/doc/classes/Quantity/QuantityInfo.html +179 -0
- data/doc/classes/Quantity/QuantityInfo.src/M000019.html +19 -0
- data/doc/classes/Quantity/QuantityInfo.src/M000020.html +18 -0
- data/doc/classes/Quantity/QuantityInfo.src/M000081.html +19 -0
- data/doc/classes/Quantity/QuantityInfo.src/M000082.html +18 -0
- data/doc/classes/Quantity.html +121 -0
- data/doc/classes/QuantityTest.html +220 -0
- data/doc/classes/QuantityTest.src/M000046.html +32 -0
- data/doc/classes/QuantityTest.src/M000047.html +33 -0
- data/doc/classes/QuantityTest.src/M000048.html +27 -0
- data/doc/classes/QuantityTest.src/M000049.html +20 -0
- data/doc/classes/QuantityTest.src/M000050.html +22 -0
- data/doc/classes/QuantityTest.src/M000051.html +20 -0
- data/doc/classes/SimpleUnitTest.html +234 -0
- data/doc/classes/SimpleUnitTest.src/M000058.html +24 -0
- data/doc/classes/SimpleUnitTest.src/M000059.html +25 -0
- data/doc/classes/SimpleUnitTest.src/M000060.html +21 -0
- data/doc/classes/SimpleUnitTest.src/M000061.html +20 -0
- data/doc/classes/SimpleUnitTest.src/M000062.html +26 -0
- data/doc/classes/SimpleUnitTest.src/M000063.html +21 -0
- data/doc/classes/SimpleUnitTest.src/M000064.html +18 -0
- data/doc/classes/SpecParserTest.html +174 -0
- data/doc/classes/SpecParserTest.src/M000019.html +25 -0
- data/doc/classes/SpecParserTest.src/M000020.html +32 -0
- data/doc/classes/SpecParserTest.src/M000021.html +31 -0
- data/doc/classes/Test.html +101 -0
- data/doc/classes/Unit/Comparable.html +156 -0
- data/doc/classes/Unit/Comparable.src/M000030.html +22 -0
- data/doc/classes/Unit/Comparable.src/M000031.html +22 -0
- data/doc/classes/Unit/Comparable.src/M000092.html +22 -0
- data/doc/classes/Unit/Comparable.src/M000093.html +22 -0
- data/doc/classes/Unit/ComposedUnit.html +301 -0
- data/doc/classes/Unit/ComposedUnit.src/M000044.html +22 -0
- data/doc/classes/Unit/ComposedUnit.src/M000045.html +25 -0
- data/doc/classes/Unit/ComposedUnit.src/M000046.html +25 -0
- data/doc/classes/Unit/ComposedUnit.src/M000047.html +22 -0
- data/doc/classes/Unit/ComposedUnit.src/M000048.html +29 -0
- data/doc/classes/Unit/ComposedUnit.src/M000049.html +24 -0
- data/doc/classes/Unit/ComposedUnit.src/M000050.html +25 -0
- data/doc/classes/Unit/ComposedUnit.src/M000051.html +18 -0
- data/doc/classes/Unit/ComposedUnit.src/M000107.html +22 -0
- data/doc/classes/Unit/ComposedUnit.src/M000108.html +25 -0
- data/doc/classes/Unit/ComposedUnit.src/M000109.html +25 -0
- data/doc/classes/Unit/ComposedUnit.src/M000110.html +22 -0
- data/doc/classes/Unit/ComposedUnit.src/M000111.html +29 -0
- data/doc/classes/Unit/ComposedUnit.src/M000112.html +24 -0
- data/doc/classes/Unit/ComposedUnit.src/M000113.html +25 -0
- data/doc/classes/Unit/ComposedUnit.src/M000114.html +18 -0
- data/doc/classes/Unit/Optimizer.html +152 -0
- data/doc/classes/Unit/Optimizer.src/M000042.html +44 -0
- data/doc/classes/Unit/Optimizer.src/M000043.html +18 -0
- data/doc/classes/Unit/Optimizer.src/M000105.html +44 -0
- data/doc/classes/Unit/Optimizer.src/M000106.html +18 -0
- data/doc/classes/Unit/Parser.html +176 -0
- data/doc/classes/Unit/Parser.src/M000039.html +18 -0
- data/doc/classes/Unit/Parser.src/M000040.html +25 -0
- data/doc/classes/Unit/Parser.src/M000041.html +19 -0
- data/doc/classes/Unit/Parser.src/M000102.html +18 -0
- data/doc/classes/Unit/Parser.src/M000103.html +25 -0
- data/doc/classes/Unit/Parser.src/M000104.html +19 -0
- data/doc/classes/Unit/SimpleUnit.html +287 -0
- data/doc/classes/Unit/SimpleUnit.src/M000032.html +20 -0
- data/doc/classes/Unit/SimpleUnit.src/M000033.html +20 -0
- data/doc/classes/Unit/SimpleUnit.src/M000034.html +20 -0
- data/doc/classes/Unit/SimpleUnit.src/M000035.html +20 -0
- data/doc/classes/Unit/SimpleUnit.src/M000036.html +18 -0
- data/doc/classes/Unit/SimpleUnit.src/M000037.html +21 -0
- data/doc/classes/Unit/SimpleUnit.src/M000038.html +18 -0
- data/doc/classes/Unit/SimpleUnit.src/M000094.html +20 -0
- data/doc/classes/Unit/SimpleUnit.src/M000095.html +20 -0
- data/doc/classes/Unit/SimpleUnit.src/M000096.html +20 -0
- data/doc/classes/Unit/SimpleUnit.src/M000097.html +20 -0
- data/doc/classes/Unit/SimpleUnit.src/M000098.html +18 -0
- data/doc/classes/Unit/SimpleUnit.src/M000099.html +21 -0
- data/doc/classes/Unit/SimpleUnit.src/M000100.html +18 -0
- data/doc/classes/Unit/SymbolConverter.html +131 -0
- data/doc/classes/Unit/SymbolConverter.src/M000029.html +24 -0
- data/doc/classes/Unit/SymbolConverter.src/M000091.html +24 -0
- data/doc/classes/Unit/TestCase.html +146 -0
- data/doc/classes/Unit/TestCase.src/M000101.html +24 -0
- data/doc/classes/Unit.html +120 -0
- data/doc/classes/UnitOptemizerTest.html +249 -0
- data/doc/classes/UnitOptemizerTest.src/M000011.html +31 -0
- data/doc/classes/UnitOptemizerTest.src/M000012.html +25 -0
- data/doc/classes/UnitOptemizerTest.src/M000013.html +27 -0
- data/doc/classes/UnitOptemizerTest.src/M000014.html +27 -0
- data/doc/classes/UnitOptemizerTest.src/M000015.html +27 -0
- data/doc/classes/UnitOptemizerTest.src/M000016.html +26 -0
- data/doc/classes/UnitOptemizerTest.src/M000017.html +23 -0
- data/doc/classes/UnitOptemizerTest.src/M000018.html +22 -0
- data/doc/created.rid +1 -0
- data/doc/files/config/default_configuration_rb.html +108 -0
- data/doc/files/quantity_rb.html +113 -0
- data/doc/files/test/all_tests_rb.html +108 -0
- data/doc/files/test/test_helper_rb.html +110 -0
- data/doc/files/test/unit/calculator_test_rb.html +109 -0
- data/doc/files/test/unit/composed_unit_test_rb.html +101 -0
- data/doc/files/test/unit/configuration_test_rb.html +109 -0
- data/doc/files/test/unit/custom_conversion_test_rb.html +109 -0
- data/doc/files/test/unit/quantifiable_test_rb.html +101 -0
- data/doc/files/test/unit/quantity_test_rb.html +101 -0
- data/doc/files/test/unit/simple_unit_test_rb.html +101 -0
- data/doc/files/test/unit/unit_optimizer_test_rb.html +101 -0
- data/doc/files/test/unit/unit_spec_parser_test_rb.html +101 -0
- data/doc/files/unitmanager/calculator_rb.html +101 -0
- data/doc/files/unitmanager/configuration_rb.html +101 -0
- data/doc/files/unitmanager/quantity_rb.html +101 -0
- data/doc/files/unitmanager/simple_unit_rb.html +108 -0
- data/doc/files/unitmanager/unit_composition_rb.html +101 -0
- data/doc/fr_class_index.html +44 -0
- data/doc/fr_file_index.html +33 -0
- data/doc/fr_method_index.html +77 -0
- data/doc/index.html +24 -0
- data/lib/config/default_configuration.rb +115 -0
- data/lib/quantity.rb +34 -0
- data/lib/unitmanager/calculator.rb +195 -0
- data/lib/unitmanager/configuration.rb +26 -0
- data/lib/unitmanager/quantity.rb +167 -0
- data/lib/unitmanager/simple_unit.rb +155 -0
- data/lib/unitmanager/unit_composition.rb +217 -0
- data/test/all_tests.rb +8 -0
- data/test/calculator_test.rb +194 -0
- data/test/composed_unit_test.rb +169 -0
- data/test/configuration_test.rb +70 -0
- data/test/custom_conversion_test.rb +90 -0
- data/test/quantifiable_test.rb +73 -0
- data/test/quantity_test.rb +79 -0
- data/test/simple_unit_test.rb +59 -0
- data/test/test_helper.rb +18 -0
- data/test/unit_optimizer_test.rb +104 -0
- data/test/unit_spec_parser_test.rb +50 -0
- 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,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
|