web_pipe 0.13.0 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -1
- data/CHANGELOG.md +29 -0
- data/Gemfile +2 -2
- data/README.md +18 -11
- 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/{dry_view.md → hanami_view.md} +20 -22
- data/docs/extensions/not_found.md +40 -0
- data/docs/extensions/params.md +6 -4
- data/docs/extensions/rails.md +31 -38
- 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 +24 -0
- 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/testing.md +64 -0
- 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 +35 -0
- 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 +67 -0
- data/lib/web_pipe/extensions/not_found/not_found.rb +26 -0
- data/lib/web_pipe/extensions/params/params.rb +2 -63
- data/lib/web_pipe/extensions/rails/rails.rb +2 -123
- 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 +31 -65
- 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 +19 -48
- data/lib/web_pipe/test_support.rb +28 -0
- data/lib/web_pipe/types.rb +1 -3
- data/lib/web_pipe/version.rb +1 -1
- data/lib/web_pipe.rb +77 -17
- data/web_pipe.gemspec +1 -2
- metadata +16 -9
- data/docs/recipes/dry_rb_integration.md +0 -18
- data/lib/web_pipe/dsl/dsl_context.rb +0 -85
- data/lib/web_pipe/dsl/instance_methods.rb +0 -114
- data/lib/web_pipe/extensions/dry_view/dry_view.rb +0 -158
data/lib/web_pipe.rb
CHANGED
@@ -1,23 +1,83 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'dry/core/extensions'
|
3
4
|
require 'web_pipe/dsl/builder'
|
4
5
|
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# Entry-point for the DSL layer.
|
7
|
+
#
|
8
|
+
# Including this module into your class adds to it a DSL layer which makes it
|
9
|
+
# convenient to interact with an instance of {WebPipe::Pipe} transparently. It
|
10
|
+
# means that the DSL is actually an optional layer, and you can achieve
|
11
|
+
# everything by using {WebPipe::Pipe} instances.
|
12
|
+
#
|
13
|
+
# Your class gets access to {WebPipe::DSL::ClassContext::DSL_METHODS} at the
|
14
|
+
# class level, while {WebPipe::DSL::InstanceContext::PIPE_METHODS} are available
|
15
|
+
# for every instance of it. Both groups of methods are delegating to
|
16
|
+
# {WebPipe::Pipe}, so you can look there for documentation.
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# class HelloWorld
|
20
|
+
# include WebPipe
|
21
|
+
#
|
22
|
+
# use :runtime, Rack::Runtime
|
23
|
+
#
|
24
|
+
# plug :content_type do |conn|
|
25
|
+
# conn.add_response_header('Content-Type', 'plain/text')
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# plug :render do |conn|
|
29
|
+
# conn.set_response_body('Hello, World!')
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# The instance of your class is itself the final rack application. When you
|
34
|
+
# initialize it, you have the chance to inject different plugs or middlewares
|
35
|
+
# from those defined at the class level.
|
36
|
+
#
|
37
|
+
# @example
|
38
|
+
# HelloWorld.new(
|
39
|
+
# middlewares: {
|
40
|
+
# runtime: [Class.new do
|
41
|
+
# def initialize(app)
|
42
|
+
# @app = app
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# def call(env)
|
46
|
+
# status, headers, body = @app.call(env)
|
47
|
+
# [status, headers.merge('Injected' => '1'), body]
|
48
|
+
# end
|
49
|
+
# end]
|
50
|
+
# },
|
51
|
+
# plugs: {
|
52
|
+
# render: ->(conn) { conn.set_response_body('Injected!') }
|
53
|
+
# }
|
54
|
+
# )
|
8
55
|
module WebPipe
|
9
56
|
extend Dry::Core::Extensions
|
10
57
|
|
11
|
-
#
|
12
|
-
#
|
58
|
+
# Called via {Module#include}, makes available web_pipe's DSL.
|
59
|
+
#
|
60
|
+
# Includes an instance of `Builder`. That means that `Builder#included` is
|
61
|
+
# eventually called.
|
13
62
|
def self.included(klass)
|
14
63
|
klass.include(call)
|
15
64
|
end
|
16
65
|
|
66
|
+
# Chained to {Module#include} to make the DSL available and provide options.
|
67
|
+
#
|
68
|
+
# @param container [#[]] Container from where resolve operations. See
|
69
|
+
# {WebPipe::Plug}.
|
70
|
+
#
|
71
|
+
# @example
|
72
|
+
# include WebPipe.call(container: Container)
|
17
73
|
def self.call(**opts)
|
18
74
|
DSL::Builder.new(**opts)
|
19
75
|
end
|
20
76
|
|
77
|
+
register_extension :container do
|
78
|
+
require 'web_pipe/extensions/container/container'
|
79
|
+
end
|
80
|
+
|
21
81
|
register_extension :cookies do
|
22
82
|
require 'web_pipe/extensions/cookies/cookies'
|
23
83
|
end
|
@@ -27,24 +87,16 @@ module WebPipe
|
|
27
87
|
require 'web_pipe/extensions/dry_schema/plugs/sanitize_params'
|
28
88
|
end
|
29
89
|
|
30
|
-
register_extension :dry_view do
|
31
|
-
require 'web_pipe/extensions/dry_view/dry_view'
|
32
|
-
end
|
33
|
-
|
34
|
-
register_extension :container do
|
35
|
-
require 'web_pipe/extensions/container/container'
|
36
|
-
end
|
37
|
-
|
38
90
|
register_extension :flash do
|
39
91
|
require 'web_pipe/extensions/flash/flash'
|
40
92
|
end
|
41
93
|
|
42
|
-
register_extension :
|
43
|
-
require 'web_pipe/extensions/
|
94
|
+
register_extension :hanami_view do
|
95
|
+
require 'web_pipe/extensions/hanami_view/hanami_view'
|
44
96
|
end
|
45
97
|
|
46
|
-
register_extension :
|
47
|
-
require 'web_pipe/extensions/
|
98
|
+
register_extension :not_found do
|
99
|
+
require 'web_pipe/extensions/not_found/not_found'
|
48
100
|
end
|
49
101
|
|
50
102
|
register_extension :params do
|
@@ -55,6 +107,14 @@ module WebPipe
|
|
55
107
|
require 'web_pipe/extensions/rails/rails'
|
56
108
|
end
|
57
109
|
|
110
|
+
register_extension :redirect do
|
111
|
+
require 'web_pipe/extensions/redirect/redirect'
|
112
|
+
end
|
113
|
+
|
114
|
+
register_extension :router_params do
|
115
|
+
require 'web_pipe/extensions/router_params/router_params'
|
116
|
+
end
|
117
|
+
|
58
118
|
register_extension :session do
|
59
119
|
require 'web_pipe/extensions/session/session'
|
60
120
|
end
|
data/web_pipe.gemspec
CHANGED
@@ -12,6 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
|
13
13
|
spec.summary = 'Rack application builder through a pipe of operations on an immutable struct.'
|
14
14
|
spec.homepage = 'https://github.com/waiting-for-dev/web_pipe'
|
15
|
+
spec.licenses = ['MIT']
|
15
16
|
|
16
17
|
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
17
18
|
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
@@ -43,8 +44,6 @@ Gem::Specification.new do |spec|
|
|
43
44
|
spec.add_development_dependency 'bundler'
|
44
45
|
spec.add_development_dependency 'dry-schema', '~> 1.0'
|
45
46
|
spec.add_development_dependency 'dry-transformer', '~> 0.1'
|
46
|
-
# TODO: Readd when dry-rb 0.8 is released (ruby 3.0 support)
|
47
|
-
# spec.add_development_dependency 'dry-view', '~> 0.8'
|
48
47
|
spec.add_development_dependency 'pry-byebug'
|
49
48
|
spec.add_development_dependency 'rack-flash3', '~> 1.0'
|
50
49
|
spec.add_development_dependency 'rack-test', '~> 1.1'
|
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.16.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: 2021-
|
11
|
+
date: 2021-11-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dry-monads
|
@@ -277,8 +277,9 @@ files:
|
|
277
277
|
- docs/extensions/container.md
|
278
278
|
- docs/extensions/cookies.md
|
279
279
|
- docs/extensions/dry_schema.md
|
280
|
-
- docs/extensions/dry_view.md
|
281
280
|
- docs/extensions/flash.md
|
281
|
+
- docs/extensions/hanami_view.md
|
282
|
+
- docs/extensions/not_found.md
|
282
283
|
- docs/extensions/params.md
|
283
284
|
- docs/extensions/rails.md
|
284
285
|
- docs/extensions/redirect.md
|
@@ -289,16 +290,19 @@ files:
|
|
289
290
|
- docs/plugging_operations.md
|
290
291
|
- docs/plugging_operations/composing_operations.md
|
291
292
|
- docs/plugging_operations/injecting_operations.md
|
293
|
+
- docs/plugging_operations/inspecting_operations.md
|
292
294
|
- docs/plugging_operations/resolving_operations.md
|
293
295
|
- docs/plugs.md
|
294
296
|
- docs/plugs/config.md
|
295
297
|
- docs/plugs/content_type.md
|
296
|
-
- docs/recipes/
|
298
|
+
- docs/recipes/hanami_2_and_dry_rb_integration.md
|
297
299
|
- docs/recipes/hanami_router_integration.md
|
298
300
|
- docs/recipes/using_all_restful_methods.md
|
301
|
+
- docs/testing.md
|
299
302
|
- docs/using_rack_middlewares.md
|
300
303
|
- docs/using_rack_middlewares/composing_middlewares.md
|
301
304
|
- docs/using_rack_middlewares/injecting_middlewares.md
|
305
|
+
- docs/using_rack_middlewares/inspecting_middlewares.md
|
302
306
|
- lib/web_pipe.rb
|
303
307
|
- lib/web_pipe/app.rb
|
304
308
|
- lib/web_pipe/conn.rb
|
@@ -309,14 +313,14 @@ files:
|
|
309
313
|
- lib/web_pipe/conn_support/types.rb
|
310
314
|
- lib/web_pipe/dsl/builder.rb
|
311
315
|
- lib/web_pipe/dsl/class_context.rb
|
312
|
-
- lib/web_pipe/dsl/
|
313
|
-
- lib/web_pipe/dsl/instance_methods.rb
|
316
|
+
- lib/web_pipe/dsl/instance_context.rb
|
314
317
|
- lib/web_pipe/extensions/container/container.rb
|
315
318
|
- lib/web_pipe/extensions/cookies/cookies.rb
|
316
319
|
- lib/web_pipe/extensions/dry_schema/dry_schema.rb
|
317
320
|
- lib/web_pipe/extensions/dry_schema/plugs/sanitize_params.rb
|
318
|
-
- lib/web_pipe/extensions/dry_view/dry_view.rb
|
319
321
|
- lib/web_pipe/extensions/flash/flash.rb
|
322
|
+
- lib/web_pipe/extensions/hanami_view/hanami_view.rb
|
323
|
+
- lib/web_pipe/extensions/not_found/not_found.rb
|
320
324
|
- lib/web_pipe/extensions/params/params.rb
|
321
325
|
- lib/web_pipe/extensions/params/params/transf.rb
|
322
326
|
- lib/web_pipe/extensions/rails/rails.rb
|
@@ -324,6 +328,7 @@ files:
|
|
324
328
|
- lib/web_pipe/extensions/router_params/router_params.rb
|
325
329
|
- lib/web_pipe/extensions/session/session.rb
|
326
330
|
- lib/web_pipe/extensions/url/url.rb
|
331
|
+
- lib/web_pipe/pipe.rb
|
327
332
|
- lib/web_pipe/plug.rb
|
328
333
|
- lib/web_pipe/plugs.rb
|
329
334
|
- lib/web_pipe/plugs/config.rb
|
@@ -331,11 +336,13 @@ files:
|
|
331
336
|
- lib/web_pipe/rack_support/app_with_middlewares.rb
|
332
337
|
- lib/web_pipe/rack_support/middleware.rb
|
333
338
|
- lib/web_pipe/rack_support/middleware_specification.rb
|
339
|
+
- lib/web_pipe/test_support.rb
|
334
340
|
- lib/web_pipe/types.rb
|
335
341
|
- lib/web_pipe/version.rb
|
336
342
|
- web_pipe.gemspec
|
337
343
|
homepage: https://github.com/waiting-for-dev/web_pipe
|
338
|
-
licenses:
|
344
|
+
licenses:
|
345
|
+
- MIT
|
339
346
|
metadata:
|
340
347
|
allowed_push_host: https://rubygems.org
|
341
348
|
homepage_uri: https://github.com/waiting-for-dev/web_pipe
|
@@ -356,7 +363,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
356
363
|
- !ruby/object:Gem::Version
|
357
364
|
version: '0'
|
358
365
|
requirements: []
|
359
|
-
rubygems_version: 3.2
|
366
|
+
rubygems_version: 3.1.2
|
360
367
|
signing_key:
|
361
368
|
specification_version: 4
|
362
369
|
summary: Rack application builder through a pipe of operations on an immutable struct.
|
@@ -1,18 +0,0 @@
|
|
1
|
-
# dry-rb integration
|
2
|
-
|
3
|
-
`web_pipe` has been designed to integrate smoothly with
|
4
|
-
[dry-rb](https://dry-rb.org/) ecosystem. It shares same design
|
5
|
-
principles and it ships with some extensions which even make this
|
6
|
-
integration tighter (like
|
7
|
-
[`:dry-view`](../extensions/dry_view.md) or
|
8
|
-
[`:dry-schema`](../extensions/dry_schema.md) extensions).
|
9
|
-
|
10
|
-
If you want to use `web_pipe` with the rest of dry-rb libraries,
|
11
|
-
your best bet is to use
|
12
|
-
[`dry-web-web_pipe`](https://github.com/waiting-for-dev/dry-web-web_pipe)
|
13
|
-
skeleton generator. It is a fork of
|
14
|
-
[`dry-web-roda`](https://github.com/dry-rb/dry-web-roda) with
|
15
|
-
`roda` dependency switched to a combination of `web_pipe` and
|
16
|
-
[`hanami-router`](https://github.com/hanami/router).
|
17
|
-
|
18
|
-
Look at `dry-web-web_pipe` README for more details.
|
@@ -1,85 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'web_pipe'
|
4
|
-
require 'web_pipe/types'
|
5
|
-
require 'web_pipe/plug'
|
6
|
-
require 'web_pipe/rack_support/middleware_specification'
|
7
|
-
|
8
|
-
module WebPipe
|
9
|
-
module DSL
|
10
|
-
# Defines the DSL for the pipe class and keeps it state.
|
11
|
-
#
|
12
|
-
# This allows adding rack middlewares and plugs at the class
|
13
|
-
# definition level.
|
14
|
-
#
|
15
|
-
# @api private
|
16
|
-
class DSLContext
|
17
|
-
# @!attribute middleware_specifications
|
18
|
-
# @return [Array<RackSupport::MiddlewareSpecifications>]
|
19
|
-
attr_reader :middleware_specifications
|
20
|
-
|
21
|
-
# @!attribute plugs
|
22
|
-
# @return [Array<Plug>]
|
23
|
-
attr_reader :plugs
|
24
|
-
|
25
|
-
def initialize(middleware_specifications, plugs)
|
26
|
-
@middleware_specifications = Types.Array(
|
27
|
-
RackSupport::MiddlewareSpecification
|
28
|
-
)[middleware_specifications]
|
29
|
-
@plugs = Types.Array(Plug::Instance)[plugs]
|
30
|
-
end
|
31
|
-
|
32
|
-
# Creates and add rack middleware specifications to the stack.
|
33
|
-
#
|
34
|
-
# The spec can be given in two forms:
|
35
|
-
#
|
36
|
-
# - As one or two arguments, first one being a
|
37
|
-
# rack middleware class and second one optionally its
|
38
|
-
# initialization options.
|
39
|
-
# - As a {WebPipe} class instance, in which case all its rack
|
40
|
-
# middlewares will be considered.
|
41
|
-
#
|
42
|
-
# @param name [RackSupport::MiddlewareSpecification::Name[]]
|
43
|
-
# @param spec [RackSupport::MiddlewareSpecification::Spec[]]
|
44
|
-
#
|
45
|
-
# @return [Array<RackSupport::Middleware>]
|
46
|
-
def use(name, *spec)
|
47
|
-
middleware_specifications << RackSupport::MiddlewareSpecification.new(name: name, spec: spec)
|
48
|
-
end
|
49
|
-
|
50
|
-
# Creates and adds a plug to the stack.
|
51
|
-
#
|
52
|
-
# The spec can be given as a {Plug::Spec}, as a block (which
|
53
|
-
# is captured into a {Proc}, one of the options for a
|
54
|
-
# {Plug::Spec} or as a {WebPipe} (in which case all its plugs
|
55
|
-
# will be composed).
|
56
|
-
#
|
57
|
-
# @param name [Plug::Name[]]
|
58
|
-
# @param spec [Plug::Spec[], WebPipe]
|
59
|
-
# @param block_spec [Proc]
|
60
|
-
#
|
61
|
-
# @return [Array<Plug>]
|
62
|
-
def plug(name, spec = nil, &block_spec)
|
63
|
-
plug_spec = if spec.is_a?(WebPipe)
|
64
|
-
spec.to_proc
|
65
|
-
elsif spec
|
66
|
-
spec
|
67
|
-
else
|
68
|
-
block_spec
|
69
|
-
end
|
70
|
-
|
71
|
-
plugs << Plug.new(name: name, spec: plug_spec)
|
72
|
-
end
|
73
|
-
|
74
|
-
# Adds middlewares and plugs from a WebPipe to respective
|
75
|
-
# stacks.
|
76
|
-
#
|
77
|
-
# @param name [Plug::Name[], Middleware::Name[]]
|
78
|
-
# @param spec [WebPipe]
|
79
|
-
def compose(name, spec)
|
80
|
-
use(name, spec)
|
81
|
-
plug(name, spec)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
@@ -1,114 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'web_pipe/types'
|
4
|
-
require 'web_pipe/conn'
|
5
|
-
require 'web_pipe/app'
|
6
|
-
require 'web_pipe/plug'
|
7
|
-
require 'web_pipe/rack_support/app_with_middlewares'
|
8
|
-
require 'web_pipe/rack_support/middleware_specification'
|
9
|
-
require 'web_pipe/conn_support/composition'
|
10
|
-
|
11
|
-
module WebPipe
|
12
|
-
module DSL
|
13
|
-
# Instance methods for the pipe.
|
14
|
-
#
|
15
|
-
# It is from here that you get the rack application you can route
|
16
|
-
# to. The initialization phase gives you the chance to inject any
|
17
|
-
# of the plugs or middlewares, while the instance you get has the
|
18
|
-
# `#call` method expected by rack.
|
19
|
-
#
|
20
|
-
# The pipe state can be accessed through the pipe class, which
|
21
|
-
# has been configured through {ClassContext}.
|
22
|
-
#
|
23
|
-
# @api private
|
24
|
-
module InstanceMethods
|
25
|
-
# No injections at all.
|
26
|
-
EMPTY_INJECTIONS = {
|
27
|
-
plugs: Types::EMPTY_HASH,
|
28
|
-
middlewares: Types::EMPTY_HASH
|
29
|
-
}.freeze
|
30
|
-
|
31
|
-
# Type for how plugs and middlewares should be injected.
|
32
|
-
Injections = Types::Strict::Hash.schema(
|
33
|
-
plugs: Plug::Injections,
|
34
|
-
middlewares: RackSupport::MiddlewareSpecification::Injections
|
35
|
-
)
|
36
|
-
|
37
|
-
# @!attribute [r] injections [Injections[]]
|
38
|
-
# Injected plugs and middlewares that allow overriding what
|
39
|
-
# has been configured.
|
40
|
-
attr_reader :injections
|
41
|
-
|
42
|
-
# @return [RackSupport::AppWithMiddlewares[]]
|
43
|
-
attr_reader :rack_app
|
44
|
-
|
45
|
-
# @return [ConnSupport::Composition::Operation[]]
|
46
|
-
attr_reader :operations
|
47
|
-
|
48
|
-
# @return [Array<RackSupport::Middlewares>]
|
49
|
-
attr_reader :middlewares
|
50
|
-
|
51
|
-
# rubocop:disable Metrics/AbcSize
|
52
|
-
def initialize(injects = EMPTY_INJECTIONS)
|
53
|
-
@injections = Injections[injects]
|
54
|
-
container = self.class.container
|
55
|
-
@middlewares = RackSupport::MiddlewareSpecification.inject_and_resolve(
|
56
|
-
self.class.middleware_specifications, injections[:middlewares]
|
57
|
-
)
|
58
|
-
@operations = Plug.inject_and_resolve(
|
59
|
-
self.class.plugs, injections[:plugs], container, self
|
60
|
-
)
|
61
|
-
app = App.new(operations)
|
62
|
-
@rack_app = RackSupport::AppWithMiddlewares.new(middlewares, app)
|
63
|
-
end
|
64
|
-
# rubocop:enable Metrics/AbcSize
|
65
|
-
|
66
|
-
# Expected interface for rack.
|
67
|
-
#
|
68
|
-
# @param env [Hash] Rack env
|
69
|
-
#
|
70
|
-
# @return [Array] Rack response
|
71
|
-
def call(env)
|
72
|
-
rack_app.call(env)
|
73
|
-
end
|
74
|
-
|
75
|
-
# Proc for the composition of all operations.
|
76
|
-
#
|
77
|
-
# This can be used to plug a {WebPipe} itself as an operation.
|
78
|
-
#
|
79
|
-
# @example
|
80
|
-
# class HtmlApp
|
81
|
-
# include WebPipe
|
82
|
-
#
|
83
|
-
# plug :html
|
84
|
-
#
|
85
|
-
# private
|
86
|
-
#
|
87
|
-
# def html(conn)
|
88
|
-
# conn.add_response_header('Content-Type', 'text/html')
|
89
|
-
# end
|
90
|
-
# end
|
91
|
-
#
|
92
|
-
# class App
|
93
|
-
# include WebPipe
|
94
|
-
#
|
95
|
-
# plug :html, &HtmlApp.new
|
96
|
-
# plug :body
|
97
|
-
#
|
98
|
-
# private
|
99
|
-
#
|
100
|
-
# def body(conn)
|
101
|
-
# conn.set_response_body('Hello, world!')
|
102
|
-
# end
|
103
|
-
# end
|
104
|
-
#
|
105
|
-
# @see ConnSupport::Composition
|
106
|
-
def to_proc
|
107
|
-
ConnSupport::Composition
|
108
|
-
.new(operations)
|
109
|
-
.method(:call)
|
110
|
-
.to_proc
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
@@ -1,158 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'web_pipe/types'
|
4
|
-
require 'web_pipe/conn'
|
5
|
-
require 'dry/view'
|
6
|
-
|
7
|
-
#:nodoc:
|
8
|
-
module WebPipe
|
9
|
-
# Integration with `dry-view` rendering system.
|
10
|
-
#
|
11
|
-
# This extensions adds a {#view} method to {WebPipe::Conn} which
|
12
|
-
# sets the string output of a `dry-view` view as response body.
|
13
|
-
#
|
14
|
-
# @example
|
15
|
-
# WebPipe.load_extensions(:dry_view)
|
16
|
-
#
|
17
|
-
# class SayHelloView < Dry::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(:dry_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 ({Dry::View::Context}) for the view can be set explicetly
|
54
|
-
# through the `context:` argument, as in a standard call to
|
55
|
-
# {Dry::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
|
-
# {Dry::View::Context#with} to create the final context at the
|
61
|
-
# moment {#view} is called.
|
62
|
-
#
|
63
|
-
# @example
|
64
|
-
# class MyContext < Dry::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 < Dry::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://dry-rb.org/gems/dry-view/
|
100
|
-
# @see WebPipe::Container
|
101
|
-
module DryView
|
102
|
-
# Where to find in {#config} request's view context generator.
|
103
|
-
VIEW_CONTEXT_KEY = :view_context
|
104
|
-
|
105
|
-
# Default request's view context
|
106
|
-
DEFAULT_VIEW_CONTEXT = ->(_conn) { Types::EMPTY_HASH }
|
107
|
-
|
108
|
-
# Sets string output of a view as response body.
|
109
|
-
#
|
110
|
-
# If the view is not a {Dry::View} instance, it is resolved from
|
111
|
-
# the configured container.
|
112
|
-
#
|
113
|
-
# `kwargs` is used as the input for the view (the arguments that
|
114
|
-
# {Dry::View#call} receives). If they doesn't contain an explicit
|
115
|
-
# `context:` key, it can be added through the injection of the
|
116
|
-
# result of a lambda present in context's `:view_context`.(see
|
117
|
-
# {Dry::View::Context#with}).
|
118
|
-
#
|
119
|
-
# @param view_spec [Dry::View, Any]
|
120
|
-
# @param kwargs [Hash] Arguments to pass along to `Dry::View#call`
|
121
|
-
#
|
122
|
-
# @return WebPipe::Conn
|
123
|
-
def view(view_spec, **kwargs)
|
124
|
-
view_instance = view_instance(view_spec)
|
125
|
-
view_input = view_input(kwargs, view_instance)
|
126
|
-
|
127
|
-
set_response_body(
|
128
|
-
view_instance.call(
|
129
|
-
**view_input
|
130
|
-
).to_str
|
131
|
-
)
|
132
|
-
end
|
133
|
-
|
134
|
-
private
|
135
|
-
|
136
|
-
def view_instance(view_spec)
|
137
|
-
return view_spec if view_spec.is_a?(Dry::View)
|
138
|
-
|
139
|
-
fetch_config(:container)[view_spec]
|
140
|
-
end
|
141
|
-
|
142
|
-
def view_input(kwargs, view_instance)
|
143
|
-
return kwargs if kwargs.key?(:context)
|
144
|
-
|
145
|
-
context = view_instance
|
146
|
-
.config
|
147
|
-
.default_context
|
148
|
-
.with(
|
149
|
-
**fetch_config(
|
150
|
-
VIEW_CONTEXT_KEY, DEFAULT_VIEW_CONTEXT
|
151
|
-
).call(self)
|
152
|
-
)
|
153
|
-
kwargs.merge(context: context)
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
Conn.include(DryView)
|
158
|
-
end
|