0

I am using a BasicObject Proxy and I need to detect whether I have passed an actual object OR such a proxy. Problem is that methods such as is_a? or class are not defined

module ControllerProxyable
  extend ActiveSupport::Concern

  included do
    attr_reader :controller
    delegate :current_user, to: :controller
  end

  def controller_proxy(controller)
    # is_a? actually is NOT defined for a BasicObject causes the following to crash
    @controller = if controller.is_a?(ControllerProxy) 
      controller
    else
      ControllerProxy.new(controller)
    end
  end
end

class ControllerProxy < BasicObject
  def initialize(controller = nil)
    @controller = controller
  end

  def some_proxy_method
  end

  # def respond_to and respond_to_missing not relevant here
end

This is an example of how I am using it :

class Foo
  include ControllerProxyable

  def initialize(controller: nil)
    controller_proxy(controller)
  end

  def bar
    bar ||= Bar.new(controller: controller)
  end
end

class Bar
  include ControllerProxyable

  def initialize(controller: nil)
    controller_proxy(controller)
  end
end

The following therefore doesn't work

Foo.new(controller: nil).bar.some_proxy_method

How can I define is_a? for a Proxy (or actually identifying I am using a proxy) ?

Cyril Duchon-Doris
  • 12,964
  • 9
  • 77
  • 164
  • This isn't an answer, just an observation: the whole point of using a proxy is that the proxy can be used as a stand-in for the real thing indistinguishably. IOW: you *shouldn't* be able to distinguish between the proxy and the real thing. In fact, depending on whom you ask, the ability for one object to simulate another indistinguishably is at the center or OOP, or even the *definition* of OOP. – Jörg W Mittag Oct 26 '17 at 10:00
  • @JörgWMittag The problem is that in my services I want a proxy over the real thing, but the real thing might already be a proxy. So I just want to avoid having proxies over proxies also in itself it might not be a problem – Cyril Duchon-Doris Oct 26 '17 at 10:03
  • I'm not sure this question is a dupe. Re-binding the methods from `Object` is one possible solution, but specifically in the case of proxies, providing an own implementation may be preferred. – Jörg W Mittag Oct 26 '17 at 10:10

2 Answers2

1

Problem is that methods such as is_a? or class are not defined

The obvious solution to the problem "some method is not defined", is to define the method:

class ControllerProxy
  def class; ControllerProxy end

  def is_a?(mod)
    self.class < mod
  end
end

But! This defeats the whole purpose of a proxy, which is to be indistinguishable from the real thing. A better way would be IMO:

class ControllerProxy
  def class; Controller end

  def is_a?(mod)
    Controller < mod
  end
end
Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
0

I actually found an answer for RUby 2 here. My question almost feels like a duplicate but in my case I was talking about an extension of the basicObject class not patching the BasicObject class itself

For such a use case this becomes :

def controller_proxy(controller)
    # Note that is_a? is not defined for a proxy
    @controller = if Kernel.instance_method(:class).bind(controller).call <= ServiceControllerProxy
      controller
    else
      ServiceControllerProxy.new(controller)
    end
  end
Cyril Duchon-Doris
  • 12,964
  • 9
  • 77
  • 164