#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
Это похоже на ваш подход «ответа», но использует регулярное выражение для получения всего содержимого между » { … }», а затем использует другое регулярное выражение для захвата каждого имени ключа перечисления.
Вероятная причина, по которой ваша версия «ответа» вызывает ошибку, заключается в том, что на самом деле она возвращает трехмерный массив, а не два:
- Внешний
.map
— это массив всех итераций. - Каждая итерация возвращает
retval
массив. - Каждый элемент
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)