Declaring instance variables iterating over a hash!

前端 未结 4 1430
忘掉有多难
忘掉有多难 2021-02-02 16:43

i want to do the following:

I want to declare the instance variables of a class iterating over a dictionary.

Let\'s assume that i have this hash

         


        
相关标签:
4条回答
  • 2021-02-02 16:54

    http://facets.rubyforge.org/apidoc/api/more/classes/OpenStructable.html

    OpensStructable is a mixin module which can provide OpenStruct behavior to any class or object. OpenStructable allows extention of data objects with arbitrary attributes.

    0 讨论(0)
  • 2021-02-02 17:03
    class MyClass
      def initialize()
        hash = {"key1" => "value1","key2" => "value2","key3" => "value3"}
        hash.each do |k,v|
          instance_variable_set("@#{k}",v)
          # if you want accessors:
          eigenclass = class<<self; self; end
          eigenclass.class_eval do
            attr_accessor k
          end
        end
      end
    end
    

    The eigenclass is a special class belonging just to a single object, so methods defined there will be instance methods of that object but not belong to other instances of the object's normal class.

    0 讨论(0)
  • 2021-02-02 17:07

    Chuck's answer is better than my last two attempts. The eigenclass is not self.class like I had thought; it took a better test than I had written to realize this.

    Using my old code, I tested in the following manner and found that the class was indeed manipulated and not the instance:

    a = MyClass.new :my_attr => 3
    b = MyClass.new :my_other_attr => 4
    
    puts "Common methods between a & b:"
    c = (a.public_methods | b.public_methods).select { |v| a.respond_to?(v) && b.respond_to?(v) && !Object.respond_to?(v) }
    c.each { |v| puts "    #{v}" }
    

    The output was:

    Common methods between a & b:
        my_other_attr=
        my_attr
        my_attr=
        my_other_attr
    

    This clearly disproves my presupposition. My apologies Chuck, you were right all along.

    Older answer:

    attr_accessor only works when evaluated in a class definition, not the initialization of an instance. Therefore, the only method to directly do what you want is to use instance_eval with a string:

    class MyClass
      def initialize(params)
        #hash = {"key1" => "value1","key2" => "value2","key3" => "value3"}
        params.each do |k,v|
          instance_variable_set("@#{k}", v)
          instance_eval %{
            def #{k}
              instance_variable_get("@#{k}")
            end
            def #{k}= (new_val)
              instance_variable_set("@#{k}", new_val)
            end
          }
        end
      end
    end
    

    To test this try:

    c = MyClass.new :my_var => 1
    puts c.my_var
    
    0 讨论(0)
  • 2021-02-02 17:12
    class MyClass
      def initialize
        # define a hash and then
        hash.each do |k,v|
          # attr_accessor k # optional
          instance_variable_set(:"@#{k}", v)
        end
      end
    end
    
    0 讨论(0)
提交回复
热议问题