web_pipe 0.15.1 → 0.16.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/.rubocop.yml +1 -1
- data/CHANGELOG.md +10 -0
- data/README.md +13 -10
- data/docs/building_a_rack_application.md +1 -1
- data/docs/composing_applications.md +4 -4
- data/docs/connection_struct/configuring_the_connection_struct.md +4 -4
- data/docs/connection_struct/halting_the_pipe.md +17 -19
- data/docs/connection_struct/sharing_data_downstream.md +9 -8
- data/docs/connection_struct.md +22 -19
- data/docs/design_model.md +10 -9
- data/docs/dsl_free_usage.md +85 -14
- data/docs/extensions/container.md +9 -10
- data/docs/extensions/cookies.md +4 -2
- data/docs/extensions/dry_schema.md +5 -4
- data/docs/extensions/flash.md +9 -11
- data/docs/extensions/hanami_view.md +10 -14
- data/docs/extensions/params.md +6 -4
- data/docs/extensions/rails.md +28 -34
- data/docs/extensions/redirect.md +5 -4
- data/docs/extensions/router_params.md +5 -5
- data/docs/extensions/session.md +4 -4
- data/docs/extensions/url.md +6 -6
- data/docs/extensions.md +5 -6
- data/docs/introduction.md +7 -7
- data/docs/plugging_operations/composing_operations.md +3 -3
- data/docs/plugging_operations/injecting_operations.md +4 -4
- data/docs/plugging_operations/inspecting_operations.md +1 -2
- data/docs/plugging_operations/resolving_operations.md +3 -3
- data/docs/plugging_operations.md +3 -3
- data/docs/plugs/config.md +1 -1
- data/docs/plugs/content_type.md +2 -1
- data/docs/plugs.md +6 -7
- data/docs/recipes/hanami_2_and_dry_rb_integration.md +12 -0
- data/docs/recipes/hanami_router_integration.md +3 -1
- data/docs/recipes/using_all_restful_methods.md +6 -5
- data/docs/using_rack_middlewares/composing_middlewares.md +2 -3
- data/docs/using_rack_middlewares/injecting_middlewares.md +6 -6
- data/docs/using_rack_middlewares/inspecting_middlewares.md +7 -6
- data/docs/using_rack_middlewares.md +6 -6
- data/lib/web_pipe/app.rb +22 -25
- data/lib/web_pipe/conn.rb +0 -1
- data/lib/web_pipe/conn_support/builder.rb +0 -7
- data/lib/web_pipe/conn_support/composition.rb +3 -26
- data/lib/web_pipe/conn_support/errors.rb +5 -5
- data/lib/web_pipe/conn_support/headers.rb +1 -50
- data/lib/web_pipe/conn_support/types.rb +3 -3
- data/lib/web_pipe/dsl/builder.rb +10 -19
- data/lib/web_pipe/dsl/class_context.rb +15 -40
- data/lib/web_pipe/dsl/instance_context.rb +53 -0
- data/lib/web_pipe/extensions/container/container.rb +2 -15
- data/lib/web_pipe/extensions/cookies/cookies.rb +2 -31
- data/lib/web_pipe/extensions/dry_schema/dry_schema.rb +2 -56
- data/lib/web_pipe/extensions/flash/flash.rb +2 -32
- data/lib/web_pipe/extensions/hanami_view/hanami_view.rb +2 -93
- data/lib/web_pipe/extensions/not_found/not_found.rb +2 -40
- data/lib/web_pipe/extensions/params/params.rb +2 -63
- data/lib/web_pipe/extensions/rails/rails.rb +2 -119
- data/lib/web_pipe/extensions/redirect/redirect.rb +2 -20
- data/lib/web_pipe/extensions/router_params/router_params.rb +1 -39
- data/lib/web_pipe/extensions/session/session.rb +2 -25
- data/lib/web_pipe/extensions/url/url.rb +2 -5
- data/lib/web_pipe/pipe.rb +229 -0
- data/lib/web_pipe/plug.rb +30 -75
- data/lib/web_pipe/plugs/config.rb +0 -2
- data/lib/web_pipe/plugs/content_type.rb +0 -2
- data/lib/web_pipe/rack_support/app_with_middlewares.rb +3 -26
- data/lib/web_pipe/rack_support/middleware.rb +2 -2
- data/lib/web_pipe/rack_support/middleware_specification.rb +17 -55
- data/lib/web_pipe/types.rb +1 -3
- data/lib/web_pipe/version.rb +1 -1
- data/lib/web_pipe.rb +77 -21
- data/web_pipe.gemspec +1 -0
- metadata +7 -6
- data/docs/recipes/dry_rb_integration.md +0 -17
- data/lib/web_pipe/dsl/dsl_context.rb +0 -85
- data/lib/web_pipe/dsl/instance_methods.rb +0 -114
@@ -1,31 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'dry/monads/result'
|
4
|
-
require 'web_pipe/types'
|
5
4
|
require 'web_pipe/conn'
|
6
5
|
|
7
6
|
module WebPipe
|
8
7
|
module ConnSupport
|
9
|
-
#
|
10
|
-
#
|
11
|
-
# It represents the composition of a series of functions which
|
12
|
-
# take a {Conn} as argument and return a {Conn}.
|
13
|
-
#
|
14
|
-
# However, {Conn} can itself be of two different types (subclasses
|
15
|
-
# of it): a {Conn::Ongoing} or a {Conn::Halted}. On execution time,
|
16
|
-
# the composition is stopped whenever the stack is emptied or a
|
17
|
-
# {Conn::Halted} is returned in any of the steps.
|
8
|
+
# @api private
|
18
9
|
class Composition
|
19
|
-
#
|
20
|
-
#
|
21
|
-
# It should be anything callable expecting a {Conn} and
|
22
|
-
# returning a {Conn}.
|
23
|
-
Operation = Types.Interface(:call)
|
24
|
-
|
25
|
-
# Error raised when an {Operation} returns something that is not
|
26
|
-
# a {Conn}.
|
10
|
+
# Raised when operation doesn't return a {WebPipe::Conn}.
|
27
11
|
class InvalidOperationResult < RuntimeError
|
28
|
-
# @param returned [Any] What was returned from the {Operation}
|
29
12
|
def initialize(returned)
|
30
13
|
super(
|
31
14
|
<<~MSG
|
@@ -39,18 +22,12 @@ module WebPipe
|
|
39
22
|
|
40
23
|
include Dry::Monads::Result::Mixin
|
41
24
|
|
42
|
-
# @!attribute [r] operations
|
43
|
-
# @return [Array<Operation[]>]
|
44
25
|
attr_reader :operations
|
45
26
|
|
46
27
|
def initialize(operations)
|
47
|
-
@operations =
|
28
|
+
@operations = operations
|
48
29
|
end
|
49
30
|
|
50
|
-
# @param conn [Conn]
|
51
|
-
# @return [Conn]
|
52
|
-
# @raise InvalidOperationResult when an operation does not
|
53
|
-
# return a {Conn}
|
54
31
|
def call(conn)
|
55
32
|
extract_result(
|
56
33
|
apply_operations(
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module WebPipe
|
4
4
|
module ConnSupport
|
5
|
-
# Error raised when trying to fetch an entry in {Conn#bag} for an
|
5
|
+
# Error raised when trying to fetch an entry in {WebPipe::Conn#bag} for an
|
6
6
|
# unknown key.
|
7
7
|
class KeyNotFoundInBagError < KeyError
|
8
8
|
# @param key [Any] Key not found in the bag
|
@@ -15,8 +15,8 @@ module WebPipe
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
# Error raised when trying to fetch an entry in {
|
19
|
-
#
|
18
|
+
# Error raised when trying to fetch an entry in {WebPipeConn#config} for an
|
19
|
+
# unknown key.
|
20
20
|
class KeyNotFoundInConfigError < KeyError
|
21
21
|
# @param key [Any] Key not found in config
|
22
22
|
def initialize(key)
|
@@ -28,8 +28,8 @@ module WebPipe
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
# Error raised when trying to use a
|
32
|
-
#
|
31
|
+
# Error raised when trying to use a {WebPipe::Conn} feature which requires a
|
32
|
+
# rack middleware that is not present
|
33
33
|
class MissingMiddlewareError < RuntimeError
|
34
34
|
# @param feature [String] Name of the feature intended to be used
|
35
35
|
# @param middleware [String] Name of the missing middleware
|
@@ -2,25 +2,14 @@
|
|
2
2
|
|
3
3
|
module WebPipe
|
4
4
|
module ConnSupport
|
5
|
-
# Helpers to work with headers and its rack's env representation.
|
6
|
-
#
|
7
5
|
# @api private
|
8
6
|
module Headers
|
9
7
|
# Headers which come as plain CGI-like variables (without the `HTTP_`
|
10
8
|
# prefixed) from the rack server.
|
11
9
|
HEADERS_AS_CGI = %w[CONTENT_TYPE CONTENT_LENGTH].freeze
|
12
10
|
|
13
|
-
# Extracts headers from rack's env.
|
14
|
-
#
|
15
11
|
# Headers are all those pairs which key begins with `HTTP_` plus
|
16
12
|
# those detailed in {HEADERS_AS_CGI}.
|
17
|
-
#
|
18
|
-
# @param env [Types::Env[]]
|
19
|
-
#
|
20
|
-
# @return [Types::Headers[]]
|
21
|
-
#
|
22
|
-
# @see HEADERS_AS_CGI
|
23
|
-
# @see .normalize_key
|
24
13
|
def self.extract(env)
|
25
14
|
Hash[
|
26
15
|
env
|
@@ -34,51 +23,20 @@ module WebPipe
|
|
34
23
|
]
|
35
24
|
end
|
36
25
|
|
37
|
-
# Adds key/value pair to given headers.
|
38
|
-
#
|
39
|
-
# Key is normalized.
|
40
|
-
#
|
41
|
-
# @param headers [Type::Headers[]]
|
42
|
-
# @param key [String]
|
43
|
-
# @param value [String]
|
44
|
-
#
|
45
|
-
# @return [Type::Headers[]]
|
46
|
-
#
|
47
|
-
# @see .normalize_key
|
48
26
|
def self.add(headers, key, value)
|
49
27
|
Hash[
|
50
28
|
headers.to_a.push(pair(key, value))
|
51
29
|
]
|
52
30
|
end
|
53
31
|
|
54
|
-
# Deletes pair with given key form headers.
|
55
|
-
#
|
56
|
-
# Accepts a non normalized key.
|
57
|
-
#
|
58
|
-
# @param headers [Type::Headers[]]
|
59
|
-
# @param key [String]
|
60
|
-
#
|
61
|
-
# @return [Type::Headers[]]
|
62
|
-
#
|
63
|
-
# @see .normalize_key
|
64
32
|
def self.delete(headers, key)
|
65
33
|
headers.reject { |k, _v| normalize_key(key) == k }
|
66
34
|
end
|
67
35
|
|
68
|
-
# Creates a pair with normalized key and raw value.
|
69
|
-
#
|
70
|
-
# @param key [String]
|
71
|
-
# @param key [String]
|
72
|
-
#
|
73
|
-
# @return [Array<String>]
|
74
|
-
#
|
75
|
-
# @see .normalize_key
|
76
36
|
def self.pair(key, value)
|
77
37
|
[normalize_key(key), value]
|
78
38
|
end
|
79
39
|
|
80
|
-
# Normalizes a header key to convention.
|
81
|
-
#
|
82
40
|
# As per RFC2616, headers names are case insensitive. This
|
83
41
|
# function normalizes them to PascalCase acting on dashes ('-').
|
84
42
|
#
|
@@ -86,18 +44,11 @@ module WebPipe
|
|
86
44
|
# dashes and underscores (`_`) are treated as dashes. This
|
87
45
|
# function substitutes all '-' to '_'.
|
88
46
|
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
# @return [String]
|
92
|
-
#
|
93
|
-
# @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
|
47
|
+
# See https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
|
94
48
|
def self.normalize_key(key)
|
95
49
|
key.downcase.gsub('_', '-').split('-').map(&:capitalize).join('-')
|
96
50
|
end
|
97
51
|
|
98
|
-
# Returns a new hash with all keys normalized.
|
99
|
-
#
|
100
|
-
# @see #normalize_key
|
101
52
|
def self.normalize(headers)
|
102
53
|
headers.transform_keys { |k| normalize_key(k) }
|
103
54
|
end
|
@@ -5,10 +5,10 @@ require 'rack/request'
|
|
5
5
|
|
6
6
|
module WebPipe
|
7
7
|
module ConnSupport
|
8
|
-
# Types used
|
8
|
+
# Types used in the {WebPipe::Conn} struct.
|
9
9
|
#
|
10
|
-
#
|
11
|
-
# attributes for documentation.
|
10
|
+
# The implementation self-describes them, but you can look at the
|
11
|
+
# {WebPipe::Conn} attributes for documentation.
|
12
12
|
module Types
|
13
13
|
include Dry.Types()
|
14
14
|
|
data/lib/web_pipe/dsl/builder.rb
CHANGED
@@ -1,36 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'web_pipe/types'
|
4
3
|
require 'web_pipe/dsl/class_context'
|
5
|
-
require 'web_pipe/dsl/
|
4
|
+
require 'web_pipe/dsl/instance_context'
|
5
|
+
require 'web_pipe/pipe'
|
6
6
|
|
7
7
|
module WebPipe
|
8
8
|
module DSL
|
9
|
-
# When an instance of it is included in a module, the module
|
10
|
-
# extends a {ClassContext} instance and includes
|
11
|
-
# {InstanceMethods}.
|
12
|
-
#
|
13
9
|
# @api private
|
14
10
|
class Builder < Module
|
15
|
-
|
16
|
-
EMPTY_CONTAINER = Types::EMPTY_HASH
|
11
|
+
attr_reader :class_context, :instance_context
|
17
12
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
def initialize(container: EMPTY_CONTAINER)
|
26
|
-
@container = Types::Container[container]
|
27
|
-
@class_context = ClassContext.new(container: container)
|
13
|
+
def initialize(container: Pipe::EMPTY_CONTAINER)
|
14
|
+
@class_context = ClassContext.new
|
15
|
+
@instance_context = InstanceContext.new(
|
16
|
+
class_context: class_context,
|
17
|
+
container: container
|
18
|
+
)
|
28
19
|
super()
|
29
20
|
end
|
30
21
|
|
31
22
|
def included(klass)
|
32
23
|
klass.extend(class_context)
|
33
|
-
klass.include(
|
24
|
+
klass.include(instance_context)
|
34
25
|
end
|
35
26
|
end
|
36
27
|
end
|
@@ -1,57 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'web_pipe/types'
|
4
|
-
require 'web_pipe/dsl/dsl_context'
|
5
|
-
|
6
3
|
module WebPipe
|
7
4
|
module DSL
|
8
|
-
# Defines the DSL and keeps the state for the pipe.
|
9
|
-
#
|
10
|
-
# This is good to be an instance because it keeps the
|
11
|
-
# configuration (state) for the pipe class: the container
|
12
|
-
# configured on initialization and both rack middlewares and plugs
|
13
|
-
# added through the DSL {DSLContext}.
|
14
|
-
#
|
15
|
-
# As the pipe is extended with an instance of this class, methods
|
16
|
-
# that are meant to be class methods in the pipe are defined as
|
17
|
-
# singleton methods of the instance.
|
18
|
-
#
|
19
5
|
# @api private
|
20
6
|
class ClassContext < Module
|
21
|
-
|
22
|
-
DSL_METHODS = %i[middleware_specifications use plugs plug compose].freeze
|
7
|
+
DSL_METHODS = %i[use plug compose].freeze
|
23
8
|
|
24
|
-
|
25
|
-
# @return [Types::Container[]]
|
26
|
-
attr_reader :container
|
9
|
+
attr_reader :ast
|
27
10
|
|
28
|
-
|
29
|
-
|
11
|
+
def initialize
|
12
|
+
@ast = []
|
13
|
+
super
|
14
|
+
end
|
30
15
|
|
31
|
-
def
|
32
|
-
|
33
|
-
@dsl_context = DSLContext.new([], [])
|
34
|
-
define_container
|
35
|
-
define_dsl
|
36
|
-
super()
|
16
|
+
def extended(klass)
|
17
|
+
define_dsl_methods(klass, ast)
|
37
18
|
end
|
38
19
|
|
39
20
|
private
|
40
21
|
|
41
|
-
def
|
42
|
-
module_exec(container) do |container|
|
43
|
-
define_method(:container) do
|
44
|
-
container
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def define_dsl
|
22
|
+
def define_dsl_methods(klass, ast)
|
50
23
|
DSL_METHODS.each do |method|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
24
|
+
klass.define_singleton_method(method) do |*args, **kwargs, &block|
|
25
|
+
ast << if block_given?
|
26
|
+
[method, args, kwargs, block]
|
27
|
+
else
|
28
|
+
[method, args, kwargs]
|
29
|
+
end
|
55
30
|
end
|
56
31
|
end
|
57
32
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'web_pipe/pipe'
|
4
|
+
|
5
|
+
module WebPipe
|
6
|
+
module DSL
|
7
|
+
# @api private
|
8
|
+
class InstanceContext < Module
|
9
|
+
PIPE_METHODS = %i[
|
10
|
+
call middlewares operations to_proc to_middlewares
|
11
|
+
].freeze
|
12
|
+
|
13
|
+
attr_reader :container, :class_context
|
14
|
+
|
15
|
+
def initialize(container:, class_context:)
|
16
|
+
@container = container
|
17
|
+
@class_context = class_context
|
18
|
+
super()
|
19
|
+
end
|
20
|
+
|
21
|
+
def included(klass)
|
22
|
+
define_initialize(klass, class_context.ast, container)
|
23
|
+
define_pipe_methods(klass)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# rubocop:disable Metrics/MethodLength
|
29
|
+
def define_initialize(klass, ast, container)
|
30
|
+
klass.define_method(:initialize) do |plugs: {}, middlewares: {}|
|
31
|
+
acc = Pipe.new(container: container, context: self)
|
32
|
+
@pipe = ast.reduce(acc) do |pipe, node|
|
33
|
+
method, args, kwargs, block = node
|
34
|
+
if block
|
35
|
+
pipe.send(method, *args, **kwargs, &block)
|
36
|
+
else
|
37
|
+
pipe.send(method, *args, **kwargs)
|
38
|
+
end
|
39
|
+
end.inject(plugs: plugs, middleware_specifications: middlewares)
|
40
|
+
end
|
41
|
+
# rubocop:enable Metrics/MethodLength
|
42
|
+
end
|
43
|
+
|
44
|
+
def define_pipe_methods(klass)
|
45
|
+
PIPE_METHODS.each do |method|
|
46
|
+
klass.define_method(method) do |*args|
|
47
|
+
@pipe.send(method, *args)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -2,22 +2,9 @@
|
|
2
2
|
|
3
3
|
require 'web_pipe'
|
4
4
|
|
5
|
-
|
5
|
+
# :nodoc:
|
6
6
|
module WebPipe
|
7
|
-
#
|
8
|
-
# `:container` key.
|
9
|
-
#
|
10
|
-
# @example
|
11
|
-
# require 'web_pipe'
|
12
|
-
#
|
13
|
-
# WebPipe.load_extensions(:container)
|
14
|
-
#
|
15
|
-
# class App
|
16
|
-
# include WebPipe
|
17
|
-
#
|
18
|
-
# plug :container, ->(conn) { conn.add_config(:container, MyContainer) }
|
19
|
-
# plug :render, ->(conn) { conn.set_response_body(conn.container['view']) }
|
20
|
-
# end
|
7
|
+
# See the docs for the extension linked from the README.
|
21
8
|
module Container
|
22
9
|
# Returns {Conn#config} `:container` value
|
23
10
|
#
|
@@ -1,40 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'web_pipe'
|
4
|
-
require 'web_pipe/types'
|
5
4
|
require 'rack/utils'
|
6
5
|
|
7
|
-
|
6
|
+
# :nodoc:
|
8
7
|
module WebPipe
|
9
|
-
#
|
10
|
-
#
|
11
|
-
# This extension helps with the addition of the `Set-Cookie` header
|
12
|
-
# to the response, which is the way the server has to instruct the
|
13
|
-
# browser to keep a cookie. A cookie can be added with the
|
14
|
-
# {#set_cookie} method, while it can be marked for deletion with
|
15
|
-
# {#delete_cookie}. Remember that marking a cookie for deletion just
|
16
|
-
# means adding the same cookie name with an expiration time in the
|
17
|
-
# past.
|
18
|
-
#
|
19
|
-
# Besides, it also adds a {#request_cookies} method to get the
|
20
|
-
# cookies in the request.
|
21
|
-
#
|
22
|
-
# @example
|
23
|
-
# require 'web_pipe'
|
24
|
-
#
|
25
|
-
# WebPipe.load_extensions(:cookies)
|
26
|
-
#
|
27
|
-
# class SetCookie
|
28
|
-
# include WebPipe
|
29
|
-
#
|
30
|
-
# plug :set_cookie, ->(conn) { conn.set_cookie('foo', 'bar', path: '/') }
|
31
|
-
# end
|
32
|
-
#
|
33
|
-
# class DeleteCookie
|
34
|
-
# include WebPipe
|
35
|
-
#
|
36
|
-
# plug :delete_cookie, ->(conn) { conn.delete_cookie('foo', path: '/') }
|
37
|
-
# end
|
8
|
+
# See the docs for the extension linked from the README.
|
38
9
|
module Cookies
|
39
10
|
# Valid options for {#set_cookie}.
|
40
11
|
SET_COOKIE_OPTIONS = Types::Strict::Hash.schema(
|
@@ -4,63 +4,9 @@ require 'web_pipe'
|
|
4
4
|
|
5
5
|
WebPipe.load_extensions(:params)
|
6
6
|
|
7
|
-
|
7
|
+
# :nodoc:
|
8
8
|
module WebPipe
|
9
|
-
#
|
10
|
-
#
|
11
|
-
# This extension provides a simple integration with `dry-schema`
|
12
|
-
# library to streamline param sanitization.
|
13
|
-
#
|
14
|
-
# On its own, the library just provides with a
|
15
|
-
# `Conn#sanitized_params` method, which will return what is set into
|
16
|
-
# config's `:sanitized_params` key.
|
17
|
-
#
|
18
|
-
# This key in config is what will be populated by `SanitizeParams` plug. It
|
19
|
-
# takes as arguments the `dry-schema` schema that will be applied to
|
20
|
-
# `Conn#params` and an error handler taking `Conn` instance and the validation
|
21
|
-
# result:
|
22
|
-
#
|
23
|
-
# @example
|
24
|
-
# require 'web_pipe'
|
25
|
-
#
|
26
|
-
# WebPipe.load_extensions(:dry_schema)
|
27
|
-
#
|
28
|
-
# class App
|
29
|
-
# include WebPipe
|
30
|
-
#
|
31
|
-
# Schema = Dry::Schema.Params do
|
32
|
-
# required(:name).filled(:string)
|
33
|
-
# end
|
34
|
-
#
|
35
|
-
# plug :sanitize_params, WebPipe::Plugs::SanitizeParams.(
|
36
|
-
# Schema,
|
37
|
-
# ->(conn, result) { ... }
|
38
|
-
# )
|
39
|
-
# plug(:do_something_with_params) do |conn|
|
40
|
-
# DB.persist(:entity, conn.sanitized_params)
|
41
|
-
# end
|
42
|
-
# end
|
43
|
-
#
|
44
|
-
# A common workflow is applying the same handler for all param
|
45
|
-
# sanitization across your application. This can be achieved configuring
|
46
|
-
# a `:param_sanitization_handler` in a upstream operation which can
|
47
|
-
# be composed downstream from any number of pipes. `SanitizeParams`
|
48
|
-
# will used configured handler if none is injected as
|
49
|
-
# argument.
|
50
|
-
#
|
51
|
-
# @example
|
52
|
-
# class App
|
53
|
-
# plug :sanitization_handler, ->(conn, result) { ... }
|
54
|
-
# end
|
55
|
-
#
|
56
|
-
# class Subapp
|
57
|
-
# Schema = Dry::Schema.Params { ... }
|
58
|
-
#
|
59
|
-
# plug :app, App.new
|
60
|
-
# plug :sanitize_params, WebPipe::Plugs::SanitizeParams.call(Schema)
|
61
|
-
# end
|
62
|
-
#
|
63
|
-
# @see https://dry-rb.org/gems/dry-schema/
|
9
|
+
# See the docs for the extension linked from the README.
|
64
10
|
module DrySchema
|
65
11
|
SANITIZED_PARAMS_KEY = :sanitized_params
|
66
12
|
|
@@ -3,39 +3,9 @@
|
|
3
3
|
require 'web_pipe/conn'
|
4
4
|
require 'web_pipe/conn_support/errors'
|
5
5
|
|
6
|
-
|
6
|
+
# :nodoc:
|
7
7
|
module WebPipe
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# @example
|
11
|
-
# require 'web_pipe'
|
12
|
-
# require 'rack/session/cookie'
|
13
|
-
# require 'rack-flash'
|
14
|
-
#
|
15
|
-
# WebPipe.load_extensions(:flash)
|
16
|
-
#
|
17
|
-
# class MyApp
|
18
|
-
# include WebPipe
|
19
|
-
#
|
20
|
-
# use :session, Rack::Session::Cookie, secret: 'secret'
|
21
|
-
# use :flash, Rack::Flash
|
22
|
-
#
|
23
|
-
# plug :add_to_flash, ->(conn) { conn.add_flash(:notice, 'Hello world') }
|
24
|
-
# plug :add_to_flash_now, ->(conn) { conn.add_flash_now(:notice_now, 'Hello world now') }
|
25
|
-
# end
|
26
|
-
#
|
27
|
-
# Usually, you will end up making `conn.flash` available to your view system:
|
28
|
-
#
|
29
|
-
# @example
|
30
|
-
# <div class="notice"><%= flash[:notice] %></div>
|
31
|
-
#
|
32
|
-
# For this extension to be used, `Rack::Flash` middleware must be
|
33
|
-
# added to the stack (gem name is `rack-flash3`. This middleware in
|
34
|
-
# turns depend on `Rack::Session` middleware.
|
35
|
-
#
|
36
|
-
# This extension is a very simple wrapper around `Rack::Flash` API.
|
37
|
-
#
|
38
|
-
# @see https://github.com/nakajima/rack-flash
|
8
|
+
# See the docs for the extension linked from the README.
|
39
9
|
module Flash
|
40
10
|
RACK_FLASH_KEY = 'x-rack.flash'
|
41
11
|
|
@@ -4,100 +4,9 @@ require 'web_pipe/types'
|
|
4
4
|
require 'web_pipe/conn'
|
5
5
|
require 'hanami/view'
|
6
6
|
|
7
|
-
|
7
|
+
# :nodoc:
|
8
8
|
module WebPipe
|
9
|
-
#
|
10
|
-
#
|
11
|
-
# This extensions adds a {#view} method to {WebPipe::Conn} which
|
12
|
-
# sets the string output of a `hanami-view` view as response body.
|
13
|
-
#
|
14
|
-
# @example
|
15
|
-
# WebPipe.load_extensions(:hanami_view)
|
16
|
-
#
|
17
|
-
# class SayHelloView < Hanami::View
|
18
|
-
# config.paths = [File.join(__dir__, '..', 'templates')]
|
19
|
-
# config.template = 'say_hello'
|
20
|
-
#
|
21
|
-
# expose :name
|
22
|
-
# end
|
23
|
-
#
|
24
|
-
# class App
|
25
|
-
# include WebPipe
|
26
|
-
#
|
27
|
-
# plug :render
|
28
|
-
#
|
29
|
-
# def render(conn)
|
30
|
-
# conn.view(SayHello.new, name: 'Joe')
|
31
|
-
# end
|
32
|
-
# end
|
33
|
-
#
|
34
|
-
# If there is a `:container` configured (in {Conn#config}), the view
|
35
|
-
# instance can be resolved from it.
|
36
|
-
#
|
37
|
-
# @example
|
38
|
-
# WebPipe.load_extensions(:hanami_view, :container)
|
39
|
-
#
|
40
|
-
# class App
|
41
|
-
# include WebPipe
|
42
|
-
#
|
43
|
-
# Container = { 'views.say_hello' => SayHelloView.new }.freeze
|
44
|
-
#
|
45
|
-
# plug :config_container, ->(conn) { conn.add_config(:container, Container) }
|
46
|
-
# plug :render
|
47
|
-
#
|
48
|
-
# def render(conn)
|
49
|
-
# conn.view('views.say_hello', name: 'Joe')
|
50
|
-
# end
|
51
|
-
# end
|
52
|
-
#
|
53
|
-
# Context ({Hanami::View::Context}) for the view can be set explicetly
|
54
|
-
# through the `context:` argument, as in a standard call to
|
55
|
-
# {Hanami::View#call}. However, it is possible to leverage configured
|
56
|
-
# default context while still being able to inject request specific
|
57
|
-
# context. For that to work, `:view_context` should be present in
|
58
|
-
# {WebPipe::Conn#config}. Its value must be a lambda accepting the
|
59
|
-
# {Conn} instance and returning a hash, which will be passed to
|
60
|
-
# {Hanami::View::Context#with} to create the final context at the
|
61
|
-
# moment {#view} is called.
|
62
|
-
#
|
63
|
-
# @example
|
64
|
-
# class MyContext < Hanami::View::Context
|
65
|
-
# attr_reader :current_path
|
66
|
-
#
|
67
|
-
# def initialize(current_path: nil, **options)
|
68
|
-
# @current_path = current_path
|
69
|
-
# super
|
70
|
-
# end
|
71
|
-
# end
|
72
|
-
#
|
73
|
-
# class SayHelloView < Hanami::View
|
74
|
-
# config.paths = [File.join(__dir__, '..', 'templates')]
|
75
|
-
# config.template = 'say_hello'
|
76
|
-
# config.default_context = MyContext.new
|
77
|
-
#
|
78
|
-
# expose :name
|
79
|
-
# end
|
80
|
-
#
|
81
|
-
# WebPipe.load_extensions(:url)
|
82
|
-
#
|
83
|
-
# class App
|
84
|
-
# include WebPipe
|
85
|
-
#
|
86
|
-
# plug :config_view_context
|
87
|
-
# plug :render
|
88
|
-
#
|
89
|
-
# def config_view_context(conn)
|
90
|
-
# conn.add_config(:view_context, ->(conn) { { current_path: conn.full_path } })
|
91
|
-
# end
|
92
|
-
#
|
93
|
-
# def render(conn)
|
94
|
-
# conn.view(SayHelloView.new, name: 'Joe') # `current_path`
|
95
|
-
# # will be available in the view scope
|
96
|
-
# end
|
97
|
-
# end
|
98
|
-
#
|
99
|
-
# @see https://github.com/hanami/view
|
100
|
-
# @see WebPipe::Container
|
9
|
+
# See the docs for the extension linked from the README.
|
101
10
|
module DryView
|
102
11
|
# Where to find in {#config} request's view context generator.
|
103
12
|
VIEW_CONTEXT_KEY = :view_context
|