Sinatra sinatra 的扩展机制.

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

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/

共收到 15 条回复

好文啊,受教学习了! 希望楼主可以多写一些关于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
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册