evil-client 0.3.3 → 1.0.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 (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
data/docs/responses.md DELETED
@@ -1,66 +0,0 @@
1
- For every operation you have to describe all expected responses and how they should be processed.
2
-
3
- Use the `response` method with anexpected http response status(es):
4
-
5
- ```ruby
6
- operation :find_cat do
7
- # ...
8
- response 200, 201
9
- end
10
- ```
11
-
12
- This definition tells a client to accept responses with given statuses, and to return an instance of `Rack::Response`.
13
-
14
- ```ruby
15
- client.operations[:find_cat].call
16
- # => #<Rack::Response @code=200 ...>
17
- ```
18
-
19
- ## Data Coersion
20
-
21
- Instead of returning a raw rack response, you can coerce it using a block. The block will take 3 options, namely the response, its body and headers:
22
-
23
- ```ruby
24
- operation :find_cat do |settings| # remember that you have access to settings
25
- # ...
26
- response 200 do |response:, body:, headers:|
27
- JSON.parse(body) if settings.format == "json"
28
- end
29
- end
30
-
31
- # later at a runtime
32
- client.operations[:find_cat].call
33
- # => { name: "Bastet", age: 10 }
34
- ```
35
-
36
-
37
-
38
- ## Raising Exceptions
39
-
40
- When processing responces with error statuses you may need to raise an exception instead of returning values. Do this using option `raise: true`
41
-
42
- ```ruby
43
- operation :find_cat do
44
- # ...
45
- response 422, raise: true
46
- end
47
- ```
48
-
49
- This time the operation will raise a `Evil::Client::ResponseError` (inherited from the `RuntimeError`). The exception carries a rack response:
50
-
51
- ```ruby
52
- begin
53
- client.operations[:find_cat].call
54
- rescue Evil::Client::ResponseError => error
55
- error.response
56
- # => #<Rack::Response @code=422 ...>
57
- end
58
- ```
59
-
60
- Like before, you can add a block to handle the response. In this case an exception will carry a result of the block.
61
-
62
- ## Unexpected Responses
63
-
64
- In case the server responded with undefined status, the operation raises `Evil::Client::UnexpectedResponseError` (inherited from the `RuntimeError`) that carries a rack response just like the `Evil::Client::ResponseError` before.
65
-
66
- Notice that you can declare default responses using anonymous `operation {}` syntax. Only those responces that are declared neither by default, nor for a specific operation, will cause unexpected response behaviour.
data/docs/security.md DELETED
@@ -1,102 +0,0 @@
1
- Use `security` declaration for the authorization schema. Inside the block you have access to 3 methods:
2
- * `basic_auth`
3
- * `token_auth`
4
- * `key_auth`
5
-
6
- ## Basic Authentication
7
-
8
- Use `basic_auth(login, password)` to define [basic authentication following RFC-7617][basic_auth]:
9
-
10
- ```ruby
11
- operation :find_cat do |settings|
12
- security do
13
- basic_auth settings.login, settings.password
14
- end
15
- end
16
- ```
17
-
18
- This declaration with add a header `"Authentication" => "Basic {encoded token}"` to every request. The header is added independenlty of declaration for other [headers][headers].
19
-
20
- ## Token Authentication
21
-
22
- The command `token_auth(token, **options)` allows you to insert a customizable token to any part of the request. Unlike `basic_auth`, you need to provide the token (build, encrypt etc.) by hand.
23
-
24
- ```ruby
25
- operation :find_cat do |settings|
26
- security do
27
- token_auth settings.token
28
- end
29
- end
30
- ```
31
-
32
- By default the token is added to `"Authentication" => {token}` header of the request. You can prepend it with a necessary prefix. For example, you can define a [Bearer token authentication following RFC-6750][bearer]:
33
-
34
- ```ruby
35
- operation :find_cat do |settings|
36
- security do
37
- token_auth settings.token, prefix: "Bearer"
38
- end
39
- end
40
- ```
41
-
42
- Instead of headers, you can send a token in either request body, or a query. In this case the token will be sent under `access_key` ignoring a prefix:
43
-
44
- ```ruby
45
- operation :find_cat do |settings|
46
- path { "/cats" }
47
- security do
48
- token_auth settings.token, using: :query
49
- end
50
- end
51
-
52
- # will send a request to "../cats?access_key={token}"
53
- ```
54
-
55
- ## Authentication Using Arbitrary Key
56
-
57
- The most customizeable option is to authenticate requests with an arbitrary key. This time key-value pair will be added to the selected part (`headers`, `body`, or `query`) of the request:
58
-
59
- ```ruby
60
- operation :find_cat do |settings|
61
- path { "/cats" }
62
- security do
63
- key_auth :accss_key, settings.token, using: :query
64
- end
65
- end
66
- ```
67
-
68
- ## Authentication Using Several Schemes
69
-
70
- You can define several schemes for the same request. All of them will be applied at once:
71
-
72
- ```ruby
73
- operation :find_cat do |settings|
74
- security do
75
- basic_auth settings.login, settings.password
76
- token_auth settings.token, using: :query
77
- end
78
- end
79
- ```
80
-
81
- Moreover, you can declare shared authentication by default, and either update, or reload it for a specific operation:
82
-
83
- ```ruby
84
- operation do |settings|
85
- security { basic_auth settings.login, settings.password }
86
- end
87
-
88
- operation :find_cat do |settings|
89
- security { token_auth settings.token, using: :query } # added to default security
90
- end
91
-
92
- operation :find_cats do |settings|
93
- security { token_auth settings.token } # reloads default "Authentication" header
94
- end
95
- ```
96
-
97
-
98
- [basic_auth]: https://tools.ietf.org/html/rfc7617
99
- [bearer]: https://tools.ietf.org/html/rfc6750
100
- [headers]:
101
- [body]:
102
- [query]:
data/docs/settings.md DELETED
@@ -1,32 +0,0 @@
1
- Use `settings` to parameterize an instance of the client.
2
-
3
- Inside the block you can define both `param`s and `option`s for a client constructor. See [dry-initializer docs][dry-initializer] for detailed description of the methods' syntax.
4
-
5
- ```ruby
6
- require "evil-client"
7
- require "dry-types"
8
-
9
- class CatsClient < Evil::Client
10
- settings do
11
- param :roor_url
12
- option :version, type: Dry::Types["coercible.int"], default: proc { 1 }
13
- option :login, type: Dry::Types["strict.string"] # required
14
- option :password, type: Dry::Types["strict.string"] # required
15
- end
16
- end
17
- ```
18
-
19
- Now you can initialize a client:
20
-
21
- ```ruby
22
- client = CatsClient.new "https://cats.example.com",
23
- login: "cats_lover",
24
- password: "purr"
25
- ```
26
-
27
- A container with assigned settings will be passed to blocks declaring [base_url][base_url], [connection][connection], and [operations][operation].
28
-
29
- [base_url]:
30
- [connection]:
31
- [operation]:
32
- [dry-initializer]: http://dry-rb.org/gems/dry-initializer
@@ -1,57 +0,0 @@
1
- require "net/http"
2
- require "net/https"
3
-
4
- class Evil::Client
5
- class Connection
6
- # Net::HTTP based implementation of [Evil::Client::Connection]
7
- class NetHTTP < Connection
8
- # Sends a request to the remote uri,
9
- # and returns rack-compatible response
10
- #
11
- # @param [Hash] env Middleware environment with keys:
12
- # :http_method, :path, :query_string, :body_string, :headers
13
- # @return [Array] Rack-compatible response [status, body, headers]
14
- #
15
- def call(env, *)
16
- request = build_request(env)
17
- Net::HTTP.start base_uri.host, base_uri.port, opts do |http|
18
- handle http.request(request)
19
- end
20
- end
21
-
22
- private
23
-
24
- def opts
25
- @opts ||= {}.tap { |hash| hash[:use_ssl] = base_uri.scheme == "https" }
26
- end
27
-
28
- def build_request(env)
29
- type, path, query, body, headers = parse_env(env)
30
-
31
- sender = build_sender(type)
32
- uri = build_uri(path, query)
33
-
34
- sender.new(uri).tap do |request|
35
- request.body = body
36
- headers.each { |key, value| request[key] = value }
37
- end
38
- end
39
-
40
- def parse_env(env)
41
- env.values_at :http_method, :path, :query_string, :body_string, :headers
42
- end
43
-
44
- def build_sender(type)
45
- Net::HTTP.const_get type.capitalize
46
- end
47
-
48
- def build_uri(path, query)
49
- base_uri.merge(URI.encode(path)).tap { |uri| uri.query = query }
50
- end
51
-
52
- def handle(response)
53
- [response.code.to_i, Hash(response.header), Array(response.body)]
54
- end
55
- end
56
- end
57
- end
@@ -1,127 +0,0 @@
1
- class Evil::Client
2
- # Defines a DSL to customize class-level settings of the specific client
3
- module DSL
4
- require_relative "dsl/base"
5
- require_relative "dsl/files"
6
- require_relative "dsl/headers"
7
- require_relative "dsl/http_method"
8
- require_relative "dsl/path"
9
- require_relative "dsl/query"
10
- require_relative "dsl/response"
11
- require_relative "dsl/responses"
12
- require_relative "dsl/security"
13
- require_relative "dsl/verifier"
14
- require_relative "dsl/operation"
15
- require_relative "dsl/operations"
16
- require_relative "dsl/scope"
17
-
18
- # Adds [#operations] to a specific client's instances
19
- def self.extended(klass)
20
- klass.include Dry::Initializer.define -> do
21
- param :settings
22
- param :base_url
23
- param :operations
24
- end
25
- end
26
-
27
- # Helper to define params and options a for a client's constructor
28
- #
29
- # @example
30
- # class MyClient < Evil::Client
31
- # end
32
- #
33
- # MyClient.new "https://foo.com", user: "bar", token: "baz"
34
- #
35
- # @param [Proc] block
36
- # @return [self]
37
- #
38
- def settings(&block)
39
- return self unless block
40
- schema[:settings] = Class.new { include Dry::Initializer.define(&block) }
41
- self
42
- end
43
-
44
- # Helper to define base url of the server
45
- #
46
- # @param [#to_s] value
47
- # @return [self]
48
- #
49
- def base_url(&block)
50
- return self unless block
51
- schema[:base_url] = block
52
- self
53
- end
54
-
55
- # Helper specify a connection to be used by a client
56
- #
57
- # @param [#to_sym] type (nil)
58
- # The specific type of connection. Uses NetHTTP by default.
59
- # @return [self]
60
- #
61
- def connection(type = nil, &block)
62
- schema[:connection] = Connection[type]
63
- schema[:middleware] = Middleware.new(&block)
64
- self
65
- end
66
-
67
- # Helper to declare operation, either default or specific
68
- #
69
- # @param [#to_sym] name (nil)
70
- # @param [Proc] block
71
- # @return [self]
72
- #
73
- def operation(name = nil, &block)
74
- schema[:operations].register(name, &block)
75
- self
76
- end
77
-
78
- # Helper to define scopes of the client's top-level DSL
79
- #
80
- # @param [#to_sym] name (:[])
81
- # @param [Proc] block
82
- # @return [self]
83
- #
84
- def scope(name = :[], &block)
85
- klass = Class.new(Scope, &block)
86
- define_method(name) do |*args, **options|
87
- klass.new(*args, __scope__: self, **options)
88
- end
89
- self
90
- end
91
-
92
- # Takes constructor arguments and builds a final schema for an instance
93
- # (All the instantiation magics goes here)
94
- #
95
- # @param [Object] *args
96
- # @return [Hash<Symbol, Object>]
97
- #
98
- def new(*args)
99
- settings = schema[:settings].new(*args)
100
- base_url = schema[:base_url].call(settings)
101
- middleware = schema[:middleware].finalize(settings)
102
- operations = schema[:operations].finalize(settings)
103
- client = schema[:connection].new URI(base_url)
104
- connection = Middleware.prepend.(middleware.(Middleware.append.(client)))
105
-
106
- data = operations.each_with_object({}) do |(key, schema), hash|
107
- hash[key] = Evil::Client::Operation.new schema, connection
108
- end
109
-
110
- super(settings, base_url, data)
111
- end
112
-
113
- private
114
-
115
- BASE_URL = proc { raise NotImplementedError.new "Base url is not defined" }
116
-
117
- def schema
118
- @schema ||= {
119
- settings: Class.new,
120
- base_url: BASE_URL,
121
- connection: Connection[nil],
122
- middleware: Middleware.new,
123
- operations: Operations.new
124
- }
125
- end
126
- end
127
- end
@@ -1,26 +0,0 @@
1
- module Evil::Client::DSL
2
- class Base
3
- def self.[](schema, *args, &block)
4
- new(*args, &block).call(schema)
5
- end
6
-
7
- def call(schema)
8
- schema
9
- end
10
-
11
- private
12
-
13
- def merge(source, target)
14
- target.inject(source) do |obj, (key, val)|
15
- obj.merge key => (Hash === val ? merge(obj.fetch(key, {}), val) : val)
16
- end
17
- end
18
-
19
- def coercer
20
- @coercer ||= if @model && @block then Class.new(@model, &@block)
21
- elsif @block then Class.new(Evil::Struct, &@block)
22
- elsif @model then @model
23
- end
24
- end
25
- end
26
- end
@@ -1,37 +0,0 @@
1
- module Evil::Client::DSL
2
- # Nested definition for attached files
3
- class Files
4
- # Builds a final upload schema from 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 files @schema
26
- # ==========================================================================
27
-
28
- def add(data, type: "text/plain", charset: "utf-8", filename: nil, **)
29
- @schema << {
30
- file: data.respond_to?(:read) ? data : StringIO.new(data),
31
- type: MIME::Types[type].first,
32
- charset: charset,
33
- filename: filename
34
- }
35
- end
36
- end
37
- end