Spec-Zone.ru › Ruby on Rails 6.1

модуль ActiveSupport::Inflector

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

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

Константы

ALLOWED_ENCODINGS_FOR_TRANSLITERATE

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

camelize(term, uppercase_first_letter = true) Показать исходный код
# 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!("/", "::")
  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"
classify(table_name) Показать исходный код
# 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(/.*\./, "")))
end

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

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

Единичные имена не обрабатываются правильно:

classify('calculus')     # => "Calculu"
constantize(camel_cased_word) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 272
def constantize(camel_cased_word)
  if camel_cased_word.blank? || !camel_cased_word.include?("::")
    Object.const_get(camel_cased_word)
  else
    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
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 209
def dasherize(underscored_word)
  underscored_word.tr("_", "-")
end

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

dasherize('puni_puni') # => "puni-puni"
deconstantize(path) Показать исходный код
# 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.

demodulize(path) Показать исходный код
# 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.

foreign_key(class_name, separate_class_name_and_id_with_underscore = true) Показать исходный код
# 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"
humanize(lower_case_and_underscored_word, capitalize: true, keep_id_suffix: false) Показать исходный код
# 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_+/, "")
  unless keep_id_suffix
    result.delete_suffix!("_id")
  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 247
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 348
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 361
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 и будет использовать настроенный I18n.locale.

pluralize(word, locale = :en) Показать исходный код
# 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"
safe_constantize(camel_cased_word) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 329
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
singularize(word, locale = :en) Показать исходный код
# 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"
tableize(class_name) Показать исходный код
# 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"
END_OF_DOCUMENT_MARKER
titleize(word, keep_id_suffix: false) Показать исходный код
# 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"
transliterate(string, replacement = "?", locale: nil) Показать исходный код
# 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, как показано выше, или, для более сложных требований, — функцией:

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 92
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 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–2020 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

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