evil-client 0.3.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +0 -11
  3. data/.gitignore +1 -0
  4. data/.rspec +0 -1
  5. data/.rubocop.yml +22 -19
  6. data/.travis.yml +1 -0
  7. data/CHANGELOG.md +251 -6
  8. data/LICENSE.txt +3 -1
  9. data/README.md +47 -81
  10. data/docs/helpers/body.md +93 -0
  11. data/docs/helpers/connection.md +19 -0
  12. data/docs/helpers/headers.md +72 -0
  13. data/docs/helpers/http_method.md +39 -0
  14. data/docs/helpers/let.md +14 -0
  15. data/docs/helpers/logger.md +24 -0
  16. data/docs/helpers/middleware.md +56 -0
  17. data/docs/helpers/operation.md +103 -0
  18. data/docs/helpers/option.md +50 -0
  19. data/docs/helpers/path.md +37 -0
  20. data/docs/helpers/query.md +59 -0
  21. data/docs/helpers/response.md +40 -0
  22. data/docs/helpers/scope.md +121 -0
  23. data/docs/helpers/security.md +102 -0
  24. data/docs/helpers/validate.md +68 -0
  25. data/docs/index.md +70 -78
  26. data/docs/license.md +5 -1
  27. data/docs/rspec.md +96 -0
  28. data/evil-client.gemspec +10 -8
  29. data/lib/evil/client.rb +126 -72
  30. data/lib/evil/client/builder.rb +47 -0
  31. data/lib/evil/client/builder/operation.rb +40 -0
  32. data/lib/evil/client/builder/scope.rb +31 -0
  33. data/lib/evil/client/chaining.rb +17 -0
  34. data/lib/evil/client/connection.rb +60 -20
  35. data/lib/evil/client/container.rb +66 -0
  36. data/lib/evil/client/container/operation.rb +23 -0
  37. data/lib/evil/client/container/scope.rb +28 -0
  38. data/lib/evil/client/exceptions/definition_error.rb +15 -0
  39. data/lib/evil/client/exceptions/name_error.rb +32 -0
  40. data/lib/evil/client/exceptions/response_error.rb +42 -0
  41. data/lib/evil/client/exceptions/type_error.rb +29 -0
  42. data/lib/evil/client/exceptions/validation_error.rb +27 -0
  43. data/lib/evil/client/formatter.rb +49 -0
  44. data/lib/evil/client/formatter/form.rb +45 -0
  45. data/lib/evil/client/formatter/multipart.rb +33 -0
  46. data/lib/evil/client/formatter/part.rb +66 -0
  47. data/lib/evil/client/formatter/text.rb +21 -0
  48. data/lib/evil/client/resolver.rb +84 -0
  49. data/lib/evil/client/resolver/body.rb +22 -0
  50. data/lib/evil/client/resolver/format.rb +30 -0
  51. data/lib/evil/client/resolver/headers.rb +46 -0
  52. data/lib/evil/client/resolver/http_method.rb +34 -0
  53. data/lib/evil/client/resolver/middleware.rb +36 -0
  54. data/lib/evil/client/resolver/query.rb +39 -0
  55. data/lib/evil/client/resolver/request.rb +96 -0
  56. data/lib/evil/client/resolver/response.rb +26 -0
  57. data/lib/evil/client/resolver/security.rb +113 -0
  58. data/lib/evil/client/resolver/uri.rb +35 -0
  59. data/lib/evil/client/rspec.rb +127 -0
  60. data/lib/evil/client/schema.rb +105 -0
  61. data/lib/evil/client/schema/operation.rb +177 -0
  62. data/lib/evil/client/schema/scope.rb +73 -0
  63. data/lib/evil/client/settings.rb +172 -0
  64. data/lib/evil/client/settings/validator.rb +64 -0
  65. data/mkdocs.yml +21 -15
  66. data/spec/features/custom_connection_spec.rb +17 -0
  67. data/spec/features/operation/middleware_spec.rb +50 -0
  68. data/spec/features/operation/options_spec.rb +71 -0
  69. data/spec/features/operation/request_spec.rb +94 -0
  70. data/spec/features/operation/response_spec.rb +48 -0
  71. data/spec/features/scope/options_spec.rb +52 -0
  72. data/spec/fixtures/locales/en.yml +16 -0
  73. data/spec/fixtures/test_client.rb +76 -0
  74. data/spec/spec_helper.rb +18 -6
  75. data/spec/support/fixtures_helper.rb +7 -0
  76. data/spec/unit/builder/operation_spec.rb +90 -0
  77. data/spec/unit/builder/scope_spec.rb +84 -0
  78. data/spec/unit/client_spec.rb +137 -0
  79. data/spec/unit/connection_spec.rb +78 -0
  80. data/spec/unit/container/operation_spec.rb +81 -0
  81. data/spec/unit/container/scope_spec.rb +61 -0
  82. data/spec/unit/container_spec.rb +107 -0
  83. data/spec/unit/exceptions/definition_error_spec.rb +15 -0
  84. data/spec/unit/exceptions/name_error_spec.rb +77 -0
  85. data/spec/unit/exceptions/response_error_spec.rb +22 -0
  86. data/spec/unit/exceptions/type_error_spec.rb +71 -0
  87. data/spec/unit/exceptions/validation_error_spec.rb +13 -0
  88. data/spec/unit/formatter/form_spec.rb +27 -0
  89. data/spec/unit/formatter/multipart_spec.rb +23 -0
  90. data/spec/unit/formatter/part_spec.rb +49 -0
  91. data/spec/unit/formatter/text_spec.rb +37 -0
  92. data/spec/unit/formatter_spec.rb +46 -0
  93. data/spec/unit/resolver/body_spec.rb +65 -0
  94. data/spec/unit/resolver/format_spec.rb +66 -0
  95. data/spec/unit/resolver/headers_spec.rb +93 -0
  96. data/spec/unit/resolver/http_method_spec.rb +67 -0
  97. data/spec/unit/resolver/middleware_spec.rb +83 -0
  98. data/spec/unit/resolver/query_spec.rb +85 -0
  99. data/spec/unit/resolver/request_spec.rb +121 -0
  100. data/spec/unit/resolver/response_spec.rb +64 -0
  101. data/spec/unit/resolver/security_spec.rb +156 -0
  102. data/spec/unit/resolver/uri_spec.rb +117 -0
  103. data/spec/unit/rspec_spec.rb +342 -0
  104. data/spec/unit/schema/operation_spec.rb +309 -0
  105. data/spec/unit/schema/scope_spec.rb +110 -0
  106. data/spec/unit/schema_spec.rb +157 -0
  107. data/spec/unit/settings/validator_spec.rb +128 -0
  108. data/spec/unit/settings_spec.rb +248 -0
  109. metadata +192 -135
  110. data/docs/base_url.md +0 -38
  111. data/docs/documentation.md +0 -9
  112. data/docs/headers.md +0 -59
  113. data/docs/http_method.md +0 -31
  114. data/docs/model.md +0 -173
  115. data/docs/operation.md +0 -0
  116. data/docs/overview.md +0 -0
  117. data/docs/path.md +0 -48
  118. data/docs/query.md +0 -99
  119. data/docs/responses.md +0 -66
  120. data/docs/security.md +0 -102
  121. data/docs/settings.md +0 -32
  122. data/lib/evil/client/connection/net_http.rb +0 -57
  123. data/lib/evil/client/dsl.rb +0 -127
  124. data/lib/evil/client/dsl/base.rb +0 -26
  125. data/lib/evil/client/dsl/files.rb +0 -37
  126. data/lib/evil/client/dsl/headers.rb +0 -16
  127. data/lib/evil/client/dsl/http_method.rb +0 -24
  128. data/lib/evil/client/dsl/operation.rb +0 -91
  129. data/lib/evil/client/dsl/operations.rb +0 -41
  130. data/lib/evil/client/dsl/path.rb +0 -25
  131. data/lib/evil/client/dsl/query.rb +0 -16
  132. data/lib/evil/client/dsl/response.rb +0 -61
  133. data/lib/evil/client/dsl/responses.rb +0 -29
  134. data/lib/evil/client/dsl/scope.rb +0 -27
  135. data/lib/evil/client/dsl/security.rb +0 -57
  136. data/lib/evil/client/dsl/verifier.rb +0 -35
  137. data/lib/evil/client/middleware.rb +0 -81
  138. data/lib/evil/client/middleware/base.rb +0 -11
  139. data/lib/evil/client/middleware/merge_security.rb +0 -20
  140. data/lib/evil/client/middleware/normalize_headers.rb +0 -17
  141. data/lib/evil/client/middleware/stringify_form.rb +0 -40
  142. data/lib/evil/client/middleware/stringify_json.rb +0 -19
  143. data/lib/evil/client/middleware/stringify_multipart.rb +0 -36
  144. data/lib/evil/client/middleware/stringify_multipart/part.rb +0 -36
  145. data/lib/evil/client/middleware/stringify_query.rb +0 -35
  146. data/lib/evil/client/operation.rb +0 -34
  147. data/lib/evil/client/operation/request.rb +0 -26
  148. data/lib/evil/client/operation/response.rb +0 -39
  149. data/lib/evil/client/operation/response_error.rb +0 -13
  150. data/lib/evil/client/operation/unexpected_response_error.rb +0 -19
  151. data/spec/features/instantiation_spec.rb +0 -68
  152. data/spec/features/middleware_spec.rb +0 -79
  153. data/spec/features/operation_with_documentation_spec.rb +0 -41
  154. data/spec/features/operation_with_files_spec.rb +0 -40
  155. data/spec/features/operation_with_form_body_spec.rb +0 -158
  156. data/spec/features/operation_with_headers_spec.rb +0 -99
  157. data/spec/features/operation_with_http_method_spec.rb +0 -45
  158. data/spec/features/operation_with_json_body_spec.rb +0 -156
  159. data/spec/features/operation_with_nested_responses_spec.rb +0 -95
  160. data/spec/features/operation_with_path_spec.rb +0 -47
  161. data/spec/features/operation_with_query_spec.rb +0 -84
  162. data/spec/features/operation_with_security_spec.rb +0 -228
  163. data/spec/features/scoping_spec.rb +0 -48
  164. data/spec/support/test_client.rb +0 -15
  165. data/spec/unit/evil/client/connection/net_http_spec.rb +0 -38
  166. data/spec/unit/evil/client/dsl/files_spec.rb +0 -37
  167. data/spec/unit/evil/client/dsl/operation_spec.rb +0 -374
  168. data/spec/unit/evil/client/dsl/operations_spec.rb +0 -29
  169. data/spec/unit/evil/client/dsl/scope_spec.rb +0 -32
  170. data/spec/unit/evil/client/dsl/security_spec.rb +0 -135
  171. data/spec/unit/evil/client/middleware/merge_security_spec.rb +0 -32
  172. data/spec/unit/evil/client/middleware/normalize_headers_spec.rb +0 -17
  173. data/spec/unit/evil/client/middleware/stringify_form_spec.rb +0 -63
  174. data/spec/unit/evil/client/middleware/stringify_json_spec.rb +0 -61
  175. data/spec/unit/evil/client/middleware/stringify_multipart/part_spec.rb +0 -59
  176. data/spec/unit/evil/client/middleware/stringify_multipart_spec.rb +0 -62
  177. data/spec/unit/evil/client/middleware/stringify_query_spec.rb +0 -40
  178. data/spec/unit/evil/client/middleware_spec.rb +0 -46
  179. data/spec/unit/evil/client/operation/request_spec.rb +0 -49
  180. data/spec/unit/evil/client/operation/response_spec.rb +0 -63
@@ -1,16 +0,0 @@
1
- module Evil::Client::DSL
2
- class Headers < Base
3
- def call(schema)
4
- merge schema, headers: coercer
5
- end
6
-
7
- private
8
-
9
- attr_reader :model, :block
10
-
11
- def initialize(model: Evil::Struct, &block)
12
- @model = model
13
- @block = block
14
- end
15
- end
16
- end
@@ -1,24 +0,0 @@
1
- module Evil::Client::DSL
2
- class HttpMethod < Base
3
- def call(schema)
4
- merge schema, method: http_method
5
- end
6
-
7
- private
8
-
9
- attr_reader :block, :string
10
-
11
- def initialize(string = nil, &block)
12
- @string = string.to_s.downcase
13
- @block = block
14
- end
15
-
16
- def http_method
17
- if block
18
- ->(opts) { block.call(opts).to_s.downcase }
19
- else
20
- proc { string }
21
- end
22
- end
23
- end
24
- end
@@ -1,91 +0,0 @@
1
- module Evil::Client::DSL
2
- class Operation
3
- attr_reader :schema
4
-
5
- def finalize(settings)
6
- @mutex.synchronize do
7
- @schema = @default.dup
8
- instance_exec(settings, &@block) if @block
9
- @schema[:middleware]&.finalize(settings)
10
- @schema
11
- end
12
- end
13
-
14
- private
15
-
16
- def initialize(key, block)
17
- @mutex = Mutex.new
18
- @block = block
19
- @default = { key: key, responses: {} }
20
- end
21
-
22
- # ==========================================================================
23
- # Helper methods that mutate a @schema
24
- # ==========================================================================
25
-
26
- def documentation(value)
27
- @schema[:doc] = value
28
- end
29
-
30
- def http_method(value = nil, &block)
31
- @schema = HttpMethod[schema, value, &block]
32
- end
33
-
34
- def path(value = nil, &block)
35
- @schema = Path[schema, value, &block]
36
- end
37
-
38
- def security(&block)
39
- @schema[:security] = Security.new(&block)
40
- end
41
-
42
- def files(&block)
43
- @schema[:files] = Files.new(&block)
44
- @schema[:format] = "multipart"
45
- @schema.delete :body
46
- end
47
-
48
- def body(format: "json", **options, &block)
49
- @schema[:body] = __model__(options, &block)
50
- @schema[:format] = __valid_format__(format)
51
- @schema.delete :files
52
- end
53
-
54
- def headers(model: Evil::Struct, &block)
55
- @schema = Headers[schema, model: model, &block]
56
- end
57
-
58
- def query(model: Evil::Struct, &block)
59
- @schema = Query[schema, model: model, &block]
60
- end
61
-
62
- def responses(options = {}, &block)
63
- Responses.new(self, options, &block)
64
- end
65
-
66
- def response(name, status, **options, &block)
67
- @schema[:responses][name] = Response[status, block: block, **options]
68
- end
69
-
70
- # ==========================================================================
71
- # Utilities for helpers TODO: extract to a separate module
72
- # ==========================================================================
73
-
74
- def __valid_format__(format)
75
- formats = %w[json form]
76
- return format.to_s if formats.include? format.to_s
77
- raise ArgumentError.new "Invalid format #{format} for body." \
78
- " Use one of formats: #{formats}"
79
- end
80
-
81
- def __model__(model: nil, **, &block)
82
- if model && block
83
- Class.new(model, &block)
84
- elsif block
85
- Class.new(Evil::Struct, &block)
86
- elsif model
87
- model
88
- end
89
- end
90
- end
91
- end
@@ -1,41 +0,0 @@
1
- module Evil::Client::DSL
2
- # Container for operations definitions
3
- # Applies settings to definitions and returns a final schema
4
- class Operations
5
- # Adds block definition as a named operation
6
- #
7
- # @param [#to_sym] key
8
- # @param [Proc] block
9
- # @return [self]
10
- #
11
- def register(key, &block)
12
- @schema[key] = Operation.new(key, block)
13
- self
14
- end
15
-
16
- # Applies settings to all definitions and returns a final schema
17
- #
18
- # @param [Object] settings
19
- # @return [Hash<Symbol, Object>]
20
- #
21
- def finalize(settings)
22
- default = @schema[nil].finalize(settings)
23
- custom = @schema.select { |key| key }
24
-
25
- schema = custom.each_with_object({}) do |(key, operation), hash|
26
- custom = operation.finalize(settings)
27
- hash[key] = default.merge(custom)
28
- hash[key][:format] ||= "json"
29
- hash[key][:responses] = default[:responses].merge(custom[:responses])
30
- end
31
-
32
- Verifier.call(schema)
33
- end
34
-
35
- private
36
-
37
- def initialize
38
- @schema = { nil => Operation.new(nil, nil) }
39
- end
40
- end
41
- end
@@ -1,25 +0,0 @@
1
- module Evil::Client::DSL
2
- # Adds path settings to the operation's schema
3
- class Path < Base
4
- def call(schema)
5
- merge schema, path: path
6
- end
7
-
8
- private
9
-
10
- SLASHES = %r{\A/+|/+\z}
11
-
12
- attr_reader :block, :value
13
-
14
- def initialize(value = nil, &block)
15
- @value = value.to_s.gsub(SLASHES, "")
16
- @block = block
17
- end
18
-
19
- def path
20
- if block then ->(opts) { block.call(opts).to_s.gsub(SLASHES, "") }
21
- else ->(_) { value }
22
- end
23
- end
24
- end
25
- end
@@ -1,16 +0,0 @@
1
- module Evil::Client::DSL
2
- class Query < Base
3
- def call(schema)
4
- merge schema, query: coercer
5
- end
6
-
7
- private
8
-
9
- attr_reader :model, :block
10
-
11
- def initialize(model: nil, &block)
12
- @model = model
13
- @block = block
14
- end
15
- end
16
- end
@@ -1,61 +0,0 @@
1
- module Evil::Client::DSL
2
- # Builds a schema for response processor
3
- class Response
4
- extend Dry::Initializer::Mixin
5
- param :status
6
- option :raise, default: proc { false }
7
- option :format, default: proc {}
8
- option :model, default: proc { nil }
9
- option :block, default: proc { nil }
10
-
11
- def self.[](*args)
12
- new(*args).to_h
13
- end
14
-
15
- def to_h
16
- { status: status.to_i, coercer: coercer, raise: raise }
17
- end
18
-
19
- private
20
-
21
- def json?
22
- format.to_s == "json"
23
- end
24
-
25
- def arity
26
- block&.arity
27
- end
28
-
29
- def coercer
30
- handlers = [parser, processor, wrapper, finalizer].compact
31
- proc { |body| handlers.inject(body) { |obj, handler| handler.call(obj) } }
32
- end
33
-
34
- def parser
35
- proc { |body| JSON.parse(body) } if json?
36
- end
37
-
38
- def wrapper
39
- return unless json?
40
- proc { |data| data.is_a?(Hash) ? data : { data: data } }
41
- end
42
-
43
- def processor
44
- return unless block&.arity == 1
45
- block
46
- end
47
-
48
- def addon
49
- return unless arity == 0
50
- proc { |klass| klass.instance_eval(&block) }
51
- end
52
-
53
- def finalizer
54
- case [model.nil?, addon.nil?]
55
- when [false, true] then model
56
- when [false, false] then Class.new(model).tap(&addon)
57
- when [true, false] then Class.new(Evil::Struct).tap(&addon)
58
- end
59
- end
60
- end
61
- end
@@ -1,29 +0,0 @@
1
- class Evil::Client::DSL::Responses
2
- # Add settings shared by several responses
3
- #
4
- # @param [#to_sym] name
5
- # @param [#to_i] status
6
- # @param [Hash<Symbol, Object>] options
7
- # @param [Proc] block
8
- #
9
- def response(name, status, **options, &block)
10
- @client.send :response, name, status, @options.merge(options), &block
11
- end
12
-
13
- # Add settings shared by several responses
14
- #
15
- # @param [Hash<Symbol, Object>] options
16
- # @param [Proc] block
17
- #
18
- def responses(**options, &block)
19
- self.class.new(@client, @options.merge(options), &block)
20
- end
21
-
22
- private
23
-
24
- def initialize(client, **options, &block)
25
- @client = client
26
- @options = options
27
- instance_eval(&block)
28
- end
29
- end
@@ -1,27 +0,0 @@
1
- module Evil::Client::DSL
2
- # Provides a namespace for client's top-level DSL
3
- class Scope
4
- extend Dry::Initializer::Mixin
5
- option :__scope__, default: proc {}, reader: :private
6
-
7
- # Declares a method that opens new scope inside the current one
8
- # An instance of new scope has access to methods of its parent
9
- #
10
- # @param [#to_sym] name (:[]) The name of the new scope
11
- # @return [self]
12
- #
13
- def self.scope(name = :[], &block)
14
- klass = Class.new(Scope, &block)
15
- define_method(name) do |*args, **options|
16
- klass.new(*args, __scope__: self, **options)
17
- end
18
- self
19
- end
20
-
21
- private
22
-
23
- def method_missing(name, *args)
24
- __scope__.send(name, *args)
25
- end
26
- end
27
- end
@@ -1,57 +0,0 @@
1
- module Evil::Client::DSL
2
- # Nested definition for a security schemas
3
- class Security
4
- # Builds final security schema dependent on request options
5
- #
6
- # @param [Hash<Symbol, Object>] options
7
- # @return [Hash<Symbol, Object>]
8
- #
9
- def call(**options)
10
- @mutex.synchronize do
11
- @schema = {}
12
- instance_exec(options, &@block)
13
- @schema
14
- end
15
- end
16
-
17
- private
18
-
19
- def initialize(&block)
20
- @mutex = Mutex.new
21
- @block = block
22
- end
23
-
24
- # ==========================================================================
25
- # Helper methods that mutate a security @schema
26
- # ==========================================================================
27
-
28
- # @see [https://tools.ietf.org/html/rfc7617]
29
- def basic_auth(user, password)
30
- token = Base64.encode64("#{user}:#{password}").delete("\n")
31
- token_auth(token, prefix: "Basic")
32
- end
33
-
34
- def token_auth(token, using: :headers, prefix: nil)
35
- if using == :headers
36
- prefixed_token = [prefix&.to_s&.capitalize, token].compact.join(" ")
37
- key_auth("authorization", prefixed_token, using: :headers)
38
- else
39
- key_auth("access_token", token, using: using)
40
- end
41
- end
42
-
43
- def key_auth(key, value, using: :headers)
44
- __validate__ using
45
- @schema[using] ||= {}
46
- @schema[using][key.to_s] = value
47
- end
48
-
49
- # ==========================================================================
50
-
51
- def __validate__(part)
52
- parts = %i[body query headers]
53
- return if parts.include? part
54
- raise ArgumentError.new "Wrong part '#{part}'. Use one of parts: #{parts}"
55
- end
56
- end
57
- end
@@ -1,35 +0,0 @@
1
- module Evil::Client::DSL
2
- SchemaError = Class.new(StandardError)
3
-
4
- # Verifies a final schema
5
- class Verifier
6
- def self.call(schema)
7
- new(schema).call
8
- end
9
-
10
- def call
11
- @schema.each do |key, schema|
12
- check_path(key, schema)
13
- check_method(key, schema)
14
- end
15
- end
16
-
17
- private
18
-
19
- def initialize(schema)
20
- @schema = schema
21
- end
22
-
23
- def check_path(key, schema)
24
- return if schema[:path]
25
- raise SchemaError,
26
- "Path definition is missed for operation :#{key}"
27
- end
28
-
29
- def check_method(key, schema)
30
- return if schema[:method]
31
- raise SchemaError,
32
- "HTTP method definition is missed for operation :#{key}"
33
- end
34
- end
35
- end
@@ -1,81 +0,0 @@
1
- class Evil::Client
2
- # Builds and carries stack of middleware parameterized by settings
3
- #
4
- # @example
5
- # # during client definition
6
- # middleware = Evil::Client::Middleware.new do |settings|
7
- # run CustomMiddleware if settings.version > 1
8
- # end
9
- #
10
- # # during client instantiation
11
- # stack = middleware.finalize(settings)
12
- # conn = stack.wrap(connection)
13
- #
14
- # # during runtime to make a request
15
- # conn.call request
16
- #
17
- class Middleware
18
- class << self
19
- require_relative "middleware/base"
20
- require_relative "middleware/merge_security"
21
- require_relative "middleware/normalize_headers"
22
- require_relative "middleware/stringify_json"
23
- require_relative "middleware/stringify_multipart"
24
- require_relative "middleware/stringify_query"
25
- require_relative "middleware/stringify_form"
26
-
27
- # Middleware to be added on top of full stack (before custom ones)
28
- def prepend
29
- new do
30
- run NormalizeHeaders
31
- run MergeSecurity
32
- end.finalize
33
- end
34
-
35
- # Middleware to be added on bottom of full stack
36
- # (between custom stack and connection)
37
- def append
38
- new do
39
- run StringifyQuery
40
- run StringifyJson
41
- run StringifyForm
42
- run StringifyMultipart
43
- end.finalize
44
- end
45
- end
46
-
47
- # Applies client settings to build stack of middleware
48
- #
49
- # @param [Object] settings
50
- # @return [self]
51
- #
52
- def finalize(settings = nil)
53
- @mutex.synchronize do
54
- @stack = []
55
- instance_exec(settings, &@block) if @block
56
- self
57
- end
58
- end
59
-
60
- # Wraps the connection instance to the current stack of middleware
61
- #
62
- # @param [#call] connection
63
- # @return [#call]
64
- #
65
- def call(other)
66
- @stack.reverse.inject(other) { |a, e| e.new(a) }
67
- end
68
-
69
- private
70
-
71
- def initialize(&block)
72
- @mutex = Mutex.new
73
- @block = block
74
- end
75
-
76
- def run(klass)
77
- @stack << klass
78
- self
79
- end
80
- end
81
- end