4

I'd like to provide some refinements to a DSL. I'm able to get refinements working with this example:

module ArrayExtras
  refine Array do
    def speak
      puts 'array!'
    end
  end
end

module MyUniverse
  using ArrayExtras
  class Thing
    def initialize
      [1].speak
    end
  end
end
MyUniverse::Thing.new

This prints out "array!" just fine. But once I introduce instance_eval, the method can't be found:

module MyUniverse
  using ArrayExtras
  class DSL
    def initialize(&block)
      instance_eval(&block)
    end
  end
end

MyUniverse::DSL.new do
  [1].speak
end

I get a undefined methodspeak' for [1]:Array (NoMethodError)`

Is there a way to get refinements working within an instance_eval?

3 Answers 3

1

Refinements are lexically scoped. You are activating the Refinement in the wrong lexical context. You need to activate it where you are calling the refined method:

module ArrayExtras
  refine Array do
    def speak
      puts 'array!'
    end
  end
end

module MyUniverse
  class DSL
    def initialize(&block)
      instance_eval(&block)
    end
  end
end

using ArrayExtras

MyUniverse::DSL.new do
  [1].speak
end
# array!
Sign up to request clarification or add additional context in comments.

1 Comment

So there is no way to make MyUniverse::DSL.new method call self-contained? I.e. to not require users of this method to add using ... line to their code.
1

In some cases you can achieve it by using ArrayExtras on the binding.

module MyUniverse
  using ArrayExtras
  class DSL
    def initialize(&block)
      block.binding.eval("using ArrayExtras")
      instance_eval(&block)
    end
  end
end

MyUniverse::DSL.new do
  [1].speak
end

This will however only work if you are not using your class in an instance, it only works if the binding is a module or class context, otherwise the eval will fail because main.using is permitted only at toplevel .

Comments

-1

If you want to refine the ruby core BaseObject, you need to modify it as below.

module ArrayExtras
  refine ::Array do
    def speak
      puts 'array!'
   end
  end
end

It will be found in top level class.

Comments

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.