evil-client 0.3.0 → 0.3.1
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.
- checksums.yaml +4 -4
- data/.codeclimate.yml +12 -1
- data/.rubocop.yml +15 -6
- data/CHANGELOG.md +7 -0
- data/README.md +1 -1
- data/docs/headers.md +1 -1
- data/docs/index.md +1 -1
- data/docs/model.md +5 -5
- data/docs/query.md +1 -1
- data/evil-client.gemspec +5 -5
- data/lib/evil-client.rb +1 -0
- data/lib/evil/client.rb +2 -2
- data/lib/evil/client/dsl/operation.rb +1 -1
- data/lib/evil/client/dsl/response.rb +2 -3
- data/lib/evil/client/operation/response.rb +2 -2
- data/spec/features/operation_with_form_body_spec.rb +1 -1
- data/spec/features/operation_with_json_body_spec.rb +1 -1
- data/spec/features/operation_with_nested_responses_spec.rb +1 -1
- data/spec/features/operation_with_query_spec.rb +1 -1
- data/spec/features/scoping_spec.rb +1 -1
- data/spec/unit/evil/client/dsl/operation_spec.rb +8 -8
- data/spec/unit/evil/client/operation/request_spec.rb +3 -3
- metadata +23 -18
- data/lib/evil/client/model.rb +0 -69
- data/spec/unit/evil/client/model_spec.rb +0 -100
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1993a11c6b8086dec9802e02c4beeb56e8aadef3
|
4
|
+
data.tar.gz: 273f6c22939793760abc5bbae79681c03490116b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d639bf5c2a2e8e1362df945d6416cc012052ea653ee8103eaeb7548c9e733aeaa400e3d7fa3c6eafee617a496c6edcfc581e22eb2dca31f003c175c716cca1b
|
7
|
+
data.tar.gz: 07011a575fdbbe193f280fe2cc68c0556547092b752fa617f5d40e1524bb26ee30b207efe4d98f217e1a38997772c8889cc5014ff026be35122e89338e822507
|
data/.codeclimate.yml
CHANGED
@@ -4,4 +4,15 @@ engines:
|
|
4
4
|
enabled: true
|
5
5
|
checks:
|
6
6
|
Rubocop/Style/FrozenStringLiteralComment:
|
7
|
-
enabled: false
|
7
|
+
enabled: false
|
8
|
+
Rubocop/Style/Documentation:
|
9
|
+
enabled: false
|
10
|
+
Rubocop/Style/ClassAndModuleChildren:
|
11
|
+
enabled: false
|
12
|
+
Rubocop/Style/SpaceInLambdaLiteral:
|
13
|
+
enabled: false
|
14
|
+
Style/SingleLineBlockParams:
|
15
|
+
enabled: false
|
16
|
+
ratings:
|
17
|
+
paths:
|
18
|
+
- "lib/**.rb"
|
data/.rubocop.yml
CHANGED
@@ -8,21 +8,23 @@ AllCops:
|
|
8
8
|
Style/Alias:
|
9
9
|
Enabled: false
|
10
10
|
|
11
|
-
Style/
|
12
|
-
|
11
|
+
Style/FileName:
|
12
|
+
Exclude:
|
13
|
+
- lib/evil-client.rb
|
13
14
|
|
14
15
|
Style/Documentation:
|
15
16
|
Enabled: false
|
16
17
|
|
17
|
-
Style/DoubleNegation:
|
18
|
-
Enabled: false
|
19
|
-
|
20
18
|
Style/LambdaCall:
|
21
19
|
Enabled: false
|
22
20
|
|
23
21
|
Style/MethodMissing:
|
24
22
|
Enabled: false
|
25
23
|
|
24
|
+
Style/MultilineMethodCallIndentation:
|
25
|
+
Exclude:
|
26
|
+
- spec/**.rb
|
27
|
+
|
26
28
|
Style/NumericPredicate:
|
27
29
|
Enabled: false
|
28
30
|
|
@@ -32,12 +34,19 @@ Style/RaiseArgs:
|
|
32
34
|
Style/RescueModifier:
|
33
35
|
Enabled: false
|
34
36
|
|
37
|
+
Style/SingleLineBlockParams:
|
38
|
+
Enabled: false
|
39
|
+
|
35
40
|
Style/SingleLineMethods:
|
36
41
|
Exclude:
|
37
|
-
- spec
|
42
|
+
- spec/**.rb
|
38
43
|
|
39
44
|
Style/StringLiterals:
|
40
45
|
EnforcedStyle: double_quotes
|
41
46
|
|
42
47
|
Style/StringLiteralsInInterpolation:
|
43
48
|
EnforcedStyle: double_quotes
|
49
|
+
|
50
|
+
Style/SymbolProc:
|
51
|
+
Exclude:
|
52
|
+
- spec/**.rb
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
# v0.3.1 2016-11-20
|
2
|
+
|
3
|
+
## Internal
|
4
|
+
- Class `Evil::Client::Model` is extracted to `evil-struct` gem (nepalez)
|
5
|
+
|
6
|
+
[Compare v0.3.0...v0.3.1](https://github.com/dry-rb/dry-initializer/compare/v0.3.0...v0.3.1)
|
7
|
+
|
1
8
|
# v0.3.0 2016-11-18
|
2
9
|
|
3
10
|
This version changes the way of processing responses. Instead of dealing
|
data/README.md
CHANGED
@@ -53,7 +53,7 @@ require "dry-types"
|
|
53
53
|
|
54
54
|
class CatsClient < Evil::Client
|
55
55
|
# describe a client-specific model of cat (the furry pinnacle of evolution)
|
56
|
-
class Cat < Evil::
|
56
|
+
class Cat < Evil::Struct
|
57
57
|
attribute :name, type: Dry::Types["strict.string"], optional: true
|
58
58
|
attribute :color, type: Dry::Types["strict.string"]
|
59
59
|
attribute :age, type: Dry::Types["coercible.int"], default: proc { 0 }
|
data/docs/headers.md
CHANGED
@@ -9,7 +9,7 @@ operation :find_cat do |settings|
|
|
9
9
|
end
|
10
10
|
```
|
11
11
|
|
12
|
-
The syntax of the attribute declaration is exactly the same as of [Evil::
|
12
|
+
The syntax of the attribute declaration is exactly the same as of [Evil::Struct][model]. Type constraints and default values are available.
|
13
13
|
|
14
14
|
All values for the headers will be taken from a request options:
|
15
15
|
|
data/docs/index.md
CHANGED
@@ -42,7 +42,7 @@ require "dry-types"
|
|
42
42
|
|
43
43
|
class CatsClient < Evil::Client
|
44
44
|
# describe a client-specific model of cat (the furry pinnacle of evolution)
|
45
|
-
class Cat < Evil::
|
45
|
+
class Cat < Evil::Struct
|
46
46
|
attribute :name, type: Dry::Types["strict.string"], optional: true
|
47
47
|
attribute :color, type: Dry::Types["strict.string"]
|
48
48
|
attribute :age, type: Dry::Types["coercible.int"], default: proc { 0 }
|
data/docs/model.md
CHANGED
@@ -4,10 +4,10 @@ They are needed to prepare and validate nested bodies and queries, as well as wr
|
|
4
4
|
|
5
5
|
# Model Definition
|
6
6
|
|
7
|
-
To define a model create a subclass of `Evil::
|
7
|
+
To define a model create a subclass of `Evil::Struct` and define its attributes.
|
8
8
|
|
9
9
|
```ruby
|
10
|
-
class Cat < Evil::
|
10
|
+
class Cat < Evil::Struct
|
11
11
|
attribute :name, type: Dry::Types["strict.string"], optional: true
|
12
12
|
attribute :age, type: Dry::Types["coercible.int"], default: proc { 0 }
|
13
13
|
attribute :color, type: Dry::Types["strict.string"]
|
@@ -40,7 +40,7 @@ Cat.new("name" => "Navuxodonosor II", "age" => 15, "color" => "black")
|
|
40
40
|
You can use other (nested) models in type definitions:
|
41
41
|
|
42
42
|
```ruby
|
43
|
-
class CatPack < Evil::
|
43
|
+
class CatPack < Evil::Struct
|
44
44
|
attribute :cats, type: Dry::Types["array"].member(Cat)
|
45
45
|
end
|
46
46
|
|
@@ -102,7 +102,7 @@ Nethertheless, there is an important difference between the implementations of n
|
|
102
102
|
|
103
103
|
The main reason to define gem-specific model is the following. In `Dry::Struct` both the `optional` and `default` properties belong to value type constraint. The gem does not draw the line between attributes that are not set, and those that are set to `nil`.
|
104
104
|
|
105
|
-
To the contrary, in [dry-initializer][dry-initializer] and `Evil::
|
105
|
+
To the contrary, in [dry-initializer][dry-initializer] and `Evil::Struct` both `optional` and `default` properties describe not a value type by itself, but its relation to the model. An attribute value can be set to `nil`, or been kept in undefined state.
|
106
106
|
|
107
107
|
Let's see the difference on the example of `StructCat` and `ModelCat`:
|
108
108
|
|
@@ -112,7 +112,7 @@ class StructCat < Dry::Struct
|
|
112
112
|
attribute :age, type: Dry::Types["coercible.int"].default(0)
|
113
113
|
end
|
114
114
|
|
115
|
-
class ModelCat < Evil::
|
115
|
+
class ModelCat < Evil::Struct
|
116
116
|
attribute :name, type: Dry::Types["strict.string"], optional: true
|
117
117
|
attribute :age, type: Dry::Types["coercible.int"], default: proc { 0 }
|
118
118
|
end
|
data/docs/query.md
CHANGED
@@ -30,7 +30,7 @@ Non-unicode symbols are encoded as defined in [RFC-3986][rfc-3986]
|
|
30
30
|
Use [models][model] to provide validation of query data:
|
31
31
|
|
32
32
|
```ruby
|
33
|
-
class Cat < Evil::
|
33
|
+
class Cat < Evil::Struct
|
34
34
|
attribute :name, type: Dry::Types["strict.string"], optional: true
|
35
35
|
attribute :age, type: Dry::Types["strict.int"], default: proc { 0 }
|
36
36
|
attribute :color, type: Dry::Types["strict.string"]
|
data/evil-client.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |gem|
|
2
2
|
gem.name = "evil-client"
|
3
|
-
gem.version = "0.3.
|
4
|
-
gem.author = "Andrew Kozin (nepalez)"
|
3
|
+
gem.version = "0.3.1"
|
4
|
+
gem.author = ["Andrew Kozin (nepalez)", "Ravil Bairamgalin (brainopia)"]
|
5
5
|
gem.email = "andrew.kozin@gmail.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"
|
@@ -13,9 +13,9 @@ Gem::Specification.new do |gem|
|
|
13
13
|
|
14
14
|
gem.required_ruby_version = ">= 2.3"
|
15
15
|
|
16
|
-
gem.add_runtime_dependency "
|
17
|
-
gem.add_runtime_dependency "mime-types", "
|
18
|
-
gem.add_runtime_dependency "rack", "
|
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"
|
19
19
|
|
20
20
|
gem.add_development_dependency "dry-types", "~> 0.9"
|
21
21
|
gem.add_development_dependency "rspec", "~> 3.0"
|
data/lib/evil-client.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_relative "evil/client"
|
data/lib/evil/client.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
require "
|
1
|
+
require "evil-struct"
|
2
2
|
require "mime-types"
|
3
3
|
require "rack"
|
4
|
+
require "json"
|
4
5
|
|
5
6
|
# Absctract base class for clients to remote APIs
|
6
7
|
#
|
@@ -71,7 +72,6 @@ require "rack"
|
|
71
72
|
#
|
72
73
|
module Evil
|
73
74
|
class Client
|
74
|
-
require_relative "client/model"
|
75
75
|
require_relative "client/connection"
|
76
76
|
require_relative "client/middleware"
|
77
77
|
require_relative "client/operation"
|
@@ -37,7 +37,7 @@ module Evil::Client::DSL
|
|
37
37
|
|
38
38
|
def wrapper
|
39
39
|
return unless json?
|
40
|
-
proc { |data| Hash
|
40
|
+
proc { |data| data.is_a?(Hash) ? data : { data: data } }
|
41
41
|
end
|
42
42
|
|
43
43
|
def processor
|
@@ -54,8 +54,7 @@ module Evil::Client::DSL
|
|
54
54
|
case [model.nil?, addon.nil?]
|
55
55
|
when [false, true] then model
|
56
56
|
when [false, false] then Class.new(model).tap(&addon)
|
57
|
-
when [true, false] then Class.new(Evil::
|
58
|
-
else nil
|
57
|
+
when [true, false] then Class.new(Evil::Struct).tap(&addon)
|
59
58
|
end
|
60
59
|
end
|
61
60
|
end
|
@@ -32,8 +32,8 @@ class Evil::Client::Operation
|
|
32
32
|
private
|
33
33
|
|
34
34
|
def handlers(status)
|
35
|
-
schema[:responses].values
|
36
|
-
|
35
|
+
list = schema[:responses].values.select { |item| item[:status] == status }
|
36
|
+
list.reject { |item| item[:raise] } + list.select { |item| item[:raise] }
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
@@ -43,6 +43,6 @@ RSpec.describe "scoping" do
|
|
43
43
|
it "provides access to params over nested scopes" do
|
44
44
|
client["qux"].users[7].update name: "baz"
|
45
45
|
|
46
|
-
expect(a_request(:put, path).with
|
46
|
+
expect(a_request(:put, path).with(body: "name=baz")).to have_been_made
|
47
47
|
end
|
48
48
|
end
|
@@ -119,7 +119,7 @@ RSpec.describe Evil::Client::DSL::Operation do
|
|
119
119
|
|
120
120
|
context "with :model without block" do
|
121
121
|
before do
|
122
|
-
class Test::Foo < Evil::
|
122
|
+
class Test::Foo < Evil::Struct
|
123
123
|
attribute :qux
|
124
124
|
end
|
125
125
|
end
|
@@ -138,7 +138,7 @@ RSpec.describe Evil::Client::DSL::Operation do
|
|
138
138
|
|
139
139
|
context "with :model and block" do
|
140
140
|
before do
|
141
|
-
class Test::Foo < Evil::
|
141
|
+
class Test::Foo < Evil::Struct
|
142
142
|
attribute :qux
|
143
143
|
end
|
144
144
|
end
|
@@ -161,7 +161,7 @@ RSpec.describe Evil::Client::DSL::Operation do
|
|
161
161
|
|
162
162
|
context "with #query" do
|
163
163
|
before do
|
164
|
-
class Test::Foo < Evil::
|
164
|
+
class Test::Foo < Evil::Struct
|
165
165
|
attribute :qux
|
166
166
|
end
|
167
167
|
end
|
@@ -183,7 +183,7 @@ RSpec.describe Evil::Client::DSL::Operation do
|
|
183
183
|
|
184
184
|
context "with #headers" do
|
185
185
|
before do
|
186
|
-
class Test::Foo < Evil::
|
186
|
+
class Test::Foo < Evil::Struct
|
187
187
|
attribute :qux
|
188
188
|
end
|
189
189
|
end
|
@@ -290,7 +290,7 @@ RSpec.describe Evil::Client::DSL::Operation do
|
|
290
290
|
|
291
291
|
context "with json format and type" do
|
292
292
|
before do
|
293
|
-
class Test::Foo < Evil::
|
293
|
+
class Test::Foo < Evil::Struct
|
294
294
|
attribute :foo
|
295
295
|
end
|
296
296
|
end
|
@@ -309,7 +309,7 @@ RSpec.describe Evil::Client::DSL::Operation do
|
|
309
309
|
|
310
310
|
context "with json format, type and handler" do
|
311
311
|
before do
|
312
|
-
class Test::Foo < Evil::
|
312
|
+
class Test::Foo < Evil::Struct
|
313
313
|
attribute :foo
|
314
314
|
end
|
315
315
|
end
|
@@ -331,7 +331,7 @@ RSpec.describe Evil::Client::DSL::Operation do
|
|
331
331
|
|
332
332
|
context "with json format and filter" do
|
333
333
|
before do
|
334
|
-
class Test::Foo < Evil::
|
334
|
+
class Test::Foo < Evil::Struct
|
335
335
|
attribute :foo
|
336
336
|
end
|
337
337
|
end
|
@@ -352,7 +352,7 @@ RSpec.describe Evil::Client::DSL::Operation do
|
|
352
352
|
|
353
353
|
context "with json format, type and filter" do
|
354
354
|
before do
|
355
|
-
class Test::Foo < Evil::
|
355
|
+
class Test::Foo < Evil::Struct
|
356
356
|
attribute :foo
|
357
357
|
end
|
358
358
|
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
RSpec.describe Evil::Client::Operation::Request do
|
2
2
|
before do
|
3
|
-
class Test::Body < Evil::
|
3
|
+
class Test::Body < Evil::Struct
|
4
4
|
attribute :foo
|
5
5
|
end
|
6
6
|
|
7
|
-
class Test::Query < Evil::
|
7
|
+
class Test::Query < Evil::Struct
|
8
8
|
attribute :bar
|
9
9
|
end
|
10
10
|
|
11
|
-
class Test::Headers < Evil::
|
11
|
+
class Test::Headers < Evil::Struct
|
12
12
|
attribute :baz
|
13
13
|
end
|
14
14
|
end
|
metadata
CHANGED
@@ -1,57 +1,64 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: evil-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kozin (nepalez)
|
8
|
+
- Ravil Bairamgalin (brainopia)
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2016-11-
|
12
|
+
date: 2016-11-20 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
15
|
+
name: evil-struct
|
15
16
|
requirement: !ruby/object:Gem::Requirement
|
16
17
|
requirements:
|
17
|
-
- - "
|
18
|
+
- - ">="
|
18
19
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
20
|
+
version: 0.0.2
|
20
21
|
type: :runtime
|
21
22
|
prerelease: false
|
22
23
|
version_requirements: !ruby/object:Gem::Requirement
|
23
24
|
requirements:
|
24
|
-
- - "
|
25
|
+
- - ">="
|
25
26
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
27
|
+
version: 0.0.2
|
27
28
|
- !ruby/object:Gem::Dependency
|
28
29
|
name: mime-types
|
29
30
|
requirement: !ruby/object:Gem::Requirement
|
30
31
|
requirements:
|
31
|
-
- - "
|
32
|
+
- - ">"
|
32
33
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
34
|
+
version: '1'
|
34
35
|
type: :runtime
|
35
36
|
prerelease: false
|
36
37
|
version_requirements: !ruby/object:Gem::Requirement
|
37
38
|
requirements:
|
38
|
-
- - "
|
39
|
+
- - ">"
|
39
40
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
41
|
+
version: '1'
|
41
42
|
- !ruby/object:Gem::Dependency
|
42
43
|
name: rack
|
43
44
|
requirement: !ruby/object:Gem::Requirement
|
44
45
|
requirements:
|
45
|
-
- - "
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '1'
|
49
|
+
- - "<"
|
46
50
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
51
|
+
version: '3'
|
48
52
|
type: :runtime
|
49
53
|
prerelease: false
|
50
54
|
version_requirements: !ruby/object:Gem::Requirement
|
51
55
|
requirements:
|
52
|
-
- - "
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '1'
|
59
|
+
- - "<"
|
53
60
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
61
|
+
version: '3'
|
55
62
|
- !ruby/object:Gem::Dependency
|
56
63
|
name: dry-types
|
57
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -155,6 +162,7 @@ files:
|
|
155
162
|
- docs/security.md
|
156
163
|
- docs/settings.md
|
157
164
|
- evil-client.gemspec
|
165
|
+
- lib/evil-client.rb
|
158
166
|
- lib/evil/client.rb
|
159
167
|
- lib/evil/client/connection.rb
|
160
168
|
- lib/evil/client/connection/net_http.rb
|
@@ -175,7 +183,6 @@ files:
|
|
175
183
|
- lib/evil/client/middleware/stringify_multipart.rb
|
176
184
|
- lib/evil/client/middleware/stringify_multipart/part.rb
|
177
185
|
- lib/evil/client/middleware/stringify_query.rb
|
178
|
-
- lib/evil/client/model.rb
|
179
186
|
- lib/evil/client/operation.rb
|
180
187
|
- lib/evil/client/operation/request.rb
|
181
188
|
- lib/evil/client/operation/response.rb
|
@@ -211,7 +218,6 @@ files:
|
|
211
218
|
- spec/unit/evil/client/middleware/stringify_multipart_spec.rb
|
212
219
|
- spec/unit/evil/client/middleware/stringify_query_spec.rb
|
213
220
|
- spec/unit/evil/client/middleware_spec.rb
|
214
|
-
- spec/unit/evil/client/model_spec.rb
|
215
221
|
- spec/unit/evil/client/operation/request_spec.rb
|
216
222
|
- spec/unit/evil/client/operation/response_spec.rb
|
217
223
|
homepage: https://github.com/evilmartians/evil-client
|
@@ -268,6 +274,5 @@ test_files:
|
|
268
274
|
- spec/unit/evil/client/middleware/stringify_multipart_spec.rb
|
269
275
|
- spec/unit/evil/client/middleware/stringify_query_spec.rb
|
270
276
|
- spec/unit/evil/client/middleware_spec.rb
|
271
|
-
- spec/unit/evil/client/model_spec.rb
|
272
277
|
- spec/unit/evil/client/operation/request_spec.rb
|
273
278
|
- spec/unit/evil/client/operation/response_spec.rb
|
data/lib/evil/client/model.rb
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
# Base structure for models describing parts of requests and responses
|
2
|
-
#
|
3
|
-
# The initializer accepts a hash with symbol/string keys,
|
4
|
-
# from which it takes and validates necessary options.
|
5
|
-
#
|
6
|
-
# The method [#to_h] converts nested data to hash
|
7
|
-
# with symbolic keys at any level of nesting.
|
8
|
-
#
|
9
|
-
class Evil::Client
|
10
|
-
class Model
|
11
|
-
class << self
|
12
|
-
include Dry::Initializer::Mixin
|
13
|
-
|
14
|
-
def new(value)
|
15
|
-
return value if value.is_a? self
|
16
|
-
value = value.to_h.each_with_object({}) do |(key, val), obj|
|
17
|
-
obj[key.to_sym] = val
|
18
|
-
end
|
19
|
-
super value
|
20
|
-
end
|
21
|
-
alias_method :call, :new
|
22
|
-
alias_method :[], :new
|
23
|
-
|
24
|
-
def attributes
|
25
|
-
@attributes ||= []
|
26
|
-
end
|
27
|
-
|
28
|
-
def option(name, type = nil, as: nil, **opts)
|
29
|
-
super.tap { attributes << (as || name).to_sym }
|
30
|
-
end
|
31
|
-
alias_method :attribute, :option
|
32
|
-
alias_method :param, :option
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
def inherited(klass)
|
37
|
-
super
|
38
|
-
klass.instance_variable_set :@attributes, attributes.dup
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def ==(other)
|
43
|
-
other.respond_to?(:to_h) ? to_h == other.to_h : false
|
44
|
-
end
|
45
|
-
|
46
|
-
def to_h
|
47
|
-
self.class.attributes.each_with_object({}) do |key, hash|
|
48
|
-
val = send(key)
|
49
|
-
hash[key] = hashify(val) unless val == Dry::Initializer::UNDEFINED
|
50
|
-
end
|
51
|
-
end
|
52
|
-
alias_method :[], :send
|
53
|
-
|
54
|
-
private
|
55
|
-
|
56
|
-
def hashify(value)
|
57
|
-
if value.is_a? Evil::Client::Model
|
58
|
-
value.to_h
|
59
|
-
elsif value.respond_to? :to_hash
|
60
|
-
value.to_hash
|
61
|
-
.each_with_object({}) { |(key, val), obj| obj[key] = hashify(val) }
|
62
|
-
elsif value.is_a? Enumerable
|
63
|
-
value.map { |val| hashify(val) }
|
64
|
-
else
|
65
|
-
value
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
@@ -1,100 +0,0 @@
|
|
1
|
-
RSpec.describe Evil::Client::Model do
|
2
|
-
before do
|
3
|
-
class Test::User < Evil::Client::Model
|
4
|
-
option :name, type: Dry::Types["strict.string"]
|
5
|
-
option :email, type: Dry::Types["strict.string"], default: proc { nil }
|
6
|
-
option :phone, type: Dry::Types["strict.string"], optional: true
|
7
|
-
end
|
8
|
-
|
9
|
-
class Test::Order < Evil::Client::Model
|
10
|
-
param :user, type: Test::User
|
11
|
-
attribute :sum, type: Dry::Types["strict.int"]
|
12
|
-
option :items, type: Dry::Types["array"].member(Dry::Types["strict.int"])
|
13
|
-
option :qt, default: proc { nil }
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
describe ".new" do
|
18
|
-
it "is tolerant to unknown options" do
|
19
|
-
user = Test::User.new(name: "Andrew", foo: "bar")
|
20
|
-
expect(user.to_h).to eq name: "Andrew", email: nil
|
21
|
-
end
|
22
|
-
|
23
|
-
it "checks types" do
|
24
|
-
expect { Test::User.new(name: "Andrew", email: nil) }
|
25
|
-
.to raise_error TypeError
|
26
|
-
end
|
27
|
-
|
28
|
-
it "accepts string keys" do
|
29
|
-
user = Test::User.new("name" => "Andrew")
|
30
|
-
expect(user).to eq Test::User.new(name: "Andrew")
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
describe ".call" do
|
35
|
-
it "is shortcuts filtering" do
|
36
|
-
user = Test::User.call(name: "Andrew")
|
37
|
-
expect(user).to eq name: "Andrew", email: nil
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
describe ".[]" do
|
42
|
-
it "is an alias for .call" do
|
43
|
-
user = Test::User[name: "Andrew"]
|
44
|
-
expect(user).to eq Test::User.call(name: "Andrew")
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
describe "#to_h" do
|
49
|
-
it "provides a hash with assigned values only" do
|
50
|
-
user = Test::User[name: "Andrew"]
|
51
|
-
expect(user.to_h).to eq name: "Andrew", email: nil
|
52
|
-
|
53
|
-
user = Test::User[name: "Alan", email: "alan@example.com"]
|
54
|
-
expect(user.to_h).to eq name: "Alan", email: "alan@example.com"
|
55
|
-
|
56
|
-
user = Test::User[name: "Alice", phone: "12345"]
|
57
|
-
expect(user.to_h).to eq name: "Alice", email: nil, phone: "12345"
|
58
|
-
|
59
|
-
user = Test::User[name: "Avdi", phone: "12345"]
|
60
|
-
expect(user.to_h).to eq name: "Avdi", email: nil, phone: "12345"
|
61
|
-
end
|
62
|
-
|
63
|
-
it "hashifies models it depth" do
|
64
|
-
order = Test::Order[user: { name: "Bob" }, sum: 100, items: [1, 2]]
|
65
|
-
expect(order.to_h).to eq user: { name: "Bob", email: nil },
|
66
|
-
sum: 100,
|
67
|
-
items: [1, 2],
|
68
|
-
qt: nil
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
describe "#[]" do
|
73
|
-
it "is an alias for #send" do
|
74
|
-
user = Test::User.new(name: "Andrew")
|
75
|
-
expect(user[:name]).to eq user.name
|
76
|
-
expect(user["name"]).to eq user.name
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
describe "#==" do
|
81
|
-
it "compares model to model with the same attributes" do
|
82
|
-
user = Test::User[name: "Andrew"]
|
83
|
-
expect(user).to eq Test::User[name: "Andrew"]
|
84
|
-
expect(user).not_to eq Test::User[name: "Andrew", phone: "71112234455"]
|
85
|
-
end
|
86
|
-
|
87
|
-
it "compares model to some hash" do
|
88
|
-
user = Test::User[name: "Andrew"]
|
89
|
-
expect(user).to eq name: "Andrew", email: nil
|
90
|
-
end
|
91
|
-
|
92
|
-
it "makes comparison in depth" do
|
93
|
-
order = Test::Order[user: { name: "Bob" }, sum: 100, items: [1, 2]]
|
94
|
-
expect(order).to eq user: { name: "Bob", email: nil },
|
95
|
-
sum: 100,
|
96
|
-
items: [1, 2],
|
97
|
-
qt: nil
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|