grape 1.6.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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)