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
data/docs/license.md CHANGED
@@ -1,4 +1,8 @@
1
- Copyright (c) 2016 Andrew Kozin (aka nepalez), andrew.kozin@gmail.com
1
+ # The MIT License (MIT)
2
+
3
+ Copyright (c) 2015-2017 Andrew Kozin (nepalez),
4
+ Ravil Bairamgalin (brainopia),
5
+ Evil Martians (evilmartians)
2
6
 
3
7
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
8
  of this software and associated documentation files (the "Software"), to deal
data/docs/rspec.md ADDED
@@ -0,0 +1,96 @@
1
+ When you provide a client to remote API, you would provide some means for its users to test their operations.
2
+
3
+ Surely, they could use [webmock] to check the ultimate requests that are sent to the server. But doing this, they would inadvertedly specify not their own code, but your client's code too. What do they actually need is a means to check calls of your client's operations. This way they would back on correctness of your client, and take its interface as an endpoint.
4
+
5
+ For this reason, we support a special RSpec matcher `perform_operation`. It checks, what operations are called via evil-client, and what options are used in there.
6
+
7
+ The matcher isn't loaded by default, so you must require it first:
8
+
9
+ ```ruby
10
+ require "evil/client/rspec"
11
+ ```
12
+
13
+ Providing that you defined some client...
14
+
15
+ ```ruby
16
+ class CatsClient < Evil::Client
17
+ option :token
18
+ # ...
19
+ scope :cats do
20
+ option :version
21
+ # ...
22
+ operation :fetch do
23
+ option :id
24
+ # ...
25
+ end
26
+ end
27
+ end
28
+ ```
29
+
30
+ ... lets write a specification:
31
+
32
+ ```ruby
33
+ require "evil/client/rspec"
34
+
35
+ RSpec.describe CatsClient, "cats.fetch" do
36
+ let(:client) { CatsClient.new(token: "foo") }
37
+ let(:scope) { client.cats(version: 1) }
38
+
39
+ it "fetches a cat by id" do
40
+ expect { scope.fetch(id: 8) }
41
+ .to perform_operation("CatsClient.client.fetch")
42
+ end
43
+ end
44
+ ```
45
+
46
+ You can add chaining using one of 3 additional methods: `with`, `with_exactly`, or `without`.
47
+
48
+ ## with
49
+
50
+ This method checks that the operation **includes some options**:
51
+
52
+ ```ruby
53
+ expect { scope.fetch(id: 8) }
54
+ .to perform_operation("CatsClient.client.fetch")
55
+ .with token: "foo"
56
+ ```
57
+
58
+ ## with_exactly
59
+
60
+ This time you can check the full list of options given to operation:
61
+
62
+ ```ruby
63
+ expect { scope.fetch(id: 8) }
64
+ .to perform_operation("CatsClient.client.fetch")
65
+ .with_exactly token: "foo", version: 1, id: 8
66
+ ```
67
+
68
+ ## without
69
+
70
+ You can also check that some keys are absent:
71
+
72
+ ```ruby
73
+ expect { scope.fetch(id: 8) }
74
+ .to perform_operation("CatsClient.client.fetch")
75
+ .without :name, :email
76
+ ```
77
+
78
+ This can be useful to check a behaviour of the client with optional attributes.
79
+
80
+ All checks can be negated as well:
81
+
82
+ ```ruby
83
+ expect { scope.fetch(id: 8) }
84
+ .not_to perform_operation("CatsClient.client.fetch")
85
+ .with token: "foo"
86
+ ```
87
+
88
+ **Notice**: Under the hood the matcher doesn't stub the request, so its better to stub all requests by hand:
89
+
90
+ ```ruby
91
+ require "webmock/rspec"
92
+
93
+ before { stub_request :any, // }
94
+ ```
95
+
96
+ [webmock]: https://github.com/bblimke/webmock
data/evil-client.gemspec CHANGED
@@ -1,8 +1,8 @@
1
1
  Gem::Specification.new do |gem|
2
2
  gem.name = "evil-client"
3
- gem.version = "0.3.3"
3
+ gem.version = "1.0.0"
4
4
  gem.author = ["Andrew Kozin (nepalez)", "Ravil Bairamgalin (brainopia)"]
5
- gem.email = "andrew.kozin@gmail.com"
5
+ gem.email = ["andrew.kozin@gmail.com", "nepalez@evilmartians.com"]
6
6
  gem.homepage = "https://github.com/evilmartians/evil-client"
7
7
  gem.summary = "Human-friendly DSL for building HTTP(s) clients in Ruby"
8
8
  gem.license = "MIT"
@@ -13,13 +13,15 @@ Gem::Specification.new do |gem|
13
13
 
14
14
  gem.required_ruby_version = ">= 2.3"
15
15
 
16
- gem.add_runtime_dependency "evil-struct", ">= 0.0.2"
17
- gem.add_runtime_dependency "mime-types", "> 1"
18
- gem.add_runtime_dependency "rack", ">= 1", "< 3"
16
+ gem.add_runtime_dependency "dry-initializer", "~> 1.4"
17
+ gem.add_runtime_dependency "i18n", "~> 0.8.6"
18
+ gem.add_runtime_dependency "mime-types", "~> 3.1"
19
+ gem.add_runtime_dependency "rack", "~> 1"
19
20
 
20
- gem.add_development_dependency "dry-types", "~> 0.9"
21
+ gem.add_development_dependency "rake", ">= 10"
21
22
  gem.add_development_dependency "rspec", "~> 3.0"
22
- gem.add_development_dependency "rake", "~> 11"
23
+ gem.add_development_dependency "rspec-its", "~> 1.2"
24
+ gem.add_development_dependency "rubocop", "~> 0.42"
25
+ gem.add_development_dependency "timecop", "~> 0.9"
23
26
  gem.add_development_dependency "webmock", "~> 2.1"
24
- gem.add_development_dependency "rubocop", "~> 0.44"
25
27
  end
data/lib/evil/client.rb CHANGED
@@ -1,83 +1,137 @@
1
- require "evil-struct"
2
- require "mime-types"
1
+ require "uri"
2
+ require "logger"
3
3
  require "rack"
4
+ require "cgi"
4
5
  require "json"
6
+ require "yaml"
7
+ require "i18n"
8
+ require "mime-types"
5
9
  require "securerandom"
6
-
7
- # Absctract base class for clients to remote APIs
8
- #
9
- # @abstract
10
- # @example
11
- # class MyClient < Evil::Client
12
- # # declare settings for the client's constructor
13
- # # the settings parameterize the rest of the client's definitions
14
- # settings do
15
- # option :version, type: Dry::Types["strict.int"].default(1)
16
- # option :user, type: Dry::Types["strict.string"]
17
- # option :token, type: Dry::Types["strict.string"]
18
- # end
19
- #
20
- # # define base url of the server
21
- # base_url do |settings|
22
- # "https://my_api.com/v#{settings.version}"
23
- # end
24
- #
25
- # # define connection and its middleware stack from bottom to top
26
- # connection :net_http do |settings|
27
- # run AddCustomRequestId
28
- # run EncryptToken if settings.token
29
- # end
30
- #
31
- # # definitions shared by all operations (can be reloaded later)
32
- # operation do |settings|
33
- # type { :json }
34
- # security { basic_auth "foo", "bar" }
35
- # end
36
- #
37
- # # operation-specific definitions
38
- # operation :find_cat do |settings|
39
- # http_method :get
40
- # path { "#{settings.url}/cats/find/#{id}" }
10
+ require "dry-initializer"
11
+ require "net/http"
12
+ require "net/https"
41
13
  #
42
- # query do
43
- # option :id, type: Dry::Types["coercible.int"].constrained(gt: 0)
44
- # end
45
- #
46
- # response 200, type: Cat
47
- # response 400, raise: true
48
- # response 422, raise: true do |body:|
49
- # JSON.parse(body.first)
50
- # end
51
- # end
52
- #
53
- # # top-level DSL for operation
54
- # scope :users do
55
- # scope do # named `:[]` by default
56
- # param :id, type: Dry::Types["strict.int"]
57
- #
58
- # def get
59
- # operations[:find_users].call(id: id)
60
- # end
61
- # end
62
- # end
63
- # end
64
- #
65
- # # Initialize a client with a corresponding settings
66
- # client = MyClient.new user: "andrew", token: "f982j23"
67
- #
68
- # # Use low-level DSL for searching a user
69
- # client.operations[:find_user].call(id: 1)
70
- #
71
- # # Use top-level DSL for the same operation
72
- # client.users[1].get
14
+ # Namespace for gems created by Evil Martians
73
15
  #
74
16
  module Evil
17
+ #
18
+ # Absctract base class for clients to remote APIs
19
+ #
75
20
  class Client
21
+ require_relative "client/exceptions/definition_error"
22
+ require_relative "client/exceptions/name_error"
23
+ require_relative "client/exceptions/response_error"
24
+ require_relative "client/exceptions/type_error"
25
+ require_relative "client/exceptions/validation_error"
26
+
27
+ require_relative "client/chaining"
28
+ require_relative "client/settings"
29
+ require_relative "client/schema"
30
+ require_relative "client/container"
31
+ require_relative "client/builder"
76
32
  require_relative "client/connection"
77
- require_relative "client/middleware"
78
- require_relative "client/operation"
79
- require_relative "client/dsl"
33
+ require_relative "client/formatter"
34
+ require_relative "client/resolver"
35
+
36
+ include Chaining
37
+
38
+ class << self
39
+ # Object used as an HTTP(s) connection to remote API
40
+ #
41
+ # It is expected to implement the method [#call] which
42
+ # should take one argument for a rack-compatible request environment,
43
+ # and return a rack-compatible response.
44
+ #
45
+ # By default the connection is set to [Evil::Client::Connection],
46
+ # but it can be redefined for a custom client.
47
+ #
48
+ # @return [#call] connection (Evil::Client::Connection)
49
+ #
50
+ def connection
51
+ @connection ||= Evil::Client::Connection
52
+ end
53
+
54
+ # Sets a custom connection, or resets it to a default one
55
+ #
56
+ # @param [#call, nil] connection
57
+ # @return [self]
58
+ #
59
+ def connection=(connection)
60
+ @connection = connection
61
+ self
62
+ end
63
+
64
+ # Schema for the root scope of the client
65
+ #
66
+ # @return [Evil::Client::Schema::Scope]
67
+ #
68
+ def schema
69
+ @schema ||= Schema::Scope.new(self)
70
+ end
71
+
72
+ private
73
+
74
+ def respond_to_missing?(name, *)
75
+ schema.respond_to? name
76
+ end
77
+
78
+ def method_missing(*args, &block)
79
+ respond_to_missing?(*args) ? schema.send(*args, &block) : super
80
+ end
81
+ end
82
+
83
+ # Initialized root scope container
84
+ #
85
+ # @return [Evil::Client::Container::Scope]
86
+ #
87
+ attr_reader :scope
88
+
89
+ # Logger for the root scope
90
+ #
91
+ # @return (see Evil::Client::Settings#logger)
92
+ #
93
+ def logger
94
+ @scope.logger
95
+ end
96
+
97
+ # Sets logger to the client
98
+ #
99
+ # @param [Logger, nil] logger
100
+ # @return [self]
101
+ #
102
+ def logger=(logger)
103
+ @scope.logger = logger
104
+ self
105
+ end
106
+
107
+ # Operations defined at the root of the client
108
+ #
109
+ # @return (see Evil::Client::Container::Scope#operations)
110
+ #
111
+ def operations
112
+ @scope.operations
113
+ end
114
+
115
+ # Subscopes of client root
116
+ #
117
+ # @return (see Evil::Client::Container::Scope#scopes)
118
+ #
119
+ def scopes
120
+ @scope.scopes
121
+ end
122
+
123
+ # Options assigned to the client
124
+ #
125
+ # @return (see Evil::Client::Container#options)
126
+ #
127
+ def options
128
+ @scope.options
129
+ end
130
+
131
+ private
80
132
 
81
- extend DSL
133
+ def initialize(**options)
134
+ @scope = Container::Scope.new self.class.send(:schema), options
135
+ end
82
136
  end
83
137
  end
@@ -0,0 +1,47 @@
1
+ class Evil::Client
2
+ #
3
+ # @abstract
4
+ # Base class for scope/operation builders
5
+ #
6
+ # Every builder just wraps scope/operation schema along with
7
+ # preinitialized [#parent] settings of its super-scope.
8
+ # The instance method [#new] quacks like the lazy constructor
9
+ # for scope/operation instance whose options reload the [#parent]'s ones.
10
+ #
11
+ class Builder
12
+ # Load concrete implementations for the abstact builder
13
+ require_relative "builder/scope"
14
+ require_relative "builder/operation"
15
+
16
+ # The schema for an instance to be constructed via [#new]
17
+ # @return [Evil::Client::Schema]
18
+ attr_reader :schema
19
+
20
+ # The instance of parent scope carrying default settings
21
+ # @return [Evil::Client::Container::Scope]
22
+ attr_reader :parent
23
+
24
+ # Alias method for [#to_s]
25
+ #
26
+ # @return [String]
27
+ #
28
+ def to_str
29
+ to_s
30
+ end
31
+
32
+ # Alias method for [#to_s]
33
+ #
34
+ # @return [String]
35
+ #
36
+ def inspect
37
+ to_s
38
+ end
39
+
40
+ private
41
+
42
+ def initialize(schema, parent)
43
+ @schema = schema
44
+ @parent = parent
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,40 @@
1
+ class Evil::Client
2
+ #
3
+ # Lazy container for a [#schema] and [#parent] settings
4
+ # of a [#new] operation to be initialized with its own options,
5
+ # that reload the [#parent] ones.
6
+ #
7
+ class Builder::Operation < Builder
8
+ # Human-readable representation of the handler
9
+ #
10
+ # @example
11
+ # '#<MyClient.scopes[:users] @version="1.1">.operations[:fetch]'
12
+ #
13
+ # @return [String]
14
+ #
15
+ def to_s
16
+ "#{parent}.operations[:#{schema.name}]"
17
+ end
18
+
19
+ # @!method new(options)
20
+ # Builds new operation with options reloading those of its [#parent]
21
+ #
22
+ # @param [Hash<Symbol, Object>] options ({}) Custom options
23
+ # @return [Evil::Client::Container::Operation]
24
+ #
25
+ def new(**options)
26
+ Container::Operation.new schema, parent.options.merge(options)
27
+ end
28
+
29
+ # @!method call(options)
30
+ # Builds and calls operation at once
31
+ #
32
+ # @param (see #new)
33
+ # @return (see Container::Operation#call)
34
+ #
35
+ def call(**options)
36
+ new(**options).call
37
+ end
38
+ alias_method :[], :call
39
+ end
40
+ end
@@ -0,0 +1,31 @@
1
+ class Evil::Client
2
+ #
3
+ # Lazy container for a [#schema] and [#parent] settings
4
+ # of a [#new] scope to be initialized with its own options,
5
+ # that reload the [#parent] ones.
6
+ #
7
+ class Builder::Scope < Builder
8
+ # Human-readable representation of the handler
9
+ #
10
+ # @example
11
+ # '#<MyClient.scopes[:crm] @version="1.1">.scopes[:users]'
12
+ #
13
+ # @return [String]
14
+ #
15
+ def to_s
16
+ "#{parent}.scopes[:#{schema.name}]"
17
+ end
18
+
19
+ # @!method new(options)
20
+ # Builds new scope with options reloading those of its [#parent]
21
+ #
22
+ # @param [Hash<Symbol, Object>] options Custom options
23
+ # @return [Evil::Client::Container::Scope]
24
+ #
25
+ def new(**options)
26
+ Container::Scope.new schema, parent.options.merge(options)
27
+ end
28
+ alias_method :call, :new
29
+ alias_method :[], :new
30
+ end
31
+ end