如何修改实例化的OpenStruct class

How to modify OpenStruct in the instantiated class

我有以下代码,我在其中实例化了一个 returns 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

我想让 class 工作,这样我就可以即时修改 result 的任何属性。

test = TestModel.new

test.result
=> #<OpenStruct successful?=false>

test.result.successful!
=> #<OpenStruct successful?=true>

此语法来自官方 OpenStruct 页面,它只能独立运行,但不能在实例化的 class - 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

有什么想法吗?我真的很想知道怎么做。

OpenStruct requires you to use Object#send 或类似哈希的键来使用谓词符号。文档说:

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 [].

此外,不清楚为什么要将 @result 定义为可写,或者为什么要重写 getter 方法以便 TestModel#result 始终 returns 错误。这可能至少导致了您的部分问题。

相反,我将重写代码如下:

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>

如果愿意,您当然可以将结构成员初始化为 false 而不是 nil,但我认为这在语义上更清晰。您在这方面的进展可能会有所不同。