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 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.2"
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"]
@@ -4,5 +4,5 @@ require 'dimensional/unit'
4
4
  require 'dimensional/measure'
5
5
 
6
6
  module Dimensional
7
- VERSION = "0.0.2"
7
+ VERSION = "0.0.3"
8
8
  end
@@ -39,7 +39,6 @@ module Dimensional
39
39
  if block
40
40
  self.class.new(new_context).instance_eval &block
41
41
  else
42
- @context = new_context
43
42
  self # Allow chaining
44
43
  end
45
44
  end
@@ -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
@@ -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.sort{|a,b| (@units.has_key?(b) ? 1 : 0) <=> (@units.has_key?(a) ? 1 : 0)}
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
@@ -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')
@@ -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']
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dimensional
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Hapgood