quantity 0.0.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +204 -0
- data/VERSION +1 -1
- data/lib/quantity.rb +365 -6
- data/lib/quantity/all.rb +8 -0
- data/lib/quantity/dimension.rb +269 -0
- data/lib/quantity/dimension/base.rb +54 -0
- data/lib/quantity/systems/enumerable.rb +12 -0
- data/lib/quantity/systems/imperial.rb +10 -0
- data/lib/quantity/systems/information.rb +30 -0
- data/lib/quantity/systems/si.rb +105 -0
- data/lib/quantity/systems/us.rb +19 -0
- data/lib/quantity/unit.rb +309 -17
- data/lib/quantity/version.rb +1 -1
- metadata +11 -10
- data/lib/quantity/unit/current.rb +0 -9
- data/lib/quantity/unit/length.rb +0 -9
- data/lib/quantity/unit/luminosity.rb +0 -9
- data/lib/quantity/unit/mass.rb +0 -9
- data/lib/quantity/unit/substance.rb +0 -9
- data/lib/quantity/unit/temperature.rb +0 -9
- data/lib/quantity/unit/time.rb +0 -9
data/lib/quantity/all.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'quantity'
|
2
|
+
require 'quantity/systems/si'
|
3
|
+
# this could just as well be 'imperial', had to pick something.
|
4
|
+
require 'quantity/systems/us'
|
5
|
+
require 'quantity/systems/information'
|
6
|
+
require 'quantity/systems/enumerable'
|
7
|
+
# other isn't done yet
|
8
|
+
#require 'quantity/systems/other'
|
@@ -0,0 +1,269 @@
|
|
1
|
+
class Quantity
|
2
|
+
# A Dimension is a measurable something. It is often
|
3
|
+
# called a 'base quantity'.
|
4
|
+
#
|
5
|
+
# There are 8 base physical dimensions: Length, Mass,
|
6
|
+
# Current, Mass, Time, Temperature, Substance, and Luminosity.
|
7
|
+
# There are additionally a number of other useful dimensions,
|
8
|
+
# such as Enumerable items (think of 'dozen' as a unit of
|
9
|
+
# measurement).
|
10
|
+
#
|
11
|
+
# From these base dimensions all other measurement dimensions
|
12
|
+
# can be constructed. For example, speed is Length / Time.
|
13
|
+
# Such dimensions are called compound dimensions.
|
14
|
+
#
|
15
|
+
class Dimension
|
16
|
+
### Class-level methods/vars
|
17
|
+
# all known dimensions
|
18
|
+
@@dimensions = {}
|
19
|
+
|
20
|
+
# The dimension for a given symbol, dimension, or string description
|
21
|
+
# of a compound dimension
|
22
|
+
# @param [String Symbol Dimension]
|
23
|
+
# @return [Dimension]
|
24
|
+
def self.for(to)
|
25
|
+
case to
|
26
|
+
when Dimension
|
27
|
+
if @@dimensions[to.name]
|
28
|
+
@@dimensions[to.name]
|
29
|
+
else
|
30
|
+
add_alias to, to.name
|
31
|
+
to
|
32
|
+
end
|
33
|
+
when Symbol
|
34
|
+
if @@dimensions.has_key?(to)
|
35
|
+
@@dimensions[to]
|
36
|
+
else
|
37
|
+
# it's possible we have a non-normalized form, such as mass*length
|
38
|
+
# instead of length * mass
|
39
|
+
@@dimensions[string_form(parse_string_form(to)).to_sym]
|
40
|
+
end
|
41
|
+
when Array
|
42
|
+
@@dimensions[string_form(to).to_sym]
|
43
|
+
else
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# DSL component to add a new dimension. Dimension name, reference unit,
|
49
|
+
# and aliases. This should be the only way that dimensions are added.
|
50
|
+
# @param [Symbol] name
|
51
|
+
# @param [[Symbol String]] *aliases
|
52
|
+
def self.add_dimension(name, *aliases)
|
53
|
+
dim = nil
|
54
|
+
if name.is_a?(Dimension)
|
55
|
+
dim = name
|
56
|
+
name.name = aliases.first if aliases.first
|
57
|
+
else
|
58
|
+
dim = self.for(name) || self.new({ :name => aliases.first , :description => name})
|
59
|
+
self.add_alias(dim,name)
|
60
|
+
end
|
61
|
+
unless (dim.class == Dimension)
|
62
|
+
dim.name = dim.class.name.downcase.split(/::/).last.to_sym
|
63
|
+
self.add_alias(dim,dim.name)
|
64
|
+
end
|
65
|
+
self.add_alias(dim,*aliases)
|
66
|
+
dim
|
67
|
+
end
|
68
|
+
|
69
|
+
# Register a dimension to the known list, with the given aliases
|
70
|
+
# @param [Dimension]
|
71
|
+
# @param [[*names]]
|
72
|
+
def self.add_alias(dimension, *names)
|
73
|
+
names.each do |name|
|
74
|
+
raise ArgumentError, "Invalid dimension alias: #{name}" unless (name.to_s =~ /^(\^|\/)/).nil?
|
75
|
+
@@dimensions[name] = dimension
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# All known dimensions
|
80
|
+
# @return [[Dimension]]
|
81
|
+
def self.all_dimensions
|
82
|
+
@@dimensions.values.uniq
|
83
|
+
end
|
84
|
+
|
85
|
+
# Reset the known dimensions. Generally only used for testing.
|
86
|
+
def self.__reset!
|
87
|
+
@@dimensions = {}
|
88
|
+
end
|
89
|
+
|
90
|
+
DimensionComponent = Struct.new(:dimension, :power)
|
91
|
+
DimensionComponent.class_eval do
|
92
|
+
def inspect
|
93
|
+
"#{dimension.inspect}^#{power}"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
attr_reader :numerators, :denominators
|
98
|
+
attr_accessor :name
|
99
|
+
### Instance-level methods/vars
|
100
|
+
|
101
|
+
# A new dimension
|
102
|
+
# @param [Hash] options
|
103
|
+
# @return Dimension
|
104
|
+
def initialize(opts)
|
105
|
+
if (opts[:description])
|
106
|
+
(@numerators,@denominators) = Dimension.parse_string_form(opts[:description])
|
107
|
+
elsif (opts[:numerators])
|
108
|
+
@numerators = opts[:numerators]
|
109
|
+
@denominators = opts[:denominators]
|
110
|
+
else
|
111
|
+
raise ArgumentError, "Invalid options for dimension constructors"
|
112
|
+
end
|
113
|
+
raise ArgumentError, "Dimensions require a numerator" unless @numerators.first.dimension
|
114
|
+
@name = opts[:name] || string_form.to_sym
|
115
|
+
Dimension.add_alias(self,@name)
|
116
|
+
Dimension.add_alias(self,string_form.to_sym)
|
117
|
+
end
|
118
|
+
|
119
|
+
def to_s
|
120
|
+
@name.to_s
|
121
|
+
end
|
122
|
+
|
123
|
+
# Dimensional multiplication
|
124
|
+
# @param [Dimension] other
|
125
|
+
# @return [Dimension]
|
126
|
+
def *(other)
|
127
|
+
raise ArgumentError, "Cannot multiply #{self} and #{other.class}" unless other.is_a?(Dimension)
|
128
|
+
(new_n, new_d) = Dimension.reduce(@numerators + other.numerators, @denominators + other.denominators)
|
129
|
+
existing = Dimension.for([new_n,new_d])
|
130
|
+
existing.nil? ? Dimension.new({:numerators => new_n, :denominators => new_d}) : existing
|
131
|
+
end
|
132
|
+
|
133
|
+
# Dimensional division
|
134
|
+
# @param [Dimension] other
|
135
|
+
# @return [Dimension]
|
136
|
+
def /(other)
|
137
|
+
raise ArgumentError, "Cannot divide #{self} by #{other.class}" unless other.is_a?(Dimension)
|
138
|
+
(new_n, new_d) = Dimension.reduce(@numerators + other.denominators, @denominators + other.numerators)
|
139
|
+
existing = Dimension.for([new_n,new_d])
|
140
|
+
existing.nil? ? Dimension.new({:numerators => new_n, :denominators => new_d}) : existing
|
141
|
+
end
|
142
|
+
|
143
|
+
# Dimensional exponentiation
|
144
|
+
# @param [Numeric] other
|
145
|
+
# @return [Dimension]
|
146
|
+
def **(other)
|
147
|
+
raise ArgumentError, "Dimensions can only be raised to whole powers" unless other.is_a?(Fixnum) && other > 0
|
148
|
+
other == 1 ? self : self * self**(other-1)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Whether or not this is a compound representation of a base dimension
|
152
|
+
# @return [Boolean]
|
153
|
+
def is_base?
|
154
|
+
@denominators.size == 0 && @numerators.size == 1 && @numerators.first.power == 1
|
155
|
+
end
|
156
|
+
|
157
|
+
# Spaceship operator for comparable.
|
158
|
+
# @param [Any] other
|
159
|
+
# @return [-1 0 1]
|
160
|
+
def <=>(other)
|
161
|
+
if other.is_a?(Dimension)
|
162
|
+
if self.is_base? && other.is_base?
|
163
|
+
name.to_s <=> other.name.to_s
|
164
|
+
elsif other.is_base?
|
165
|
+
1
|
166
|
+
else
|
167
|
+
string_form <=> other.string_form
|
168
|
+
end
|
169
|
+
else
|
170
|
+
nil
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# Returns a developer-friendly representation of this value.
|
175
|
+
#
|
176
|
+
# The string will be of the format `#<Quantity::Dimension::0x12345678(...)>`,
|
177
|
+
# where `...` is the string returned by #to_s.
|
178
|
+
#
|
179
|
+
# @return [String]
|
180
|
+
def inspect
|
181
|
+
sprintf("#<%s:%#0x %s (%s)>", self.class.name, object_id, string_form, @name)
|
182
|
+
end
|
183
|
+
|
184
|
+
|
185
|
+
# Returns a vaguely human-readable and parsable description of this dimension
|
186
|
+
# @return [String]
|
187
|
+
def string_form
|
188
|
+
Dimension.string_form(@numerators,@denominators)
|
189
|
+
end
|
190
|
+
|
191
|
+
# A vaguely human-readable, vaguely machine-readable string description of
|
192
|
+
# a set of numerators and denominators.
|
193
|
+
# @private
|
194
|
+
# @ param [[DimensionComponent],[DimensionComponent]]
|
195
|
+
# @return [String]
|
196
|
+
def self.string_form(numerators, denominators = nil)
|
197
|
+
# We sometimes get [numerators,denominators],nil
|
198
|
+
(numerators,denominators) = numerators if (numerators.first.is_a?(Array))
|
199
|
+
string = ""
|
200
|
+
string_thunk = lambda do | array |
|
201
|
+
array.each_with_index do | component, n |
|
202
|
+
string << component.dimension.to_s
|
203
|
+
(string << '^' << component.power.to_s) if component.power.to_i > 1
|
204
|
+
string << '*' if n < array.size - 1
|
205
|
+
end
|
206
|
+
end
|
207
|
+
string_thunk.call(numerators)
|
208
|
+
string << "/" if denominators && denominators.size > 0
|
209
|
+
string_thunk.call(denominators) if denominators
|
210
|
+
string
|
211
|
+
end
|
212
|
+
|
213
|
+
# Parse the output of string_form into numerators and denominators
|
214
|
+
# @param [String] string
|
215
|
+
# @return [[DimensionComponent],[DimensionComponent]]
|
216
|
+
# @private
|
217
|
+
def self.parse_string_form(serialized)
|
218
|
+
parse_thunk = lambda do | string |
|
219
|
+
components = []
|
220
|
+
if !string.nil?
|
221
|
+
string.split(/\*/).each do | component |
|
222
|
+
(dimension, power) = component.split(/\^/)
|
223
|
+
components << DimensionComponent.new(dimension.to_sym,power.nil? ? 1 : power.to_i)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
components
|
227
|
+
end
|
228
|
+
(top, bottom) = serialized.to_s.split(/\//)
|
229
|
+
Dimension.reduce(parse_thunk.call(top), parse_thunk.call(bottom))
|
230
|
+
end
|
231
|
+
|
232
|
+
# Returns numerators and denominators that represent the reduced form of the given
|
233
|
+
# numerators and denominators
|
234
|
+
# @return [[Array],[Array]]
|
235
|
+
# @private
|
236
|
+
def self.reduce(numerators,denominators)
|
237
|
+
new_numerators = reduce_multiplied_units(numerators)
|
238
|
+
new_denominators = reduce_multiplied_units(denominators)
|
239
|
+
|
240
|
+
new_numerators.each_with_index do | comp, i |
|
241
|
+
new_denominators.each_with_index do | dcomp, j |
|
242
|
+
if dcomp.dimension == comp.dimension
|
243
|
+
diff = [dcomp.power,comp.power].max - (dcomp.power - comp.power).abs
|
244
|
+
dcomp.power -= diff
|
245
|
+
comp.power -= diff
|
246
|
+
new_numerators.delete_at(i) if comp.power <= 0
|
247
|
+
new_denominators.delete_at(j) if dcomp.power <= 0
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
[new_numerators, new_denominators]
|
252
|
+
end
|
253
|
+
|
254
|
+
# Reduce an array of units to its most compact, sorted form
|
255
|
+
# @param [[DimensionComponent]]
|
256
|
+
# @return [[DimensionComponent]]
|
257
|
+
# @private
|
258
|
+
def self.reduce_multiplied_units(array)
|
259
|
+
new = {}
|
260
|
+
array.each do | item |
|
261
|
+
new[item.dimension] = DimensionComponent.new(item.dimension,0) unless new[item.dimension]
|
262
|
+
new[item.dimension].power += item.power
|
263
|
+
end
|
264
|
+
new.values.sort { |a,b| a.dimension.to_s <=> b.dimension.to_s }
|
265
|
+
end
|
266
|
+
|
267
|
+
|
268
|
+
end
|
269
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
#
|
2
|
+
#
|
3
|
+
class Quantity
|
4
|
+
#
|
5
|
+
# This module attempts to enumerate all of simple, base dimensions.
|
6
|
+
# This includes all of the base SI dimensions and some others
|
7
|
+
#
|
8
|
+
class Dimension
|
9
|
+
|
10
|
+
class Length < Quantity::Dimension ; end
|
11
|
+
length = Length.add_dimension :length, :width, :distance
|
12
|
+
|
13
|
+
class Time < Quantity::Dimension ; end
|
14
|
+
time = Time.add_dimension :time
|
15
|
+
|
16
|
+
class Mass < Quantity::Dimension ; end
|
17
|
+
mass = Mass.add_dimension :mass
|
18
|
+
|
19
|
+
class Current < Quantity::Dimension ; end
|
20
|
+
current = Current.add_dimension :current
|
21
|
+
|
22
|
+
class Luminosity < Quantity::Dimension ; end
|
23
|
+
luminosity = Luminosity.add_dimension :luminosity
|
24
|
+
|
25
|
+
class Substance < Quantity::Dimension ; end
|
26
|
+
substance = Substance.add_dimension :substance
|
27
|
+
|
28
|
+
class Temperature < Quantity::Dimension ; end
|
29
|
+
temp = Temperature.add_dimension :temperature
|
30
|
+
|
31
|
+
area = add_dimension length**2, :area
|
32
|
+
|
33
|
+
speed = add_dimension length / time, :speed, :velocity
|
34
|
+
|
35
|
+
accel = add_dimension speed / time, :acceleration
|
36
|
+
|
37
|
+
force = add_dimension mass * accel, :force
|
38
|
+
|
39
|
+
volume = add_dimension length**3, :volume
|
40
|
+
|
41
|
+
class Information < Quantity::Dimension ; end
|
42
|
+
information = Information.add_dimension :information, :data
|
43
|
+
|
44
|
+
# Quantity is the base dimension for the quantity of enumerable objects.
|
45
|
+
# Units are things like '2 dozen'.
|
46
|
+
class Quantity < Quantity::Dimension ; end
|
47
|
+
information = Quantity.add_dimension :quantity, :items, :enumerables
|
48
|
+
|
49
|
+
# Hardly a scientific base measurement, but it comes up a lot
|
50
|
+
class Currency < Dimension ; end
|
51
|
+
currency = Currency.add_dimension :money
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# Imperial versions of british/american customary units
|
2
|
+
class Quantity::Unit
|
3
|
+
add_unit :foot, :length, 304.8, :ft, :feet
|
4
|
+
add_unit :inch, :length, 25.4, :in, :inches
|
5
|
+
add_unit :yard, :length, 914.4, :yd, :yards
|
6
|
+
add_unit :mile, :length, 1_609_344, :miles
|
7
|
+
|
8
|
+
add_unit :pound, :mass, 453592.37, :pounds, :lb, :lbs
|
9
|
+
add_unit :ounce, :mass, 28349.5231, :ounces, :oz
|
10
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Quantity
|
2
|
+
class Unit
|
3
|
+
##
|
4
|
+
# @see http://en.wikipedia.org/wiki/Mebibyte
|
5
|
+
# @see http://en.wikipedia.org/wiki/Units_of_information
|
6
|
+
|
7
|
+
add_unit :bit, :data, 1, :bits
|
8
|
+
add_unit :nibble, :data, 4, :nibbles, :nybble, :nybbles
|
9
|
+
add_unit :byte, :data, 8, :bytes
|
10
|
+
|
11
|
+
add_unit :kilobyte, :data, 8 * 1000, :kb, :kilobytes
|
12
|
+
add_unit :megabyte, :data, 8 * (1000**2), :mb, :megabytes
|
13
|
+
add_unit :gigabyte, :data, 8 * (1000**3), :gb, :gigabytes
|
14
|
+
add_unit :terabyte, :data, 8 * (1000**4), :tb, :terabytes
|
15
|
+
add_unit :petabyte, :data, 8 * (1000**5), :pb, :petabytes
|
16
|
+
add_unit :exabyte, :data, 8 * (1000**6), :exabytes
|
17
|
+
add_unit :zettabyte, :data, 8 * (1000**7), :zettabytes
|
18
|
+
add_unit :yottabyte, :data, 8 * (1000**8), :yottabytes
|
19
|
+
|
20
|
+
add_unit :kibibyte, :data, 8 * 1024, :kibibytes, :KiB, :kib
|
21
|
+
add_unit :mebibyte, :data, 8 * (1024**2), :mebibytes, :MiB, :mib
|
22
|
+
add_unit :gibibyte, :data, 8 * (1024**3), :gibibytes, :GiB, :gib
|
23
|
+
add_unit :tebibyte, :data, 8 * (1024**4), :tebibytes, :TiB, :tib
|
24
|
+
add_unit :pebibyte, :data, 8 * (1024**5), :pebibytes, :PiB, :pib
|
25
|
+
add_unit :exbibyte, :data, 8 * (1024**6), :exbibytes, :EiB, :eib
|
26
|
+
add_unit :zebibyte, :data, 8 * (1024**7), :zebibytes, :ZiB, :zib
|
27
|
+
add_unit :yobibyte, :data, 8 * (1024**8), :yobibytes, :YiB, :yib
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'quantity/dimension/base'
|
2
|
+
|
3
|
+
# SI units for Length, Mass, Luminosity, Current, Substance,
|
4
|
+
# Temperature, and Time. Units from yocto- to yotta- are supplied.
|
5
|
+
#
|
6
|
+
# Also supplied:
|
7
|
+
# * Ångstroms are supplied for Length. (use angstrom or angstroms)
|
8
|
+
# * Tonnes (Metric) are supplied for mass.
|
9
|
+
# * cc's for volume
|
10
|
+
#
|
11
|
+
# Volume (liters) is also part of this, since it follows the same pattern,
|
12
|
+
# even though the SI considers it a derived unit.
|
13
|
+
#
|
14
|
+
# The 'reference' unit is milli-. Units larger than milli-
|
15
|
+
# constructed via Fixnums/Bignums, such as 2.meters, will be stored with
|
16
|
+
# Fixnum / Bignum accuracy. Smaller items, such as 35.femtometers, will
|
17
|
+
# be stored with rationals or floats. Generally speaking, you shouldn't
|
18
|
+
# have to worry about this--use the numbers, and it will Do The Right Thing.
|
19
|
+
# Do remember that you may need to do a .to_f before dividing if that's
|
20
|
+
# what you want.
|
21
|
+
#
|
22
|
+
# @see http://physics.nist.gov/cuu/Units/units.html
|
23
|
+
# @see http://physics.nist.gov/cuu/Units/current.html
|
24
|
+
# @see http://physics.nist.gov/cuu/Units/prefixes.html
|
25
|
+
class Quantity
|
26
|
+
class Unit
|
27
|
+
|
28
|
+
prefixes = {}
|
29
|
+
units = {}
|
30
|
+
aliases = {}
|
31
|
+
|
32
|
+
prefixes['yotta'] = 10 ** 27
|
33
|
+
prefixes['zetta'] = 10 ** 24
|
34
|
+
prefixes['exa'] = 10 ** 21
|
35
|
+
prefixes['peta'] = 10 ** 18
|
36
|
+
prefixes['tera'] = 10 ** 15
|
37
|
+
prefixes['giga'] = 10 ** 12
|
38
|
+
prefixes['mega'] = 10 ** 9
|
39
|
+
prefixes['kilo'] = 10 ** 6
|
40
|
+
prefixes['hecto'] = 10 ** 5
|
41
|
+
prefixes['deca'] = 10 ** 4
|
42
|
+
prefixes[''] = 10 ** 3
|
43
|
+
prefixes['deci'] = 10 ** 2
|
44
|
+
prefixes['centi'] = 10
|
45
|
+
# milli is the reference point for SI-measured units
|
46
|
+
prefixes['milli'] = 1
|
47
|
+
prefixes['micro'] = 10 ** -3
|
48
|
+
prefixes['nano'] = 10 ** -6
|
49
|
+
prefixes['pico'] = 10 ** -9
|
50
|
+
prefixes['femto'] = 10 ** -12
|
51
|
+
prefixes['atto'] = 10 ** -15
|
52
|
+
prefixes['zepto'] = 10 ** -18
|
53
|
+
prefixes['yocto'] = 10 ** -21
|
54
|
+
|
55
|
+
units['meter'] = :length
|
56
|
+
units['gram'] = :mass
|
57
|
+
units['second'] = :time
|
58
|
+
units['kelvin'] = :temperature
|
59
|
+
units['candela'] = :luminosity
|
60
|
+
units['ampere'] = :current
|
61
|
+
units['mole'] = :substance
|
62
|
+
# liter is a special cased, handled separately below
|
63
|
+
|
64
|
+
aliases['ampere'] = ['amp', 'amps', 'A']
|
65
|
+
aliases['liter'] = ['litre', 'litres']
|
66
|
+
aliases['candela'] = ['cd']
|
67
|
+
aliases['mole'] = ['mol']
|
68
|
+
aliases['kelvin'] = ['K']
|
69
|
+
|
70
|
+
units.each do | unit, dimension |
|
71
|
+
prefixes.each do | prefix, value |
|
72
|
+
add_unit "#{prefix + unit}".to_sym, dimension, value, "#{prefix + unit}s".to_sym
|
73
|
+
if aliases[unit]
|
74
|
+
aliases[unit].each do | unit_alias |
|
75
|
+
add_alias "#{prefix + unit}".to_sym, "#{prefix + unit_alias}".to_sym
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
add_alias :kilometer, :km
|
82
|
+
add_alias :centimeter, :cm
|
83
|
+
add_alias :meter, :m
|
84
|
+
add_alias :nanometer, :nm
|
85
|
+
add_alias :millimeter, :mm
|
86
|
+
add_alias :millisecond, :ms
|
87
|
+
add_unit :angstrom, :length, 10 ** -7, :angstroms
|
88
|
+
|
89
|
+
add_alias :kilogram, :kg
|
90
|
+
add_alias :gram, :g
|
91
|
+
add_alias :milligram, :mg
|
92
|
+
add_alias :megagram, :tonne, :tonnes
|
93
|
+
|
94
|
+
|
95
|
+
prefixes.each do | prefix, value |
|
96
|
+
add_unit "#{prefix}liter".to_sym, :volume, value * 1000, "#{prefix}liters".to_sym
|
97
|
+
(aliases['liter']).each do | unit_alias |
|
98
|
+
add_alias "#{prefix}liter".to_sym, "#{prefix + unit_alias}".to_sym
|
99
|
+
end
|
100
|
+
end
|
101
|
+
add_alias :liter, :l
|
102
|
+
add_alias :milliliter, :ml
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|