Sinatra通过helpers
和register
函数进行扩展
首先看一下helpers
函数,用来是来扩展Base类的实例方法。
1 2 3 4
| def helpers(*extensions, &block) class_eval(&block) if block_given? include(*extensions) if extensions.any? end
|
在看一下register
函数,用来扩展Base类的类方法
1 2 3 4 5 6 7 8
| def register(*extensions, &block) extensions << Module.new(&block) if block_given? @extensions += extensions extensions.each do |extension| extend extension extension.registered(self) if extension.respond_to?(:registered) end end
|
两个方法都支持通过代码块扩展,也支持通过Module来扩展。
两种扩展方法对应Sinatra的两种编程风格。
Sinatra编程的两种风格:
经典风格:
1 2 3 4 5
| require'sinatra' get '/' do "hello world" end
|
模块化风格:
1 2 3 4 5 6 7 8 9 10
| require'sinatra/base' class Hello < Sinatra::Base get "/" do "hello world" end run! end
|
为两种风格编写扩展:
Sinatra扩展也分为两种:
helper 型
dsl 型
helper型:
1 2 3 4 5 6 7 8 9 10 11
| require 'sinatra/base' module Sinatra module FormatHelper def escape_html(text) Rack::Utils.escape_html(text) end end helpers FormatHelper end
|
classic style 使用extension
1 2 3 4 5
| require 'sinatra' get '/' do escape_html("x > y") end
|
modular style 使用extension
1 2 3 4 5 6 7 8 9 10 11 12
| require 'sinatra/base' class Hello < Sinatra::Base helpers Sinatra::FormatHelper get '/' do escape_html("x > y") end run! end
|
这里的helpers
其实相当于include
dsl型:
1 2 3 4 5 6 7 8 9 10 11 12 13
| require 'sinatra/base' module Sinatra module Devise def authenticate! before { halt 403, "You Bastards!" } end end register Devise end
|
classic style 使用 dsl extension
1 2 3 4 5 6 7
| require 'sinatra' authenticate! get '/' do escape_html("x > y") end
|
modular style 使用 dsl extension
1 2 3 4 5 6 7 8 9 10 11 12 13
| require 'sinatra/base' class Hello < Sinatra::Base register Sinatra::Devise authenticate! get '/' do "hello world" end run! end
|
上面就是两种扩展的用法,我们在深入一点
在Sinatra/main
的最后几行可以看到extend Sinatra::Delegator
,其实当 require 'sinatra'
的时候就是执行的上面那行代码,作为整个Sinatra的入口。
看一下Delegator
模块,默认的target是Application
,也就是helpers
和register
等Sinatra的一干关键字get post ...
等都是通过动态派发给Application
类执行的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| module Delegator def self.delegate(*methods) methods.each do |method_name| define_method(method_name) do |*args, &block| return super(*args, &block) if respond_to? method_name Delegator.target.send(method_name, *args, &block) end private method_name end end delegate :get, :patch, :put, :post, :delete, :head, :options, :link, :unlink, :template, :layout, :before, :after, :error, :not_found, :configure, :set, :mime_type, :enable, :disable, :use, :development?, :test?, :production?, :helpers, :settings, :register class << self attr_accessor :target end self.target = Application end
|
Delegator
模块功能就是定义派发给Application
的函数(不管实现,只是转发)
整个通过Delegator.delegate
注册的方法的实现都在Helper
这个模块里,在Base
类里include
各种方法的实现,然后Application
在继承Base
,有点绕~。
1 2 3 4 5 6
| class Base include Rack::Utils include Helpers include Templates ... end
|
通过一张图理清楚他们的关系
定义自己的关键字,像get post
这样。
扩展方法首先在Delegator
模块调用delegate
方法的时候添加你扩展的关键字名称,类似delegate :get, :patch, ... , :my_fun
, 然后在Helper
模块里定义my_fun
的实现
1 2 3 4 5 6
| module Helpers my_fun p "my_fun" end ... end
|
这样就可以像关键字一样使用my_fun了,当然也可以通过上面介绍的两个方法进行扩展。
参考 http://saito.im/note/Sinatra-Extensions/