PageRenderTime 49ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/bundle/ruby/1.9.1/gems/activesupport-3.2.2/lib/active_support/inflector/methods.rb

https://bitbucket.org/mulligan/extractext
Ruby | 320 lines | 168 code | 18 blank | 134 comment | 15 complexity | 511f42f9038653a92bf3dc45ef0b1d00 MD5 | raw file
Possible License(s): Apache-2.0, MIT, GPL-3.0, GPL-2.0, BSD-3-Clause, MPL-2.0-no-copyleft-exception, BSD-2-Clause, JSON
  1. require 'active_support/inflector/inflections'
  2. module ActiveSupport
  3. # The Inflector transforms words from singular to plural, class names to table names, modularized class names to ones without,
  4. # and class names to foreign keys. The default inflections for pluralization, singularization, and uncountable words are kept
  5. # in inflections.rb.
  6. #
  7. # The Rails core team has stated patches for the inflections library will not be accepted
  8. # in order to avoid breaking legacy applications which may be relying on errant inflections.
  9. # If you discover an incorrect inflection and require it for your application, you'll need
  10. # to correct it yourself (explained below).
  11. module Inflector
  12. extend self
  13. # Returns the plural form of the word in the string.
  14. #
  15. # Examples:
  16. # "post".pluralize # => "posts"
  17. # "octopus".pluralize # => "octopi"
  18. # "sheep".pluralize # => "sheep"
  19. # "words".pluralize # => "words"
  20. # "CamelOctopus".pluralize # => "CamelOctopi"
  21. def pluralize(word)
  22. apply_inflections(word, inflections.plurals)
  23. end
  24. # The reverse of +pluralize+, returns the singular form of a word in a string.
  25. #
  26. # Examples:
  27. # "posts".singularize # => "post"
  28. # "octopi".singularize # => "octopus"
  29. # "sheep".singularize # => "sheep"
  30. # "word".singularize # => "word"
  31. # "CamelOctopi".singularize # => "CamelOctopus"
  32. def singularize(word)
  33. apply_inflections(word, inflections.singulars)
  34. end
  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. # Examples:
  41. # "active_model".camelize # => "ActiveModel"
  42. # "active_model".camelize(:lower) # => "activeModel"
  43. # "active_model/errors".camelize # => "ActiveModel::Errors"
  44. # "active_model/errors".camelize(:lower) # => "activeModel::Errors"
  45. #
  46. # As a rule of thumb you can think of +camelize+ as the inverse of +underscore+,
  47. # though there are cases where that does not hold:
  48. #
  49. # "SSLError".underscore.camelize # => "SslError"
  50. def camelize(term, uppercase_first_letter = true)
  51. string = term.to_s
  52. if uppercase_first_letter
  53. string = string.sub(/^[a-z\d]*/) { inflections.acronyms[$&] || $&.capitalize }
  54. else
  55. string = string.sub(/^(?:#{inflections.acronym_regex}(?=\b|[A-Z_])|\w)/) { $&.downcase }
  56. end
  57. string.gsub(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }.gsub('/', '::')
  58. end
  59. # Makes an underscored, lowercase form from the expression in the string.
  60. #
  61. # Changes '::' to '/' to convert namespaces to paths.
  62. #
  63. # Examples:
  64. # "ActiveModel".underscore # => "active_model"
  65. # "ActiveModel::Errors".underscore # => "active_model/errors"
  66. #
  67. # As a rule of thumb you can think of +underscore+ as the inverse of +camelize+,
  68. # though there are cases where that does not hold:
  69. #
  70. # "SSLError".underscore.camelize # => "SslError"
  71. def underscore(camel_cased_word)
  72. word = camel_cased_word.to_s.dup
  73. word.gsub!(/::/, '/')
  74. word.gsub!(/(?:([A-Za-z\d])|^)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$1}#{$1 && '_'}#{$2.downcase}" }
  75. word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
  76. word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
  77. word.tr!("-", "_")
  78. word.downcase!
  79. word
  80. end
  81. # Capitalizes the first word and turns underscores into spaces and strips a
  82. # trailing "_id", if any. Like +titleize+, this is meant for creating pretty output.
  83. #
  84. # Examples:
  85. # "employee_salary" # => "Employee salary"
  86. # "author_id" # => "Author"
  87. def humanize(lower_case_and_underscored_word)
  88. result = lower_case_and_underscored_word.to_s.dup
  89. inflections.humans.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
  90. result.gsub!(/_id$/, "")
  91. result.gsub!(/_/, ' ')
  92. result.gsub(/([a-z\d]*)/i) { |match|
  93. "#{inflections.acronyms[match] || match.downcase}"
  94. }.gsub(/^\w/) { $&.upcase }
  95. end
  96. # Capitalizes all the words and replaces some characters in the string to create
  97. # a nicer looking title. +titleize+ is meant for creating pretty output. It is not
  98. # used in the Rails internals.
  99. #
  100. # +titleize+ is also aliased as as +titlecase+.
  101. #
  102. # Examples:
  103. # "man from the boondocks".titleize # => "Man From The Boondocks"
  104. # "x-men: the last stand".titleize # => "X Men: The Last Stand"
  105. # "TheManWithoutAPast".titleize # => "The Man Without A Past"
  106. # "raiders_of_the_lost_ark".titleize # => "Raiders Of The Lost Ark"
  107. def titleize(word)
  108. humanize(underscore(word)).gsub(/\b('?[a-z])/) { $1.capitalize }
  109. end
  110. # Create the name of a table like Rails does for models to table names. This method
  111. # uses the +pluralize+ method on the last word in the string.
  112. #
  113. # Examples
  114. # "RawScaledScorer".tableize # => "raw_scaled_scorers"
  115. # "egg_and_ham".tableize # => "egg_and_hams"
  116. # "fancyCategory".tableize # => "fancy_categories"
  117. def tableize(class_name)
  118. pluralize(underscore(class_name))
  119. end
  120. # Create a class name from a plural table name like Rails does for table names to models.
  121. # Note that this returns a string and not a Class. (To convert to an actual class
  122. # follow +classify+ with +constantize+.)
  123. #
  124. # Examples:
  125. # "egg_and_hams".classify # => "EggAndHam"
  126. # "posts".classify # => "Post"
  127. #
  128. # Singular names are not handled correctly:
  129. # "business".classify # => "Busines"
  130. def classify(table_name)
  131. # strip out any leading schema name
  132. camelize(singularize(table_name.to_s.sub(/.*\./, '')))
  133. end
  134. # Replaces underscores with dashes in the string.
  135. #
  136. # Example:
  137. # "puni_puni" # => "puni-puni"
  138. def dasherize(underscored_word)
  139. underscored_word.gsub(/_/, '-')
  140. end
  141. # Removes the module part from the expression in the string:
  142. #
  143. # "ActiveRecord::CoreExtensions::String::Inflections".demodulize # => "Inflections"
  144. # "Inflections".demodulize # => "Inflections"
  145. #
  146. # See also +deconstantize+.
  147. def demodulize(path)
  148. path = path.to_s
  149. if i = path.rindex('::')
  150. path[(i+2)..-1]
  151. else
  152. path
  153. end
  154. end
  155. # Removes the rightmost segment from the constant expression in the string:
  156. #
  157. # "Net::HTTP".deconstantize # => "Net"
  158. # "::Net::HTTP".deconstantize # => "::Net"
  159. # "String".deconstantize # => ""
  160. # "::String".deconstantize # => ""
  161. # "".deconstantize # => ""
  162. #
  163. # See also +demodulize+.
  164. def deconstantize(path)
  165. path.to_s[0...(path.rindex('::') || 0)] # implementation based on the one in facets' Module#spacename
  166. end
  167. # Creates a foreign key name from a class name.
  168. # +separate_class_name_and_id_with_underscore+ sets whether
  169. # the method should put '_' between the name and 'id'.
  170. #
  171. # Examples:
  172. # "Message".foreign_key # => "message_id"
  173. # "Message".foreign_key(false) # => "messageid"
  174. # "Admin::Post".foreign_key # => "post_id"
  175. def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
  176. underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
  177. end
  178. # Ruby 1.9 introduces an inherit argument for Module#const_get and
  179. # #const_defined? and changes their default behavior.
  180. if Module.method(:const_get).arity == 1
  181. # Tries to find a constant with the name specified in the argument string:
  182. #
  183. # "Module".constantize # => Module
  184. # "Test::Unit".constantize # => Test::Unit
  185. #
  186. # The name is assumed to be the one of a top-level constant, no matter whether
  187. # it starts with "::" or not. No lexical context is taken into account:
  188. #
  189. # C = 'outside'
  190. # module M
  191. # C = 'inside'
  192. # C # => 'inside'
  193. # "C".constantize # => 'outside', same as ::C
  194. # end
  195. #
  196. # NameError is raised when the name is not in CamelCase or the constant is
  197. # unknown.
  198. def constantize(camel_cased_word)
  199. names = camel_cased_word.split('::')
  200. names.shift if names.empty? || names.first.empty?
  201. constant = Object
  202. names.each do |name|
  203. constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
  204. end
  205. constant
  206. end
  207. else
  208. def constantize(camel_cased_word) #:nodoc:
  209. names = camel_cased_word.split('::')
  210. names.shift if names.empty? || names.first.empty?
  211. constant = Object
  212. names.each do |name|
  213. constant = constant.const_defined?(name, false) ? constant.const_get(name) : constant.const_missing(name)
  214. end
  215. constant
  216. end
  217. end
  218. # Tries to find a constant with the name specified in the argument string:
  219. #
  220. # "Module".safe_constantize # => Module
  221. # "Test::Unit".safe_constantize # => Test::Unit
  222. #
  223. # The name is assumed to be the one of a top-level constant, no matter whether
  224. # it starts with "::" or not. No lexical context is taken into account:
  225. #
  226. # C = 'outside'
  227. # module M
  228. # C = 'inside'
  229. # C # => 'inside'
  230. # "C".safe_constantize # => 'outside', same as ::C
  231. # end
  232. #
  233. # nil is returned when the name is not in CamelCase or the constant (or part of it) is
  234. # unknown.
  235. #
  236. # "blargle".safe_constantize # => nil
  237. # "UnknownModule".safe_constantize # => nil
  238. # "UnknownModule::Foo::Bar".safe_constantize # => nil
  239. #
  240. def safe_constantize(camel_cased_word)
  241. begin
  242. constantize(camel_cased_word)
  243. rescue NameError => e
  244. raise unless e.message =~ /(uninitialized constant|wrong constant name) #{const_regexp(camel_cased_word)}$/ ||
  245. e.name.to_s == camel_cased_word.to_s
  246. rescue ArgumentError => e
  247. raise unless e.message =~ /not missing constant #{const_regexp(camel_cased_word)}\!$/
  248. end
  249. end
  250. # Turns a number into an ordinal string used to denote the position in an
  251. # ordered sequence such as 1st, 2nd, 3rd, 4th.
  252. #
  253. # Examples:
  254. # ordinalize(1) # => "1st"
  255. # ordinalize(2) # => "2nd"
  256. # ordinalize(1002) # => "1002nd"
  257. # ordinalize(1003) # => "1003rd"
  258. # ordinalize(-11) # => "-11th"
  259. # ordinalize(-1021) # => "-1021st"
  260. def ordinalize(number)
  261. if (11..13).include?(number.to_i.abs % 100)
  262. "#{number}th"
  263. else
  264. case number.to_i.abs % 10
  265. when 1; "#{number}st"
  266. when 2; "#{number}nd"
  267. when 3; "#{number}rd"
  268. else "#{number}th"
  269. end
  270. end
  271. end
  272. private
  273. # Mount a regular expression that will match part by part of the constant.
  274. # For instance, Foo::Bar::Baz will generate Foo(::Bar(::Baz)?)?
  275. def const_regexp(camel_cased_word) #:nodoc:
  276. parts = camel_cased_word.split("::")
  277. last = parts.pop
  278. parts.reverse.inject(last) do |acc, part|
  279. part.empty? ? acc : "#{part}(::#{acc})?"
  280. end
  281. end
  282. # Applies inflection rules for +singularize+ and +pluralize+.
  283. #
  284. # Examples:
  285. # apply_inflections("post", inflections.plurals) # => "posts"
  286. # apply_inflections("posts", inflections.singulars) # => "post"
  287. def apply_inflections(word, rules)
  288. result = word.to_s.dup
  289. if word.empty? || inflections.uncountables.any? { |inflection| result =~ /\b#{inflection}\Z/i }
  290. result
  291. else
  292. rules.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
  293. result
  294. end
  295. end
  296. end
  297. end