web_pipe 0.13.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -1
  3. data/CHANGELOG.md +29 -0
  4. data/Gemfile +2 -2
  5. data/README.md +18 -11
  6. data/docs/building_a_rack_application.md +1 -1
  7. data/docs/composing_applications.md +4 -4
  8. data/docs/connection_struct/configuring_the_connection_struct.md +4 -4
  9. data/docs/connection_struct/halting_the_pipe.md +17 -19
  10. data/docs/connection_struct/sharing_data_downstream.md +9 -8
  11. data/docs/connection_struct.md +22 -19
  12. data/docs/design_model.md +10 -9
  13. data/docs/dsl_free_usage.md +85 -14
  14. data/docs/extensions/container.md +9 -10
  15. data/docs/extensions/cookies.md +4 -2
  16. data/docs/extensions/dry_schema.md +5 -4
  17. data/docs/extensions/flash.md +9 -11
  18. data/docs/extensions/{dry_view.md → hanami_view.md} +20 -22
  19. data/docs/extensions/not_found.md +40 -0
  20. data/docs/extensions/params.md +6 -4
  21. data/docs/extensions/rails.md +31 -38
  22. data/docs/extensions/redirect.md +5 -4
  23. data/docs/extensions/router_params.md +5 -5
  24. data/docs/extensions/session.md +4 -4
  25. data/docs/extensions/url.md +6 -6
  26. data/docs/extensions.md +5 -6
  27. data/docs/introduction.md +7 -7
  28. data/docs/plugging_operations/composing_operations.md +3 -3
  29. data/docs/plugging_operations/injecting_operations.md +4 -4
  30. data/docs/plugging_operations/inspecting_operations.md +24 -0
  31. data/docs/plugging_operations/resolving_operations.md +3 -3
  32. data/docs/plugging_operations.md +3 -3
  33. data/docs/plugs/config.md +1 -1
  34. data/docs/plugs/content_type.md +2 -1
  35. data/docs/plugs.md +6 -7
  36. data/docs/recipes/hanami_2_and_dry_rb_integration.md +12 -0
  37. data/docs/recipes/hanami_router_integration.md +3 -1
  38. data/docs/recipes/using_all_restful_methods.md +6 -5
  39. data/docs/testing.md +64 -0
  40. data/docs/using_rack_middlewares/composing_middlewares.md +2 -3
  41. data/docs/using_rack_middlewares/injecting_middlewares.md +6 -6
  42. data/docs/using_rack_middlewares/inspecting_middlewares.md +35 -0
  43. data/docs/using_rack_middlewares.md +6 -6
  44. data/lib/web_pipe/app.rb +22 -25
  45. data/lib/web_pipe/conn.rb +0 -1
  46. data/lib/web_pipe/conn_support/builder.rb +0 -7
  47. data/lib/web_pipe/conn_support/composition.rb +3 -26
  48. data/lib/web_pipe/conn_support/errors.rb +5 -5
  49. data/lib/web_pipe/conn_support/headers.rb +1 -50
  50. data/lib/web_pipe/conn_support/types.rb +3 -3
  51. data/lib/web_pipe/dsl/builder.rb +10 -19
  52. data/lib/web_pipe/dsl/class_context.rb +15 -40
  53. data/lib/web_pipe/dsl/instance_context.rb +53 -0
  54. data/lib/web_pipe/extensions/container/container.rb +2 -15
  55. data/lib/web_pipe/extensions/cookies/cookies.rb +2 -31
  56. data/lib/web_pipe/extensions/dry_schema/dry_schema.rb +2 -56
  57. data/lib/web_pipe/extensions/flash/flash.rb +2 -32
  58. data/lib/web_pipe/extensions/hanami_view/hanami_view.rb +67 -0
  59. data/lib/web_pipe/extensions/not_found/not_found.rb +26 -0
  60. data/lib/web_pipe/extensions/params/params.rb +2 -63
  61. data/lib/web_pipe/extensions/rails/rails.rb +2 -123
  62. data/lib/web_pipe/extensions/redirect/redirect.rb +2 -20
  63. data/lib/web_pipe/extensions/router_params/router_params.rb +1 -39
  64. data/lib/web_pipe/extensions/session/session.rb +2 -25
  65. data/lib/web_pipe/extensions/url/url.rb +2 -5
  66. data/lib/web_pipe/pipe.rb +229 -0
  67. data/lib/web_pipe/plug.rb +31 -65
  68. data/lib/web_pipe/plugs/config.rb +0 -2
  69. data/lib/web_pipe/plugs/content_type.rb +0 -2
  70. data/lib/web_pipe/rack_support/app_with_middlewares.rb +3 -26
  71. data/lib/web_pipe/rack_support/middleware.rb +2 -2
  72. data/lib/web_pipe/rack_support/middleware_specification.rb +19 -48
  73. data/lib/web_pipe/test_support.rb +28 -0
  74. data/lib/web_pipe/types.rb +1 -3
  75. data/lib/web_pipe/version.rb +1 -1
  76. data/lib/web_pipe.rb +77 -17
  77. data/web_pipe.gemspec +1 -2
  78. metadata +16 -9
  79. data/docs/recipes/dry_rb_integration.md +0 -18
  80. data/lib/web_pipe/dsl/dsl_context.rb +0 -85
  81. data/lib/web_pipe/dsl/instance_methods.rb +0 -114
  82. data/lib/web_pipe/extensions/dry_view/dry_view.rb +0 -158
@@ -1,19 +1,19 @@
1
1
  # Injecting middlewares
2
2
 
3
- Middlewares can be injected at the moment an application is initialized,
3
+ You can inject middlewares at the moment an application is initialized,
4
4
  allowing you to override what you have defined in the DSL.
5
5
 
6
- For that purpose, you have to use `middlewares:` keyword argument. It must be a
6
+ For that purpose, you have to use the `middlewares:` keyword argument. It must be a
7
7
  hash where middlewares are matched by the name you gave them in its definition.
8
8
 
9
- A middleware must be specified as an `Array`. First item must be a rack
10
- middleware class. The rest of arguments (if any) should be any option it may
9
+ A middleware must be specified as an `Array`. The first item must be a rack
10
+ middleware class. The rest of the arguments (if any) should be any options it may
11
11
  need.
12
12
 
13
- This is mainly useful for testing purposes, where you can switch a heavy
13
+ That is mainly useful for testing purposes, where you can switch a heavy
14
14
  middleware and use a mocked one instead.
15
15
 
16
- In the following example, rack session mechanism is being mocked:
16
+ In the following example, we mock the rack session mechanism:
17
17
 
18
18
  ```ruby
19
19
  # config.ru
@@ -0,0 +1,35 @@
1
+ # Inspecting middlewares
2
+
3
+ Once a `WebPipe` class is initialized, all its middlewares get resolved. You
4
+ can access them through the `#middlewares` method.
5
+
6
+ Each middleware is represented by a
7
+ `WebPipe::RackSupport::MiddlewareSpecification` instance, which contains two
8
+ accessors: `middleware` returns the middleware class. In contrast, `options`
9
+ returns an array with the arguments provided to the middleware on
10
+ initialization.
11
+
12
+ Keep in mind that every middleware is resolved as an array. That is because it
13
+ can be composed by a chain of middlewares built through
14
+ [composition](composing_middlewares.md).
15
+
16
+
17
+ ```ruby
18
+ require 'web_pipe'
19
+ require 'rack/session'
20
+
21
+ class MyApp
22
+ include WebPipe
23
+
24
+ use :session, Rack::Session::Cookie, key: 'my_app.session', secret: 'long'
25
+
26
+ plug(:hello) do |conn|
27
+ conn.set_response_body('Hello world!')
28
+ end
29
+ end
30
+
31
+ app = MyApp.new
32
+ session_middleware = app.middlewares[:session][0]
33
+ session_middleware.middleware # => Rack::Session::Cookie
34
+ session_middleware.options # => [{ key: 'my_app.session', secret: 'long' }]
35
+ ```
@@ -1,16 +1,16 @@
1
1
  # Using rack middlewares
2
2
 
3
3
  A one-way pipe like the one `web_pipe` implements can deal with any required
4
- feature in a web application. However, usually it is convenient to be able to
5
- use some well-known rack middleware so you don't have to reinvent the wheel.
6
- Even if you can add them at the router layer, `web_pipe` allows you to
7
- encapsulate them in your application definition.
4
+ feature in a web application. However, usually, it is convenient to use some
5
+ well-known rack middleware, so you don't have to reinvent the wheel. Even if
6
+ you can add them to the router layer, `web_pipe` allows you to encapsulate them
7
+ in your application definition.
8
8
 
9
- In order to add rack middlewares to the stack, you have to use the DSL method
9
+ To add rack middlewares to the stack, you have to use the DSL method
10
10
  `use`. The first argument it takes is a `Symbol` with the name you want to
11
11
  assign to it (which is needed to allow
12
12
  [injection](using_rack_middlewares/injecting_middlewares.md) on
13
- initialization). Then, it must follow the middleware class and any option it
13
+ initialization). Then, it must follow the middleware class and any options it
14
14
  may need:
15
15
 
16
16
  ```ruby
data/lib/web_pipe/app.rb CHANGED
@@ -1,54 +1,51 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'web_pipe/types'
4
3
  require 'web_pipe/conn'
5
4
  require 'web_pipe/conn_support/builder'
6
5
  require 'web_pipe/conn_support/composition'
7
6
 
8
7
  module WebPipe
9
- # Rack application built around applying a pipe of {Operation} to
10
- # a {Conn}.
8
+ # Rack app built from a chain of functions that take and return a
9
+ # {WebPipe::Conn}.
11
10
  #
12
- # A rack application is something callable accepting rack's `env`
13
- # as argument and returning a rack response. So, the workflow
14
- # followed to build it is:
11
+ # This is the abstraction encompassing a rack application built only with the
12
+ # functions on {WebPipe::Conn}. {WebPipe::RackSupport::AppWithMiddlewares}
13
+ # takes middlewares also into account.
15
14
  #
16
- # - Take rack's `env` and create a {Conn} from here.
17
- # - Starting from it, apply the pipe of operations (anything
18
- # callable accepting a {Conn} and returning a {Conn}).
19
- # - Convert last {Conn} back to a rack response and
20
- # return it.
15
+ # A rack application is something callable that takes the rack environment as
16
+ # an argument, and returns a rack response. So, this class needs to:
21
17
  #
22
- # {Conn} can itself be of two different types (subclasses of it}:
23
- # {Conn::Ongoing} and {Conn::Halted}. The pipe is stopped
24
- # whenever the stack is emptied or a {Conn::Halted} is
25
- # returned in any of the steps.
18
+ # - Take rack's environment and create a {WebPipe::Conn} struct from there.
19
+ # - Starting from the initial struct, apply the pipe of functions.
20
+ # - Convert the last {WebPipe::Conn} back to a rack response.
21
+ #
22
+ # {WebPipe::Conn} can itself be of two different types (subclasses of it}:
23
+ # {Conn::Ongoing} and {Conn::Halted}. The pipe is stopped on two scenarios:
24
+ #
25
+ # - The end of the pipe is reached.
26
+ # - One function returns a {Conn::Halted}.
26
27
  class App
27
- # Type for a rack environment.
28
- RackEnv = Types::Strict::Hash
29
-
30
28
  include Dry::Monads::Result::Mixin
31
29
 
32
30
  # @!attribute [r] operations
33
- # @return [Array<Operation[]>]
31
+ # @return [Array<Proc>]
34
32
  attr_reader :operations
35
33
 
34
+ # @param operations [Array<Proc>]
36
35
  def initialize(operations)
37
- @operations = Types.Array(
38
- ConnSupport::Composition::Operation
39
- )[operations]
36
+ @operations = operations
40
37
  end
41
38
 
42
- # @param env [Hash] Rack env
39
+ # @param env [Hash] Rack environment
43
40
  #
44
41
  # @return env [Array] Rack response
45
42
  # @raise ConnSupport::Composition::InvalidOperationResult when an
46
- # operation does not return a {Conn}
43
+ # operation doesn't return a {WebPipe::Conn}
47
44
  def call(env)
48
45
  extract_rack_response(
49
46
  apply_operations(
50
47
  conn_from_env(
51
- RackEnv[env]
48
+ env
52
49
  )
53
50
  )
54
51
  )
data/lib/web_pipe/conn.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'dry/struct'
4
- require 'web_pipe/types'
5
4
  require 'web_pipe/conn_support/types'
6
5
  require 'web_pipe/conn_support/errors'
7
6
  require 'web_pipe/conn_support/headers'
@@ -6,15 +6,8 @@ require 'web_pipe/conn_support/headers'
6
6
 
7
7
  module WebPipe
8
8
  module ConnSupport
9
- # Helper module to build a {Conn} from a rack's env.
10
- #
11
- # It always return a {Conn::Ongoing} subclass.
12
- #
13
9
  # @api private
14
10
  module Builder
15
- # @param env [Types::Env] Rack's env
16
- #
17
- # @return [Conn::Ongoing]
18
11
  # rubocop:disable Metrics/MethodLength
19
12
  def self.call(env)
20
13
  rr = Rack::Request.new(env)
@@ -1,31 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'dry/monads/result'
4
- require 'web_pipe/types'
5
4
  require 'web_pipe/conn'
6
5
 
7
6
  module WebPipe
8
7
  module ConnSupport
9
- # Composition of a pipe of {Operation} on a {Conn}.
10
- #
11
- # It represents the composition of a series of functions which
12
- # take a {Conn} as argument and return a {Conn}.
13
- #
14
- # However, {Conn} can itself be of two different types (subclasses
15
- # of it): a {Conn::Ongoing} or a {Conn::Halted}. On execution time,
16
- # the composition is stopped whenever the stack is emptied or a
17
- # {Conn::Halted} is returned in any of the steps.
8
+ # @api private
18
9
  class Composition
19
- # Type for an operation.
20
- #
21
- # It should be anything callable expecting a {Conn} and
22
- # returning a {Conn}.
23
- Operation = Types.Interface(:call)
24
-
25
- # Error raised when an {Operation} returns something that is not
26
- # a {Conn}.
10
+ # Raised when operation doesn't return a {WebPipe::Conn}.
27
11
  class InvalidOperationResult < RuntimeError
28
- # @param returned [Any] What was returned from the {Operation}
29
12
  def initialize(returned)
30
13
  super(
31
14
  <<~MSG
@@ -39,18 +22,12 @@ module WebPipe
39
22
 
40
23
  include Dry::Monads::Result::Mixin
41
24
 
42
- # @!attribute [r] operations
43
- # @return [Array<Operation[]>]
44
25
  attr_reader :operations
45
26
 
46
27
  def initialize(operations)
47
- @operations = Types.Array(Operation)[operations]
28
+ @operations = operations
48
29
  end
49
30
 
50
- # @param conn [Conn]
51
- # @return [Conn]
52
- # @raise InvalidOperationResult when an operation does not
53
- # return a {Conn}
54
31
  def call(conn)
55
32
  extract_result(
56
33
  apply_operations(
@@ -2,7 +2,7 @@
2
2
 
3
3
  module WebPipe
4
4
  module ConnSupport
5
- # Error raised when trying to fetch an entry in {Conn#bag} for an
5
+ # Error raised when trying to fetch an entry in {WebPipe::Conn#bag} for an
6
6
  # unknown key.
7
7
  class KeyNotFoundInBagError < KeyError
8
8
  # @param key [Any] Key not found in the bag
@@ -15,8 +15,8 @@ module WebPipe
15
15
  end
16
16
  end
17
17
 
18
- # Error raised when trying to fetch an entry in {Conn#config} for
19
- # an unknown key.
18
+ # Error raised when trying to fetch an entry in {WebPipeConn#config} for an
19
+ # unknown key.
20
20
  class KeyNotFoundInConfigError < KeyError
21
21
  # @param key [Any] Key not found in config
22
22
  def initialize(key)
@@ -28,8 +28,8 @@ module WebPipe
28
28
  end
29
29
  end
30
30
 
31
- # Error raised when trying to use a conn's feature which requires
32
- # a rack middleware which is not present
31
+ # Error raised when trying to use a {WebPipe::Conn} feature which requires a
32
+ # rack middleware that is not present
33
33
  class MissingMiddlewareError < RuntimeError
34
34
  # @param feature [String] Name of the feature intended to be used
35
35
  # @param middleware [String] Name of the missing middleware
@@ -2,25 +2,14 @@
2
2
 
3
3
  module WebPipe
4
4
  module ConnSupport
5
- # Helpers to work with headers and its rack's env representation.
6
- #
7
5
  # @api private
8
6
  module Headers
9
7
  # Headers which come as plain CGI-like variables (without the `HTTP_`
10
8
  # prefixed) from the rack server.
11
9
  HEADERS_AS_CGI = %w[CONTENT_TYPE CONTENT_LENGTH].freeze
12
10
 
13
- # Extracts headers from rack's env.
14
- #
15
11
  # Headers are all those pairs which key begins with `HTTP_` plus
16
12
  # those detailed in {HEADERS_AS_CGI}.
17
- #
18
- # @param env [Types::Env[]]
19
- #
20
- # @return [Types::Headers[]]
21
- #
22
- # @see HEADERS_AS_CGI
23
- # @see .normalize_key
24
13
  def self.extract(env)
25
14
  Hash[
26
15
  env
@@ -34,51 +23,20 @@ module WebPipe
34
23
  ]
35
24
  end
36
25
 
37
- # Adds key/value pair to given headers.
38
- #
39
- # Key is normalized.
40
- #
41
- # @param headers [Type::Headers[]]
42
- # @param key [String]
43
- # @param value [String]
44
- #
45
- # @return [Type::Headers[]]
46
- #
47
- # @see .normalize_key
48
26
  def self.add(headers, key, value)
49
27
  Hash[
50
28
  headers.to_a.push(pair(key, value))
51
29
  ]
52
30
  end
53
31
 
54
- # Deletes pair with given key form headers.
55
- #
56
- # Accepts a non normalized key.
57
- #
58
- # @param headers [Type::Headers[]]
59
- # @param key [String]
60
- #
61
- # @return [Type::Headers[]]
62
- #
63
- # @see .normalize_key
64
32
  def self.delete(headers, key)
65
33
  headers.reject { |k, _v| normalize_key(key) == k }
66
34
  end
67
35
 
68
- # Creates a pair with normalized key and raw value.
69
- #
70
- # @param key [String]
71
- # @param key [String]
72
- #
73
- # @return [Array<String>]
74
- #
75
- # @see .normalize_key
76
36
  def self.pair(key, value)
77
37
  [normalize_key(key), value]
78
38
  end
79
39
 
80
- # Normalizes a header key to convention.
81
- #
82
40
  # As per RFC2616, headers names are case insensitive. This
83
41
  # function normalizes them to PascalCase acting on dashes ('-').
84
42
  #
@@ -86,18 +44,11 @@ module WebPipe
86
44
  # dashes and underscores (`_`) are treated as dashes. This
87
45
  # function substitutes all '-' to '_'.
88
46
  #
89
- # @param key [String]
90
- #
91
- # @return [String]
92
- #
93
- # @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
47
+ # See https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
94
48
  def self.normalize_key(key)
95
49
  key.downcase.gsub('_', '-').split('-').map(&:capitalize).join('-')
96
50
  end
97
51
 
98
- # Returns a new hash with all keys normalized.
99
- #
100
- # @see #normalize_key
101
52
  def self.normalize(headers)
102
53
  headers.transform_keys { |k| normalize_key(k) }
103
54
  end
@@ -5,10 +5,10 @@ require 'rack/request'
5
5
 
6
6
  module WebPipe
7
7
  module ConnSupport
8
- # Types used for {Conn} struct.
8
+ # Types used in the {WebPipe::Conn} struct.
9
9
  #
10
- # Implementation self-describes them, but you can look at {Conn}
11
- # attributes for documentation.
10
+ # The implementation self-describes them, but you can look at the
11
+ # {WebPipe::Conn} attributes for documentation.
12
12
  module Types
13
13
  include Dry.Types()
14
14
 
@@ -1,36 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'web_pipe/types'
4
3
  require 'web_pipe/dsl/class_context'
5
- require 'web_pipe/dsl/instance_methods'
4
+ require 'web_pipe/dsl/instance_context'
5
+ require 'web_pipe/pipe'
6
6
 
7
7
  module WebPipe
8
8
  module DSL
9
- # When an instance of it is included in a module, the module
10
- # extends a {ClassContext} instance and includes
11
- # {InstanceMethods}.
12
- #
13
9
  # @api private
14
10
  class Builder < Module
15
- # Container with nothing registered.
16
- EMPTY_CONTAINER = Types::EMPTY_HASH
11
+ attr_reader :class_context, :instance_context
17
12
 
18
- # @!attribute [r] container
19
- # @return [Types::Container[]]
20
- attr_reader :container
21
-
22
- # @return [ClassContext]
23
- attr_reader :class_context
24
-
25
- def initialize(container: EMPTY_CONTAINER)
26
- @container = Types::Container[container]
27
- @class_context = ClassContext.new(container: container)
13
+ def initialize(container: Pipe::EMPTY_CONTAINER)
14
+ @class_context = ClassContext.new
15
+ @instance_context = InstanceContext.new(
16
+ class_context: class_context,
17
+ container: container
18
+ )
28
19
  super()
29
20
  end
30
21
 
31
22
  def included(klass)
32
23
  klass.extend(class_context)
33
- klass.include(InstanceMethods)
24
+ klass.include(instance_context)
34
25
  end
35
26
  end
36
27
  end
@@ -1,57 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'web_pipe/types'
4
- require 'web_pipe/dsl/dsl_context'
5
-
6
3
  module WebPipe
7
4
  module DSL
8
- # Defines the DSL and keeps the state for the pipe.
9
- #
10
- # This is good to be an instance because it keeps the
11
- # configuration (state) for the pipe class: the container
12
- # configured on initialization and both rack middlewares and plugs
13
- # added through the DSL {DSLContext}.
14
- #
15
- # As the pipe is extended with an instance of this class, methods
16
- # that are meant to be class methods in the pipe are defined as
17
- # singleton methods of the instance.
18
- #
19
5
  # @api private
20
6
  class ClassContext < Module
21
- # Methods to be imported from the {DSLContext}.
22
- DSL_METHODS = %i[middleware_specifications use plugs plug compose].freeze
7
+ DSL_METHODS = %i[use plug compose].freeze
23
8
 
24
- # @!attribute [r] container
25
- # @return [Types::Container[]]
26
- attr_reader :container
9
+ attr_reader :ast
27
10
 
28
- # @return [DSLContext]
29
- attr_reader :dsl_context
11
+ def initialize
12
+ @ast = []
13
+ super
14
+ end
30
15
 
31
- def initialize(container:)
32
- @container = Types::Container[container]
33
- @dsl_context = DSLContext.new([], [])
34
- define_container
35
- define_dsl
36
- super()
16
+ def extended(klass)
17
+ define_dsl_methods(klass, ast)
37
18
  end
38
19
 
39
20
  private
40
21
 
41
- def define_container
42
- module_exec(container) do |container|
43
- define_method(:container) do
44
- container
45
- end
46
- end
47
- end
48
-
49
- def define_dsl
22
+ def define_dsl_methods(klass, ast)
50
23
  DSL_METHODS.each do |method|
51
- module_exec(dsl_context) do |dsl_context|
52
- define_method(method) do |*args, &block|
53
- dsl_context.method(method).call(*args, &block)
54
- end
24
+ klass.define_singleton_method(method) do |*args, **kwargs, &block|
25
+ ast << if block_given?
26
+ [method, args, kwargs, block]
27
+ else
28
+ [method, args, kwargs]
29
+ end
55
30
  end
56
31
  end
57
32
  end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'web_pipe/pipe'
4
+
5
+ module WebPipe
6
+ module DSL
7
+ # @api private
8
+ class InstanceContext < Module
9
+ PIPE_METHODS = %i[
10
+ call middlewares operations to_proc to_middlewares
11
+ ].freeze
12
+
13
+ attr_reader :container, :class_context
14
+
15
+ def initialize(container:, class_context:)
16
+ @container = container
17
+ @class_context = class_context
18
+ super()
19
+ end
20
+
21
+ def included(klass)
22
+ define_initialize(klass, class_context.ast, container)
23
+ define_pipe_methods(klass)
24
+ end
25
+
26
+ private
27
+
28
+ # rubocop:disable Metrics/MethodLength
29
+ def define_initialize(klass, ast, container)
30
+ klass.define_method(:initialize) do |plugs: {}, middlewares: {}|
31
+ acc = Pipe.new(container: container, context: self)
32
+ @pipe = ast.reduce(acc) do |pipe, node|
33
+ method, args, kwargs, block = node
34
+ if block
35
+ pipe.send(method, *args, **kwargs, &block)
36
+ else
37
+ pipe.send(method, *args, **kwargs)
38
+ end
39
+ end.inject(plugs: plugs, middleware_specifications: middlewares)
40
+ end
41
+ # rubocop:enable Metrics/MethodLength
42
+ end
43
+
44
+ def define_pipe_methods(klass)
45
+ PIPE_METHODS.each do |method|
46
+ klass.define_method(method) do |*args|
47
+ @pipe.send(method, *args)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -2,22 +2,9 @@
2
2
 
3
3
  require 'web_pipe'
4
4
 
5
- #:nodoc:
5
+ # :nodoc:
6
6
  module WebPipe
7
- # Extension adding a `#container` method which returns {Conn#config}
8
- # `:container` key.
9
- #
10
- # @example
11
- # require 'web_pipe'
12
- #
13
- # WebPipe.load_extensions(:container)
14
- #
15
- # class App
16
- # include WebPipe
17
- #
18
- # plug :container, ->(conn) { conn.add_config(:container, MyContainer) }
19
- # plug :render, ->(conn) { conn.set_response_body(conn.container['view']) }
20
- # end
7
+ # See the docs for the extension linked from the README.
21
8
  module Container
22
9
  # Returns {Conn#config} `:container` value
23
10
  #
@@ -1,40 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'web_pipe'
4
- require 'web_pipe/types'
5
4
  require 'rack/utils'
6
5
 
7
- #:nodoc:
6
+ # :nodoc:
8
7
  module WebPipe
9
- # Extension to help dealing with request and response cookies.
10
- #
11
- # This extension helps with the addition of the `Set-Cookie` header
12
- # to the response, which is the way the server has to instruct the
13
- # browser to keep a cookie. A cookie can be added with the
14
- # {#set_cookie} method, while it can be marked for deletion with
15
- # {#delete_cookie}. Remember that marking a cookie for deletion just
16
- # means adding the same cookie name with an expiration time in the
17
- # past.
18
- #
19
- # Besides, it also adds a {#request_cookies} method to get the
20
- # cookies in the request.
21
- #
22
- # @example
23
- # require 'web_pipe'
24
- #
25
- # WebPipe.load_extensions(:cookies)
26
- #
27
- # class SetCookie
28
- # include WebPipe
29
- #
30
- # plug :set_cookie, ->(conn) { conn.set_cookie('foo', 'bar', path: '/') }
31
- # end
32
- #
33
- # class DeleteCookie
34
- # include WebPipe
35
- #
36
- # plug :delete_cookie, ->(conn) { conn.delete_cookie('foo', path: '/') }
37
- # end
8
+ # See the docs for the extension linked from the README.
38
9
  module Cookies
39
10
  # Valid options for {#set_cookie}.
40
11
  SET_COOKIE_OPTIONS = Types::Strict::Hash.schema(