web_pipe 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d89f930070f399bae4f6949b4f62b61d2fcb6f8716e9527baa350cf673daa4a6
4
- data.tar.gz: a7942d96afa3110e68dd55591a56b780d39a61c6e5b22cff5087a628b5997a6e
3
+ metadata.gz: 2f0e9b6d0efd9e7280bd1628237d3219f1307a28d63ec0d8f0e63366ce93e166
4
+ data.tar.gz: 407269e3f023e97a84855fe315ca3558ccf49a2b0cb78674336274fb1ae2c800
5
5
  SHA512:
6
- metadata.gz: 9a5b905649927d6bbba53540583f9429ef862aa0ee764087f037f3b490e32c87d3d24cbd30980267d7a7bd89735d23c9a3965c21938fa50d326f7a794eab6c6b
7
- data.tar.gz: 19c1b7ec4247cfe48cde66b0c74eee6978f905759f943b77d0b93d315e2cc603759a4ae5afc7282945255093d4fd746e4101e62834067b10853aaa9f69e3d254
6
+ metadata.gz: a2bf1652e9c88e4dcd708b95fc573d1daffeea2f3d56fd908598eb447c1819912c2ac53a35eecf0a5315d4e1195b9c412c34e5a58fb70cf3c5cfa36da602aa45
7
+ data.tar.gz: 386e1da635847bc21ab2eee5203babda8020fb89f8a11be51e2718bf844e34405ccdb60f4e537d3d3e7afb3d62264f32add6be94711420f490e2f02c3420c9be
data/CHANGELOG.md CHANGED
@@ -4,6 +4,70 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/).
6
6
 
7
+ ## [0.3.0] - 2019-07-12
8
+ ### Added
9
+ - **BREAKING**: When plugging with `plug:`, the operation is no longer specified through `with:`. Now it is just the second positional argument ([9](https://github.com/waiting-for-dev/web_pipe/pull/9)):
10
+
11
+ ```ruby
12
+ plug :from_container, 'container'
13
+ plug :inline, ->(conn) { conn.set_response_body('Hello world') }
14
+ ```
15
+ - It is possible to plug a block ([9](https://github.com/waiting-for-dev/web_pipe/pull/9)):
16
+ ```ruby
17
+ plug(:content_type) { |conn| conn.add_response_header('Content-Type', 'text/html') }
18
+ ```
19
+
20
+ - WebPipe plug's can be composed. A WebPipe proc representation is the composition of all its operations, which is an operation itself ([9](https://github.com/waiting-for-dev/web_pipe/pull/9)):
21
+
22
+ ```ruby
23
+ class HtmlApp
24
+ include WebPipe
25
+
26
+ plug :content_type
27
+ plug :default_status
28
+
29
+ private
30
+
31
+ def content_type(conn)
32
+ conn.add_response_header('Content-Type', 'text/html')
33
+ end
34
+
35
+ def default_status(conn)
36
+ conn.set_status(404)
37
+ end
38
+ end
39
+
40
+ class App
41
+ include WebPipe
42
+
43
+ plug :html, &HtmlApp.new
44
+ plug :body
45
+
46
+ private
47
+
48
+ def body(conn)
49
+ conn.set_response_body('Hello, world!')
50
+ end
51
+ end
52
+ ```
53
+
54
+ - WebPipe's middlewares can be composed into another WebPipe class, also through `:use`:
55
+
56
+ ```ruby
57
+ class HtmlApp
58
+ include WebPipe
59
+
60
+ use Rack::Session::Cookie, key: 'key', secret: 'top_secret'
61
+ use Rack::MethodOverride
62
+ end
63
+
64
+ class App
65
+ include WebPipe
66
+
67
+ use HtmlApp
68
+ end
69
+ ```
70
+
7
71
  ## [0.2.0] - 2019-07-05
8
72
  ### Added
9
73
  - dry-view integration ([#1](https://github.com/waiting-for-dev/web_pipe/pull/1), [#3](https://github.com/waiting-for-dev/web_pipe/pull/3), [#4](https://github.com/waiting-for-dev/web_pipe/pull/4), [#5](https://github.com/waiting-for-dev/web_pipe/pull/5) and [#6](https://github.com/waiting-for-dev/web_pipe/pull/6))
@@ -15,4 +79,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
15
79
 
16
80
  ## [0.1.0] - 2019-05-07
17
81
  ### Added
18
- - Initial release.
82
+ - Initial release.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- web_pipe (0.1.0)
4
+ web_pipe (0.2.0)
5
5
  dry-initializer (~> 3.0)
6
6
  dry-monads (~> 1.2)
7
7
  dry-struct (~> 1.0)
data/README.md CHANGED
@@ -180,20 +180,52 @@ class App
180
180
 
181
181
  #### Proc (or anything responding to `#call`)
182
182
 
183
- Operations can also be defined inline, through the `with:` keyword, as
184
- anything that responds to `#call`, like a `Proc`:
183
+ Operations can also be defined inline as anything that responds to
184
+ `#call`, like a `Proc`, or also like a block:
185
185
 
186
186
  ```ruby
187
187
  class App
188
188
  include WebPipe
189
189
 
190
- plug :hello, with: ->(conn) { conn }
190
+ plug :hello, ->(conn) { conn }
191
+ plug(:hello2) { |conn| conn }
192
+ end
193
+ ```
194
+
195
+ The representation of a `WebPipe` as a Proc is itself an operation
196
+ accepting a `Conn` and returning a `Conn`: the composition of all its
197
+ plugs. Therefore, it can be plugged to any other `WebPipe`:
198
+
199
+ ```ruby
200
+ class HtmlApp
201
+ include WebPipe
202
+
203
+ plug :html
204
+
205
+ private
206
+
207
+ def html(conn)
208
+ conn.add_response_header('Content-Type', 'text/html')
209
+ end
210
+ end
211
+
212
+ class App
213
+ include WebPipe
214
+
215
+ plug :html, &HtmlApp.new
216
+ plug :body
217
+
218
+ private
219
+
220
+ def body(conn)
221
+ conn.set_response_body('Hello, world!')
222
+ end
191
223
  end
192
224
  ```
193
225
 
194
226
  #### Container
195
227
 
196
- When `with:` is a `String` or a `Symbol`, it can be used as the key to
228
+ When a `String` or a `Symbol` is given, it can be used as the key to
197
229
  resolve an operation from a container. A container is just anything
198
230
  responding to `#[]`.
199
231
 
@@ -207,7 +239,7 @@ class App
207
239
 
208
240
  include WebPipe.(container: Container)
209
241
 
210
- plug :hello, with: 'plugs.hello'
242
+ plug :hello, 'plugs.hello'
211
243
  end
212
244
  ```
213
245
 
@@ -220,7 +252,7 @@ overriding those configured through `plug`:
220
252
  class App
221
253
  include WebPipe
222
254
 
223
- plug :hello, with: ->(conn) { conn.set_response_body('Hello') }
255
+ plug :hello, ->(conn) { conn.set_response_body('Hello') }
224
256
  end
225
257
 
226
258
  run App.new(
@@ -243,7 +275,20 @@ class App
243
275
  use Middleware1
244
276
  use Middleware2, option_1: value_1
245
277
 
246
- plug :hello, with: ->(conn) { conn }
278
+ plug :hello, ->(conn) { conn }
279
+ end
280
+ ```
281
+
282
+ It is also possible to compose all the middlewares from another pipe
283
+ class. Extending from previous example:
284
+
285
+ ```ruby
286
+ class App2
287
+ include WebPipe
288
+
289
+ use App # it will also use Middleware1 and Middleware2
290
+
291
+ plug :hello, ->(conn) { conn }
247
292
  end
248
293
  ```
249
294
 
data/lib/web_pipe/app.rb CHANGED
@@ -1,11 +1,8 @@
1
1
  require 'dry/initializer'
2
- require 'dry/monads/result'
3
2
  require 'web_pipe/types'
4
3
  require 'web_pipe/conn'
5
4
  require 'web_pipe/conn_support/builder'
6
- require 'dry/monads/result/extensions/either'
7
-
8
- Dry::Monads::Result.load_extensions(:either)
5
+ require 'web_pipe/conn_support/composition'
9
6
 
10
7
  module WebPipe
11
8
  # Rack application built around applying a pipe of {Operation} to
@@ -26,41 +23,24 @@ module WebPipe
26
23
  # whenever the stack is emptied or a {Conn::Dirty} is
27
24
  # returned in any of the steps.
28
25
  class App
29
- # Type for an operation.
30
- #
31
- # It should be anything callable expecting a {Conn} and
32
- # returning a {Conn}.
33
- Operation = Types.Interface(:call)
34
-
35
26
  # Type for a rack environment.
36
27
  RackEnv = Types::Strict::Hash
37
28
 
38
- # Error raised when an {Operation} returns something that is not a
39
- # {Conn}.
40
- class InvalidOperationResult < RuntimeError
41
- # @param returned [Any] What was returned from the {Operation}
42
- def initialize(returned)
43
- super(
44
- <<~eos
45
- An operation returned +#{returned.inspect}+. To be valid,
46
- an operation must return whether a
47
- WebPipe::Conn::Clean or a WebPipe::Conn::Dirty.
48
- eos
49
- )
50
- end
51
- end
52
-
53
29
  include Dry::Monads::Result::Mixin
54
30
 
55
31
  include Dry::Initializer.define -> do
56
32
  # @!attribute [r] operations
57
33
  # @return [Array<Operation[]>]
58
- param :operations, type: Types.Array(Operation)
34
+ param :operations, type: Types.Array(
35
+ ConnSupport::Composition::Operation
36
+ )
59
37
  end
60
38
 
61
39
  # @param env [Hash] Rack env
62
40
  #
63
41
  # @return env [Array] Rack response
42
+ # @raise ConnSupport::Composition::InvalidOperationResult when an
43
+ # operation does not return a {Conn}
64
44
  def call(env)
65
45
  extract_rack_response(
66
46
  apply_operations(
@@ -74,33 +54,15 @@ module WebPipe
74
54
  private
75
55
 
76
56
  def conn_from_env(env)
77
- Success(
78
- ConnSupport::Builder.(env)
79
- )
57
+ ConnSupport::Builder.(env)
80
58
  end
81
59
 
82
60
  def apply_operations(conn)
83
- operations.reduce(conn) do |new_conn, operation|
84
- new_conn.bind { |c| apply_operation(c, operation) }
85
- end
86
- end
87
-
88
- def apply_operation(conn, operation)
89
- result = operation.(conn)
90
- case result
91
- when Conn::Clean
92
- Success(result)
93
- when Conn::Dirty
94
- Failure(result)
95
- else
96
- raise InvalidOperationResult.new(result)
97
- end
61
+ ConnSupport::Composition.new(operations).call(conn)
98
62
  end
99
63
 
100
64
  def extract_rack_response(conn)
101
- extract_proc = :rack_response.to_proc
102
-
103
- conn.either(extract_proc, extract_proc)
65
+ conn.rack_response
104
66
  end
105
67
  end
106
68
  end
@@ -0,0 +1,89 @@
1
+ require 'dry/initializer'
2
+ require 'dry/monads/result'
3
+ require 'web_pipe/types'
4
+ require 'web_pipe/conn'
5
+ require 'dry/monads/result/extensions/either'
6
+
7
+ Dry::Monads::Result.load_extensions(:either)
8
+
9
+ module WebPipe
10
+ module ConnSupport
11
+ # Composition of a pipe of {Operation} on a {Conn}.
12
+ #
13
+ # It represents the composition of a series of functions which
14
+ # take a {Conn} as argument and return a {Conn}.
15
+ #
16
+ # However, {Conn} can itself be of two different types (subclasses
17
+ # of it): a {Conn::Clean} or a {Conn::Dirty}. On execution time,
18
+ # the composition is stopped whenever the stack is emptied or a
19
+ # {Conn::Dirty} is returned in any of the steps.
20
+ class Composition
21
+ # Type for an operation.
22
+ #
23
+ # It should be anything callable expecting a {Conn} and
24
+ # returning a {Conn}.
25
+ Operation = Types.Interface(:call)
26
+
27
+ # Error raised when an {Operation} returns something that is not
28
+ # a {Conn}.
29
+ class InvalidOperationResult < RuntimeError
30
+ # @param returned [Any] What was returned from the {Operation}
31
+ def initialize(returned)
32
+ super(
33
+ <<~eos
34
+ An operation returned +#{returned.inspect}+. To be valid,
35
+ an operation must return whether a
36
+ WebPipe::Conn::Clean or a WebPipe::Conn::Dirty.
37
+ eos
38
+ )
39
+ end
40
+ end
41
+
42
+ include Dry::Monads::Result::Mixin
43
+
44
+ include Dry::Initializer.define -> do
45
+ # @!attribute [r] operations
46
+ # @return [Array<Operation[]>]
47
+ param :operations, type: Types.Array(Operation)
48
+ end
49
+
50
+ # @param conn [Conn]
51
+ # @return [Conn]
52
+ # @raise InvalidOperationResult when an operation does not
53
+ # return a {Conn}
54
+ def call(conn)
55
+ extract_result(
56
+ apply_operations(
57
+ conn
58
+ )
59
+ )
60
+ end
61
+
62
+ private
63
+
64
+ def apply_operations(conn)
65
+ operations.reduce(Success(conn)) do |new_conn, operation|
66
+ new_conn.bind { |c| apply_operation(c, operation) }
67
+ end
68
+ end
69
+
70
+ def apply_operation(conn, operation)
71
+ result = operation.(conn)
72
+ case result
73
+ when Conn::Clean
74
+ Success(result)
75
+ when Conn::Dirty
76
+ Failure(result)
77
+ else
78
+ raise InvalidOperationResult.new(result)
79
+ end
80
+ end
81
+
82
+ def extract_result(result)
83
+ extract_proc = :itself.to_proc
84
+
85
+ result.either(extract_proc, extract_proc)
86
+ end
87
+ end
88
+ end
89
+ end
@@ -51,8 +51,8 @@ module WebPipe
51
51
  def define_dsl
52
52
  DSL_METHODS.each do |method|
53
53
  module_exec(dsl_context) do |dsl_context|
54
- define_method(method) do |*args|
55
- dsl_context.method(method).(*args)
54
+ define_method(method) do |*args, &block|
55
+ dsl_context.method(method).(*args, &block)
56
56
  end
57
57
  end
58
58
  end
@@ -2,6 +2,7 @@ require 'dry/initializer'
2
2
  require 'web_pipe/types'
3
3
  require 'web_pipe/plug'
4
4
  require 'web_pipe/rack/middleware'
5
+ require 'web_pipe/rack/middleware_specification'
5
6
 
6
7
  module WebPipe
7
8
  module DSL
@@ -21,32 +22,42 @@ module WebPipe
21
22
 
22
23
  include Dry::Initializer.define -> do
23
24
  param :middlewares,
24
- type: Types.Array(Rack::Middleware::Instance)
25
+ type: Types.Array(Rack::Middleware)
25
26
 
26
27
  param :plugs,
27
28
  type: Types.Array(Plug::Instance)
28
29
  end
29
30
 
30
- # Creates and add a rack middleware to the stack.
31
+ # Creates and add rack middlewares to the stack.
31
32
  #
32
- # @param middleware
33
- # [WebPipe::Rack::Middleware::MiddlewareClass[]] Rack middleware
34
- # @param middleware [WebPipe::Rack::Options[]] Options to
35
- # initialize
33
+ # The spec can be given in two forms:
34
+ #
35
+ # - As one or two arguments, first one being a
36
+ # {::Rack::Middleware} class and second one optionally its
37
+ # initialization options.
38
+ # - As a {WebPipe} class, in which case all its rack middlewares
39
+ # will be added to the stack in order.
40
+ #
41
+ # @param spec [Rack::MiddlewareSpecification::Spec[]]
36
42
  #
37
43
  # @return [Array<Rack::Middleware>]
38
- def use(middleware, *options)
39
- middlewares << Rack::Middleware.new(middleware, options)
44
+ def use(*spec)
45
+ middlewares.push(*Rack::MiddlewareSpecification.call(spec))
40
46
  end
41
47
 
42
48
  # Creates and adds a plug to the stack.
43
49
  #
50
+ # The spec can be given as a {Plug::Spec} or as a block, which
51
+ # is captured into a {Proc} (one of the options for a
52
+ # {Plug::Spec}.
53
+ #
44
54
  # @param name [Plug::Name[]]
45
- # @param with [Plug::Spec[]]
55
+ # @param spec [Plug::Spec[]]
56
+ # @param block_spec [Proc]
46
57
  #
47
58
  # @return [Array<Plug>]
48
- def plug(name, with: nil)
49
- plugs << Plug.new(name, with)
59
+ def plug(name, spec = nil, &block_spec)
60
+ plugs << Plug.new(name, spec || block_spec)
50
61
  end
51
62
  end
52
63
  end
@@ -4,6 +4,7 @@ require 'web_pipe/conn'
4
4
  require 'web_pipe/app'
5
5
  require 'web_pipe/plug'
6
6
  require 'web_pipe/rack/app_with_middlewares'
7
+ require 'web_pipe/conn_support/composition'
7
8
 
8
9
  module WebPipe
9
10
  module DSL
@@ -35,14 +36,17 @@ module WebPipe
35
36
  type: Injections
36
37
  end
37
38
 
38
- # @return [Rack::AppWithMiddlewares]
39
+ # @return [Rack::AppWithMiddlewares[]]
39
40
  attr_reader :rack_app
40
41
 
42
+ # @return [ConnSupport::Composition::Operation[]]
43
+ attr_reader :operations
44
+
41
45
  def initialize(*args)
42
46
  super
43
47
  middlewares = self.class.middlewares
44
48
  container = self.class.container
45
- operations = Plug.inject_and_resolve(self.class.plugs, injections, container, self)
49
+ @operations = Plug.inject_and_resolve(self.class.plugs, injections, container, self)
46
50
  app = App.new(operations)
47
51
  @rack_app = Rack::AppWithMiddlewares.new(middlewares, app)
48
52
  end
@@ -55,6 +59,44 @@ module WebPipe
55
59
  def call(env)
56
60
  rack_app.call(env)
57
61
  end
62
+
63
+ # Proc for the composition of all operations.
64
+ #
65
+ # This can be used to plug a {WebPipe} itself as an operation.
66
+ #
67
+ # @example
68
+ # class HtmlApp
69
+ # include WebPipe
70
+ #
71
+ # plug :html
72
+ #
73
+ # private
74
+ #
75
+ # def html(conn)
76
+ # conn.add_response_header('Content-Type', 'text/html')
77
+ # end
78
+ # end
79
+ #
80
+ # class App
81
+ # include WebPipe
82
+ #
83
+ # plug :html, &HtmlApp.new
84
+ # plug :body
85
+ #
86
+ # private
87
+ #
88
+ # def body(conn)
89
+ # conn.set_response_body('Hello, world!')
90
+ # end
91
+ # end
92
+ #
93
+ # @see ConnSupport::Composition
94
+ def to_proc
95
+ ConnSupport::Composition.
96
+ new(operations).
97
+ method(:call).
98
+ to_proc
99
+ end
58
100
  end
59
101
  end
60
102
  end
@@ -38,7 +38,7 @@ module WebPipe
38
38
  #
39
39
  # Container = { 'views.say_hello' => SayHelloView.new }.freeze
40
40
  #
41
- # plug :container, with: WebPipe::Plugs::Container[Container]
41
+ # plug :container, WebPipe::Plugs::Container[Container]
42
42
  # plug :render
43
43
  #
44
44
  # def render(conn)
@@ -17,7 +17,7 @@ module WebPipe
17
17
  #
18
18
  # ViewContext = (conn) -> { { current_path: conn.full_path } }
19
19
  #
20
- # plug :view_context, with: WebPipe::Plugs::ViewContext[ViewContext]
20
+ # plug :view_context, WebPipe::Plugs::ViewContext[ViewContext]
21
21
  # plug :render
22
22
  #
23
23
  # def render
data/lib/web_pipe/plug.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'dry/initializer'
2
2
  require 'web_pipe/types'
3
- require 'web_pipe/app'
3
+ require 'web_pipe/conn_support/composition'
4
4
 
5
5
  module WebPipe
6
6
  # A plug is a specification to resolve a callable object.
@@ -25,8 +25,8 @@ module WebPipe
25
25
  super(
26
26
  <<~eos
27
27
  Plug with name +#{name}+ is invalid. It must be something
28
- callable, an instance method when `with:` is not given, or
29
- something callable registered in the container."
28
+ callable, an instance method when no operation is given,
29
+ or something callable registered in the container."
30
30
  eos
31
31
  )
32
32
  end
@@ -35,9 +35,13 @@ module WebPipe
35
35
  # Type for the name of a plug.
36
36
  Name = Types::Strict::Symbol.constructor(&:to_sym)
37
37
 
38
- # Type for the spec to resolve and {App::Operation} on a
39
- # {Conn} used by {Plug}.
40
- Spec = App::Operation | Types.Constant(nil) | Types::Strict::String | Types::Strict::Symbol
38
+ # Type for the spec to resolve and
39
+ # {ConnSupport::Composition::Operation} on a {Conn} used by
40
+ # {Plug}.
41
+ Spec = ConnSupport::Composition::Operation |
42
+ Types.Constant(nil) |
43
+ Types::Strict::String |
44
+ Types::Strict::Symbol
41
45
 
42
46
  # Type for an instance of self.
43
47
  Instance = Types.Instance(self)
@@ -68,7 +72,7 @@ module WebPipe
68
72
  # @param container [Types::Container[]]
69
73
  # @param object [Object]
70
74
  #
71
- # @return [Operation[]]
75
+ # @return [ConnSupport::Composition::Operation[]]
72
76
  # @raise [InvalidPlugError] When nothing callable is resolved.
73
77
  def call(container, pipe)
74
78
  if spec.respond_to?(:call)
@@ -89,7 +93,7 @@ module WebPipe
89
93
  # @container container [Types::Container[]]
90
94
  # @object [Object]
91
95
  #
92
- # @return [Array<Operation[]>]
96
+ # @return [Array<ConnSupport::Composition::Operation[]>]
93
97
  def self.inject_and_resolve(plugs, injections, container, object)
94
98
  plugs.map do |plug|
95
99
  if injections.has_key?(plug.name)
@@ -13,7 +13,7 @@ module WebPipe
13
13
  #
14
14
  # Cont = { name: SomeDependency.new }.freeze
15
15
  #
16
- # plug :container, with: WebPipe::Plugs::Container[Cont]
16
+ # plug :container, WebPipe::Plugs::Container[Cont]
17
17
  # plug :resolve
18
18
  #
19
19
  # private
@@ -10,7 +10,7 @@ module WebPipe
10
10
  # class App
11
11
  # include WebPipe
12
12
  #
13
- # plug :html, with: WebPipe::Plugs::ContentType['text/html']
13
+ # plug :html, WebPipe::Plugs::ContentType['text/html']
14
14
  # end
15
15
  module ContentType
16
16
  # Content-Type header
@@ -24,7 +24,7 @@ module WebPipe
24
24
 
25
25
  include Dry::Initializer.define -> do
26
26
  param :rack_middlewares,
27
- type: Types.Array(Middleware::Instance)
27
+ type: Types.Array(Middleware)
28
28
 
29
29
  param :app, type: App
30
30
  end
@@ -51,7 +51,7 @@ module WebPipe
51
51
  def build_rack_app(rack_middlewares, app)
52
52
  ::Rack::Builder.new.tap do |b|
53
53
  rack_middlewares.each do |middleware|
54
- b.use(middleware.middleware, *middleware.middleware_options)
54
+ b.use(middleware.middleware, *middleware.options)
55
55
  end
56
56
  b.run(app)
57
57
  end
@@ -1,14 +1,14 @@
1
1
  require 'dry/initializer'
2
2
  require 'web_pipe/types'
3
+ require 'dry/struct'
3
4
 
4
5
  module WebPipe
5
6
  module Rack
6
7
  # Simple data structure to represent a rack middleware class with
7
8
  # its initialization options.
8
- class Middleware
9
- # Type for an instance of self.
10
- Instance = Types.Instance(self)
11
-
9
+ #
10
+ # @api private
11
+ class Middleware < Dry::Struct
12
12
  # Type for a rack middleware class.
13
13
  MiddlewareClass = Types.Instance(Class)
14
14
 
@@ -17,17 +17,11 @@ module WebPipe
17
17
 
18
18
  # @!attribute [r] middleware
19
19
  # @return [MiddlewareClass[]] Rack middleware
20
+ attribute :middleware, MiddlewareClass
20
21
 
21
22
  # @!attribute [r] options
22
- # @return [Options[]]
23
- # Options to initialize the rack middleware
24
-
25
-
26
- include Dry::Initializer.define -> do
27
- param :middleware, type: MiddlewareClass
28
-
29
- param :middleware_options, type: Options
30
- end
23
+ # @return [Options[]] Options to initialize the rack middleware
24
+ attribute :options, Options
31
25
  end
32
26
  end
33
27
  end
@@ -0,0 +1,33 @@
1
+ require 'web_pipe/rack/middleware'
2
+ require 'web_pipe/types'
3
+
4
+ module WebPipe
5
+ module Rack
6
+ # Specification on how to resolve {Rack::Middleware}'s.
7
+ #
8
+ # Rack middlewares can be specified in two ways:
9
+ #
10
+ # - As an array where fist element is a rack middleware class
11
+ # while the rest of elements are its initialization options.
12
+ # - A single element array where it is a class including
13
+ # {WebPipe}. This specifies all {Rack::Middlewares} configured
14
+ # for that {WebPipe}.
15
+ #
16
+ # @api private
17
+ module MiddlewareSpecification
18
+ # Resolves {Rack::Middlewares} from given specification.
19
+ #
20
+ # @param spec [Array]
21
+ # @return [Array<Rack::Middleware>]
22
+ def self.call(spec)
23
+ klass = spec[0]
24
+ options = spec[1..-1] || Types::EMPTY_ARRAY
25
+ if klass.included_modules.include?(WebPipe)
26
+ klass.middlewares
27
+ elsif klass.is_a?(Class)
28
+ [Middleware.new(middleware: klass, options: options)]
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,3 +1,3 @@
1
1
  module WebPipe
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: web_pipe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marc Busqué
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-07-05 00:00:00.000000000 Z
11
+ date: 2019-07-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -221,6 +221,7 @@ files:
221
221
  - lib/web_pipe/app.rb
222
222
  - lib/web_pipe/conn.rb
223
223
  - lib/web_pipe/conn_support/builder.rb
224
+ - lib/web_pipe/conn_support/composition.rb
224
225
  - lib/web_pipe/conn_support/errors.rb
225
226
  - lib/web_pipe/conn_support/headers.rb
226
227
  - lib/web_pipe/conn_support/types.rb
@@ -236,6 +237,7 @@ files:
236
237
  - lib/web_pipe/plugs/content_type.rb
237
238
  - lib/web_pipe/rack/app_with_middlewares.rb
238
239
  - lib/web_pipe/rack/middleware.rb
240
+ - lib/web_pipe/rack/middleware_specification.rb
239
241
  - lib/web_pipe/types.rb
240
242
  - lib/web_pipe/version.rb
241
243
  - web_pipe.gemspec