Class: Rack::Builder

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/builder.rb

Overview

Rack::Builder implements a small DSL to iteratively construct Rack applications.

Example:

require 'rack/lobster'
app = Rack::Builder.new do
  use Rack::CommonLogger
  use Rack::ShowExceptions
  map "/lobster" do
    use Rack::Lint
    run Rack::Lobster.new
  end
end

run app

Or

app = Rack::Builder.app do
  use Rack::CommonLogger
  lambda { |env| [200, {'Content-Type' => 'text/plain'}, 'OK'] }
end

run app

use adds a middleware to the stack, run dispatches to an application. You can use map to construct a Rack::URLMap in a convenient way.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(&block) ⇒ Builder

Returns a new instance of Builder.



49
50
51
52
# File 'lib/rack/builder.rb', line 49

def initialize(&block)
  @ins = []
  instance_eval(&block) if block_given?
end

Class Method Details

.app(&block) ⇒ Object



54
55
56
# File 'lib/rack/builder.rb', line 54

def self.app(&block)
  self.new(&block).to_app
end

.parse_file(config, opts = Server::Options.new) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/rack/builder.rb', line 32

def self.parse_file(config, opts = Server::Options.new)
  options = {}
  if config =~ /\.ru$/
    cfgfile = ::File.read(config)
    if cfgfile[/^#\\(.*)/] && opts
      options = opts.parse! $1.split(/\s+/)
    end
    cfgfile.sub!(/^__END__\n.*/, '')
    app = eval "Rack::Builder.new {\n" + cfgfile + "\n}.to_app",
      TOPLEVEL_BINDING, config
  else
    require config
    app = Object.const_get(::File.basename(config, '.rb').capitalize)
  end
  return app, options
end

Instance Method Details

#call(env) ⇒ Object



133
134
135
# File 'lib/rack/builder.rb', line 133

def call(env)
  to_app.call(env)
end

#map(path, &block) ⇒ Object

Creates a route within the application.

Rack::Builder.app do
  map '/' do
    run Heartbeat
  end
end

The use method can also be used here to specify middleware to run under a specific path:

Rack::Builder.app do
  map '/' do
    use Middleware
    run Heartbeat
  end
end

This example includes a piece of middleware which will run before requests hit Heartbeat.



118
119
120
121
122
123
124
125
# File 'lib/rack/builder.rb', line 118

def map(path, &block)
  if @ins.last.kind_of? Hash
    @ins.last[path] = self.class.new(&block).to_app
  else
    @ins << {}
    map(path, &block)
  end
end

#run(app) ⇒ Object

Takes an argument that is an object that responds to #call and returns a Rack response. The simplest form of this is a lambda object:

run lambda { |env| [200, { "Content-Type" => "text/plain" }, ["OK"]] }

However this could also be a class:

class Heartbeat
  def self.call(env)
   [200, { "Content-Type" => "text/plain" }, ["OK"]]
 end
end

run Heartbeat


95
96
97
# File 'lib/rack/builder.rb', line 95

def run(app)
  @ins << app #lambda { |nothing| app }
end

#to_appObject



127
128
129
130
131
# File 'lib/rack/builder.rb', line 127

def to_app
  @ins[-1] = Rack::URLMap.new(@ins.last)  if Hash === @ins.last
  inner_app = @ins.last
  @ins[0...-1].reverse.inject(inner_app) { |a, e| e.call(a) }
end

#use(middleware, *args, &block) ⇒ Object

Specifies a middleware to use in a stack.

class Middleware
  def initialize(app)
    @app = app
  end

  def call(env)
    env["rack.some_header"] = "setting an example"
    @app.call(env)
  end
end

use Middleware
run lambda { |env| [200, { "Content-Type => "text/plain" }, ["OK"]] }

All requests through to this application will first be processed by the middleware class. The call method in this example sets an additional environment key which then can be referenced in the application if required.



77
78
79
# File 'lib/rack/builder.rb', line 77

def use(middleware, *args, &block)
  @ins << lambda { |app| middleware.new(app, *args, &block) }
end