Class: WebPipe::Pipe

Inherits:
Object
  • Object
show all
Defined in:
lib/web_pipe/pipe.rb

Overview

Composable rack application builder.

An instance of this class helps build rack applications that can compose. Besides the DSL, which only adds a convenience layer, this is the higher abstraction on the library.

Applications are built by plugging functions that take and return a Conn instance. That's an immutable struct that contains all the request information alongside methods to build the response. See #plug for details.

Middlewares can also be added to the resulting application thanks to #use.

Be aware that instances of this class are immutable, so methods return new objects every time.

The instance itself is the final rack application.

config.ru

require 'web_pipe/pipe'

app = WebPipe::Pipe.new .use(:runtime, Rack::Runtime) .plug(:content_type) do |conn| conn.add_response_header('Content-Type', 'text/plain') end .plug(:render) do |conn| conn.set_response_body('Hello, World!') end

run app

Constant Summary collapse

EMPTY_CONTAINER =

Container that resolves nothing

{}.freeze
EMPTY_PLUGS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

[].freeze
EMPTY_MIDDLEWARE_SPECIFICATIONS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

[].freeze
Container =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Types.Interface(:[])

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(container: EMPTY_CONTAINER, context: nil, plugs: EMPTY_PLUGS, middleware_specifications: EMPTY_MIDDLEWARE_SPECIFICATIONS) ⇒ Pipe

(see #plug). #plug)

Parameters:

  • container (#to_h) (defaults to: EMPTY_CONTAINER)

    Container from where resolve plug's operations

  • context (Any) (defaults to: nil)

    Object from where resolve plug's operations (see



74
75
76
77
78
79
80
81
82
83
84
# File 'lib/web_pipe/pipe.rb', line 74

def initialize(
  container: EMPTY_CONTAINER,
  context: nil,
  plugs: EMPTY_PLUGS,
  middleware_specifications: EMPTY_MIDDLEWARE_SPECIFICATIONS
)
  @plugs = plugs
  @middleware_specifications = middleware_specifications
  @container = Container[container]
  @context = context
end

Instance Attribute Details

#containerObject (readonly)

Returns the value of attribute container.



49
50
51
# File 'lib/web_pipe/pipe.rb', line 49

def container
  @container
end

#contextObject (readonly)

Returns the value of attribute context.



53
54
55
# File 'lib/web_pipe/pipe.rb', line 53

def context
  @context
end

#middleware_specificationsObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



68
69
70
# File 'lib/web_pipe/pipe.rb', line 68

def middleware_specifications
  @middleware_specifications
end

#plugsObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



65
66
67
# File 'lib/web_pipe/pipe.rb', line 65

def plugs
  @plugs
end

Instance Method Details

#call(env) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



202
203
204
# File 'lib/web_pipe/pipe.rb', line 202

def call(env)
  rack_app.call(env)
end

#compose(name, spec) ⇒ Object

Shortcut for #plug and #use a pipe at once.

Parameters:



149
150
151
152
# File 'lib/web_pipe/pipe.rb', line 149

def compose(name, spec)
  use(name, spec)
    .plug(name, spec)
end

#inject(plugs: {}, middleware_specifications: {}) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/web_pipe/pipe.rb', line 188

def inject(plugs: {}, middleware_specifications: {})
  res_mw_specs = RackSupport::MiddlewareSpecification.inject(
    self.middleware_specifications, middleware_specifications
  )
  res_plugs = Plug.inject(
    self.plugs, plugs
  )
  with(
    plugs: res_plugs,
    middleware_specifications: res_mw_specs
  )
end

#middlewaresHash{Symbol=>Array<WebPipe::RackSupport::Middleware>}

Middlewares #used in the app, mapped by their names.

Returns them wrapped within RackSupport::Middleware instances, from where you can access their classes and options.

Returns:



169
170
171
172
173
# File 'lib/web_pipe/pipe.rb', line 169

def middlewares
  @middlewares ||= Hash[
    middleware_specifications.map { |mw_spec| [mw_spec.name, mw_spec.call] }
  ]
end

#operationsHash{Symbol => Proc}

Operations #plugged to the app, mapped by their names.

Returns:

  • (Hash{Symbol => Proc})


157
158
159
160
161
# File 'lib/web_pipe/pipe.rb', line 157

def operations
  @operations ||= Hash[
    plugs.map { |plug| [plug.name, plug.call(container, context)] }
  ]
end

#plug(name, spec = nil) {|| ... } ⇒ WebPipe::Pipe

Names and adds a plug operation to the application.

The operation can be provided in several ways:

  • Through the spec parameter as:
    • Anything responding to #call (like a Proc).
    • As a string or symbol key for something registered in #container.
    • Anything responding to #to_proc (like another WebPipe::Pipe instance or an instance of a class including WebPipe).
    • As nil (default), meaning that the operation is a method in #context matching the name parameter.
  • Through a block, if the spec parameter is nil.

Parameters:

  • name (Symbol)
  • spec (#call, #to_proc, String, Symbol, nil) (defaults to: nil)

Yield Parameters:

Returns:



104
105
106
107
108
109
110
111
# File 'lib/web_pipe/pipe.rb', line 104

def plug(name, spec = nil, &block_spec)
  with(
    plugs: [
      *plugs,
      Plug.new(name: name, spec: spec || block_spec)
    ]
  )
end

#to_middlewaresObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



183
184
185
# File 'lib/web_pipe/pipe.rb', line 183

def to_middlewares
  middlewares.values.flatten
end

#to_procObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



176
177
178
179
180
# File 'lib/web_pipe/pipe.rb', line 176

def to_proc
  ConnSupport::Composition
    .new(operations.values)
    .method(:call)
end

#use(name, middleware_class) ⇒ WebPipe::Pipe #use(name, middleware_class, middleware_options) ⇒ WebPipe::Pipe #use(name, to_middlewares) ⇒ WebPipe::Pipe

Names and adds a rack middleware to the final application.

The middleware can be given in three forms:

  • As one or two arguments, the first one being a rack middleware class, and optionally a second one with its initialization options.
  • As something responding to #to_middlewares with an array of RackSupport::Middleware (like another WebPipe::Pipe instance or a class including WebPipe), case in which all middlewares are used.

Overloads:

  • #use(name, middleware_class) ⇒ WebPipe::Pipe

    Parameters:

    • name (Symbol)
    • middleware_class (Class)
  • #use(name, middleware_class, middleware_options) ⇒ WebPipe::Pipe

    Parameters:

    • name (Symbol)
    • middleware_class (Class)
    • middleware_options (Any)
  • #use(name, to_middlewares) ⇒ WebPipe::Pipe

    Parameters:

Returns:

  • (WebPipe::Pipe)

    A fresh new instance with the added middleware.



136
137
138
139
140
141
142
143
# File 'lib/web_pipe/pipe.rb', line 136

def use(name, *spec)
  with(
    middleware_specifications: [
      *middleware_specifications,
      RackSupport::MiddlewareSpecification.new(name: name, spec: spec)
    ]
  )
end