dimensional 0.0.2 → 0.0.3
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/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']
|