2

(edited to make question more specific)

I would like to know if it's possible to execute a singleton method in the context of another object as in the following example:

class A
  def initialize
    @foo = 'foo'
  end
end

def A.singleton(*args)
  puts 'in singleton'
  puts @foo
end

A.new.instance_eval &A.method(:singleton)

# output is:
# - in singleton

# desired output:
# - in singleton
# - foo
coxy
  • 90
  • 5
  • Can you justify why you're using this confusing structure? I can think of no reason why defining a singleton method on a module would result in an instance method being defined in the enclosing module. If we know the use case, we might be able to show you a more idiomatic approach. – Max Feb 18 '15 at 21:14
  • It's an experiment and a purely syntactical one as a way to group or add extra functionality to certain methods. I appreciate a more idiomatic way might be to use a class method something like `special_method :baz` etc but I was just exploring an alternative approach. A possible application might be to memoize a method in this way, i.e. `def memoize.baz` but I agree it's confusing and probably not something I'd use in a real project. I'd still be interested in knowing if it's possible though. – coxy Feb 18 '15 at 22:01

2 Answers2

0

I don't think this is possible. A::Singletons is, ironically, itself a singleton (in the sense of the Singleton Pattern), and so, since there is only one single A::Singletons in the system, but A may be includeded in many different modules, there is no way of knowing in which module to add the method.

Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
  • Thanks Jörg. Maybe it's not possible then. Though I did get closer (I think) - I've updated the example. The `instance_exec` method does call the `baz` method (tested with puts statements) but it's not printing the value of `@bar` – coxy Feb 18 '15 at 19:30
  • It is possible to work around this using anonymous modules in place of `A::Singletons`, but even then you run into the error mentioned in my answer. – Max Feb 19 '15 at 20:33
0

This is not possible. In fact Ruby has a specific error for when you try to do so:

module Foo
  def self.bar
  end
end

class Baz
end

Foo.method(:bar).unbind.bind(Baz.new)
# TypeError: singleton method called for a different object

This really is an artificial restriction, since UnboundMethod#bind could easily just skip the type check and let you do it. But it would be a fundamental contradiction if you could call a singleton method with a different receiver: a singleton method is defined for a single instance. It makes sense that this isn't allowed.

Max
  • 21,123
  • 5
  • 49
  • 71