2

I want to be able to define a block, and later evaluate that block from within a dynamically generated module/class. It seems like I could accomplish this somehow using eval and block.binding, but I haven't figured it out.

I have this as the base:

def define_module(name, &block)
  name = name.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
  parts = name.split("::")
  parts.each_with_index do |part, index|
    sub_name = parts[0..index].join("::")
    eval("module #{sub_name}; end")
  end
  clazz = eval(name)
  clazz.class_eval(&block) if block_given?
  clazz
end

def add_module(name, &block)
  module_block = block
  define_module(name).class_eval <<-EOF
    def self.included(base)
      base.class_eval do
        # something like this, I'm stuck
        instance_eval(&#{module_block})
      end
    end
  EOF
end

And I want to use it like this:

add_module("My::Library") do
  def a_method
    "added 'a_method'"
  end
end

class ::User
  include My::Library
end

user = ::User.new

assert_equal "added 'a_method'", user.a_method

Is there any way to do something like that?

1
  • ok, don't use string based evals, use block based evals, that way you can close over block Commented Sep 11, 2010 at 4:59

1 Answer 1

2

This works:

def add_module(name, &block)
    define_module(name).class_eval do
        class << self; self; end.send(:define_method, :included) { |base|
            base.class_eval(&block)
        }
    end
end

add_module("My::Library") do
    def a_method
        "added 'a_method'"
    end
end

class ::User
    include My::Library
end

user = ::User.new
user.a_method #=> "added a_method"

EDIT:

Why don't you just do this instead? Much simpler, and it's actually the job of a module:

def add_module(name, &block)
    define_module(name).class_eval(&block)
end
Sign up to request clarification or add additional context in comments.

1 Comment

though the whole idea seems weird -- why not just class_eval the block on the module itself rather than waiting until the include ? Seems like you're unnecessarily rewriting the entire idea of a module using the included hook???

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.