我最近一直在玩ruby并且了解一些关于传递块的基础知识 一个方法以及如何将值返回到块等,但我遇到了以下内容 Rspec中的代码:
RSpec.configure do |config|
config.use_transactional_fixtures = true
end
现在这对我来说看起来非常疲惫和有趣,但我并不完全理解它。 怎么可能通过' config'配置,同时它成为一个可调用的对象 在块内作为' config.use_transactional_fixtures ....'
有人可以帮助我一个可以在上面的例子中调用的基本实现,并且这个技术有名称吗?我将继续探索这个问题!
答案 0 :(得分:2)
以下是具有配置对象和配置方法的类的示例:
class ConfigObject
attr_accessor :some_configuration_variable, :some_option
def initialize
# set default values in initialize
@some_configuration_variable = false
@some_option = :default
end
end
class MyClass
# open the metaclass (access to the MyClass object instance)
class << self
def configure
yield configuration_object
end
# return the configuration object, or initialize it if it doesn't yet exist.
def configuration_object
@configuration_object ||= ConfigObject.new
end
end
end
由于类实例MyClass是单例对象,因此只存在一个配置对象。 MyClass
的实例可以MyClass.new.class.configuration_object
访问该对象。或者,对于更灵活的方法,您可以定义配置对象的访问者并将消息转发给它:
require 'forwardable'
class MyClass
extend Forwardable
def_delegators :configuration_object, :some_configuration_variable, :some_option
def configuration_object
MyClass.configuration_object
end
end
MyClass.configure do |config|
config.some_configuration_variable = true
config.some_option = :option_a
end
instance = MyClass.new
instance.some_configuration_variable #=> true
instance.some_option #=> :option_a
答案 1 :(得分:1)
幕后发生的事情如下:
Rspec.configure
是一种需要阻止的方法。yield
)传入参数。RSpec::Core::Configuration
答案 2 :(得分:0)
好吧,块(对我来说)是Ruby中最棘手的事情之一,但是当你完全理解它们是如何工作的时候它们也非常强大。
让我们采用最常用的使用块的函数each
:
['a', 'b', 'c'].each do |value|
# do something with value
end
这相当于['a', 'b', 'c'].each(&Proc.new{ |v| print v })
,其中&
是将对象传递给函数的语法,将其标记为可通过yield
调用的块(更多在yield
以后)。所以一个块只是一个Proc
实例(一个匿名函数),因此就像一个对象,就像Ruby中的其他东西一样。
这是数组的each
的基本实现(它不包括你没有传递一个块的情况,因为它对我们来说不是很有趣):< / p>
def each(array)
i = 0
while i < array.size
yield array[i]
i += 1
end
array
end
each( ['a', 'b', 'c'] ) { |v| print v } #=> prints abc , returns array
这里的关键是yield
:正如我们所说,块({ |v| print v }
)是一个Proc
实例,您通常会将它传递给其他函数,通常< strong>执行它,使用yield [args]
调用它。你不是被迫执行它,如果声明为参数,你甚至可以有一个块引用,并按你的意愿使用它:
def puts_block(&block)
puts block
end
puts_block { |v| } #=> #<Proc:0x007f16092b7660@(irb):15>
所以,RSpec.configure
可能是这样实现的:
class RSpec
def self.configure
@config ||= Config.new
block_given? ? yield @config : @config
end
end
block_given?
允许知道函数是否被调用将块传递给它;以这种方式调用Rspec.configure
只返回@config
对象,而RSpec.configure { |c| ... }
将@config
对象传递给您传递给RSpec.configure
的块。
关于Google上的Ruby阻止的更多信息:P