module FlagTrait

  as_trait do |field, options|

    options ||= {}

    default = options[:default]
    virtual = options[:virtual]
    allow_nil = !!(options[:allow_nil] || virtual)
    field_var = "@#{field}"
    set_field = "#{field}="

    validates_inclusion_of field.to_sym, :in => [true, false], :allow_nil => allow_nil
    has_defaults field.to_sym => default unless virtual

    if virtual

      define_method field do
        if instance_variable_get(field_var).nil?
          return default.call(self) if default.respond_to?(:call)
          return default if default == true || default == false
          raise "Unknown default value for #{field}"
        end
        return instance_variable_get(field_var)
      end

      define_method set_field do |value|
        value = ActiveRecord::Type::Boolean.new.cast(value)
        instance_variable_set(field_var, value)
      end

    end

  end

end
