quantity 0.0.0 → 0.1.1
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/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
|