haveapi 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 (84) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Rakefile +6 -6
  4. data/haveapi.gemspec +13 -13
  5. data/lib/haveapi/action.rb +140 -158
  6. data/lib/haveapi/action_state.rb +2 -6
  7. data/lib/haveapi/actions/default.rb +8 -10
  8. data/lib/haveapi/api.rb +2 -1
  9. data/lib/haveapi/authentication/base.rb +5 -8
  10. data/lib/haveapi/authentication/basic/provider.rb +4 -5
  11. data/lib/haveapi/authentication/chain.rb +19 -17
  12. data/lib/haveapi/authentication/oauth2/config.rb +12 -32
  13. data/lib/haveapi/authentication/oauth2/provider.rb +20 -30
  14. data/lib/haveapi/authentication/oauth2/revoke_endpoint.rb +1 -2
  15. data/lib/haveapi/authentication/token/action_config.rb +5 -3
  16. data/lib/haveapi/authentication/token/config.rb +5 -5
  17. data/lib/haveapi/authentication/token/provider.rb +33 -37
  18. data/lib/haveapi/authorization.rb +5 -4
  19. data/lib/haveapi/client_example.rb +11 -14
  20. data/lib/haveapi/client_examples/curl.rb +37 -37
  21. data/lib/haveapi/client_examples/fs_client.rb +29 -31
  22. data/lib/haveapi/client_examples/http.rb +35 -36
  23. data/lib/haveapi/client_examples/js_client.rb +62 -63
  24. data/lib/haveapi/client_examples/php_client.rb +77 -76
  25. data/lib/haveapi/client_examples/ruby_cli.rb +30 -30
  26. data/lib/haveapi/client_examples/ruby_client.rb +26 -26
  27. data/lib/haveapi/common.rb +3 -4
  28. data/lib/haveapi/context.rb +11 -10
  29. data/lib/haveapi/example.rb +9 -4
  30. data/lib/haveapi/example_list.rb +2 -2
  31. data/lib/haveapi/exceptions.rb +1 -1
  32. data/lib/haveapi/extensions/action_exceptions.rb +2 -2
  33. data/lib/haveapi/extensions/base.rb +1 -3
  34. data/lib/haveapi/extensions/exception_mailer.rb +260 -257
  35. data/lib/haveapi/hooks.rb +40 -39
  36. data/lib/haveapi/metadata.rb +1 -1
  37. data/lib/haveapi/model_adapter.rb +16 -27
  38. data/lib/haveapi/model_adapters/active_record.rb +59 -69
  39. data/lib/haveapi/output_formatter.rb +7 -7
  40. data/lib/haveapi/output_formatters/base.rb +2 -4
  41. data/lib/haveapi/parameters/resource.rb +7 -7
  42. data/lib/haveapi/parameters/typed.rb +6 -9
  43. data/lib/haveapi/params.rb +38 -45
  44. data/lib/haveapi/resource.rb +8 -8
  45. data/lib/haveapi/resources/action_state.rb +11 -19
  46. data/lib/haveapi/server.rb +105 -108
  47. data/lib/haveapi/spec/api_response.rb +1 -1
  48. data/lib/haveapi/spec/helpers.rb +1 -1
  49. data/lib/haveapi/spec/mock_action.rb +11 -10
  50. data/lib/haveapi/spec/spec_methods.rb +9 -8
  51. data/lib/haveapi/tasks/yard.rb +2 -2
  52. data/lib/haveapi/types.rb +5 -6
  53. data/lib/haveapi/validator.rb +6 -3
  54. data/lib/haveapi/validator_chain.rb +9 -8
  55. data/lib/haveapi/validators/acceptance.rb +6 -6
  56. data/lib/haveapi/validators/confirmation.rb +2 -3
  57. data/lib/haveapi/validators/exclusion.rb +1 -1
  58. data/lib/haveapi/validators/format.rb +1 -1
  59. data/lib/haveapi/validators/inclusion.rb +1 -1
  60. data/lib/haveapi/validators/length.rb +12 -11
  61. data/lib/haveapi/validators/numericality.rb +14 -13
  62. data/lib/haveapi/validators/presence.rb +4 -3
  63. data/lib/haveapi/version.rb +2 -2
  64. data/lib/haveapi.rb +2 -3
  65. data/spec/.rubocop.yml +4 -0
  66. data/spec/action/dsl_spec.rb +18 -18
  67. data/spec/authorization_spec.rb +8 -8
  68. data/spec/common_spec.rb +2 -1
  69. data/spec/documentation_spec.rb +2 -9
  70. data/spec/envelope_spec.rb +2 -2
  71. data/spec/hooks_spec.rb +12 -12
  72. data/spec/parameters/typed_spec.rb +6 -6
  73. data/spec/params_spec.rb +22 -24
  74. data/spec/resource_spec.rb +5 -7
  75. data/spec/spec_helper.rb +0 -1
  76. data/spec/validators/acceptance_spec.rb +1 -1
  77. data/spec/validators/confirmation_spec.rb +5 -5
  78. data/spec/validators/exclusion_spec.rb +3 -3
  79. data/spec/validators/format_spec.rb +2 -2
  80. data/spec/validators/inclusion_spec.rb +4 -4
  81. data/spec/validators/length_spec.rb +23 -23
  82. data/spec/validators/numericality_spec.rb +13 -13
  83. data/spec/validators/presence_spec.rb +3 -3
  84. metadata +49 -48
@@ -6,34 +6,34 @@ require 'haveapi/hooks'
6
6
 
7
7
  module HaveAPI
8
8
  class Server
9
- attr_reader :root, :routes, :module_name, :auth_chain, :versions, :default_version,
10
- :extensions
11
- attr_accessor :action_state
9
+ attr_accessor :default_version, :action_state
10
+ attr_reader :root, :routes, :module_name, :auth_chain, :versions, :extensions
12
11
 
13
12
  include Hookable
14
13
 
15
14
  # Called after the user was authenticated (or not). The block is passed
16
15
  # current user object or nil as an argument.
17
16
  has_hook :post_authenticated,
18
- desc: 'Called after the user was authenticated',
19
- args: {
20
- current_user: 'object returned by the authentication backend',
21
- }
17
+ desc: 'Called after the user was authenticated',
18
+ args: {
19
+ current_user: 'object returned by the authentication backend'
20
+ }
22
21
 
23
22
  has_hook :description_exception,
24
- desc: 'Called when an exception occurs when building self-description',
25
- args: {
26
- context: 'HaveAPI::Context',
27
- exception: 'exception instance',
28
- },
29
- ret: {
30
- http_status: 'HTTP status code to send to client',
31
- message: 'error message sent to the client',
32
- }
23
+ desc: 'Called when an exception occurs when building self-description',
24
+ args: {
25
+ context: 'HaveAPI::Context',
26
+ exception: 'exception instance'
27
+ },
28
+ ret: {
29
+ http_status: 'HTTP status code to send to client',
30
+ message: 'error message sent to the client'
31
+ }
33
32
 
34
33
  module ServerHelpers
35
34
  def setup_formatter
36
35
  return if @formatter
36
+
37
37
  @formatter = OutputFormatter.new
38
38
 
39
39
  unless @formatter.supports?(request.accept)
@@ -57,15 +57,15 @@ module HaveAPI
57
57
  end
58
58
 
59
59
  def access_control
60
- if request.env['HTTP_ORIGIN'] && request.env['HTTP_ACCESS_CONTROL_REQUEST_METHOD']
61
- halt 200, {
62
- 'Access-Control-Allow-Origin' => '*',
63
- 'Access-Control-Allow-Methods' => 'GET,POST,OPTIONS,PATCH,PUT,DELETE',
64
- 'Access-Control-Allow-Credentials' => 'false',
65
- 'Access-Control-Allow-Headers' => settings.api_server.allowed_headers,
66
- 'Access-Control-Max-Age' => (60*60).to_s
67
- }, ''
68
- end
60
+ return unless request.env['HTTP_ORIGIN'] && request.env['HTTP_ACCESS_CONTROL_REQUEST_METHOD']
61
+
62
+ halt 200, {
63
+ 'Access-Control-Allow-Origin' => '*',
64
+ 'Access-Control-Allow-Methods' => 'GET,POST,OPTIONS,PATCH,PUT,DELETE',
65
+ 'Access-Control-Allow-Credentials' => 'false',
66
+ 'Access-Control-Allow-Headers' => settings.api_server.allowed_headers,
67
+ 'Access-Control-Max-Age' => (60 * 60).to_s
68
+ }, ''
69
69
  end
70
70
 
71
71
  def current_user
@@ -80,7 +80,7 @@ module HaveAPI
80
80
  def require_auth!
81
81
  report_error(
82
82
  401,
83
- {'WWW-Authenticate' => 'Basic realm="Restricted Area"'},
83
+ { 'WWW-Authenticate' => 'Basic realm="Restricted Area"' },
84
84
  'Action requires user to authenticate'
85
85
  )
86
86
  end
@@ -106,12 +106,12 @@ module HaveAPI
106
106
  end
107
107
 
108
108
  def base_url
109
- if request.env['HTTP_X_FORWARDED_SSL'] == 'on'
110
- scheme = 'https'
109
+ scheme = if request.env['HTTP_X_FORWARDED_SSL'] == 'on'
110
+ 'https'
111
111
 
112
- else
113
- scheme = request.env['rack.url_scheme']
114
- end
112
+ else
113
+ request.env['rack.url_scheme']
114
+ end
115
115
 
116
116
  "#{scheme}://#{request.env['HTTP_HOST']}"
117
117
  end
@@ -140,6 +140,7 @@ module HaveAPI
140
140
  module DocHelpers
141
141
  def format_param_type(param)
142
142
  return param[:type] if param[:type] != 'Resource'
143
+
143
144
  "<a href=\"#root-#{param[:resource].join('-')}-show\">#{param[:type]}</a>"
144
145
  end
145
146
 
@@ -188,14 +189,11 @@ module HaveAPI
188
189
  end
189
190
 
190
191
  # Set default version of API.
191
- def default_version=(v)
192
- @default_version = v
193
- end
194
192
 
195
193
  # Load routes for all resource from included API versions.
196
194
  # All routes are mounted under prefix `path`.
197
195
  # If no default version is set, the last included version is used.
198
- def mount(prefix='/')
196
+ def mount(prefix = '/')
199
197
  @root = prefix
200
198
 
201
199
  @sinatra = Sinatra.new do
@@ -203,8 +201,8 @@ module HaveAPI
203
201
  # for markdown files with extension .md, only .markdown
204
202
  Tilt[:md]
205
203
 
206
- set :views, settings.root + '/views'
207
- set :public_folder, settings.root + '/public'
204
+ set :views, "#{settings.root}/views"
205
+ set :public_folder, "#{settings.root}/public"
208
206
  set :bind, '0.0.0.0'
209
207
 
210
208
  if settings.development?
@@ -230,7 +228,9 @@ module HaveAPI
230
228
  end
231
229
 
232
230
  after do
233
- ActiveRecord::Base.clear_active_connections! if Object.const_defined?(:ActiveRecord)
231
+ if Object.const_defined?(:ActiveRecord)
232
+ ActiveRecord::Base.connection_handler.clear_active_connections!
233
+ end
234
234
  end
235
235
  end
236
236
 
@@ -244,10 +244,10 @@ module HaveAPI
244
244
  authenticated?(settings.api_server.default_version)
245
245
 
246
246
  @api = settings.api_server.describe(Context.new(
247
- settings.api_server,
248
- user: current_user,
249
- params: params
250
- ))
247
+ settings.api_server,
248
+ user: current_user,
249
+ params:
250
+ ))
251
251
 
252
252
  content_type 'text/html'
253
253
  erb :index, layout: :main_layout
@@ -259,27 +259,27 @@ module HaveAPI
259
259
  authenticated?(settings.api_server.default_version)
260
260
  ret = nil
261
261
 
262
- case params[:describe]
263
- when 'versions'
264
- ret = {
265
- versions: settings.api_server.versions,
266
- default: settings.api_server.default_version
267
- }
268
-
269
- when 'default'
270
- ret = settings.api_server.describe_version(Context.new(
271
- settings.api_server,
272
- version: settings.api_server.default_version,
273
- user: current_user, params: params
274
- ))
275
-
276
- else
277
- ret = settings.api_server.describe(Context.new(
278
- settings.api_server,
279
- user: current_user,
280
- params: params
281
- ))
282
- end
262
+ ret = case params[:describe]
263
+ when 'versions'
264
+ {
265
+ versions: settings.api_server.versions,
266
+ default: settings.api_server.default_version
267
+ }
268
+
269
+ when 'default'
270
+ settings.api_server.describe_version(Context.new(
271
+ settings.api_server,
272
+ version: settings.api_server.default_version,
273
+ user: current_user, params:
274
+ ))
275
+
276
+ else
277
+ settings.api_server.describe(Context.new(
278
+ settings.api_server,
279
+ user: current_user,
280
+ params:
281
+ ))
282
+ end
283
283
 
284
284
  @formatter.format(true, ret)
285
285
  end
@@ -296,7 +296,7 @@ module HaveAPI
296
296
  content_type 'text/html'
297
297
 
298
298
  erb :main_layout do
299
- GitHub::Markdown.render(File.new(settings.views + '/../../../README.md').read)
299
+ GitHub::Markdown.render(File.new("#{settings.views}/../../../README.md").read)
300
300
  end
301
301
  end
302
302
 
@@ -313,7 +313,6 @@ module HaveAPI
313
313
  erb :doc_layout, layout: :main_layout do
314
314
  begin
315
315
  @content = doc(f)
316
-
317
316
  rescue Errno::ENOENT
318
317
  halt 404
319
318
  end
@@ -357,11 +356,11 @@ module HaveAPI
357
356
 
358
357
  @v = v
359
358
  @help = settings.api_server.describe_version(Context.new(
360
- settings.api_server,
361
- version: v,
362
- user: current_user,
363
- params: params
364
- ))
359
+ settings.api_server,
360
+ version: v,
361
+ user: current_user,
362
+ params:
363
+ ))
365
364
 
366
365
  content_type 'text/html'
367
366
  erb :doc_layout, layout: :main_layout do
@@ -376,11 +375,11 @@ module HaveAPI
376
375
  authenticated?(v)
377
376
 
378
377
  @formatter.format(true, settings.api_server.describe_version(Context.new(
379
- settings.api_server,
380
- version: v,
381
- user: current_user,
382
- params: params
383
- )))
378
+ settings.api_server,
379
+ version: v,
380
+ user: current_user,
381
+ params:
382
+ )))
384
383
  end
385
384
 
386
385
  # Register blocking resource
@@ -402,16 +401,14 @@ module HaveAPI
402
401
 
403
402
  def validate_resources(resources)
404
403
  resources.each_value do |r|
405
- r[:actions].each_key do |a|
406
- a.validate_build
407
- end
404
+ r[:actions].each_key(&:validate_build)
408
405
 
409
406
  validate_resources(r[:resources])
410
407
  end
411
408
  end
412
409
 
413
410
  def mount_resource(prefix, v, resource, hash)
414
- hash[resource] = {resources: {}, actions: {}}
411
+ hash[resource] = { resources: {}, actions: {} }
415
412
 
416
413
  resource.routes(prefix).each do |route|
417
414
  if route.is_a?(Hash)
@@ -428,7 +425,7 @@ module HaveAPI
428
425
  end
429
426
 
430
427
  def mount_nested_resource(v, routes)
431
- ret = {resources: {}, actions: {}}
428
+ ret = { resources: {}, actions: {} }
432
429
 
433
430
  routes.each do |route|
434
431
  if route.is_a?(Hash)
@@ -458,27 +455,26 @@ module HaveAPI
458
455
  begin
459
456
  body = request.body.read
460
457
 
461
- if body.empty?
462
- body = nil
463
- else
464
- body = JSON.parse(body, symbolize_names: true)
465
- end
466
-
467
- rescue => e
458
+ body = if body.empty?
459
+ nil
460
+ else
461
+ JSON.parse(body, symbolize_names: true)
462
+ end
463
+ rescue StandardError => e
468
464
  report_error(400, {}, 'Bad JSON syntax')
469
465
  end
470
466
 
471
467
  action = route.action.new(request, v, params, body, Context.new(
472
- settings.api_server,
473
- version: v,
474
- request: self,
475
- action: route.action,
476
- path: route.path,
477
- params: params,
478
- user: current_user,
479
- endpoint: true,
480
- resource_path: route.resource_path,
481
- ))
468
+ settings.api_server,
469
+ version: v,
470
+ request: self,
471
+ action: route.action,
472
+ path: route.path,
473
+ params:,
474
+ user: current_user,
475
+ endpoint: true,
476
+ resource_path: route.resource_path
477
+ ))
482
478
 
483
479
  unless action.authorized?(current_user)
484
480
  report_error(403, {}, 'Access denied. Insufficient permissions.')
@@ -491,11 +487,11 @@ module HaveAPI
491
487
  http_status || 200,
492
488
  @formatter.format(
493
489
  status,
494
- status ? reply : nil,
495
- !status ? reply : nil,
490
+ status ? reply : nil,
491
+ status ? nil : reply,
496
492
  errors,
497
493
  version: false
498
- ),
494
+ )
499
495
  ]
500
496
  end
501
497
 
@@ -518,11 +514,11 @@ module HaveAPI
518
514
  request: self,
519
515
  action: route.action,
520
516
  path: route.path,
521
- args: args,
522
- params: params,
517
+ args:,
518
+ params:,
523
519
  user: current_user,
524
520
  endpoint: true,
525
- resource_path: route.resource_path,
521
+ resource_path: route.resource_path
526
522
  )
527
523
 
528
524
  begin
@@ -531,8 +527,7 @@ module HaveAPI
531
527
  unless desc
532
528
  report_error(403, {}, 'Access denied. Insufficient permissions.')
533
529
  end
534
-
535
- rescue => e
530
+ rescue StandardError => e
536
531
  tmp = settings.api_server.call_hooks_for(:description_exception, args: [ctx, e])
537
532
  report_error(
538
533
  tmp[:http_status] || 500,
@@ -550,7 +545,7 @@ module HaveAPI
550
545
 
551
546
  ret = {
552
547
  default_version: @default_version,
553
- versions: {default: describe_version(context)},
548
+ versions: { default: describe_version(context) }
554
549
  }
555
550
 
556
551
  @versions.each do |v|
@@ -569,7 +564,7 @@ module HaveAPI
569
564
  help: version_prefix(context.version)
570
565
  }
571
566
 
572
- #puts JSON.pretty_generate(@routes)
567
+ # puts JSON.pretty_generate(@routes)
573
568
 
574
569
  @routes[context.version][:resources].each do |resource, children|
575
570
  r_name = resource.resource_name.underscore
@@ -599,7 +594,7 @@ module HaveAPI
599
594
  end
600
595
 
601
596
  def add_auth_module(v, name, mod, prefix: '')
602
- @routes[v] ||= {authentication: {name => {resources: {}}}}
597
+ @routes[v] ||= { authentication: { name => { resources: {} } } }
603
598
 
604
599
  HaveAPI.get_version_resources(mod, v).each do |r|
605
600
  mount_resource("#{@root}_auth/#{prefix}/", v, r, @routes[v][:authentication][name][:resources])
@@ -613,6 +608,7 @@ module HaveAPI
613
608
 
614
609
  def allowed_headers
615
610
  return @allowed_headers_str if @allowed_headers_str
611
+
616
612
  @allowed_headers_str = @allowed_headers.join(',')
617
613
  end
618
614
 
@@ -625,6 +621,7 @@ module HaveAPI
625
621
  end
626
622
 
627
623
  private
624
+
628
625
  def do_authenticate(v, request)
629
626
  @auth_chain.authenticate(v, request)
630
627
  end
@@ -1,4 +1,4 @@
1
- module HaveAPI::Spec
1
+ module HaveAPI::Spec
2
2
  # This class wraps raw reply from the API and provides a more friendly
3
3
  # interface.
4
4
  class ApiResponse
@@ -1,7 +1,7 @@
1
1
  require 'rack/test'
2
2
 
3
3
  module HaveAPI
4
- module Spec ; end
4
+ module Spec; end
5
5
  end
6
6
 
7
7
  require_relative 'api_builder'
@@ -10,21 +10,22 @@ module HaveAPI::Spec
10
10
 
11
11
  def call(input, user: nil, &block)
12
12
  action = @action.new(nil, @v, input, nil, HaveAPI::Context.new(
13
- @server,
14
- version: @v,
15
- action: @action,
16
- path: @path,
17
- params: input,
18
- user: user,
19
- endpoint: true
20
- ))
13
+ @server,
14
+ version: @v,
15
+ action: @action,
16
+ path: @path,
17
+ params: input,
18
+ user:,
19
+ endpoint: true
20
+ ))
21
21
 
22
22
  unless action.authorized?(user)
23
- fail 'Access denied. Insufficient permissions.'
23
+ raise 'Access denied. Insufficient permissions.'
24
24
  end
25
25
 
26
26
  status, data, errors = action.safe_exec
27
- fail (data || 'action failed') unless status
27
+ raise(data || 'action failed') unless status
28
+
28
29
  action.instance_exec(@test, &block)
29
30
  data
30
31
  end
@@ -28,7 +28,7 @@ module HaveAPI::Spec
28
28
  # Two modes:
29
29
  # http_method, path, params = {}
30
30
  # [resource], action, params, &block
31
- def call_api(*args, &block)
31
+ def call_api(*args, &)
32
32
  if args[0].is_a?(::Array) || args[1].is_a?(::Symbol)
33
33
  r_name, a_name, params = args
34
34
 
@@ -42,7 +42,7 @@ module HaveAPI::Spec
42
42
  method(action.http_method).call(
43
43
  path,
44
44
  params && params.to_json,
45
- {'Content-Type' => 'application/json'}
45
+ { 'Content-Type' => 'application/json' }
46
46
  )
47
47
 
48
48
  else
@@ -51,7 +51,7 @@ module HaveAPI::Spec
51
51
  method(http_method).call(
52
52
  path,
53
53
  params && params.to_json,
54
- {'Content-Type' => 'application/json'}
54
+ { 'Content-Type' => 'application/json' }
55
55
  )
56
56
  end
57
57
  end
@@ -79,22 +79,23 @@ module HaveAPI::Spec
79
79
  v = version || @api.default_version
80
80
  action, path = find_action(v, r_name, a_name)
81
81
  m = MockAction.new(self, @api, action, path, v)
82
- m.call(params, user: user, &block)
82
+ m.call(params, user:, &block)
83
83
  end
84
84
 
85
85
  # Return parsed API response.
86
86
  # @return [HaveAPI::Spec::ApiResponse]
87
87
  def api_response
88
- if last_response != @last_response
88
+ if last_response == @last_response
89
+ @api_response ||= ApiResponse.new(last_response.body)
90
+ else
89
91
  @last_response = last_response
90
92
  @api_response = ApiResponse.new(last_response.body)
91
93
 
92
- else
93
- @api_response ||= ApiResponse.new(last_response.body)
94
94
  end
95
95
  end
96
96
 
97
97
  protected
98
+
98
99
  def get_opt(name)
99
100
  self.class.opts && self.class.opts[name]
100
101
  end
@@ -113,7 +114,7 @@ module HaveAPI::Spec
113
114
  end.second
114
115
  end
115
116
 
116
- top[:actions].detect do |k, v|
117
+ top[:actions].detect do |k, _v|
117
118
  k.to_s.demodulize.underscore.to_sym == a_name
118
119
  end
119
120
  end
@@ -3,10 +3,10 @@ require 'haveapi/tasks/hooks'
3
3
  def render_doc_file(src, dst)
4
4
  src = File.join(File.dirname(__FILE__), '..', '..', '..', src)
5
5
 
6
- Proc.new do
6
+ proc do
7
7
  File.write(
8
8
  dst,
9
- ERB.new(File.read(src), 0).result(binding)
9
+ ERB.new(File.read(src)).result(binding)
10
10
  )
11
11
  end
12
12
  end
data/lib/haveapi/types.rb CHANGED
@@ -2,23 +2,22 @@
2
2
  module Boolean
3
3
  def self.to_b(str)
4
4
  return true if str === true
5
- return true if str =~ /^(true|t|yes|y|1)$/i
6
-
7
5
  return false if str === false
8
- return false if str =~ /^(false|f|no|n|0)$/i
6
+
7
+ if str.respond_to?(:=~)
8
+ return true if str =~ /^(true|t|yes|y|1)$/i
9
+ return false if str =~ /^(false|f|no|n|0)$/i
10
+ end
9
11
 
10
12
  false
11
13
  end
12
14
  end
13
15
 
14
16
  module Datetime
15
-
16
17
  end
17
18
 
18
19
  module Custom
19
-
20
20
  end
21
21
 
22
22
  class Text < String
23
-
24
23
  end
@@ -1,6 +1,6 @@
1
1
  module HaveAPI
2
2
  # Validators are stored in this module.
3
- module Validators ; end
3
+ module Validators; end
4
4
 
5
5
  # Base class for all validators.
6
6
  #
@@ -37,7 +37,7 @@ module HaveAPI
37
37
 
38
38
  # True if this validator uses any of options in hash `opts`.
39
39
  def use?(opts)
40
- !(opts.keys & @takes).empty?
40
+ opts.keys.intersect?(@takes)
41
41
  end
42
42
 
43
43
  # Use the validator on given set of options in hash `opts`. Used
@@ -45,7 +45,8 @@ module HaveAPI
45
45
  def use(opts)
46
46
  keys = opts.keys & @takes
47
47
 
48
- fail 'too many keys' if keys.size > 1
48
+ raise 'too many keys' if keys.size > 1
49
+
49
50
  new(keys.first, opts.delete(keys.first))
50
51
  end
51
52
  end
@@ -94,6 +95,7 @@ module HaveAPI
94
95
  end
95
96
 
96
97
  protected
98
+
97
99
  # This method has three modes of function.
98
100
  #
99
101
  # 1. If `v` is nil, it returns `@opts`. It is used if `@opts` is not a hash
@@ -109,6 +111,7 @@ module HaveAPI
109
111
  else
110
112
  return default unless @opts.is_a?(::Hash)
111
113
  return @opts[v] unless @opts[v].nil?
114
+
112
115
  default
113
116
  end
114
117
  end
@@ -8,6 +8,7 @@ module HaveAPI
8
8
  find_validators(args) do |validator|
9
9
  obj = validator.use(args)
10
10
  next unless obj.useful?
11
+
11
12
  @required = true if obj.is_a?(Validators::Presence)
12
13
  @validators << obj
13
14
  end
@@ -21,8 +22,8 @@ module HaveAPI
21
22
  def add_or_replace(name, opt)
22
23
  args = { name => opt }
23
24
 
24
- unless v_class = find_validator(args)
25
- fail "validator for '#{name}' not found"
25
+ unless (v_class = find_validator(args))
26
+ raise "validator for '#{name}' not found"
26
27
  end
27
28
 
28
29
  exists = @validators.detect { |v| v.is_a?(v_class) }
@@ -42,9 +43,9 @@ module HaveAPI
42
43
  @validators << obj if obj.useful?
43
44
  end
44
45
 
45
- if v_class == Validators::Presence
46
- @required = !opt.nil? && obj.useful? ? true : false
47
- end
46
+ return unless v_class == Validators::Presence
47
+
48
+ @required = !opt.nil? && obj.useful?
48
49
  end
49
50
 
50
51
  # Returns true if validator Validators::Presence is used.
@@ -69,15 +70,15 @@ module HaveAPI
69
70
 
70
71
  @validators.each do |validator|
71
72
  next if validator.validate(value, params)
72
- ret << validator.message % {
73
- value: value
74
- }
73
+
74
+ ret << (format(validator.message, value:))
75
75
  end
76
76
 
77
77
  ret.empty? ? true : ret
78
78
  end
79
79
 
80
80
  protected
81
+
81
82
  def find_validator(args)
82
83
  HaveAPI::Validators.constants.select do |v|
83
84
  validator = HaveAPI::Validators.const_get(v)