2

私は 2 つのクラス A と B を持っています。どちらにもいくつかのオプションがあります。通常、1 つのハッシュを使用して次のようなオプションを格納します@options[:name]='xxxx'。今、メタプログラミングを使用してリファクタリングしたいのですが、

class A
    set_option :name, "james"
    set_option :address, "some street"

    def hello
        puts @options[:name]
        puts @options[:address]
    end
end


class B
    set_option :age, 18

    def greeting
        put @options[:age]
    end
end 

set_optionここで、キーと値のペアを 1 つのハッシュ インスタンスに設定するために使用したいのですが@options、どうすればよいですか?

さらに、ソリューションを別のモジュールにラップしたいと考えています。

更新しました:

最初に感謝します。すべての回答は私にとって価値があり、より明確になります。今、私が望んでいることがあまり正しくないことに気づきました。このような質問をするとどうなりますか?

  • optionを置き換えるために1つの方法を使用するのは@optionsどうですか?
  • クラスAとBの両方が1つの同じキーに異なるオプションを設定できるため、一部の回答@@optionsが機能しない可能性がありますか? 異なるクラスが異なるハッシュインスタンスを持つことができるようにしたい。

このように:

class A
    set_option :name, "james"
    set_option :provider, 'twitter'

    def hello
        puts option[:name]
    end
end


class B
    set_option :name, "not james"

    def greeting
        put option[:name]
    end
end 

よく考えた後、私が本当に欲しいのは、クラスのインスタンスではなく、異なるクラスの異なるオプションハッシュインスタンスだと思います。

これが私が望むものであり、それは機能します。

module HasOptions
  def self.included(cls)
    cls.class_eval do
      def self.set_option(key, value)
        options[key] = value
      end

      def self.options
        @options ||= {}
      end

      def options
        self.class.options
      end
    end
  end
end


class Baz
  include HasOptions
  set_option :name, "bad"

  def greeting
        puts options[:name]
  end
end

class Foo
  include HasOptions
  set_option :name, "foo"

  def greeting
        puts options[:name]
  end
end

ご助力いただきありがとうございます。

4

3 に答える 3

5

あなたがやろうとしているように、インスタンス変数を使用してもうまくいきません。ただし、次のような方法を使用できます。

module HasOptions
  def self.included(cls)
    cls.class_eval do
      def self.set_option(key, value)
        (@@options ||= {})[key] = value
      end
    end
  end

  def options
    @options ||= @@options.dup
  end
end

この実装により、すべてのインスタンスに共通のオプションを上書きすることなく、インスタンスごとのオプションを設定できます。

于 2013-02-17T08:06:28.623 に答える
2

あなたは物事を少し台​​無しにしているように見えます。あなたが解決したい質問をリストアップしてみましょう:

  • クラス変数のインスタンスにオプションを格納しますHash(正しいと思いましたか? — クラスのすべてのインスタンスに対して 1 つのハッシュ)。
  • オプションの設定にはきれいな表記法を使用してください。

上記のどれも、実際にメタプログラミングを必要としません。最初の条件を満たすには、すべてのクラスの最初の共通の祖先を見つけて、@@optionsvar とset_optionメソッドで [monkey]patch を適用するだけです。すべてのクラスに独自のスーパークラスを提供することに決めなかった場合は、祖先 (Kernelモジュールなど)にパッチを適用しましょう。

module Kernel
  def set_option name, value
    (@@options ||= {})[name.to_sym] = value
  end
end

現在、任意のクラスに、オプションを共有オプション ハッシュset_optionに入れるための「命令」を含めることができます (オプションをインスタンス固有にする代わりに、インスタンス変数を使用することを検討するか、Alex D のソリューションを使用してください)。@options@@options

オプション設定のための派手な構文 (デフォルト、インプレース チェッカー、ルーシュ、ぜいたく品) が必要な場合は、ここでDSLを使用する必要があります。この記事の最初の例はset_option、DSLを使用して pure を実装する方法を示しています。さらなるチューニングはあなたの想像力によってのみ制限されます。

于 2013-02-17T10:14:50.420 に答える
1

init インスタンス オプションが必要な場合は、インスタンス メソッドを使用して実行する必要があります。

module OptionSetter
  def set_option(key, value)
    @options[key] = value
  end
end

class Base
  def initialize(options = {})
    @options = {}
    options.each do |key, value|
      set_option key, value
    end
  end
end

class A < Base
  include OptionSetter

  def hello
    puts @options[:name]
    puts @options[:address]
  end
end

class B < Base
  include OptionSetter

  def greeting
    puts @options[:age]
  end
end

A.new(name: "james", address: "some street").hello
B.new(age: 18).greeting

ルビーでそれを作るより一般的な方法は、を使用することattr_accessorです

class Base
  attr_accessor :options

  def initialize(options = {})
    @options = options
  end
end

class A < Base
  def hello
    puts @options[:name]
    puts @options[:address]
  end
end

class B < Base
  def greeting
    puts @options[:age]
  end
end

A.new(name: "james", address: "some street").hello
B.new(age: 18).greeting

# another approach
james = A.new
james.options[:name] = "james"
james.options[:address] = "some street"
james.hello
于 2013-02-17T08:15:04.527 に答える