1

いくつかのプライベート属性を含むクラスがあります。私がやりたいことは、特定のブロックの実行のためだけに、これらのいくつかのセッターを動的に追加することです。

私ができるようにしたいことの例:

class Content
  attr_reader :a, :b

  def initialize
    @a = 1
    @b = "plop"
  end

  def set(&block)
    extend(Setter)
    instance_eval(&block)
    unextend(Setter) ????
  end

  module Setter
    def a(value)
      @a = value
    end
    def b(value)
      @b = value
    end
  end
end

content = Content.new
content.set do
  a 2
  b "yeah!"
end
content.a # should return 2

編集:これまで素晴らしい回答をありがとう。モジュールで定義されたセッターと競合する可能性があるクラス自体で属性リーダーを実際に定義する必要があるため、質問を明確にしました。質問を投稿するときにこの部分を忘れていました。(遅かった^^)

明確化: このクラスは、DSL が構成ファイルを書き込むためのものです。非開発者を対象としているため、オペレーターが少ないほど良いです。

私は現在、ブロックするプロキシクラスを使用してこれを実装してinstance_evalいますが、値を設定するためにいじるinstance_variable_set必要があり、好きではありません。コードを読みやすくできるかどうかを確認する別の方法を試しています。

4

4 に答える 4

3

Ruby でモジュールを「拡張解除」するネイティブな方法はありません。mixology gemは、このパターンを C (および JRuby の場合は Java) 拡張として実装し、メソッドを作成mixinunmixます。ただし、Ruby 1.9 のサポートが必要な場合は、パッチを適用する必要があるようです。

サードパーティ ライブラリの使用を避けたい場合は、セッターを非公開にする別の方法があります。

class Content
  def initialize
    @a = 1
    @b = "plop"
  end

  def set(&block)
    instance_eval(&block)
  end

  private

  def a(val)
    @a = val
  end

  def b(val)
    @b = val
  end 

end

content = Content.new

#This will succeed
content.set do
  a 2
  b "yeah!"
end

# This will raise a NoMethodError, as it attempts to call a private method
content.a 3
于 2009-06-10T00:42:13.747 に答える
2
  def set(&block)
    extend(Setter)
    instance_eval(&block)
    Setter.instance_methods.each do |m| 
      instance_eval "undef #{m}"
    end
  end

何かがあるかもしれませんが、あなたのためにそれを行うメソッドは知りません..しかし、これは、Setterのすべてのインスタンスメソッドを見つけて、コンテンツでそれらを定義解除することによって、仕事をするはずです.

于 2009-06-09T21:53:43.730 に答える
2

_why の mixico ライブラリ( github で入手可能)を使用できます。

これにより、次のことが可能になります。

require 'mixology'
#...
def set(&block)
  Setter.mix_eval(Setter, &block)
end

mixology gemはほとんど同じことを行いますが、わずかに異なります。

于 2009-06-10T02:00:30.987 に答える
0

実験的な気分になっている場合は、dup_evalもチェックしてください。

いくつかの点で mixico に似ていますが、いくつかの興味深い追加機能 ( object2module )があります。

于 2009-07-23T08:26:43.183 に答える