web_pipe 0.13.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1a993e68cff01cb6b0ef493b6bdf3207e62a7baca650302c9f65024f3981c18a
4
- data.tar.gz: dc94f7dfabc97ad712a058f725e85831c38fe2658f42adeca3243b29f10273f9
3
+ metadata.gz: b0a90514a384a44456634dd195280291d82ab67eb336f69904c0cdc6bc3518ba
4
+ data.tar.gz: b2a3295f82715c9bf128d971994667eda13095631349b7cb33e1ccb97777b7e8
5
5
  SHA512:
6
- metadata.gz: 2e5925278ef21f20b3c9b8ae25f7bd614c7e17b278693f3521f018cefe1acd1ef63116aba61a9722bc1f4d5b98bfbeb56a6e03d0d246ac359aa595e4c451f6eb
7
- data.tar.gz: baf191023d9a19ed7facfc77f3107db45e2adb1949a25e4fc306b0a9f85e061e474fc557848beb469aaf0c5ad0446918b9c285b63cc5501bf21d31c19229878c
6
+ metadata.gz: b353968992c5d5f2d5952fe3ae55c1a2691e8c852e8dd72525b4fcbb6e35e5fe0741016cc362e1afcdfe217594bdc43adc182c46e752989006fe8a5cc6a694af
7
+ data.tar.gz: c5d206d3058b7bd83dc3b0634c97d77e0e21bfc1468e6745708e7eaffd8aef1d4c7467a49894de8161d2af1bfd212ce647a7858f61875ed3eabd784e4ed7a101
data/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.7.2
2
+ TargetRubyVersion: 3.0
3
3
  NewCops: enable
4
4
  SuggestExtensions: false
5
5
  Exclude:
@@ -13,3 +13,6 @@ Metrics/BlockLength:
13
13
 
14
14
  Naming/AccessorMethodName:
15
15
  Enabled: false
16
+
17
+ Style/HashConversion:
18
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -4,6 +4,35 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/).
6
6
 
7
+ ## [0.16.0] - 2021-11-07
8
+ ### Added
9
+ - Extract the DSL as an optional convenience layer and introduce
10
+ `WebPipe::Pipe` as top abstraction.
11
+ [#47](https://github.com/waiting-for-dev/web_pipe/pull/47)
12
+ - Be able to plug anything responding to `#to_proc`.
13
+ [#47](https://github.com/waiting-for-dev/web_pipe/pull/47)
14
+ - Be able to use anything responding to `#to_middlewares`.
15
+ [#47](https://github.com/waiting-for-dev/web_pipe/pull/47)
16
+
17
+ ## [0.15.1] - 2021-09-19
18
+ ### Added
19
+ - `:not_found` extension
20
+ [#46](https://github.com/waiting-for-dev/web_pipe/pull/46)
21
+
22
+ ## [0.15.0] - 2021-09-12
23
+ ### Added
24
+ - **BREAKING**. Switch `dry_view` extension with `hanami_view`.
25
+ [#45](https://github.com/waiting-for-dev/web_pipe/pull/45)
26
+
27
+ ## [0.14.0] - 2021-04-14
28
+ ### Added
29
+ - Inspecting operations
30
+ [#42](https://github.com/waiting-for-dev/web_pipe/pull/42)
31
+ - Inspecting middlewares
32
+ [#43](https://github.com/waiting-for-dev/web_pipe/pull/43)
33
+ - Testing support
34
+ [#44](https://github.com/waiting-for-dev/web_pipe/pull/44)
35
+
7
36
  ## [0.13.0] - 2021-01-15
8
37
  ### Added
9
38
  - **BREAKING**. Ruby 2.5 deprecated.
data/Gemfile CHANGED
@@ -7,7 +7,7 @@ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
7
7
  # Specify your gem's dependencies in web_pipe.gemspec
8
8
  gemspec
9
9
 
10
- # TODO: Remove when dry-rb 0.8 is released (ruby 3.0 support)
11
10
  group :development do
12
- gem 'dry-view', github: 'dry-rb/dry-view', ref: 'a048e32'
11
+ # TODO: Move to gemspec when hanami-view 2.0 is available
12
+ gem 'hanami-view', github: 'hanami/view', tag: 'v2.0.0.alpha2'
13
13
  end
data/README.md CHANGED
@@ -3,15 +3,18 @@
3
3
 
4
4
  # WebPipe
5
5
 
6
- `web_pipe` is a modular rack application builder through a pipe of
7
- operations on an immutable struct.
6
+ `web_pipe` is a builder of composable rack applications through a pipe of
7
+ functions on an immutable struct.
8
8
 
9
- In order to use in conjunction with [dry-rb](https://dry-rb.org/)
10
- ecosystem, see also
11
- [`dry-web-web_pipe`](https://github.com/waiting-for-dev/dry-web-web_pipe).
9
+ > `web_pipe` plays incredibly well with `hanami 2`. If you want to create a
10
+ > `hanami 2` app with `web_pipe`, you can take inspiration from this sample todo
11
+ > application:
12
+ >
13
+ > https://github.com/waiting-for-dev/hanami_2_web_pipe_todo_app
12
14
 
13
- If you want to use it with a Rails project, don't miss docs for the [rails
14
- extension](docs/extensions/rails.md).
15
+ To use in conjunction with [hanami](https://hanamirb.org/) [dry-rb](https://dry-rb.org/) ecosystem,
16
+ see also
17
+ [`dry-web-web_pipe`](https://github.com/waiting-for-dev/dry-web-web_pipe).
15
18
 
16
19
  1. [Introduction](docs/introduction.md)
17
20
  1. [Design model](docs/design_model.md)
@@ -20,9 +23,11 @@ extension](docs/extensions/rails.md).
20
23
  1. [Resolving operations](docs/plugging_operations/resolving_operations.md)
21
24
  1. [Injecting operations](docs/plugging_operations/injecting_operations.md)
22
25
  1. [Composing operations](docs/plugging_operations/composing_operations.md)
26
+ 1. [Inspecting operations](docs/plugging_operations/inspecting_operations.md)
23
27
  1. [Using rack middlewares](docs/using_rack_middlewares.md)
24
28
  1. [Injecting middlewares](docs/using_rack_middlewares/injecting_middlewares.md)
25
29
  1. [Composing middlewares](docs/using_rack_middlewares/composing_middlewares.md)
30
+ 1. [Inspecting middlewares](docs/using_rack_middlewares/inspecting_middlewares.md)
26
31
  1. [Composing applications](docs/composing_applications.md)
27
32
  1. [Connection struct](docs/connection_struct.md)
28
33
  1. [Sharing data downstream](docs/connection_struct/sharing_data_downstream.md)
@@ -32,12 +37,14 @@ extension](docs/extensions/rails.md).
32
37
  1. [Plugs](docs/plugs.md)
33
38
  1. [Config](docs/plugs/config.md)
34
39
  1. [ContentType](docs/plugs/content_type.md)
40
+ 1. [Testing](docs/testing.md)
35
41
  1. [Extensions](docs/extensions.md)
36
42
  1. [Container](docs/extensions/container.md)
37
43
  1. [Cookies](docs/extensions/cookies.md)
38
44
  1. [Flash](docs/extensions/flash.md)
39
45
  1. [Dry Schema](docs/extensions/dry_schema.md)
40
- 1. [Dry View](docs/extensions/dry_view.md)
46
+ 1. [Hanami View](docs/extensions/hanami_view.md)
47
+ 1. [Not found](docs/extensions/not_found.md)
41
48
  1. [Params](docs/extensions/params.md)
42
49
  1. [Rails](docs/extensions/rails.md)
43
50
  1. [Redirect](docs/extensions/redirect.md)
@@ -45,7 +52,7 @@ extension](docs/extensions/rails.md).
45
52
  1. [Session](docs/extensions/session.md)
46
53
  1. [URL](docs/extensions/url.md)
47
54
  1. Recipes
48
- 1. [dry-rb integration](docs/recipes/dry_rb_integration.md)
55
+ 1. [hanami 2 & dry-rb integration](docs/recipes/hanami_2_and_dry_rb_integration.md)
49
56
  1. [hanami-router integration](docs/recipes/hanami_router_integration.md)
50
57
  1. [Using all RESTful methods](docs/recipes/using_all_restful_methods.md)
51
58
 
@@ -93,8 +100,8 @@ run HelloApp.new
93
100
  ## Current status
94
101
 
95
102
  `web_pipe` is in active development but ready to be used in any environment.
96
- Common needs are covered and while you can expect some API changes, they won't
97
- be very important and everything will be properly documented.
103
+ Everyday needs are covered, and while you can expect some API changes,
104
+ they won't be essential, and we'll document everything appropriately.
98
105
 
99
106
  ## Contributing
100
107
 
@@ -1,6 +1,6 @@
1
1
  # Building a rack application
2
2
 
3
- In order to build a rack application with `web_pipe` you have to include
3
+ To build a rack application with `web_pipe`, you have to include
4
4
  `WebPipe` module in a class:
5
5
 
6
6
  ```ruby
@@ -3,10 +3,10 @@
3
3
  Previously, we have seen how to [compose plugged
4
4
  operations](plugging_operations/composing_operations.md) and how to [compose
5
5
  rack middlewares](using_rack_middlewares/composing_middlewares.md). The logical
6
- next step is thinking about composing `web_pipe` applications, which is exactly
7
- the same as composing both operations and middlewares at the same time.
6
+ next step is composing `web_pipe` applications, which is the same as composing
7
+ operations and middlewares simultaneously.
8
8
 
9
- The DSL method `compose` does exactly that:
9
+ The DSL method `compose` does precisely that:
10
10
 
11
11
  ```ruby
12
12
  class HtmlApp
@@ -33,7 +33,7 @@ class MyApp
33
33
  include WebPipe
34
34
 
35
35
  compose :web, HtmlApp.new
36
- # It does exactly the same than:
36
+ # It does exactly the same as:
37
37
  # use :web, HtmlApp.new
38
38
  # plug :web, HtmlApp.new
39
39
 
@@ -1,13 +1,13 @@
1
1
  # Configuring the connection struct
2
2
 
3
3
  [Extensions](../extensions.md) add extra behaviour to the connection struct.
4
- Sometimes they need some user provided value to work properly or they may allow
5
- some tweak depending on user needs.
4
+ Sometimes they need some user-provided value to work properly or allow some
5
+ tweak depending on user needs.
6
6
 
7
7
  For this reason, you can add configuration data to a `WebPipe::Conn` instance
8
8
  so that extensions can fetch it. This shared place where extensions look for
9
- what they need is `#config` attribute, which is very similar to `#bag` except
10
- for its more private intention.
9
+ what they need is the `#config` attribute, which is very similar to `#bag`
10
+ except for its more private intention.
11
11
 
12
12
  In order to interact with `#config`, you can use the method `#add_config(key,
13
13
  value)` or [`Config` plug](../plugs/config.md).
@@ -1,36 +1,34 @@
1
1
  # Halting the pipe
2
2
 
3
- Each operation in a pipe takes a single `WebPipe::Conn` instance as argument
4
- and returns another (or same) instance of it. In this way, a series of
5
- operations on the connection struct is propagated until final response is sent
6
- to the client.
3
+ Each operation in a pipe takes a single `WebPipe::Conn` instance as an argument
4
+ and returns another (or the same) instance. A series of operations on the
5
+ connection struct is propagated until a final response is sent to the client.
7
6
 
8
7
  More often than not, you may need to conditionally stop the propagation of a
9
- pipe at a given operation. A lot of times the requirement to do something like
10
- that will be authorization policies. For example, you could fetch the user
11
- requesting a resource. In the case she was granted to perform required action
12
- you would go on. However, if she wasn't you would like to halt the connection
13
- and respond with a 4xx http status code.
8
+ pipe at a given operation. For example, you could fetch the user requesting a
9
+ resource. In the case they were granted to perform the required action, you
10
+ would go on. However, if they weren't, you would like to halt the connection
11
+ and respond with a 4xx HTTP status code.
14
12
 
15
- In order to stop the pipe, you simply have to call `#halt` on the connection
16
- struct.
13
+ To stop the pipe, you have to call `#halt` on the connection struct.
17
14
 
18
- At implementation level, we must admit that we've not been 100% accurate until
19
- now. We said that the first operation in the pipe recerived a `WebPipe::Conn`
20
- instance. That's true. However, it is more precise saying that it gets a
21
- `WebPipe::Conn::Ongoing` instance (`WebPipe::Conn::Ongoing` being a subclass of
15
+ At the implementation level, we must admit that we've not been 100% accurate
16
+ until now. We said that the first operation in the pipe received a
17
+ `WebPipe::Conn` instance. That's true. However, it is more precise to say that
18
+ it gets a `WebPipe::Conn::Ongoing` instance `WebPipe::Conn::Ongoing` being a
19
+ subclass of
22
20
  `WebPipe::Conn`).
23
21
 
24
22
  As long as an operation responds with a `WebPipe::Conn::Ongoing`
25
23
  instance, the propagation will go on. However, when an operation
26
24
  returns a `WebPipe::Conn::Halted` instance (another subclass of
27
25
  `WebPipe::Conn`) then any operation downstream will be ignored.
28
- Calling `#halt` simply copies all attributes to a `WebPipe::Conn::Halted`
26
+ Calling `#halt` copies all attributes to a `WebPipe::Conn::Halted`
29
27
  instance and returns it.
30
28
 
31
- This made-up example checks if the user in the request has an admin role. If
32
- she has, it returns solicited resource. Otherwise she is unauthorized and never
33
- gets the resource.
29
+ This made-up example checks if the user in the request has an admin role. In
30
+ that case, it returns the solicited resource. Otherwise, they're unauthorized,
31
+ and they never get it.
34
32
 
35
33
  ```ruby
36
34
  WebPipe.load_extensions(:params)
@@ -1,19 +1,20 @@
1
1
  # Sharing data downstream
2
2
 
3
- Usually you'll find the need to prepare some data in one operation with the
3
+ Usually, you'll find the need to prepare some data in one operation with the
4
4
  intention for it to be consumed by another downstream operation. The connection
5
- struct has a `#bag` attribute which is useful for this purpose.
5
+ struct has a `#bag` attribute which is helpful for this purpose.
6
6
 
7
- `WebPipe::Conn#bag` is a `Hash` with `Symbol` keys where values can
8
- be anything you need to share. To help with the process we have following methods:
7
+ `WebPipe::Conn#bag` is a `Hash` with `Symbol` keys where the values can be
8
+ anything you need to share. To help with the process, we have the following
9
+ methods:
9
10
 
10
11
  - `#add(key, value)`: Assigns a value to a key.
11
- - `#fetch(key)`, `#fetch(key, default)`: Retrieves value associated
12
- to given key. If it is not found, `default` is returned when
12
+ - `#fetch(key)`, `#fetch(key, default)`: Retrieves the value associated
13
+ to a given key. If it is not found, `default` is returned when
13
14
  provided.
14
15
 
15
- This is a simple example of a web application which reads a `name`
16
- parameter and normalizes it before using in the response body.
16
+ This is a simple example of a web application that reads a `name`
17
+ parameter and normalizes it before using it in the response body.
17
18
 
18
19
  ```ruby
19
20
  # config.ru
@@ -1,11 +1,11 @@
1
1
  # Connection struct
2
2
 
3
- First operation you plug in a `web_pipe` application receives an instance of
4
- `WebPipe::Conn` which has been automatically created.
3
+ The first operation you plug in a `web_pipe` application receives an instance of
4
+ `WebPipe::Conn` automatically created.
5
5
 
6
- This is just a struct data type which contains all the information from current
7
- web request. In this regard, you can think of it as a structured rack's env
8
- hash.
6
+ `WebPipe::Conn` is just a struct data type that contains all the information
7
+ from the current web request. In this regard, you can think of it as a
8
+ structured rack's env hash.
9
9
 
10
10
  Request related attributes of this struct are:
11
11
 
@@ -22,25 +22,27 @@ Request related attributes of this struct are:
22
22
  - `#env`: Rack's env hash.
23
23
  - `#request`: Rack::Request instance.
24
24
 
25
- Your operations must return another (or same) instance of the struct, which
26
- will be consumed by next operation downstream. The struct contains methods to
27
- add response data to it:
25
+ Your operations must return another (or the same) instance of the struct, which
26
+ will be consumed by the next operation downstream.
28
27
 
29
- - `#set_status(code)`: makes it accessible in `#status` attribute.
30
- - `#set_response_body(body)`: makes it accessible in `#response_body`
28
+ The struct contains methods to add the response data to it:
29
+
30
+ - `#set_status(code)`: makes it accessible in the `#status` attribute.
31
+ - `#set_response_body(body)`: makes it accessible in the `#response_body`
31
32
  attribute.
32
33
  - `#set_response_headers(headers)`: makes them accessible in
33
- `#response_headers` attribute. Besides, there are also
34
+ the `#response_headers` attribute. Besides, there are also
34
35
  `#add_response_header(key, value)` and `#delete_response_header(key)`
35
36
  methods.
36
37
 
37
- Response in last struct returned in the pipe will be what is sent to client.
38
+ The response in the last struct returned in the pipe will be what is sent to
39
+ client.
38
40
 
39
41
  Every attribute and method is [fully
40
42
  documented](https://www.rubydoc.info/github/waiting-for-dev/web_pipe/master/WebPipe/Conn)
41
- in code documentation.
43
+ in the code documentation.
42
44
 
43
- Here we have a contrived web application which just returns as response body
45
+ Here we have a contrived web application which returns as response body
44
46
  the request body it has received:
45
47
 
46
48
  ```ruby
@@ -67,16 +69,17 @@ end
67
69
  run DummyApp.new
68
70
  ```
69
71
 
70
- As you can see, default available features are the very minimal to read from a
71
- request and to write a response. However, you can pick from several
72
+ As you can see, by default, the available features are very minimal to read
73
+ from a request and to write a response. However, you can pick from several
72
74
  (extensions)[extensions.md] which will make your life much easier.
73
75
 
74
76
  Immutability is a core design principle in `web_pipe`. All methods in
75
- `WebPipe::Conn` which are used to add data to it (both in core behaviour and
76
- extensions) return a fresh new instance. It also makes possible chaining
77
+ `WebPipe::Conn`, which are used to add data to it (both in core behavior and
78
+ extensions), return a fresh new instance. It also makes possible chaining
77
79
  methods in a very readable way.
78
80
 
79
- You can use ruby 2.7 pattern matching on a `WebPipe::Conn` struct, as in:
81
+ If you're using ruby 2.7 or greater, you can pattern match on a `WebPipe::Conn`
82
+ struct, as in:
80
83
 
81
84
  ```ruby
82
85
  # GET http://example.org
data/docs/design_model.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Design model
2
2
 
3
- If you are familiar with rack you know that it models a two-way pipe. In it,
3
+ If you are familiar with rack, you know that it models a two-way pipe. In it,
4
4
  each middleware has the ability to:
5
5
 
6
6
  - During the outbound trip modifying the request as it heads to the actual
@@ -20,11 +20,12 @@ each middleware has the ability to:
20
20
 
21
21
  ```
22
22
 
23
- `web_pipe` follows a simpler but equally powerful model: a one-way pipe which
24
- is abstracted on top of rack. A struct that contains data from a web request is
25
- piped trough a stack of operations (functions). Each operation takes as
26
- argument an instance of the struct and returns also an instance of it.
27
- Response data can be added to the struct at any moment in the pipe.
23
+ `web_pipe` follows a simpler but equally powerful model: a one-way
24
+ pipe abstracted on top of rack. A struct that contains data from a
25
+ web request is piped through a stack of operations (functions). Each
26
+ operation takes as argument an instance of the struct and also
27
+ returns an instance of it. You can add response data to the struct at
28
+ any moment in the pipe.
28
29
 
29
30
  ```
30
31
 
@@ -35,9 +36,9 @@ Response data can be added to the struct at any moment in the pipe.
35
36
  ```
36
37
 
37
38
  Additionally, any operation in the stack can halt the propagation of the pipe,
38
- leaving downstream operations unexecuted. In this way, final response is the
39
- one contained in the struct at the moment the pipe was halted, or last one if
40
- the pipe wasn't halted.
39
+ leaving downstream operations unexecuted. In this way, the final
40
+ response is the one contained in the struct at the moment the pipe was
41
+ halted, or the last one if the pipe wasn't halted.
41
42
 
42
43
  As you may know, this is the same model used by Elixir's
43
44
  [`plug`](https://hexdocs.pm/plug/readme.html), from which `web_pipe` takes
@@ -1,26 +1,97 @@
1
1
  # DSL free usage
2
2
 
3
- DSL's (like the one in `web_pipe` with methods like `plug` or
4
- `use`) provide developers with a user friendly and ergonomic way to
5
- use a library. However, they usually come at expenses of increasing complexity
6
- in internal code (which sooner than later translates into some kind of issue).
3
+ DSL's (like the one in `web_pipe` with class methods like `plug` or
4
+ `use`) provide developers with a user-friendly way to
5
+ use a library. However, they usually come at the expense of increasing
6
+ complexity in internal code (which sooner than later translates into some
7
+ issue).
7
8
 
8
- `web_pipe` has tried to do an extra effort to minimize these problems. For this
9
- reason, DSL in this library is just a layer on top of an independent core
10
- functionality.
9
+ `web_pipe` has tried to make an extra effort to minimize these problems. For
10
+ this reason, the DSL in this library is just a layer providing convenience on
11
+ top of the independent core functionality.
11
12
 
12
- To use `web_pipe` without its DSL layer, you just need to initialize a
13
- `WebPipe::App` instance with an array of all the operations that otherwise
14
- you'd `plug`. That instance will be a rack application ready to be used.
13
+ The DSL methods delegate transparently to instances of `WebPipe::Pipe`, so you
14
+ can also work directly with them and forget about magic.
15
+
16
+ For instance, the following rack application written through the DSL:
15
17
 
16
18
  ```ruby
17
19
  # config.ru
18
- require 'web_pipe/app'
20
+ require 'web_pipe'
21
+
22
+ WebPipe.load_extensions(:params)
23
+
24
+ class HelloApp
25
+ include WebPipe
26
+
27
+ plug :fetch_name
28
+ plug :render
29
+
30
+ private
31
+
32
+ def fetch_name(conn)
33
+ conn.add(:name, conn.params['name'])
34
+ end
35
+
36
+ def render(conn)
37
+ conn.set_response_body("Hello, #{conn.fetch(:name)}!")
38
+ end
39
+ end
40
+
41
+ run HelloApp.new
42
+ ```
43
+
44
+ is exactly equivalent to:
45
+
46
+ ```ruby
47
+ # config.ru
48
+ require 'web_pipe'
49
+ require 'web_pipe/pipe'
50
+
51
+ WebPipe.load_extensions(:params)
52
+
53
+ app = WebPipe::Pipe.new
54
+ .plug(:fetch_name, ->(conn) { conn.add(:name, conn.params['name']) })
55
+ .plug(:render, ->(conn) { conn.set_response_body("Hello, #{conn.fetch(:name)}") })
56
+
57
+ run app
58
+ ```
59
+
60
+ As you see, the instance of `WebPipe::Pipe` is itself the rack application.
61
+
62
+ As with the DSL, plug operations can be resolved from a container given on
63
+ initialization.
64
+
65
+ ```ruby
66
+ container = {
67
+ fetch_name: ->(conn) { conn.add(:name, conn.params['name']) },
68
+ render: ->(conn) { conn.set_response_body("Hello, #{conn.fetch(:name)}") }
69
+ }
70
+
71
+ app = WebPipe::Pipe.new(container: container)
72
+ .plug(:fetch_name, :fetch_name)
73
+ .plug(:render, :render)
74
+
75
+ run app
76
+ ```
77
+
78
+ Likewise, you can provide a context object to resolve methods when only a name
79
+ is given on `#plug`:
80
+
81
+ ```ruby
82
+ class Context
83
+ def fetch_name(conn)
84
+ conn.add(:name, conn.params['name'])
85
+ end
19
86
 
20
- op_1 = ->(conn) { conn.set_status(200) }
21
- op_2 = ->(conn) { conn.set_response_body('Hello, World!') }
87
+ def render(conn)
88
+ conn.set_response_body("Hello, #{conn.fetch(:name)}")
89
+ end
90
+ end
22
91
 
23
- app = WebPipe::App.new([op_1, op_2])
92
+ app = WebPipe::Pipe.new(context: Context.new)
93
+ .plug(:fetch_name)
94
+ .plug(:render)
24
95
 
25
96
  run app
26
97
  ```
@@ -1,18 +1,17 @@
1
1
  # Container
2
2
 
3
- `:container` is a very simple extension which allows you to configure a
4
- dependency injection container to be accessible from a `WebPipe::Conn`
5
- instance.
3
+ `:container` is a simple extension that allows you to configure a dependency
4
+ injection container to be accessible from a `WebPipe::Conn` instance.
6
5
 
7
- The container to use must be configured under `:configuration` key. It will be
8
- accessible through the `#container` method.
6
+ The container to use must be configured under the `:container` config key. It
7
+ will be accessible through the `#container` method.
9
8
 
10
- You may be thinking why you should worry about configuring a container for a
9
+ You may be wondering why you should worry about configuring a container for a
11
10
  connection instance when you already have access to the container configured
12
- for an application (from where you can resolve plugged operations). The idea
13
- here is decoupling operations from application DSL. If at anytime in the future
14
- you decide to get rid off the DSL, the process will be straightforward if
15
- operations are using the container configured in a connection instance.
11
+ for an application (where you can resolve plugged operations). The idea is
12
+ decoupling operations from application DSL. If you decide to get rid of the DSL
13
+ at any time in the future, the process will be straightforward if operations
14
+ are using the container configured in a connection instance.
16
15
 
17
16
  ```ruby
18
17
  require 'web_pipe'
@@ -24,8 +24,10 @@ This extension adds following methods:
24
24
  - `same_site:` must be one of the symbols `:none`, `:lax` or `:strict`.
25
25
 
26
26
  - `#delete_cookie(key)` or `#delete_cookie(key, options)`: Instructs browser to
27
- delete a previously sent cookie. Deleting a cookie just means setting again
28
- the same key with an expiration time in the past.
27
+ delete a previously sent cookie.
28
+
29
+ Deleting a cookie just means setting again the same key with an expiration
30
+ time in the past.
29
31
 
30
32
  It accepts `domain:` and `path:` options (see above for a description of
31
33
  them).
@@ -1,20 +1,21 @@
1
1
  # Dry Schema
2
2
 
3
- Extension providing integration for a common
3
+ Extension providing integration for every day
4
4
  [`dry-schema`](https://dry-rb.org/gems/dry-schema/) workflow to validate
5
5
  parameters.
6
6
 
7
7
  A plug `WebPipe::Plugs::SanitizeParams` is added so that you can use it in your
8
8
  pipe of operations. It takes as arguments a `dry-schema` schema and a handler.
9
9
  On success, it makes output available at `WebPipe::Conn#sanitized_params`. On
10
- error, it calls given handler with the connection struct and validation result.
10
+ error, it calls the given handler with the connection struct and validation
11
+ result.
11
12
 
12
13
  This extension automatically loads [`:params` extension](params.md),
13
14
  as it takes `WebPipe::Conn#params` as input for the validation schema.
14
15
 
15
16
  Instead of providing an error handler as the second argument for the plug, you
16
- can configure it under `:param_sanitization_handler` key. In this way, it can
17
- be reused through composition by others applications.
17
+ can configure it under the `:param_sanitization_handler` key. In this way, it
18
+ can be reused through composition by other applications.
18
19
 
19
20
  ```ruby
20
21
  require 'db'
@@ -1,22 +1,20 @@
1
1
  # Flash
2
2
 
3
- This extension provides with typical flash messages functionality. Messages for
4
- users are stored in session in order to be consumed by another request after a
5
- redirect.
3
+ This extension provides the typical flash messages functionality. Messages for
4
+ users are stored in session to be consumed by another request after a redirect.
6
5
 
7
6
  This extension depends on
8
7
  [`Rack::Flash`](https://rubygems.org/gems/rack-flash3) (gem name is
9
8
  `rack-flash3`) and `Rack::Session` (shipped with rack) middlewares.
10
9
 
11
- `WebPipe::Conn#flash` contains the flash bag. In order to add a message to it,
12
- you can use `#add_flash(key, value)` method.
10
+ `WebPipe::Conn#flash` contains the flash bag. You can use the `#add_flash(key,
11
+ value)` method to add a message to it.
13
12
 
14
- There is also an `#add_flash_now(key, value)` method, which is used to add a
15
- message to the bag with the intention for it to be consumed in the current
16
- request. Be aware that it is in fact a coupling with the view layer.
17
- Something that has to be consumed in the current request should be just data
18
- given to the view layer, but it helps when it can treat both scenarios as flash
19
- messages.
13
+ There is also an `#add_flash_now(key, value)` method, which adds a message to
14
+ the bag to consume it in the current request. Be aware that it is, in fact,
15
+ coupling with the view layer. Something that has to be consumed in the current
16
+ request should be just data given to the view layer, but it helps when it can
17
+ treat both scenarios as flash messages.
20
18
 
21
19
  ```ruby
22
20
  require 'web_pipe'