adding attributes to a Ruby object dynamically

前端 未结 6 2009
梦毁少年i
梦毁少年i 2020-12-24 06:07

I have an object created, and I want, based on some conditional check, to add some attributes to this object. How can I do this? To explain what I want:

A=O         


        
相关标签:
6条回答
  • 2020-12-24 06:47

    First of all the thing about ruby is that it allows a different syntax which is used widely by ruby coders. Capitalized identifiers are Classes or Constants (thanks to sepp2k for his comment), but you try to make it an object. And almost nobody uses {} to mark a multiline block.

    a = Object.new
    if (something happens)
      # do something
    end
    

    I'm not sure what your question is, but I have an idea, and this would be the solution:

    If you know what attributes that class can have, and it's limited you should use

    class YourClass
      attr_accessor :age
    end
    

    attr_accessor :age is short for:

    def age
      @age
    end
    def age=(new_age)
      @age = new_age
    end
    

    Now you can do something like this:

    a = YourClass.new
    if (some condition)
      a.age = new_value
    end
    

    If you want to do it completely dynamically you can do something like this:

    a = Object.new
    if (some condition)
      a.class.module_eval { attr_accessor :age}
      a.age = new_age_value
    end
    
    0 讨论(0)
  • 2020-12-24 06:51

    This adds the attribute to only the object:

    a = Object.new
    if (something happens)
      class << a
        attr_accessor :age
      end
      a.age = new_age_value
    end
    
    0 讨论(0)
  • 2020-12-24 06:53
    class Person; end
    person = Person.new
    person.age # throws NoMethodError
    
    if true
      person.singleton_class.module_eval { attr_accessor :age }
    end
    
    person.age = 123
    person.age #=> 123
    
    person2 = Person.new
    person2.age #=> throws NoMethodError
    
    0 讨论(0)
  • 2020-12-24 07:03

    You could use an OpenStruct:

    a = OpenStruct.new
    if condition
        a.age = 4
    end
    

    Or just use a plain old hash.

    0 讨论(0)
  • 2020-12-24 07:03

    If the name of the attribute is known at code-writing time then you can do what was suggested already:

    class A
    end
    
    a = A.new
    a.age = 20 # Raises undefined method `age='
    
    # Inject attribute accessors into instance of A
    class << a
      attr_accessor :age
    end
    
    a.age = 20 # Succeeds
    a.age # Returns 20
    
    b = A.new
    b.age # Raises undefined method, as expected, since we only modified one instance of A
    

    However, if the attribute's name is dynamic and only known at runtime then you'll have to call attr_accessor a bit differently:

    attr_name = 'foo'
    
    class A
    end
    
    a = A.new
    a.foo = 20 # Raises undefined method `foo='
    
    # Inject attribute accessors into instance of A
    a.instance_eval { class << self; self end }.send(:attr_accessor, attr_name)
    
    a.foo = 20 # Succeeds
    a.foo # Returns 20
    
    0 讨论(0)
  • 2020-12-24 07:09

    You can use instance_variable_set to set a variable on an instance of the Object class (and instance_variable_get to get it.) The Object class doesn't have any attributes you can set directly.

    However, I suspect this is not the best solution for what you are trying to achieve; it is not the norm to directly work with the Object class, but rather to define or use classes that inherit from it, that have the attributes you want to work with.

    0 讨论(0)
提交回复
热议问题