Active Support Inflector¶ ↑
Inflector 负责将单词从单数转换为复数,类名转换为表名,模块化类名转换为非模块化类名,以及类名转换为外键。复数化、单数化和不可数单词的默认规则保存在 inflections.rb 文件中。
Rails 核心团队已声明,为了避免破坏可能依赖于错误规则的旧版应用程序,将不接受对 inflections 库的补丁。如果您发现一个错误的转写规则,并且您的应用程序需要它,或者您想为除英语以外的语言定义规则,请自行更正或添加(如下文所述)。
- 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) Link
将字符串转换为 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"
# 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) Link
根据 Rails 将表名转换为模型名的方式,从复数表名创建类名。请注意,这会返回一个字符串而不是一个 Class。(要转换为实际的类,请在 classify 后面加上 constantize。)
classify('ham_and_eggs') # => "HamAndEgg" classify('posts') # => "Post"
单数名称处理不正确。
classify('calculus') # => "Calculu"
constantize(camel_cased_word) Link
尝试查找参数字符串中指定的常量。
constantize('Module') # => Module constantize('Foo::Bar') # => Foo::Bar
假定该名称是顶级常量的名称,无论它是否以“::”开头。不考虑词法上下文。
C = 'outside' module M C = 'inside' C # => 'inside' constantize('C') # => 'outside', same as ::C end
当名称不是 CamelCase 或常量未知时,会引发 NameError。
dasherize(underscored_word) Link
将字符串中的下划线替换为破折号。
dasherize('puni_puni') # => "puni-puni"
deconstantize(path) Link
删除字符串中常量表达式的最右边部分。
deconstantize('Net::HTTP') # => "Net" deconstantize('::Net::HTTP') # => "::Net" deconstantize('String') # => "" deconstantize('::String') # => "" deconstantize('') # => ""
另请参阅 demodulize。
demodulize(path) Link
删除字符串中模块部分。
demodulize('ActiveSupport::Inflector::Inflections') # => "Inflections" demodulize('Inflections') # => "Inflections" demodulize('::Inflections') # => "Inflections" demodulize('') # => ""
另请参阅 deconstantize。
downcase_first(string) Link
将字符串的第一个字符转换为小写。
downcase_first('If they enjoyed The Matrix') # => "if they enjoyed The Matrix" downcase_first('I') # => "i" downcase_first('') # => ""
foreign_key(class_name, separate_class_name_and_id_with_underscore = true) Link
从类名创建外键名。separate_class_name_and_id_with_underscore 指定该方法是否应在名称和“id”之间添加下划线。
foreign_key('Message') # => "message_id" foreign_key('Message', false) # => "messageid" foreign_key('Admin::Post') # => "post_id"
humanize(lower_case_and_underscored_word, capitalize: true, keep_id_suffix: false) Link
调整属性名,使其更易于用户显示。
具体执行以下转换:
-
应用人类可读的转写规则到参数。
-
删除开头的下划线(如果有)。
-
移除结尾的 “_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"
# 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) Link
会屈服一个单例的 Inflector::Inflections 实例,以便您可以指定额外的转写规则。如果传入可选的 locale 参数,则可以指定其他语言的规则。如果未指定,则默认为 :en。只提供英语的规则。
ActiveSupport::Inflector.inflections(:en) do |inflect| inflect.uncountable 'rails' end
ordinal(number) Link
返回应添加到数字后面的后缀,以表示其在有序序列中的位置,例如 1st、2nd、3rd、4th。
ordinal(1) # => "st" ordinal(2) # => "nd" ordinal(1002) # => "nd" ordinal(1003) # => "rd" ordinal(-11) # => "th" ordinal(-1021) # => "st"
ordinalize(number) Link
将数字转换为序数字符串,用于表示在有序序列中的位置,例如 1st、2nd、3rd、4th。
ordinalize(1) # => "1st" ordinalize(2) # => "2nd" ordinalize(1002) # => "1002nd" ordinalize(1003) # => "1003rd" ordinalize(-11) # => "-11th" ordinalize(-1021) # => "-1021st"
parameterize(string, separator: "-", preserve_case: false, locale: nil) Link
替换字符串中的特殊字符,以便它可以用作“美化”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。
# 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? # No more than one of the separator in a row. if separator.length == 1 parameterized_string.squeeze!(separator) else re_sep = Regexp.escape(separator) parameterized_string.gsub!(/#{re_sep}{2,}/, separator) end # Remove leading/trailing separator. parameterized_string.delete_prefix!(separator) parameterized_string.delete_suffix!(separator) end parameterized_string.downcase! unless preserve_case parameterized_string end
pluralize(word, locale = :en) Link
返回字符串中单词的复数形式。
如果传入可选的 locale 参数,则将使用为该语言定义的规则来复数化单词。默认情况下,此参数设置为 :en。
pluralize('post') # => "posts" pluralize('octopus') # => "octopi" pluralize('sheep') # => "sheep" pluralize('words') # => "words" pluralize('CamelOctopus') # => "CamelOctopi" pluralize('ley', :es) # => "leyes"
safe_constantize(camel_cased_word) Link
尝试查找参数字符串中指定的常量。
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
# 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) Link
与 pluralize 相反,返回字符串中单词的单数形式。
如果传入可选的 locale 参数,则将使用为该语言定义的规则来单数化单词。默认情况下,此参数设置为 :en。
singularize('posts') # => "post" singularize('octopi') # => "octopus" singularize('sheep') # => "sheep" singularize('word') # => "word" singularize('CamelOctopi') # => "CamelOctopus" singularize('leyes', :es) # => "ley"
tableize(class_name) Link
创建表名,就像 Rails 将模型转换为表名一样。此方法使用字符串中最后一个单词的 pluralize 方法。
tableize('RawScaledScorer') # => "raw_scaled_scorers" tableize('ham_and_egg') # => "ham_and_eggs" tableize('fancyCategory') # => "fancy_categories"
titleize(word, keep_id_suffix: false) Link
将字符串中的所有单词首字母大写,并替换某些字符,以创建更美观的标题。titleize 用于创建漂亮的输出。它不用于 Rails 内部。
通过将可选参数 keep_id_suffix 设置为 true,可以保留并大写结尾的 ‘_id’、‘Id’ 等。
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"
transliterate(string, replacement = "?", locale: nil) Link
将非 ASCII 字符替换为 ASCII 近似字符,如果不存在,则替换为默认值为“?”的替换字符。
transliterate('Ærøskøbing') # => "AEroskobing"
为西方/拉丁字符(例如,“ø”、“ñ”、“é”、“ß”等)提供了默认的近似。
此方法支持 I18n,因此您可以为特定 locale 设置自定义近似。例如,这对于将德语的“ü”和“ö”转写为“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) } } })
现在您可以为不同的 locale 设置不同的转写规则。
transliterate('Jürgen', locale: :en) # => "Jurgen" transliterate('Jürgen', locale: :de) # => "Juergen"
转写限制为 UTF-8、US-ASCII 和 GB18030 字符串。其他编码将引发 ArgumentError。
# 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) Link
将字符串中的表达式转换为下划线分隔的、小写的形式。
将“::”更改为“/”,以将命名空间转换为路径。
underscore('ActiveModel') # => "active_model" underscore('ActiveModel::Errors') # => "active_model/errors"
经验法则上,您可以认为 underscore 是 camelize 的反向操作,尽管在某些情况下这并不成立。
camelize(underscore('SSLError')) # => "SslError"
# 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) Link
将字符串的第一个字符转换为大写。
upcase_first('what a Lovely Day') # => "What a Lovely Day" upcase_first('w') # => "W" upcase_first('') # => ""