Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 218 lines (161 sloc) 9.333 kB
27c2eaf @bendiken Created repository.
bendiken authored
1 Quantity.rb: Units and Quantities for Ruby
2 ==========================================
ff0525a @bhuga README fixes
authored
3 Quantity.rb provides first-class support for units and quantities in Ruby.
945a014 @bhuga More cleanup for release
authored
4 The right abstractions for true quantity representation and complex conversions.
ff0525a @bhuga README fixes
authored
5 Hopefully this readme will be all you need, but [there are yardocs](http://quantity.rubyforge.org)
ee32400 @bhuga More housekeeping for first release
authored
6
0e49499 @bhuga A few documentation bugs, and a missed file
authored
7 ## Overview
ee32400 @bhuga More housekeeping for first release
authored
8 require 'quantity/all'
945a014 @bhuga More cleanup for release
authored
9 1.meter #=> 1 meter
10 1.meter.to_feet #=> 3.28083... foot
11 c = 299792458.meters / 1.second #=> 299792458 meter/second
ee32400 @bhuga More housekeeping for first release
authored
12
945a014 @bhuga More cleanup for release
authored
13 newton = 1.meter * 1.kilogram / 1.second**2 #=> 1 meter*kilogram/second^2
14 newton.to_feet #=> 3.28083989501312 foot*kilogram/second^2
15 newton.convert(:feet) #=> 3.28083989501312 foot*kilogram/second^2
404e52f @bhuga README typo
authored
16 jerk_newton = newton / 1.second #=> 1 meter*kilogram/second^3
945a014 @bhuga More cleanup for release
authored
17 jerk_newton * 1.second == newton #=> true
18
19 mmcubed = 1.mm.cubed #=> 1 millimeter^3
20 mmcubed * 1000 == 1.milliliter #=> true
21
22 [1.meter, 1.foot, 1.inch].sort #=> [1 inch, 1 foot, 1 meter]
23
24 m_to_f = Quantity::Unit.for(:meter).convert_proc(:feet)
25 m_to_f.call(1) #=> 3.28083... (or a Rational)
26
27 Quantity.rb provides full-featured support for quantities, units, and
ff0525a @bhuga README fixes
authored
28 dimensions in Ruby. Some terminology:
945a014 @bhuga More cleanup for release
authored
29
30 * Quantity: An amount of a unit, such as 12 meters.
31 * Unit: An amount of a given dimension to be measured, such as 'meter'
32 * Dimension: Some base quantity to be measured, such as 'length'
33
34 Quantities perform complete mathematical operations over their units,
6b637ed @bhuga Major refactoring of dimension specs. No behavior changes.
authored
35 including `+`, `-`, `\*`, `/`, `**`, `%`, `abs`, `divmod`, `<=>`, and negation. Units
36 and the dimensions they measure are fully represented and support `*` and `/`.
945a014 @bhuga More cleanup for release
authored
37
38 Quantity extends Numeric to allow easy creation of quantities, but there
39 are direct interfaces to the library as well.
40
0e49499 @bhuga A few documentation bugs, and a missed file
authored
41 1.meter == Quantity.new(1,Quantity::Unit.for(:meter))
42 1.meter.unit == Quantity::Unit.for(:meter)
945a014 @bhuga More cleanup for release
authored
43 1.meter.unit.dimension == Quantity::Dimension.for(:length)
44
45 See the units section for supported units, and how to add your own.
46
47 Quantities are first-class citizens which do a fair job of imitating
48 Numeric. Quantities support coerce, and can thus be used in almost
49 any situation a numeric can:
50
51 2.5 + 5.meters # => 7.5 meters
52 5 == 5.meters # => true
53
54 ## Status and TODO
55 Quantity.rb is not ready for production use for some areas, but should be
56 fine for simple conversion use cases. If it breaks, please email the
57 author for a full refund.
58
6cbfeda @bhuga Update docs with fixed bug
authored
59 Specifically broken in this version are some operations on named
945a014 @bhuga More cleanup for release
authored
60 higher dimensions:
61
6cbfeda @bhuga Update docs with fixed bug
authored
62 1.liter / 1.second #=> should be 1 liter/second, but explodes
63 1.liter.convert(:'mm^3') / 1.second #=> 1000000.0 millimeter^3/second
64
945a014 @bhuga More cleanup for release
authored
65 If you just work with units derived from the base dimensions, there aren't
ff0525a @bhuga README fixes
authored
66 known bugs. Please add a spec if you find one.
945a014 @bhuga More cleanup for release
authored
67
68 ### TODO
69 * Lots more units are planned.
ff0525a @bhuga README fixes
authored
70 * BigDecimal support a la Rational.
945a014 @bhuga More cleanup for release
authored
71 * Supporting lambdas for unit values
72 * BigDecimal/Rational compatible values for existing units
ff0525a @bhuga README fixes
authored
73 * Some DSL sugar for adding derived dimension units
945a014 @bhuga More cleanup for release
authored
74
75 ## Units
76 Quantity.rb comes with a sizable collection of units, but still needs significant expansion.
77
78 A number of base unit sets exist:
79 require 'quantity/all' #=> load everything. uses US versions of foot, lb, etc
80 require 'quantity/systems/si' #=> load SI
81 require 'quantity/systems/us' #=> load US versions of foot, lb, etc
ff0525a @bhuga README fixes
authored
82 require 'quantity/systems/imperial' #=> load British versions of foot, lb, etc
945a014 @bhuga More cleanup for release
authored
83 require 'quantity/systems/information' #=> bits, bytes, and all that
0e49499 @bhuga A few documentation bugs, and a missed file
authored
84 require 'quantity/systems/enumerable' #=> countable things--dozen, score, etc
945a014 @bhuga More cleanup for release
authored
85
ff0525a @bhuga README fixes
authored
86 Note that US and Imperial conflict with each other. Loading both is unsupported.
945a014 @bhuga More cleanup for release
authored
87
88 Adding your own units is simple:
89
90 Quantity::Unit.add_unit :furlong, :length, 201168, :furlongs
91 1.furlong #=> 1 furlong
92
93 201168 represents 1 furlong in millimeters. Each base dimension, such as length, time,
94 current, temperature, etc, is represented by a reference unit, which is generally the
95 milli-version of the SI unit referencing that domain. [NIST](http://physics.nist.gov/cuu/Units/units.html)
96 has an explanation of how the SI system works, and how all units are actually derived from
97 very few.
98
99 All units for derived dimensions used the derived reference unit. For example, length
100 is referenced to millimeters, so each unit of length is defined in terms of them:
101
102 Quantity::Unit.add_unit :meter, :length, 1000
0e49499 @bhuga A few documentation bugs, and a missed file
authored
103 Quantity::Unit.add_unit :millimeter, :length, 1, :mm
945a014 @bhuga More cleanup for release
authored
104
ff0525a @bhuga README fixes
authored
105 Thus, the base unit for volume is 1 mm^3:
945a014 @bhuga More cleanup for release
authored
106 volume = Quantity::Dimension.add_dimension length**3, :volume
107 ml = Quantity::Dimension.add_unit :milliliter, :volume, 1000, :ml, :milliliters
108 1.mm**3 * 1000 == 1.milliliter #=> true
109
110 See the bugs section for some current issues using units defined on derived dimensions.
111
112 The full list of included base dimensions and their reference units:
113 * :length => :millimeter
114 * :time => :millisecond
115 * :current => :milliampere
116 * :luminosity => :millicandela
117 * :substance => :millimole
118 * :temperature => :millikelvin
119 * :mass => :milligram
120 * :information => :bit # use :megabytes and :mebibytes
121 * :quantity => :item # for countable quantities. units include 1.dozen, for example
122 * :currency => :dollar # These are not really implemented yet
123
ff0525a @bhuga README fixes
authored
124 To determine the base unit for a derived dimension, you can use Quantity.rb itself:
945a014 @bhuga More cleanup for release
authored
125
126 force = Quantity::Dimension.for(:force)
127 newton = 1.meter * 1.kilogram / 1.second**2
128 newton.measures == force #=> true
129 newton_value = newton.to_mm.to_mg.to_ms #=> 1000.0 millimeter*milligram/millisecond^2
130
131 Thus, a newton would be 1000 when added specifically:
132
133 Quantity::Unit.add_unit :newton, :force, 1000, :newtons
134 1.newton == newton #=> true
135
136 ## Dimensions
137 A dimension is a measurable thing, often called a 'base quantity' in scientific literature,
ff0525a @bhuga README fixes
authored
138 but Quantity.rb specifically avoids that nomenclature, reserving 'quantity' for the class
945a014 @bhuga More cleanup for release
authored
139 representing a unit and a value. As always, [wikipedia has the answers.](http://en.wikipedia.org/wiki/Physical_quantity)
140
141 Dimensions are not very useful by themselves, but you can play with them
142 if you want.
143
144 length = Quantity::Dimension.for(:length)
145 time = Quantity::Dimension.for(:time)
146 speed = length / time
147
148 A number of dimensions are enabled by default (see dimension/base.rb).
149
150 A DSL of sorts is provided for declaring dimensions:
151
152 length = Quantity::Dimension.add_dimenson :length
153 area = Quantity::Dimension.add_dimension length**2, :area
154
155 length = Quantity::Dimension.for(:length)
156 area = Quantity::Dimension.for(:area)
157 area == length * length #=> true
158
159 Quantity::Dimension is extended with empty subclasses for some base dimensions,
160 so you can do pattern patching on the class:
161
162 case 1.meter.measures
163 when Quantity::Dimension::Length
164 puts "I am printed"
165 end
166
167 ## I just want to convert things, this is all just too much
168 Quantity.rb provides you the ability to intuitively create the conversions
169 your application needs, and then bypass the rest of the library.
170
171 m_to_f = 1.meter.measures.convert_proc(:feet)
172 m_to_f.call(5) # => 5 meters in feet
173
ff0525a @bhuga README fixes
authored
174 This Proc object has been broken down into a single division; it no longer references
175 any units, dimensions, or quantities. It's hard to be faster in pure Ruby.
945a014 @bhuga More cleanup for release
authored
176
0e49499 @bhuga A few documentation bugs, and a missed file
authored
177 ### On precision and speed
178
179 By default, whatever Numeric you are using will be the stored value for the
180 quantity.
181
182 5.meters
183 Rational(5).meters
184 5.0.meters
185
186 This value will be held. However, divisions are required for conversions,
187 and the default is to force values into floats.
188
189 If accuracy is required, just require 'rational'. If Rational is defined,
190 you'll get rationals instead of divided floats everywhere. In tests, this
191 is an order of magnitude slower.
945a014 @bhuga More cleanup for release
authored
192
193 ## 'Why' and previous work
194 This is by no means the first unit conversion/quantity library for Ruby, but
195 none of the existing ones scratched my itch just right. My goal is that this will
196 be the last one I (and you) need. The abstractions go all the way down, and
ff0525a @bhuga README fixes
authored
197 any conceivable conversion or munging functionality should be buildable on top
945a014 @bhuga More cleanup for release
authored
198 of this.
199
200 Inspiration comes from:
201
202 * [Quanty](http://narray.rubyforge.org/quanty/quanty-en.html)
8f9c041 @bhuga README typo
authored
203 Why oh why did they involve yacc?
945a014 @bhuga More cleanup for release
authored
204 * [Ruby Units](http://ruby-units.rubyforge.org/ruby-units/)
205 * [Alchemist](http://github.com/toastyapps/alchemist)
27c2eaf @bendiken Created repository.
bendiken authored
206
207 Authors
208 -------
209
210 * [Ben Lavender](mailto:blavender@gmail.com) - <http://bhuga.net/>
211 * [Arto Bendiken](mailto:arto.bendiken@gmail.com) - <http://ar.to/>
acea5e4 @bhuga Add Matt Todd to the contributors list
authored
212 * [Matt Todd](mtodd@highgroove.com) - <http://maraby.org/>
27c2eaf @bendiken Created repository.
bendiken authored
213 License
214 -------
215
216 Quantity.rb is free and unencumbered public domain software. For more
217 information, see <http://unlicense.org/> or the accompanying UNLICENSE file.
Something went wrong with that request. Please try again.