Class: Sinatra::Base

Inherits:
Object
  • Object
show all
Includes:
Rack::Utils, Helpers, Templates
Defined in:
lib/sinatra/base.rb

Overview

Base class for all Sinatra applications and middleware.

Direct Known Subclasses

Application

Constant Summary collapse

URI_INSTANCE =
URI::Parser.new
CALLERS_TO_IGNORE =

:nodoc:

[ # :nodoc:
  /\/sinatra(\/(base|main|show_exceptions))?\.rb$/,   # all sinatra code
  /lib\/tilt.*\.rb$/,                                 # all tilt code
  /^\(.*\)$/,                                         # generated code
  /rubygems\/(custom|core_ext\/kernel)_require\.rb$/, # rubygems require hacks
  /active_support/,                                   # active_support require hacks
  /bundler(\/(?:runtime|inline))?\.rb/,               # bundler require hacks
  /<internal:/,                                       # internal in ruby >= 1.9.2
  /src\/kernel\/bootstrap\/[A-Z]/                     # maglev kernel files
]

Constants included from Helpers

Helpers::ETAG_KINDS

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Templates

#asciidoc, #builder, #coffee, #creole, #erb, #erubis, #find_template, #haml, #less, #liquid, #markaby, #markdown, #mediawiki, #nokogiri, #rabl, #radius, #rdoc, #sass, #scss, #slim, #stylus, #textile, #wlang, #yajl

Methods included from Helpers

#attachment, #back, #bad_request?, #body, #cache_control, #client_error?, #content_type, #error, #etag, #expires, #headers, #informational?, #last_modified, #logger, #mime_type, #not_found, #not_found?, #redirect, #redirect?, #send_file, #server_error?, #session, #status, #stream, #success?, #time_for, #uri

Constructor Details

#initialize(app = nil) {|_self| ... } ⇒ Base

Returns a new instance of Base.

Yields:

  • (_self)

Yield Parameters:

  • _self (Sinatra::Base)

    the object that the method was called on


919
920
921
922
923
924
925
# File 'lib/sinatra/base.rb', line 919

def initialize(app = nil)
  super()
  @app = app
  @template_cache = Tilt::Cache.new
  @pinned_response = nil # whether a before! filter pinned the content-type
  yield self if block_given?
end

Class Attribute Details

.errorsObject (readonly)

Returns the value of attribute errors


1222
1223
1224
# File 'lib/sinatra/base.rb', line 1222

def errors
  @errors
end

.filtersObject (readonly)

Returns the value of attribute filters


1222
1223
1224
# File 'lib/sinatra/base.rb', line 1222

def filters
  @filters
end

.routesObject (readonly)

Returns the value of attribute routes


1222
1223
1224
# File 'lib/sinatra/base.rb', line 1222

def routes
  @routes
end

.templatesObject (readonly)

Returns the value of attribute templates


1222
1223
1224
# File 'lib/sinatra/base.rb', line 1222

def templates
  @templates
end

Instance Attribute Details

#appObject

Returns the value of attribute app


916
917
918
# File 'lib/sinatra/base.rb', line 916

def app
  @app
end

#envObject

Returns the value of attribute env


916
917
918
# File 'lib/sinatra/base.rb', line 916

def env
  @env
end

#paramsObject

Returns the value of attribute params


916
917
918
# File 'lib/sinatra/base.rb', line 916

def params
  @params
end

#requestObject

Returns the value of attribute request


916
917
918
# File 'lib/sinatra/base.rb', line 916

def request
  @request
end

#responseObject

Returns the value of attribute response


916
917
918
# File 'lib/sinatra/base.rb', line 916

def response
  @response
end

#template_cacheObject (readonly)

Returns the value of attribute template_cache


917
918
919
# File 'lib/sinatra/base.rb', line 917

def template_cache
  @template_cache
end

Class Method Details

.add_filter(type, path = /.*/, **options, &block) ⇒ Object

add a filter


1399
1400
1401
# File 'lib/sinatra/base.rb', line 1399

def add_filter(type, path = /.*/, **options, &block)
  filters[type] << compile!(type, path, block, **options)
end

.after(path = /.*/, **options, &block) ⇒ Object

Define an after filter; runs after all requests within the same context as route handlers and may access/modify the request and response.


1394
1395
1396
# File 'lib/sinatra/base.rb', line 1394

def after(path = /.*/, **options, &block)
  add_filter(:after, path, **options, &block)
end

.before(path = /.*/, **options, &block) ⇒ Object

Define a before filter; runs before all requests within the same context as route handlers and may access/modify the request and response.


1387
1388
1389
# File 'lib/sinatra/base.rb', line 1387

def before(path = /.*/, **options, &block)
  add_filter(:before, path, **options, &block)
end

.build(app) ⇒ Object

Creates a Rack::Builder instance with all the middleware set up and the given +app+ as end point.


1533
1534
1535
1536
1537
1538
1539
# File 'lib/sinatra/base.rb', line 1533

def build(app)
  builder = Rack::Builder.new
  setup_default_middleware builder
  setup_middleware builder
  builder.run app
  builder
end

.call(env) ⇒ Object


1541
1542
1543
# File 'lib/sinatra/base.rb', line 1541

def call(env)
  synchronize { prototype.call(env) }
end

.caller_filesObject

Like Kernel#caller but excluding certain magic entries and without line / method information; the resulting array contains filenames only.


1547
1548
1549
# File 'lib/sinatra/base.rb', line 1547

def caller_files
  cleaned_caller(1).flatten
end

.caller_locationsObject

Like caller_files, but containing Arrays rather than strings with the first element being the file, and the second being the line.


1553
1554
1555
# File 'lib/sinatra/base.rb', line 1553

def caller_locations
  cleaned_caller 2
end

.condition(name = "#{caller.first[/`.*'/]} condition", &block) ⇒ Object

Add a route condition. The route is considered non-matching when the block returns false.


1405
1406
1407
# File 'lib/sinatra/base.rb', line 1405

def condition(name = "#{caller.first[/`.*'/]} condition", &block)
  @conditions << generate_method(name, &block)
end

.configure(*envs) {|_self| ... } ⇒ Object

Set configuration options for Sinatra and/or the app. Allows scoping of settings for certain environments.

Yields:

  • (_self)

Yield Parameters:

  • _self (Sinatra::Base)

    the object that the method was called on


1465
1466
1467
# File 'lib/sinatra/base.rb', line 1465

def configure(*envs)
  yield self if envs.empty? || envs.include?(environment.to_sym)
end

.delete(path, opts = {}, &bk) ⇒ Object


1434
# File 'lib/sinatra/base.rb', line 1434

def delete(path, opts = {}, &bk)  route 'DELETE',  path, opts, &bk end

.development?Boolean

Returns:

  • (Boolean)

1459
# File 'lib/sinatra/base.rb', line 1459

def development?; environment == :development end

.disable(*opts) ⇒ Object

Same as calling set :option, false for each of the given options.


1303
1304
1305
# File 'lib/sinatra/base.rb', line 1303

def disable(*opts)
  opts.each { |key| set(key, false) }
end

.enable(*opts) ⇒ Object

Same as calling set :option, true for each of the given options.


1298
1299
1300
# File 'lib/sinatra/base.rb', line 1298

def enable(*opts)
  opts.each { |key| set(key, true) }
end

.error(*codes, &block) ⇒ Object

Define a custom error handler. Optionally takes either an Exception class, or an HTTP status code to specify which errors should be handled.


1310
1311
1312
1313
1314
1315
1316
# File 'lib/sinatra/base.rb', line 1310

def error(*codes, &block)
  args  = compile! "ERROR", /.*/, block
  codes = codes.flat_map(&method(:Array))
  codes << Exception if codes.empty?
  codes << Sinatra::NotFound if codes.include?(404)
  codes.each { |c| (@errors[c] ||= []) << args }
end

.extensionsObject

Extension modules registered on this class and all superclasses.


1243
1244
1245
1246
1247
1248
1249
# File 'lib/sinatra/base.rb', line 1243

def extensions
  if superclass.respond_to?(:extensions)
    (@extensions + superclass.extensions).uniq
  else
    @extensions
  end
end

.get(path, opts = {}, &block) ⇒ Object

Defining a GET handler also automatically defines a HEAD handler.


1424
1425
1426
1427
1428
1429
1430
# File 'lib/sinatra/base.rb', line 1424

def get(path, opts = {}, &block)
  conditions = @conditions.dup
  route('GET', path, opts, &block)

  @conditions = conditions
  route('HEAD', path, opts, &block)
end

.head(path, opts = {}, &bk) ⇒ Object


1435
# File 'lib/sinatra/base.rb', line 1435

def head(path, opts = {}, &bk)    route 'HEAD',    path, opts, &bk end

.helpers(*extensions, &block) ⇒ Object

Makes the methods defined in the block and in the Modules given in extensions available to the handlers and templates


1443
1444
1445
1446
# File 'lib/sinatra/base.rb', line 1443

def helpers(*extensions, &block)
  class_eval(&block)   if block_given?
  prepend(*extensions) if extensions.any?
end

.inline_templates=(file = nil) ⇒ Object

Load embedded templates from the file; uses the caller's FILE when no file is specified.


1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
# File 'lib/sinatra/base.rb', line 1336

def inline_templates=(file = nil)
  file = (file.nil? || file == true) ? (caller_files.first || File.expand_path($0)) : file

  begin
    io = ::IO.respond_to?(:binread) ? ::IO.binread(file) : ::IO.read(file)
    app, data = io.gsub("\r\n", "\n").split(/^__END__$/, 2)
  rescue Errno::ENOENT
    app, data = nil
  end

  if data
    if app and app =~ /([^\n]*\n)?#[^\n]*coding: *(\S+)/m
      encoding = $2
    else
      encoding = settings.default_encoding
    end
    lines = app.count("\n") + 1
    template = nil
    force_encoding data, encoding
    data.each_line do |line|
      lines += 1
      if line =~ /^@@\s*(.*\S)\s*$/
        template = force_encoding(String.new, encoding)
        templates[$1.to_sym] = [template, file, lines]
      elsif template
        template << line
      end
    end
  end
end

.layout(name = :layout, &block) ⇒ Object

Define the layout template. The block must return the template source.


1330
1331
1332
# File 'lib/sinatra/base.rb', line 1330

def layout(name = :layout, &block)
  template name, &block
end

1438
# File 'lib/sinatra/base.rb', line 1438

def link(path, opts = {}, &bk)    route 'LINK',    path, opts, &bk end

.middlewareObject

Middleware used in this class and all superclasses.


1252
1253
1254
1255
1256
1257
1258
# File 'lib/sinatra/base.rb', line 1252

def middleware
  if superclass.respond_to?(:middleware)
    superclass.middleware + @middleware
  else
    @middleware
  end
end

.mime_type(type, value = nil) ⇒ Object

Lookup or register a mime type in Rack's mime registry.


1368
1369
1370
1371
1372
1373
1374
# File 'lib/sinatra/base.rb', line 1368

def mime_type(type, value = nil)
  return type      if type.nil?
  return type.to_s if type.to_s.include?('/')
  type = ".#{type}" unless type.to_s[0] == ?.
  return Rack::Mime.mime_type(type, nil) unless value
  Rack::Mime::MIME_TYPES[type] = value
end

.mime_types(type) ⇒ Object

provides all mime types matching type, including deprecated types: mime_types :html # => ['text/html'] mime_types :js # => ['application/javascript', 'text/javascript']


1379
1380
1381
1382
# File 'lib/sinatra/base.rb', line 1379

def mime_types(type)
  type = mime_type type
  type =~ /^application\/(xml|javascript)$/ ? [type, "text/#$1"] : [type]
end

.new(*args, &bk) ⇒ Object

Create a new instance of the class fronted by its middleware pipeline. The object is guaranteed to respond to #call but may not be an instance of the class new was called on.


1526
1527
1528
1529
# File 'lib/sinatra/base.rb', line 1526

def new(*args, &bk)
  instance = new!(*args, &bk)
  Wrapper.new(build(instance).to_app, instance)
end

.not_found(&block) ⇒ Object

Sugar for error(404) { ... }


1319
1320
1321
# File 'lib/sinatra/base.rb', line 1319

def not_found(&block)
  error(404, &block)
end

.options(path, opts = {}, &bk) ⇒ Object


1436
# File 'lib/sinatra/base.rb', line 1436

def options(path, opts = {}, &bk) route 'OPTIONS', path, opts, &bk end

.patch(path, opts = {}, &bk) ⇒ Object


1437
# File 'lib/sinatra/base.rb', line 1437

def patch(path, opts = {}, &bk)   route 'PATCH',   path, opts, &bk end

.post(path, opts = {}, &bk) ⇒ Object


1433
# File 'lib/sinatra/base.rb', line 1433

def post(path, opts = {}, &bk)    route 'POST',    path, opts, &bk end

.production?Boolean

Returns:

  • (Boolean)

1460
# File 'lib/sinatra/base.rb', line 1460

def production?;  environment == :production  end

.prototypeObject

The prototype instance used to process requests.


1516
1517
1518
# File 'lib/sinatra/base.rb', line 1516

def prototype
  @prototype ||= new
end

.public=(value) ⇒ Object


1409
1410
1411
1412
# File 'lib/sinatra/base.rb', line 1409

def public=(value)
  warn ":public is no longer used to avoid overloading Module#public, use :public_folder or :public_dir instead"
  set(:public_folder, value)
end

.public_dirObject


1418
1419
1420
# File 'lib/sinatra/base.rb', line 1418

def public_dir
  public_folder
end

.public_dir=(value) ⇒ Object


1414
1415
1416
# File 'lib/sinatra/base.rb', line 1414

def public_dir=(value)
  self.public_folder = value
end

.put(path, opts = {}, &bk) ⇒ Object


1432
# File 'lib/sinatra/base.rb', line 1432

def put(path, opts = {}, &bk)     route 'PUT',     path, opts, &bk end

.quit!Object Also known as: stop!

Stop the self-hosted server if running.


1476
1477
1478
1479
1480
1481
1482
1483
# File 'lib/sinatra/base.rb', line 1476

def quit!
  return unless running?
  # Use Thin's hard #stop! if available, otherwise just #stop.
  running_server.respond_to?(:stop!) ? running_server.stop! : running_server.stop
  $stderr.puts "== Sinatra has ended his set (crowd applauds)" unless suppress_messages?
  set :running_server, nil
  set :handler_name, nil
end

.register(*extensions, &block) ⇒ Object

Register an extension. Alternatively take a block from which an extension will be created and registered on the fly.


1450
1451
1452
1453
1454
1455
1456
1457
# File 'lib/sinatra/base.rb', line 1450

def register(*extensions, &block)
  extensions << Module.new(&block) if block_given?
  @extensions += extensions
  extensions.each do |extension|
    extend extension
    extension.registered(self) if extension.respond_to?(:registered)
  end
end

.reset!Object

Removes all routes, filters, middleware and extension hooks from the current class (not routes/filters/... defined by its superclass).


1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
# File 'lib/sinatra/base.rb', line 1226

def reset!
  @conditions     = []
  @routes         = {}
  @filters        = {:before => [], :after => []}
  @errors         = {}
  @middleware     = []
  @prototype      = nil
  @extensions     = []

  if superclass.respond_to?(:templates)
    @templates = Hash.new { |hash, key| superclass.templates[key] }
  else
    @templates = {}
  end
end

.run!(options = {}, &block) ⇒ Object Also known as: start!

Run the Sinatra app as a self-hosted server using Puma, Mongrel, or WEBrick (in that order). If given a block, will call with the constructed handler once we have taken the stage.


1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
# File 'lib/sinatra/base.rb', line 1490

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

.running?Boolean

Check whether the self-hosted server is running or not.

Returns:

  • (Boolean)

1511
1512
1513
# File 'lib/sinatra/base.rb', line 1511

def running?
  running_server?
end

.set(option, value = (not_set = true), ignore_setter = false, &block) ⇒ Object

Sets an option to the given value. If the value is a proc, the proc will be called every time the option is accessed.

Raises:

  • (ArgumentError)

1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
# File 'lib/sinatra/base.rb', line 1262

def set(option, value = (not_set = true), ignore_setter = false, &block)
  raise ArgumentError if block and !not_set
  value, not_set = block, false if block

  if not_set
    raise ArgumentError unless option.respond_to?(:each)
    option.each { |k,v| set(k, v) }
    return self
  end

  if respond_to?("#{option}=") and not ignore_setter
    return __send__("#{option}=", value)
  end

  setter = proc { |val| set option, val, true }
  getter = proc { value }

  case value
  when Proc
    getter = value
  when Symbol, Integer, FalseClass, TrueClass, NilClass
    getter = value.inspect
  when Hash
    setter = proc do |val|
      val = value.merge val if Hash === val
      set option, val, true
    end
  end

  define_singleton("#{option}=", setter)
  define_singleton(option, getter)
  define_singleton("#{option}?", "!!#{option}") unless method_defined? "#{option}?"
  self
end

.settingsObject

Access settings defined with Base.set.


954
955
956
# File 'lib/sinatra/base.rb', line 954

def self.settings
  self
end

.template(name, &block) ⇒ Object

Define a named template. The block must return the template source.


1324
1325
1326
1327
# File 'lib/sinatra/base.rb', line 1324

def template(name, &block)
  filename, line = caller_locations.first
  templates[name] = [block, filename, line.to_i]
end

.test?Boolean

Returns:

  • (Boolean)

1461
# File 'lib/sinatra/base.rb', line 1461

def test?;        environment == :test        end

1439
# File 'lib/sinatra/base.rb', line 1439

def unlink(path, opts = {}, &bk)  route 'UNLINK',  path, opts, &bk end

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

Use the specified Rack middleware


1470
1471
1472
1473
# File 'lib/sinatra/base.rb', line 1470

def use(middleware, *args, &block)
  @prototype = nil
  @middleware << [middleware, args, block]
end

Instance Method Details

#call(env) ⇒ Object

Rack call interface.


928
929
930
# File 'lib/sinatra/base.rb', line 928

def call(env)
  dup.call!(env)
end

#call!(env) ⇒ Object

:nodoc:


932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
# File 'lib/sinatra/base.rb', line 932

def call!(env) # :nodoc:
  @env      = env
  @params   = IndifferentHash.new
  @request  = Request.new(env)
  @response = Response.new
  template_cache.clear if settings.reload_templates

  invoke { dispatch! }
  invoke { error_block!(response.status) } unless @env['sinatra.error']

  unless @response['Content-Type']
    if Array === body && body[0].respond_to?(:content_type)
      content_type body[0].content_type
    elsif default = settings.default_content_type
      content_type default
    end
  end

  @response.finish
end

#forwardObject

Forward the request to the downstream app -- middleware only.


984
985
986
987
988
989
990
991
# File 'lib/sinatra/base.rb', line 984

def forward
  fail "downstream app not set" unless @app.respond_to? :call
  status, headers, body = @app.call env
  @response.status = status
  @response.body = body
  @response.headers.merge! headers
  nil
end

#halt(*response) ⇒ Object

Exit the current block, halts any further processing of the request, and returns the specified response.


971
972
973
974
# File 'lib/sinatra/base.rb', line 971

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

#new!Object

Create a new instance without middleware in front of it.


1521
# File 'lib/sinatra/base.rb', line 1521

alias new! new

#optionsObject


963
964
965
966
967
# File 'lib/sinatra/base.rb', line 963

def options
  warn "Sinatra::Base#options is deprecated and will be removed, " \
    "use #settings instead."
  settings
end

#pass(&block) ⇒ Object

Pass control to the next matching route. If there are no more matching routes, Sinatra will return a 404 response.


979
980
981
# File 'lib/sinatra/base.rb', line 979

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

#settingsObject

Access settings defined with Base.set.


959
960
961
# File 'lib/sinatra/base.rb', line 959

def settings
  self.class.settings
end