inflection.js 31 KB

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