модуль ActiveSupport::Inflector
Инфлектор Active Support
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
Если имя не записано в CamelCase или константа неизвестна, возникает NameError.
# 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!(/([[[:alpha:]]\d]+)/i) do |match|
match.downcase!
inflections.acronyms[match] || match
end
if capitalize
result.sub!(/\A[[:alpha:]]/) 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 282
def inflections(locale = :en)
if block_given?
yield Inflections.instance(locale)
else
Inflections.instance_or_fallback(locale)
end
end Передаёт блоку singleton-экземпляр Inflector::Inflections, чтобы можно было указать дополнительные правила склонения. Если передать необязательную локаль, можно задать правила для других языков. Если локаль не указана, используется :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 Возвращает суффикс, который следует добавить к числу, чтобы обозначить его позицию в упорядоченной последовательности, например 1st, 2nd, 3rd, 4th.
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 Преобразует число в порядковую строку, обозначающую его позицию в упорядоченной последовательности, например 1st, 2nd, 3rd, 4th.
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?
# 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 Заменяет специальные символы в строке, чтобы её можно было использовать в составе «красивого» 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
Если имя не записано в 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 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 i18n.transliterate.rule:
# 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.