zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    POJ 3258 (NOIP2015 D2T1跳石头)
    POJ 3122 二分
    POJ 3104 二分
    POJ 1995 快速幂
    409. Longest Palindrome
    389. Find the Difference
    381. Insert Delete GetRandom O(1)
    380. Insert Delete GetRandom O(1)
    355. Design Twitter
    347. Top K Frequent Elements (sort map)
  • 原文地址:https://www.cnblogs.com/cuiliqiang/p/2499937.html
Copyright © 2011-2022 走看看