модуль ActiveSupport::Inflector
Класс Inflector преобразует слова от единственного к множественному числу, имена классов в имена таблиц, имена модульных классов в имена без модулей и имена классов в внешние ключи. Стандартные склонения для множественного, единственного числа и несчётных слов хранятся в inflections.rb.
Команда разработчиков Rails заявила, что исправления для библиотеки склонений не принимаются, чтобы избежать разрыва совместимости с устаревшими приложениями, которые могут полагаться на неправильные склонения. Если вы обнаружите неверное склонение, необходимое для вашего приложения, или захотите определить правила для языков помимо английского, пожалуйста, исправьте или добавьте их самостоятельно (объяснено ниже).
Общедоступные методы экземпляра
# File activesupport/lib/active_support/inflector/methods.rb, line 66
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.acronym_regex}(?=\b|[A-Z_])|\w)/) { |match| match.downcase }
end
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }
string.gsub!('/'.freeze, '::'.freeze)
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 186 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 257
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 Пытается найти константу с именем, указанным в строке аргумента.
'Module'.constantize # => Module 'Foo::Bar'.constantize # => Foo::Bar
Имя предполагается как имя константы верхнего уровня, независимо от того, начинается ли оно с «::» или нет. Никакой лексический контекст не учитывается:
C = 'outside' module M C = 'inside' C # => 'inside' 'C'.constantize # => 'outside', same as ::C end
NameError возникает, когда имя не в формате CamelCase или константа неизвестна.
# File activesupport/lib/active_support/inflector/methods.rb, line 194
def dasherize(underscored_word)
underscored_word.tr('_'.freeze, '-'.freeze)
end Заменяет все символы подчёркивания на тире в строке.
dasherize('puni_puni') # => "puni-puni"
# File activesupport/lib/active_support/inflector/methods.rb, line 224
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 206
def demodulize(path)
path = path.to_s
if i = path.rindex('::')
path[(i+2)..-1]
else
path
end
end Удаляет модульную часть из выражения в строке.
demodulize('ActiveRecord::CoreExtensions::String::Inflections') # => "Inflections"
demodulize('Inflections') # => "Inflections"
demodulize('::Inflections') # => "Inflections"
demodulize('') # => ""
См. также deconstantize.
# File activesupport/lib/active_support/inflector/methods.rb, line 235 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 123
def humanize(lower_case_and_underscored_word, options = {})
result = lower_case_and_underscored_word.to_s.dup
inflections.humans.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
result.sub!(/\A_+/, ''.freeze)
result.sub!(/_id\z/, ''.freeze)
result.tr!('_'.freeze, ' '.freeze)
result.gsub!(/([a-z\d]*)/i) do |match|
"#{inflections.acronyms[match] || match.downcase}"
end
if options.fetch(:capitalize, true)
result.sub!(/\A\w/) { |match| match.upcase }
end
result
end Изменяет имя атрибута для отображения конечным пользователям.
В частности, выполняет следующие преобразования:
-
Применяет правила человеческой инфлекции к аргументу.
-
Удаляет ведущие символы подчёркивания, если они есть.
-
Удаляет суффикс «_id», если он есть.
-
Заменяет подчёркивания пробелами, если они есть.
-
Преобразует все слова в нижний регистр, за исключением аббревиатур.
-
Заглавную букву первого слова.
Заглавную букву первого слова можно отключить, установив опцию :capitalize в false (по умолчанию true).
humanize('employee_salary') # => "Employee salary"
humanize('author_id') # => "Author"
humanize('author_id', capitalize: false) # => "author"
humanize('_id') # => "Id"
Если «SSL» определено как аббревиатура:
humanize('ssl_error') # => "SSL error"
# File activesupport/lib/active_support/inflector/inflections.rb, line 234
def inflections(locale = :en)
if block_given?
yield Inflections.instance(locale)
else
Inflections.instance(locale)
end
end Возвращает единственный экземпляр Inflector::Inflections, позволяющий задавать дополнительные правила инфлектора. Если указан необязательный параметр языка, правила для других языков можно указать. Если не указан, по умолчанию :en. Представлены только правила для английского языка.
ActiveSupport::Inflector.inflections(:en) do |inflect| inflect.uncountable 'rails' end
# File activesupport/lib/active_support/inflector/methods.rb, line 328
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 352
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 82
def parameterize(string, sep = :unused, separator: '-', preserve_case: false)
unless sep == :unused
ActiveSupport::Deprecation.warn("Passing the separator argument as a positional parameter is deprecated and will soon be removed. Use `separator: '#{sep}'` instead.")
separator = sep
end
# 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"
# File activesupport/lib/active_support/inflector/methods.rb, line 29 def pluralize(word, locale = :en) apply_inflections(word, inflections(locale).plurals) 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 310
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 e.message =~ /not missing constant #{const_regexp(camel_cased_word)}\!$/
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 46 def singularize(word, locale = :en) apply_inflections(word, inflections(locale).singulars) 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 172 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 162
def titleize(word)
humanize(underscore(word)).gsub(/\b(?<!['’`])[a-z]/) { |match| match.capitalize }
end Преобразует все слова в верхний регистр и заменяет некоторые символы в строке, чтобы создать более привлекательное название. titleize предназначено для создания привлекательного вывода. Оно не используется во внутренней работе Rails.
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"
# File activesupport/lib/active_support/inflector/transliterate.rb, line 60
def transliterate(string, replacement = "?".freeze)
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:
i18n.transliterate.rule Значение для 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 89
def underscore(camel_cased_word)
return camel_cased_word unless camel_cased_word =~ /[A-Z-]|::/
word = camel_cased_word.to_s.gsub('::'.freeze, '/'.freeze)
word.gsub!(/(?:(?<=([A-Za-z\d]))|\b)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$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 148 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.