Spec-Zone.ru › Ruby on Rails 8.1

модуль ActiveSupport::Inflector

Инфлектор Active Support

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

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

Константы

ALLOWED_ENCODINGS_FOR_TRANSLITERATE

Открытые методы экземпляра

camelize (term, uppercase_first_letter = true) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 70
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 }
  elsif string.match?(/\A[a-z\d]*\z/)
    return inflections.acronyms[string]&.dup || string.capitalize
  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"
classify (table_name) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 218
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 289
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

Если имя не записано в CamelCase или константа неизвестна, возникает NameError.

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

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

dasherize('puni_puni') # => "puni-puni"
deconstantize (path) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 256
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 238
def demodulize(path)
  path = path.to_s
  if i = path.rindex("::")
    path[(i + 2), path.length]
  else
    path
  end
end

Удаляет часть с модулем из выражения в строке.

demodulize('ActiveSupport::Inflector::Inflections') # => "Inflections"
demodulize('Inflections')                           # => "Inflections"
demodulize('::Inflections')                         # => "Inflections"
demodulize('')                                      # => ""

См. также deconstantize.

downcase_first (string) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 175
def downcase_first(string)
  string.length > 0 ? string[0].downcase.concat(string[1..-1]) : +""
end

Преобразует первый символ строки в строчную букву.

downcase_first('If they enjoyed The Matrix') # => "if they enjoyed The Matrix"
downcase_first('I')                          # => "i"
downcase_first('')                           # => ""
foreign_key (class_name, separate_class_name_and_id_with_underscore = true) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 267
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 135
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!
  if !keep_id_suffix && lower_case_and_underscored_word&.end_with?("_id")
    result.delete_suffix!(" id")
  end

  result.gsub!(/([[[:alpha:]]\d]+)/i) do |match|
    match.downcase!
    inflections.acronyms[match] || match
  end

  if capitalize
    result.sub!(/\A[[:alpha:]]/) 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"
inflections (locale = :en) { |instance| ... } Показать исходный код
# File activesupport/lib/active_support/inflector/inflections.rb, line 282
def inflections(locale = :en)
  if block_given?
    yield Inflections.instance(locale)
  else
    Inflections.instance_or_fallback(locale)
  end
end

Передаёт блоку singleton-экземпляр Inflector::Inflections, чтобы можно было указать дополнительные правила склонения. Если передать необязательную локаль, можно задать правила для других языков. Если локаль не указана, используется :en. Предоставляются только правила для английского языка.

ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.uncountable 'rails'
end
ordinal (number) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 334
def ordinal(number)
  I18n.translate("number.nth.ordinals", number: number)
end

Возвращает суффикс, который следует добавить к числу, чтобы обозначить его позицию в упорядоченной последовательности, например 1st, 2nd, 3rd, 4th.

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 347
def ordinalize(number)
  I18n.translate("number.nth.ordinalized", number: number)
end

Преобразует число в порядковую строку, обозначающую его позицию в упорядоченной последовательности, например 1st, 2nd, 3rd, 4th.

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 123
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?
    # No more than one of the separator in a row.
    if separator.length == 1
      parameterized_string.squeeze!(separator)
    else
      re_sep = Regexp.escape(separator)
      parameterized_string.gsub!(/#{re_sep}{2,}/, separator)
    end
    # Remove leading/trailing separator.
    parameterized_string.delete_prefix!(separator)
    parameterized_string.delete_suffix!(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 33
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 315
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

Если имя не записано в CamelCase или константа (либо её часть) неизвестна, возвращается nil.

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 50
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 204
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 192
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('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)
  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)

  return string.dup if string.ascii_only?
  string = string.dup if string.frozen?

  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.

underscore (camel_cased_word) Показать исходный код
# File activesupport/lib/active_support/inflector/methods.rb, line 99
def underscore(camel_cased_word)
  return camel_cased_word.to_s.dup 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])/, "_")
  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 166
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.

Spec-Zone.ru

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