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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -1
  3. data/CHANGELOG.md +29 -0
  4. data/Gemfile +2 -2
  5. data/README.md +18 -11
  6. data/docs/building_a_rack_application.md +1 -1
  7. data/docs/composing_applications.md +4 -4
  8. data/docs/connection_struct/configuring_the_connection_struct.md +4 -4
  9. data/docs/connection_struct/halting_the_pipe.md +17 -19
  10. data/docs/connection_struct/sharing_data_downstream.md +9 -8
  11. data/docs/connection_struct.md +22 -19
  12. data/docs/design_model.md +10 -9
  13. data/docs/dsl_free_usage.md +85 -14
  14. data/docs/extensions/container.md +9 -10
  15. data/docs/extensions/cookies.md +4 -2
  16. data/docs/extensions/dry_schema.md +5 -4
  17. data/docs/extensions/flash.md +9 -11
  18. data/docs/extensions/{dry_view.md → hanami_view.md} +20 -22
  19. data/docs/extensions/not_found.md +40 -0
  20. data/docs/extensions/params.md +6 -4
  21. data/docs/extensions/rails.md +31 -38
  22. data/docs/extensions/redirect.md +5 -4
  23. data/docs/extensions/router_params.md +5 -5
  24. data/docs/extensions/session.md +4 -4
  25. data/docs/extensions/url.md +6 -6
  26. data/docs/extensions.md +5 -6
  27. data/docs/introduction.md +7 -7
  28. data/docs/plugging_operations/composing_operations.md +3 -3
  29. data/docs/plugging_operations/injecting_operations.md +4 -4
  30. data/docs/plugging_operations/inspecting_operations.md +24 -0
  31. data/docs/plugging_operations/resolving_operations.md +3 -3
  32. data/docs/plugging_operations.md +3 -3
  33. data/docs/plugs/config.md +1 -1
  34. data/docs/plugs/content_type.md +2 -1
  35. data/docs/plugs.md +6 -7
  36. data/docs/recipes/hanami_2_and_dry_rb_integration.md +12 -0
  37. data/docs/recipes/hanami_router_integration.md +3 -1
  38. data/docs/recipes/using_all_restful_methods.md +6 -5
  39. data/docs/testing.md +64 -0
  40. data/docs/using_rack_middlewares/composing_middlewares.md +2 -3
  41. data/docs/using_rack_middlewares/injecting_middlewares.md +6 -6
  42. data/docs/using_rack_middlewares/inspecting_middlewares.md +35 -0
  43. data/docs/using_rack_middlewares.md +6 -6
  44. data/lib/web_pipe/app.rb +22 -25
  45. data/lib/web_pipe/conn.rb +0 -1
  46. data/lib/web_pipe/conn_support/builder.rb +0 -7
  47. data/lib/web_pipe/conn_support/composition.rb +3 -26
  48. data/lib/web_pipe/conn_support/errors.rb +5 -5
  49. data/lib/web_pipe/conn_support/headers.rb +1 -50
  50. data/lib/web_pipe/conn_support/types.rb +3 -3
  51. data/lib/web_pipe/dsl/builder.rb +10 -19
  52. data/lib/web_pipe/dsl/class_context.rb +15 -40
  53. data/lib/web_pipe/dsl/instance_context.rb +53 -0
  54. data/lib/web_pipe/extensions/container/container.rb +2 -15
  55. data/lib/web_pipe/extensions/cookies/cookies.rb +2 -31
  56. data/lib/web_pipe/extensions/dry_schema/dry_schema.rb +2 -56
  57. data/lib/web_pipe/extensions/flash/flash.rb +2 -32
  58. data/lib/web_pipe/extensions/hanami_view/hanami_view.rb +67 -0
  59. data/lib/web_pipe/extensions/not_found/not_found.rb +26 -0
  60. data/lib/web_pipe/extensions/params/params.rb +2 -63
  61. data/lib/web_pipe/extensions/rails/rails.rb +2 -123
  62. data/lib/web_pipe/extensions/redirect/redirect.rb +2 -20
  63. data/lib/web_pipe/extensions/router_params/router_params.rb +1 -39
  64. data/lib/web_pipe/extensions/session/session.rb +2 -25
  65. data/lib/web_pipe/extensions/url/url.rb +2 -5
  66. data/lib/web_pipe/pipe.rb +229 -0
  67. data/lib/web_pipe/plug.rb +31 -65
  68. data/lib/web_pipe/plugs/config.rb +0 -2
  69. data/lib/web_pipe/plugs/content_type.rb +0 -2
  70. data/lib/web_pipe/rack_support/app_with_middlewares.rb +3 -26
  71. data/lib/web_pipe/rack_support/middleware.rb +2 -2
  72. data/lib/web_pipe/rack_support/middleware_specification.rb +19 -48
  73. data/lib/web_pipe/test_support.rb +28 -0
  74. data/lib/web_pipe/types.rb +1 -3
  75. data/lib/web_pipe/version.rb +1 -1
  76. data/lib/web_pipe.rb +77 -17
  77. data/web_pipe.gemspec +1 -2
  78. metadata +16 -9
  79. data/docs/recipes/dry_rb_integration.md +0 -18
  80. data/lib/web_pipe/dsl/dsl_context.rb +0 -85
  81. data/lib/web_pipe/dsl/instance_methods.rb +0 -114
  82. 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
- # Error raised when no operation can be resolved from a {Spec}.
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}+ is invalid. It must be something
30
- callable, an instance method when no operation is given,
31
- or something callable registered in the container."
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
- # Type for the spec to resolve and
41
- # {ConnSupport::Composition::Operation} on a {Conn} used by
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
- Plug::Name, Plug::Spec
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
- # Resolves the operation.
75
- #
76
- # @param container [Types::Container[]]
77
- # @param object [Object]
78
- #
79
- # @return [ConnSupport::Composition::Operation[]]
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
- pipe.method(name)
86
- elsif container[spec].respond_to?(:call)
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
- # Change `plugs` spec's present in `injections` and resolves.
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
- if injections.key?(plug.name)
104
- plug.with(injections[plug.name])
105
- else
106
- plug
107
- end.call(container, object)
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,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'web_pipe/types'
4
-
5
3
  module WebPipe
6
4
  module Plugs
7
5
  # Adds given pairs to {Conn#config}.
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'web_pipe/types'
4
-
5
3
  module WebPipe
6
4
  module Plugs
7
5
  # Sets `Content-Type` response header.
@@ -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
- # Type for a rack application.
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 = Types.Array(Middleware)[rack_middlewares]
32
- @app = App[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
- RackSupport::MiddlewareSpecification::Name, RackSupport::MiddlewareSpecification::Spec
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
- # Change spec's present in `injections` and resolves.
43
- #
44
- # @param middleware_specifications [Array<MiddlewareSpecification>]
45
- # @param injections [Injections[]]
46
- #
47
- # @return [Array<RackSupport::Middleware>]
48
- def self.inject_and_resolve(middleware_specifications, injections)
49
- middleware_specifications.map do |spec|
50
- if injections.key?(spec.name)
51
- spec.with(injections[spec.name])
52
- else
53
- spec
54
- end.call
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
- klass = spec[0]
39
+ klass_or_pipe = spec[0]
63
40
  options = spec[1..] || Types::EMPTY_ARRAY
64
- case klass
65
- when WebPipe
66
- klass.middlewares
67
- when Class
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
@@ -4,11 +4,9 @@ require 'dry/types'
4
4
  require 'dry/core/constants'
5
5
 
6
6
  module WebPipe
7
- # Namespace for generic library types.
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module WebPipe
4
- VERSION = '0.13.0'
4
+ VERSION = '0.16.0'
5
5
  end