Spec-Zone.ru › Ruby on Rails 6.0

модуль ActiveSupport::Inflector

Класс Inflector преобразует слова от единственного к множественному числу, имена классов в имена таблиц, имена модульных классов в имена без модулей и имена классов в внешние ключи. Стандартные склонения для множественного, единственного числа и несчётных слов хранятся в inflections.rb.

Команда разработчиков Rails заявила, что исправления для библиотеки склонений не принимаются, чтобы избежать разрыва совместимости с устаревшими приложениями, которые могут полагаться на неправильные склонения. Если вы обнаружите неверное склонение, необходимое для вашего приложения, или захотите определить правила для языков помимо английского, пожалуйста, исправьте или добавьте их самостоятельно (объяснено ниже).

Общедоступные методы экземпляров

camelize(term, uppercase_first_letter = true) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 68
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!("/", "::")
  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"
classify(table_name) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 200
def classify(table_name)
  # strip out any leading schema name
  camelize(singularize(table_name.to_s.sub(/.*\./, "")))
end

Создаёт имя класса из имени таблицы в множественном числе, как это делает Rails для имён таблиц и моделей. Обратите внимание, что это возвращает строку, а не Класс (чтобы преобразовать в фактический класс, выполните classify с constantize).

classify('ham_and_eggs') # => "HamAndEgg"
classify('posts')        # => "Post"

Имена в единственном числе не обрабатываются корректно:

classify('calculus')     # => "Calculus"
constantize(camel_cased_word) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 271
def constantize(camel_cased_word)
  names = camel_cased_word.split("::")

  # 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 или константа неизвестна.

dasherize(underscored_word) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 208
def dasherize(underscored_word)
  underscored_word.tr("_", "-")
end

Заменяет все символы подчеркивания на дефисы в строке.

dasherize('puni_puni') # => "puni-puni"
deconstantize(path) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 238
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.

demodulize(path) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 220
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.

foreign_key(class_name, separate_class_name_and_id_with_underscore = true) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 249
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"
humanize(lower_case_and_underscored_word, capitalize: true, keep_id_suffix: false) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 128
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_+/, "")
  unless keep_id_suffix
    result.sub!(/_id\z/, "")
  end
  result.tr!("_", " ")

  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"
inflections(locale = :en) { |instance| ... } Показать исходный код
# File activesupport/lib/active_support/inflector/inflections.rb, line 249
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
ordinal(number) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 344
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"
ordinalize(number) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 357
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"
parameterize(string, separator: "-", preserve_case: false, locale: nil) Показать исходный код
# 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, и он будет использовать настроенный <tt>I18n.locale<tt>.

pluralize(word, locale = :en) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 31
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"
safe_constantize(camel_cased_word) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 324
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)
rescue LoadError => e
  raise unless /Unable to autoload 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
singularize(word, locale = :en) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 48
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"
tableize(class_name) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 186
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"
titleize(word, keep_id_suffix: false) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 174
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"
transliterate(string, replacement = "?", locale: nil) Показать исходный код
# File activesupport/lib/active_support/inflector/transliterate.rb, line 62
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)

  allowed_encodings = [Encoding::UTF_8, Encoding::US_ASCII, Encoding::GB18030]
  raise ArgumentError, "Can not transliterate strings with #{string.encoding} encoding" unless allowed_encodings.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.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) }
  }
})

Теперь у вас могут быть разные транслитерации для каждого языка:

transliterate('Jürgen', locale: :en)
# => "Jurgen"

transliterate('Jürgen', locale: :de)
# => "Juergen"

Транслитерация ограничена строками UTF-8, US-ASCII и GB18030. Другие кодировки вызовут исключение ArgumentError.

underscore(camel_cased_word) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 91
def underscore(camel_cased_word)
  return camel_cased_word 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\d]+)([A-Z][a-z])/, '\1_\2')
  word.gsub!(/([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"
upcase_first(string) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 155
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–2019 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API