ruby 如何检测BasicObject Proxy?

bgibtngc  于 12个月前  发布在  Ruby
关注(0)|答案(3)|浏览(86)

我正在使用一个基本对象代理,我需要检测我是否传递了一个实际的对象或这样的代理。问题是没有定义is_a?class等方法

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

这是我如何使用它的一个例子:

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

因此,以下内容不起作用

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

如何为代理定义is_a?(或实际标识我正在使用代理)?

ldfqzlk8

ldfqzlk81#

问题是没有定义is_a?class等方法
对于“某些方法没有定义”的问题,最明显的解决方案是定义方法:

class ControllerProxy
  def class; ControllerProxy end

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

但是!这违背了代理的全部目的,即与真实的东西无法区分。更好的方法是IMO:

class ControllerProxy
  def class; Controller end

  def is_a?(mod)
    Controller < mod
  end
end
hujrc8aj

hujrc8aj2#

我其实找到了RUby 2 here的答案。我的问题几乎感觉像是重复,但在我的情况下,我谈论的是basicObject类的扩展,而不是修补BasicObject类本身
对于这样的用例,这变为:

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
vptzau2j

vptzau2j3#

可以识别一个代理来转发所有带有===的方法:
下面是我如何识别AR模型的Octopus::ScopeProxy Package 器的示例:

> wrapped = Model.using(:slave)
=> Model(id: integer)

# is_a? is forwarded
> wrapped.is_a?(Octopus::ScopeProxy) 
=> false

# === cannot be forwarded as it is not called on proxy but on the class
> Octopus::ScopeProxy === wrapped 
=> true

# Case uses === under the hood to compare objects so it check for multiple classes.
> case wrapped
> when Octopus::ScopeProxy  
>   :proxy
> when ActiveRecord::Relation  
>   :ar_relation
> end  
=> :proxy

相关问题