модуль ActiveSupport::Inflector
Преобразователь Inflector преобразует слова от единственного к множественному числу, имена классов в имена таблиц, имена модульных классов в имена без модулей и имена классов в внешние ключи. По умолчанию склонения для множественного, единственного числа и несчётных слов хранятся в inflections.rb.
Команда разработчиков Rails заявила, что исправления для библиотеки склонений не будут приниматься, чтобы избежать разрыва работы старых приложений, которые могут полагаться на ошибочные склонения. Если вы обнаружите неверное склонение, и оно необходимо для вашего приложения, или хотите определить правила для языков, отличных от английского, пожалуйста, исправьте или добавьте их сами (объяснено ниже).
Константы
- ALLOWED_ENCODINGS_FOR_TRANSLITERATE
Методы публичного экземпляра
# File activesupport/lib/active_support/inflector/methods.rb, line 69
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 }
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 208 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 279 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 216
def dasherize(underscored_word)
underscored_word.tr("_", "-")
end Заменяет подчёркивания на тире в строке.
dasherize('puni_puni') # => "puni-puni"
# File activesupport/lib/active_support/inflector/methods.rb, line 246
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 228
def demodulize(path)
path = path.to_s
if i = path.rindex("::")
path[(i + 2)..-1]
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 257 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 132
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!
unless keep_id_suffix
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 263
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 324
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 337
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 121
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 32 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 305
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 49 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 194 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 182
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 также имеет псевдоним titlecase.
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)
string = string.dup if string.frozen?
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)
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 96
def underscore(camel_cased_word)
return camel_cased_word.to_s 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])/) { ($1 || $2) << "_" }
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 163 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.