rubocop 0.66.0 → 0.67.0
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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +75 -26
- data/exe/rubocop +12 -0
- data/lib/rubocop.rb +12 -5
- data/lib/rubocop/cli.rb +11 -9
- data/lib/rubocop/config.rb +3 -0
- data/lib/rubocop/config_loader_resolver.rb +2 -2
- data/lib/rubocop/cop/commissioner.rb +3 -3
- data/lib/rubocop/cop/layout/multiline_array_line_breaks.rb +39 -0
- data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +50 -0
- data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +52 -0
- data/lib/rubocop/cop/lint/to_json.rb +5 -2
- data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +33 -0
- data/lib/rubocop/cop/mixin/uncommunicative_name.rb +6 -1
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +76 -0
- data/lib/rubocop/cop/rails/active_record_override.rb +67 -0
- data/lib/rubocop/cop/rails/blank.rb +6 -0
- data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +30 -4
- data/lib/rubocop/cop/rails/link_to_blank.rb +7 -6
- data/lib/rubocop/cop/rails/present.rb +5 -1
- data/lib/rubocop/cop/rails/redundant_allow_nil.rb +105 -0
- data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +1 -0
- data/lib/rubocop/cop/style/block_comments.rb +9 -1
- data/lib/rubocop/cop/{performance → style}/redundant_sort_by.rb +1 -1
- data/lib/rubocop/cop/{performance → style}/sample.rb +1 -1
- data/lib/rubocop/cop/style/stderr_puts.rb +9 -3
- data/lib/rubocop/cop/{performance/lstrip_rstrip.rb → style/strip.rb} +2 -2
- data/lib/rubocop/cop/style/struct_inheritance.rb +10 -2
- data/lib/rubocop/cop/{performance → style}/unneeded_sort.rb +1 -1
- data/lib/rubocop/node_pattern.rb +8 -6
- data/lib/rubocop/path_util.rb +3 -3
- data/lib/rubocop/processed_source.rb +2 -2
- data/lib/rubocop/remote_config.rb +6 -4
- data/lib/rubocop/result_cache.rb +2 -2
- data/lib/rubocop/runner.rb +2 -2
- data/lib/rubocop/target_finder.rb +7 -2
- data/lib/rubocop/version.rb +1 -1
- metadata +29 -7
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Layout
|
6
|
+
# This cop ensures that each key in a multi-line hash
|
7
|
+
# starts on a separate line.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# # bad
|
12
|
+
# {
|
13
|
+
# a: 1, b: 2,
|
14
|
+
# c: 3
|
15
|
+
# }
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# {
|
19
|
+
# a: 1,
|
20
|
+
# b: 2,
|
21
|
+
# c: 3
|
22
|
+
# }
|
23
|
+
class MultilineHashKeyLineBreaks < Cop
|
24
|
+
include MultilineElementLineBreaks
|
25
|
+
|
26
|
+
MSG = 'Each key in a multi-line hash must start on a ' \
|
27
|
+
'separate line.'.freeze
|
28
|
+
|
29
|
+
def on_hash(node)
|
30
|
+
# This cop only deals with hashes wrapped by a set of curly
|
31
|
+
# braces like {foo: 1}. That is, not a kwargs hashes.
|
32
|
+
# Style/MultilineMethodArgumentLineBreaks handles those.
|
33
|
+
return unless starts_with_curly_brace?(node)
|
34
|
+
|
35
|
+
check_line_breaks(node, node.children) if node.loc.begin
|
36
|
+
end
|
37
|
+
|
38
|
+
def autocorrect(node)
|
39
|
+
EmptyLineCorrector.insert_before(node)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def starts_with_curly_brace?(node)
|
45
|
+
node.loc.begin
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Layout
|
6
|
+
# This cop ensures that each argument in a multi-line method call
|
7
|
+
# starts on a separate line.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# # bad
|
12
|
+
# foo(a, b,
|
13
|
+
# c
|
14
|
+
# )
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# foo(
|
18
|
+
# a,
|
19
|
+
# b,
|
20
|
+
# c
|
21
|
+
# )
|
22
|
+
class MultilineMethodArgumentLineBreaks < Cop
|
23
|
+
include(MultilineElementLineBreaks)
|
24
|
+
|
25
|
+
MSG = 'Each argument in a multi-line method call must start ' \
|
26
|
+
'on a separate line.'.freeze
|
27
|
+
|
28
|
+
def on_send(node)
|
29
|
+
args = node.arguments
|
30
|
+
|
31
|
+
# If there is a trailing hash arg without explicit braces, like this:
|
32
|
+
#
|
33
|
+
# method(1, 'key1' => value1, 'key2' => value2)
|
34
|
+
#
|
35
|
+
# ...then each key/value pair is treated as a method 'argument'
|
36
|
+
# when determining where line breaks should appear.
|
37
|
+
if (last_arg = args.last)
|
38
|
+
if last_arg.hash_type? && !last_arg.braces?
|
39
|
+
args = args.concat(args.pop.children)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
check_line_breaks(node, args)
|
44
|
+
end
|
45
|
+
|
46
|
+
def autocorrect(node)
|
47
|
+
EmptyLineCorrector.insert_before(node)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -14,7 +14,7 @@ module RuboCop
|
|
14
14
|
# end
|
15
15
|
#
|
16
16
|
# # good
|
17
|
-
# def to_json(
|
17
|
+
# def to_json(*_args)
|
18
18
|
# end
|
19
19
|
#
|
20
20
|
class ToJSON < Cop
|
@@ -29,7 +29,10 @@ module RuboCop
|
|
29
29
|
|
30
30
|
def autocorrect(node)
|
31
31
|
lambda do |corrector|
|
32
|
-
|
32
|
+
# The following used `*_args` because `to_json(*args)` has
|
33
|
+
# an offense of `Lint/UnusedMethodArgument` cop if `*args`
|
34
|
+
# is not used.
|
35
|
+
corrector.insert_after(node.loc.name, '(*_args)')
|
33
36
|
end
|
34
37
|
end
|
35
38
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# TEAM: backend_infra
|
4
|
+
# WATCHERS: maxh
|
5
|
+
|
6
|
+
module RuboCop
|
7
|
+
module Cop
|
8
|
+
# Common functionality for checking for a line break before each
|
9
|
+
# element in a multi-line collection.
|
10
|
+
module MultilineElementLineBreaks
|
11
|
+
private
|
12
|
+
|
13
|
+
def check_line_breaks(_node, children)
|
14
|
+
return if all_on_same_line?(children)
|
15
|
+
|
16
|
+
last_seen_line = -1
|
17
|
+
children.each do |child|
|
18
|
+
if last_seen_line >= child.first_line
|
19
|
+
add_offense(child)
|
20
|
+
else
|
21
|
+
last_seen_line = child.last_line
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def all_on_same_line?(nodes)
|
27
|
+
return true if nodes.empty?
|
28
|
+
|
29
|
+
nodes.first.first_line == nodes.last.last_line
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -13,7 +13,12 @@ module RuboCop
|
|
13
13
|
|
14
14
|
def check(node, args)
|
15
15
|
args.each do |arg|
|
16
|
-
|
16
|
+
# Argument names might be "_" or prefixed with "_" to indicate they
|
17
|
+
# are unused. Trim away this prefix and only analyse the basename.
|
18
|
+
full_name = arg.children.first.to_s
|
19
|
+
next if full_name == '_'
|
20
|
+
|
21
|
+
name = full_name.gsub(/\A([_]+)/, '')
|
17
22
|
next if (arg.restarg_type? || arg.kwrestarg_type?) && name.empty?
|
18
23
|
next if allowed_names.include?(name)
|
19
24
|
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Naming
|
6
|
+
# This cop makes sure that rescued exceptions variables are named as
|
7
|
+
# expected.
|
8
|
+
#
|
9
|
+
# The `PreferredName` config option takes a `String`. It represents
|
10
|
+
# the required name of the variable. Its default is `e`.
|
11
|
+
#
|
12
|
+
# @example PreferredName: e (default)
|
13
|
+
# # bad
|
14
|
+
# begin
|
15
|
+
# # do something
|
16
|
+
# rescue MyException => exc
|
17
|
+
# # do something
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# begin
|
22
|
+
# # do something
|
23
|
+
# rescue MyException => e
|
24
|
+
# # do something
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# @example PreferredName: exception
|
28
|
+
# # bad
|
29
|
+
# begin
|
30
|
+
# # do something
|
31
|
+
# rescue MyException => e
|
32
|
+
# # do something
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# # good
|
36
|
+
# begin
|
37
|
+
# # do something
|
38
|
+
# rescue MyException => ex
|
39
|
+
# # do something
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
class RescuedExceptionsVariableName < Cop
|
43
|
+
MSG = 'Use `%<preferred>s` instead of `%<bad>s`.'.freeze
|
44
|
+
|
45
|
+
def on_resbody(node)
|
46
|
+
exception_type, @exception_name = *node
|
47
|
+
return unless exception_type || @exception_name
|
48
|
+
|
49
|
+
@exception_name ||= exception_type.children.first
|
50
|
+
return if @exception_name.const_type? ||
|
51
|
+
variable_name == preferred_name
|
52
|
+
|
53
|
+
add_offense(node, location: location)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def preferred_name
|
59
|
+
@preferred_name ||= cop_config.fetch('PreferredName', 'e')
|
60
|
+
end
|
61
|
+
|
62
|
+
def variable_name
|
63
|
+
@variable_name ||= location.source
|
64
|
+
end
|
65
|
+
|
66
|
+
def location
|
67
|
+
@location ||= @exception_name.loc.expression
|
68
|
+
end
|
69
|
+
|
70
|
+
def message(_node = nil)
|
71
|
+
format(MSG, preferred: preferred_name, bad: variable_name)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Checks for overriding built-in Active Record methods instead of using
|
7
|
+
# callbacks.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# class Book < ApplicationRecord
|
12
|
+
# def save
|
13
|
+
# self.title = title.upcase!
|
14
|
+
# super
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# # good
|
19
|
+
# class Book < ApplicationRecord
|
20
|
+
# before_save :upcase_title
|
21
|
+
#
|
22
|
+
# def upcase_title
|
23
|
+
# self.title = title.upcase!
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
class ActiveRecordOverride < Cop
|
28
|
+
MSG =
|
29
|
+
'Use %<prefer>s callbacks instead of overriding the Active Record ' \
|
30
|
+
'method `%<bad>s`.'.freeze
|
31
|
+
BAD_METHODS = %i[create destroy save update].freeze
|
32
|
+
|
33
|
+
def on_def(node)
|
34
|
+
method_name = node.method_name
|
35
|
+
return unless BAD_METHODS.include?(node.method_name)
|
36
|
+
|
37
|
+
parent_parts = node.parent.node_parts
|
38
|
+
parent_class = parent_parts.take_while do |part|
|
39
|
+
!part.nil? && part.const_type?
|
40
|
+
end.last
|
41
|
+
return unless %w[ApplicationRecord ActiveModel::Base]
|
42
|
+
.include?(parent_class.const_name)
|
43
|
+
|
44
|
+
return unless node.descendants.any?(&:zsuper_type?)
|
45
|
+
|
46
|
+
add_offense(node, message: message(method_name))
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def callback_names(method_name)
|
52
|
+
names = %w[before_ around_ after_].map do |prefix|
|
53
|
+
"`#{prefix}#{method_name}`"
|
54
|
+
end
|
55
|
+
|
56
|
+
names[-1] = "or #{names.last}"
|
57
|
+
|
58
|
+
names.join(', ')
|
59
|
+
end
|
60
|
+
|
61
|
+
def message(method_name)
|
62
|
+
format(MSG, prefer: callback_names(method_name), bad: method_name)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -6,6 +6,11 @@ module RuboCop
|
|
6
6
|
# This cop checks for code that can be written with simpler conditionals
|
7
7
|
# using `Object#blank?` defined by Active Support.
|
8
8
|
#
|
9
|
+
# Interaction with `Style/UnlessElse`:
|
10
|
+
# The configuration of `NotPresent` will not produce an offense in the
|
11
|
+
# context of `unless else` if `Style/UnlessElse` is inabled. This is
|
12
|
+
# to prevent interference between the auto-correction of the two cops.
|
13
|
+
#
|
9
14
|
# @example NilOrEmpty: true (default)
|
10
15
|
# # Converts usages of `nil? || empty?` to `blank?`
|
11
16
|
#
|
@@ -111,6 +116,7 @@ module RuboCop
|
|
111
116
|
def on_if(node)
|
112
117
|
return unless cop_config['UnlessPresent']
|
113
118
|
return unless node.unless?
|
119
|
+
return if node.else? && config.for_cop('Style/UnlessElse')['Enabled']
|
114
120
|
|
115
121
|
unless_present?(node) do |method_call, receiver|
|
116
122
|
range = unless_condition(node, method_call)
|
@@ -6,10 +6,13 @@ module RuboCop
|
|
6
6
|
# This cop checks that methods specified in the filter's `only` or
|
7
7
|
# `except` options are defined within the same class or module.
|
8
8
|
#
|
9
|
-
# You can technically specify methods of superclass or methods added
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
9
|
+
# You can technically specify methods of superclass or methods added by
|
10
|
+
# mixins on the filter, but these can confuse developers. If you specify
|
11
|
+
# methods that are defined in other classes or modules, you should
|
12
|
+
# define the filter in that class or module.
|
13
|
+
#
|
14
|
+
# If you rely on behaviour defined in the superclass actions, you must
|
15
|
+
# remember to invoke `super` in the subclass actions.
|
13
16
|
#
|
14
17
|
# @example
|
15
18
|
# # bad
|
@@ -56,6 +59,29 @@ module RuboCop
|
|
56
59
|
# # something
|
57
60
|
# end
|
58
61
|
# end
|
62
|
+
#
|
63
|
+
# @example
|
64
|
+
# class ContentController < ApplicationController
|
65
|
+
# def update
|
66
|
+
# @content.update(content_attributes)
|
67
|
+
# end
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# class ArticlesController < ContentController
|
71
|
+
# before_action :load_article, only: [:update]
|
72
|
+
#
|
73
|
+
# # the cop requires this method, but it relies on behaviour defined
|
74
|
+
# # in the superclass, so needs to invoke `super`
|
75
|
+
# def update
|
76
|
+
# super
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
# private
|
80
|
+
#
|
81
|
+
# def load_article
|
82
|
+
# @content = Article.find(params[:article_id])
|
83
|
+
# end
|
84
|
+
# end
|
59
85
|
class LexicallyScopedActionFilter < Cop
|
60
86
|
MSG = '%<action>s not explicitly defined on the %<type>s.'.freeze
|
61
87
|
|
@@ -22,7 +22,7 @@ module RuboCop
|
|
22
22
|
PATTERN
|
23
23
|
|
24
24
|
def_node_matcher :includes_noopener?, <<-PATTERN
|
25
|
-
(pair {(sym :rel) (str "rel")} (str #contains_noopener?))
|
25
|
+
(pair {(sym :rel) (str "rel")} ({str sym} #contains_noopener?))
|
26
26
|
PATTERN
|
27
27
|
|
28
28
|
def_node_matcher :rel_node?, <<-PATTERN
|
@@ -72,17 +72,18 @@ module RuboCop
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def add_rel(send_node, offence_node, corrector)
|
75
|
-
|
76
|
-
|
75
|
+
opening_quote = offence_node.children.last.source[0]
|
76
|
+
closing_quote = opening_quote == ':' ? '' : opening_quote
|
77
|
+
new_rel_exp = ", rel: #{opening_quote}noopener#{closing_quote}"
|
77
78
|
range = send_node.arguments.last.source_range
|
78
79
|
|
79
80
|
corrector.insert_after(range, new_rel_exp)
|
80
81
|
end
|
81
82
|
|
82
|
-
def contains_noopener?(
|
83
|
-
return false unless
|
83
|
+
def contains_noopener?(value)
|
84
|
+
return false unless value
|
84
85
|
|
85
|
-
|
86
|
+
value.to_s.split(' ').include?('noopener')
|
86
87
|
end
|
87
88
|
end
|
88
89
|
end
|
@@ -6,7 +6,10 @@ module RuboCop
|
|
6
6
|
# This cop checks for code that can be written with simpler conditionals
|
7
7
|
# using `Object#present?` defined by Active Support.
|
8
8
|
#
|
9
|
-
#
|
9
|
+
# Interaction with `Style/UnlessElse`:
|
10
|
+
# The configuration of `NotBlank` will not produce an offense in the
|
11
|
+
# context of `unless else` if `Style/UnlessElse` is inabled. This is
|
12
|
+
# to prevent interference between the auto-correction of the two cops.
|
10
13
|
#
|
11
14
|
# @example NotNilAndNotEmpty: true (default)
|
12
15
|
# # Converts usages of `!nil? && !empty?` to `present?`
|
@@ -104,6 +107,7 @@ module RuboCop
|
|
104
107
|
def on_if(node)
|
105
108
|
return unless cop_config['UnlessBlank']
|
106
109
|
return unless node.unless?
|
110
|
+
return if node.else? && config.for_cop('Style/UnlessElse')['Enabled']
|
107
111
|
|
108
112
|
unless_blank?(node) do |method_call, receiver|
|
109
113
|
range = unless_condition(node, method_call)
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Checks Rails model validations for a redundant `allow_nil` when
|
7
|
+
# `allow_blank` is present.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# validates :x, length: { is: 5 }, allow_nil: true, allow_blank: true
|
12
|
+
#
|
13
|
+
# # bad
|
14
|
+
# validates :x, length: { is: 5 }, allow_nil: false, allow_blank: true
|
15
|
+
#
|
16
|
+
# # bad
|
17
|
+
# validates :x, length: { is: 5 }, allow_nil: false, allow_blank: false
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# validates :x, length: { is: 5 }, allow_blank: true
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# validates :x, length: { is: 5 }, allow_blank: false
|
24
|
+
#
|
25
|
+
# # good
|
26
|
+
# # Here, `nil` is valid but `''` is not
|
27
|
+
# validates :x, length: { is: 5 }, allow_nil: true, allow_blank: false
|
28
|
+
#
|
29
|
+
class RedundantAllowNil < Cop
|
30
|
+
include RangeHelp
|
31
|
+
|
32
|
+
MSG_SAME =
|
33
|
+
'`allow_nil` is redundant when `allow_blank` has the same value.'
|
34
|
+
.freeze
|
35
|
+
MSG_ALLOW_NIL_FALSE =
|
36
|
+
'`allow_nil: false` is redundant when `allow_blank` is true.'.freeze
|
37
|
+
|
38
|
+
def on_send(node)
|
39
|
+
return unless node.method_name == :validates
|
40
|
+
|
41
|
+
allow_nil, allow_blank = find_allow_nil_and_allow_blank(node)
|
42
|
+
allow_nil_val = allow_nil.children.last
|
43
|
+
allow_blank_val = allow_blank.children.last
|
44
|
+
|
45
|
+
if allow_nil_val.type == allow_blank_val.type
|
46
|
+
add_offense(allow_nil, message: MSG_SAME)
|
47
|
+
elsif allow_nil_val.false_type? && allow_blank_val.true_type?
|
48
|
+
add_offense(allow_nil, message: MSG_ALLOW_NIL_FALSE)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def autocorrect(node)
|
53
|
+
prv_sib = previous_sibling(node)
|
54
|
+
nxt_sib = next_sibling(node)
|
55
|
+
|
56
|
+
lambda do |corrector|
|
57
|
+
if nxt_sib
|
58
|
+
corrector.remove(range_between(node_beg(node), node_beg(nxt_sib)))
|
59
|
+
elsif prv_sib
|
60
|
+
corrector.remove(range_between(node_end(prv_sib), node_end(node)))
|
61
|
+
else
|
62
|
+
corrector.remove(node.loc.expression)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def find_allow_nil_and_allow_blank(node)
|
70
|
+
allow_nil = nil
|
71
|
+
allow_blank = nil
|
72
|
+
|
73
|
+
node.each_descendant do |descendant|
|
74
|
+
next unless descendant.pair_type?
|
75
|
+
|
76
|
+
key = descendant.children.first.value
|
77
|
+
|
78
|
+
allow_nil = descendant if key == :allow_nil
|
79
|
+
allow_blank = descendant if key == :allow_blank
|
80
|
+
|
81
|
+
break if allow_nil && allow_blank
|
82
|
+
end
|
83
|
+
|
84
|
+
[allow_nil, allow_blank]
|
85
|
+
end
|
86
|
+
|
87
|
+
def previous_sibling(node)
|
88
|
+
node.parent.children[node.sibling_index - 1]
|
89
|
+
end
|
90
|
+
|
91
|
+
def next_sibling(node)
|
92
|
+
node.parent.children[node.sibling_index + 1]
|
93
|
+
end
|
94
|
+
|
95
|
+
def node_beg(node)
|
96
|
+
node.loc.expression.begin_pos
|
97
|
+
end
|
98
|
+
|
99
|
+
def node_end(node)
|
100
|
+
node.loc.expression.end_pos
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|