i18n-пользовательский сканер задач для перечислений

#ruby-on-rails #ruby #enums #rails-models #i18n-tasks

Вопрос:

Я хотел бы создать пользовательский сканер для i18n-задач, который может обнаруживать перечисления, объявленные как хэши в моделях.

Мой шаблон объявления перечисления всегда будет таким:

 class Conversation < ActiveRecord::Base
  enum status: { active: 0, archived: 1}, _prefix: true
  enum subject: { science: 0, literature: 1, music: 2, art: 3 }, _prefix: true
end
 

Перечисления всегда будут объявлены как хэши, и всегда будут иметь числовое значение хэша, и всегда будут иметь опцию _prefix: true в конце объявления. В хэше может быть любое количество значений.

Мой пользовательский сканер в настоящее время выглядит следующим образом:

 require 'i18n/tasks/scanners/file_scanner'
class ScanModelEnums < I18n::Tasks::Scanners::FileScanner
  include I18n::Tasks::Scanners::OccurrenceFromPosition

  # @return [Array<[absolute key, Results::Occurrence]>]
  def scan_file(path)
    text = read_file(path)
    text.scan(/enums([a-zA-Z]*?):s{.*W(w ):.*}, _prefix: true$/).map do |prefix, attribute|
      occurrence = occurrence_from_position(
          path, text, Regexp.last_match.offset(0).first)
      model = File.basename(path, ".rb") #.split('/').last
      name = prefix   "_"   attribute
      ["activerecord.attributes.%s.%s" % [model, name], occurrence]
    end
  end
end

I18n::Tasks.add_scanner 'ScanModelEnums'
 

Однако это возвращает только самый последний элемент каждого хэша:

  • activerecord.attributes.conversation.status_archived
  • activerecord.attributes.conversation.subject_art

Как я могу вернуть все элементы каждого хэша? Я хочу увидеть такой результат:

  • activerecord.attributes.conversation.status_active
  • activerecord.attributes.conversation.status_archived
  • activerecord.attributes.conversation.subject_science
  • activerecord.attributes.conversation.subject_literature
  • activerecord.attributes.conversation.subject_music
  • activerecord.attributes.conversation.subject_art

Для справки, репозиторий github i18n-tasks предлагает пример пользовательского сканера.

Класс сканера файлов, который он использует, можно найти здесь.

Комментарии:

1. И вместо того, чтобы вывести один массив, я также попытался запечатлеть все, что между { И } , а затем разделив на , и отображает этот массив strip , split(":") и последний strip , чтобы получить все перечисления атрибутов в массив, затем цикл над этими и толк какой бы вывод массива в другой массив, и, наконец, вывод из 2D массива. Однако я получаю ошибку key_occurrences.rb:48:in 'each': undefined method 'path' в отношении второго атрибута перечисления.

Ответ №1:

Это работает:

 def scan_file(path)
  result = []
  text = read_file(path)

  text.scan(/enums([a-zA-Z]*?):s{(.*)}, _prefix: true$/).each do |prefix, body|
    occurrence = occurrence_from_position(path, text, 
                                            Regexp.last_match.offset(0).first)

    body.scan(/(w ):/).flatten.each do |attr|
      model = File.basename(path, ".rb")
      name = "#{prefix}_#{attr}" 
      result << ["activerecord.attributes.#{model}.#{name}", occurrence]
    end
  end
  result
end
 

Это похоже на ваш подход «ответа», но использует регулярное выражение для получения всего содержимого между » { … }», а затем использует другое регулярное выражение для захвата каждого имени ключа перечисления.

Вероятная причина, по которой ваша версия «ответа» вызывает ошибку, заключается в том, что на самом деле она возвращает трехмерный массив, а не два:

  1. Внешний .map — это массив всех итераций.
  2. Каждая итерация возвращает retval массив.
  3. Каждый элемент retail представляет собой массив ['key', occurrence] пар.

Ответ №2:

Это не ответ, это просто другая попытка, которую я предпринял, которая выводит двумерный массив вместо одного массива:

 require 'i18n/tasks/scanners/file_scanner'
class ScanModelEnums < I18n::Tasks::Scanners::FileScanner
  include I18n::Tasks::Scanners::OccurrenceFromPosition

  # @return [Array<[absolute key, Results::Occurrence]>]
  def scan_file(path)
    text = read_file(path)
    text.scan(/enums([a-zA-Z]*?):s{(.*)}, _prefix: true/).map do |prefix, attributes|
      retval = []
      model = File.basename(path, ".rb")
      names = attributes.split(",").map!{ |e| e.strip; e.split(":").first.strip }
      names.each do |attribute|
        pos = (Regexp.last_match.offset(0).first   8   prefix.length   attributes.index(attribute))
        occurrence = occurrence_from_position(
            path, text, pos)
        name = prefix   "_"   attribute
        # p "================"
        # p type
        # p message
        # p ["activerecord.attributes.%s.%s" % [model, name], occurrence]
        # p "================"
        retval.push(["activerecord.attributes.%s.%s" % [model, name], occurrence])
      end
      retval
    end
  end
end

I18n::Tasks.add_scanner 'ScanModelEnums'
 

Однако это приводит к ошибке для второго обнаруженного атрибута:

 gems/i18n-tasks-0.9.34/lib/i18n/tasks/scanners/results/key_occurrences.rb:48:in `each': undefined method `path' for ["activerecord.attributes.conversation.status_archived", Occurrence(app/models/project.rb:3:32:98::)]:Array (NoMethodError)