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
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'