rubocop 0.60.0 → 0.61.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 +4 -4
- data/config/default.yml +573 -560
- data/lib/rubocop.rb +5 -0
- data/lib/rubocop/ast/node.rb +1 -1
- data/lib/rubocop/ast/sexp.rb +1 -1
- data/lib/rubocop/cli.rb +9 -14
- data/lib/rubocop/config.rb +4 -3
- data/lib/rubocop/config_loader.rb +25 -22
- data/lib/rubocop/config_loader_resolver.rb +3 -2
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +53 -0
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +73 -0
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +138 -0
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +52 -46
- data/lib/rubocop/cop/generator.rb +13 -17
- data/lib/rubocop/cop/generator/configuration_injector.rb +60 -0
- data/lib/rubocop/cop/layout/align_hash.rb +3 -0
- data/lib/rubocop/cop/layout/comment_indentation.rb +32 -2
- data/lib/rubocop/cop/layout/indent_heredoc.rb +11 -5
- data/lib/rubocop/cop/layout/indentation_width.rb +7 -1
- data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +11 -11
- data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +1 -1
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +16 -3
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +30 -17
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +11 -0
- data/lib/rubocop/cop/lint/shadowed_exception.rb +2 -5
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -1
- data/lib/rubocop/cop/metrics/line_length.rb +2 -2
- data/lib/rubocop/cop/mixin/trailing_comma.rb +11 -15
- data/lib/rubocop/cop/offense.rb +1 -1
- data/lib/rubocop/cop/performance/open_struct.rb +46 -0
- data/lib/rubocop/cop/performance/redundant_merge.rb +18 -4
- data/lib/rubocop/cop/rails/bulk_change_table.rb +2 -2
- data/lib/rubocop/cop/rails/dynamic_find_by.rb +15 -8
- data/lib/rubocop/cop/rails/http_positional_arguments.rb +17 -14
- data/lib/rubocop/cop/rails/http_status.rb +4 -4
- data/lib/rubocop/cop/rails/inverse_of.rb +2 -2
- data/lib/rubocop/cop/rails/reversible_migration.rb +1 -1
- data/lib/rubocop/cop/rails/skips_model_validations.rb +1 -1
- data/lib/rubocop/cop/rails/validation.rb +4 -4
- data/lib/rubocop/cop/security/open.rb +31 -11
- data/lib/rubocop/cop/style/begin_block.rb +6 -0
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +1 -1
- data/lib/rubocop/cop/style/empty_case_condition.rb +13 -7
- data/lib/rubocop/cop/style/for.rb +9 -78
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +6 -4
- data/lib/rubocop/cop/style/global_vars.rb +1 -1
- data/lib/rubocop/cop/style/infinite_loop.rb +42 -6
- data/lib/rubocop/cop/style/lambda.rb +4 -87
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +221 -16
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/regexp_literal.rb +62 -10
- data/lib/rubocop/cop/style/unneeded_condition.rb +2 -2
- data/lib/rubocop/cop/variable_force.rb +4 -2
- data/lib/rubocop/cop/variable_force/variable.rb +2 -0
- data/lib/rubocop/magic_comment.rb +1 -1
- data/lib/rubocop/remote_config.rb +13 -4
- data/lib/rubocop/rspec/expect_offense.rb +1 -1
- data/lib/rubocop/runner.rb +15 -4
- data/lib/rubocop/version.rb +1 -1
- metadata +7 -2
data/lib/rubocop.rb
CHANGED
@@ -76,6 +76,7 @@ require_relative 'rubocop/cop/corrector'
|
|
76
76
|
require_relative 'rubocop/cop/force'
|
77
77
|
require_relative 'rubocop/cop/severity'
|
78
78
|
require_relative 'rubocop/cop/generator'
|
79
|
+
require_relative 'rubocop/cop/generator/configuration_injector'
|
79
80
|
require_relative 'rubocop/cop/generator/require_file_injector'
|
80
81
|
|
81
82
|
require_relative 'rubocop/cop/variable_force'
|
@@ -150,7 +151,10 @@ require_relative 'rubocop/cop/mixin/unused_argument'
|
|
150
151
|
|
151
152
|
require_relative 'rubocop/cop/correctors/alignment_corrector'
|
152
153
|
require_relative 'rubocop/cop/correctors/condition_corrector'
|
154
|
+
require_relative 'rubocop/cop/correctors/each_to_for_corrector'
|
153
155
|
require_relative 'rubocop/cop/correctors/empty_line_corrector'
|
156
|
+
require_relative 'rubocop/cop/correctors/for_to_each_corrector'
|
157
|
+
require_relative 'rubocop/cop/correctors/lambda_literal_to_method_corrector'
|
154
158
|
require_relative 'rubocop/cop/correctors/line_break_corrector'
|
155
159
|
require_relative 'rubocop/cop/correctors/multiline_literal_brace_corrector'
|
156
160
|
require_relative 'rubocop/cop/correctors/ordered_gem_corrector'
|
@@ -368,6 +372,7 @@ require_relative 'rubocop/cop/performance/fixed_size'
|
|
368
372
|
require_relative 'rubocop/cop/performance/flat_map'
|
369
373
|
require_relative 'rubocop/cop/performance/inefficient_hash_search'
|
370
374
|
require_relative 'rubocop/cop/performance/lstrip_rstrip'
|
375
|
+
require_relative 'rubocop/cop/performance/open_struct'
|
371
376
|
require_relative 'rubocop/cop/performance/range_include'
|
372
377
|
require_relative 'rubocop/cop/performance/redundant_block_call'
|
373
378
|
require_relative 'rubocop/cop/performance/redundant_match'
|
data/lib/rubocop/ast/node.rb
CHANGED
@@ -54,7 +54,7 @@ module RuboCop
|
|
54
54
|
OPERATOR_KEYWORDS = %i[and or].freeze
|
55
55
|
SPECIAL_KEYWORDS = %w[__FILE__ __LINE__ __ENCODING__].freeze
|
56
56
|
|
57
|
-
# @see
|
57
|
+
# @see https://www.rubydoc.info/gems/ast/AST/Node:initialize
|
58
58
|
def initialize(type, children = [], properties = {})
|
59
59
|
@mutable_attributes = {}
|
60
60
|
|
data/lib/rubocop/ast/sexp.rb
CHANGED
@@ -5,7 +5,7 @@ module RuboCop
|
|
5
5
|
# This module provides a shorthand method to create a {Node} like
|
6
6
|
# `Parser::AST::Sexp`.
|
7
7
|
#
|
8
|
-
# @see
|
8
|
+
# @see https://www.rubydoc.info/gems/ast/AST/Sexp
|
9
9
|
module Sexp
|
10
10
|
# Creates a {Node} with type `type` and children `children`.
|
11
11
|
def s(type, *children)
|
data/lib/rubocop/cli.rb
CHANGED
@@ -10,9 +10,10 @@ module RuboCop
|
|
10
10
|
SKIPPED_PHASE_1 = 'Phase 1 of 2: run Metrics/LineLength cop (skipped ' \
|
11
11
|
'because the default Metrics/LineLength:Max is ' \
|
12
12
|
'overridden)'.freeze
|
13
|
-
STATUS_SUCCESS
|
14
|
-
STATUS_OFFENSES
|
15
|
-
STATUS_ERROR
|
13
|
+
STATUS_SUCCESS = 0
|
14
|
+
STATUS_OFFENSES = 1
|
15
|
+
STATUS_ERROR = 2
|
16
|
+
STATUS_INTERRUPTED = 128 + Signal.list['INT']
|
16
17
|
|
17
18
|
class Finished < RuntimeError; end
|
18
19
|
|
@@ -58,15 +59,6 @@ module RuboCop
|
|
58
59
|
end
|
59
60
|
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
60
61
|
|
61
|
-
def trap_interrupt(runner)
|
62
|
-
Signal.trap('INT') do
|
63
|
-
exit!(1) if runner.aborting?
|
64
|
-
runner.abort
|
65
|
-
warn
|
66
|
-
warn 'Exiting... Interrupt again to exit immediately.'
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
62
|
private
|
71
63
|
|
72
64
|
def execute_runners(paths)
|
@@ -118,6 +110,7 @@ module RuboCop
|
|
118
110
|
|
119
111
|
def reset_config_and_auto_gen_file
|
120
112
|
@config_store = ConfigStore.new
|
113
|
+
@config_store.options_config = @options[:config] if @options[:config]
|
121
114
|
File.open(ConfigLoader::AUTO_GENERATED_FILE, 'w') {}
|
122
115
|
ConfigLoader.add_inheritance_from_auto_generated_file
|
123
116
|
end
|
@@ -135,6 +128,7 @@ module RuboCop
|
|
135
128
|
ConfigLoader.debug = @options[:debug]
|
136
129
|
ConfigLoader.auto_gen_config = @options[:auto_gen_config]
|
137
130
|
ConfigLoader.ignore_parent_exclusion = @options[:ignore_parent_exclusion]
|
131
|
+
ConfigLoader.options_config = @options[:config]
|
138
132
|
|
139
133
|
@config_store.options_config = @options[:config] if @options[:config]
|
140
134
|
@config_store.force_default_config! if @options[:force_default_config]
|
@@ -153,7 +147,6 @@ module RuboCop
|
|
153
147
|
def execute_runner(paths)
|
154
148
|
runner = Runner.new(@options, @config_store)
|
155
149
|
|
156
|
-
trap_interrupt(runner)
|
157
150
|
all_passed = runner.run(paths)
|
158
151
|
display_warning_summary(runner.warnings)
|
159
152
|
display_error_summary(runner.errors)
|
@@ -161,7 +154,9 @@ module RuboCop
|
|
161
154
|
|
162
155
|
all_pass_or_excluded = all_passed || @options[:auto_gen_config]
|
163
156
|
|
164
|
-
if
|
157
|
+
if runner.aborting?
|
158
|
+
STATUS_INTERRUPTED
|
159
|
+
elsif all_pass_or_excluded && runner.errors.empty?
|
165
160
|
STATUS_SUCCESS
|
166
161
|
else
|
167
162
|
STATUS_OFFENSES
|
data/lib/rubocop/config.rb
CHANGED
@@ -14,7 +14,7 @@ module RuboCop
|
|
14
14
|
include PathUtil
|
15
15
|
include FileFinder
|
16
16
|
|
17
|
-
COMMON_PARAMS = %w[Exclude Include Severity
|
17
|
+
COMMON_PARAMS = %w[Exclude Include Severity inherit_mode
|
18
18
|
AutoCorrect StyleGuide Details].freeze
|
19
19
|
# 2.2 is the oldest officially supported Ruby version.
|
20
20
|
DEFAULT_RUBY_VERSION = 2.2
|
@@ -440,11 +440,11 @@ module RuboCop
|
|
440
440
|
end
|
441
441
|
|
442
442
|
def target_ruby_version
|
443
|
-
@target_ruby_version ||=
|
443
|
+
@target_ruby_version ||= begin
|
444
444
|
if for_all_cops['TargetRubyVersion']
|
445
445
|
@target_ruby_version_source = :rubocop_yml
|
446
446
|
|
447
|
-
for_all_cops['TargetRubyVersion']
|
447
|
+
for_all_cops['TargetRubyVersion'].to_f
|
448
448
|
elsif target_ruby_version_from_version_file
|
449
449
|
@target_ruby_version_source = :ruby_version_file
|
450
450
|
|
@@ -456,6 +456,7 @@ module RuboCop
|
|
456
456
|
else
|
457
457
|
DEFAULT_RUBY_VERSION
|
458
458
|
end
|
459
|
+
end
|
459
460
|
end
|
460
461
|
|
461
462
|
def target_rails_version
|
@@ -22,7 +22,8 @@ module RuboCop
|
|
22
22
|
class << self
|
23
23
|
include FileFinder
|
24
24
|
|
25
|
-
attr_accessor :debug, :auto_gen_config, :ignore_parent_exclusion
|
25
|
+
attr_accessor :debug, :auto_gen_config, :ignore_parent_exclusion,
|
26
|
+
:options_config
|
26
27
|
attr_writer :default_configuration
|
27
28
|
|
28
29
|
alias debug? debug
|
@@ -30,7 +31,7 @@ module RuboCop
|
|
30
31
|
alias ignore_parent_exclusion? ignore_parent_exclusion
|
31
32
|
|
32
33
|
def clear_options
|
33
|
-
@debug = @auto_gen_config = nil
|
34
|
+
@debug = @auto_gen_config = @options_config = nil
|
34
35
|
FileFinder.root_level = nil
|
35
36
|
end
|
36
37
|
|
@@ -43,7 +44,6 @@ module RuboCop
|
|
43
44
|
resolver.resolve_requires(path, hash)
|
44
45
|
|
45
46
|
add_missing_namespaces(path, hash)
|
46
|
-
target_ruby_version_to_f!(hash)
|
47
47
|
|
48
48
|
resolver.resolve_inheritance_from_gems(hash, hash.delete('inherit_gem'))
|
49
49
|
resolver.resolve_inheritance(path, hash, file, debug?)
|
@@ -117,36 +117,38 @@ module RuboCop
|
|
117
117
|
resolver.merge_with_default(config, config_file)
|
118
118
|
end
|
119
119
|
|
120
|
-
def target_ruby_version_to_f!(hash)
|
121
|
-
version = 'TargetRubyVersion'
|
122
|
-
return unless hash['AllCops'] && hash['AllCops'][version]
|
123
|
-
|
124
|
-
hash['AllCops'][version] = hash['AllCops'][version].to_f
|
125
|
-
end
|
126
|
-
|
127
120
|
def add_inheritance_from_auto_generated_file
|
128
121
|
file_string = " #{AUTO_GENERATED_FILE}"
|
129
122
|
|
130
|
-
|
131
|
-
|
123
|
+
config_file = options_config || DOTFILE
|
124
|
+
|
125
|
+
if File.exist?(config_file)
|
126
|
+
files = Array(load_yaml_configuration(config_file)['inherit_from'])
|
127
|
+
|
132
128
|
return if files.include?(AUTO_GENERATED_FILE)
|
133
129
|
|
134
130
|
files.unshift(AUTO_GENERATED_FILE)
|
135
131
|
file_string = "\n - " + files.join("\n - ") if files.size > 1
|
136
|
-
rubocop_yml_contents =
|
137
|
-
.sub(/^inherit_from: *[.\w]+/, '')
|
138
|
-
.sub(/^inherit_from: *(\n *- *[.\w]+)+/, '')
|
132
|
+
rubocop_yml_contents = existing_configuration(config_file)
|
139
133
|
end
|
140
|
-
|
134
|
+
|
135
|
+
write_config_file(config_file, file_string, rubocop_yml_contents)
|
136
|
+
|
141
137
|
puts "Added inheritance from `#{AUTO_GENERATED_FILE}` in `#{DOTFILE}`."
|
142
138
|
end
|
143
139
|
|
144
140
|
private
|
145
141
|
|
146
|
-
def
|
147
|
-
|
142
|
+
def existing_configuration(config_file)
|
143
|
+
IO.read(config_file, encoding: Encoding::UTF_8)
|
144
|
+
.sub(%r{^inherit_from: *[.\/\w]+}, '')
|
145
|
+
.sub(%r{^inherit_from: *(\n *- *[.\/\w]+)+}, '')
|
146
|
+
end
|
147
|
+
|
148
|
+
def write_config_file(file_name, file_string, rubocop_yml_contents)
|
149
|
+
File.open(file_name, 'w') do |f|
|
148
150
|
f.write "inherit_from:#{file_string}\n"
|
149
|
-
f.write "\n#{rubocop_yml_contents}" if rubocop_yml_contents
|
151
|
+
f.write "\n#{rubocop_yml_contents}" if rubocop_yml_contents =~ /\S/
|
150
152
|
end
|
151
153
|
end
|
152
154
|
|
@@ -181,11 +183,12 @@ module RuboCop
|
|
181
183
|
if defined?(SafeYAML) && SafeYAML.respond_to?(:load)
|
182
184
|
SafeYAML.load(yaml_code, filename,
|
183
185
|
whitelisted_tags: %w[!ruby/regexp])
|
184
|
-
|
186
|
+
# Ruby 2.6+
|
187
|
+
elsif Gem::Version.new(Psych::VERSION) >= Gem::Version.new('3.1.0.pre1')
|
185
188
|
YAML.safe_load(
|
186
189
|
yaml_code,
|
187
|
-
|
188
|
-
|
190
|
+
permitted_classes: [Regexp, Symbol],
|
191
|
+
permitted_symbols: [],
|
189
192
|
aliases: false,
|
190
193
|
filename: filename
|
191
194
|
)
|
@@ -76,11 +76,11 @@ module RuboCop
|
|
76
76
|
config_file)
|
77
77
|
end
|
78
78
|
|
79
|
-
# Returns a new hash where the parameters of the given config hash have
|
80
|
-
# been replaced by parameters returned by the given block.
|
81
79
|
# Return a recursive merge of two hashes. That is, a normal hash merge,
|
82
80
|
# with the addition that any value that is a hash, and occurs in both
|
83
81
|
# arguments, will also be merged. And so on.
|
82
|
+
#
|
83
|
+
# rubocop:disable Metrics/AbcSize
|
84
84
|
def merge(base_hash, derived_hash, **opts)
|
85
85
|
result = base_hash.merge(derived_hash)
|
86
86
|
keys_appearing_in_both = base_hash.keys & derived_hash.keys
|
@@ -95,6 +95,7 @@ module RuboCop
|
|
95
95
|
end
|
96
96
|
result
|
97
97
|
end
|
98
|
+
# rubocop:enable Metrics/AbcSize
|
98
99
|
|
99
100
|
private
|
100
101
|
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# This class auto-corrects `#each` enumeration to `for` iteration.
|
6
|
+
class EachToForCorrector
|
7
|
+
extend NodePattern::Macros
|
8
|
+
|
9
|
+
CORRECTION_WITH_ARGUMENTS =
|
10
|
+
'for %<variables>s in %<collection>s do'.freeze
|
11
|
+
CORRECTION_WITHOUT_ARGUMENTS = 'for _ in %<enumerable>s do'.freeze
|
12
|
+
|
13
|
+
def initialize(block_node)
|
14
|
+
@block_node = block_node
|
15
|
+
@collection_node = block_node.send_node.receiver
|
16
|
+
@argument_node = block_node.arguments
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(corrector)
|
20
|
+
corrector.replace(offending_range, correction)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_reader :block_node, :collection_node, :argument_node
|
26
|
+
|
27
|
+
def correction
|
28
|
+
if block_node.arguments?
|
29
|
+
format(CORRECTION_WITH_ARGUMENTS,
|
30
|
+
collection: collection_node.source,
|
31
|
+
variables: argument_node.children.first.source)
|
32
|
+
else
|
33
|
+
format(CORRECTION_WITHOUT_ARGUMENTS,
|
34
|
+
enumerable: collection_node.source)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def offending_range
|
39
|
+
if block_node.arguments?
|
40
|
+
replacement_range(argument_node.loc.expression.end_pos)
|
41
|
+
else
|
42
|
+
replacement_range(block_node.loc.begin.end_pos)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def replacement_range(end_pos)
|
47
|
+
Parser::Source::Range.new(block_node.loc.expression.source_buffer,
|
48
|
+
block_node.loc.expression.begin_pos,
|
49
|
+
end_pos)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# This class auto-corrects `for` iteration to `#each` enumeration.
|
6
|
+
class ForToEachCorrector
|
7
|
+
extend NodePattern::Macros
|
8
|
+
|
9
|
+
CORRECTION = '%<collection>s.each do |%<argument>s|'.freeze
|
10
|
+
|
11
|
+
def initialize(for_node)
|
12
|
+
@for_node = for_node
|
13
|
+
@variable_node = for_node.variable
|
14
|
+
@collection_node = for_node.collection
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(corrector)
|
18
|
+
corrector.replace(offending_range, correction)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
attr_reader :for_node, :variable_node, :collection_node
|
24
|
+
|
25
|
+
def correction
|
26
|
+
format(CORRECTION, collection: collection_source,
|
27
|
+
argument: variable_node.source)
|
28
|
+
end
|
29
|
+
|
30
|
+
def collection_source
|
31
|
+
if requires_parentheses?
|
32
|
+
"(#{collection_node.source})"
|
33
|
+
else
|
34
|
+
collection_node.source
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def requires_parentheses?
|
39
|
+
collection_node.irange_type? || collection_node.erange_type?
|
40
|
+
end
|
41
|
+
|
42
|
+
def end_position
|
43
|
+
if for_node.do?
|
44
|
+
keyword_begin.end_pos
|
45
|
+
else
|
46
|
+
collection_end.end_pos
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def keyword_begin
|
51
|
+
for_node.loc.begin
|
52
|
+
end
|
53
|
+
|
54
|
+
def collection_end
|
55
|
+
if collection_node.begin_type?
|
56
|
+
collection_node.loc.end
|
57
|
+
else
|
58
|
+
collection_node.loc.expression
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def offending_range
|
63
|
+
replacement_range(end_position)
|
64
|
+
end
|
65
|
+
|
66
|
+
def replacement_range(end_pos)
|
67
|
+
Parser::Source::Range.new(for_node.loc.expression.source_buffer,
|
68
|
+
for_node.loc.expression.begin_pos,
|
69
|
+
end_pos)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# This class auto-corrects lambda literal to method notation.
|
6
|
+
class LambdaLiteralToMethodCorrector
|
7
|
+
def initialize(block_node)
|
8
|
+
@block_node = block_node
|
9
|
+
@method = block_node.send_node
|
10
|
+
@arguments = block_node.arguments
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(corrector)
|
14
|
+
# Check for unparenthesized args' preceding and trailing whitespaces.
|
15
|
+
remove_unparenthesized_whitespace(corrector)
|
16
|
+
|
17
|
+
# Avoid correcting to `lambdado` by inserting whitespace
|
18
|
+
# if none exists before or after the lambda arguments.
|
19
|
+
insert_separating_space(corrector)
|
20
|
+
|
21
|
+
replace_selector(corrector)
|
22
|
+
remove_arguments(corrector)
|
23
|
+
|
24
|
+
replace_delimiters(corrector)
|
25
|
+
|
26
|
+
insert_arguments(corrector)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
attr_reader :block_node, :method, :arguments
|
32
|
+
|
33
|
+
def remove_unparenthesized_whitespace(corrector)
|
34
|
+
return unless !arguments.empty? && !arguments.parenthesized_call?
|
35
|
+
|
36
|
+
remove_leading_whitespace(corrector)
|
37
|
+
remove_trailing_whitespace(corrector)
|
38
|
+
end
|
39
|
+
|
40
|
+
def insert_separating_space(corrector)
|
41
|
+
return unless needs_separating_space?
|
42
|
+
|
43
|
+
corrector.insert_before(block_begin, ' ')
|
44
|
+
end
|
45
|
+
|
46
|
+
def replace_selector(corrector)
|
47
|
+
corrector.replace(method.source_range, 'lambda')
|
48
|
+
end
|
49
|
+
|
50
|
+
def remove_arguments(corrector)
|
51
|
+
return if arguments.empty_and_without_delimiters?
|
52
|
+
|
53
|
+
corrector.remove(arguments.source_range)
|
54
|
+
end
|
55
|
+
|
56
|
+
def insert_arguments(corrector)
|
57
|
+
return if arguments.empty?
|
58
|
+
|
59
|
+
arg_str = " |#{lambda_arg_string}|"
|
60
|
+
corrector.insert_after(block_node.loc.begin, arg_str)
|
61
|
+
end
|
62
|
+
|
63
|
+
def remove_leading_whitespace(corrector)
|
64
|
+
corrector.remove_preceding(
|
65
|
+
arguments.source_range,
|
66
|
+
arguments.source_range.begin_pos -
|
67
|
+
block_node.send_node.source_range.end_pos
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
def remove_trailing_whitespace(corrector)
|
72
|
+
corrector.remove_preceding(
|
73
|
+
block_begin,
|
74
|
+
block_begin.begin_pos - arguments.source_range.end_pos - 1
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
def replace_delimiters(corrector)
|
79
|
+
return if block_node.braces? || !arg_to_unparenthesized_call?
|
80
|
+
|
81
|
+
corrector.insert_after(block_begin, ' ') unless separating_space?
|
82
|
+
|
83
|
+
corrector.replace(block_begin, '{')
|
84
|
+
corrector.replace(block_end, '}')
|
85
|
+
end
|
86
|
+
|
87
|
+
def lambda_arg_string
|
88
|
+
arguments.children.map(&:source).join(', ')
|
89
|
+
end
|
90
|
+
|
91
|
+
def needs_separating_space?
|
92
|
+
block_begin.begin_pos == arguments_end_pos &&
|
93
|
+
selector_end.end_pos == arguments_begin_pos ||
|
94
|
+
block_begin.begin_pos == selector_end.end_pos
|
95
|
+
end
|
96
|
+
|
97
|
+
def arguments_end_pos
|
98
|
+
arguments.loc.end && arguments.loc.end.end_pos
|
99
|
+
end
|
100
|
+
|
101
|
+
def arguments_begin_pos
|
102
|
+
arguments.loc.begin && arguments.loc.begin.begin_pos
|
103
|
+
end
|
104
|
+
|
105
|
+
def block_end
|
106
|
+
block_node.loc.end
|
107
|
+
end
|
108
|
+
|
109
|
+
def block_begin
|
110
|
+
block_node.loc.begin
|
111
|
+
end
|
112
|
+
|
113
|
+
def selector_end
|
114
|
+
method.loc.selector.end
|
115
|
+
end
|
116
|
+
|
117
|
+
def arg_to_unparenthesized_call?
|
118
|
+
current_node = block_node
|
119
|
+
|
120
|
+
parent = current_node.parent
|
121
|
+
|
122
|
+
if parent && parent.pair_type?
|
123
|
+
current_node = parent.parent
|
124
|
+
parent = current_node.parent
|
125
|
+
end
|
126
|
+
|
127
|
+
return false unless parent && parent.send_type?
|
128
|
+
return false if parent.parenthesized_call?
|
129
|
+
|
130
|
+
current_node.sibling_index > 1
|
131
|
+
end
|
132
|
+
|
133
|
+
def separating_space?
|
134
|
+
block_begin.source_buffer.source[block_begin.begin_pos + 2].match(/\s/)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|