Ruby on rails 带参数的Ruby块

Ruby on rails 带参数的Ruby块,ruby-on-rails,ruby,Ruby On Rails,Ruby,我正在读一本很有说服力的Ruby书(到目前为止,这本书非常棒),但我不明白有哪一节谈到了blocs、params和scope。这是密码 class SomeApplication # Rest of the class omitted... def do_something with_logging('load', nil) { @doc = Document.load( 'book' ) } # Do something with the document...

我正在读一本很有说服力的Ruby书(到目前为止,这本书非常棒),但我不明白有哪一节谈到了blocs、params和scope。这是密码

class SomeApplication
# Rest of the class omitted...
  def do_something 
    with_logging('load', nil) { @doc = Document.load( 'book' ) }

    # Do something with the document...

    with_logging('save', @doc) { |the_object| the_object.save } 
  end

  def with_logging(description, the_object) 
    begin
      @logger.debug( "Starting #{description}" )
      yield( the_object )
      @logger.debug( "Completed #{description}" ) 
    rescue
      @logger.error( "#{description} failed!!")
      raise 
    end
  end 
end
这本书说,代码比需要的更复杂,因为@doc在代码块中自动可见。所以没有必要把它作为一个论点来传递

我不明白他说的是哪个参数,@doc还是
| u对象|
。更改此代码以消除不必要的复杂性后,此代码会是什么样子

或者这是否意味着在
中创建的@doc(带有日志记录('load',nil)
仍然可见?即使是这样,我也不确定底部带有_logging的
方法如何访问它。

它是一个实例变量(由@表示),因此在整个类中,在任何方法中都可用。

块(和lambdas/procs)是闭包。这意味着它们可以访问创建它们的环境中的任何变量
@doc
是一个实例变量,因此它总是在类上下文中的作用域中
@doc
是绑定到\u对象的值,这是不必要的。修订后的守则如下:

class SomeApplication
  # Rest of the class omitted...
  def do_something 
    with_logging('load') { @doc = Document.load( 'book' ) }

    # Do something with the document...

    with_logging('save') { @doc.save } 
  end

  def with_logging(description) 
    begin
      @logger.debug( "Starting #{description}" )
      yield
      @logger.debug( "Completed #{description}" ) 
    rescue
      @logger.error( "#{description} failed!!")
      raise 
    end
  end 
end
@doc
是一个。它是在对象范围内定义的(在本例中,是类
SomeApplication
的实例),通常用于存储“属于”该实例的值。实例变量始终可用于对象的实例方法。它们在对象外部不可用,除非将它们设置为属性

你的困惑是:这个例子可能源于作者将值从方法
do\u something
传递到方法
的迂回方式。调用带有日志记录的
时,它会收到两个参数,
'save'
@doc
。在带有日志记录的
中,局部变量
description
被设置为
'save'
,而局部变量
对象
被设置为
@doc
。然后用参数
调用
yield
,将
对象
传递到第二次调用
时定义的代码块,并使用\u logging
,可以将其视为某种匿名函数。但当然,正如作者所指出的,
@doc
在第一次调用
时就已经设置好了,因此没有必要将其作为参数传递。他可以将第二个函数调用编写为:

with_logging('save') { @doc.save }
第一个是:

with_logging('load') { @doc = Document.load('book') }
然后调用
yield
,不带任何参数,效果相同