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
@@ -0,0 +1,229 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'web_pipe/conn_support/composition'
|
4
|
+
require 'web_pipe/app'
|
5
|
+
require 'web_pipe/plug'
|
6
|
+
require 'web_pipe/rack_support/middleware_specification'
|
7
|
+
require 'web_pipe/rack_support/app_with_middlewares'
|
8
|
+
require 'web_pipe/types'
|
9
|
+
|
10
|
+
module WebPipe
|
11
|
+
# Composable rack application builder.
|
12
|
+
#
|
13
|
+
# An instance of this class helps build rack applications that can compose.
|
14
|
+
# Besides the DSL, which only adds a convenience layer, this is the higher
|
15
|
+
# abstraction on the library.
|
16
|
+
#
|
17
|
+
# Applications are built by plugging functions that take and return a
|
18
|
+
# {WebPipe::Conn} instance. That's an immutable struct that contains all the
|
19
|
+
# request information alongside methods to build the response. See {#plug} for
|
20
|
+
# details.
|
21
|
+
#
|
22
|
+
# Middlewares can also be added to the resulting application thanks to {#use}.
|
23
|
+
#
|
24
|
+
# Be aware that instances of this class are immutable, so methods return new
|
25
|
+
# objects every time.
|
26
|
+
#
|
27
|
+
# The instance itself is the final rack application.
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# # config.ru
|
31
|
+
# require 'web_pipe/pipe'
|
32
|
+
#
|
33
|
+
# app = WebPipe::Pipe.new
|
34
|
+
# .use(:runtime, Rack::Runtime)
|
35
|
+
# .plug(:content_type) do |conn|
|
36
|
+
# conn.add_response_header('Content-Type', 'text/plain')
|
37
|
+
# end
|
38
|
+
# .plug(:render) do |conn|
|
39
|
+
# conn.set_response_body('Hello, World!')
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# run app
|
43
|
+
class Pipe
|
44
|
+
# Container that resolves nothing
|
45
|
+
EMPTY_CONTAINER = {}.freeze
|
46
|
+
|
47
|
+
# @!attribute [r] container
|
48
|
+
# Container from where resolve operations. See {#plug}.
|
49
|
+
attr_reader :container
|
50
|
+
|
51
|
+
# @!attribute [r] context
|
52
|
+
# Object from where resolve operations. See {#plug}.
|
53
|
+
attr_reader :context
|
54
|
+
|
55
|
+
# @api private
|
56
|
+
EMPTY_PLUGS = [].freeze
|
57
|
+
|
58
|
+
# @api private
|
59
|
+
EMPTY_MIDDLEWARE_SPECIFICATIONS = [].freeze
|
60
|
+
|
61
|
+
# @api private
|
62
|
+
Container = Types.Interface(:[])
|
63
|
+
|
64
|
+
# @api private
|
65
|
+
attr_reader :plugs
|
66
|
+
|
67
|
+
# @api private
|
68
|
+
attr_reader :middleware_specifications
|
69
|
+
|
70
|
+
# @param container [#to_h] Container from where resolve plug's operations
|
71
|
+
# (see {#plug}).
|
72
|
+
# @param context [Any] Object from where resolve plug's operations (see
|
73
|
+
# {#plug})
|
74
|
+
def initialize(
|
75
|
+
container: EMPTY_CONTAINER,
|
76
|
+
context: nil,
|
77
|
+
plugs: EMPTY_PLUGS,
|
78
|
+
middleware_specifications: EMPTY_MIDDLEWARE_SPECIFICATIONS
|
79
|
+
)
|
80
|
+
@plugs = plugs
|
81
|
+
@middleware_specifications = middleware_specifications
|
82
|
+
@container = Container[container]
|
83
|
+
@context = context
|
84
|
+
end
|
85
|
+
|
86
|
+
# Names and adds a plug operation to the application.
|
87
|
+
#
|
88
|
+
# The operation can be provided in several ways:
|
89
|
+
#
|
90
|
+
# - Through the `spec` parameter as:
|
91
|
+
# - Anything responding to `#call` (like a {Proc}).
|
92
|
+
# - As a string or symbol key for something registered in {#container}.
|
93
|
+
# - Anything responding to `#to_proc` (like another {WebPipe::Pipe}
|
94
|
+
# instance or an instance of a class including {WebPipe}).
|
95
|
+
# - As `nil` (default), meaning that the operation is a method in
|
96
|
+
# {#context} matching the `name` parameter.
|
97
|
+
# - Through a block, if the `spec` parameter is `nil`.
|
98
|
+
#
|
99
|
+
# @param name [Symbol]
|
100
|
+
# @param spec [#call, #to_proc, String, Symbol, nil]
|
101
|
+
# @yieldparam [WebPipe::Conn]
|
102
|
+
#
|
103
|
+
# @return [WebPipe::Pipe] A fresh new instance with the added plug.
|
104
|
+
def plug(name, spec = nil, &block_spec)
|
105
|
+
with(
|
106
|
+
plugs: [
|
107
|
+
*plugs,
|
108
|
+
Plug.new(name: name, spec: spec || block_spec)
|
109
|
+
]
|
110
|
+
)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Names and adds a rack middleware to the final application.
|
114
|
+
#
|
115
|
+
# The middleware can be given in three forms:
|
116
|
+
#
|
117
|
+
# - As one or two arguments, the first one being a
|
118
|
+
# rack middleware class, and optionally a second one with its initialization
|
119
|
+
# options.
|
120
|
+
# - As something responding to `#to_middlewares` with an array of
|
121
|
+
# {WebPipe::RackSupport::Middleware} (like another {WebPipe::Pipe} instance
|
122
|
+
# or a class including {WebPipe}), case in which all middlewares are used.
|
123
|
+
#
|
124
|
+
# @overload use(name, middleware_class)
|
125
|
+
# @param name [Symbol]
|
126
|
+
# @param middleware_class [Class]
|
127
|
+
# @overload use(name, middleware_class, middleware_options)
|
128
|
+
# @param name [Symbol]
|
129
|
+
# @param middleware_class [Class]
|
130
|
+
# @param middleware_options [Any]
|
131
|
+
# @overload use(name, to_middlewares)
|
132
|
+
# @param name [Symbol]
|
133
|
+
# @param middleware_class [#to_middlewares]
|
134
|
+
#
|
135
|
+
# @return [WebPipe::Pipe] A fresh new instance with the added middleware.
|
136
|
+
def use(name, *spec)
|
137
|
+
with(
|
138
|
+
middleware_specifications: [
|
139
|
+
*middleware_specifications,
|
140
|
+
RackSupport::MiddlewareSpecification.new(name: name, spec: spec)
|
141
|
+
]
|
142
|
+
)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Shortcut for {#plug} and {#use} a pipe at once.
|
146
|
+
#
|
147
|
+
# @param name [#to_sym]
|
148
|
+
# @param spec [#to_proc#to_middlewares]
|
149
|
+
def compose(name, spec)
|
150
|
+
use(name, spec)
|
151
|
+
.plug(name, spec)
|
152
|
+
end
|
153
|
+
|
154
|
+
# Operations {#plug}ged to the app, mapped by their names.
|
155
|
+
#
|
156
|
+
# @return [Hash{Symbol => Proc}]
|
157
|
+
def operations
|
158
|
+
@operations ||= Hash[
|
159
|
+
plugs.map { |plug| [plug.name, plug.call(container, context)] }
|
160
|
+
]
|
161
|
+
end
|
162
|
+
|
163
|
+
# Middlewares {#use}d in the app, mapped by their names.
|
164
|
+
#
|
165
|
+
# Returns them wrapped within {WebPipe::RackSupport::Middleware} instances,
|
166
|
+
# from where you can access their classes and options.
|
167
|
+
#
|
168
|
+
# @return [Hash{Symbol=>Array<WebPipe::RackSupport::Middleware>}]
|
169
|
+
def middlewares
|
170
|
+
@middlewares ||= Hash[
|
171
|
+
middleware_specifications.map { |mw_spec| [mw_spec.name, mw_spec.call] }
|
172
|
+
]
|
173
|
+
end
|
174
|
+
|
175
|
+
# @api private
|
176
|
+
def to_proc
|
177
|
+
ConnSupport::Composition
|
178
|
+
.new(operations.values)
|
179
|
+
.method(:call)
|
180
|
+
end
|
181
|
+
|
182
|
+
# @api private
|
183
|
+
def to_middlewares
|
184
|
+
middlewares.values.flatten
|
185
|
+
end
|
186
|
+
|
187
|
+
# @api private
|
188
|
+
def inject(plugs: {}, middleware_specifications: {})
|
189
|
+
res_mw_specs = RackSupport::MiddlewareSpecification.inject(
|
190
|
+
self.middleware_specifications, middleware_specifications
|
191
|
+
)
|
192
|
+
res_plugs = Plug.inject(
|
193
|
+
self.plugs, plugs
|
194
|
+
)
|
195
|
+
with(
|
196
|
+
plugs: res_plugs,
|
197
|
+
middleware_specifications: res_mw_specs
|
198
|
+
)
|
199
|
+
end
|
200
|
+
|
201
|
+
# @api private
|
202
|
+
def call(env)
|
203
|
+
rack_app.call(env)
|
204
|
+
end
|
205
|
+
|
206
|
+
private
|
207
|
+
|
208
|
+
def app
|
209
|
+
App.new(operations.values).freeze
|
210
|
+
end
|
211
|
+
|
212
|
+
def rack_app
|
213
|
+
RackSupport::AppWithMiddlewares.new(
|
214
|
+
to_middlewares,
|
215
|
+
app
|
216
|
+
).freeze
|
217
|
+
end
|
218
|
+
|
219
|
+
def with(plugs: nil, middleware_specifications: nil)
|
220
|
+
self.class.new(
|
221
|
+
container: container,
|
222
|
+
context: context,
|
223
|
+
middleware_specifications: middleware_specifications ||
|
224
|
+
self.middleware_specifications,
|
225
|
+
plugs: plugs || self.plugs
|
226
|
+
)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
data/lib/web_pipe/plug.rb
CHANGED
@@ -5,106 +5,72 @@ require 'web_pipe/types'
|
|
5
5
|
require 'web_pipe/conn_support/composition'
|
6
6
|
|
7
7
|
module WebPipe
|
8
|
-
# A plug is a specification to resolve a callable object.
|
9
|
-
#
|
10
|
-
# It is initialized with a {Name} and a {Spec} and, on resolution
|
11
|
-
# time, is called with a {Types::Container} and an {Object} to act
|
12
|
-
# in the following fashion:
|
13
|
-
#
|
14
|
-
# - When the spec responds to `#call`, it is returned itself as the
|
15
|
-
# callable object.
|
16
|
-
# - When the spec is `nil`, then a {Proc} wrapping a method with the
|
17
|
-
# plug name in `object` is returned.
|
18
|
-
# - Otherwise, spec is taken as the key to resolve the operation
|
19
|
-
# from the `container`.
|
20
|
-
#
|
21
8
|
# @api private
|
22
9
|
class Plug < Dry::Struct
|
23
|
-
#
|
10
|
+
# Raised when the specification for an operation is invalid.
|
24
11
|
class InvalidPlugError < ArgumentError
|
25
|
-
# @param name [Any] Name for the plug that can't be resolved
|
26
12
|
def initialize(name)
|
27
13
|
super(
|
28
14
|
<<~MSG
|
29
|
-
Plug with name +#{name}+
|
30
|
-
|
31
|
-
|
15
|
+
Plug with name +#{name}+ can't be resolved. You must provide
|
16
|
+
something responding to `#call` or `#to_proc`, or a key for
|
17
|
+
something registered in the container obeying those exact
|
18
|
+
constraints. If nothing is given, it's expected to be a method
|
19
|
+
defined in the context object.
|
32
20
|
MSG
|
33
21
|
)
|
34
22
|
end
|
35
23
|
end
|
36
|
-
|
37
|
-
# Type for the name of a plug.
|
38
24
|
Name = Types::Strict::Symbol.constructor(&:to_sym)
|
39
25
|
|
40
|
-
|
41
|
-
|
42
|
-
# {Plug}.
|
43
|
-
Spec = ConnSupport::Composition::Operation |
|
26
|
+
Spec = Types.Interface(:call) |
|
27
|
+
Types.Interface(:to_proc) |
|
44
28
|
Types.Constant(nil) |
|
45
29
|
Types::Strict::String |
|
46
30
|
Types::Strict::Symbol
|
47
31
|
|
48
|
-
# Type for an instance of self.
|
49
|
-
Instance = Types.Instance(self)
|
50
|
-
|
51
|
-
# Schema expected to inject plugs.
|
52
|
-
#
|
53
|
-
# @see #inject_and_resolve
|
54
32
|
Injections = Types::Strict::Hash.map(
|
55
|
-
|
33
|
+
Name, Spec
|
56
34
|
).default(Types::EMPTY_HASH)
|
57
35
|
|
58
|
-
# @!attribute [r] name
|
59
|
-
# @return [Name[]]
|
60
36
|
attribute :name, Name
|
61
37
|
|
62
|
-
# @!attribute [r] spec
|
63
|
-
# @return [Spec[]]
|
64
38
|
attribute :spec, Spec
|
65
39
|
|
66
|
-
# Creates a new instance with given `spec` but keeping `name`.
|
67
|
-
#
|
68
|
-
# @param new_spec [Spec[]]
|
69
|
-
# @return [self]
|
70
40
|
def with(new_spec)
|
71
41
|
new(spec: new_spec)
|
72
42
|
end
|
73
43
|
|
74
|
-
#
|
75
|
-
#
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
# @raise [InvalidPlugError] When nothing callable is resolved.
|
81
|
-
def call(container, pipe)
|
82
|
-
if spec.respond_to?(:call)
|
44
|
+
# rubocop:disable Metrics/MethodLength
|
45
|
+
# rubocop:disable Metrics/AbcSize
|
46
|
+
def call(container, context)
|
47
|
+
if spec.respond_to?(:to_proc) && !spec.is_a?(Symbol)
|
48
|
+
spec.to_proc
|
49
|
+
elsif spec.respond_to?(:call)
|
83
50
|
spec
|
84
51
|
elsif spec.nil?
|
85
|
-
|
86
|
-
elsif container[spec]
|
87
|
-
container[spec]
|
52
|
+
context.method(name)
|
53
|
+
elsif container[spec]
|
54
|
+
with(container[spec]).call(container, context)
|
88
55
|
else
|
89
56
|
raise InvalidPlugError, name
|
90
57
|
end
|
91
58
|
end
|
59
|
+
# rubocop:enable Metrics/MethodLength
|
60
|
+
# rubocop:enable Metrics/AbcSize
|
92
61
|
|
93
|
-
|
94
|
-
#
|
95
|
-
# @param plugs [Array<Plug>]
|
96
|
-
# @param injections [InstanceMethods::PlugInjections[]]
|
97
|
-
# @container container [Types::Container[]]
|
98
|
-
# @object [Object]
|
99
|
-
#
|
100
|
-
# @return [Array<ConnSupport::Composition::Operation[]>]
|
101
|
-
def self.inject_and_resolve(plugs, injections, container, object)
|
62
|
+
def self.inject(plugs, injections)
|
102
63
|
plugs.map do |plug|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
64
|
+
inject_plug(plug, injections)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.inject_plug(plug, injections)
|
69
|
+
name = plug.name
|
70
|
+
if injections.key?(name)
|
71
|
+
plug.with(injections[name])
|
72
|
+
else
|
73
|
+
plug
|
108
74
|
end
|
109
75
|
end
|
110
76
|
end
|
@@ -1,43 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'web_pipe/types'
|
4
3
|
require 'web_pipe/rack_support/middleware'
|
5
4
|
require 'rack'
|
6
5
|
|
7
6
|
module WebPipe
|
8
7
|
module RackSupport
|
9
|
-
# Helper to build and call a rack application with middlewares.
|
10
|
-
#
|
11
8
|
# @api private
|
12
9
|
class AppWithMiddlewares
|
13
|
-
|
14
|
-
#
|
15
|
-
# It should be something callable accepting a rack env and
|
16
|
-
# returning a rack response.
|
17
|
-
App = Types.Interface(:call)
|
18
|
-
|
19
|
-
# @!attribute [r] rack_middlewares
|
20
|
-
# @return [Array<RackMiddleware>]
|
21
|
-
attr_reader :rack_middlewares
|
22
|
-
|
23
|
-
# @!attribute [r] app
|
24
|
-
# @return [App[]]
|
25
|
-
attr_reader :app
|
26
|
-
|
27
|
-
# @return [Rack::Builder]
|
28
|
-
attr_reader :builder
|
10
|
+
attr_reader :rack_middlewares, :app, :builder
|
29
11
|
|
30
12
|
def initialize(rack_middlewares, app)
|
31
|
-
@rack_middlewares =
|
32
|
-
@app =
|
13
|
+
@rack_middlewares = rack_middlewares
|
14
|
+
@app = app
|
33
15
|
@builder = build_rack_app(rack_middlewares, app)
|
34
16
|
end
|
35
17
|
|
36
|
-
# Calls rack application.
|
37
|
-
#
|
38
|
-
# @param env [Hash] Rack env
|
39
|
-
#
|
40
|
-
# @return [Array] Rack resonse
|
41
18
|
def call(env)
|
42
19
|
builder.call(env)
|
43
20
|
end
|
@@ -5,10 +5,10 @@ require 'dry/struct'
|
|
5
5
|
|
6
6
|
module WebPipe
|
7
7
|
module RackSupport
|
8
|
+
# Wrapper for a rack middleware.
|
9
|
+
#
|
8
10
|
# Simple data structure to represent a rack middleware class with
|
9
11
|
# its initialization options.
|
10
|
-
#
|
11
|
-
# @api private
|
12
12
|
class Middleware < Dry::Struct
|
13
13
|
# Type for a rack middleware class.
|
14
14
|
MiddlewareClass = Types.Instance(Class)
|
@@ -6,74 +6,45 @@ require 'web_pipe/types'
|
|
6
6
|
|
7
7
|
module WebPipe
|
8
8
|
module RackSupport
|
9
|
-
# Specification on how to resolve {Rack::Middleware}'s.
|
10
|
-
#
|
11
|
-
# Rack middlewares can be specified in two ways:
|
12
|
-
#
|
13
|
-
# - As an array where fist element is a rack middleware class
|
14
|
-
# while the rest of elements are its initialization options.
|
15
|
-
# - A single element array where it is an instance of a class
|
16
|
-
# including {WebPipe}. This specifies all {RackSupport::Middlewares} for
|
17
|
-
# that {WebPipe}.
|
18
|
-
#
|
19
9
|
# @api private
|
20
10
|
class MiddlewareSpecification < Dry::Struct
|
21
|
-
# Type for the name given to a middleware.
|
22
11
|
Name = Types::Strict::Symbol.constructor(&:to_sym)
|
23
12
|
|
24
|
-
# Poor type for the specification to resolve a rack middleware.
|
25
13
|
Spec = Types::Strict::Array
|
26
14
|
|
27
|
-
# Schema expected to inject middleware specifications.
|
28
|
-
#
|
29
|
-
# @see #inject_and_resolve
|
30
15
|
Injections = Types::Strict::Hash.map(
|
31
|
-
|
16
|
+
Name, Spec
|
32
17
|
).default(Types::EMPTY_HASH)
|
33
18
|
|
34
|
-
# @!attribute [r] name
|
35
|
-
# @return [Name[]]
|
36
19
|
attribute :name, Name
|
37
20
|
|
38
|
-
# @!attribute [r] spec
|
39
|
-
# @return [Spec[]]
|
40
21
|
attribute :spec, Spec
|
41
22
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
def self.
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
end.flatten
|
23
|
+
def self.inject(middleware_specifications, injections)
|
24
|
+
middleware_specifications.map do |middleware_spec|
|
25
|
+
inject_middleware(middleware_spec, injections)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.inject_middleware(middleware_spec, injections)
|
30
|
+
name = middleware_spec.name
|
31
|
+
if injections.key?(name)
|
32
|
+
middleware_spec.with(injections[name])
|
33
|
+
else
|
34
|
+
middleware_spec
|
35
|
+
end
|
56
36
|
end
|
57
37
|
|
58
|
-
# Resolves {RackSupport::Middlewares} from given specification.
|
59
|
-
#
|
60
|
-
# @return [Array<RackSupport::Middleware>]
|
61
38
|
def call
|
62
|
-
|
39
|
+
klass_or_pipe = spec[0]
|
63
40
|
options = spec[1..] || Types::EMPTY_ARRAY
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
[Middleware.new(middleware: klass, options: options)]
|
41
|
+
if klass_or_pipe.respond_to?(:to_middlewares)
|
42
|
+
klass_or_pipe.to_middlewares
|
43
|
+
elsif klass_or_pipe.is_a?(Class)
|
44
|
+
[Middleware.new(middleware: klass_or_pipe, options: options)]
|
69
45
|
end
|
70
46
|
end
|
71
47
|
|
72
|
-
# Returns new instance with {#spec} replaced.
|
73
|
-
#
|
74
|
-
# @param new_spec [Spec[]]
|
75
|
-
#
|
76
|
-
# @return [MiddlewareSpecification]
|
77
48
|
def with(new_spec)
|
78
49
|
new(spec: new_spec)
|
79
50
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'web_pipe/conn_support/builder'
|
4
|
+
require 'rack/mock'
|
5
|
+
|
6
|
+
module WebPipe
|
7
|
+
# Test helper methods.
|
8
|
+
#
|
9
|
+
# This module is meant to be included in a test file to provide helper
|
10
|
+
# methods.
|
11
|
+
module TestSupport
|
12
|
+
# Builds a {WebPipe::Conn}
|
13
|
+
#
|
14
|
+
# @param uri [String] URI that will be used to populate the request
|
15
|
+
# attributes
|
16
|
+
# @param attributes [Hash<Symbol, Any>] Manually set attributes for the
|
17
|
+
# struct. It overrides what is taken from the `uri` parameter
|
18
|
+
# @param env_opts [Hash] Options to be added to the `env` from which the
|
19
|
+
# connection struct is created. See {Rack::MockRequest.env_for}.
|
20
|
+
# @return [Conn]
|
21
|
+
def build_conn(uri = '', attributes: {}, env_opts: {})
|
22
|
+
env = Rack::MockRequest.env_for(uri, env_opts)
|
23
|
+
ConnSupport::Builder
|
24
|
+
.call(env)
|
25
|
+
.new(attributes)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/web_pipe/types.rb
CHANGED
@@ -4,11 +4,9 @@ require 'dry/types'
|
|
4
4
|
require 'dry/core/constants'
|
5
5
|
|
6
6
|
module WebPipe
|
7
|
-
# Namespace for generic
|
7
|
+
# Namespace for generic types.
|
8
8
|
module Types
|
9
9
|
include Dry.Types()
|
10
10
|
include Dry::Core::Constants
|
11
|
-
|
12
|
-
Container = Interface(:[])
|
13
11
|
end
|
14
12
|
end
|
data/lib/web_pipe/version.rb
CHANGED