Reputation: 156
I'd like to delegate a class method on Bar to an instance of the Foo class, but I can't get the delegation to work. None of the delegated methods throw an error, the getters simply return nil. Here's what my code looks like:
class Foo
attr_reader :worksheet_id, :access_token
def configure worksheet_id: raise, access_token: raise
@worksheet_id = worksheet_id
@access_token = access_token
end
end
class Bar
class << self
extend Forwardable
def_delegators Foo.new, :configure, :worksheet_id, :access_token
end
configure worksheet_id: 1, access_token: 2
end
And here's what I'd like to be able to do.
Bar.worksheet_id # => returns nil, should be 1.
Bar.access_token # => returns nil, should be 2.
What am I doing wrong?
Upvotes: 1
Views: 2485
Reputation: 369428
The first argument to the def_delegator
family of methods is a Symbol
or String
(or anything else that implements to_s
) that denotes the "accessor" by which to access the delegation target. It is not the delegation target itself.
So, something like this will work:
class Bar
class << self
extend Forwardable
def_delegators :@foo, :configure, :worksheet_id, :access_token
end
@foo = Foo.new
configure worksheet_id: 1, access_token: 2
end
Bar.worksheet_id # => 1
Bar.access_token # => 2
What actually happens, is that the forwardable
library uses string interpolation to build definitions for forwarder methods, which are then eval
d.
In essence, it looks like this:
"#{target}.__send__(#{method})"
So, you can pass anything as target
, whose to_s
results in something that you can eval
and then call __send__
on. However, in your case, Foo.new.to_s
is something like #<Foo:0x007fc4aa521ab8>
. When interpolated into the string and eval
d, the line starts with a #
character, or simply put: the forwarder method consists of a single line which is commented out! And that's why it returns nil
, because that's what an empty method returns.
Upvotes: 5