在Web上公开任何Ruby对象

Rub*_*ist 4 ruby

有人可以解释下面的Ruby代码是如何工作的吗?(取自要点:675667)

require 'rubygems'
require 'rack'

class Object
  def webapp
    class << self
       define_method :call do |env|
         func, *attrs = env['PATH_INFO'].split('/').reject(&:empty?)
         [200, {}, [send(func, *attrs).to_s]]
       end
    end
    self
  end
end

Rack::Handler::Mongrel.run [].webapp, :Port => 9292
#                         ^^^^^^^^^^^
#                              |          (x)
#                         ROFLSCALE DB ---/
#
Run Code Online (Sandbox Code Playgroud)

如果我们运行它,我们可以通过Web访问它:

GET http://localhost:9292/push/1  -> 1
GET http://localhost:9292/push/2  -> 12
GET http://localhost:9292/push/3  -> 123
GET http://localhost:9292/to_a    -> 123
GET http://localhost:9292/pop     -> 3
GET http://localhost:9292/shift   -> 1
Run Code Online (Sandbox Code Playgroud)

当然,我们可以运行如下:

GET http://localhost:9292/instance_eval/exec("rm -rf /")
Run Code Online (Sandbox Code Playgroud)

无论如何......它是如何工作的?你能逐步指导我完成代码吗?

tro*_*skn 11

该类Object是Ruby中所有对象的基类.webapp在此定义了一个新方法,使其可以对所有对象进行调用.

在调用时webapp,在self.define_method对象类上调用该方法(但仅针对该特定对象 - 顺便说一下,这称为元类).这call为其实例定义了一个新方法(例如,对象).

这个新call方法env作为参数,并PATH_INFO通过正斜杠和存储在数组中进行拆分.然后将第一个元素分配给变量func,将余数分配给变量attrs.然后send调用magic方法,它基本上通过变量的名称调用方法func.然后它返回一个数组,由一个状态代码(200),一个空哈希和方法调用的输出组成.

在最后一行,创建一个新的数组实例([]是简写Array.new).然后在其webapp上调用该call方法,如上所述,该方法用该方法对其进行了丰富.webapp方便回报self.因此,您可以将其直接传递给它Rack::Handler::Mongrel.run,这将启动Web服务器(Mongrel是Web服务器 - Rack是一个抽象层,为不同的Web服务器提供统一的接口).服务器将请求传递给call方法,并解释返回值以发回响应.