<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>zhlwish (Liang)</title>
    <link>https://ruby-china.org/zhlwish</link>
    <description>关注程序，更关注秩序；思考算法、更思考活法</description>
    <language>en-us</language>
    <item>
      <title>你们公司招聘毕业生都考很多算法么？</title>
      <description>&lt;p&gt;我个人是比较喜欢实践经验比较多的，对于技术上能聊得开的就更好了。但是公司要求面试的时候一定要问一些基础的算法，如平衡二叉树什么之类的，这样导致有过比较多项目经验的同学反而相对比较吃亏，面试到底该考察什么呢？&lt;/p&gt;</description>
      <author>zhlwish</author>
      <pubDate>Mon, 25 Mar 2013 22:11:50 +0800</pubDate>
      <link>https://ruby-china.org/topics/9747</link>
      <guid>https://ruby-china.org/topics/9747</guid>
    </item>
    <item>
      <title>老大们决定用 JRuby on Rails，看看这个版块的冷清，就知道...</title>
      <description>&lt;p&gt;老大们觉得 JRuby 的 gc 好等等，决定上 JRuby on Rails，有没有有经验的同志介绍一下都有些什么坑啊&lt;/p&gt;</description>
      <author>zhlwish</author>
      <pubDate>Thu, 20 Dec 2012 03:13:17 +0800</pubDate>
      <link>https://ruby-china.org/topics/7705</link>
      <guid>https://ruby-china.org/topics/7705</guid>
    </item>
    <item>
      <title>[求助] 社区的编辑器是怎么实现的？</title>
      <description>&lt;p&gt;很喜欢这个支持 markdown 编辑和预览的编辑器，很好奇是怎么实现的，呵呵，希望高手帮忙！&lt;/p&gt;</description>
      <author>zhlwish</author>
      <pubDate>Fri, 02 Nov 2012 15:20:18 +0800</pubDate>
      <link>https://ruby-china.org/topics/6481</link>
      <guid>https://ruby-china.org/topics/6481</guid>
    </item>
    <item>
      <title>Refactoring from Good to Great</title>
      <description>&lt;p&gt;一个视频，在线看估计要翻墙，但是可以下载，值得一看，讲重构的一些经验。&lt;/p&gt;

&lt;p&gt;Most developers know enough about refactoring to write code that's pretty good. They create short methods, and classes with one responsibility. They're also familiar with a good handful of refactorings, and the code smells that motivate them.&lt;/p&gt;

&lt;p&gt;This talk is about the next level of knowledge: the things advanced developers know that let them turn good code into great. Code that's easy to read and a breeze to change.&lt;/p&gt;

&lt;p&gt;These topics will be covered solely by LIVE CODING; no slides. We'll boldly refactor right on stage, and pray the tests stay green. You might even learn some vim tricks as well as an expert user shows you his workflow.&lt;/p&gt;

&lt;p&gt;Topics to cover include: * The Open-Closed Principle * The types of coupling, and their dangers * Why composition is so damn great * A powerful refactoring that Kent Beck refers to as "deep deep magic" * How to destroy conditionals with a NullObject * The beauty of the Decorator pattern * Testing smells, including Mystery Guest and stubbing the system under test * The stuff from the last halves of Refactoring and Clean Code that you never quite got to :) organizers') Obviously, my credibility relies entirely on this talk being awesome, so come ready to laugh, learn, and enjoy yourself.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://confreaks.com/videos/1233-aloharuby2012-refactoring-from-good-to-great" rel="nofollow" target="_blank"&gt;http://confreaks.com/videos/1233-aloharuby2012-refactoring-from-good-to-great&lt;/a&gt;&lt;/p&gt;</description>
      <author>zhlwish</author>
      <pubDate>Fri, 02 Nov 2012 13:29:51 +0800</pubDate>
      <link>https://ruby-china.org/topics/6480</link>
      <guid>https://ruby-china.org/topics/6480</guid>
    </item>
    <item>
      <title>JavaScript Date API</title>
      <description>&lt;p&gt;今天工作中遇到 JavaScript 的 Date 计算和格式化的问题，顺便整理了一下 JavaScript 中的 Date 的相关 API，试做简单记录，有什么不对请大家指正。原文发布在我的博客上：&lt;a href="http://www.zhlwish.com/2012/09/11/javascript-date/" rel="nofollow" target="_blank"&gt;http://www.zhlwish.com/2012/09/11/javascript-date/&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="Date构造函数"&gt;Date 构造函数&lt;/h2&gt;
&lt;p&gt;// 当前时间
    // Tue Sep 11 2012 15:37:46 GMT+0800 (中国标准时间)
    new Date();
    // Fri Jan 02 1970 08:00:00 GMT+0800 (中国标准时间)
    new Date(3600 * 24 * 1000);&lt;/p&gt;

&lt;p&gt;除了构造函数外，&lt;code&gt;Date.UTC()&lt;/code&gt;也用于构造日期，但是并不返回 Date，而是返回从 1970-01-01 开始的毫秒数，比如：&lt;/p&gt;

&lt;p&gt;// 1328054400100, 即 2012-01-01 00:00:00 0100
    Date.UTC(2012, 1, 1, 0, 0, 0, 100);&lt;/p&gt;

&lt;p&gt;需要注意的是，&lt;code&gt;Date()&lt;/code&gt;函数返回日期字符串，比如&lt;/p&gt;

&lt;p&gt;// date 是字符串：'Tue Sep 11 2012 15:34:48 GMT+0800 (中国标准时间)'
    var date = Date(); &lt;/p&gt;
&lt;h2 id="字符串转日期"&gt;字符串转日期&lt;/h2&gt;
&lt;p&gt;Date.parse(string) 方法并&lt;em&gt;不是返回 Date，而是返回整数&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;// 1120752000000, 即 2005-07-08
    Date.parse("Jul 8, 2005");
    Date.parse("2005-07-08");
    Date.parse("2005/07/08");&lt;/p&gt;
&lt;h2 id="日期转字符串"&gt;日期转字符串&lt;/h2&gt;
&lt;p&gt;toString();         // Tue Sep 11 2012 15:09:01 GMT+0800
    toTimeString();     // 15:09:34 GMT+0800 
    toDateString();     // Tue Sep 11 2012 
    toGMTString();      // Tue, 11 Sep 2012 07:10:05 GMT 
    toUTCString();      // Tue, 11 Sep 2012 07:10:17 GMT 
    toLocaleString();   // 2012 年 9 月 11 日 15:10:31 
    toLocaleTimeString();   // 15:10:45 
    toLocaleDateString();   // 2012 年 9 月 11 日 &lt;/p&gt;
&lt;h2 id="Get系列方法"&gt;Get 系列方法&lt;/h2&gt;
&lt;p&gt;Date 提供了一系列 Get 和 Set 方法，可以获取和设置年份、月份、日期、小时等等信息，并且提供了本地时间和 UTC 时间两套方案。本地时间方法如下：&lt;/p&gt;

&lt;p&gt;var date = new Date();
    date.getDate();     // 从 Date 对象返回一个月中的某一天 (1 ~ 31)。
    date.getDay();      // 从 Date 对象返回一周中的某一天 (0 ~ 6)。
    date.getMonth();    // 从 Date 对象返回月份 (0 ~ 11)。
    date.getFullYear(); // 从 Date 对象以四位数字返回年份。不用使用 getYear()。
    date.getHours();    // 返回 Date 对象的小时 (0 ~ 23)。
    date.getMinutes();  // 返回 Date 对象的分钟 (0 ~ 59)。
    date.getSeconds();  // 返回 Date 对象的秒数 (0 ~ 59)。
    date.getMilliseconds(); //返回 Date 对象的毫秒 (0 ~ 999)。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;date.getTime()&lt;/code&gt;方法返回从 1970-01-01 开始到现在的毫秒数&lt;/p&gt;

&lt;p&gt;date.getTime();     // 返回 1970 年 1 月 1 日至今的毫秒数。&lt;/p&gt;

&lt;p&gt;Get 系列获取本地时间的方法和获取 UTC 时间的方法一一对应，如&lt;code&gt;date.getUTCDate();&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="Set系列方法"&gt;Set 系列方法&lt;/h2&gt;
&lt;p&gt;Set 系列方法和 Get 系列方法一一对应，如：&lt;/p&gt;

&lt;p&gt;date.setDate(24);
    date.setUTCDate(24);&lt;/p&gt;

&lt;p&gt;&lt;code&gt;date.setTime(time)&lt;/code&gt;方法以毫秒数设置 Date 对象，和&lt;code&gt;new Date(time)&lt;/code&gt;的作用一样。&lt;/p&gt;
&lt;h2 id="Date之间的计算"&gt;Date 之间的计算&lt;/h2&gt;
&lt;p&gt;Date 之间的计算实际上是毫秒数的计算，加法除外，比如&lt;/p&gt;

&lt;p&gt;// Tue Sep 11 2012 15:40:45 GMT+0800 (中国标准时间)
    var d = new Date();
    // Tue Sep 11 2012 15:40:50 GMT+0800 (中国标准时间)
    var b = new Date();
    // -5781
    console.log(d - b);
    // 'Tue Sep 11 2012 15:40:45 GMT+0800 (中国标准时间)Tue Sep 11 2012 15:40:50 GMT+0800 (中国标准时间)'
    console.log(d + b);
    // 0.999999995709353
    console.log(d / b);
    // 1.8153499959824195e+24
    console.log(d * b);&lt;/p&gt;
&lt;h2 id="Date到字符串的自定义格式转换"&gt;Date 到字符串的自定义格式转换&lt;/h2&gt;
&lt;p&gt;JavaScript 并没有提供像 Ruby 的&lt;code&gt;strftime()&lt;/code&gt;这样的方法，如果需要某种格式的日期字符串只能自己实现。比如下面方法实现将日期转化成&lt;em&gt;yyyy-mm-dd&lt;/em&gt;形式的字符串。&lt;/p&gt;

&lt;p&gt;Date.prototype.toHyphenDateString = function() {
        var year = this.getFullYear();
        var month = this.getMonth() + 1;
        var date = this.getDate();
        if (month &amp;lt; 10) {
            month = "0" + month;
        }
        if (date &amp;lt; 10) {
            date = "0" + date;
        }
        return year + "-" + month + "-" + date;
    };&lt;/p&gt;

&lt;p&gt;var date = new Date();
    // 输出 2012-09-11
    console.log(date.toHyphenDateString());&lt;/p&gt;

&lt;p&gt;如果需要将日期转换为&lt;strong&gt;“3 天之前”&lt;/strong&gt;或者&lt;strong&gt;“4 小时之前”&lt;/strong&gt;这样的字符串，可以使用&lt;a href="http://timeago.yarp.com/" rel="nofollow" target="_blank" title=""&gt;JQuery timeago 插件&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;  &lt;a href="http://www.w3school.com.cn/js/jsref_obj_date.asp" rel="nofollow" target="_blank" title=""&gt;JavaScript Date 对象参考手册&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="http://timeago.yarp.com/" rel="nofollow" target="_blank" title=""&gt;JQuery timeago 插件&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="http://nodejs.org/" rel="nofollow" target="_blank" title=""&gt;Node.js&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>zhlwish</author>
      <pubDate>Tue, 11 Sep 2012 16:25:10 +0800</pubDate>
      <link>https://ruby-china.org/topics/5479</link>
      <guid>https://ruby-china.org/topics/5479</guid>
    </item>
    <item>
      <title>[Rails API] ApplicationController#default_url_options ()</title>
      <description>&lt;p&gt;来自：&lt;a href="http://kan.weibo.com/con/3487676393188469" rel="nofollow" target="_blank"&gt;http://kan.weibo.com/con/3487676393188469&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;在 RoR 应用中写 view 的时候，经常要写这样的代码：&lt;/p&gt;

&lt;p&gt;&amp;lt;%=link_to 'link name', :controller =&amp;gt; 'user' :action =&amp;gt; 'view', :username =&amp;gt; &lt;a href="/user.name" class="user-mention" title="@user.name"&gt;&lt;i&gt;@&lt;/i&gt;user.name&lt;/a&gt;, :param2 =&amp;gt; 'param2' %&amp;gt;&lt;/p&gt;

&lt;p&gt;但是总会遇到所有的链接中都会添加某个参数的情况，比如上面例子中的 username 参数，难道每写一个&lt;code&gt;link_to()&lt;/code&gt;或者&lt;code&gt;url_for()&lt;/code&gt;都需要手动的写上这个参数么？&lt;/p&gt;

&lt;p&gt;当然不，Rails 提供了一种设置全局 URL 参数的方法，只要在你的&lt;code&gt;ApplicationController&lt;/code&gt;中加上&lt;code&gt;default_url_options()&lt;/code&gt;方法就行了，这个方法返回一个 Hash，我们可以在这个 Hash 中加入我们的全局 URL 参数就可以了，比如：&lt;/p&gt;

&lt;p&gt;class ApplicationController &amp;lt; ActionController::Base
        def default_url_options()
            {:user=&amp;gt; &lt;a href="/user.username" class="user-mention" title="@user.username"&gt;&lt;i&gt;@&lt;/i&gt;user.username&lt;/a&gt;}
        end
    end&lt;/p&gt;

&lt;p&gt;这样之后，在 view 中的&lt;code&gt;link_to()&lt;/code&gt;和&lt;code&gt;url_for()&lt;/code&gt;以及其他生成 URL 的方法都会自动加上这个参数。&lt;/p&gt;

&lt;p&gt;详见：&lt;a href="http://guides.rubyonrails.org/action_controller_overview.html#default_url_options" rel="nofollow" target="_blank"&gt;http://guides.rubyonrails.org/action_controller_overview.html#default_url_options&lt;/a&gt;&lt;/p&gt;</description>
      <author>zhlwish</author>
      <pubDate>Fri, 07 Sep 2012 17:36:28 +0800</pubDate>
      <link>https://ruby-china.org/topics/5413</link>
      <guid>https://ruby-china.org/topics/5413</guid>
    </item>
    <item>
      <title>一点点心得: Rack 在 Rails 中的使用</title>
      <description>&lt;p&gt;新手上路，有说得不对的地方请大家指正，嘿嘿，最开始发在我的博客上：&lt;a href="http://www.zhlwish.com/2012/08/01/rails-rack/" rel="nofollow" target="_blank" title=""&gt;Rack 在 Rails 中的使用&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;今天工作中遇到 Rails 的一个问题，最后发现是使用的一个叫 Rack 包版本不兼容 Rails2.3 引起的，虽然问题很容易就解决了，但是 Rack 这个包是干什么的却引发了我的兴趣，经过查资料阅读代码，写了这篇博客。&lt;/p&gt;

&lt;p&gt;Rack 是一个中间件，介于 Web 应用程序和 Web 服务器之间，为所有的 Web 服务器都提供了统一的接口，使用 Rack 构建的 Web 应用程序能简单换到其他的 Web 服务器上，因为 Rails 在底层用到了 Rack，所以我们可以在开发的时候使用 Webrick，然后通过 fastcgi 或者 ruby_mod 发布到 nginx 或者 Apache。&lt;/p&gt;

&lt;p&gt;#Rack 简介&lt;/p&gt;

&lt;p&gt;使用 Rack 构建的应用程序比 Rails 要简单多了，当然，功能也简单多了，只有 request, response, session, logger 等一些基本的组件，不过对于一些简单的应用，足够了。基于 Rack 的 Web 应用太简单了，以至于大家都用一句话来描述：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A Rack application is any Ruby object that responds to the call method, takes a single hash parameter and returns an array containing the response status code, HTTP response headers and the response body as an array of strings.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;意思就是，一个包含&lt;code&gt;call(env)&lt;/code&gt;方法的对象就能做为一个 Rack Web 应用，参数 env 是一个 hash，方法的返回值是一个列表，包含三个元素：HTTP 状态码 (200, 500 等)，HTTP 响应头 (Hash)，HTTP 响应内容 (字符串数组)。&lt;/p&gt;

&lt;p&gt;先安装 rack 和 mongrel&lt;/p&gt;

&lt;p&gt;sudo gem install rack
    sudo gem install mongrel --pre&lt;/p&gt;

&lt;p&gt;下面代码演示了如何创建一个用 Rack 来创建一个 Web 应用，在控制台中执行下面的代码，然后用浏览器访问&lt;a href="http://localhost:3000Hello" rel="nofollow" target="_blank"&gt;http://localhost:3000Hello&lt;/a&gt;，即可看到显示“Rack!”的页面。&lt;/p&gt;

&lt;p&gt;#!/usr/bin/env ruby
    require 'rubygems'
    require 'rack'&lt;/p&gt;

&lt;p&gt;class HelloRack
        def call(env)
            [
                200,
                {"Content-Type" =&amp;gt; "text/html"},
                ["Hello Rack!"]
            ]
        end
    end&lt;/p&gt;

&lt;p&gt;Rack::Handler::Mongrel.run(HelloRack.new, :Port =&amp;gt; 3000)&lt;/p&gt;

&lt;p&gt;我们可以将后端的 Web 服务器 Ruby 标准库中的 WEBrick，只需要将上面代码的最后一行改为：&lt;/p&gt;

&lt;p&gt;Rack::Handler::WEBrick.run(HelloRack.new, :Port =&amp;gt; 3000)&lt;/p&gt;

&lt;p&gt;当然要是 Rack 只能支持对于根路径的响应就没有啥意义了，Rack 还提供了一个称为&lt;a href="http://rack.rubyforge.org/doc/Rack/Builder.html" rel="nofollow" target="_blank" title=""&gt;Rack::Builder&lt;/a&gt;的 API，提供了简单的 DSL，可以定义简单的 URL mapping，使对不同路径的请求由不同的程序来处理，不过，这个和 Rails 暂时无关，有兴趣请阅读&lt;a href="http://m.onkey.org/ruby-on-rack-1-hello-rack" rel="nofollow" target="_blank" title=""&gt;Ruby on Rack #1 - Hello Rack!&lt;/a&gt;和&lt;a href="http://m.onkey.org/ruby-on-rack-2-the-builder" rel="nofollow" target="_blank" title=""&gt;Ruby on Rack #2 - The Builder&lt;/a&gt;，或者&lt;a href="http://blog.ixti.net/development/ruby/2011/09/03/understanding-rack-builder/" rel="nofollow" target="_blank" title=""&gt;Understanding Rack Builder&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rack 还提供一个有意思的东西，叫 rakeup，使得可以将主要的对请求的响应都放在一个名为&lt;code&gt;config.ru&lt;/code&gt;文件中，和 Rails 关系不大，这篇文章可能讲解得更加清楚一些：&lt;a href="http://ruby.about.com/od/rack/a/Using-Rack.htm" rel="nofollow" target="_blank" title=""&gt;Using Rack&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;我目前发现的，真正和 Rails 相关的，是&lt;a href="http://rack.rubyforge.org/doc/classes/Rack/Server.html" rel="nofollow" target="_blank" title=""&gt;Rack::Server&lt;/a&gt; API。下面是一个简单的示例。&lt;/p&gt;

&lt;p&gt;Rack::Server.start(
      :app =&amp;gt; proc {|env| 200, {"Content-Type" =&amp;gt; "text/html"}, ["Hello Rack!"]]},
      :server =&amp;gt; 'webrick',
      :Port =&amp;gt; 3030
    )&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Server#start({})&lt;/code&gt;的参数是一个 Hash，其参数包括&lt;code&gt;:server&lt;/code&gt;, &lt;code&gt;:Host&lt;/code&gt;, &lt;code&gt;:Port&lt;/code&gt;等，其中&lt;code&gt;:config&lt;/code&gt;可以是一个&lt;code&gt;.ru&lt;/code&gt;文件的路径，用于覆盖&lt;code&gt;:app&lt;/code&gt;的配置，比如下面代码，我们从&lt;code&gt;config.ru&lt;/code&gt;中读取处理请求的函数，比如下面的代码。&lt;/p&gt;

&lt;p&gt;Rack::Server.start(
      :config =&amp;gt; 'config.ru'
      :server =&amp;gt; 'webrick',
      :Port =&amp;gt; 3030
    )&lt;/p&gt;

&lt;p&gt;&lt;code&gt;config.ru&lt;/code&gt;的代码如下所示，仅仅一行。&lt;/p&gt;

&lt;p&gt;run proc {|env| [200, {"Content-Type" =&amp;gt; 'text/html'}, ["Hello Rack!"]]}&lt;/p&gt;
&lt;h2 id="Rails中的Rack"&gt;Rails 中的 Rack&lt;/h2&gt;
&lt;p&gt;对 Rails 的分析采用倒推的方式，我们启动 Rails 应用的时候，使用&lt;code&gt;rails server&lt;/code&gt;命令。这个命令会调用&lt;a href="https://github.com/rails/rails/blob/master/railties/lib/rails/commands/server.rb" rel="nofollow" target="_blank" title=""&gt;railties/lib/rails/commands/server.rb&lt;/a&gt;代码，下面是代码的节选。&lt;/p&gt;

&lt;p&gt;module Rails
        class Server &amp;lt; ::Rack::Server
            def start
                # …
                super
            end&lt;/p&gt;

&lt;p&gt;def default_options
                super.merge({
                    :Port        =&amp;gt; 3000,
                    :DoNotReverseLookup =&amp;gt; true,
                    :environment =&amp;gt; (ENV['RAILS_ENV'] || "development").dup,
                    :daemonize   =&amp;gt; false,
                    :debugger    =&amp;gt; false,
                    :pid         =&amp;gt; File.expand_path("tmp/pids/server.pid"),
                    :config      =&amp;gt; File.expand_path("config.ru")
                })
            end
        end
    end&lt;/p&gt;

&lt;p&gt;可以看到，&lt;code&gt;Rails::Server&lt;/code&gt;继承了&lt;code&gt;Rack::Server&lt;/code&gt;，在前一节已经了解到，&lt;code&gt;Rack::Server#start()&lt;/code&gt;方法会启动服务，&lt;code&gt;Rails:Server&lt;/code&gt;覆盖了&lt;code&gt;start()&lt;/code&gt;方法，并且在做了一些处理之后使用&lt;code&gt;super&lt;/code&gt;调用了父类的同名方法，因此调用这个方法同样能启动服务。而且，&lt;code&gt;Rails:Server&lt;/code&gt;也覆盖了父类的&lt;code&gt;default_options()&lt;/code&gt;，这里的&lt;code&gt;super&lt;/code&gt;也表示调用父类的同名方法，其返回值为 Hash，使用&lt;code&gt;Hash#merge()&lt;/code&gt;覆盖了父类的一些配置信息，比如将 Rack 默认的 9292 端口改为 3000，等等。最后是最为关键的配置信息：&lt;code&gt;:config =&amp;gt; File.expand_path("config.ru")&lt;/code&gt;，意味着&lt;code&gt;Rails::Server&lt;/code&gt;会读取从 Rails App 根目录的&lt;code&gt;config.ru&lt;/code&gt;，然后交给 Rack 执行。&lt;/p&gt;

&lt;p&gt;在 Rails App 的根目录下面找到&lt;code&gt;config.ru&lt;/code&gt;，里面一如既往的简单，只有两条语句：&lt;/p&gt;

&lt;p&gt;require ::File.expand_path('../config/environment',  &lt;strong&gt;FILE&lt;/strong&gt;)
    run AppName::Application&lt;/p&gt;

&lt;p&gt;第一句是加载&lt;code&gt;config/environment.rb&lt;/code&gt;，第二句和前一节的最后一段的代码非常相似，我们现在可以勇敢地猜测，&lt;code&gt;AppName::Application&lt;/code&gt;中肯定定义了&lt;code&gt;call(env)&lt;/code&gt;方法。&lt;/p&gt;

&lt;p&gt;Rails3 的&lt;code&gt;config/environment.rb&lt;/code&gt;文件也很简单，第一句加载相同目录下的&lt;code&gt;application.rb&lt;/code&gt;，第二句调用了&lt;code&gt;AppName::Application&lt;/code&gt;的&lt;code&gt;initialize!()&lt;/code&gt;方法。(注意，Rails2 的启动流程不一样)。&lt;/p&gt;

&lt;p&gt;require File.expand_path('../application', &lt;strong&gt;FILE&lt;/strong&gt;)
    AppName::Application.initialize!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;config/application.rb&lt;/code&gt;还是的定义依然很简单，继承了&lt;code&gt;Rails::Application&lt;/code&gt;，仅仅做了一些配置工作，比如禁止在 log 文件中记录&lt;code&gt;:password&lt;/code&gt;，启用 Rails3 新引入的 SASS 和 Coffie Script。&lt;/p&gt;

&lt;p&gt;module AppName
        class Application &amp;lt; Rails::Application
            config.encoding = "utf-8"
            config.filter_parameters += [:password]
            config.active_record.whitelist_attributes = true
            config.assets.enable = true
            config.assets.version = '1.0'
        end
    end&lt;/p&gt;

&lt;p&gt;因此，进一步找到&lt;a href="https://github.com/rails/rails/blob/master/railties/lib/rails/application.rb" rel="nofollow" target="_blank" title=""&gt;railties/lib/rails/application.rb&lt;/a&gt;，这个文件定义了&lt;code&gt;Rails::Application&lt;/code&gt;，而且终于看到了我们预测中的&lt;code&gt;call(env)&lt;/code&gt;。当然，除此意外 Rails 做的更多，比如定义了&lt;a href="https://github.com/rails/rails/blob/master/railties/lib/rails/rack/logger.rb" rel="nofollow" target="_blank" title=""&gt;Rails::Rack::Logger&lt;/a&gt;用来替代 Rack 自身的日志系统。&lt;/p&gt;

&lt;p&gt;module Rails
        class Application &amp;lt; Engine
            def call(env)
                env["ORIGINAL_FULLPATH"] = build_original_fullpath(env)
                super(env)
            end
        end
    end&lt;/p&gt;

&lt;p&gt;另外，&lt;code&gt;Rails::Application&lt;/code&gt;的父类&lt;a href="https://github.com/rails/rails/blob/master/railties/lib/rails/engine.rb" rel="nofollow" target="_blank" title=""&gt;Rails::Engine&lt;/a&gt;是 Rails 的启动配置的核心所在，一次加载了 config/routes.rb、app/views 等信息。&lt;/p&gt;

&lt;p&gt;#总结&lt;/p&gt;

&lt;p&gt;总的来说，Rails 首先加载了&lt;code&gt;config/application.rb&lt;/code&gt;中定义了&lt;code&gt;AppName::Application&lt;/code&gt;，然后调用其&lt;code&gt;initialize!()&lt;/code&gt;方法执行一些初始化工作，最后使用 Rack 的&lt;code&gt;run AppName::Application&lt;/code&gt;运行整个应用程序。Rails 也通过 Rack 可以很方便的部署于 Apache、nginx、lighttpd 等各种服务器，包括 Ruby 自带的 Webrick，以及 mongrel 等。要更深入的了解 Rack 需要进一步阅读参考中的链接。&lt;/p&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://ruby.about.com/od/rack/a/What-Is-Rack.htm" rel="nofollow" target="_blank" title=""&gt;What's Rack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://ruby.about.com/od/rack/a/Using-Rack.htm" rel="nofollow" target="_blank" title=""&gt;Using Rack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://chneukirchen.org/blog/archive/2007/02/introducing-rack.html" rel="nofollow" target="_blank" title=""&gt;Introducing Rack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://rack.rubyforge.org/doc/SPEC.html" rel="nofollow" target="_blank" title=""&gt;Rake Spec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://m.onkey.org/ruby-on-rack-1-hello-rack" rel="nofollow" target="_blank" title=""&gt;Ruby on Rack, Hello Rack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://m.onkey.org/ruby-on-rack-2-the-builder" rel="nofollow" target="_blank" title=""&gt;Ruby on Rack, The builder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.ixti.net/development/ruby/2011/09/03/understanding-rack-builder/" rel="nofollow" target="_blank" title=""&gt;Understanding Rack Builder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://rack.rubyforge.org/doc/" rel="nofollow" target="_blank" title=""&gt;rack doc&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>zhlwish</author>
      <pubDate>Thu, 09 Aug 2012 21:11:42 +0800</pubDate>
      <link>https://ruby-china.org/topics/4840</link>
      <guid>https://ruby-china.org/topics/4840</guid>
    </item>
  </channel>
</rss>
