ruby - 通过 Web 公开任何 Ruby 对象

标签 ruby

谁能解释一下下面的 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/

相关文章:

ruby - Middleman & Haml 与 Github 风格的围栏代码块

ruby-on-rails - 如何从控制台调用Rails的模型实例方法

ruby-on-rails - Ransack Gem Rails 和多选

ruby-on-rails - 有什么方法可以让 rack-livereload 运行得更快?

ruby-on-rails - 为什么人们大多包装 I18n.t 方法而不是委托(delegate)?

ruby-on-rails - Nginx 和 Passenger 用户权限。最佳实践?

ruby - 动态交换 Rails3 布局

ruby - 如何使用 GridFS 上传文件并将其直接保存到 MongoDB

Ruby - 将字符映射到二维数组中的整数

ruby-on-rails - 在这种情况下 OAuth 是否矫枉过正?