web_pipe 0.13.0 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -1
  3. data/CHANGELOG.md +29 -0
  4. data/Gemfile +2 -2
  5. data/README.md +18 -11
  6. data/docs/building_a_rack_application.md +1 -1
  7. data/docs/composing_applications.md +4 -4
  8. data/docs/connection_struct/configuring_the_connection_struct.md +4 -4
  9. data/docs/connection_struct/halting_the_pipe.md +17 -19
  10. data/docs/connection_struct/sharing_data_downstream.md +9 -8
  11. data/docs/connection_struct.md +22 -19
  12. data/docs/design_model.md +10 -9
  13. data/docs/dsl_free_usage.md +85 -14
  14. data/docs/extensions/container.md +9 -10
  15. data/docs/extensions/cookies.md +4 -2
  16. data/docs/extensions/dry_schema.md +5 -4
  17. data/docs/extensions/flash.md +9 -11
  18. data/docs/extensions/{dry_view.md → hanami_view.md} +20 -22
  19. data/docs/extensions/not_found.md +40 -0
  20. data/docs/extensions/params.md +6 -4
  21. data/docs/extensions/rails.md +31 -38
  22. data/docs/extensions/redirect.md +5 -4
  23. data/docs/extensions/router_params.md +5 -5
  24. data/docs/extensions/session.md +4 -4
  25. data/docs/extensions/url.md +6 -6
  26. data/docs/extensions.md +5 -6
  27. data/docs/introduction.md +7 -7
  28. data/docs/plugging_operations/composing_operations.md +3 -3
  29. data/docs/plugging_operations/injecting_operations.md +4 -4
  30. data/docs/plugging_operations/inspecting_operations.md +24 -0
  31. data/docs/plugging_operations/resolving_operations.md +3 -3
  32. data/docs/plugging_operations.md +3 -3
  33. data/docs/plugs/config.md +1 -1
  34. data/docs/plugs/content_type.md +2 -1
  35. data/docs/plugs.md +6 -7
  36. data/docs/recipes/hanami_2_and_dry_rb_integration.md +12 -0
  37. data/docs/recipes/hanami_router_integration.md +3 -1
  38. data/docs/recipes/using_all_restful_methods.md +6 -5
  39. data/docs/testing.md +64 -0
  40. data/docs/using_rack_middlewares/composing_middlewares.md +2 -3
  41. data/docs/using_rack_middlewares/injecting_middlewares.md +6 -6
  42. data/docs/using_rack_middlewares/inspecting_middlewares.md +35 -0
  43. data/docs/using_rack_middlewares.md +6 -6
  44. data/lib/web_pipe/app.rb +22 -25
  45. data/lib/web_pipe/conn.rb +0 -1
  46. data/lib/web_pipe/conn_support/builder.rb +0 -7
  47. data/lib/web_pipe/conn_support/composition.rb +3 -26
  48. data/lib/web_pipe/conn_support/errors.rb +5 -5
  49. data/lib/web_pipe/conn_support/headers.rb +1 -50
  50. data/lib/web_pipe/conn_support/types.rb +3 -3
  51. data/lib/web_pipe/dsl/builder.rb +10 -19
  52. data/lib/web_pipe/dsl/class_context.rb +15 -40
  53. data/lib/web_pipe/dsl/instance_context.rb +53 -0
  54. data/lib/web_pipe/extensions/container/container.rb +2 -15
  55. data/lib/web_pipe/extensions/cookies/cookies.rb +2 -31
  56. data/lib/web_pipe/extensions/dry_schema/dry_schema.rb +2 -56
  57. data/lib/web_pipe/extensions/flash/flash.rb +2 -32
  58. data/lib/web_pipe/extensions/hanami_view/hanami_view.rb +67 -0
  59. data/lib/web_pipe/extensions/not_found/not_found.rb +26 -0
  60. data/lib/web_pipe/extensions/params/params.rb +2 -63
  61. data/lib/web_pipe/extensions/rails/rails.rb +2 -123
  62. data/lib/web_pipe/extensions/redirect/redirect.rb +2 -20
  63. data/lib/web_pipe/extensions/router_params/router_params.rb +1 -39
  64. data/lib/web_pipe/extensions/session/session.rb +2 -25
  65. data/lib/web_pipe/extensions/url/url.rb +2 -5
  66. data/lib/web_pipe/pipe.rb +229 -0
  67. data/lib/web_pipe/plug.rb +31 -65
  68. data/lib/web_pipe/plugs/config.rb +0 -2
  69. data/lib/web_pipe/plugs/content_type.rb +0 -2
  70. data/lib/web_pipe/rack_support/app_with_middlewares.rb +3 -26
  71. data/lib/web_pipe/rack_support/middleware.rb +2 -2
  72. data/lib/web_pipe/rack_support/middleware_specification.rb +19 -48
  73. data/lib/web_pipe/test_support.rb +28 -0
  74. data/lib/web_pipe/types.rb +1 -3
  75. data/lib/web_pipe/version.rb +1 -1
  76. data/lib/web_pipe.rb +77 -17
  77. data/web_pipe.gemspec +1 -2
  78. metadata +16 -9
  79. data/docs/recipes/dry_rb_integration.md +0 -18
  80. data/lib/web_pipe/dsl/dsl_context.rb +0 -85
  81. data/lib/web_pipe/dsl/instance_methods.rb +0 -114
  82. data/lib/web_pipe/extensions/dry_view/dry_view.rb +0 -158
@@ -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(