module ActiveSupport::Inflector
Active Support Inflector
The Inflector преобразует слова от единственного к множественному числу, имена классов в имена таблиц, модулизованные имена классов в имена без модулей и имена классов в внешние ключи. Стандартные склонения для множественного числа, единственного числа и неисчисляемых слов хранятся в inflections.rb.
Команда разработчиков Rails заявила, что исправления для библиотеки склонений не будут приниматься, чтобы избежать нарушения работы устаревших приложений, которые могут полагаться на ошибочные склонения. Если вы обнаружите неправильное склонение, необходимое для вашего приложения, или захотите определить правила для языков, отличных от английского, пожалуйста, исправьте или добавьте их самостоятельно (объяснено ниже).
Константы
- ALLOWED_ENCODINGS_FOR_TRANSLITERATE
Методы публичного интерфейса
# 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 Преобразует строки в 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 218 def classify(table_name) # strip out any leading schema name camelize(singularize(table_name.to_s.sub(/.*\./, ""))) end
Создаёт имя класса из имени таблицы в множественном числе, как это делает Rails для имён таблиц и моделей. Обратите внимание, что это возвращает строку, а не Class. (Для преобразования в фактический класс следуйте за classify с constantize.)
classify('ham_and_eggs') # => "HamAndEgg"
classify('posts') # => "Post"
Имена единственного числа обрабатываются некорректно:
classify('calculus') # => "Calculu"
# File activesupport/lib/active_support/inflector/methods.rb, line 289 def constantize(camel_cased_word) Object.const_get(camel_cased_word) end
Пытается найти константу с именем, указанным в строке аргумента.
constantize('Module') # => Module
constantize('Foo::Bar') # => Foo::Bar
Имя предполагается как имя константы верхнего уровня, независимо от того, начинается ли оно с «::» или нет. Не учитывается лексический контекст:
C = 'outside'
module M
C = 'inside'
C # => 'inside'
constantize('C') # => 'outside', same as ::C
end
NameError генерируется, когда имя не в CamelCase или константа неизвестна.
# File activesupport/lib/active_support/inflector/methods.rb, line 226
def dasherize(underscored_word)
underscored_word.tr("_", "-")
end Заменяет подчёркивания дефисами в строке.
dasherize('puni_puni') # => "puni-puni"
# 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 Удаляет правую часть константного выражения в строке.
deconstantize('Net::HTTP') # => "Net"
deconstantize('::Net::HTTP') # => "::Net"
deconstantize('String') # => ""
deconstantize('::String') # => ""
deconstantize('') # => ""
См. также demodulize.
# 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 Удаляет модульную часть из выражения в строке.
demodulize('ActiveSupport::Inflector::Inflections') # => "Inflections"
demodulize('Inflections') # => "Inflections"
demodulize('::Inflections') # => "Inflections"
demodulize('') # => ""
См. также deconstantize.
# 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
Преобразует первый символ в строке в нижний регистр.
downcase_first('If they enjoyed The Matrix') # => "if they enjoyed The Matrix"
downcase_first('I') # => "i"
downcase_first('') # => ""
# 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
Создаёт имя внешнего ключа из имени класса. separate_class_name_and_id_with_underscore определяет, нужно ли вставлять ‘_’ между именем и ‘id’.
foreign_key('Message') # => "message_id"
foreign_key('Message', false) # => "messageid"
foreign_key('Admin::Post') # => "post_id"
# 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 Настраивает имя атрибута для отображения пользователям.
В частности, выполняет следующие преобразования:
-
Применяет правила склонения к аргументу.
-
Удаляет ведущие подчёркивания, если они есть.
-
Удаляет суффикс «_id», если он есть.
-
Заменяет подчёркивания пробелами, если они есть.
-
Приводит все слова к нижнему регистру, за исключением аббревиатур.
-
Приводит первое слово к верхнему регистру.
Регистр первого слова можно отключить, установив опцию :capitalize в false (по умолчанию true).
Конечный суффикс ‘_id’ можно сохранить и привести к верхнему регистру, установив необязательный параметр keep_id_suffix в true (по умолчанию false).
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/inflections.rb, line 265
def inflections(locale = :en)
if block_given?
yield Inflections.instance(locale)
else
Inflections.instance_or_fallback(locale)
end
end Возвращает единственный экземпляр Inflector::Inflections, чтобы вы могли указать дополнительные правила склонения. Если передан необязательный параметр locale, можно указать правила для других языков. Если не указано, по умолчанию используется :en. Предоставлены только правила для английского языка.
ActiveSupport::Inflector.inflections(:en) do |inflect| inflect.uncountable 'rails' end
# File activesupport/lib/active_support/inflector/methods.rb, line 334
def ordinal(number)
I18n.translate("number.nth.ordinals", number: number)
end Возвращает суффикс, который необходимо добавить к числу, чтобы указать позицию в упорядоченной последовательности, например, 1-е, 2-е, 3-е, 4-е.
ordinal(1) # => "st" ordinal(2) # => "nd" ordinal(1002) # => "nd" ordinal(1003) # => "rd" ordinal(-11) # => "th" ordinal(-1021) # => "st"
# File activesupport/lib/active_support/inflector/methods.rb, line 347
def ordinalize(number)
I18n.translate("number.nth.ordinalized", number: number)
end Преобразует число в строку порядкового числа, используемую для обозначения позиции в упорядоченной последовательности, например, 1-е, 2-е, 3-е, 4-е.
ordinalize(1) # => "1st" ordinalize(2) # => "2nd" ordinalize(1002) # => "1002nd" ordinalize(1003) # => "1003rd" ordinalize(-11) # => "-11th" ordinalize(-1021) # => "-1021st"
# 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 Заменяет специальные символы в строке, чтобы её можно было использовать в качестве части «красивого» 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/methods.rb, line 33 def pluralize(word, locale = :en) apply_inflections(word, inflections(locale).plurals, locale) end
Возвращает форму слова во множественном числе.
Если передан необязательный параметр locale, слово будет приведено к форме множественного числа с использованием правил, определённых для этого языка. По умолчанию этот параметр :en.
pluralize('post') # => "posts"
pluralize('octopus') # => "octopi"
pluralize('sheep') # => "sheep"
pluralize('words') # => "words"
pluralize('CamelOctopus') # => "CamelOctopi"
pluralize('ley', :es) # => "leyes"
# 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 Пытается найти константу с именем, указанным в строке аргумента.
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
Возвращается nil, если имя не в CamelCase или константа (или её часть) неизвестна.
safe_constantize('blargle') # => nil
safe_constantize('UnknownModule') # => nil
safe_constantize('UnknownModule::Foo::Bar') # => nil
# File activesupport/lib/active_support/inflector/methods.rb, line 50 def singularize(word, locale = :en) apply_inflections(word, inflections(locale).singulars, locale) end
Обратное действие pluralize, возвращает единственное число слова в строке.
Если передать необязательный параметр locale, слово будет приведено к единственному числу, используя правила для этого языка. По умолчанию этот параметр установлен на :en.
singularize('posts') # => "post"
singularize('octopi') # => "octopus"
singularize('sheep') # => "sheep"
singularize('word') # => "word"
singularize('CamelOctopi') # => "CamelOctopus"
singularize('leyes', :es) # => "ley"
# File activesupport/lib/active_support/inflector/methods.rb, line 204 def tableize(class_name) pluralize(underscore(class_name)) end
Создаёт имя таблицы, как это делает Rails для моделей и имён таблиц. Этот метод использует метод pluralize для последнего слова в строке.
tableize('RawScaledScorer') # => "raw_scaled_scorers"
tableize('ham_and_egg') # => "ham_and_eggs"
tableize('fancyCategory') # => "fancy_categories"
# 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 Преобразует все слова в заглавные и заменяет некоторые символы в строке, чтобы создать более красивое название. titleize предназначен для создания красивого вывода. Он не используется во внутренних компонентах Rails.
Завершающие ‘_id’,‘Id’.. могут быть сохранены и приведены к верхнему регистру, установив необязательный параметр keep_id_suffix в true. По умолчанию этот параметр равен 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"
# 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 Заменяет символы, не являющиеся 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.
# 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 Преобразует выражение в строке в нижний регистр с подчёркиванием.
Заменяет ‘::’ на ‘/’ для преобразования пространств имён в пути.
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 166 def upcase_first(string) string.length > 0 ? string[0].upcase.concat(string[1..-1]) : +"" end
Преобразует первый символ в строке в верхний регистр.
upcase_first('what a Lovely Day') # => "What a Lovely Day"
upcase_first('w') # => "W"
upcase_first('') # => ""
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.