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
@@ -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