standard 1.27.0 → 1.28.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/.gitignore +1 -0
- data/CHANGELOG.md +18 -0
- data/Gemfile +6 -4
- data/Gemfile.lock +10 -7
- data/LICENSE.txt +3 -4
- data/README.md +353 -465
- data/bin/console +0 -4
- data/bin/run +9 -0
- data/config/base.yml +0 -161
- data/config/default.yml +9 -0
- data/config/ruby-2.2.yml +0 -3
- data/docs/ARCHITECTURE.md +31 -0
- data/lib/standard/base/plugin.rb +65 -0
- data/lib/standard/base.rb +8 -0
- data/lib/standard/creates_config_store/assigns_rubocop_yaml.rb +1 -35
- data/lib/standard/creates_config_store/merges_user_config_extensions.rb +21 -51
- data/lib/standard/creates_config_store.rb +2 -0
- data/lib/standard/formatter.rb +1 -1
- data/lib/standard/loads_yaml_config.rb +1 -0
- data/lib/standard/plugin/combines_plugin_configs.rb +15 -0
- data/lib/standard/plugin/creates_runner_context.rb +15 -0
- data/lib/standard/plugin/determines_class_constant.rb +56 -0
- data/lib/standard/plugin/initializes_plugins.rb +23 -0
- data/lib/standard/plugin/merges_plugins_into_rubocop_config.rb +158 -0
- data/lib/standard/plugin/standardizes_configured_plugins.rb +37 -0
- data/lib/standard/plugin.rb +11 -0
- data/lib/standard/railtie.rb +1 -1
- data/lib/standard/runners/help.rb +2 -2
- data/lib/standard/runners/rubocop.rb +1 -1
- data/lib/standard/version.rb +1 -1
- data/lib/standard.rb +5 -2
- data/standard.gemspec +5 -2
- metadata +54 -15
- data/lib/standard/cop/block_single_line_braces.rb +0 -96
@@ -0,0 +1,158 @@
|
|
1
|
+
module Standard
|
2
|
+
module Plugin
|
3
|
+
class MergesPluginsIntoRubocopConfig
|
4
|
+
# Blank configuration object to merge plugins into, with only the following spared:
|
5
|
+
# - AllCops keys set to avoid warnings about unknown properties
|
6
|
+
# - Lint/Syntax must be set to avoid a nil error when verifying inherited configs
|
7
|
+
MANDATORY_RUBOCOP_CONFIG_KEYS = ["AllCops", "Lint/Syntax"].freeze
|
8
|
+
|
9
|
+
# AllCops keys that standard does not allow to be set by plugins
|
10
|
+
DISALLOWED_ALLCOPS_KEYS = [
|
11
|
+
"Include",
|
12
|
+
"Exclude",
|
13
|
+
"StyleGuideBaseURL",
|
14
|
+
"StyleGuideCopsOnly",
|
15
|
+
"TargetRubyVersion",
|
16
|
+
"EnabledByDefault",
|
17
|
+
"DisabledByDefault",
|
18
|
+
|
19
|
+
# The AllCops[Enabled] key is an unused artifact of #merge_with_default.
|
20
|
+
# See: https://github.com/rubocop/rubocop/blob/master/lib/rubocop/config_loader_resolver.rb#L81-L85
|
21
|
+
"Enabled"
|
22
|
+
].freeze
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
@creates_runner_context = Standard::Plugin::CreatesRunnerContext.new
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(options_config, standard_config, plugins, permit_merging:)
|
29
|
+
runner_context = @creates_runner_context.call(standard_config)
|
30
|
+
plugin_config = combine_rubocop_configs(options_config, runner_context, plugins).to_h
|
31
|
+
merge_config_into_all_cops!(options_config, plugin_config)
|
32
|
+
merge_config_into_standard!(options_config, plugin_config, permit_merging: permit_merging)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def combine_rubocop_configs(options_config, runner_context, plugins)
|
38
|
+
fake_out_rubocop_default_configuration(options_config) do |fake_config|
|
39
|
+
all_cop_keys_configured_by_plugins = []
|
40
|
+
|
41
|
+
plugins.reduce(fake_config) do |combined_config, plugin|
|
42
|
+
RuboCop::ConfigLoader.instance_variable_set(:@default_configuration, combined_config)
|
43
|
+
next_config, path = config_for_plugin(plugin, runner_context)
|
44
|
+
|
45
|
+
next_config["AllCops"], all_cop_keys_configured_by_plugins = merge_all_cop_settings(
|
46
|
+
combined_config["AllCops"],
|
47
|
+
next_config["AllCops"],
|
48
|
+
all_cop_keys_configured_by_plugins
|
49
|
+
)
|
50
|
+
delete_already_configured_keys!(combined_config.keys, next_config, dont_delete_keys: ["AllCops"])
|
51
|
+
|
52
|
+
RuboCop::ConfigLoader.merge_with_default(next_config, path)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def config_for_plugin(plugin, runner_context)
|
58
|
+
rules = plugin.rules(runner_context)
|
59
|
+
|
60
|
+
if rules.type == :path
|
61
|
+
[RuboCop::ConfigLoader.load_file(rules.value), rules.value]
|
62
|
+
elsif rules.type == :object
|
63
|
+
[RuboCop::Config.new(rules.value), nil]
|
64
|
+
elsif rules.type == :error
|
65
|
+
raise "Plugin `#{plugin.about&.name || plugin.inspect}' failed to load with error: #{rules.value.respond_to?(:message) ? rules.value.message : rules.value}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# This is how we ensure "first-in wins": plugins can override AllCops settings that are
|
70
|
+
# set by RuboCop's default configuration, but once a plugin sets an AllCop setting, they
|
71
|
+
# have exclusive first-in-wins rights to that setting.
|
72
|
+
#
|
73
|
+
# The one exception to this are array fields, because we don't want to
|
74
|
+
# overwrite the AllCops defaults but rather munge the arrays (`existing |
|
75
|
+
# new`) to allow plugins to add to the array, for example Include and
|
76
|
+
# Exclude paths and patterns.
|
77
|
+
def merge_all_cop_settings(existing_all_cops, new_all_cops, already_configured_keys)
|
78
|
+
return [existing_all_cops, already_configured_keys] unless new_all_cops.is_a?(Hash)
|
79
|
+
|
80
|
+
combined_all_cops = existing_all_cops.dup
|
81
|
+
combined_configured_keys = already_configured_keys.dup
|
82
|
+
|
83
|
+
new_all_cops.each do |key, value|
|
84
|
+
if combined_all_cops[key].is_a?(Array) && value.is_a?(Array)
|
85
|
+
combined_all_cops[key] |= value
|
86
|
+
combined_configured_keys |= [key]
|
87
|
+
elsif !combined_configured_keys.include?(key)
|
88
|
+
combined_all_cops[key] = value
|
89
|
+
combined_configured_keys << key
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
[combined_all_cops, combined_configured_keys]
|
94
|
+
end
|
95
|
+
|
96
|
+
def delete_already_configured_keys!(configured_keys, next_config, dont_delete_keys: [])
|
97
|
+
duplicate_keys = configured_keys & Array(next_config&.keys)
|
98
|
+
|
99
|
+
(duplicate_keys - dont_delete_keys).each do |key|
|
100
|
+
next_config.delete(key)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def merge_config_into_all_cops!(options_config, plugin_config)
|
105
|
+
options_config["AllCops"].merge!(
|
106
|
+
except(plugin_config["AllCops"], DISALLOWED_ALLCOPS_KEYS)
|
107
|
+
)
|
108
|
+
end
|
109
|
+
|
110
|
+
def merge_config_into_standard!(options_config, plugin_config, permit_merging:)
|
111
|
+
if permit_merging
|
112
|
+
plugin_config.each do |key, value|
|
113
|
+
options_config[key] = if options_config[key].is_a?(Hash)
|
114
|
+
merge(options_config[key], value)
|
115
|
+
else
|
116
|
+
value
|
117
|
+
end
|
118
|
+
end
|
119
|
+
else
|
120
|
+
except(plugin_config, options_config.keys).each do |key, value|
|
121
|
+
options_config[key] = value
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def fake_out_rubocop_default_configuration(options_config)
|
127
|
+
og_default_config = RuboCop::ConfigLoader.instance_variable_get(:@default_configuration)
|
128
|
+
result = yield blank_rubocop_config(options_config)
|
129
|
+
RuboCop::ConfigLoader.instance_variable_set(:@default_configuration, og_default_config)
|
130
|
+
result
|
131
|
+
end
|
132
|
+
|
133
|
+
def blank_rubocop_config(example_config)
|
134
|
+
RuboCop::Config.new(example_config.to_h.slice(*MANDATORY_RUBOCOP_CONFIG_KEYS), "")
|
135
|
+
end
|
136
|
+
|
137
|
+
def except(hash_or_config, keys)
|
138
|
+
hash_or_config.to_h.reject { |key, _| keys.include?(key) }.to_h
|
139
|
+
end
|
140
|
+
|
141
|
+
# Always deletes nil entries, always overwrites arrays
|
142
|
+
# This is a simplified version of rubocop's ConfigLoader#merge:
|
143
|
+
# https://github.com/rubocop/rubocop/blob/v1.48.1/lib/rubocop/config_loader_resolver.rb#L98
|
144
|
+
def merge(old_hash, new_hash)
|
145
|
+
result = old_hash.merge(new_hash)
|
146
|
+
keys_appearing_in_both = old_hash.keys & new_hash.keys
|
147
|
+
keys_appearing_in_both.each do |key|
|
148
|
+
if new_hash[key].nil?
|
149
|
+
result.delete(key)
|
150
|
+
elsif old_hash[key].is_a?(Hash) && new_hash[key].is_a?(Hash)
|
151
|
+
result[key] = merge(old_hash[key], new_hash[key])
|
152
|
+
end
|
153
|
+
end
|
154
|
+
result
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Standard
|
2
|
+
module Plugin
|
3
|
+
class StandardizesConfiguredPlugins
|
4
|
+
DEFAULT_PLUGIN_CONFIG = {
|
5
|
+
"enabled" => true,
|
6
|
+
"require_path" => nil, # If not set, will be set to the plugin name
|
7
|
+
"plugin_class_name" => nil # If not set, looks for gemspec `spec.metadata["default_lint_roller_plugin"]`
|
8
|
+
}.freeze
|
9
|
+
|
10
|
+
BUILT_INS = [
|
11
|
+
{"standard-base" => {
|
12
|
+
"require_path" => "standard/base",
|
13
|
+
"plugin_class_name" => "Standard::Base::Plugin"
|
14
|
+
}},
|
15
|
+
"standard-custom",
|
16
|
+
"standard-performance"
|
17
|
+
].freeze
|
18
|
+
|
19
|
+
def call(plugins)
|
20
|
+
normalize_config_shape(BUILT_INS + plugins)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def normalize_config_shape(plugins)
|
26
|
+
plugins.map { |plugin|
|
27
|
+
if plugin.is_a?(Hash)
|
28
|
+
plugin_name = plugin.keys.first
|
29
|
+
[plugin_name, DEFAULT_PLUGIN_CONFIG.merge({"require_path" => plugin_name}, plugin.values.first)]
|
30
|
+
else
|
31
|
+
[plugin, DEFAULT_PLUGIN_CONFIG.merge("require_path" => plugin)]
|
32
|
+
end
|
33
|
+
}.to_h
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Standard
|
2
|
+
module Plugin
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
require_relative "plugin/creates_runner_context"
|
7
|
+
require_relative "plugin/combines_plugin_configs"
|
8
|
+
require_relative "plugin/merges_plugins_into_rubocop_config"
|
9
|
+
require_relative "plugin/standardizes_configured_plugins"
|
10
|
+
require_relative "plugin/determines_class_constant"
|
11
|
+
require_relative "plugin/initializes_plugins"
|
data/lib/standard/railtie.rb
CHANGED
@@ -27,7 +27,7 @@ module Standard
|
|
27
27
|
While Standard only offers a few configuration options, most can be set in
|
28
28
|
a `.standard.yml` file. For full documentation, please visit:
|
29
29
|
|
30
|
-
https://github.com/
|
30
|
+
https://github.com/standardrb/standard
|
31
31
|
|
32
32
|
Having trouble? Here's some diagnostic information:
|
33
33
|
|
@@ -39,7 +39,7 @@ module Standard
|
|
39
39
|
|
40
40
|
Please report any problems (and include the above information) at the URL below:
|
41
41
|
|
42
|
-
https://github.com/
|
42
|
+
https://github.com/standardrb/standard/issues/new
|
43
43
|
|
44
44
|
MESSAGE
|
45
45
|
end
|
@@ -19,7 +19,7 @@ module Standard
|
|
19
19
|
|
20
20
|
# This is a workaround for an issue with how `parallel` and `stdin`
|
21
21
|
# interact when invoked in this way. See:
|
22
|
-
# https://github.com/
|
22
|
+
# https://github.com/standardrb/standard/issues/536
|
23
23
|
def without_parallelizing_in_stdin_mode(options)
|
24
24
|
if options[:stdin]
|
25
25
|
options.delete(:parallel)
|
data/lib/standard/version.rb
CHANGED
data/lib/standard.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
1
|
require "rubocop"
|
2
|
+
require "lint_roller"
|
3
|
+
|
4
|
+
module Standard
|
5
|
+
end
|
2
6
|
|
3
7
|
require "standard/rubocop/ext"
|
4
8
|
|
@@ -9,5 +13,4 @@ require "standard/railtie" if defined?(Rails) && defined?(Rails::Railtie)
|
|
9
13
|
require "standard/formatter"
|
10
14
|
require "standard/cop/block_single_line_braces"
|
11
15
|
|
12
|
-
|
13
|
-
end
|
16
|
+
require "standard/plugin"
|
data/standard.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.required_ruby_version = ">= 2.6.0"
|
11
11
|
|
12
12
|
spec.summary = "Ruby Style Guide, with linter & automatic code fixer"
|
13
|
-
spec.homepage = "https://github.com/
|
13
|
+
spec.homepage = "https://github.com/standardrb/standard"
|
14
14
|
spec.metadata["homepage_uri"] = spec.homepage
|
15
15
|
spec.metadata["source_code_uri"] = spec.homepage
|
16
16
|
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
@@ -24,7 +24,10 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.metadata["rubygems_mfa_required"] = "true"
|
25
25
|
|
26
26
|
spec.add_dependency "rubocop", "~> 1.50.2"
|
27
|
-
|
27
|
+
|
28
|
+
spec.add_dependency "lint_roller", "~> 1.0"
|
29
|
+
spec.add_dependency "standard-custom", "~> 1.0.0"
|
30
|
+
spec.add_dependency "standard-performance", "~> 1.0.1"
|
28
31
|
|
29
32
|
# not semver: first three are lsp protocol version, last is patch
|
30
33
|
spec.add_dependency "language_server-protocol", "~> 3.17.0.2"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: standard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.28.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Searls
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-04-
|
11
|
+
date: 2023-04-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubocop
|
@@ -25,19 +25,47 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.50.2
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: lint_roller
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 1.
|
33
|
+
version: '1.0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 1.
|
40
|
+
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: standard-custom
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.0.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.0.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: standard-performance
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.0.1
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.0.1
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: language_server-protocol
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,7 +80,7 @@ dependencies:
|
|
52
80
|
- - "~>"
|
53
81
|
- !ruby/object:Gem::Version
|
54
82
|
version: 3.17.0.2
|
55
|
-
description:
|
83
|
+
description:
|
56
84
|
email:
|
57
85
|
- searls@gmail.com
|
58
86
|
executables:
|
@@ -72,8 +100,10 @@ files:
|
|
72
100
|
- README.md
|
73
101
|
- Rakefile
|
74
102
|
- bin/console
|
103
|
+
- bin/run
|
75
104
|
- bin/setup
|
76
105
|
- config/base.yml
|
106
|
+
- config/default.yml
|
77
107
|
- config/ruby-1.8.yml
|
78
108
|
- config/ruby-1.9.yml
|
79
109
|
- config/ruby-2.0.yml
|
@@ -86,13 +116,15 @@ files:
|
|
86
116
|
- config/ruby-2.7.yml
|
87
117
|
- config/ruby-3.0.yml
|
88
118
|
- config/ruby-3.1.yml
|
119
|
+
- docs/ARCHITECTURE.md
|
89
120
|
- docs/NEW_RUBIES.md
|
90
121
|
- docs/RELEASE.md
|
91
122
|
- exe/standardrb
|
92
123
|
- lib/standard.rb
|
124
|
+
- lib/standard/base.rb
|
125
|
+
- lib/standard/base/plugin.rb
|
93
126
|
- lib/standard/builds_config.rb
|
94
127
|
- lib/standard/cli.rb
|
95
|
-
- lib/standard/cop/block_single_line_braces.rb
|
96
128
|
- lib/standard/creates_config_store.rb
|
97
129
|
- lib/standard/creates_config_store/assigns_rubocop_yaml.rb
|
98
130
|
- lib/standard/creates_config_store/configures_ignored_paths.rb
|
@@ -108,6 +140,13 @@ files:
|
|
108
140
|
- lib/standard/lsp/server.rb
|
109
141
|
- lib/standard/lsp/standardizer.rb
|
110
142
|
- lib/standard/merges_settings.rb
|
143
|
+
- lib/standard/plugin.rb
|
144
|
+
- lib/standard/plugin/combines_plugin_configs.rb
|
145
|
+
- lib/standard/plugin/creates_runner_context.rb
|
146
|
+
- lib/standard/plugin/determines_class_constant.rb
|
147
|
+
- lib/standard/plugin/initializes_plugins.rb
|
148
|
+
- lib/standard/plugin/merges_plugins_into_rubocop_config.rb
|
149
|
+
- lib/standard/plugin/standardizes_configured_plugins.rb
|
111
150
|
- lib/standard/railtie.rb
|
112
151
|
- lib/standard/rake.rb
|
113
152
|
- lib/standard/resolves_yaml_option.rb
|
@@ -120,14 +159,14 @@ files:
|
|
120
159
|
- lib/standard/runners/version.rb
|
121
160
|
- lib/standard/version.rb
|
122
161
|
- standard.gemspec
|
123
|
-
homepage: https://github.com/
|
162
|
+
homepage: https://github.com/standardrb/standard
|
124
163
|
licenses: []
|
125
164
|
metadata:
|
126
|
-
homepage_uri: https://github.com/
|
127
|
-
source_code_uri: https://github.com/
|
128
|
-
changelog_uri: https://github.com/
|
165
|
+
homepage_uri: https://github.com/standardrb/standard
|
166
|
+
source_code_uri: https://github.com/standardrb/standard
|
167
|
+
changelog_uri: https://github.com/standardrb/standard/blob/main/CHANGELOG.md
|
129
168
|
rubygems_mfa_required: 'true'
|
130
|
-
post_install_message:
|
169
|
+
post_install_message:
|
131
170
|
rdoc_options: []
|
132
171
|
require_paths:
|
133
172
|
- lib
|
@@ -142,8 +181,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
142
181
|
- !ruby/object:Gem::Version
|
143
182
|
version: '0'
|
144
183
|
requirements: []
|
145
|
-
rubygems_version: 3.
|
146
|
-
signing_key:
|
184
|
+
rubygems_version: 3.4.10
|
185
|
+
signing_key:
|
147
186
|
specification_version: 4
|
148
187
|
summary: Ruby Style Guide, with linter & automatic code fixer
|
149
188
|
test_files: []
|
@@ -1,96 +0,0 @@
|
|
1
|
-
module RuboCop::Cop
|
2
|
-
module Standard
|
3
|
-
# Check for uses of braces around single line blocks, but allows either
|
4
|
-
# braces or do/end for multi-line blocks.
|
5
|
-
#
|
6
|
-
# @example
|
7
|
-
# # bad - single line block
|
8
|
-
# items.each do |item| item / 5 end
|
9
|
-
#
|
10
|
-
# # good - single line block
|
11
|
-
# items.each { |item| item / 5 }
|
12
|
-
#
|
13
|
-
class BlockSingleLineBraces < RuboCop::Cop::Base
|
14
|
-
extend RuboCop::Cop::AutoCorrector
|
15
|
-
|
16
|
-
def on_send(node)
|
17
|
-
return unless node.arguments?
|
18
|
-
return if node.parenthesized?
|
19
|
-
return if node.operator_method? || node.assignment_method?
|
20
|
-
|
21
|
-
node.arguments.each do |arg|
|
22
|
-
get_blocks(arg) do |block|
|
23
|
-
# If there are no parentheses around the arguments, then braces
|
24
|
-
# and do-end have different meaning due to how they bind, so we
|
25
|
-
# allow either.
|
26
|
-
ignore_node(block)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def on_block(node)
|
32
|
-
return if ignored_node?(node)
|
33
|
-
return if proper_block_style?(node)
|
34
|
-
|
35
|
-
message = message(node)
|
36
|
-
add_offense(node.loc.begin, message: message) do |corrector|
|
37
|
-
autocorrect(corrector, node)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
def get_blocks(node, &block)
|
44
|
-
case node.type
|
45
|
-
when :block
|
46
|
-
yield node
|
47
|
-
when :send
|
48
|
-
get_blocks(node.receiver, &block) if node.receiver
|
49
|
-
when :hash
|
50
|
-
# A hash which is passed as method argument may have no braces
|
51
|
-
# In that case, one of the K/V pairs could contain a block node
|
52
|
-
# which could change in meaning if do...end replaced {...}
|
53
|
-
return if node.braces?
|
54
|
-
|
55
|
-
node.each_child_node { |child| get_blocks(child, &block) }
|
56
|
-
when :pair
|
57
|
-
node.each_child_node { |child| get_blocks(child, &block) }
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def proper_block_style?(node)
|
62
|
-
node.multiline? || node.braces?
|
63
|
-
end
|
64
|
-
|
65
|
-
def message(node)
|
66
|
-
"Prefer `{...}` over `do...end` for single-line blocks."
|
67
|
-
end
|
68
|
-
|
69
|
-
def autocorrect(corrector, node)
|
70
|
-
return if correction_would_break_code?(node)
|
71
|
-
|
72
|
-
replace_do_end_with_braces(corrector, node.loc)
|
73
|
-
end
|
74
|
-
|
75
|
-
def correction_would_break_code?(node)
|
76
|
-
return unless node.keywords?
|
77
|
-
|
78
|
-
node.send_node.arguments? && !node.send_node.parenthesized?
|
79
|
-
end
|
80
|
-
|
81
|
-
def replace_do_end_with_braces(corrector, loc)
|
82
|
-
b = loc.begin
|
83
|
-
e = loc.end
|
84
|
-
|
85
|
-
corrector.insert_after(b, " ") unless whitespace_after?(b, 2)
|
86
|
-
|
87
|
-
corrector.replace(b, "{")
|
88
|
-
corrector.replace(e, "}")
|
89
|
-
end
|
90
|
-
|
91
|
-
def whitespace_after?(range, length = 1)
|
92
|
-
/\s/.match?(range.source_buffer.source[range.begin_pos + length, 1])
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|