Reputation: 93146
How do I use methods from two different namespaces?
class Bar
def self.configure &block
new.instance_eval &block
end
def method2
puts "from Bar"
end
end
class Foo
def method1
puts "from Foo"
end
def start
Bar.configure do
method1
method2
end
end
end
Foo.new.start
In the above example the method1 can't be called because it is not from the Bar scope. How do I make methods from both scopes callable at the same time?
Upvotes: 0
Views: 249
Reputation: 64363
I would simplify your code as follows:
class Bar
def self.configure &block
obj = new
block.call(obj)
obj
end
def method2
puts "from Bar"
end
end
class Foo
def method1
puts "from Foo"
end
def start
Bar.configure do |obj|
method1
obj.method2
end
end
end
Foo.new.start
Block logic is clean and implementation doesn't require context switching. You are using the standard ruby functionality of passing parameters to the block.
Upvotes: 1
Reputation: 146
Maybe, this is the easiest way. It doesn't need to modify Bar.
class Bar
def self.configure &block
new.instance_eval &block
end
def method2
puts "from Bar"
end
end
class Foo
def method1
puts "from Foo"
end
def start
foo = self # add
Bar.configure do
foo.method1 # modify
method2
end
end
end
Foo.new.start
Upvotes: 1
Reputation: 29895
The trick is to forward missing method calls to the instance of Foo
:
class Bar
def self.configure(&block)
o = new
context = eval('self', block.binding)
class << o; self; end.send(:define_method, :method_missing) do |meth, *args|
context.send(meth, *args)
end
o.instance_eval &block
end
def method2
puts "from Bar"
end
end
class Foo
def method1
puts "from Foo"
end
def start
Bar.configure do
method1
method2
end
end
end
Foo.new.start #=> "from Foo"
#=> "from Bar"
Upvotes: 3
Reputation: 2871
Try this:
class Bar
def initialize(foo)
puts "init"
@f = foo
end
def self.configure(foo, &block)
new(foo).instance_eval &block
end
def method2
puts "from Bar"
end
end
class Foo
def method1
puts "from Foo"
end
def start
Bar.configure(self) do
@f.method1
method2
end
end
end
This makes @f a class level instance variable of Bar, which is set when you initialize an object of Bar using new(foo) in Bar.configure. The block being passed assumes the existence of @f, which contains a reference to the object of class Foo.
It's a convoluted way of doing this - I can't think of anything better though. It'd be interesting to know the use case.
Upvotes: 1