构建 Rack-based 框架 (Rails/Grape/Sinatra) 的几个 Tricks

简介: 构建 Rack-based 框架 (Rails/Grape/Sinatra) 的几个 Tricks

曾经看过一本书《Rebuilding Own Rails》,土豪请支持作者。对于中国读者来说,此书确实挺贵。

看了这两本书以后,略作总结,顺便和大家分享一下。

Trick #1 Rack

无论是 Rails、还是 Sinatra 这些基于 Rack 的框架,原理都是调用 Rack 的 call 函数,此函数接受一个参数,env。 Rack 的基本原理,是把对 Rack 对象发送 HTTP 请求的“环境“,变量 env,作为参数来调用 call 方法,然后把返回值当作是对请求的回应。 在我们生成的 Rails 应用程序里面,有个文件config.ru,这个文件就是为 Rack 准备的。 我们可以试试如下代码 (节选至《代码的未来》,210 页):

# hello.rb
class HelloApp
   def call(env)
       [ 200,                                  # 依次是 HTTP 状态码,200表示成功;
         {"Content-Type" => "text/plain"},    #  HTTP 响应头部(即HTML文件中header部分),放在Hash中;
         ["Hello, Rack World!"]              # HTTP 响应主体(即HTML文件中body部分,也就是我们打开浏览器看到的内容)
                                                  #必须是字符串数组。(为什么是字符串数组,而不是字符串?)
       ]       
   end
end

call 函数的返回值,最后一个 body 部分,因为在 Ruby 1.9 里,如果是字符串,就会导致程序崩溃,所以必须是 Enumerator 类型的,(可接受 each 方法),具体前往Rack SPEC

另外需要准备一个配置文件,以.ru结尾

# hello.ru
require  'rubygems'
require 'rack'
require 'hello'
#至为关键的一句
run HelloApp.new

然后在命令行终端运行:

$ rackup hello.ru

在 Rails 项目里,相应的配置文件名为config.ru

# config.ru
# This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment',  __FILE__)   # 包含启动文件
run Rails.application  #启动程序

如果你在 Rails 应用的目录下运行以下命令,会有如下输出:

diancai.in master % rackup config.ru
[2015-10-12 21:36:37] INFO  WEBrick 1.3.1
[2015-10-12 21:36:37] INFO  ruby 2.2.3 (2015-08-18) [x86_64-darwin15]
[2015-10-12 21:36:37] INFO  WEBrick::HTTPServer#start: pid=6490 port=9292

神奇吧!

好了,说完 Rack 的基础知识,再看看 Sinatra 是怎么使用 Rack 的。

Trick #2 Application = Sinatra::Base.new

这个是用来简化代码,让框架看起来更像是 DSL。 以下代码来自于Let's Build Sinatra

module Nancy
     class Base
     end
     Application = Base.new
end

这个其实很容易理解,但是对简化代码来说,不得不说是一个巧妙的设计。

Trick #3 Delegator

这一点稍微有点让人费解

module Nancy
  module Delegator
    def self.delegate(*methods, to:)
      Array(methods).each do |method_name|
        define_method(method_name) do |*args, &block|
          to.send(method_name, *args, &block)
        end
        private method_name
      end
    end
    delegate :get, :patch, :put, :post, :delete, :head, to: Application
  end
end

这段代码采用元编程的技术,让我们在调用函数时不必这样写:

Application.get "/", {}

而可以直接写成

get '/', {}

上面的代码利用 define_method 动态定义了:get, :patch 等,而且把这些方法作为 Application(即:Nancy::Base.new 实例的实例方法)。

它的真正的 trick 在于,在利用这个框架,写的应用程序,如:

# app.rb
# run with `ruby app.rb`
require "./nancy"
get "/" do
  "Hey there!"
end

中,表面上好像直接调用 Object 的 get 方法,于是你查看所有 ruby 文档也没有 get 这个方法,你可能有点崩溃了,不知道它是来自于那里,干什么用的。 其实,就是因为在nancy.rb里面有一句include Nancy::Delegator, 我们把get方法补全,就一下看明白这个故意设计的 trick;

# app.rb
# run with `ruby app.rb`
require "./nancy"
Nancy::Application.get "/" do
  "Hey there!"
end

或者更近一步:

# app.rb
# run with `ruby app.rb`
require "./nancy"
Nancy::Base.new.get "/" do
  "Hey there!"
end

这样写,就清楚明了了,但是可能写两句你就很不乐意了。

总结,无论是 Rails,还是 Sinatra,在使用了这些元编程技术之后,让我们的代码更加简洁,也让我们对于代码所要完成的任务更加清晰明了。

相关文章
|
11月前
|
存储 Ubuntu Linux
【Matter】Matter 环境构建参考文档
【Matter】Matter 环境构建参考文档
254 0
|
12月前
|
存储 缓存 Rust
深入浅出 tnpm rapid 模式 - 如何比 pnpm 快 10 秒
深入浅出 tnpm rapid 模式 - 如何比 pnpm 快 10 秒
193 1
|
开发工具 git Ruby
生成和定制Rails生成器和模板 Creating and Customizing Rails Generators & Templates2
生成和定制Rails生成器和模板 Creating and Customizing Rails Generators & Templates
79 0
|
API Ruby
生成和定制Rails生成器和模板 Creating and Customizing Rails Generators & Templates
生成和定制Rails生成器和模板 Creating and Customizing Rails Generators & Templates
91 0
|
XML 存储 SQL
Google Architecture Components应用框架初探
Google Architecture Components应用框架初探
259 0
Google Architecture Components应用框架初探
|
JavaScript Apache Ruby
用 Passenger(mod_rails) 部署 Sinatra
最近写了一些小 app / web service ,因为用不到 rails 那样的大架构和功能,于是尝试了 sinatra。
102 0
用 Passenger(mod_rails) 部署 Sinatra
|
Web App开发 人工智能 测试技术
书籍:Learn Web Development with Python - 2018.pdf
简介 使用最流行的Python Web框架(Django)进行Web编程的Python编程综合指南 主要特点 了解使用Python编程和构建Web应用程序的基础知识 使用Django从头开始构建Web应用程序 使用最新的Django框架创建真实的RESTful Web服务 图书说明 如果您想使用Django开发完整的Python Web应用程序,这个学习路径适合您。