haveapi 0.20.0 → 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.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/Rakefile +6 -6
- data/haveapi.gemspec +13 -13
- data/lib/haveapi/action.rb +140 -158
- data/lib/haveapi/action_state.rb +2 -6
- data/lib/haveapi/actions/default.rb +8 -10
- data/lib/haveapi/api.rb +2 -1
- data/lib/haveapi/authentication/base.rb +5 -8
- data/lib/haveapi/authentication/basic/provider.rb +4 -5
- data/lib/haveapi/authentication/chain.rb +19 -17
- data/lib/haveapi/authentication/oauth2/config.rb +12 -32
- data/lib/haveapi/authentication/oauth2/provider.rb +20 -30
- data/lib/haveapi/authentication/oauth2/revoke_endpoint.rb +1 -2
- data/lib/haveapi/authentication/token/action_config.rb +5 -3
- data/lib/haveapi/authentication/token/config.rb +5 -5
- data/lib/haveapi/authentication/token/provider.rb +33 -37
- data/lib/haveapi/authorization.rb +5 -4
- data/lib/haveapi/client_example.rb +11 -14
- data/lib/haveapi/client_examples/curl.rb +37 -37
- data/lib/haveapi/client_examples/fs_client.rb +29 -31
- data/lib/haveapi/client_examples/http.rb +35 -36
- data/lib/haveapi/client_examples/js_client.rb +62 -63
- data/lib/haveapi/client_examples/php_client.rb +77 -76
- data/lib/haveapi/client_examples/ruby_cli.rb +30 -30
- data/lib/haveapi/client_examples/ruby_client.rb +26 -26
- data/lib/haveapi/common.rb +3 -4
- data/lib/haveapi/context.rb +11 -10
- data/lib/haveapi/example.rb +9 -4
- data/lib/haveapi/example_list.rb +2 -2
- data/lib/haveapi/exceptions.rb +1 -1
- data/lib/haveapi/extensions/action_exceptions.rb +2 -2
- data/lib/haveapi/extensions/base.rb +1 -3
- data/lib/haveapi/extensions/exception_mailer.rb +260 -257
- data/lib/haveapi/hooks.rb +40 -39
- data/lib/haveapi/metadata.rb +1 -1
- data/lib/haveapi/model_adapter.rb +16 -27
- data/lib/haveapi/model_adapters/active_record.rb +59 -69
- data/lib/haveapi/output_formatter.rb +7 -7
- data/lib/haveapi/output_formatters/base.rb +2 -4
- data/lib/haveapi/parameters/resource.rb +7 -7
- data/lib/haveapi/parameters/typed.rb +6 -9
- data/lib/haveapi/params.rb +38 -45
- data/lib/haveapi/resource.rb +8 -8
- data/lib/haveapi/resources/action_state.rb +11 -19
- data/lib/haveapi/server.rb +102 -107
- data/lib/haveapi/spec/api_response.rb +1 -1
- data/lib/haveapi/spec/helpers.rb +1 -1
- data/lib/haveapi/spec/mock_action.rb +11 -10
- data/lib/haveapi/spec/spec_methods.rb +9 -8
- data/lib/haveapi/tasks/yard.rb +2 -2
- data/lib/haveapi/types.rb +0 -3
- data/lib/haveapi/validator.rb +6 -3
- data/lib/haveapi/validator_chain.rb +9 -8
- data/lib/haveapi/validators/acceptance.rb +6 -6
- data/lib/haveapi/validators/confirmation.rb +2 -3
- data/lib/haveapi/validators/exclusion.rb +1 -1
- data/lib/haveapi/validators/format.rb +1 -1
- data/lib/haveapi/validators/inclusion.rb +1 -1
- data/lib/haveapi/validators/length.rb +12 -11
- data/lib/haveapi/validators/numericality.rb +14 -13
- data/lib/haveapi/validators/presence.rb +4 -3
- data/lib/haveapi/version.rb +2 -2
- data/lib/haveapi.rb +2 -3
- data/spec/.rubocop.yml +4 -0
- data/spec/action/dsl_spec.rb +18 -18
- data/spec/authorization_spec.rb +8 -8
- data/spec/common_spec.rb +2 -1
- data/spec/documentation_spec.rb +2 -9
- data/spec/envelope_spec.rb +2 -2
- data/spec/hooks_spec.rb +12 -12
- data/spec/parameters/typed_spec.rb +6 -6
- data/spec/params_spec.rb +22 -24
- data/spec/resource_spec.rb +5 -7
- data/spec/spec_helper.rb +0 -1
- data/spec/validators/acceptance_spec.rb +1 -1
- data/spec/validators/confirmation_spec.rb +5 -5
- data/spec/validators/exclusion_spec.rb +3 -3
- data/spec/validators/format_spec.rb +2 -2
- data/spec/validators/inclusion_spec.rb +4 -4
- data/spec/validators/length_spec.rb +23 -23
- data/spec/validators/numericality_spec.rb +13 -13
- data/spec/validators/presence_spec.rb +3 -3
- metadata +49 -48
data/lib/haveapi/server.rb
CHANGED
@@ -6,34 +6,34 @@ require 'haveapi/hooks'
|
|
6
6
|
|
7
7
|
module HaveAPI
|
8
8
|
class Server
|
9
|
-
|
10
|
-
|
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
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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
|
-
|
109
|
+
scheme = if request.env['HTTP_X_FORWARDED_SSL'] == 'on'
|
110
|
+
'https'
|
111
111
|
|
112
|
-
|
113
|
-
|
114
|
-
|
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
|
207
|
-
set :public_folder, settings.root
|
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?
|
@@ -246,10 +244,10 @@ module HaveAPI
|
|
246
244
|
authenticated?(settings.api_server.default_version)
|
247
245
|
|
248
246
|
@api = settings.api_server.describe(Context.new(
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
247
|
+
settings.api_server,
|
248
|
+
user: current_user,
|
249
|
+
params:
|
250
|
+
))
|
253
251
|
|
254
252
|
content_type 'text/html'
|
255
253
|
erb :index, layout: :main_layout
|
@@ -261,27 +259,27 @@ module HaveAPI
|
|
261
259
|
authenticated?(settings.api_server.default_version)
|
262
260
|
ret = nil
|
263
261
|
|
264
|
-
case params[:describe]
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
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
|
285
283
|
|
286
284
|
@formatter.format(true, ret)
|
287
285
|
end
|
@@ -298,7 +296,7 @@ module HaveAPI
|
|
298
296
|
content_type 'text/html'
|
299
297
|
|
300
298
|
erb :main_layout do
|
301
|
-
GitHub::Markdown.render(File.new(settings.views
|
299
|
+
GitHub::Markdown.render(File.new("#{settings.views}/../../../README.md").read)
|
302
300
|
end
|
303
301
|
end
|
304
302
|
|
@@ -315,7 +313,6 @@ module HaveAPI
|
|
315
313
|
erb :doc_layout, layout: :main_layout do
|
316
314
|
begin
|
317
315
|
@content = doc(f)
|
318
|
-
|
319
316
|
rescue Errno::ENOENT
|
320
317
|
halt 404
|
321
318
|
end
|
@@ -359,11 +356,11 @@ module HaveAPI
|
|
359
356
|
|
360
357
|
@v = v
|
361
358
|
@help = settings.api_server.describe_version(Context.new(
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
359
|
+
settings.api_server,
|
360
|
+
version: v,
|
361
|
+
user: current_user,
|
362
|
+
params:
|
363
|
+
))
|
367
364
|
|
368
365
|
content_type 'text/html'
|
369
366
|
erb :doc_layout, layout: :main_layout do
|
@@ -378,11 +375,11 @@ module HaveAPI
|
|
378
375
|
authenticated?(v)
|
379
376
|
|
380
377
|
@formatter.format(true, settings.api_server.describe_version(Context.new(
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
378
|
+
settings.api_server,
|
379
|
+
version: v,
|
380
|
+
user: current_user,
|
381
|
+
params:
|
382
|
+
)))
|
386
383
|
end
|
387
384
|
|
388
385
|
# Register blocking resource
|
@@ -404,16 +401,14 @@ module HaveAPI
|
|
404
401
|
|
405
402
|
def validate_resources(resources)
|
406
403
|
resources.each_value do |r|
|
407
|
-
r[:actions].each_key
|
408
|
-
a.validate_build
|
409
|
-
end
|
404
|
+
r[:actions].each_key(&:validate_build)
|
410
405
|
|
411
406
|
validate_resources(r[:resources])
|
412
407
|
end
|
413
408
|
end
|
414
409
|
|
415
410
|
def mount_resource(prefix, v, resource, hash)
|
416
|
-
hash[resource] = {resources: {}, actions: {}}
|
411
|
+
hash[resource] = { resources: {}, actions: {} }
|
417
412
|
|
418
413
|
resource.routes(prefix).each do |route|
|
419
414
|
if route.is_a?(Hash)
|
@@ -430,7 +425,7 @@ module HaveAPI
|
|
430
425
|
end
|
431
426
|
|
432
427
|
def mount_nested_resource(v, routes)
|
433
|
-
ret = {resources: {}, actions: {}}
|
428
|
+
ret = { resources: {}, actions: {} }
|
434
429
|
|
435
430
|
routes.each do |route|
|
436
431
|
if route.is_a?(Hash)
|
@@ -460,27 +455,26 @@ module HaveAPI
|
|
460
455
|
begin
|
461
456
|
body = request.body.read
|
462
457
|
|
463
|
-
if body.empty?
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
rescue => e
|
458
|
+
body = if body.empty?
|
459
|
+
nil
|
460
|
+
else
|
461
|
+
JSON.parse(body, symbolize_names: true)
|
462
|
+
end
|
463
|
+
rescue StandardError => e
|
470
464
|
report_error(400, {}, 'Bad JSON syntax')
|
471
465
|
end
|
472
466
|
|
473
467
|
action = route.action.new(request, v, params, body, Context.new(
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
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
|
+
))
|
484
478
|
|
485
479
|
unless action.authorized?(current_user)
|
486
480
|
report_error(403, {}, 'Access denied. Insufficient permissions.')
|
@@ -493,11 +487,11 @@ module HaveAPI
|
|
493
487
|
http_status || 200,
|
494
488
|
@formatter.format(
|
495
489
|
status,
|
496
|
-
status
|
497
|
-
|
490
|
+
status ? reply : nil,
|
491
|
+
status ? nil : reply,
|
498
492
|
errors,
|
499
493
|
version: false
|
500
|
-
)
|
494
|
+
)
|
501
495
|
]
|
502
496
|
end
|
503
497
|
|
@@ -520,11 +514,11 @@ module HaveAPI
|
|
520
514
|
request: self,
|
521
515
|
action: route.action,
|
522
516
|
path: route.path,
|
523
|
-
args
|
524
|
-
params
|
517
|
+
args:,
|
518
|
+
params:,
|
525
519
|
user: current_user,
|
526
520
|
endpoint: true,
|
527
|
-
resource_path: route.resource_path
|
521
|
+
resource_path: route.resource_path
|
528
522
|
)
|
529
523
|
|
530
524
|
begin
|
@@ -533,8 +527,7 @@ module HaveAPI
|
|
533
527
|
unless desc
|
534
528
|
report_error(403, {}, 'Access denied. Insufficient permissions.')
|
535
529
|
end
|
536
|
-
|
537
|
-
rescue => e
|
530
|
+
rescue StandardError => e
|
538
531
|
tmp = settings.api_server.call_hooks_for(:description_exception, args: [ctx, e])
|
539
532
|
report_error(
|
540
533
|
tmp[:http_status] || 500,
|
@@ -552,7 +545,7 @@ module HaveAPI
|
|
552
545
|
|
553
546
|
ret = {
|
554
547
|
default_version: @default_version,
|
555
|
-
versions: {default: describe_version(context)}
|
548
|
+
versions: { default: describe_version(context) }
|
556
549
|
}
|
557
550
|
|
558
551
|
@versions.each do |v|
|
@@ -571,7 +564,7 @@ module HaveAPI
|
|
571
564
|
help: version_prefix(context.version)
|
572
565
|
}
|
573
566
|
|
574
|
-
#puts JSON.pretty_generate(@routes)
|
567
|
+
# puts JSON.pretty_generate(@routes)
|
575
568
|
|
576
569
|
@routes[context.version][:resources].each do |resource, children|
|
577
570
|
r_name = resource.resource_name.underscore
|
@@ -601,7 +594,7 @@ module HaveAPI
|
|
601
594
|
end
|
602
595
|
|
603
596
|
def add_auth_module(v, name, mod, prefix: '')
|
604
|
-
@routes[v] ||= {authentication: {name => {resources: {}}}}
|
597
|
+
@routes[v] ||= { authentication: { name => { resources: {} } } }
|
605
598
|
|
606
599
|
HaveAPI.get_version_resources(mod, v).each do |r|
|
607
600
|
mount_resource("#{@root}_auth/#{prefix}/", v, r, @routes[v][:authentication][name][:resources])
|
@@ -615,6 +608,7 @@ module HaveAPI
|
|
615
608
|
|
616
609
|
def allowed_headers
|
617
610
|
return @allowed_headers_str if @allowed_headers_str
|
611
|
+
|
618
612
|
@allowed_headers_str = @allowed_headers.join(',')
|
619
613
|
end
|
620
614
|
|
@@ -627,6 +621,7 @@ module HaveAPI
|
|
627
621
|
end
|
628
622
|
|
629
623
|
private
|
624
|
+
|
630
625
|
def do_authenticate(v, request)
|
631
626
|
@auth_chain.authenticate(v, request)
|
632
627
|
end
|
data/lib/haveapi/spec/helpers.rb
CHANGED
@@ -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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
23
|
+
raise 'Access denied. Insufficient permissions.'
|
24
24
|
end
|
25
25
|
|
26
26
|
status, data, errors = action.safe_exec
|
27
|
-
|
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, &
|
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
|
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
|
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,
|
117
|
+
top[:actions].detect do |k, _v|
|
117
118
|
k.to_s.demodulize.underscore.to_sym == a_name
|
118
119
|
end
|
119
120
|
end
|
data/lib/haveapi/tasks/yard.rb
CHANGED
@@ -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
|
-
|
6
|
+
proc do
|
7
7
|
File.write(
|
8
8
|
dst,
|
9
|
-
ERB.new(File.read(src)
|
9
|
+
ERB.new(File.read(src)).result(binding)
|
10
10
|
)
|
11
11
|
end
|
12
12
|
end
|
data/lib/haveapi/types.rb
CHANGED
data/lib/haveapi/validator.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module HaveAPI
|
2
2
|
# Validators are stored in this module.
|
3
|
-
module Validators
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
46
|
-
|
47
|
-
|
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
|
-
|
73
|
-
|
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)
|
@@ -16,12 +16,12 @@ module HaveAPI
|
|
16
16
|
takes :accept
|
17
17
|
|
18
18
|
def setup
|
19
|
-
if simple?
|
20
|
-
|
19
|
+
@value = if simple?
|
20
|
+
take
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
else
|
23
|
+
take(:value)
|
24
|
+
end
|
25
25
|
|
26
26
|
@message = take(:message, "has to be #{@value}")
|
27
27
|
end
|
@@ -29,7 +29,7 @@ module HaveAPI
|
|
29
29
|
def describe
|
30
30
|
{
|
31
31
|
value: @value,
|
32
|
-
message: @message
|
32
|
+
message: @message
|
33
33
|
}
|
34
34
|
end
|
35
35
|
|
@@ -23,8 +23,7 @@ module HaveAPI
|
|
23
23
|
@equal = take(:equal, true)
|
24
24
|
@message = take(
|
25
25
|
:message,
|
26
|
-
@equal ? "must be the same as #{@param}"
|
27
|
-
: "must be different from #{@param}"
|
26
|
+
@equal ? "must be the same as #{@param}" : "must be different from #{@param}"
|
28
27
|
)
|
29
28
|
end
|
30
29
|
|
@@ -32,7 +31,7 @@ module HaveAPI
|
|
32
31
|
{
|
33
32
|
equal: @equal ? true : false,
|
34
33
|
parameter: @param,
|
35
|
-
message: @message
|
34
|
+
message: @message
|
36
35
|
}
|
37
36
|
end
|
38
37
|
|