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