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> 

更新:ミーシャは、私とほぼ同じ方法で、あなたのコメントにすでに返信しています。 Kernel#Arrayto_aryはその引数で呼び出しを試行しto_a、失敗した場合は呼び出しを試み、失敗した場合は引数を唯一の要素として配列を作成します。

どのような動作が必要かは明確ではありません。を使用して回避したいだけのように思え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 に答える