ruby-units-brewpoo 1.3.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,118 @@
1
+ require 'time'
2
+ # make a string into a unit
3
+ class String
4
+ def to_unit(other = nil)
5
+ other ? Unit.new(self).to(other) : Unit.new(self)
6
+ end
7
+ alias :unit :to_unit
8
+ alias :u :to_unit
9
+ alias :unit_format :%
10
+
11
+ # format unit output using formating codes '%0.2f' % '1 mm'.unit => '1.00 mm'
12
+ def %(*args)
13
+ return if self.empty?
14
+ case
15
+ when Unit === args[0]
16
+ args[0].to_s(self)
17
+ when (!defined?(Uncertain).nil? && (Uncertain === args[0]))
18
+ args[0].to_s(self)
19
+ when Complex === args[0]
20
+ args[0].to_s
21
+ else
22
+ unit_format(*args)
23
+ end
24
+ end
25
+
26
+ #needed for compatibility with Rails, which defines a String.from method
27
+ if self.public_instance_methods.include? 'from'
28
+ alias :old_from :from
29
+ end
30
+
31
+ def from(time_point = ::Time.now)
32
+ return old_from(time_point) if Integer === time_point
33
+ self.unit.from(time_point)
34
+ end
35
+
36
+ alias :after :from
37
+ alias :from_now :from
38
+
39
+ def ago
40
+ self.unit.ago
41
+ end
42
+
43
+ def before(time_point = ::Time.now)
44
+ self.unit.before(time_point)
45
+ end
46
+ alias :before_now :before
47
+
48
+ def since(time_point = ::Time.now)
49
+ self.unit.since(time_point)
50
+ end
51
+
52
+ def until(time_point = ::Time.now)
53
+ self.unit.until(time_point)
54
+ end
55
+
56
+ def to(other)
57
+ self.unit.to(other)
58
+ end
59
+
60
+ def time(options = {})
61
+ self.to_time(options) rescue self.to_datetime(options)
62
+ end
63
+
64
+ def to_time(options = {})
65
+ begin
66
+ #raises exception when Chronic not defined or when it returns a nil (i.e., can't parse the input)
67
+ r = Chronic.parse(self,options)
68
+ raise(ArgumentError, 'Invalid Time String') unless r
69
+ return r
70
+ rescue
71
+ case
72
+ when self == "now"
73
+ Time.now
74
+ when Time.respond_to?(:parse)
75
+ Time.parse(self)
76
+ else
77
+ Time.local(*ParseDate.parsedate(self))
78
+ end
79
+ end
80
+ end
81
+
82
+ def to_datetime(options = {})
83
+ begin
84
+ # raises an exception if Chronic.parse = nil or if Chronic not defined
85
+ r = Chronic.parse(self,options).send(:to_datetime)
86
+ rescue Exception => e
87
+ r = case
88
+ when self.to_s == "now"
89
+ DateTime.now
90
+ else
91
+ DateTime.parse(self)
92
+ end
93
+ end
94
+ raise RuntimeError, "Invalid Time String (#{self.to_s})" if r == DateTime.new
95
+ return r
96
+ end
97
+
98
+ def to_date(options={})
99
+ begin
100
+ r = Chronic.parse(self,options).to_date
101
+ rescue
102
+ r = case
103
+ when self == "today"
104
+ Date.today
105
+ when RUBY_VERSION < "1.9"
106
+ Date.civil(*ParseDate.parsedate(self)[0..5].compact)
107
+ else
108
+ Date.parse(self)
109
+ end
110
+ end
111
+ raise RuntimeError, 'Invalid Date String' if r == Date.new
112
+ return r
113
+ end
114
+
115
+ def datetime(options = {})
116
+ self.to_datetime(options) rescue self.to_time(options)
117
+ end
118
+ end
@@ -0,0 +1,73 @@
1
+ #
2
+ # Time math is handled slightly differently. The difference is considered to be an exact duration if
3
+ # the subtracted value is in hours, minutes, or seconds. It is rounded to the nearest day if the offset
4
+ # is in years, decades, or centuries. This leads to less precise values, but ones that match the
5
+ # calendar better.
6
+ class Time
7
+
8
+ class << self
9
+ alias unit_time_at at
10
+ end
11
+
12
+ def self.at(*args)
13
+ if Unit === args[0]
14
+ unit_time_at(args[0].to("s").scalar)
15
+ else
16
+ unit_time_at(*args)
17
+ end
18
+ end
19
+
20
+ def to_unit(other = nil)
21
+ other ? Unit.new(self).to(other) : Unit.new(self)
22
+ end
23
+ alias :unit :to_unit
24
+ alias :u :to_unit
25
+ alias :unit_add :+
26
+
27
+ unless Time.instance_methods.include?(:to_date)
28
+ def to_date
29
+ x=(Date.civil(1970,1,1)+((self.to_f+self.gmt_offset)/86400.0)-0.5)
30
+ Date.civil(x.year, x.month, x.day)
31
+ end
32
+ end
33
+
34
+ def +(other)
35
+ case other
36
+ when Unit
37
+ other = other.to('d').round.to('s') if ['y', 'decade', 'century'].include? other.units
38
+ begin
39
+ unit_add(other.to('s').scalar)
40
+ rescue RangeError
41
+ self.to_datetime + other
42
+ end
43
+ when DateTime
44
+ unit_add(other.to_time)
45
+ else
46
+ unit_add(other)
47
+ end
48
+ end
49
+
50
+ # usage: Time.in '5 min'
51
+ def self.in(duration)
52
+ Time.now + duration.to_unit
53
+ end
54
+
55
+ alias :unit_sub :-
56
+
57
+ def -(other)
58
+ case other
59
+ when Unit
60
+ other = other.to('d').round.to('s') if ['y', 'decade', 'century'].include? other.units
61
+ begin
62
+ unit_sub(other.to('s').scalar)
63
+ rescue RangeError
64
+ self.send(:to_datetime) - other
65
+ end
66
+
67
+ when DateTime
68
+ unit_sub(other.to_time)
69
+ else
70
+ unit_sub(other)
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,252 @@
1
+
2
+
3
+ class Unit < Numeric
4
+ UNIT_DEFINITIONS = {
5
+ # prefixes
6
+ '<googol>' => [%w{googol}, 1e100, :prefix],
7
+ '<kibi>' => [%w{Ki Kibi kibi}, 2**10, :prefix],
8
+ '<mebi>' => [%w{Mi Mebi mebi}, 2**20, :prefix],
9
+ '<gibi>' => [%w{Gi Gibi gibi}, 2**30, :prefix],
10
+ '<tebi>' => [%w{Ti Tebi tebi}, 2**40, :prefix],
11
+ '<pebi>' => [%w{Pi Pebi pebi}, 2**50, :prefix],
12
+ '<exi>' => [%w{Ei Exi exi}, 2**60, :prefix],
13
+ '<zebi>' => [%w{Zi Zebi zebi}, 2**70, :prefix],
14
+ '<yebi>' => [%w{Yi Yebi yebi}, 2**80, :prefix],
15
+ '<yotta>' => [%w{Y Yotta yotta}, 1e24, :prefix],
16
+ '<zetta>' => [%w{Z Zetta zetta}, 1e21, :prefix],
17
+ '<exa>' => [%w{E Exa exa}, 1e18, :prefix],
18
+ '<peta>' => [%w{P Peta peta}, 1e15, :prefix],
19
+ '<tera>' => [%w{T Tera tera}, 1e12, :prefix],
20
+ '<giga>' => [%w{G Giga giga}, 1e9, :prefix],
21
+ '<mega>' => [%w{M Mega mega}, 1e6, :prefix],
22
+ '<kilo>' => [%w{k kilo}, 1e3, :prefix],
23
+ '<hecto>' => [%w{h Hecto hecto}, 1e2, :prefix],
24
+ '<deca>' => [%w{da Deca deca deka}, 1e1, :prefix],
25
+ '<deci>' => [%w{d Deci deci}, 1e-1, :prefix],
26
+ '<centi>' => [%w{c Centi centi}, 1e-2, :prefix],
27
+ '<milli>' => [%w{m Milli milli}, 1e-3, :prefix],
28
+ '<micro>' => [%w{u Micro micro}, 1e-6, :prefix],
29
+ '<nano>' => [%w{n Nano nano}, 1e-9, :prefix],
30
+ '<pico>' => [%w{p Pico pico}, 1e-12, :prefix],
31
+ '<femto>' => [%w{f Femto femto}, 1e-15, :prefix],
32
+ '<atto>' => [%w{a Atto atto}, 1e-18, :prefix],
33
+ '<zepto>' => [%w{z Zepto zepto}, 1e-21, :prefix],
34
+ '<yocto>' => [%w{y Yocto yocto}, 1e-24, :prefix],
35
+ '<1>' => [%w{1},1,:prefix],
36
+
37
+ # length units
38
+ '<meter>' => [%w{m meter meters metre metres}, 1.0, :length, %w{<meter>} ],
39
+ '<inch>' => [%w{in inch inches "}, 0.0254, :length, %w{<meter>}],
40
+ '<foot>' => [%w{ft foot feet '}, 0.3048, :length, %w{<meter>}],
41
+ '<yard>' => [%w{yd yard yards}, 0.9144, :length, %w{<meter>}],
42
+ '<mile>' => [%w{mi mile miles}, 1609.344, :length, %w{<meter>}],
43
+ '<naut-mile>' => [%w{nmi}, 1852, :length, %w{<meter>}],
44
+ '<league>'=> [%w{league leagues}, 4828, :length, %w{<meter>}],
45
+ '<furlong>'=> [%w{furlong furlongs}, 201.2, :length, %w{<meter>}],
46
+ '<rod>' => [%w{rd rod rods}, 5.029, :length, %w{<meter>}],
47
+ '<mil>' => [%w{mil mils}, 0.0000254, :length, %w{<meter>}],
48
+ '<angstrom>' =>[%w{ang angstrom angstroms}, 1e-10, :length, %w{<meter>}],
49
+ '<fathom>' => [%w{fathom fathoms}, 1.829, :length, %w{<meter>}],
50
+ '<pica>' => [%w{pica picas}, 0.004217, :length, %w{<meter>}],
51
+ '<point>' => [%w{pt point points}, 0.0003514, :length, %w{<meter>}],
52
+ '<redshift>' => [%w{z red-shift}, 1.302773e26, :length, %w{<meter>}],
53
+ '<AU>' => [%w{AU astronomical-unit}, 149597900000, :length, %w{<meter>}],
54
+ '<light-second>'=>[%w{ls light-second}, 299792500, :length, %w{<meter>}],
55
+ '<light-minute>'=>[%w{lmin light-minute}, 17987550000, :length, %w{<meter>}],
56
+ '<light-year>' => [%w{ly light-year}, 9460528000000000, :length, %w{<meter>}],
57
+ '<parsec>' => [%w{pc parsec parsecs}, 30856780000000000, :length, %w{<meter>}],
58
+
59
+ #mass
60
+ '<kilogram>' => [%w{kg kilogram kilograms}, 1.0, :mass, %w{<kilogram>}],
61
+ '<AMU>' => [%w{u AMU amu}, 6.0221415e26, :mass, %w{<kilogram>}],
62
+ '<dalton>' => [%w{Da Dalton Daltons dalton daltons}, 6.0221415e26, :mass, %w{<kilogram>}],
63
+ '<slug>' => [%w{slug slugs}, 14.5939029, :mass, %w{<kilogram>}],
64
+ '<short-ton>' => [%w{tn ton}, 907.18474, :mass, %w{<kilogram>}],
65
+ '<metric-ton>'=>[%w{tonne}, 1000, :mass, %w{<kilogram>}],
66
+ '<carat>' => [%w{ct carat carats}, 0.0002, :mass, %w{<kilogram>}],
67
+ '<pound>' => [%w{lbs lb pound pounds #}, 0.45359237, :mass, %w{<kilogram>}],
68
+ '<ounce>' => [%w{oz ounce ounces}, 0.0283495231, :mass, %w{<kilogram>}],
69
+ '<gram>' => [%w{g gram grams gramme grammes},1e-3,:mass, %w{<kilogram>}],
70
+
71
+ #area
72
+ '<hectare>'=>[%w{hectare}, 10000, :area, %w{<meter> <meter>}],
73
+ '<acre>'=>[%w(acre acres), 4046.85642, :area, %w{<meter> <meter>}],
74
+ '<sqft>'=>[%w(sqft), 1, :area, %w{<feet> <feet>}],
75
+
76
+ #volume
77
+ '<liter>' => [%w{l L liter liters litre litres}, 0.001, :volume, %w{<meter> <meter> <meter>}],
78
+ '<barrel>' => [%w{bbl bbls barrel barrels}, 0.00852167911, :volume, %w{<meter> <meter> <meter>}],
79
+ '<keg>' => [%w{keg kegs}, 0.0170433582, :volume, %w{<meter> <meter> <meter>}],
80
+ '<gallon>'=> [%w{gal gallon gallons}, 0.0037854118, :volume, %w{<meter> <meter> <meter>}],
81
+ '<quart>'=> [%w{qt quart quarts}, 0.00094635295, :volume, %w{<meter> <meter> <meter>}],
82
+ '<pint>'=> [%w{pt pint pints}, 0.000473176475, :volume, %w{<meter> <meter> <meter>}],
83
+ '<cup>'=> [%w{cu cup cups}, 0.000236588238, :volume, %w{<meter> <meter> <meter>}],
84
+ '<fluid-ounce>'=> [%w{floz fluid-ounce}, 2.95735297e-5, :volume, %w{<meter> <meter> <meter>}],
85
+ '<tablespoon>'=> [%w{tbs tablespoon tablespoons}, 1.47867648e-5, :volume, %w{<meter> <meter> <meter>}],
86
+ '<teaspoon>'=> [%w{tsp teaspoon teaspoons}, 4.92892161e-6, :volume, %w{<meter> <meter> <meter>}],
87
+
88
+ #speed
89
+ '<kph>' => [%w{kph}, 0.277777778, :speed, %w{<meter>}, %w{<second>}],
90
+ '<mph>' => [%w{mph}, 0.44704, :speed, %w{<meter>}, %w{<second>}],
91
+ '<knot>' => [%w{kt kn kts knot knots}, 0.514444444, :speed, %w{<meter>}, %w{<second>}],
92
+ '<fps>' => [%w{fps}, 0.3048, :speed, %w{<meter>}, %w{<second>}],
93
+
94
+ #acceleration
95
+ '<gee>' => [%w{gee}, 9.80655, :acceleration, %w{<meter>}, %w{<second> <second>}],
96
+
97
+ #temperature_difference
98
+ '<kelvin>' => [%w{degK kelvin}, 1.0, :temperature, %w{<kelvin>}],
99
+ '<celsius>' => [%w{degC celsius celsius centigrade}, 1.0, :temperature, %w{<kelvin>}],
100
+ '<fahrenheit>' => [%w{degF fahrenheit}, 1/1.8, :temperature, %w{<kelvin>}],
101
+ '<rankine>' => [%w{degR rankine}, 1/1.8, :temperature, %w{<kelvin>}],
102
+ '<temp-K>' => [%w{tempK}, 1.0, :temperature, %w{<temp-K>}],
103
+ '<temp-C>' => [%w{tempC}, 1.0, :temperature, %w{<temp-K>}],
104
+ '<temp-F>' => [%w{tempF}, 1/1.8, :temperature, %w{<temp-K>}],
105
+ '<temp-R>' => [%w{tempR}, 1/1.8, :temperature, %w{<temp-K>}],
106
+
107
+ #time
108
+ '<second>'=> [%w{s sec second seconds}, 1.0, :time, %w{<second>}],
109
+ '<minute>'=> [%w{min minute minutes}, 60.0, :time, %w{<second>}],
110
+ '<hour>'=> [%w{h hr hrs hour hours}, 3600.0, :time, %w{<second>}],
111
+ '<day>'=> [%w{d day days}, 3600*24, :time, %w{<second>}],
112
+ '<week>'=> [%w{wk week weeks}, 7*3600*24, :time, %w{<second>}],
113
+ '<fortnight>'=> [%w{fortnight fortnights}, 1209600, :time, %W{<second>}],
114
+ '<year>'=> [%w{y yr year years annum}, 31556926, :time, %w{<second>}],
115
+ '<decade>'=>[%w{decade decades}, 315569260, :time, %w{<second>}],
116
+ '<century>'=>[%w{century centuries}, 3155692600, :time, %w{<second>}],
117
+
118
+ #pressure
119
+ '<pascal>' => [%w{Pa pascal Pascal}, 1.0, :pressure, %w{<kilogram>},%w{<meter> <second> <second>}],
120
+ '<bar>' => [%w{bar bars}, 100000, :pressure, %w{<kilogram>},%w{<meter> <second> <second>}],
121
+ '<mmHg>' => [%w{mmHg}, 133.322368,:pressure, %w{<kilogram>},%w{<meter> <second> <second>}],
122
+ '<inHg>' => [%w{inHg}, 3386.3881472,:pressure, %w{<kilogram>},%w{<meter> <second> <second>}],
123
+ '<torr>' => [%w{torr}, 133.322368,:pressure, %w{<kilogram>},%w{<meter> <second> <second>}],
124
+ '<bar>' => [%w{bar}, 100000,:pressure, %w{<kilogram>},%w{<meter> <second> <second>}],
125
+ '<atm>' => [%w{atm ATM atmosphere atmospheres}, 101325,:pressure, %w{<kilogram>},%w{<meter> <second> <second>}],
126
+ '<psi>' => [%w{psi}, 6894.76,:pressure, %w{<kilogram>},%w{<meter> <second> <second>}],
127
+ '<cmh2o>' => [%w{cmH2O}, 98.0638,:pressure, %w{<kilogram>},%w{<meter> <second> <second>}],
128
+ '<inh2o>' => [%w{inH2O}, 249.082052,:pressure, %w{<kilogram>},%w{<meter> <second> <second>}],
129
+
130
+ #viscosity
131
+ '<poise>' => [%w{P poise}, 0.1, :viscosity, %w{<kilogram>},%w{<meter> <second>} ],
132
+ '<stokes>' => [%w{St stokes}, 1e-4, :viscosity, %w{<meter> <meter>}, %w{<second>}],
133
+
134
+ #substance
135
+ '<mole>' => [%w{mol mole}, 1.0, :substance, %w{<mole>}],
136
+
137
+ #concentration
138
+ '<molar>' => [%w{M molar}, 1000, :concentration, %w{<mole>}, %w{<meter> <meter> <meter>}],
139
+ '<wtpercent>' => [%w{wt% wtpercent}, 10, :concentration, %w{<kilogram>}, %w{<meter> <meter> <meter>}],
140
+
141
+ #activity
142
+ '<katal>' => [%w{kat katal Katal}, 1.0, :activity, %w{<mole>}, %w{<second>}],
143
+ '<unit>' => [%w{U enzUnit}, 16.667e-16, :activity, %w{<mole>}, %w{<second>}],
144
+
145
+ #capacitance
146
+ '<farad>' => [%w{F farad Farad}, 1.0, :capacitance, %w{<farad>}],
147
+
148
+ #charge
149
+ '<coulomb>' => [%w{C coulomb Coulomb}, 1.0, :charge, %w{<ampere> <second>}],
150
+
151
+ #current
152
+ '<ampere>' => [%w{A Ampere ampere amp amps}, 1.0, :current, %w{<ampere>}],
153
+
154
+ #conductance
155
+ '<siemens>' => [%w{S Siemens siemens}, 1.0, :resistance, %w{<second> <second> <second> <ampere> <ampere>}, %w{<kilogram> <meter> <meter>}],
156
+
157
+ #inductance
158
+ '<henry>' => [%w{H Henry henry}, 1.0, :inductance, %w{<meter> <meter> <kilogram>}, %w{<second> <second> <ampere> <ampere>}],
159
+
160
+ #potential
161
+ '<volt>' => [%w{V Volt volt volts}, 1.0, :potential, %w{<meter> <meter> <kilogram>}, %w{<second> <second> <second> <ampere>}],
162
+
163
+ #resistance
164
+ '<ohm>' => [%w{Ohm ohm}, 1.0, :resistance, %w{<meter> <meter> <kilogram>},%w{<second> <second> <second> <ampere> <ampere>}],
165
+
166
+ #magnetism
167
+ '<weber>' => [%w{Wb weber webers}, 1.0, :magnetism, %w{<meter> <meter> <kilogram>}, %w{<second> <second> <ampere>}],
168
+ '<tesla>' => [%w{T tesla teslas}, 1.0, :magnetism, %w{<kilogram>}, %w{<second> <second> <ampere>}],
169
+ '<gauss>' => [%w{G gauss}, 1e-4, :magnetism, %w{<kilogram>}, %w{<second> <second> <ampere>}],
170
+ '<maxwell>' => [%w{Mx maxwell maxwells}, 1e-8, :magnetism, %w{<meter> <meter> <kilogram>}, %w{<second> <second> <ampere>}],
171
+ '<oersted>' => [%w{Oe oersted oersteds}, 250.0/Math::PI, :magnetism, %w{<ampere>}, %w{<meter>}],
172
+
173
+ #energy
174
+ '<joule>' => [%w{J joule Joule joules}, 1.0, :energy, %w{<meter> <meter> <kilogram>}, %w{<second> <second>}],
175
+ '<erg>' => [%w{erg ergs}, 1e-7, :energy, %w{<meter> <meter> <kilogram>}, %w{<second> <second>}],
176
+ '<btu>' => [%w{BTU btu BTUs}, 1055.056, :energy, %w{<meter> <meter> <kilogram>}, %w{<second> <second>}],
177
+ '<calorie>' => [%w{cal calorie calories}, 4.18400, :energy,%w{<meter> <meter> <kilogram>}, %w{<second> <second>}],
178
+ '<Calorie>' => [%w{Cal Calorie Calories}, 4184.00, :energy,%w{<meter> <meter> <kilogram>}, %w{<second> <second>}],
179
+ '<therm-US>' => [%w{th therm therms Therm}, 105480400, :energy,%w{<meter> <meter> <kilogram>}, %w{<second> <second>}],
180
+
181
+ #force
182
+ '<newton>' => [%w{N Newton newton}, 1.0, :force, %w{<kilogram> <meter>}, %w{<second> <second>}],
183
+ '<dyne>' => [%w{dyn dyne}, 1e-5, :force, %w{<kilogram> <meter>}, %w{<second> <second>}],
184
+ '<pound-force>' => [%w{lbf pound-force}, 4.448222, :force, %w{<kilogram> <meter>}, %w{<second> <second>}],
185
+
186
+ #frequency
187
+ '<hertz>' => [%w{Hz hertz Hertz}, 1.0, :frequency, %w{<1>}, %{<second>}],
188
+
189
+ #angle
190
+ '<radian>' =>[%w{rad radian radian}, 1.0, :angle, %w{<radian>}],
191
+ '<degree>' =>[%w{deg degree degrees}, Math::PI / 180.0, :angle, %w{<radian>}],
192
+ '<grad>' =>[%w{grad gradian grads}, Math::PI / 200.0, :angle, %w{<radian>}],
193
+ '<steradian>' => [%w{sr steradian steradians}, 1.0, :solid_angle, %w{<steradian>}],
194
+
195
+ #rotation
196
+ '<rotation>' => [%w{rotation}, 2.0*Math::PI, :angle, %w{<radian>}],
197
+ '<rpm>' =>[%w{rpm}, 2.0*Math::PI / 60.0, :angular_velocity, %w{<radian>}, %w{<second>}],
198
+
199
+ #memory
200
+ '<byte>' =>[%w{B byte}, 1.0, :memory, %w{<byte>}],
201
+ '<bit>' =>[%w{b bit}, 0.125, :memory, %w{<byte>}],
202
+
203
+ #currency
204
+ '<dollar>'=>[%w{USD dollar}, 1.0, :currency, %w{<dollar>}],
205
+ '<cents>' =>[%w{cents}, 0.01, :currency, %w{<dollar>}],
206
+
207
+ #luminosity
208
+ '<candela>' => [%w{cd candela}, 1.0, :luminosity, %w{<candela>}],
209
+ '<lumen>' => [%w{lm lumen}, 1.0, :luminous_power, %w{<candela> <steradian>}],
210
+ '<lux>' =>[%w{lux}, 1.0, :illuminance, %w{<candela> <steradian>}, %w{<meter> <meter>}],
211
+
212
+ #power
213
+ '<watt>' => [%w{W watt watts}, 1.0, :power, %w{<kilogram> <meter> <meter>}, %w{<second> <second> <second>}],
214
+ '<horsepower>' => [%w{hp horsepower}, 745.699872, :power, %w{<kilogram> <meter> <meter>}, %w{<second> <second> <second>}],
215
+
216
+ #radiation
217
+ '<gray>' => [%w{Gy gray grays}, 1.0, :radiation, %w{<meter> <meter>}, %w{<second> <second>}],
218
+ '<roentgen>' => [%w{R roentgen}, 0.009330, :radiation, %w{<meter> <meter>}, %w{<second> <second>}],
219
+ '<sievert>' => [%w{Sv sievert sieverts}, 1.0, :radiation, %w{<meter> <meter>}, %w{<second> <second>}],
220
+ '<becquerel>' => [%w{Bq bequerel bequerels}, 1.0, :radiation, %w{<1>},%w{<second>}],
221
+ '<curie>' => [%w{Ci curie curies}, 3.7e10, :radiation, %w{<1>},%w{<second>}],
222
+
223
+ # rate
224
+ '<cpm>' => [%w{cpm}, 1.0/60.0, :rate, %w{<count>},%w{<second>}],
225
+ '<dpm>' => [%w{dpm}, 1.0/60.0, :rate, %w{<count>},%w{<second>}],
226
+ '<bpm>' => [%w{bpm}, 1.0/60.0, :rate, %w{<count>},%w{<second>}],
227
+
228
+ #resolution / typography
229
+ '<dot>' => [%w{dot dots}, 1, :resolution, %w{<each>}],
230
+ '<pixel>' => [%w{pixel px}, 1, :resolution, %w{<each>}],
231
+ '<ppi>' => [%w{ppi}, 1, :resolution, %w{<pixel>}, %w{<inch>}],
232
+ '<dpi>' => [%w{dpi}, 1, :typography, %w{<dot>}, %w{<inch>}],
233
+ '<pica>' => [%w{pica}, 0.00423333333 , :typography, %w{<meter>}],
234
+ '<point>' => [%w{point pt}, 0.000352777778, :typography, %w{<meter>}],
235
+
236
+ #other
237
+ '<cell>' => [%w{cells cell}, 1, :counting, %w{<each>}],
238
+ '<each>' => [%w{each}, 1.0, :counting, %w{<each>}],
239
+ '<count>' => [%w{count}, 1.0, :counting, %w{<each>}],
240
+ '<base-pair>' => [%w{bp}, 1.0, :counting, %w{<each>}],
241
+ '<nucleotide>' => [%w{nt}, 1.0, :counting, %w{<each>}],
242
+ '<molecule>' => [%w{molecule molecules}, 1.0, :counting, %w{<1>}],
243
+ '<dozen>' => [%w{doz dz dozen},12.0,:prefix_only, %w{<each>}],
244
+ '<percent>'=> [%w{% percent}, 0.01, :prefix_only, %w{<1>}],
245
+ '<ppm>' => [%w{ppm},1e-6,:prefix_only, %w{<1>}],
246
+ '<ppt>' => [%w{ppt},1e-9,:prefix_only, %w{<1>}],
247
+ '<gross>' => [%w{gr gross},144.0, :prefix_only, %w{<dozen> <dozen>}],
248
+ '<decibel>' => [%w{dB decibel decibels}, 1.0, :logarithmic, %w{<decibel>}]
249
+
250
+
251
+ } # doc
252
+ end
@@ -0,0 +1,982 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'ruby-units'
4
+ require 'yaml'
5
+ begin
6
+ require 'chronic'
7
+ rescue LoadError
8
+ warn "Can't test Chronic integration unless gem 'chronic' is installed"
9
+ end
10
+ begin
11
+ require 'uncertain'
12
+ rescue LoadError
13
+ warn "Can't test Uncertain Units unless 'Uncertain' gem is installed"
14
+ end
15
+
16
+
17
+ class Unit < Numeric
18
+ @@USER_DEFINITIONS = {'<inchworm>' => [%w{inworm inchworm}, 0.0254, :length, %w{<meter>} ],
19
+ '<habenero>' => [%w{degH}, 100, :temperature, %w{<celsius>}]}
20
+ Unit.setup
21
+ end
22
+
23
+ class Time
24
+ @@forced_now = nil
25
+ @@forced_gmt = nil
26
+ class << self
27
+ alias :unforced_now :now
28
+ def forced_now
29
+ @@forced_now.nil? ? unforced_now : @@forced_now
30
+ end
31
+ alias :now :forced_now
32
+
33
+ def forced_now=(now)
34
+ @@forced_now = now
35
+ end
36
+ end
37
+
38
+ alias :unforced_gmt :gmt_offset
39
+ def forced_gmt
40
+ @@forced_gmt.nil? ? unforced_gmt : @@forced_gmt
41
+ end
42
+ alias :gmt_offset :forced_gmt
43
+
44
+ def forced_gmt=(gmt)
45
+ @@forced_gmt = now
46
+ end
47
+
48
+ end
49
+
50
+ class DateTime
51
+ @@forced_now = nil
52
+ class << self
53
+ alias :unforced_now :now
54
+ def forced_now
55
+ return @@forced_now ? @@forced_now : unforced_now
56
+ end
57
+ alias :now :forced_now
58
+
59
+ def forced_now=(now)
60
+ @@forced_now = now
61
+ end
62
+
63
+ end
64
+ end
65
+
66
+ class Dummy
67
+ def to_unit
68
+ '1 mm'.unit
69
+ end
70
+ end
71
+
72
+ class TestRubyUnits < Test::Unit::TestCase
73
+
74
+ def setup
75
+ @april_fools = Time.at 1143910800
76
+ @april_fools_datetime = DateTime.parse('2006-04-01T12:00:00-05:00')
77
+ Time.forced_now = @april_fools
78
+ DateTime.forced_now = @april_fools_datetime
79
+ #Unit.clear_cache
80
+ end
81
+
82
+ def teardown
83
+ Time.forced_now = nil
84
+ DateTime.forced_now = nil
85
+ end
86
+
87
+ def test_to_yaml
88
+ unit = "1 mm".u
89
+ assert_equal "--- !ruby/object:Unit \nscalar: 1.0\nnumerator: \n- <milli>\n- <meter>\ndenominator: \n- <1>\nsignature: 1\nbase_scalar: 0.001\n", unit.to_yaml
90
+ end
91
+
92
+ def test_time
93
+ a = Time.now
94
+ assert_equal "s", a.to_unit.units
95
+ assert_equal a + 3600, a + "1 h".unit
96
+ assert_equal a - 3600, a - "1 h".unit
97
+ assert_in_delta Time.now - "1 h".unit, "1 h".ago, 1
98
+ assert_in_delta Time.now + 3600, "1 h".from_now, 1
99
+ assert_in_delta "1 h".unit + Time.now, "1 h".from_now, 1
100
+ assert_in_delta Time.now - 3600, "1 h".before_now, 1
101
+ assert_in_delta((Time.now.unit - Time.now).unit.scalar, 0, 1)
102
+ assert_equal "60 min", "min".until(Time.now + 3600).to_s
103
+ assert_equal "01:00", "min".since(Time.now - 3600).to_s("%H:%M")
104
+ assert_in_delta Time.now, "now".time, 1
105
+ end
106
+
107
+ def test_from_now
108
+ assert_equal "1 day".from_now, @april_fools + 86400
109
+ end
110
+
111
+ def test_from
112
+ assert_equal "1 day".from("now"), @april_fools + 86400
113
+ end
114
+
115
+ def test_ago
116
+ assert_equal "1 day".ago, @april_fools - 86400
117
+ end
118
+
119
+ def test_before_now
120
+ assert_equal "1 day".before_now, @april_fools - 86400
121
+ end
122
+
123
+ def test_before
124
+ assert_equal '1 days'.before('now'), @april_fools - 86400
125
+ end
126
+
127
+ def test_since
128
+ assert_equal 'days'.since(@april_fools - 86400), "1 day".unit
129
+ assert_equal 'days'.since('2006-3-31 12:00:00 -5:00'), "1 day".unit
130
+ assert_equal 'days'.since(DateTime.parse('2006-3-31 12:00 -5:00')), "1 day".unit
131
+ assert_raises(ArgumentError) { 'days'.since(1) }
132
+ end
133
+
134
+ def test_until
135
+ assert_equal 'days'.until('2006-04-2 12:00:00 -5:00'), '1 day'.unit
136
+ assert_raises(ArgumentError) { 'days'.until(1) }
137
+ end
138
+
139
+ def test_time_helpers
140
+ assert_equal @april_fools, Time.now
141
+ assert_equal @april_fools_datetime, DateTime.now
142
+ assert_equal Time.now, 'now'.time
143
+ assert_equal DateTime.now, 'now'.datetime
144
+ assert_equal 1143910800, Unit.new(Time.now).scalar
145
+ assert_equal @april_fools.unit.to_time, @april_fools
146
+ assert_equal Time.in('1 day'), @april_fools + 86400
147
+ assert_equal "2006-04-01T12:00:00-05:00", @april_fools_datetime.inspect
148
+ assert_equal "2006-04-01T00:00:00+00:00", '2453826.5 days'.unit.to_datetime.to_s
149
+ end
150
+
151
+ def test_string_helpers
152
+ assert_equal '1 mm'.to('in'), Unit('1 mm').to('in')
153
+ end
154
+
155
+ [:sin, :cos, :tan, :sinh, :cosh, :tanh].each do |trig|
156
+ define_method("test_#{trig}") do
157
+ assert_equal Math.send(trig, Math::PI), Math.send(trig, "180 deg".unit)
158
+ end
159
+ end
160
+
161
+ def test_clone
162
+ unit1= "1 mm".unit
163
+ unit2 = unit1.clone
164
+ assert_not_equal unit1.numerator.object_id, unit2.numerator.object_id
165
+ assert_not_equal unit1.denominator.object_id, unit2.denominator.object_id
166
+ assert unit1 === unit2
167
+ end
168
+
169
+ def test_unary_minus
170
+ unit1 = Unit.new("1 mm^2")
171
+ unit2 = Unit.new("-1 mm^2")
172
+ assert_equal unit1, -unit2
173
+ end
174
+
175
+ def test_unary_plus
176
+ unit1 = Unit.new("1 mm")
177
+ assert_equal unit1, +unit1
178
+ end
179
+
180
+ def test_create_unit_only
181
+ unit1 = Unit.new("m")
182
+ assert_equal ['<meter>'], unit1.numerator
183
+ assert_equal 1.0, unit1.scalar
184
+ end
185
+
186
+ def test_to_base
187
+ unit1 = Unit.new("100 cm")
188
+ assert_in_delta 1, unit1.to_base.scalar, 0.001
189
+ unit2 = Unit("1 mm^2 ms^-2")
190
+ assert_in_delta 1, unit2.to_base.scalar, 0.001
191
+ end
192
+
193
+ def test_to_unit
194
+ unit1 = "1 mm".to_unit
195
+ assert_equal unit1, unit1.to_unit
196
+ assert Unit === unit1
197
+ unit2 = Unit("1 mm")
198
+ assert Unit === unit1
199
+ assert unit1 == unit2
200
+ unit1 = "2.54 cm".to_unit("in")
201
+ assert_in_delta 1, unit1.scalar, 0.001
202
+ assert_equal ['<inch>'], unit1.numerator
203
+ unit1 = "2.54 cm".unit("in")
204
+ assert_in_delta 1, unit1.scalar, 0.001
205
+ assert_equal ['<inch>'], unit1.numerator
206
+ unit1 = 1.unit
207
+ assert_in_delta 1, unit1.scalar, 0.001
208
+ assert_equal ['<1>'], unit1.numerator
209
+ unit1 = [1,'mm'].unit
210
+ assert_in_delta 1, unit1.scalar, 0.001
211
+ assert_equal ['<milli>','<meter>'], unit1.numerator
212
+ end
213
+
214
+ def test_create_unitless
215
+ unit1 = Unit("1")
216
+ assert_equal 1, unit1.to_f
217
+ assert_equal ['<1>'],unit1.numerator
218
+ assert_equal ['<1>'],unit1.denominator
219
+ unit1 = Unit.new("1.5")
220
+ assert_equal 1.5,unit1.to_f
221
+ assert_equal ['<1>'],unit1.numerator
222
+ assert_equal ['<1>'],unit1.denominator
223
+ end
224
+
225
+ def test_create_simple
226
+ unit1 = Unit.new("1 m")
227
+ assert_equal 1,unit1.scalar
228
+ assert_equal ['<meter>'], unit1.numerator
229
+ assert_equal ['<1>'],unit1.denominator
230
+ end
231
+
232
+ def test_create_compound
233
+ unit1 = Unit.new("1 N*m")
234
+ assert_equal 1,unit1.scalar
235
+ assert_equal ['<newton>','<meter>'],unit1.numerator
236
+ assert_equal ['<1>'],unit1.denominator
237
+ end
238
+
239
+ def test_create_with_denominator
240
+ unit1 = Unit.new("1 m/s")
241
+ assert_equal 1, unit1.scalar
242
+ assert_equal ['<meter>'],unit1.numerator
243
+ assert_equal ['<second>'],unit1.denominator
244
+ end
245
+
246
+ def test_create_with_powers
247
+ unit1 = Unit.new("1 m^2/s^2")
248
+ assert_equal 1, unit1.scalar
249
+ assert_equal ['<meter>','<meter>'],unit1.numerator
250
+ assert_equal ['<second>','<second>'],unit1.denominator
251
+ unit1 = Unit.new("1 m^2 kg^2 J^2/s^2")
252
+ assert_equal 1, unit1.scalar
253
+ assert_equal ['<meter>','<meter>','<kilogram>','<kilogram>','<joule>','<joule>'],unit1.numerator
254
+ assert_equal ['<second>','<second>'],unit1.denominator
255
+
256
+ end
257
+
258
+ def test_create_with_zero_power
259
+ unit1 = Unit.new("1 m^0")
260
+ assert_equal 1,unit1.scalar
261
+ assert_equal ['<1>'],unit1.numerator
262
+ assert_equal ['<1>'],unit1.denominator
263
+ end
264
+
265
+ def test_create_with_negative_powers
266
+ unit1 = Unit.new("1 m^2 s^-2")
267
+ assert_equal 1, unit1.scalar
268
+ assert_equal ['<meter>','<meter>'],unit1.numerator
269
+ assert_equal ['<second>','<second>'],unit1.denominator
270
+ end
271
+
272
+ def test_create_from_array
273
+ unit1 = Unit.new(1, "mm^2", "ul^2")
274
+ assert_equal 1, unit1.scalar
275
+ assert_equal ['<milli>','<meter>','<milli>','<meter>'], unit1.numerator
276
+ assert_equal ['<micro>','<liter>','<micro>','<liter>'], unit1.denominator
277
+ end
278
+
279
+ def test_bad_create
280
+ assert_raises(ArgumentError) { Unit.new(nil)}
281
+ assert_raises(ArgumentError) { Unit.new(true)}
282
+ assert_raises(ArgumentError) { Unit.new(false)}
283
+ assert_raises(ArgumentError) { Unit.new(/(.+)/)}
284
+ end
285
+
286
+ def test_convert
287
+ unit1 = Unit.new("1 attoparsec/microfortnight")
288
+ assert_nothing_raised {
289
+ unit2 = unit1 >> "in/s"
290
+ assert_equal ['<inch>'],unit2.numerator
291
+ assert_equal ['<second>'],unit2.denominator
292
+ assert_in_delta 1.0043269330917,unit2.scalar,0.00001
293
+ }
294
+ end
295
+
296
+ def test_add_operator
297
+ a = '0 mm'.unit
298
+ b = '10 cm'.unit
299
+ c = '1 in'.unit
300
+ d = '1 ml'.unit
301
+
302
+ assert_equal((a+b), b)
303
+ assert_equal((a+b).units, b.units)
304
+ assert_equal((b+a), b)
305
+ assert_equal((b+a).units, b.units)
306
+ assert_in_delta((b+c).scalar, 12.54, 0.01)
307
+ assert_equal((b+c).units, 'cm')
308
+ assert_raises(ArgumentError) {
309
+ b + d
310
+ }
311
+ end
312
+
313
+ def test_subtract_operator
314
+ a = '0 mm'.unit
315
+ b = '10 cm'.unit
316
+ c = '1 in'.unit
317
+ d = '1 ml'.unit
318
+
319
+ assert_equal((a-b), -b)
320
+ assert_equal((a-b).units, b.units)
321
+ assert_equal((b-a), b)
322
+ assert_equal((b-a).units, b.units)
323
+ assert_in_delta((b-c).scalar, 7.46, 0.01)
324
+ assert_equal((b-c).units, 'cm')
325
+ assert_raises(ArgumentError) {
326
+ b - d
327
+ }
328
+ end
329
+
330
+ def test_convert_to
331
+ unit1 = Unit.new("1 mm")
332
+ unit2 = Unit.new("1 ft")
333
+ assert_nothing_raised {
334
+ unit3 = unit1 >> unit2
335
+ assert_equal ['<foot>'], unit3.numerator
336
+ assert_equal ['<1>'],unit3.denominator
337
+ unit3 = unit1 >> "ft"
338
+ assert_equal ['<foot>'], unit3.numerator
339
+ assert_equal ['<1>'],unit3.denominator
340
+ }
341
+ assert_raises(ArgumentError) { unit1 >> 5.0}
342
+ assert_equal unit1, unit1.to(true)
343
+ assert_equal unit1, unit1.to(false)
344
+ assert_equal unit1, unit1.to(nil)
345
+ end
346
+
347
+ def test_compare
348
+ unit1 = "1 mm".unit
349
+ unit2 = "1 mm".unit
350
+ unit3 = unit2 >> "in"
351
+ assert unit1 === unit2
352
+ assert !(unit1 === unit3)
353
+ assert unit1 === "1 mm"
354
+ end
355
+
356
+ def test_matched_units
357
+ unit1 = Unit.new("1 m*kg/s")
358
+ unit2 = Unit.new("1 in*pound/min")
359
+ assert unit1 =~ unit2
360
+ end
361
+
362
+ def test_matched_units_using_string
363
+ unit1 = Unit.new("1 m*kg/s")
364
+ assert unit1 =~ "in*pound/min"
365
+ end
366
+
367
+ def test_unmatched_units
368
+ unit1 = Unit.new("1 m*kg/s")
369
+ unit2 = Unit.new("1 mm")
370
+ assert unit1 !~ unit2
371
+ end
372
+
373
+ def test_comparison_like_units
374
+ unit1 = Unit.new("1 in")
375
+ unit2 = Unit.new("1 mm")
376
+ assert_nothing_raised {
377
+ assert unit1 > unit2
378
+ }
379
+ end
380
+
381
+ def test_comparison_unlike_units
382
+ unit1 = Unit.new("1 kg")
383
+ unit2 = Unit.new("1 mm")
384
+ assert_raise(ArgumentError) { unit1 > unit2 }
385
+ end
386
+
387
+ def test_add_like_units
388
+ unit1 = Unit.new("1 mm")
389
+ unit2 = Unit.new("2 mm")
390
+ assert_nothing_raised {
391
+ assert_equal 3.0, (unit1+unit2).scalar
392
+ }
393
+ end
394
+
395
+ def test_add_similar_units
396
+ unit1 = Unit.new("1 cm")
397
+ unit2 = Unit.new("1 in")
398
+ assert_nothing_raised {
399
+ unit3 = unit1 + unit2
400
+ assert_in_delta 3.54, unit3.scalar, 0.01
401
+ }
402
+ end
403
+
404
+ def test_subtract_similar_units
405
+ unit1 = Unit.new("1 cm")
406
+ unit2 = Unit.new("1 in")
407
+ assert_nothing_raised {
408
+ unit3 = unit1 - unit2
409
+ assert_in_delta(-1.54, unit3.scalar, 0.01)
410
+ }
411
+ end
412
+
413
+ def test_add_unlike_units
414
+ unit1 = Unit.new("1 mm")
415
+ unit2 = Unit.new("2 ml")
416
+ assert_raise(ArgumentError) {(unit1+unit2).scalar}
417
+ end
418
+
419
+ def test_add_coerce
420
+ unit1 = "1 mm".unit
421
+ assert_nothing_raised {
422
+ unit2 = unit1 + "1 mm"
423
+ assert_equal "2 mm".unit, unit2
424
+ }
425
+ assert_nothing_raised {
426
+ unit2 = unit1 + [1,"mm"]
427
+ assert_equal "2 mm".unit, unit2
428
+ }
429
+ assert_nothing_raised {
430
+ unit2 = "1".unit + 1
431
+ assert_equal "2".unit, unit2
432
+ }
433
+ assert_raises(ArgumentError) {
434
+ "1".unit + nil
435
+ }
436
+ end
437
+
438
+ def test_subtract_coerce
439
+ unit1 = "1 mm".unit
440
+ assert_nothing_raised {
441
+ unit2 = unit1 - "1 mm"
442
+ assert_equal "0 mm".unit, unit2
443
+ }
444
+ end
445
+ def test_multiply_coerce
446
+ unit1 = "1 mm".unit
447
+ assert_nothing_raised {
448
+ unit2 = unit1 * "1 mm"
449
+ assert_equal "1 mm^2".unit, unit2
450
+ }
451
+ end
452
+ def test_divide_coerce
453
+ unit1 = "1 mm".unit
454
+ assert_nothing_raised {
455
+ unit2 = unit1 / "1 mm"
456
+ assert_equal "1".unit, unit2
457
+ }
458
+ end
459
+
460
+ def test_signature #"1 m s deg K kg A mol cd byte rad
461
+ unit1 = Unit.new("1 m*s*degK*kg*A*mol*cd*byte*rad*dollar")
462
+ assert_equal unit1.signature, (0..9).inject(0) {|product, n| product + 20**n}
463
+ end
464
+
465
+ def test_subtract_like_units
466
+ unit1 = Unit.new("1 mm")
467
+ unit2 = Unit.new("2 mm")
468
+ assert_nothing_raised {
469
+ assert_equal(-1, (unit1-unit2).scalar)
470
+ }
471
+ end
472
+
473
+ def test_subtract_unlike_units
474
+ unit1 = Unit.new("1 mm")
475
+ unit2 = Unit.new("2 ml")
476
+ assert_raise(ArgumentError) {(unit1-unit2).scalar}
477
+ end
478
+
479
+ def test_multiply
480
+ unit1 = Unit.new("1 m/ms")
481
+ unit2 = Unit.new("1 m/ms")
482
+ assert_nothing_raised {
483
+ unit3 = unit1 * unit2
484
+ assert_equal Unit.new("1 m^2/ms^2"), unit3
485
+ }
486
+ assert_equal unit1 * 0, '0 m/ms'.unit
487
+ end
488
+
489
+ def test_divide
490
+ unit1 = Unit.new("200 M*g/mol")
491
+ unit2 = Unit.new("200 g/mole")
492
+ assert_nothing_raised {
493
+ unit3 = unit1 / unit2
494
+ assert_equal Unit.new("1 M"), unit3
495
+ }
496
+ assert_equal unit2 / 1, unit2
497
+ unit3 = '0 s'.unit
498
+ assert_raises(ZeroDivisionError) {
499
+ unit1 / unit3
500
+ }
501
+
502
+ assert_raises(ZeroDivisionError) {
503
+ unit1 / 0
504
+ }
505
+ end
506
+
507
+ def test_inverse
508
+ unit1 = Unit.new("1 m")
509
+ unit2 = Unit.new("1 1/m")
510
+ assert_equal unit2, unit1.inverse
511
+ assert_raises((ZeroDivisionError)) { 0.unit.inverse }
512
+ end
513
+
514
+ def test_exponentiate_positive
515
+ unit1 = Unit.new("1 mm")
516
+ unit2 = Unit.new("1 mm^2")
517
+ assert_nothing_raised {
518
+ assert_equal unit2, unit1**2
519
+ }
520
+ end
521
+
522
+ def test_exponentiate_float
523
+ unit1 = Unit.new("1 mm")
524
+ assert_raise(ArgumentError) {unit1**2.5}
525
+ end
526
+
527
+ def test_exponentiate_negative
528
+ unit1 = Unit.new("1 m")
529
+ unit2 = Unit.new("1 m^-2")
530
+ assert_nothing_raised {
531
+ assert_equal unit2, unit1**-2
532
+ }
533
+ assert_raises(ZeroDivisionError) {
534
+ "0 mm".unit**-1
535
+ }
536
+ end
537
+
538
+ def test_exponentiate_zero
539
+ unit1 = Unit.new("10 mm")
540
+ unit2 = Unit.new("1")
541
+ assert_nothing_raised {
542
+ assert_equal unit2, unit1**0
543
+ }
544
+ assert_equal 1, "0 mm".unit**0
545
+ end
546
+
547
+ def test_abs
548
+ unit1 = Unit.new("-1 mm")
549
+ assert_equal 1, unit1.abs
550
+ end
551
+
552
+ def test_ceil
553
+ unit1 = Unit.new("1.1 mm")
554
+ unit2 = Unit.new("2 mm")
555
+ assert_equal unit2, unit1.ceil
556
+ assert_equal(('1 mm'.unit / '1 mm'.unit).ceil, 1)
557
+ assert_equal("11 kg*m".unit, ("1003 kg*m".unit / 100).ceil)
558
+ end
559
+
560
+ def test_floor
561
+ unit1 = Unit.new("1.1 mm")
562
+ unit2 = Unit.new("1 mm")
563
+ assert_equal unit2, unit1.floor
564
+ assert_equal(('1 mm'.unit / '1 mm'.unit).floor, 1)
565
+ end
566
+
567
+ def test_to_int
568
+ assert_raises(RuntimeError) {Unit.new("1.1 mm").to_i}
569
+ assert_nothing_raised {Unit.new(10.5).to_i}
570
+ end
571
+
572
+ def test_truncate
573
+ unit1 = Unit.new("1.1 mm")
574
+ unit2 = Unit.new("1 mm")
575
+ assert_equal unit2, unit1.truncate
576
+ assert_equal((unit1/unit2).truncate, 1)
577
+ end
578
+
579
+ def test_round
580
+ unit1 = Unit.new("1.1 mm")
581
+ unit2 = Unit.new("1 mm")
582
+ assert_equal unit2, unit1.round
583
+ assert_equal((unit1/unit2).round, 1)
584
+ end
585
+
586
+ def test_zero?
587
+ unit1 = Unit.new("0")
588
+ assert unit1.zero?
589
+ end
590
+
591
+ def test_nonzero?
592
+ unit1 = Unit.new("0")
593
+ unit2 = Unit.new("1 mm")
594
+ assert_nil unit1.nonzero?
595
+ assert_equal unit2, unit2.nonzero?
596
+ end
597
+
598
+ def test_equality
599
+ unit1 = Unit.new("1 cm")
600
+ unit2 = Unit.new("10 mm")
601
+ assert unit1 == unit2
602
+ end
603
+
604
+ def test_temperature_conversions
605
+ assert_raises(ArgumentError) { '-1 tempK'.unit}
606
+ assert_raises(ArgumentError) { '-1 tempR'.unit}
607
+ assert_raises(ArgumentError) { '-1000 tempC'.unit}
608
+ assert_raises(ArgumentError) { '-1000 tempF'.unit}
609
+
610
+ assert_in_delta '32 tempF'.unit.base_scalar, '0 tempC'.unit.base_scalar, 0.01
611
+ assert_in_delta '0 tempC'.unit.base_scalar, '32 tempF'.unit.base_scalar, 0.01
612
+ assert_in_delta '0 tempC'.unit.base_scalar, '273.15 tempK'.unit.base_scalar, 0.01
613
+ assert_in_delta '0 tempC'.unit.base_scalar, '491.67 tempR'.unit.base_scalar, 0.01
614
+
615
+ a = '10 degC'.unit
616
+ assert_equal a >> 'tempC', '-263.15 tempC'.unit
617
+ assert_equal a >> 'tempK', '10 tempK'.unit
618
+ assert_equal a >> 'tempR', '18 tempR'.unit
619
+ assert_equal a >> 'tempF', '-441.67 tempF'.unit
620
+
621
+ unit1 = '37 tempC'.unit
622
+ assert_equal unit1 >> 'tempF' >> 'tempK' >> 'tempR' >> 'tempC', unit1
623
+
624
+ a = '100 tempF'.unit
625
+ b = '10 degC'.unit
626
+ c = '50 tempF'.unit
627
+ d = '18 degF'.unit
628
+ assert_equal('118 tempF'.unit,a+b)
629
+ assert_equal b+a, '118 tempF'.unit
630
+ assert_equal a-b, '82 tempF'.unit
631
+ assert_in_delta((a-c).scalar, '50 degF'.unit.scalar, 0.01)
632
+ assert_equal b+d, '20 degC'.unit
633
+
634
+ assert_raises(ArgumentError) { a * b }
635
+ assert_raises(ArgumentError) { a / b }
636
+ assert_raises(ArgumentError) { a ** 2 }
637
+ assert_raises(ArgumentError) { c - '400 degK'.unit}
638
+ assert_equal a, a.to('tempF')
639
+ end
640
+
641
+ def test_feet
642
+ unit1 = Unit.new("6'6\"")
643
+ assert_in_delta 6.5, unit1.scalar, 0.01
644
+ unit2 = "6'".unit
645
+ assert_equal unit2, '6 feet'.unit
646
+ unit3 = '6"'.unit
647
+ assert_equal unit3, '6 inch'.unit
648
+
649
+ end
650
+
651
+ def test_pounds
652
+ unit1 = Unit.new("8 pounds, 8 ounces")
653
+ assert_in_delta 8.5, unit1.scalar, 0.01
654
+ assert_equal '150#'.unit, '150 lbs'.unit
655
+ end
656
+
657
+ # these units are 'ambiguous' and could be mis-parsed
658
+ def test_parse_tricky_units
659
+ unit1 = Unit.new('1 mm') #sometimes parsed as 'm*m'
660
+ assert_equal ['<milli>','<meter>'], unit1.numerator
661
+ unit2 = Unit.new('1 cd') # could be a 'centi-day' instead of a candela
662
+ assert_equal ['<candela>'], unit2.numerator
663
+ unit3 = Unit.new('1 min') # could be a 'milli-inch' instead of a minute
664
+ assert_equal ['<minute>'], unit3.numerator
665
+ unit4 = Unit.new('1 ft') # could be a 'femto-ton' instead of a foot
666
+ assert_equal ['<foot>'], unit4.numerator
667
+ unit5 = "1 atm".unit
668
+ assert_equal ['<atm>'], unit5.numerator
669
+ unit6 = "1 doz".unit
670
+ assert_equal ['<dozen>'], unit6.numerator
671
+ end
672
+
673
+ def test_to_s
674
+ unit1 = Unit.new("1")
675
+ assert_equal "1", unit1.to_s
676
+ unit2 = Unit.new("mm")
677
+ assert_equal "1 mm", unit2.to_s
678
+ assert_equal "0.04 in", unit2.to_s("%0.2f in")
679
+ assert_equal "0.1 cm", unit2.to_s("cm")
680
+ unit3 = Unit.new("1 mm")
681
+ assert_equal "1 mm", unit3.to_s
682
+ assert_equal "0.04 in", unit3.to_s("%0.2f in")
683
+ unit4 = Unit.new("1 mm^2")
684
+ assert_equal "1 mm^2", unit4.to_s
685
+ unit5 = Unit.new("1 mm^2 s^-2")
686
+ assert_equal "1 mm^2/s^2", unit5.to_s
687
+ unit6= Unit.new("1 kg*m/s")
688
+ assert_equal "1 kg*m/s", unit6.to_s
689
+ unit7= Unit.new("1 1/m")
690
+ assert_equal "1 1/m", unit7.to_s
691
+ assert_equal("1.5 mm", Unit.new("1.5 mm").to_s)
692
+ assert_equal("1.5 mm", "#{Unit.new('1.5 mm')}")
693
+ end
694
+
695
+ def test_to_feet_inches
696
+ unit1 = Unit.new("6'5\"")
697
+ assert_equal "6'5\"", unit1.to_s(:ft)
698
+ assert_raises(ArgumentError) {
699
+ unit1 = Unit.new("1 kg")
700
+ unit1.to_s(:ft)
701
+ }
702
+ end
703
+
704
+ def test_to_lbs_oz
705
+ unit1 = Unit.new("8 lbs 8 oz")
706
+ assert_equal "8 lbs, 8 oz", unit1.to_s(:lbs)
707
+ assert_raises(ArgumentError) {
708
+ unit1 = Unit.new("1 m")
709
+ unit1.to_s(:lbs)
710
+ }
711
+ end
712
+
713
+ def test_add_units
714
+ a = Unit.new("1 inchworm")
715
+ assert_equal "1 inworm", a.to_s
716
+ end
717
+
718
+ def test_ideal_gas_law
719
+ p = Unit "100 kPa"
720
+ v = Unit "1 m^3"
721
+ n = Unit "1 mole"
722
+ r = Unit "8.31451 J/mol*degK"
723
+ t = ((p*v)/(n*r)).to('tempK')
724
+ assert_in_delta 12027.16,t.base_scalar, 0.1
725
+ end
726
+
727
+
728
+ def test_eliminate_terms
729
+ a = ['<meter>','<meter>','<kelvin>','<second>']
730
+ b = ['<meter>','<meter>','<second>']
731
+ h = Unit.eliminate_terms(1,a,b)
732
+ assert_equal ['<kelvin>'], h[:numerator]
733
+ end
734
+
735
+ def test_to_base_consistency
736
+ a = "1 W*m/J*s".unit
737
+ assert_equal a.signature, a.to_base.signature
738
+ end
739
+
740
+ def test_unit_roots
741
+ unit1 = Unit "2 m*J*kg"
742
+ unit2 = Unit "4 m^2*J^2*kg^2"
743
+ unit3 = Unit "8 m^3*J^3*kg^3"
744
+ assert_equal unit2**(1/2), unit1
745
+ assert_equal unit3**(1/3), unit1
746
+ end
747
+
748
+ def test_inspect
749
+ unit1 = Unit "1 mm"
750
+ assert_equal "1 mm", unit1.inspect
751
+ assert_not_equal "1.0 mm", unit1.inspect(:dump)
752
+ end
753
+
754
+ def test_to_f
755
+ assert_equal 1, 1.unit.to_f
756
+ assert_raises(RuntimeError) {
757
+ assert_equal 1, "1 mm".unit.to_f
758
+ }
759
+ end
760
+
761
+ def test_exponentiate_float2
762
+ assert_equal "2 m".unit, "4 m^2".unit**(0.5)
763
+ assert_raises(ArgumentError) { "1 mm".unit**(2/3)}
764
+ assert_raises(ArgumentError) { "1 mm".unit**("A")}
765
+
766
+ end
767
+
768
+ def test_range
769
+ a = Unit "1 mm"
770
+ b = Unit "3 mm"
771
+ c = (a..b).to_a
772
+ assert_equal ["1 mm".unit, "2 mm".unit, "3 mm".unit], c
773
+ end
774
+
775
+ def test_scientific
776
+ a = Unit "1e6 cells"
777
+ assert_equal 1e6, a.scalar
778
+ assert_equal "cells", a.units
779
+ end
780
+
781
+ if defined?(Uncertain)
782
+ def test_uncertain
783
+ a = '1 +/- 1 mm'.unit
784
+ assert_equal a.to_s, '1 +/- 1 mm'
785
+ end
786
+ end
787
+
788
+ def test_format
789
+ assert_equal "%0.2f" % "1 mm".unit, "1.00 mm"
790
+ end
791
+
792
+ def test_bad_units
793
+ assert_raises(ArgumentError) { '1 doohickey / thingamabob'.unit}
794
+ assert_raises(ArgumentError) { '1 minimeter'.unit}
795
+ end
796
+
797
+ def test_currency
798
+ assert_nothing_raised {"$1".unit}
799
+ end
800
+
801
+ def test_kind
802
+ a = "1 mm".unit
803
+ assert_equal a.kind, :length
804
+ end
805
+
806
+ def test_percent
807
+ assert_nothing_raised {
808
+ "1 percent".unit
809
+ "1%".unit
810
+ "0.01%".unit
811
+ }
812
+ a = '100 ml'.unit
813
+ b = '50%'.unit
814
+ c = a*b >> 'ml'
815
+ assert c =~ a
816
+ assert_in_delta '50 ml'.unit.scalar, c.scalar, 0.0001
817
+ end
818
+
819
+ def test_parse
820
+ assert_nothing_raised { "1 1/m".unit }
821
+ assert_raises(ArgumentError) { "3 s/s/ft".unit }
822
+ assert_raises(ArgumentError) { "3 s**2|,s**2".unit }
823
+ assert_raises(ArgumentError) { "3 s**2 4s s**2".unit }
824
+ assert_raises(ArgumentError) { "3 s 5^6".unit }
825
+ assert_raises(ArgumentError) { "".unit }
826
+ end
827
+
828
+ def test_time_conversions
829
+ today = 'now'.to_time
830
+ assert_equal today,@april_fools
831
+ last_century = today - '150 years'.unit
832
+ assert_equal last_century.to_date, '1856-04-01'.to_date
833
+ end
834
+
835
+ def test_coercion
836
+ assert_nothing_raised { 1.0 * '1 mm'.unit}
837
+ assert_nothing_raised { '1 mm'.unit * 1.0}
838
+ end
839
+
840
+ def test_zero
841
+ assert_nothing_raised { Unit.new(0) }
842
+ end
843
+
844
+ def test_divide_results_in_unitless
845
+ a = '10 mg/ml'.unit
846
+ b = '10 mg/ml'.unit
847
+ assert_equal a/b, 1
848
+ end
849
+
850
+ def test_wt_percent
851
+ a = '1 wt%'.unit
852
+ b = '1 g/dl'.unit
853
+ assert_equal a,b
854
+ end
855
+
856
+ def test_parse_durations
857
+ assert_equal "1:00".unit, '1 hour'.unit
858
+ assert_equal "1:30".unit, "1.5 hour".unit
859
+ assert_equal "1:30:30".unit, "1.5 hour".unit + '30 sec'.unit
860
+ assert_equal "1:30:30,200".unit, "1.5 hour".unit + '30 sec'.unit + '200 usec'.unit
861
+ end
862
+
863
+ def test_coercion_2
864
+ a = Dummy.new
865
+ b = '1 mm'.unit
866
+ assert_equal '2 mm'.unit, b + a
867
+ end
868
+
869
+ def test_create_with_other_unit
870
+ a = '1 g'.unit
871
+ b = 0.unit(a)
872
+ assert_equal b, '0 g'.unit
873
+ end
874
+
875
+ def test_sqrt
876
+ a = '-9 mm^2'.unit
877
+ b = a**(0.5)
878
+ assert_in_delta Math.sqrt(a).to_unit.scalar.real, b.scalar.real, 0.00001
879
+ # ruby 1.8.x uses .image while 1.9.x uses .imaginary
880
+ if Complex.instance_methods.include?(:imaginary)
881
+ assert_in_delta Math.sqrt(a).to_unit.scalar.imaginary, b.scalar.imaginary, 0.00001
882
+ else
883
+ assert_in_delta Math.sqrt(a).to_unit.scalar.image, b.scalar.image, 0.00001
884
+ end
885
+ end
886
+
887
+ def test_div
888
+ assert_equal 11,"23 m".unit.div('2 m'.unit)
889
+ end
890
+
891
+ def test_divmod
892
+ assert_equal [277,1], 555.unit('mm').divmod(2.unit('mm'))
893
+ assert_equal [277, 0.0010000000000000373], '0.555 m'.unit.divmod('2 mm'.unit)
894
+ assert_raises(ArgumentError) { '1 m'.unit.divmod('1 kg'.unit) }
895
+ end
896
+
897
+ if Math.respond_to?(:cbrt)
898
+ def test_cbrt
899
+ assert_in_delta '2 mm'.to_unit, Math.cbrt('8 mm^3'.to_unit), 0.0001
900
+ end
901
+ end
902
+
903
+ def test_hypot
904
+ assert_equal Math.hypot('3 mm'.unit,'4 mm'.unit), '5 mm'.unit
905
+ assert_raises(ArgumentError) { Math.hypot('3 mm'.unit, '4 kg'.unit)}
906
+ end
907
+
908
+ def test_complex
909
+ assert_equal '1+1i mm'.unit.scalar, Complex(1,1)
910
+ assert_equal '1+1i'.unit.scalar, Complex(1,1)
911
+ assert_raises(RuntimeError) { '1+1i mm'.unit.to_c}
912
+ end
913
+
914
+ def test_atan2
915
+ assert_equal Math.atan2('1 mm'.unit,'1 mm'.unit), Math.atan2(1,1)
916
+ assert_raises(ArgumentError) {Math.atan2('1 mm'.unit, '1 lb'.unit)}
917
+ assert_raises(ArgumentError) {Math.atan2('1 mm'.unit, 1)}
918
+ end
919
+
920
+ def test_rational_units
921
+ assert_equal '1/4 cup'.unit, '0.25 cup'.unit
922
+ assert_equal '1/4 in/s'.unit, '0.25 in/s'.unit
923
+ assert_equal '1/4'.unit, 0.25
924
+ end
925
+
926
+ def test_to_date
927
+ a = Time.now
928
+ assert_equal a.send(:to_date), Date.today
929
+ end
930
+
931
+ def test_natural_language
932
+ assert_equal Unit.parse("10 mm in cm"), '10 mm'.unit.to('cm')
933
+ end
934
+
935
+ def test_round_pounds
936
+ assert_equal '1 lbs'.unit, '1.1 lbs'.unit.round
937
+ end
938
+
939
+ def test_explicit_init
940
+ assert_equal '1 lbf'.unit, '1 <pound-force>'.unit
941
+ assert_equal '1 lbs'.unit, '1 <pound>'.unit
942
+ assert_equal('1 kg*m'.unit, '1 <kilogram>*<meter>'.unit)
943
+ end
944
+
945
+ def test_format_nil_string
946
+ assert_nothing_raised {"" % nil}
947
+ assert_nothing_raised {"" % false}
948
+ end
949
+
950
+ def test_to_s_cache
951
+ Unit.clear_cache
952
+ a = Unit.new('1 mm')
953
+ a.to_s # cache the conversion to itself
954
+ b = Unit.new('2 mm')
955
+ assert_equal('2 mm', b.to_s)
956
+ assert_equal('0.001 m', a.to_s('m'))
957
+ assert_equal('0.001 m', a.output['m'])
958
+ end
959
+
960
+ def test_version
961
+ assert_equal('1.2.0.a', Unit::VERSION)
962
+ end
963
+
964
+ def test_negation
965
+ a = 1.to_unit
966
+ assert_equal(a.class, (1-a).class)
967
+ end
968
+
969
+ def test_degree
970
+ assert "100 tempF".unit.degree?
971
+ assert "100 degC".unit.degree?
972
+ assert !"1 mm".unit.degree?
973
+ end
974
+
975
+ def test_temperature
976
+ assert "100 tempF".unit.temperature?
977
+ assert !"100 degC".unit.temperature?
978
+ assert !"1 mm".unit.temperature?
979
+ end
980
+
981
+ end
982
+