evil-client 2.0.0 → 2.1.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +56 -5
- data/docs/helpers/response.md +25 -0
- data/evil-client.gemspec +3 -3
- data/lib/evil/client.rb +14 -6
- data/lib/evil/client/dictionary.rb +77 -0
- data/lib/evil/client/model.rb +126 -0
- data/lib/evil/client/policy.rb +12 -12
- data/lib/evil/client/resolver.rb +1 -1
- data/lib/evil/client/resolver/query.rb +1 -1
- data/lib/evil/client/resolver/response.rb +14 -5
- data/lib/evil/client/resolver/uri.rb +1 -1
- data/lib/evil/client/schema.rb +4 -4
- data/lib/evil/client/settings.rb +7 -77
- data/spec/fixtures/config.yml +4 -0
- data/spec/fixtures/locales/en.yml +4 -0
- data/spec/unit/dictionary_spec.rb +58 -0
- data/spec/unit/model_spec.rb +133 -0
- data/spec/unit/policy_spec.rb +2 -2
- data/spec/unit/resolver/response_spec.rb +22 -2
- data/spec/unit/settings_spec.rb +7 -19
- metadata +50 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e0323c33d7f3cf56d4aca84057aef698e57efbb
|
4
|
+
data.tar.gz: fde6a5543b7c8775350d18cf805b8efe277d65cb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4bcaf9be801454e01f7a99d0385f71eafabbe6e98955ea24b3541d0a5a68bfb88e891ca714736354a8bbd3e45c57c4936ee84e2a2f65abd4606b4b45dc53b149
|
7
|
+
data.tar.gz: 21161df236b8079fb8511bac24f5a3c87e4054803d18f7811a0d46a68941595ed4a5de59517e856c1e4a9ce8f1ef9022eeebf7e67a7dc4b9154303e684ebb09d
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,55 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog], and this project adheres
|
5
5
|
to [Semantic Versioning].
|
6
6
|
|
7
|
+
## [2.1.0] [WIP]
|
8
|
+
|
9
|
+
### Added
|
10
|
+
|
11
|
+
- Class `Evil::Client::Model` (nepalez)
|
12
|
+
Describes standalone model with `.option`, `.let`, and `.validate` extracted
|
13
|
+
from `Evil::Client::Settings`.
|
14
|
+
|
15
|
+
- Module `Evil::Client::Dictionary` (nepalez)
|
16
|
+
Describes a yaml dictionary-based collection of items
|
17
|
+
|
18
|
+
- Helper method `extend` to inject a model into another model, or settings (nepalez)
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
operation :update_user do
|
22
|
+
extend User # takes option-s, let-s, and validate-s from User
|
23
|
+
end
|
24
|
+
```
|
25
|
+
|
26
|
+
- Method to pass response handling to parent scopes by @Envek ([#21](https://github.com/evilmartians/evil-client/pull/21]))
|
27
|
+
|
28
|
+
Allow to handle specific cases in operations and common cases in parent scopes.
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
scope :entities do
|
32
|
+
operation :create do
|
33
|
+
response(409) do |_, _, (data, *)|
|
34
|
+
super! unless data["errorCode"] == "201"
|
35
|
+
raise YourAPI::AlreadyExists, data["errorMessage"]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
response(409) do |_, _, (data, *)|
|
40
|
+
raise YourAPI::Error, data.dig["errorsMessage"]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
### Fixed
|
46
|
+
|
47
|
+
- Generation of English error messages in case of using non-English locales
|
48
|
+
|
49
|
+
### Changed
|
50
|
+
|
51
|
+
- Version requirement for tram-policy is limited due to regression in 0.2.4
|
52
|
+
|
53
|
+
See https://github.com/tram-rb/tram-policy/commit/874c8f61399dbe174c158fec729d16c2b1ffb2fd#r26432444
|
54
|
+
|
55
|
+
|
7
56
|
## [2.0.0] [2017-09-02]
|
8
57
|
|
9
58
|
### Changed
|
@@ -381,11 +430,13 @@ formats will be added.
|
|
381
430
|
response :not_found, 404, format: "json", raise: true
|
382
431
|
```
|
383
432
|
|
384
|
-
[1.1.0]: https://github.com/evilmartians/evil-client/compare/v1.0.0...v1.1.0
|
385
|
-
[1.0.0]: https://github.com/evilmartians/evil-client/compare/v0.3.3...v1.0.0
|
386
|
-
[0.3.3]: https://github.com/evilmartians/evil-client/compare/v0.3.2...v0.3.3
|
387
|
-
[0.3.2]: https://github.com/evilmartians/evil-client/compare/v0.3.1...v0.3.2
|
388
|
-
[0.3.1]: https://github.com/evilmartians/evil-client/compare/v0.3.0...v0.3.1
|
389
433
|
[Keep a Changelog]: http://keepachangelog.com/
|
390
434
|
[Semantic Versioning]: http://semver.org/
|
391
435
|
[dry-initializer]: http://github.com/dry-rb/dry-initalizer
|
436
|
+
[0.3.1]: https://github.com/evilmartians/evil-client/compare/v0.3.0...v0.3.1
|
437
|
+
[0.3.2]: https://github.com/evilmartians/evil-client/compare/v0.3.1...v0.3.2
|
438
|
+
[0.3.3]: https://github.com/evilmartians/evil-client/compare/v0.3.2...v0.3.3
|
439
|
+
[1.0.0]: https://github.com/evilmartians/evil-client/compare/v0.3.3...v1.0.0
|
440
|
+
[1.1.0]: https://github.com/evilmartians/evil-client/compare/v1.0.0...v1.1.0
|
441
|
+
[2.0.0]: https://github.com/evilmartians/evil-client/compare/v1.1.0...v2.0.0
|
442
|
+
[2.1.0]: https://github.com/evilmartians/evil-client/compare/v2.0.0...v2.1.0
|
data/docs/helpers/response.md
CHANGED
@@ -32,6 +32,31 @@ response 400, 422 do |_status, *|
|
|
32
32
|
end
|
33
33
|
```
|
34
34
|
|
35
|
+
In case if you want to implement hierarchical processing of errors from more specific to certain operations or scopes to common errors of whole API, you can call `super!` method from response handler when you want to delegate handling to parent scope:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
class YourAPI < Evil::Client
|
39
|
+
scope :entities do
|
40
|
+
operation :create do
|
41
|
+
response(409) do |_, _, body|
|
42
|
+
data = JSON.parse(body.first)
|
43
|
+
case data.dig("errors", 0, "errorId")
|
44
|
+
when 35021
|
45
|
+
raise YourAPI::AlreadyExists, data.dig("errors", 0, "message")
|
46
|
+
else
|
47
|
+
super!
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
response(409) do |_, _, body|
|
54
|
+
data = JSON.parse(body.first)
|
55
|
+
raise EbayAPI::Error, data.dig("errors", 0, "message")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
```
|
59
|
+
|
35
60
|
When you use client-specific [middleware], the `response` block will receive the result already processed by the whole middleware stack. The helper will serve a final step of its handling. Its result wouldn't be processed further in any way.
|
36
61
|
|
37
62
|
If a remote API will respond with a status, not defined for the operation, the `Evil::Client::ResponseError` will be risen. The exception carries both the response, and all its parts (status, headers, and body).
|
data/evil-client.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |gem|
|
2
2
|
gem.name = "evil-client"
|
3
|
-
gem.version = "2.
|
3
|
+
gem.version = "2.1.0"
|
4
4
|
gem.author = ["Andrew Kozin (nepalez)", "Ravil Bairamgalin (brainopia)"]
|
5
5
|
gem.email = ["andrew.kozin@gmail.com", "nepalez@evilmartians.com"]
|
6
6
|
gem.homepage = "https://github.com/evilmartians/evil-client"
|
@@ -13,10 +13,10 @@ Gem::Specification.new do |gem|
|
|
13
13
|
|
14
14
|
gem.required_ruby_version = "~> 2.3"
|
15
15
|
|
16
|
-
gem.add_runtime_dependency "dry-initializer", "~> 2.
|
17
|
-
gem.add_runtime_dependency "tram-policy", "~> 0.2.1"
|
16
|
+
gem.add_runtime_dependency "dry-initializer", "~> 2.1"
|
18
17
|
gem.add_runtime_dependency "mime-types", "~> 3.1"
|
19
18
|
gem.add_runtime_dependency "rack", "~> 2"
|
19
|
+
gem.add_runtime_dependency "tram-policy", "~> 0.2.2", "<= 0.2.3"
|
20
20
|
|
21
21
|
gem.add_development_dependency "rake", ">= 10"
|
22
22
|
gem.add_development_dependency "rspec", "~> 3.0"
|
data/lib/evil/client.rb
CHANGED
@@ -30,6 +30,7 @@ module Evil
|
|
30
30
|
require_relative "client/chaining"
|
31
31
|
require_relative "client/options"
|
32
32
|
require_relative "client/policy"
|
33
|
+
require_relative "client/model"
|
33
34
|
require_relative "client/settings"
|
34
35
|
require_relative "client/schema"
|
35
36
|
require_relative "client/container"
|
@@ -37,6 +38,7 @@ module Evil
|
|
37
38
|
require_relative "client/connection"
|
38
39
|
require_relative "client/formatter"
|
39
40
|
require_relative "client/resolver"
|
41
|
+
require_relative "client/dictionary"
|
40
42
|
|
41
43
|
include Chaining
|
42
44
|
|
@@ -59,12 +61,8 @@ module Evil
|
|
59
61
|
# Sets a custom connection, or resets it to a default one
|
60
62
|
#
|
61
63
|
# @param [#call, nil] connection
|
62
|
-
# @return [self]
|
63
64
|
#
|
64
|
-
|
65
|
-
@connection = connection
|
66
|
-
self
|
67
|
-
end
|
65
|
+
attr_writer :connection
|
68
66
|
|
69
67
|
# Schema for the root scope of the client
|
70
68
|
#
|
@@ -106,7 +104,6 @@ module Evil
|
|
106
104
|
#
|
107
105
|
def logger=(logger)
|
108
106
|
@scope.logger = logger
|
109
|
-
self
|
110
107
|
end
|
111
108
|
|
112
109
|
# Operations defined at the root of the client
|
@@ -141,6 +138,17 @@ module Evil
|
|
141
138
|
@scope.options
|
142
139
|
end
|
143
140
|
|
141
|
+
# Human-readable representation of the client
|
142
|
+
#
|
143
|
+
# @return [String]
|
144
|
+
#
|
145
|
+
def inspect
|
146
|
+
vars = options.map { |k, v| "@#{k}=#{v}" }.join(", ")
|
147
|
+
"#<#{self.class}:#{format('0x%014x', object_id)} #{vars}>"
|
148
|
+
end
|
149
|
+
alias to_s inspect
|
150
|
+
alias to_str inspect
|
151
|
+
|
144
152
|
private
|
145
153
|
|
146
154
|
def initialize(**options)
|
@@ -0,0 +1,77 @@
|
|
1
|
+
class Evil::Client
|
2
|
+
# Class-level methods
|
3
|
+
module Dictionary
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
# Exception to be risen when item cannot be found in a dictionary
|
7
|
+
Error = Class.new(ArgumentError)
|
8
|
+
|
9
|
+
# Raw data for the dictionary items
|
10
|
+
# @return [String]
|
11
|
+
def raw
|
12
|
+
@raw ||= []
|
13
|
+
end
|
14
|
+
|
15
|
+
# List of the dictionary items
|
16
|
+
# @return [Array<Evil::Client::Dictionary>]
|
17
|
+
def all
|
18
|
+
@all ||= raw.map { |item| new(item) }
|
19
|
+
end
|
20
|
+
|
21
|
+
# Iterates by dictionary items
|
22
|
+
# @return [Enumerator<Evil::Client::Dictionary>]
|
23
|
+
def each
|
24
|
+
block_given? ? all.each { |item| yield(item) } : all.to_enum
|
25
|
+
end
|
26
|
+
|
27
|
+
# Calls the item and raises when it is not in the dictionary
|
28
|
+
#
|
29
|
+
# @param [Evil::Client::Dictionary] item
|
30
|
+
# @return [Evil::Client::Dictionary]
|
31
|
+
# @raise [Evil::Client::Dictionary::Error]
|
32
|
+
#
|
33
|
+
def call(item)
|
34
|
+
return item if all.include? item
|
35
|
+
raise Error, "#{item} is absent in the dictionary #{self}"
|
36
|
+
end
|
37
|
+
|
38
|
+
# Alias for [.call]
|
39
|
+
#
|
40
|
+
# @param [Evil::Client::Dictionary] item
|
41
|
+
# @return [Evil::Client::Dictionary]
|
42
|
+
# @raise [Evil::Client::Dictionary::Error]
|
43
|
+
#
|
44
|
+
def [](item)
|
45
|
+
call(item)
|
46
|
+
end
|
47
|
+
|
48
|
+
class << self
|
49
|
+
# Loads [#raw] dictionary from YAML config file
|
50
|
+
#
|
51
|
+
# @param [String] path
|
52
|
+
# @return [self]
|
53
|
+
#
|
54
|
+
def [](path)
|
55
|
+
file, paths = path.to_s.split("#")
|
56
|
+
list = YAML.load_file(file)
|
57
|
+
keys = paths.to_s.split("/").map(&:to_sym)
|
58
|
+
@raw = keys.any? ? Hash(list).dig(*keys) : list
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def extended(klass)
|
65
|
+
super
|
66
|
+
klass.send :instance_variable_set, :@raw, @raw.to_a
|
67
|
+
@raw = nil
|
68
|
+
end
|
69
|
+
|
70
|
+
def included(klass)
|
71
|
+
super
|
72
|
+
klass.send :define_method, :raw, &@raw.method(:to_a)
|
73
|
+
@raw = nil
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
class Evil::Client
|
2
|
+
#
|
3
|
+
# Data structure with validators and memoizers
|
4
|
+
#
|
5
|
+
class Model
|
6
|
+
extend Dry::Initializer
|
7
|
+
|
8
|
+
@policy = Policy
|
9
|
+
|
10
|
+
class << self
|
11
|
+
# @!method options(key, type = nil, opts = {})
|
12
|
+
# Creates or updates the settings' initializer
|
13
|
+
#
|
14
|
+
# @see [http://dry-rb.org/gems/dry-initializer]
|
15
|
+
#
|
16
|
+
# @param [#to_sym] key Symbolic name of the option
|
17
|
+
# @param [#call] type (nil) Type coercer for the option
|
18
|
+
# @option opts [#call] :type Another way to assign type coercer
|
19
|
+
# @option opts [#call] :default Proc containing default value
|
20
|
+
# @option opts [Boolean] :optional Whether it can be missed
|
21
|
+
# @option opts [#to_sym] :as The name of settings variable
|
22
|
+
# @option opts [false, :private, :protected] :reader Reader method type
|
23
|
+
# @return [self]
|
24
|
+
#
|
25
|
+
def option(key, type = nil, as: key.to_sym, **opts)
|
26
|
+
NameError.check!(as)
|
27
|
+
super
|
28
|
+
self
|
29
|
+
end
|
30
|
+
undef_method :param # model initializes with [#options] only
|
31
|
+
|
32
|
+
# Creates or reloads memoized attribute
|
33
|
+
#
|
34
|
+
# @param [#to_sym] key The name of the attribute
|
35
|
+
# @param [Proc] block The body of new attribute
|
36
|
+
# @return [self]
|
37
|
+
#
|
38
|
+
def let(key, &block)
|
39
|
+
NameError.check!(key)
|
40
|
+
lets[key.to_sym] = block
|
41
|
+
|
42
|
+
define_method(key) do
|
43
|
+
instance_variable_get(:"@#{key}") ||
|
44
|
+
instance_variable_set(:"@#{key}", instance_exec(&block))
|
45
|
+
end
|
46
|
+
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
# Definitions for virtual attributes
|
51
|
+
#
|
52
|
+
# @return [Hash<Symbol, Proc>]
|
53
|
+
#
|
54
|
+
def lets
|
55
|
+
@lets ||= {}
|
56
|
+
end
|
57
|
+
|
58
|
+
# Policy object for model instances
|
59
|
+
#
|
60
|
+
# @return [Evil::Client::Policy]
|
61
|
+
#
|
62
|
+
def policy
|
63
|
+
@policy ||= superclass.policy.for(self)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Add validation rule to the [#policy]
|
67
|
+
#
|
68
|
+
# @param [Proc] block The body of new attribute
|
69
|
+
# @return [self]
|
70
|
+
#
|
71
|
+
def validate(&block)
|
72
|
+
policy.validate(&block)
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
76
|
+
# Merges [.option]-s, virtual attributes [.let] and [.validation]-s
|
77
|
+
# from another model into the current one.
|
78
|
+
#
|
79
|
+
# @param [Evil::Client::Model] other
|
80
|
+
# @return [self]
|
81
|
+
#
|
82
|
+
# rubocop: disable Metrics/AbcSize
|
83
|
+
def extend(other)
|
84
|
+
return super if other.instance_of? Module
|
85
|
+
|
86
|
+
unless other.ancestors.include? Evil::Client::Model
|
87
|
+
raise TypeError, "#{other} is not a subclass of Evil::Client::Model"
|
88
|
+
end
|
89
|
+
|
90
|
+
other.dry_initializer.options.each do |definition|
|
91
|
+
option definition.source, definition.options
|
92
|
+
end
|
93
|
+
|
94
|
+
other.lets.each { |key, block| let(key, &block) }
|
95
|
+
other.policy.all.each { |validator| policy.local << validator }
|
96
|
+
end
|
97
|
+
# rubocop: enable Metrics/AbcSize
|
98
|
+
|
99
|
+
# Model instance constructor
|
100
|
+
#
|
101
|
+
# @param [Hash] op Model options
|
102
|
+
# @return [Evil::Client::Model]
|
103
|
+
#
|
104
|
+
def new(op = {})
|
105
|
+
op = Hash(op).each_with_object({}) { |(k, v), obj| obj[k.to_sym] = v }
|
106
|
+
super(op).tap { |item| in_english { policy[item].validate! } }
|
107
|
+
rescue StandardError => error
|
108
|
+
raise ValidationError, error.message
|
109
|
+
end
|
110
|
+
alias call new
|
111
|
+
alias [] call
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def in_english(&block)
|
116
|
+
unless I18n.available_locales.include?(:en)
|
117
|
+
available_locales = I18n.available_locales
|
118
|
+
I18n.available_locales += %i[en]
|
119
|
+
end
|
120
|
+
I18n.with_locale(:en, &block)
|
121
|
+
ensure
|
122
|
+
I18n.available_locales = available_locales if available_locales
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/evil/client/policy.rb
CHANGED
@@ -4,29 +4,29 @@ class Evil::Client
|
|
4
4
|
#
|
5
5
|
class Policy < Tram::Policy
|
6
6
|
class << self
|
7
|
-
# Subclasses itself for a
|
7
|
+
# Subclasses itself for a model class
|
8
8
|
#
|
9
|
-
# @param [Class]
|
9
|
+
# @param [Class] model Settings class to validate
|
10
10
|
# @return [Class]
|
11
11
|
#
|
12
|
-
def for(
|
12
|
+
def for(model)
|
13
13
|
Class.new(self).tap do |klass|
|
14
|
-
klass.send :instance_variable_set, :@
|
14
|
+
klass.send :instance_variable_set, :@model, model
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
# Reference to the
|
18
|
+
# Reference to the model whose instances are validated by the policy
|
19
19
|
#
|
20
20
|
# @return [Class, nil]
|
21
21
|
#
|
22
|
-
attr_reader :
|
22
|
+
attr_reader :model
|
23
23
|
|
24
|
-
# Delegates the name of the policy to the name of checked
|
24
|
+
# Delegates the name of the policy to the name of checked model
|
25
25
|
#
|
26
26
|
# @return [String, nil]
|
27
27
|
#
|
28
28
|
def name
|
29
|
-
"#{
|
29
|
+
"#{model}.policy"
|
30
30
|
end
|
31
31
|
alias_method :to_s, :name
|
32
32
|
alias_method :to_sym, :name
|
@@ -36,21 +36,21 @@ class Evil::Client
|
|
36
36
|
|
37
37
|
def scope
|
38
38
|
@scope ||= %i[evil client errors] << \
|
39
|
-
Tram::Policy::Inflector.underscore(
|
39
|
+
Tram::Policy::Inflector.underscore(model.to_s)
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
43
|
# An instance of settings to be checked by the policy
|
44
|
-
param :
|
44
|
+
param :model
|
45
45
|
|
46
46
|
private
|
47
47
|
|
48
48
|
def respond_to_missing?(name, *)
|
49
|
-
|
49
|
+
model.respond_to?(name)
|
50
50
|
end
|
51
51
|
|
52
52
|
def method_missing(*args)
|
53
|
-
respond_to_missing?(*args) ?
|
53
|
+
respond_to_missing?(*args) ? model.__send__(*args) : super
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
data/lib/evil/client/resolver.rb
CHANGED
@@ -31,7 +31,7 @@ class Evil::Client
|
|
31
31
|
|
32
32
|
left = __stringify_keys__(left)
|
33
33
|
right = __stringify_keys__(right)
|
34
|
-
right.
|
34
|
+
right.each_key { |key| left[key] = __deep_merge__ left[key], right[key] }
|
35
35
|
|
36
36
|
left
|
37
37
|
end
|
@@ -6,6 +6,9 @@ class Evil::Client
|
|
6
6
|
class Resolver::Response < Resolver
|
7
7
|
private
|
8
8
|
|
9
|
+
PROCESSING_DONE = Object.new
|
10
|
+
SKIP_RESPONSE = Object.new
|
11
|
+
|
9
12
|
def initialize(schema, settings, response)
|
10
13
|
@__response__ = Array response
|
11
14
|
super schema, settings, :responses, @__response__.first.to_i
|
@@ -13,14 +16,20 @@ class Evil::Client
|
|
13
16
|
|
14
17
|
def __call__
|
15
18
|
super do
|
16
|
-
|
17
|
-
|
19
|
+
catch(PROCESSING_DONE) do
|
20
|
+
__blocks__.reverse_each do |block|
|
21
|
+
catch(SKIP_RESPONSE) do
|
22
|
+
throw(PROCESSING_DONE, instance_exec(*@__response__, &block))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
# We're here if 1) no blocks or 2) all blocks skipped processing
|
26
|
+
raise ResponseError.new(@__schema__, @__settings__, @__response__)
|
27
|
+
end
|
18
28
|
end
|
19
29
|
end
|
20
30
|
|
21
|
-
def
|
22
|
-
|
23
|
-
raise ResponseError.new(@__schema__, @__settings__, @__response__)
|
31
|
+
def super!
|
32
|
+
throw SKIP_RESPONSE
|
24
33
|
end
|
25
34
|
end
|
26
35
|
end
|
data/lib/evil/client/schema.rb
CHANGED
@@ -60,8 +60,8 @@ class Evil::Client
|
|
60
60
|
|
61
61
|
# Adds an option to the [#settings] class
|
62
62
|
#
|
63
|
-
# @param (see Evil::Client::
|
64
|
-
# @option (see Evil::Client::
|
63
|
+
# @param (see Evil::Client::Model.option)
|
64
|
+
# @option (see Evil::Client::Model.option)
|
65
65
|
# @return [self]
|
66
66
|
#
|
67
67
|
def option(key, type = nil, **opts)
|
@@ -71,7 +71,7 @@ class Evil::Client
|
|
71
71
|
|
72
72
|
# Adds a memoized method to the [#settings] class
|
73
73
|
#
|
74
|
-
# @param (see Evil::Client::
|
74
|
+
# @param (see Evil::Client::Model.let)
|
75
75
|
# @return [self]
|
76
76
|
#
|
77
77
|
def let(key, &block)
|
@@ -81,7 +81,7 @@ class Evil::Client
|
|
81
81
|
|
82
82
|
# Adds validator to the [#settings] class
|
83
83
|
#
|
84
|
-
# @param (see Evil::Client::
|
84
|
+
# @param (see Evil::Client::Model.validate)
|
85
85
|
# @return [self]
|
86
86
|
#
|
87
87
|
def validate(&block)
|
data/lib/evil/client/settings.rb
CHANGED
@@ -2,11 +2,8 @@ class Evil::Client
|
|
2
2
|
#
|
3
3
|
# Container for settings assigned to some operation or scope.
|
4
4
|
#
|
5
|
-
class Settings
|
5
|
+
class Settings < Model
|
6
6
|
Names.clean(self) # Remove unnecessary methods from the instance
|
7
|
-
extend ::Dry::Initializer
|
8
|
-
|
9
|
-
@policy = Policy
|
10
7
|
|
11
8
|
class << self
|
12
9
|
# Subclasses itself for a given schema
|
@@ -37,54 +34,6 @@ class Evil::Client
|
|
37
34
|
alias_method :to_str, :name
|
38
35
|
alias_method :inspect, :name
|
39
36
|
|
40
|
-
# Only options can be defined for the settings container
|
41
|
-
# @private
|
42
|
-
def param(*args)
|
43
|
-
option(*args)
|
44
|
-
end
|
45
|
-
|
46
|
-
# Creates or updates the settings' initializer
|
47
|
-
#
|
48
|
-
# @see [http://dry-rb.org/gems/dry-initializer]
|
49
|
-
#
|
50
|
-
# @param [#to_sym] key Symbolic name of the option
|
51
|
-
# @param [#call] type Type coercer for the option
|
52
|
-
# @option opts [#call] :type Another way to assign type coercer
|
53
|
-
# @option opts [#call] :default Proc containing default value
|
54
|
-
# @option opts [Boolean] :optional Whether it can be missed
|
55
|
-
# @option opts [#to_sym] :as The name of settings variable
|
56
|
-
# @option opts [false, :private, :protected] :reader Reader method type
|
57
|
-
# @return [self]
|
58
|
-
#
|
59
|
-
def option(key, type = nil, as: key.to_sym, **opts)
|
60
|
-
NameError.check!(as)
|
61
|
-
super
|
62
|
-
self
|
63
|
-
end
|
64
|
-
|
65
|
-
# Creates or reloads memoized attribute
|
66
|
-
#
|
67
|
-
# @param [#to_sym] key The name of the attribute
|
68
|
-
# @param [Proc] block The body of new attribute
|
69
|
-
# @return [self]
|
70
|
-
#
|
71
|
-
def let(key, &block)
|
72
|
-
NameError.check!(key)
|
73
|
-
define_method(key) do
|
74
|
-
instance_variable_get(:"@#{key}") ||
|
75
|
-
instance_variable_set(:"@#{key}", instance_exec(&block))
|
76
|
-
end
|
77
|
-
self
|
78
|
-
end
|
79
|
-
|
80
|
-
# Policy class that collects all the necessary validators
|
81
|
-
#
|
82
|
-
# @return [Class] a subclass of [Tram::Policy] named after the scope
|
83
|
-
#
|
84
|
-
def policy
|
85
|
-
@policy ||= superclass.policy.for(self)
|
86
|
-
end
|
87
|
-
|
88
37
|
# Add validation rule to the [#policy]
|
89
38
|
#
|
90
39
|
# @param [Proc] block The body of new attribute
|
@@ -101,22 +50,12 @@ class Evil::Client
|
|
101
50
|
# @param [Hash<#to_sym, Object>, nil] opts
|
102
51
|
# @return [Evil::Client::Settings]
|
103
52
|
#
|
104
|
-
def new(logger,
|
105
|
-
logger&.debug(self) { "initializing with options #{
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
end
|
111
|
-
|
112
|
-
private
|
113
|
-
|
114
|
-
def in_english(&block)
|
115
|
-
available_locales = I18n.available_locales
|
116
|
-
I18n.available_locales = %i[en]
|
117
|
-
I18n.with_locale(:en, &block)
|
118
|
-
ensure
|
119
|
-
I18n.available_locales = available_locales
|
53
|
+
def new(logger, op = {})
|
54
|
+
logger&.debug(self) { "initializing with options #{op}..." }
|
55
|
+
super(op).tap do |item|
|
56
|
+
item.logger = logger
|
57
|
+
logger&.debug(item) { "initialized" }
|
58
|
+
end
|
120
59
|
end
|
121
60
|
end
|
122
61
|
|
@@ -160,14 +99,5 @@ class Evil::Client
|
|
160
99
|
end
|
161
100
|
alias_method :to_str, :inspect
|
162
101
|
alias_method :to_s, :inspect
|
163
|
-
|
164
|
-
private
|
165
|
-
|
166
|
-
def initialize(logger, **options)
|
167
|
-
super(options)
|
168
|
-
@logger = logger
|
169
|
-
self.class.policy[self].validate!
|
170
|
-
logger&.debug(self) { "initialized" }
|
171
|
-
end
|
172
102
|
end
|
173
103
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
RSpec.describe Evil::Client::Dictionary do
|
2
|
+
shared_examples :a_dictionary do |scope|
|
3
|
+
before do
|
4
|
+
class Test::Dictionary < String
|
5
|
+
def initialize(value)
|
6
|
+
super(value.downcase)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:klass) { Test::Dictionary }
|
12
|
+
|
13
|
+
describe "#all (#{scope})" do
|
14
|
+
subject { klass.all }
|
15
|
+
|
16
|
+
it "returns all items from a dictionary" do
|
17
|
+
expect(subject).to eq %w[one two]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#each (#{scope})" do
|
22
|
+
subject { klass.map(&:reverse) }
|
23
|
+
|
24
|
+
it "iterates over dictionary items" do
|
25
|
+
expect(subject).to eq %w[eno owt]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#call (#{scope})" do
|
30
|
+
it "returns dictionary item" do
|
31
|
+
expect(klass.call("one")).to eq "one"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "raises when the item not in the dictionary" do
|
35
|
+
expect { klass.call "ONE" }
|
36
|
+
.to raise_error Evil::Client::Dictionary::Error
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it_behaves_like :a_dictionary, "when class extended by the module" do
|
42
|
+
before do
|
43
|
+
class Test::Dictionary < String
|
44
|
+
extend Evil::Client::Dictionary["spec/fixtures/config.yml"]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it_behaves_like :a_dictionary, "when singleton class includes the module" do
|
50
|
+
before do
|
51
|
+
class Test::Dictionary < String
|
52
|
+
class << self
|
53
|
+
include Evil::Client::Dictionary["spec/fixtures/config.yml"]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
RSpec.describe Evil::Client::Model do
|
2
|
+
before { class Test::Model < described_class; end }
|
3
|
+
|
4
|
+
let(:model) { klass.new(options) }
|
5
|
+
let(:klass) { Test::Model }
|
6
|
+
let(:options) { { "id" => 42, "name" => "Andrew" } }
|
7
|
+
let(:dsl_methods) do
|
8
|
+
%i[options datetime logger scope basic_auth key_auth token_auth]
|
9
|
+
end
|
10
|
+
|
11
|
+
describe ".policy" do
|
12
|
+
subject { klass.policy }
|
13
|
+
|
14
|
+
it "subclasses Evil::Client::Policy" do
|
15
|
+
expect(subject.superclass).to eq described_class.policy
|
16
|
+
expect(described_class.policy.superclass).to eq Tram::Policy
|
17
|
+
end
|
18
|
+
|
19
|
+
it "refers back to the model" do
|
20
|
+
expect(subject.model).to eq klass
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe ".option" do
|
25
|
+
it "is defined by Dry::Initializer DSL" do
|
26
|
+
expect(klass).to be_a Dry::Initializer
|
27
|
+
end
|
28
|
+
|
29
|
+
it "fails when method name is reserved for DSL" do
|
30
|
+
dsl_methods.each do |name|
|
31
|
+
expect { klass.option name }
|
32
|
+
.to raise_error Evil::Client::NameError
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it "allows the option to be renamed" do
|
37
|
+
expect { klass.option :basic_auth, as: :something }.not_to raise_error
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe ".let" do
|
42
|
+
before do
|
43
|
+
klass.option :id
|
44
|
+
klass.let(:square_id) { id**2 }
|
45
|
+
end
|
46
|
+
|
47
|
+
subject { model.square_id }
|
48
|
+
|
49
|
+
it "adds the corresponding memoizer to the instance" do
|
50
|
+
expect(subject).to eq(42**2)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "fails when method name is reserved for DSL" do
|
54
|
+
dsl_methods.each do |name|
|
55
|
+
expect { klass.let(name) { 0 } }
|
56
|
+
.to raise_error Evil::Client::NameError
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe ".validate" do
|
62
|
+
before do
|
63
|
+
klass.option :name
|
64
|
+
klass.validate { errors.add :name_present if name.to_s == "" }
|
65
|
+
end
|
66
|
+
|
67
|
+
let(:options) { { "name" => "" } }
|
68
|
+
|
69
|
+
it "adds validation for an instance" do
|
70
|
+
# see spec/fixtures/locale/en.yml
|
71
|
+
expect { model }
|
72
|
+
.to raise_error(Evil::Client::ValidationError, /The user has no name/)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe ".new" do
|
77
|
+
subject { model }
|
78
|
+
|
79
|
+
context "with wrong options" do
|
80
|
+
before { klass.option :user, as: :customer }
|
81
|
+
|
82
|
+
it "raises Evil::Client::ValidationError" do
|
83
|
+
expect { subject }.to raise_error Evil::Client::ValidationError, /user/
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe ".extend" do
|
89
|
+
before do
|
90
|
+
class Test::Other < described_class
|
91
|
+
option :first_name, optional: true
|
92
|
+
option :last_name, optional: true
|
93
|
+
|
94
|
+
let(:name) { [first_name, last_name].compact.join(" ") }
|
95
|
+
|
96
|
+
validate { errors.add :empty_name if name == "" }
|
97
|
+
end
|
98
|
+
|
99
|
+
class Test::Model < described_class
|
100
|
+
extend Test::Other
|
101
|
+
option :email, optional: true
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
let(:options) do
|
106
|
+
{ first_name: "Joe", last_name: "Doe", email: "joe@example.com" }
|
107
|
+
end
|
108
|
+
|
109
|
+
subject { model }
|
110
|
+
|
111
|
+
it "behaves like a model" do
|
112
|
+
expect(subject).to be_a klass
|
113
|
+
expect(subject.email).to eq "joe@example.com"
|
114
|
+
end
|
115
|
+
|
116
|
+
it "injects options from the other model" do
|
117
|
+
expect(subject.first_name).to eq "Joe"
|
118
|
+
expect(subject.last_name).to eq "Doe"
|
119
|
+
end
|
120
|
+
|
121
|
+
it "injects memoizers from the other model" do
|
122
|
+
expect(subject.name).to eq "Joe Doe"
|
123
|
+
end
|
124
|
+
|
125
|
+
context "with invalid options" do
|
126
|
+
let(:options) { { email: "joe@example.com" } }
|
127
|
+
|
128
|
+
it "injects validators from the other model" do
|
129
|
+
expect { subject }.to raise_error(StandardError, /name/)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
data/spec/unit/policy_spec.rb
CHANGED
@@ -22,10 +22,10 @@ RSpec.describe Evil::Client::Policy do
|
|
22
22
|
end
|
23
23
|
|
24
24
|
it "keeps reference to the settings" do
|
25
|
-
expect(subject.
|
25
|
+
expect(subject.model).to eq settings
|
26
26
|
end
|
27
27
|
|
28
|
-
it "takes the name from settings
|
28
|
+
it "takes the name from settings class" do
|
29
29
|
expect(subject.name).to eq "Foo.policy"
|
30
30
|
end
|
31
31
|
end
|
@@ -5,16 +5,18 @@ RSpec.describe Evil::Client::Resolver::Response, ".call" do
|
|
5
5
|
let(:logger) { Logger.new log }
|
6
6
|
let(:response) { [201, { "Content-Language" => "en" }, ["success"]] }
|
7
7
|
|
8
|
+
let(:root_response_handler) { proc { |*args| args } }
|
8
9
|
let(:root_schema) do
|
9
10
|
double :my_parent_schema,
|
10
|
-
definitions: { responses: { 201 =>
|
11
|
+
definitions: { responses: { 201 => root_response_handler } },
|
11
12
|
parent: nil
|
12
13
|
end
|
13
14
|
|
15
|
+
let(:response_handler) { proc { |_, _, body| body.first } }
|
14
16
|
let(:schema) do
|
15
17
|
double :my_schema,
|
16
18
|
definitions: {
|
17
|
-
responses: { 201 =>
|
19
|
+
responses: { 201 => response_handler }
|
18
20
|
},
|
19
21
|
parent: root_schema
|
20
22
|
end
|
@@ -53,6 +55,24 @@ RSpec.describe Evil::Client::Resolver::Response, ".call" do
|
|
53
55
|
end
|
54
56
|
end
|
55
57
|
|
58
|
+
context "when root definition reloaded but schema handler skips response" do
|
59
|
+
let(:response_handler) do
|
60
|
+
proc { |_, _, _| super! }
|
61
|
+
end
|
62
|
+
|
63
|
+
it "applies root schema to response" do
|
64
|
+
expect(subject).to eq response
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when root definition skips response handling too" do
|
68
|
+
let(:root_response_handler) { proc { super! } }
|
69
|
+
|
70
|
+
it "raises Evil::Client::ResponseError" do
|
71
|
+
expect { subject }.to raise_error Evil::Client::ResponseError
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
56
76
|
context "when no definitions was given for the status" do
|
57
77
|
let(:response) { [202, { "Content-Language" => "en" }, ["success"]] }
|
58
78
|
|
data/spec/unit/settings_spec.rb
CHANGED
@@ -26,11 +26,12 @@ RSpec.describe Evil::Client::Settings do
|
|
26
26
|
subject { klass.policy }
|
27
27
|
|
28
28
|
it "subclasses Evil::Client::Policy" do
|
29
|
-
expect(subject.superclass).to eq
|
29
|
+
expect(subject.superclass).to eq described_class.policy
|
30
|
+
expect(described_class.policy.superclass).to eq Evil::Client::Policy
|
30
31
|
end
|
31
32
|
|
32
33
|
it "refers back to the settings" do
|
33
|
-
expect(subject.
|
34
|
+
expect(subject.model).to eq klass
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
@@ -44,7 +45,7 @@ RSpec.describe Evil::Client::Settings do
|
|
44
45
|
end
|
45
46
|
|
46
47
|
it "refers back to the settings" do
|
47
|
-
expect(subject.
|
48
|
+
expect(subject.model).to eq scope_klass
|
48
49
|
end
|
49
50
|
end
|
50
51
|
end
|
@@ -66,22 +67,9 @@ RSpec.describe Evil::Client::Settings do
|
|
66
67
|
end
|
67
68
|
end
|
68
69
|
|
69
|
-
describe ".param" do
|
70
|
-
before do
|
71
|
-
klass.param :id, optional: true
|
72
|
-
klass.param :email, optional: true
|
73
|
-
end
|
74
|
-
|
75
|
-
subject { settings.options }
|
76
|
-
|
77
|
-
it "acts like .option" do
|
78
|
-
expect(subject).to eq id: 42
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
70
|
describe ".let" do
|
83
71
|
before do
|
84
|
-
klass.
|
72
|
+
klass.option :id
|
85
73
|
klass.let(:square_id) { id**2 }
|
86
74
|
end
|
87
75
|
|
@@ -101,7 +89,7 @@ RSpec.describe Evil::Client::Settings do
|
|
101
89
|
|
102
90
|
describe ".validate" do
|
103
91
|
before do
|
104
|
-
klass.
|
92
|
+
klass.option :name
|
105
93
|
klass.validate { errors.add :name_present if name.to_s == "" }
|
106
94
|
end
|
107
95
|
|
@@ -207,7 +195,7 @@ RSpec.describe Evil::Client::Settings do
|
|
207
195
|
end
|
208
196
|
|
209
197
|
describe "#datetime" do
|
210
|
-
let(:time) {
|
198
|
+
let(:time) { Time.parse "2017-07-21 16:58:00 UTC" }
|
211
199
|
subject { settings.datetime value }
|
212
200
|
|
213
201
|
context "with a parceable string" do
|
metadata
CHANGED
@@ -1,157 +1,163 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: evil-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kozin (nepalez)
|
8
8
|
- Ravil Bairamgalin (brainopia)
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2018-01-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
+
name: dry-initializer
|
15
16
|
requirement: !ruby/object:Gem::Requirement
|
16
17
|
requirements:
|
17
18
|
- - "~>"
|
18
19
|
- !ruby/object:Gem::Version
|
19
|
-
version: 2.
|
20
|
-
name: dry-initializer
|
21
|
-
prerelease: false
|
20
|
+
version: '2.1'
|
22
21
|
type: :runtime
|
22
|
+
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: 2.
|
27
|
+
version: '2.1'
|
28
28
|
- !ruby/object:Gem::Dependency
|
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
|
-
name: tram-policy
|
35
|
-
prerelease: false
|
34
|
+
version: '3.1'
|
36
35
|
type: :runtime
|
36
|
+
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
39
|
- - "~>"
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version:
|
41
|
+
version: '3.1'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
|
+
name: rack
|
43
44
|
requirement: !ruby/object:Gem::Requirement
|
44
45
|
requirements:
|
45
46
|
- - "~>"
|
46
47
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
48
|
-
name: mime-types
|
49
|
-
prerelease: false
|
48
|
+
version: '2'
|
50
49
|
type: :runtime
|
50
|
+
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
53
|
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version: '
|
55
|
+
version: '2'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
|
+
name: tram-policy
|
57
58
|
requirement: !ruby/object:Gem::Requirement
|
58
59
|
requirements:
|
59
60
|
- - "~>"
|
60
61
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
62
|
-
|
63
|
-
|
62
|
+
version: 0.2.2
|
63
|
+
- - "<="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 0.2.3
|
64
66
|
type: :runtime
|
67
|
+
prerelease: false
|
65
68
|
version_requirements: !ruby/object:Gem::Requirement
|
66
69
|
requirements:
|
67
70
|
- - "~>"
|
68
71
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
72
|
+
version: 0.2.2
|
73
|
+
- - "<="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.2.3
|
70
76
|
- !ruby/object:Gem::Dependency
|
77
|
+
name: rake
|
71
78
|
requirement: !ruby/object:Gem::Requirement
|
72
79
|
requirements:
|
73
80
|
- - ">="
|
74
81
|
- !ruby/object:Gem::Version
|
75
82
|
version: '10'
|
76
|
-
name: rake
|
77
|
-
prerelease: false
|
78
83
|
type: :development
|
84
|
+
prerelease: false
|
79
85
|
version_requirements: !ruby/object:Gem::Requirement
|
80
86
|
requirements:
|
81
87
|
- - ">="
|
82
88
|
- !ruby/object:Gem::Version
|
83
89
|
version: '10'
|
84
90
|
- !ruby/object:Gem::Dependency
|
91
|
+
name: rspec
|
85
92
|
requirement: !ruby/object:Gem::Requirement
|
86
93
|
requirements:
|
87
94
|
- - "~>"
|
88
95
|
- !ruby/object:Gem::Version
|
89
96
|
version: '3.0'
|
90
|
-
name: rspec
|
91
|
-
prerelease: false
|
92
97
|
type: :development
|
98
|
+
prerelease: false
|
93
99
|
version_requirements: !ruby/object:Gem::Requirement
|
94
100
|
requirements:
|
95
101
|
- - "~>"
|
96
102
|
- !ruby/object:Gem::Version
|
97
103
|
version: '3.0'
|
98
104
|
- !ruby/object:Gem::Dependency
|
105
|
+
name: rspec-its
|
99
106
|
requirement: !ruby/object:Gem::Requirement
|
100
107
|
requirements:
|
101
108
|
- - "~>"
|
102
109
|
- !ruby/object:Gem::Version
|
103
110
|
version: '1.2'
|
104
|
-
name: rspec-its
|
105
|
-
prerelease: false
|
106
111
|
type: :development
|
112
|
+
prerelease: false
|
107
113
|
version_requirements: !ruby/object:Gem::Requirement
|
108
114
|
requirements:
|
109
115
|
- - "~>"
|
110
116
|
- !ruby/object:Gem::Version
|
111
117
|
version: '1.2'
|
112
118
|
- !ruby/object:Gem::Dependency
|
119
|
+
name: rubocop
|
113
120
|
requirement: !ruby/object:Gem::Requirement
|
114
121
|
requirements:
|
115
122
|
- - "~>"
|
116
123
|
- !ruby/object:Gem::Version
|
117
124
|
version: '0.42'
|
118
|
-
name: rubocop
|
119
|
-
prerelease: false
|
120
125
|
type: :development
|
126
|
+
prerelease: false
|
121
127
|
version_requirements: !ruby/object:Gem::Requirement
|
122
128
|
requirements:
|
123
129
|
- - "~>"
|
124
130
|
- !ruby/object:Gem::Version
|
125
131
|
version: '0.42'
|
126
132
|
- !ruby/object:Gem::Dependency
|
133
|
+
name: timecop
|
127
134
|
requirement: !ruby/object:Gem::Requirement
|
128
135
|
requirements:
|
129
136
|
- - "~>"
|
130
137
|
- !ruby/object:Gem::Version
|
131
138
|
version: '0.9'
|
132
|
-
name: timecop
|
133
|
-
prerelease: false
|
134
139
|
type: :development
|
140
|
+
prerelease: false
|
135
141
|
version_requirements: !ruby/object:Gem::Requirement
|
136
142
|
requirements:
|
137
143
|
- - "~>"
|
138
144
|
- !ruby/object:Gem::Version
|
139
145
|
version: '0.9'
|
140
146
|
- !ruby/object:Gem::Dependency
|
147
|
+
name: webmock
|
141
148
|
requirement: !ruby/object:Gem::Requirement
|
142
149
|
requirements:
|
143
150
|
- - "~>"
|
144
151
|
- !ruby/object:Gem::Version
|
145
152
|
version: '2.1'
|
146
|
-
name: webmock
|
147
|
-
prerelease: false
|
148
153
|
type: :development
|
154
|
+
prerelease: false
|
149
155
|
version_requirements: !ruby/object:Gem::Requirement
|
150
156
|
requirements:
|
151
157
|
- - "~>"
|
152
158
|
- !ruby/object:Gem::Version
|
153
159
|
version: '2.1'
|
154
|
-
description:
|
160
|
+
description:
|
155
161
|
email:
|
156
162
|
- andrew.kozin@gmail.com
|
157
163
|
- nepalez@evilmartians.com
|
@@ -200,6 +206,7 @@ files:
|
|
200
206
|
- lib/evil/client/container.rb
|
201
207
|
- lib/evil/client/container/operation.rb
|
202
208
|
- lib/evil/client/container/scope.rb
|
209
|
+
- lib/evil/client/dictionary.rb
|
203
210
|
- lib/evil/client/exceptions/definition_error.rb
|
204
211
|
- lib/evil/client/exceptions/name_error.rb
|
205
212
|
- lib/evil/client/exceptions/response_error.rb
|
@@ -210,6 +217,7 @@ files:
|
|
210
217
|
- lib/evil/client/formatter/multipart.rb
|
211
218
|
- lib/evil/client/formatter/part.rb
|
212
219
|
- lib/evil/client/formatter/text.rb
|
220
|
+
- lib/evil/client/model.rb
|
213
221
|
- lib/evil/client/names.rb
|
214
222
|
- lib/evil/client/options.rb
|
215
223
|
- lib/evil/client/policy.rb
|
@@ -240,6 +248,7 @@ files:
|
|
240
248
|
- spec/features/operation/request_spec.rb
|
241
249
|
- spec/features/operation/response_spec.rb
|
242
250
|
- spec/features/scope/options_spec.rb
|
251
|
+
- spec/fixtures/config.yml
|
243
252
|
- spec/fixtures/locales/en.yml
|
244
253
|
- spec/fixtures/test_client.rb
|
245
254
|
- spec/spec_helper.rb
|
@@ -251,6 +260,7 @@ files:
|
|
251
260
|
- spec/unit/container/operation_spec.rb
|
252
261
|
- spec/unit/container/scope_spec.rb
|
253
262
|
- spec/unit/container_spec.rb
|
263
|
+
- spec/unit/dictionary_spec.rb
|
254
264
|
- spec/unit/exceptions/definition_error_spec.rb
|
255
265
|
- spec/unit/exceptions/name_error_spec.rb
|
256
266
|
- spec/unit/exceptions/response_error_spec.rb
|
@@ -261,6 +271,7 @@ files:
|
|
261
271
|
- spec/unit/formatter/part_spec.rb
|
262
272
|
- spec/unit/formatter/text_spec.rb
|
263
273
|
- spec/unit/formatter_spec.rb
|
274
|
+
- spec/unit/model_spec.rb
|
264
275
|
- spec/unit/options_spec.rb
|
265
276
|
- spec/unit/policy_spec.rb
|
266
277
|
- spec/unit/resolver/body_spec.rb
|
@@ -284,7 +295,7 @@ homepage: https://github.com/evilmartians/evil-client
|
|
284
295
|
licenses:
|
285
296
|
- MIT
|
286
297
|
metadata: {}
|
287
|
-
post_install_message:
|
298
|
+
post_install_message:
|
288
299
|
rdoc_options: []
|
289
300
|
require_paths:
|
290
301
|
- lib
|
@@ -299,9 +310,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
299
310
|
- !ruby/object:Gem::Version
|
300
311
|
version: '0'
|
301
312
|
requirements: []
|
302
|
-
rubyforge_project:
|
303
|
-
rubygems_version: 2.6.
|
304
|
-
signing_key:
|
313
|
+
rubyforge_project:
|
314
|
+
rubygems_version: 2.6.14
|
315
|
+
signing_key:
|
305
316
|
specification_version: 4
|
306
317
|
summary: Human-friendly DSL for building HTTP(s) clients in Ruby
|
307
318
|
test_files:
|
@@ -311,6 +322,7 @@ test_files:
|
|
311
322
|
- spec/features/operation/request_spec.rb
|
312
323
|
- spec/features/operation/response_spec.rb
|
313
324
|
- spec/features/scope/options_spec.rb
|
325
|
+
- spec/fixtures/config.yml
|
314
326
|
- spec/fixtures/locales/en.yml
|
315
327
|
- spec/fixtures/test_client.rb
|
316
328
|
- spec/spec_helper.rb
|
@@ -322,6 +334,7 @@ test_files:
|
|
322
334
|
- spec/unit/container/operation_spec.rb
|
323
335
|
- spec/unit/container/scope_spec.rb
|
324
336
|
- spec/unit/container_spec.rb
|
337
|
+
- spec/unit/dictionary_spec.rb
|
325
338
|
- spec/unit/exceptions/definition_error_spec.rb
|
326
339
|
- spec/unit/exceptions/name_error_spec.rb
|
327
340
|
- spec/unit/exceptions/response_error_spec.rb
|
@@ -332,6 +345,7 @@ test_files:
|
|
332
345
|
- spec/unit/formatter/part_spec.rb
|
333
346
|
- spec/unit/formatter/text_spec.rb
|
334
347
|
- spec/unit/formatter_spec.rb
|
348
|
+
- spec/unit/model_spec.rb
|
335
349
|
- spec/unit/options_spec.rb
|
336
350
|
- spec/unit/policy_spec.rb
|
337
351
|
- spec/unit/resolver/body_spec.rb
|