web_pipe 0.8.0 → 0.9.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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/Gemfile +4 -2
  4. data/README.md +60 -310
  5. data/Rakefile +5 -3
  6. data/bin/console +4 -3
  7. data/docs/_config.yml +1 -0
  8. data/docs/building_a_rack_application.md +25 -0
  9. data/docs/composing_applications.md +43 -0
  10. data/docs/connection_struct/configuring_the_connection_struct.md +25 -0
  11. data/docs/connection_struct/halting_the_pipe.md +71 -0
  12. data/docs/connection_struct/sharing_data_downstream.md +46 -0
  13. data/docs/connection_struct.md +77 -0
  14. data/docs/design_model.md +44 -0
  15. data/docs/dsl_free_usage.md +26 -0
  16. data/docs/extensions/container.md +41 -0
  17. data/docs/extensions/cookies.md +47 -0
  18. data/docs/extensions/dry_schema.md +51 -0
  19. data/docs/extensions/dry_view.md +113 -0
  20. data/docs/extensions/flash.md +41 -0
  21. data/docs/extensions/params.md +117 -0
  22. data/docs/extensions/redirect.md +25 -0
  23. data/docs/extensions/router_params.md +40 -0
  24. data/docs/extensions/session.md +39 -0
  25. data/docs/extensions/url.md +11 -0
  26. data/docs/extensions.md +13 -0
  27. data/docs/introduction.md +73 -0
  28. data/docs/plugging_operations/composing_operations.md +36 -0
  29. data/docs/plugging_operations/injecting_operations.md +32 -0
  30. data/docs/plugging_operations/resolving_operations.md +71 -0
  31. data/docs/plugging_operations.md +21 -0
  32. data/docs/plugs/config.md +18 -0
  33. data/docs/plugs/content_type.md +16 -0
  34. data/docs/plugs.md +13 -0
  35. data/docs/recipes/dry_rb_integration.md +18 -0
  36. data/docs/recipes/hanami_router_integration.md +25 -0
  37. data/docs/recipes/using_all_restful_methods.md +25 -0
  38. data/docs/using_rack_middlewares/composing_middlewares.md +26 -0
  39. data/docs/using_rack_middlewares/injecting_middlewares.md +47 -0
  40. data/docs/using_rack_middlewares.md +22 -0
  41. data/lib/web_pipe/app.rb +4 -2
  42. data/lib/web_pipe/conn.rb +5 -3
  43. data/lib/web_pipe/conn_support/builder.rb +2 -0
  44. data/lib/web_pipe/conn_support/composition.rb +9 -7
  45. data/lib/web_pipe/conn_support/errors.rb +3 -1
  46. data/lib/web_pipe/conn_support/headers.rb +12 -10
  47. data/lib/web_pipe/conn_support/types.rb +11 -9
  48. data/lib/web_pipe/dsl/builder.rb +5 -3
  49. data/lib/web_pipe/dsl/class_context.rb +5 -3
  50. data/lib/web_pipe/dsl/dsl_context.rb +7 -5
  51. data/lib/web_pipe/dsl/instance_methods.rb +7 -5
  52. data/lib/web_pipe/extensions/container/container.rb +2 -0
  53. data/lib/web_pipe/extensions/cookies/cookies.rb +4 -3
  54. data/lib/web_pipe/extensions/dry_schema/dry_schema.rb +2 -0
  55. data/lib/web_pipe/extensions/dry_schema/plugs/sanitize_params.rb +4 -2
  56. data/lib/web_pipe/extensions/dry_view/dry_view.rb +13 -9
  57. data/lib/web_pipe/extensions/flash/flash.rb +7 -7
  58. data/lib/web_pipe/extensions/params/params/transf.rb +3 -1
  59. data/lib/web_pipe/extensions/params/params.rb +7 -5
  60. data/lib/web_pipe/extensions/redirect/redirect.rb +8 -6
  61. data/lib/web_pipe/extensions/router_params/router_params.rb +4 -2
  62. data/lib/web_pipe/extensions/session/session.rb +6 -4
  63. data/lib/web_pipe/extensions/url/url.rb +3 -1
  64. data/lib/web_pipe/plug.rb +7 -5
  65. data/lib/web_pipe/plugs.rb +7 -1
  66. data/lib/web_pipe/rack_support/app_with_middlewares.rb +3 -1
  67. data/lib/web_pipe/rack_support/middleware.rb +2 -0
  68. data/lib/web_pipe/rack_support/middleware_specification.rb +5 -3
  69. data/lib/web_pipe/types.rb +3 -1
  70. data/lib/web_pipe/version.rb +3 -1
  71. data/lib/web_pipe.rb +5 -3
  72. data/web_pipe.gemspec +34 -34
  73. metadata +82 -48
@@ -0,0 +1,73 @@
1
+ # Introduction
2
+
3
+ `web_pipe` is a rack application builder.
4
+
5
+ It means that with it and a rack router (like
6
+ [`hanami-router`](https://github.com/hanami/router),
7
+ [`http_router`](https://github.com/joshbuddy/http_router) or plain
8
+ [rack](https://github.com/rack/rack) routing methods you can build a complete
9
+ web application. However, the idea behind `web_pipe` is being a decoupled
10
+ component within a web framework. For this reason, it plays extremely well
11
+ with [dry-rb](https://dry-rb.org/) ecosystem. If it helps, you can think of it
12
+ as a decoupled web controller (as the C in MVC).
13
+
14
+ `web_pipe` applications are built as a [pipe of
15
+ operations](/docs/design_model.md) on an [immutable
16
+ struct](/docs/connection_struct.md). The struct is automatically created
17
+ with data from an HTTP request, and it contains methods to
18
+ incrementally add data to generate an HTTP response. The pipe can
19
+ be [halted](/docs/connection_struct/halting_the_pipe.md) at any moment,
20
+ taking away from all operations downstream any chance to modify the
21
+ response.
22
+
23
+ `web_pipe` has a modular design, with only the minimal functionalities needed
24
+ to build a web application enabled by default. However, it ships with several
25
+ [extensions](/docs/extensions.md) to make your life easier.
26
+
27
+ Following there is a simple example. It is a web application that will check
28
+ the value of a `user` parameter. When it is `Alice` or `Joe`, it will kindly
29
+ say hello. Otherwise, it will unauthorize:
30
+
31
+ > In order to try this example you can paste it to a file with name `config.ru`
32
+ and launch the rack command `rackup` within the same directory. The application
33
+ will be available in `http://localhost:9292`.
34
+
35
+ ```ruby
36
+ require 'web_pipe'
37
+
38
+ WebPipe.load_extensions(:params)
39
+
40
+ class HelloApp
41
+ include WebPipe
42
+
43
+ AUTHORIZED_USERS = %w[Alice Joe]
44
+
45
+ plug :html
46
+ plug :authorize
47
+ plug :greet
48
+
49
+ private
50
+
51
+ def html(conn)
52
+ conn.add_response_header('Content-Type', 'text/html')
53
+ end
54
+
55
+ def authorize(conn)
56
+ user = conn.params['user']
57
+ if AUTHORIZED_USERS.include?(user)
58
+ conn.add(:user, user)
59
+ else
60
+ conn.
61
+ set_status(401).
62
+ set_response_body('<h1>Not authorized</h1>').
63
+ halt
64
+ end
65
+ end
66
+
67
+ def greet(conn)
68
+ conn.set_response_body("<h1>Hello #{conn.fetch(:user)}</h1>")
69
+ end
70
+ end
71
+
72
+ run HelloApp.new
73
+ ``
@@ -0,0 +1,36 @@
1
+ # Composing operations
2
+
3
+ As we already have said, operations are functions taking a connection struct
4
+ and returning a connection struct. As a result, a composition of operations is
5
+ an operation in itself (as it also takes a connection struct and returns a
6
+ connection struct).
7
+
8
+ This can be leveraged to plug a whole `web_pipe` application as an operation
9
+ to another application. Doing so, you are plugging an operation which is the
10
+ composition of all operations for given application.
11
+
12
+ ```ruby
13
+ class HtmlApp
14
+ include WebPipe
15
+
16
+ plug :content_type
17
+ plug :default_status
18
+
19
+ private
20
+
21
+ def content_type(conn)
22
+ conn.add_response_header('Content-Type' => 'text/html')
23
+ end
24
+
25
+ def default_status(conn)
26
+ conn.set_status(404)
27
+ end
28
+ end
29
+
30
+ class MyApp
31
+ include WebPipe
32
+
33
+ plug :html, HtmlApp.new
34
+ # plug ...
35
+ end
36
+ ```
@@ -0,0 +1,32 @@
1
+ # Injecting operations
2
+
3
+ Operations can be injected at the moment an application is initialized,
4
+ which allows you to override what the definition declares.
5
+
6
+ To this effect, you must use `plugs:` keyword argument. It must be a hash where
7
+ operations are matched by the name you gave them in its definition.
8
+
9
+ This is mainly useful for testing purposes, where you can switch a heavy
10
+ operation and use another lighter one.
11
+
12
+ In the following example, the response body of the application will be
13
+ `'Hello from injection'`:
14
+
15
+ ```ruby
16
+ # config.ru
17
+ require 'web_pipe'
18
+
19
+ class MyApp
20
+ include WebPipe
21
+
22
+ plug(:hello) do |conn|
23
+ conn.set_response_body('Hello from definition')
24
+ end
25
+ end
26
+
27
+ injection = lambda do |conn|
28
+ conn.set_response_body('Hello from injection')
29
+ end
30
+
31
+ run MyApp.new(plugs: { hello: injection })
32
+ ```
@@ -0,0 +1,71 @@
1
+ # Resolving operations
2
+
3
+ There are several ways you can specify how an operation is resolved.
4
+
5
+ ## Instance method
6
+
7
+ Operations can be plugged as methods (both public and private) in the
8
+ application class:
9
+
10
+ ```ruby
11
+ class MyApp
12
+ include WebPipe
13
+
14
+ plug :html
15
+
16
+ private
17
+
18
+ def html(conn)
19
+ conn.add_response_header('Content-Type' => 'text/html')
20
+ end
21
+ end
22
+ ```
23
+
24
+ ## `#call`
25
+
26
+ Operations can be plugged inline as anything responding to `#call`, like a
27
+ `Proc` or a `lambda`:
28
+
29
+ ```ruby
30
+ class MyApp
31
+ include WebPipe
32
+
33
+ plug :html, ->(conn) { conn.add_response_header('Content-Type' => 'text/html') }
34
+ end
35
+ ```
36
+
37
+ ## Block
38
+
39
+ In the same way that `#call`, operations can also be plugged inline as blocks:
40
+
41
+ ```ruby
42
+ class MyApp
43
+ include WebPipe
44
+
45
+ plug :html do |conn|
46
+ conn.add_response_header('Content-Type' => 'text/html')
47
+ end
48
+ end
49
+ ```
50
+
51
+ ## Container
52
+
53
+ Operations can be resolved from a dependency injection container.
54
+
55
+ A container is anything that responds to `#[]` (accepting `Symbol` or `String`
56
+ as argument) in order to resolve a dependency. It can be configured at the
57
+ moment `WebPipe` module is included:
58
+
59
+ ```ruby
60
+ MyContainer = Hash[
61
+ 'plugs.html' => lambda do |conn|
62
+ conn.add_response_header('Content-Type' => 'text/html')
63
+ end
64
+ ]
65
+
66
+ class MyApp
67
+ include WebPipe.(container: MyContainer)
68
+
69
+ plug :html, 'plugs.html'
70
+ end
71
+ ```
@@ -0,0 +1,21 @@
1
+ # Plugging operations
2
+
3
+ You can plug operations to your application with the DSL method `plug`. The
4
+ first argument it always takes is a symbol with the name you want
5
+ to give to the operation (which is needed to allow
6
+ [injection](/docs/plugging_operations/injecting_operations.md) on
7
+ initialization).
8
+
9
+ ```ruby
10
+ class MyApp
11
+ include WebPipe
12
+
13
+ plug :dummy_operation, ->(conn) { conn }
14
+ end
15
+ ```
16
+
17
+ Remember, an operation is just a function (in ruby, anything responding to
18
+ `#call`) that takes a struct with connection information and returns another
19
+ instance of it. First operation in the stack receives a struct which has been
20
+ automatically created with the request data. From then on, any operation can
21
+ add to it response data.
@@ -0,0 +1,18 @@
1
+ # Config
2
+
3
+ `Config` plug helps in the addition of configuration settings (`#config` hash
4
+ attribute) to an instance of `WebPipe::Conn`.
5
+
6
+ ```ruby
7
+ require 'web_pipe'
8
+ require 'web_pipe/plugs/config'
9
+
10
+ class MyApp
11
+ include WebPipe
12
+
13
+ plug :config, WebPipe::Plugs::Config.(
14
+ key1: :value1,
15
+ key2: :value2
16
+ )
17
+ end
18
+ ```
@@ -0,0 +1,16 @@
1
+ # ContentType
2
+
3
+ `ContentType` plug is just a helper to set `Content-Type` response header.
4
+
5
+ Example:
6
+
7
+ ```ruby
8
+ require 'web_pipe'
9
+ require 'web_pipe/plugs/content_type'
10
+
11
+ class MyApp
12
+ include WebPipe
13
+
14
+ plug :html, WebPipe::Plugs::ContentType.('text/html')
15
+ end
16
+ ```
data/docs/plugs.md ADDED
@@ -0,0 +1,13 @@
1
+ # Plugs
2
+
3
+ Some group of operations can be generalized as following same pattern. For
4
+ example, an operation setting `Content-Type` header to `text/html` is very
5
+ similar to another one setting same header to `application/json`. We name plugs
6
+ to this level of abstraction on top of operations: plugs are operation
7
+ builders. In other words, they are higher order functions which return
8
+ functions.
9
+
10
+ Being just functions, we take as convention that plugs respond to `#call` in
11
+ order to create an operation.
12
+
13
+ This library ships with some useful plugs.
@@ -0,0 +1,18 @@
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`](/docs/extensions/dry_view.md) or
8
+ [`:dry-schema`](/docs/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.
@@ -0,0 +1,25 @@
1
+ # hanami-router integration
2
+
3
+ A `web_pipe` application instance is a rack application.
4
+ Consequently, you can mount it with `hanami-router`'s' `to:`
5
+ option.
6
+
7
+ ```ruby
8
+ # config.ru
9
+ require 'hanami/router'
10
+ require 'web_pipe'
11
+
12
+ class MyApp
13
+ include WebPipe
14
+
15
+ plug :this, ->(conn) { conn.set_response_body('This') }
16
+ end
17
+
18
+ router = Hanami::Router.new do
19
+ get 'my_app', to: MyApp.new
20
+ end
21
+
22
+ run router
23
+ ```
24
+
25
+ In order to perform [string matching with variables](https://github.com/hanami/router#string-matching-with-variables) you just need to load [`:router_params` extension](/docs/extensions/router_params.md).
@@ -0,0 +1,25 @@
1
+ # Using all RESTful methods
2
+
3
+ As you probably know, a lot of browsers don't support some RESTful
4
+ methods like `PATCH` or `PUT`. [Rack's `MethodOverride`
5
+ middleware](https://github.com/rack/rack/blob/master/lib/rack/method_override.rb)
6
+ provides a workaround for this limitation, allowing to override
7
+ request method in rack's env if a magical `_method` parameter or
8
+ `HTTP_METHOD_OVERRIDE` request header is found.
9
+
10
+ You have to be aware that if you use this middleware within a
11
+ `web_pipe` application (through [`use` DSL
12
+ method](docs/using_rack_middlewares.md)) it will have no effect.
13
+ When your `web_pipe` application takes control of the request it
14
+ has already gone through the router, which is the one who should
15
+ read the request method set by rack.
16
+
17
+ The solution for this is very simple. Just use `MethodOverride` middleware before your router does its work. For example, in `config.ru`:
18
+
19
+ ```ruby
20
+ # config.ru
21
+
22
+ use Rack::MethodOverride
23
+
24
+ # Load your router and map to web_pipe applications
25
+ ```
@@ -0,0 +1,26 @@
1
+ # Composing middlewares
2
+
3
+ In a similar way that you compose plugged operations, you can also compose rack
4
+ middlewares from another application.
5
+
6
+ For that, you just need to `use` another application. When you do so, all the
7
+ middlewares for that application will be added to the stack in the same order
8
+ they had there.
9
+
10
+ ```ruby
11
+ class HtmlApp
12
+ include WebPipe
13
+
14
+ use :session, Rack::Session::Cookie, key: 'my_app.session', secret: 'long'
15
+ use :csrf, Rack::Csrf, raise: true
16
+ end
17
+
18
+ class MyApp
19
+ include WebPipe
20
+
21
+ use :html, HtmlApp.new
22
+ # use ...
23
+
24
+ # plug ...
25
+ end
26
+ ```
@@ -0,0 +1,47 @@
1
+ # Injecting middlewares
2
+
3
+ Middlewares can be injected at the moment an application is initialized,
4
+ allowing you to override what you have defined in the DSL.
5
+
6
+ For that purpose, you have to use `middlewares:` keyword argument. It must be a
7
+ hash where middlewares are matched by the name you gave them in its definition.
8
+
9
+ A middleware must be specified as an `Array`. First item must be a rack
10
+ middleware class. The rest of arguments (if any) should be any option it may
11
+ need.
12
+
13
+ This is mainly useful for testing purposes, where you can switch a heavy
14
+ middleware and use a mocked one instead.
15
+
16
+ In the following example, rack session mechanism is being mocked:
17
+
18
+ ```ruby
19
+ # config.ru
20
+ require 'web_pipe'
21
+ require 'rack/session/cookie'
22
+
23
+ class MyApp
24
+ include WebPipe
25
+
26
+ use :session, Rack::Session::Cookie, key: 'my_app.session', secret: 'long'
27
+
28
+ plug(:serialize_session) do |conn|
29
+ conn.set_response_body(conn.env['rack.session'].inspect)
30
+ end
31
+ end
32
+
33
+ class MockedSession
34
+ attr_reader :app, :key
35
+
36
+ def initialize(app, key)
37
+ @app = app
38
+ @key = key
39
+ end
40
+
41
+ def call(env)
42
+ env['rack.session'] = "Mocked for '#{key}' key"
43
+ end
44
+ end
45
+
46
+ run MyApp.new(middlewares: { session: [MockedSession, 'my_app_mocked'] })
47
+ ```
@@ -0,0 +1,22 @@
1
+ # Using rack middlewares
2
+
3
+ A one-way pipe like the one `web_pipe` implements can deal with any required
4
+ feature in a web application. However, usually it is convenient to be able to
5
+ use some well-known rack middleware so you don't have to reinvent the wheel.
6
+ Even if you can add them at the router layer, `web_pipe` allows you to
7
+ encapsulate them in your application definition.
8
+
9
+ In order to add rack middlewares to the stack, you have to use the DSL method
10
+ `use`. The first argument it takes is a `Symbol` with the name you want to
11
+ assign to it (which is needed to allow
12
+ [injection](/docs/using_rack_middlewares/injecting_middlewares.md) on
13
+ initialization). Then, it must follow the middleware class and any option it
14
+ may need:
15
+
16
+ ```ruby
17
+ class MyApp
18
+ include WebPipe
19
+
20
+ use :cookies, Rack::Session::Cookie, key: 'my_app.session', secret: 'long'
21
+ end
22
+ ```
data/lib/web_pipe/app.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'web_pipe/types'
2
4
  require 'web_pipe/conn'
3
5
  require 'web_pipe/conn_support/builder'
@@ -55,7 +57,7 @@ module WebPipe
55
57
  private
56
58
 
57
59
  def conn_from_env(env)
58
- ConnSupport::Builder.(env)
60
+ ConnSupport::Builder.call(env)
59
61
  end
60
62
 
61
63
  def apply_operations(conn)
@@ -66,4 +68,4 @@ module WebPipe
66
68
  conn.rack_response
67
69
  end
68
70
  end
69
- end
71
+ end
data/lib/web_pipe/conn.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/struct'
2
4
  require 'web_pipe/types'
3
5
  require 'web_pipe/conn_support/types'
@@ -315,7 +317,7 @@ module WebPipe
315
317
  def fetch(key, default = Types::Undefined)
316
318
  return bag.fetch(key, default) unless default == Types::Undefined
317
319
 
318
- bag.fetch(key) { raise ConnSupport::KeyNotFoundInBagError.new(key) }
320
+ bag.fetch(key) { raise ConnSupport::KeyNotFoundInBagError, key }
319
321
  end
320
322
 
321
323
  # Writes an item to the {#bag}.
@@ -343,7 +345,7 @@ module WebPipe
343
345
  def fetch_config(key, default = Types::Undefined)
344
346
  return config.fetch(key, default) unless default == Types::Undefined
345
347
 
346
- config.fetch(key) { raise ConnSupport::KeyNotFoundInConfigError.new(key) }
348
+ config.fetch(key) { raise ConnSupport::KeyNotFoundInConfigError, key }
347
349
  end
348
350
 
349
351
  # Writes an item to {#config}.
@@ -402,4 +404,4 @@ module WebPipe
402
404
  # cycle.
403
405
  class Halted < Conn; end
404
406
  end
405
- end
407
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rack'
2
4
  require 'web_pipe/conn'
3
5
  require 'web_pipe/conn_support/headers'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/monads/result'
2
4
  require 'web_pipe/types'
3
5
  require 'web_pipe/conn'
@@ -27,10 +29,10 @@ module WebPipe
27
29
  def initialize(returned)
28
30
  super(
29
31
  <<~eos
30
- An operation returned +#{returned.inspect}+. To be valid,
31
- an operation must return whether a
32
- WebPipe::Conn::Ongoing or a WebPipe::Conn::Halted.
33
- eos
32
+ An operation returned +#{returned.inspect}+. To be valid,
33
+ an operation must return whether a
34
+ WebPipe::Conn::Ongoing or a WebPipe::Conn::Halted.
35
+ eos
34
36
  )
35
37
  end
36
38
  end
@@ -66,14 +68,14 @@ module WebPipe
66
68
  end
67
69
 
68
70
  def apply_operation(conn, operation)
69
- result = operation.(conn)
71
+ result = operation.call(conn)
70
72
  case result
71
73
  when Conn::Ongoing
72
74
  Success(result)
73
75
  when Conn::Halted
74
76
  Failure(result)
75
77
  else
76
- raise InvalidOperationResult.new(result)
78
+ raise InvalidOperationResult, result
77
79
  end
78
80
  end
79
81
 
@@ -84,4 +86,4 @@ module WebPipe
84
86
  end
85
87
  end
86
88
  end
87
- end
89
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebPipe
2
4
  module ConnSupport
3
5
  # Error raised when trying to fetch an entry in {Conn#bag} for an
@@ -42,4 +44,4 @@ module WebPipe
42
44
  end
43
45
  end
44
46
  end
45
- end
47
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebPipe
2
4
  module ConnSupport
3
5
  # Helpers to work with headers and its rack's env representation.
@@ -12,7 +14,7 @@ module WebPipe
12
14
  #
13
15
  # Headers are all those pairs which key begins with `HTTP_` plus
14
16
  # those detailed in {HEADERS_AS_CGI}.
15
- #
17
+ #
16
18
  # @param env [Types::Env[]]
17
19
  #
18
20
  # @return [Types::Headers[]]
@@ -21,14 +23,14 @@ module WebPipe
21
23
  # @see .normalize_key
22
24
  def self.extract(env)
23
25
  Hash[
24
- env.
25
- select { |k, _v| k.start_with?('HTTP_') }.
26
- map { |k, v| pair(k[5 .. -1], v) }.
27
- concat(
28
- env.
29
- select { |k, _v| HEADERS_AS_CGI.include?(k) }.
30
- map { |k, v| pair(k, v) }
31
- )
26
+ env
27
+ .select { |k, _v| k.start_with?('HTTP_') }
28
+ .map { |k, v| pair(k[5..-1], v) }
29
+ .concat(
30
+ env
31
+ .select { |k, _v| HEADERS_AS_CGI.include?(k) }
32
+ .map { |k, v| pair(k, v) }
33
+ )
32
34
  ]
33
35
  end
34
36
 
@@ -103,4 +105,4 @@ module WebPipe
103
105
  end
104
106
  end
105
107
  end
106
- end
108
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/types'
2
4
  require 'rack/request'
3
5
 
@@ -25,18 +27,18 @@ module WebPipe
25
27
  QueryString = Strict::String
26
28
  RequestBody = Interface(:gets, :each, :read, :rewind)
27
29
 
28
- Status = Strict::Integer.
29
- default(200).
30
- constrained(gteq: 100, lteq: 599)
30
+ Status = Strict::Integer
31
+ .default(200)
32
+ .constrained(gteq: 100, lteq: 599)
31
33
  ResponseBody = Interface(:each).default { [''] }
32
34
 
33
- Headers = Strict::Hash.
34
- map(Strict::String, Strict::String).
35
- default { {} }
35
+ Headers = Strict::Hash
36
+ .map(Strict::String, Strict::String)
37
+ .default { {} }
36
38
 
37
- Bag = Strict::Hash.
38
- map(Strict::Symbol, Strict::Any).
39
- default { {} }
39
+ Bag = Strict::Hash
40
+ .map(Strict::Symbol, Strict::Any)
41
+ .default { {} }
40
42
  end
41
43
  end
42
44
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'web_pipe/types'
2
4
  require 'web_pipe/dsl/class_context'
3
5
  require 'web_pipe/dsl/instance_methods'
@@ -12,7 +14,7 @@ module WebPipe
12
14
  class Builder < Module
13
15
  # Container with nothing registered.
14
16
  EMPTY_CONTAINER = Types::EMPTY_HASH
15
-
17
+
16
18
  # @!attribute [r] container
17
19
  # @return [Types::Container[]]
18
20
  attr_reader :container
@@ -24,11 +26,11 @@ module WebPipe
24
26
  @container = Types::Container[container]
25
27
  @class_context = ClassContext.new(container: container)
26
28
  end
27
-
29
+
28
30
  def included(klass)
29
31
  klass.extend(class_context)
30
32
  klass.include(InstanceMethods)
31
33
  end
32
34
  end
33
35
  end
34
- end
36
+ end