module Traco class Attributes < Module def initialize(*attributes) @options = attributes.extract_options! @attributes = attributes.map(&:to_sym) attributes.each do |attribute| define_reader(attribute) define_writer(attribute) define_query(attribute) end end def included(base) self.class.ensure_translatable_attributes(base) base.translatable_attributes |= @attributes base.extend ClassMethods end private def define_reader(attribute) default_fallback = @options.fetch(:fallback, LocaleFallbacks::DEFAULT_FALLBACK) class_eval <<-EOM, __FILE__, __LINE__ + 1 def #{attribute}(locale: nil, fallback: #{default_fallback.inspect}) return send(Traco.column(:#{attribute}, locale)) if locale columns_to_try = self.class._locale_columns_for_attribute(:#{attribute}, fallback: fallback) columns_to_try.each do |column| value = send(column) return value if value.present? end nil end EOM end def define_writer(attribute) class_eval <<-EOM, __FILE__, __LINE__ + 1 def #{attribute}=(value) column = Traco.column(:#{attribute}, I18n.locale).to_s + "=" send(column, value) end EOM end def define_query(attribute) class_eval <<-EOM, __FILE__, __LINE__ + 1 def #{attribute}?(locale: nil) send(:#{attribute}, locale: locale).present? end EOM end # Only called once per class or inheritance chain (e.g. once # for the superclass, not at all for subclasses). The separation # is important if we don't want to overwrite values if running # multiple times in the same class or in different classes of # an inheritance chain. def self.ensure_translatable_attributes(base) return if base.respond_to?(:translatable_attributes) base.class_attribute :translatable_attributes base.translatable_attributes = [] end end end