web_pipe 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 17cb26c4876d3063751dd001c823d57f3ada911be264407078b76bd8cfc684b5
4
- data.tar.gz: 251591e61a0f30661a09ca507f28231e418fa9a626856613c8e171a67a107f37
3
+ metadata.gz: da7aa2093465c5b9b0b2fa4653f28580657989498aff26dfe9e52c3241b7efb9
4
+ data.tar.gz: 80562491db7789419a49030d2ab239330b98ad40310e428806dfed8f0381259e
5
5
  SHA512:
6
- metadata.gz: 8ae7586e3ed9a3969d540609bad29257f0d7c5eb06c244ad954e7a10cce44507ce5b247a7f7a18ece6d3713969108e8c172aac85442f01d41824bd477270bbe1
7
- data.tar.gz: d3a4900f7daf79377aaf7dd9ad3df397b5b55d16eb53d1ac025a029f9feb28e392819b969f9a64e5573216252db257f9e6f4ef359960c246b45321ed3708d6c7
6
+ metadata.gz: 2dad49f899b9c25a18fba6b8caebaa8898de0afab6ba124f3618d3080f1ccbdb4c98c2805298eea29d02ed3fdaef06cb0c29f228283e230832729884c533cb12
7
+ data.tar.gz: 3bf25d5a0c73b45263bd5ae3a8718f57412f5513da33313c9600163b17e116834dbff3ab55df26cfc61b06226727e2700849a77ee8f4daf45a9f7064d1f4058a
data/CHANGELOG.md CHANGED
@@ -1,200 +1,117 @@
1
1
  # Change Log
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
- The format is based on [Keep a Changelog](http://keepachangelog.com/)
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.5.0] - 2019-07-26
7
+ ## [0.6.0] - 2019-08-02
8
8
  ### Added
9
- - **BREAKING**: `container` is now an extension
10
- ([16](https://github.com/waiting-for-dev/web_pipe/pull/16)):
11
-
12
- It adds a `Conn#container` method, while the plug while being the same than before it has been moved to `web_pipe/extensions/container/plugs/container`.
13
-
14
- - Extension providing Integration with `dry-schema` [([18](https://github.com/waiting-for-dev/web_pipe/pull/18))]. See [`extensions/dry_schema.rb`](lib/web_pipe/extensions/dry_schema/dry_schema.rb).
9
+ - **BREAKING**. Rename `put` methods as `add`.
10
+ [[#26]](https://github.com/waiting-for-dev/web_pipe/pull/26).
15
11
 
16
- - No need to manually call `#to_proc` when composing plugs. This makes both of
17
- the following valid
18
- ([13](https://github.com/waiting-for-dev/web_pipe/pull/13)):
12
+ - **BREAKING**. Rename taint to halt, and clean/dirty to ongoing/halted.
13
+ [[#25](https://github.com/waiting-for-dev/web_pipe/pull/25)].
19
14
 
20
- ```ruby
21
- plug :app, &App.new
22
- plug :app, App.new
23
- ```
15
+ - **BREAKING**. URL redundant methods need to be loaded from `:url` extension.
16
+ [[#24](https://github.com/waiting-for-dev/web_pipe/pull/24)].
24
17
 
25
- - Extension adding flash functionality to conn ([15](https://github.com/waiting-for-dev/web_pipe/pull/15)).
18
+ - Merge router params with GET and POST params.
19
+ [[#23](https://github.com/waiting-for-dev/web_pipe/pull/23)].
26
20
 
27
- For this extension to work,
28
- [`Rack::Flash`](https://github.com/treeder/rack-flash) and `Rack::Session`
29
- middlewares must be used:
21
+ - Extension integrating rack session.
22
+ [[#21](https://github.com/waiting-for-dev/web_pipe/pull/21)].
30
23
 
31
- ```ruby
32
- require 'rack-flash'
33
- require 'rack/session/cookie'
24
+ - Extension to add/delete cookies.
25
+ [[#20](https://github.com/waiting-for-dev/web_pipe/pull/20)] &
26
+ [[#22](https://github.com/waiting-for-dev/web_pipe/pull/22)].
34
27
 
35
- class App
36
- include WebPipe
37
-
38
- use :session, Rack::Session::Cookie, secret: 'secret'
39
- use :flash, Rack::Flash
40
-
41
- plug :put_in_flash, ->(conn) { conn.put_flash(:error, 'Error') }
42
- plug :put_in_flash_now, ->(conn) { conn.put_flash_now(:error_now, 'Error now') }
43
- end
44
- ```
28
+ - Extension to easily create HTTP redirects.
29
+ [[#19](https://github.com/waiting-for-dev/web_pipe/pull/19)].
45
30
 
46
- Usually you will expose `conn.flash` to your views.
31
+ - Added `Conn#set_response_headers` method.
32
+ [[#27](https://github.com/waiting-for-dev/web_pipe/pull/27)].
47
33
 
48
- - Extension automatically require their associated plugs, so there is no need
49
- to require them manually anymore.
50
-
51
- ### Fixed
52
- - Fixed bug not allowing middlewares to modify responses initially set with
53
- default values ([14](https://github.com/waiting-for-dev/web_pipe/pull/14))
54
34
 
55
- ## [0.4.0] - 2019-07-17
35
+ ## [0.5.0] - 2019-07-26
56
36
  ### Added
57
- - **BREAKING**: Middlewares have to be named when used
58
- ([11](https://github.com/waiting-for-dev/web_pipe/pull/11)):
59
-
60
- ```ruby
61
- use :cookies, Rack::Session:Cookie, secret: 'my_secret', key: 'foo'
62
- ```
37
+ - **BREAKING**. `container` is now an extension.
38
+ [[#16](https://github.com/waiting-for-dev/web_pipe/pull/16)].
63
39
 
64
- - **BREAKING**: Middlewares have to be initialized when composed
65
- ([11](https://github.com/waiting-for-dev/web_pipe/pull/11)):
40
+ - Extension providing Integration with `dry-schema`.
41
+ [[#18](https://github.com/waiting-for-dev/web_pipe/pull/18)].
66
42
 
67
- ```ruby
68
- use :pipe, PipeWithMiddlewares.new
69
- ```
43
+ - No need to manually call `#to_proc` when composing plugs.
44
+ [[#13](https://github.com/waiting-for-dev/web_pipe/pull/13)].
70
45
 
71
- - **BREAKING**: The array of injected plugs is now scoped within a `plugs:`
72
- kwarg ([11](https://github.com/waiting-for-dev/web_pipe/pull/11)):
46
+ - Extension adding flash functionality to conn.
47
+ [[#15](https://github.com/waiting-for-dev/web_pipe/pull/15)].
73
48
 
74
- ```ruby
75
- App.new(plugs: { nothing: ->(conn) { conn } })
76
- ```
49
+ - Extensions automatically require their associated plugs, so there is no need
50
+ to require them manually anymore.
51
+ [[#17](https://github.com/waiting-for-dev/web_pipe/pull/17)].
77
52
 
78
- - Middlewares can be injected
79
- ([11](https://github.com/waiting-for-dev/web_pipe/pull/11)):
80
-
81
- ```ruby
82
- App.new(middlewares: { cache: [MyMiddleware, my_options] })
83
- ```
84
-
85
- - DSL helper method `compose` to add middlewares and plugs in order and in a
86
- single shot ([12](https://github.com/waiting-for-dev/web_pipe/pull/11)):
53
+ ### Fixed
54
+ - Fixed bug not allowing middlewares to modify responses initially set with
55
+ default values.
56
+ [[#14](https://github.com/waiting-for-dev/web_pipe/pull/14)].
87
57
 
88
- ```ruby
89
- class App
90
- include WebPipe.(container: Container)
91
58
 
92
- use :first, FirstMiddleware
59
+ ## [0.4.0] - 2019-07-17
60
+ ### Added
61
+ - **BREAKING**. Middlewares have to be named when used.
62
+ [[#11](https://github.com/waiting-for-dev/web_pipe/pull/11)].
93
63
 
94
- plug :first_plug, 'first_plug'
95
- end
64
+ - **BREAKING**. Middlewares have to be initialized when composed.
65
+ [[#11](https://github.com/waiting-for-dev/web_pipe/pull/11)].
96
66
 
97
- class AnotherApp
98
- include WebPipe.(container: Container)
67
+ - **BREAKING**. The array of injected plugs is now scoped within a `plugs:`
68
+ kwarg.
69
+ [[#11](https://github.com/waiting-for-dev/web_pipe/pull/11)].
99
70
 
100
- compose App
101
- # Equivalent to:
102
- # use App.new
103
- # plug &App.new
71
+ - Middlewares can be injected.
72
+ [[#11](https://github.com/waiting-for-dev/web_pipe/pull/11)].
104
73
 
105
- use :second, SecondMiddleware
74
+ - DSL helper method `compose` to add middlewares and plugs in order and in a
75
+ single shot-
76
+ [[#12](https://github.com/waiting-for-dev/web_pipe/pull/11)].
106
77
 
107
- plug :second_plug, 'second_plug'
108
- end
109
- ```
110
78
 
111
79
  ## [0.3.0] - 2019-07-12
112
80
  ### Added
113
- - **BREAKING**: When plugging with `plug:`, the operation is no longer
114
- specified through `with:`. Now it is just the second positional argument
115
- ([9](https://github.com/waiting-for-dev/web_pipe/pull/9)):
116
-
117
- ```ruby
118
- plug :from_container, 'container'
119
- plug :inline, ->(conn) { conn.set_response_body('Hello world') }
120
- ```
121
- - It is possible to plug a block
122
- ([9](https://github.com/waiting-for-dev/web_pipe/pull/9)):
123
- ```ruby
124
- plug(:content_type) { |conn| conn.add_response_header('Content-Type', 'text/html') }
125
- ```
81
+ - **BREAKING**. When plugging with `plug:`, the operation is no longer
82
+ specified through `with:`. Now it is just the second positional argument-
83
+ [[#9](https://github.com/waiting-for-dev/web_pipe/pull/9)].
126
84
 
127
- - WebPipe plug's can be composed. A WebPipe proc representation is the
128
- composition of all its operations, which is an operation itself
129
- ([9](https://github.com/waiting-for-dev/web_pipe/pull/9)):
130
-
131
- ```ruby
132
- class HtmlApp
133
- include WebPipe
134
-
135
- plug :content_type
136
- plug :default_status
137
-
138
- private
139
-
140
- def content_type(conn)
141
- conn.add_response_header('Content-Type', 'text/html')
142
- end
143
-
144
- def default_status(conn)
145
- conn.set_status(404)
146
- end
147
- end
148
-
149
- class App
150
- include WebPipe
151
-
152
- plug :html, &HtmlApp.new
153
- plug :body
85
+ - It is possible to plug a block-
86
+ [[#9](https://github.com/waiting-for-dev/web_pipe/pull/9)].
154
87
 
155
- private
156
-
157
- def body(conn)
158
- conn.set_response_body('Hello, world!')
159
- end
160
- end
161
- ```
162
-
163
- - WebPipe's middlewares can be composed into another WebPipe class, also
164
- through `:use` ([10](https://github.com/waiting-for-dev/web_pipe/pull/10)):
165
-
166
- ```ruby
167
- class HtmlApp
168
- include WebPipe
169
-
170
- use Rack::Session::Cookie, key: 'key', secret: 'top_secret'
171
- use Rack::MethodOverride
172
- end
88
+ - WebPipe plug's can be composed. A WebPipe proc representation is the
89
+ composition of all its operations, which is an operation itself-
90
+ [[#9](https://github.com/waiting-for-dev/web_pipe/pull/9)].
173
91
 
174
- class App
175
- include WebPipe
92
+ - WebPipe's middlewares can be composed into another WebPipe class-
93
+ [[#10](https://github.com/waiting-for-dev/web_pipe/pull/10)].
176
94
 
177
- use HtmlApp
178
- end
179
- ```
180
95
 
181
96
  ## [0.2.0] - 2019-07-05
182
97
  ### Added
183
- - dry-view integration
184
- ([#1](https://github.com/waiting-for-dev/web_pipe/pull/1),
185
- [#3](https://github.com/waiting-for-dev/web_pipe/pull/3),
186
- [#4](https://github.com/waiting-for-dev/web_pipe/pull/4),
187
- [#5](https://github.com/waiting-for-dev/web_pipe/pull/5) and
188
- [#6](https://github.com/waiting-for-dev/web_pipe/pull/6))
189
- - Configuring a container in `WebPipe::Conn`
190
- ([#2](https://github.com/waiting-for-dev/web_pipe/pull/2) and
191
- [#5](https://github.com/waiting-for-dev/web_pipe/pull/5))
192
- - Plug to set `Content-Type` response header
193
- ([#7](https://github.com/waiting-for-dev/web_pipe/pull/7))
98
+ - dry-view integration-
99
+ [[#1](https://github.com/waiting-for-dev/web_pipe/pull/1)],
100
+ [[#3](https://github.com/waiting-for-dev/web_pipe/pull/3)],
101
+ [[#4](https://github.com/waiting-for-dev/web_pipe/pull/4)],
102
+ [[#5](https://github.com/waiting-for-dev/web_pipe/pull/5)] &
103
+ [[#6](https://github.com/waiting-for-dev/web_pipe/pull/6)].
104
+
105
+ - Configuring a container in `WebPipe::Conn`-
106
+ [[#2](https://github.com/waiting-for-dev/web_pipe/pull/2)] &
107
+ [[#5](https://github.com/waiting-for-dev/web_pipe/pull/5)].
108
+
109
+ - Plug to set `Content-Type` response header-
110
+ [[#7](https://github.com/waiting-for-dev/web_pipe/pull/7)].
194
111
 
195
112
  ### Fixed
196
- - Fix key interpolation in `KeyNotFoundInBagError`
197
- ([#8](https://github.com/waiting-for-dev/web_pipe/pull/8))
113
+ - Fix key interpolation in `KeyNotFoundInBagError`-
114
+ [[#8](https://github.com/waiting-for-dev/web_pipe/pull/8)].
198
115
 
199
116
  ## [0.1.0] - 2019-05-07
200
117
  ### Added
data/README.md CHANGED
@@ -100,12 +100,12 @@ class GreetingAdminApp
100
100
  user = UsersRepo[conn.params['id'].to_i]
101
101
  if user
102
102
  conn.
103
- put(:user, user)
103
+ add(:user, user)
104
104
  else
105
105
  conn.
106
106
  set_status(404).
107
107
  set_response_body('<h1>Not foud</h1>').
108
- taint
108
+ halt
109
109
  end
110
110
  end
111
111
 
@@ -116,7 +116,7 @@ class GreetingAdminApp
116
116
  conn.
117
117
  set_status(401).
118
118
  set_response_body('<h1>Unauthorized</h1>').
119
- taint
119
+ halt
120
120
  end
121
121
  end
122
122
 
@@ -144,14 +144,14 @@ immutability and make method chaining possible.
144
144
  Each operation in the pipe must accept a single argument of a
145
145
  `WebPipe::Conn` instance and it must also return an instance of it.
146
146
  In fact, what the first operation in the pipe takes is a
147
- `WebPipe::Conn::Clean` subclass instance. When one of your operations
148
- calls `#taint` on it, a `WebPipe::Conn::Dirty` is returned and the pipe
149
- is halted. This one or the 'clean' instance that reaches the end of
147
+ `WebPipe::Conn::Ongoing` subclass instance. When one of your operations
148
+ calls `#halt` on it, a `WebPipe::Conn::Halted` is returned and the pipe
149
+ is halted. This one or the 'ongoing' instance that reaches the end of
150
150
  the pipe will be in command of the web response.
151
151
 
152
152
  Operations have the chance to prepare data to be consumed by
153
153
  downstream operations. Data can be added to the struct through
154
- `#put(key, value)`, while it can be consumed with `#fetch(key)`.
154
+ `#add(key, value)`, while it can be consumed with `#fetch(key)`.
155
155
 
156
156
  Attributes and methods in `WebPipe::Conn` are [fully
157
157
  documented](https://www.rubydoc.info/github/waiting-for-dev/web_pipe/master/WebPipe/Conn).
data/lib/web_pipe/app.rb CHANGED
@@ -18,8 +18,8 @@ module WebPipe
18
18
  # return it.
19
19
  #
20
20
  # {Conn} can itself be of two different types (subclasses of it}:
21
- # {Conn::Clean} and {Conn::Dirty}. The pipe is stopped
22
- # whenever the stack is emptied or a {Conn::Dirty} is
21
+ # {Conn::Ongoing} and {Conn::Halted}. The pipe is stopped
22
+ # whenever the stack is emptied or a {Conn::Halted} is
23
23
  # returned in any of the steps.
24
24
  class App
25
25
  # Type for a rack environment.
data/lib/web_pipe/conn.rb CHANGED
@@ -17,10 +17,10 @@ module WebPipe
17
17
  # calls.
18
18
  #
19
19
  # There are two subclasses (two types) for this:
20
- # {Conn::Clean} and {Conn::Dirty}. {ConnSupport::Builder} constructs
21
- # a {Conn::Clean} struct, while {#taint} copies the data to a
22
- # {Conn::Dirty} instance. The intention of this is to halt
23
- # operations on the web request/response cycle one a {Conn::Dirty}
20
+ # {Conn::Ongoing} and {Conn::Halted}. {ConnSupport::Builder} constructs
21
+ # a {Conn::Ongoing} struct, while {#halt} copies the data to a
22
+ # {Conn::Halted} instance. The intention of this is to halt
23
+ # operations on the web request/response cycle one a {Conn::Halted}
24
24
  # instance is detected.
25
25
  #
26
26
  # @example
@@ -28,7 +28,7 @@ module WebPipe
28
28
  # set_status(404).
29
29
  # add_response_header('Content-Type', 'text/plain').
30
30
  # set_response_body('Not found').
31
- # taint
31
+ # halt
32
32
  class Conn < Dry::Struct
33
33
  include ConnSupport::Types
34
34
 
@@ -210,71 +210,11 @@ module WebPipe
210
210
  # @return [Bag[]]
211
211
  attribute :bag, Bag
212
212
 
213
- # Base part of the URL.
214
- #
215
- # This is {#scheme} and {#host}, adding {#port} unless it is the
216
- # default one for the scheme.
217
- #
218
- # @return [BaseUrl]
219
- #
220
- # @example
221
- # 'https://example.org'
222
- # 'http://example.org:8000'
223
- def base_url
224
- request.base_url
225
- end
226
-
227
- # URL path.
228
- #
229
- # This is {#script_name} and {#path_info}.
230
- #
231
- # @return [Path]
232
- #
233
- # @example
234
- # 'index.rb/users'
235
- def path
236
- request.path
237
- end
238
-
239
- # URL full path.
240
- #
241
- # This is {#path} with {#query_string} if present.
242
- #
243
- # @return [FullPath]
244
- #
245
- # @example
246
- # '/users?id=1'
247
- def full_path
248
- request.fullpath
249
- end
250
-
251
- # Request URL.
252
- #
253
- # This is the same as {#base_url} plus {#full_path}.
254
- #
255
- # @return [Url]
256
- #
257
- # @example
258
- # 'http://www.example.org:8000/users?id=1'
259
- def url
260
- request.url
261
- end
262
-
263
- # GET and POST params merged in a hash.
264
- #
265
- # @return [Params]
266
- #
267
- # @example
268
- # { 'id' => 1, 'name' => 'Joe' }
269
- def params
270
- request.params
271
- end
272
-
273
213
  # Sets response status code.
274
214
  #
275
215
  # @param code [StatusCode]
276
216
  #
277
- # @return {Conn}
217
+ # @return [Conn]
278
218
  def set_status(code)
279
219
  new(
280
220
  status: code
@@ -290,7 +230,7 @@ module WebPipe
290
230
  #
291
231
  # @param content [#each, String]
292
232
  #
293
- # @return {Conn}
233
+ # @return [Conn]
294
234
  #
295
235
  # @see https://www.rubydoc.info/github/rack/rack/master/file/SPEC#label-The+Body
296
236
  def set_response_body(content)
@@ -299,6 +239,24 @@ module WebPipe
299
239
  )
300
240
  end
301
241
 
242
+ # Sets response headers.
243
+ #
244
+ # Substitues everything that was present as response headers by
245
+ # the new given hash.
246
+ #
247
+ # Headers keys are normalized.
248
+ #
249
+ # @param headers [Hash]
250
+ #
251
+ # @return [Conn]
252
+ #
253
+ # @see ConnSupport::Headers.normalize_key
254
+ def set_response_headers(headers)
255
+ new(
256
+ response_headers: ConnSupport::Headers.normalize(headers)
257
+ )
258
+ end
259
+
302
260
  # Adds given pair to response headers.
303
261
  #
304
262
  # `key` is normalized.
@@ -306,7 +264,7 @@ module WebPipe
306
264
  # @param key [String]
307
265
  # @param value [String]
308
266
  #
309
- # @return {Conn}
267
+ # @return [Conn]
310
268
  #
311
269
  # @see ConnSupport::Headers.normalize_key
312
270
  def add_response_header(key, value)
@@ -323,7 +281,7 @@ module WebPipe
323
281
  #
324
282
  # @param key [String]
325
283
  #
326
- # @return {Conn}
284
+ # @return [Conn]
327
285
  #
328
286
  # @see ConnSupport::Headers.normalize_key
329
287
  def delete_response_header(key)
@@ -356,7 +314,7 @@ module WebPipe
356
314
  # @param value [Object]
357
315
  #
358
316
  # @return [Conn]
359
- def put(key, value)
317
+ def add(key, value)
360
318
  new(
361
319
  bag: bag.merge(key => value)
362
320
  )
@@ -381,20 +339,27 @@ module WebPipe
381
339
  ]
382
340
  end
383
341
 
384
- # Copies all the data to a {Dirty} instance and
342
+ # Copies all the data to a {Halted} instance and
385
343
  # returns it.
386
344
  #
387
- # @return [Dirty]
388
- def taint
389
- Dirty.new(attributes)
345
+ # @return [Halted]
346
+ def halt
347
+ Halted.new(attributes)
348
+ end
349
+
350
+ # Returns whether the instance is {Halted}.
351
+ #
352
+ # @return [Bool]
353
+ def halted?
354
+ is_a?(Halted)
390
355
  end
391
356
 
392
357
  # Type of {Conn} representing an ongoing request/response
393
358
  # cycle.
394
- class Clean < Conn; end
359
+ class Ongoing < Conn; end
395
360
 
396
361
  # Type of {Conn} representing a halted request/response
397
362
  # cycle.
398
- class Dirty < Conn; end
363
+ class Halted < Conn; end
399
364
  end
400
365
  end
@@ -6,16 +6,16 @@ module WebPipe
6
6
  module ConnSupport
7
7
  # Helper module to build a {Conn} from a rack's env.
8
8
  #
9
- # It always return a {Conn::Clean} subclass.
9
+ # It always return a {Conn::Ongoing} subclass.
10
10
  #
11
11
  # @api private
12
12
  module Builder
13
13
  # @param env [Types::Env] Rack's env
14
14
  #
15
- # @return [Conn::Clean]
15
+ # @return [Conn::Ongoing]
16
16
  def self.call(env)
17
17
  rr = ::Rack::Request.new(env)
18
- Conn::Clean.new(
18
+ Conn::Ongoing.new(
19
19
  request: rr,
20
20
  env: env,
21
21
 
@@ -13,9 +13,9 @@ module WebPipe
13
13
  # take a {Conn} as argument and return a {Conn}.
14
14
  #
15
15
  # However, {Conn} can itself be of two different types (subclasses
16
- # of it): a {Conn::Clean} or a {Conn::Dirty}. On execution time,
16
+ # of it): a {Conn::Ongoing} or a {Conn::Halted}. On execution time,
17
17
  # the composition is stopped whenever the stack is emptied or a
18
- # {Conn::Dirty} is returned in any of the steps.
18
+ # {Conn::Halted} is returned in any of the steps.
19
19
  class Composition
20
20
  # Type for an operation.
21
21
  #
@@ -32,7 +32,7 @@ module WebPipe
32
32
  <<~eos
33
33
  An operation returned +#{returned.inspect}+. To be valid,
34
34
  an operation must return whether a
35
- WebPipe::Conn::Clean or a WebPipe::Conn::Dirty.
35
+ WebPipe::Conn::Ongoing or a WebPipe::Conn::Halted.
36
36
  eos
37
37
  )
38
38
  end
@@ -71,9 +71,9 @@ module WebPipe
71
71
  def apply_operation(conn, operation)
72
72
  result = operation.(conn)
73
73
  case result
74
- when Conn::Clean
74
+ when Conn::Ongoing
75
75
  Success(result)
76
- when Conn::Dirty
76
+ when Conn::Halted
77
77
  Failure(result)
78
78
  else
79
79
  raise InvalidOperationResult.new(result)
@@ -92,6 +92,13 @@ module WebPipe
92
92
  def self.normalize_key(key)
93
93
  key.downcase.gsub('_', '-').split('-').map(&:capitalize).join('-')
94
94
  end
95
+
96
+ # Returns a new hash with all keys normalized.
97
+ #
98
+ # @see #normalize_key
99
+ def self.normalize(headers)
100
+ headers.transform_keys(&method(:normalize_key))
101
+ end
95
102
  end
96
103
  end
97
104
  end
@@ -25,12 +25,6 @@ module WebPipe
25
25
  QueryString = Strict::String
26
26
  RequestBody = Interface(:gets, :each, :read, :rewind)
27
27
 
28
- BaseUrl = Strict::String
29
- Path = Strict::String
30
- FullPath = Strict::String
31
- Url = Strict::String
32
- Params = Strict::Hash
33
-
34
28
  Status = Strict::Integer.
35
29
  default(200).
36
30
  constrained(gteq: 100, lteq: 599)
@@ -19,12 +19,12 @@ module WebPipe
19
19
  # private
20
20
  #
21
21
  # def resolve(conn)
22
- # conn.put(:dependency, conn.fetch(:container)[:name])
22
+ # conn.add(:dependency, conn.fetch(:container)[:name])
23
23
  # end
24
24
  # end
25
25
  module Container
26
26
  def self.[](container)
27
- ->(conn) { conn.put(:container, Types::Container[container]) }
27
+ ->(conn) { conn.add(:container, Types::Container[container]) }
28
28
  end
29
29
  end
30
30
  end
@@ -0,0 +1,84 @@
1
+ require 'web_pipe'
2
+ require 'web_pipe/types'
3
+ require 'rack/utils'
4
+
5
+ module WebPipe
6
+ # Extension to help dealing with request and response cookies.
7
+ #
8
+ # This extension helps with the addition of the `Set-Cookie` header
9
+ # to the response, which is the way the server has to instruct the
10
+ # browser to keep a cookie. A cookie can be added with the
11
+ # {#add_cookie} method, while it can be marked for deletion with
12
+ # {#delete_cookie}. Remember that marking a cookie for deletion just
13
+ # means adding the same cookie name with an expiration time in the
14
+ # past.
15
+ #
16
+ # Besides, it also adds a {#request_cookies} method to get the
17
+ # cookies in the request.
18
+ #
19
+ # @example
20
+ # require 'web_pipe'
21
+ #
22
+ # WebPipe.load_extensions(:cookies)
23
+ #
24
+ # class SetCookie
25
+ # include WebPipe
26
+ #
27
+ # plug :set_cookie, ->(conn) { conn.set_cookie('foo', 'bar', path: '/') }
28
+ # end
29
+ #
30
+ # class DeleteCookie
31
+ # include WebPipe
32
+ #
33
+ # plug :delete_cookie, ->(conn) { conn.delete_cookie('foo', path: '/') }
34
+ # end
35
+ module Cookies
36
+ # Valid options for {#set_cookie}.
37
+ SET_COOKIE_OPTIONS = Types::Strict::Hash.schema(
38
+ domain?: Types::Strict::String.optional,
39
+ path?: Types::Strict::String.optional,
40
+ max_age?: Types::Strict::Integer.optional,
41
+ expires?: Types::Strict::Time.optional,
42
+ secure?: Types::Strict::Bool.optional,
43
+ http_only?: Types::Strict::Bool.optional,
44
+ same_site?: Types::Strict::Symbol.enum(:none, :lax, :strict).optional
45
+ )
46
+
47
+ # Valid options for {#delete_cookie}.
48
+ DELETE_COOKIE_OPTIONS = Types::Strict::Hash.schema(
49
+ domain?: Types::Strict::String.optional,
50
+ path?: Types::Strict::String.optional
51
+ )
52
+
53
+ # @return [Hash]
54
+ def request_cookies
55
+ request.cookies
56
+ end
57
+
58
+
59
+ # @param key [String]
60
+ # @param value [String]
61
+ # @param opts [SET_COOKIE_OPTIONS[]]
62
+ def set_cookie(key, value, opts = Types::EMPTY_HASH)
63
+ ::Rack::Utils.set_cookie_header!(
64
+ response_headers,
65
+ key,
66
+ { value: value }.merge(SET_COOKIE_OPTIONS[opts])
67
+ )
68
+ self
69
+ end
70
+
71
+ # @param key [String]
72
+ # @param opts [DELETE_COOKIE_OPTIONS[]]
73
+ def delete_cookie(key, opts = Types::EMPTY_HASH)
74
+ ::Rack::Utils.delete_cookie_header!(
75
+ response_headers,
76
+ key,
77
+ DELETE_COOKIE_OPTIONS[opts]
78
+ )
79
+ self
80
+ end
81
+ end
82
+
83
+ Conn.include(Cookies)
84
+ end
@@ -33,7 +33,7 @@ module WebPipe
33
33
  # end
34
34
  #
35
35
  # By default, when the result of applying the schema is a failure,
36
- # {Conn} is tainted with a 500 as status code. However, you can
36
+ # {Conn} is halted with a 500 as status code. However, you can
37
37
  # specify your own handler for the unhappy path. It will take the
38
38
  # {Conn} and {Dry::Schema::Result} instances as arguments:
39
39
  #
@@ -19,7 +19,7 @@ module WebPipe
19
19
  # @return [ConnSupport::Composition::Operation[]]
20
20
  def self.[](handler)
21
21
  lambda do |conn|
22
- conn.put(PARAM_SANITIZATION_HANDLER_KEY, Handler[handler])
22
+ conn.add(PARAM_SANITIZATION_HANDLER_KEY, Handler[handler])
23
23
  end
24
24
  end
25
25
  end
@@ -15,7 +15,7 @@ module WebPipe
15
15
  conn.
16
16
  set_status(500).
17
17
  set_response_body('Given params do not conform with the expected schema').
18
- taint
18
+ halt
19
19
  end
20
20
 
21
21
  # @param schema [Dry::Schema::Processor]
@@ -26,7 +26,7 @@ module WebPipe
26
26
  lambda do |conn|
27
27
  result = schema.(conn.params)
28
28
  if result.success?
29
- conn.put(DrySchema::SANITIZED_PARAMS_KEY, result.output)
29
+ conn.add(DrySchema::SANITIZED_PARAMS_KEY, result.output)
30
30
  else
31
31
  get_handler(conn, handler).(conn, result)
32
32
  end
@@ -3,7 +3,7 @@ require 'web_pipe/extensions/dry_view/dry_view'
3
3
 
4
4
  module WebPipe
5
5
  module Plugs
6
- # Calls object with conn and puts the result into bag's `:view_context`.
6
+ # Calls object with conn and add the result into bag's `:view_context`.
7
7
  #
8
8
  # This is meant to contain a Proc which will be called with the same
9
9
  # {WebPipe::Conn} instance of the operation. It must return
@@ -30,7 +30,7 @@ module WebPipe
30
30
  def self.[](view_context_proc)
31
31
  Types.Interface(:call)[view_context_proc]
32
32
  lambda do |conn|
33
- conn.put(Conn::VIEW_CONTEXT_KEY, view_context_proc.(conn))
33
+ conn.add(Conn::VIEW_CONTEXT_KEY, view_context_proc.(conn))
34
34
  end
35
35
  end
36
36
  end
@@ -19,8 +19,8 @@ module WebPipe
19
19
  # use :session, Rack::Session::Cookie, secret: 'secret'
20
20
  # use :flash, Rack::Flash
21
21
  #
22
- # plug :put_in_flash, ->(conn) { conn.put_flash(:notice, 'Hello world') }
23
- # plug :put_in_flash_now, ->(conn) { conn.put_flash_now(:notice_now, 'Hello world now') }
22
+ # plug :add_in_flash, ->(conn) { conn.add_flash(:notice, 'Hello world') }
23
+ # plug :add_in_flash_now, ->(conn) { conn.add_flash_now(:notice_now, 'Hello world now') }
24
24
  # end
25
25
  #
26
26
  # Usually, you will end up making `conn.flash` available to your view system:
@@ -47,26 +47,26 @@ module WebPipe
47
47
  def flash
48
48
  env.fetch(RACK_FLASH_KEY) do
49
49
  raise ConnSupport::MissingMiddlewareError.new(
50
- 'flash', 'Rack::Flash', 'rack-flash3'
50
+ 'flash', 'Rack::Flash', 'https://rubygems.org/gems/rack-flash3'
51
51
  )
52
52
  end
53
53
  end
54
54
 
55
- # Puts an item to the flash bag to be consumed by next request.
55
+ # Adds an item to the flash bag to be consumed by next request.
56
56
  #
57
57
  # @param key [String]
58
58
  # @param value [String]
59
- def put_flash(key, value)
59
+ def add_flash(key, value)
60
60
  flash[key] = value
61
61
  self
62
62
  end
63
63
 
64
- # Puts an item to the flash bag to be consumed by the same request
64
+ # Adds an item to the flash bag to be consumed by the same request
65
65
  # in process.
66
66
  #
67
67
  # @param key [String]
68
68
  # @param value [String]
69
- def put_flash_now(key, value)
69
+ def add_flash_now(key, value)
70
70
  flash.now[key] = value
71
71
  self
72
72
  end
@@ -0,0 +1,39 @@
1
+ require 'web_pipe/types'
2
+
3
+ module WebPipe
4
+ # Helper method to create redirect responses.
5
+ #
6
+ # This extensions adds a {#redirect} method to {Conn} which helps
7
+ # setting the `Location` header and the status code needed to
8
+ # instruct the browser to perform a redirect. By default, `302`
9
+ # status code is used.
10
+ #
11
+ # @example
12
+ # require 'web_pipe'
13
+ #
14
+ # WebPipe.load_extensions(:redirect)
15
+ #
16
+ # class MyApp
17
+ # include WebPipe
18
+ #
19
+ # plug(:redirect) do |conn|
20
+ # conn.redirect('/', 301)
21
+ # end
22
+ # end
23
+ module Redirect
24
+ # Location header
25
+ LOCATION_HEADER = 'Location'
26
+
27
+ # Valid type for a redirect status code
28
+ RedirectCode = Types::Strict::Integer.constrained(gteq: 300, lteq: 399)
29
+
30
+ # @param path [String]
31
+ # @param code [Integer]
32
+ def redirect(path, code = 302)
33
+ add_response_header(LOCATION_HEADER, path).
34
+ set_status(RedirectCode[code])
35
+ end
36
+ end
37
+
38
+ Conn.include(Redirect)
39
+ end
@@ -0,0 +1,86 @@
1
+ require 'web_pipe/conn'
2
+ require 'web_pipe/types'
3
+ require 'rack'
4
+
5
+ module WebPipe
6
+ # Wrapper around Rack::Session middlewares.
7
+ #
8
+ # This extension provides with helper methods to retrieve rack
9
+ # session and work with it while still being able to chain {Conn}
10
+ # method calls.
11
+ #
12
+ # It requires one of `Rack::Session` middlewares to be present.
13
+ #
14
+ # @example
15
+ # require 'web_pipe'
16
+ #
17
+ # WebPipe.load_extensions(:session)
18
+ #
19
+ # class MyApp
20
+ # include WebPipe
21
+ #
22
+ # use Rack::Cookie, secret: 'top_secret'
23
+ #
24
+ # plug :add_session, ->(conn) { conn.add_session('foo', 'bar') }
25
+ # plug :fetch_session, ->(conn) { conn.add(:foo, conn.fetch_session('foo')) }
26
+ # plug :delete_session, ->(conn) { conn.delete_session('foo') }
27
+ # plug :clear_session, ->(conn) { conn.clear_session }
28
+ # end
29
+ module Session
30
+ # Type for session keys.
31
+ SESSION_KEY = Types::Strict::String
32
+
33
+ # Returns Rack::Session's hash
34
+ #
35
+ # @return [Rack::Session::Abstract::SessionHash]
36
+ def session
37
+ env.fetch(::Rack::RACK_SESSION) do
38
+ raise ConnSupport::MissingMiddlewareError.new(
39
+ 'session', 'Rack::Session', 'https://www.rubydoc.info/github/rack/rack/Rack/Session'
40
+ )
41
+ end
42
+ end
43
+
44
+ # Fetches given key from the session.
45
+ #
46
+ # @param key [SESSION_KEY[]] Session key to fetch
47
+ # @param default [Any] Default value if key is not found
48
+ # @yieldreturn Default value if key is not found and default is not given
49
+ # @raise KeyError When key is not found and not default nor block are given
50
+ # @return [Any]
51
+ def fetch_session(*args, &block)
52
+ SESSION_KEY[args[0]]
53
+ session.fetch(*args, &block)
54
+ end
55
+
56
+
57
+ # Adds given key/value pair to the session.
58
+ #
59
+ # @param key [SESSION_KEY[]] Session key
60
+ # @param value [Any] Value
61
+ # @return [Conn]
62
+ def add_session(key, value)
63
+ session[SESSION_KEY[key]] = value
64
+ self
65
+ end
66
+
67
+ # Deletes given key form the session.
68
+ #
69
+ # @param key [SESSION_KEY[]] Session key
70
+ # @return [Conn]
71
+ def delete_session(key)
72
+ session.delete(SESSION_KEY[key])
73
+ self
74
+ end
75
+
76
+ # Deletes everything from the session.
77
+ #
78
+ # @return [Conn]
79
+ def clear_session
80
+ session.clear
81
+ self
82
+ end
83
+ end
84
+
85
+ Conn.include(Session)
86
+ end
@@ -0,0 +1,95 @@
1
+ module WebPipe
2
+ # Adds helper methods related to the request URL.
3
+ #
4
+ # This methods are in fact redundant with the information already
5
+ # present in {Conn} struct but, of course, they are very useful.
6
+ module Url
7
+ # Env's key used to retrieve params set by the router.
8
+ #
9
+ # @see #router_params
10
+ ROUTER_PARAMS_KEY = 'router.params'
11
+
12
+ # Base part of the URL.
13
+ #
14
+ # This is {#scheme} and {#host}, adding {#port} unless it is the
15
+ # default one for the scheme.
16
+ #
17
+ # @return [String]
18
+ #
19
+ # @example
20
+ # 'https://example.org'
21
+ # 'http://example.org:8000'
22
+ def base_url
23
+ request.base_url
24
+ end
25
+
26
+ # URL path.
27
+ #
28
+ # This is {#script_name} and {#path_info}.
29
+ #
30
+ # @return [String]
31
+ #
32
+ # @example
33
+ # 'index.rb/users'
34
+ def path
35
+ request.path
36
+ end
37
+
38
+ # URL full path.
39
+ #
40
+ # This is {#path} with {#query_string} if present.
41
+ #
42
+ # @return [String]
43
+ #
44
+ # @example
45
+ # '/users?id=1'
46
+ def full_path
47
+ request.fullpath
48
+ end
49
+
50
+ # Request URL.
51
+ #
52
+ # This is the same as {#base_url} plus {#full_path}.
53
+ #
54
+ # @return [String]
55
+ #
56
+ # @example
57
+ # 'http://www.example.org:8000/users?id=1'
58
+ def url
59
+ request.url
60
+ end
61
+
62
+ # *Params* in rack env's 'router.params' key.
63
+ #
64
+ # Routers used to map routes to applications build with
65
+ # {WebPipe} have the option to introduce extra params through
66
+ # setting env's 'router.params' key. These parameters will be
67
+ # merged with GET and POST ones when calling {#params}.
68
+ #
69
+ # This kind of functionality is usually implemented from the
70
+ # router side allowing the addition of variables in the route
71
+ # definition, e.g.:
72
+ #
73
+ # @example
74
+ # /user/:id/update
75
+ #
76
+ # @return [Hash]
77
+ def router_params
78
+ env.fetch(ROUTER_PARAMS_KEY, Types::EMPTY_HASH)
79
+ end
80
+
81
+ # GET, POST and {#router_params} merged in a hash.
82
+ #
83
+ # @return [Params]
84
+ #
85
+ # @example
86
+ # { 'id' => '1', 'name' => 'Joe' }
87
+ #
88
+ # @return Hash
89
+ def params
90
+ request.params.merge(router_params)
91
+ end
92
+ end
93
+
94
+ Conn.include(Url)
95
+ end
@@ -1,3 +1,3 @@
1
1
  module WebPipe
2
- VERSION = "0.5.0"
2
+ VERSION = "0.6.0"
3
3
  end
data/lib/web_pipe.rb CHANGED
@@ -16,6 +16,10 @@ module WebPipe
16
16
  DSL::Builder.new(*args)
17
17
  end
18
18
 
19
+ register_extension :cookies do
20
+ require 'web_pipe/extensions/cookies/cookies'
21
+ end
22
+
19
23
  register_extension :dry_schema do
20
24
  require 'web_pipe/extensions/dry_schema/dry_schema'
21
25
  require 'web_pipe/extensions/dry_schema/plugs/sanitize_params'
@@ -35,4 +39,16 @@ module WebPipe
35
39
  register_extension :flash do
36
40
  require 'web_pipe/extensions/flash/flash'
37
41
  end
42
+
43
+ register_extension :redirect do
44
+ require 'web_pipe/extensions/redirect/redirect'
45
+ end
46
+
47
+ register_extension :session do
48
+ require 'web_pipe/extensions/session/session'
49
+ end
50
+
51
+ register_extension :url do
52
+ require 'web_pipe/extensions/url/url'
53
+ end
38
54
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: web_pipe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marc Busqué
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-07-26 00:00:00.000000000 Z
11
+ date: 2019-08-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -244,12 +244,16 @@ files:
244
244
  - lib/web_pipe/dsl/instance_methods.rb
245
245
  - lib/web_pipe/extensions/container/container.rb
246
246
  - lib/web_pipe/extensions/container/plugs/container.rb
247
+ - lib/web_pipe/extensions/cookies/cookies.rb
247
248
  - lib/web_pipe/extensions/dry_schema/dry_schema.rb
248
249
  - lib/web_pipe/extensions/dry_schema/plugs/param_sanitization_handler.rb
249
250
  - lib/web_pipe/extensions/dry_schema/plugs/sanitize_params.rb
250
251
  - lib/web_pipe/extensions/dry_view/dry_view.rb
251
252
  - lib/web_pipe/extensions/dry_view/plugs/view_context.rb
252
253
  - lib/web_pipe/extensions/flash/flash.rb
254
+ - lib/web_pipe/extensions/redirect/redirect.rb
255
+ - lib/web_pipe/extensions/session/session.rb
256
+ - lib/web_pipe/extensions/url/url.rb
253
257
  - lib/web_pipe/plug.rb
254
258
  - lib/web_pipe/plugs.rb
255
259
  - lib/web_pipe/plugs/content_type.rb