модуль ActiveSupport::Inflector
Класс Inflector преобразует слова от единственного к множественному числу, имена классов в имена таблиц, имена модульных классов в имена без модулей и имена классов в внешние ключи. Стандартные склонения для множественного, единственного числа и несчётных слов хранятся в inflections.rb.
Команда разработчиков Rails заявила, что исправления для библиотеки склонений не принимаются, чтобы избежать разрыва совместимости с устаревшими приложениями, которые могут полагаться на неправильные склонения. Если вы обнаружите неверное склонение, необходимое для вашего приложения, или захотите определить правила для языков помимо английского, пожалуйста, исправьте или добавьте их самостоятельно (объяснено ниже).
Общедоступные методы экземпляра
# File activesupport/lib/active_support/inflector/methods.rb, line 69
def camelize(term, uppercase_first_letter = true)
string = term.to_s
if uppercase_first_letter
string = string.sub(/^[a-z\d]*/) { |match| inflections.acronyms[match] || match.capitalize }
else
string = string.sub(inflections.acronyms_camelize_regex) { |match| match.downcase }
end
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }
string.gsub!("/".freeze, "::".freeze)
string
end Преобразует строки в ВерхнийCamelCase. Если параметр 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 201 def classify(table_name) # strip out any leading schema name camelize(singularize(table_name.to_s.sub(/.*\./, "".freeze))) end
Создаёт имя класса из имени таблицы в множественном числе, как это делает Rails для имён таблиц и моделей. Обратите внимание, что это возвращает строку, а не Класс (Чтобы преобразовать в фактический класс, выполните classify с constantize).
classify('ham_and_eggs') # => "HamAndEgg"
classify('posts') # => "Post"
Имена в единственном числе не обрабатываются корректно:
classify('calculus') # => "Calculus"
# File activesupport/lib/active_support/inflector/methods.rb, line 272
def constantize(camel_cased_word)
names = camel_cased_word.split("::".freeze)
# Trigger a built-in NameError exception including the ill-formed constant in the message.
Object.const_get(camel_cased_word) if names.empty?
# Remove the first blank element in case of '::ClassName' notation.
names.shift if names.size > 1 && names.first.empty?
names.inject(Object) do |constant, name|
if constant == Object
constant.const_get(name)
else
candidate = constant.const_get(name)
next candidate if constant.const_defined?(name, false)
next candidate unless Object.const_defined?(name)
# Go down the ancestors to check if it is owned directly. The check
# stops when we reach Object or the end of ancestors tree.
constant = constant.ancestors.inject(constant) do |const, ancestor|
break const if ancestor == Object
break ancestor if ancestor.const_defined?(name, false)
const
end
# owner is in Object, so raise
constant.const_get(name, false)
end
end
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 209
def dasherize(underscored_word)
underscored_word.tr("_".freeze, "-".freeze)
end Заменяет подчёркивания на дефисы в строке.
dasherize('puni_puni') # => "puni-puni"
# File activesupport/lib/active_support/inflector/methods.rb, line 239
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 221
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 250 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 129
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.sub!(/\A_+/, "".freeze)
unless keep_id_suffix
result.sub!(/_id\z/, "".freeze)
end
result.tr!("_".freeze, " ".freeze)
result.gsub!(/([a-z\d]*)/i) do |match|
"#{inflections.acronyms[match.downcase] || match.downcase}"
end
if capitalize
result.sub!(/\A\w/) { |match| match.upcase }
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 252
def inflections(locale = :en)
if block_given?
yield Inflections.instance(locale)
else
Inflections.instance(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 343
def ordinal(number)
abs_number = number.to_i.abs
if (11..13).include?(abs_number % 100)
"th"
else
case abs_number % 10
when 1; "st"
when 2; "nd"
when 3; "rd"
else "th"
end
end
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 367
def ordinalize(number)
"#{number}#{ordinal(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 92
def parameterize(string, separator: "-", preserve_case: false)
# Replace accented chars with their ASCII equivalents.
parameterized_string = transliterate(string)
# Turn unwanted chars into the separator.
parameterized_string.gsub!(/[^a-z0-9\-_]+/i, separator)
unless separator.nil? || separator.empty?
if separator == "-".freeze
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, "".freeze)
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--"
# 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 325
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 ArgumentError => e
raise unless /not missing constant #{const_regexp(camel_cased_word)}!$/.match?(e.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 187 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 175
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 61
def transliterate(string, replacement = "?".freeze)
raise ArgumentError, "Can only transliterate strings. Received #{string.class.name}" unless string.is_a?(String)
I18n.transliterate(
ActiveSupport::Multibyte::Unicode.normalize(
ActiveSupport::Multibyte::Unicode.tidy_bytes(string), :c),
replacement: replacement)
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 может быть простым словарям, который сопоставляет символы с их ASCII-аналогами, как показано выше, или, для более сложных требований, функцией:
I18n.backend.store_translations(:de, i18n: {
transliterate: {
rule: ->(string) { MyTransliterator.transliterate(string) }
}
})
Теперь вы можете иметь разные транслитерации для каждой локали:
I18n.locale = :en
transliterate('Jürgen')
# => "Jurgen"
I18n.locale = :de
transliterate('Jürgen')
# => "Juergen"
# File activesupport/lib/active_support/inflector/methods.rb, line 92
def underscore(camel_cased_word)
return camel_cased_word unless /[A-Z-]|::/.match?(camel_cased_word)
word = camel_cased_word.to_s.gsub("::".freeze, "/".freeze)
word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_'.freeze }#{$2.downcase}" }
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2'.freeze)
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2'.freeze)
word.tr!("-".freeze, "_".freeze)
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 156 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–2018 David Heinemeier Hansson
Licensed under the MIT License.