谁能解释一下下面的 Ruby 代码是如何工作的? (取自gist: 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 ---/
#
如果我们运行它,我们可以通过 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
当然,我们可以这样运行:
GET http://localhost:9292/instance_eval/exec("rm -rf /")
无论如何...它是如何工作的?你能逐步指导我完成代码吗?
最佳答案
Object
类是 Ruby 中所有对象的基类。在此之上定义了一个新方法 webapp
,这使得它可以被所有对象调用。
当调用 webapp
时,方法 self.define_method
在对象类上被调用(但仅针对那个特定的对象 - 顺便说一句,这叫做 meta-class ).这为其实例(例如对象)定义了一个新方法 call
。
这个新的 call
方法将 env
作为参数并通过正斜杠拆分 PATH_INFO
并存储在数组中。然后将第一个元素分配给变量 func
,将其余元素分配给变量 attrs
。然后调用魔术方法send
,它基本上通过变量func
的名称调用方法。然后它返回一个数组,其中包含一个状态代码 (200)、一个空哈希和方法调用的输出。
在最后一行,创建了一个新的数组实例([]
是 Array.new
的简写)。然后调用 webapp
方法,用 call
方法丰富它,如上所述。 webapp
方便地返回 self
。所以你可以直接将它传递给 Rack::Handler::Mongrel.run
,它将启动一个网络服务器(Mongrel 是网络服务器 - Rack 是一个抽象层,它为不同的网络服务器提供统一的界面)。服务器将请求传递给 call
方法,并解释返回值以发送回响应。
关于ruby - 通过 Web 公开任何 Ruby 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4198883/