打破一些从Rails中获取的Ruby代码

时间:2010-03-04 21:40:10

标签: ruby-on-rails ruby

有人能够在方法,参数,块解释等方面分解每个这些语句所包含的Ruby细节。这在Rails代码中很常见,我试图理解如何Ruby解释器读取此代码:

respond_to do |format|
  format.xml { render :layout => false }
end

据我了解,respond_to是一个为其提供一个参数的方法,即块。所以我猜它写的是:

def respond_to(&block)
    block.call
end

..或类似的东西?

在块本身中,格式是对象respond_to传递到块中,xml是请求设置的对象,此时如果请求要求XML类型数据并且继续调用它,它会调用块本身一个render方法,传递一个基于关键字的参数,:layout =>假?

有人会清理我对它们如何运作的理解。这种类型的代码遍布Rails,在使用它之前我想先了解它。

4 个答案:

答案 0 :(得分:1)

这是Ruby中内部DSL的典型实现模式:您向块生成一个对象,然后该块接受新的方法调用和块,从而引导接口。 (实际上,它在Java中也很常见,它用于为内部DSL获取有意义的代码完成。)

以下是一个例子:

def respond_to
  yield FormatProxy.new(@responders ||= {})
end

class FormatProxy
  def initialize(responders)
    @responders = responders
  end

  def method_missing(msg, *args, &block)
    @responders[msg] = [args, block]
  end
end

现在,您可以将格式映射到@responders中存储的可执行代码段,您可以稍后在不同的地方调用它,无论何时,无论何时,无论何时,您都需要:

respond_to do |f|
  f.myformat { puts 'My cool format' }
  f.myotherformat { puts 'The other' }
end

@responders[:myformat].last.call # => My cool format
@responders[:myotherformat].last.call # => The other

正如我在上面所暗示的,如果不使用仅使用method_missing的哑代理对象,而是使用具有最重要方法的代理对象(xmlhtml,{ {1}},jsonrss等预定义,一个足够智能的IDE甚至可以为您提供有意义的代码完成。

注意:我完全不知道这是否是如何在Rails中实现的,但无论如何实现,它可能是一些变体。

答案 1 :(得分:1)

你基本上已经掌握了它,源代码足够可读,可以弄清楚发生了什么。如果你想采取类似这样的潜水,只需要几个步骤。

1。弄清楚Rails在哪里。

$ gem environment

RubyGems Environment:
  - RUBYGEMS VERSION: 1.3.5
  - RUBY VERSION: 1.8.7 (2009-06-12 patchlevel 174) [i686-darwin9.8.0]
  - INSTALLATION DIRECTORY: /opt/ruby-enterprise-1.8.7-2009.10/lib/ruby/gems/1.8
  ...

2。找出代码在Rails中的位置。

$ cd /opt/ruby-enterprise-1.8.7-2009.10/lib/ruby/gems/1.8/gems  # installation directory from above + "/gems"

$ ack "def respond_to"

...
actionpack-2.3.5/lib/action_controller/mime_responds.rb
102:      def respond_to(*types, &block)
...

3。潜入。

$ vim actionpack-2.3.5/lib/action_controller/mime_responds.rb

答案 2 :(得分:0)

如果您有这样的问题或不确定如何工作,最好的方法是找到它(在Ruby中非常易读)。

对于这个特定问题,您可以转到mime_respond.rb。第187行ATM。

评论解释说:

# Here's the same action, with web-service support baked in:
#
#   def index
#     @people = Person.find(:all)
#
#     respond_to do |format|
#       format.html
#       format.xml { render :xml => @people.to_xml }
#     end
#   end
#
# What that says is, "if the client wants HTML in response to this action, just respond as we
# would have before, but if the client wants XML, return them the list of people in XML format."
# (Rails determines the desired response format from the HTTP Accept header submitted by the client.)

此外respond_to采用块或MIME类型来响应。

我真的建议看看那里的代码 评论非常全面。

答案 3 :(得分:0)

def respond_to(&block)
    block.call
end

这是带有一个参数的方法的定义。 &告诉解释器,当我们要以块do ... end形式respond_to do puts 1 end调用方法时,也可以给出参数。此参数也可以是响应调用metod的任何对象(如Proc或lambda):
a = lambda{ puts 1 }; respond_to(a)

respond_to do |format|
   format.xml { render :layout => false }
end

这使用一个参数respond_to块调用do ... end方法。在第二个respond_to方法的实现中,此块的调用类似于以下内容:

def respond_to(&block)
    block.call(@format) # or yield @format
end

所以为了符合1参数调用,我们的代码块也必须接受1个参数,它在do ... end' syntax is given between the bars |格式|`