uom 1.2.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.
@@ -0,0 +1,4 @@
1
+ === 1.2.1 / 2010-09-30
2
+
3
+ * Initial public release
4
+
data/LEGAL ADDED
@@ -0,0 +1,5 @@
1
+ LEGAL NOTICE INFORMATION
2
+ ------------------------
3
+
4
+ All the files in this distribution are covered under either the MIT
5
+ license (see the file LICENSE).
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2010 Oregon Health & Science University Knight Cancer Institute
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,102 @@
1
+ UOM: Unit of Measure library
2
+ ============================
3
+
4
+ **Git**: [http://github.com/caruby/uom](http://github.com/caruby/uom)
5
+ **Author**: OHSU Knight Cancer Institute
6
+ **Copyright**: 2010
7
+ **License**: MIT License
8
+ **Latest Version**: 1.2.1
9
+ **Release Date**: September 30th 2010
10
+
11
+ Synopsis
12
+ --------
13
+
14
+ UOM implements Units of Measurement based on the
15
+ [http://physics.nist.gov/Pubs/SP330/sp330.pdf](International System of Units) (SI).
16
+ The base SI units, metric scalar factors and all possible combinations of these units
17
+ are supported out of the box.
18
+
19
+ Common alternative non-metric measurement systems, e.g. US Customary units, are
20
+ supported with conversions between these units and the SI units.
21
+ Additional units can be defined with conversion to an existing unit.
22
+ UOM infers full conversion capability between units of the same dimension from
23
+ the minimal number of conversion definitions.
24
+
25
+ Arithmetic operations between UOM Measurement objects converts the measurement units
26
+ and scalar factors as necessary, including unit products, quotients and powers of
27
+ arbitrary complexity.
28
+
29
+ Feature List
30
+ ------------
31
+
32
+ 1. Built-in support for standard scientific units
33
+
34
+ 2. Conversion between arbitrary unit combinations
35
+
36
+ 3. Custom unit definition
37
+
38
+ 4. Measurement parser
39
+
40
+ Installing
41
+ ----------
42
+
43
+ To install UOM, use the following command:
44
+
45
+ $ gem install caruby-uom
46
+
47
+ (Add `sudo` if you're installing under a POSIX system as root)
48
+
49
+ Alternatively, if you've checked the source out directly, you can call
50
+ `rake install` from the root project directory.
51
+
52
+ Usage
53
+ -----
54
+
55
+ #### Create a Measurement
56
+ require 'uom'
57
+
58
+ UOM::Measurement.new(:g, 1) #=> 1 gram
59
+ UOM::Measurement.new(:mg, 1) #=> 1 milligram
60
+ UOM::Measurement.new(:mg_per_l, 1) #=> 1 milligram per liter
61
+
62
+ #### Scale a Measurement
63
+
64
+ UOM::Measurement.new(:g, 1).as(:mg) #=> 1000 milligrams
65
+
66
+ #### Measurement arithmetic
67
+
68
+ UOM::Measurement.new(:g, 1) * 2 #=> 2 grams
69
+ UOM::Measurement.new(:g, 2) / UOM::Measurement.new(:l, 1) #=> 2 milligrams per liter
70
+
71
+ #### Parse a measurement String
72
+
73
+ "1 g".to_measurement #=> 1 gram Measurement
74
+ "1 gm".to_measurement #=> 1 gram Measurement
75
+ "2 grams".to_measurement #=> 2 gram Measurement
76
+
77
+ #### Convert a Measurement
78
+
79
+ UOM::Measurement.new(:g, 2).to_f #=> 2.0
80
+ UOM::Measurement.new(:g, 1).to_s #=> "1 gram"
81
+ UOM::Measurement.new(:g, 2).to_s #=> "2 grams"
82
+
83
+ #### Label a novel unit
84
+
85
+ module UOM
86
+ # joule-pecks per erg-gauss
87
+ JPEG = Unit.for((JOULE * PECK) / (ERG * GAUSS)).add_abbreviation(:jpeg)
88
+ end
89
+ UOM::Measurement.new(:jpeg, 1) #=> 1 jpeg
90
+
91
+ Changelog
92
+ ---------
93
+
94
+ - **September.30.10**: 2010.1 release
95
+ - Initial public release
96
+
97
+ Copyright
98
+ ---------
99
+
100
+ UOM © 2010 by [Oregon Health & Sciences University](mailto:loneyf@ohsu.edu).
101
+ UOM is licensed under the MIT license. Please see the LICENSE and LEGAL
102
+ documents for more information.
@@ -0,0 +1,53 @@
1
+ ampere, amperes, A, milliampere, milliamperes, mA, microampere, microamperes, uA, nanoampere, nanoamperes, nA, picoampere, picoamperes, pA, teraampere, teraamperes, TA, gigaampere, gigaamperes, GA, megaampere, megaamperes, MA, kiloampere, kiloamperes, kA
2
+ angstrom, angstroms, a
3
+ astronomical_unit, astronomical_units, AU, AUs
4
+ barye, baryes, Ba, Bas, millibarye, millibaryes, mBa, mBas, microbarye, microbaryes, uBa, uBas, nanobarye, nanobaryes, nBa, nBas, picobarye, picobaryes, pBa, pBas, terabarye, terabaryes, TBa, TBas, gigabarye, gigabaryes, GBa, GBas, megabarye, megabaryes, MBa, MBas, kilobarye, kilobaryes, kBa, kBas
5
+ bit, bits
6
+ bushel, bushels, bu, bus
7
+ byte, bytes, Byte, Bytes, B, b, kilobyte, kilobytes, KByte, KBytes, KB, KBs, megabyte, megabytes, MByte, MBytes, MB, MBs, gigabyte, gigabytes, GByte, GBytes, GB, GBs, terabyte, terabytes, TByte, TBytes, TB, TBs, petabyte, petabytes, PByte, PBytes, PB, PBs
8
+ candela, candelas, cd, cds
9
+ celsius, C
10
+ coulomb, coulombs, millicoulomb, millicoulombs, microcoulomb, microcoulombs, nanocoulomb, nanocoulombs, picocoulomb, picocoulombs, teracoulomb, teracoulombs, gigacoulomb, gigacoulombs, megacoulomb, megacoulombs, kilocoulomb, kilocoulombs
11
+ cup, cups, cp, cps
12
+ day, days
13
+ dram, drams, dr, drs
14
+ dry_gallon, dry_gallons, dry_gal, dry_gals
15
+ dry_pint, dry_pints, dry_pt, dry_pts
16
+ dry_quart, dry_quarts, dry_qt, dry_qts
17
+ dyne, dynes, dyn, dyns, millidyne, millidynes, mdyn, mdyns, microdyne, microdynes, udyn, udyns, nanodyne, nanodynes, ndyn, ndyns, picodyne, picodynes, pdyn, pdyns, teradyne, teradynes, Tdyn, Tdyns, gigadyne, gigadynes, Gdyn, Gdyns, megadyne, megadynes, Mdyn, Mdyns, kilodyne, kilodynes, kdyn, kdyns
18
+ erg, ergs, millierg, milliergs, microerg, microergs, nanoerg, nanoergs, picoerg, picoergs, teraerg, teraergs, gigaerg, gigaergs, megaerg, megaergs, kiloerg, kiloergs
19
+ farad, farads, millifarad, millifarads, microfarad, microfarads, nanofarad, nanofarads, picofarad, picofarads, terafarad, terafarads, gigafarad, gigafarads, megafarad, megafarads, kilofarad, kilofarads
20
+ farenheit, F
21
+ fluid_ounce, fluid_ounces, fl_oz, fl_ozs
22
+ foot, foots, ft, fts
23
+ gallon, gallons, gal, gals
24
+ gauss, gausses, G
25
+ grain, grains, gr, grs
26
+ gram, grams, gm, gms, g, yottagram, yottagrams, Ygm, Ygms, Yg, zettagram, zettagrams, Zgm, Zgms, Zg, exagram, exagrams, Egm, Egms, Eg, teragram, teragrams, Tgm, Tgms, Tg, gigagram, gigagrams, Ggm, Ggms, Gg, megagram, megagrams, Mgm, Mgms, Mg, kilogram, kilograms, kgm, kgms, kg, hectogram, hectograms, hgm, hgms, hg, decagram, decagrams, dagm, dagms, dag, decigram, decigrams, dgm, dgms, dg, centigram, centigrams, cgm, cgms, cg, milligram, milligrams, mgm, mgms, mg, microgram, micrograms, ugm, ugms, ug, nanogram, nanograms, ngm, ngms, ng, picogram, picograms, pgm, pgms, pg, femtogram, femtograms, fgm, fgms, fg, attogram, attograms, agm, agms, ag, zeptogram, zeptograms, zgm, zgms, zg, yoctogram, yoctograms, ygm, ygms, yg
27
+ henry, henries, H
28
+ hour, hours, hr, hrs
29
+ inch, inches, in, ins
30
+ joule, joules, J, millijoule, millijoules, mJ, microjoule, microjoules, uJ, nanojoule, nanojoules, nJ, picojoule, picojoules, pJ, terajoule, terajoules, TJ, gigajoule, gigajoules, GJ, megajoule, megajoules, MJ, kilojoule, kilojoules, kJ
31
+ kelvin, K
32
+ light_year, light_years, ly, lys
33
+ liter, liters, l, L, yottaliter, yottaliters, Yl, YL, zettaliter, zettaliters, Zl, ZL, exaliter, exaliters, El, EL, teraliter, teraliters, Tl, TL, gigaliter, gigaliters, Gl, GL, megaliter, megaliters, Ml, ML, kiloliter, kiloliters, kl, kL, hectoliter, hectoliters, hl, hL, decaliter, decaliters, dal, daL, deciliter, deciliters, dl, dL, centiliter, centiliters, cl, cL, milliliter, milliliters, ml, mL, microliter, microliters, ul, uL, nanoliter, nanoliters, nl, nL, picoliter, picoliters, pl, pL, femtoliter, femtoliters, fl, fL, attoliter, attoliters, al, aL, zeptoliter, zeptoliters, zl, zL, yoctoliter, yoctoliters, yl, yL
34
+ maxwell, maxwells, Mx, Mxs
35
+ meter, meters, m, yottameter, yottameters, Ym, zettameter, zettameters, Zm, exameter, exameters, Em, terameter, terameters, Tm, gigameter, gigameters, Gm, megameter, megameters, Mm, kilometer, kilometers, km, hectometer, hectometers, hm, decameter, decameters, dam, decimeter, decimeters, dm, centimeter, centimeters, cm, millimeter, millimeters, mm, micrometer, micrometers, um, nanometer, nanometers, nm, picometer, picometers, pm, femtometer, femtometers, fm, attometer, attometers, am, zeptometer, zeptometers, zm, yoctometer, yoctometers, ym
36
+ mile, miles, mi, mis
37
+ minute, minutes, min, mins
38
+ mole, moles, mol, mols
39
+ ohm, ohms
40
+ ounce, ounces, oz, ozs
41
+ peck, pecks, pk, pks
42
+ pint, pints, pt, pts
43
+ poise, poises, P, kilopoise, kilopoises, kP, millipoise, millipoises, mP, micropoise, micropoises, uP, nanopoise, nanopoises, nP, picopoise, picopoises, pP
44
+ pound, pounds, lb, lbs
45
+ quart, quarts, qt, qts
46
+ second, seconds, sec, secs, s, millisecond, milliseconds, msec, msecs, ms, microsecond, microseconds, usec, usecs, us, nanosecond, nanoseconds, nsec, nsecs, ns, picosecond, picoseconds, psec, psecs, ps, femtosecond, femtoseconds, fsec, fsecs, fs
47
+ tablespoon, tablespoons, tbsp, tbsps
48
+ teaspoon, teaspoons, tsp, tsps
49
+ tesla, teslas, T, decitesla, deciteslas, dT, centitesla, centiteslas, cT, millitesla, milliteslas, mT, microtesla, microteslas, uT, nanotesla, nanoteslas, nT, picotesla, picoteslas, pT
50
+ ton, tons
51
+ volt, volts, V, millivolt, millivolts, mV, microvolt, microvolts, uV, nanovolt, nanovolts, nV, picovolt, picovolts, pV, teravolt, teravolts, TV, gigavolt, gigavolts, GV, megavolt, megavolts, MV, kilovolt, kilovolts, kV
52
+ weber, webers, Wb, Wbs, milliweber, milliwebers, mWb, mWbs, microweber, microwebers, uWb, uWbs, nanoweber, nanowebers, nWb, nWbs, picoweber, picowebers, pWb, pWbs, teraweber, terawebers, TWb, TWbs, gigaweber, gigawebers, GWb, GWbs, megaweber, megawebers, MWb, MWbs, kiloweber, kilowebers, kWb, kWbs
53
+ yard, yards, yd, yds
@@ -0,0 +1,2 @@
1
+ The files in this directory are shamelessly stolen from Rails. They are included here rather than pulled in as a gem
2
+ in order to avoid a dependency on the entire Rails project for a limited utility.
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+
3
+ require 'active_support/core_ext/string/inflections'
4
+
5
+ class String #:nodoc:
6
+ include ActiveSupport::CoreExtensions::String::Inflections
7
+ end
@@ -0,0 +1,167 @@
1
+ require 'active_support/inflector'
2
+
3
+ module ActiveSupport #:nodoc:
4
+ module CoreExtensions #:nodoc:
5
+ module String #:nodoc:
6
+ # String inflections define new methods on the String class to transform names for different purposes.
7
+ # For instance, you can figure out the name of a database from the name of a class.
8
+ #
9
+ # "ScaleScore".tableize #=>"scale_scores"
10
+ module Inflections
11
+ # Returns the plural form of the word in the string.
12
+ #
13
+ # "post".pluralize #=>"posts"
14
+ # "octopus".pluralize #=>"octopi"
15
+ # "sheep".pluralize #=>"sheep"
16
+ # "words".pluralize #=>"words"
17
+ # "the blue mailman".pluralize #=>"the blue mailmen"
18
+ # "CamelOctopus".pluralize #=>"CamelOctopi"
19
+ def pluralize
20
+ Inflector.pluralize(self)
21
+ end
22
+
23
+ # The reverse of +pluralize+, returns the singular form of a word in a string.
24
+ #
25
+ # "posts".singularize #=>"post"
26
+ # "octopi".singularize #=>"octopus"
27
+ # "sheep".singularize #=>"sheep"
28
+ # "word".singularize #=>"word"
29
+ # "the blue mailmen".singularize #=>"the blue mailman"
30
+ # "CamelOctopi".singularize #=>"CamelOctopus"
31
+ def singularize
32
+ Inflector.singularize(self)
33
+ end
34
+
35
+ # By default, +camelize+ converts strings to UpperCamelCase. If the argument to camelize
36
+ # is set to <tt>:lower</tt> then camelize produces lowerCamelCase.
37
+ #
38
+ # +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
39
+ #
40
+ # "active_record".camelize #=>"ActiveRecord"
41
+ # "active_record".camelize(:lower) #=>"activeRecord"
42
+ # "active_record/errors".camelize #=>"ActiveRecord::Errors"
43
+ # "active_record/errors".camelize(:lower) #=>"activeRecord::Errors"
44
+ def camelize(first_letter = :upper)
45
+ case first_letter
46
+ when :upper then Inflector.camelize(self, true)
47
+ when :lower then Inflector.camelize(self, false)
48
+ end
49
+ end
50
+ alias_method :camelcase, :camelize
51
+
52
+ # Capitalizes all the words and replaces some characters in the string to create
53
+ # a nicer looking title. +titleize+ is meant for creating pretty output. It is not
54
+ # used in the Rails internals.
55
+ #
56
+ # +titleize+ is also aliased as +titlecase+.
57
+ #
58
+ # "man from the boondocks".titleize #=>"Man From The Boondocks"
59
+ # "x-men: the last stand".titleize #=>"X Men: The Last Stand"
60
+ def titleize
61
+ Inflector.titleize(self)
62
+ end
63
+ alias_method :titlecase, :titleize
64
+
65
+ # The reverse of +camelize+. Makes an underscored, lowercase form from the expression in the string.
66
+ #
67
+ # +underscore+ will also change '::' to '/' to convert namespaces to paths.
68
+ #
69
+ # "ActiveRecord".underscore #=>"active_record"
70
+ # "ActiveRecord::Errors".underscore #=>active_record/errors
71
+ def underscore
72
+ Inflector.underscore(self)
73
+ end
74
+
75
+ # Replaces underscores with dashes in the string.
76
+ #
77
+ # "puni_puni" #=>"puni-puni"
78
+ def dasherize
79
+ Inflector.dasherize(self)
80
+ end
81
+
82
+ # Removes the module part from the constant expression in the string.
83
+ #
84
+ # "ActiveRecord::CoreExtensions::String::Inflections".demodulize #=>"Inflections"
85
+ # "Inflections".demodulize #=>"Inflections"
86
+ def demodulize
87
+ Inflector.demodulize(self)
88
+ end
89
+
90
+ # Replaces special characters in a string so that it may be used as part of a 'pretty' URL.
91
+ #
92
+ # ==== Examples
93
+ #
94
+ # class Person
95
+ # def to_param
96
+ # "#{id}-#{name.parameterize}"
97
+ # end
98
+ # end
99
+ #
100
+ # @person = Person.find(1)
101
+ # #=>#<Person id: 1, name: "Donald E. Knuth">
102
+ #
103
+ # <%= link_to(@person.name, person_path %>
104
+ # #=><a href="/person/1-donald-e-knuth">Donald E. Knuth</a>
105
+ def parameterize
106
+ Inflector.parameterize(self)
107
+ end
108
+
109
+ # Creates the name of a table like Rails does for models to table names. This method
110
+ # uses the +pluralize+ method on the last word in the string.
111
+ #
112
+ # "RawScaledScorer".tableize #=>"raw_scaled_scorers"
113
+ # "egg_and_ham".tableize #=>"egg_and_hams"
114
+ # "fancyCategory".tableize #=>"fancy_categories"
115
+ def tableize
116
+ Inflector.tableize(self)
117
+ end
118
+
119
+ # Create a class name from a plural table name like Rails does for table names to models.
120
+ # Note that this returns a string and not a class. (To convert to an actual class
121
+ # follow +classify+ with +constantize+.)
122
+ #
123
+ # "egg_and_hams".classify #=>"EggAndHam"
124
+ # "posts".classify #=>"Post"
125
+ #
126
+ # Singular names are not handled correctly.
127
+ #
128
+ # "business".classify #=>"Busines"
129
+ def classify
130
+ Inflector.classify(self)
131
+ end
132
+
133
+ # Capitalizes the first word, turns underscores into spaces, and strips '_id'.
134
+ # Like +titleize+, this is meant for creating pretty output.
135
+ #
136
+ # "employee_salary" #=>"Employee salary"
137
+ # "author_id" #=>"Author"
138
+ def humanize
139
+ Inflector.humanize(self)
140
+ end
141
+
142
+ # Creates a foreign key name from a class name.
143
+ # +separate_class_name_and_id_with_underscore+ sets whether
144
+ # the method should put '_' between the name and 'id'.
145
+ #
146
+ # Examples
147
+ # "Message".foreign_key #=>"message_id"
148
+ # "Message".foreign_key(false) #=>"messageid"
149
+ # "Admin::Post".foreign_key #=>"post_id"
150
+ def foreign_key(separate_class_name_and_id_with_underscore = true)
151
+ Inflector.foreign_key(self, separate_class_name_and_id_with_underscore)
152
+ end
153
+
154
+ # +constantize+ tries to find a declared constant with the name specified
155
+ # in the string. It raises a NameError when the name is not in CamelCase
156
+ # or is not initialized.
157
+ #
158
+ # Examples
159
+ # "Module".constantize #=>Module
160
+ # "Class".constantize #=>Class
161
+ def constantize
162
+ Inflector.constantize(self)
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,55 @@
1
+ module ActiveSupport
2
+ Inflector.inflections do |inflect|
3
+ inflect.plural(/$/, 's')
4
+ inflect.plural(/s$/i, 's')
5
+ inflect.plural(/(ax|test)is$/i, '\1es')
6
+ inflect.plural(/(octop|vir)us$/i, '\1i')
7
+ inflect.plural(/(alias|status)$/i, '\1es')
8
+ inflect.plural(/(bu)s$/i, '\1ses')
9
+ inflect.plural(/(buffal|tomat)o$/i, '\1oes')
10
+ inflect.plural(/([ti])um$/i, '\1a')
11
+ inflect.plural(/sis$/i, 'ses')
12
+ inflect.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
13
+ inflect.plural(/(hive)$/i, '\1s')
14
+ inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies')
15
+ inflect.plural(/(x|ch|ss|sh)$/i, '\1es')
16
+ inflect.plural(/(matr|vert|ind)(?:ix|ex)$/i, '\1ices')
17
+ inflect.plural(/([m|l])ouse$/i, '\1ice')
18
+ inflect.plural(/^(ox)$/i, '\1en')
19
+ inflect.plural(/(quiz)$/i, '\1zes')
20
+
21
+ inflect.singular(/s$/i, '')
22
+ inflect.singular(/(n)ews$/i, '\1ews')
23
+ inflect.singular(/([ti])a$/i, '\1um')
24
+ inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, '\1\2sis')
25
+ inflect.singular(/(^analy)ses$/i, '\1sis')
26
+ inflect.singular(/([^f])ves$/i, '\1fe')
27
+ inflect.singular(/(hive)s$/i, '\1')
28
+ inflect.singular(/(tive)s$/i, '\1')
29
+ inflect.singular(/([lr])ves$/i, '\1f')
30
+ inflect.singular(/([^aeiouy]|qu)ies$/i, '\1y')
31
+ inflect.singular(/(s)eries$/i, '\1eries')
32
+ inflect.singular(/(m)ovies$/i, '\1ovie')
33
+ inflect.singular(/(x|ch|ss|sh)es$/i, '\1')
34
+ inflect.singular(/([m|l])ice$/i, '\1ouse')
35
+ inflect.singular(/(bus)es$/i, '\1')
36
+ inflect.singular(/(o)es$/i, '\1')
37
+ inflect.singular(/(shoe)s$/i, '\1')
38
+ inflect.singular(/(cris|ax|test)es$/i, '\1is')
39
+ inflect.singular(/(octop|vir)i$/i, '\1us')
40
+ inflect.singular(/(alias|status)es$/i, '\1')
41
+ inflect.singular(/^(ox)en/i, '\1')
42
+ inflect.singular(/(vert|ind)ices$/i, '\1ex')
43
+ inflect.singular(/(matr)ices$/i, '\1ix')
44
+ inflect.singular(/(quiz)zes$/i, '\1')
45
+
46
+ inflect.irregular('person', 'people')
47
+ inflect.irregular('man', 'men')
48
+ inflect.irregular('child', 'children')
49
+ inflect.irregular('sex', 'sexes')
50
+ inflect.irregular('move', 'moves')
51
+ inflect.irregular('cow', 'kine')
52
+
53
+ inflect.uncountable(%w(equipment information rice money species series fish sheep))
54
+ end
55
+ end
@@ -0,0 +1,396 @@
1
+ # encoding: utf-8
2
+ require 'singleton'
3
+ require 'iconv'
4
+
5
+ module ActiveSupport
6
+ # The Inflector transforms words from singular to plural, class names to table names, modularized class names to ones without,
7
+ # and class names to foreign keys. The default inflections for pluralization, singularization, and uncountable words are kept
8
+ # in inflections.rb.
9
+ #
10
+ # The Rails core team has stated patches for the inflections library will not be accepted
11
+ # in order to avoid breaking legacy applications which may be relying on errant inflections.
12
+ # If you discover an incorrect inflection and require it for your application, you'll need
13
+ # to correct it yourself (explained below).
14
+ module Inflector
15
+ extend self
16
+
17
+ # A singleton instance of this class is yielded by Inflector.inflections, which can then be used to specify additional
18
+ # inflection rules. Examples:
19
+ #
20
+ # ActiveSupport::Inflector.inflections do |inflect|
21
+ # inflect.plural /^(ox)$/i, '\1\2en'
22
+ # inflect.singular /^(ox)en/i, '\1'
23
+ #
24
+ # inflect.irregular 'octopus', 'octopi'
25
+ #
26
+ # inflect.uncountable "equipment"
27
+ # end
28
+ #
29
+ # New rules are added at the top. So in the example above, the irregular rule for octopus will now be the first of the
30
+ # pluralization and singularization rules that is runs. This guarantees that your rules run before any of the rules that may
31
+ # already have been loaded.
32
+ class Inflections
33
+ include Singleton
34
+
35
+ attr_reader :plurals, :singulars, :uncountables, :humans
36
+
37
+ def initialize
38
+ @plurals, @singulars, @uncountables, @humans = [], [], [], []
39
+ end
40
+
41
+ # Specifies a new pluralization rule and its replacement. The rule can either be a string or a regular expression.
42
+ # The replacement should always be a string that may include references to the matched data from the rule.
43
+ def plural(rule, replacement)
44
+ @uncountables.delete(rule) if String === rule
45
+ @uncountables.delete(replacement)
46
+ @plurals.insert(0, [rule, replacement])
47
+ end
48
+
49
+ # Specifies a new singularization rule and its replacement. The rule can either be a string or a regular expression.
50
+ # The replacement should always be a string that may include references to the matched data from the rule.
51
+ def singular(rule, replacement)
52
+ @uncountables.delete(rule) if String === rule
53
+ @uncountables.delete(replacement)
54
+ @singulars.insert(0, [rule, replacement])
55
+ end
56
+
57
+ # Specifies a new irregular that applies to both pluralization and singularization at the same time. This can only be used
58
+ # for strings, not regular expressions. You simply pass the irregular in singular and plural form.
59
+ #
60
+ # Examples:
61
+ # irregular 'octopus', 'octopi'
62
+ # irregular 'person', 'people'
63
+ def irregular(singular, plural)
64
+ @uncountables.delete(singular)
65
+ @uncountables.delete(plural)
66
+ if singular[0,1].upcase == plural[0,1].upcase
67
+ plural(Regexp.new("(#{singular[0,1]})#{singular[1..-1]}$", "i"), '\1' + plural[1..-1])
68
+ singular(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + singular[1..-1])
69
+ else
70
+ plural(Regexp.new("#{singular[0,1].upcase}(?i)#{singular[1..-1]}$"), plural[0,1].upcase + plural[1..-1])
71
+ plural(Regexp.new("#{singular[0,1].downcase}(?i)#{singular[1..-1]}$"), plural[0,1].downcase + plural[1..-1])
72
+ singular(Regexp.new("#{plural[0,1].upcase}(?i)#{plural[1..-1]}$"), singular[0,1].upcase + singular[1..-1])
73
+ singular(Regexp.new("#{plural[0,1].downcase}(?i)#{plural[1..-1]}$"), singular[0,1].downcase + singular[1..-1])
74
+ end
75
+ end
76
+
77
+ # Add uncountable words that shouldn't be attempted inflected.
78
+ #
79
+ # Examples:
80
+ # uncountable "money"
81
+ # uncountable "money", "information"
82
+ # uncountable %w( money information rice )
83
+ def uncountable(*words)
84
+ (@uncountables << words).flatten!
85
+ end
86
+
87
+ # Specifies a humanized form of a string by a regular expression rule or by a string mapping.
88
+ # When using a regular expression based replacement, the normal humanize formatting is called after the replacement.
89
+ # When a string is used, the human form should be specified as desired (example: 'The name', not 'the_name')
90
+ #
91
+ # Examples:
92
+ # human /_cnt$/i, '\1_count'
93
+ # human "legacy_col_person_name", "Name"
94
+ def human(rule, replacement)
95
+ @humans.insert(0, [rule, replacement])
96
+ end
97
+
98
+ # Clears the loaded inflections within a given scope (default is <tt>:all</tt>).
99
+ # Give the scope as a symbol of the inflection type, the options are: <tt>:plurals</tt>,
100
+ # <tt>:singulars</tt>, <tt>:uncountables</tt>, <tt>:humans</tt>.
101
+ #
102
+ # Examples:
103
+ # clear :all
104
+ # clear :plurals
105
+ def clear(scope = :all)
106
+ case scope
107
+ when :all
108
+ @plurals, @singulars, @uncountables = [], [], []
109
+ else
110
+ instance_variable_set "@#{scope}", []
111
+ end
112
+ end
113
+ end
114
+
115
+ # Yields a singleton instance of Inflector::Inflections so you can specify additional
116
+ # inflector rules.
117
+ #
118
+ # Example:
119
+ # ActiveSupport::Inflector.inflections do |inflect|
120
+ # inflect.uncountable "rails"
121
+ # end
122
+ def inflections
123
+ if block_given?
124
+ yield Inflections.instance
125
+ else
126
+ Inflections.instance
127
+ end
128
+ end
129
+
130
+ # Returns the plural form of the word in the string.
131
+ #
132
+ # Examples:
133
+ # "post".pluralize #=>"posts"
134
+ # "octopus".pluralize #=>"octopi"
135
+ # "sheep".pluralize #=>"sheep"
136
+ # "words".pluralize #=>"words"
137
+ # "CamelOctopus".pluralize #=>"CamelOctopi"
138
+ def pluralize(word)
139
+ result = word.to_s.dup
140
+
141
+ if word.empty? || inflections.uncountables.include?(result.downcase)
142
+ result
143
+ else
144
+ inflections.plurals.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
145
+ result
146
+ end
147
+ end
148
+
149
+ # The reverse of +pluralize+, returns the singular form of a word in a string.
150
+ #
151
+ # Examples:
152
+ # "posts".singularize #=>"post"
153
+ # "octopi".singularize #=>"octopus"
154
+ # "sheep".singluarize #=>"sheep"
155
+ # "word".singularize #=>"word"
156
+ # "CamelOctopi".singularize #=>"CamelOctopus"
157
+ def singularize(word)
158
+ result = word.to_s.dup
159
+
160
+ if inflections.uncountables.include?(result.downcase)
161
+ result
162
+ else
163
+ inflections.singulars.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
164
+ result
165
+ end
166
+ end
167
+
168
+ # By default, +camelize+ converts strings to UpperCamelCase. If the argument to +camelize+
169
+ # is set to <tt>:lower</tt> then +camelize+ produces lowerCamelCase.
170
+ #
171
+ # +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
172
+ #
173
+ # Examples:
174
+ # "active_record".camelize #=>"ActiveRecord"
175
+ # "active_record".camelize(:lower) #=>"activeRecord"
176
+ # "active_record/errors".camelize #=>"ActiveRecord::Errors"
177
+ # "active_record/errors".camelize(:lower) #=>"activeRecord::Errors"
178
+ def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
179
+ if first_letter_in_uppercase
180
+ lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase }" }.gsub(/(?:^|_)(.)/) { $1.upcase }
181
+ else
182
+ lower_case_and_underscored_word.first.downcase + camelize(lower_case_and_underscored_word)[1..-1]
183
+ end
184
+ end
185
+
186
+ # Capitalizes all the words and replaces some characters in the string to create
187
+ # a nicer looking title. +titleize+ is meant for creating pretty output. It is not
188
+ # used in the Rails internals.
189
+ #
190
+ # +titleize+ is also aliased as as +titlecase+.
191
+ #
192
+ # Examples:
193
+ # "man from the boondocks".titleize #=>"Man From The Boondocks"
194
+ # "x-men: the last stand".titleize #=>"X Men: The Last Stand"
195
+ def titleize(word)
196
+ humanize(underscore(word)).gsub(/\b('?[a-z])/) { $1.capitalize }
197
+ end
198
+
199
+ # The reverse of +camelize+. Makes an underscored, lowercase form from the expression in the string.
200
+ #
201
+ # Changes '::' to '/' to convert namespaces to paths.
202
+ #
203
+ # Examples:
204
+ # "ActiveRecord".underscore #=>"active_record"
205
+ # "ActiveRecord::Errors".underscore #=>active_record/errors
206
+ def underscore(camel_cased_word)
207
+ camel_cased_word.to_s.gsub(/::/, '/').
208
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
209
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
210
+ tr("-", "_").
211
+ downcase
212
+ end
213
+
214
+ # Replaces underscores with dashes in the string.
215
+ #
216
+ # Example:
217
+ # "puni_puni" #=>"puni-puni"
218
+ def dasherize(underscored_word)
219
+ underscored_word.gsub(/_/, '-')
220
+ end
221
+
222
+ # Capitalizes the first word and turns underscores into spaces and strips a
223
+ # trailing "_id", if any. Like +titleize+, this is meant for creating pretty output.
224
+ #
225
+ # Examples:
226
+ # "employee_salary" #=>"Employee salary"
227
+ # "author_id" #=>"Author"
228
+ def humanize(lower_case_and_underscored_word)
229
+ result = lower_case_and_underscored_word.to_s.dup
230
+
231
+ inflections.humans.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
232
+ result.gsub(/_id$/, "").gsub(/_/, " ").capitalize
233
+ end
234
+
235
+ # Removes the module part from the expression in the string.
236
+ #
237
+ # Examples:
238
+ # "ActiveRecord::CoreExtensions::String::Inflections".demodulize #=>"Inflections"
239
+ # "Inflections".demodulize #=>"Inflections"
240
+ def demodulize(class_name_in_module)
241
+ class_name_in_module.to_s.gsub(/^.*::/, '')
242
+ end
243
+
244
+ # Replaces special characters in a string so that it may be used as part of a 'pretty' URL.
245
+ #
246
+ # ==== Examples
247
+ #
248
+ # class Person
249
+ # def to_param
250
+ # "#{id}-#{name.parameterize}"
251
+ # end
252
+ # end
253
+ #
254
+ # @person = Person.find(1)
255
+ # #=>#<Person id: 1, name: "Donald E. Knuth">
256
+ #
257
+ # <%= link_to(@person.name, person_path %>
258
+ # #=><a href="/person/1-donald-e-knuth">Donald E. Knuth</a>
259
+ def parameterize(string, sep = '-')
260
+ re_sep = Regexp.escape(sep)
261
+ # replace accented chars with ther ascii equivalents
262
+ parameterized_string = transliterate(string)
263
+ # Turn unwanted chars into the seperator
264
+ parameterized_string.gsub!(/[^a-z0-9\-_\+]+/i, sep)
265
+ # No more than one of the separator in a row.
266
+ parameterized_string.squeeze!(sep)
267
+ # Remove leading/trailing separator.
268
+ parameterized_string.gsub!(/^#{re_sep}|#{re_sep}$/i, '')
269
+ parameterized_string.downcase
270
+ end
271
+
272
+ # Replaces accented characters with their ascii equivalents.
273
+ def transliterate(string)
274
+ Iconv.iconv('ascii//ignore//translit', 'utf-8', string).to_s
275
+ end
276
+
277
+ # The iconv transliteration code doesn't function correctly
278
+ # on some platforms, but it's very fast where it does function.
279
+ if "foo" != Inflector.transliterate("föö")
280
+ undef_method :transliterate
281
+ def transliterate(string)
282
+ string.mb_chars.normalize(:kd). # Decompose accented characters
283
+ gsub(/[^\x00-\x7F]+/, '') # Remove anything non-ASCII entirely (e.g. diacritics).
284
+ end
285
+ end
286
+
287
+ # Create the name of a table like Rails does for models to table names. This method
288
+ # uses the +pluralize+ method on the last word in the string.
289
+ #
290
+ # Examples
291
+ # "RawScaledScorer".tableize #=>"raw_scaled_scorers"
292
+ # "egg_and_ham".tableize #=>"egg_and_hams"
293
+ # "fancyCategory".tableize #=>"fancy_categories"
294
+ def tableize(class_name)
295
+ pluralize(underscore(class_name))
296
+ end
297
+
298
+ # Create a class name from a plural table name like Rails does for table names to models.
299
+ # Note that this returns a string and not a Class. (To convert to an actual class
300
+ # follow +classify+ with +constantize+.)
301
+ #
302
+ # Examples:
303
+ # "egg_and_hams".classify #=>"EggAndHam"
304
+ # "posts".classify #=>"Post"
305
+ #
306
+ # Singular names are not handled correctly:
307
+ # "business".classify #=>"Busines"
308
+ def classify(table_name)
309
+ # strip out any leading schema name
310
+ camelize(singularize(table_name.to_s.sub(/.*\./, '')))
311
+ end
312
+
313
+ # Creates a foreign key name from a class name.
314
+ # +separate_class_name_and_id_with_underscore+ sets whether
315
+ # the method should put '_' between the name and 'id'.
316
+ #
317
+ # Examples:
318
+ # "Message".foreign_key #=>"message_id"
319
+ # "Message".foreign_key(false) #=>"messageid"
320
+ # "Admin::Post".foreign_key #=>"post_id"
321
+ def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
322
+ underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
323
+ end
324
+
325
+ # Ruby 1.9 introduces an inherit argument for Module#const_get and
326
+ # #const_defined? and changes their default behavior.
327
+ if Module.method(:const_get).arity == 1
328
+ # Tries to find a constant with the name specified in the argument string:
329
+ #
330
+ # "Module".constantize #=>Module
331
+ # "Test::Unit".constantize #=>Test::Unit
332
+ #
333
+ # The name is assumed to be the one of a top-level constant, no matter whether
334
+ # it starts with "::" or not. No lexical context is taken into account:
335
+ #
336
+ # C = 'outside'
337
+ # module M
338
+ # C = 'inside'
339
+ # C #=>'inside'
340
+ # "C".constantize #=>'outside', same as ::C
341
+ # end
342
+ #
343
+ # NameError is raised when the name is not in CamelCase or the constant is
344
+ # unknown.
345
+ def constantize(camel_cased_word)
346
+ names = camel_cased_word.split('::')
347
+ names.shift if names.empty? || names.first.empty?
348
+
349
+ constant = Object
350
+ names.each do |name|
351
+ constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
352
+ end
353
+ constant
354
+ end
355
+ else
356
+ def constantize(camel_cased_word) #:nodoc:
357
+ names = camel_cased_word.split('::')
358
+ names.shift if names.empty? || names.first.empty?
359
+
360
+ constant = Object
361
+ names.each do |name|
362
+ constant = constant.const_get(name, false) || constant.const_missing(name)
363
+ end
364
+ constant
365
+ end
366
+ end
367
+
368
+ # Turns a number into an ordinal string used to denote the position in an
369
+ # ordered sequence such as 1st, 2nd, 3rd, 4th.
370
+ #
371
+ # Examples:
372
+ # ordinalize(1) #=>"1st"
373
+ # ordinalize(2) #=>"2nd"
374
+ # ordinalize(1002) #=>"1002nd"
375
+ # ordinalize(1003) #=>"1003rd"
376
+ def ordinalize(number)
377
+ if (11..13).include?(number.to_i % 100)
378
+ "#{number}th"
379
+ else
380
+ case number.to_i % 10
381
+ when 1; "#{number}st"
382
+ when 2; "#{number}nd"
383
+ when 3; "#{number}rd"
384
+ else "#{number}th"
385
+ end
386
+ end
387
+ end
388
+ end
389
+ end
390
+
391
+ # in case caruby/active_support/inflector is required without the rest of active_support
392
+ require 'active_support/inflections'
393
+ require 'active_support/core_ext/string/inflections'
394
+ unless String.included_modules.include?(ActiveSupport::CoreExtensions::String::Inflections)
395
+ String.send :include, ActiveSupport::CoreExtensions::String::Inflections
396
+ end