grape 1.6.0 → 1.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -0
  3. data/CONTRIBUTING.md +1 -0
  4. data/README.md +9 -1
  5. data/lib/grape/api.rb +12 -0
  6. data/lib/grape/dry_types.rb +12 -0
  7. data/lib/grape/dsl/headers.rb +5 -2
  8. data/lib/grape/dsl/helpers.rb +1 -1
  9. data/lib/grape/middleware/auth/dsl.rb +7 -1
  10. data/lib/grape/middleware/base.rb +1 -1
  11. data/lib/grape/util/json.rb +2 -0
  12. data/lib/grape/util/strict_hash_configuration.rb +1 -1
  13. data/lib/grape/validations/types/array_coercer.rb +0 -2
  14. data/lib/grape/validations/types/dry_type_coercer.rb +1 -10
  15. data/lib/grape/validations/types/json.rb +0 -2
  16. data/lib/grape/validations/types/primitive_coercer.rb +5 -7
  17. data/lib/grape/validations/types/set_coercer.rb +0 -3
  18. data/lib/grape/validations/types.rb +83 -9
  19. data/lib/grape/validations/validators/all_or_none_of_validator.rb +16 -0
  20. data/lib/grape/validations/validators/allow_blank_validator.rb +20 -0
  21. data/lib/grape/validations/validators/as_validator.rb +14 -0
  22. data/lib/grape/validations/validators/at_least_one_of_validator.rb +15 -0
  23. data/lib/grape/validations/validators/base.rb +73 -71
  24. data/lib/grape/validations/validators/coerce_validator.rb +75 -0
  25. data/lib/grape/validations/validators/default_validator.rb +51 -0
  26. data/lib/grape/validations/validators/exactly_one_of_validator.rb +17 -0
  27. data/lib/grape/validations/validators/except_values_validator.rb +24 -0
  28. data/lib/grape/validations/validators/multiple_params_base.rb +24 -22
  29. data/lib/grape/validations/validators/mutual_exclusion_validator.rb +16 -0
  30. data/lib/grape/validations/validators/presence_validator.rb +15 -0
  31. data/lib/grape/validations/validators/regexp_validator.rb +16 -0
  32. data/lib/grape/validations/validators/same_as_validator.rb +29 -0
  33. data/lib/grape/validations/validators/values_validator.rb +88 -0
  34. data/lib/grape/version.rb +1 -1
  35. data/lib/grape.rb +59 -24
  36. data/spec/grape/api/custom_validations_spec.rb +77 -46
  37. data/spec/grape/api/deeply_included_options_spec.rb +3 -3
  38. data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -1
  39. data/spec/grape/api/invalid_format_spec.rb +2 -0
  40. data/spec/grape/api/recognize_path_spec.rb +1 -1
  41. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -15
  42. data/spec/grape/api_remount_spec.rb +16 -15
  43. data/spec/grape/api_spec.rb +317 -193
  44. data/spec/grape/dsl/callbacks_spec.rb +1 -0
  45. data/spec/grape/dsl/headers_spec.rb +39 -9
  46. data/spec/grape/dsl/helpers_spec.rb +3 -2
  47. data/spec/grape/dsl/inside_route_spec.rb +6 -4
  48. data/spec/grape/dsl/logger_spec.rb +16 -18
  49. data/spec/grape/dsl/middleware_spec.rb +1 -0
  50. data/spec/grape/dsl/parameters_spec.rb +1 -0
  51. data/spec/grape/dsl/request_response_spec.rb +1 -0
  52. data/spec/grape/dsl/routing_spec.rb +9 -6
  53. data/spec/grape/endpoint/declared_spec.rb +12 -12
  54. data/spec/grape/endpoint_spec.rb +59 -50
  55. data/spec/grape/entity_spec.rb +13 -13
  56. data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -0
  57. data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -22
  58. data/spec/grape/exceptions/validation_errors_spec.rb +13 -10
  59. data/spec/grape/exceptions/validation_spec.rb +5 -3
  60. data/spec/grape/extensions/param_builders/hash_spec.rb +7 -7
  61. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -8
  62. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -8
  63. data/spec/grape/integration/rack_sendfile_spec.rb +1 -1
  64. data/spec/grape/loading_spec.rb +8 -8
  65. data/spec/grape/middleware/auth/dsl_spec.rb +14 -5
  66. data/spec/grape/middleware/auth/strategies_spec.rb +60 -20
  67. data/spec/grape/middleware/base_spec.rb +24 -15
  68. data/spec/grape/middleware/error_spec.rb +1 -0
  69. data/spec/grape/middleware/exception_spec.rb +111 -161
  70. data/spec/grape/middleware/formatter_spec.rb +25 -4
  71. data/spec/grape/middleware/globals_spec.rb +7 -4
  72. data/spec/grape/middleware/stack_spec.rb +11 -11
  73. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -1
  74. data/spec/grape/middleware/versioner/header_spec.rb +14 -13
  75. data/spec/grape/middleware/versioner/param_spec.rb +7 -1
  76. data/spec/grape/middleware/versioner/path_spec.rb +5 -1
  77. data/spec/grape/middleware/versioner_spec.rb +1 -1
  78. data/spec/grape/parser_spec.rb +4 -0
  79. data/spec/grape/path_spec.rb +52 -52
  80. data/spec/grape/presenters/presenter_spec.rb +7 -6
  81. data/spec/grape/request_spec.rb +6 -4
  82. data/spec/grape/util/inheritable_setting_spec.rb +7 -7
  83. data/spec/grape/util/inheritable_values_spec.rb +3 -2
  84. data/spec/grape/util/reverse_stackable_values_spec.rb +3 -1
  85. data/spec/grape/util/stackable_values_spec.rb +7 -5
  86. data/spec/grape/validations/instance_behaivour_spec.rb +9 -10
  87. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +1 -0
  88. data/spec/grape/validations/params_scope_spec.rb +9 -7
  89. data/spec/grape/validations/single_attribute_iterator_spec.rb +1 -0
  90. data/spec/grape/validations/types/primitive_coercer_spec.rb +2 -2
  91. data/spec/grape/validations/types_spec.rb +8 -8
  92. data/spec/grape/validations/validators/all_or_none_spec.rb +50 -56
  93. data/spec/grape/validations/validators/allow_blank_spec.rb +136 -140
  94. data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -56
  95. data/spec/grape/validations/validators/coerce_spec.rb +10 -12
  96. data/spec/grape/validations/validators/default_spec.rb +72 -78
  97. data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -77
  98. data/spec/grape/validations/validators/except_values_spec.rb +1 -1
  99. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -77
  100. data/spec/grape/validations/validators/presence_spec.rb +16 -1
  101. data/spec/grape/validations/validators/regexp_spec.rb +25 -31
  102. data/spec/grape/validations/validators/same_as_spec.rb +14 -20
  103. data/spec/grape/validations/validators/values_spec.rb +172 -171
  104. data/spec/grape/validations_spec.rb +45 -16
  105. data/spec/integration/eager_load/eager_load_spec.rb +2 -2
  106. data/spec/integration/multi_json/json_spec.rb +1 -1
  107. data/spec/integration/multi_xml/xml_spec.rb +1 -1
  108. data/spec/shared/versioning_examples.rb +10 -7
  109. data/spec/spec_helper.rb +11 -1
  110. metadata +116 -116
  111. data/lib/grape/validations/types/build_coercer.rb +0 -94
  112. data/lib/grape/validations/validators/all_or_none.rb +0 -16
  113. data/lib/grape/validations/validators/allow_blank.rb +0 -18
  114. data/lib/grape/validations/validators/as.rb +0 -12
  115. data/lib/grape/validations/validators/at_least_one_of.rb +0 -15
  116. data/lib/grape/validations/validators/coerce.rb +0 -87
  117. data/lib/grape/validations/validators/default.rb +0 -49
  118. data/lib/grape/validations/validators/exactly_one_of.rb +0 -17
  119. data/lib/grape/validations/validators/except_values.rb +0 -22
  120. data/lib/grape/validations/validators/mutual_exclusion.rb +0 -16
  121. data/lib/grape/validations/validators/presence.rb +0 -13
  122. data/lib/grape/validations/validators/regexp.rb +0 -14
  123. data/lib/grape/validations/validators/same_as.rb +0 -27
  124. data/lib/grape/validations/validators/values.rb +0 -86
@@ -4,7 +4,10 @@ require 'spec_helper'
4
4
  require 'shared/versioning_examples'
5
5
 
6
6
  describe Grape::API do
7
- subject { Class.new(Grape::API) }
7
+ subject do
8
+ puts described_class
9
+ Class.new(described_class)
10
+ end
8
11
 
9
12
  def app
10
13
  subject
@@ -18,7 +21,7 @@ describe Grape::API do
18
21
  end
19
22
 
20
23
  get 'awesome/sauce/'
21
- expect(last_response.status).to eql 200
24
+ expect(last_response.status).to be 200
22
25
  expect(last_response.body).to eql 'Hello there.'
23
26
  end
24
27
 
@@ -32,7 +35,7 @@ describe Grape::API do
32
35
  expect(last_response.body).to eql 'Hello there.'
33
36
 
34
37
  get '/hello'
35
- expect(last_response.status).to eql 404
38
+ expect(last_response.status).to be 404
36
39
  end
37
40
 
38
41
  it 'supports OPTIONS' do
@@ -42,7 +45,7 @@ describe Grape::API do
42
45
  end
43
46
 
44
47
  options 'awesome/sauce'
45
- expect(last_response.status).to eql 204
48
+ expect(last_response.status).to be 204
46
49
  expect(last_response.body).to be_blank
47
50
  end
48
51
 
@@ -51,7 +54,7 @@ describe Grape::API do
51
54
  subject.get
52
55
 
53
56
  post 'awesome/sauce'
54
- expect(last_response.status).to eql 405
57
+ expect(last_response.status).to be 405
55
58
  end
56
59
  end
57
60
 
@@ -71,7 +74,7 @@ describe Grape::API do
71
74
  end
72
75
 
73
76
  describe '.version using path' do
74
- it_should_behave_like 'versioning' do
77
+ it_behaves_like 'versioning' do
75
78
  let(:macro_options) do
76
79
  {
77
80
  using: :path
@@ -81,7 +84,7 @@ describe Grape::API do
81
84
  end
82
85
 
83
86
  describe '.version using param' do
84
- it_should_behave_like 'versioning' do
87
+ it_behaves_like 'versioning' do
85
88
  let(:macro_options) do
86
89
  {
87
90
  using: :param,
@@ -92,7 +95,7 @@ describe Grape::API do
92
95
  end
93
96
 
94
97
  describe '.version using header' do
95
- it_should_behave_like 'versioning' do
98
+ it_behaves_like 'versioning' do
96
99
  let(:macro_options) do
97
100
  {
98
101
  using: :header,
@@ -120,7 +123,7 @@ describe Grape::API do
120
123
  end
121
124
 
122
125
  describe '.version using accept_version_header' do
123
- it_should_behave_like 'versioning' do
126
+ it_behaves_like 'versioning' do
124
127
  let(:macro_options) do
125
128
  {
126
129
  using: :accept_version_header
@@ -389,7 +392,7 @@ describe Grape::API do
389
392
  end
390
393
  end
391
394
 
392
- before(:each) do
395
+ before do
393
396
  allow_any_instance_of(ApiSpec::DummyFormatClass).to receive(:to_json).and_return('abc')
394
397
  allow_any_instance_of(ApiSpec::DummyFormatClass).to receive(:to_txt).and_return('def')
395
398
 
@@ -447,7 +450,7 @@ describe Grape::API do
447
450
  end
448
451
 
449
452
  %i[put post].each do |verb|
450
- context verb do
453
+ context verb.to_s do
451
454
  ['string', :symbol, 1, -1.1, {}, [], true, false, nil].each do |object|
452
455
  it "allows a(n) #{object.class} json object in params" do
453
456
  subject.format :json
@@ -459,6 +462,7 @@ describe Grape::API do
459
462
  expect(last_response.body).to eql ::Grape::Json.dump(object)
460
463
  expect(last_request.params).to eql({})
461
464
  end
465
+
462
466
  it 'stores input in api.request.input' do
463
467
  subject.format :json
464
468
  subject.send(verb) do
@@ -468,6 +472,7 @@ describe Grape::API do
468
472
  expect(last_response.status).to eq(verb == :post ? 201 : 200)
469
473
  expect(last_response.body).to eql ::Grape::Json.dump(object).to_json
470
474
  end
475
+
471
476
  context 'chunked transfer encoding' do
472
477
  it 'stores input in api.request.input' do
473
478
  subject.format :json
@@ -562,7 +567,8 @@ describe Grape::API do
562
567
  send(other_verb, '/example')
563
568
  expected_rc = if other_verb == 'options' then 204
564
569
  elsif other_verb == 'head' && verb == 'get' then 200
565
- else 405
570
+ else
571
+ 405
566
572
  end
567
573
  expect(last_response.status).to eql expected_rc
568
574
  end
@@ -575,7 +581,7 @@ describe Grape::API do
575
581
  end
576
582
 
577
583
  post '/example'
578
- expect(last_response.status).to eql 201
584
+ expect(last_response.status).to be 201
579
585
  expect(last_response.body).to eql 'Created'
580
586
  end
581
587
 
@@ -585,7 +591,7 @@ describe Grape::API do
585
591
  'example'
586
592
  end
587
593
  put '/example'
588
- expect(last_response.status).to eql 405
594
+ expect(last_response.status).to be 405
589
595
  expect(last_response.body).to eql '405 Not Allowed'
590
596
  expect(last_response.headers['X-Custom-Header']).to eql 'foo'
591
597
  end
@@ -593,15 +599,17 @@ describe Grape::API do
593
599
  it 'runs only the before filter on 405 bad method' do
594
600
  subject.namespace :example do
595
601
  before { header 'X-Custom-Header', 'foo' }
602
+
596
603
  before_validation { raise 'before_validation filter should not run' }
597
604
  after_validation { raise 'after_validation filter should not run' }
598
605
  after { raise 'after filter should not run' }
606
+
599
607
  params { requires :only_for_get }
600
608
  get
601
609
  end
602
610
 
603
611
  post '/example'
604
- expect(last_response.status).to eql 405
612
+ expect(last_response.status).to be 405
605
613
  expect(last_response.headers['X-Custom-Header']).to eql 'foo'
606
614
  end
607
615
 
@@ -614,26 +622,29 @@ describe Grape::API do
614
622
  already_run = true
615
623
  header 'X-Custom-Header', 'foo'
616
624
  end
625
+
617
626
  get
618
627
  end
619
628
 
620
629
  post '/example'
621
- expect(last_response.status).to eql 405
630
+ expect(last_response.status).to be 405
622
631
  expect(last_response.headers['X-Custom-Header']).to eql 'foo'
623
632
  end
624
633
 
625
634
  it 'runs all filters and body with a custom OPTIONS method' do
626
635
  subject.namespace :example do
627
636
  before { header 'X-Custom-Header-1', 'foo' }
637
+
628
638
  before_validation { header 'X-Custom-Header-2', 'foo' }
629
639
  after_validation { header 'X-Custom-Header-3', 'foo' }
630
640
  after { header 'X-Custom-Header-4', 'foo' }
641
+
631
642
  options { 'yup' }
632
643
  get
633
644
  end
634
645
 
635
646
  options '/example'
636
- expect(last_response.status).to eql 200
647
+ expect(last_response.status).to be 200
637
648
  expect(last_response.body).to eql 'yup'
638
649
  expect(last_response.headers['Allow']).to be_nil
639
650
  expect(last_response.headers['X-Custom-Header-1']).to eql 'foo'
@@ -650,7 +661,7 @@ describe Grape::API do
650
661
  end
651
662
 
652
663
  put '/example'
653
- expect(last_response.status).to eql 405
664
+ expect(last_response.status).to be 405
654
665
  expect(last_response.body).to eq <<~XML
655
666
  <?xml version="1.0" encoding="UTF-8"?>
656
667
  <error>
@@ -670,7 +681,7 @@ describe Grape::API do
670
681
  'example'
671
682
  end
672
683
  put '/example'
673
- expect(last_response.status).to eql 405
684
+ expect(last_response.status).to be 405
674
685
  expect(last_response.body).to eql '405 Not Allowed'
675
686
  end
676
687
  end
@@ -714,7 +725,7 @@ describe Grape::API do
714
725
  end
715
726
 
716
727
  it 'returns a 204' do
717
- expect(last_response.status).to eql 204
728
+ expect(last_response.status).to be 204
718
729
  end
719
730
 
720
731
  it 'has an empty body' do
@@ -778,7 +789,7 @@ describe Grape::API do
778
789
 
779
790
  describe 'it adds an OPTIONS route for namespaced endpoints that' do
780
791
  it 'returns a 204' do
781
- expect(last_response.status).to eql 204
792
+ expect(last_response.status).to be 204
782
793
  end
783
794
 
784
795
  it 'has an empty body' do
@@ -796,6 +807,7 @@ describe Grape::API do
796
807
  subject.before { header 'X-Custom-Header', 'foo' }
797
808
  subject.namespace :example do
798
809
  before { header 'X-Custom-Header-2', 'foo' }
810
+
799
811
  get :inner do
800
812
  'example/inner'
801
813
  end
@@ -804,7 +816,7 @@ describe Grape::API do
804
816
  end
805
817
 
806
818
  it 'returns a 204' do
807
- expect(last_response.status).to eql 204
819
+ expect(last_response.status).to be 204
808
820
  end
809
821
 
810
822
  it 'has an empty body' do
@@ -842,7 +854,7 @@ describe Grape::API do
842
854
  end
843
855
 
844
856
  it 'returns a 405' do
845
- expect(last_response.status).to eql 405
857
+ expect(last_response.status).to be 405
846
858
  end
847
859
 
848
860
  it 'contains error message in body' do
@@ -858,7 +870,7 @@ describe Grape::API do
858
870
  end
859
871
  end
860
872
 
861
- describe 'when hook behaviour is controlled by attributes on the route ' do
873
+ describe 'when hook behaviour is controlled by attributes on the route' do
862
874
  before do
863
875
  subject.before do
864
876
  error!('Access Denied', 401) unless route.options[:secret] == params[:secret]
@@ -881,28 +893,31 @@ describe Grape::API do
881
893
  let(:response) { delete('/example') }
882
894
 
883
895
  it 'responds with a 405 status' do
884
- expect(response.status).to eql 405
896
+ expect(response.status).to be 405
885
897
  end
886
898
  end
887
899
 
888
900
  context 'when HTTP method is defined with attribute' do
889
901
  let(:response) { post('/example?secret=incorrect_password') }
902
+
890
903
  it 'responds with the defined error in the before hook' do
891
- expect(response.status).to eql 401
904
+ expect(response.status).to be 401
892
905
  end
893
906
  end
894
907
 
895
908
  context 'when HTTP method is defined and the underlying before hook expectation is not met' do
896
909
  let(:response) { post('/example?secret=password&namespace_secret=wrong_namespace_password') }
910
+
897
911
  it 'ends up in the endpoint' do
898
- expect(response.status).to eql 401
912
+ expect(response.status).to be 401
899
913
  end
900
914
  end
901
915
 
902
916
  context 'when HTTP method is defined and everything is like the before hooks expect' do
903
917
  let(:response) { post('/example?secret=password&namespace_secret=namespace_password') }
918
+
904
919
  it 'ends up in the endpoint' do
905
- expect(response.status).to eql 201
920
+ expect(response.status).to be 201
906
921
  end
907
922
  end
908
923
 
@@ -910,7 +925,7 @@ describe Grape::API do
910
925
  let(:response) { head('/example?id=504') }
911
926
 
912
927
  it 'responds with 401 because before expectations in before hooks are not met' do
913
- expect(response.status).to eql 401
928
+ expect(response.status).to be 401
914
929
  end
915
930
  end
916
931
 
@@ -918,7 +933,7 @@ describe Grape::API do
918
933
  let(:response) { head('/example?id=504&secret=password') }
919
934
 
920
935
  it 'responds with 200 because before hooks are not called' do
921
- expect(response.status).to eql 200
936
+ expect(response.status).to be 200
922
937
  end
923
938
  end
924
939
  end
@@ -935,7 +950,7 @@ describe Grape::API do
935
950
  end
936
951
 
937
952
  it 'returns a 200' do
938
- expect(last_response.status).to eql 200
953
+ expect(last_response.status).to be 200
939
954
  end
940
955
 
941
956
  it 'has an empty body' do
@@ -951,31 +966,33 @@ describe Grape::API do
951
966
  'example'
952
967
  end
953
968
  head '/example'
954
- expect(last_response.status).to eql 400
969
+ expect(last_response.status).to be 400
955
970
  end
956
971
  end
957
972
 
958
973
  context 'do_not_route_head!' do
959
- before :each do
974
+ before do
960
975
  subject.do_not_route_head!
961
976
  subject.get 'example' do
962
977
  'example'
963
978
  end
964
979
  end
980
+
965
981
  it 'options does not contain HEAD' do
966
982
  options '/example'
967
- expect(last_response.status).to eql 204
983
+ expect(last_response.status).to be 204
968
984
  expect(last_response.body).to eql ''
969
985
  expect(last_response.headers['Allow']).to eql 'OPTIONS, GET'
970
986
  end
987
+
971
988
  it 'does not allow HEAD on a GET request' do
972
989
  head '/example'
973
- expect(last_response.status).to eql 405
990
+ expect(last_response.status).to be 405
974
991
  end
975
992
  end
976
993
 
977
994
  context 'do_not_route_options!' do
978
- before :each do
995
+ before do
979
996
  subject.do_not_route_options!
980
997
  subject.get 'example' do
981
998
  'example'
@@ -984,19 +1001,19 @@ describe Grape::API do
984
1001
 
985
1002
  it 'does not create an OPTIONS route' do
986
1003
  options '/example'
987
- expect(last_response.status).to eql 405
1004
+ expect(last_response.status).to be 405
988
1005
  end
989
1006
 
990
1007
  it 'does not include OPTIONS in Allow header' do
991
1008
  options '/example'
992
- expect(last_response.status).to eql 405
1009
+ expect(last_response.status).to be 405
993
1010
  expect(last_response.headers['Allow']).to eql 'GET, HEAD'
994
1011
  end
995
1012
  end
996
1013
 
997
1014
  describe '.compile!' do
998
1015
  it 'requires the grape/eager_load file' do
999
- expect(app).to receive(:require).with('grape/eager_load') { nil }
1016
+ expect(app).to receive(:require).with('grape/eager_load').and_return(nil)
1000
1017
  app.compile!
1001
1018
  end
1002
1019
 
@@ -1018,7 +1035,7 @@ describe Grape::API do
1018
1035
  context 'when the app was mounted' do
1019
1036
  it 'returns the first mounted instance' do
1020
1037
  mounted_app = app
1021
- Class.new(Grape::API) do
1038
+ Class.new(described_class) do
1022
1039
  namespace 'new_namespace' do
1023
1040
  mount mounted_app
1024
1041
  end
@@ -1046,6 +1063,7 @@ describe Grape::API do
1046
1063
  end
1047
1064
  subject.namespace :blah do
1048
1065
  before { @foo = 'foo' }
1066
+
1049
1067
  get '/' do
1050
1068
  "blah - #{@foo}"
1051
1069
  end
@@ -1087,7 +1105,7 @@ describe Grape::API do
1087
1105
  @var ||= 'default'
1088
1106
  end
1089
1107
 
1090
- expect(m).to receive(:do_something!).exactly(2).times
1108
+ expect(m).to receive(:do_something!).twice
1091
1109
  get '/'
1092
1110
  expect(last_response.body).to eql 'default'
1093
1111
  end
@@ -1103,21 +1121,23 @@ describe Grape::API do
1103
1121
  end
1104
1122
  subject.resource ':id' do
1105
1123
  before { a.do_something! }
1124
+
1106
1125
  before_validation { b.do_something! }
1107
1126
  after_validation { c.do_something! }
1108
1127
  after { d.do_something! }
1128
+
1109
1129
  get do
1110
1130
  'got it'
1111
1131
  end
1112
1132
  end
1113
1133
 
1114
- expect(a).to receive(:do_something!).exactly(1).times
1115
- expect(b).to receive(:do_something!).exactly(1).times
1116
- expect(c).to receive(:do_something!).exactly(1).times
1117
- expect(d).to receive(:do_something!).exactly(1).times
1134
+ expect(a).to receive(:do_something!).once
1135
+ expect(b).to receive(:do_something!).once
1136
+ expect(c).to receive(:do_something!).once
1137
+ expect(d).to receive(:do_something!).once
1118
1138
 
1119
1139
  get '/123'
1120
- expect(last_response.status).to eql 200
1140
+ expect(last_response.status).to be 200
1121
1141
  expect(last_response.body).to eql 'got it'
1122
1142
  end
1123
1143
 
@@ -1132,21 +1152,23 @@ describe Grape::API do
1132
1152
  end
1133
1153
  subject.resource ':id' do
1134
1154
  before { a.do_something! }
1155
+
1135
1156
  before_validation { b.do_something! }
1136
1157
  after_validation { c.do_something! }
1137
1158
  after { d.do_something! }
1159
+
1138
1160
  get do
1139
1161
  'got it'
1140
1162
  end
1141
1163
  end
1142
1164
 
1143
- expect(a).to receive(:do_something!).exactly(1).times
1144
- expect(b).to receive(:do_something!).exactly(1).times
1165
+ expect(a).to receive(:do_something!).once
1166
+ expect(b).to receive(:do_something!).once
1145
1167
  expect(c).to receive(:do_something!).exactly(0).times
1146
1168
  expect(d).to receive(:do_something!).exactly(0).times
1147
1169
 
1148
1170
  get '/abc'
1149
- expect(last_response.status).to eql 400
1171
+ expect(last_response.status).to be 400
1150
1172
  expect(last_response.body).to eql 'id is invalid'
1151
1173
  end
1152
1174
 
@@ -1162,21 +1184,23 @@ describe Grape::API do
1162
1184
  end
1163
1185
  subject.resource ':id' do
1164
1186
  before { a.here(i += 1) }
1187
+
1165
1188
  before_validation { b.here(i += 1) }
1166
1189
  after_validation { c.here(i += 1) }
1167
1190
  after { d.here(i += 1) }
1191
+
1168
1192
  get do
1169
1193
  'got it'
1170
1194
  end
1171
1195
  end
1172
1196
 
1173
- expect(a).to receive(:here).with(1).exactly(1).times
1174
- expect(b).to receive(:here).with(2).exactly(1).times
1175
- expect(c).to receive(:here).with(3).exactly(1).times
1176
- expect(d).to receive(:here).with(4).exactly(1).times
1197
+ expect(a).to receive(:here).with(1).once
1198
+ expect(b).to receive(:here).with(2).once
1199
+ expect(c).to receive(:here).with(3).once
1200
+ expect(d).to receive(:here).with(4).once
1177
1201
 
1178
1202
  get '/123'
1179
- expect(last_response.status).to eql 200
1203
+ expect(last_response.status).to be 200
1180
1204
  expect(last_response.body).to eql 'got it'
1181
1205
  end
1182
1206
  end
@@ -1267,7 +1291,7 @@ describe Grape::API do
1267
1291
  subject.format :json
1268
1292
  subject.get('/error') { error!('error in json', 500) }
1269
1293
  get '/error.json'
1270
- expect(last_response.status).to eql 500
1294
+ expect(last_response.status).to be 500
1271
1295
  expect(last_response.headers['Content-Type']).to eql 'application/json'
1272
1296
  end
1273
1297
 
@@ -1275,7 +1299,7 @@ describe Grape::API do
1275
1299
  subject.format :xml
1276
1300
  subject.get('/error') { error!('error in xml', 500) }
1277
1301
  get '/error'
1278
- expect(last_response.status).to eql 500
1302
+ expect(last_response.status).to be 500
1279
1303
  expect(last_response.headers['Content-Type']).to eql 'application/xml'
1280
1304
  end
1281
1305
 
@@ -1534,9 +1558,9 @@ describe Grape::API do
1534
1558
  end
1535
1559
  subject.get(:hello) { 'Hello, world.' }
1536
1560
  get '/hello'
1537
- expect(last_response.status).to eql 401
1561
+ expect(last_response.status).to be 401
1538
1562
  get '/hello', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('allow', 'whatever')
1539
- expect(last_response.status).to eql 200
1563
+ expect(last_response.status).to be 200
1540
1564
  end
1541
1565
 
1542
1566
  it 'is scopable' do
@@ -1550,9 +1574,9 @@ describe Grape::API do
1550
1574
  end
1551
1575
 
1552
1576
  get '/hello'
1553
- expect(last_response.status).to eql 200
1577
+ expect(last_response.status).to be 200
1554
1578
  get '/admin/hello'
1555
- expect(last_response.status).to eql 401
1579
+ expect(last_response.status).to be 401
1556
1580
  end
1557
1581
 
1558
1582
  it 'is callable via .auth as well' do
@@ -1562,9 +1586,9 @@ describe Grape::API do
1562
1586
 
1563
1587
  subject.get(:hello) { 'Hello, world.' }
1564
1588
  get '/hello'
1565
- expect(last_response.status).to eql 401
1589
+ expect(last_response.status).to be 401
1566
1590
  get '/hello', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('allow', 'whatever')
1567
- expect(last_response.status).to eql 200
1591
+ expect(last_response.status).to be 200
1568
1592
  end
1569
1593
 
1570
1594
  it 'has access to the current endpoint' do
@@ -1594,9 +1618,9 @@ describe Grape::API do
1594
1618
 
1595
1619
  subject.get(:hello) { 'Hello, world.' }
1596
1620
  get '/hello', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('allow', 'whatever')
1597
- expect(last_response.status).to eql 200
1621
+ expect(last_response.status).to be 200
1598
1622
  get '/hello', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('disallow', 'whatever')
1599
- expect(last_response.status).to eql 401
1623
+ expect(last_response.status).to be 401
1600
1624
  end
1601
1625
 
1602
1626
  it 'can set instance variables accessible to routes' do
@@ -1608,44 +1632,36 @@ describe Grape::API do
1608
1632
 
1609
1633
  subject.get(:hello) { @hello }
1610
1634
  get '/hello', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('allow', 'whatever')
1611
- expect(last_response.status).to eql 200
1635
+ expect(last_response.status).to be 200
1612
1636
  expect(last_response.body).to eql 'Hello, world.'
1613
1637
  end
1614
1638
  end
1615
1639
 
1616
1640
  describe '.logger' do
1617
- subject do
1618
- Class.new(Grape::API) do
1619
- def self.io
1620
- @io ||= StringIO.new
1621
- end
1622
- logger ::Logger.new(io)
1623
- end
1624
- end
1625
-
1626
1641
  it 'returns an instance of Logger class by default' do
1627
1642
  expect(subject.logger.class).to eql Logger
1628
1643
  end
1629
1644
 
1630
- it 'allows setting a custom logger' do
1631
- mylogger = Class.new
1632
- subject.logger mylogger
1633
- expect(mylogger).to receive(:info).exactly(1).times
1634
- subject.logger.info 'this will be logged'
1635
- end
1645
+ context 'with a custom logger' do
1646
+ subject do
1647
+ Class.new(described_class) do
1648
+ def self.io
1649
+ @io ||= StringIO.new
1650
+ end
1651
+ logger ::Logger.new(io)
1652
+ end
1653
+ end
1636
1654
 
1637
- it 'defaults to a standard logger log format' do
1638
- t = Time.at(100)
1639
- allow(Time).to receive(:now).and_return(t)
1640
- message = "this will be logged\n"
1641
- message = "I, [#{Logger::Formatter.new.send(:format_datetime, t)}\##{Process.pid}] INFO -- : #{message}" if !defined?(Rails) || Gem::Version.new(Rails::VERSION::STRING) >= Gem::Version.new('4.0')
1642
- expect(subject.io).to receive(:write).with(message)
1643
- subject.logger.info 'this will be logged'
1655
+ it 'exposes its interaface' do
1656
+ message = 'this will be logged'
1657
+ subject.logger.info message
1658
+ expect(subject.io.string).to include(message)
1659
+ end
1644
1660
  end
1645
1661
 
1646
1662
  it 'does not unnecessarily retain duplicate setup blocks' do
1647
1663
  subject.logger
1648
- expect { subject.logger }.to_not change(subject.instance_variable_get(:@setup), :size)
1664
+ expect { subject.logger }.not_to change(subject.instance_variable_get(:@setup), :size)
1649
1665
  end
1650
1666
  end
1651
1667
 
@@ -1771,13 +1787,13 @@ describe Grape::API do
1771
1787
  end
1772
1788
 
1773
1789
  get '/new/abc'
1774
- expect(last_response.status).to eql 404
1790
+ expect(last_response.status).to be 404
1775
1791
  get '/legacy/abc'
1776
- expect(last_response.status).to eql 200
1792
+ expect(last_response.status).to be 200
1777
1793
  get '/legacy/def'
1778
- expect(last_response.status).to eql 404
1794
+ expect(last_response.status).to be 404
1779
1795
  get '/new/def'
1780
- expect(last_response.status).to eql 200
1796
+ expect(last_response.status).to be 200
1781
1797
  end
1782
1798
  end
1783
1799
 
@@ -1997,8 +2013,8 @@ describe Grape::API do
1997
2013
  end
1998
2014
 
1999
2015
  context 'with multiple apis' do
2000
- let(:a) { Class.new(Grape::API) }
2001
- let(:b) { Class.new(Grape::API) }
2016
+ let(:a) { Class.new(described_class) }
2017
+ let(:b) { Class.new(described_class) }
2002
2018
 
2003
2019
  before do
2004
2020
  a.helpers do
@@ -2032,7 +2048,7 @@ describe Grape::API do
2032
2048
  raise 'rain!'
2033
2049
  end
2034
2050
  get '/exception'
2035
- expect(last_response.status).to eql 500
2051
+ expect(last_response.status).to be 500
2036
2052
  expect(last_response.body).to eq 'rain!'
2037
2053
  end
2038
2054
 
@@ -2044,7 +2060,7 @@ describe Grape::API do
2044
2060
  raise 'rain!'
2045
2061
  end
2046
2062
  get '/exception'
2047
- expect(last_response.status).to eql 500
2063
+ expect(last_response.status).to be 500
2048
2064
  expect(last_response.body).to eq({ error: 'rain!' }.to_json)
2049
2065
  end
2050
2066
 
@@ -2054,7 +2070,7 @@ describe Grape::API do
2054
2070
  subject.get('/unrescued') { raise 'beefcake' }
2055
2071
 
2056
2072
  get '/rescued'
2057
- expect(last_response.status).to eql 500
2073
+ expect(last_response.status).to be 500
2058
2074
 
2059
2075
  expect { get '/unrescued' }.to raise_error(RuntimeError, 'beefcake')
2060
2076
  end
@@ -2073,10 +2089,10 @@ describe Grape::API do
2073
2089
  subject.get('/standard_error') { raise StandardError }
2074
2090
 
2075
2091
  get '/child_of_standard_error'
2076
- expect(last_response.status).to eql 402
2092
+ expect(last_response.status).to be 402
2077
2093
 
2078
2094
  get '/standard_error'
2079
- expect(last_response.status).to eql 401
2095
+ expect(last_response.status).to be 401
2080
2096
  end
2081
2097
 
2082
2098
  context 'CustomError subclass of Grape::Exceptions::Base' do
@@ -2117,7 +2133,7 @@ describe Grape::API do
2117
2133
  subject.get('/formatter_exception') { 'Hello world' }
2118
2134
 
2119
2135
  get '/formatter_exception'
2120
- expect(last_response.status).to eql 500
2136
+ expect(last_response.status).to be 500
2121
2137
  expect(last_response.body).to eq('Formatter Error')
2122
2138
  end
2123
2139
 
@@ -2127,7 +2143,7 @@ describe Grape::API do
2127
2143
 
2128
2144
  expect_any_instance_of(Grape::Middleware::Error).to receive(:default_rescue_handler).and_call_original
2129
2145
  get '/'
2130
- expect(last_response.status).to eql 500
2146
+ expect(last_response.status).to be 500
2131
2147
  expect(last_response.body).to eql 'Invalid response'
2132
2148
  end
2133
2149
  end
@@ -2141,7 +2157,7 @@ describe Grape::API do
2141
2157
  raise 'rain!'
2142
2158
  end
2143
2159
  get '/exception'
2144
- expect(last_response.status).to eql 202
2160
+ expect(last_response.status).to be 202
2145
2161
  expect(last_response.body).to eq('rescued from rain!')
2146
2162
  end
2147
2163
 
@@ -2162,9 +2178,10 @@ describe Grape::API do
2162
2178
  raise ConnectionError
2163
2179
  end
2164
2180
  get '/exception'
2165
- expect(last_response.status).to eql 500
2181
+ expect(last_response.status).to be 500
2166
2182
  expect(last_response.body).to eq('rescued from ConnectionError')
2167
2183
  end
2184
+
2168
2185
  it 'rescues a specific error' do
2169
2186
  subject.rescue_from ConnectionError do |e|
2170
2187
  rack_response("rescued from #{e.class.name}", 500)
@@ -2173,9 +2190,10 @@ describe Grape::API do
2173
2190
  raise ConnectionError
2174
2191
  end
2175
2192
  get '/exception'
2176
- expect(last_response.status).to eql 500
2193
+ expect(last_response.status).to be 500
2177
2194
  expect(last_response.body).to eq('rescued from ConnectionError')
2178
2195
  end
2196
+
2179
2197
  it 'rescues a subclass of an error by default' do
2180
2198
  subject.rescue_from RuntimeError do |e|
2181
2199
  rack_response("rescued from #{e.class.name}", 500)
@@ -2184,9 +2202,10 @@ describe Grape::API do
2184
2202
  raise ConnectionError
2185
2203
  end
2186
2204
  get '/exception'
2187
- expect(last_response.status).to eql 500
2205
+ expect(last_response.status).to be 500
2188
2206
  expect(last_response.body).to eq('rescued from ConnectionError')
2189
2207
  end
2208
+
2190
2209
  it 'rescues multiple specific errors' do
2191
2210
  subject.rescue_from ConnectionError do |e|
2192
2211
  rack_response("rescued from #{e.class.name}", 500)
@@ -2201,12 +2220,13 @@ describe Grape::API do
2201
2220
  raise DatabaseError
2202
2221
  end
2203
2222
  get '/connection'
2204
- expect(last_response.status).to eql 500
2223
+ expect(last_response.status).to be 500
2205
2224
  expect(last_response.body).to eq('rescued from ConnectionError')
2206
2225
  get '/database'
2207
- expect(last_response.status).to eql 500
2226
+ expect(last_response.status).to be 500
2208
2227
  expect(last_response.body).to eq('rescued from DatabaseError')
2209
2228
  end
2229
+
2210
2230
  it 'does not rescue a different error' do
2211
2231
  subject.rescue_from RuntimeError do |e|
2212
2232
  rack_response("rescued from #{e.class.name}", 500)
@@ -2272,7 +2292,7 @@ describe Grape::API do
2272
2292
  subject.rescue_from :all, with: :not_exist_method
2273
2293
  subject.get('/rescue_method') { raise StandardError }
2274
2294
 
2275
- expect { get '/rescue_method' }.to raise_error(NoMethodError, 'undefined method `not_exist_method\'')
2295
+ expect { get '/rescue_method' }.to raise_error(NoMethodError, /^undefined method `not_exist_method'/)
2276
2296
  end
2277
2297
 
2278
2298
  it 'correctly chooses exception handler if :all handler is specified' do
@@ -2327,9 +2347,9 @@ describe Grape::API do
2327
2347
  end
2328
2348
 
2329
2349
  get '/caught_child'
2330
- expect(last_response.status).to eql 500
2350
+ expect(last_response.status).to be 500
2331
2351
  get '/caught_parent'
2332
- expect(last_response.status).to eql 500
2352
+ expect(last_response.status).to be 500
2333
2353
  expect { get '/uncaught_parent' }.to raise_error(StandardError)
2334
2354
  end
2335
2355
 
@@ -2342,7 +2362,7 @@ describe Grape::API do
2342
2362
  end
2343
2363
 
2344
2364
  get '/caught_child'
2345
- expect(last_response.status).to eql 500
2365
+ expect(last_response.status).to be 500
2346
2366
  end
2347
2367
 
2348
2368
  it 'does not rescue child errors if rescue_subclasses is false' do
@@ -2437,7 +2457,7 @@ describe Grape::API do
2437
2457
  end
2438
2458
 
2439
2459
  context 'class' do
2440
- before :each do
2460
+ before do
2441
2461
  module ApiSpec
2442
2462
  class CustomErrorFormatter
2443
2463
  def self.call(message, _backtrace, _options, _env, _original_exception)
@@ -2446,6 +2466,7 @@ describe Grape::API do
2446
2466
  end
2447
2467
  end
2448
2468
  end
2469
+
2449
2470
  it 'returns a custom error format' do
2450
2471
  subject.rescue_from :all, backtrace: true
2451
2472
  subject.error_formatter :txt, ApiSpec::CustomErrorFormatter
@@ -2459,7 +2480,7 @@ describe Grape::API do
2459
2480
 
2460
2481
  describe 'with' do
2461
2482
  context 'class' do
2462
- before :each do
2483
+ before do
2463
2484
  module ApiSpec
2464
2485
  class CustomErrorFormatter
2465
2486
  def self.call(message, _backtrace, _option, _env, _original_exception)
@@ -2489,6 +2510,7 @@ describe Grape::API do
2489
2510
  get '/exception'
2490
2511
  expect(last_response.body).to eql '{"error":"rain!"}'
2491
2512
  end
2513
+
2492
2514
  it 'rescues all errors and return :json with backtrace' do
2493
2515
  subject.rescue_from :all, backtrace: true
2494
2516
  subject.format :json
@@ -2500,6 +2522,7 @@ describe Grape::API do
2500
2522
  expect(json['error']).to eql 'rain!'
2501
2523
  expect(json['backtrace'].length).to be > 0
2502
2524
  end
2525
+
2503
2526
  it 'rescues error! and return txt' do
2504
2527
  subject.format :txt
2505
2528
  subject.get '/error' do
@@ -2508,23 +2531,26 @@ describe Grape::API do
2508
2531
  get '/error'
2509
2532
  expect(last_response.body).to eql 'Access Denied'
2510
2533
  end
2534
+
2511
2535
  context 'with json format' do
2512
2536
  before { subject.format :json }
2513
2537
 
2538
+ after do
2539
+ get '/error'
2540
+ expect(last_response.body).to eql('{"error":"failure"}')
2541
+ end
2542
+
2514
2543
  it 'rescues error! called with a string and returns json' do
2515
2544
  subject.get('/error') { error!(:failure, 401) }
2516
2545
  end
2546
+
2517
2547
  it 'rescues error! called with a symbol and returns json' do
2518
2548
  subject.get('/error') { error!(:failure, 401) }
2519
2549
  end
2550
+
2520
2551
  it 'rescues error! called with a hash and returns json' do
2521
2552
  subject.get('/error') { error!({ error: :failure }, 401) }
2522
2553
  end
2523
-
2524
- after do
2525
- get '/error'
2526
- expect(last_response.body).to eql('{"error":"failure"}')
2527
- end
2528
2554
  end
2529
2555
  end
2530
2556
 
@@ -2537,6 +2563,7 @@ describe Grape::API do
2537
2563
  get '/excel.xls'
2538
2564
  expect(last_response.content_type).to eq('application/vnd.ms-excel')
2539
2565
  end
2566
+
2540
2567
  it 'allows to override content-type' do
2541
2568
  subject.get :content do
2542
2569
  content_type 'text/javascript'
@@ -2545,6 +2572,7 @@ describe Grape::API do
2545
2572
  get '/content'
2546
2573
  expect(last_response.content_type).to eq('text/javascript')
2547
2574
  end
2575
+
2548
2576
  it 'removes existing content types' do
2549
2577
  subject.content_type :xls, 'application/vnd.ms-excel'
2550
2578
  subject.get :excel do
@@ -2562,24 +2590,27 @@ describe Grape::API do
2562
2590
 
2563
2591
  describe '.formatter' do
2564
2592
  context 'multiple formatters' do
2565
- before :each do
2593
+ before do
2566
2594
  subject.formatter :json, ->(object, _env) { "{\"custom_formatter\":\"#{object[:some]}\"}" }
2567
2595
  subject.formatter :txt, ->(object, _env) { "custom_formatter: #{object[:some]}" }
2568
2596
  subject.get :simple do
2569
2597
  { some: 'hash' }
2570
2598
  end
2571
2599
  end
2600
+
2572
2601
  it 'sets one formatter' do
2573
2602
  get '/simple.json'
2574
2603
  expect(last_response.body).to eql '{"custom_formatter":"hash"}'
2575
2604
  end
2605
+
2576
2606
  it 'sets another formatter' do
2577
2607
  get '/simple.txt'
2578
2608
  expect(last_response.body).to eql 'custom_formatter: hash'
2579
2609
  end
2580
2610
  end
2611
+
2581
2612
  context 'custom formatter' do
2582
- before :each do
2613
+ before do
2583
2614
  subject.content_type :json, 'application/json'
2584
2615
  subject.content_type :custom, 'application/custom'
2585
2616
  subject.formatter :custom, ->(object, _env) { "{\"custom_formatter\":\"#{object[:some]}\"}" }
@@ -2587,15 +2618,18 @@ describe Grape::API do
2587
2618
  { some: 'hash' }
2588
2619
  end
2589
2620
  end
2621
+
2590
2622
  it 'uses json' do
2591
2623
  get '/simple.json'
2592
2624
  expect(last_response.body).to eql '{"some":"hash"}'
2593
2625
  end
2626
+
2594
2627
  it 'uses custom formatter' do
2595
2628
  get '/simple.custom', 'HTTP_ACCEPT' => 'application/custom'
2596
2629
  expect(last_response.body).to eql '{"custom_formatter":"hash"}'
2597
2630
  end
2598
2631
  end
2632
+
2599
2633
  context 'custom formatter class' do
2600
2634
  module ApiSpec
2601
2635
  module CustomFormatter
@@ -2604,7 +2638,7 @@ describe Grape::API do
2604
2638
  end
2605
2639
  end
2606
2640
  end
2607
- before :each do
2641
+ before do
2608
2642
  subject.content_type :json, 'application/json'
2609
2643
  subject.content_type :custom, 'application/custom'
2610
2644
  subject.formatter :custom, ApiSpec::CustomFormatter
@@ -2612,10 +2646,12 @@ describe Grape::API do
2612
2646
  { some: 'hash' }
2613
2647
  end
2614
2648
  end
2649
+
2615
2650
  it 'uses json' do
2616
2651
  get '/simple.json'
2617
2652
  expect(last_response.body).to eql '{"some":"hash"}'
2618
2653
  end
2654
+
2619
2655
  it 'uses custom formatter' do
2620
2656
  get '/simple.custom', 'HTTP_ACCEPT' => 'application/custom'
2621
2657
  expect(last_response.body).to eql '{"custom_formatter":"hash"}'
@@ -2633,8 +2669,9 @@ describe Grape::API do
2633
2669
  expect(last_response.status).to eq(201)
2634
2670
  expect(last_response.body).to eq('{"x":42}')
2635
2671
  end
2672
+
2636
2673
  context 'lambda parser' do
2637
- before :each do
2674
+ before do
2638
2675
  subject.content_type :txt, 'text/plain'
2639
2676
  subject.content_type :custom, 'text/custom'
2640
2677
  subject.parser :custom, ->(object, _env) { { object.to_sym => object.to_s.reverse } }
@@ -2642,6 +2679,7 @@ describe Grape::API do
2642
2679
  params[:simple]
2643
2680
  end
2644
2681
  end
2682
+
2645
2683
  ['text/custom', 'text/custom; charset=UTF-8'].each do |content_type|
2646
2684
  it "uses parser for #{content_type}" do
2647
2685
  put '/simple', 'simple', 'CONTENT_TYPE' => content_type
@@ -2650,6 +2688,7 @@ describe Grape::API do
2650
2688
  end
2651
2689
  end
2652
2690
  end
2691
+
2653
2692
  context 'custom parser class' do
2654
2693
  module ApiSpec
2655
2694
  module CustomParser
@@ -2658,7 +2697,7 @@ describe Grape::API do
2658
2697
  end
2659
2698
  end
2660
2699
  end
2661
- before :each do
2700
+ before do
2662
2701
  subject.content_type :txt, 'text/plain'
2663
2702
  subject.content_type :custom, 'text/custom'
2664
2703
  subject.parser :custom, ApiSpec::CustomParser
@@ -2666,12 +2705,14 @@ describe Grape::API do
2666
2705
  params[:simple]
2667
2706
  end
2668
2707
  end
2708
+
2669
2709
  it 'uses custom parser' do
2670
2710
  put '/simple', 'simple', 'CONTENT_TYPE' => 'text/custom'
2671
2711
  expect(last_response.status).to eq(200)
2672
2712
  expect(last_response.body).to eql 'elpmis'
2673
2713
  end
2674
2714
  end
2715
+
2675
2716
  if Object.const_defined? :MultiXml
2676
2717
  context 'multi_xml' do
2677
2718
  it "doesn't parse yaml" do
@@ -2696,12 +2737,13 @@ describe Grape::API do
2696
2737
  end
2697
2738
  end
2698
2739
  context 'none parser class' do
2699
- before :each do
2740
+ before do
2700
2741
  subject.parser :json, nil
2701
2742
  subject.put 'data' do
2702
2743
  "body: #{env['api.request.body']}"
2703
2744
  end
2704
2745
  end
2746
+
2705
2747
  it 'does not parse data' do
2706
2748
  put '/data', 'not valid json', 'CONTENT_TYPE' => 'application/json'
2707
2749
  expect(last_response.status).to eq(200)
@@ -2711,10 +2753,11 @@ describe Grape::API do
2711
2753
  end
2712
2754
 
2713
2755
  describe '.default_format' do
2714
- before :each do
2756
+ before do
2715
2757
  subject.format :json
2716
2758
  subject.default_format :json
2717
2759
  end
2760
+
2718
2761
  it 'returns data in default format' do
2719
2762
  subject.get '/data' do
2720
2763
  { x: 42 }
@@ -2723,6 +2766,7 @@ describe Grape::API do
2723
2766
  expect(last_response.status).to eq(200)
2724
2767
  expect(last_response.body).to eq('{"x":42}')
2725
2768
  end
2769
+
2726
2770
  it 'parses data in default format' do
2727
2771
  subject.post '/data' do
2728
2772
  { x: params[:x] }
@@ -2741,16 +2785,18 @@ describe Grape::API do
2741
2785
  raise 'rain!'
2742
2786
  end
2743
2787
  get '/exception'
2744
- expect(last_response.status).to eql 200
2788
+ expect(last_response.status).to be 200
2745
2789
  end
2790
+
2746
2791
  it 'has a default error status' do
2747
2792
  subject.rescue_from :all
2748
2793
  subject.get '/exception' do
2749
2794
  raise 'rain!'
2750
2795
  end
2751
2796
  get '/exception'
2752
- expect(last_response.status).to eql 500
2797
+ expect(last_response.status).to be 500
2753
2798
  end
2799
+
2754
2800
  it 'uses the default error status in error!' do
2755
2801
  subject.rescue_from :all
2756
2802
  subject.default_error_status 400
@@ -2758,7 +2804,7 @@ describe Grape::API do
2758
2804
  error! 'rain!'
2759
2805
  end
2760
2806
  get '/exception'
2761
- expect(last_response.status).to eql 400
2807
+ expect(last_response.status).to be 400
2762
2808
  end
2763
2809
  end
2764
2810
 
@@ -2784,7 +2830,7 @@ describe Grape::API do
2784
2830
  end
2785
2831
 
2786
2832
  get '/exception'
2787
- expect(last_response.status).to eql 408
2833
+ expect(last_response.status).to be 408
2788
2834
  expect(last_response.body).to eql({ code: 408, static: 'some static text' }.to_json)
2789
2835
  end
2790
2836
 
@@ -2795,7 +2841,7 @@ describe Grape::API do
2795
2841
  end
2796
2842
 
2797
2843
  get '/exception'
2798
- expect(last_response.status).to eql 408
2844
+ expect(last_response.status).to be 408
2799
2845
  expect(last_response.body).to eql({ code: 408, static: 'some static text' }.to_json)
2800
2846
  end
2801
2847
  end
@@ -2806,12 +2852,14 @@ describe Grape::API do
2806
2852
  expect(subject.routes).to eq([])
2807
2853
  end
2808
2854
  end
2855
+
2809
2856
  describe 'single method api structure' do
2810
- before(:each) do
2857
+ before do
2811
2858
  subject.get :ping do
2812
2859
  'pong'
2813
2860
  end
2814
2861
  end
2862
+
2815
2863
  it 'returns one route' do
2816
2864
  expect(subject.routes.size).to eq(1)
2817
2865
  route = subject.routes[0]
@@ -2820,8 +2868,9 @@ describe Grape::API do
2820
2868
  expect(route.request_method).to eq('GET')
2821
2869
  end
2822
2870
  end
2871
+
2823
2872
  describe 'api structure with two versions and a namespace' do
2824
- before :each do
2873
+ before do
2825
2874
  subject.version 'v1', using: :path
2826
2875
  subject.get 'version' do
2827
2876
  api.version
@@ -2837,30 +2886,37 @@ describe Grape::API do
2837
2886
  end
2838
2887
  end
2839
2888
  end
2889
+
2840
2890
  it 'returns the latest version set' do
2841
2891
  expect(subject.version).to eq('v2')
2842
2892
  end
2893
+
2843
2894
  it 'returns versions' do
2844
2895
  expect(subject.versions).to eq(%w[v1 v2])
2845
2896
  end
2897
+
2846
2898
  it 'sets route paths' do
2847
2899
  expect(subject.routes.size).to be >= 2
2848
2900
  expect(subject.routes[0].path).to eq('/:version/version(.:format)')
2849
2901
  expect(subject.routes[1].path).to eq('/p/:version/n1/n2/version(.:format)')
2850
2902
  end
2903
+
2851
2904
  it 'sets route versions' do
2852
2905
  expect(subject.routes[0].version).to eq('v1')
2853
2906
  expect(subject.routes[1].version).to eq('v2')
2854
2907
  end
2908
+
2855
2909
  it 'sets a nested namespace' do
2856
2910
  expect(subject.routes[1].namespace).to eq('/n1/n2')
2857
2911
  end
2912
+
2858
2913
  it 'sets prefix' do
2859
2914
  expect(subject.routes[1].prefix).to eq('p')
2860
2915
  end
2861
2916
  end
2917
+
2862
2918
  describe 'api structure with additional parameters' do
2863
- before(:each) do
2919
+ before do
2864
2920
  subject.params do
2865
2921
  requires :token, desc: 'a token'
2866
2922
  optional :limit, desc: 'the limit'
@@ -2869,14 +2925,17 @@ describe Grape::API do
2869
2925
  params[:string].split(params[:token], (params[:limit] || 0).to_i)
2870
2926
  end
2871
2927
  end
2928
+
2872
2929
  it 'splits a string' do
2873
2930
  get '/split/a,b,c.json', token: ','
2874
2931
  expect(last_response.body).to eq('["a","b","c"]')
2875
2932
  end
2933
+
2876
2934
  it 'splits a string with limit' do
2877
2935
  get '/split/a,b,c.json', token: ',', limit: '2'
2878
2936
  expect(last_response.body).to eq('["a","b,c"]')
2879
2937
  end
2938
+
2880
2939
  it 'sets params' do
2881
2940
  expect(subject.routes.map do |route|
2882
2941
  { params: route.params }
@@ -2891,8 +2950,9 @@ describe Grape::API do
2891
2950
  ]
2892
2951
  end
2893
2952
  end
2953
+
2894
2954
  describe 'api structure with multiple apis' do
2895
- before(:each) do
2955
+ before do
2896
2956
  subject.params do
2897
2957
  requires :one, desc: 'a token'
2898
2958
  optional :two, desc: 'the limit'
@@ -2907,6 +2967,7 @@ describe Grape::API do
2907
2967
  subject.get 'two' do
2908
2968
  end
2909
2969
  end
2970
+
2910
2971
  it 'sets params' do
2911
2972
  expect(subject.routes.map do |route|
2912
2973
  { params: route.params }
@@ -2926,8 +2987,9 @@ describe Grape::API do
2926
2987
  ]
2927
2988
  end
2928
2989
  end
2990
+
2929
2991
  describe 'api structure with an api without params' do
2930
- before(:each) do
2992
+ before do
2931
2993
  subject.params do
2932
2994
  requires :one, desc: 'a token'
2933
2995
  optional :two, desc: 'the limit'
@@ -2938,6 +3000,7 @@ describe Grape::API do
2938
3000
  subject.get 'two' do
2939
3001
  end
2940
3002
  end
3003
+
2941
3004
  it 'sets params' do
2942
3005
  expect(subject.routes.map do |route|
2943
3006
  { params: route.params }
@@ -2954,17 +3017,20 @@ describe Grape::API do
2954
3017
  ]
2955
3018
  end
2956
3019
  end
3020
+
2957
3021
  describe 'api with a custom route setting' do
2958
- before(:each) do
3022
+ before do
2959
3023
  subject.route_setting :custom, key: 'value'
2960
3024
  subject.get 'one'
2961
3025
  end
3026
+
2962
3027
  it 'exposed' do
2963
3028
  expect(subject.routes.count).to eq 1
2964
3029
  route = subject.routes.first
2965
3030
  expect(route.settings[:custom]).to eq(key: 'value')
2966
3031
  end
2967
3032
  end
3033
+
2968
3034
  describe 'status' do
2969
3035
  it 'can be set to arbitrary Integer value' do
2970
3036
  subject.get '/foo' do
@@ -2973,6 +3039,7 @@ describe Grape::API do
2973
3039
  get '/foo'
2974
3040
  expect(last_response.status).to eq 210
2975
3041
  end
3042
+
2976
3043
  it 'can be set with a status code symbol' do
2977
3044
  subject.get '/foo' do
2978
3045
  status :see_other
@@ -2987,10 +3054,12 @@ describe Grape::API do
2987
3054
  it 'empty array of routes' do
2988
3055
  expect(subject.routes).to eq([])
2989
3056
  end
3057
+
2990
3058
  it 'empty array of routes' do
2991
3059
  subject.desc 'grape api'
2992
3060
  expect(subject.routes).to eq([])
2993
3061
  end
3062
+
2994
3063
  it 'describes a method' do
2995
3064
  subject.desc 'first method'
2996
3065
  subject.get :first
@@ -3001,6 +3070,7 @@ describe Grape::API do
3001
3070
  expect(route.params).to eq({})
3002
3071
  expect(route.options).to be_a_kind_of(Hash)
3003
3072
  end
3073
+
3004
3074
  it 'has params which does not include format and version as named captures' do
3005
3075
  subject.version :v1, using: :path
3006
3076
  subject.get :first
@@ -3008,6 +3078,7 @@ describe Grape::API do
3008
3078
  expect(param_keys).not_to include('format')
3009
3079
  expect(param_keys).not_to include('version')
3010
3080
  end
3081
+
3011
3082
  it 'describes methods separately' do
3012
3083
  subject.desc 'first method'
3013
3084
  subject.get :first
@@ -3021,6 +3092,7 @@ describe Grape::API do
3021
3092
  { description: 'second method', params: {} }
3022
3093
  ]
3023
3094
  end
3095
+
3024
3096
  it 'resets desc' do
3025
3097
  subject.desc 'first method'
3026
3098
  subject.get :first
@@ -3032,6 +3104,7 @@ describe Grape::API do
3032
3104
  { description: nil, params: {} }
3033
3105
  ]
3034
3106
  end
3107
+
3035
3108
  it 'namespaces and describe arbitrary parameters' do
3036
3109
  subject.namespace 'ns' do
3037
3110
  desc 'ns second', foo: 'bar'
@@ -3043,6 +3116,7 @@ describe Grape::API do
3043
3116
  { description: 'ns second', foo: 'bar', params: {} }
3044
3117
  ]
3045
3118
  end
3119
+
3046
3120
  it 'includes details' do
3047
3121
  subject.desc 'method', details: 'method details'
3048
3122
  subject.get 'method'
@@ -3052,6 +3126,7 @@ describe Grape::API do
3052
3126
  { description: 'method', details: 'method details', params: {} }
3053
3127
  ]
3054
3128
  end
3129
+
3055
3130
  it 'describes a method with parameters' do
3056
3131
  subject.desc 'Reverses a string.', params: { 's' => { desc: 'string to reverse', type: 'string' } }
3057
3132
  subject.get 'reverse' do
@@ -3063,6 +3138,7 @@ describe Grape::API do
3063
3138
  { description: 'Reverses a string.', params: { 's' => { desc: 'string to reverse', type: 'string' } } }
3064
3139
  ]
3065
3140
  end
3141
+
3066
3142
  it 'does not inherit param descriptions in consequent namespaces' do
3067
3143
  subject.desc 'global description'
3068
3144
  subject.params do
@@ -3093,6 +3169,7 @@ describe Grape::API do
3093
3169
  } }
3094
3170
  ]
3095
3171
  end
3172
+
3096
3173
  it 'merges the parameters of the namespace with the parameters of the method' do
3097
3174
  subject.desc 'namespace'
3098
3175
  subject.params do
@@ -3117,6 +3194,7 @@ describe Grape::API do
3117
3194
  } }
3118
3195
  ]
3119
3196
  end
3197
+
3120
3198
  it 'merges the parameters of nested namespaces' do
3121
3199
  subject.desc 'ns1'
3122
3200
  subject.params do
@@ -3149,6 +3227,7 @@ describe Grape::API do
3149
3227
  } }
3150
3228
  ]
3151
3229
  end
3230
+
3152
3231
  it 'groups nested params and prevents overwriting of params with same name in different groups' do
3153
3232
  subject.desc 'method'
3154
3233
  subject.params do
@@ -3172,6 +3251,7 @@ describe Grape::API do
3172
3251
  'group2[param2]' => { required: true, desc: 'group2 param2 desc' }
3173
3252
  }]
3174
3253
  end
3254
+
3175
3255
  it 'uses full name of parameters in nested groups' do
3176
3256
  subject.desc 'nesting'
3177
3257
  subject.params do
@@ -3192,6 +3272,7 @@ describe Grape::API do
3192
3272
  } }
3193
3273
  ]
3194
3274
  end
3275
+
3195
3276
  it 'allows to set the type attribute on :group element' do
3196
3277
  subject.params do
3197
3278
  group :foo, type: Array do
@@ -3199,6 +3280,7 @@ describe Grape::API do
3199
3280
  end
3200
3281
  end
3201
3282
  end
3283
+
3202
3284
  it 'parses parameters when no description is given' do
3203
3285
  subject.params do
3204
3286
  requires :one_param, desc: 'one param'
@@ -3210,6 +3292,7 @@ describe Grape::API do
3210
3292
  { description: nil, params: { 'one_param' => { required: true, desc: 'one param' } } }
3211
3293
  ]
3212
3294
  end
3295
+
3213
3296
  it 'does not symbolize params' do
3214
3297
  subject.desc 'Reverses a string.', params: { 's' => { desc: 'string to reverse', type: 'string' } }
3215
3298
  subject.get 'reverse/:s' do
@@ -3268,7 +3351,7 @@ describe Grape::API do
3268
3351
  subject.version 'v1', using: :path
3269
3352
 
3270
3353
  subject.namespace :cool do
3271
- app = Class.new(Grape::API)
3354
+ app = Class.new(Grape::API) # rubocop:disable RSpec/DescribedClass
3272
3355
  app.get('/awesome') do
3273
3356
  'yo'
3274
3357
  end
@@ -3284,12 +3367,12 @@ describe Grape::API do
3284
3367
  subject.version 'v1', using: :path
3285
3368
 
3286
3369
  subject.namespace :cool do
3287
- inner_app = Class.new(Grape::API)
3370
+ inner_app = Class.new(Grape::API) # rubocop:disable RSpec/DescribedClass
3288
3371
  inner_app.get('/awesome') do
3289
3372
  'yo'
3290
3373
  end
3291
3374
 
3292
- app = Class.new(Grape::API)
3375
+ app = Class.new(Grape::API) # rubocop:disable RSpec/DescribedClass
3293
3376
  app.mount inner_app
3294
3377
  mount app
3295
3378
  end
@@ -3304,7 +3387,7 @@ describe Grape::API do
3304
3387
  rack_response("rescued from #{e.message}", 202)
3305
3388
  end
3306
3389
 
3307
- app = Class.new(Grape::API)
3390
+ app = Class.new(described_class)
3308
3391
 
3309
3392
  subject.namespace :mounted do
3310
3393
  app.rescue_from ArgumentError
@@ -3313,15 +3396,16 @@ describe Grape::API do
3313
3396
  end
3314
3397
 
3315
3398
  get '/mounted/fail'
3316
- expect(last_response.status).to eql 202
3399
+ expect(last_response.status).to be 202
3317
3400
  expect(last_response.body).to eq('rescued from doh!')
3318
3401
  end
3402
+
3319
3403
  it 'prefers rescues defined by mounted if they rescue similar error class' do
3320
3404
  subject.rescue_from StandardError do
3321
3405
  rack_response('outer rescue')
3322
3406
  end
3323
3407
 
3324
- app = Class.new(Grape::API)
3408
+ app = Class.new(described_class)
3325
3409
 
3326
3410
  subject.namespace :mounted do
3327
3411
  rescue_from StandardError do
@@ -3334,12 +3418,13 @@ describe Grape::API do
3334
3418
  get '/mounted/fail'
3335
3419
  expect(last_response.body).to eq('inner rescue')
3336
3420
  end
3421
+
3337
3422
  it 'prefers rescues defined by mounted even if outer is more specific' do
3338
3423
  subject.rescue_from ArgumentError do
3339
3424
  rack_response('outer rescue')
3340
3425
  end
3341
3426
 
3342
- app = Class.new(Grape::API)
3427
+ app = Class.new(described_class)
3343
3428
 
3344
3429
  subject.namespace :mounted do
3345
3430
  rescue_from StandardError do
@@ -3352,12 +3437,13 @@ describe Grape::API do
3352
3437
  get '/mounted/fail'
3353
3438
  expect(last_response.body).to eq('inner rescue')
3354
3439
  end
3440
+
3355
3441
  it 'prefers more specific rescues defined by mounted' do
3356
3442
  subject.rescue_from StandardError do
3357
3443
  rack_response('outer rescue')
3358
3444
  end
3359
3445
 
3360
- app = Class.new(Grape::API)
3446
+ app = Class.new(described_class)
3361
3447
 
3362
3448
  subject.namespace :mounted do
3363
3449
  rescue_from ArgumentError do
@@ -3374,7 +3460,7 @@ describe Grape::API do
3374
3460
 
3375
3461
  it 'collects the routes of the mounted api' do
3376
3462
  subject.namespace :cool do
3377
- app = Class.new(Grape::API)
3463
+ app = Class.new(Grape::API) # rubocop:disable RSpec/DescribedClass
3378
3464
  app.get('/awesome') {}
3379
3465
  app.post('/sauce') {}
3380
3466
  mount app
@@ -3386,7 +3472,7 @@ describe Grape::API do
3386
3472
 
3387
3473
  it 'mounts on a path' do
3388
3474
  subject.namespace :cool do
3389
- app = Class.new(Grape::API)
3475
+ app = Class.new(Grape::API) # rubocop:disable RSpec/DescribedClass
3390
3476
  app.get '/awesome' do
3391
3477
  'sauce'
3392
3478
  end
@@ -3398,8 +3484,8 @@ describe Grape::API do
3398
3484
  end
3399
3485
 
3400
3486
  it 'mounts on a nested path' do
3401
- APP1 = Class.new(Grape::API)
3402
- APP2 = Class.new(Grape::API)
3487
+ APP1 = Class.new(described_class)
3488
+ APP2 = Class.new(described_class)
3403
3489
  APP2.get '/nice' do
3404
3490
  'play'
3405
3491
  end
@@ -3415,7 +3501,7 @@ describe Grape::API do
3415
3501
  end
3416
3502
 
3417
3503
  it 'responds to options' do
3418
- app = Class.new(Grape::API)
3504
+ app = Class.new(described_class)
3419
3505
  app.get '/colour' do
3420
3506
  'red'
3421
3507
  end
@@ -3429,21 +3515,21 @@ describe Grape::API do
3429
3515
  end
3430
3516
 
3431
3517
  get '/apples/colour'
3432
- expect(last_response.status).to eql 200
3518
+ expect(last_response.status).to be 200
3433
3519
  expect(last_response.body).to eq('red')
3434
3520
  options '/apples/colour'
3435
- expect(last_response.status).to eql 204
3521
+ expect(last_response.status).to be 204
3436
3522
  get '/apples/pears/colour'
3437
- expect(last_response.status).to eql 200
3523
+ expect(last_response.status).to be 200
3438
3524
  expect(last_response.body).to eq('green')
3439
3525
  options '/apples/pears/colour'
3440
- expect(last_response.status).to eql 204
3526
+ expect(last_response.status).to be 204
3441
3527
  end
3442
3528
 
3443
3529
  it 'responds to options with path versioning' do
3444
3530
  subject.version 'v1', using: :path
3445
3531
  subject.namespace :apples do
3446
- app = Class.new(Grape::API)
3532
+ app = Class.new(Grape::API) # rubocop:disable RSpec/DescribedClass
3447
3533
  app.get('/colour') do
3448
3534
  'red'
3449
3535
  end
@@ -3451,14 +3537,14 @@ describe Grape::API do
3451
3537
  end
3452
3538
 
3453
3539
  get '/v1/apples/colour'
3454
- expect(last_response.status).to eql 200
3540
+ expect(last_response.status).to be 200
3455
3541
  expect(last_response.body).to eq('red')
3456
3542
  options '/v1/apples/colour'
3457
- expect(last_response.status).to eql 204
3543
+ expect(last_response.status).to be 204
3458
3544
  end
3459
3545
 
3460
3546
  it 'mounts a versioned API with nested resources' do
3461
- api = Class.new(Grape::API) do
3547
+ api = Class.new(described_class) do
3462
3548
  version 'v1'
3463
3549
  resources :users do
3464
3550
  get :hello do
@@ -3473,7 +3559,7 @@ describe Grape::API do
3473
3559
  end
3474
3560
 
3475
3561
  it 'mounts a prefixed API with nested resources' do
3476
- api = Class.new(Grape::API) do
3562
+ api = Class.new(described_class) do
3477
3563
  prefix 'api'
3478
3564
  resources :users do
3479
3565
  get :hello do
@@ -3488,7 +3574,7 @@ describe Grape::API do
3488
3574
  end
3489
3575
 
3490
3576
  it 'applies format to a mounted API with nested resources' do
3491
- api = Class.new(Grape::API) do
3577
+ api = Class.new(described_class) do
3492
3578
  format :json
3493
3579
  resources :users do
3494
3580
  get do
@@ -3503,7 +3589,7 @@ describe Grape::API do
3503
3589
  end
3504
3590
 
3505
3591
  it 'applies auth to a mounted API with nested resources' do
3506
- api = Class.new(Grape::API) do
3592
+ api = Class.new(described_class) do
3507
3593
  format :json
3508
3594
  http_basic do |username, password|
3509
3595
  username == 'username' && password == 'password'
@@ -3524,7 +3610,7 @@ describe Grape::API do
3524
3610
  end
3525
3611
 
3526
3612
  it 'mounts multiple versioned APIs with nested resources' do
3527
- api1 = Class.new(Grape::API) do
3613
+ api1 = Class.new(described_class) do
3528
3614
  version 'one', using: :header, vendor: 'test'
3529
3615
  resources :users do
3530
3616
  get :hello do
@@ -3533,7 +3619,7 @@ describe Grape::API do
3533
3619
  end
3534
3620
  end
3535
3621
 
3536
- api2 = Class.new(Grape::API) do
3622
+ api2 = Class.new(described_class) do
3537
3623
  version 'two', using: :header, vendor: 'test'
3538
3624
  resources :users do
3539
3625
  get :hello do
@@ -3552,7 +3638,7 @@ describe Grape::API do
3552
3638
  end
3553
3639
 
3554
3640
  it 'recognizes potential versions with mounted path' do
3555
- a = Class.new(Grape::API) do
3641
+ a = Class.new(described_class) do
3556
3642
  version :v1, using: :path
3557
3643
 
3558
3644
  get '/hello' do
@@ -3560,7 +3646,7 @@ describe Grape::API do
3560
3646
  end
3561
3647
  end
3562
3648
 
3563
- b = Class.new(Grape::API) do
3649
+ b = Class.new(described_class) do
3564
3650
  version :v1, using: :path
3565
3651
 
3566
3652
  get '/world' do
@@ -3580,11 +3666,11 @@ describe Grape::API do
3580
3666
 
3581
3667
  context 'when mounting class extends a subclass of Grape::API' do
3582
3668
  it 'mounts APIs with the same superclass' do
3583
- base_api = Class.new(Grape::API)
3669
+ base_api = Class.new(described_class)
3584
3670
  a = Class.new(base_api)
3585
3671
  b = Class.new(base_api)
3586
3672
 
3587
- expect { a.mount b }.to_not raise_error
3673
+ expect { a.mount b }.not_to raise_error
3588
3674
  end
3589
3675
  end
3590
3676
 
@@ -3603,22 +3689,22 @@ describe Grape::API do
3603
3689
  end
3604
3690
  end
3605
3691
 
3606
- it 'should correctly include module in nested mount' do
3692
+ it 'correctlies include module in nested mount' do
3607
3693
  module_to_include = included_module
3608
- v1 = Class.new(Grape::API) do
3694
+ v1 = Class.new(described_class) do
3609
3695
  version :v1, using: :path
3610
3696
  include module_to_include
3611
3697
  my_method
3612
3698
  end
3613
- v2 = Class.new(Grape::API) do
3699
+ v2 = Class.new(described_class) do
3614
3700
  version :v2, using: :path
3615
3701
  end
3616
- segment_base = Class.new(Grape::API) do
3702
+ segment_base = Class.new(described_class) do
3617
3703
  mount v1
3618
3704
  mount v2
3619
3705
  end
3620
3706
 
3621
- Class.new(Grape::API) do
3707
+ Class.new(described_class) do
3622
3708
  mount segment_base
3623
3709
  end
3624
3710
 
@@ -3653,7 +3739,7 @@ describe Grape::API do
3653
3739
  end
3654
3740
 
3655
3741
  describe '.endpoint' do
3656
- before(:each) do
3742
+ before do
3657
3743
  subject.format :json
3658
3744
  subject.get '/endpoint/options' do
3659
3745
  {
@@ -3662,6 +3748,7 @@ describe Grape::API do
3662
3748
  }
3663
3749
  end
3664
3750
  end
3751
+
3665
3752
  it 'path' do
3666
3753
  get '/endpoint/options'
3667
3754
  options = ::Grape::Json.load(last_response.body)
@@ -3673,7 +3760,7 @@ describe Grape::API do
3673
3760
 
3674
3761
  describe '.route' do
3675
3762
  context 'plain' do
3676
- before(:each) do
3763
+ before do
3677
3764
  subject.get '/' do
3678
3765
  route.path
3679
3766
  end
@@ -3681,6 +3768,7 @@ describe Grape::API do
3681
3768
  route.path
3682
3769
  end
3683
3770
  end
3771
+
3684
3772
  it 'provides access to route info' do
3685
3773
  get '/'
3686
3774
  expect(last_response.body).to eq('/(.:format)')
@@ -3688,8 +3776,9 @@ describe Grape::API do
3688
3776
  expect(last_response.body).to eq('/path(.:format)')
3689
3777
  end
3690
3778
  end
3779
+
3691
3780
  context 'with desc' do
3692
- before(:each) do
3781
+ before do
3693
3782
  subject.desc 'returns description'
3694
3783
  subject.get '/description' do
3695
3784
  route.description
@@ -3699,82 +3788,98 @@ describe Grape::API do
3699
3788
  route.params[params[:id]]
3700
3789
  end
3701
3790
  end
3791
+
3702
3792
  it 'returns route description' do
3703
3793
  get '/description'
3704
3794
  expect(last_response.body).to eq('returns description')
3705
3795
  end
3796
+
3706
3797
  it 'returns route parameters' do
3707
3798
  get '/params/x'
3708
3799
  expect(last_response.body).to eq('y')
3709
3800
  end
3710
3801
  end
3711
3802
  end
3803
+
3712
3804
  describe '.format' do
3713
3805
  context ':txt' do
3714
- before(:each) do
3806
+ before do
3715
3807
  subject.format :txt
3716
3808
  subject.content_type :json, 'application/json'
3717
3809
  subject.get '/meaning_of_life' do
3718
3810
  { meaning_of_life: 42 }
3719
3811
  end
3720
3812
  end
3813
+
3721
3814
  it 'forces txt without an extension' do
3722
3815
  get '/meaning_of_life'
3723
3816
  expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s)
3724
3817
  end
3818
+
3725
3819
  it 'does not force txt with an extension' do
3726
3820
  get '/meaning_of_life.json'
3727
3821
  expect(last_response.body).to eq({ meaning_of_life: 42 }.to_json)
3728
3822
  end
3823
+
3729
3824
  it 'forces txt from a non-accepting header' do
3730
3825
  get '/meaning_of_life', {}, 'HTTP_ACCEPT' => 'application/json'
3731
3826
  expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s)
3732
3827
  end
3733
3828
  end
3829
+
3734
3830
  context ':txt only' do
3735
- before(:each) do
3831
+ before do
3736
3832
  subject.format :txt
3737
3833
  subject.get '/meaning_of_life' do
3738
3834
  { meaning_of_life: 42 }
3739
3835
  end
3740
3836
  end
3837
+
3741
3838
  it 'forces txt without an extension' do
3742
3839
  get '/meaning_of_life'
3743
3840
  expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s)
3744
3841
  end
3842
+
3745
3843
  it 'accepts specified extension' do
3746
3844
  get '/meaning_of_life.txt'
3747
3845
  expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s)
3748
3846
  end
3847
+
3749
3848
  it 'does not accept extensions other than specified' do
3750
3849
  get '/meaning_of_life.json'
3751
3850
  expect(last_response.status).to eq(404)
3752
3851
  end
3852
+
3753
3853
  it 'forces txt from a non-accepting header' do
3754
3854
  get '/meaning_of_life', {}, 'HTTP_ACCEPT' => 'application/json'
3755
3855
  expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s)
3756
3856
  end
3757
3857
  end
3858
+
3758
3859
  context ':json' do
3759
- before(:each) do
3860
+ before do
3760
3861
  subject.format :json
3761
3862
  subject.content_type :txt, 'text/plain'
3762
3863
  subject.get '/meaning_of_life' do
3763
3864
  { meaning_of_life: 42 }
3764
3865
  end
3765
3866
  end
3867
+
3766
3868
  it 'forces json without an extension' do
3767
3869
  get '/meaning_of_life'
3768
3870
  expect(last_response.body).to eq({ meaning_of_life: 42 }.to_json)
3769
3871
  end
3872
+
3770
3873
  it 'does not force json with an extension' do
3771
3874
  get '/meaning_of_life.txt'
3772
3875
  expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s)
3773
3876
  end
3877
+
3774
3878
  it 'forces json from a non-accepting header' do
3775
3879
  get '/meaning_of_life', {}, 'HTTP_ACCEPT' => 'text/html'
3776
3880
  expect(last_response.body).to eq({ meaning_of_life: 42 }.to_json)
3777
3881
  end
3882
+
3778
3883
  it 'can be overwritten with an explicit content type' do
3779
3884
  subject.get '/meaning_of_life_with_content_type' do
3780
3885
  content_type 'text/plain'
@@ -3783,6 +3888,7 @@ describe Grape::API do
3783
3888
  get '/meaning_of_life_with_content_type'
3784
3889
  expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s)
3785
3890
  end
3891
+
3786
3892
  it 'raised :error from middleware' do
3787
3893
  middleware = Class.new(Grape::Middleware::Base) do
3788
3894
  def before
@@ -3797,6 +3903,7 @@ describe Grape::API do
3797
3903
  expect(last_response.body).to eq({ error: 'Unauthorized' }.to_json)
3798
3904
  end
3799
3905
  end
3906
+
3800
3907
  context ':serializable_hash' do
3801
3908
  class SerializableHashExample
3802
3909
  def serializable_hash
@@ -3804,9 +3911,10 @@ describe Grape::API do
3804
3911
  end
3805
3912
  end
3806
3913
 
3807
- before(:each) do
3914
+ before do
3808
3915
  subject.format :serializable_hash
3809
3916
  end
3917
+
3810
3918
  it 'instance' do
3811
3919
  subject.get '/example' do
3812
3920
  SerializableHashExample.new
@@ -3814,6 +3922,7 @@ describe Grape::API do
3814
3922
  get '/example'
3815
3923
  expect(last_response.body).to eq('{"abc":"def"}')
3816
3924
  end
3925
+
3817
3926
  it 'root' do
3818
3927
  subject.get '/example' do
3819
3928
  { 'root' => SerializableHashExample.new }
@@ -3821,6 +3930,7 @@ describe Grape::API do
3821
3930
  get '/example'
3822
3931
  expect(last_response.body).to eq('{"root":{"abc":"def"}}')
3823
3932
  end
3933
+
3824
3934
  it 'array' do
3825
3935
  subject.get '/examples' do
3826
3936
  [SerializableHashExample.new, SerializableHashExample.new]
@@ -3829,10 +3939,12 @@ describe Grape::API do
3829
3939
  expect(last_response.body).to eq('[{"abc":"def"},{"abc":"def"}]')
3830
3940
  end
3831
3941
  end
3942
+
3832
3943
  context ':xml' do
3833
- before(:each) do
3944
+ before do
3834
3945
  subject.format :xml
3835
3946
  end
3947
+
3836
3948
  it 'string' do
3837
3949
  subject.get '/example' do
3838
3950
  'example'
@@ -3846,6 +3958,7 @@ describe Grape::API do
3846
3958
  </error>
3847
3959
  XML
3848
3960
  end
3961
+
3849
3962
  it 'hash' do
3850
3963
  subject.get '/example' do
3851
3964
  {
@@ -3863,6 +3976,7 @@ describe Grape::API do
3863
3976
  </hash>
3864
3977
  XML
3865
3978
  end
3979
+
3866
3980
  it 'array' do
3867
3981
  subject.get '/example' do
3868
3982
  %w[example1 example2]
@@ -3877,6 +3991,7 @@ describe Grape::API do
3877
3991
  </strings>
3878
3992
  XML
3879
3993
  end
3994
+
3880
3995
  it 'raised :error from middleware' do
3881
3996
  middleware = Class.new(Grape::Middleware::Base) do
3882
3997
  def before
@@ -3938,12 +4053,12 @@ describe Grape::API do
3938
4053
 
3939
4054
  context 'catch-all' do
3940
4055
  before do
3941
- api1 = Class.new(Grape::API)
4056
+ api1 = Class.new(described_class)
3942
4057
  api1.version 'v1', using: :path
3943
4058
  api1.get 'hello' do
3944
4059
  'v1'
3945
4060
  end
3946
- api2 = Class.new(Grape::API)
4061
+ api2 = Class.new(described_class)
3947
4062
  api2.version 'v2', using: :path
3948
4063
  api2.get 'hello' do
3949
4064
  'v2'
@@ -3951,6 +4066,7 @@ describe Grape::API do
3951
4066
  subject.mount api1
3952
4067
  subject.mount api2
3953
4068
  end
4069
+
3954
4070
  [true, false].each do |anchor|
3955
4071
  it "anchor=#{anchor}" do
3956
4072
  subject.route :any, '*path', anchor: anchor do
@@ -3983,6 +4099,7 @@ describe Grape::API do
3983
4099
  expect(last_response.status).to eq(404)
3984
4100
  expect(last_response.headers['X-Cascade']).to eq('pass')
3985
4101
  end
4102
+
3986
4103
  it 'does not cascade' do
3987
4104
  subject.version 'v2', using: :path, cascade: false
3988
4105
  get '/v2/hello'
@@ -3990,6 +4107,7 @@ describe Grape::API do
3990
4107
  expect(last_response.headers.keys).not_to include 'X-Cascade'
3991
4108
  end
3992
4109
  end
4110
+
3993
4111
  context 'via endpoint' do
3994
4112
  it 'cascades' do
3995
4113
  subject.cascade true
@@ -3997,6 +4115,7 @@ describe Grape::API do
3997
4115
  expect(last_response.status).to eq(404)
3998
4116
  expect(last_response.headers['X-Cascade']).to eq('pass')
3999
4117
  end
4118
+
4000
4119
  it 'does not cascade' do
4001
4120
  subject.cascade false
4002
4121
  get '/hello'
@@ -4046,12 +4165,14 @@ describe Grape::API do
4046
4165
  body false
4047
4166
  end
4048
4167
  end
4168
+
4049
4169
  it 'returns blank body' do
4050
4170
  get '/blank'
4051
4171
  expect(last_response.status).to eq(204)
4052
4172
  expect(last_response.body).to be_blank
4053
4173
  end
4054
4174
  end
4175
+
4055
4176
  context 'plain text' do
4056
4177
  before do
4057
4178
  subject.get '/text' do
@@ -4060,6 +4181,7 @@ describe Grape::API do
4060
4181
  'ignored'
4061
4182
  end
4062
4183
  end
4184
+
4063
4185
  it 'returns blank body' do
4064
4186
  get '/text'
4065
4187
  expect(last_response.status).to eq(200)
@@ -4069,7 +4191,7 @@ describe Grape::API do
4069
4191
  end
4070
4192
 
4071
4193
  describe 'normal class methods' do
4072
- subject(:grape_api) { Class.new(Grape::API) }
4194
+ subject(:grape_api) { Class.new(described_class) }
4073
4195
 
4074
4196
  before do
4075
4197
  stub_const('MyAPI', grape_api)
@@ -4089,7 +4211,7 @@ describe Grape::API do
4089
4211
  describe '.inherited' do
4090
4212
  context 'overriding within class' do
4091
4213
  let(:root_api) do
4092
- Class.new(Grape::API) do
4214
+ Class.new(described_class) do
4093
4215
  @bar = 'Hello, world'
4094
4216
 
4095
4217
  def self.inherited(child_api)
@@ -4115,7 +4237,7 @@ describe Grape::API do
4115
4237
  end
4116
4238
 
4117
4239
  let(:root_api) do
4118
- Class.new(Grape::API) do
4240
+ Class.new(described_class) do
4119
4241
  @bar = 'Hello, world'
4120
4242
  extend Inherited
4121
4243
  end
@@ -4130,9 +4252,10 @@ describe Grape::API do
4130
4252
  end
4131
4253
 
4132
4254
  describe 'const_missing' do
4133
- subject(:grape_api) { Class.new(Grape::API) }
4255
+ subject(:grape_api) { Class.new(described_class) }
4256
+
4134
4257
  let(:mounted) do
4135
- Class.new(Grape::API) do
4258
+ Class.new(described_class) do
4136
4259
  get '/missing' do
4137
4260
  SomeRandomConstant
4138
4261
  end
@@ -4147,6 +4270,12 @@ describe Grape::API do
4147
4270
  end
4148
4271
 
4149
4272
  describe 'custom route helpers on nested APIs' do
4273
+ subject(:grape_api) do
4274
+ Class.new(described_class) do
4275
+ version 'v1', using: :path
4276
+ end
4277
+ end
4278
+
4150
4279
  let(:shared_api_module) do
4151
4280
  Module.new do
4152
4281
  # rubocop:disable Style/ExplicitBlockArgument because this causes
@@ -4180,7 +4309,7 @@ describe Grape::API do
4180
4309
  let(:orders_root) do
4181
4310
  shared = shared_api_definitions
4182
4311
  find = orders_find_endpoint
4183
- Class.new(Grape::API) do
4312
+ Class.new(described_class) do
4184
4313
  include shared
4185
4314
 
4186
4315
  namespace(:orders) do
@@ -4190,7 +4319,7 @@ describe Grape::API do
4190
4319
  end
4191
4320
  let(:orders_find_endpoint) do
4192
4321
  shared = shared_api_definitions
4193
- Class.new(Grape::API) do
4322
+ Class.new(described_class) do
4194
4323
  include shared
4195
4324
 
4196
4325
  uniqe_id_route do
@@ -4201,11 +4330,6 @@ describe Grape::API do
4201
4330
  end
4202
4331
  end
4203
4332
  end
4204
- subject(:grape_api) do
4205
- Class.new(Grape::API) do
4206
- version 'v1', using: :path
4207
- end
4208
- end
4209
4333
 
4210
4334
  before do
4211
4335
  Grape::API::Instance.extend(shared_api_module)