Active Support Inflector
Inflector
将单词从单数转换为复数,将类名转换为表名,将模块化类名转换为无模块化类名,将类名转换为外键。复数化、单数化和不可数单词的默认词形变化保存在 inflections.rb 中。
Rails 核心团队已声明,为了避免破坏可能依赖于错误词形变化的旧应用程序,将不接受词形变化库的补丁。如果您发现不正确的词形变化并且需要将其用于您的应用程序,或希望为除英语以外的其他语言定义规则,请自行更正或添加它们(如下所述)。
- C
- D
- F
- H
- I
- O
- P
- S
- T
- U
常量
ALLOWED_ENCODINGS_FOR_TRANSLITERATE | = | [Encoding::UTF_8, Encoding::US_ASCII, Encoding::GB18030].freeze |
实例公共方法
camelize(term, uppercase_first_letter = true) 链接
将字符串转换为 UpperCamelCase。如果 uppercase_first_letter
参数设置为 false,则生成 lowerCamelCase。
还将“/”转换为“::”,这对于将路径转换为命名空间很有用。
camelize('active_model') # => "ActiveModel"
camelize('active_model', false) # => "activeModel"
camelize('active_model/errors') # => "ActiveModel::Errors"
camelize('active_model/errors', false) # => "activeModel::Errors"
根据经验,您可以将 camelize
视为 underscore
的逆运算,尽管在某些情况下不成立
camelize(underscore('SSLError')) # => "SslError"
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/methods.rb, line 70 def camelize(term, uppercase_first_letter = true) string = term.to_s # String#camelize takes a symbol (:upper or :lower), so here we also support :lower to keep the methods consistent. if !uppercase_first_letter || uppercase_first_letter == :lower string = string.sub(inflections.acronyms_camelize_regex) { |match| match.downcase! || match } elsif string.match?(/\A[a-z\d]*\z/) return inflections.acronyms[string]&.dup || string.capitalize else string = string.sub(/^[a-z\d]*/) { |match| inflections.acronyms[match] || match.capitalize! || match } end string.gsub!(/(?:_|(\/))([a-z\d]*)/i) do word = $2 substituted = inflections.acronyms[word] || word.capitalize! || word $1 ? "::#{substituted}" : substituted end string end
classify(table_name) 链接
从复数表名创建类名,就像 Rails 为表名创建模型一样。请注意,这会返回一个字符串,而不是 Class
。(要转换为实际类,请将 classify
与 constantize
一起使用。)
classify('ham_and_eggs') # => "HamAndEgg"
classify('posts') # => "Post"
单数名称处理不正确
classify('calculus') # => "Calculu"
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/methods.rb, line 218 def classify(table_name) # strip out any leading schema name camelize(singularize(table_name.to_s.sub(/.*\./, ""))) end
constantize(camel_cased_word) 链接
尝试查找与参数字符串中指定的名称相匹配的常量。
constantize('Module') # => Module
constantize('Foo::Bar') # => Foo::Bar
无论名称是否以“::”开头,都假定它是顶级常量。不考虑词法上下文
C = 'outside'
module M
C = 'inside'
C # => 'inside'
constantize('C') # => 'outside', same as ::C
end
当名称不是骆驼拼写法或常量未知时,会引发 NameError
。
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/methods.rb, line 289 def constantize(camel_cased_word) Object.const_get(camel_cased_word) end
dasherize(underscored_word) 链接
用破折号替换字符串中的下划线。
dasherize('puni_puni') # => "puni-puni"
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/methods.rb, line 226 def dasherize(underscored_word) underscored_word.tr("_", "-") end
deconstantize(path) 链接
从字符串中的常量表达式中移除最右边的部分。
deconstantize('Net::HTTP') # => "Net"
deconstantize('::Net::HTTP') # => "::Net"
deconstantize('String') # => ""
deconstantize('::String') # => ""
deconstantize('') # => ""
另请参见 demodulize
。
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/methods.rb, line 256 def deconstantize(path) path.to_s[0, path.rindex("::") || 0] # implementation based on the one in facets' Module#spacename end
demodulize(path) 链接
从字符串中的表达式中移除模块部分。
demodulize('ActiveSupport::Inflector::Inflections') # => "Inflections"
demodulize('Inflections') # => "Inflections"
demodulize('::Inflections') # => "Inflections"
demodulize('') # => ""
另请参见 deconstantize
。
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/methods.rb, line 238 def demodulize(path) path = path.to_s if i = path.rindex("::") path[(i + 2), path.length] else path end end
downcase_first(string) 链接
将字符串中的第一个字符转换为小写。
downcase_first('If they enjoyed The Matrix') # => "if they enjoyed The Matrix"
downcase_first('I') # => "i"
downcase_first('') # => ""
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/methods.rb, line 175 def downcase_first(string) string.length > 0 ? string[0].downcase.concat(string[1..-1]) : +"" end
foreign_key(class_name, separate_class_name_and_id_with_underscore = true) 链接
从类名称创建外键名称。separate_class_name_and_id_with_underscore
设置方法是否在名称和“id”之间放置“_”。
foreign_key('Message') # => "message_id"
foreign_key('Message', false) # => "messageid"
foreign_key('Admin::Post') # => "post_id"
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/methods.rb, line 267 def foreign_key(class_name, separate_class_name_and_id_with_underscore = true) underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id") end
humanize(lower_case_and_underscored_word, capitalize: true, keep_id_suffix: false) 链接
调整属性名称以显示给最终用户。
具体来说,执行以下转换
-
对参数应用人类屈折规则。
-
删除前导下划线(如果有)。
-
删除“_id”后缀(如果有)。
-
将下划线替换为空格(如果有)。
-
将除首字母缩略词以外的所有单词小写。
-
将第一个单词大写。
可以通过将:capitalize
选项设置为 false 来关闭第一个单词的大写(默认为 true)。
可以通过将可选参数keep_id_suffix
设置为 true(默认为 false)来保留并大写尾随的“_id”。
humanize('employee_salary') # => "Employee salary"
humanize('author_id') # => "Author"
humanize('author_id', capitalize: false) # => "author"
humanize('_id') # => "Id"
humanize('author_id', keep_id_suffix: true) # => "Author id"
如果“SSL”被定义为首字母缩略词
humanize('ssl_error') # => "SSL error"
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/methods.rb, line 135 def humanize(lower_case_and_underscored_word, capitalize: true, keep_id_suffix: false) result = lower_case_and_underscored_word.to_s.dup inflections.humans.each { |(rule, replacement)| break if result.sub!(rule, replacement) } result.tr!("_", " ") result.lstrip! if !keep_id_suffix && lower_case_and_underscored_word&.end_with?("_id") result.delete_suffix!(" id") end result.gsub!(/([a-z\d]+)/i) do |match| match.downcase! inflections.acronyms[match] || match end if capitalize result.sub!(/\A\w/) do |match| match.upcase! match end end result end
inflections(locale = :en) 链接
生成 Inflector::Inflections
的单例实例,以便您可以指定其他屈折规则。如果传递了一个可选的语言环境,则可以指定其他语言的规则。如果未指定,则默认为:en
。仅提供英语规则。
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.uncountable 'rails'
end
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/inflections.rb, line 265 def inflections(locale = :en) if block_given? yield Inflections.instance(locale) else Inflections.instance_or_fallback(locale) end end
ordinal(number) 链接
返回应添加到数字以表示有序序列中位置的后缀,例如 1st、2nd、3rd、4th。
ordinal(1) # => "st"
ordinal(2) # => "nd"
ordinal(1002) # => "nd"
ordinal(1003) # => "rd"
ordinal(-11) # => "th"
ordinal(-1021) # => "st"
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/methods.rb, line 334 def ordinal(number) I18n.translate("number.nth.ordinals", number: number) end
ordinalize(number) 链接
将数字转换为用于表示有序序列中位置的序数字符串,例如 1st、2nd、3rd、4th。
ordinalize(1) # => "1st"
ordinalize(2) # => "2nd"
ordinalize(1002) # => "1002nd"
ordinalize(1003) # => "1003rd"
ordinalize(-11) # => "-11th"
ordinalize(-1021) # => "-1021st"
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/methods.rb, line 347 def ordinalize(number) I18n.translate("number.nth.ordinalized", number: number) end
parameterize(string, separator: "-", preserve_case: false, locale: nil) 链接
替换字符串中的特殊字符,以便将其用作“漂亮”URL 的一部分。
parameterize("Donald E. Knuth") # => "donald-e-knuth"
parameterize("^très|Jolie-- ") # => "tres-jolie"
要使用自定义分隔符,请覆盖 separator
参数。
parameterize("Donald E. Knuth", separator: '_') # => "donald_e_knuth"
parameterize("^très|Jolie__ ", separator: '_') # => "tres_jolie"
要保留字符串中字符的大小写,请使用 preserve_case
参数。
parameterize("Donald E. Knuth", preserve_case: true) # => "Donald-E-Knuth"
parameterize("^très|Jolie-- ", preserve_case: true) # => "tres-Jolie"
它保留破折号和下划线,除非它们用作分隔符
parameterize("^très|Jolie__ ") # => "tres-jolie__"
parameterize("^très|Jolie-- ", separator: "_") # => "tres_jolie--"
parameterize("^très_Jolie-- ", separator: ".") # => "tres_jolie--"
如果指定了可选参数 locale
,则该单词将作为该语言的单词进行参数化。默认情况下,此参数设置为 nil
,它将使用配置的 I18n.locale
。
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/transliterate.rb, line 123 def parameterize(string, separator: "-", preserve_case: false, locale: nil) # Replace accented chars with their ASCII equivalents. parameterized_string = transliterate(string, locale: locale) # Turn unwanted chars into the separator. parameterized_string.gsub!(/[^a-z0-9\-_]+/i, separator) unless separator.nil? || separator.empty? if separator == "-" re_duplicate_separator = /-{2,}/ re_leading_trailing_separator = /^-|-$/i else re_sep = Regexp.escape(separator) re_duplicate_separator = /#{re_sep}{2,}/ re_leading_trailing_separator = /^#{re_sep}|#{re_sep}$/i end # No more than one of the separator in a row. parameterized_string.gsub!(re_duplicate_separator, separator) # Remove leading/trailing separator. parameterized_string.gsub!(re_leading_trailing_separator, "") end parameterized_string.downcase! unless preserve_case parameterized_string end
pluralize(word, locale = :en) 链接
返回字符串中单词的复数形式。
如果传递了可选的 locale
参数,则该单词将使用为该语言定义的规则进行复数化。默认情况下,此参数设置为 :en
。
pluralize('post') # => "posts"
pluralize('octopus') # => "octopi"
pluralize('sheep') # => "sheep"
pluralize('words') # => "words"
pluralize('CamelOctopus') # => "CamelOctopi"
pluralize('ley', :es) # => "leyes"
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/methods.rb, line 33 def pluralize(word, locale = :en) apply_inflections(word, inflections(locale).plurals, locale) end
safe_constantize(camel_cased_word) 链接
尝试查找与参数字符串中指定的名称相匹配的常量。
safe_constantize('Module') # => Module
safe_constantize('Foo::Bar') # => Foo::Bar
无论名称是否以“::”开头,都假定它是顶级常量。不考虑词法上下文
C = 'outside'
module M
C = 'inside'
C # => 'inside'
safe_constantize('C') # => 'outside', same as ::C
end
当名称不是 CamelCase 或常量(或其一部分)未知时,返回 nil
。
safe_constantize('blargle') # => nil
safe_constantize('UnknownModule') # => nil
safe_constantize('UnknownModule::Foo::Bar') # => nil
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/methods.rb, line 315 def safe_constantize(camel_cased_word) constantize(camel_cased_word) rescue NameError => e raise if e.name && !(camel_cased_word.to_s.split("::").include?(e.name.to_s) || e.name.to_s == camel_cased_word.to_s) rescue LoadError => e message = e.respond_to?(:original_message) ? e.original_message : e.message raise unless /Unable to autoload constant #{const_regexp(camel_cased_word)}/.match?(message) end
singularize(word, locale = :en) 链接
pluralize
的反向操作,返回字符串中某个单词的单数形式。
如果传递了一个可选的 locale
参数,将使用为该语言定义的规则对单词进行单数化。默认情况下,此参数设置为 :en
。
singularize('posts') # => "post"
singularize('octopi') # => "octopus"
singularize('sheep') # => "sheep"
singularize('word') # => "word"
singularize('CamelOctopi') # => "CamelOctopus"
singularize('leyes', :es) # => "ley"
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/methods.rb, line 50 def singularize(word, locale = :en) apply_inflections(word, inflections(locale).singulars, locale) end
tableize(class_name) 链接
创建表名,就像 Rails 为模型创建表名一样。此方法对字符串中最后一个单词使用 pluralize
方法。
tableize('RawScaledScorer') # => "raw_scaled_scorers"
tableize('ham_and_egg') # => "ham_and_eggs"
tableize('fancyCategory') # => "fancy_categories"
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/methods.rb, line 204 def tableize(class_name) pluralize(underscore(class_name)) end
titleize(word, keep_id_suffix: false) 链接
将字符串中的所有单词大写,并替换一些字符,以创建更好看的标题。titleize
用于创建漂亮的输出。它不用于 Rails 内部。
可以通过将可选参数 keep_id_suffix
设置为 true 来保留并大写结尾的“_id”、“Id”等内容。默认情况下,此参数为 false。
titleize('man from the boondocks') # => "Man From The Boondocks"
titleize('x-men: the last stand') # => "X Men: The Last Stand"
titleize('TheManWithoutAPast') # => "The Man Without A Past"
titleize('raiders_of_the_lost_ark') # => "Raiders Of The Lost Ark"
titleize('string_ending_with_id', keep_id_suffix: true) # => "String Ending With Id"
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/methods.rb, line 192 def titleize(word, keep_id_suffix: false) humanize(underscore(word), keep_id_suffix: keep_id_suffix).gsub(/\b(?<!\w['’`()])[a-z]/) do |match| match.capitalize end end
transliterate(string, replacement = "?", locale: nil) 链接
用 ASCII 近似值替换非 ASCII 字符,如果不存在,则用替换字符替换,该字符默认为“?”。
transliterate('Ærøskøbing')
# => "AEroskobing"
为西方/拉丁字符提供了默认近似值,例如“ø”、“ñ”、“é”、“ß”等。
此方法支持 I18n,因此可以为某个语言环境设置自定义近似值。例如,这对于将德语的“ü”和“ö”音译为“ue”和“oe”,或添加对将俄语音译为 ASCII 的支持很有用。
为了使自定义音译可用,必须将它们设置为 i18n.transliterate.rule
i18n 键
# Store the transliterations in locales/de.yml
i18n:
transliterate:
rule:
ü: "ue"
ö: "oe"
# Or set them using Ruby
I18n.backend.store_translations(:de, i18n: {
transliterate: {
rule: {
'ü' => 'ue',
'ö' => 'oe'
}
}
})
i18n.transliterate.rule
的值可以是一个简单的 Hash
,它将字符映射到 ASCII 近似值,如上所示,或者对于更复杂的要求,可以是一个 Proc
I18n.backend.store_translations(:de, i18n: {
transliterate: {
rule: ->(string) { MyTransliterator.transliterate(string) }
}
})
现在可以为每个语言环境设置不同的音译
transliterate('Jürgen', locale: :en)
# => "Jurgen"
transliterate('Jürgen', locale: :de)
# => "Juergen"
音译仅限于 UTF-8、US-ASCII 和 GB18030 字符串。其他编码将引发 ArgumentError。
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/transliterate.rb, line 64 def transliterate(string, replacement = "?", locale: nil) raise ArgumentError, "Can only transliterate strings. Received #{string.class.name}" unless string.is_a?(String) raise ArgumentError, "Cannot transliterate strings with #{string.encoding} encoding" unless ALLOWED_ENCODINGS_FOR_TRANSLITERATE.include?(string.encoding) return string.dup if string.ascii_only? string = string.dup if string.frozen? input_encoding = string.encoding # US-ASCII is a subset of UTF-8 so we'll force encoding as UTF-8 if # US-ASCII is given. This way we can let tidy_bytes handle the string # in the same way as we do for UTF-8 string.force_encoding(Encoding::UTF_8) if string.encoding == Encoding::US_ASCII # GB18030 is Unicode compatible but is not a direct mapping so needs to be # transcoded. Using invalid/undef :replace will result in loss of data in # the event of invalid characters, but since tidy_bytes will replace # invalid/undef with a "?" we're safe to do the same beforehand string.encode!(Encoding::UTF_8, invalid: :replace, undef: :replace) if string.encoding == Encoding::GB18030 transliterated = I18n.transliterate( ActiveSupport::Multibyte::Unicode.tidy_bytes(string).unicode_normalize(:nfc), replacement: replacement, locale: locale ) # Restore the string encoding of the input if it was not UTF-8. # Apply invalid/undef :replace as tidy_bytes does transliterated.encode!(input_encoding, invalid: :replace, undef: :replace) if input_encoding != transliterated.encoding transliterated end
underscore(camel_cased_word) 链接
根据字符串中的表达式生成下划线分隔的小写形式。
将“::”更改为“/”以将命名空间转换为路径。
underscore('ActiveModel') # => "active_model"
underscore('ActiveModel::Errors') # => "active_model/errors"
根据经验,你可以将underscore
视为camelize
的逆运算,尽管在某些情况下不成立
camelize(underscore('SSLError')) # => "SslError"
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/methods.rb, line 99 def underscore(camel_cased_word) return camel_cased_word.to_s.dup unless /[A-Z-]|::/.match?(camel_cased_word) word = camel_cased_word.to_s.gsub("::", "/") word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_' }#{$2.downcase}" } word.gsub!(/(?<=[A-Z])(?=[A-Z][a-z])|(?<=[a-z\d])(?=[A-Z])/, "_") word.tr!("-", "_") word.downcase! word end
upcase_first(string) 链接
将字符串中的第一个字符转换为大写。
upcase_first('what a Lovely Day') # => "What a Lovely Day"
upcase_first('w') # => "W"
upcase_first('') # => ""
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/inflector/methods.rb, line 166 def upcase_first(string) string.length > 0 ? string[0].upcase.concat(string[1..-1]) : +"" end