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
|