blob: 5cb80e113a4332f6206e3e2a9ffcb274718a1c49 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
# frozen_string_literal: true
module RuboCop
module Cop
module API
class GrapeArrayMissingCoerce < RuboCop::Cop::Base
# This cop checks that Grape API parameters using an Array type
# implement a coerce_with method:
#
# https://github.com/ruby-grape/grape/blob/master/UPGRADING.md#ensure-that-array-types-have-explicit-coercions
#
# @example
#
# # bad
# requires :values, type: Array[String]
#
# # good
# requires :values, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce
#
# end
MSG = 'This Grape parameter defines an Array but is missing a coerce_with definition. ' \
'For more details, see https://github.com/ruby-grape/grape/blob/master/UPGRADING.md#ensure-that-array-types-have-explicit-coercions'
def_node_matcher :grape_api_instance?, <<~PATTERN
(class
(const _ _)
(const
(const
(const nil? :Grape) :API) :Instance)
...
)
PATTERN
def_node_matcher :grape_api_param_block?, <<~PATTERN
(send _ {:requires :optional}
(sym _)
$_)
PATTERN
def_node_matcher :grape_type_def?, <<~PATTERN
(sym :type)
PATTERN
def_node_matcher :grape_array_type?, <<~PATTERN
(send
(const nil? :Array) :[]
(const nil? _))
PATTERN
def_node_matcher :grape_coerce_with?, <<~PATTERN
(sym :coerce_with)
PATTERN
def on_class(node)
@grape_api ||= grape_api_instance?(node)
end
def on_send(node)
return unless @grape_api
match = grape_api_param_block?(node)
return unless match.is_a?(RuboCop::AST::HashNode)
is_array_type = false
has_coerce_method = false
match.each_pair do |first, second|
has_coerce_method ||= grape_coerce_with?(first)
if grape_type_def?(first) && grape_array_type?(second)
is_array_type = true
end
end
if is_array_type && !has_coerce_method
add_offense(node)
end
end
end
end
end
end
|