2

我有一个包装其他实例以提供附加功能(演示者)的类,并且现在希望拥有提供相同功能的子类。所以它会是这样的:

class BasePresenter
  attr_accessor :base_object

  def initialize(base_object)
    self.base_object = base_object
  end
end

class WalrusPresenter < BasePresenter
end

我希望能够做到这一点:

BasePresenter(:bubbles)
  #=> <# BasePresenter @base_object=:bubbles >

WalrusPresenter(:frank)
  #=> <# WalrusPresenter @base_object=:frank >

更新

我认为功能差异超出了问题的范围,但它们似乎是一个症结所在,所以我会添加它们。

我不是要委派.new

BasePresenter.new接受一个参数并将其包装在演示者中。BasePresenter()接受一个对象并且:

  • 如果已经是演示者,则返回
  • 如果它是一个对象数组,则映射它们并创建一个新的演示者
  • 如果它是单个对象,则将其包装在演示器中并返回。

这更接近 ActiveSupport 的Array#wrap,但我认为括号语法与其功能相当交流,所以如果可能的话我想使用它。继承部分是什么让我绊倒;将其定义为基类之一,以便对所有子类都可用。

BasePresenter(:bubbles)
  #=> <# BasePresenter @base_object=:bubbles >

BasePresenter([:waldorf, :statler])
  #=> [ <# BasePresenter @base_object=:waldorf >, <# BasePresenter @base_object=:staler> ]

WalrusPresenter.new(:frank)
  #=> <# WalrusPresenter @base_object=:frank >
WalrusPresenter([:harold, :richard])
  #=> [ <# WalrusPresenter @base_object=:harold >, <# WalrusPresenter @base_object=:richard > ]

WalrusPresenter(WalrusPresenter(WalrusPresenter(:frank)))
  #=> <# WalrusPresenter @base_object=:frank >
4

3 回答 3

4

我可能错过了您的问题的重点,但对我来说,您似乎只是忘记使用new来创建您的类的实例:

BasePresenter.new(:bubbles)
# => #<BasePresenter:0x00000001ae33b8 @base_object=:bubbles> 
WalrusPresenter.new(:frank)
# => #<WalrusPresenter:0x00000001ae7878 @base_object=:frank> 

更新: Mischa 已经以与我相同的方式回复了您的评论。 Kernel#Array尝试调用to_ary它的参数,如果失败则尝试调用to_a它,如果失败也创建一个以参数作为唯一元素的数组。

不清楚你想要什么行为;似乎您只是想绕过 using new,当然可以这样做,但这很愚蠢:

def BasePresenter(base)
  BasePresenter.new(base)
end

def WalrusPresenter(base)
  WalrusPresenter.new(base)
end

您可以进行一些元编程以避免在创建包装器时重复自己。但是我看不到您要避免的原因new,并且没有很好的理由这样做,我不得不建议不要这样做。Ruby 用于new实例化对象。

更新 2:感谢您澄清您在寻找什么。这是我首先想到的。你绝对可以把它清理一下,但这样的事情应该让你开始。(wrap根本不需要BasePresenter进去。)无论如何,给你:

class BasePresenter
  attr_accessor :base_object

  def initialize(base_object)
    self.base_object = base_object
  end

  def self.wrap klass
    Object.class_eval do
      define_method klass.to_s do |object|
        case object
        when BasePresenter
          object
        when Array
          object.map{|base| klass.new(base)}
        else
          klass.new(object)
        end
      end
    end
  end

  BasePresenter.wrap BasePresenter

  def self.inherited child_klass
    BasePresenter.wrap child_klass
  end
end

class WalrusPresenter < BasePresenter
end

这似乎做你想做的事:

BasePresenter(:bubbles)
# => #<BasePresenter:0x00000001db05a0 @base_object=:bubbles> 

BasePresenter([:waldorf, :statler])
# => [#<BasePresenter:0x00000001da7c98 @base_object=:waldorf>,
      #<BasePresenter:0x00000001da7c70 @base_object=:statler>] 

WalrusPresenter.new(:frank)
# => #<WalrusPresenter:0x00000001da4070 @base_object=:frank> 

WalrusPresenter([:harold, :richard])
# => [#<WalrusPresenter:0x00000001d773e0 @base_object=:harold>,
     #<WalrusPresenter:0x00000001d773b8 @base_object=:richard>]

WalrusPresenter(WalrusPresenter(WalrusPresenter(:frank)))
# => #<WalrusPresenter:0x00000001d6c760 @base_object=:frank>
于 2013-07-03T23:39:57.453 回答
0

首先,我不认为你想要做的事情是超级明智的——可能有更好的方法来完成你想要的。但是,如果您真的想通过添加括号处理来针对类创建一个新运算符,那么下面的代码可以完成我认为的工作。

我正在从CodeErr的这篇很棒的博客文章中复制粗糙的类处理代码。

这是我使用他的代码解决您的问题的方法:

class Object
  alias_method :orig_method_missing, :method_missing

  def method_missing(m, *a, &b)
    klass = begin
      (self.is_a?(Module) ? self : self.class).const_get(m)
    rescue NameError
    end

    return klass.send(:parens, *a, &b)  if klass.respond_to? :parens
    orig_method_missing m, *a, &b
  end
end

class X
  @@class_arg = {}
  def self.class_arg
    @@class_arg[self.name]
  end
  def self.parens(*args)
    @@class_arg[self.name] = args[0]
    Class.new(self).class_eval do
      define_method :initialize do
        super(*args)
      end
      self
    end
  end

end


class Y < X
end
class Z < X
end

Z(:bubbles)
Y(:frank)
puts Z.class_arg # "bubbles"
puts Y.class_arg # "frank"
于 2013-07-04T03:41:43.850 回答
0

我的解决方案:

class BasePresenter
  attr_accessor :base_object

  def initialize(base_object)
    self.base_object = base_object
  end

  Object.class_eval do
    def BasePresenter base_object
        BasePresenter.new base_object
    end
  end

  def self.inherited child_klass
    Object.class_eval do
           define_method child_klass.to_s.to_sym do |base_object|
               child_klass.new base_object
        end
    end
  end

end

class WalrusPresenter < BasePresenter
end

class Test < WalrusPresenter; end

puts BasePresenter(:bubbles)
puts WalrusPresenter(:frank)
puts Test(:test)
于 2013-07-04T04:29:38.780 回答