Sinatra sinatra 的扩展机制.

Saito · 2012年03月25日 · 最后由 yangwen13 回复于 2013年12月18日 · 7671 次阅读

sinatra 扩展:

Sinatra 编程的两种风格:

经典风格:

require'sinatra'

get '/' do
  "hello world"
end



模块化风格:

require'sinatra/base'

class Hello < Sinatra::Base

  get "/" do
    "hello world"
  end

  run!
end



为两种风格编写扩展:

Sinatra 扩展也分为两种:

  • helper 型

  • dsl 型

helper 型:

require 'sinatra/base'

module Sinatra
  module FormatHelper
    def escape_html(text)
      Rack::Utils.escape_html(text)
    end
  end

  # make sure classic style can use this extension
  helpers FormatHelper 
end



classic style 使用 extension

require 'sinatra'

get '/' do
  escape_html("x > y")
end



modular style 使用 extension

require 'sinatra/base'

class Hello < Sinatra::Base

  helpers Sinatra::FormatHelper

  get '/' do
    escape_html("x > y")
  end

  run!
end



dsl 型:

require 'sinatra/base'

module Sinatra
  module Devise
    def authenticate!
      before {
        halt 403, "You Bastards!"
      }
    end
  end

  # make sure classic style can use this extension
  register Devise
end



classic style 使用 dsl extension

require 'sinatra'

authenticate!

get '/' do
  escape_html("x > y")
end



modular style 使用 dsl extension

require 'sinatra/base'

class Hello < Sinatra::Base
  register Sinatra::Devise

  authenticate!

  get '/' do
    "hello world"
  end

  run!
end



两种扩展可以为 sinatra 扩展很多东西。

例如:

actionpack 的各种 helpers. 可以移植到 sinatra 上面来。

sinatra 自己的 devise 也是很容易通过扩展机制来实现的。

Sinatra helpers 和 register 的实现机制。

# lib/sinatra/base.rb#1772L
# Extend the top-level DSL with the modules provided.
def self.register(*extensions, &block)
  Delegator.target.register(*extensions, &block)
end

# Include the helper modules provided in Sinatra's request context.
def self.helpers(*extensions, &block)
  Delegator.target.helpers(*extensions, &block)
end



如果 Delegator.target 本身没有被覆盖。则为 Application 本身。

而 Application 的 register 方法如下:

# lib/sinatra/base.rb#1681L
def self.register(*extensions, &block) #:nodoc:
  added_methods = extensions.map {|m| m.public_instance_methods }.flatten
  Delegator.delegate(*added_methods)
  super(*extensions, &block)
end



将扩展的 public_instace_methods 全部抽出来了,然后给 Delegator.然后 delegator 通过 send 动态调用该 method.

Sinatra 核心的方法几乎都是 delegate 方式实现的:

# lib/sinatra/base.rb#1702L
delegate :get, :patch, :put, :post, :delete, :head, :options, :template, :layout,
             :before, :after, :error, :not_found, :configure, :set, :mime_type,
             :enable, :disable, :use, :development?, :test?, :production?,
             :helpers, :settings


Sinatra 的 helper 则是直接被 include 至当前 module 或者 classic 模式下面的。

MRI vs JVM

JVM:

java version "1.6.0_29"

Java(TM) SE Runtime Environment (build 1.6.0_29-b11-402-11D50)

Java HotSpot(TM) 64-Bit Server VM (build 20.4-b02-402, mixed mode)

        user       system     total       real
send    0.378000   0.000000   0.378000 (  0.335000)
method  0.114000   0.000000   0.114000 (  0.114000)



MRI:

ruby 1.9.3p125 (2012-02-16 revision 34643) [x86_64-darwin11.3.0]

        user       system     total       real
send    0.290000   0.000000   0.290000 (  0.284137)
method  0.280000   0.000000   0.280000 (  0.281496)



不难想象 JRuby 下的 sinatra 跑的比较慢.(暂时没有 openjdk7 的环境,或许在 JDK7 下会跑的比较快.)

原文链接:http://saito.im/note/Sinatra-Extensions/

好文啊,受教学习了! 希望楼主可以多写一些关于 sinatra 的文章 :)

jruby 应该比 MRI 快不少的,要等 JVM 和 Jruby 都 warmup。 另外最近 padrino 貌似已经超过 sinatra 的使用了。

顶,写的很好

jruby 也就跑 benchmark 快一些⋯⋯

thx。。受益匪浅

大家都用模块化风格?

#8 楼 @hooopo 我们用 经典风格,全部 require 进来就能跑。

模块化风格不好使..

#9 楼 @Saito 文档好像推荐的是模块化风格啊!

模块化风格相当于给了你一个作用域.. 域与域之间隔离。helper plugins 什么的不会串。

大概就这点好处。

#11 楼 @Saito 是我的话,我也推荐模块化风格,我写的话还是经典 . 哈哈!

#12 楼 @Saito 模块化可以 mount 多个 app?我看 padrino 是这样的。

#13 楼 @hooopo mount 逻辑是自己写的,rack 支持你这么做的。

经典的话分文件一起 require 进来就好了。模块化感觉分文件就很别扭..

建议企业级系统用模块化风格。

hooopo How Sinatra Works 提及了此话题。 07月12日 13:45
Ice-storm Sinatra 扩展机制原理分析 提及了此话题。 07月15日 23:47
需要 登录 后方可回复, 如果你还没有账号请 注册新账号