eymiha_units 0.1.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.
@@ -0,0 +1,229 @@
1
+ require 'eymiha'
2
+
3
+ require 'forward_referencing'
4
+
5
+ require 'units/units_measure'
6
+ require 'units/units_exception'
7
+ require 'units/numeric'
8
+ require 'units/numeric_with_units'
9
+ require 'units/units_hash'
10
+ require 'units/object'
11
+
12
+ # The Units framework
13
+ #
14
+ # Units is the top level that you'll typically never have to deal with
15
+ # directly. While it provides a few chunks of general functionality such
16
+ # as getting defined units and ranking, most of its guts are devoted to
17
+ # defining new UnitsMeasures - unless you're setting up your own sets of
18
+ # specialized units, you will hardly know it's here.
19
+ class Units
20
+
21
+ @@debug = false
22
+
23
+ def self.debug=(value)
24
+ @@debug = value
25
+ end
26
+
27
+ extend ForwardReferencing
28
+ start_forward_referencing
29
+
30
+ @@measures = {}
31
+ @@units = {}
32
+ @@defining = nil
33
+ @@holding = nil
34
+
35
+ # Returns an Array of the defined UnitsMeasures.
36
+ def Units.units_measures
37
+ @@measures.keys
38
+ end
39
+
40
+ # Creates or extends a UnitsMeasure.
41
+ def Units.create(name, &block)
42
+ measure = (@@measures[name.to_s] ||= UnitsMeasure.new)
43
+ block.call measure if block_given?
44
+ measure
45
+ end
46
+
47
+ # Creates or extends a UnitsMeasure derived from other UnitsMeasures.
48
+ def Units.derive(name, target, &block)
49
+ measure = ( @@measures[name.to_s] =
50
+ if target.kind_of? UnitsMeasure
51
+ if target.derived && (derived = find_by_derivation target.derived)
52
+ derived
53
+ else
54
+ target
55
+ end
56
+ else
57
+ Units.create(target.to_s)
58
+ end )
59
+ block.call measure if block_given?
60
+ measure
61
+ end
62
+
63
+ # Returns the UnitsMeasure with the given derivation.
64
+ def Units.find_by_derivation(derivation)
65
+ matches = @@measures.values.uniq.select { |measure|
66
+ if measure.derived
67
+ measure == derivation
68
+ elsif derivation.size == 1
69
+ a = derivation.to_a[0]
70
+ a[0] == measure and a[1] == 1
71
+ else
72
+ false
73
+ end
74
+ }
75
+ case matches.size
76
+ when 0 then nil
77
+ when 1 then matches[0]
78
+ else raise UnitsException.new(
79
+ "Multiple UnitsMeasures with same derivation found")
80
+ end
81
+ end
82
+
83
+ # Removes the named UnitsMeasure from the Units framework.
84
+ def Units.delete(name)
85
+ @@measures.delete name.to_s
86
+ end
87
+
88
+ # Clears the Units framework of all defined elements.
89
+ def Units.clear
90
+ @@measures.clear
91
+ @@units.clear
92
+ forward_references_clear
93
+ self
94
+ end
95
+
96
+ # Returns the number of defined UnitsMeasures.
97
+ def Units.size
98
+ @@measures.size
99
+ end
100
+
101
+ # Returns the named UnitsMeasure.
102
+ def Units.[](name)
103
+ @@measures[name.to_s]
104
+ end
105
+
106
+ def Units.method_missing(method,*args) # :nodoc:
107
+ measure = self[method]
108
+ raise UnitsException.new("UnitsMeasure '#{method}' undefined") if !measure
109
+ measure
110
+ end
111
+
112
+ # Returns an Array containing the names of a given UnitsMeasure.
113
+ def Units.names_of(units_measure)
114
+ @@measures.keys.select { |name| @@measures[name].equal? units_measure }
115
+ end
116
+
117
+ def Units.add_unit(unit,unit_identifier=nil) # :nodoc:
118
+ if unit_identifier
119
+ if (element = @@units[unit_identifier])
120
+ @@units[unit_identifier] += [ unit ] unless element.index(unit)
121
+ else
122
+ @@units[unit_identifier] = [ unit ]
123
+ end
124
+ else
125
+ add_unit unit, unit.name
126
+ add_unit unit, unit.plural
127
+ unit.abbrevs.each { |abbrev| add_unit unit, abbrev }
128
+ end
129
+ end
130
+
131
+ # Returns an Array of UnitsUnit associated with a singular, plural or
132
+ # abbreviated name.
133
+ def Units.lookup(unit_identifier)
134
+ @@units[unit_identifier.to_s] || [ ]
135
+ end
136
+
137
+ # Answers the question of whether a UnitsMeasure is being defined with the
138
+ # instance if true, or nil if false.
139
+ def Units.defining?
140
+ @@defining
141
+ end
142
+
143
+ def Units.defining(measure) # :nodoc:
144
+ @@defining = measure
145
+ end
146
+
147
+ def Units.convert(numeric,unit_identifier) # :nodoc:
148
+ puts "Units:convert #{numeric} #{unit_identifier}" if @@debug
149
+ if (candidates = lookup(unit_identifier)).size == 0
150
+ puts @@units.keys.sort.join(" ") if @@debug
151
+ puts " no candidates!" if @@debug
152
+ raise MissingUnitsException.new(unit_identifier.to_s)
153
+ elsif !defining?
154
+ if candidates.size > 1
155
+ raise AmbiguousUnitsException.new(unit_identifier.to_s)
156
+ else
157
+ unit = candidates[0]
158
+ NumericWithUnits.new(numeric,unit)
159
+ end
160
+ else
161
+ if candidates.size == 1
162
+ units = candidates
163
+ else
164
+ units = candidates.select { |candidate|
165
+ @@defining == candidate.units_system.units_measure }
166
+ units = candidates.select { |candidate|
167
+ @@defining.derived[candidate.units_measure] } if units.size == 0
168
+ end
169
+ case units.size
170
+ when 0 then
171
+ raise MissingUnitsException.new(unit_identifier.to_s)
172
+ when 1 then
173
+ unit = units[0]
174
+ if unit.equals.kind_of? Array
175
+ element = unit.equals[0]
176
+ value = NumericWithUnits.
177
+ new(numeric*element.numeric,element.unit)
178
+ else
179
+ value = NumericWithUnits.
180
+ new(numeric*unit.equals.numeric,unit.equals.unit)
181
+ end
182
+ value.original = numeric.unite(unit)
183
+ value
184
+ else
185
+ raise AmbiguousUnitsException.new(unit_identifier.to_s)
186
+ end
187
+ end
188
+ end
189
+
190
+ def Units.make_forward_reference(method,context) # :nodoc:
191
+ @@holding ? nil : create_forward_reference(method,context)
192
+ end
193
+
194
+ def Units.release_forward_reference(reference = nil) # :nodoc:
195
+ remove_forward_reference(reference) if reference != nil
196
+ end
197
+
198
+ def Units.hold_forward_reference(hold = true) # :nodoc:
199
+ @@holding = hold
200
+ end
201
+
202
+ def Units.holding_forward_reference? # :nodoc:
203
+ @@holding
204
+ end
205
+
206
+ def Units.establish_forward_reference_context(context) # :nodoc:
207
+ defining context
208
+ end
209
+
210
+ # Given a Hash of units to raking weights, a set of samples, and
211
+ # optionally a block that returns rankings, returns an Array of units
212
+ # ordered by best weighted fit over the samples. Like golf, low scores
213
+ # rank best. In absence of a block, ranking is based on the number of
214
+ # unit values whose magnitudes are between 1 and 10.
215
+ def Units.rank(unit_choices = {}, samples = [], &numeric_ranker) # :yields: n
216
+ if block_given?
217
+ scores = {}
218
+ samples.each {|s|
219
+ unit_choices.each {|uc,w|
220
+ scores[uc] = (scores[uc] || 0) + w*(yield s.convert(uc).numeric) } }
221
+ scores.sort {|e1,e2| -(e1[1] <=> e2[1])}.collect {|s| s[0]}
222
+ else
223
+ rank(unit_choices,samples) { |n|
224
+ e = ((((n.abs)-5.5).abs-4.5).at_least(0))
225
+ (e == 0) ? 0 : (e == 1)? 0 : -(e + 1/(1-e)) }
226
+ end
227
+ end
228
+
229
+ end
@@ -0,0 +1,14 @@
1
+ # Raised when a general problem has occurred in the Units framework or some
2
+ # other error has occurred during its use.
3
+ class UnitsException < Exception
4
+ end
5
+
6
+
7
+ # Raised when a unit was expected but was not found.
8
+ class MissingUnitsException < UnitsException
9
+ end
10
+
11
+
12
+ # Raised when a unit was expected but more than one was found.
13
+ class AmbiguousUnitsException < UnitsException
14
+ end
@@ -0,0 +1,112 @@
1
+ require "units/units"
2
+
3
+ # The unit part of a NumericWithUnits is a UnitsHash - a Hash from UnitsUnit
4
+ # instances to powers.
5
+ class UnitsHash < Hash
6
+
7
+ @@debug = false
8
+
9
+ def self.debug=(value)
10
+ @@debug = value
11
+ end
12
+
13
+ def initialize(unit = nil,power = 1) # :nodoc
14
+ if unit
15
+ if unit.kind_of? UnitsUnit
16
+ self[unit] = power
17
+ elsif unit.kind_of? UnitsHash
18
+ unit.each { |k,v| self[k] = v*power }
19
+ else
20
+ raise UnitsException.new("invalid unit: #{unit}")
21
+ end
22
+ end
23
+ end
24
+
25
+ # Returns a String reprentation of the instance. If there is only one item in
26
+ # the UnitsHash, whole names are rendered; otherwise abbreviations are used.
27
+ def to_s(numeric = 1,use_abbrevs = false)
28
+ if size == 1 &&
29
+ (su = select {|k,v| v == 1}).size == 1 &&
30
+ !use_abbrevs
31
+ su = su.to_a[0][0]
32
+ ((numeric == 1)? su.name : su.plural).gsub(/_/,' ')
33
+ else
34
+ abbrevs_to_s
35
+ end
36
+ end
37
+
38
+ def abbrevs_to_s # :nodoc:
39
+ p = select {|k,v| v > 0}.sort{|e1,e2| e1[1] <=> e2[1]}.collect {|e|
40
+ "#{e[0].abbrevs[0] || e[0].name}#{(e[1] == 1) ? "" : "^#{e[1]}"}"}
41
+ n = select {|k,v| v < 0}.sort{|e1,e2| e1[1] <=> e2[1]}.collect {|e|
42
+ "#{e[0].abbrevs[0] || e[0].name}#{(e[1] == -1) ? "" : "^#{-e[1]}"}"}
43
+ numerator = (p.size > 0)? p.join(" ") : (n.size > 0)? "1" : ""
44
+ denominator = (n.size > 0)? ((p.size > 0)? " / " : "/")+n.join(" ") : ""
45
+ "#{numerator}#{denominator}"
46
+ end
47
+
48
+ # Raises and returns the instance after each of its exponents has been raised
49
+ # by the given power.
50
+ def power!(power)
51
+ self.each { |k,v| self[k] = v*power }
52
+ end
53
+
54
+ # Returns a new UnitsHash whose value is the instance raised to the given
55
+ # power.
56
+ def **(power)
57
+ clone.power!(power)
58
+ end
59
+
60
+ # Returns a new UnitsHash whose value is the instance's units and powers have
61
+ # been merged with the given value raised to the power.
62
+ def merge(value,power=1)
63
+ clone.merge!(value,power)
64
+ end
65
+
66
+ # Merges and returns the instance after the value raised to the power has
67
+ # been merged into it.
68
+ def merge!(value,power=1)
69
+ value.unit.each { |k,v|
70
+ self[k] = (self[k] || 0) + v*power
71
+ delete k if self[k] == 0
72
+ }
73
+ self
74
+ end
75
+
76
+ alias :* :merge
77
+
78
+ # Returns the UnitsMeasure of the instance if defined.
79
+ def measure
80
+ measure = UnitsMeasure.new
81
+ each { |unit,power|
82
+ measure.merge_derivation unit.units_system.units_measure => power }
83
+ Units.find_by_derivation(measure.derived)
84
+ end
85
+
86
+ # Returns true is any of the instance's components are derived.
87
+ def derived?
88
+ keys.select{|unit| unit.units_system.units_measure.derived != nil}.size > 0
89
+ end
90
+
91
+ # Return a NumericWithUnits that represents the instance when all derived
92
+ # units have been replaced with the units from which they derive.
93
+ def reduce
94
+ puts "UnitsHash:reduce #{to_s}" if @@debug
95
+ factor = 1.0
96
+ new_unit = UnitsHash.new
97
+ each do |unit,power|
98
+ puts " #{unit} #{power}" if @@debug
99
+ factor *= unit.equals.numeric**power
100
+ puts " #{factor}" if @@debug
101
+ new_unit.merge!(unit.equals,power)
102
+ end
103
+ factor.unite new_unit
104
+ end
105
+
106
+ # Return true if the instance is not equal to 1, ie. has at least one non-zero
107
+ # exponent.
108
+ def has_units?
109
+ (self.select {|k,v| v != 0.0}).size > 0
110
+ end
111
+
112
+ end
@@ -0,0 +1,91 @@
1
+ require 'units/units_system'
2
+ require 'methodic_hash'
3
+
4
+ # A UnitsMeasure groups sets of units that measure the same quality.
5
+ class UnitsMeasure < MethodicHash
6
+
7
+ # A Hash of UnitsMeasures to powers that represent the bases for this
8
+ # UnitsMeasure if it is derived.
9
+ attr_reader :derived
10
+ attr_writer :derived # :nodoc:
11
+
12
+ # A Methodic Hash mapping names of formats to procs that implement them.
13
+ attr_reader :formats
14
+
15
+ def initialize # :nodoc:
16
+ @formats = MethodicHash.new
17
+ end
18
+
19
+ # Defines or extends a UnitsSystem. During definition, if forward
20
+ # references between entities may occur and when encountered, are stored.
21
+ # Upon completion of the definition, if any existing unresolved still
22
+ # exist, an attempt is made to resolve them.
23
+ def system(name,&block)
24
+ Units.defining self
25
+ system = (self[name] ||= UnitsSystem.new(self,name))
26
+ block.call system if block_given?
27
+ Units.resolve_forward_references
28
+ Units.defining nil
29
+ system
30
+ end
31
+
32
+ # Returns the names by which this UnitsMeasure is known.
33
+ def names
34
+ Units.names_of self
35
+ end
36
+
37
+ # Returns a new UnitsMeasure equal to the instance raised to the given
38
+ # power. This is typically used to derive UnitsMeasures - for example,
39
+ # if length is a UnitsMeasure, then length**3 could be used as the target
40
+ # to derive volume.
41
+ def **(exponent)
42
+ UnitsMeasure.new.merge_derivation(self => exponent)
43
+ end
44
+
45
+ # Returns a new UnitsMeasure equal to the instance divided by another
46
+ # UnitsMeasure. This is typically used to derive UnitsMeasures - for
47
+ # example, if mass and volume are UnitsMeasures, then mass/volume could be
48
+ # used as the target to derive density.
49
+ def /(divisor)
50
+ UnitsMeasure.new.merge_derivation(self).merge_derivation(divisor,-1)
51
+ end
52
+
53
+ # Returns a new UnitsMeasure equal to the instance multiplied by another
54
+ # UnitsMeasure. This is typically used to derive UnitsMeasures - for
55
+ # example, if length is a UnitsMeasure, then length*length could be
56
+ # used as the target to derive area.
57
+ def *(factor)
58
+ UnitsMeasure.new.merge_derivation(self).merge_derivation(factor)
59
+ end
60
+
61
+ def merge_derivation derivation, multiplier=1 # :nodoc:
62
+ current = (self.derived ||= {})
63
+ if derivation.kind_of? UnitsMeasure
64
+ if derivation.derived
65
+ derivation.derived.each {|key,value|
66
+ current[key] = (current[key] || 0) + multiplier*value }
67
+ else
68
+ current[derivation] = (current[derivation] || 0) + multiplier
69
+ end
70
+ elsif derivation.kind_of? Hash
71
+ derivation.each {|key,value|
72
+ current[key] = ((current[key] || 0 ) + multiplier*value) }
73
+ else
74
+ raise UnitsException.new(
75
+ "Cannot add #{derivation.self_name} to derivation")
76
+ end
77
+ self
78
+ end
79
+
80
+ # Returns a String containing the names of this UnitsMeasure and the
81
+ # namse of the UnitsSystems defined within it.
82
+ def to_s
83
+ "#{self_name} #{names} #{keys}"
84
+ end
85
+
86
+ # Associates the name of a format with an output formatter.
87
+ def format(options)
88
+ @formats[options[:name]] = options[:format]
89
+ end
90
+
91
+ end
@@ -0,0 +1,85 @@
1
+ require 'units/units_unit'
2
+ require 'methodic_hash'
3
+
4
+ # A UnitsSystem groups units that measure the same quality and are
5
+ # conceptually organized together within a UnitsMeasure. Its a MethodicHash
6
+ # of unit names to UnitsUnit instances.
7
+ class UnitsSystem < MethodicHash
8
+
9
+ # The UnitsMeasure to which this instance is associated.
10
+ attr_reader :units_measure
11
+ # The name of this UnitsSystem
12
+ attr_reader :name
13
+
14
+ def initialize(units_measure,name) # :nodoc:
15
+ @units_measure = units_measure
16
+ @name = name
17
+ end
18
+
19
+ # Defines a new UnitsUnit. If ten-based or two-based greeking is defined,
20
+ # it is applied.
21
+ def unit(attributes)
22
+ unit = nil
23
+ if !Units.holding_forward_reference?
24
+ unit = UnitsUnit.new self, attributes
25
+ self[unit.name] = unit
26
+ Units.add_unit unit
27
+ case unit.greek
28
+ when :ten then greek_ten unit
29
+ when :two then greek_two unit
30
+ end
31
+ else
32
+ Units.hold_forward_reference nil
33
+ end
34
+ Units.continue_forward_reference_resolution
35
+ unit
36
+ end
37
+
38
+ # Associates the name of a format with an output formatter in the instance's
39
+ # UnitsMeasure.
40
+ def format(options)
41
+ @units_measure.format(options)
42
+ end
43
+
44
+ def greek_ten(base) # :nodoc:
45
+ greek_unit base, "yocto", "y", 0.000000000000000000000001
46
+ greek_unit base, "zepto", "z", 0.000000000000000000001
47
+ greek_unit base, "atto", "a", 0.000000000000000001
48
+ greek_unit base, "femto", "f", 0.000000000000001
49
+ greek_unit base, "pico", "p", 0.000000000001
50
+ greek_unit base, "nano", "n", 0.000000001
51
+ greek_unit base, "micro", "u", 0.000001
52
+ greek_unit base, "milli", "m", 0.001
53
+ greek_unit base, "centi", "c", 0.01
54
+ greek_unit base, "deci", "d", 0.1
55
+ greek_unit base, "deca", "da", 10.0
56
+ greek_unit base, "hecto", "h", 100.0
57
+ greek_unit base, "kilo", "k", 1000.0
58
+ greek_unit base, "mega", "M", 1000000.0
59
+ greek_unit base, "giga", "G", 1000000000.0
60
+ greek_unit base, "tera", "T", 1000000000000.0
61
+ greek_unit base, "peta", "P", 1000000000000000.0
62
+ greek_unit base, "exa", "E", 1000000000000000000.0
63
+ greek_unit base, "zetta", "Z", 1000000000000000000000.0
64
+ greek_unit base, "yotta", "Y", 1000000000000000000000000.0
65
+ end
66
+
67
+ def greek_two(base) # :nodoc:
68
+ greek_unit base, "kilo", "k", 2**10
69
+ greek_unit base, "mega", "m", 2**20
70
+ greek_unit base, "giga", "g", 2**30
71
+ greek_unit base, "tera", "t", 2**40
72
+ greek_unit base, "peta", "p", 2**50
73
+ greek_unit base, "exa", "e", 2**60
74
+ greek_unit base, "zetta", "z", 2**70
75
+ greek_unit base, "yotta", "y", 2**80
76
+ end
77
+
78
+ def greek_unit(base,prefix,abbrev_prefix,scalar) # :nodoc:
79
+ unit :name => prefix+base.name,
80
+ :plural => prefix+base.plural,
81
+ :abbrevs => base.abbrevs.collect { |abbrev| abbrev_prefix+abbrev },
82
+ :equals => base.equals * scalar
83
+ end
84
+
85
+ end
@@ -0,0 +1,60 @@
1
+ require 'methodic_hash'
2
+
3
+ require 'units/numeric_with_units'
4
+
5
+ # A unit in the context of a particular UnitsSystem. It's a MethodicHash of
6
+ # its named qualities.
7
+ class UnitsUnit < MethodicHash
8
+
9
+ # The UnitsSystem to which this instance is associated.
10
+ attr_reader :units_system
11
+
12
+ def initialize(units_system,attributes) # :nodoc:
13
+ @units_system = units_system
14
+ merge! attributes
15
+ normalize
16
+ end
17
+
18
+ def ==(unit) # :nodoc:
19
+ self.equal? unit
20
+ end
21
+
22
+ def normalize # :nodoc:
23
+ raise UnitsException.new("UnitUnits must have a name attribute") unless
24
+ self.name
25
+ self.name = self.name.to_s
26
+ add_plural
27
+ add_abbrevs
28
+ add_equals
29
+ equals.each { |n| n.promote_original } if equals.kind_of? Array
30
+ self
31
+ end
32
+
33
+ def add_plural # :nodoc:
34
+ self.plural =
35
+ (self.no_plural == true) ? self.name :
36
+ (plural = self.plural) ? plural.to_s : self.name+'s'
37
+ end
38
+
39
+ def add_abbrevs(attribute = nil) # :nodoc:
40
+ if attribute == nil
41
+ self.abbrevs = add_abbrevs(:abbrev)+add_abbrevs(:abbrevs)
42
+ elsif (value = self[attribute])
43
+ self.delete(attribute)
44
+ (value.kind_of? Array) ? value.collect {|e| e.to_s } : [ value.to_s ]
45
+ else
46
+ [ ]
47
+ end
48
+ end
49
+
50
+ def add_equals # :nodoc:
51
+ self.equals = NumericWithUnits.new(1,self) unless self.equals
52
+ end
53
+
54
+ # returns the UnitsMeasure containing the UnitsSystem to which this instance
55
+ # belongs.
56
+ def units_measure
57
+ units_system.units_measure
58
+ end
59
+
60
+ end
data/lib/units.rb ADDED
@@ -0,0 +1,4 @@
1
+ # Adds the Units framework and a set of basic definitions.
2
+ require 'units/units'
3
+ require 'units/definitions/measures'
4
+
data/rakefile.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'gem_package'
2
+ require 'gem_raker'
data/test/framework.rb ADDED
@@ -0,0 +1,7 @@
1
+ module UnitsTest
2
+
3
+ def setup
4
+ Units.clear
5
+ end
6
+
7
+ end
@@ -0,0 +1,49 @@
1
+ require 'test/unit'
2
+
3
+ require 'units'
4
+
5
+ class TC_definitions < Test::Unit::TestCase
6
+
7
+ def test_definitions
8
+
9
+ assert(Units.forward_references.size == 0) # all the definitions loaded
10
+
11
+ t = 5.years
12
+ assert(t.to_s == "5 years")
13
+ assert(t.in_months.to_s == "60 months")
14
+ assert(t.in_months.in_days.to_s == "1800 days")
15
+ assert(t.in_days.to_s == "1825 days")
16
+ assert(t.in_days.in_months.to_s == "60.8333333333333 months")
17
+ assert(t.in_hours.to_s == "43800.0 hours")
18
+ assert(t.in_weeks.to_s == "260 weeks")
19
+ assert(t.in_months.in_weeks.to_s == "240 weeks")
20
+ assert(t.in_days.in_weeks.to_s == "260.714285714286 weeks")
21
+ assert(t.in_days == 260.weeks+5.days)
22
+
23
+ assert(days_in_january.to_s == "31.0")
24
+ assert(hours_in_january.to_s == "744.0")
25
+ assert(hours_per_january == 744)
26
+ assert(1.january.hours == 744.hours)
27
+ assert(january.hours == 744.hours)
28
+ assert(february.hours == 672.hours)
29
+ assert(july.weeks.to_s == "4.42857142857143 weeks")
30
+ assert(july.format(:weeks_and_days).to_s == "4 weeks 3 days")
31
+ assert(july.to_s(:weeks_and_days) == "4 weeks 3 days")
32
+
33
+ assert(speed_of_light.in_mi_s.to_s == "186282.024486427 mi / s")
34
+ assert(4.5.ly.in_mi.to_s == "26435654658917.8 miles")
35
+ assert(4.5.ly.AU.to_s == "284389.813364457 astronomical units")
36
+ assert(speed_of_light.miles.to_s == "186282.024486427 mi / s")
37
+ assert(speed_of_light.feet_nanosecond.to_s == "0.983569089288333 ft / ns")
38
+ assert(4.5.unite(["light_years"]).AU.to_s ==
39
+ "284389.813364457 astronomical units")
40
+ assert(4.5.light_years.AU.to_s ==
41
+ "284389.813364457 astronomical units")
42
+ assert(4.5.light_years.astronomical_units.to_s ==
43
+ "284389.813364457 astronomical units")
44
+ assert(1.speed_of_light.to_s == "1 speed of light")
45
+ assert(4.5.speed_of_light.to_s == "4.5 speed of light")
46
+
47
+ end
48
+
49
+ end
@@ -0,0 +1,41 @@
1
+ require 'test/unit'
2
+ require 'test/framework'
3
+
4
+ require 'units'
5
+
6
+ class TC_formatting < Test::Unit::TestCase
7
+
8
+ understands UnitsTest
9
+
10
+ def test_fractions
11
+
12
+ Units.create :length do |m|
13
+ m.system :english do |s|
14
+ s.unit :name => :inch, :plural => :inches, :abbrev => :in
15
+ s.unit :name => :foot, :plural => :feet, :abbrev => :ft,
16
+ :equals => 12.inches
17
+ s.unit :name => :yard, :abbrevs => :yd, :equals => 3.feet
18
+ s.unit :name => :mile, :abbrevs => :mi, :equals => 1760.yards
19
+ s.format :name => :feet_inches_and_32s,
20
+ :format => lambda { |u|
21
+ ru = u.inch.round_to_nearest 32
22
+ feet = ru.feet.floor
23
+ inches = (ru-feet).inches
24
+ "#{feet} #{inches.with_fraction 32}" }
25
+ end
26
+ end
27
+
28
+ l = 13.28090635.ft
29
+ assert(l.measure == Units.length)
30
+ assert(3.46875.with_fraction(32) == "3-15/32")
31
+ assert(l.format(:feet_inches_and_32s) == "13 feet 3-12/32 inches")
32
+
33
+ almost = 1.999.ft
34
+ assert(almost.inch.round_to_nearest(32) == 24.0.in)
35
+
36
+ almost = 1.996.ft
37
+ assert(almost.inch.round_to_nearest(32) == 23.9375.in)
38
+
39
+ end
40
+
41
+ end