2016-04-19 16 views
3

Rubyでは、クラス定義に次のものを追加することで、getter/setterメソッドを作成できます。例えばすべてのインスタンス変数に `attr_reader`をリストアップせずに宣言する

attr_reader :key1, :key2, :key4 
attr_writer :key1, :key2, :key3 

または同等

attr_accessor :key1, :key2, :key3 

class Foo 
    attr_reader :blah, :bar, :foo, :rah, :jar 

    def initialize a, b, c 
     @blah = calculate_blah(a,b) 
     @bar = calculate_bar(a) 
     @foo = calculate_foo(b,c) 
     @rah = calculate_rah(a,b,c) 
     @jar = calculate_jar(a,c) 
    end 
    # etc etc 
end 

のは、多くのインスタンス変数があるとしましょう、と私はそれらのすべてのgetterメソッド をしたいです。

attr_readerをすべてのインスタンス変数に宣言することはできますか?

initializeメソッドでは変数のリストを2つ(同一)保持する必要がなく、attr_readerで別の変数のリストを保持する必要がないという利点があります。したがって、後で別のインスタンス変数を追加する場合は、リストに追加することなく、initializeメソッドで設定するだけで済みます。

attr_readerですぐに利用できない場合は、おそらく一部のメタプログラミングを呼び出すことができますか?

ここでの主な目的は、これがRubyで可能かどうかを理解することです。 メタプログラミングを使用すると、パフォーマンスとあいまいさが発生することがよくあります。しかし、それはこの質問の範囲を超えています。

私はそれが正しいことであるかどうかではなく、何かをすることが可能かどうかを知ることにもっと興味があります。

+1

を書くことができますが、これらのインスタンス変数の名前の配列を得ましたか。 –

+1

実行時にインスタンス変数が存在しません。彼らは価値が割り当てられているときに生きる。これは、同じクラスの異なるインスタンスが、実行されるロジックに応じて異なるインスタンス変数セットを持つことができることを意味します。これを知ったので、オブジェクトのライフサイクルのどの時点でメソッドを作成したいのですか? –

+2

"おそらくいくつかのメタプログラミング魔法が役立つかもしれません" - あなたの正確なユースケースは非常に不明ですが、それが純粋な怠惰から外れている場合は、メタプログラミングを伴わないでください。 100イーバーズのクラスは十分に悪いです:) –

答えて

1

他の人が言ったように、実際には同様のコードを使用することはお勧めできませんが、あなたが求めているメタ関数を記述することは可能です。 これは、さまざまな解決策の1つです。アイデアは、インスタンス変数がすでにオブジェクト上に定義されているライフサイクルで、一度使用しているすべてのオブジェクトを増やすことです。これは、初期化中または初期化後に発生する可能性があります。

class Foo 
    def initialize 
    @a = @b = @c = 33 
    # you could call define_attr_readers here 
    end 

    def define_attr_readers 
    # get the eigenclass of the current object 
    klass = class << self; self; end 

    symbols = instance_variables.map { |s| 
     # remove the @ at the start of the symbol 
     s.to_s[1..-1].to_sym 
    } 

    # augment the eigenclass 
    klass.class_eval do 
     symbols.each do |s| 
     attr_reader s 
     end 
    end 
    end 
end 

f = Foo.new 
f.define_attr_readers 
p f.a, f.b, f.c 
+1

" eigenclass "の公用語は" singleton class "です。そのためのgetterもあります。 'singleton_class'です。 –

+0

解決に感謝します。私たちはRubyのメタプログラミングの力を見ます。 –

3

ここではシングルトン法を使用したソリューションです。ノートcreate_gettersはプライベートメソッドなので、外部はメタプログラミング(実装の詳細)の使用を認識していません。 IRBでこれを実行している

class Foo 
    def initialize a, b 
    @foo = a + b 
    @bar = a - b 
    @jar = a + b + 1000 

    create_getters 
    end 

    private 

    def create_getters 
    instance_variables.each do |v| 
     define_singleton_method(v.to_s.tr('@','')) do 
     instance_variable_get(v) 
     end 
    end 
    end 
end 

2.2.1 :082 > x=Foo.new 100, 99 
=> #<Foo:0x007fb4f3c31ce8 @foo=199, @bar=1, @jar=1199> 
2.2.1 :083 > x.foo 
=> 199 
2.2.1 :084 > x.bar 
=> 1 
2.2.1 :085 > x.jar 
=> 1199 

は注意して:このようにそれを行うことによって、オブジェクトのインスタンス化とゲッターメソッド呼び出しの両方が遅くなります。

0

は、インスタンス変数を評価するために、一度クラスをインスタンス化し、クラス

class Hey 
    def initialize 
    @foo, @bar, @shabaz = [1,2,3] 
    end 
end 

Hey.new.instance_variables.tap do |inst_vars| 
    Hey.class_eval do 
    attr_reader *inst_vars.map { |var| var.to_s.sub(/^@/, '').to_sym } 
    end 
end 

p Hey.new.foo 
p Hey.new.bar 
p Hey.new.shabaz 
0

見て、MAを再定義します!メタプログラミングはありません!その後

と仮定

class A 
    def initialize 
    @b=0 
    @c=1 
    end 
end 

a = A.new 

a.instance_variables.each { |iv| self.class.send(:attr_reader, iv.to_s[1..-1].to_sym) } 

a.b #=> 0 
a.C#=> 1 

すべてのインスタンス変数がinitializeで定義されている場合は、

class A 
    def initialize 
    @b=0 
    @c=1 
    end.tap { |instance| instance.instance_variables.each { |iv| 
    self.class.send(:attr_reader, iv.to_s[1..-1].to_sym) } } 
end 

a = A.new 
a.b #=> 0 
a.C#=> 1 
関連する問題