【发布时间】:2021-11-21 11:35:54
【问题描述】:
测试环境
我在 Ruby 3.0.2 和 Ruby 2.73 中都试过这个,结果相似。手头的问题应该没关系,因为我也在不同的 shell 和 ruby 管理器下尝试过,但这主要是在以下环境下进行测试:
- 鱼,版本 3.3.1
- chruby:0.3.9
- chruby-fish: 0.8.2
- macOS 11.6
描述问题(后续部分中的代码和错误)
我正在尝试使用 Delegator 类中糟糕的(甚至可能未记录的)DelegateClass 来为 YAML::Store 创建一个外观,它允许我在 YAML 存储中读取和写入任意键。但是,我显然不明白如何正确委托给 YAML::Store 实例,或者以我想要的方式覆盖或扩展功能。
为简单起见,我将我的示例编写为一个自执行的 Ruby 文件名 example.rb,因此请滚动到最后查看对类的实际调用。我希望我的错误是相当微不足道的,但如果我从根本上误解了如何实际执行 CollaboratorWithData#write 和 ollaboratorWithData#read 到 MultiWriter 的委托,请教育我。
注意:我知道如何通过简单地将 YAML::Store 视为在我的类中实例化的对象,甚至作为从 YAML::Store 继承的单独对象(例如 class MultiWriter < YAML::Store)来解决这个问题,但我'我非常想了解如何正确使用 Forwardable、SimpleDelegator 和 Delegate 在一般情况和这个特定用例中包装对象。
自执行代码文件(需要一些垂直滚动)
#!/usr/bin/env ruby
require 'delegate'
require 'yaml/store'
module ExampleDelegator
attr_accessor :yaml_store, :data
class CollaboratorWithData
def initialize
@yaml_store = MultiWriter.new
@data = {}
end
def some_data
{a: 1, b:2, c: [1, 2, 3]}
end
end
class MultiWriter < DelegateClass(YAML::Store)
attr_reader :store
def initialize file_name="store.yml", thread_safe=true
super
@store = self
end
def write **kwargs
@store.transaction { kwargs.each { |k, v| @store[k] = v } }
end
def read *keys
@store.transaction(read_only=true) { keys.map { |k| @store[k] } }
end
end
end
if __FILE__ == $0
include ExampleDelegator
c = CollaboratorWithData.new
c.data = c.some_data
c.write(c.data)
end
运行文件时的错误
初始化程序出错
Traceback (most recent call last):
5: from ./example.rb:40:in `<main>'
4: from ./example.rb:40:in `new'
3: from ./example.rb:11:in `initialize'
2: from ./example.rb:11:in `new'
1: from ./example.rb:24:in `initialize'
/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/delegate.rb:71:in `initialize': wrong number of arguments (given 2, expected 1) (ArgumentError)
请注意,如果您仔细查看YAML::Store#new 的调用,可能的签名之一确实 带有两个参数。我不明白为什么当我可以在 IRB 中指定线程安全时它不允许我指定线程安全:
foo = YAML::Store.new 'foo.yml', true
#=> #<Psych::Store:0x00007f9f520f52c8 @opt={}, @filename="foo.yml", @abort=false, @ultra_safe=false, @thread_safe=true, @lock=#<Thread::Mutex:0x00007f9f520f5138>>
使用已修改初始化程序的方法委派错误
即使我取出 thread_safe 参数,在调用委托的 #write 方法时,我仍然会从 CollaboratorWithData 得到 NoMethodError,这让我相信我的委托实现在初始化程序之外存在问题.
./example.rb
Traceback (most recent call last):
./example.rb:42:in `<main>': undefined method `write' for #<ExampleDelegator::CollaboratorWithData:0x00007ff86e0e15c8> (NoMethodError)
【问题讨论】:
标签: ruby yaml delegates wrapper facade