I'm trying to define a macro that wraps another method, then pass the instance to the macro. Here's a contrived example...
module Wrapper
def wrap(method_name, options: {})
class_eval do
new_method = "_wrap_#{method_name}"
alias_method new_method, method_name
define_method method_name do |*args, &block|
# binding.pry
puts "Options... #{options}"
send new_method, *args, &block
end
end
end
end
class Thing
extend Wrapper
class << self
extend Wrapper
def bar
puts 'Bar!'
end
wrap :bar, options: -> { bar_options }
private
def bar_options
{ bar: 2 }
end
end
def foo
puts 'Foo!'
end
wrap :foo, options: -> { foo_options }
private
def foo_options
{ foo: 1 }
end
end
So, I know I have access to the instance from within define_method
, but I don't think I should have to create / rename / alias methods within my classes to conform to a module - I'd like to pass the config in, so to speak. I feel like instance_exec/eval
is my friend, here, but I can't seem to get the incantation correct. I tried with passing a block to the code as well, but yield
behaved the same as the proc. Maybe binding
, but I can't wrap my head around that at all, for some reason.
This is from within the define_method
call...
> Thing.new.foo
=> Options... #<Proc:0x00007fcb0782cfd8@(irb):24>
Foo!
> self.class
=> Thing
> self
=> #<Thing:0x00007fdfb78b88e8>
> options
=> #<Proc:0x00007fcb0782cfd8@(irb):24>
> options.call
# NameError: undefined local variable or method `foo_options` for Thing:Class
> foo_options
=> {:foo=>1}
> self.class.instance_eval &options
# NameError: undefined local variable or method `foo_options` for Thing:Class
> self.class.instance_exec &options
# NameError: undefined local variable or method `foo_options` for Thing:Class
I understand how a proc captures scope to use for later, so I can see how the use of a proc/lambda is incorrect here. When the class loads, the wrap
method "wraps" the method and captures foo_options
at the class level to be called for later - which doesn't exist at the class level. Calling options: foo_options
does the same thing, just blows up on load.
Any bit helps... Thanks!