class Rack::Builder
def self.app(default_app = nil, &block)
Create a new Rack::Builder instance and return the Rack application
def self.app(default_app = nil, &block) self.new(default_app, &block).to_app end
def self.load_file(path, opts = Server::Options.new)
require './app.rb'
use Rack::ContentLength
#\ -p 9393
$ cat config.ru
Example config.ru file:
use of +__END__+ will not result in a syntax error.
Ignores content in the file after +__END__+, so that
options passed on a rackup command line.
that starts with a backslash as options similar to
Treats the first comment at the beginning of a line
contents as if specified inside a Rack::Builder block.
Load the given file as a rackup file, treating the
def self.load_file(path, opts = Server::Options.new) options = {} cfgfile = ::File.read(path) cfgfile.slice!(/\A#{UTF_8_BOM}/) if cfgfile.encoding == Encoding::UTF_8 if cfgfile[/^#\\(.*)/] && opts warn "Parsing options from the first comment line is deprecated!" options = opts.parse! $1.split(/\s+/) end cfgfile.sub!(/^__END__\n.*\Z/m, '') app = new_from_string cfgfile, path return app, options end
def self.new_from_string(builder_script, file = "(rackup)")
Evaluate the given +builder_script+ string in the context of
def self.new_from_string(builder_script, file = "(rackup)") # We want to build a variant of TOPLEVEL_BINDING with self as a Rack::Builder instance. # We cannot use instance_eval(String) as that would resolve constants differently. binding, builder = TOPLEVEL_BINDING.eval('Rack::Builder.new.instance_eval { [binding, self] }') eval builder_script, binding, file builder.to_app end
def self.parse_file(config, opts = Server::Options.new)
# process's current directory. After requiring,
# requires ./my_app.rb, which should be in the
Rack::Builder.parse_file('./my_app.rb')
# contains Rack application
# load path. After requiring, assumes App constant
# requires app.rb, which can be anywhere in Ruby's
Rack::Builder.parse_file('app.rb')
# Rack application built using Rack::Builder.new
Rack::Builder.parse_file('config.ru')
Examples:
The options given will be ignored in this case.
to guess which constant will be the Rack application to run.
required and Rack will use the basename of the file
If the config file does not end in +.ru+, it is
options.
specified inside a Rack::Builder block, using the given
rackup file and the contents will be treated as if
If the config file ends in +.ru+, it is treated as a
Parse the given config file to get a Rack application.
def self.parse_file(config, opts = Server::Options.new) if config.end_with?('.ru') return self.load_file(config, opts) else require config app = Object.const_get(::File.basename(config, '.rb').split('_').map(&:capitalize).join('')) return app, {} end end
def call(env)
this rebuilds the Rack application and runs the warmup code (if any)
Call the Rack application generated by this builder instance. Note that
def call(env) to_app.call(env) end
def freeze_app
Freeze the app (set using run) and all middleware instances when building the application
def freeze_app @freeze_app = true end
def generate_map(default_app, mapping)
Generate a URLMap instance by generating new Rack applications for each
def generate_map(default_app, mapping) mapped = default_app ? { '/' => default_app } : {} mapping.each { |r, b| mapped[r] = self.class.new(default_app, &b).to_app } URLMap.new(mapped) end
def initialize(default_app = nil, &block)
default application if +run+ is not called later. If a block
Initialize a new Rack::Builder instance. +default_app+ specifies the
def initialize(default_app = nil, &block) @use, @map, @run, @warmup, @freeze_app = [], nil, default_app, nil, false instance_eval(&block) if block_given? end
def map(path, &block)
Note that providing a +path+ of +/+ will ignore any default application given in a +run+ statement
This example includes a piece of middleware which will run before +/heartbeat+ requests hit +Heartbeat+.
end
run App
end
run Heartbeat
use Middleware
map '/heartbeat' do
Rack::Builder.app do
The +use+ method can also be used inside the block to specify middleware to run under a specific path:
end
run App
end
run Heartbeat
map '/heartbeat' do
Rack::Builder.app do
default application specified by run outside the block.
the Rack application specified by run inside the block. Other requests will be sent to the
Creates a route within the application. Routes under the mapped path will be sent to
def map(path, &block) @map ||= {} @map[path] = block end
def run(app)
end
end
[200, { "Content-Type" => "text/plain" }, ["OK"]]
def self.call(env)
class Heartbeat
However this could also be a class:
run lambda { |env| [200, { "Content-Type" => "text/plain" }, ["OK"]] }
The simplest form of this is a lambda object:
Takes an argument that is an object that responds to #call and returns a Rack response.
def run(app) @run = app end
def to_app
def to_app app = @map ? generate_map(@run, @map) : @run fail "missing run or map statement" unless app app.freeze if @freeze_app app = @use.reverse.inject(app) { |a, e| e[a].tap { |x| x.freeze if @freeze_app } } @warmup.call(app) if @warmup app end
def use(middleware, *args, &block)
The +call+ method in this example sets an additional environment key which then can be
All requests through to this application will first be processed by the middleware class.
run lambda { |env| [200, { "Content-Type" => "text/plain" }, ["OK"]] }
use Middleware
end
end
@app.call(env)
env["rack.some_header"] = "setting an example"
def call(env)
end
@app = app
def initialize(app)
class Middleware
Specifies middleware to use in a stack.
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
def warmup(prc = nil, &block)
use SomeMiddleware
end
client.get('/')
client = Rack::MockRequest.new(app)
warmup do |app|
before the Rack application is returned by to_app.
Takes a lambda or block that is used to warm-up the application. This block is called
def warmup(prc = nil, &block) @warmup = prc || block end