grape 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -3
  3. data/README.md +56 -8
  4. data/UPGRADING.md +43 -4
  5. data/lib/grape/api.rb +2 -2
  6. data/lib/grape/dsl/helpers.rb +1 -0
  7. data/lib/grape/dsl/inside_route.rb +26 -38
  8. data/lib/grape/dsl/routing.rb +2 -4
  9. data/lib/grape/middleware/base.rb +2 -1
  10. data/lib/grape/middleware/error.rb +10 -12
  11. data/lib/grape/middleware/stack.rb +17 -4
  12. data/lib/grape/request.rb +1 -1
  13. data/lib/grape/router.rb +1 -1
  14. data/lib/grape/router/attribute_translator.rb +2 -2
  15. data/lib/grape/util/base_inheritable.rb +2 -2
  16. data/lib/grape/util/lazy_value.rb +1 -0
  17. data/lib/grape/validations/params_scope.rb +2 -1
  18. data/lib/grape/validations/types/custom_type_coercer.rb +13 -1
  19. data/lib/grape/validations/validators/as.rb +1 -1
  20. data/lib/grape/validations/validators/base.rb +2 -4
  21. data/lib/grape/validations/validators/default.rb +3 -4
  22. data/lib/grape/validations/validators/except_values.rb +1 -1
  23. data/lib/grape/validations/validators/values.rb +1 -1
  24. data/lib/grape/version.rb +1 -1
  25. data/spec/grape/api_spec.rb +10 -0
  26. data/spec/grape/dsl/inside_route_spec.rb +7 -0
  27. data/spec/grape/endpoint/declared_spec.rb +590 -0
  28. data/spec/grape/endpoint_spec.rb +0 -534
  29. data/spec/grape/entity_spec.rb +6 -0
  30. data/spec/grape/middleware/error_spec.rb +1 -1
  31. data/spec/grape/middleware/stack_spec.rb +3 -1
  32. data/spec/grape/validations/params_scope_spec.rb +26 -0
  33. data/spec/grape/validations/validators/coerce_spec.rb +24 -0
  34. data/spec/grape/validations/validators/default_spec.rb +49 -0
  35. data/spec/grape/validations/validators/except_values_spec.rb +1 -0
  36. data/spec/spec_helper.rb +0 -10
  37. data/spec/support/chunks.rb +14 -0
  38. data/spec/support/versioned_helpers.rb +3 -5
  39. metadata +9 -5
@@ -181,6 +181,7 @@ describe Grape::Entity do
181
181
  subject.get '/example' do
182
182
  c = Class.new do
183
183
  attr_reader :id
184
+
184
185
  def initialize(id)
185
186
  @id = id
186
187
  end
@@ -202,6 +203,7 @@ describe Grape::Entity do
202
203
  subject.get '/examples' do
203
204
  c = Class.new do
204
205
  attr_reader :id
206
+
205
207
  def initialize(id)
206
208
  @id = id
207
209
  end
@@ -226,6 +228,7 @@ describe Grape::Entity do
226
228
  subject.get '/example' do
227
229
  c = Class.new do
228
230
  attr_reader :name
231
+
229
232
  def initialize(args)
230
233
  @name = args[:name] || 'no name set'
231
234
  end
@@ -255,6 +258,7 @@ XML
255
258
  subject.get '/example' do
256
259
  c = Class.new do
257
260
  attr_reader :name
261
+
258
262
  def initialize(args)
259
263
  @name = args[:name] || 'no name set'
260
264
  end
@@ -284,6 +288,7 @@ XML
284
288
  subject.get '/example' do
285
289
  c = Class.new do
286
290
  attr_reader :name
291
+
287
292
  def initialize(args)
288
293
  @name = args[:name] || 'no name set'
289
294
  end
@@ -302,6 +307,7 @@ XML
302
307
  it 'present with multiple entities using optional symbol' do
303
308
  user = Class.new do
304
309
  attr_reader :name
310
+
305
311
  def initialize(args)
306
312
  @name = args[:name] || 'no name set'
307
313
  end
@@ -30,7 +30,7 @@ describe Grape::Middleware::Error do
30
30
  opts = options
31
31
  Rack::Builder.app do
32
32
  use Spec::Support::EndpointFaker
33
- use Grape::Middleware::Error, opts
33
+ use Grape::Middleware::Error, **opts
34
34
  run ErrorSpec::ErrApp
35
35
  end
36
36
  end
@@ -8,6 +8,7 @@ describe Grape::Middleware::Stack do
8
8
  class BarMiddleware; end
9
9
  class BlockMiddleware
10
10
  attr_reader :block
11
+
11
12
  def initialize(&block)
12
13
  @block = block
13
14
  end
@@ -34,7 +35,8 @@ describe Grape::Middleware::Stack do
34
35
  expect { subject.use StackSpec::BarMiddleware, false, my_arg: 42 }
35
36
  .to change { subject.size }.by(1)
36
37
  expect(subject.last).to eq(StackSpec::BarMiddleware)
37
- expect(subject.last.args).to eq([false, { my_arg: 42 }])
38
+ expect(subject.last.args).to eq([false])
39
+ expect(subject.last.opts).to eq(my_arg: 42)
38
40
  end
39
41
 
40
42
  it 'pushes a middleware class with block arguments onto the stack' do
@@ -633,6 +633,32 @@ describe Grape::Validations::ParamsScope do
633
633
  expect(last_response.status).to eq(200)
634
634
  end
635
635
 
636
+ it 'detect unmet nested dependency' do
637
+ subject.params do
638
+ requires :a, type: String, allow_blank: false, values: %w[x y z]
639
+ given a: ->(val) { val == 'z' } do
640
+ requires :inner3, type: Array, allow_blank: false do
641
+ requires :bar, type: String, allow_blank: false
642
+ given bar: ->(val) { val == 'b' } do
643
+ requires :baz, type: Array do
644
+ optional :baz_category, type: String
645
+ end
646
+ end
647
+ given bar: ->(val) { val == 'c' } do
648
+ requires :baz, type: Array do
649
+ requires :baz_category, type: String
650
+ end
651
+ end
652
+ end
653
+ end
654
+ end
655
+ subject.get('/nested-dependency') { declared(params).to_json }
656
+
657
+ get '/nested-dependency', a: 'z', inner3: [{ bar: 'c', baz: [{ unrelated: 'nope' }] }]
658
+ expect(last_response.status).to eq(400)
659
+ expect(last_response.body).to eq 'inner3[0][baz][0][baz_category] is missing'
660
+ end
661
+
636
662
  it 'includes the parameter within #declared(params)' do
637
663
  get '/test', a: true, b: true
638
664
 
@@ -620,6 +620,30 @@ describe Grape::Validations::CoerceValidator do
620
620
  expect(JSON.parse(last_response.body)).to eq(%w[a b c d])
621
621
  end
622
622
 
623
+ it 'parses parameters with Array[Array[String]] type and coerce_with' do
624
+ subject.params do
625
+ requires :values, type: Array[Array[String]], coerce_with: ->(val) { val.is_a?(String) ? [val.split(/,/).map(&:strip)] : val }
626
+ end
627
+ subject.post '/coerce_nested_strings' do
628
+ params[:values]
629
+ end
630
+
631
+ post '/coerce_nested_strings', ::Grape::Json.dump(values: 'a,b,c,d'), 'CONTENT_TYPE' => 'application/json'
632
+ expect(last_response.status).to eq(201)
633
+ expect(JSON.parse(last_response.body)).to eq([%w[a b c d]])
634
+
635
+ post '/coerce_nested_strings', ::Grape::Json.dump(values: [%w[a c], %w[b]]), 'CONTENT_TYPE' => 'application/json'
636
+ expect(last_response.status).to eq(201)
637
+ expect(JSON.parse(last_response.body)).to eq([%w[a c], %w[b]])
638
+
639
+ post '/coerce_nested_strings', ::Grape::Json.dump(values: [[]]), 'CONTENT_TYPE' => 'application/json'
640
+ expect(last_response.status).to eq(201)
641
+ expect(JSON.parse(last_response.body)).to eq([[]])
642
+
643
+ post '/coerce_nested_strings', ::Grape::Json.dump(values: [['a', { bar: 0 }], ['b']]), 'CONTENT_TYPE' => 'application/json'
644
+ expect(last_response.status).to eq(400)
645
+ end
646
+
623
647
  it 'parses parameters with Array[Integer] type' do
624
648
  subject.params do
625
649
  requires :values, type: Array[Integer], coerce_with: ->(val) { val.split(/\s+/).map(&:to_i) }
@@ -419,4 +419,53 @@ describe Grape::Validations::DefaultValidator do
419
419
  end
420
420
  end
421
421
  end
422
+
423
+ context 'array with default values and given conditions' do
424
+ subject do
425
+ Class.new(Grape::API) do
426
+ default_format :json
427
+ end
428
+ end
429
+
430
+ def app
431
+ subject
432
+ end
433
+
434
+ it 'applies the default values only if the conditions are met' do
435
+ subject.params do
436
+ requires :ary, type: Array do
437
+ requires :has_value, type: Grape::API::Boolean
438
+ given has_value: ->(has_value) { has_value } do
439
+ optional :type, type: String, values: %w[str int], default: 'str'
440
+ given type: ->(type) { type == 'str' } do
441
+ optional :str, type: String, default: 'a'
442
+ end
443
+ given type: ->(type) { type == 'int' } do
444
+ optional :int, type: Integer, default: 1
445
+ end
446
+ end
447
+ end
448
+ end
449
+ subject.post('/nested_given_and_default') { declared(self.params) }
450
+
451
+ params = {
452
+ ary: [
453
+ { has_value: false },
454
+ { has_value: true, type: 'int', int: 123 },
455
+ { has_value: true, type: 'str', str: 'b' }
456
+ ]
457
+ }
458
+ expected = {
459
+ 'ary' => [
460
+ { 'has_value' => false, 'type' => nil, 'int' => nil, 'str' => nil },
461
+ { 'has_value' => true, 'type' => 'int', 'int' => 123, 'str' => nil },
462
+ { 'has_value' => true, 'type' => 'str', 'int' => nil, 'str' => 'b' }
463
+ ]
464
+ }
465
+
466
+ post '/nested_given_and_default', params
467
+ expect(last_response.status).to eq(201)
468
+ expect(JSON.parse(last_response.body)).to eq(expected)
469
+ end
470
+ end
422
471
  end
@@ -8,6 +8,7 @@ describe Grape::Validations::ExceptValuesValidator do
8
8
  DEFAULT_EXCEPTS = ['invalid-type1', 'invalid-type2', 'invalid-type3'].freeze
9
9
  class << self
10
10
  attr_accessor :excepts
11
+
11
12
  def excepts
12
13
  @excepts ||= []
13
14
  [DEFAULT_EXCEPTS + @excepts].flatten.uniq
@@ -20,17 +20,7 @@ eager_load!
20
20
  # so it should be set to true here as well to reflect that.
21
21
  I18n.enforce_available_locales = true
22
22
 
23
- module Chunks
24
- def read_chunks(body)
25
- buffer = []
26
- body.each { |chunk| buffer << chunk }
27
-
28
- buffer
29
- end
30
- end
31
-
32
23
  RSpec.configure do |config|
33
- config.include Chunks
34
24
  config.include Rack::Test::Methods
35
25
  config.include Spec::Support::Helpers
36
26
  config.raise_errors_for_deprecations!
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Chunks
4
+ def read_chunks(body)
5
+ buffer = []
6
+ body.each { |chunk| buffer << chunk }
7
+
8
+ buffer
9
+ end
10
+ end
11
+
12
+ RSpec.configure do |config|
13
+ config.include Chunks
14
+ end
@@ -6,7 +6,7 @@ module Spec
6
6
  module Helpers
7
7
  # Returns the path with options[:version] prefixed if options[:using] is :path.
8
8
  # Returns normal path otherwise.
9
- def versioned_path(options = {})
9
+ def versioned_path(**options)
10
10
  case options[:using]
11
11
  when :path
12
12
  File.join('/', options[:prefix] || '', options[:version], options[:path])
@@ -43,13 +43,11 @@ module Spec
43
43
  end
44
44
  end
45
45
 
46
- def versioned_get(path, version_name, version_options = {})
46
+ def versioned_get(path, version_name, **version_options)
47
47
  path = versioned_path(version_options.merge(version: version_name, path: path))
48
48
  headers = versioned_headers(**version_options.merge(version: version_name))
49
49
  params = {}
50
- if version_options[:using] == :param
51
- params = { version_options[:parameter] => version_name }
52
- end
50
+ params = { version_options[:parameter] => version_name } if version_options[:using] == :param
53
51
  get path, params, headers
54
52
  end
55
53
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grape
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Bleigh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-10 00:00:00.000000000 Z
11
+ date: 2020-10-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -282,6 +282,7 @@ files:
282
282
  - spec/grape/dsl/routing_spec.rb
283
283
  - spec/grape/dsl/settings_spec.rb
284
284
  - spec/grape/dsl/validations_spec.rb
285
+ - spec/grape/endpoint/declared_spec.rb
285
286
  - spec/grape/endpoint_spec.rb
286
287
  - spec/grape/entity_spec.rb
287
288
  - spec/grape/exceptions/base_spec.rb
@@ -356,6 +357,7 @@ files:
356
357
  - spec/shared/versioning_examples.rb
357
358
  - spec/spec_helper.rb
358
359
  - spec/support/basic_auth_encode_helpers.rb
360
+ - spec/support/chunks.rb
359
361
  - spec/support/content_type_helpers.rb
360
362
  - spec/support/eager_load.rb
361
363
  - spec/support/endpoint_faker.rb
@@ -367,9 +369,9 @@ licenses:
367
369
  - MIT
368
370
  metadata:
369
371
  bug_tracker_uri: https://github.com/ruby-grape/grape/issues
370
- changelog_uri: https://github.com/ruby-grape/grape/blob/v1.4.0/CHANGELOG.md
371
- documentation_uri: https://www.rubydoc.info/gems/grape/1.4.0
372
- source_code_uri: https://github.com/ruby-grape/grape/tree/v1.4.0
372
+ changelog_uri: https://github.com/ruby-grape/grape/blob/v1.5.0/CHANGELOG.md
373
+ documentation_uri: https://www.rubydoc.info/gems/grape/1.5.0
374
+ source_code_uri: https://github.com/ruby-grape/grape/tree/v1.5.0
373
375
  post_install_message:
374
376
  rdoc_options: []
375
377
  require_paths:
@@ -397,6 +399,7 @@ test_files:
397
399
  - spec/shared/versioning_examples.rb
398
400
  - spec/support/basic_auth_encode_helpers.rb
399
401
  - spec/support/endpoint_faker.rb
402
+ - spec/support/chunks.rb
400
403
  - spec/support/file_streamer.rb
401
404
  - spec/support/versioned_helpers.rb
402
405
  - spec/support/content_type_helpers.rb
@@ -470,6 +473,7 @@ test_files:
470
473
  - spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb
471
474
  - spec/grape/parser_spec.rb
472
475
  - spec/grape/request_spec.rb
476
+ - spec/grape/endpoint/declared_spec.rb
473
477
  - spec/grape/api/parameters_modification_spec.rb
474
478
  - spec/grape/api/patch_method_helpers_spec.rb
475
479
  - spec/grape/api/required_parameters_with_invalid_method_spec.rb