| // The Inflector transforms words from singular to plural, class names to table names, modularized class names to ones without, |
| // and class names to foreign keys. The default inflections for pluralization, singularization, and uncountable words are kept |
| // in inflections.coffee |
| // |
| // If you discover an incorrect inflection and require it for your application, you'll need |
| // to correct it yourself (explained below). |
| |
| var util = require('./util'); |
| |
| var inflect = module.exports; |
| |
| // Import [inflections](inflections.html) instance |
| inflect.inflections = require('./inflections') |
| |
| // Gives easy access to add inflections to this class |
| inflect.inflect = function (inflections_function) { |
| inflections_function(inflect.inflections); |
| }; |
| |
| // By default, _camelize_ converts strings to UpperCamelCase. If the argument to _camelize_ |
| // is set to _false_ then _camelize_ produces lowerCamelCase. |
| // |
| // _camelize_ will also convert '/' to '.' which is useful for converting paths to namespaces. |
| // |
| // "bullet_record".camelize() // => "BulletRecord" |
| // "bullet_record".camelize(false) // => "bulletRecord" |
| // "bullet_record/errors".camelize() // => "BulletRecord.Errors" |
| // "bullet_record/errors".camelize(false) // => "bulletRecord.Errors" |
| // |
| // As a rule of thumb you can think of _camelize_ as the inverse of _underscore_, |
| // though there are cases where that does not hold: |
| // |
| // "SSLError".underscore.camelize // => "SslError" |
| inflect.camelize = function(lower_case_and_underscored_word, first_letter_in_uppercase) { |
| var result; |
| if (first_letter_in_uppercase == null) first_letter_in_uppercase = true; |
| result = util.string.gsub(lower_case_and_underscored_word, /\/(.?)/, function($) { |
| return "." + (util.string.upcase($[1])); |
| }); |
| result = util.string.gsub(result, /(?:_)(.)/, function($) { |
| return util.string.upcase($[1]); |
| }); |
| if (first_letter_in_uppercase) { |
| return util.string.upcase(result); |
| } else { |
| return util.string.downcase(result); |
| } |
| }; |
| |
| // Makes an underscored, lowercase form from the expression in the string. |
| // |
| // Changes '.' to '/' to convert namespaces to paths. |
| // |
| // "BulletRecord".underscore() // => "bullet_record" |
| // "BulletRecord.Errors".underscore() // => "bullet_record/errors" |
| // |
| // As a rule of thumb you can think of +underscore+ as the inverse of +camelize+, |
| // though there are cases where that does not hold: |
| // |
| // "SSLError".underscore().camelize() // => "SslError" |
| inflect.underscore = function (camel_cased_word) { |
| var self; |
| self = util.string.gsub(camel_cased_word, /\./, '/'); |
| self = util.string.gsub(self, /([A-Z]+)([A-Z][a-z])/, "$1_$2"); |
| self = util.string.gsub(self, /([a-z\d])([A-Z])/, "$1_$2"); |
| self = util.string.gsub(self, /-/, '_'); |
| return self.toLowerCase(); |
| }; |
| |
| // Replaces underscores with dashes in the string. |
| // |
| // "puni_puni".dasherize() // => "puni-puni" |
| inflect.dasherize = function (underscored_word) { |
| return util.string.gsub(underscored_word, /_/, '-'); |
| }; |
| |
| // Removes the module part from the expression in the string. |
| // |
| // "BulletRecord.String.Inflections".demodulize() // => "Inflections" |
| // "Inflections".demodulize() // => "Inflections" |
| inflect.demodulize = function (class_name_in_module) { |
| return util.string.gsub(class_name_in_module, /^.*\./, ''); |
| }; |
| |
| // Creates a foreign key name from a class name. |
| // _separate_class_name_and_id_with_underscore_ sets whether |
| // the method should put '_' between the name and 'id'. |
| // |
| // "Message".foreign_key() // => "message_id" |
| // "Message".foreign_key(false) // => "messageid" |
| // "Admin::Post".foreign_key() // => "post_id" |
| inflect.foreign_key = function (class_name, separate_class_name_and_id_with_underscore) { |
| if (separate_class_name_and_id_with_underscore == null) { |
| separate_class_name_and_id_with_underscore = true; |
| } |
| return inflect.underscore(inflect.demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id"); |
| }; |
| |
| // Turns a number into an ordinal string used to denote the position in an |
| // ordered sequence such as 1st, 2nd, 3rd, 4th. |
| // |
| // ordinalize(1) // => "1st" |
| // ordinalize(2) // => "2nd" |
| // ordinalize(1002) // => "1002nd" |
| // ordinalize(1003) // => "1003rd" |
| // ordinalize(-11) // => "-11th" |
| // ordinalize(-1021) // => "-1021st" |
| inflect.ordinalize = function (number) { |
| var _ref; |
| number = parseInt(number); |
| if ((_ref = Math.abs(number) % 100) === 11 || _ref === 12 || _ref === 13) { |
| return "" + number + "th"; |
| } else { |
| switch (Math.abs(number) % 10) { |
| case 1: |
| return "" + number + "st"; |
| case 2: |
| return "" + number + "nd"; |
| case 3: |
| return "" + number + "rd"; |
| default: |
| return "" + number + "th"; |
| } |
| } |
| }; |
| |
| // Checks a given word for uncountability |
| // |
| // "money".uncountability() // => true |
| // "my money".uncountability() // => true |
| inflect.uncountability = function (word) { |
| return inflect.inflections.uncountables.some(function(ele, ind, arr) { |
| return word.match(new RegExp("(\\b|_)" + ele + "$", 'i')) != null; |
| }); |
| }; |
| |
| // Returns the plural form of the word in the string. |
| // |
| // "post".pluralize() // => "posts" |
| // "octopus".pluralize() // => "octopi" |
| // "sheep".pluralize() // => "sheep" |
| // "words".pluralize() // => "words" |
| // "CamelOctopus".pluralize() // => "CamelOctopi" |
| inflect.pluralize = function (word) { |
| var plural, result; |
| result = word; |
| if (word === '' || inflect.uncountability(word)) { |
| return result; |
| } else { |
| for (var i = 0; i < inflect.inflections.plurals.length; i++) { |
| plural = inflect.inflections.plurals[i]; |
| result = util.string.gsub(result, plural[0], plural[1]); |
| if (word.match(plural[0]) != null) break; |
| } |
| return result; |
| } |
| }; |
| |
| // The reverse of _pluralize_, returns the singular form of a word in a string. |
| // |
| // "posts".singularize() // => "post" |
| // "octopi".singularize() // => "octopus" |
| // "sheep".singularize() // => "sheep" |
| // "word".singularize() // => "word" |
| // "CamelOctopi".singularize() // => "CamelOctopus" |
| inflect.singularize = function (word) { |
| var result, singular; |
| result = word; |
| if (word === '' || inflect.uncountability(word)) { |
| return result; |
| } else { |
| for (var i = 0; i < inflect.inflections.singulars.length; i++) { |
| singular = inflect.inflections.singulars[i]; |
| result = util.string.gsub(result, singular[0], singular[1]); |
| if (word.match(singular[0])) break; |
| } |
| return result; |
| } |
| }; |
| |
| // Capitalizes the first word and turns underscores into spaces and strips a |
| // trailing "_id", if any. Like _titleize_, this is meant for creating pretty output. |
| // |
| // "employee_salary".humanize() // => "Employee salary" |
| // "author_id".humanize() // => "Author" |
| inflect.humanize = function (lower_case_and_underscored_word) { |
| var human, result; |
| result = lower_case_and_underscored_word; |
| for (var i = 0; i < inflect.inflections.humans.length; i++) { |
| human = inflect.inflections.humans[i]; |
| result = util.string.gsub(result, human[0], human[1]); |
| } |
| result = util.string.gsub(result, /_id$/, ""); |
| result = util.string.gsub(result, /_/, " "); |
| return util.string.capitalize(result, true); |
| }; |
| |
| // Capitalizes all the words and replaces some characters in the string to create |
| // a nicer looking title. _titleize_ is meant for creating pretty output. It is not |
| // used in the Bullet internals. |
| // |
| // |
| // "man from the boondocks".titleize() // => "Man From The Boondocks" |
| // "x-men: the last stand".titleize() // => "X Men: The Last Stand" |
| inflect.titleize = function (word) { |
| var self; |
| self = inflect.humanize(inflect.underscore(word)); |
| self = util.string.gsub(self, /[^a-zA-Z:']/, ' '); |
| return util.string.capitalize(self); |
| }; |
| |
| // Create the name of a table like Bullet does for models to table names. This method |
| // uses the _pluralize_ method on the last word in the string. |
| // |
| // "RawScaledScorer".tableize() // => "raw_scaled_scorers" |
| // "egg_and_ham".tableize() // => "egg_and_hams" |
| // "fancyCategory".tableize() // => "fancy_categories" |
| inflect.tableize = function (class_name) { |
| return inflect.pluralize(inflect.underscore(class_name)); |
| }; |
| |
| // Create a class name from a plural table name like Bullet does for table names to models. |
| // Note that this returns a string and not a Class. |
| // |
| // "egg_and_hams".classify() // => "EggAndHam" |
| // "posts".classify() // => "Post" |
| // |
| // Singular names are not handled correctly: |
| // |
| // "business".classify() // => "Busines" |
| inflect.classify = function (table_name) { |
| return inflect.camelize(inflect.singularize(util.string.gsub(table_name, /.*\./, ''))); |
| } |