s12chung s12chung - 5 months ago 10
Ruby Question

module that defines methods that allow included to call super

Suppose I want an interface as such:

class SomeModel
include MagicModule

attribute :some_method1
attribute :some_method2

def some_method1; super end
end


And
MagicModule
is something like:

module MagicModule
def self.included(base)
base.extend(ClassMethods)
end

module ClassMethods
def attribute(attribute_name)
define_method(attribute_name) { attribute_name.to_s }
end
end
end


How would you make
MagicModule
work such that
def some_method1; super end
above works?




I've tried something like this:

module MagicModule
extend ActiveSupport::Concern

included do
hidden_module = Module.new do
def hidden_module; method(__callee__).owner end
end
extend hidden_module
end

module ClassMethods
def attribute(attribute_name)
hidden_module.send(:define_method, attribute_name) { attribute_name.to_s }
end
end
end


But no luck.

Answer

The idea of creating a module to that contains your accessors is the right one (this is what rails does for its auto generated accessors for example). However you want to include the module rather than extend it

module MagicModule
  def self.included(base)
    base.send(:extend, ClassMethods)
  end

  module ClassMethods
    def attribute(attribute_name)
      unless @hidden_module
        @hidden_module = Module.new
        include @hidden_module
      end
      @hidden_module.send(:define_method, attribute_name) { attribute_name.to_s }
    end
  end 
end

I've moved around where the module gets created so that if you subclass SomeModel you can still define new attributes on that subclass.