web_pipe 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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