0

私はRubyが初めてで、ユーザークラスにメソッドを追加するという点で、にClass似たメソッドを作成する方法について混乱:attr_accessorしていますが、これらの追加されたメソッドは事前に初期化されたインスタンス変数にアクセスできます。私が説明するのは難しいので、ここに私の努力の非常に単純化されたサンプルがあります:

class Class
    def super_accessor_wow(attr_name)
        attr_name = attr_name.to_s 
        new_var_name = "@crazy_var_name"

        instance_variable_set(new_var_name, ["hi", "everyone"])

        module_eval(%Q/
            def super_#{attr_name}()
                return @#{attr_name}
            end

            def super_#{attr_name}=(value)
                @#{attr_name} = value
            end

            def greetings
                return #{new_var_name}
            end
        /)
    end
end

これは、新しいメソッドを使用しClassて自分のクラスを変更しようとしている方法です。

class Foo
    super_accessor_wow(:bar)
end

foo1 = Foo.new()
foo1.super_bar = 1000

puts foo1.super_bar
puts foo1.greetings.inspect

最初に印刷物を置きます'1000'

2番目はprintsを置く'nil'ため、私のinstance_variable_set呼び出しはsuper_accessor_wow一見効果がありません。

ちなみに、2番目のプットが印刷'['hi', 'everyone']'されると思っていました。このコードはすべて、単一の Ruby ファイルに含まれています。

4

2 に答える 2

1

Yourは、クラス定義中にinstance_variable_set呼び出すと呼び出されます。super_accessor_wowクラスのインスタンスはまだ存在しません。を呼び出すときに、クラスのインスタンスを作成しますnew@crazy_var_name初期化をコンストラクターに追加するか、greetingsメソッドで定義することができます。

デフォルトをクラス変数に入れ、コンストラクターでインスタンス変数を初期化します (これにより、クラスのコンストラクターが作成され、独自のコンストラクターを作成すると、これがオーバーライドされることに注意してください)。

class Class
    def super_accessor_wow(attr_name)
        attr_name = attr_name.to_s
        new_var_name = "@crazy_var_name"
        new_var_name_default = "@#{new_var_name}"

        module_eval(%Q/
            #{new_var_name_default} = ["hi", "everyone"]

            def initialize()
              #{new_var_name} = #{new_var_name_default}
            end

            def super_#{attr_name}()
                return @#{attr_name}
            end

            def super_#{attr_name}=(value)
                @#{attr_name} = value
            end

            def greetings
                return #{new_var_name}
            end
        /)
    end
end

class Foo
    super_accessor_wow(:bar)
end

foo1 = Foo.new()
foo1.super_bar = 1000

puts foo1.super_bar
puts foo1.greetings.inspect
puts Foo.class_variable_get('@@crazy_var_name').inspect
puts foo1.instance_variable_get('@crazy_var_name').inspect

出力:

1000
["hi", "everyone"]
["hi", "everyone"]
["hi", "everyone"]

greetingsメソッドで定義します。

class Class
    def super_accessor_wow(attr_name)
        attr_name = attr_name.to_s
        new_var_name = "@crazy_var_name"

        module_eval(%Q/
            def super_#{attr_name}()
                return @#{attr_name}
            end

            def super_#{attr_name}=(value)
                @#{attr_name} = value
            end

            def greetings
                #{new_var_name} = ["hi", "everyone"] unless #{new_var_name}
                return #{new_var_name}
            end
        /)
    end
end

class Foo
    super_accessor_wow(:bar)
end

foo1 = Foo.new()
foo1.super_bar = 1000

puts foo1.super_bar
puts foo1.greetings.inspect

出力

1000
["hi", "everyone"]
于 2012-07-29T00:26:14.580 に答える
0

コメントで述べたように、instance_variable_set は文字列ではなくシンボルを取るため、最初にそれを修正します。

instance_variable_set(new_var_name.to_sym, ["hi", "everyone"])

しかし、大きな問題は、instance_variable_set が Foo のインスタンスによって呼び出されているのではなく、Foo クラス自体によって呼び出されていることです。したがって、インスタンス変数が設定されていますが、期待どおりではありません。

Foo.instance_variable_get(:@crazy_var_name).inspect
# ["hi", "everyone"]
于 2012-07-29T00:26:55.453 に答える