uom 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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