<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>suffering (zhubo)</title>
    <link>https://ruby-china.org/suffering</link>
    <description>我爱爱我的人，我恨恨我的人。</description>
    <language>en-us</language>
    <item>
      <title>Rails 项目 Gem 依赖的社交关系网络关系图及其生成</title>
      <description>&lt;p&gt;自己做的小玩具，以及做小玩具的思路:).&lt;/p&gt;
&lt;h2 id="WHAT"&gt;WHAT&lt;/h2&gt;&lt;h3 id="Rails 4.2.1 初始化项目gem依赖关系图:"&gt;Rails 4.2.1 初始化项目 gem 依赖关系图：&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/5fbf7033265d563de19ad416bb04cd71.png" title="" alt=""&gt;
原图 (上传至 ruby-china.org 的图会被压缩): &lt;a href="http://gemrelationship.zhuboliu.me/gem_relationship.png" rel="nofollow" target="_blank"&gt;http://gemrelationship.zhuboliu.me/gem_relationship.png&lt;/a&gt;
(帖出来后才发现这张图神似欧亚大陆，连澳大利亚都有~)&lt;/p&gt;
&lt;h2 id="WHY?"&gt;WHY?&lt;/h2&gt;
&lt;p&gt;在阅读 Rails 源码时，我脑子里总是冒出这样的念头:"卧操！这是什么鬼!?这方法是哪里来的!? 自定义的!? 来自父类!? 来自 include/extend 的模块!? 来自第三方 gem!? 哪一个？". 如果是项目内引用定义的，倒是很好查找。但是，如果是来自第三方项目，那来自哪些？这样的阅读体验无疑让人很痛苦。&lt;/p&gt;

&lt;p&gt;换个思路，用社交关系网络的概念来生成图，让各种依赖关系一目了然。&lt;/p&gt;
&lt;h2 id="IDEAS"&gt;IDEAS&lt;/h2&gt;
&lt;p&gt;rails 依赖许多 gem. 现在，rails 的主要模块本身就被拆成了数个独立的 gem. 我们可以理解为 rails 依赖这些 gem. 同时，这些 gem 又依赖于其他的 gem. 拨出萝卜带出泥，不胜期烦。&lt;/p&gt;

&lt;p&gt;从社交关系的角度来看问题，我们作如下两点设定：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;一个项目是一个社交圈&lt;/li&gt;
&lt;li&gt;项目中运行的每一个 gem, 即为圈子内的一个独立的用户。&lt;/li&gt;
&lt;li&gt;如果 gemA 依赖于 gemB , 即 gemA 关注了 gemB, 换而言之 gemA 是 gemB 的粉丝。即画一个 gemA 指向 gemB 的有向箭头指向。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;最终生成的图，通过看线条与箭头，我们可以清楚地看到哪些 Gem 受欢迎 (大批的粉丝).&lt;/p&gt;

&lt;p&gt;有了思路，接下来就要考虑如何实现的问题了。&lt;/p&gt;
&lt;h2 id="HOW?"&gt;HOW?&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;用户 (gem) 列表数据，即图内的节点。&lt;/li&gt;
&lt;li&gt;用户 (gem) 关系数据，即节点间的有向线段。&lt;/li&gt;
&lt;li&gt;数据可视化方案。即展示方案，或者说绘图方案。错综复杂的关系如何布局与绘图非常重要。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;问题 1 和问题 2 很简单，项目内通过&lt;code&gt;bundle install&lt;/code&gt;生成的&lt;code&gt;Gemfile.lock&lt;/code&gt;提供了所有的节点与关系。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is important: the Gemfile.lock makes your application a single package of both your own code and the third-party code it ran the last time you know for sure that everything worked. Specifying exact versions of the third-party code you depend on in your Gemfile would not provide the same guarantee, because gems usually declare a range of versions for their dependencies.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;问题 3, 通过网络搜索，发现&lt;a href="http://graphviz.org/" rel="nofollow" target="_blank" title=""&gt;Graphviz&lt;/a&gt;(Graph Visualization Software) 可以很好地解决这个问题。&lt;/p&gt;
&lt;h3 id="取数据, 生成Graphviz有效的文件"&gt;取数据，生成 Graphviz 有效的文件&lt;/h3&gt;
&lt;p&gt;创建一个 Rails 原生项目，不添加任何其他 Gem.&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;to/your/path
&lt;span class="c"&gt;# rails 4.2.1&lt;/span&gt;
rails new rgraph
&lt;span class="nb"&gt;cd &lt;/span&gt;graph
bundle &lt;span class="nb"&gt;install
touch &lt;/span&gt;graph.rb
&lt;span class="c"&gt;# edit graph.rb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;分析&lt;code&gt;Gemfile.lock&lt;/code&gt;文件，生成&lt;code&gt;gem_relationshop.gv&lt;/code&gt;文件。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# rails/app/root/path/graph.rb&lt;/span&gt;
&lt;span class="n"&gt;src_box&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'gem_relationship.gv'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'w'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"digraph G {"&lt;/span&gt;
  &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Gemfile.lock"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="c1"&gt;# 通过缩进来判断指向关系.&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/^( {2,})([a-zA-Z0-9_-]+)/&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vg"&gt;$1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="vg"&gt;$1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
      &lt;span class="vi"&gt;@src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vg"&gt;$2&lt;/span&gt;
      &lt;span class="n"&gt;src_box&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="vi"&gt;@src&lt;/span&gt;
    &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="vg"&gt;$1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="vg"&gt;$1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
      &lt;span class="vi"&gt;@target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vg"&gt;$2&lt;/span&gt;
      &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="vi"&gt;@src&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"  &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@src&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; -&amp;gt; &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"}"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行 script 生成源文件：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ruby graph.rb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行 graphviz 相关命令生成图：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 系统内必须装好 Graphviz.&lt;/span&gt;
dot &lt;span class="nt"&gt;-Tpng&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; ./gem_relationship.png ./gem_relationship.gv
&lt;span class="c"&gt;# open gem_relationship.png&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Done!&lt;/p&gt;
&lt;h3 id="再来一个 web 版的吧."&gt;再来一个 web 版的吧。&lt;/h3&gt;
&lt;p&gt;google 的结果是&lt;a href="http://arborjs.org/" rel="nofollow" target="_blank" title=""&gt;arborjs&lt;/a&gt;勉强可以干这事儿，而且&lt;code&gt;arborjs&lt;/code&gt;语法类似&lt;code&gt;Graphviz&lt;/code&gt;的语法.
使用源码中的 demo，复制一份 json 文件，将生成的&lt;code&gt;.gv&lt;/code&gt;的主内容帖进，hack 一下，测试，发布：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/b623bc515cb9b8c0c2730b809f8dc29b.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;在线演示地址：&lt;a href="http://gemrelationship.zhuboliu.me" rel="nofollow" target="_blank"&gt;http://gemrelationship.zhuboliu.me&lt;/a&gt;
在线站点支持节点拖曳。支持在线编辑，可以考虑直接在项目要目录下生成的文件帖到右边的框内，实时生成关系图。&lt;/p&gt;

&lt;p&gt;如果你需要使用此演示站的功能生成自己的 ruby 项目，请确保项目使用&lt;code&gt;bundler&lt;/code&gt;且&lt;code&gt;Gemfile.lock&lt;/code&gt;存在。&lt;/p&gt;

&lt;p&gt;站点实时生成关系图的数据的代码略有不同，如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;css_box&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%W{NAVY BLUE AQUA TEAL OLIVE GREEN LIME ORANGE RED MAROON FUCHSIA PURPLE BLACK GRAY SILVER}&lt;/span&gt;
&lt;span class="n"&gt;src_box&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'gem_relationship.gv'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'w'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="c1"&gt;# t.puts "digraph G {"&lt;/span&gt;
  &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Gemfile.lock"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="c1"&gt;# 通过缩进来判断指向关系.&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/^( {2,})([a-zA-Z0-9_-]+)/&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vg"&gt;$1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="vg"&gt;$1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
      &lt;span class="vi"&gt;@src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vg"&gt;$2&lt;/span&gt;
      &lt;span class="n"&gt;src_box&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="vi"&gt;@src&lt;/span&gt;
    &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="vg"&gt;$1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="vg"&gt;$1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
      &lt;span class="vi"&gt;@target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vg"&gt;$2&lt;/span&gt;
      &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="vi"&gt;@src&lt;/span&gt;
      &lt;span class="c1"&gt;# t.puts "  \"#{@src}\" -&amp;gt; \"#{@target}\""&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@src&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; -&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="c1"&gt;# t.puts "}"&lt;/span&gt;
  &lt;span class="c1"&gt;# 随机生成色彩.&lt;/span&gt;
  &lt;span class="n"&gt;src_box&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; {color:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;css_box&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shuffle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;}"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;注意：不要帖入大型项目的关系数据，节点太多，结果会很难看。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="看图说话"&gt;看图说话&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;railtie&lt;/code&gt;, &lt;code&gt;activesupport&lt;/code&gt;, &lt;code&gt;activepack&lt;/code&gt;, &lt;code&gt;rack&lt;/code&gt;是真正的大 V, 粉丝无数，若要阅读 Rails 源码，从了解它们开始吧。&lt;/p&gt;

&lt;p&gt;附上一张个人的小项目 (引入第三方 gem 若干) 的图:
&lt;img src="https://l.ruby-china.com/photo/2015/dc6129390524397fcd1bf82c02532d35.png" title="" alt=""&gt;
原图地址：&lt;a href="http://gemrelationship.zhuboliu.me/color.png" rel="nofollow" target="_blank"&gt;http://gemrelationship.zhuboliu.me/color.png&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="后续开发意见征集"&gt;后续开发意见征集&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;有必要做成一个 gem 吗？添加 command line, 在 ruby 项目下运行即直接生成相应关系图。&lt;/li&gt;
&lt;li&gt;或者，做成 engine, 在开发模式下，随时可能通过链接进入到一个页面看到指向关系图？类似&lt;a href="http://localhost:3000/rails/info" rel="nofollow" target="_blank"&gt;http://localhost:3000/rails/info&lt;/a&gt;的功能。&lt;/li&gt;
&lt;li&gt;在前两者的基础上做些 option 定制，可以手动选定中心结点？或者为结点加上链接，可直接点到相应 gem 的官方文档页去？&lt;/li&gt;
&lt;li&gt;其他&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;请有好的意见 &lt;a href="/suffering" class="user-mention" title="@suffering"&gt;&lt;i&gt;@&lt;/i&gt;suffering&lt;/a&gt;, 谢谢。&lt;/p&gt;
&lt;h2 id="参考资料"&gt;参考资料&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://bundler.io/v1.7/rationale.html#checking-your-code-into-version-control" rel="nofollow" target="_blank"&gt;http://bundler.io/v1.7/rationale.html#checking-your-code-into-version-control&lt;/a&gt;
&lt;a href="http://www.graphviz.org/" rel="nofollow" target="_blank"&gt;http://www.graphviz.org/&lt;/a&gt;
&lt;a href="http://arborjs.org/" rel="nofollow" target="_blank"&gt;http://arborjs.org/&lt;/a&gt;
&lt;a href="http://arborjs.org/docs/barnes-hut" rel="nofollow" target="_blank"&gt;http://arborjs.org/docs/barnes-hut&lt;/a&gt;
&lt;a href="http://getspringy.com/" rel="nofollow" target="_blank"&gt;http://getspringy.com/&lt;/a&gt;&lt;/p&gt;</description>
      <author>suffering</author>
      <pubDate>Wed, 15 Jul 2015 18:26:27 +0800</pubDate>
      <link>https://ruby-china.org/topics/26502</link>
      <guid>https://ruby-china.org/topics/26502</guid>
    </item>
    <item>
      <title>why no windows</title>
      <description>&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/c428d8afaaeb5706887c55f189834494.jpeg" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>suffering</author>
      <pubDate>Thu, 18 Jun 2015 16:21:34 +0800</pubDate>
      <link>https://ruby-china.org/topics/26092</link>
      <guid>https://ruby-china.org/topics/26092</guid>
    </item>
    <item>
      <title>初步深入 Rack (一)</title>
      <description>&lt;p&gt;前段时间写了篇文章&lt;a href="https://ruby-china.org/topics/21517" title=""&gt;&amp;lt;为什么我们需要 Rack?&amp;gt;&lt;/a&gt;, 再过段时间，对 rack 一直都是一个知其然，不知道其所以然的状态。最近从源码读起，这里与大家分享一下.
注意：本帖前半段极其无聊，请大家注意。&lt;/p&gt;
&lt;h2 id="Rack项目的知其然"&gt;Rack 项目的知其然&lt;/h2&gt;
&lt;p&gt;首先，创建&lt;code&gt;config.ru&lt;/code&gt;. 这里直接引用前文的例子。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#config.ru&lt;/span&gt;
&lt;span class="c1"&gt;# 将 body 标签的内容转换为全大写.&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ToUpper&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@app.call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;upcased_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upcase&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;upcased_body&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="c1"&gt;# 将 body 内容置于标签, 设置字体颜色为红色, 并指明返回的内容为 text/html.&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WrapWithRedP&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@app.call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;red_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;p style='color:red;'&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/p&amp;gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Content-type'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'text/html'&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;red_body&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# 将 body 内容放置到 HTML 文档中.&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WrapWithHtml&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@app.call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;wrap_html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
       &amp;lt;!DOCTYPE html&amp;gt;
       &amp;lt;html&amp;gt;
         &amp;lt;head&amp;gt;
         &amp;lt;title&amp;gt;hello&amp;lt;/title&amp;gt;
         &amp;lt;body&amp;gt;
         &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
         &amp;lt;/body&amp;gt;
       &amp;lt;/html&amp;gt;
&lt;/span&gt;&lt;span class="no"&gt;    EOF&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;wrap_html&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# 起始点, 只返回一行字符的 rack app.&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Hello&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'Content-Type'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'text/plain'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"hello, this is a test."&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;WrapWithHtml&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;WrapWithRedP&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ToUpper&lt;/span&gt;
&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="no"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 termial 中输入&lt;code&gt;rackup&lt;/code&gt;, 而后，一个 web 服务就运行了.
关于这段例子，前文的解释是：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;use 与 run 本质上没有太大的差别，只是 run 是最先调用的。 &lt;del&gt;它们生成一个 statck&lt;/del&gt;(谢谢 &lt;a href="/est" class="user-mention" title="@est"&gt;&lt;i&gt;@&lt;/i&gt;est&lt;/a&gt; 指出错误) 本质上是先调用 Hello.new#call, 而后返回 ternary-array, 而后再将之交给另一个 ToUpper, ToUpper 干完自己的活，再交给 WrapWithRedP, 如此一直到 stack 调用完成.
&lt;code&gt;use ToUpper; run Hello.new&lt;/code&gt; 本质上是完成如下调用:
&lt;code&gt;ToUpper.new(Hello.new.call(env)).call(env)&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="提出问题"&gt;提出问题&lt;/h2&gt;
&lt;p&gt;看到这里，个人有许多疑问：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;rackup&lt;/code&gt;命令来自于哪里？&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rackup&lt;/code&gt;命令如何找到&lt;code&gt;config.ru&lt;/code&gt;这个文件的，又是如何加载它运行它的，或者说它是如何加载代码创建服务的？&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;use&lt;/code&gt; 后面跟着的是 middleware 这个知道，但是，它是如何生成加载的 stack 的？&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;run&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;所有的 middleware 只要其实例响应&lt;code&gt;call&lt;/code&gt;方法就可以了，它们如何工作？&lt;/li&gt;
&lt;li&gt;yyyy?&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="rackup 命令来自于哪里? 如何加载 config.ru 并生成项目的?"&gt;rackup 命令来自于哪里？如何加载 config.ru 并生成项目的？&lt;/h2&gt;
&lt;p&gt;那么，从源码一行一行看过去吧，首先是&lt;code&gt;rackup&lt;/code&gt;, 放在&lt;code&gt;rack&lt;/code&gt;项目的&lt;code&gt;bin&lt;/code&gt;文件夹下，只有几行：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env ruby&lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"rack"&lt;/span&gt;
&lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;好吧，个人表示不理解，于是跳到 &lt;code&gt;lib\server.rb&lt;/code&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# lib\server.rb&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;-_-!&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# lib\server.rb&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="vi"&gt;@options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;
  &lt;span class="vi"&gt;@app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:app&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:app&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;-_-! 好吧，&lt;code&gt;Rack::Server.start&lt;/code&gt; 时一个参数也没有。因此 &lt;code&gt;new&lt;/code&gt; =&amp;gt; &lt;code&gt;initialize&lt;/code&gt; 时也一个参数也没有。也即是说最后从类方法&lt;code&gt;start&lt;/code&gt;又跳回了实例方法&lt;code&gt;start&lt;/code&gt;上：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# lib\server.rb&lt;/span&gt;
&lt;span class="c1"&gt;# 这该死的start实例方法相当之长, 这里只引用关键点:&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;blk&lt;/span&gt;
&lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt; &lt;span class="n"&gt;wrapped_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;blk&lt;/span&gt;
&lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;好吧，server 来自于方法，wrapped_app 也是个方法：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# lib\server.rb&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;server&lt;/span&gt;
  &lt;span class="vi"&gt;@_server&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:server&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapped_app&lt;/span&gt;
  &lt;span class="vi"&gt;@wrapped_app&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="n"&gt;build_app&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:environment&lt;/span&gt;&lt;span class="p"&gt;]].&lt;/span&gt;&lt;span class="nf"&gt;reverse_each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;middleware&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond_to?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:call&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;next&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;middleware&lt;/span&gt;
    &lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;middleware&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;app&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;app&lt;/span&gt;
  &lt;span class="vi"&gt;@app&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:builder&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;build_app_from_string&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;build_app_and_options_from_config&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这方法间引来引去的，实在让人抓狂，这里直接给出关键点吧。以下内容也不帖出这该死的方法链了，只帖关键点。这样写下去不如直接帖源码自己看不是吗？(我承认我只是表达一下我抓狂的心情)
关键点在于：server 方法的后半段&lt;code&gt;Rack::Handler.default(options)&lt;/code&gt; 以及 &lt;code&gt;wrapped_app&lt;/code&gt;方法.
这里不卖关子，前者直接决定了调用哪个服务器来运行项目，是&lt;code&gt;thin&lt;/code&gt;还是&lt;code&gt;mongrel&lt;/code&gt;, &lt;code&gt;WEBrick&lt;/code&gt;之类的.
&lt;code&gt;wrapped_app&lt;/code&gt;与&lt;code&gt;app&lt;/code&gt;两个方法则决定了会加载&lt;code&gt;config.ru&lt;/code&gt;的内容作为运行项目.
&lt;code&gt;options[:builder] ? build_app_from_string : build_app_and_options_from_config&lt;/code&gt; 这一行可知，因为 option 根本没指定，所以会调用 &lt;code&gt;build_app_from_string&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# lib\server.rb&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_app_from_string&lt;/span&gt;
  &lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new_from_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:builder&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是我们华丽地滚到了&lt;code&gt;lib\builder.rb&lt;/code&gt;文件：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# lib\builder.rb&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new_from_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder_script&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"(rackup)"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"Rack::Builder.new {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;builder_script&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;}.to_app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="no"&gt;TOPLEVEL_BINDING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;好吧，历经千动百难我们终于找到了正主。这个&lt;code&gt;builder_script&lt;/code&gt;就是&lt;code&gt;config.ru&lt;/code&gt;文件的内容了。&lt;code&gt;eval&lt;/code&gt;方法在&lt;code&gt;TOPLEVEL_BINDING&lt;/code&gt;环境下，也即我们运行&lt;code&gt;rackup&lt;/code&gt;命令的环境下运行代码.
....但是，妈蛋，这&lt;code&gt;builder_script&lt;/code&gt;来自于哪里？&lt;code&gt;self.options[:builder]&lt;/code&gt;作为参数传进来的，但是泥煤的这个 options 不是一直都是空的吗!!?
好吧，这个不是&lt;code&gt;options&lt;/code&gt;, 这个是&lt;code&gt;options&lt;/code&gt;类方法。属于&lt;code&gt;Rack::Server&lt;/code&gt;类.
经研究，顺序是这样的：options 方法里引用&lt;code&gt;parse_options(ARGV)&lt;/code&gt;也即是分析用户输入内容，但是明显我们没有输入任何内容。&lt;code&gt;parse_options&lt;/code&gt;方法开篇第一句：&lt;code&gt;options = default_options&lt;/code&gt;, 而后在后面的代码分析 ARGV, 死命地覆盖它。
&lt;code&gt;default_options&lt;/code&gt; 是这个方法，里面的一行指定了，&lt;code&gt;options[:config]&lt;/code&gt;, 是&lt;code&gt;config.ru&lt;/code&gt;文件。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# lib\server.rb&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;options&lt;/span&gt;
  &lt;span class="vi"&gt;@options&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="n"&gt;parse_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ARGV&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parse_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;default_options&lt;/span&gt;

  &lt;span class="c1"&gt;# Don't evaluate CGI ISINDEX parameters.&lt;/span&gt;
  &lt;span class="c1"&gt;# http://www.meb.uni-bonn.de/docs/cgi/cl.html&lt;/span&gt;
  &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;REQUEST_METHOD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge!&lt;/span&gt; &lt;span class="n"&gt;opt_parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:config&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expand_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:config&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"RACK_ENV"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:environment&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;default_options&lt;/span&gt;
  &lt;span class="n"&gt;environment&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'RACK_ENV'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s1"&gt;'development'&lt;/span&gt;
  &lt;span class="n"&gt;default_host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'development'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s1"&gt;'localhost'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'0.0.0.0'&lt;/span&gt;

  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;:environment&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;:pid&lt;/span&gt;         &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;:Port&lt;/span&gt;        &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;9292&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;:Host&lt;/span&gt;        &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;default_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;:AccessLog&lt;/span&gt;   &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="ss"&gt;:config&lt;/span&gt;      &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"config.ru"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="Rack 如何创建服务并生成stack的?"&gt;Rack 如何创建服务并生成 stack 的？&lt;/h2&gt;
&lt;p&gt;思维回溯，&lt;code&gt;config.ru&lt;/code&gt;终于传入&lt;code&gt;eval&lt;/code&gt;之中了，我们的项目找到根脚了，个人不禁泪流满面。而 &lt;code&gt;Rack::Builder.initialize&lt;/code&gt;最后会将其传入的 block 通过&lt;code&gt;instance_eval&lt;/code&gt;方法运行其实例变量环境之中。也即是&lt;code&gt;config.ru&lt;/code&gt;的所有文本内容，在&lt;code&gt;Rack::Builder&lt;/code&gt;实例化后，在其环境下调用了。&lt;del&gt;于是 use 生成 stack&lt;/del&gt;, 于是 use 方法将 middlewares 加入到&lt;a href="/use" class="user-mention" title="@use"&gt;&lt;i&gt;@&lt;/i&gt;use&lt;/a&gt; array 中去，run 方法将其参数设置为起始项目并存入&lt;a href="/app" class="user-mention" title="@app"&gt;&lt;i&gt;@&lt;/i&gt;app&lt;/a&gt;, 而后再通过 to_app 将之转化为 stack 待用，最后用户发起请求，server 调用 call 方法，并传入 env. env 在主项目&lt;a href="/app" class="user-mention" title="@app"&gt;&lt;i&gt;@&lt;/i&gt;app&lt;/a&gt;, 和 &lt;a href="/use" class="user-mention" title="@use"&gt;&lt;i&gt;@&lt;/i&gt;use&lt;/a&gt; 中的 middlewares 中薪火相传，每经手一次，就可能被做些修改，最后，返回值 .&lt;/p&gt;

&lt;p&gt;再回到&lt;code&gt;builder.rb&lt;/code&gt;文件，也即&lt;code&gt;eval&lt;/code&gt;所在的内容：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new_from_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder_script&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"(rackup)"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"Rack::Builder.new {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;builder_script&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;}.to_app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="no"&gt;TOPLEVEL_BINDING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;好吧，我们知道它调用了类&lt;code&gt;Rack::Builder&lt;/code&gt;类的&lt;code&gt;initialize&lt;/code&gt;方法。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default_app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# middlewares 默认为空[]; @map默认不存在. @run 默认等于创建时的项目, @warmup默认不存在.&lt;/span&gt;
  &lt;span class="vi"&gt;@use&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@run&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@warmup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
  &lt;span class="c1"&gt;# 在Builder实例中运行block, 也即是在builder运行环境中再执行block中的代码.&lt;/span&gt;
  &lt;span class="nb"&gt;instance_eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;block_given?&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;太过细节的东西不要再讲了，我们再简化一下吧：&lt;code&gt;Rack::Builder&lt;/code&gt; 类是核心所在。它包含了生成 middlewares stack 的核心代码，决定了 middlewares 的调用顺序。也决定了它们如何被调用。它提供的&lt;code&gt;use&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;run&lt;/code&gt;, &lt;code&gt;to_app&lt;/code&gt;等方法，决定了一切：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@map&lt;/span&gt;
    &lt;span class="n"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
    &lt;span class="vi"&gt;@use&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;generate_map&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mapping&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="vi"&gt;@use&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="vi"&gt;@use&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="vi"&gt;@run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="vi"&gt;@map&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="vi"&gt;@map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_app&lt;/span&gt;
  &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@map&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;generate_map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@run&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@map&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="vi"&gt;@run&lt;/span&gt;
  &lt;span class="nb"&gt;fail&lt;/span&gt; &lt;span class="s2"&gt;"missing run or map statement"&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
  &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@use.reverse.inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="vi"&gt;@warmup.call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@warmup&lt;/span&gt;
  &lt;span class="n"&gt;app&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;to_app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;use&lt;/code&gt;方法将 middleware 放到一个 proc 之中，再将此 proc 放到&lt;a href="/use" class="user-mention" title="@use"&gt;&lt;i&gt;@&lt;/i&gt;use&lt;/a&gt;这个 array 之中。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;run&lt;/code&gt;方法将起始项目放到&lt;a href="/app" class="user-mention" title="@app"&gt;&lt;i&gt;@&lt;/i&gt;app&lt;/a&gt;实例变量之中。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;map&lt;/code&gt;方法用于生成简单的 rack 项目内路由。暂时不放入讨论之中。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;to_app&lt;/code&gt;方法生成 stack, 并等待最后从 server 处传传进来。用户打开浏览器地址，server(如 thin) 就会调用这个 call 方法，并传入 env 作为其值。问题的关键点在于&lt;code&gt;to_app&lt;/code&gt;方法最后返回的那个&lt;code&gt;app&lt;/code&gt;, 它本质上已经将项目以及 middlewares 全部串在了一起，并且保证一次调用 call, 就会按规则走完 middlewares 全流程。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;_&lt;/em&gt; (是否对前面那么啰嗦，后面语言简洁的转折表示不适应？)&lt;/p&gt;
&lt;h2 id="抽象问题, 模拟过程"&gt;抽象问题，模拟过程&lt;/h2&gt;
&lt;p&gt;这里不再去解释源码的调用链了，我们来写一段小程序来模拟这个创建 stack，并调用它们的全过程：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# t5.rb&lt;/span&gt;
&lt;span class="vi"&gt;@use&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Mdw&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"mdw1:"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;
    &lt;span class="vi"&gt;@app.call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Mdw2&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"mdw2:"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;
    &lt;span class="vi"&gt;@app.call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;startApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'startApp:'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="vi"&gt;@use&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="vi"&gt;@use.reverse.inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@app&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="vi"&gt;@app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Mdw&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Mdw2&lt;/span&gt;
&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="n"&gt;startApp&lt;/span&gt;

&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'env'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行&lt;code&gt;ruby t5.rb&lt;/code&gt;, 可以得到如下内容：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mdw1:env
mdw2:mdw1:env
startApp:mdw2:mdw1:env
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;startApp&lt;/code&gt;与&lt;code&gt;middlewares&lt;/code&gt;中用的&lt;code&gt;puts&lt;/code&gt;方法输出了值的全变化过程.
这里没有模拟&lt;code&gt;rack&lt;/code&gt;返回&lt;code&gt;[statusCode, Headers, Body]&lt;/code&gt;模式的部分。只模拟了链式调用的生成，以及调用的过程。&lt;/p&gt;
&lt;h2 id="相关资料"&gt;相关资料&lt;/h2&gt;
&lt;p&gt;一切的关键在于&lt;code&gt;@use.reverse.inject(@app){|a, w| w[a] }.call(s)&lt;/code&gt;这行代码，在 &lt;a href="/use" class="user-mention" title="@use"&gt;&lt;i&gt;@&lt;/i&gt;use&lt;/a&gt; 变量上调用 inject 的过程，以及 block 调用的特殊方法。
&lt;strong&gt;有多少人知道，proc/lambda是可以通过&lt;code&gt;[ ]&lt;/code&gt;来调用的？&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;关于&lt;code&gt;inject&lt;/code&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Combines all elements of enum by applying a binary operation, specified by a block or a symbol that names a method or operator.
If you specify a block, then for each element in enum the block is passed an accumulator value (memo) and the element. If you specify a symbol instead, then each element in the collection will be passed to the named method of memo. In either case, the result becomes the new value for memo. At the end of the iteration, the final value of memo is the return value for the method.
If you do not explicitly specify an initial value for memo, then the first element of collection is used as the initial value of memo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;关于&lt;code&gt;block&lt;/code&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;prc[params,...]
Invokes the block, setting the block’s parameters to the values in params using something close to method calling semantics. Generates a warning if multiple values are passed to a proc that expects just one (previously this silently converted the parameters to an array). Note that prc.() invokes prc.call() with the parameters given. It’s a syntax sugar to hide “call”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;array.inject(i){|a, b| b[a]}&lt;/code&gt;的运行过程中，前一轮的 b[a] 被存到内存中，并加载了下一轮的 a 变量中。因为 a 和 b 都是 proc, 所以 procA[procB] 本质上是调用这个代码块。在这个过程中，初始点 app, 会被放在最底层，而 middleware 会一层一层套在上面。&lt;code&gt;@use.reverse.inject(@app){|a, w| w[a] }&lt;/code&gt;返回的是最外层的那个 middleware 的实例。模拟的代码，只是将 call() 方法手动引用了而已.(本来，它是等着用户行为，再由 server 来调用，传值的)&lt;/p&gt;
&lt;h2 id="模拟推衍过程"&gt;模拟推衍过程&lt;/h2&gt;
&lt;p&gt;下面附上示例代码&lt;code&gt;t5.rb&lt;/code&gt;运行过程的推衍过程:
注意：以下内容极其无聊，请精神正常的人不要较真：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;最后数行代码的推衍过程&lt;/span&gt;
&lt;span class="c1"&gt;# 前面定义middleware类的过程请无视.&lt;/span&gt;
&lt;span class="c1"&gt;# step 1, `use Mdw;useMdw2;run startApp`&lt;/span&gt;
&lt;span class="vi"&gt;@app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'startApp:'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="vi"&gt;@use&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;Mdw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;Mdw2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;
&lt;span class="c1"&gt;# step 2: `@use.reverse.inject(@a){|a, w| w[a] }`&lt;/span&gt;
&lt;span class="c1"&gt;# step 2.1, 第一轮&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'startApp:'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;Mdw2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# step 2.2, 第二轮&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;Mdw2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'startApp:'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;
&lt;span class="c1"&gt;# 实际值: a = Md2.new(proc {|app| puts tmp = 'startApp:' + app })&lt;/span&gt;
&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;Mdw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;# step 2.3, 第三轮&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;Mdw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;Mdw2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'startApp:'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;}]]&lt;/span&gt;
&lt;span class="c1"&gt;# 实际值: a = proc {|app| Mdw.new(t) }[Mdw2.new(proc {|app| puts tmp = 'startApp:' + app })]&lt;/span&gt;
&lt;span class="c1"&gt;# 实际值: a = Mdw.new(Mdw2.new(proc {|app| puts tmp = 'startApp:' + app }))&lt;/span&gt;
&lt;span class="c1"&gt;# step 3, @use.reverse.inject(@a){|a, w| w[a] }.call('s')&lt;/span&gt;
&lt;span class="c1"&gt;# step 3.1&lt;/span&gt;
&lt;span class="no"&gt;Mdw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Md2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'startApp:'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;})).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'s'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# step 3.2&lt;/span&gt;
&lt;span class="no"&gt;Mdw2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'startApp:'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Mdw1:'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;'s'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# step 3.3&lt;/span&gt;
&lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'startApp:'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Mdw2:'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s1"&gt;'Mdw1:'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;'s'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="s1"&gt;'startApp:'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;'Mdw2:'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s1"&gt;'Mdw1:'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;'s'&lt;/span&gt;
&lt;span class="c1"&gt;# 如果想实现链式调用, 一个作为另一个的参数, 形成套娃机制. 需要彼此为参数的设定.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;看代码，何其苦！虽说真正的猛士敢于面对惨淡的人生，敢于正视淋漓的鲜血，但是且容我们叫一声苦。&lt;/p&gt;</description>
      <author>suffering</author>
      <pubDate>Sun, 08 Feb 2015 21:26:17 +0800</pubDate>
      <link>https://ruby-china.org/topics/24166</link>
      <guid>https://ruby-china.org/topics/24166</guid>
    </item>
    <item>
      <title>Rails 3 组织分割 routes</title>
      <description>&lt;p&gt;项目中 routes 太多太乱时，仅仅备注的话是很乱的，因此可以考虑将之分组之分割到不同的文件里。&lt;/p&gt;

&lt;p&gt;解决的思路如下：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;在 config 下新建 routes 文件夹&lt;/li&gt;
&lt;li&gt;将 routes.rb 拆分放到不同的文件夹内&lt;/li&gt;
&lt;li&gt;更改 application.rb 的 load path&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="场景"&gt;场景&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#config/routes.rb&lt;/span&gt;
&lt;span class="no"&gt;YourApppic&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:products&lt;/span&gt;
  &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:categories&lt;/span&gt;
  &lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ss"&gt;:admin&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:products&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s1"&gt;'welcome/index'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="创建并拆分文件"&gt;创建并拆分文件&lt;/h3&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd path/to/your_app/config
mkdir routes
touch admin_routes.rb
touch data_routes.rb
touch none_restful_routes.rb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而后变成：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#config/admin_routes.rb&lt;/span&gt;
&lt;span class="no"&gt;YourApppic&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ss"&gt;:admin&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:products&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#config/routes/data_routes.rb&lt;/span&gt;
&lt;span class="no"&gt;YourApppic&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:products&lt;/span&gt;
  &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:categories&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#config/routes/none_restful_routes.rb&lt;/span&gt;
&lt;span class="no"&gt;YourApppic&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s1"&gt;'welcome/index'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="修改 application.rb"&gt;修改 application.rb&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"config/routes"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"config/routes/*.rb"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="sb"&gt;`
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重启项目，一切 ok .&lt;/p&gt;
&lt;h3 id="考虑 routes override"&gt;考虑 routes override&lt;/h3&gt;
&lt;p&gt;如果你的 routes 非常依赖顺序。就不要使用 &lt;code&gt;config.paths["config/routes"] += Dir[Rails.root.join("config/routes/*.rb")]&lt;/code&gt; 可以考虑指定顺序加载分割后的文件：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# 逐个加载&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"config/routes/none_restful_routes.rb"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"config/routes/admin_routes.rb"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"config/routes/data_routes.rb"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# alphabetical 排序加载&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"config/routes"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"config/routes/*.rb"&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;
&lt;span class="c1"&gt;# 这个需要重命名下文件, 如 0_none_restful_routes.rb, 1_admin_routes.rb, 2_data_routes.rb 这种做法.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="参考"&gt;参考&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://rails-bestpractices.com/posts/73-split-route-namespaces-into-different-files" rel="nofollow" target="_blank"&gt;http://rails-bestpractices.com/posts/73-split-route-namespaces-into-different-files&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://stackoverflow.com/questions/7303660/splitting-routes-file-into-multiple-files" rel="nofollow" target="_blank"&gt;http://stackoverflow.com/questions/7303660/splitting-routes-file-into-multiple-files&lt;/a&gt;&lt;/p&gt;</description>
      <author>suffering</author>
      <pubDate>Fri, 28 Nov 2014 23:53:37 +0800</pubDate>
      <link>https://ruby-china.org/topics/22919</link>
      <guid>https://ruby-china.org/topics/22919</guid>
    </item>
    <item>
      <title>此版太冷, 发图求暖</title>
      <description>&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/aff2ab931b90ac33492d2543a2d228a0.jpg" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>suffering</author>
      <pubDate>Fri, 17 Oct 2014 14:52:38 +0800</pubDate>
      <link>https://ruby-china.org/topics/22089</link>
      <guid>https://ruby-china.org/topics/22089</guid>
    </item>
    <item>
      <title>关于 axlsx 导出 excel 的问题</title>
      <description>&lt;p&gt;最近项目上需要导出 excel 并快速打印单据.
工作环境：windows xp + google chrome + EPSON-LQ-630K
具体的工作流程如下：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;click to export excel (.xlsx)&lt;/li&gt;
&lt;li&gt;open the exported excel&lt;/li&gt;
&lt;li&gt;click to print
这个流程倒是很简单。直接使用&lt;code&gt;axlsx&lt;/code&gt;, 简单好用很快就搞定了。但是在打印时问题出现了:
导出的 excel 的打印尺寸应该是&lt;code&gt;8.5in * 5.5in&lt;/code&gt;. 这不是微软默认的打印尺寸，也不是 epson 默认的打印尺寸。所以只能定义一个打印尺寸.
具体参见：&lt;a href="http://msdn.microsoft.com/en-us/library/windows/desktop/dd319099v=vs.85).aspx" rel="nofollow" target="_blank"&gt;http://msdn.microsoft.com/en-us/library/windows/desktop/dd319099v=vs.85).aspx&lt;/a&gt;(
&lt;code&gt;axlsx&lt;/code&gt;提供了丰富的方法来设置&lt;code&gt;pager size&lt;/code&gt;, 也提供了自定义尺寸的 options, 但是，实际使用中却怎么也调试不好。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这里的 axlsx 相应的源码：&lt;a href="https://github.com/randym/axlsx/blob/master/lib/axlsx/workbook/worksheet/page_setup.rb" rel="nofollow" target="_blank"&gt;https://github.com/randym/axlsx/blob/master/lib/axlsx/workbook/worksheet/page_setup.rb&lt;/a&gt; 
读完后发现&lt;code&gt;usePrinterDefaults&lt;/code&gt;放在 todo 里。也即是说，即使设置打印机的默认打印纸，也是不行。导出的 excel 默认为设置成&lt;code&gt;Letter&lt;/code&gt;格式.
...&lt;/p&gt;

&lt;p&gt;果然程序员最痛恨的还是 windows...&lt;/p&gt;

&lt;p&gt;大家有没有好的意见？hack axlsx 的方案或直接换个 gem? 已经试过&lt;code&gt;writeexcel&lt;/code&gt;,这个更坑。&lt;/p&gt;

&lt;p&gt;悲剧地无人理会...&lt;/p&gt;</description>
      <author>suffering</author>
      <pubDate>Tue, 14 Oct 2014 21:08:27 +0800</pubDate>
      <link>https://ruby-china.org/topics/22043</link>
      <guid>https://ruby-china.org/topics/22043</guid>
    </item>
    <item>
      <title>为什么我们需要 Rack ?</title>
      <description>&lt;h2 id="一切从 Rack 开始"&gt;一切从 Rack 开始&lt;/h2&gt;
&lt;p&gt;Rails 就是一个 Rack app. 实际上，基本上所有的 Ruby web framework 都是&lt;code&gt;rack app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;官网中列出的使用 Rack 的 web 框架：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Camping&lt;/li&gt;
&lt;li&gt;Coset&lt;/li&gt;
&lt;li&gt;Espresso&lt;/li&gt;
&lt;li&gt;Halcyon&lt;/li&gt;
&lt;li&gt;Mack&lt;/li&gt;
&lt;li&gt;Maveric&lt;/li&gt;
&lt;li&gt;Merb&lt;/li&gt;
&lt;li&gt;Racktools::SimpleApplication&lt;/li&gt;
&lt;li&gt;Ramaze&lt;/li&gt;
&lt;li&gt;Ruby on Rails&lt;/li&gt;
&lt;li&gt;Rum&lt;/li&gt;
&lt;li&gt;Sinatra&lt;/li&gt;
&lt;li&gt;Sin&lt;/li&gt;
&lt;li&gt;Vintage&lt;/li&gt;
&lt;li&gt;Waves&lt;/li&gt;
&lt;li&gt;Wee&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;基本上，Ruby 世界的 web, rack 已经一统天下了。有兴趣的童鞋可以看看&lt;code&gt;ruby-toolbox&lt;/code&gt;的&lt;code&gt;web-app-framework&lt;/code&gt;, 看看有哪些没有用到 rack 的：&lt;a href="https://www.ruby-toolbox.com/categories/web_app_frameworks" rel="nofollow" target="_blank"&gt;https://www.ruby-toolbox.com/categories/web_app_frameworks&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="简介"&gt;简介&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Rack provides a minimal, modular and adaptable interface for developing web applications in Ruby. By wrapping HTTP requests and responses in the simplest way possible, it unifies and distills the API for web servers, web frameworks, and software in between(the so-called middleware) into a single method call.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;简单点说，rack 是 Ruby web 应用的简单的模块化的接口。它封装 HTTP 请求与响应，并提供大量的实用工具。它需要一个响应 call 方法的对象，接受 env. 返回三元素的数组：分别是 status code, header, body. 其中 status code 大于等于 100, 小于 600. header 是一个 hash, body 是一个响应 each 方法的数组。&lt;/p&gt;

&lt;p&gt;理解上述接口标准，就可以写一个完整的 rack app 了。除了这些，rack 还提供了许多有工具。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gem install rack
gem install pry
pry
require 'rack'
cd Rack
ls
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上述得到如下内容：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;constants:
  Auth       CommonLogger    Deflater        Handler  MethodOverride  NullLogger  Runtime         ShowStatus
  BodyProxy  ConditionalGet  Directory       Head     Mime            Recursive   Sendfile        Static
  Builder    Config          ETag            Lint     MockRequest     Reloader    Server          URLMap
  Cascade    ContentLength   File            Lock     MockResponse    Request     Session         Utils
  Chunked    ContentType     ForwardRequest  Logger   Multipart       Response    ShowExceptions  VERSION
Rack.methods: release  version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上内容，除少部分是 Rack 自身运行的依赖外，大部分都是 Rack 提供的可选模块，它们封装了许多简单实用的方法，比如说处理静态文件，缓存，log, 非法内容 sanitize . 使用它们，Ruby web 开发才不会那么痛苦.
另外，还有许多 Rack middleware. 这里有详细列表:
&lt;a href="https://github.com/rack/rack/wiki/List-of-Middleware" rel="nofollow" target="_blank"&gt;https://github.com/rack/rack/wiki/List-of-Middleware&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="为什么需要 Rack"&gt;为什么需要 Rack&lt;/h3&gt;
&lt;p&gt;这里不防用反证法，带大家看看若是没有 Rack, 我们应该如何开发一个 Ruby web app.&lt;/p&gt;

&lt;p&gt;如果从零开始了解 web 世界。我们知道，浏览器与服务端通过 HTTP 协议交互。这是一个 request 与 response 的过程。&lt;/p&gt;

&lt;p&gt;request 从客户端发出，包含了字符串的头文件，它包括请求的地址，请求方式 (get/post/put/delete 等). 浏览器发送的是格式化的字符串，作为服务端，我们需要分析这段字符串，如果没有 Rack, 我们得自己程序来分析这个 orgin string header.&lt;/p&gt;

&lt;p&gt;同样的，按照 http 协议，Response 也是类似的字符串。浏览器接收到它们后，分析并 render, 最终生成页面。没有 rack, 这字符串也得自己来生成。&lt;/p&gt;

&lt;p&gt;这里看一个例子，非常有意思的博文。博主去面试，让他写一个简单的 Ruby web server, 要求如下：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Web server returns “Hello World”.&lt;/li&gt;
&lt;li&gt;Web server returns the list of files in the base directory.&lt;/li&gt;
&lt;li&gt;Web server allows to navigate the directory structure.&lt;/li&gt;
&lt;li&gt;If a user click on a file the browser should display it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;总计 4 条要求，其中第一二条实现了，后面两条却失败了 .事后好好研究了下这个，并写出了博客。这个是第三条的实现，就是自己手动输出 response string :&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"socket"&lt;/span&gt;
&lt;span class="n"&gt;webserver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;TCPServer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'localhost'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;base_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;"HTTP/1.1 200/OK&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;Content-type:text/html&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gets&lt;/span&gt;
  &lt;span class="n"&gt;trimmedrequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/GET\ \//&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/\ HTTP.*/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;trimmedrequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chomp&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
    &lt;span class="n"&gt;base_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"./&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;trimmedrequest&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chomp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;"
&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;trimmedrequest&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;

"&lt;/span&gt;

  &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;base_dir&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists?&lt;/span&gt; &lt;span class="n"&gt;base_dir&lt;/span&gt;
     &lt;span class="n"&gt;base_dir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;directory?&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;
         &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;a href="&lt;/span&gt;&lt;span class="c1"&gt;#{f}"&amp;gt; #{f}&amp;lt;/a&amp;gt;")&lt;/span&gt;
       &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"
&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;

"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="k"&gt;end&lt;/span&gt;
     &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Directory does not exists!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;原文地址：&lt;a href="http://matteomelani.wordpress.com/2011/11/11/a-simple-web-server-is-ruby/" rel="nofollow" target="_blank" title=""&gt;A Simple Web Server in Ruby&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;就像&lt;code&gt;terminal&lt;/code&gt;端的 Ruby code 运行时通过 gets 方法来获取用户的输入一样，真是简陋得可以。
仔细看一下博主的实现，就是将&lt;code&gt;request&lt;/code&gt;当字符串处理 (其实 request 本来就是格式化的字符串), 通过正则来获取其&lt;code&gt;REQUEST_METHOD&lt;/code&gt;, &lt;code&gt;PATH_INFO&lt;/code&gt;等等，将&lt;code&gt;Content-Type&lt;/code&gt;设置为&lt;code&gt;text/html&lt;/code&gt;, 最后将信息打包，作为&lt;code&gt;response&lt;/code&gt;发送给客户端.
至于第四条，则需要手动去设置&lt;code&gt;mimi-type&lt;/code&gt;,这样才能以完整的方式将图片等内容在 web 页面中正常展现。&lt;/p&gt;

&lt;p&gt;看看 http request header fields: &lt;a href="http://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Request_fields" rel="nofollow" target="_blank"&gt;http://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Request_fields&lt;/a&gt;
数十条，各有其含义。从头至尾写一个 web server, 你得分析它们，作不同的响应。&lt;/p&gt;

&lt;p&gt;再看看 http response fields: &lt;a href="http://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Response_fields" rel="nofollow" target="_blank"&gt;http://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Response_fields&lt;/a&gt;
同样数十条，浏览器会根据你返回的 header 来决定如何 render page. 如果手动去生成，那是头皮发麻的工作量。&lt;/p&gt;

&lt;p&gt;但是，使用 Rack, 以及它提供的工具的话，实现博主接受的考题要求，我们可以这样做，只需要两行代码：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require 'rack'
Rack::Handler::Thin.run Rack::Directory.new('./'), :Port =&amp;gt; 9292 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当然，是否允许这样做就不得而知了。&lt;/p&gt;
&lt;h3 id="数行代码的rack app"&gt;数行代码的&lt;code&gt;rack app&lt;/code&gt;
&lt;/h3&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gem install rack
cd to/your/path
touch app.rb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;app.rb&lt;/code&gt;内容如下;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#app.rb&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rack'&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HelloWorld&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"Content-Type"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"text/html"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Hello Rack!"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Handler&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Mongrel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt; &lt;span class="no"&gt;HelloWorld&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:Port&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;9292&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 terminal 里运行&lt;code&gt;ruby app.rb&lt;/code&gt;, 而后在浏览器里打开&lt;code&gt;http://localhost:9292&lt;/code&gt;就可以看到返回的内容了。&lt;/p&gt;
&lt;h3 id="使用 middleware stack 的 rack app"&gt;使用 middleware stack 的 rack app&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#config.ru&lt;/span&gt;

&lt;span class="c1"&gt;# 将 body 标签的内容转换为全大写.&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ToUpper&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@app.call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;upcased_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upcase&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;upcased_body&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="c1"&gt;# 将 body 内容置于标签, 设置字体颜色为红色, 并指明返回的内容为 text/html.&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WrapWithRedP&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@app.call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;red_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;p style='color:red;'&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/p&amp;gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Content-type'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'text/html'&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;red_body&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# 将 body 内容放置到 HTML 文档中.&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WrapWithHtml&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@app.call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;wrap_html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
       &amp;lt;!DOCTYPE html&amp;gt;
       &amp;lt;html&amp;gt;
         &amp;lt;head&amp;gt;
         &amp;lt;title&amp;gt;hello&amp;lt;/title&amp;gt;
         &amp;lt;body&amp;gt;
         &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
         &amp;lt;/body&amp;gt;
       &amp;lt;/html&amp;gt;
&lt;/span&gt;&lt;span class="no"&gt;    EOF&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;wrap_html&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# 起始点, 只返回一行字符的 rack app.&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Hello&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'Content-Type'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'text/plain'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"hello, this is a test."&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;WrapWithHtml&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;WrapWithRedP&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ToUpper&lt;/span&gt;
&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="no"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;直接运行&lt;code&gt;rackup&lt;/code&gt;就可以运行上述 app.&lt;/p&gt;

&lt;p&gt;use 与 run 本质上没有太大的差别，只是 run 是最先调用的。它们生成一个 statck, 本质上是先调用 Hello.new#call, 而后返回 ternary-array, 而后再将之交给另一个 ToUpper, ToUpper 干完自己的活，再交给 WrapWithRedP, 如此一直到 stack 调用完成。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;use ToUpper; run Hello.new&lt;/code&gt;本质上是完成如下调用：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;ToUpper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上只是简单的举例，实际的 web 项目中，有无数的场景需求。
比如说，你可以随时需要更改 status code, 或者，你需要判断当前请求是什么类型的，比如说是 get 还是 post, 在 rails 中 resource 生成的同样的 path，如 &lt;code&gt;/products/:id&lt;/code&gt;可以是&lt;code&gt;get/put/delete&lt;/code&gt;. 但是 Rails 如何知道调用&lt;code&gt;show/update/destroy&lt;/code&gt;中的哪一个？这时，这个时候可以去看看 env['REQUEST_METHOD'], 而后判断。这们做虽然不用去分析原始的 head 文件，但是也是愚蠢的行为，这个时候就可以直接用 rack 提供的一些工具了。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rack'&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Hello&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_request&lt;/span&gt;
       &lt;span class="vi"&gt;@request&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
      &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"respond"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@respond&lt;/span&gt;
      &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;flatten&lt;/span&gt;
      &lt;span class="vi"&gt;@response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_response&lt;/span&gt;
      &lt;span class="vi"&gt;@response&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="sx"&gt;%W{get? put? post? delete? patch? trace?}&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;define_method&lt;/span&gt; &lt;span class="n"&gt;md&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
            &lt;span class="n"&gt;get_request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;intern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="sx"&gt;%W{body headers length= status=  body= header length 
       redirect status content_length content_type}&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;define_method&lt;/span&gt; &lt;span class="n"&gt;md&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|*&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
            &lt;span class="n"&gt;get_response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;intern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
   &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;
      &lt;span class="n"&gt;content_type&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'text/plain'&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;get?&lt;/span&gt;
        &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'you send a get request'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;403&lt;/span&gt;
        &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'we do not support request method except get, please try another.'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Handler&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Thin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt; &lt;span class="no"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:Port&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;9292&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;若想测试非 get 方法，可以通过&lt;code&gt;curl -X POST http://localhost:9292/&lt;/code&gt;来测试.
以上示例是对 Rack::Request, Rack::Response 的非常愚蠢的封装，只是展示下使用它们的便捷之处。想看高质的封装代码，不仿看看 sinatra 的:
&lt;a href="https://github.com/bmizerany/sinatra/blob/work/lib/sinatra/base.rb#L15" rel="nofollow" target="_blank"&gt;https://github.com/bmizerany/sinatra/blob/work/lib/sinatra/base.rb#L15&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="Rails On Rack"&gt;Rails On Rack&lt;/h3&gt;
&lt;p&gt;Rails 中使用的 rack middleware stack:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd to/your/rails/project/path
rake middleware
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;得到的内容如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Sendfile&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ActionDispatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Static&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Lock&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x000000029a0838&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Runtime&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;MethodOverride&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ActionDispatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;RequestId&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Logger&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ActionDispatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ShowExceptions&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ActionDispatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;DebugExceptions&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ActionDispatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;RemoteIp&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ActionDispatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Reloader&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ActionDispatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Callbacks&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Migration&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;CheckPending&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ConnectionAdapters&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ConnectionManagement&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;QueryCache&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ActionDispatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Cookies&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ActionDispatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Session&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;CookieStore&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ActionDispatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Flash&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ActionDispatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ParamsParser&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Head&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ConditionalGet&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ETag&lt;/span&gt;
&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;routes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看出，Rails 重度依赖 Rack. 理解 Rails, 不防从 Rack 开始。按上述列表，先从&lt;code&gt;Rails.application.routes&lt;/code&gt;开始
一直走到最后一步.
关于在 Rails 如何使用 rack, 具体请参照 &lt;a href="http://guides.rubyonrails.org/rails_on_rack.html" rel="nofollow" target="_blank"&gt;http://guides.rubyonrails.org/rails_on_rack.html&lt;/a&gt;
另外这里有&lt;code&gt;xdite&lt;/code&gt;一篇博文，讲的是 Rails 如何支持 Rack, 又为什么要支持 Rack, 非常清晰明了。详细可以看看这里：&lt;a href="http://wp.xdite.net/?p=1557" rel="nofollow" target="_blank"&gt;http://wp.xdite.net/?p=1557&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="结论"&gt;结论&lt;/h3&gt;
&lt;p&gt;:)&lt;/p&gt;
&lt;h3 id="更多文档资料"&gt;更多文档资料&lt;/h3&gt;
&lt;p&gt;想更深入了解 Rack, 可以参见:
&lt;a href="http://rack.github.io/" rel="nofollow" target="_blank"&gt;http://rack.github.io/&lt;/a&gt;
&lt;a href="http://wp.xdite.net/?p=1557" rel="nofollow" target="_blank"&gt;http://wp.xdite.net/?p=1557&lt;/a&gt;
&lt;a href="http://m.onkey.org/ruby-on-rack-1-hello-rack" rel="nofollow" target="_blank"&gt;http://m.onkey.org/ruby-on-rack-1-hello-rack&lt;/a&gt;
&lt;a href="http://guides.rubyonrails.org/rails_on_rack.html" rel="nofollow" target="_blank"&gt;http://guides.rubyonrails.org/rails_on_rack.html&lt;/a&gt;
&lt;a href="http://rubylearning.com/blog/a-quick-introduction-to-rack/" rel="nofollow" target="_blank"&gt;http://rubylearning.com/blog/a-quick-introduction-to-rack/&lt;/a&gt;
&lt;a href="https://www.digitalocean.com/community/tutorials/a-comparison-of-rack-web-servers-for-ruby-web-applications" rel="nofollow" target="_blank"&gt;https://www.digitalocean.com/community/tutorials/a-comparison-of-rack-web-servers-for-ruby-web-applications&lt;/a&gt;
&lt;a href="http://codecondo.com/12-small-ruby-frameworks/" rel="nofollow" target="_blank"&gt;http://codecondo.com/12-small-ruby-frameworks/&lt;/a&gt;
这里特别推荐 railscasts-china.com 的一篇演讲：&lt;a href="http://railscasts-china.com/episodes/the-rails-initialization-process-by-kenshin54" rel="nofollow" target="_blank"&gt;http://railscasts-china.com/episodes/the-rails-initialization-process-by-kenshin54&lt;/a&gt;&lt;/p&gt;</description>
      <author>suffering</author>
      <pubDate>Sat, 13 Sep 2014 15:21:14 +0800</pubDate>
      <link>https://ruby-china.org/topics/21517</link>
      <guid>https://ruby-china.org/topics/21517</guid>
    </item>
    <item>
      <title>从头开始写一个 Rails-like web 框架</title>
      <description>&lt;p&gt;最近阅读&lt;a href="https://rebuilding-rails.com/" rel="nofollow" target="_blank" title=""&gt;Rebuilding Rails&lt;/a&gt;时对自建&lt;code&gt;ruby web framework&lt;/code&gt;有了兴趣，就模仿 rails 的功能写了个。&lt;/p&gt;

&lt;p&gt;目的不是再造个轮子，我也没有这个能力，主要是想在自己写框架的过程中理解 rails 的基本工作原理，提升一下自己的水平。这只是一个演示项目，没有半点的实际使用价值，唯一的作用就是便于阅读，在阅读的过程中可以了解一些 RAILS 的基本原理。&lt;/p&gt;

&lt;p&gt;项目地址：&lt;a href="https://github.com/suffering/learnmvc" rel="nofollow" target="_blank"&gt;https://github.com/suffering/learnmvc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;贴上部分 README:&lt;/p&gt;
&lt;h2 id="目标"&gt;目标&lt;/h2&gt;
&lt;p&gt;这个项目的目的不是重写一个&lt;code&gt;Ruby web framework&lt;/code&gt;, 而是在自己开发一个&lt;code&gt;Rails-like framework&lt;/code&gt;时，试着去理解一个&lt;code&gt;ruby mvc style web framework&lt;/code&gt;的一些基本原理。&lt;/p&gt;
&lt;h2 id="为什么需要"&gt;为什么需要&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Rails&lt;/code&gt;的源码就是头恐怖的怪兽，无数的童鞋倒前仆后继地打开源码，而后倒下。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Rails&lt;/code&gt;看起来就像魔法，运行&lt;code&gt;rails s&lt;/code&gt;, 而后一切就开始运行了。这些行为都是从哪里开始的？客户端的请求到达后它如何接收？如何处理？为什么在 controller 里可以调用 Model 里定义的模型？为什么 controller 里的实例变量可以在 view 中运用？Rails 是如何将 erb 文件渲染而后生成内容的？它如何与 layout 协作并返回？如此种种。&lt;/p&gt;

&lt;p&gt;对于新手来说，这个就是魔法，虽然很疑惑，却是没有时间也没有能力去寻找这些答案。同时，新手也不需要去理解这些因为哪怕不理解，只要懂得 rails 的规则，把相应的东西写在相应的地方 (MVC), rails 就会将它们组合在一起，生成内容并打包发送。事实上，很多人即使不了解这些，只要对 rails 足够了解，经验充足，也可以写出很好的项目来。&lt;/p&gt;

&lt;p&gt;但是这样是不够的，只有更多地理解 rails 的内部原理，才能更好地使用它，写出灵活高效的代码。&lt;/p&gt;
&lt;h2 id="已经实现的功能"&gt;已经实现的功能&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;以 rails MVC 的方式组织代码，以 rails 的规则命名 controller, view, model 等之后，相互之间可以协作。&lt;/li&gt;
&lt;li&gt;自定义 route, 使用&lt;code&gt;match&lt;/code&gt;, &lt;code&gt;resources&lt;/code&gt;, &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;post&lt;/code&gt;, &lt;code&gt;put&lt;/code&gt;, &lt;code&gt;delete&lt;/code&gt;等方法自定义路由。如 &lt;code&gt;match '/products/:id' =&amp;gt; 'products#show'&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;自定义 database.yml, 使用&lt;code&gt;activerecord&lt;/code&gt;作为&lt;code&gt;ROM&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;实现 layout yield, content_for, yield, render, redirect_to 等等&lt;/li&gt;
&lt;li&gt;实现静态文件 serve.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;注：已实现的只是 rails 的九牛一毛。展示的只是基本的调用链。及 MVC 基本的结合方式。许多功能诸如 session, cache, secure, test, configable 等都没有实现。&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="基本逻辑"&gt;基本逻辑&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;一切从 Rack 开始。几乎所有的 ruby web framework 都是 rack app. Rack 对象响应 call 方法，返回三元素的 array, 分别是 status code, header, content body. 只要你的项目符合以上三个要求，就是一个合法的 rack app. 可以运行它，在浏览器访问，看到完整的响应内容。所以，主流程即是 request 与 response 的地程。我们所做的事情就是在中间加入一些自己的东西。&lt;/li&gt;
&lt;li&gt;http request 到达 web server 后会即被 rack 封装，而后你得到一个 env 对象。它包含了客户的请求类型 (get/post/put/delete/..), 请求的地址 (env['PATH_INFO'], QUERY_STRING 等等.

&lt;ol&gt;
&lt;li&gt;通过分析 env, 我们知道客户的请求是指向哪个 controller#action. 而后查看路由表我们的 app 能否响应此请求。&lt;/li&gt;
&lt;li&gt;路由表在新建 app 对象时通过 routes 方法来定义，具体的做法是接受一个 block, block 内调用&lt;code&gt;match&lt;/code&gt;, &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;post&lt;/code&gt;等方法时，生成路由规则加入路由表。路由表里包含路径字符串的匹配正则，controller, action, params 等等。&lt;/li&gt;
&lt;li&gt;参照上一条，在路由规则中检查 &lt;code&gt;env['PATH\_INFO']&lt;/code&gt;, 若匹配，就知道了指向哪个 controller 的哪个 action, 以及其 params. 通过 &lt;code&gt;ctrl_const = Object.const_get(params[:controller].capitalize)&lt;/code&gt;来得到相应的 controller.&lt;/li&gt;
&lt;li&gt;通过 ctrl_const.new(env).call(params[:action]) 可以调用到相应的方法。&lt;/li&gt;
&lt;li&gt;到这一步，已经初步描述了一个请求从客户端到服务器端并指向需要的&lt;code&gt;controller#action&lt;/code&gt;的基本过程。也即处理 request 的过程完成。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Response 的过程:

&lt;ol&gt;
&lt;li&gt;在 ctrl_const.new 上调用 action 后新的对象内就会拥有相应的实例变量。这时通过&lt;code&gt;Tilt&lt;/code&gt;gem, 按规则生成目标 view 的名字，找到它，而后 render, render 时将 self 作为 scope 传入。至此 view 里可以调用 action 里所有的实例变量。&lt;code&gt;Tilt.new(view).render self&lt;/code&gt; 得到了应该返回的 html 的内容。&lt;/li&gt;
&lt;li&gt;上一步render得到的只是Controller#action对应的view, 需要将它交给 layout 处理。同样的使用&lt;code&gt;Tilt&lt;/code&gt;, 将上一步得到的 partial view 放到 block 中提交过去。这样 layout 中的&lt;code&gt;&amp;lt;%= yield %&amp;gt;&lt;/code&gt;关键字生效。至此，得到完整的 html 内容。&lt;/li&gt;
&lt;li&gt;Rack 要求调用 call 后的返回的值是一个三值的 array, 分别是 [status code, head content, body].上一步得到的是 html 内容就是 body 部分。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="如何使用和阅读本项目的源码"&gt;如何使用和阅读本项目的源码&lt;/h2&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/suffering/learnmvc.git
cd learnmvc
#在编辑器中打开
cd srbmvc
bundle install
cd ../simpleapp
bundle install
rackup -p 3002
#通过rackup方式打开后, 代码在更改后不会自动重载, 可以考虑使用rerun
# gem install rerun
# rerun 'rackup -p 3002'
#以这种方式运行, 对任何文件的修改都会重载代码. 简单模拟rails的development mode.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Demo app 运行后，可以看到项目正常运行。&lt;/p&gt;

&lt;p&gt;查看&lt;code&gt;simpleapp&lt;/code&gt;的源码，你会看到它的基本结构与 rails app 基本相同。&lt;/p&gt;

&lt;p&gt;查阅&lt;code&gt;srbmvc&lt;/code&gt;的源码，按前文的基本逻辑栏来查看代码，观看其调用链。代码中有少量的注释，没有解释具体的细节，只简单标注出此方法实现的目的与功能。此部分代码的关键点在于从 request 开始后的调用链，route 规则的指定与检查，controller#action的定位 以及 render view 部分。其他皆渣。&lt;/p&gt;

&lt;p&gt;请将&lt;code&gt;simpleapp&lt;/code&gt;与&lt;code&gt;srbmvc&lt;/code&gt;结合来阅读。&lt;/p&gt;

&lt;p&gt;最好的学习方式是，看完后，自己写一个。在写的过程中，会发现很多以前注意不到的细节。在实现 rails 的各种功能的过程中，你必须对 mvc 的协作方式进行深入思考。人在思考的过程中成长。&lt;/p&gt;

&lt;p&gt;感谢&lt;a href="/wikimo" class="user-mention" title="@wikimo"&gt;&lt;i&gt;@&lt;/i&gt;wikimo&lt;/a&gt;同学帮忙纠正错误~&lt;/p&gt;</description>
      <author>suffering</author>
      <pubDate>Fri, 12 Sep 2014 21:21:52 +0800</pubDate>
      <link>https://ruby-china.org/topics/21508</link>
      <guid>https://ruby-china.org/topics/21508</guid>
    </item>
    <item>
      <title>Jsquirks: 列出那些变态的 JS 类型转换</title>
      <description>&lt;p&gt;最近从基础开始学习 JS, 被其中的动态类型转换弄得受不了了，于是写了&lt;a href="https://github.com/suffering/jsquirks" rel="nofollow" target="_blank" title=""&gt;Jsquirks&lt;/a&gt;
(好吧，我承认是我在参加 Elance 的 JS Skill Test 时被里面的题玩了，于是我才决定重基础开始研究 JS 的.)
研究 JS 的动态类型转换时，总是试图去找其中的模式，结果往往自以为发现了一个能用规则，结果一眨眼就会蹦出个反例。于是就写了段代码用穷举的方式列出各种变态的特殊值与各种值的可能组合，同时列出其值.
后来干脆做成了网页版的，可自由选择用于组合的&lt;code&gt;operand&lt;/code&gt;与&lt;code&gt;operator&lt;/code&gt;. 
github 发布，而后上线。与大家分享。对 JS 有兴趣的同学可以去逛逛。各种希奇古怪的计算结果啊，我表示再也不会试图去总结什么固定模式了。&lt;/p&gt;

&lt;p&gt;好吧，贴上才写的&lt;code&gt;README.md&lt;/code&gt;:&lt;/p&gt;
&lt;h3 id="Javascript Quirks with special values and Operations"&gt;Javascript Quirks with special values and Operations&lt;/h3&gt;
&lt;p&gt;Demo online: &lt;a href="http://jsquirks.zhuboliu.me" rel="nofollow" target="_blank"&gt;http://jsquirks.zhuboliu.me&lt;/a&gt;&lt;/p&gt;
&lt;h4 id="Do What"&gt;Do What&lt;/h4&gt;
&lt;p&gt;The App combinate the special values and values you selected to simple expressions, run it with the function &lt;code&gt;eval&lt;/code&gt;, and display the list of outputs in a table and logged it in the console. By using this, you can find some weired pattern in javascript value type converting. &lt;/p&gt;
&lt;h4 id="Special Values"&gt;Special Values&lt;/h4&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;special_values&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;Infinity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kc"&gt;Infinity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="Operators"&gt;Operators&lt;/h4&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;arithmatic_operators&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;%&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;comparison_operators&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;logical_operators&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;||&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;equality_operators&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;==&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;!=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;===&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;!==&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;bitwise_operators&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;unary_operators&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typeof&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;void&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;!!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;operators&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;arithmatic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;arithmatic_operators&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;comparison&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;comparison_operators&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;logical&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;logical_operators&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;equality&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;equality_operators&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can add some other operations such as bitwise operaters to the list.&lt;/p&gt;
&lt;h4 id="Why am I doing this?"&gt;Why am I doing this?&lt;/h4&gt;
&lt;p&gt;As you know, Javascript will dynamically convert value type in different situations;&lt;/p&gt;

&lt;p&gt;The type converting is very weird. I tried to find the inner-rule of dynamic type converting, but I found nothing, It seems that there is no hard and fast rule at all. Every time I found a rule in one place, I found it was wrong in another place later.&lt;/p&gt;

&lt;p&gt;At last, I write this simple tool to help me find the rules, of cause it's useless. But with this tool I found some quirks I never found before. Hope this will help.&lt;/p&gt;

&lt;p&gt;If You are preparing for some javascript quiz ,for example Elance skill test, this may help.
If you found something wrong in the output, please send me a email or open an issue.
If you found some hard and fast rule, please pull request.&lt;/p&gt;
&lt;h4 id="Resources"&gt;Resources&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;CSS Framework: &lt;a href="http://getbootstrap.com" rel="nofollow" target="_blank"&gt;http://getbootstrap.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;View Template: &lt;a href="http://getbootstrap.com/examples/dashboard/" rel="nofollow" target="_blank"&gt;http://getbootstrap.com/examples/dashboard/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;JS Libary: 

&lt;ul&gt;
&lt;li&gt;angularjs: &lt;a href="http://angularjs.org" rel="nofollow" target="_blank"&gt;http://angularjs.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;checklist-model: &lt;a href="http://vitalets.github.io/checklist-model/" rel="nofollow" target="_blank"&gt;http://vitalets.github.io/checklist-model/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="TODO"&gt;TODO&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;add some resourses helpful for understanding the value type converting.&lt;/li&gt;
&lt;li&gt;add bitwise operators&lt;/li&gt;
&lt;li&gt;add &lt;code&gt;new&lt;/code&gt; to operators&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>suffering</author>
      <pubDate>Fri, 08 Aug 2014 01:46:25 +0800</pubDate>
      <link>https://ruby-china.org/topics/20901</link>
      <guid>https://ruby-china.org/topics/20901</guid>
    </item>
    <item>
      <title>升级到 Mac OSX 10.10, 若干天后, 所有 Homebrew 安装的程序全部挂掉</title>
      <description>&lt;p&gt;如题，有什么好的解决方案吗？&lt;code&gt;mysql&lt;/code&gt;, &lt;code&gt;mongodb&lt;/code&gt;, &lt;code&gt;redis&lt;/code&gt;等等等等全部挂掉，系统表示无此程序.
&lt;code&gt;brew update&lt;/code&gt;, &lt;code&gt;brew doctor&lt;/code&gt; 都无视了这些问题。troubleshooting 上也没有好的解决方案，真是无语啊.
话说升级后若干天一切运行正常，只是昨天把电脑交给两个小屁孩玩了一会儿而已，难道现在的的零零后都会折腾 terminal 了吗？
&amp;gt;_&amp;lt;&lt;/p&gt;</description>
      <author>suffering</author>
      <pubDate>Mon, 04 Aug 2014 11:45:03 +0800</pubDate>
      <link>https://ruby-china.org/topics/20829</link>
      <guid>https://ruby-china.org/topics/20829</guid>
    </item>
    <item>
      <title>经典排序算法资料及 ruby 实现</title>
      <description>&lt;h2 id="经典排序算法资料及ruby实现"&gt;经典排序算法资料及 ruby 实现&lt;/h2&gt;
&lt;p&gt;学习&amp;lt;算法导论&amp;gt;时到网络上找了一批排序算法的资料。结合参考资料分别用 ruby 写了一遍。这里分享给大家。配上图与参考资料。&lt;/p&gt;
&lt;h3 id="插入排序"&gt;插入排序&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/9c37b8be54c219e9edc5605376cadeeb.gif" title="" alt="insert sort"&gt;
&lt;img src="http://upload.wikimedia.org/wikipedia/commons/0/0f/Insertion-sort-example-300px.gif" title="" alt="insert sort"&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;insert_sort!&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;
      &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="冒泡排序"&gt;冒泡排序&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://upload.wikimedia.org/wikipedia/commons/5/54/Sorting_bubblesort_anim.gif" title="" alt="buble sort"&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://upload.wikimedia.org/wikipedia/commons/0/06/Bubble-sort.gif" title="" alt="buble sort"&gt;&lt;/p&gt;

&lt;p&gt;wikipedia 详解：&lt;a href="http://en.wikipedia.org/wiki/Insertion_sort" rel="nofollow" target="_blank"&gt;http://en.wikipedia.org/wiki/Insertion_sort&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://en.wikibooks.org/wiki/A-level_Computing/AQA/Problem_Solving,_Programming,_Data_Representation_and_Practical_Exercise/Problem_Solving/Searching_and_sorting" rel="nofollow" target="_blank" title=""&gt;Problem Solving: Searching and sorting&lt;/a&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bubble_sort!&lt;/span&gt;
  &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="鸡尾酒排序"&gt;鸡尾酒排序&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://upload.wikimedia.org/wikipedia/commons/e/ef/Sorting_shaker_sort_anim.gif" title="" alt="cocktail sort"&gt;&lt;/p&gt;

&lt;p&gt;wikipedia 详解：&lt;a href="http://en.wikipedia.org/wiki/Cocktail_sort" rel="nofollow" target="_blank"&gt;http://en.wikipedia.org/wiki/Cocktail_sort&lt;/a&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cocktail_sort!&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
      &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
      &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
         &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
         &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt; 
      &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="合并排序"&gt;合并排序&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://upload.wikimedia.org/wikipedia/commons/c/cc/Merge-sort-example-300px.gif" title="" alt="merge sort"&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://upload.wikimedia.org/wikipedia/commons/thumb/e/e6/Merge_sort_algorithm_diagram.svg/600px-Merge_sort_algorithm_diagram.svg.png" title="" alt="merge sort"&gt;&lt;/p&gt;

&lt;p&gt;wikipedia 详解：&lt;a href="http://en.wikipedia.org/wiki/Merge_sort" rel="nofollow" target="_blank"&gt;http://en.wikipedia.org/wiki/Merge_sort&lt;/a&gt;  &lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;merge_sort!&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="no"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge_sort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge_sort&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;sorted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="k"&gt;until&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;empty?&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;empty?&lt;/span&gt;
      &lt;span class="n"&gt;sorted&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;sorted&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="快速排序"&gt;快速排序&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif" title="" alt="quick sort"&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://upload.wikimedia.org/wikipedia/commons/9/9c/Quicksort-example.gif" title="" alt="quick sort"&gt;&lt;/p&gt;

&lt;p&gt;wikipedia 详解：&lt;a href="http://en.wikipedia.org/wiki/Quicksort" rel="nofollow" target="_blank"&gt;http://en.wikipedia.org/wiki/Quicksort&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;三种 qicksort 的实现方式：&lt;a href="http://c2.com/cgi/wiki?QuickSortInRuby" rel="nofollow" target="_blank"&gt;http://c2.com/cgi/wiki?QuickSortInRuby&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;在线图示加语音详解：&lt;a href="http://www.csanimated.com/animation.php?t=Quicksort" rel="nofollow" target="_blank"&gt;http://www.csanimated.com/animation.php?t=Quicksort&lt;/a&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;quick_sort!&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;empty?&lt;/span&gt;
  &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
  &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;partition&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quick_sort&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quick_sort&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="heapSort"&gt;heapSort&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://upload.wikimedia.org/wikipedia/commons/1/1b/Sorting_heapsort_anim.gif" title="" alt="heap sort"&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://upload.wikimedia.org/wikipedia/commons/4/4d/Heapsort-example.gif" title="" alt="heap sort"&gt;  &lt;/p&gt;

&lt;p&gt;wikipedia 详解：&lt;a href="http://en.wikipedia.org/wiki/Heapsort" rel="nofollow" target="_blank"&gt;http://en.wikipedia.org/wiki/Heapsort&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;更深入分析：&lt;a href="http://www.personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms/Sorting/heapSort.htm" rel="nofollow" target="_blank"&gt;http://www.personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms/Sorting/heapSort.htm&lt;/a&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;heap_sort!&lt;/span&gt;
  &lt;span class="c1"&gt;# in pseudo-code, heapify only called once, so inline it here&lt;/span&gt;
  &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;downto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;siftdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;

  &lt;span class="c1"&gt;# "end" is a ruby keyword&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;downto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;end_&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;end_&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;end_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;siftdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;siftdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;
  &lt;span class="kp"&gt;loop&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;end_&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;end_&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;

&lt;p&gt;最后，附上完整的 ruby 实现：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;
  &lt;span class="c1"&gt;# 插入排序&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;insert_sort!&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;
        &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# 快速排序&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;quick_sort!&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;empty?&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
    &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;partition&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quick_sort&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quick_sort&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# 冒泡排序&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bubble_sort!&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# 鸡尾酒排序(&amp;gt;_&amp;lt;)&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cocktail_sort!&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
      &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
      &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
         &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
         &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt; 
      &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# 合并排序&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;merge_sort!&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="no"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge_sort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge_sort&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sorted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;until&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;empty?&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;empty?&lt;/span&gt;
        &lt;span class="n"&gt;sorted&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;sorted&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# heap排序&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;heap_sort!&lt;/span&gt;
    &lt;span class="c1"&gt;# in pseudo-code, heapify only called once, so inline it here&lt;/span&gt;
    &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;downto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;siftdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;

    &lt;span class="c1"&gt;# "end" is a ruby keyword&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;downto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;end_&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;end_&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;end_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;siftdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;siftdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;
    &lt;span class="kp"&gt;loop&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;end_&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;end_&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="sx"&gt;%w(insert quick bubble cocktail merge heap)&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;metd&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;define_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;metd&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_sort"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;metd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_sort!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;shuffle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;grep&lt;/span&gt; &lt;span class="sr"&gt;/_sort/&lt;/span&gt;
&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert_sort&lt;/span&gt;
&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bubble_sort&lt;/span&gt;
&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quick_sort&lt;/span&gt;
&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cocktail_sort&lt;/span&gt;
&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge_sort&lt;/span&gt;
&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;heap_sort&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;gt;_&amp;lt; 请原谅我闪花了你的眼。神马？你觉得眼不花？那看看这个吧：&lt;a href="http://www.sorting-algorithms.com/" rel="nofollow" target="_blank"&gt;http://www.sorting-algorithms.com/&lt;/a&gt;&lt;/p&gt;</description>
      <author>suffering</author>
      <pubDate>Fri, 18 Jul 2014 13:23:50 +0800</pubDate>
      <link>https://ruby-china.org/topics/20569</link>
      <guid>https://ruby-china.org/topics/20569</guid>
    </item>
    <item>
      <title>RubyChinaSPA by Anugarjs 发布</title>
      <description>&lt;p&gt;闲时写的基于 Angularjs 的 ruby-china.org spa 端。&lt;/p&gt;

&lt;p&gt;&lt;img title=":smile:" alt="😄" src="https://twemoji.ruby-china.com/2/svg/1f604.svg" class="twemoji"&gt; 本贴发自 spa 端 (截图除外).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/suffering/rubychinaspa" rel="nofollow" target="_blank" title=""&gt;https://github.com/suffering/rubychinaspa&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="rubyChinaSpa"&gt;rubyChinaSpa&lt;/h2&gt;
&lt;p&gt;Build with angularjs and ruby-china.org api/v2.&lt;/p&gt;
&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;p&gt;ruby-china.org 的 SPA 版，根据 ruby-china.org api 制作。使用简单的 angularjs 语法，未涉及复杂的 directive 与 filters 等。&lt;/p&gt;
&lt;h2 id="功能"&gt;功能&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;帖子 (index/show)&lt;/li&gt;
&lt;li&gt;节点 (index/show)&lt;/li&gt;
&lt;li&gt;用户 (index/show)&lt;/li&gt;
&lt;li&gt;用户登陆 (基于 loginname, token)

&lt;ul&gt;
&lt;li&gt;发表新贴&lt;/li&gt;
&lt;li&gt;发表评论&lt;/li&gt;
&lt;li&gt;收藏帖子&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;支持 markdown 即时预览 (预览格式与 ruby-china.org 原站略有不同.)&lt;/li&gt;
&lt;li&gt;支持 emoji&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="DEMO"&gt;&lt;del&gt;DEMO&lt;/del&gt;&lt;/h2&gt;
&lt;p&gt;&lt;del&gt;因为 CROS 的原因，无论是在线测试还是本地测试，都无法获取 ruby-china.org 的 api 数据。除非 ruby-china.org 管理员允许 CROS.&lt;/del&gt;&lt;/p&gt;

&lt;p&gt;当前 ruby-china.org 官方已支持 CROS, :), 此节可省。以下部分保留以作参考;&lt;/p&gt;
&lt;h3 id="DEMO运行的前提"&gt;&lt;del&gt;DEMO 运行的前提&lt;/del&gt;&lt;/h3&gt;
&lt;p&gt;&lt;del&gt;Google chrome 浏览器通过运行非安全模式 (暂时) 解决此问题：&lt;/del&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linux: &lt;code&gt;google-chrome --disable-web-security&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Mac: &lt;code&gt;open -a Google\ Chrome --args --disable-web-security&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;windows: 进入到 chrome 安装目录，&lt;code&gt;chrome.exe --disable-web-security&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;注意：必须完全关闭 google chrome 之后再运行此命令。否则只要有任何一个 chrome 实例存在，此模式将启动失败。&lt;/p&gt;

&lt;p&gt;如果运行命令后出现&lt;code&gt;You are using an unsupported command-line flag: --disable-web-security. Stability and security will suffer.&lt;/code&gt; 或 &lt;code&gt;您使用的是不受支持的命令行标记: —disable-web-security. 稳定性和安全性会有所下降.&lt;/code&gt;的提示，即可正常浏览。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://stackoverflow.com/questions/3102819/disable-same-origin-policy-in-chrome/6083677#6083677" rel="nofollow" target="_blank" title=""&gt;参考&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="Online Demo:"&gt;Online Demo:&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://rbspa.zhuboliu.me" rel="nofollow" target="_blank" title=""&gt;http://rbspa.zhuboliu.me&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;测试帐号&lt;/strong&gt;: rbspa&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;token&lt;/strong&gt;: 3d8757cc530374f18778:13471&lt;/p&gt;

&lt;p&gt;以上帐号仅为新注册的测试帐号，不能发帖，只能回帖。&lt;/p&gt;

&lt;p&gt;注意：可以使用个人的登陆名与 token 登陆，但不推荐使用 (虽然个人保证不在 log 中记录任何个人的 token).&lt;/p&gt;
&lt;h3 id="本地测试"&gt;本地测试&lt;/h3&gt;
&lt;p&gt;git clone &lt;a href="https://github.com/suffering/rubychinaspa.git" rel="nofollow" target="_blank"&gt;https://github.com/suffering/rubychinaspa.git&lt;/a&gt;
    cd rubychinaspa
    npm install connect
    node server.js
    google-chrome &lt;a href="http://localhost:1337" rel="nofollow" target="_blank"&gt;http://localhost:1337&lt;/a&gt; --disable-web-security&lt;/p&gt;

&lt;p&gt;本地测试分两种模式，一种是直接引用 ruby-china.org/api/v2 的数据，另一种是本地运行 ruby-china, 而后将&lt;code&gt;services.js&lt;/code&gt;中的&lt;code&gt;base_url()&lt;/code&gt;函数的返回值改为&lt;code&gt;http://localhost:3000&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="TODO"&gt;TODO&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;简化代码，引入更多 angularjs 的高阶应用。&lt;/li&gt;
&lt;li&gt;用户&lt;code&gt;喜欢&lt;/code&gt;/&lt;code&gt;收藏&lt;/code&gt;功能。&lt;/li&gt;
&lt;li&gt;图片上传功能&lt;/li&gt;
&lt;li&gt;允许多界面多主题切换。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;帖子列表&lt;/strong&gt;
&lt;img src="https://l.ruby-china.com/photo/2014/9bdfcb9484284a9165f9911ee6f81938.png" title="" alt=""&gt;
&lt;strong&gt;发帖，markdown 即时预览&lt;/strong&gt;
&lt;img src="https://l.ruby-china.com/photo/2014/929a5e67edcf3743eb63fa672097ee71.png" title="" alt=""&gt;
&lt;strong&gt;节点&lt;/strong&gt;
&lt;img src="https://l.ruby-china.com/photo/2014/89de6a00aefd4a7eb5e7663b5855320d.png" title="" alt=""&gt;
&lt;strong&gt;Login&lt;/strong&gt;
&lt;img src="https://l.ruby-china.com/photo/2014/a80b340ff8d0cbb2924fe965dc0ffde3.png" title="" alt=""&gt;
&lt;strong&gt;Users#show&lt;/strong&gt;
&lt;img src="https://l.ruby-china.com/photo/2014/82fd1f0051d02e43d0f164ce82750478.png" title="" alt=""&gt;
&lt;img src="https://l.ruby-china.com/photo/2014/ef497440fcecae29b279445df7c41fde.png" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="相关的帖子"&gt;相关的帖子&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://ruby-china.org/topics/19531" rel="nofollow" target="_blank"&gt;https://ruby-china.org/topics/19531&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/19654" rel="nofollow" target="_blank"&gt;https://ruby-china.org/topics/19654&lt;/a&gt;&lt;/p&gt;</description>
      <author>suffering</author>
      <pubDate>Thu, 05 Jun 2014 02:20:49 +0800</pubDate>
      <link>https://ruby-china.org/topics/19745</link>
      <guid>https://ruby-china.org/topics/19745</guid>
    </item>
    <item>
      <title>通过 API POST photos 时的 BUG</title>
      <description>&lt;p&gt;本地测试使用 ruby-china.org 的 api_v2 进行图片上传。图片上传成功，但是返回的地址却都是 &lt;code&gt;photo/.jpg&lt;/code&gt;. 在&lt;code&gt;console&lt;/code&gt;里找到上传的图片 &lt;code&gt;Photo.all.collect{|t| t.image.url}&lt;/code&gt;, 返回的地址也全部都是&lt;code&gt;photo/.jpg&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;查看 log, 发现 &lt;code&gt;params[:Filedata]&lt;/code&gt; 是一个 &lt;code&gt;&amp;lt;Hashie::Mash&amp;gt;&lt;/code&gt;. 而 carrierwave 是无法处理它的。&lt;/p&gt;

&lt;p&gt;试着将&lt;code&gt;Hashie::Mash&lt;/code&gt;转化为&lt;code&gt;ActionDispatch::Http::UploadedFile&lt;/code&gt; 对象后上传也失败了。&lt;/p&gt;

&lt;p&gt;通过 API POST 的图片对象是：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#&amp;lt;Hashie::Mash Filedata=#&amp;lt;Hashie::Mash filename="4.png" head="Content-Disposition: form-data; name=\"Filedata\"; filename=\"4.png\"\r\nContent-Type: image/png\r\n" name="Filedata" tempfile=#&amp;lt;Tempfile:/var/folders/27/xnmldrkd5f3fq07zvfzb9by00000gn/T/RackMultipart20140530-7213-1t6ys2x&amp;gt; type="image/png"&amp;gt; format="json" route_info=#&amp;lt;Grape::Route:0x0000010443eef0 @options={:prefix=&amp;gt;"api", :version=&amp;gt;"v2", :namespace=&amp;gt;"/photos", :method=&amp;gt;"POST", :path=&amp;gt;"/api/:version/photos(.:format)", :params=&amp;gt;{}, :compiled=&amp;gt;/\A\/api\/(?&amp;lt;version&amp;gt;v2)\/photos(?:\.(?&amp;lt;format&amp;gt;[^\/.?]+))?\Z/}&amp;gt; token="[FILTERED]" version="v2"&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;hack 后的代码&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#api_v2&lt;/span&gt;
&lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="ss"&gt;:photos&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;authenticate!&lt;/span&gt;
      &lt;span class="n"&gt;filedata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:Filedata&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;filedata_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="ss"&gt;:filename&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;filedata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:filename&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="ss"&gt;:orginal_filename&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;filedata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:filename&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="ss"&gt;:type&lt;/span&gt;     &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;filedata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:type&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="ss"&gt;:headers&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;filedata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:head&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="ss"&gt;:tempfile&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;filedata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:tempfile&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="vi"&gt;@photo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Photo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
      &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"------ &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="vi"&gt;@photo.image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ActionDispatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Http&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;UploadedFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filedata_hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt; &lt;span class="vi"&gt;@photo.image.inspect&lt;/span&gt;
      &lt;span class="vi"&gt;@photo.user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@photo.save&lt;/span&gt;
        &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"------ &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@photo.inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="vi"&gt;@photo.image.url&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;error!&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@photo.errors.full_messages&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;关于这个问题，是否需要其他方式的 POST, 比如说 BINARY MODE 之类的。折腾了好久，一直没能解决这个问题。&lt;/p&gt;</description>
      <author>suffering</author>
      <pubDate>Fri, 30 May 2014 17:27:27 +0800</pubDate>
      <link>https://ruby-china.org/topics/19654</link>
      <guid>https://ruby-china.org/topics/19654</guid>
    </item>
    <item>
      <title>ruby china SPA by angular js</title>
      <description>&lt;p&gt;闲着无聊使用 anuglarjs 做的 ruby-china.org 的 SPA 应用。&lt;/p&gt;

&lt;p&gt;当前只有远程看帖，发帖，回帖的功能，界面也是随便弄的一个，上图片：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/f2baafb63874a041872d61f8207e95a0.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/8c26215d3ac8b0cfc36adeff1573e6d6.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;功能上有点鸡肋，希望有一天能被采用，到时 rubychina 能切换多主题，甚至自定义界面 : )&lt;/p&gt;
&lt;h2 id="changelog"&gt;changelog&lt;/h2&gt;
&lt;p&gt;5 月 29&lt;/p&gt;

&lt;p&gt;新增 创建贴子或添加评论时的&lt;strong&gt;markdown&lt;/strong&gt;内容实时预览，支持 emoji. 
上图片:
&lt;img src="https://l.ruby-china.com/photo/2014/f28fae5718ec0df1feb5bbb90fbeb191.png" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>suffering</author>
      <pubDate>Mon, 26 May 2014 04:34:13 +0800</pubDate>
      <link>https://ruby-china.org/topics/19531</link>
      <guid>https://ruby-china.org/topics/19531</guid>
    </item>
    <item>
      <title>写求职信的 gem - zresume</title>
      <description>&lt;p&gt;最近写的用来求职的 GEM, 很简单，希望对求职或招聘有帮助.
RUBY 程序员就应该以 RUBY 的方式来写简历.
&lt;a href="https://github.com/suffering/zresume" rel="nofollow" target="_blank"&gt;https://github.com/suffering/zresume&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;写这个 gem 主要是为了我个人求职。我想的是写这么个 gem, 在中间用一些自己擅长的技巧，招聘的人若有兴趣可以去看一下源码 (源码也很简单，只有三个文件),看完了，大概也了解了我的水平了，合适与否也一目了然了。这样双方省事不少。&lt;/p&gt;</description>
      <author>suffering</author>
      <pubDate>Tue, 02 Apr 2013 14:45:13 +0800</pubDate>
      <link>https://ruby-china.org/topics/9923</link>
      <guid>https://ruby-china.org/topics/9923</guid>
    </item>
    <item>
      <title>如何在 Mongoid 下做出 active_record 下的 STI (Single Table Inheritance) 逻辑？</title>
      <description>&lt;p&gt;碰到个蛋疼的要求！类似于在 active_record 下使用的 STI(Single Table Inheritance) 逻辑。
换个说法：Mongoid inheritance，如何利用父类的 controller 与 view 创建对象到指定子类？
Model 如下：
&lt;strong&gt;Models&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#1&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Mongoid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Document&lt;/span&gt;
  &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:products&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:pages&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;#2&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Pagecategory&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Category&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;#3&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Prodcategory&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Category&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;#4&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Page&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Mongoid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Document&lt;/span&gt;
  &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;
  &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:content&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:category&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;#5&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Mongoid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Document&lt;/span&gt;
  &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;
  &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:description&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:category&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;




&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;要求可以使用已有的 categories 的 controller 与 views 直接创建 Pagecategory 与 Prodcategory 的实例。（不新建任何 controller 与 views）。
可以直接在新建 product 时选择其类。模式如下：
&amp;lt;%= simple_form_for &lt;a href="/Product" class="user-mention" title="@Product"&gt;&lt;i&gt;@&lt;/i&gt;Product&lt;/a&gt; do |f|%&amp;gt;
    &amp;lt;%= f.input :category_id, :collection =&amp;gt; Prodcategory.all %&amp;gt;
        &amp;lt;%= f.input :name %&amp;gt;
        &lt;/p&gt;
          &amp;lt;%= f.submit %&amp;gt;
        
&amp;lt;% end %&amp;gt;
问题变成了&lt;code&gt;如何在创建category时，将其自由创建到Pagecategory或Prodcategory?(不让新建controller与view)&lt;/code&gt;
这相当于是让 categories 多态。但是，有这种搞法吗？
有没有好的解决方案？</description>
      <author>suffering</author>
      <pubDate>Thu, 22 Mar 2012 17:11:48 +0800</pubDate>
      <link>https://ruby-china.org/topics/2064</link>
      <guid>https://ruby-china.org/topics/2064</guid>
    </item>
    <item>
      <title>github 再一次被墙了？还是仅仅只是我这里的网络环境的问题？</title>
      <description>&lt;p&gt;杯具啊~~~  &lt;/p&gt;</description>
      <author>suffering</author>
      <pubDate>Thu, 22 Mar 2012 14:26:27 +0800</pubDate>
      <link>https://ruby-china.org/topics/2056</link>
      <guid>https://ruby-china.org/topics/2056</guid>
    </item>
    <item>
      <title>如何把握 DRY 的度？</title>
      <description>&lt;p&gt;在 Rails 编程中，感觉很难把握 DRY 原则的度。&lt;/p&gt;

&lt;p&gt;比如说有一个流程，建立 product 模型。
编程 MVC 将所有的功能都做好了。
&lt;strong&gt;routes.rb 如下：&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="s1"&gt;'/products/:id/hide'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'products#hide'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:hide_product&lt;/span&gt;
  &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="s1"&gt;'/products/:id/release'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'products#release'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:release_product&lt;/span&gt;
  &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="s1"&gt;'/products/offlines'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'products#offline'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:product_offline&lt;/span&gt;
  &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:products&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="s1"&gt;'sort'&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在要加一个独立后台，运行&lt;code&gt;rails generate controller Cpanel::Products&lt;/code&gt;.
至此，在 routes.rb 里除了原本的&lt;code&gt;resources :products&lt;/code&gt;外又多出了：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ss"&gt;:cpanel&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:products&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;到这一步得去编辑 namespace，将算定义的 hide,release,offlines,sort 之类的方法重写一次。&lt;/p&gt;

&lt;p&gt;同时，views 里相应地也建立了 cpanel/products, controllers 里相应建立了 cpanel/products_controller.rb 文件。&lt;/p&gt;

&lt;p&gt;于是又得将已经写好的 view 与 controller 重写一次。
当然，可以直接&lt;code&gt;render :file =&amp;gt; 'products/show'&lt;/code&gt;,&lt;code&gt;render :file =&amp;gt; 'products/index'&lt;/code&gt;,但是，很明显，如果 render 'products/form'的话在后台里编辑后会直接跳转到前端 show 页面。&lt;/p&gt;

&lt;p&gt;这样的话，routes,views,controllers 里多出了许多只有细微差别的代码。虽然只要 copy 一下，但是感觉上却非常糟糕，很明显是违背 DRY 原则的。&lt;/p&gt;

&lt;p&gt;在这种情况下，有什么好的解决方案？copy 不累人，只是这样整出的代码自己都觉得无法原谅。  &lt;/p&gt;</description>
      <author>suffering</author>
      <pubDate>Tue, 20 Mar 2012 17:54:11 +0800</pubDate>
      <link>https://ruby-china.org/topics/1999</link>
      <guid>https://ruby-china.org/topics/1999</guid>
    </item>
    <item>
      <title>RAILS 中 如何上传超过 200M~300M 的文件？</title>
      <description>&lt;p&gt;&lt;strong&gt;配置：&lt;/strong&gt;
&lt;code&gt;
LINUX UBUNTU 10.04 (Linode VPS)
NGINX 
PASSENGER
RUBY 1.9.3
RAILS 3.2.1
&lt;/code&gt;
其中，nginx 的配置基本保持默认状态。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;相关代码：&lt;/strong&gt;
&lt;em&gt;Gemfile:&lt;/em&gt;
&lt;code&gt;
gem 'mongoid'
gem 'paperclip_mongoid'
&lt;/code&gt;
&lt;em&gt;Model:&lt;/em&gt;
&lt;code&gt;
class Support
  include Mongoid::Document
  include Mongoid::Paperclip
  validates_attachment_size :download, :less_than =&amp;gt; 300.megabytes
  validates_attachment_presence :download
end
&lt;/code&gt;
这样的配置，在本地时上传文件没有问题。但是在服务器上之后，20M 的文件都没能成功上传过一个。  &lt;/p&gt;</description>
      <author>suffering</author>
      <pubDate>Tue, 13 Mar 2012 17:27:26 +0800</pubDate>
      <link>https://ruby-china.org/topics/1835</link>
      <guid>https://ruby-china.org/topics/1835</guid>
    </item>
    <item>
      <title>如何让 RAILS 支持中文路径？</title>
      <description>&lt;p&gt;使用 paperclip 上传文件。
客户需要可以上传中文的文件。但是，在 rails 里，似乎&lt;code&gt;&amp;lt;%= link_to “download", “你好.rar" %&amp;gt;&lt;/code&gt;这样的链接会找不到文件。报的是 routes 错误。
试过 URI.encode 的方案，不行。大家平时是怎么做的？  &lt;/p&gt;</description>
      <author>suffering</author>
      <pubDate>Mon, 12 Mar 2012 16:00:49 +0800</pubDate>
      <link>https://ruby-china.org/topics/1806</link>
      <guid>https://ruby-china.org/topics/1806</guid>
    </item>
  </channel>
</rss>
