gpt4 book ai didi

Ruby 赋值方法不会收到 block ?

转载 作者:数据小太阳 更新时间:2023-10-29 08:58:47 24 4
gpt4 key购买 nike

我正在构建一个 DSL 并拥有这个模块

module EDAApiBuilder
module Client

attr_accessor :api_client, :endpoint, :url

def api_client(api_name)
@apis ||= {}
raise ArgumentError.new('API name already exists.') if @apis.has_key?(api_name)
@api_client = api_name
@apis[@api_client] = {}
yield(self) if block_given?
end

def fetch_client(api_name)
@apis[api_name]
end

def endpoint(endpoint_name)
raise ArgumentError.new("Endpoint #{endpoint_name} already exists for #{@api_client} API client.") if fetch_client(@api_client).has_key?(endpoint_name)
@endpoint = endpoint_name
@apis[@api_client][@endpoint] = {}
yield(self) if block_given?
end

def url=(endpoint_url)
fetch_client(@api_client)[@endpoint]['url'] = endpoint_url
end

end
end

所以我有这样的测试

  context 'errors' do

it 'raises an ArgumentError when trying to create an already existent API client' do
expect {
obj = MixinTester.new
obj.api_client('google')
obj.api_client('google')
}.to raise_error(ArgumentError,'API name already exists.')
end

it 'raises an ArgumentError when trying to create a repeated endpoint for the same API client' do
expect {
obj = MixinTester.new
obj.api_client('google') do |apic|
apic.endpoint('test1')
apic.endpoint('test1')
end
}.to raise_error(ArgumentError,"Endpoint test1 already exists for google API client.")
end

end

我宁愿将#api_client写成赋值 block

def api_client=(api_name)

这样我就可以写

obj = MixinTester.new
obj.api_client = 'google' do |apic| # <=== Notice the difference here
apic.endpoint('test1')
apic.endpoint('test1')
end

因为我觉得这个notation(with assignment)更有意义。但是,当我以这种方式运行测试时,我只是收到一条错误消息,指出 keyworkd_do 在这种情况下是意外的。

在我看来,赋值 block 的定义是语法糖,不会考虑 block 。

这是正确的吗?有人知道这方面的信息吗?

顺便说一句:MixinTester只是一个用于测试的类,在我的spec/spec_helper.rb中定义为

class MixinTester
include EDAApiBuilder::Client
end

最佳答案

语法错误

It seems to me that the definition of an assignment [method] is syntactic sugar which won't contemplate blocks.

看来你是对的。看起来没有带有 = 的方法可以接受一个 block ,即使是正常的方法调用并且没有语法糖:

class MixinTester
def name=(name,&block)
end

def set_name(name, &block)
end
end

obj = MixinTester.new

obj.set_name('test') do |x|
puts x
end

obj.name=('test') do |x| # <- syntax error, unexpected keyword_do, expecting end-of-input
puts x
end

备选

哈希参数

另一种方法可以用哈希来写:

class MixinTester
def api(params, &block)
block.call(params)
end
end

obj = MixinTester.new

obj.api client: 'google' do |apic|
puts apic
end
#=> {:client=>"google"}

您可以根据口味调整方法名称和哈希参数。

带 block 的参数

如果 block 属于方法参数,而不是 setter 方法,则接受语法:

def google(&block)
puts "Instantiate Google API"
block.call("custom apic object")
end

class MixinTester
attr_writer :api_client
end

obj = MixinTester.new

obj.api_client = google do |apic|
puts apic
end

# =>
# Instantiate Google API
# custom apic object

它看起来很奇怪,但它非常接近您想要实现的目标。

关于Ruby 赋值方法不会收到 block ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41945244/

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