-
-
Notifications
You must be signed in to change notification settings - Fork 3k
/
single_line_methods.rb
135 lines (113 loc) · 4.18 KB
/
single_line_methods.rb
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# frozen_string_literal: true
module RuboCop
module Cop
module Style
# This cop checks for single-line method definitions that contain a body.
# It will accept single-line methods with no body.
#
# Endless methods added in Ruby 3.0 are also accepted by this cop.
#
# If `Style/EndlessMethod` is enabled with `EnforcedStyle: allow_single_line` or
# `allow_always`, single-line methods will be auto-corrected to endless
# methods if there is only one statement in the body.
#
# @example
# # bad
# def some_method; body end
# def link_to(url); {:name => url}; end
# def @table.columns; super; end
#
# # good
# def self.resource_class=(klass); end
# def @table.columns; end
# def some_method() = body
#
# @example AllowIfMethodIsEmpty: true (default)
# # good
# def no_op; end
#
# @example AllowIfMethodIsEmpty: false
# # bad
# def no_op; end
#
class SingleLineMethods < Base
include Alignment
extend AutoCorrector
MSG = 'Avoid single-line method definitions.'
def on_def(node)
return unless node.single_line?
return if node.endless?
return if allow_empty? && !node.body
add_offense(node) { |corrector| autocorrect(corrector, node) }
end
alias on_defs on_def
private
def autocorrect(corrector, node)
if correct_to_endless?(node.body)
correct_to_endless(corrector, node)
else
correct_to_multiline(corrector, node)
end
end
def allow_empty?
cop_config['AllowIfMethodIsEmpty']
end
def correct_to_endless?(body_node)
return false if target_ruby_version < 3.0
endless_method_config = config.for_cop('Style/EndlessMethod')
return false unless endless_method_config['Enabled']
return false if endless_method_config['EnforcedStyle'] == 'disallow'
return false unless body_node
return false if body_node.parent.assignment_method?
!(body_node.begin_type? || body_node.kwbegin_type?)
end
def correct_to_multiline(corrector, node)
each_part(node.body) do |part|
LineBreakCorrector.break_line_before(
range: part, node: node, corrector: corrector,
configured_width: configured_indentation_width
)
end
LineBreakCorrector.break_line_before(
range: node.loc.end, node: node, corrector: corrector,
indent_steps: 0, configured_width: configured_indentation_width
)
move_comment(node, corrector)
end
def correct_to_endless(corrector, node)
self_receiver = node.self_receiver? ? 'self.' : ''
arguments = node.arguments.any? ? node.arguments.source : '()'
body_source = method_body_source(node.body)
replacement = "def #{self_receiver}#{node.method_name}#{arguments} = #{body_source}"
corrector.replace(node, replacement)
end
def each_part(body)
return unless body
if body.begin_type?
body.each_child_node { |part| yield part.source_range }
else
yield body.source_range
end
end
def move_comment(node, corrector)
LineBreakCorrector.move_comment(
eol_comment: processed_source.comment_at_line(node.source_range.line),
node: node, corrector: corrector
)
end
def method_body_source(method_body)
if require_parentheses?(method_body)
arguments_source = method_body.arguments.map(&:source).join(', ')
body_source = "#{method_body.method_name}(#{arguments_source})"
method_body.receiver ? "#{method_body.receiver.source}.#{body_source}" : body_source
else
method_body.source
end
end
def require_parentheses?(method_body)
method_body.send_type? && !method_body.arguments.empty? && !method_body.comparison_method?
end
end
end
end
end