How rackup works

  “rack是一个最简化的web application标准”,这句话在很多资料里面见到过很多次,并且都会给出一个5行代码的例子,然后一个web application华丽丽的就起来了。确实比较简单,看看这个一页纸的specification就知道了。但是看了很多次之后还是没有什么感觉,一个简单的specification当然不能帮助你启动程序,需要的是它的实现,而且rack只是application的标准,还需要第三方的web server作为支持。还好rack这个gem帮我们实现了这个specification和相关的一些功能,并且打包了常用的web server,比如webrick和thin。最后还提供了一个命令行工具:rackup。

  看一个rack gem里面提供的rackup的例子:

// lobster.ru

require 'rack/lobster'

use Rack::ShowExceptions
run Rack::Lobster.new

  然后调用rackup lobster.ru就可以了。其中使用到了use和run这样的DSL,那么这些DSL是怎么实现的,rackup的过程是如何发生的呢,且看我慢慢道来吧。

  先看看rackup这个可执行文件:

// rackup

1 #!/usr/bin/env ruby
2 
3 require "rack"
4 Rack::Server.start

  恩~没什么特别的,看看Rack::Server里面做了什么

// server.rb

 1 require 'optparse'
 2 
 3 module Rack
 4   class Server
 5     ...
 6     def self.start(options = nil)
 7       new(options).start
 8     end
 9     ...
10   end
11 end

  OK,又代理到了实例方法start

1 def start &blk
2   #一些parse参数的代码
3   wrapped_app
4 
5   daemonize_app if options[:daemonize]
6   ...
7 
8   server.run wrapped_app, options, &blk
9 end

  恩~,这里的warped_app是用来生成我们的rack app的核心代码

1 def wrapped_app
2     @wrapped_app ||= build_app app
3 end

  又引出了build_app和app这两个函数,先看app

 1 def app
 2   @app ||= begin
 3     if !::File.exist? options[:config]
 4       abort "configuration #{options[:config]} not found"
 5     end
 6 
 7     app, options = Rack::Builder.parse_file(self.options[:config], opt_parser)
 8     self.options.merge! options
 9     app
10   end
11 end

  重点来了,options这个函数把命令行中传入的lobster.ru这个文件放到了options[:config]以供使用。然后再使用Rack::Builder.parse_file这个方法来解析ru配置文件。

 1 def self.parse_file(config, opts = Server::Options.new)
 2   options = {}
 3   if config =~ /\.ru$/
 4     cfgfile = ::File.read(config)
 5     #对cfgfile做点处理
 6     app = eval "Rack::Builder.new {\n" + cfgfile + "\n}.to_app",
 7       TOPLEVEL_BINDING, config
 8   else
 9     #这种情况下config文件只是定义了一个rack app的类
10     require config
11     app = Object.const_get(::File.basename(config, '.rb').capitalize)
12   end
13   return app, options
14 end

  there you go,第6行使用了eval来把ru配置文件里面的那些代码在一个Rack::Builder的实例的上下文中执行,于是Rack::Builder中定义的方法run,use就都可用了。use是用来添加middleware,run应该是用来启动程序了吧?其实不是。。真正启动server的代码在上面列出来了,就是在Server的实例方法start的最后一行。顺便说一句,第6行的那个to_app还提供了url mapping的功能,不过还没仔细看。

  后面的代码就不再赘述了。大概说下,就是在构造好了rack app上添加middleware,然后使用default的web server来运行它。

  最后给个链接,里面给出了很多rack相关的链接,很是不错:http://jasonseifer.com/2009/04/08/32-rack-resources-to-get-you-started

原文地址:https://www.cnblogs.com/cuiliqiang/p/2499937.html