динамическое добавление атрибутов к объекту Ruby - PullRequest
41 голосов
/ 08 июля 2010

У меня есть созданный объект, и я хочу, основываясь на некоторой условной проверке, добавить некоторые атрибуты в этот объект.Как я могу это сделать?Чтобы объяснить, что я хочу:

A=Object.new
if(something happens)
{
  #make A have another attibute say age
  #& store something in A.age

}

Ответы [ 6 ]

48 голосов
/ 08 июля 2010

Прежде всего, в ruby ​​есть то, что он допускает другой синтаксис, который широко используется кодировщиками ruby.Идентификаторы с заглавной буквы - это Classes или Constants (спасибо sepp2k за его комментарий), но вы пытаетесь сделать его объектом.И почти никто не использует {}, чтобы пометить многострочный блок.

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

Я не уверен, что ваш вопрос, но у меня есть идея, и это было бы решением:

Если вы знаете, какие атрибуты могут иметь этот класс, и он ограничен, вы должны использовать

class YourClass
  attr_accessor :age
end

attr_accessor :age - это сокращение:

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

Теперь вы можете сделать что-то вроде этого:

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

Если вы хотите сделать это полностью динамично, вы можете сделать что-то вроде этого:

a = Object.new
if (some condition)
  a.class.module_eval { attr_accessor :age}
  a.age = new_age_value
end
21 голосов
/ 23 сентября 2011

Добавляет атрибут только к объекту:

a = Object.new
if (something happens)
  class << a
    attr_accessor :age
  end
  a.age = new_age_value
end
20 голосов
/ 14 августа 2012

Вы можете использовать OpenStruct:

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

Или просто используйте простой старый хеш.

11 голосов
/ 04 октября 2012

Если имя атрибута известно во время написания кода, тогда вы можете сделать то, что уже было предложено:

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

Однако, если имя атрибута динамическое и известно только во время выполнения, вам придется вызывать attr_accessor немного по-другому:

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
6 голосов
/ 08 июля 2010

Вы можете использовать instance_variable_set, чтобы установить переменную для экземпляра класса Object (и instance_variable_get, чтобы получить его.) Класс Object не имеет атрибутов, которые вы можете установить напрямую.

Однако я подозреваю, что это не лучшее решение для того, чего вы пытаетесь достичь; напрямую работать с классом Object не является нормой, а скорее определять или использовать классы, которые наследуют его, и имеют атрибуты, с которыми вы хотите работать.

1 голос
/ 18 мая 2018
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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...