Sinatra源码学习【上】

简介: Sinatra是一个ruby的轻量级Web框架,这这个框架总共就1000多行代码,非常简洁,值得一读。 一、Sinatra组成 Sinatra的主要实现的代码在base.rb中,主要有以下几个部分: Request:继承于Rack::Request,用于描述一个请求,通过这个类可以很方便获取到请求

Sinatra是一个ruby的轻量级Web框架,这这个框架总共就1000多行代码,非常简洁,值得一读。

 

一、Sinatra组成


Sinatra的主要实现的代码在base.rb中,主要有以下几个部分:


  1. Request:继承于Rack::Request,用于描述一个请求,通过这个类可以很方便获取到请求 中的各个CGI参数


  1. Response:继承于Rack::Response,用于描述一个响应


  1. CommonLogger:继承于Rack::CommonLogger,日志系统


  1. Helpers:一些辅助方法,可以在用户编写的路由、前置∕后置过滤器或者视图中使用,用 户可以使用这里面的方法实现修改响应的status、header、body等,而且还可以进行重定 向,上传文件,访问session,操作缓存等功能


  1. Templates:主要用于模板渲染


  1. Base:Sinatra的主要实现的部分,是所有Sinatra应用程序和中间件的基类,这个类实现了call方法,符合Rack应用程序的标准


  1. Application:Base的子类


  1. Delegator:Application的代理,通过将其混入到main object中,我们可以使用诸如get、 post等Application中的方法


  1. Wrapper:对整个Sinatra的一个包装


二、Sinatra应用的启动流程


Sinatra应用的启动分为这么几步: 路由注册——>用户的运行参数设置——>启动服务 我们接下来一块一块看


1、路由注册


这一步就是将用户写的类似于下面这样的路由代码注册进来:


get('/') do
  'this is a simple app'
end


这些方法对应于HTTP的各个方法,对于get方法,他会同时定义GET和HEAD这两个句柄:


def get(path, opts = {}, &block) conditions = @conditions.dup route('GET', path, opts, &block)
@conditions = conditions
route('HEAD', path, opts, &block) end
def put(path, opts = {}, &bk) route 'PUT',
def post(path, opts = {}, &bk) route 'POST',
def delete(path, opts = {}, &bk) route 'DELETE', path, opts, &bk end 
def head(path, opts = {}, &bk) route 'HEAD', path, opts, &bk end 
def options(path, opts = {}, &bk) route 'OPTIONS', path, opts, &bk end 
def patch(path, opts = {}, &bk) route 'PATCH', path, opts, &bk end 
def link(path, opts = {}, &bk) route 'LINK', path, opts, &bk end
def unlink(path, opts = {}, &bk) route 'UNLINK', path, opts, &bk end


由上面可以看到这些方法都调用了route这个方法,所以我们重点看下这个方法的实现



def route(verb, path, options = {}, &block)
  # Because of self.options.host 
  host_name(options.delete(:host)) if options.key?(:host)
  enable :empty_path_info if path == "" and empty_path_info.nil? 
  signature = compile!(verb, path, block, options)
  (@routes[verb] ||= []) << signature 
  invoke_hook(:route_added, verb, path, block) signature
end


这个方法的参数介绍如下:


verb:HTTP方法


path:URL路径


option:用户的路由中的设置的匹配条件


block:路由中的代码块


route方法主要就是生成路由的签名然后保存在routes对应的http方法的数组中,所以这段代码中关键的一处是:


signature = compile!(verb, path, block, options)


我们进去看下compile!方法:


def compile!(verb, path, block, options = {}) 
  options.each_pair { |option, args| send(option, *args) }
  method_name     = "#{verb} #{path}"
  unbound_method = generate_method(method_name, &block)
  pattern, keys = compile path
  conditions, @conditions = @conditions, []
  wrapper = block.arity != 0 ?
    proc { |a,p| unbound_method.bind(a).call(*p) } : 
    proc { |a,p| unbound_method.bind(a).call }
  wrapper.instance_variable_set(:@route_name, method_name)
  [ pattern, keys, conditions, wrapper ] 
end


这个函数主要有两个作用,一个就是根据verb path 以及block做了一个以”#{verb} #{path}”为 函数名,block为函数体的非绑定的方法,然后将这个方法和proc对象wrapper绑定起来,另 一个作用相信大家也看到了:


pattern, keys = compile path


这个compile方法是用来解析URL匹配范式,根据我们写的URL得出匹配符用于将来处理请求时 正则匹配对应的路由,而且将我们URL中的具名参数解析了出来,将具名参数名作为键,方便 我们直接访问这些参数。

 

2、用户运行参数设置、服务启动


这块的实现主要在main.rb中


module Sinatra
  class Application <; Base
    # we assume that the first file that requires 'sinatra' is the
    # app_file. all other path related options are calculated based 
    # on this path by default.
    set :app_file, caller_files.first || $0
    set :run, Proc.new { File.expand_path($0) == File.expand_path(app_file) }
    if run? &&; ARGV.any? 
      require 'optparse' 
      OptionParser.new { |op| 
        op.on('-p port', 'set the port (default is 4567)') { |val| set :port, Integer(val) }
        op.on('-o addr', "set the host (default is #{bind})") { |val| set :bind, val }
        op.on('-e env', 'set the environment (default is development)') { |val| set :environment, val.to_sym }
        op.on('-s server', 'specify rack server/handler (default is thin)') { |val| set :server, val } 
        op.on('-x', 'turn on the mutex lock (default is off)') { set :lock, true } 
      }.parse!(ARGV.dup) 
    end 
  end 
  at_exit { Application.run! if $!.nil? && Application.run? } 
end


这里就是利用ruby类的开放性,动态的给Application增加了一些代码,当Application被加载 时,就会执行这里面的代码,这块代码就做了两件事:设置命令行参数,启动服务,命令行参 数这块很简单,我们直接看启动服务这块:


at_exit { Application.run! if $!.nil? && Application.run? }


大家注意到这里用到了at_exit这个方法,这个方法作用就是在整个ruby程序结束后再执行 block中的代码,为什么要这么做呢?原因很简单,这里就相当于Sinatra将我们所写的代码执 行完毕(路由注册,各种过滤器处理等等)后再启动服务。我们主要看下run!方法:


def run!(options = {}, &block)
  return if running?
  set options
  handler = detect_rack_handler
  handler_name = handler.name.gsub(/.*::/, '')
  server_settings = settings.respond_to?(:server_settings) ? settings.server_settings : {} 
  server_settings.merge!(:Port => port, :Host => bind)
  begin
    start_server(handler, server_settings, handler_name, &block)
  rescue Errno::EADDRINUSE
    $stderr.puts "== Someone is already performing on port #{port}!" raise
  ensure 
    quit!
  end 
end


这块代码主要就是确定我们起服务所要用的服务器句柄(rack应用程序就是通过这些服务器句 柄来启动服务器的),然后设置好端口,IP,最后启动服务器。

相关文章
|
SQL 关系型数据库 MySQL
如何在 MySQL 或 MariaDB 中导入和导出数据库
如何在 MySQL 或 MariaDB 中导入和导出数据库
1074 0
|
JavaScript Java 测试技术
基于微信小程序校园订餐的设计与实现(源码+lw+部署文档+讲解等)
基于微信小程序校园订餐的设计与实现(源码+lw+部署文档+讲解等)
|
数据采集 存储 监控
数据质量最佳实践(2):通过归档和分析异常数据,快速定位质量问题
在Dataphin数据治理系列:基于数据质量管理,支撑业务快速发展这篇文章中,我们详细的介绍了Dataphin数据质量模块的产品核心能力和产品使用演示。 在实际的质量管理过程中,经常需要通过查看异常数据,来确定质量问题产生的原因,从而针对性的修复质量问题,下面我们一起来看下Dataphin质量模块的异常数据归档能力。
684 0
数据质量最佳实践(2):通过归档和分析异常数据,快速定位质量问题
|
IDE Java 开发工具
Android开发环境搭建
现在国内大部分开发人员还是使用的Eclipse,而谷歌宣布不再更新ADT后,并且官网也去掉了集成Android开发环境的Eclipse下载链接,各种现象都表示开发者最后都终将过渡到Android Studio,当然这段过渡时间会很长,但如果你是刚学Android的话建议直接冲Android Studio着手;而且很多优秀的开源项目都是基于Android Studio!
250 0
|
7天前
|
存储 弹性计算 人工智能
【2025云栖精华内容】 打造持续领先,全球覆盖的澎湃算力底座——通用计算产品发布与行业实践专场回顾
2025年9月24日,阿里云弹性计算团队多位产品、技术专家及服务器团队技术专家共同在【2025云栖大会】现场带来了《通用计算产品发布与行业实践》的专场论坛,本论坛聚焦弹性计算多款通用算力产品发布。同时,ECS云服务器安全能力、资源售卖模式、计算AI助手等用户体验关键环节也宣布升级,让用云更简单、更智能。海尔三翼鸟云服务负责人刘建锋先生作为特邀嘉宾,莅临现场分享了关于阿里云ECS g9i推动AIoT平台的场景落地实践。
【2025云栖精华内容】 打造持续领先,全球覆盖的澎湃算力底座——通用计算产品发布与行业实践专场回顾
|
1天前
|
弹性计算 人工智能 安全
云上十五年——「弹性计算十五周年」系列客户故事(第二期)
阿里云弹性计算十五年深耕,以第九代ECS g9i实例引领算力革新。携手海尔三翼鸟、小鹏汽车、微帧科技等企业,实现性能跃升与成本优化,赋能AI、物联网、智能驾驶等前沿场景,共绘云端增长新图景。
|
6天前
|
人工智能 自然语言处理 自动驾驶
关于举办首届全国大学生“启真问智”人工智能模型&智能体大赛决赛的通知
关于举办首届全国大学生“启真问智”人工智能模型&智能体大赛决赛的通知