I have the following code where I instantiate an object that returns an OpenStruct result.
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
I want the class to work so that I could modify any attributes of my result
on the fly.
test = TestModel.new
test.result
=> #<OpenStruct successful?=false>
test.result.successful!
=> #<OpenStruct successful?=true>
This syntax comes from the official OpenStruct page, and it works just on its own but not inside an instantiated class - https://ruby-doc.org/stdlib-2.5.3/libdoc/ostruct/rdoc/OpenStruct.html
result.send('successful?', true)
I've also tried to use lambda
but to no avail
def result
OpenStruct.new(successful?: false, :successful! => lamdba {self.uccessful? = true})
end
Any ideas? I really want to know how to do that.
OpenStruct requires you to use Object#send or Hash-like keys to make use of predicate symbols. The documentation says:
Hash keys with spaces or characters that could normally not be used for method calls (e.g.
()[]*
) will not be immediately available on the OpenStruct object as a method for retrieval or assignment, but can still be reached through the Object#send method or using[]
.
In addition, it's unclear why you want to define @result as writable, or why you would override the getter method so that TestModel#result always returns false. That's probably causing at least part of your problem.
Instead, I'd rewrite the code as follows:
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>
You could certainly initialize the struct member as false
rather than nil
if you prefer, but I think this is semantically clearer. Your mileage in that regard may vary.