web_pipe 0.4.0 → 0.5.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: 846bd7956d65605edaad299346280d7ae4b426d8cf4160e47ebac7375135b4e7
4
- data.tar.gz: 41923761b8227c956f6b554bf8dc49fdc6323dc97e08399b5f8b4bc043552fdf
3
+ metadata.gz: 17cb26c4876d3063751dd001c823d57f3ada911be264407078b76bd8cfc684b5
4
+ data.tar.gz: 251591e61a0f30661a09ca507f28231e418fa9a626856613c8e171a67a107f37
5
5
  SHA512:
6
- metadata.gz: b2de9d0a5e7f172e9c42fcf2e97b6ff22046552670c9cf096d270438aab9d572fb4bd915fba282e578f48b39c412ba867d8359881426073b936c9734b3e8a693
7
- data.tar.gz: b72848b3ad1e98f18dea9da6b8dc19eef99c61ffb3f71115fd041b1fe699b5ca22bf0395f80e4fd16621d1b72ba8970a1555577126f148ffadf4768ed4a417b4
6
+ metadata.gz: 8ae7586e3ed9a3969d540609bad29257f0d7c5eb06c244ad954e7a10cce44507ce5b247a7f7a18ece6d3713969108e8c172aac85442f01d41824bd477270bbe1
7
+ data.tar.gz: d3a4900f7daf79377aaf7dd9ad3df397b5b55d16eb53d1ac025a029f9feb28e392819b969f9a64e5573216252db257f9e6f4ef359960c246b45321ed3708d6c7
data/.gitignore CHANGED
@@ -9,3 +9,5 @@
9
9
 
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
+
13
+ Gemfile.lock
data/CHANGELOG.md CHANGED
@@ -4,33 +4,86 @@ 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.5.0] - 2019-07-26
8
+ ### Added
9
+ - **BREAKING**: `container` is now an extension
10
+ ([16](https://github.com/waiting-for-dev/web_pipe/pull/16)):
11
+
12
+ It adds a `Conn#container` method, while the plug while being the same than before it has been moved to `web_pipe/extensions/container/plugs/container`.
13
+
14
+ - Extension providing Integration with `dry-schema` [([18](https://github.com/waiting-for-dev/web_pipe/pull/18))]. See [`extensions/dry_schema.rb`](lib/web_pipe/extensions/dry_schema/dry_schema.rb).
15
+
16
+ - No need to manually call `#to_proc` when composing plugs. This makes both of
17
+ the following valid
18
+ ([13](https://github.com/waiting-for-dev/web_pipe/pull/13)):
19
+
20
+ ```ruby
21
+ plug :app, &App.new
22
+ plug :app, App.new
23
+ ```
24
+
25
+ - Extension adding flash functionality to conn ([15](https://github.com/waiting-for-dev/web_pipe/pull/15)).
26
+
27
+ For this extension to work,
28
+ [`Rack::Flash`](https://github.com/treeder/rack-flash) and `Rack::Session`
29
+ middlewares must be used:
30
+
31
+ ```ruby
32
+ require 'rack-flash'
33
+ require 'rack/session/cookie'
34
+
35
+ class App
36
+ include WebPipe
37
+
38
+ use :session, Rack::Session::Cookie, secret: 'secret'
39
+ use :flash, Rack::Flash
40
+
41
+ plug :put_in_flash, ->(conn) { conn.put_flash(:error, 'Error') }
42
+ plug :put_in_flash_now, ->(conn) { conn.put_flash_now(:error_now, 'Error now') }
43
+ end
44
+ ```
45
+
46
+ Usually you will expose `conn.flash` to your views.
47
+
48
+ - Extension automatically require their associated plugs, so there is no need
49
+ to require them manually anymore.
50
+
51
+ ### Fixed
52
+ - Fixed bug not allowing middlewares to modify responses initially set with
53
+ default values ([14](https://github.com/waiting-for-dev/web_pipe/pull/14))
54
+
7
55
  ## [0.4.0] - 2019-07-17
8
56
  ### Added
9
- - **BREAKING**: Middlewares have to be named when used ([11](https://github.com/waiting-for-dev/web_pipe/pull/11)):
57
+ - **BREAKING**: Middlewares have to be named when used
58
+ ([11](https://github.com/waiting-for-dev/web_pipe/pull/11)):
10
59
 
11
60
  ```ruby
12
61
  use :cookies, Rack::Session:Cookie, secret: 'my_secret', key: 'foo'
13
62
  ```
14
63
 
15
- - **BREAKING**: Middlewares have to be initialized when composed ([11](https://github.com/waiting-for-dev/web_pipe/pull/11)):
64
+ - **BREAKING**: Middlewares have to be initialized when composed
65
+ ([11](https://github.com/waiting-for-dev/web_pipe/pull/11)):
16
66
 
17
67
  ```ruby
18
68
  use :pipe, PipeWithMiddlewares.new
19
69
  ```
20
70
 
21
- - **BREAKING**: The array of injected plugs is now scoped within a `plugs:` kwarg ([11](https://github.com/waiting-for-dev/web_pipe/pull/11)):
71
+ - **BREAKING**: The array of injected plugs is now scoped within a `plugs:`
72
+ kwarg ([11](https://github.com/waiting-for-dev/web_pipe/pull/11)):
22
73
 
23
74
  ```ruby
24
75
  App.new(plugs: { nothing: ->(conn) { conn } })
25
76
  ```
26
77
 
27
- - Middlewares can be injected ([11](https://github.com/waiting-for-dev/web_pipe/pull/11)):
78
+ - Middlewares can be injected
79
+ ([11](https://github.com/waiting-for-dev/web_pipe/pull/11)):
28
80
 
29
81
  ```ruby
30
82
  App.new(middlewares: { cache: [MyMiddleware, my_options] })
31
83
  ```
32
84
 
33
- - DSL helper method `compose` to add middlewares and plugs in order and in a single shot ([12](https://github.com/waiting-for-dev/web_pipe/pull/11)):
85
+ - DSL helper method `compose` to add middlewares and plugs in order and in a
86
+ single shot ([12](https://github.com/waiting-for-dev/web_pipe/pull/11)):
34
87
 
35
88
  ```ruby
36
89
  class App
@@ -57,18 +110,23 @@ end
57
110
 
58
111
  ## [0.3.0] - 2019-07-12
59
112
  ### Added
60
- - **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)):
113
+ - **BREAKING**: When plugging with `plug:`, the operation is no longer
114
+ specified through `with:`. Now it is just the second positional argument
115
+ ([9](https://github.com/waiting-for-dev/web_pipe/pull/9)):
61
116
 
62
117
  ```ruby
63
118
  plug :from_container, 'container'
64
119
  plug :inline, ->(conn) { conn.set_response_body('Hello world') }
65
120
  ```
66
- - It is possible to plug a block ([9](https://github.com/waiting-for-dev/web_pipe/pull/9)):
121
+ - It is possible to plug a block
122
+ ([9](https://github.com/waiting-for-dev/web_pipe/pull/9)):
67
123
  ```ruby
68
124
  plug(:content_type) { |conn| conn.add_response_header('Content-Type', 'text/html') }
69
125
  ```
70
126
 
71
- - 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)):
127
+ - WebPipe plug's can be composed. A WebPipe proc representation is the
128
+ composition of all its operations, which is an operation itself
129
+ ([9](https://github.com/waiting-for-dev/web_pipe/pull/9)):
72
130
 
73
131
  ```ruby
74
132
  class HtmlApp
@@ -102,7 +160,8 @@ class App
102
160
  end
103
161
  ```
104
162
 
105
- - WebPipe's middlewares can be composed into another WebPipe class, also through `:use` ([10](https://github.com/waiting-for-dev/web_pipe/pull/10)):
163
+ - WebPipe's middlewares can be composed into another WebPipe class, also
164
+ through `:use` ([10](https://github.com/waiting-for-dev/web_pipe/pull/10)):
106
165
 
107
166
  ```ruby
108
167
  class HtmlApp
@@ -121,12 +180,21 @@ end
121
180
 
122
181
  ## [0.2.0] - 2019-07-05
123
182
  ### Added
124
- - 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))
125
- - Configuring a container in `WebPipe::Conn` ([#2](https://github.com/waiting-for-dev/web_pipe/pull/2) and [#5](https://github.com/waiting-for-dev/web_pipe/pull/5))
126
- - Plug to set `Content-Type` response header ([#7](https://github.com/waiting-for-dev/web_pipe/pull/7))
183
+ - dry-view integration
184
+ ([#1](https://github.com/waiting-for-dev/web_pipe/pull/1),
185
+ [#3](https://github.com/waiting-for-dev/web_pipe/pull/3),
186
+ [#4](https://github.com/waiting-for-dev/web_pipe/pull/4),
187
+ [#5](https://github.com/waiting-for-dev/web_pipe/pull/5) and
188
+ [#6](https://github.com/waiting-for-dev/web_pipe/pull/6))
189
+ - Configuring a container in `WebPipe::Conn`
190
+ ([#2](https://github.com/waiting-for-dev/web_pipe/pull/2) and
191
+ [#5](https://github.com/waiting-for-dev/web_pipe/pull/5))
192
+ - Plug to set `Content-Type` response header
193
+ ([#7](https://github.com/waiting-for-dev/web_pipe/pull/7))
127
194
 
128
195
  ### Fixed
129
- - Fix key interpolation in `KeyNotFoundInBagError` ([#8](https://github.com/waiting-for-dev/web_pipe/pull/8))
196
+ - Fix key interpolation in `KeyNotFoundInBagError`
197
+ ([#8](https://github.com/waiting-for-dev/web_pipe/pull/8))
130
198
 
131
199
  ## [0.1.0] - 2019-05-07
132
200
  ### Added
data/README.md CHANGED
@@ -212,7 +212,7 @@ end
212
212
  class App
213
213
  include WebPipe
214
214
 
215
- plug :html, &HtmlApp.new
215
+ plug :html, HtmlApp.new
216
216
  plug :body
217
217
 
218
218
  private
@@ -321,8 +321,6 @@ WebPipe::App.new([op_1, op_2])
321
321
  `web_pipe` ships with a series of common operations you can take
322
322
  advantage in order to build your application:
323
323
 
324
- - [container](lib/web_pipe/plugs/container.rb): Allows
325
- configuring a container to resolve dependencies.
326
324
  - [content_type](lib/web_pipe/plugs/content_type.rb): Sets
327
325
  `Content-Type` response header.
328
326
 
@@ -332,6 +330,8 @@ By default, `web_pipe` behavior is the very minimal you need to build
332
330
  a web application. However, you can extend it with the following
333
331
  extensions (click on each name for details on the usage):
334
332
 
333
+ - [container](lib/web_pipe/plugs/container.rb): Allows
334
+ configuring a container to resolve dependencies.
335
335
  - [dry-view](lib/web_pipe/extensions/dry_view/dry_view.rb):
336
336
  Integration with [`dry-view`](https://dry-rb.org/gems/dry-view/)
337
337
  rendering system.
data/lib/web_pipe/app.rb CHANGED
@@ -1,4 +1,3 @@
1
- require 'dry/initializer'
2
1
  require 'web_pipe/types'
3
2
  require 'web_pipe/conn'
4
3
  require 'web_pipe/conn_support/builder'
@@ -28,12 +27,14 @@ module WebPipe
28
27
 
29
28
  include Dry::Monads::Result::Mixin
30
29
 
31
- include Dry::Initializer.define -> do
32
- # @!attribute [r] operations
33
- # @return [Array<Operation[]>]
34
- param :operations, type: Types.Array(
35
- ConnSupport::Composition::Operation
36
- )
30
+ # @!attribute [r] operations
31
+ # @return [Array<Operation[]>]
32
+ attr_reader :operations
33
+
34
+ def initialize(operations)
35
+ @operations = Types.Array(
36
+ ConnSupport::Composition::Operation
37
+ )[operations]
37
38
  end
38
39
 
39
40
  # @param env [Hash] Rack env
@@ -1,4 +1,3 @@
1
- require 'dry/initializer'
2
1
  require 'dry/monads/result'
3
2
  require 'web_pipe/types'
4
3
  require 'web_pipe/conn'
@@ -41,10 +40,12 @@ module WebPipe
41
40
 
42
41
  include Dry::Monads::Result::Mixin
43
42
 
44
- include Dry::Initializer.define -> do
45
- # @!attribute [r] operations
46
- # @return [Array<Operation[]>]
47
- param :operations, type: Types.Array(Operation)
43
+ # @!attribute [r] operations
44
+ # @return [Array<Operation[]>]
45
+ attr_reader :operations
46
+
47
+ def initialize(operations)
48
+ @operations = Types.Array(Operation)[operations]
48
49
  end
49
50
 
50
51
  # @param conn [Conn]
@@ -12,5 +12,21 @@ module WebPipe
12
12
  )
13
13
  end
14
14
  end
15
+
16
+ # Error raised when trying to use a conn's feature which requires
17
+ # a rack middleware which is not present
18
+ class MissingMiddlewareError < RuntimeError
19
+ # @param feature [String] Name of the feature intended to be used
20
+ # @param middleware [String] Name of the missing middleware
21
+ # @param gem [String] Gem name for the middleware
22
+ def initialize(feature, middleware, gem)
23
+ super(
24
+ <<~eos
25
+ In order to use #{feature} you must use #{middleware} middleware:
26
+ https://rubygems.org/gems/#{gem}
27
+ eos
28
+ )
29
+ end
30
+ end
15
31
  end
16
32
  end
@@ -34,15 +34,15 @@ module WebPipe
34
34
  Status = Strict::Integer.
35
35
  default(200).
36
36
  constrained(gteq: 100, lteq: 599)
37
- ResponseBody = Interface(:each).default([''].freeze)
37
+ ResponseBody = Interface(:each).default { [''] }
38
38
 
39
39
  Headers = Strict::Hash.
40
40
  map(Strict::String, Strict::String).
41
- default({}.freeze)
41
+ default { {} }
42
42
 
43
43
  Bag = Strict::Hash.
44
44
  map(Strict::Symbol, Strict::Any).
45
- default({}.freeze)
45
+ default { {} }
46
46
  end
47
47
  end
48
48
  end
@@ -1,4 +1,3 @@
1
- require 'dry/initializer'
2
1
  require 'web_pipe/types'
3
2
  require 'web_pipe/dsl/class_context'
4
3
  require 'web_pipe/dsl/instance_methods'
@@ -16,17 +15,13 @@ module WebPipe
16
15
 
17
16
  # @!attribute [r] container
18
17
  # @return [Types::Container[]]
19
-
20
-
21
- include Dry::Initializer.define -> do
22
- option :container, type: Types::Container, default: proc { EMPTY_CONTAINER }
23
- end
18
+ attr_reader :container
24
19
 
25
20
  # @return [ClassContext]
26
21
  attr_reader :class_context
27
22
 
28
- def initialize(*args)
29
- super
23
+ def initialize(container: EMPTY_CONTAINER)
24
+ @container = Types::Container[container]
30
25
  @class_context = ClassContext.new(container: container)
31
26
  end
32
27
 
@@ -1,4 +1,3 @@
1
- require 'dry-initializer'
2
1
  require 'web_pipe/types'
3
2
  require 'web_pipe/dsl/dsl_context'
4
3
 
@@ -22,17 +21,13 @@ module WebPipe
22
21
 
23
22
  # @!attribute [r] container
24
23
  # @return [Types::Container[]]
25
-
26
-
27
- include Dry::Initializer.define -> do
28
- option :container, type: Types::Container
29
- end
24
+ attr_reader :container
30
25
 
31
26
  # @return [DSLContext]
32
27
  attr_reader :dsl_context
33
28
 
34
- def initialize(*args)
35
- super
29
+ def initialize(container:)
30
+ @container = Types::Container[container]
36
31
  @dsl_context = DSLContext.new([], [])
37
32
  define_container
38
33
  define_dsl
@@ -1,4 +1,4 @@
1
- require 'dry/initializer'
1
+ require 'web_pipe'
2
2
  require 'web_pipe/types'
3
3
  require 'web_pipe/plug'
4
4
  require 'web_pipe/rack/middleware_specification'
@@ -14,17 +14,17 @@ module WebPipe
14
14
  class DSLContext
15
15
  # @!attribute middleware_specifications
16
16
  # @return [Array<Rack::MiddlewareSpecifications>]
17
+ attr_reader :middleware_specifications
17
18
 
18
19
  # @!attribute plugs
19
20
  # @return [Array<Plug>]
21
+ attr_reader :plugs
20
22
 
21
-
22
- include Dry::Initializer.define -> do
23
- param :middleware_specifications,
24
- type: Types.Array(Rack::MiddlewareSpecification)
25
-
26
- param :plugs,
27
- type: Types.Array(Plug::Instance)
23
+ def initialize(middleware_specifications, plugs)
24
+ @middleware_specifications = Types.Array(
25
+ Rack::MiddlewareSpecification
26
+ )[middleware_specifications]
27
+ @plugs = Types.Array(Plug::Instance)[plugs]
28
28
  end
29
29
 
30
30
  # Creates and add rack middleware specifications to the stack.
@@ -42,22 +42,31 @@ module WebPipe
42
42
  #
43
43
  # @return [Array<Rack::Middleware>]
44
44
  def use(name, *spec)
45
- middleware_specifications << Rack::MiddlewareSpecification.new(name, spec)
45
+ middleware_specifications << Rack::MiddlewareSpecification.new(name: name, spec: spec)
46
46
  end
47
47
 
48
48
  # Creates and adds a plug to the stack.
49
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}.
50
+ # The spec can be given as a {Plug::Spec}, as a block (which
51
+ # is captured into a {Proc}, one of the options for a
52
+ # {Plug::Spec} or as a {WebPipe} (in which case all its plugs
53
+ # will be composed).
53
54
  #
54
55
  # @param name [Plug::Name[]]
55
- # @param spec [Plug::Spec[]]
56
+ # @param spec [Plug::Spec[], WebPipe]
56
57
  # @param block_spec [Proc]
57
58
  #
58
59
  # @return [Array<Plug>]
59
60
  def plug(name, spec = nil, &block_spec)
60
- plugs << Plug.new(name, spec || block_spec)
61
+ plug_spec = if spec.is_a?(WebPipe)
62
+ spec.to_proc
63
+ elsif spec
64
+ spec
65
+ else
66
+ block_spec
67
+ end
68
+
69
+ plugs << Plug.new(name: name, spec: plug_spec)
61
70
  end
62
71
 
63
72
  # Adds middlewares and plugs from a WebPipe to respective
@@ -67,7 +76,7 @@ module WebPipe
67
76
  # @param spec [WebPipe]
68
77
  def compose(name, spec)
69
78
  use(name, spec)
70
- plug(name, &spec)
79
+ plug(name, spec)
71
80
  end
72
81
  end
73
82
  end
@@ -1,4 +1,3 @@
1
- require 'dry/initializer'
2
1
  require 'web_pipe/types'
3
2
  require 'web_pipe/conn'
4
3
  require 'web_pipe/app'
@@ -36,13 +35,7 @@ module WebPipe
36
35
  # @!attribute [r] injections [Injections[]]
37
36
  # Injected plugs and middlewares that allow overriding what
38
37
  # has been configured.
39
-
40
-
41
- include Dry::Initializer.define -> do
42
- param :injections,
43
- default: proc { EMPTY_INJECTIONS },
44
- type: Injections
45
- end
38
+ attr_reader :injections
46
39
 
47
40
  # @return [Rack::AppWithMiddlewares[]]
48
41
  attr_reader :rack_app
@@ -53,8 +46,8 @@ module WebPipe
53
46
  # @return [Array<Rack::Middlewares>]
54
47
  attr_reader :middlewares
55
48
 
56
- def initialize(*args)
57
- super
49
+ def initialize(injects = EMPTY_INJECTIONS)
50
+ @injections = Injections[injects]
58
51
  container = self.class.container
59
52
  @middlewares = Rack::MiddlewareSpecification.inject_and_resolve(
60
53
  self.class.middleware_specifications, injections[:middlewares]
@@ -0,0 +1,30 @@
1
+ require 'web_pipe'
2
+
3
+ module WebPipe
4
+ # Extension adding a `#container` method to fetch bag's `:container`
5
+ # key.
6
+ #
7
+ # Usually, the container is set with {WebPipe::Plugs::Container}.
8
+ #
9
+ # @example
10
+ # require 'web_pipe'
11
+ #
12
+ # WebPipe.load_extensions(:container)
13
+ #
14
+ # class App
15
+ # include WebPipe
16
+ #
17
+ # plug :container, WebPipe::Plugs::Container[MyContainer]
18
+ # plug :render, ->(conn) { conn.set_response_body(conn.container['view']) }
19
+ # end
20
+ module Container
21
+ # Returns bag `:container` value
22
+ #
23
+ # @return [Any]
24
+ def container
25
+ fetch(:container)
26
+ end
27
+ end
28
+
29
+ Conn.include(Container)
30
+ end
@@ -0,0 +1,78 @@
1
+ require 'web_pipe'
2
+
3
+ module WebPipe
4
+ # Integration with `dry-schema` validation library.
5
+ #
6
+ # This extension provides a simple integration with `dry-schema`
7
+ # library to streamline param sanitization.
8
+ #
9
+ # On its own, the library just provides with a
10
+ # `Conn#sanitized_params` method, which will return what is set into
11
+ # bag's `:sanitized_params` key.
12
+ #
13
+ # This key in the bag is what will be populated by `SanitizeParams`
14
+ # plug, which accepts a `dry-validation` schema that will be applied
15
+ # to `Conn#params`:
16
+ #
17
+ # @example
18
+ # require 'web_pipe'
19
+ #
20
+ # WebPipe.load_extensions(:dry_schema)
21
+ #
22
+ # class App
23
+ # include WebPipe
24
+ #
25
+ # Schema = Dry::Schema.Params do
26
+ # required(:name).filled(:string)
27
+ # end
28
+ #
29
+ # plug :sanitize_params, WebPipe::Plugs::SanitizeParams[Schema]
30
+ # plug(:do_something_with_params) do |conn|
31
+ # DB.persist(:entity, conn.sanitized_params)
32
+ # end
33
+ # end
34
+ #
35
+ # By default, when the result of applying the schema is a failure,
36
+ # {Conn} is tainted with a 500 as status code. However, you can
37
+ # specify your own handler for the unhappy path. It will take the
38
+ # {Conn} and {Dry::Schema::Result} instances as arguments:
39
+ #
40
+ # @example
41
+ # plug :sanitize_params, WebPipe::Plugs::SanitizeParams[
42
+ # Schema,
43
+ # ->(conn, result) { ... }
44
+ # ]
45
+ #
46
+ # A common workflow is applying the same handler for all param
47
+ # sanitization across your application. This can be achieved setting
48
+ # a `:param_sanitization_handler` bag key in a upstream operation
49
+ # which can be composed downstream for any number of
50
+ # pipes. `SanitizeParams` will used configured handler if none is
51
+ # injected as argument. Another plug `ParamSanitizationHandler`
52
+ # exists to help with this process:
53
+ #
54
+ # @example
55
+ # class App
56
+ # plug :sanitization_handler, WebPipe::Plugs::ParamSanitizationHandler[
57
+ # ->(conn, result) { ... }
58
+ # ]
59
+ # end
60
+ #
61
+ # class Subapp
62
+ # Schema = Dry::Schema.Params { ... }
63
+ #
64
+ # plug :app, App.new
65
+ # plug :sanitize_params, WebPipe::Plugs::SanitizeParams[Schema]
66
+ # end
67
+ #
68
+ # @see https://dry-rb.org/gems/dry-schema/
69
+ module DrySchema
70
+ SANITIZED_PARAMS_KEY = :sanitized_params
71
+
72
+ def sanitized_params
73
+ fetch(SANITIZED_PARAMS_KEY)
74
+ end
75
+ end
76
+
77
+ Conn.include(DrySchema)
78
+ end
@@ -0,0 +1,27 @@
1
+ require 'web_pipe/types'
2
+
3
+ module WebPipe
4
+ module Plugs
5
+ # Sets `:param_sanitization_handler` bag key.
6
+ #
7
+ # @see WebPipe::DrySchema
8
+ module ParamSanitizationHandler
9
+ # Bag key to store the handler.
10
+ #
11
+ # @return [Symbol]
12
+ PARAM_SANITIZATION_HANDLER_KEY = :param_sanitization_handler
13
+
14
+ # Type constructor for the handler.
15
+ Handler = Types.Interface(:call)
16
+
17
+ # @param handler [Handler[]]
18
+ #
19
+ # @return [ConnSupport::Composition::Operation[]]
20
+ def self.[](handler)
21
+ lambda do |conn|
22
+ conn.put(PARAM_SANITIZATION_HANDLER_KEY, Handler[handler])
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,46 @@
1
+ require 'web_pipe/types'
2
+ require 'web_pipe/extensions/dry_schema/dry_schema'
3
+ require 'web_pipe/extensions/dry_schema/plugs/param_sanitization_handler'
4
+
5
+ module WebPipe
6
+ module Plugs
7
+ # Sanitize {Conn#params} with given `dry-schema` Schema.
8
+ #
9
+ # @see WebPipe::DrySchema
10
+ module SanitizeParams
11
+ # Default handler if none is configured nor injected.
12
+ #
13
+ # @return [ParamSanitizationHandler::Handler[]]
14
+ DEFAULT_HANDLER = lambda do |conn, _result|
15
+ conn.
16
+ set_status(500).
17
+ set_response_body('Given params do not conform with the expected schema').
18
+ taint
19
+ end
20
+
21
+ # @param schema [Dry::Schema::Processor]
22
+ # @param handler [ParamSanitizationHandler::Handler[]]
23
+ #
24
+ # @return [ConnSupport::Composition::Operation[], Types::Undefined]
25
+ def self.[](schema, handler = Types::Undefined)
26
+ lambda do |conn|
27
+ result = schema.(conn.params)
28
+ if result.success?
29
+ conn.put(DrySchema::SANITIZED_PARAMS_KEY, result.output)
30
+ else
31
+ get_handler(conn, handler).(conn, result)
32
+ end
33
+ end
34
+ end
35
+
36
+ def self.get_handler(conn, handler)
37
+ return handler unless handler == Types::Undefined
38
+
39
+ conn.fetch(
40
+ Plugs::ParamSanitizationHandler::PARAM_SANITIZATION_HANDLER_KEY, DEFAULT_HANDLER
41
+ )
42
+ end
43
+ private_class_method :get_handler
44
+ end
45
+ end
46
+ end
@@ -29,10 +29,12 @@ module WebPipe
29
29
  # end
30
30
  #
31
31
  # If {WebPipe::Conn#bag} has a `:container` key, the view instance
32
- # can be resolved from it. {WebPipe::Plugs::Container} can be used
33
- # to streamline this integration.
32
+ # can be resolved from it. {WebPipe::Container} extension can be
33
+ # used to streamline this integration.
34
34
  #
35
35
  # @example
36
+ # WebPipe.load_extensions(:dry_view, :container)
37
+ #
36
38
  # class App
37
39
  # include WebPipe
38
40
  #
@@ -100,7 +102,8 @@ module WebPipe
100
102
  # # ...
101
103
  #
102
104
  # @see https://dry-rb.org/gems/dry-view/
103
- class Conn < Dry::Struct
105
+ # @see WebPipe::Container
106
+ module DryView
104
107
  # Where to find in {#bag} request's view context
105
108
  VIEW_CONTEXT_KEY = :view_context
106
109
 
@@ -153,4 +156,6 @@ module WebPipe
153
156
  kwargs.merge(context: context)
154
157
  end
155
158
  end
159
+
160
+ Conn.include(DryView)
156
161
  end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'web_pipe/conn'
4
+ require 'web_pipe/conn_support/errors'
5
+
6
+ module WebPipe
7
+ # Provides with a tipical flash messages functionality.
8
+ #
9
+ # @example
10
+ # require 'web_pipe'
11
+ # require 'rack/session/cookie'
12
+ # require 'rack-flash'
13
+ #
14
+ # WebPipe.load_extensions(:flash)
15
+ #
16
+ # class MyApp
17
+ # include WebPipe
18
+ #
19
+ # use :session, Rack::Session::Cookie, secret: 'secret'
20
+ # use :flash, Rack::Flash
21
+ #
22
+ # plug :put_in_flash, ->(conn) { conn.put_flash(:notice, 'Hello world') }
23
+ # plug :put_in_flash_now, ->(conn) { conn.put_flash_now(:notice_now, 'Hello world now') }
24
+ # end
25
+ #
26
+ # Usually, you will end up making `conn.flash` available to your view system:
27
+ #
28
+ # @example
29
+ # <div class="notice"><%= flash[:notice] %></div>
30
+ #
31
+ # For this extension to be used, `Rack::Flash` middleware must be
32
+ # added to the stack (gem name is `rack-flash3`. This middleware in
33
+ # turns depend on `Rack::Session` middleware.
34
+ #
35
+ # This extension is a very simple wrapper around `Rack::Flash` API.
36
+ #
37
+ # @see https://github.com/nakajima/rack-flash
38
+ module Flash
39
+ RACK_FLASH_KEY = 'x-rack.flash'
40
+
41
+ # Returns the flash bag.
42
+ #
43
+ # @return [Rack::Flash::FlashHash]
44
+ #
45
+ # @raises ConnSupport::MissingMiddlewareError when `Rack::Flash`
46
+ # is not being used as middleware
47
+ def flash
48
+ env.fetch(RACK_FLASH_KEY) do
49
+ raise ConnSupport::MissingMiddlewareError.new(
50
+ 'flash', 'Rack::Flash', 'rack-flash3'
51
+ )
52
+ end
53
+ end
54
+
55
+ # Puts an item to the flash bag to be consumed by next request.
56
+ #
57
+ # @param key [String]
58
+ # @param value [String]
59
+ def put_flash(key, value)
60
+ flash[key] = value
61
+ self
62
+ end
63
+
64
+ # Puts an item to the flash bag to be consumed by the same request
65
+ # in process.
66
+ #
67
+ # @param key [String]
68
+ # @param value [String]
69
+ def put_flash_now(key, value)
70
+ flash.now[key] = value
71
+ self
72
+ end
73
+ end
74
+
75
+ Conn.include(Flash)
76
+ end
data/lib/web_pipe/plug.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'dry/initializer'
1
+ require 'dry/struct'
2
2
  require 'web_pipe/types'
3
3
  require 'web_pipe/conn_support/composition'
4
4
 
@@ -17,7 +17,7 @@ module WebPipe
17
17
  # from the `container`.
18
18
  #
19
19
  # @api private
20
- class Plug
20
+ class Plug < Dry::Struct
21
21
  # Error raised when no operation can be resolved from a {Spec}.
22
22
  class InvalidPlugError < ArgumentError
23
23
  # @param name [Any] Name for the plug that can't be resolved
@@ -55,23 +55,18 @@ module WebPipe
55
55
 
56
56
  # @!attribute [r] name
57
57
  # @return [Name[]]
58
+ attribute :name, Name
58
59
 
59
60
  # @!attribute [r] spec
60
61
  # @return [Spec[]]
61
-
62
-
63
- include Dry::Initializer.define -> do
64
- param :name, Name
65
-
66
- param :spec, Spec
67
- end
62
+ attribute :spec, Spec
68
63
 
69
64
  # Creates a new instance with given `spec` but keeping `name`.
70
65
  #
71
66
  # @param new_spec [Spec[]]
72
67
  # @return [self]
73
68
  def with(new_spec)
74
- self.class.new(name, new_spec)
69
+ new(spec: new_spec)
75
70
  end
76
71
 
77
72
  # Resolves the operation.
@@ -1,4 +1,3 @@
1
- require 'dry/initializer'
2
1
  require 'web_pipe/types'
3
2
  require 'web_pipe/rack/middleware'
4
3
  require 'rack'
@@ -17,23 +16,18 @@ module WebPipe
17
16
 
18
17
  # @!attribute [r] rack_middlewares
19
18
  # @return [Array<RackMiddleware>]
19
+ attr_reader :rack_middlewares
20
20
 
21
21
  # @!attribute [r] app
22
22
  # @return [App[]]
23
-
24
-
25
- include Dry::Initializer.define -> do
26
- param :rack_middlewares,
27
- type: Types.Array(Middleware)
28
-
29
- param :app, type: App
30
- end
23
+ attr_reader :app
31
24
 
32
25
  # @return [Rack::Builder]
33
26
  attr_reader :builder
34
27
 
35
- def initialize(*args)
36
- super
28
+ def initialize(rack_middlewares, app)
29
+ @rack_middlewares = Types.Array(Middleware)[rack_middlewares]
30
+ @app = App[app]
37
31
  @builder = build_rack_app(rack_middlewares, app)
38
32
  end
39
33
 
@@ -1,4 +1,3 @@
1
- require 'dry/initializer'
2
1
  require 'web_pipe/types'
3
2
  require 'dry/struct'
4
3
 
@@ -1,3 +1,4 @@
1
+ require 'dry/struct'
1
2
  require 'web_pipe/rack/middleware'
2
3
  require 'web_pipe/types'
3
4
 
@@ -14,7 +15,7 @@ module WebPipe
14
15
  # for that {WebPipe}.
15
16
  #
16
17
  # @api private
17
- class MiddlewareSpecification
18
+ class MiddlewareSpecification < Dry::Struct
18
19
  # Type for the name given to a middleware.
19
20
  Name = Types::Strict::Symbol.constructor(&:to_sym)
20
21
 
@@ -30,16 +31,11 @@ module WebPipe
30
31
 
31
32
  # @!attribute [r] name
32
33
  # @return [Name[]]
34
+ attribute :name, Name
33
35
 
34
36
  # @!attribute [r] spec
35
37
  # @return [Spec[]]
36
-
37
-
38
- include Dry::Initializer.define -> do
39
- param :name, Name
40
-
41
- param :spec, Spec
42
- end
38
+ attribute :spec, Spec
43
39
 
44
40
  # Change spec's present in `injections` and resolves.
45
41
  #
@@ -76,7 +72,7 @@ module WebPipe
76
72
  #
77
73
  # @return [MiddlewareSpecification]
78
74
  def with(new_spec)
79
- self.class.new(name, new_spec)
75
+ new(spec: new_spec)
80
76
  end
81
77
  end
82
78
  end
@@ -1,3 +1,3 @@
1
1
  module WebPipe
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
data/lib/web_pipe.rb CHANGED
@@ -16,7 +16,23 @@ module WebPipe
16
16
  DSL::Builder.new(*args)
17
17
  end
18
18
 
19
+ register_extension :dry_schema do
20
+ require 'web_pipe/extensions/dry_schema/dry_schema'
21
+ require 'web_pipe/extensions/dry_schema/plugs/sanitize_params'
22
+ require 'web_pipe/extensions/dry_schema/plugs/param_sanitization_handler'
23
+ end
24
+
19
25
  register_extension :dry_view do
20
26
  require 'web_pipe/extensions/dry_view/dry_view'
27
+ require 'web_pipe/extensions/dry_view/plugs/view_context'
28
+ end
29
+
30
+ register_extension :container do
31
+ require 'web_pipe/extensions/container/container'
32
+ require 'web_pipe/extensions/container/plugs/container'
33
+ end
34
+
35
+ register_extension :flash do
36
+ require 'web_pipe/extensions/flash/flash'
21
37
  end
22
38
  end
data/web_pipe.gemspec CHANGED
@@ -39,7 +39,6 @@ Gem::Specification.new do |spec|
39
39
  spec.add_runtime_dependency "dry-monads", "~> 1.2"
40
40
  spec.add_runtime_dependency "dry-types", "~> 1.1"
41
41
  spec.add_runtime_dependency "dry-struct", "~> 1.0"
42
- spec.add_runtime_dependency "dry-initializer", "~> 3.0"
43
42
 
44
43
  spec.add_development_dependency "bundler", "~> 1.17"
45
44
  spec.add_development_dependency "rake", "~> 10.0"
@@ -49,4 +48,6 @@ Gem::Specification.new do |spec|
49
48
  spec.add_development_dependency "redcarpet", "~> 3.4"
50
49
  spec.add_development_dependency "pry-byebug"
51
50
  spec.add_development_dependency "dry-view", "~> 0.7"
51
+ spec.add_development_dependency "rack-flash3", "~> 1.0"
52
+ spec.add_development_dependency "dry-schema", "~> 1.0"
52
53
  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.4.0
4
+ version: 0.5.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-17 00:00:00.000000000 Z
11
+ date: 2019-07-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -66,20 +66,6 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1.0'
69
- - !ruby/object:Gem::Dependency
70
- name: dry-initializer
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '3.0'
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '3.0'
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: bundler
85
71
  requirement: !ruby/object:Gem::Requirement
@@ -198,6 +184,34 @@ dependencies:
198
184
  - - "~>"
199
185
  - !ruby/object:Gem::Version
200
186
  version: '0.7'
187
+ - !ruby/object:Gem::Dependency
188
+ name: rack-flash3
189
+ requirement: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - "~>"
192
+ - !ruby/object:Gem::Version
193
+ version: '1.0'
194
+ type: :development
195
+ prerelease: false
196
+ version_requirements: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - "~>"
199
+ - !ruby/object:Gem::Version
200
+ version: '1.0'
201
+ - !ruby/object:Gem::Dependency
202
+ name: dry-schema
203
+ requirement: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - "~>"
206
+ - !ruby/object:Gem::Version
207
+ version: '1.0'
208
+ type: :development
209
+ prerelease: false
210
+ version_requirements: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - "~>"
213
+ - !ruby/object:Gem::Version
214
+ version: '1.0'
201
215
  description:
202
216
  email:
203
217
  - marc@lamarciana.com
@@ -211,7 +225,6 @@ files:
211
225
  - ".yardopts"
212
226
  - CHANGELOG.md
213
227
  - Gemfile
214
- - Gemfile.lock
215
228
  - README.md
216
229
  - Rakefile
217
230
  - bin/console
@@ -229,11 +242,16 @@ files:
229
242
  - lib/web_pipe/dsl/class_context.rb
230
243
  - lib/web_pipe/dsl/dsl_context.rb
231
244
  - lib/web_pipe/dsl/instance_methods.rb
245
+ - lib/web_pipe/extensions/container/container.rb
246
+ - lib/web_pipe/extensions/container/plugs/container.rb
247
+ - lib/web_pipe/extensions/dry_schema/dry_schema.rb
248
+ - lib/web_pipe/extensions/dry_schema/plugs/param_sanitization_handler.rb
249
+ - lib/web_pipe/extensions/dry_schema/plugs/sanitize_params.rb
232
250
  - lib/web_pipe/extensions/dry_view/dry_view.rb
233
251
  - lib/web_pipe/extensions/dry_view/plugs/view_context.rb
252
+ - lib/web_pipe/extensions/flash/flash.rb
234
253
  - lib/web_pipe/plug.rb
235
254
  - lib/web_pipe/plugs.rb
236
- - lib/web_pipe/plugs/container.rb
237
255
  - lib/web_pipe/plugs/content_type.rb
238
256
  - lib/web_pipe/rack/app_with_middlewares.rb
239
257
  - lib/web_pipe/rack/middleware.rb
data/Gemfile.lock DELETED
@@ -1,99 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- web_pipe (0.3.0)
5
- dry-initializer (~> 3.0)
6
- dry-monads (~> 1.2)
7
- dry-struct (~> 1.0)
8
- dry-types (~> 1.1)
9
- rack (~> 2.0)
10
-
11
- GEM
12
- remote: https://rubygems.org/
13
- specs:
14
- byebug (11.0.0)
15
- coderay (1.1.2)
16
- concurrent-ruby (1.1.5)
17
- diff-lcs (1.3)
18
- dry-configurable (0.8.2)
19
- concurrent-ruby (~> 1.0)
20
- dry-core (~> 0.4, >= 0.4.7)
21
- dry-container (0.7.1)
22
- concurrent-ruby (~> 1.0)
23
- dry-configurable (~> 0.1, >= 0.1.3)
24
- dry-core (0.4.7)
25
- concurrent-ruby (~> 1.0)
26
- dry-equalizer (0.2.2)
27
- dry-inflector (0.1.2)
28
- dry-initializer (3.0.1)
29
- dry-logic (1.0.2)
30
- concurrent-ruby (~> 1.0)
31
- dry-core (~> 0.2)
32
- dry-equalizer (~> 0.2)
33
- dry-monads (1.2.0)
34
- concurrent-ruby (~> 1.0)
35
- dry-core (~> 0.4, >= 0.4.4)
36
- dry-equalizer
37
- dry-struct (1.0.0)
38
- dry-core (~> 0.4, >= 0.4.3)
39
- dry-equalizer (~> 0.2)
40
- dry-types (~> 1.0)
41
- ice_nine (~> 0.11)
42
- dry-types (1.1.0)
43
- concurrent-ruby (~> 1.0)
44
- dry-container (~> 0.3)
45
- dry-core (~> 0.4, >= 0.4.4)
46
- dry-equalizer (~> 0.2, >= 0.2.2)
47
- dry-inflector (~> 0.1, >= 0.1.2)
48
- dry-logic (~> 1.0, >= 1.0.2)
49
- dry-view (0.7.0)
50
- dry-configurable (~> 0.1)
51
- dry-core (~> 0.2)
52
- dry-equalizer (~> 0.2)
53
- dry-inflector (~> 0.1)
54
- tilt (~> 2.0, >= 2.0.6)
55
- ice_nine (0.11.2)
56
- method_source (0.9.2)
57
- pry (0.12.2)
58
- coderay (~> 1.1.0)
59
- method_source (~> 0.9.0)
60
- pry-byebug (3.7.0)
61
- byebug (~> 11.0)
62
- pry (~> 0.10)
63
- rack (2.0.6)
64
- rack-test (1.1.0)
65
- rack (>= 1.0, < 3)
66
- rake (10.5.0)
67
- redcarpet (3.4.0)
68
- rspec (3.8.0)
69
- rspec-core (~> 3.8.0)
70
- rspec-expectations (~> 3.8.0)
71
- rspec-mocks (~> 3.8.0)
72
- rspec-core (3.8.0)
73
- rspec-support (~> 3.8.0)
74
- rspec-expectations (3.8.2)
75
- diff-lcs (>= 1.2.0, < 2.0)
76
- rspec-support (~> 3.8.0)
77
- rspec-mocks (3.8.0)
78
- diff-lcs (>= 1.2.0, < 2.0)
79
- rspec-support (~> 3.8.0)
80
- rspec-support (3.8.0)
81
- tilt (2.0.9)
82
- yard (0.9.20)
83
-
84
- PLATFORMS
85
- ruby
86
-
87
- DEPENDENCIES
88
- bundler (~> 1.17)
89
- dry-view (~> 0.7)
90
- pry-byebug
91
- rack-test (~> 1.1)
92
- rake (~> 10.0)
93
- redcarpet (~> 3.4)
94
- rspec (~> 3.0)
95
- web_pipe!
96
- yard (~> 0.9, >= 0.9.20)
97
-
98
- BUNDLED WITH
99
- 1.17.2