web_pipe 0.6.1 → 0.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2e30728a57f73a570c6345efd53dc22d32006a3b6bd6eb666c15b3f079fd3f83
4
- data.tar.gz: e85225c017e8ee7c23a65b7d5cda617cabc403d052c2196087542fc56c3d3636
3
+ metadata.gz: ce3123c1c702c02eaab09f4cb56209b512499d913fddaa55a95307e779748e15
4
+ data.tar.gz: f8fdcce1e652e37b719e3a621b19f9762ec3a47b74ff39ab4695f30f5ea0722c
5
5
  SHA512:
6
- metadata.gz: 6b24b6829b5657403ce5ef161fc4c0fe265a091195fc0de5c878751aaf88041e169ad1628e448fbb6dd27412f3564b50e087cad782fab4c9ad39b6a0acbf4e18
7
- data.tar.gz: a60f0297742a97ea66a2cf0b8629319a05881921c2589b6c493ded751dd27bfb29e64284e1048cb39981ea756a575e5b955a7f8a3efd6965c19ba395c3534353
6
+ metadata.gz: 117619501c7d97297266b8ac7cd89a6a2440c1cca7a1791da00e2b2a1935e790e4cd0d1877ea9ec5c9208cc9bac6ed8e07b981b04708102d67ca2760d1ed95e6
7
+ data.tar.gz: '08a391660d75a830e5e9e0bda97b62a4b299f5f543a86959d5fe86c8dda823b11438640d253400ec8a742a009c2a312cdeeb6a95c7a4cb4af4711589e5075fdd'
@@ -4,6 +4,33 @@ 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.7.0] - 2019-08-27
8
+ ### Added
9
+ - **BREAKING**. `Conn#config` instead of `Conn#bag` for extension configuration.
10
+ [[#29]](https://github.com/waiting-for-dev/web_pipe/pull/29)
11
+
12
+ - **BREAKING**. `:params` extension extracted from `:url` extension.
13
+ [[#30]](https://github.com/waiting-for-dev/web_pipe/pull/30)
14
+
15
+ - **BREAKING**. Router params are extracted as a param transformation.
16
+ [[#30]](https://github.com/waiting-for-dev/web_pipe/pull/30)
17
+
18
+ - **BREAKING**. Plugs now respond to `.call` instead of `.[]`.
19
+ [[#31]](https://github.com/waiting-for-dev/web_pipe/pull/31)
20
+
21
+ - **BREAKING**. `:dry-schema` extension has not a default handler.
22
+ [[#32]](https://github.com/waiting-for-dev/web_pipe/pull/32)
23
+
24
+ - **BREAKING**. `:dry-schema` extension stores output in `#config`.
25
+ [[#32]](https://github.com/waiting-for-dev/web_pipe/pull/32)
26
+
27
+ - Integration with `transproc` gem to provide any number of params
28
+ transformations.
29
+ [[#30]](https://github.com/waiting-for-dev/web_pipe/pull/30)
30
+
31
+ - `:dry-schema` extension automatically loads `:params` extension.
32
+ [[#32]](https://github.com/waiting-for-dev/web_pipe/pull/32)
33
+
7
34
  ## [0.6.1] - 2019-08-02
8
35
  ### Fixed
9
36
  - Fixed support for ruby 2.4.
@@ -0,0 +1 @@
1
+ theme: jekyll-theme-slate
@@ -23,27 +23,32 @@ module WebPipe
23
23
  register_extension :dry_schema do
24
24
  require 'web_pipe/extensions/dry_schema/dry_schema'
25
25
  require 'web_pipe/extensions/dry_schema/plugs/sanitize_params'
26
- require 'web_pipe/extensions/dry_schema/plugs/param_sanitization_handler'
27
26
  end
28
27
 
29
28
  register_extension :dry_view do
30
29
  require 'web_pipe/extensions/dry_view/dry_view'
31
- require 'web_pipe/extensions/dry_view/plugs/view_context'
32
30
  end
33
31
 
34
32
  register_extension :container do
35
33
  require 'web_pipe/extensions/container/container'
36
- require 'web_pipe/extensions/container/plugs/container'
37
34
  end
38
35
 
39
36
  register_extension :flash do
40
37
  require 'web_pipe/extensions/flash/flash'
41
38
  end
42
39
 
40
+ register_extension :router_params do
41
+ require 'web_pipe/extensions/router_params/router_params'
42
+ end
43
+
43
44
  register_extension :redirect do
44
45
  require 'web_pipe/extensions/redirect/redirect'
45
46
  end
46
47
 
48
+ register_extension :params do
49
+ require 'web_pipe/extensions/params/params'
50
+ end
51
+
47
52
  register_extension :session do
48
53
  require 'web_pipe/extensions/session/session'
49
54
  end
@@ -210,6 +210,18 @@ module WebPipe
210
210
  # @return [Bag[]]
211
211
  attribute :bag, Bag
212
212
 
213
+ # @!attribute [r] config
214
+ #
215
+ # Instance level configuration.
216
+ #
217
+ # It is a hash where anything can be stored. Keys must be symbols.
218
+ #
219
+ # The idea of it is for extensions to have somewhere to store user
220
+ # provided values they may need at some point.
221
+ #
222
+ # @return [Bag[]]
223
+ attribute :config, Bag
224
+
213
225
  # Sets response status code.
214
226
  #
215
227
  # @param code [StatusCode]
@@ -320,6 +332,34 @@ module WebPipe
320
332
  )
321
333
  end
322
334
 
335
+ # Reads an item from {#config}.
336
+ #
337
+ # @param key [Symbol]
338
+ #
339
+ # @return [Object]
340
+ #
341
+ # @raise ConnSupport::KeyNotFoundInConfigError when key is not
342
+ # present in {#config}.
343
+ def fetch_config(key, default = Types::Undefined)
344
+ return config.fetch(key, default) unless default == Types::Undefined
345
+
346
+ config.fetch(key) { raise ConnSupport::KeyNotFoundInConfigError.new(key) }
347
+ end
348
+
349
+ # Writes an item to {#config}.
350
+ #
351
+ # If it already exists, it is overwritten.
352
+ #
353
+ # @param key [Symbol]
354
+ # @param value [Object]
355
+ #
356
+ # @return [Conn]
357
+ def add_config(key, value)
358
+ new(
359
+ config: config.merge(key => value)
360
+ )
361
+ end
362
+
323
363
  # Builds response in the way rack expects.
324
364
  #
325
365
  # It is useful to finish a rack application built with a
@@ -1,9 +1,6 @@
1
1
  require 'dry/monads/result'
2
2
  require 'web_pipe/types'
3
3
  require 'web_pipe/conn'
4
- require 'dry/monads/result/extensions/either'
5
-
6
- Dry::Monads::Result.load_extensions(:either)
7
4
 
8
5
  module WebPipe
9
6
  module ConnSupport
@@ -1,7 +1,7 @@
1
1
  module WebPipe
2
2
  module ConnSupport
3
- # Error raised when trying to fetch an entry in {Conn}'s bag for
4
- # an unknown key.
3
+ # Error raised when trying to fetch an entry in {Conn#bag} for an
4
+ # unknown key.
5
5
  class KeyNotFoundInBagError < KeyError
6
6
  # @param key [Any] Key not found in the bag
7
7
  def initialize(key)
@@ -13,6 +13,19 @@ module WebPipe
13
13
  end
14
14
  end
15
15
 
16
+ # Error raised when trying to fetch an entry in {Conn#config} for
17
+ # an unknown key.
18
+ class KeyNotFoundInConfigError < KeyError
19
+ # @param key [Any] Key not found in config
20
+ def initialize(key)
21
+ super(
22
+ <<~eos
23
+ Config does not contain a key with name +#{key}+.
24
+ eos
25
+ )
26
+ end
27
+ end
28
+
16
29
  # Error raised when trying to use a conn's feature which requires
17
30
  # a rack middleware which is not present
18
31
  class MissingMiddlewareError < RuntimeError
@@ -1,10 +1,8 @@
1
1
  require 'web_pipe'
2
2
 
3
3
  module WebPipe
4
- # Extension adding a `#container` method to fetch bag's `:container`
5
- # key.
6
- #
7
- # Usually, the container is set with {WebPipe::Plugs::Container}.
4
+ # Extension adding a `#container` method which returns {Conn#config}
5
+ # `:container` key.
8
6
  #
9
7
  # @example
10
8
  # require 'web_pipe'
@@ -14,15 +12,15 @@ module WebPipe
14
12
  # class App
15
13
  # include WebPipe
16
14
  #
17
- # plug :container, WebPipe::Plugs::Container[MyContainer]
15
+ # plug :container, ->(conn) { conn.add_config(:container, MyContainer) }
18
16
  # plug :render, ->(conn) { conn.set_response_body(conn.container['view']) }
19
17
  # end
20
18
  module Container
21
- # Returns bag `:container` value
19
+ # Returns {Conn#config} `:container` value
22
20
  #
23
21
  # @return [Any]
24
22
  def container
25
- fetch(:container)
23
+ fetch_config(:container)
26
24
  end
27
25
  end
28
26
 
@@ -1,5 +1,7 @@
1
1
  require 'web_pipe'
2
2
 
3
+ WebPipe.load_extensions(:params)
4
+
3
5
  module WebPipe
4
6
  # Integration with `dry-schema` validation library.
5
7
  #
@@ -8,11 +10,12 @@ module WebPipe
8
10
  #
9
11
  # On its own, the library just provides with a
10
12
  # `Conn#sanitized_params` method, which will return what is set into
11
- # bag's `:sanitized_params` key.
13
+ # config's `:sanitized_params` key.
12
14
  #
13
- # This key in the bag is what will be populated by `SanitizeParams`
14
- # plug, which accepts a `dry-validation` schema that will be applied
15
- # to `Conn#params`:
15
+ # This key in config is what will be populated by `SanitizeParams` plug. It
16
+ # takes as arguments the `dry-schema` schema that will be applied to
17
+ # `Conn#params` and an error handler taking `Conn` instance and the validation
18
+ # result:
16
19
  #
17
20
  # @example
18
21
  # require 'web_pipe'
@@ -26,43 +29,32 @@ module WebPipe
26
29
  # required(:name).filled(:string)
27
30
  # end
28
31
  #
29
- # plug :sanitize_params, WebPipe::Plugs::SanitizeParams[Schema]
32
+ # plug :sanitize_params, WebPipe::Plugs::SanitizeParams.(
33
+ # Schema,
34
+ # ->(conn, result) { ... }
35
+ # )
30
36
  # plug(:do_something_with_params) do |conn|
31
37
  # DB.persist(:entity, conn.sanitized_params)
32
38
  # end
33
39
  # end
34
40
  #
35
- # By default, when the result of applying the schema is a failure,
36
- # {Conn} is halted with a 500 as status code. However, you can
37
- # specify your own handler for the unhappy path. It will take the
38
- # {Conn} and {Dry::Schema::Result} instances as arguments:
39
- #
40
- # @example
41
- # plug :sanitize_params, WebPipe::Plugs::SanitizeParams[
42
- # Schema,
43
- # ->(conn, result) { ... }
44
- # ]
45
- #
46
41
  # A common workflow is applying the same handler for all param
47
- # sanitization across your application. This can be achieved setting
48
- # a `:param_sanitization_handler` bag key in a upstream operation
49
- # which can be composed downstream for any number of
50
- # pipes. `SanitizeParams` will used configured handler if none is
51
- # injected as argument. Another plug `ParamSanitizationHandler`
52
- # exists to help with this process:
42
+ # sanitization across your application. This can be achieved configuring
43
+ # a `:param_sanitization_handler` in a upstream operation which can
44
+ # be composed downstream from any number of pipes. `SanitizeParams`
45
+ # will used configured handler if none is injected as
46
+ # argument.
53
47
  #
54
48
  # @example
55
49
  # class App
56
- # plug :sanitization_handler, WebPipe::Plugs::ParamSanitizationHandler[
57
- # ->(conn, result) { ... }
58
- # ]
50
+ # plug :sanitization_handler, ->(conn, result) { ... }
59
51
  # end
60
52
  #
61
53
  # class Subapp
62
54
  # Schema = Dry::Schema.Params { ... }
63
55
  #
64
56
  # plug :app, App.new
65
- # plug :sanitize_params, WebPipe::Plugs::SanitizeParams[Schema]
57
+ # plug :sanitize_params, WebPipe::Plugs::SanitizeParams.call(Schema)
66
58
  # end
67
59
  #
68
60
  # @see https://dry-rb.org/gems/dry-schema/
@@ -70,9 +62,9 @@ module WebPipe
70
62
  SANITIZED_PARAMS_KEY = :sanitized_params
71
63
 
72
64
  def sanitized_params
73
- fetch(SANITIZED_PARAMS_KEY)
65
+ fetch_config(SANITIZED_PARAMS_KEY)
74
66
  end
75
67
  end
76
68
 
77
69
  Conn.include(DrySchema)
78
- end
70
+ end
@@ -1,6 +1,5 @@
1
1
  require 'web_pipe/types'
2
2
  require 'web_pipe/extensions/dry_schema/dry_schema'
3
- require 'web_pipe/extensions/dry_schema/plugs/param_sanitization_handler'
4
3
 
5
4
  module WebPipe
6
5
  module Plugs
@@ -8,25 +7,20 @@ module WebPipe
8
7
  #
9
8
  # @see WebPipe::DrySchema
10
9
  module SanitizeParams
11
- # Default handler if none is configured nor injected.
10
+ # {Conn#config} key to store the handler.
12
11
  #
13
- # @return [ParamSanitizationHandler::Handler[]]
14
- DEFAULT_HANDLER = lambda do |conn, _result|
15
- conn.
16
- set_status(500).
17
- set_response_body('Given params do not conform with the expected schema').
18
- halt
19
- end
12
+ # @return [Symbol]
13
+ PARAM_SANITIZATION_HANDLER_KEY = :param_sanitization_handler
20
14
 
21
15
  # @param schema [Dry::Schema::Processor]
22
16
  # @param handler [ParamSanitizationHandler::Handler[]]
23
17
  #
24
18
  # @return [ConnSupport::Composition::Operation[], Types::Undefined]
25
- def self.[](schema, handler = Types::Undefined)
19
+ def self.call(schema, handler = Types::Undefined)
26
20
  lambda do |conn|
27
21
  result = schema.(conn.params)
28
22
  if result.success?
29
- conn.add(DrySchema::SANITIZED_PARAMS_KEY, result.output)
23
+ conn.add_config(DrySchema::SANITIZED_PARAMS_KEY, result.output)
30
24
  else
31
25
  get_handler(conn, handler).(conn, result)
32
26
  end
@@ -36,11 +30,9 @@ module WebPipe
36
30
  def self.get_handler(conn, handler)
37
31
  return handler unless handler == Types::Undefined
38
32
 
39
- conn.fetch(
40
- Plugs::ParamSanitizationHandler::PARAM_SANITIZATION_HANDLER_KEY, DEFAULT_HANDLER
41
- )
33
+ conn.fetch_config(PARAM_SANITIZATION_HANDLER_KEY)
42
34
  end
43
35
  private_class_method :get_handler
44
36
  end
45
37
  end
46
- end
38
+ end
@@ -28,9 +28,8 @@ module WebPipe
28
28
  # end
29
29
  # end
30
30
  #
31
- # If {WebPipe::Conn#bag} has a `:container` key, the view instance
32
- # can be resolved from it. {WebPipe::Container} extension can be
33
- # used to streamline this integration.
31
+ # If there is a `:container` configured (in {Conn#config}), the view
32
+ # instance can be resolved from it.
34
33
  #
35
34
  # @example
36
35
  # WebPipe.load_extensions(:dry_view, :container)
@@ -40,7 +39,7 @@ module WebPipe
40
39
  #
41
40
  # Container = { 'views.say_hello' => SayHelloView.new }.freeze
42
41
  #
43
- # plug :container, WebPipe::Plugs::Container[Container]
42
+ # plug :config_container, ->(conn) { conn.add_config(:container, Container[Container]) }
44
43
  # plug :render
45
44
  #
46
45
  # def render(conn)
@@ -52,9 +51,11 @@ module WebPipe
52
51
  # through the `context:` argument, as in a standard call to
53
52
  # {Dry::View#call}. However, it is possible to leverage configured
54
53
  # default context while still being able to inject request specific
55
- # context. For that to work, a key `:view_context` should be present
56
- # in {WebPipe::Conn#bag}. It must be equal to a hash which will be
57
- # passed to {Dry::View::Context#with} to create the final context:
54
+ # context. For that to work, `:view_context` should be present in
55
+ # {WebPipe::Conn#config}. Its value must be a lambda accepting the
56
+ # {Conn} instance and returning a hash, which will be passed to
57
+ # {Dry::View::Context#with} to create the final context at the
58
+ # moment {#view} is called.
58
59
  #
59
60
  # @example
60
61
  # class MyContext < Dry::View::Context
@@ -77,11 +78,11 @@ module WebPipe
77
78
  # class App
78
79
  # include WebPipe
79
80
  #
80
- # plug :set_view_context
81
+ # plug :config_view_context
81
82
  # plug :render
82
83
  #
83
- # def set_view_context(conn)
84
- # conn.put(:view_context, { current_path: conn.full_path })
84
+ # def config_view_context(conn)
85
+ # conn.add_config(:view_context, ->(conn) { { current_path: conn.full_path } })
85
86
  # end
86
87
  #
87
88
  # def render(conn)
@@ -90,25 +91,14 @@ module WebPipe
90
91
  # end
91
92
  # end
92
93
  #
93
- # It can be streamline using {WebPipe::Plugs::ViewContext} plug,
94
- # which accepts a callable object which should return the request
95
- # context from given {WebPipe::Conn}:
96
- #
97
- # @example
98
- # # ...
99
- # plug :set_view_context, WebPipe::Plugs::ViewContext[
100
- # ->(conn) { { current_path: conn.full_path } }
101
- # ]
102
- # # ...
103
- #
104
94
  # @see https://dry-rb.org/gems/dry-view/
105
95
  # @see WebPipe::Container
106
96
  module DryView
107
- # Where to find in {#bag} request's view context
97
+ # Where to find in {#config} request's view context generator.
108
98
  VIEW_CONTEXT_KEY = :view_context
109
99
 
110
100
  # Default request's view context
111
- DEFAULT_VIEW_CONTEXT = Types::EMPTY_HASH
101
+ DEFAULT_VIEW_CONTEXT = ->(_conn) { Types::EMPTY_HASH }
112
102
 
113
103
  # Sets string output of a view as response body.
114
104
  #
@@ -117,8 +107,8 @@ module WebPipe
117
107
  #
118
108
  # `kwargs` is used as the input for the view (the arguments that
119
109
  # {Dry::View#call} receives). If they doesn't contain an explicit
120
- # `context:` key, it can be added through the injection injection
121
- # of what is present in bag's `:view_context`.(see
110
+ # `context:` key, it can be added through the injection of the
111
+ # result of a lambda present in context's `:view_context`.(see
122
112
  # {Dry::View::Context#with}).
123
113
  #
124
114
  # @param view_spec [Dry::View, Any]
@@ -141,7 +131,7 @@ module WebPipe
141
131
  def view_instance(view_spec)
142
132
  return view_spec if view_spec.is_a?(Dry::View)
143
133
 
144
- fetch(:container)[view_spec]
134
+ fetch_config(:container)[view_spec]
145
135
  end
146
136
 
147
137
  def view_input(kwargs, view_instance)
@@ -151,7 +141,7 @@ module WebPipe
151
141
  config.
152
142
  default_context.
153
143
  with(
154
- fetch(VIEW_CONTEXT_KEY, DEFAULT_VIEW_CONTEXT)
144
+ fetch_config(VIEW_CONTEXT_KEY, DEFAULT_VIEW_CONTEXT).(self)
155
145
  )
156
146
  kwargs.merge(context: context)
157
147
  end
@@ -0,0 +1,99 @@
1
+ require 'web_pipe/types'
2
+ require 'web_pipe/extensions/params/params/transf'
3
+
4
+ module WebPipe
5
+ # Adds a {Conn#params} method which can perform any number of
6
+ # transformations to the request parameters.
7
+ #
8
+ # When no transformations are given, {#params} just returns request
9
+ # parameters (both GET and POST) as a hash:
10
+ #
11
+ # @example
12
+ # # http://www.example.com?foo=bar
13
+ # conn.params #=> { 'foo' => 'bar' }
14
+ #
15
+ # Further processing can be specified thanks to `transproc` gem (you
16
+ # need to add it yourself to the Gemfile). All hash transformations
17
+ # in `transproc` are available:
18
+ #
19
+ # @example
20
+ # # http://www.example.com?foo=bar
21
+ # conn.params([:deep_symbolize_keys]) #=> { foo: 'bar' }
22
+ #
23
+ # Extra needed arguments can be provided as an array:
24
+ #
25
+ # @example
26
+ # # http://www.example.com?foo=bar&zoo=zoo
27
+ # conn.params([:deep_symbolize_keys, [:reject_keys, [:zoo]]) #=> { foo: 'bar' }
28
+ #
29
+ # Instead of injecting transformations at the moment `#params` is
30
+ # called, you can configure them to be automatically used.
31
+ #
32
+ # @example
33
+ # # http://www.example.com?foo=bar
34
+ # conn.
35
+ # add_config(:param_transformation, [:deep_symbolize_keys]).
36
+ # params #=> { foo: 'bar' }
37
+ #
38
+ # You can register your own transformation functions:
39
+ #
40
+ # @example
41
+ # # http://www.example.com?foo=bar
42
+ # fake = ->(_params) { { fake: :params } }
43
+ # WebPipe::Params::Transf.register(:fake, fake)
44
+ # conn.params([:fake]) #=> { fake: :params }
45
+ #
46
+ # Your own transformation functions can depend on the {Conn}
47
+ # instance at the moment of execution. For that, just place it as the
48
+ # last argument of the function and it will be curried automatically:
49
+ #
50
+ # @example
51
+ # # http://www.example.com?foo=bar
52
+ # add_name = ->(params, conn) { params.merge(name: conn.fetch(:name)) }
53
+ # WebPipe::Params::Transf.register(:add_name, add_name)
54
+ # conn.
55
+ # add(:name, 'Joe').
56
+ # params([:deep_symbolize_keys, :add_name]) #=> { foo: 'bar', name: 'Joe' }
57
+ #
58
+ # Inline transformations can also be provided:
59
+ #
60
+ # @example
61
+ # # http://www.example.com?foo=bar
62
+ # fake = ->(_params) { { fake: :params } }
63
+ # conn.
64
+ # params(fake) #=> { fake: :params }
65
+ #
66
+ # @see https://github.com/solnic/transproc
67
+ module Params
68
+ # Key where configured transformations are set
69
+ PARAM_TRANSFORMATION_KEY = :param_transformations
70
+
71
+ # @param transformation_specs [Array<Symbol, Array>, Types::Undefined]
72
+ # @return [Any]
73
+ def params(transformation_specs = Types::Undefined)
74
+ specs = if transformation_specs == Types::Undefined
75
+ fetch_config(PARAM_TRANSFORMATION_KEY, [])
76
+ else
77
+ transformation_specs
78
+ end
79
+ transformations = specs.reduce(Transf[:id]) do |acc, t|
80
+ acc.>>transformation(t)
81
+ end
82
+
83
+ Transf[transformations].(request.params)
84
+ end
85
+
86
+ private
87
+
88
+ def transformation(spec)
89
+ transformation = Transf[*spec]
90
+ if (transformation.fn.arity - transformation.args.count) == 1
91
+ transformation
92
+ else
93
+ Transf[*[spec, self]]
94
+ end
95
+ end
96
+ end
97
+
98
+ Conn.include(Params)
99
+ end
@@ -0,0 +1,15 @@
1
+ require 'transproc'
2
+
3
+ module WebPipe
4
+ module Params
5
+ module Transf
6
+ extend Transproc::Registry
7
+
8
+ import Transproc::HashTransformations
9
+
10
+ def self.id(params)
11
+ params
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,59 @@
1
+ require 'web_pipe'
2
+ require 'web_pipe/types'
3
+
4
+ WebPipe.load_extensions(:params)
5
+
6
+ module WebPipe
7
+ # Adds a transformation to merge router params into {Conn#params}.
8
+ #
9
+ # This extension gives an opportunity for rack routers to modify
10
+ # {Conn#params} hash. This is useful so that they can provide *route
11
+ # parameters*, which are typically rendered as variables in routes
12
+ # definitions (e.g.: `/user/:id/edit`).
13
+ #
14
+ # It adds a `:router_params` transformation that, when used, will
15
+ # merged env's `router.params` in {Conn#params} hash. Choosing this
16
+ # name automatically integrates with `hanami-router`.
17
+ #
18
+ # When using this extension, `:params` extension is automatically enabled.
19
+ #
20
+ # @example
21
+ # require 'web_pipe'
22
+ #
23
+ # WebPipe.load_extensions(:router_params)
24
+ #
25
+ # class MyApp
26
+ # include WebPipe
27
+ #
28
+ # plug :config
29
+ # plug :get_params
30
+ #
31
+ # private
32
+ #
33
+ # def config(conn)
34
+ # conn.add_config(:param_transformation, [:router_params])
35
+ # end
36
+ #
37
+ # def get_params(conn)
38
+ # # http://example.com/users/1/edit
39
+ # conn.params #=> { id: 1 }
40
+ # conn
41
+ # end
42
+ # end
43
+ #
44
+ # @see WebPipe::Params
45
+ # @see https://github.com/hanami/router#string-matching-with-variables
46
+ module RouterParams
47
+ ROUTER_PARAM_KEY = 'router.params'
48
+
49
+ # @param params [Hash]
50
+ # @param conn [WebPipe::Conn]
51
+ #
52
+ # @return [Hash]
53
+ def self.call(params, conn)
54
+ params.merge(conn.env.fetch(ROUTER_PARAM_KEY, Types::EMPTY_HASH))
55
+ end
56
+
57
+ WebPipe::Params::Transf.register(:router_params, method(:call))
58
+ end
59
+ end
@@ -4,11 +4,6 @@ module WebPipe
4
4
  # This methods are in fact redundant with the information already
5
5
  # present in {Conn} struct but, of course, they are very useful.
6
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
7
  # Base part of the URL.
13
8
  #
14
9
  # This is {#scheme} and {#host}, adding {#port} unless it is the
@@ -58,37 +53,6 @@ module WebPipe
58
53
  def url
59
54
  request.url
60
55
  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
56
  end
93
57
 
94
58
  Conn.include(Url)
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'web_pipe/types'
4
+
5
+ module WebPipe
6
+ module Plugs
7
+ # Adds given pairs to {Conn#config}.
8
+ #
9
+ # @example
10
+ # class App
11
+ # include WebPipe
12
+ #
13
+ # plug :config, WebPipe::Plugs::Config.(foo: :bar)
14
+ # end
15
+ module Config
16
+ def self.call(pairs)
17
+ lambda do |conn|
18
+ conn.new(
19
+ config: conn.config.merge(pairs)
20
+ )
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -10,13 +10,13 @@ module WebPipe
10
10
  # class App
11
11
  # include WebPipe
12
12
  #
13
- # plug :html, WebPipe::Plugs::ContentType['text/html']
13
+ # plug :html, WebPipe::Plugs::ContentType.call('text/html')
14
14
  # end
15
15
  module ContentType
16
16
  # Content-Type header
17
17
  HEADER = 'Content-Type'
18
18
 
19
- def self.[](content_type)
19
+ def self.call(content_type)
20
20
  ->(conn) { conn.add_response_header(HEADER, content_type) }
21
21
  end
22
22
  end
@@ -1,3 +1,3 @@
1
1
  module WebPipe
2
- VERSION = "0.6.1"
2
+ VERSION = "0.7.0"
3
3
  end
@@ -36,9 +36,10 @@ Gem::Specification.new do |spec|
36
36
  spec.require_paths = ["lib"]
37
37
 
38
38
  spec.add_runtime_dependency "rack", "~> 2.0"
39
- spec.add_runtime_dependency "dry-monads", "~> 1.2"
39
+ spec.add_runtime_dependency "dry-monads", "~> 1.3"
40
40
  spec.add_runtime_dependency "dry-types", "~> 1.1"
41
41
  spec.add_runtime_dependency "dry-struct", "~> 1.0"
42
+ spec.add_runtime_dependency "transproc", "~> 1.1"
42
43
 
43
44
  spec.add_development_dependency "bundler", "~> 1.17"
44
45
  spec.add_development_dependency "rake", "~> 10.0"
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.6.1
4
+ version: 0.7.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-08-02 00:00:00.000000000 Z
11
+ date: 2019-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.2'
33
+ version: '1.3'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.2'
40
+ version: '1.3'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: dry-types
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: transproc
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.1'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.1'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: bundler
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -227,9 +241,9 @@ files:
227
241
  - Gemfile
228
242
  - README.md
229
243
  - Rakefile
244
+ - _config.yml
230
245
  - bin/console
231
246
  - bin/setup
232
- - lib/dry/monads/result/extensions/either.rb
233
247
  - lib/web_pipe.rb
234
248
  - lib/web_pipe/app.rb
235
249
  - lib/web_pipe/conn.rb
@@ -243,19 +257,20 @@ files:
243
257
  - lib/web_pipe/dsl/dsl_context.rb
244
258
  - lib/web_pipe/dsl/instance_methods.rb
245
259
  - lib/web_pipe/extensions/container/container.rb
246
- - lib/web_pipe/extensions/container/plugs/container.rb
247
260
  - lib/web_pipe/extensions/cookies/cookies.rb
248
261
  - lib/web_pipe/extensions/dry_schema/dry_schema.rb
249
- - lib/web_pipe/extensions/dry_schema/plugs/param_sanitization_handler.rb
250
262
  - lib/web_pipe/extensions/dry_schema/plugs/sanitize_params.rb
251
263
  - lib/web_pipe/extensions/dry_view/dry_view.rb
252
- - lib/web_pipe/extensions/dry_view/plugs/view_context.rb
253
264
  - lib/web_pipe/extensions/flash/flash.rb
265
+ - lib/web_pipe/extensions/params/params.rb
266
+ - lib/web_pipe/extensions/params/params/transf.rb
254
267
  - lib/web_pipe/extensions/redirect/redirect.rb
268
+ - lib/web_pipe/extensions/router_params/router_params.rb
255
269
  - lib/web_pipe/extensions/session/session.rb
256
270
  - lib/web_pipe/extensions/url/url.rb
257
271
  - lib/web_pipe/plug.rb
258
272
  - lib/web_pipe/plugs.rb
273
+ - lib/web_pipe/plugs/config.rb
259
274
  - lib/web_pipe/plugs/content_type.rb
260
275
  - lib/web_pipe/rack/app_with_middlewares.rb
261
276
  - lib/web_pipe/rack/middleware.rb
@@ -1,42 +0,0 @@
1
- require "dry/core/extensions"
2
-
3
- module Dry
4
- module Monads
5
- # This is currently a PR in dry-monads:
6
- #
7
- # https://github.com/dry-rb/dry-monads/pull/84
8
- class Result
9
- extend Dry::Core::Extensions
10
-
11
- register_extension(:either) do
12
- class Success
13
- # Returns result of applying first function to the internal value.
14
- #
15
- # @example
16
- # Dry::Monads.Success(1).either(-> x { x + 1 }, -> x { x + 2 }) # => 2
17
- #
18
- # @param f [#call] Function to apply
19
- # @param g [#call] Ignored
20
- # @return [Any] Return value of `f`
21
- def either(f, _g)
22
- f.(success)
23
- end
24
- end
25
-
26
- class Failure
27
- # Returns result of applying second function to the internal value.
28
- #
29
- # @example
30
- # Dry::Monads.Failure(1).either(-> x { x + 1 }, -> x { x + 2 }) # => 3
31
- #
32
- # @param f [#call] Ignored
33
- # @param g [#call] Function to call
34
- # @return [Any] Return value of `g`
35
- def either(_f, g)
36
- g.(failure)
37
- end
38
- end
39
- end
40
- end
41
- end
42
- end
@@ -1,31 +0,0 @@
1
- require 'web_pipe/types'
2
-
3
- module WebPipe
4
- module Plugs
5
- # Sets a container into bag's `:container` key.
6
- #
7
- # Given container is check to respond to `#[]` method, which is
8
- # meant to be used to resolve dependencies.
9
- #
10
- # @example
11
- # class App
12
- # include WebPipe
13
- #
14
- # Cont = { name: SomeDependency.new }.freeze
15
- #
16
- # plug :container, WebPipe::Plugs::Container[Cont]
17
- # plug :resolve
18
- #
19
- # private
20
- #
21
- # def resolve(conn)
22
- # conn.add(:dependency, conn.fetch(:container)[:name])
23
- # end
24
- # end
25
- module Container
26
- def self.[](container)
27
- ->(conn) { conn.add(:container, Types::Container[container]) }
28
- end
29
- end
30
- end
31
- end
@@ -1,27 +0,0 @@
1
- require 'web_pipe/types'
2
-
3
- module WebPipe
4
- module Plugs
5
- # Sets `:param_sanitization_handler` bag key.
6
- #
7
- # @see WebPipe::DrySchema
8
- module ParamSanitizationHandler
9
- # Bag key to store the handler.
10
- #
11
- # @return [Symbol]
12
- PARAM_SANITIZATION_HANDLER_KEY = :param_sanitization_handler
13
-
14
- # Type constructor for the handler.
15
- Handler = Types.Interface(:call)
16
-
17
- # @param handler [Handler[]]
18
- #
19
- # @return [ConnSupport::Composition::Operation[]]
20
- def self.[](handler)
21
- lambda do |conn|
22
- conn.add(PARAM_SANITIZATION_HANDLER_KEY, Handler[handler])
23
- end
24
- end
25
- end
26
- end
27
- end
@@ -1,38 +0,0 @@
1
- require 'web_pipe/types'
2
- require 'web_pipe/extensions/dry_view/dry_view'
3
-
4
- module WebPipe
5
- module Plugs
6
- # Calls object with conn and add the result into bag's `:view_context`.
7
- #
8
- # This is meant to contain a Proc which will be called with the same
9
- # {WebPipe::Conn} instance of the operation. It must return
10
- # request specific view context as a hash. Ultimately, this will
11
- # be provided to {Dry::View::Context#with} before passing the
12
- # result along to the view instance.
13
- #
14
- # @example
15
- # class App
16
- # include WebPipe
17
- #
18
- # ViewContext = (conn) -> { { current_path: conn.full_path } }
19
- #
20
- # plug :view_context, WebPipe::Plugs::ViewContext[ViewContext]
21
- # plug :render
22
- #
23
- # def render
24
- # view(MyView.new)
25
- # end
26
- # end
27
- #
28
- # @see WebPipe::Conn#view
29
- module ViewContext
30
- def self.[](view_context_proc)
31
- Types.Interface(:call)[view_context_proc]
32
- lambda do |conn|
33
- conn.add(Conn::VIEW_CONTEXT_KEY, view_context_proc.(conn))
34
- end
35
- end
36
- end
37
- end
38
- end