inflection.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086
  1. /*!
  2. * inflection
  3. * Copyright(c) 2011 Ben Lin <ben@dreamerslab.com>
  4. * MIT Licensed
  5. *
  6. * @fileoverview
  7. * A port of inflection-js to node.js module.
  8. */
  9. ( function ( root, factory ){
  10. if( typeof define === 'function' && define.amd ){
  11. define([], factory );
  12. }else if( typeof exports === 'object' ){
  13. module.exports = factory();
  14. }else{
  15. root.inflection = factory();
  16. }
  17. }( this, function (){
  18. /**
  19. * @description This is a list of nouns that use the same form for both singular and plural.
  20. * This list should remain entirely in lower case to correctly match Strings.
  21. * @private
  22. */
  23. var uncountable_words = [
  24. // 'access',
  25. 'accommodation',
  26. 'adulthood',
  27. 'advertising',
  28. 'advice',
  29. 'aggression',
  30. 'aid',
  31. 'air',
  32. 'aircraft',
  33. 'alcohol',
  34. 'anger',
  35. 'applause',
  36. 'arithmetic',
  37. // 'art',
  38. 'assistance',
  39. 'athletics',
  40. // 'attention',
  41. 'bacon',
  42. 'baggage',
  43. // 'ballet',
  44. // 'beauty',
  45. 'beef',
  46. // 'beer',
  47. // 'behavior',
  48. 'biology',
  49. // 'billiards',
  50. 'blood',
  51. 'botany',
  52. // 'bowels',
  53. 'bread',
  54. // 'business',
  55. 'butter',
  56. 'carbon',
  57. 'cardboard',
  58. 'cash',
  59. 'chalk',
  60. 'chaos',
  61. 'chess',
  62. 'crossroads',
  63. 'countryside',
  64. // 'damage',
  65. 'dancing',
  66. // 'danger',
  67. 'deer',
  68. // 'delight',
  69. // 'dessert',
  70. 'dignity',
  71. 'dirt',
  72. // 'distribution',
  73. 'dust',
  74. 'economics',
  75. 'education',
  76. 'electricity',
  77. // 'employment',
  78. // 'energy',
  79. 'engineering',
  80. 'enjoyment',
  81. // 'entertainment',
  82. 'envy',
  83. 'equipment',
  84. 'ethics',
  85. 'evidence',
  86. 'evolution',
  87. // 'failure',
  88. // 'faith',
  89. 'fame',
  90. 'fiction',
  91. // 'fish',
  92. 'flour',
  93. 'flu',
  94. 'food',
  95. // 'freedom',
  96. // 'fruit',
  97. 'fuel',
  98. 'fun',
  99. // 'funeral',
  100. 'furniture',
  101. 'gallows',
  102. 'garbage',
  103. 'garlic',
  104. // 'gas',
  105. 'genetics',
  106. // 'glass',
  107. 'gold',
  108. 'golf',
  109. 'gossip',
  110. 'grammar',
  111. // 'grass',
  112. 'gratitude',
  113. 'grief',
  114. // 'ground',
  115. 'guilt',
  116. 'gymnastics',
  117. // 'hair',
  118. 'happiness',
  119. 'hardware',
  120. 'harm',
  121. 'hate',
  122. 'hatred',
  123. 'health',
  124. 'heat',
  125. // 'height',
  126. 'help',
  127. 'homework',
  128. 'honesty',
  129. 'honey',
  130. 'hospitality',
  131. 'housework',
  132. 'humour',
  133. 'hunger',
  134. 'hydrogen',
  135. 'ice',
  136. 'importance',
  137. 'inflation',
  138. 'information',
  139. // 'injustice',
  140. 'innocence',
  141. // 'intelligence',
  142. 'iron',
  143. 'irony',
  144. 'jam',
  145. // 'jealousy',
  146. // 'jelly',
  147. 'jewelry',
  148. // 'joy',
  149. 'judo',
  150. // 'juice',
  151. // 'justice',
  152. 'karate',
  153. // 'kindness',
  154. 'knowledge',
  155. // 'labour',
  156. 'lack',
  157. // 'land',
  158. 'laughter',
  159. 'lava',
  160. 'leather',
  161. 'leisure',
  162. 'lightning',
  163. 'linguine',
  164. 'linguini',
  165. 'linguistics',
  166. 'literature',
  167. 'litter',
  168. 'livestock',
  169. 'logic',
  170. 'loneliness',
  171. // 'love',
  172. 'luck',
  173. 'luggage',
  174. 'macaroni',
  175. 'machinery',
  176. 'magic',
  177. // 'mail',
  178. 'management',
  179. 'mankind',
  180. 'marble',
  181. 'mathematics',
  182. 'mayonnaise',
  183. 'measles',
  184. // 'meat',
  185. // 'metal',
  186. 'methane',
  187. 'milk',
  188. 'minus',
  189. 'money',
  190. // 'moose',
  191. 'mud',
  192. 'music',
  193. 'mumps',
  194. 'nature',
  195. 'news',
  196. 'nitrogen',
  197. 'nonsense',
  198. 'nurture',
  199. 'nutrition',
  200. 'obedience',
  201. 'obesity',
  202. // 'oil',
  203. 'oxygen',
  204. // 'paper',
  205. // 'passion',
  206. 'pasta',
  207. 'patience',
  208. // 'permission',
  209. 'physics',
  210. 'poetry',
  211. 'pollution',
  212. 'poverty',
  213. // 'power',
  214. 'pride',
  215. // 'production',
  216. // 'progress',
  217. // 'pronunciation',
  218. 'psychology',
  219. 'publicity',
  220. 'punctuation',
  221. // 'quality',
  222. // 'quantity',
  223. 'quartz',
  224. 'racism',
  225. // 'rain',
  226. // 'recreation',
  227. 'relaxation',
  228. 'reliability',
  229. 'research',
  230. 'respect',
  231. 'revenge',
  232. 'rice',
  233. 'rubbish',
  234. 'rum',
  235. 'safety',
  236. // 'salad',
  237. // 'salt',
  238. // 'sand',
  239. // 'satire',
  240. 'scenery',
  241. 'seafood',
  242. 'seaside',
  243. 'series',
  244. 'shame',
  245. 'sheep',
  246. 'shopping',
  247. // 'silence',
  248. 'sleep',
  249. // 'slang'
  250. 'smoke',
  251. 'smoking',
  252. 'snow',
  253. 'soap',
  254. 'software',
  255. 'soil',
  256. // 'sorrow',
  257. // 'soup',
  258. 'spaghetti',
  259. // 'speed',
  260. 'species',
  261. // 'spelling',
  262. // 'sport',
  263. 'steam',
  264. // 'strength',
  265. 'stuff',
  266. 'stupidity',
  267. // 'success',
  268. // 'sugar',
  269. 'sunshine',
  270. 'symmetry',
  271. // 'tea',
  272. 'tennis',
  273. 'thirst',
  274. 'thunder',
  275. 'timber',
  276. // 'time',
  277. // 'toast',
  278. // 'tolerance',
  279. // 'trade',
  280. 'traffic',
  281. 'transportation',
  282. // 'travel',
  283. 'trust',
  284. // 'understanding',
  285. 'underwear',
  286. 'unemployment',
  287. 'unity',
  288. // 'usage',
  289. 'validity',
  290. 'veal',
  291. 'vegetation',
  292. 'vegetarianism',
  293. 'vengeance',
  294. 'violence',
  295. // 'vision',
  296. 'vitality',
  297. 'warmth',
  298. // 'water',
  299. 'wealth',
  300. 'weather',
  301. // 'weight',
  302. 'welfare',
  303. 'wheat',
  304. // 'whiskey',
  305. // 'width',
  306. 'wildlife',
  307. // 'wine',
  308. 'wisdom',
  309. // 'wood',
  310. // 'wool',
  311. // 'work',
  312. // 'yeast',
  313. 'yoga',
  314. 'zinc',
  315. 'zoology'
  316. ];
  317. /**
  318. * @description These rules translate from the singular form of a noun to its plural form.
  319. * @private
  320. */
  321. var regex = {
  322. plural : {
  323. men : new RegExp( '^(m|wom)en$' , 'gi' ),
  324. people : new RegExp( '(pe)ople$' , 'gi' ),
  325. children : new RegExp( '(child)ren$' , 'gi' ),
  326. tia : new RegExp( '([ti])a$' , 'gi' ),
  327. analyses : new RegExp( '((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$','gi' ),
  328. hives : new RegExp( '(hi|ti)ves$' , 'gi' ),
  329. curves : new RegExp( '(curve)s$' , 'gi' ),
  330. lrves : new RegExp( '([lr])ves$' , 'gi' ),
  331. aves : new RegExp( '([a])ves$' , 'gi' ),
  332. foves : new RegExp( '([^fo])ves$' , 'gi' ),
  333. movies : new RegExp( '(m)ovies$' , 'gi' ),
  334. aeiouyies : new RegExp( '([^aeiouy]|qu)ies$' , 'gi' ),
  335. series : new RegExp( '(s)eries$' , 'gi' ),
  336. xes : new RegExp( '(x|ch|ss|sh)es$' , 'gi' ),
  337. mice : new RegExp( '([m|l])ice$' , 'gi' ),
  338. buses : new RegExp( '(bus)es$' , 'gi' ),
  339. oes : new RegExp( '(o)es$' , 'gi' ),
  340. shoes : new RegExp( '(shoe)s$' , 'gi' ),
  341. crises : new RegExp( '(cris|ax|test)es$' , 'gi' ),
  342. octopi : new RegExp( '(octop|vir)i$' , 'gi' ),
  343. aliases : new RegExp( '(alias|canvas|status|campus)es$', 'gi' ),
  344. summonses : new RegExp( '^(summons)es$' , 'gi' ),
  345. oxen : new RegExp( '^(ox)en' , 'gi' ),
  346. matrices : new RegExp( '(matr)ices$' , 'gi' ),
  347. vertices : new RegExp( '(vert|ind)ices$' , 'gi' ),
  348. feet : new RegExp( '^feet$' , 'gi' ),
  349. teeth : new RegExp( '^teeth$' , 'gi' ),
  350. geese : new RegExp( '^geese$' , 'gi' ),
  351. quizzes : new RegExp( '(quiz)zes$' , 'gi' ),
  352. whereases : new RegExp( '^(whereas)es$' , 'gi' ),
  353. criteria : new RegExp( '^(criteri)a$' , 'gi' ),
  354. genera : new RegExp( '^genera$' , 'gi' ),
  355. ss : new RegExp( 'ss$' , 'gi' ),
  356. s : new RegExp( 's$' , 'gi' )
  357. },
  358. singular : {
  359. man : new RegExp( '^(m|wom)an$' , 'gi' ),
  360. person : new RegExp( '(pe)rson$' , 'gi' ),
  361. child : new RegExp( '(child)$' , 'gi' ),
  362. ox : new RegExp( '^(ox)$' , 'gi' ),
  363. axis : new RegExp( '(ax|test)is$' , 'gi' ),
  364. octopus : new RegExp( '(octop|vir)us$' , 'gi' ),
  365. alias : new RegExp( '(alias|status|canvas|campus)$', 'gi' ),
  366. summons : new RegExp( '^(summons)$' , 'gi' ),
  367. bus : new RegExp( '(bu)s$' , 'gi' ),
  368. buffalo : new RegExp( '(buffal|tomat|potat)o$' , 'gi' ),
  369. tium : new RegExp( '([ti])um$' , 'gi' ),
  370. sis : new RegExp( 'sis$' , 'gi' ),
  371. ffe : new RegExp( '(?:([^f])fe|([lr])f)$' , 'gi' ),
  372. hive : new RegExp( '(hi|ti)ve$' , 'gi' ),
  373. aeiouyy : new RegExp( '([^aeiouy]|qu)y$' , 'gi' ),
  374. x : new RegExp( '(x|ch|ss|sh)$' , 'gi' ),
  375. matrix : new RegExp( '(matr)ix$' , 'gi' ),
  376. vertex : new RegExp( '(vert|ind)ex$' , 'gi' ),
  377. mouse : new RegExp( '([m|l])ouse$' , 'gi' ),
  378. foot : new RegExp( '^foot$' , 'gi' ),
  379. tooth : new RegExp( '^tooth$' , 'gi' ),
  380. goose : new RegExp( '^goose$' , 'gi' ),
  381. quiz : new RegExp( '(quiz)$' , 'gi' ),
  382. whereas : new RegExp( '^(whereas)$' , 'gi' ),
  383. criterion : new RegExp( '^(criteri)on$' , 'gi' ),
  384. genus : new RegExp( '^genus$' , 'gi' ),
  385. s : new RegExp( 's$' , 'gi' ),
  386. common : new RegExp( '$' , 'gi' )
  387. }
  388. };
  389. var plural_rules = [
  390. // do not replace if its already a plural word
  391. [ regex.plural.men ],
  392. [ regex.plural.people ],
  393. [ regex.plural.children ],
  394. [ regex.plural.tia ],
  395. [ regex.plural.analyses ],
  396. [ regex.plural.hives ],
  397. [ regex.plural.curves ],
  398. [ regex.plural.lrves ],
  399. [ regex.plural.foves ],
  400. [ regex.plural.aeiouyies ],
  401. [ regex.plural.series ],
  402. [ regex.plural.movies ],
  403. [ regex.plural.xes ],
  404. [ regex.plural.mice ],
  405. [ regex.plural.buses ],
  406. [ regex.plural.oes ],
  407. [ regex.plural.shoes ],
  408. [ regex.plural.crises ],
  409. [ regex.plural.octopi ],
  410. [ regex.plural.aliases ],
  411. [ regex.plural.summonses ],
  412. [ regex.plural.oxen ],
  413. [ regex.plural.matrices ],
  414. [ regex.plural.feet ],
  415. [ regex.plural.teeth ],
  416. [ regex.plural.geese ],
  417. [ regex.plural.quizzes ],
  418. [ regex.plural.whereases ],
  419. [ regex.plural.criteria ],
  420. [ regex.plural.genera ],
  421. // original rule
  422. [ regex.singular.man , '$1en' ],
  423. [ regex.singular.person , '$1ople' ],
  424. [ regex.singular.child , '$1ren' ],
  425. [ regex.singular.ox , '$1en' ],
  426. [ regex.singular.axis , '$1es' ],
  427. [ regex.singular.octopus , '$1i' ],
  428. [ regex.singular.alias , '$1es' ],
  429. [ regex.singular.summons , '$1es' ],
  430. [ regex.singular.bus , '$1ses' ],
  431. [ regex.singular.buffalo , '$1oes' ],
  432. [ regex.singular.tium , '$1a' ],
  433. [ regex.singular.sis , 'ses' ],
  434. [ regex.singular.ffe , '$1$2ves' ],
  435. [ regex.singular.hive , '$1ves' ],
  436. [ regex.singular.aeiouyy , '$1ies' ],
  437. [ regex.singular.matrix , '$1ices' ],
  438. [ regex.singular.vertex , '$1ices' ],
  439. [ regex.singular.x , '$1es' ],
  440. [ regex.singular.mouse , '$1ice' ],
  441. [ regex.singular.foot , 'feet' ],
  442. [ regex.singular.tooth , 'teeth' ],
  443. [ regex.singular.goose , 'geese' ],
  444. [ regex.singular.quiz , '$1zes' ],
  445. [ regex.singular.whereas , '$1es' ],
  446. [ regex.singular.criterion, '$1a' ],
  447. [ regex.singular.genus , 'genera' ],
  448. [ regex.singular.s , 's' ],
  449. [ regex.singular.common, 's' ]
  450. ];
  451. /**
  452. * @description These rules translate from the plural form of a noun to its singular form.
  453. * @private
  454. */
  455. var singular_rules = [
  456. // do not replace if its already a singular word
  457. [ regex.singular.man ],
  458. [ regex.singular.person ],
  459. [ regex.singular.child ],
  460. [ regex.singular.ox ],
  461. [ regex.singular.axis ],
  462. [ regex.singular.octopus ],
  463. [ regex.singular.alias ],
  464. [ regex.singular.summons ],
  465. [ regex.singular.bus ],
  466. [ regex.singular.buffalo ],
  467. [ regex.singular.tium ],
  468. [ regex.singular.sis ],
  469. [ regex.singular.ffe ],
  470. [ regex.singular.hive ],
  471. [ regex.singular.aeiouyy ],
  472. [ regex.singular.x ],
  473. [ regex.singular.matrix ],
  474. [ regex.singular.mouse ],
  475. [ regex.singular.foot ],
  476. [ regex.singular.tooth ],
  477. [ regex.singular.goose ],
  478. [ regex.singular.quiz ],
  479. [ regex.singular.whereas ],
  480. [ regex.singular.criterion ],
  481. [ regex.singular.genus ],
  482. // original rule
  483. [ regex.plural.men , '$1an' ],
  484. [ regex.plural.people , '$1rson' ],
  485. [ regex.plural.children , '$1' ],
  486. [ regex.plural.genera , 'genus'],
  487. [ regex.plural.criteria , '$1on'],
  488. [ regex.plural.tia , '$1um' ],
  489. [ regex.plural.analyses , '$1$2sis' ],
  490. [ regex.plural.hives , '$1ve' ],
  491. [ regex.plural.curves , '$1' ],
  492. [ regex.plural.lrves , '$1f' ],
  493. [ regex.plural.aves , '$1ve' ],
  494. [ regex.plural.foves , '$1fe' ],
  495. [ regex.plural.movies , '$1ovie' ],
  496. [ regex.plural.aeiouyies, '$1y' ],
  497. [ regex.plural.series , '$1eries' ],
  498. [ regex.plural.xes , '$1' ],
  499. [ regex.plural.mice , '$1ouse' ],
  500. [ regex.plural.buses , '$1' ],
  501. [ regex.plural.oes , '$1' ],
  502. [ regex.plural.shoes , '$1' ],
  503. [ regex.plural.crises , '$1is' ],
  504. [ regex.plural.octopi , '$1us' ],
  505. [ regex.plural.aliases , '$1' ],
  506. [ regex.plural.summonses, '$1' ],
  507. [ regex.plural.oxen , '$1' ],
  508. [ regex.plural.matrices , '$1ix' ],
  509. [ regex.plural.vertices , '$1ex' ],
  510. [ regex.plural.feet , 'foot' ],
  511. [ regex.plural.teeth , 'tooth' ],
  512. [ regex.plural.geese , 'goose' ],
  513. [ regex.plural.quizzes , '$1' ],
  514. [ regex.plural.whereases, '$1' ],
  515. [ regex.plural.ss, 'ss' ],
  516. [ regex.plural.s , '' ]
  517. ];
  518. /**
  519. * @description This is a list of words that should not be capitalized for title case.
  520. * @private
  521. */
  522. var non_titlecased_words = [
  523. 'and', 'or', 'nor', 'a', 'an', 'the', 'so', 'but', 'to', 'of', 'at','by',
  524. 'from', 'into', 'on', 'onto', 'off', 'out', 'in', 'over', 'with', 'for'
  525. ];
  526. /**
  527. * @description These are regular expressions used for converting between String formats.
  528. * @private
  529. */
  530. var id_suffix = new RegExp( '(_ids|_id)$', 'g' );
  531. var underbar = new RegExp( '_', 'g' );
  532. var space_or_underbar = new RegExp( '[\ _]', 'g' );
  533. var uppercase = new RegExp( '([A-Z])', 'g' );
  534. var underbar_prefix = new RegExp( '^_' );
  535. var inflector = {
  536. /**
  537. * A helper method that applies rules based replacement to a String.
  538. * @private
  539. * @function
  540. * @param {String} str String to modify and return based on the passed rules.
  541. * @param {Array: [RegExp, String]} rules Regexp to match paired with String to use for replacement
  542. * @param {Array: [String]} skip Strings to skip if they match
  543. * @param {String} override String to return as though this method succeeded (used to conform to APIs)
  544. * @returns {String} Return passed String modified by passed rules.
  545. * @example
  546. *
  547. * this._apply_rules( 'cows', singular_rules ); // === 'cow'
  548. */
  549. _apply_rules : function ( str, rules, skip, override ){
  550. if( override ){
  551. str = override;
  552. }else{
  553. var ignore = ( inflector.indexOf( skip, str.toLowerCase()) > -1 );
  554. if( !ignore ){
  555. var i = 0;
  556. var j = rules.length;
  557. for( ; i < j; i++ ){
  558. if( str.match( rules[ i ][ 0 ])){
  559. if( rules[ i ][ 1 ] !== undefined ){
  560. str = str.replace( rules[ i ][ 0 ], rules[ i ][ 1 ]);
  561. }
  562. break;
  563. }
  564. }
  565. }
  566. }
  567. return str;
  568. },
  569. /**
  570. * This lets us detect if an Array contains a given element.
  571. * @public
  572. * @function
  573. * @param {Array} arr The subject array.
  574. * @param {Object} item Object to locate in the Array.
  575. * @param {Number} from_index Starts checking from this position in the Array.(optional)
  576. * @param {Function} compare_func Function used to compare Array item vs passed item.(optional)
  577. * @returns {Number} Return index position in the Array of the passed item.
  578. * @example
  579. *
  580. * var inflection = require( 'inflection' );
  581. *
  582. * inflection.indexOf([ 'hi','there' ], 'guys' ); // === -1
  583. * inflection.indexOf([ 'hi','there' ], 'hi' ); // === 0
  584. */
  585. indexOf : function ( arr, item, from_index, compare_func ){
  586. if( !from_index ){
  587. from_index = -1;
  588. }
  589. var index = -1;
  590. var i = from_index;
  591. var j = arr.length;
  592. for( ; i < j; i++ ){
  593. if( arr[ i ] === item || compare_func && compare_func( arr[ i ], item )){
  594. index = i;
  595. break;
  596. }
  597. }
  598. return index;
  599. },
  600. /**
  601. * This function adds pluralization support to every String object.
  602. * @public
  603. * @function
  604. * @param {String} str The subject string.
  605. * @param {String} plural Overrides normal output with said String.(optional)
  606. * @returns {String} Singular English language nouns are returned in plural form.
  607. * @example
  608. *
  609. * var inflection = require( 'inflection' );
  610. *
  611. * inflection.pluralize( 'person' ); // === 'people'
  612. * inflection.pluralize( 'octopus' ); // === 'octopi'
  613. * inflection.pluralize( 'Hat' ); // === 'Hats'
  614. * inflection.pluralize( 'person', 'guys' ); // === 'guys'
  615. */
  616. pluralize : function ( str, plural ){
  617. return inflector._apply_rules( str, plural_rules, uncountable_words, plural );
  618. },
  619. /**
  620. * This function adds singularization support to every String object.
  621. * @public
  622. * @function
  623. * @param {String} str The subject string.
  624. * @param {String} singular Overrides normal output with said String.(optional)
  625. * @returns {String} Plural English language nouns are returned in singular form.
  626. * @example
  627. *
  628. * var inflection = require( 'inflection' );
  629. *
  630. * inflection.singularize( 'people' ); // === 'person'
  631. * inflection.singularize( 'octopi' ); // === 'octopus'
  632. * inflection.singularize( 'Hats' ); // === 'Hat'
  633. * inflection.singularize( 'guys', 'person' ); // === 'person'
  634. */
  635. singularize : function ( str, singular ){
  636. return inflector._apply_rules( str, singular_rules, uncountable_words, singular );
  637. },
  638. /**
  639. * This function will pluralize or singularlize a String appropriately based on an integer value
  640. * @public
  641. * @function
  642. * @param {String} str The subject string.
  643. * @param {Number} count The number to base pluralization off of.
  644. * @param {String} singular Overrides normal output with said String.(optional)
  645. * @param {String} plural Overrides normal output with said String.(optional)
  646. * @returns {String} English language nouns are returned in the plural or singular form based on the count.
  647. * @example
  648. *
  649. * var inflection = require( 'inflection' );
  650. *
  651. * inflection.inflect( 'people' 1 ); // === 'person'
  652. * inflection.inflect( 'octopi' 1 ); // === 'octopus'
  653. * inflection.inflect( 'Hats' 1 ); // === 'Hat'
  654. * inflection.inflect( 'guys', 1 , 'person' ); // === 'person'
  655. * inflection.inflect( 'person', 2 ); // === 'people'
  656. * inflection.inflect( 'octopus', 2 ); // === 'octopi'
  657. * inflection.inflect( 'Hat', 2 ); // === 'Hats'
  658. * inflection.inflect( 'person', 2, null, 'guys' ); // === 'guys'
  659. */
  660. inflect : function ( str, count, singular, plural ){
  661. count = parseInt( count, 10 );
  662. if( isNaN( count )) return str;
  663. if( count === 0 || count > 1 ){
  664. return inflector._apply_rules( str, plural_rules, uncountable_words, plural );
  665. }else{
  666. return inflector._apply_rules( str, singular_rules, uncountable_words, singular );
  667. }
  668. },
  669. /**
  670. * This function adds camelization support to every String object.
  671. * @public
  672. * @function
  673. * @param {String} str The subject string.
  674. * @param {Boolean} low_first_letter Default is to capitalize the first letter of the results.(optional)
  675. * Passing true will lowercase it.
  676. * @returns {String} Lower case underscored words will be returned in camel case.
  677. * additionally '/' is translated to '::'
  678. * @example
  679. *
  680. * var inflection = require( 'inflection' );
  681. *
  682. * inflection.camelize( 'message_properties' ); // === 'MessageProperties'
  683. * inflection.camelize( 'message_properties', true ); // === 'messageProperties'
  684. */
  685. camelize : function ( str, low_first_letter ){
  686. var str_path = str.split( '/' );
  687. var i = 0;
  688. var j = str_path.length;
  689. var str_arr, init_x, k, l, first;
  690. for( ; i < j; i++ ){
  691. str_arr = str_path[ i ].split( '_' );
  692. k = 0;
  693. l = str_arr.length;
  694. for( ; k < l; k++ ){
  695. if( k !== 0 ){
  696. str_arr[ k ] = str_arr[ k ].toLowerCase();
  697. }
  698. first = str_arr[ k ].charAt( 0 );
  699. first = low_first_letter && i === 0 && k === 0
  700. ? first.toLowerCase() : first.toUpperCase();
  701. str_arr[ k ] = first + str_arr[ k ].substring( 1 );
  702. }
  703. str_path[ i ] = str_arr.join( '' );
  704. }
  705. return str_path.join( '::' );
  706. },
  707. /**
  708. * This function adds underscore support to every String object.
  709. * @public
  710. * @function
  711. * @param {String} str The subject string.
  712. * @param {Boolean} all_upper_case Default is to lowercase and add underscore prefix.(optional)
  713. * Passing true will return as entered.
  714. * @returns {String} Camel cased words are returned as lower cased and underscored.
  715. * additionally '::' is translated to '/'.
  716. * @example
  717. *
  718. * var inflection = require( 'inflection' );
  719. *
  720. * inflection.underscore( 'MessageProperties' ); // === 'message_properties'
  721. * inflection.underscore( 'messageProperties' ); // === 'message_properties'
  722. * inflection.underscore( 'MP', true ); // === 'MP'
  723. */
  724. underscore : function ( str, all_upper_case ){
  725. if( all_upper_case && str === str.toUpperCase()) return str;
  726. var str_path = str.split( '::' );
  727. var i = 0;
  728. var j = str_path.length;
  729. for( ; i < j; i++ ){
  730. str_path[ i ] = str_path[ i ].replace( uppercase, '_$1' );
  731. str_path[ i ] = str_path[ i ].replace( underbar_prefix, '' );
  732. }
  733. return str_path.join( '/' ).toLowerCase();
  734. },
  735. /**
  736. * This function adds humanize support to every String object.
  737. * @public
  738. * @function
  739. * @param {String} str The subject string.
  740. * @param {Boolean} low_first_letter Default is to capitalize the first letter of the results.(optional)
  741. * Passing true will lowercase it.
  742. * @returns {String} Lower case underscored words will be returned in humanized form.
  743. * @example
  744. *
  745. * var inflection = require( 'inflection' );
  746. *
  747. * inflection.humanize( 'message_properties' ); // === 'Message properties'
  748. * inflection.humanize( 'message_properties', true ); // === 'message properties'
  749. */
  750. humanize : function ( str, low_first_letter ){
  751. str = str.toLowerCase();
  752. str = str.replace( id_suffix, '' );
  753. str = str.replace( underbar, ' ' );
  754. if( !low_first_letter ){
  755. str = inflector.capitalize( str );
  756. }
  757. return str;
  758. },
  759. /**
  760. * This function adds capitalization support to every String object.
  761. * @public
  762. * @function
  763. * @param {String} str The subject string.
  764. * @returns {String} All characters will be lower case and the first will be upper.
  765. * @example
  766. *
  767. * var inflection = require( 'inflection' );
  768. *
  769. * inflection.capitalize( 'message_properties' ); // === 'Message_properties'
  770. * inflection.capitalize( 'message properties', true ); // === 'Message properties'
  771. */
  772. capitalize : function ( str ){
  773. str = str.toLowerCase();
  774. return str.substring( 0, 1 ).toUpperCase() + str.substring( 1 );
  775. },
  776. /**
  777. * This function replaces underscores with dashes in the string.
  778. * @public
  779. * @function
  780. * @param {String} str The subject string.
  781. * @returns {String} Replaces all spaces or underscores with dashes.
  782. * @example
  783. *
  784. * var inflection = require( 'inflection' );
  785. *
  786. * inflection.dasherize( 'message_properties' ); // === 'message-properties'
  787. * inflection.dasherize( 'Message Properties' ); // === 'Message-Properties'
  788. */
  789. dasherize : function ( str ){
  790. return str.replace( space_or_underbar, '-' );
  791. },
  792. /**
  793. * This function adds titleize support to every String object.
  794. * @public
  795. * @function
  796. * @param {String} str The subject string.
  797. * @returns {String} Capitalizes words as you would for a book title.
  798. * @example
  799. *
  800. * var inflection = require( 'inflection' );
  801. *
  802. * inflection.titleize( 'message_properties' ); // === 'Message Properties'
  803. * inflection.titleize( 'message properties to keep' ); // === 'Message Properties to Keep'
  804. */
  805. titleize : function ( str ){
  806. str = str.toLowerCase().replace( underbar, ' ' );
  807. var str_arr = str.split( ' ' );
  808. var i = 0;
  809. var j = str_arr.length;
  810. var d, k, l;
  811. for( ; i < j; i++ ){
  812. d = str_arr[ i ].split( '-' );
  813. k = 0;
  814. l = d.length;
  815. for( ; k < l; k++){
  816. if( inflector.indexOf( non_titlecased_words, d[ k ].toLowerCase()) < 0 ){
  817. d[ k ] = inflector.capitalize( d[ k ]);
  818. }
  819. }
  820. str_arr[ i ] = d.join( '-' );
  821. }
  822. str = str_arr.join( ' ' );
  823. str = str.substring( 0, 1 ).toUpperCase() + str.substring( 1 );
  824. return str;
  825. },
  826. /**
  827. * This function adds demodulize support to every String object.
  828. * @public
  829. * @function
  830. * @param {String} str The subject string.
  831. * @returns {String} Removes module names leaving only class names.(Ruby style)
  832. * @example
  833. *
  834. * var inflection = require( 'inflection' );
  835. *
  836. * inflection.demodulize( 'Message::Bus::Properties' ); // === 'Properties'
  837. */
  838. demodulize : function ( str ){
  839. var str_arr = str.split( '::' );
  840. return str_arr[ str_arr.length - 1 ];
  841. },
  842. /**
  843. * This function adds tableize support to every String object.
  844. * @public
  845. * @function
  846. * @param {String} str The subject string.
  847. * @returns {String} Return camel cased words into their underscored plural form.
  848. * @example
  849. *
  850. * var inflection = require( 'inflection' );
  851. *
  852. * inflection.tableize( 'MessageBusProperty' ); // === 'message_bus_properties'
  853. */
  854. tableize : function ( str ){
  855. str = inflector.underscore( str );
  856. str = inflector.pluralize( str );
  857. return str;
  858. },
  859. /**
  860. * This function adds classification support to every String object.
  861. * @public
  862. * @function
  863. * @param {String} str The subject string.
  864. * @returns {String} Underscored plural nouns become the camel cased singular form.
  865. * @example
  866. *
  867. * var inflection = require( 'inflection' );
  868. *
  869. * inflection.classify( 'message_bus_properties' ); // === 'MessageBusProperty'
  870. */
  871. classify : function ( str ){
  872. str = inflector.camelize( str );
  873. str = inflector.singularize( str );
  874. return str;
  875. },
  876. /**
  877. * This function adds foreign key support to every String object.
  878. * @public
  879. * @function
  880. * @param {String} str The subject string.
  881. * @param {Boolean} drop_id_ubar Default is to seperate id with an underbar at the end of the class name,
  882. you can pass true to skip it.(optional)
  883. * @returns {String} Underscored plural nouns become the camel cased singular form.
  884. * @example
  885. *
  886. * var inflection = require( 'inflection' );
  887. *
  888. * inflection.foreign_key( 'MessageBusProperty' ); // === 'message_bus_property_id'
  889. * inflection.foreign_key( 'MessageBusProperty', true ); // === 'message_bus_propertyid'
  890. */
  891. foreign_key : function ( str, drop_id_ubar ){
  892. str = inflector.demodulize( str );
  893. str = inflector.underscore( str ) + (( drop_id_ubar ) ? ( '' ) : ( '_' )) + 'id';
  894. return str;
  895. },
  896. /**
  897. * This function adds ordinalize support to every String object.
  898. * @public
  899. * @function
  900. * @param {String} str The subject string.
  901. * @returns {String} Return all found numbers their sequence like '22nd'.
  902. * @example
  903. *
  904. * var inflection = require( 'inflection' );
  905. *
  906. * inflection.ordinalize( 'the 1 pitch' ); // === 'the 1st pitch'
  907. */
  908. ordinalize : function ( str ){
  909. var str_arr = str.split( ' ' );
  910. var i = 0;
  911. var j = str_arr.length;
  912. for( ; i < j; i++ ){
  913. var k = parseInt( str_arr[ i ], 10 );
  914. if( !isNaN( k )){
  915. var ltd = str_arr[ i ].substring( str_arr[ i ].length - 2 );
  916. var ld = str_arr[ i ].substring( str_arr[ i ].length - 1 );
  917. var suf = 'th';
  918. if( ltd != '11' && ltd != '12' && ltd != '13' ){
  919. if( ld === '1' ){
  920. suf = 'st';
  921. }else if( ld === '2' ){
  922. suf = 'nd';
  923. }else if( ld === '3' ){
  924. suf = 'rd';
  925. }
  926. }
  927. str_arr[ i ] += suf;
  928. }
  929. }
  930. return str_arr.join( ' ' );
  931. },
  932. /**
  933. * This function performs multiple inflection methods on a string
  934. * @public
  935. * @function
  936. * @param {String} str The subject string.
  937. * @param {Array} arr An array of inflection methods.
  938. * @returns {String}
  939. * @example
  940. *
  941. * var inflection = require( 'inflection' );
  942. *
  943. * inflection.transform( 'all job', [ 'pluralize', 'capitalize', 'dasherize' ]); // === 'All-jobs'
  944. */
  945. transform : function ( str, arr ){
  946. var i = 0;
  947. var j = arr.length;
  948. for( ;i < j; i++ ){
  949. var method = arr[ i ];
  950. if( inflector.hasOwnProperty( method )){
  951. str = inflector[ method ]( str );
  952. }
  953. }
  954. return str;
  955. }
  956. };
  957. /**
  958. * @public
  959. */
  960. inflector.version = '1.12.0';
  961. return inflector;
  962. }));