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 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