haveapi-client 0.19.3 → 0.21.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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +5 -0
  3. data/Rakefile +0 -1
  4. data/haveapi-client.gemspec +7 -10
  5. data/lib/haveapi/cli/action_state.rb +50 -51
  6. data/lib/haveapi/cli/authentication/base.rb +4 -9
  7. data/lib/haveapi/cli/authentication/basic.rb +3 -1
  8. data/lib/haveapi/cli/authentication/token.rb +7 -8
  9. data/lib/haveapi/cli/cli.rb +115 -127
  10. data/lib/haveapi/cli/command.rb +2 -4
  11. data/lib/haveapi/cli/commands/action_state_wait.rb +9 -9
  12. data/lib/haveapi/cli/example_formatter.rb +8 -8
  13. data/lib/haveapi/cli/output_formatter.rb +39 -36
  14. data/lib/haveapi/cli/utils.rb +5 -5
  15. data/lib/haveapi/cli.rb +1 -1
  16. data/lib/haveapi/client/action.rb +17 -20
  17. data/lib/haveapi/client/action_state.rb +3 -7
  18. data/lib/haveapi/client/authentication/base.rb +4 -7
  19. data/lib/haveapi/client/authentication/basic.rb +2 -2
  20. data/lib/haveapi/client/authentication/noauth.rb +0 -1
  21. data/lib/haveapi/client/authentication/token.rb +28 -27
  22. data/lib/haveapi/client/client.rb +12 -6
  23. data/lib/haveapi/client/communicator.rb +33 -35
  24. data/lib/haveapi/client/exceptions.rb +5 -9
  25. data/lib/haveapi/client/parameters/resource.rb +1 -0
  26. data/lib/haveapi/client/parameters/typed.rb +3 -5
  27. data/lib/haveapi/client/params.rb +8 -8
  28. data/lib/haveapi/client/resource.rb +12 -13
  29. data/lib/haveapi/client/resource_instance.rb +71 -72
  30. data/lib/haveapi/client/resource_instance_list.rb +2 -1
  31. data/lib/haveapi/client/response.rb +8 -8
  32. data/lib/haveapi/client/validator.rb +7 -8
  33. data/lib/haveapi/client/validators/confirmation.rb +1 -0
  34. data/lib/haveapi/client/validators/length.rb +1 -0
  35. data/lib/haveapi/client/validators/numericality.rb +2 -1
  36. data/lib/haveapi/client/validators/presence.rb +1 -0
  37. data/lib/haveapi/client/version.rb +2 -2
  38. data/lib/haveapi/client.rb +2 -2
  39. data/lib/restclient_ext/resource.rb +5 -5
  40. data/shell.nix +1 -1
  41. metadata +15 -43
@@ -34,10 +34,12 @@ module HaveAPI::Client
34
34
  # @return [:imperfect] if minor version differs
35
35
  # @return [false] if not compatible
36
36
  def compatible?
37
- description_for(path_for, {describe: :versions})
38
- @proto_version == HaveAPI::Client::PROTOCOL_VERSION ? :compatible
39
- : :imperfect
40
-
37
+ description_for(path_for, { describe: :versions })
38
+ if @proto_version == HaveAPI::Client::PROTOCOL_VERSION
39
+ :compatible
40
+ else
41
+ :imperfect
42
+ end
41
43
  rescue ProtocolError
42
44
  false
43
45
  end
@@ -45,14 +47,14 @@ module HaveAPI::Client
45
47
  # Authenticate user with selected +auth_method+.
46
48
  # +auth_method+ is a name of registered authentication provider.
47
49
  # +options+ are specific for each authentication provider.
48
- def authenticate(auth_method, options = {}, &block)
50
+ def authenticate(auth_method, options = {}, &)
49
51
  desc = describe_api(@version)
50
52
 
51
53
  @auth = self.class.auth_methods[auth_method].new(
52
54
  self,
53
55
  desc[:authentication][auth_method],
54
56
  options,
55
- &block
57
+ &
56
58
  )
57
59
  @rest = @auth.resource || @rest
58
60
  end
@@ -62,11 +64,11 @@ module HaveAPI::Client
62
64
  end
63
65
 
64
66
  def available_versions
65
- description_for(path_for, {describe: :versions})
67
+ description_for(path_for, { describe: :versions })
66
68
  end
67
69
 
68
- def describe_api(v=nil)
69
- description_for(path_for(v), v.nil? ? {describe: :default} : {})
70
+ def describe_api(v = nil)
71
+ description_for(path_for(v), v.nil? ? { describe: :default } : {})
70
72
  end
71
73
 
72
74
  def describe_resource(path)
@@ -97,7 +99,7 @@ module HaveAPI::Client
97
99
  a = tmp[:actions][action]
98
100
 
99
101
  unless a # search in aliases
100
- tmp[:actions].each do |_, v|
102
+ tmp[:actions].each_value do |v|
101
103
  if v[:aliases].include?(action.to_s)
102
104
  a = v
103
105
  break
@@ -124,43 +126,39 @@ module HaveAPI::Client
124
126
  params.delete(:meta)
125
127
  end
126
128
 
127
- if %w(POST PUT).include?(action.http_method)
129
+ if %w[POST PUT].include?(action.http_method)
128
130
  ns = {}
129
131
  ns[input_namespace] = params if input_namespace
130
132
  ns[:_meta] = meta if meta
131
133
  ns.update(@auth.request_payload)
132
134
 
133
135
  args << ns.to_json
134
- args << {content_type: :json, accept: :json, user_agent: @identity}.update(@auth.request_headers)
136
+ args << { content_type: :json, accept: :json, user_agent: @identity }.update(@auth.request_headers)
135
137
 
136
- elsif %w(GET DELETE).include?(action.http_method)
138
+ elsif %w[GET DELETE].include?(action.http_method)
137
139
  get_params = {}
138
140
 
139
141
  params.each do |k, v|
140
142
  get_params["#{input_namespace}[#{k}]"] = v
141
143
  end
142
144
 
143
- meta.each do |k, v|
144
- get_params["_meta[#{k}]"] = v # FIXME: read _meta namespace from the description
145
-
146
- end if meta
145
+ if meta
146
+ meta.each do |k, v|
147
+ get_params["_meta[#{k}]"] = v # FIXME: read _meta namespace from the description
148
+ end
149
+ end
147
150
 
148
- args << {params: get_params.update(@auth.request_query_params), accept: :json, user_agent: @identity}.update(@auth.request_headers)
151
+ args << { params: get_params.update(@auth.request_query_params), accept: :json, user_agent: @identity }.update(@auth.request_headers)
149
152
  end
150
153
 
151
154
  begin
152
155
  response = parse(@rest[action.prepared_path].method(action.http_method.downcase.to_sym).call(*args))
153
-
154
156
  rescue RestClient::Forbidden
155
157
  return error('Access forbidden. Bad user name or password? Not authorized?')
156
-
157
- rescue RestClient::ResourceNotFound => e
158
- response = parse(e.http_body)
159
-
160
- rescue RestClient::BadRequest => e
158
+ rescue RestClient::ResourceNotFound,
159
+ RestClient::BadRequest => e
161
160
  response = parse(e.http_body)
162
-
163
- rescue => e
161
+ rescue StandardError => e
164
162
  return error("Fatal API error: #{e.inspect}")
165
163
  end
166
164
 
@@ -177,15 +175,16 @@ module HaveAPI::Client
177
175
  end
178
176
 
179
177
  private
178
+
180
179
  def ok(response)
181
- {status: true, response: response}
180
+ { status: true, response: }
182
181
  end
183
182
 
184
- def error(msg, errors={})
185
- {status: false, message: msg, errors: errors}
183
+ def error(msg, errors = {})
184
+ { status: false, message: msg, errors: }
186
185
  end
187
186
 
188
- def path_for(v=nil, r=nil)
187
+ def path_for(v = nil, r = nil)
189
188
  ret = '/'
190
189
 
191
190
  ret += "v#{v}/" if v
@@ -194,7 +193,7 @@ module HaveAPI::Client
194
193
  ret
195
194
  end
196
195
 
197
- def description_for(path, query_params={})
196
+ def description_for(path, query_params = {})
198
197
  ret = parse(@rest[path].get_options({
199
198
  params: @auth.request_payload.update(@auth.request_query_params).update(query_params),
200
199
  user_agent: @identity
@@ -206,8 +205,7 @@ module HaveAPI::Client
206
205
 
207
206
  unless ret[:version]
208
207
  raise ProtocolError,
209
- "Incompatible protocol version: the client uses v#{p_v} "+
210
- "while the API server uses an unspecified version (pre 1.0)"
208
+ "Incompatible protocol version: the client uses v#{p_v} while the API server uses an unspecified version (pre 1.0)"
211
209
  end
212
210
 
213
211
  major1, minor1 = ret[:version].split('.')
@@ -215,8 +213,8 @@ module HaveAPI::Client
215
213
 
216
214
  if major1 != major2
217
215
  raise ProtocolError,
218
- "Incompatible protocol version: the client uses v#{p_v} "+
219
- "while the API server uses v#{ret[:version]}"
216
+ "Incompatible protocol version: the client uses v#{p_v} " \
217
+ "while the API server uses v#{ret[:version]}"
220
218
  end
221
219
 
222
220
  warn "The client uses protocol v#{p_v} while the API server uses v#{ret[:version]}"
@@ -1,15 +1,13 @@
1
1
  module HaveAPI::Client
2
- class ProtocolError < StandardError ; end
2
+ class ProtocolError < StandardError; end
3
3
 
4
4
  class ActionFailed < StandardError
5
5
  attr_reader :response
6
6
 
7
7
  def initialize(response)
8
- @response = response
9
- end
8
+ super("#{response.action.name} failed: #{response.message}")
10
9
 
11
- def message
12
- "#{@response.action.name} failed: #{@response.message}"
10
+ @response = response
13
11
  end
14
12
  end
15
13
 
@@ -17,12 +15,10 @@ module HaveAPI::Client
17
15
  attr_reader :errors
18
16
 
19
17
  def initialize(action, errors)
18
+ super("#{action.name} failed: input parameters not valid")
19
+
20
20
  @action = action
21
21
  @errors = errors
22
22
  end
23
-
24
- def message
25
- "#{@action.name} failed: input parameters not valid"
26
- end
27
23
  end
28
24
  end
@@ -16,6 +16,7 @@ module HaveAPI::Client
16
16
  end
17
17
 
18
18
  protected
19
+
19
20
  def coerce(v)
20
21
  if !v.is_a?(::Integer) && /\A\d+\z/ !~ v
21
22
  @errors << 'not a valid resource id'
@@ -40,10 +40,11 @@ module HaveAPI::Client
40
40
  end
41
41
 
42
42
  protected
43
+
43
44
  def coerce(raw)
44
45
  type = @desc[:type]
45
46
 
46
- val = if type == 'Integer'
47
+ if type == 'Integer'
47
48
  raw.to_i
48
49
 
49
50
  elsif type == 'Float'
@@ -62,21 +63,18 @@ module HaveAPI::Client
62
63
  else
63
64
  begin
64
65
  DateTime.iso8601(raw).to_time
65
-
66
66
  rescue ArgumentError
67
67
  @errors << 'not in ISO 8601 format'
68
68
  nil
69
69
  end
70
70
  end
71
71
 
72
- elsif %w(String Text).include?(type)
72
+ elsif %w[String Text].include?(type)
73
73
  raw.to_s
74
74
 
75
75
  else
76
76
  raw
77
77
  end
78
-
79
- val
80
78
  end
81
79
  end
82
80
  end
@@ -1,5 +1,5 @@
1
1
  module HaveAPI::Client
2
- module Parameters ; end
2
+ module Parameters; end
3
3
 
4
4
  class Params
5
5
  attr_reader :errors, :params
@@ -16,12 +16,12 @@ module HaveAPI::Client
16
16
  @action.input_params.each do |name, p|
17
17
  next unless @data.has_key?(name)
18
18
 
19
- if p[:type] == 'Resource'
20
- @params[name] = Parameters::Resource.new(self, p, @data[name])
19
+ @params[name] = if p[:type] == 'Resource'
20
+ Parameters::Resource.new(self, p, @data[name])
21
21
 
22
- else
23
- @params[name] = Parameters::Typed.new(self, p, @data[name])
24
- end
22
+ else
23
+ Parameters::Typed.new(self, p, @data[name])
24
+ end
25
25
  end
26
26
  end
27
27
 
@@ -36,10 +36,9 @@ module HaveAPI::Client
36
36
  next
37
37
  end
38
38
 
39
- if !@params[name].valid?
39
+ unless @params[name].valid?
40
40
  error(name, @params[name].errors)
41
41
  end
42
-
43
42
  end
44
43
 
45
44
  @errors.empty?
@@ -58,6 +57,7 @@ module HaveAPI::Client
58
57
  end
59
58
 
60
59
  protected
60
+
61
61
  def error(param, msg)
62
62
  @errors[param] ||= []
63
63
 
@@ -71,6 +71,7 @@ module HaveAPI::Client
71
71
  end
72
72
 
73
73
  protected
74
+
74
75
  # Define access/write methods for action +action+.
75
76
  def define_action(action)
76
77
  action.aliases(true).each do |name|
@@ -116,7 +117,7 @@ module HaveAPI::Client
116
117
  if user_params.has_key?(:meta)
117
118
  meta = user_params[:meta]
118
119
 
119
- %i(block block_interval block_timeout).each do |p|
120
+ %i[block block_interval block_timeout].each do |p|
120
121
  client_opts[p] = meta.delete(p) if meta.has_key?(p)
121
122
  end
122
123
  end
@@ -126,21 +127,18 @@ module HaveAPI::Client
126
127
 
127
128
  ret = Response.new(action, action.execute(input_params))
128
129
 
129
- raise ActionFailed.new(ret) unless ret.ok?
130
+ raise ActionFailed, ret unless ret.ok?
130
131
 
131
132
  return_value = case action.output && action.output_layout
132
- when :object
133
- ResourceInstance.new(@client, @api, self, action: action, response: ret)
134
-
135
- when :object_list
136
- ResourceInstanceList.new(@client, @api, self, action, ret)
133
+ when :object
134
+ ResourceInstance.new(@client, @api, self, action:, response: ret)
137
135
 
138
- when :hash, :hash_list
139
- ret
136
+ when :object_list
137
+ ResourceInstanceList.new(@client, @api, self, action, ret)
140
138
 
141
- else
142
- ret
143
- end
139
+ else # :hash, :hash_list
140
+ ret
141
+ end
144
142
 
145
143
  if action.blocking? && client_opts[:block]
146
144
  wait_opts = {}
@@ -165,7 +163,8 @@ module HaveAPI::Client
165
163
  # Called before defining a method named +name+ that will
166
164
  # invoke +action+.
167
165
  def define_method?(action, name)
168
- return false if %i(new).include?(name.to_sym)
166
+ return false if %i[new].include?(name.to_sym)
167
+
169
168
  true
170
169
  end
171
170
 
@@ -24,28 +24,28 @@ module HaveAPI::Client
24
24
  if response.is_a?(Hash)
25
25
  @params = response
26
26
  @prepared_args = response[:_meta][:path_params]
27
- @meta = response[:_meta] unless @meta
27
+ @meta ||= response[:_meta]
28
28
 
29
29
  else
30
30
  @response = response
31
31
  @params = response.response
32
32
  @prepared_args = response.meta[:path_params]
33
- @meta = response.meta unless @meta
33
+ @meta ||= response.meta
34
34
  end
35
35
 
36
36
  setup_from_clone(resource)
37
37
  define_attributes
38
38
  end
39
39
 
40
- unless @persistent
41
- setup_from_clone(resource)
42
- define_implicit_attributes
43
- define_attributes(@action.input_params)
44
- end
40
+ return if @persistent
41
+
42
+ setup_from_clone(resource)
43
+ define_implicit_attributes
44
+ define_attributes(@action.input_params)
45
45
  end
46
46
 
47
47
  def new
48
- raise NoMethodError.new
48
+ raise NoMethodError
49
49
  end
50
50
 
51
51
  # Invoke +create+ action if the object is not persistent,
@@ -58,13 +58,10 @@ module HaveAPI::Client
58
58
  @action.provide_args
59
59
  @response = Response.new(@action, @action.execute(attributes_for_api(@action)))
60
60
 
61
- if @response.ok?
62
- @params = @response.response
63
- define_attributes
61
+ return nil unless @response.ok?
64
62
 
65
- else
66
- return nil
67
- end
63
+ @params = @response.response
64
+ define_attributes
68
65
 
69
66
  @persistent = true
70
67
  self
@@ -73,7 +70,8 @@ module HaveAPI::Client
73
70
 
74
71
  # Call #save and raise ActionFailed if it fails.
75
72
  def save!
76
- raise ActionFailed.new(@response) if save.nil?
73
+ raise ActionFailed, @response if save.nil?
74
+
77
75
  self
78
76
  end
79
77
 
@@ -104,68 +102,69 @@ module HaveAPI::Client
104
102
  end
105
103
 
106
104
  def to_s
107
- "<#{self.class.to_s}:#{object_id}:#{@resource._name}>"
105
+ "<#{self.class}:#{object_id}:#{@resource._name}>"
108
106
  end
109
107
 
110
108
  protected
109
+
111
110
  # Define access/writer methods for object attributes.
112
111
  def define_attributes(params = nil)
113
112
  (params || @action.params).each do |name, param|
114
113
  case param[:type]
115
- when 'Resource'
116
- @resource_instances[name] = find_association(param, @params[name])
117
-
118
- # id reader
119
- ensure_method(:"#{name}_id") do
120
- @params[name] && @params[name][ param[:value_id].to_sym ]
121
- end
122
-
123
- # id writer
124
- ensure_method(:"#{name}_id=") do |id|
125
- @params[name] ||= {}
126
- @params[name][ param[:value_id].to_sym ] = id
127
-
128
- @resource_instances[name] = find_association(
129
- param,
130
- {
131
- param[:value_id] => id,
132
- :_meta => {
133
- resolved: false,
134
- # TODO: this will not work for nested resources, as they have
135
- # multiple IDs
136
- path_params: [id],
137
- },
114
+ when 'Resource'
115
+ @resource_instances[name] = find_association(param, @params[name])
116
+
117
+ # id reader
118
+ ensure_method(:"#{name}_id") do
119
+ @params[name] && @params[name][ param[:value_id].to_sym ]
120
+ end
121
+
122
+ # id writer
123
+ ensure_method(:"#{name}_id=") do |id|
124
+ @params[name] ||= {}
125
+ @params[name][ param[:value_id].to_sym ] = id
126
+
127
+ @resource_instances[name] = find_association(
128
+ param,
129
+ {
130
+ param[:value_id] => id,
131
+ :_meta => {
132
+ resolved: false,
133
+ # TODO: this will not work for nested resources, as they have
134
+ # multiple IDs
135
+ path_params: [id]
138
136
  }
139
- )
140
- end
137
+ }
138
+ )
139
+ end
141
140
 
142
- # value reader
143
- ensure_method(name) do
144
- @resource_instances[name] && @resource_instances[name].resolve
145
- end
141
+ # value reader
142
+ ensure_method(name) do
143
+ @resource_instances[name] && @resource_instances[name].resolve
144
+ end
146
145
 
147
- # value writer
148
- ensure_method(:"#{name}=") do |obj|
149
- @params[name] ||= {}
150
- @params[name][ param[:value_id].to_sym ] = obj.method(param[:value_id]).call
151
- @params[name][ param[:value_label].to_sym ] = obj.method(param[:value_label]).call
146
+ # value writer
147
+ ensure_method(:"#{name}=") do |obj|
148
+ @params[name] ||= {}
149
+ @params[name][ param[:value_id].to_sym ] = obj.method(param[:value_id]).call
150
+ @params[name][ param[:value_label].to_sym ] = obj.method(param[:value_label]).call
152
151
 
153
- @resource_instances[name] = obj
154
- end
152
+ @resource_instances[name] = obj
153
+ end
155
154
 
156
- else
157
- # reader
158
- ensure_method(name) { @params[name] }
155
+ else
156
+ # reader
157
+ ensure_method(name) { @params[name] }
159
158
 
160
- # writer
161
- ensure_method(:"#{name}=") { |new_val| @params[name] = new_val }
159
+ # writer
160
+ ensure_method(:"#{name}=") { |new_val| @params[name] = new_val }
162
161
  end
163
162
  end
164
163
  end
165
164
 
166
165
  # Define method +name+ with +block+ if it isn't defined yet.
167
- def ensure_method(name, &block)
168
- define_singleton_method(name, &block) unless respond_to?(name)
166
+ def ensure_method(name, &)
167
+ define_singleton_method(name, &) unless respond_to?(name)
169
168
  end
170
169
 
171
170
  # Define nil references to resource attributes.
@@ -185,13 +184,13 @@ module HaveAPI::Client
185
184
  return ret if action.input_layout != :object
186
185
 
187
186
  action.input_params.each do |name, param|
188
- case param[:type]
189
- when 'Resource'
190
- ret[name] = @params[name][ param[:value_id].to_sym ]
187
+ ret[name] = case param[:type]
188
+ when 'Resource'
189
+ @params[name][ param[:value_id].to_sym ]
191
190
 
192
- else
193
- ret[name] = @params[name]
194
- end
191
+ else
192
+ @params[name]
193
+ end
195
194
  end
196
195
 
197
196
  ret
@@ -209,13 +208,13 @@ module HaveAPI::Client
209
208
 
210
209
  # FIXME: read _meta namespace from description
211
210
  ResourceInstance.new(
212
- @client,
213
- @api,
214
- tmp,
215
- action: tmp.actions[:show],
216
- resolved: res_val[:_meta][:resolved],
217
- response: res_val[:_meta][:resolved] ? res_val : nil,
218
- meta: res_val[:_meta]
211
+ @client,
212
+ @api,
213
+ tmp,
214
+ action: tmp.actions[:show],
215
+ resolved: res_val[:_meta][:resolved],
216
+ response: res_val[:_meta][:resolved] ? res_val : nil,
217
+ meta: res_val[:_meta]
219
218
  )
220
219
  end
221
220
 
@@ -2,10 +2,11 @@ module HaveAPI::Client
2
2
  # A list of ResourceInstance objects.
3
3
  class ResourceInstanceList < Array
4
4
  def initialize(client, api, resource, action, response)
5
+ super()
5
6
  @response = response
6
7
 
7
8
  response.response.each do |hash|
8
- self << ResourceInstance.new(client, api, resource, action: action, response: hash)
9
+ self << ResourceInstance.new(client, api, resource, action:, response: hash)
9
10
  end
10
11
  end
11
12
 
@@ -19,10 +19,10 @@ class HaveAPI::Client::Response
19
19
 
20
20
  def response
21
21
  case @action.output_layout
22
- when :object, :object_list, :hash, :hash_list
23
- @response[:response][@action.namespace(:output).to_sym]
24
- else
25
- @response[:response]
22
+ when :object, :object_list, :hash, :hash_list
23
+ @response[:response][@action.namespace(:output).to_sym]
24
+ else
25
+ @response[:response]
26
26
  end
27
27
  end
28
28
 
@@ -44,7 +44,7 @@ class HaveAPI::Client::Response
44
44
 
45
45
  # Access namespaced params directly.
46
46
  def [](key)
47
- return unless %i(object hash).include?(@action.output_layout.to_sym)
47
+ return unless %i[object hash].include?(@action.output_layout.to_sym)
48
48
 
49
49
  @response[:response][@action.namespace(:output).to_sym][key]
50
50
  end
@@ -52,7 +52,7 @@ class HaveAPI::Client::Response
52
52
  # Iterate over namespaced items directly. Works for only for
53
53
  # object_list or hash_list.
54
54
  def each
55
- return unless %i(list).include?(@action.layout.to_sym)
55
+ return unless %i[list].include?(@action.layout.to_sym)
56
56
 
57
57
  @response[:response][@action.namespace(:output).to_sym].each
58
58
  end
@@ -61,10 +61,10 @@ class HaveAPI::Client::Response
61
61
  # it is regularly called with the action's state.
62
62
  #
63
63
  # @see HaveAPI::Client::Action#wait_for_completion
64
- def wait_for_completion(**kwargs, &block)
64
+ def wait_for_completion(**, &)
65
65
  id = meta[:action_state_id]
66
66
  return nil unless id
67
67
 
68
- HaveAPI::Client::Action.wait_for_completion(@action.client, id, **kwargs, &block)
68
+ HaveAPI::Client::Action.wait_for_completion(@action.client, id, **, &)
69
69
  end
70
70
  end
@@ -1,12 +1,12 @@
1
1
  module HaveAPI::Client
2
- module Validators ; end
2
+ module Validators; end
3
3
 
4
4
  class Validator
5
5
  class << self
6
6
  def name(v)
7
7
  Validator.register(v, self)
8
8
  end
9
-
9
+
10
10
  def register(name, klass)
11
11
  @validators ||= {}
12
12
  @validators[name] = klass
@@ -14,9 +14,9 @@ module HaveAPI::Client
14
14
 
15
15
  def validate(validators, param, other_params)
16
16
  ret = []
17
-
17
+
18
18
  validators.each do |name, desc|
19
- fail "unsupported validator '#{name}'" if @validators[name].nil?
19
+ raise "unsupported validator '#{name}'" if @validators[name].nil?
20
20
 
21
21
  v = @validators[name].new(desc, param, other_params)
22
22
  ret.concat(v.errors) unless v.valid?
@@ -35,7 +35,7 @@ module HaveAPI::Client
35
35
  end
36
36
 
37
37
  def errors
38
- @errors || [opts[:message] % { value: value }]
38
+ @errors || [format(opts[:message], value:)]
39
39
  end
40
40
 
41
41
  def valid?
@@ -43,9 +43,8 @@ module HaveAPI::Client
43
43
  end
44
44
 
45
45
  protected
46
- def opts
47
- @opts
48
- end
46
+
47
+ attr_reader :opts
49
48
 
50
49
  def error(e)
51
50
  @errors ||= []
@@ -9,6 +9,7 @@ module HaveAPI::Client
9
9
 
10
10
  if opts[:equal]
11
11
  return false if params[other].nil?
12
+
12
13
  value == params[other].value
13
14
 
14
15
  else