Class: Puma::Rack::Builder

Inherits:
Object
  • Object
show all
Defined in:
lib/puma/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
  run lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['OK']] }
end

run app

use adds 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(default_app = nil, &block) ⇒ Builder

Returns a new instance of Builder.



176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/puma/rack/builder.rb', line 176

def initialize(default_app = nil, &block)
  @use, @map, @run, @warmup = [], nil, default_app, nil

  # Conditionally load rack now, so that any rack middlewares,
  # etc are available.
  begin
    require 'rack'
  rescue LoadError
  end

  instance_eval(&block) if block
end

Class Method Details

.app(default_app = nil, &block) ⇒ Object



189
190
191
# File 'lib/puma/rack/builder.rb', line 189

def self.app(default_app = nil, &block)
  self.new(default_app, &block).to_app
end

.new_from_string(builder_script, file = "(rackup)") ⇒ Object



171
172
173
174
# File 'lib/puma/rack/builder.rb', line 171

def self.new_from_string(builder_script, file="(rackup)")
  eval "Puma::Rack::Builder.new {\n" + builder_script + "\n}.to_app",
    TOPLEVEL_BINDING, file, 0
end

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



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/puma/rack/builder.rb', line 155

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

Instance Method Details

#call(env) ⇒ Object



283
284
285
# File 'lib/puma/rack/builder.rb', line 283

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.



270
271
272
273
# File 'lib/puma/rack/builder.rb', line 270

def map(path, &block)
  @map ||= {}
  @map[path] = block
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


234
235
236
# File 'lib/puma/rack/builder.rb', line 234

def run(app)
  @run = app
end

#to_appObject



275
276
277
278
279
280
281
# File 'lib/puma/rack/builder.rb', line 275

def to_app
  app = @map ? generate_map(@run, @map) : @run
  fail "missing run or map statement" unless app
  app = @use.reverse.inject(app) { |a,e| e[a] }
  @warmup&.call app
  app
end

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

Specifies 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.



212
213
214
215
216
217
218
# File 'lib/puma/rack/builder.rb', line 212

def use(middleware, *args, &block)
  if @map
    mapping, @map = @map, nil
    @use << proc { |app| generate_map app, mapping }
  end
  @use << proc { |app| middleware.new(app, *args, &block) }
end

#warmup(prc = nil, &block) ⇒ Object

Takes a lambda or block that is used to warm-up the application.

warmup do |app|
  client = Rack::MockRequest.new(app)
  client.get('/')
end

use SomeMiddleware
run MyApp


247
248
249
# File 'lib/puma/rack/builder.rb', line 247

def warmup(prc=nil, &block)
  @warmup = prc || block
end