gpt4 book ai didi

Ruby 元编程 - 如何处理参数错误

转载 作者:太空宇宙 更新时间:2023-11-03 18:03:05 31 4
gpt4 key购买 nike

我有一个使用 DSL 进行复杂配置的文件,该较大 DSL 的一部分是名称/值设置 DSL。

每当我使用名为 name 的设置时,我都会收到错误消息。

Failure/Error: name 'SomeName' ArgumentError: wrong number of arguments (given 1, expected 0)

我正在寻找解决这种极端情况的方法。

SettingsDsl 的任何实例都可以有一个唯一的名称来标识自己,这是初始化程序的可选参数。

例子

main_dsl = MainDsl.new do 
settings do
rails_port 3000
end
settings :key_values do
rails_port 3000
end
end

这将创建两个 SettingsDsl 实例,一个名称为 :settings,另一个名称为 :key_values

这是 MainDsl 和 SettingsDsl 的代码

class MainDsl
attr_reader :meta_data

def initialize(&block)

@meta_data = HashWithIndifferentAccess.new

if block_given?
self.instance_eval(&block)
end
end

def settings(name = nil,&block)
settings = SettingsDsl.new(@meta_data, name, &block)

puts setting.name

settings
end

end

class SettingsDsl

attr_reader :name

def initialize(data, name = nil, &block)
@data = data
@name = name ||= :settings

@data[name] = {}

self.instance_eval(&block) if block_given?
end

def method_missing(key, *args, &block)
@data[@name][key] = args[0]
end

def get_value(key)
@data[@name][key]
end

end

一切正常,直到我使用名为name

的内部键/值对

我使用 method_missing 来查找新键并将这些值存储到哈希中,但是对于 name,已经有一个 attr_reader,这使用了稍微不同的签名并导致参数错误。

main_dsl = MainDsl.new do 
settings do
rails_port 3000
name 'SomeName' # Intercept the error for this and store 'SomeName' into @data[@name]['name']
another_property 'Something Else'
end
settings :more do
hello 'world'
end
end

Failure/Error: name 'SomeName' ArgumentError: wrong number of arguments (given 1, expected 0)

问题的发生是因为在内部有一个设置组的名称属性,例如

SettingsDsl.new('name_goes_here')
# and gets stored in @name
# and is accessible via attr_reader :name
# which creates a read-only method called name. e.g.
SettingsDsl.new('name_goes_here').name

我想拦截这个方法调用的 ArgumentError 并适本地处理这个边缘情况

最终输出看起来像

{
'settings': {
'rails_port': 3000,
'name': 'SomeName',
'another_property': 'Something Else'
},
'more': {
'hello': 'world'
}
}

最佳答案

您可以摆脱 attr_reader :name 并自己实现边缘情况逻辑:

def name(*args)
args.empty? ? @name : @data[@name][:name] = args[0]
end

这是一个完整的例子:

stackoverflow-57540225.rb:

require 'active_support/hash_with_indifferent_access'
require 'json'

class MainDsl
attr_reader :meta_data

def initialize(&block)
@meta_data = HashWithIndifferentAccess.new

if block_given?
self.instance_eval(&block)
end
end

def settings(name = nil,&block)
settings = SettingsDsl.new(@meta_data, name, &block)
end
end

class SettingsDsl
def initialize(data, name = nil, &block)
@data = data
@name = name ||= :settings

@data[name] = HashWithIndifferentAccess.new

self.instance_eval(&block) if block_given?
end

def name(*args)
args.empty? ? @name : @data[@name][:name] = args[0]
end

def method_missing(key, *args, &block)
@data[@name][key] = args[0]
end

def get_value(key)
@data[@name][key]
end
end

main_dsl = MainDsl.new do
settings do
rails_port 3000
name 'SomeName'
another_property 'Something Else'
end
settings :more do
hello 'world'
end
end

puts main_dsl.meta_data.to_json

结果:

$ ruby stackoverflow-57540225.rb | jq .
{
"settings": {
"rails_port": 3000,
"name": "SomeName",
"another_property": "Something Else"
},
"more": {
"hello": "world"
}
}

关于Ruby 元编程 - 如何处理参数错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57540225/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com