grape 0.12.0 → 0.14.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.
Potentially problematic release.
This version of grape might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Appraisals +9 -4
- data/CHANGELOG.md +265 -215
- data/CONTRIBUTING.md +4 -4
- data/Gemfile +0 -1
- data/Gemfile.lock +166 -0
- data/README.md +426 -161
- data/RELEASING.md +14 -6
- data/Rakefile +30 -33
- data/UPGRADING.md +54 -23
- data/benchmark/simple.rb +27 -0
- data/gemfiles/rack_1.5.2.gemfile +13 -0
- data/gemfiles/rails_3.gemfile +2 -2
- data/gemfiles/rails_4.gemfile +1 -2
- data/grape.gemspec +6 -7
- data/lib/grape/api.rb +24 -4
- data/lib/grape/dsl/callbacks.rb +20 -0
- data/lib/grape/dsl/configuration.rb +59 -2
- data/lib/grape/dsl/helpers.rb +8 -3
- data/lib/grape/dsl/inside_route.rb +100 -45
- data/lib/grape/dsl/parameters.rb +96 -7
- data/lib/grape/dsl/request_response.rb +1 -1
- data/lib/grape/dsl/routing.rb +17 -4
- data/lib/grape/dsl/settings.rb +36 -1
- data/lib/grape/dsl/validations.rb +7 -5
- data/lib/grape/endpoint.rb +102 -57
- data/lib/grape/error_formatter/base.rb +6 -6
- data/lib/grape/exceptions/base.rb +5 -5
- data/lib/grape/exceptions/invalid_version_header.rb +10 -0
- data/lib/grape/exceptions/unknown_parameter.rb +10 -0
- data/lib/grape/exceptions/validation_errors.rb +4 -3
- data/lib/grape/formatter/serializable_hash.rb +3 -2
- data/lib/grape/http/headers.rb +0 -1
- data/lib/grape/locale/en.yml +5 -1
- data/lib/grape/middleware/auth/base.rb +2 -2
- data/lib/grape/middleware/auth/dsl.rb +1 -1
- data/lib/grape/middleware/auth/strategies.rb +1 -1
- data/lib/grape/middleware/base.rb +8 -4
- data/lib/grape/middleware/error.rb +3 -2
- data/lib/grape/middleware/filter.rb +1 -1
- data/lib/grape/middleware/formatter.rb +64 -45
- data/lib/grape/middleware/globals.rb +3 -3
- data/lib/grape/middleware/versioner/accept_version_header.rb +5 -7
- data/lib/grape/middleware/versioner/header.rb +113 -50
- data/lib/grape/middleware/versioner/param.rb +5 -8
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +20 -0
- data/lib/grape/middleware/versioner/path.rb +3 -6
- data/lib/grape/namespace.rb +13 -2
- data/lib/grape/path.rb +4 -3
- data/lib/grape/request.rb +40 -0
- data/lib/grape/route.rb +5 -0
- data/lib/grape/util/content_types.rb +9 -9
- data/lib/grape/util/env.rb +22 -0
- data/lib/grape/util/file_response.rb +21 -0
- data/lib/grape/util/inheritable_setting.rb +23 -2
- data/lib/grape/util/inheritable_values.rb +1 -1
- data/lib/grape/util/stackable_values.rb +5 -2
- data/lib/grape/util/strict_hash_configuration.rb +2 -1
- data/lib/grape/validations/attributes_iterator.rb +8 -3
- data/lib/grape/validations/params_scope.rb +164 -22
- data/lib/grape/validations/types/build_coercer.rb +53 -0
- data/lib/grape/validations/types/custom_type_coercer.rb +183 -0
- data/lib/grape/validations/types/file.rb +28 -0
- data/lib/grape/validations/types/json.rb +65 -0
- data/lib/grape/validations/types/multiple_type_coercer.rb +76 -0
- data/lib/grape/validations/types/variant_collection_coercer.rb +59 -0
- data/lib/grape/validations/types/virtus_collection_patch.rb +16 -0
- data/lib/grape/validations/types.rb +144 -0
- data/lib/grape/validations/validators/all_or_none.rb +1 -1
- data/lib/grape/validations/validators/allow_blank.rb +3 -3
- data/lib/grape/validations/validators/base.rb +7 -0
- data/lib/grape/validations/validators/coerce.rb +32 -34
- data/lib/grape/validations/validators/presence.rb +2 -3
- data/lib/grape/validations/validators/regexp.rb +2 -4
- data/lib/grape/validations/validators/values.rb +3 -3
- data/lib/grape/validations.rb +5 -0
- data/lib/grape/version.rb +2 -1
- data/lib/grape.rb +15 -12
- data/pkg/grape-0.13.0.gem +0 -0
- data/spec/grape/api/custom_validations_spec.rb +5 -4
- data/spec/grape/api/deeply_included_options_spec.rb +7 -7
- data/spec/grape/api/nested_helpers_spec.rb +4 -2
- data/spec/grape/api/shared_helpers_spec.rb +8 -8
- data/spec/grape/api_spec.rb +151 -54
- data/spec/grape/dsl/configuration_spec.rb +13 -0
- data/spec/grape/dsl/helpers_spec.rb +16 -2
- data/spec/grape/dsl/inside_route_spec.rb +40 -4
- data/spec/grape/dsl/parameters_spec.rb +0 -6
- data/spec/grape/dsl/routing_spec.rb +1 -1
- data/spec/grape/dsl/validations_spec.rb +18 -0
- data/spec/grape/endpoint_spec.rb +130 -6
- data/spec/grape/entity_spec.rb +10 -8
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +1 -15
- data/spec/grape/exceptions/validation_errors_spec.rb +28 -0
- data/spec/grape/integration/rack_spec.rb +3 -2
- data/spec/grape/middleware/base_spec.rb +40 -16
- data/spec/grape/middleware/error_spec.rb +16 -15
- data/spec/grape/middleware/exception_spec.rb +45 -43
- data/spec/grape/middleware/formatter_spec.rb +34 -5
- data/spec/grape/middleware/versioner/header_spec.rb +79 -47
- data/spec/grape/path_spec.rb +10 -10
- data/spec/grape/presenters/presenter_spec.rb +2 -2
- data/spec/grape/request_spec.rb +100 -0
- data/spec/grape/util/inheritable_values_spec.rb +14 -0
- data/spec/grape/util/stackable_values_spec.rb +10 -0
- data/spec/grape/validations/params_scope_spec.rb +86 -0
- data/spec/grape/validations/types_spec.rb +95 -0
- data/spec/grape/validations/validators/coerce_spec.rb +364 -10
- data/spec/grape/validations/validators/values_spec.rb +27 -15
- data/spec/grape/validations_spec.rb +53 -24
- data/spec/shared/versioning_examples.rb +2 -2
- data/spec/spec_helper.rb +0 -1
- data/spec/support/versioned_helpers.rb +2 -2
- metadata +55 -14
- data/.gitignore +0 -46
- data/.rspec +0 -2
- data/.rubocop.yml +0 -7
- data/.rubocop_todo.yml +0 -84
- data/.travis.yml +0 -20
- data/.yardopts +0 -2
- data/lib/backports/active_support/deep_dup.rb +0 -49
- data/lib/backports/active_support/duplicable.rb +0 -88
- data/lib/grape/http/request.rb +0 -27
data/spec/grape/api_spec.rb
CHANGED
@@ -537,16 +537,38 @@ describe Grape::API do
|
|
537
537
|
expect(last_response.headers['Content-Type']).to eql 'text/plain'
|
538
538
|
end
|
539
539
|
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
'example'
|
540
|
+
describe 'adds an OPTIONS route that' do
|
541
|
+
before do
|
542
|
+
subject.before { header 'X-Custom-Header', 'foo' }
|
543
|
+
subject.get 'example' do
|
544
|
+
'example'
|
545
|
+
end
|
546
|
+
options '/example'
|
547
|
+
end
|
548
|
+
|
549
|
+
it 'returns a 204' do
|
550
|
+
expect(last_response.status).to eql 204
|
551
|
+
end
|
552
|
+
|
553
|
+
it 'has an empty body' do
|
554
|
+
expect(last_response.body).to be_blank
|
555
|
+
end
|
556
|
+
|
557
|
+
it 'has an Allow header' do
|
558
|
+
expect(last_response.headers['Allow']).to eql 'OPTIONS, GET, HEAD'
|
559
|
+
end
|
560
|
+
|
561
|
+
it 'has a X-Custom-Header' do
|
562
|
+
expect(last_response.headers['X-Custom-Header']).to eql 'foo'
|
563
|
+
end
|
564
|
+
|
565
|
+
it 'has no Content-Type' do
|
566
|
+
expect(last_response.content_type).to be_nil
|
567
|
+
end
|
568
|
+
|
569
|
+
it 'has no Content-Length' do
|
570
|
+
expect(last_response.content_length).to be_nil
|
544
571
|
end
|
545
|
-
options '/example'
|
546
|
-
expect(last_response.status).to eql 204
|
547
|
-
expect(last_response.body).to eql ''
|
548
|
-
expect(last_response.headers['Allow']).to eql 'OPTIONS, GET, HEAD'
|
549
|
-
expect(last_response.headers['X-Custom-Header']).to eql 'foo'
|
550
572
|
end
|
551
573
|
|
552
574
|
it 'allows HEAD on a GET request' do
|
@@ -640,7 +662,7 @@ describe Grape::API do
|
|
640
662
|
end
|
641
663
|
|
642
664
|
it 'adds a after_validation filter' do
|
643
|
-
subject.after_validation { @foo = "first #{params[:id]
|
665
|
+
subject.after_validation { @foo = "first #{params[:id]}:#{params[:id].class}" }
|
644
666
|
subject.after_validation { @bar = 'second' }
|
645
667
|
subject.params do
|
646
668
|
requires :id, type: Integer
|
@@ -787,7 +809,7 @@ describe Grape::API do
|
|
787
809
|
|
788
810
|
it 'returns raw data when content type binary' do
|
789
811
|
image_filename = 'grape.png'
|
790
|
-
file = File.open(image_filename, 'rb'
|
812
|
+
file = File.open(image_filename, 'rb', &:read)
|
791
813
|
subject.format :binary
|
792
814
|
subject.get('/binary_file') { File.binread(image_filename) }
|
793
815
|
get '/binary_file'
|
@@ -795,6 +817,37 @@ describe Grape::API do
|
|
795
817
|
expect(last_response.body).to eq(file)
|
796
818
|
end
|
797
819
|
|
820
|
+
it 'returns the content of the file with file' do
|
821
|
+
file_content = 'This is some file content'
|
822
|
+
test_file = Tempfile.new('test')
|
823
|
+
test_file.write file_content
|
824
|
+
test_file.rewind
|
825
|
+
|
826
|
+
subject.get('/file') { file test_file }
|
827
|
+
get '/file'
|
828
|
+
expect(last_response.headers['Content-Length']).to eq('25')
|
829
|
+
expect(last_response.headers['Content-Type']).to eq('text/plain')
|
830
|
+
expect(last_response.body).to eq(file_content)
|
831
|
+
end
|
832
|
+
|
833
|
+
it 'streams the content of the file with stream' do
|
834
|
+
test_stream = Enumerator.new do |blk|
|
835
|
+
blk.yield 'This is some'
|
836
|
+
blk.yield ' file content'
|
837
|
+
end
|
838
|
+
|
839
|
+
subject.use Rack::Chunked
|
840
|
+
subject.get('/stream') { stream test_stream }
|
841
|
+
get '/stream', {}, 'HTTP_VERSION' => 'HTTP/1.1'
|
842
|
+
|
843
|
+
expect(last_response.headers['Content-Type']).to eq('text/plain')
|
844
|
+
expect(last_response.headers['Content-Length']).to eq(nil)
|
845
|
+
expect(last_response.headers['Cache-Control']).to eq('no-cache')
|
846
|
+
expect(last_response.headers['Transfer-Encoding']).to eq('chunked')
|
847
|
+
|
848
|
+
expect(last_response.body).to eq("c\r\nThis is some\r\nd\r\n file content\r\n0\r\n\r\n")
|
849
|
+
end
|
850
|
+
|
798
851
|
it 'sets content type for error' do
|
799
852
|
subject.get('/error') { error!('error in plain text', 500) }
|
800
853
|
get '/error'
|
@@ -1035,7 +1088,7 @@ describe Grape::API do
|
|
1035
1088
|
|
1036
1089
|
subject.get(:hello) { 'Hello, world.' }
|
1037
1090
|
get '/hello', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('allow', 'whatever')
|
1038
|
-
expect(basic_auth_context).to
|
1091
|
+
expect(basic_auth_context).to be_a_kind_of(Grape::Endpoint)
|
1039
1092
|
end
|
1040
1093
|
|
1041
1094
|
it 'has access to helper methods' do
|
@@ -1278,21 +1331,23 @@ describe Grape::API do
|
|
1278
1331
|
|
1279
1332
|
context 'CustomError subclass of Grape::Exceptions::Base' do
|
1280
1333
|
before do
|
1281
|
-
|
1334
|
+
module ApiSpec
|
1335
|
+
class CustomError < Grape::Exceptions::Base; end
|
1336
|
+
end
|
1282
1337
|
end
|
1283
1338
|
|
1284
1339
|
it 'does not re-raise exceptions of type Grape::Exceptions::Base' do
|
1285
|
-
subject.get('/custom_exception') { fail CustomError }
|
1340
|
+
subject.get('/custom_exception') { fail ApiSpec::CustomError }
|
1286
1341
|
|
1287
1342
|
expect { get '/custom_exception' }.not_to raise_error
|
1288
1343
|
end
|
1289
1344
|
|
1290
1345
|
it 'rescues custom grape exceptions' do
|
1291
|
-
subject.rescue_from CustomError do |e|
|
1346
|
+
subject.rescue_from ApiSpec::CustomError do |e|
|
1292
1347
|
rack_response('New Error', e.status)
|
1293
1348
|
end
|
1294
1349
|
subject.get '/custom_error' do
|
1295
|
-
fail CustomError, status: 400, message: 'Custom Error'
|
1350
|
+
fail ApiSpec::CustomError, status: 400, message: 'Custom Error'
|
1296
1351
|
end
|
1297
1352
|
|
1298
1353
|
get '/custom_error'
|
@@ -1404,7 +1459,7 @@ describe Grape::API do
|
|
1404
1459
|
|
1405
1460
|
describe '.rescue_from klass, lambda' do
|
1406
1461
|
it 'rescues an error with the lambda' do
|
1407
|
-
subject.rescue_from ArgumentError,
|
1462
|
+
subject.rescue_from ArgumentError, lambda {
|
1408
1463
|
rack_response('rescued with a lambda', 400)
|
1409
1464
|
}
|
1410
1465
|
subject.get('/rescue_lambda') { fail ArgumentError }
|
@@ -1415,7 +1470,7 @@ describe Grape::API do
|
|
1415
1470
|
end
|
1416
1471
|
|
1417
1472
|
it 'can execute the lambda with an argument' do
|
1418
|
-
subject.rescue_from ArgumentError,
|
1473
|
+
subject.rescue_from ArgumentError, lambda { |e|
|
1419
1474
|
rack_response(e.message, 400)
|
1420
1475
|
}
|
1421
1476
|
subject.get('/rescue_lambda') { fail ArgumentError, 'lambda takes an argument' }
|
@@ -1443,21 +1498,23 @@ describe Grape::API do
|
|
1443
1498
|
|
1444
1499
|
describe '.rescue_from klass, rescue_subclasses: boolean' do
|
1445
1500
|
before do
|
1446
|
-
module
|
1447
|
-
|
1448
|
-
|
1501
|
+
module ApiSpec
|
1502
|
+
module APIErrors
|
1503
|
+
class ParentError < StandardError; end
|
1504
|
+
class ChildError < ParentError; end
|
1505
|
+
end
|
1449
1506
|
end
|
1450
1507
|
end
|
1451
1508
|
|
1452
1509
|
it 'rescues error as well as subclass errors with rescue_subclasses option set' do
|
1453
|
-
subject.rescue_from APIErrors::ParentError, rescue_subclasses: true do |e|
|
1510
|
+
subject.rescue_from ApiSpec::APIErrors::ParentError, rescue_subclasses: true do |e|
|
1454
1511
|
rack_response("rescued from #{e.class.name}", 500)
|
1455
1512
|
end
|
1456
1513
|
subject.get '/caught_child' do
|
1457
|
-
fail APIErrors::ChildError
|
1514
|
+
fail ApiSpec::APIErrors::ChildError
|
1458
1515
|
end
|
1459
1516
|
subject.get '/caught_parent' do
|
1460
|
-
fail APIErrors::ParentError
|
1517
|
+
fail ApiSpec::APIErrors::ParentError
|
1461
1518
|
end
|
1462
1519
|
subject.get '/uncaught_parent' do
|
1463
1520
|
fail StandardError
|
@@ -1471,11 +1528,11 @@ describe Grape::API do
|
|
1471
1528
|
end
|
1472
1529
|
|
1473
1530
|
it 'sets rescue_subclasses to true by default' do
|
1474
|
-
subject.rescue_from APIErrors::ParentError do |e|
|
1531
|
+
subject.rescue_from ApiSpec::APIErrors::ParentError do |e|
|
1475
1532
|
rack_response("rescued from #{e.class.name}", 500)
|
1476
1533
|
end
|
1477
1534
|
subject.get '/caught_child' do
|
1478
|
-
fail APIErrors::ChildError
|
1535
|
+
fail ApiSpec::APIErrors::ChildError
|
1479
1536
|
end
|
1480
1537
|
|
1481
1538
|
get '/caught_child'
|
@@ -1483,13 +1540,13 @@ describe Grape::API do
|
|
1483
1540
|
end
|
1484
1541
|
|
1485
1542
|
it 'does not rescue child errors if rescue_subclasses is false' do
|
1486
|
-
subject.rescue_from APIErrors::ParentError, rescue_subclasses: false do |e|
|
1543
|
+
subject.rescue_from ApiSpec::APIErrors::ParentError, rescue_subclasses: false do |e|
|
1487
1544
|
rack_response("rescued from #{e.class.name}", 500)
|
1488
1545
|
end
|
1489
1546
|
subject.get '/uncaught' do
|
1490
|
-
fail APIErrors::ChildError
|
1547
|
+
fail ApiSpec::APIErrors::ChildError
|
1491
1548
|
end
|
1492
|
-
expect { get '/uncaught' }.to raise_error(APIErrors::ChildError)
|
1549
|
+
expect { get '/uncaught' }.to raise_error(ApiSpec::APIErrors::ChildError)
|
1493
1550
|
end
|
1494
1551
|
end
|
1495
1552
|
|
@@ -1541,15 +1598,17 @@ describe Grape::API do
|
|
1541
1598
|
|
1542
1599
|
context 'class' do
|
1543
1600
|
before :each do
|
1544
|
-
|
1545
|
-
|
1546
|
-
|
1601
|
+
module ApiSpec
|
1602
|
+
class CustomErrorFormatter
|
1603
|
+
def self.call(message, _backtrace, _options, _env)
|
1604
|
+
"message: #{message} @backtrace"
|
1605
|
+
end
|
1547
1606
|
end
|
1548
1607
|
end
|
1549
1608
|
end
|
1550
1609
|
it 'returns a custom error format' do
|
1551
1610
|
subject.rescue_from :all, backtrace: true
|
1552
|
-
subject.error_formatter :txt, CustomErrorFormatter
|
1611
|
+
subject.error_formatter :txt, ApiSpec::CustomErrorFormatter
|
1553
1612
|
subject.get '/exception' do
|
1554
1613
|
fail 'rain!'
|
1555
1614
|
end
|
@@ -1561,16 +1620,18 @@ describe Grape::API do
|
|
1561
1620
|
describe 'with' do
|
1562
1621
|
context 'class' do
|
1563
1622
|
before :each do
|
1564
|
-
|
1565
|
-
|
1566
|
-
|
1623
|
+
module ApiSpec
|
1624
|
+
class CustomErrorFormatter
|
1625
|
+
def self.call(message, _backtrace, _option, _env)
|
1626
|
+
"message: #{message} @backtrace"
|
1627
|
+
end
|
1567
1628
|
end
|
1568
1629
|
end
|
1569
1630
|
end
|
1570
1631
|
|
1571
1632
|
it 'returns a custom error format' do
|
1572
1633
|
subject.rescue_from :all, backtrace: true
|
1573
|
-
subject.error_formatter :txt, with: CustomErrorFormatter
|
1634
|
+
subject.error_formatter :txt, with: ApiSpec::CustomErrorFormatter
|
1574
1635
|
subject.get('/exception') { fail 'rain!' }
|
1575
1636
|
|
1576
1637
|
get '/exception'
|
@@ -1648,8 +1709,8 @@ describe Grape::API do
|
|
1648
1709
|
describe '.formatter' do
|
1649
1710
|
context 'multiple formatters' do
|
1650
1711
|
before :each do
|
1651
|
-
subject.formatter :json, ->(object, _env) { "{\"custom_formatter\":\"#{object[:some]
|
1652
|
-
subject.formatter :txt, ->(object, _env) { "custom_formatter: #{object[:some]
|
1712
|
+
subject.formatter :json, ->(object, _env) { "{\"custom_formatter\":\"#{object[:some]}\"}" }
|
1713
|
+
subject.formatter :txt, ->(object, _env) { "custom_formatter: #{object[:some]}" }
|
1653
1714
|
subject.get :simple do
|
1654
1715
|
{ some: 'hash' }
|
1655
1716
|
end
|
@@ -1667,7 +1728,7 @@ describe Grape::API do
|
|
1667
1728
|
before :each do
|
1668
1729
|
subject.content_type :json, 'application/json'
|
1669
1730
|
subject.content_type :custom, 'application/custom'
|
1670
|
-
subject.formatter :custom, ->(object, _env) { "{\"custom_formatter\":\"#{object[:some]
|
1731
|
+
subject.formatter :custom, ->(object, _env) { "{\"custom_formatter\":\"#{object[:some]}\"}" }
|
1671
1732
|
subject.get :simple do
|
1672
1733
|
{ some: 'hash' }
|
1673
1734
|
end
|
@@ -1682,15 +1743,17 @@ describe Grape::API do
|
|
1682
1743
|
end
|
1683
1744
|
end
|
1684
1745
|
context 'custom formatter class' do
|
1685
|
-
module
|
1686
|
-
|
1687
|
-
|
1746
|
+
module ApiSpec
|
1747
|
+
module CustomFormatter
|
1748
|
+
def self.call(object, _env)
|
1749
|
+
"{\"custom_formatter\":\"#{object[:some]}\"}"
|
1750
|
+
end
|
1688
1751
|
end
|
1689
1752
|
end
|
1690
1753
|
before :each do
|
1691
1754
|
subject.content_type :json, 'application/json'
|
1692
1755
|
subject.content_type :custom, 'application/custom'
|
1693
|
-
subject.formatter :custom, CustomFormatter
|
1756
|
+
subject.formatter :custom, ApiSpec::CustomFormatter
|
1694
1757
|
subject.get :simple do
|
1695
1758
|
{ some: 'hash' }
|
1696
1759
|
end
|
@@ -1734,15 +1797,17 @@ describe Grape::API do
|
|
1734
1797
|
end
|
1735
1798
|
end
|
1736
1799
|
context 'custom parser class' do
|
1737
|
-
module
|
1738
|
-
|
1739
|
-
|
1800
|
+
module ApiSpec
|
1801
|
+
module CustomParser
|
1802
|
+
def self.call(object, _env)
|
1803
|
+
{ object.to_sym => object.to_s.reverse }
|
1804
|
+
end
|
1740
1805
|
end
|
1741
1806
|
end
|
1742
1807
|
before :each do
|
1743
1808
|
subject.content_type :txt, 'text/plain'
|
1744
1809
|
subject.content_type :custom, 'text/custom'
|
1745
|
-
subject.parser :custom, CustomParser
|
1810
|
+
subject.parser :custom, ApiSpec::CustomParser
|
1746
1811
|
subject.put :simple do
|
1747
1812
|
params[:simple]
|
1748
1813
|
end
|
@@ -1767,7 +1832,7 @@ describe Grape::API do
|
|
1767
1832
|
before :each do
|
1768
1833
|
subject.parser :json, nil
|
1769
1834
|
subject.put 'data' do
|
1770
|
-
"body: #{env['api.request.body']
|
1835
|
+
"body: #{env['api.request.body']}"
|
1771
1836
|
end
|
1772
1837
|
end
|
1773
1838
|
it 'does not parse data' do
|
@@ -2123,6 +2188,38 @@ describe Grape::API do
|
|
2123
2188
|
{ description: 'Reverses a string.', params: { 's' => { desc: 'string to reverse', type: 'string' } } }
|
2124
2189
|
]
|
2125
2190
|
end
|
2191
|
+
it 'does not inherit param descriptions in consequent namespaces' do
|
2192
|
+
subject.desc 'global description'
|
2193
|
+
subject.params do
|
2194
|
+
requires :param1
|
2195
|
+
optional :param2
|
2196
|
+
end
|
2197
|
+
subject.namespace 'ns1' do
|
2198
|
+
get do; end
|
2199
|
+
end
|
2200
|
+
subject.params do
|
2201
|
+
optional :param2
|
2202
|
+
end
|
2203
|
+
subject.namespace 'ns2' do
|
2204
|
+
get do; end
|
2205
|
+
end
|
2206
|
+
routes_doc = subject.routes.map { |route|
|
2207
|
+
{ description: route.route_description, params: route.route_params }
|
2208
|
+
}
|
2209
|
+
expect(routes_doc).to eq [
|
2210
|
+
{ description: 'global description',
|
2211
|
+
params: {
|
2212
|
+
'param1' => { required: true },
|
2213
|
+
'param2' => { required: false }
|
2214
|
+
}
|
2215
|
+
},
|
2216
|
+
{ description: 'global description',
|
2217
|
+
params: {
|
2218
|
+
'param2' => { required: false }
|
2219
|
+
}
|
2220
|
+
}
|
2221
|
+
]
|
2222
|
+
end
|
2126
2223
|
it 'merges the parameters of the namespace with the parameters of the method' do
|
2127
2224
|
subject.desc 'namespace'
|
2128
2225
|
subject.params do
|
@@ -2749,10 +2846,10 @@ XML
|
|
2749
2846
|
end
|
2750
2847
|
it 'hash' do
|
2751
2848
|
subject.get '/example' do
|
2752
|
-
|
2753
|
-
:
|
2754
|
-
:
|
2755
|
-
|
2849
|
+
{
|
2850
|
+
example1: 'example1',
|
2851
|
+
example2: 'example2'
|
2852
|
+
}
|
2756
2853
|
end
|
2757
2854
|
get '/example'
|
2758
2855
|
expect(last_response.status).to eq(200)
|
@@ -2817,7 +2914,7 @@ XML
|
|
2817
2914
|
[true, false].each do |anchor|
|
2818
2915
|
it "anchor=#{anchor}" do
|
2819
2916
|
subject.route :any, '*path', anchor: anchor do
|
2820
|
-
error!("Unrecognized request path: #{params[:path]
|
2917
|
+
error!("Unrecognized request path: #{params[:path]} - #{env['PATH_INFO']}#{env['SCRIPT_NAME']}", 404)
|
2821
2918
|
end
|
2822
2919
|
get '/v1/hello'
|
2823
2920
|
expect(last_response.status).to eq(200)
|
@@ -70,6 +70,19 @@ module Grape
|
|
70
70
|
expect(subject.namespace_setting(:description)).to eq(expected_options)
|
71
71
|
expect(subject.route_setting(:description)).to eq(expected_options)
|
72
72
|
end
|
73
|
+
|
74
|
+
it 'can be set with options and a block' do
|
75
|
+
expect(subject).to receive(:warn).with('[DEPRECATION] Passing a options hash and a block to `desc` is deprecated. Move all hash options to block.')
|
76
|
+
|
77
|
+
desc_text = 'The description'
|
78
|
+
detail_text = 'more details'
|
79
|
+
options = { message: 'none' }
|
80
|
+
subject.desc desc_text, options do
|
81
|
+
detail detail_text
|
82
|
+
end
|
83
|
+
expect(subject.namespace_setting(:description)).to eq(description: desc_text, detail: detail_text)
|
84
|
+
expect(subject.route_setting(:description)).to eq(description: desc_text, detail: detail_text)
|
85
|
+
end
|
73
86
|
end
|
74
87
|
end
|
75
88
|
end
|
@@ -6,13 +6,20 @@ module Grape
|
|
6
6
|
class Dummy
|
7
7
|
include Grape::DSL::Helpers
|
8
8
|
|
9
|
-
# rubocop:disable TrivialAccessors
|
10
9
|
def self.mod
|
11
10
|
namespace_stackable(:helpers).first
|
12
11
|
end
|
13
|
-
# rubocop:enable TrivialAccessors
|
14
12
|
end
|
15
13
|
end
|
14
|
+
|
15
|
+
module BooleanParam
|
16
|
+
extend Grape::API::Helpers
|
17
|
+
|
18
|
+
params :requires_toggle_prm do
|
19
|
+
requires :toggle_prm, type: Boolean
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
16
23
|
describe Helpers do
|
17
24
|
subject { Class.new(HelpersSpec::Dummy) }
|
18
25
|
let(:proc) do
|
@@ -41,6 +48,13 @@ module Grape
|
|
41
48
|
|
42
49
|
expect(subject.mod).to eq mod
|
43
50
|
end
|
51
|
+
|
52
|
+
context 'with an external file' do
|
53
|
+
it 'sets Boolean as a Virtus::Attribute::Boolean' do
|
54
|
+
subject.helpers BooleanParam
|
55
|
+
expect(subject.mod::Boolean).to eq Virtus::Attribute::Boolean
|
56
|
+
end
|
57
|
+
end
|
44
58
|
end
|
45
59
|
end
|
46
60
|
end
|
@@ -201,8 +201,43 @@ module Grape
|
|
201
201
|
subject.file 'file'
|
202
202
|
end
|
203
203
|
|
204
|
-
it 'returns value' do
|
205
|
-
expect(subject.file).to eq 'file'
|
204
|
+
it 'returns value wrapped in FileResponse' do
|
205
|
+
expect(subject.file).to eq Grape::Util::FileResponse.new('file')
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'returns default' do
|
210
|
+
expect(subject.file).to be nil
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
describe '#stream' do
|
215
|
+
describe 'set' do
|
216
|
+
before do
|
217
|
+
subject.header 'Cache-Control', 'cache'
|
218
|
+
subject.header 'Content-Length', 123
|
219
|
+
subject.header 'Transfer-Encoding', 'base64'
|
220
|
+
subject.stream 'file'
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'returns value wrapped in FileResponse' do
|
224
|
+
expect(subject.stream).to eq Grape::Util::FileResponse.new('file')
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'also sets result of file to value wrapped in FileResponse' do
|
228
|
+
expect(subject.file).to eq Grape::Util::FileResponse.new('file')
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'sets Cache-Control header to no-cache' do
|
232
|
+
expect(subject.header['Cache-Control']).to eq 'no-cache'
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'sets Content-Length header to nil' do
|
236
|
+
expect(subject.header['Content-Length']).to eq nil
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'sets Transfer-Encoding header to nil' do
|
240
|
+
expect(subject.header['Transfer-Encoding']).to eq nil
|
206
241
|
end
|
207
242
|
end
|
208
243
|
|
@@ -308,8 +343,9 @@ module Grape
|
|
308
343
|
describe '#declared' do
|
309
344
|
# see endpoint_spec.rb#declared for spec coverage
|
310
345
|
|
311
|
-
it '
|
312
|
-
expect
|
346
|
+
it 'is not available by default' do
|
347
|
+
expect { subject.declared({}) }.to raise_error(
|
348
|
+
Grape::DSL::InsideRoute::MethodNotYetAvailable)
|
313
349
|
end
|
314
350
|
end
|
315
351
|
end
|
@@ -11,31 +11,25 @@ module Grape
|
|
11
11
|
@validate_attributes = *args
|
12
12
|
end
|
13
13
|
|
14
|
-
# rubocop:disable TrivialAccessors
|
15
14
|
def validate_attributes_reader
|
16
15
|
@validate_attributes
|
17
16
|
end
|
18
|
-
# rubocop:enable TrivialAccessors
|
19
17
|
|
20
18
|
def push_declared_params(*args)
|
21
19
|
@push_declared_params = args
|
22
20
|
end
|
23
21
|
|
24
|
-
# rubocop:disable TrivialAccessors
|
25
22
|
def push_declared_params_reader
|
26
23
|
@push_declared_params
|
27
24
|
end
|
28
|
-
# rubocop:enable TrivialAccessors
|
29
25
|
|
30
26
|
def validates(*args)
|
31
27
|
@validates = *args
|
32
28
|
end
|
33
29
|
|
34
|
-
# rubocop:disable TrivialAccessors
|
35
30
|
def validates_reader
|
36
31
|
@validates
|
37
32
|
end
|
38
|
-
# rubocop:enable TrivialAccessors
|
39
33
|
end
|
40
34
|
end
|
41
35
|
|
@@ -228,7 +228,7 @@ module Grape
|
|
228
228
|
end
|
229
229
|
|
230
230
|
let(:regex) { /(.*)/ }
|
231
|
-
let!(:options) {
|
231
|
+
let!(:options) { { requirements: regex } }
|
232
232
|
it 'nests requirements option under param name' do
|
233
233
|
expect(subject).to receive(:namespace) do |_param, options|
|
234
234
|
expect(options[:requirements][:foo]).to eq regex
|
@@ -15,9 +15,15 @@ module Grape
|
|
15
15
|
before do
|
16
16
|
subject.namespace_stackable :declared_params, ['dummy']
|
17
17
|
subject.namespace_stackable :validations, ['dummy']
|
18
|
+
subject.namespace_stackable :params, ['dummy']
|
19
|
+
subject.route_setting :description, description: 'lol', params: ['dummy']
|
18
20
|
subject.reset_validations!
|
19
21
|
end
|
20
22
|
|
23
|
+
after do
|
24
|
+
subject.unset_route_setting :description
|
25
|
+
end
|
26
|
+
|
21
27
|
it 'resets declared params' do
|
22
28
|
expect(subject.namespace_stackable(:declared_params)).to eq []
|
23
29
|
end
|
@@ -25,6 +31,18 @@ module Grape
|
|
25
31
|
it 'resets validations' do
|
26
32
|
expect(subject.namespace_stackable(:validations)).to eq []
|
27
33
|
end
|
34
|
+
|
35
|
+
it 'resets params' do
|
36
|
+
expect(subject.namespace_stackable(:params)).to eq []
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'resets documentation params' do
|
40
|
+
expect(subject.route_setting(:description)[:params]).to be_nil
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'does not reset documentation description' do
|
44
|
+
expect(subject.route_setting(:description)[:description]).to eq 'lol'
|
45
|
+
end
|
28
46
|
end
|
29
47
|
|
30
48
|
describe '.params' do
|