有人能够在方法,参数,块解释等方面分解每个这些语句所包含的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,在使用它之前我想先了解它。
答案 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
的哑代理对象,而是使用具有最重要方法的代理对象(xml
,html
,{ {1}},json
,rss
等预定义,一个足够智能的IDE甚至可以为您提供有意义的代码完成。
注意:我完全不知道这是否是如何在Rails中实现的,但无论如何实现,它可能是一些变体。
答案 1 :(得分:1)
你基本上已经掌握了它,源代码足够可读,可以弄清楚发生了什么。如果你想采取类似这样的潜水,只需要几个步骤。
$ 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
...
$ 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)
...
$ 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
|格式|`