web_pipe 0.6.1 → 0.7.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 +4 -4
- data/CHANGELOG.md +27 -0
- data/_config.yml +1 -0
- data/lib/web_pipe.rb +8 -3
- data/lib/web_pipe/conn.rb +40 -0
- data/lib/web_pipe/conn_support/composition.rb +0 -3
- data/lib/web_pipe/conn_support/errors.rb +15 -2
- data/lib/web_pipe/extensions/container/container.rb +5 -7
- data/lib/web_pipe/extensions/dry_schema/dry_schema.rb +20 -28
- data/lib/web_pipe/extensions/dry_schema/plugs/sanitize_params.rb +7 -15
- data/lib/web_pipe/extensions/dry_view/dry_view.rb +17 -27
- data/lib/web_pipe/extensions/params/params.rb +99 -0
- data/lib/web_pipe/extensions/params/params/transf.rb +15 -0
- data/lib/web_pipe/extensions/router_params/router_params.rb +59 -0
- data/lib/web_pipe/extensions/url/url.rb +0 -36
- data/lib/web_pipe/plugs/config.rb +25 -0
- data/lib/web_pipe/plugs/content_type.rb +2 -2
- data/lib/web_pipe/version.rb +1 -1
- data/web_pipe.gemspec +2 -1
- metadata +23 -8
- data/lib/dry/monads/result/extensions/either.rb +0 -42
- data/lib/web_pipe/extensions/container/plugs/container.rb +0 -31
- data/lib/web_pipe/extensions/dry_schema/plugs/param_sanitization_handler.rb +0 -27
- data/lib/web_pipe/extensions/dry_view/plugs/view_context.rb +0 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ce3123c1c702c02eaab09f4cb56209b512499d913fddaa55a95307e779748e15
|
4
|
+
data.tar.gz: f8fdcce1e652e37b719e3a621b19f9762ec3a47b74ff39ab4695f30f5ea0722c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 117619501c7d97297266b8ac7cd89a6a2440c1cca7a1791da00e2b2a1935e790e4cd0d1877ea9ec5c9208cc9bac6ed8e07b981b04708102d67ca2760d1ed95e6
|
7
|
+
data.tar.gz: '08a391660d75a830e5e9e0bda97b62a4b299f5f543a86959d5fe86c8dda823b11438640d253400ec8a742a009c2a312cdeeb6a95c7a4cb4af4711589e5075fdd'
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,33 @@ 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.7.0] - 2019-08-27
|
8
|
+
### Added
|
9
|
+
- **BREAKING**. `Conn#config` instead of `Conn#bag` for extension configuration.
|
10
|
+
[[#29]](https://github.com/waiting-for-dev/web_pipe/pull/29)
|
11
|
+
|
12
|
+
- **BREAKING**. `:params` extension extracted from `:url` extension.
|
13
|
+
[[#30]](https://github.com/waiting-for-dev/web_pipe/pull/30)
|
14
|
+
|
15
|
+
- **BREAKING**. Router params are extracted as a param transformation.
|
16
|
+
[[#30]](https://github.com/waiting-for-dev/web_pipe/pull/30)
|
17
|
+
|
18
|
+
- **BREAKING**. Plugs now respond to `.call` instead of `.[]`.
|
19
|
+
[[#31]](https://github.com/waiting-for-dev/web_pipe/pull/31)
|
20
|
+
|
21
|
+
- **BREAKING**. `:dry-schema` extension has not a default handler.
|
22
|
+
[[#32]](https://github.com/waiting-for-dev/web_pipe/pull/32)
|
23
|
+
|
24
|
+
- **BREAKING**. `:dry-schema` extension stores output in `#config`.
|
25
|
+
[[#32]](https://github.com/waiting-for-dev/web_pipe/pull/32)
|
26
|
+
|
27
|
+
- Integration with `transproc` gem to provide any number of params
|
28
|
+
transformations.
|
29
|
+
[[#30]](https://github.com/waiting-for-dev/web_pipe/pull/30)
|
30
|
+
|
31
|
+
- `:dry-schema` extension automatically loads `:params` extension.
|
32
|
+
[[#32]](https://github.com/waiting-for-dev/web_pipe/pull/32)
|
33
|
+
|
7
34
|
## [0.6.1] - 2019-08-02
|
8
35
|
### Fixed
|
9
36
|
- Fixed support for ruby 2.4.
|
data/_config.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
theme: jekyll-theme-slate
|
data/lib/web_pipe.rb
CHANGED
@@ -23,27 +23,32 @@ module WebPipe
|
|
23
23
|
register_extension :dry_schema do
|
24
24
|
require 'web_pipe/extensions/dry_schema/dry_schema'
|
25
25
|
require 'web_pipe/extensions/dry_schema/plugs/sanitize_params'
|
26
|
-
require 'web_pipe/extensions/dry_schema/plugs/param_sanitization_handler'
|
27
26
|
end
|
28
27
|
|
29
28
|
register_extension :dry_view do
|
30
29
|
require 'web_pipe/extensions/dry_view/dry_view'
|
31
|
-
require 'web_pipe/extensions/dry_view/plugs/view_context'
|
32
30
|
end
|
33
31
|
|
34
32
|
register_extension :container do
|
35
33
|
require 'web_pipe/extensions/container/container'
|
36
|
-
require 'web_pipe/extensions/container/plugs/container'
|
37
34
|
end
|
38
35
|
|
39
36
|
register_extension :flash do
|
40
37
|
require 'web_pipe/extensions/flash/flash'
|
41
38
|
end
|
42
39
|
|
40
|
+
register_extension :router_params do
|
41
|
+
require 'web_pipe/extensions/router_params/router_params'
|
42
|
+
end
|
43
|
+
|
43
44
|
register_extension :redirect do
|
44
45
|
require 'web_pipe/extensions/redirect/redirect'
|
45
46
|
end
|
46
47
|
|
48
|
+
register_extension :params do
|
49
|
+
require 'web_pipe/extensions/params/params'
|
50
|
+
end
|
51
|
+
|
47
52
|
register_extension :session do
|
48
53
|
require 'web_pipe/extensions/session/session'
|
49
54
|
end
|
data/lib/web_pipe/conn.rb
CHANGED
@@ -210,6 +210,18 @@ module WebPipe
|
|
210
210
|
# @return [Bag[]]
|
211
211
|
attribute :bag, Bag
|
212
212
|
|
213
|
+
# @!attribute [r] config
|
214
|
+
#
|
215
|
+
# Instance level configuration.
|
216
|
+
#
|
217
|
+
# It is a hash where anything can be stored. Keys must be symbols.
|
218
|
+
#
|
219
|
+
# The idea of it is for extensions to have somewhere to store user
|
220
|
+
# provided values they may need at some point.
|
221
|
+
#
|
222
|
+
# @return [Bag[]]
|
223
|
+
attribute :config, Bag
|
224
|
+
|
213
225
|
# Sets response status code.
|
214
226
|
#
|
215
227
|
# @param code [StatusCode]
|
@@ -320,6 +332,34 @@ module WebPipe
|
|
320
332
|
)
|
321
333
|
end
|
322
334
|
|
335
|
+
# Reads an item from {#config}.
|
336
|
+
#
|
337
|
+
# @param key [Symbol]
|
338
|
+
#
|
339
|
+
# @return [Object]
|
340
|
+
#
|
341
|
+
# @raise ConnSupport::KeyNotFoundInConfigError when key is not
|
342
|
+
# present in {#config}.
|
343
|
+
def fetch_config(key, default = Types::Undefined)
|
344
|
+
return config.fetch(key, default) unless default == Types::Undefined
|
345
|
+
|
346
|
+
config.fetch(key) { raise ConnSupport::KeyNotFoundInConfigError.new(key) }
|
347
|
+
end
|
348
|
+
|
349
|
+
# Writes an item to {#config}.
|
350
|
+
#
|
351
|
+
# If it already exists, it is overwritten.
|
352
|
+
#
|
353
|
+
# @param key [Symbol]
|
354
|
+
# @param value [Object]
|
355
|
+
#
|
356
|
+
# @return [Conn]
|
357
|
+
def add_config(key, value)
|
358
|
+
new(
|
359
|
+
config: config.merge(key => value)
|
360
|
+
)
|
361
|
+
end
|
362
|
+
|
323
363
|
# Builds response in the way rack expects.
|
324
364
|
#
|
325
365
|
# It is useful to finish a rack application built with a
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module WebPipe
|
2
2
|
module ConnSupport
|
3
|
-
# Error raised when trying to fetch an entry in {Conn}
|
4
|
-
#
|
3
|
+
# Error raised when trying to fetch an entry in {Conn#bag} for an
|
4
|
+
# unknown key.
|
5
5
|
class KeyNotFoundInBagError < KeyError
|
6
6
|
# @param key [Any] Key not found in the bag
|
7
7
|
def initialize(key)
|
@@ -13,6 +13,19 @@ module WebPipe
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
+
# Error raised when trying to fetch an entry in {Conn#config} for
|
17
|
+
# an unknown key.
|
18
|
+
class KeyNotFoundInConfigError < KeyError
|
19
|
+
# @param key [Any] Key not found in config
|
20
|
+
def initialize(key)
|
21
|
+
super(
|
22
|
+
<<~eos
|
23
|
+
Config does not contain a key with name +#{key}+.
|
24
|
+
eos
|
25
|
+
)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
16
29
|
# Error raised when trying to use a conn's feature which requires
|
17
30
|
# a rack middleware which is not present
|
18
31
|
class MissingMiddlewareError < RuntimeError
|
@@ -1,10 +1,8 @@
|
|
1
1
|
require 'web_pipe'
|
2
2
|
|
3
3
|
module WebPipe
|
4
|
-
# Extension adding a `#container` method
|
5
|
-
# key.
|
6
|
-
#
|
7
|
-
# Usually, the container is set with {WebPipe::Plugs::Container}.
|
4
|
+
# Extension adding a `#container` method which returns {Conn#config}
|
5
|
+
# `:container` key.
|
8
6
|
#
|
9
7
|
# @example
|
10
8
|
# require 'web_pipe'
|
@@ -14,15 +12,15 @@ module WebPipe
|
|
14
12
|
# class App
|
15
13
|
# include WebPipe
|
16
14
|
#
|
17
|
-
# plug :container,
|
15
|
+
# plug :container, ->(conn) { conn.add_config(:container, MyContainer) }
|
18
16
|
# plug :render, ->(conn) { conn.set_response_body(conn.container['view']) }
|
19
17
|
# end
|
20
18
|
module Container
|
21
|
-
# Returns
|
19
|
+
# Returns {Conn#config} `:container` value
|
22
20
|
#
|
23
21
|
# @return [Any]
|
24
22
|
def container
|
25
|
-
|
23
|
+
fetch_config(:container)
|
26
24
|
end
|
27
25
|
end
|
28
26
|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'web_pipe'
|
2
2
|
|
3
|
+
WebPipe.load_extensions(:params)
|
4
|
+
|
3
5
|
module WebPipe
|
4
6
|
# Integration with `dry-schema` validation library.
|
5
7
|
#
|
@@ -8,11 +10,12 @@ module WebPipe
|
|
8
10
|
#
|
9
11
|
# On its own, the library just provides with a
|
10
12
|
# `Conn#sanitized_params` method, which will return what is set into
|
11
|
-
#
|
13
|
+
# config's `:sanitized_params` key.
|
12
14
|
#
|
13
|
-
# This key in
|
14
|
-
#
|
15
|
-
#
|
15
|
+
# This key in config is what will be populated by `SanitizeParams` plug. It
|
16
|
+
# takes as arguments the `dry-schema` schema that will be applied to
|
17
|
+
# `Conn#params` and an error handler taking `Conn` instance and the validation
|
18
|
+
# result:
|
16
19
|
#
|
17
20
|
# @example
|
18
21
|
# require 'web_pipe'
|
@@ -26,43 +29,32 @@ module WebPipe
|
|
26
29
|
# required(:name).filled(:string)
|
27
30
|
# end
|
28
31
|
#
|
29
|
-
# plug :sanitize_params, WebPipe::Plugs::SanitizeParams
|
32
|
+
# plug :sanitize_params, WebPipe::Plugs::SanitizeParams.(
|
33
|
+
# Schema,
|
34
|
+
# ->(conn, result) { ... }
|
35
|
+
# )
|
30
36
|
# plug(:do_something_with_params) do |conn|
|
31
37
|
# DB.persist(:entity, conn.sanitized_params)
|
32
38
|
# end
|
33
39
|
# end
|
34
40
|
#
|
35
|
-
# By default, when the result of applying the schema is a failure,
|
36
|
-
# {Conn} is halted 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
41
|
# A common workflow is applying the same handler for all param
|
47
|
-
# sanitization across your application. This can be achieved
|
48
|
-
# a `:param_sanitization_handler`
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
# exists to help with this process:
|
42
|
+
# sanitization across your application. This can be achieved configuring
|
43
|
+
# a `:param_sanitization_handler` in a upstream operation which can
|
44
|
+
# be composed downstream from any number of pipes. `SanitizeParams`
|
45
|
+
# will used configured handler if none is injected as
|
46
|
+
# argument.
|
53
47
|
#
|
54
48
|
# @example
|
55
49
|
# class App
|
56
|
-
# plug :sanitization_handler,
|
57
|
-
# ->(conn, result) { ... }
|
58
|
-
# ]
|
50
|
+
# plug :sanitization_handler, ->(conn, result) { ... }
|
59
51
|
# end
|
60
52
|
#
|
61
53
|
# class Subapp
|
62
54
|
# Schema = Dry::Schema.Params { ... }
|
63
55
|
#
|
64
56
|
# plug :app, App.new
|
65
|
-
# plug :sanitize_params, WebPipe::Plugs::SanitizeParams
|
57
|
+
# plug :sanitize_params, WebPipe::Plugs::SanitizeParams.call(Schema)
|
66
58
|
# end
|
67
59
|
#
|
68
60
|
# @see https://dry-rb.org/gems/dry-schema/
|
@@ -70,9 +62,9 @@ module WebPipe
|
|
70
62
|
SANITIZED_PARAMS_KEY = :sanitized_params
|
71
63
|
|
72
64
|
def sanitized_params
|
73
|
-
|
65
|
+
fetch_config(SANITIZED_PARAMS_KEY)
|
74
66
|
end
|
75
67
|
end
|
76
68
|
|
77
69
|
Conn.include(DrySchema)
|
78
|
-
end
|
70
|
+
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'web_pipe/types'
|
2
2
|
require 'web_pipe/extensions/dry_schema/dry_schema'
|
3
|
-
require 'web_pipe/extensions/dry_schema/plugs/param_sanitization_handler'
|
4
3
|
|
5
4
|
module WebPipe
|
6
5
|
module Plugs
|
@@ -8,25 +7,20 @@ module WebPipe
|
|
8
7
|
#
|
9
8
|
# @see WebPipe::DrySchema
|
10
9
|
module SanitizeParams
|
11
|
-
#
|
10
|
+
# {Conn#config} key to store the handler.
|
12
11
|
#
|
13
|
-
# @return [
|
14
|
-
|
15
|
-
conn.
|
16
|
-
set_status(500).
|
17
|
-
set_response_body('Given params do not conform with the expected schema').
|
18
|
-
halt
|
19
|
-
end
|
12
|
+
# @return [Symbol]
|
13
|
+
PARAM_SANITIZATION_HANDLER_KEY = :param_sanitization_handler
|
20
14
|
|
21
15
|
# @param schema [Dry::Schema::Processor]
|
22
16
|
# @param handler [ParamSanitizationHandler::Handler[]]
|
23
17
|
#
|
24
18
|
# @return [ConnSupport::Composition::Operation[], Types::Undefined]
|
25
|
-
def self.
|
19
|
+
def self.call(schema, handler = Types::Undefined)
|
26
20
|
lambda do |conn|
|
27
21
|
result = schema.(conn.params)
|
28
22
|
if result.success?
|
29
|
-
conn.
|
23
|
+
conn.add_config(DrySchema::SANITIZED_PARAMS_KEY, result.output)
|
30
24
|
else
|
31
25
|
get_handler(conn, handler).(conn, result)
|
32
26
|
end
|
@@ -36,11 +30,9 @@ module WebPipe
|
|
36
30
|
def self.get_handler(conn, handler)
|
37
31
|
return handler unless handler == Types::Undefined
|
38
32
|
|
39
|
-
conn.
|
40
|
-
Plugs::ParamSanitizationHandler::PARAM_SANITIZATION_HANDLER_KEY, DEFAULT_HANDLER
|
41
|
-
)
|
33
|
+
conn.fetch_config(PARAM_SANITIZATION_HANDLER_KEY)
|
42
34
|
end
|
43
35
|
private_class_method :get_handler
|
44
36
|
end
|
45
37
|
end
|
46
|
-
end
|
38
|
+
end
|
@@ -28,9 +28,8 @@ module WebPipe
|
|
28
28
|
# end
|
29
29
|
# end
|
30
30
|
#
|
31
|
-
# If
|
32
|
-
# can be resolved from it.
|
33
|
-
# used to streamline this integration.
|
31
|
+
# If there is a `:container` configured (in {Conn#config}), the view
|
32
|
+
# instance can be resolved from it.
|
34
33
|
#
|
35
34
|
# @example
|
36
35
|
# WebPipe.load_extensions(:dry_view, :container)
|
@@ -40,7 +39,7 @@ module WebPipe
|
|
40
39
|
#
|
41
40
|
# Container = { 'views.say_hello' => SayHelloView.new }.freeze
|
42
41
|
#
|
43
|
-
# plug :container,
|
42
|
+
# plug :config_container, ->(conn) { conn.add_config(:container, Container[Container]) }
|
44
43
|
# plug :render
|
45
44
|
#
|
46
45
|
# def render(conn)
|
@@ -52,9 +51,11 @@ module WebPipe
|
|
52
51
|
# through the `context:` argument, as in a standard call to
|
53
52
|
# {Dry::View#call}. However, it is possible to leverage configured
|
54
53
|
# default context while still being able to inject request specific
|
55
|
-
# context. For that to work,
|
56
|
-
#
|
57
|
-
#
|
54
|
+
# context. For that to work, `:view_context` should be present in
|
55
|
+
# {WebPipe::Conn#config}. Its value must be a lambda accepting the
|
56
|
+
# {Conn} instance and returning a hash, which will be passed to
|
57
|
+
# {Dry::View::Context#with} to create the final context at the
|
58
|
+
# moment {#view} is called.
|
58
59
|
#
|
59
60
|
# @example
|
60
61
|
# class MyContext < Dry::View::Context
|
@@ -77,11 +78,11 @@ module WebPipe
|
|
77
78
|
# class App
|
78
79
|
# include WebPipe
|
79
80
|
#
|
80
|
-
# plug :
|
81
|
+
# plug :config_view_context
|
81
82
|
# plug :render
|
82
83
|
#
|
83
|
-
# def
|
84
|
-
# conn.
|
84
|
+
# def config_view_context(conn)
|
85
|
+
# conn.add_config(:view_context, ->(conn) { { current_path: conn.full_path } })
|
85
86
|
# end
|
86
87
|
#
|
87
88
|
# def render(conn)
|
@@ -90,25 +91,14 @@ module WebPipe
|
|
90
91
|
# end
|
91
92
|
# end
|
92
93
|
#
|
93
|
-
# It can be streamline using {WebPipe::Plugs::ViewContext} plug,
|
94
|
-
# which accepts a callable object which should return the request
|
95
|
-
# context from given {WebPipe::Conn}:
|
96
|
-
#
|
97
|
-
# @example
|
98
|
-
# # ...
|
99
|
-
# plug :set_view_context, WebPipe::Plugs::ViewContext[
|
100
|
-
# ->(conn) { { current_path: conn.full_path } }
|
101
|
-
# ]
|
102
|
-
# # ...
|
103
|
-
#
|
104
94
|
# @see https://dry-rb.org/gems/dry-view/
|
105
95
|
# @see WebPipe::Container
|
106
96
|
module DryView
|
107
|
-
# Where to find in {#
|
97
|
+
# Where to find in {#config} request's view context generator.
|
108
98
|
VIEW_CONTEXT_KEY = :view_context
|
109
99
|
|
110
100
|
# Default request's view context
|
111
|
-
DEFAULT_VIEW_CONTEXT = Types::EMPTY_HASH
|
101
|
+
DEFAULT_VIEW_CONTEXT = ->(_conn) { Types::EMPTY_HASH }
|
112
102
|
|
113
103
|
# Sets string output of a view as response body.
|
114
104
|
#
|
@@ -117,8 +107,8 @@ module WebPipe
|
|
117
107
|
#
|
118
108
|
# `kwargs` is used as the input for the view (the arguments that
|
119
109
|
# {Dry::View#call} receives). If they doesn't contain an explicit
|
120
|
-
# `context:` key, it can be added through the injection
|
121
|
-
# of
|
110
|
+
# `context:` key, it can be added through the injection of the
|
111
|
+
# result of a lambda present in context's `:view_context`.(see
|
122
112
|
# {Dry::View::Context#with}).
|
123
113
|
#
|
124
114
|
# @param view_spec [Dry::View, Any]
|
@@ -141,7 +131,7 @@ module WebPipe
|
|
141
131
|
def view_instance(view_spec)
|
142
132
|
return view_spec if view_spec.is_a?(Dry::View)
|
143
133
|
|
144
|
-
|
134
|
+
fetch_config(:container)[view_spec]
|
145
135
|
end
|
146
136
|
|
147
137
|
def view_input(kwargs, view_instance)
|
@@ -151,7 +141,7 @@ module WebPipe
|
|
151
141
|
config.
|
152
142
|
default_context.
|
153
143
|
with(
|
154
|
-
|
144
|
+
fetch_config(VIEW_CONTEXT_KEY, DEFAULT_VIEW_CONTEXT).(self)
|
155
145
|
)
|
156
146
|
kwargs.merge(context: context)
|
157
147
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'web_pipe/types'
|
2
|
+
require 'web_pipe/extensions/params/params/transf'
|
3
|
+
|
4
|
+
module WebPipe
|
5
|
+
# Adds a {Conn#params} method which can perform any number of
|
6
|
+
# transformations to the request parameters.
|
7
|
+
#
|
8
|
+
# When no transformations are given, {#params} just returns request
|
9
|
+
# parameters (both GET and POST) as a hash:
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# # http://www.example.com?foo=bar
|
13
|
+
# conn.params #=> { 'foo' => 'bar' }
|
14
|
+
#
|
15
|
+
# Further processing can be specified thanks to `transproc` gem (you
|
16
|
+
# need to add it yourself to the Gemfile). All hash transformations
|
17
|
+
# in `transproc` are available:
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# # http://www.example.com?foo=bar
|
21
|
+
# conn.params([:deep_symbolize_keys]) #=> { foo: 'bar' }
|
22
|
+
#
|
23
|
+
# Extra needed arguments can be provided as an array:
|
24
|
+
#
|
25
|
+
# @example
|
26
|
+
# # http://www.example.com?foo=bar&zoo=zoo
|
27
|
+
# conn.params([:deep_symbolize_keys, [:reject_keys, [:zoo]]) #=> { foo: 'bar' }
|
28
|
+
#
|
29
|
+
# Instead of injecting transformations at the moment `#params` is
|
30
|
+
# called, you can configure them to be automatically used.
|
31
|
+
#
|
32
|
+
# @example
|
33
|
+
# # http://www.example.com?foo=bar
|
34
|
+
# conn.
|
35
|
+
# add_config(:param_transformation, [:deep_symbolize_keys]).
|
36
|
+
# params #=> { foo: 'bar' }
|
37
|
+
#
|
38
|
+
# You can register your own transformation functions:
|
39
|
+
#
|
40
|
+
# @example
|
41
|
+
# # http://www.example.com?foo=bar
|
42
|
+
# fake = ->(_params) { { fake: :params } }
|
43
|
+
# WebPipe::Params::Transf.register(:fake, fake)
|
44
|
+
# conn.params([:fake]) #=> { fake: :params }
|
45
|
+
#
|
46
|
+
# Your own transformation functions can depend on the {Conn}
|
47
|
+
# instance at the moment of execution. For that, just place it as the
|
48
|
+
# last argument of the function and it will be curried automatically:
|
49
|
+
#
|
50
|
+
# @example
|
51
|
+
# # http://www.example.com?foo=bar
|
52
|
+
# add_name = ->(params, conn) { params.merge(name: conn.fetch(:name)) }
|
53
|
+
# WebPipe::Params::Transf.register(:add_name, add_name)
|
54
|
+
# conn.
|
55
|
+
# add(:name, 'Joe').
|
56
|
+
# params([:deep_symbolize_keys, :add_name]) #=> { foo: 'bar', name: 'Joe' }
|
57
|
+
#
|
58
|
+
# Inline transformations can also be provided:
|
59
|
+
#
|
60
|
+
# @example
|
61
|
+
# # http://www.example.com?foo=bar
|
62
|
+
# fake = ->(_params) { { fake: :params } }
|
63
|
+
# conn.
|
64
|
+
# params(fake) #=> { fake: :params }
|
65
|
+
#
|
66
|
+
# @see https://github.com/solnic/transproc
|
67
|
+
module Params
|
68
|
+
# Key where configured transformations are set
|
69
|
+
PARAM_TRANSFORMATION_KEY = :param_transformations
|
70
|
+
|
71
|
+
# @param transformation_specs [Array<Symbol, Array>, Types::Undefined]
|
72
|
+
# @return [Any]
|
73
|
+
def params(transformation_specs = Types::Undefined)
|
74
|
+
specs = if transformation_specs == Types::Undefined
|
75
|
+
fetch_config(PARAM_TRANSFORMATION_KEY, [])
|
76
|
+
else
|
77
|
+
transformation_specs
|
78
|
+
end
|
79
|
+
transformations = specs.reduce(Transf[:id]) do |acc, t|
|
80
|
+
acc.>>transformation(t)
|
81
|
+
end
|
82
|
+
|
83
|
+
Transf[transformations].(request.params)
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def transformation(spec)
|
89
|
+
transformation = Transf[*spec]
|
90
|
+
if (transformation.fn.arity - transformation.args.count) == 1
|
91
|
+
transformation
|
92
|
+
else
|
93
|
+
Transf[*[spec, self]]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
Conn.include(Params)
|
99
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'web_pipe'
|
2
|
+
require 'web_pipe/types'
|
3
|
+
|
4
|
+
WebPipe.load_extensions(:params)
|
5
|
+
|
6
|
+
module WebPipe
|
7
|
+
# Adds a transformation to merge router params into {Conn#params}.
|
8
|
+
#
|
9
|
+
# This extension gives an opportunity for rack routers to modify
|
10
|
+
# {Conn#params} hash. This is useful so that they can provide *route
|
11
|
+
# parameters*, which are typically rendered as variables in routes
|
12
|
+
# definitions (e.g.: `/user/:id/edit`).
|
13
|
+
#
|
14
|
+
# It adds a `:router_params` transformation that, when used, will
|
15
|
+
# merged env's `router.params` in {Conn#params} hash. Choosing this
|
16
|
+
# name automatically integrates with `hanami-router`.
|
17
|
+
#
|
18
|
+
# When using this extension, `:params` extension is automatically enabled.
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# require 'web_pipe'
|
22
|
+
#
|
23
|
+
# WebPipe.load_extensions(:router_params)
|
24
|
+
#
|
25
|
+
# class MyApp
|
26
|
+
# include WebPipe
|
27
|
+
#
|
28
|
+
# plug :config
|
29
|
+
# plug :get_params
|
30
|
+
#
|
31
|
+
# private
|
32
|
+
#
|
33
|
+
# def config(conn)
|
34
|
+
# conn.add_config(:param_transformation, [:router_params])
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# def get_params(conn)
|
38
|
+
# # http://example.com/users/1/edit
|
39
|
+
# conn.params #=> { id: 1 }
|
40
|
+
# conn
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# @see WebPipe::Params
|
45
|
+
# @see https://github.com/hanami/router#string-matching-with-variables
|
46
|
+
module RouterParams
|
47
|
+
ROUTER_PARAM_KEY = 'router.params'
|
48
|
+
|
49
|
+
# @param params [Hash]
|
50
|
+
# @param conn [WebPipe::Conn]
|
51
|
+
#
|
52
|
+
# @return [Hash]
|
53
|
+
def self.call(params, conn)
|
54
|
+
params.merge(conn.env.fetch(ROUTER_PARAM_KEY, Types::EMPTY_HASH))
|
55
|
+
end
|
56
|
+
|
57
|
+
WebPipe::Params::Transf.register(:router_params, method(:call))
|
58
|
+
end
|
59
|
+
end
|
@@ -4,11 +4,6 @@ module WebPipe
|
|
4
4
|
# This methods are in fact redundant with the information already
|
5
5
|
# present in {Conn} struct but, of course, they are very useful.
|
6
6
|
module Url
|
7
|
-
# Env's key used to retrieve params set by the router.
|
8
|
-
#
|
9
|
-
# @see #router_params
|
10
|
-
ROUTER_PARAMS_KEY = 'router.params'
|
11
|
-
|
12
7
|
# Base part of the URL.
|
13
8
|
#
|
14
9
|
# This is {#scheme} and {#host}, adding {#port} unless it is the
|
@@ -58,37 +53,6 @@ module WebPipe
|
|
58
53
|
def url
|
59
54
|
request.url
|
60
55
|
end
|
61
|
-
|
62
|
-
# *Params* in rack env's 'router.params' key.
|
63
|
-
#
|
64
|
-
# Routers used to map routes to applications build with
|
65
|
-
# {WebPipe} have the option to introduce extra params through
|
66
|
-
# setting env's 'router.params' key. These parameters will be
|
67
|
-
# merged with GET and POST ones when calling {#params}.
|
68
|
-
#
|
69
|
-
# This kind of functionality is usually implemented from the
|
70
|
-
# router side allowing the addition of variables in the route
|
71
|
-
# definition, e.g.:
|
72
|
-
#
|
73
|
-
# @example
|
74
|
-
# /user/:id/update
|
75
|
-
#
|
76
|
-
# @return [Hash]
|
77
|
-
def router_params
|
78
|
-
env.fetch(ROUTER_PARAMS_KEY, Types::EMPTY_HASH)
|
79
|
-
end
|
80
|
-
|
81
|
-
# GET, POST and {#router_params} merged in a hash.
|
82
|
-
#
|
83
|
-
# @return [Params]
|
84
|
-
#
|
85
|
-
# @example
|
86
|
-
# { 'id' => '1', 'name' => 'Joe' }
|
87
|
-
#
|
88
|
-
# @return Hash
|
89
|
-
def params
|
90
|
-
request.params.merge(router_params)
|
91
|
-
end
|
92
56
|
end
|
93
57
|
|
94
58
|
Conn.include(Url)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'web_pipe/types'
|
4
|
+
|
5
|
+
module WebPipe
|
6
|
+
module Plugs
|
7
|
+
# Adds given pairs to {Conn#config}.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# class App
|
11
|
+
# include WebPipe
|
12
|
+
#
|
13
|
+
# plug :config, WebPipe::Plugs::Config.(foo: :bar)
|
14
|
+
# end
|
15
|
+
module Config
|
16
|
+
def self.call(pairs)
|
17
|
+
lambda do |conn|
|
18
|
+
conn.new(
|
19
|
+
config: conn.config.merge(pairs)
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -10,13 +10,13 @@ module WebPipe
|
|
10
10
|
# class App
|
11
11
|
# include WebPipe
|
12
12
|
#
|
13
|
-
# plug :html, WebPipe::Plugs::ContentType
|
13
|
+
# plug :html, WebPipe::Plugs::ContentType.call('text/html')
|
14
14
|
# end
|
15
15
|
module ContentType
|
16
16
|
# Content-Type header
|
17
17
|
HEADER = 'Content-Type'
|
18
18
|
|
19
|
-
def self.
|
19
|
+
def self.call(content_type)
|
20
20
|
->(conn) { conn.add_response_header(HEADER, content_type) }
|
21
21
|
end
|
22
22
|
end
|
data/lib/web_pipe/version.rb
CHANGED
data/web_pipe.gemspec
CHANGED
@@ -36,9 +36,10 @@ Gem::Specification.new do |spec|
|
|
36
36
|
spec.require_paths = ["lib"]
|
37
37
|
|
38
38
|
spec.add_runtime_dependency "rack", "~> 2.0"
|
39
|
-
spec.add_runtime_dependency "dry-monads", "~> 1.
|
39
|
+
spec.add_runtime_dependency "dry-monads", "~> 1.3"
|
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 "transproc", "~> 1.1"
|
42
43
|
|
43
44
|
spec.add_development_dependency "bundler", "~> 1.17"
|
44
45
|
spec.add_development_dependency "rake", "~> 10.0"
|
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
|
+
version: 0.7.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-08-
|
11
|
+
date: 2019-08-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1.
|
33
|
+
version: '1.3'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '1.
|
40
|
+
version: '1.3'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: dry-types
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '1.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: transproc
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.1'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.1'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: bundler
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -227,9 +241,9 @@ files:
|
|
227
241
|
- Gemfile
|
228
242
|
- README.md
|
229
243
|
- Rakefile
|
244
|
+
- _config.yml
|
230
245
|
- bin/console
|
231
246
|
- bin/setup
|
232
|
-
- lib/dry/monads/result/extensions/either.rb
|
233
247
|
- lib/web_pipe.rb
|
234
248
|
- lib/web_pipe/app.rb
|
235
249
|
- lib/web_pipe/conn.rb
|
@@ -243,19 +257,20 @@ files:
|
|
243
257
|
- lib/web_pipe/dsl/dsl_context.rb
|
244
258
|
- lib/web_pipe/dsl/instance_methods.rb
|
245
259
|
- lib/web_pipe/extensions/container/container.rb
|
246
|
-
- lib/web_pipe/extensions/container/plugs/container.rb
|
247
260
|
- lib/web_pipe/extensions/cookies/cookies.rb
|
248
261
|
- lib/web_pipe/extensions/dry_schema/dry_schema.rb
|
249
|
-
- lib/web_pipe/extensions/dry_schema/plugs/param_sanitization_handler.rb
|
250
262
|
- lib/web_pipe/extensions/dry_schema/plugs/sanitize_params.rb
|
251
263
|
- lib/web_pipe/extensions/dry_view/dry_view.rb
|
252
|
-
- lib/web_pipe/extensions/dry_view/plugs/view_context.rb
|
253
264
|
- lib/web_pipe/extensions/flash/flash.rb
|
265
|
+
- lib/web_pipe/extensions/params/params.rb
|
266
|
+
- lib/web_pipe/extensions/params/params/transf.rb
|
254
267
|
- lib/web_pipe/extensions/redirect/redirect.rb
|
268
|
+
- lib/web_pipe/extensions/router_params/router_params.rb
|
255
269
|
- lib/web_pipe/extensions/session/session.rb
|
256
270
|
- lib/web_pipe/extensions/url/url.rb
|
257
271
|
- lib/web_pipe/plug.rb
|
258
272
|
- lib/web_pipe/plugs.rb
|
273
|
+
- lib/web_pipe/plugs/config.rb
|
259
274
|
- lib/web_pipe/plugs/content_type.rb
|
260
275
|
- lib/web_pipe/rack/app_with_middlewares.rb
|
261
276
|
- lib/web_pipe/rack/middleware.rb
|
@@ -1,42 +0,0 @@
|
|
1
|
-
require "dry/core/extensions"
|
2
|
-
|
3
|
-
module Dry
|
4
|
-
module Monads
|
5
|
-
# This is currently a PR in dry-monads:
|
6
|
-
#
|
7
|
-
# https://github.com/dry-rb/dry-monads/pull/84
|
8
|
-
class Result
|
9
|
-
extend Dry::Core::Extensions
|
10
|
-
|
11
|
-
register_extension(:either) do
|
12
|
-
class Success
|
13
|
-
# Returns result of applying first function to the internal value.
|
14
|
-
#
|
15
|
-
# @example
|
16
|
-
# Dry::Monads.Success(1).either(-> x { x + 1 }, -> x { x + 2 }) # => 2
|
17
|
-
#
|
18
|
-
# @param f [#call] Function to apply
|
19
|
-
# @param g [#call] Ignored
|
20
|
-
# @return [Any] Return value of `f`
|
21
|
-
def either(f, _g)
|
22
|
-
f.(success)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
class Failure
|
27
|
-
# Returns result of applying second function to the internal value.
|
28
|
-
#
|
29
|
-
# @example
|
30
|
-
# Dry::Monads.Failure(1).either(-> x { x + 1 }, -> x { x + 2 }) # => 3
|
31
|
-
#
|
32
|
-
# @param f [#call] Ignored
|
33
|
-
# @param g [#call] Function to call
|
34
|
-
# @return [Any] Return value of `g`
|
35
|
-
def either(_f, g)
|
36
|
-
g.(failure)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'web_pipe/types'
|
2
|
-
|
3
|
-
module WebPipe
|
4
|
-
module Plugs
|
5
|
-
# Sets a container into bag's `:container` key.
|
6
|
-
#
|
7
|
-
# Given container is check to respond to `#[]` method, which is
|
8
|
-
# meant to be used to resolve dependencies.
|
9
|
-
#
|
10
|
-
# @example
|
11
|
-
# class App
|
12
|
-
# include WebPipe
|
13
|
-
#
|
14
|
-
# Cont = { name: SomeDependency.new }.freeze
|
15
|
-
#
|
16
|
-
# plug :container, WebPipe::Plugs::Container[Cont]
|
17
|
-
# plug :resolve
|
18
|
-
#
|
19
|
-
# private
|
20
|
-
#
|
21
|
-
# def resolve(conn)
|
22
|
-
# conn.add(:dependency, conn.fetch(:container)[:name])
|
23
|
-
# end
|
24
|
-
# end
|
25
|
-
module Container
|
26
|
-
def self.[](container)
|
27
|
-
->(conn) { conn.add(:container, Types::Container[container]) }
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,27 +0,0 @@
|
|
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.add(PARAM_SANITIZATION_HANDLER_KEY, Handler[handler])
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'web_pipe/types'
|
2
|
-
require 'web_pipe/extensions/dry_view/dry_view'
|
3
|
-
|
4
|
-
module WebPipe
|
5
|
-
module Plugs
|
6
|
-
# Calls object with conn and add the result into bag's `:view_context`.
|
7
|
-
#
|
8
|
-
# This is meant to contain a Proc which will be called with the same
|
9
|
-
# {WebPipe::Conn} instance of the operation. It must return
|
10
|
-
# request specific view context as a hash. Ultimately, this will
|
11
|
-
# be provided to {Dry::View::Context#with} before passing the
|
12
|
-
# result along to the view instance.
|
13
|
-
#
|
14
|
-
# @example
|
15
|
-
# class App
|
16
|
-
# include WebPipe
|
17
|
-
#
|
18
|
-
# ViewContext = (conn) -> { { current_path: conn.full_path } }
|
19
|
-
#
|
20
|
-
# plug :view_context, WebPipe::Plugs::ViewContext[ViewContext]
|
21
|
-
# plug :render
|
22
|
-
#
|
23
|
-
# def render
|
24
|
-
# view(MyView.new)
|
25
|
-
# end
|
26
|
-
# end
|
27
|
-
#
|
28
|
-
# @see WebPipe::Conn#view
|
29
|
-
module ViewContext
|
30
|
-
def self.[](view_context_proc)
|
31
|
-
Types.Interface(:call)[view_context_proc]
|
32
|
-
lambda do |conn|
|
33
|
-
conn.add(Conn::VIEW_CONTEXT_KEY, view_context_proc.(conn))
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|