来自1.4.7

halt

使流程直接跳回到invoke。
使用时可带[status code、header、字符串]任意部分或全部,看invoke的逻辑,会被设置到response对象中。
如果什么都不带,则响应会是200,而内容为空。因为Rack::Response初始化时默认status为200,而不带参数的halt又令Base#invoke和Base#call!不去修改response的body

def halt(*response)
  response = response.first if response.length == 1
  throw :halt, response
end

def invoke
  res = catch(:halt) { yield }
  res = [res] if Fixnum === res or String === res
  if Array === res and Fixnum === res.first
    res = res.dup
    status(res.shift)
    body(res.pop)
    headers(*res)
  elsif res.respond_to? :each
    body res
  end
  nil # avoid double setting the same response tuple twice
end


pass

使流程直接跳到process_route的末尾,继而进入routes.each的下一循环。
(如果你真的想交由下一个match的路由来处理的话)

def pass(&block)
  throw :pass, block
end

def process_route(pattern, keys, conditions, block = nil, values = [])
  route = @request.path_info
  route = '/' if route.empty? and not settings.empty_path_info?
  return unless match = pattern.match(route)
  values += match.captures.map! { |v| force_encoding URI_INSTANCE.unescape(v) if v }

  if values.any?
    original, @params = params, params.merge('splat' => [], 'captures' => values)
    keys.zip(values) { |k,v| Array === @params[k] ? @params[k] << v : @params[k] = v if v }
  end

  catch(:pass) do
    conditions.each { |c| throw :pass if c.bind(self).call == false }
    block ? block[self, values] : yield(self, values)
  end
ensure
  @params = original if original
end


redirect

根据http版本设status code,并设置header的Location,然后halt,跳回invoke。
可带参数301(永久移动,迫使browser更新bookmark),这样回到invoke时,会以301替换掉302或303

def redirect(uri, *args)
  if env['HTTP_VERSION'] == 'HTTP/1.1' and env["REQUEST_METHOD"] != 'GET'
    status 303
  else
    status 302
  end

  # According to RFC 2616 section 14.30, "the field value consists of a
  # single absolute URI"
  response['Location'] = uri(uri.to_s, settings.absolute_redirects?, settings.prefixed_redirects?)
  halt(*args)
end


erb等各种template

来自module Template。大概就是使用Tilt来加载具体的模板技术,然后以指定的scope或self来render。无指定scope的话,通过在响应块中设置application的实例变量来让模板引用到

def erb(template, options = {}, locals = {}, &block)
  render(:erb, template, options, locals, &block)
end

def render(engine, data, options = {}, locals = {}, &block)
  # ...
  scope           = options.delete(:scope)          || self

  # ...
  begin
    layout_was      = @default_layout
    @default_layout = false
    template        = compile_template(engine, data, options, views)
    output          = template.render(scope, locals, &block)
  ensure
    @default_layout = layout_was
  end

  # render layout if layout ...
  output
end

def compile_template(engine, data, options, views)
  eat_errors = options.delete :eat_errors
  template_cache.fetch engine, data, options, views do
    template = Tilt[engine]
    raise "Template engine not found: #{engine}" if template.nil?

    case data
    when Symbol
      # ...
    when Proc, String
      # ...
    else
      raise ArgumentError, "Sorry, don't know how to render #{data.inspect}."
    end
  end
end