I would like to create a custom scanner for i18n-tasks that can detect enums declared as hashes in models.
My enum declaration pattern will always be like this:
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
The enums will always be declared as hashes, and will always have a numerical hash value, and will always have the option _prefix: true at the end of the declaration. There can be any number of values in the hash.
My custom scanner currently looks like this:
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(/enum\s([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'
However this is only returning the very last element of each hash:
activerecord.attributes.conversation.status_archived
activerecord.attributes.conversation.subject_art
How can I return all the elements of each hash? I am wanting to see a result like this:
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
For reference, the i18n-tasks github repo offers an example of a custom scanner.
The file scanner class that it uses can be found here.
This works:
def scan_file(path)
result = []
text = read_file(path)
text.scan(/enum\s([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
It's similar to your 'answer' approach, but uses the regex to get all the contents between '{...}', and then uses another regex to grab each enum key name.
The probable reason your 'answer' version raises an error is that it is actually returning a three-dimensional array, not two:
.map
is an array of all iterations.retval
, which is an array.retail
is an array of ['key', occurrence]
pairs.