Динамическое добавление атрибутов к объекту Ruby
У меня есть созданный объект, и я хочу, на основе некоторой условной проверки, добавить некоторые атрибуты к этому объекту. Как я могу это сделать?
Объяснить, что я хочу:
A=Object.new
if(something happens)
{
#make A have another attibute say age
#& store something in A.age
}
Ответы
Ответ 1
Прежде всего, дело в рубине заключается в том, что он позволяет использовать другой синтаксис, который широко используется рубиновыми кодировщиками. Капитализированные идентификаторы - это классы или константы (спасибо 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
Ответ 2
Это добавляет атрибут только к объекту:
a = Object.new
if (something happens)
class << a
attr_accessor :age
end
a.age = new_age_value
end
Ответ 3
Вы можете использовать OpenStruct:
a = OpenStruct.new
if condition
a.age = 4
end
Или просто используйте простой старый хэш.
Ответ 4
Если имя атрибута известно в момент написания кода, вы можете сделать то, что было предложено уже:
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
Ответ 5
Вы можете использовать instance_variable_set
для установки переменной в экземпляре класса Object (и instance_variable_get
для ее получения.) Класс Object не имеет никаких атрибутов, которые вы можете установить напрямую.
Однако я подозреваю, что это не лучшее решение для того, чего вы пытаетесь достичь; это не норма, чтобы непосредственно работать с классом Object, а скорее определять или использовать классы, которые наследуют от него, которые имеют атрибуты, с которыми вы хотите работать.