dimensional 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/lib/dimensional.rb +1 -1
- data/lib/dimensional/configurator.rb +0 -1
- data/lib/dimensional/measure.rb +23 -0
- data/lib/dimensional/metric.rb +7 -2
- data/test/configurator_test.rb +15 -0
- data/test/measure_test.rb +41 -0
- metadata +1 -1
data/Rakefile
CHANGED
@@ -16,7 +16,7 @@ Rake::Task['test'].comment = "Run all tests in test/*_test.rb"
|
|
16
16
|
spec = Gem::Specification.new do |s|
|
17
17
|
s.platform = Gem::Platform::RUBY
|
18
18
|
s.name = %q{dimensional}
|
19
|
-
s.version = "0.0.
|
19
|
+
s.version = "0.0.3"
|
20
20
|
s.required_ruby_version = '>= 1.6.8'
|
21
21
|
s.date = %q{2009-10-09}
|
22
22
|
s.authors = ["Chris Hapgood"]
|
data/lib/dimensional.rb
CHANGED
data/lib/dimensional/measure.rb
CHANGED
@@ -50,6 +50,29 @@ module Dimensional
|
|
50
50
|
new_value = self * unit.convert(new_unit)
|
51
51
|
self.class.new(new_value, new_unit, metric)
|
52
52
|
end
|
53
|
+
|
54
|
+
# Convert this measure to the most appropriate unit in the given system
|
55
|
+
# A heuristic approach is used that considers the resulting measure's order-of-magnitude (similar
|
56
|
+
# is good) and membership in the preferred units of the measure's metric (membership is good).
|
57
|
+
def change_system(system, fallback = false)
|
58
|
+
system = System[system] unless system.kind_of?(System)
|
59
|
+
units = metric.units.select{|u| system == u.system}
|
60
|
+
if units.empty?
|
61
|
+
if fallback
|
62
|
+
units = metric.units
|
63
|
+
else
|
64
|
+
raise "No suitable units available in #{system}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
target_oom = Math.log10(self.unit.factor)
|
68
|
+
units = units.sort_by do |u|
|
69
|
+
oom_delta = (Math.log10(u.factor) - target_oom).abs # == Math.log10(self.unit.factor / u.factor)
|
70
|
+
magnitude_fit = Math.exp(-0.20 * oom_delta) # decay function
|
71
|
+
0.75 * magnitude_fit + 0.25 * metric.preference(u)
|
72
|
+
end
|
73
|
+
u = units.last
|
74
|
+
convert(u)
|
75
|
+
end
|
53
76
|
|
54
77
|
# Return a new dimensional value expressed in the base unit
|
55
78
|
# DEPRECATE: this method has dubious semantics for composed units as there may be no defined unit with
|
data/lib/dimensional/metric.rb
CHANGED
@@ -37,16 +37,21 @@ module Dimensional
|
|
37
37
|
raise "Unit #{unit} is not compatible with dimension #{dimension || '<nil>'}." unless unit.dimension == dimension
|
38
38
|
@units[unit] = options
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
def units
|
42
42
|
baseline = parent ? parent.units : @units.keys
|
43
|
-
baseline.
|
43
|
+
baseline.sort_by{|u| 1.0 - preference(u)}
|
44
44
|
end
|
45
45
|
|
46
46
|
def preferences(u)
|
47
47
|
baseline = parent ? parent.preferences(u) : {}
|
48
48
|
baseline.merge(@units[u])
|
49
49
|
end
|
50
|
+
|
51
|
+
# How "preferred" is the given unit for this metric?
|
52
|
+
def preference(u)
|
53
|
+
@units.has_key?(u) ? 1 : 0
|
54
|
+
end
|
50
55
|
|
51
56
|
def each
|
52
57
|
units.each
|
data/test/configurator_test.rb
CHANGED
@@ -59,6 +59,21 @@ class ConfiguratorTest < Test::Unit::TestCase
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
+
def test_preserve_context_within_block
|
63
|
+
test_context = self
|
64
|
+
Dimensional::Configurator.start do
|
65
|
+
dimension(:L) do
|
66
|
+
system(:SI) do
|
67
|
+
base('meter') do
|
68
|
+
test_context.assert uc = context.unit
|
69
|
+
derive('centimeter', 1e-2)
|
70
|
+
test_context.assert_same uc, context.unit
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
62
77
|
def test_build_base_unit
|
63
78
|
Configurator.start(:system => System::SI, :dimension => Dimension::L) do
|
64
79
|
base('meter', :detector => /\A(meters?|m)\Z/, :abbreviation => 'm')
|
data/test/measure_test.rb
CHANGED
@@ -112,6 +112,47 @@ class MeasureTest < Test::Unit::TestCase
|
|
112
112
|
new_value = old_value.convert(new_unit)
|
113
113
|
assert_equal old_value, new_value
|
114
114
|
end
|
115
|
+
|
116
|
+
# These system-conversion tests rely on very specific constants in the heuristics of #change_system
|
117
|
+
def test_change_system_yd
|
118
|
+
u0 = Unit[:L, :US, 'yd']
|
119
|
+
m0 = Measure.new(1, u0, :length_over_all)
|
120
|
+
u1 = Unit[:L, :SI, 'm']
|
121
|
+
assert m1 = m0.change_system(:SI)
|
122
|
+
assert_same u1, m1.unit
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_change_system_with_metric_override
|
126
|
+
u0 = Unit[:L, :US, 'in']
|
127
|
+
m0 = Measure.new(1, u0, :length_over_all)
|
128
|
+
u1 = Unit[:L, :SI, 'm']
|
129
|
+
assert m1 = m0.change_system(:SI)
|
130
|
+
assert_same u1, m1.unit
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_change_system_with_oom_dominance
|
134
|
+
u0 = Unit[:L, :US, 'in']
|
135
|
+
m0 = Measure.new(1, u0, :L)
|
136
|
+
u1 = Unit[:L, :SI, 'cm']
|
137
|
+
assert m1 = m0.change_system(:SI)
|
138
|
+
assert_same u1, m1.unit
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_change_system_ft
|
142
|
+
u0 = Unit[:L, :US, 'ft']
|
143
|
+
m0 = Measure.new(1, u0, :length_over_all)
|
144
|
+
u1 = Unit[:L, :SI, 'm']
|
145
|
+
assert m1 = m0.change_system(:SI)
|
146
|
+
assert_same u1, m1.unit
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_change_system_mile
|
150
|
+
u0 = Unit[:L, :US, 'mile']
|
151
|
+
m0 = Measure.new(1, u0, :length_over_all)
|
152
|
+
u1 = Unit[:L, :SI, 'km']
|
153
|
+
assert m1 = m0.change_system(:SI)
|
154
|
+
assert_same u1, m1.unit
|
155
|
+
end
|
115
156
|
|
116
157
|
def test_return_base
|
117
158
|
u = Unit[:L, :BA, 'fathom']
|