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
@@ -0,0 +1,94 @@
1
+ RSpec.describe "operation request" do
2
+ before { load "spec/fixtures/test_client.rb" }
3
+ before { stub_request(:any, //) }
4
+
5
+ let(:users) do
6
+ Test::Client.new(subdomain: "europe", user: "andy", password: "foo")
7
+ .crm(version: 4)
8
+ .users
9
+ end
10
+
11
+ shared_examples :valid_client do |details = "properly"|
12
+ let(:request) { a_request(meth, path).with(body: body, headers: head) }
13
+
14
+ it "[builds a request #{details}]" do
15
+ subject
16
+ expect(request).to have_been_made
17
+ end
18
+ end
19
+
20
+ it_behaves_like :valid_client do
21
+ subject { users.fetch id: 87 }
22
+
23
+ let(:path) { "https://europe.example.com/crm/v4/users/87" }
24
+ let(:meth) { :get }
25
+ let(:body) { nil }
26
+ let(:head) { { "Content-Type" => "application/json" } }
27
+ end
28
+
29
+ it_behaves_like :valid_client, "using current definition" do
30
+ subject { users.filter id: 89 }
31
+
32
+ let(:path) { "https://europe.example.com/crm/v4/users" }
33
+ let(:meth) { :get }
34
+ let(:body) { nil }
35
+ let(:head) { { "Content-Type" => "application/json" } }
36
+ end
37
+
38
+ it_behaves_like :valid_client, "with a proper query" do
39
+ subject { users.create id: 89, name: "Andy", language: :de }
40
+
41
+ let(:path) { "https://europe.example.com/crm/v4/users?language=de" }
42
+ let(:meth) { :post }
43
+ let(:body) { '{"name":"Andy"}' }
44
+ let(:head) do
45
+ {
46
+ "Authorization" => "Basic YW5keTpmb28=",
47
+ "Content-Type" => "application/json"
48
+ }
49
+ end
50
+ end
51
+
52
+ it_behaves_like :valid_client, "with a proper query" do
53
+ subject { users.create id: 89, name: "Andy", language: :de }
54
+
55
+ let(:path) { "https://europe.example.com/crm/v4/users?language=de" }
56
+ let(:meth) { :post }
57
+ let(:body) { '{"name":"Andy"}' }
58
+ let(:head) do
59
+ {
60
+ "Authorization" => "Basic YW5keTpmb28=",
61
+ "Content-Type" => "application/json"
62
+ }
63
+ end
64
+ end
65
+
66
+ it_behaves_like :valid_client, "using current settings" do
67
+ subject { users.update id: 89, name: "Joe", language: "it" }
68
+
69
+ let(:path) { "https://europe.example.com/crm/v4/users/89?language=it" }
70
+ let(:meth) { :patch }
71
+ let(:body) { '{"name":"Joe"}' }
72
+ let(:head) { {} }
73
+ let(:head) do
74
+ {
75
+ "Authorization" => "Basic YW5keTpmb28=",
76
+ "Content-Type" => "application/json"
77
+ }
78
+ end
79
+ end
80
+
81
+ it_behaves_like :valid_client, "using reloaded settings" do
82
+ subject { users.update id: 89, name: "Joe", language: "it", version: 0 }
83
+
84
+ let(:path) { "https://europe.example.com/crm/v0/users/89?language=it" }
85
+ let(:meth) { :put }
86
+ let(:body) { "name=Joe" }
87
+ let(:head) do
88
+ {
89
+ "Authorization" => "Basic YW5keTpmb28=",
90
+ "Content-Type" => "application/x-www-form-urlencoded"
91
+ }
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,48 @@
1
+ RSpec.describe "operation request" do
2
+ before do
3
+ load "spec/fixtures/test_client.rb"
4
+ stub_request(:any, //)
5
+ .to_return(status: status, body: raw_body, headers: {})
6
+ end
7
+
8
+ let(:status) { 200 }
9
+ let(:raw_body) { '{"id":3,"name":"andy"}' }
10
+ let(:users) do
11
+ Test::Client.new(subdomain: "europe", user: "andy", password: "foo")
12
+ .crm(version: 4)
13
+ .users
14
+ end
15
+
16
+ shared_examples :valid_client do |details = "properly"|
17
+ it "[processes a response #{details}]" do
18
+ expect(subject).to eq response
19
+ end
20
+ end
21
+
22
+ it_behaves_like :valid_client do
23
+ subject { users.fetch(id: 3) }
24
+ let(:response) { [200, {}, [raw_body]] }
25
+ end
26
+
27
+ it_behaves_like :valid_client, "using operation-specific handler" do
28
+ subject { users.filter(id: 3) }
29
+ let(:response) { [{ "id" => 3, "name" => "andy" }] }
30
+ end
31
+
32
+ context "when handler raises an exception" do
33
+ let(:status) { 404 }
34
+
35
+ it "raises the original exception" do
36
+ expect { users.fetch(id: 3) }.to raise_error RuntimeError, /Not found/
37
+ end
38
+ end
39
+
40
+ context "when server responded with unexpected status" do
41
+ let(:status) { 403 }
42
+
43
+ it "raises Evil::Client::ResponseError" do
44
+ expect { users.fetch(id: 3) }
45
+ .to raise_error Evil::Client::ResponseError, /403/
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,52 @@
1
+ RSpec.describe "scope options" do
2
+ before { load "spec/fixtures/test_client.rb" }
3
+
4
+ let(:params) { { subdomain: "europe", user: "andy", token: "foo", foo: 0 } }
5
+ let(:client) { Test::Client.new(params) }
6
+ let(:crm) { client.crm(version: 4) }
7
+
8
+ shared_examples :valid_client do |details = "properly"|
9
+ it "[assigns scope options #{details}]" do
10
+ expect(subject.options).to eq options
11
+ end
12
+ end
13
+
14
+ it_behaves_like :valid_client, "with defined options" do
15
+ subject { crm.users }
16
+ let(:options) do
17
+ { subdomain: "europe", user: "andy", token: "foo", version: 4 }
18
+ end
19
+ end
20
+
21
+ it_behaves_like :valid_client, "with reloaded scope options" do
22
+ subject { crm.users(version: 8) }
23
+ let(:options) do
24
+ { subdomain: "europe", user: "andy", token: "foo", version: 8 }
25
+ end
26
+ end
27
+
28
+ it_behaves_like :valid_client, "with reloaded root options" do
29
+ subject { crm.users(user: "leo") }
30
+ let(:options) do
31
+ { subdomain: "europe", user: "leo", token: "foo", version: 4 }
32
+ end
33
+ end
34
+
35
+ context "when required options missed" do
36
+ subject { client.crm }
37
+
38
+ it "raises Evil::Client::ValidationError" do
39
+ expect { subject }
40
+ .to raise_error Evil::Client::ValidationError, /version/
41
+ end
42
+ end
43
+
44
+ context "when some validation failed" do
45
+ subject { crm.users(token: nil) }
46
+
47
+ it "raises Evil::Client::ValidationError" do
48
+ expect { subject }
49
+ .to raise_error Evil::Client::ValidationError, /token/
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,16 @@
1
+ ---
2
+ en:
3
+ evil:
4
+ client:
5
+ errors:
6
+ test/api:
7
+ users:
8
+ update:
9
+ token_present: "To update user id:%{id} you must provide a token"
10
+ name_present: "The user has no name"
11
+ test/client:
12
+ valid_credentials: You should set either token or password to authenticate the client
13
+ crm:
14
+ users:
15
+ filter:
16
+ filter_given: You should define some filter with either name, email, or id
@@ -0,0 +1,76 @@
1
+ module Test
2
+ class Client < Evil::Client
3
+ option :subdomain
4
+ option :user
5
+ option :token, optional: true
6
+ option :password, optional: true
7
+ validate(:valid_credentials) { token.nil? ^ password.nil? }
8
+
9
+ path { "https://#{subdomain}.example.com" }
10
+
11
+ response(200)
12
+ response(404) { raise "Not found" }
13
+ response(500) { raise "Server error" }
14
+
15
+ scope :crm do
16
+ option :version, defaul: proc { 1 }
17
+ format { version.to_i > 2 ? :json : :form }
18
+ path { "crm/v#{version}" }
19
+
20
+ scope :users do
21
+ path "users"
22
+
23
+ operation :filter do
24
+ option :name, optional: true
25
+ option :id, optional: true
26
+ option :email, optional: true
27
+
28
+ validate(:filter_given) { name || id || email }
29
+
30
+ http_method :get
31
+ response(200) { |*res| res.last.flat_map { |item| JSON.parse(item) } }
32
+ end
33
+
34
+ operation :fetch do
35
+ option :id
36
+
37
+ path { id }
38
+ http_method :get
39
+ end
40
+
41
+ operation :create do
42
+ option :name
43
+ option :language
44
+ option :email, optional: true
45
+
46
+ http_method :post
47
+ security { token ? token_auth(token) : basic_auth(user, password) }
48
+ body { options.select { |k| %i[name email].include? k } }
49
+ query { { language: language } }
50
+ response 201
51
+ end
52
+
53
+ operation :update do
54
+ option :id
55
+ option :name
56
+ option :language
57
+ option :email, optional: true
58
+
59
+ path { id }
60
+ http_method { version > 2 ? :patch : :put }
61
+ security { token ? token_auth(token) : basic_auth(user, password) }
62
+ body { options.select { |k| %i[name email].include? k } }
63
+ query { { language: language } }
64
+ end
65
+
66
+ operation :drop do
67
+ option :id
68
+
69
+ path { id }
70
+ http_method { :delete }
71
+ security { token ? token_auth(token) : basic_auth(user, password) }
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
data/spec/spec_helper.rb CHANGED
@@ -4,20 +4,32 @@ rescue LoadError
4
4
  nil
5
5
  end
6
6
 
7
- require "evil/client"
8
- require "dry-types"
7
+ require "bundler/setup"
9
8
  require "webmock/rspec"
9
+ require "rspec/its"
10
+ require "timecop"
11
+ require "evil/client"
12
+ require "evil/client/rspec"
13
+
14
+ require_relative "support/fixtures_helper"
10
15
 
11
16
  RSpec.configure do |config|
12
17
  config.order = :random
13
18
  config.filter_run focus: true
14
19
  config.run_all_when_everything_filtered = true
15
20
 
16
- # Prepare the Test namespace for constants defined in specs
17
- config.around(:each) do |example|
21
+ config.before(:each) do
22
+ # Stub all requests using webmock
18
23
  stub_request(:any, //)
19
- load File.expand_path("../support/test_client.rb", __FILE__)
20
- example.run
24
+ # Prepare the Test namespace for constants defined in specs
25
+ module Test; end
26
+ # Load translations
27
+ en_translations = yaml_fixture_file "locales/en.yml"
28
+ I18n.available_locales = %i[en]
29
+ I18n.backend.store_translations :en, en_translations["en"]
30
+ end
31
+
32
+ config.after(:each) do
21
33
  Object.send :remove_const, :Test
22
34
  end
23
35
  end
@@ -0,0 +1,7 @@
1
+ def fixture_file_path(filename)
2
+ File.expand_path "spec/fixtures/#{filename}"
3
+ end
4
+
5
+ def yaml_fixture_file(filename)
6
+ YAML.load_file(fixture_file_path(filename))
7
+ end
@@ -0,0 +1,90 @@
1
+ RSpec.describe Evil::Client::Builder::Operation do
2
+ let(:builder) { described_class.new schema, parent }
3
+ let(:options) { { id: 83, password: "qux", age: 38 } }
4
+ let(:parent) { double :parent, options: { user: "foo", password: "bar" } }
5
+ let(:schema) { double :schema, name: "fetch", settings: settings }
6
+
7
+ let(:settings) do
8
+ Class.new(Evil::Client::Settings) do
9
+ option :id
10
+ option :user
11
+ option :password
12
+ end
13
+ end
14
+
15
+ describe "#to_s" do
16
+ subject { builder.to_s }
17
+
18
+ it "represents the builder in a human-friendly manner" do
19
+ expect(subject).to eq "#[Double :parent].operations[:fetch]"
20
+ end
21
+ end
22
+
23
+ describe "#to_str" do
24
+ subject { builder.to_str }
25
+
26
+ it "represents the builder in a human-friendly manner" do
27
+ expect(subject).to eq "#[Double :parent].operations[:fetch]"
28
+ end
29
+ end
30
+
31
+ describe "#inspect" do
32
+ subject { builder.inspect }
33
+
34
+ it "represents the builder in a human-friendly manner" do
35
+ expect(subject).to eq "#[Double :parent].operations[:fetch]"
36
+ end
37
+ end
38
+
39
+ describe "#schema" do
40
+ subject { builder.schema }
41
+
42
+ it "refers to the wrapped schema" do
43
+ expect(subject).to eq schema
44
+ end
45
+ end
46
+
47
+ describe "#parent" do
48
+ subject { builder.parent }
49
+
50
+ it "refers to wrapped parent" do
51
+ expect(subject).to eq parent
52
+ end
53
+ end
54
+
55
+ describe "#new" do
56
+ subject { builder.new options }
57
+
58
+ it "creates operation with inherited options accepted by settings" do
59
+ expect(subject).to be_a Evil::Client::Container::Operation
60
+ expect(subject.schema).to eq schema
61
+ expect(subject.options).to eq id: 83, user: "foo", password: "qux"
62
+ end
63
+ end
64
+
65
+ describe "#call" do
66
+ let(:operation) { double call: "success" }
67
+
68
+ before { allow(builder).to receive(:new) { operation } }
69
+ subject { builder.call options }
70
+
71
+ it "builds and calls the operation at once" do
72
+ expect(builder).to receive(:new).with options
73
+ expect(operation).to receive(:call)
74
+ expect(subject).to eq "success"
75
+ end
76
+ end
77
+
78
+ describe "#[]" do
79
+ let(:operation) { double call: "success" }
80
+
81
+ before { allow(builder).to receive(:new) { operation } }
82
+ subject { builder[options] }
83
+
84
+ it "is an alias for #call" do
85
+ expect(builder).to receive(:new).with options
86
+ expect(operation).to receive(:call)
87
+ expect(subject).to eq "success"
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,84 @@
1
+ RSpec.describe Evil::Client::Builder::Scope do
2
+ let(:builder) { described_class.new schema, parent }
3
+ let(:options) { { id: 83, password: "qux", age: 38 } }
4
+ let(:parent) { double :parent, options: { user: "foo", password: "bar" } }
5
+ let(:schema) { double :schema, name: "fetch", settings: settings }
6
+
7
+ let(:settings) do
8
+ Class.new(Evil::Client::Settings) do
9
+ option :id
10
+ option :user
11
+ option :password
12
+ end
13
+ end
14
+
15
+ describe "#to_s" do
16
+ subject { builder.to_s }
17
+
18
+ it "represents the builder in a human-friendly manner" do
19
+ expect(subject).to eq "#[Double :parent].scopes[:fetch]"
20
+ end
21
+ end
22
+
23
+ describe "#to_str" do
24
+ subject { builder.to_str }
25
+
26
+ it "represents the builder in a human-friendly manner" do
27
+ expect(subject).to eq "#[Double :parent].scopes[:fetch]"
28
+ end
29
+ end
30
+
31
+ describe "#inspect" do
32
+ subject { builder.inspect }
33
+
34
+ it "represents the builder in a human-friendly manner" do
35
+ expect(subject).to eq "#[Double :parent].scopes[:fetch]"
36
+ end
37
+ end
38
+
39
+ describe "#schema" do
40
+ subject { builder.schema }
41
+
42
+ it "refers to the wrapped schema" do
43
+ expect(subject).to eq schema
44
+ end
45
+ end
46
+
47
+ describe "#parent" do
48
+ subject { builder.parent }
49
+
50
+ it "refers to wrapped parent" do
51
+ expect(subject).to eq parent
52
+ end
53
+ end
54
+
55
+ describe "#new" do
56
+ subject { builder.new options }
57
+
58
+ it "creates scope with inherited options accepted by settings" do
59
+ expect(subject).to be_a Evil::Client::Container::Scope
60
+ expect(subject.schema).to eq schema
61
+ expect(subject.options).to eq id: 83, user: "foo", password: "qux"
62
+ end
63
+ end
64
+
65
+ describe "#call" do
66
+ subject { builder.call options }
67
+
68
+ it "creates scope with inherited options accepted by settings" do
69
+ expect(subject).to be_a Evil::Client::Container::Scope
70
+ expect(subject.schema).to eq schema
71
+ expect(subject.options).to eq id: 83, user: "foo", password: "qux"
72
+ end
73
+ end
74
+
75
+ describe "#[]" do
76
+ subject { builder[options] }
77
+
78
+ it "creates scope with inherited options accepted by settings" do
79
+ expect(subject).to be_a Evil::Client::Container::Scope
80
+ expect(subject.schema).to eq schema
81
+ expect(subject.options).to eq id: 83, user: "foo", password: "qux"
82
+ end
83
+ end
84
+ end