#ruby #instantiation #openstruct
#ruby #создание экземпляра #openstruct
Вопрос:
У меня есть следующий код, в котором я создаю экземпляр объекта, который возвращает результат OpenStruct.
require 'ostruct'
class TestModel
attr_accessor :result
def initializer
end
def result
OpenStruct.new(successful?: false)
end
def successful!
result.send('successful?', true)
end
end
Я хочу, чтобы класс работал так, чтобы я мог изменять любые свои атрибуты result
«на лету».
test = TestModel.new
test.result
=> #<OpenStruct successful?=false>
test.result.successful!
=> #<OpenStruct successful?=true>
Этот синтаксис взят с официальной страницы OpenStruct, и он работает сам по себе, но не внутри созданного класса — https://ruby-doc.org/stdlib-2.5.3/libdoc/ostruct/rdoc/OpenStruct.html
result.send('successful?', true)
Я также пытался использовать lambda
, но безрезультатно
def result
OpenStruct.new(successful?: false, :successful! => lamdba {self.uccessful? = true})
end
Есть идеи? Я действительно хочу знать, как это сделать.
Ответ №1:
OpenStruct требует, чтобы вы использовали Object#send или хэш-подобные ключи для использования символов предикатов. В документации говорится:
Хэш-ключи с пробелами или символами, которые обычно не могут использоваться для вызовов методов (например
()[]*
), не будут немедленно доступны в объекте OpenStruct в качестве метода для извлечения или назначения, но все равно могут быть доступны через метод Object#send или с помощью[]
.
Кроме того, неясно, почему вы хотите определить @result как доступный для записи, или почему вы переопределяете метод getter, чтобы TestModel#result всегда возвращал false . Вероятно, это вызывает хотя бы часть вашей проблемы.
Вместо этого я бы переписал код следующим образом:
require 'ostruct'
class TestModel
attr_reader :result
def initialize
@result = OpenStruct.new :successful? => nil
end
def unsuccessful
@result.send "successful?=", false
end
def successful!
@result.send "successful?=", true
end
end
test_model = TestModel.new
#=> #<TestModel:0x00007faf5c1b9528 @result=#<OpenStruct successful?=nil>>
test_model.result
#=> nil
test_model.successful!
#=> true
test_model.result
#=> #<OpenStruct successful?=true>
test_model.unsuccessful
#=> false
test_model.result
#=> #<OpenStruct successful?=false>
Вы, конечно, могли бы инициализировать элемент struct как false
, а не nil
как, если хотите, но я думаю, что это семантически понятнее. Ваш опыт в этом отношении может отличаться.