Class: Rack::Cascade

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

Overview

Rack::Cascade tries a request on several apps, and returns the first response that is not 404 or 405 (or in a list of configured status codes). If all applications tried return one of the configured status codes, return the last response.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(apps, cascade_for = [404, 405]) ⇒ Cascade

Set the apps to send requests to, and what statuses result in cascading. Arguments:

apps: An enumerable of rack applications. cascade_for: The statuses to use cascading for. If a response is received

from an app, the next app is tried.


21
22
23
24
25
26
27
# File 'lib/rack/cascade.rb', line 21

def initialize(apps, cascade_for = [404, 405])
  @apps = []
  apps.each { |app| add app }

  @cascade_for = {}
  [*cascade_for].each { |status| @cascade_for[status] = true }
end

Instance Attribute Details

#appsObject (readonly)

An array of applications to try in order.



13
14
15
# File 'lib/rack/cascade.rb', line 13

def apps
  @apps
end

Instance Method Details

#add(app) ⇒ Object Also known as: <<

Append an app to the list of apps to cascade. This app will be tried last.



56
57
58
# File 'lib/rack/cascade.rb', line 56

def add(app)
  @apps << app
end

#call(env) ⇒ Object

Call each app in order. If the responses uses a status that requires cascading, try the next app. If all responses require cascading, return the response from the last app.



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/rack/cascade.rb', line 32

def call(env)
  return [404, { CONTENT_TYPE => "text/plain" }, []] if @apps.empty?
  result = nil
  last_body = nil

  @apps.each do |app|
    # The SPEC says that the body must be closed after it has been iterated
    # by the server, or if it is replaced by a middleware action. Cascade
    # replaces the body each time a cascade happens. It is assumed that nil
    # does not respond to close, otherwise the previous application body
    # will be closed. The final application body will not be closed, as it
    # will be passed to the server as a result.
    last_body.close if last_body.respond_to? :close

    result = app.call(env)
    return result unless @cascade_for.include?(result[0].to_i)
    last_body = result[2]
  end

  result
end

#include?(app) ⇒ Boolean

Whether the given app is one of the apps to cascade to.

Returns:

  • (Boolean)


61
62
63
# File 'lib/rack/cascade.rb', line 61

def include?(app)
  @apps.include?(app)
end