standard 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of standard might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/.circleci/config.yml +31 -0
- data/.gitignore +8 -0
- data/.standard.yml +3 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +40 -0
- data/LICENSE.txt +24 -0
- data/README.md +335 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/config/base.yml +230 -0
- data/config/ruby-1.8.yml +8 -0
- data/config/ruby-1.9.yml +4 -0
- data/config/ruby-2.2.yml +8 -0
- data/exe/standard +7 -0
- data/exe/standardrb +7 -0
- data/lib/standard/cli.rb +36 -0
- data/lib/standard/config.rb +126 -0
- data/lib/standard/cop/semantic_blocks.rb +161 -0
- data/lib/standard/file_finder.rb +13 -0
- data/lib/standard/formatter.rb +34 -0
- data/lib/standard/railtie.rb +11 -0
- data/lib/standard/rake.rb +26 -0
- data/lib/standard/rubocop/ext.rb +7 -0
- data/lib/standard/version.rb +3 -0
- data/lib/standard.rb +12 -0
- data/standard.gemspec +26 -0
- metadata +128 -0
data/config/base.yml
ADDED
@@ -0,0 +1,230 @@
|
|
1
|
+
AllCops:
|
2
|
+
# Prevent RuboCop from exploding when it finds an older-than-2.2 .ruby-version
|
3
|
+
TargetRubyVersion: 2.5
|
4
|
+
|
5
|
+
Bundler/OrderedGems:
|
6
|
+
Enabled: false
|
7
|
+
|
8
|
+
Gemspec/OrderedDependencies:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
Layout/AlignParameters:
|
12
|
+
EnforcedStyle: with_fixed_indentation
|
13
|
+
|
14
|
+
Layout/AlignHash:
|
15
|
+
EnforcedLastArgumentHashStyle: always_ignore
|
16
|
+
|
17
|
+
# Disabled because IndentOneStep can't be configured for one-liner cases. See:
|
18
|
+
# https://github.com/rubocop-hq/rubocop/issues/6447
|
19
|
+
Layout/CaseIndentation:
|
20
|
+
Enabled: false
|
21
|
+
|
22
|
+
Layout/DotPosition:
|
23
|
+
EnforcedStyle: trailing
|
24
|
+
|
25
|
+
Layout/EmptyLineAfterGuardClause:
|
26
|
+
Enabled: false
|
27
|
+
|
28
|
+
Layout/EndAlignment:
|
29
|
+
EnforcedStyleAlignWith: variable
|
30
|
+
|
31
|
+
Layout/FirstParameterIndentation:
|
32
|
+
EnforcedStyle: consistent
|
33
|
+
|
34
|
+
Layout/IndentHash:
|
35
|
+
EnforcedStyle: consistent
|
36
|
+
|
37
|
+
Layout/IndentArray:
|
38
|
+
EnforcedStyle: consistent
|
39
|
+
|
40
|
+
Layout/MultilineMethodCallIndentation:
|
41
|
+
EnforcedStyle: indented
|
42
|
+
|
43
|
+
# Disabled without this:
|
44
|
+
# http://github.com/rubocop-hq/rubocop/issues/6446
|
45
|
+
Layout/SpaceInsideBlockBraces:
|
46
|
+
Enabled: false
|
47
|
+
|
48
|
+
Layout/SpaceInsideHashLiteralBraces:
|
49
|
+
EnforcedStyle: no_space
|
50
|
+
|
51
|
+
Lint/ScriptPermission:
|
52
|
+
Enabled: false
|
53
|
+
|
54
|
+
Metrics/AbcSize:
|
55
|
+
Enabled: false
|
56
|
+
|
57
|
+
Metrics/BlockLength:
|
58
|
+
Enabled: false
|
59
|
+
|
60
|
+
Metrics/BlockNesting:
|
61
|
+
Enabled: false
|
62
|
+
|
63
|
+
Metrics/ClassLength:
|
64
|
+
Enabled: false
|
65
|
+
|
66
|
+
Metrics/CyclomaticComplexity:
|
67
|
+
Enabled: false
|
68
|
+
|
69
|
+
Metrics/LineLength:
|
70
|
+
Enabled: false
|
71
|
+
|
72
|
+
Metrics/MethodLength:
|
73
|
+
Enabled: false
|
74
|
+
|
75
|
+
Metrics/ModuleLength:
|
76
|
+
Enabled: false
|
77
|
+
|
78
|
+
Metrics/ParameterLists:
|
79
|
+
Enabled: false
|
80
|
+
|
81
|
+
Metrics/PerceivedComplexity:
|
82
|
+
Enabled: false
|
83
|
+
|
84
|
+
Naming/PredicateName:
|
85
|
+
Enabled: false
|
86
|
+
|
87
|
+
Naming/UncommunicativeMethodParamName:
|
88
|
+
Enabled: false
|
89
|
+
|
90
|
+
Naming/VariableNumber:
|
91
|
+
Enabled: false
|
92
|
+
|
93
|
+
Performance/TimesMap:
|
94
|
+
Enabled: false
|
95
|
+
|
96
|
+
Security/MarshalLoad:
|
97
|
+
Enabled: false
|
98
|
+
|
99
|
+
Standard/SemanticBlocks:
|
100
|
+
ProceduralMethods:
|
101
|
+
- benchmark
|
102
|
+
- bm
|
103
|
+
- bmbm
|
104
|
+
- create
|
105
|
+
- each_with_object
|
106
|
+
- measure
|
107
|
+
- new
|
108
|
+
- realtime
|
109
|
+
- tap
|
110
|
+
- with_object
|
111
|
+
FunctionalMethods:
|
112
|
+
- let
|
113
|
+
- let!
|
114
|
+
- subject
|
115
|
+
- watch
|
116
|
+
- Given
|
117
|
+
- Given!
|
118
|
+
- Invariant
|
119
|
+
- Then
|
120
|
+
- And
|
121
|
+
IgnoredMethods:
|
122
|
+
- lambda
|
123
|
+
- proc
|
124
|
+
- it
|
125
|
+
- When
|
126
|
+
|
127
|
+
Style/AsciiComments:
|
128
|
+
Enabled: false
|
129
|
+
|
130
|
+
Style/BlockDelimiters:
|
131
|
+
Enabled: false
|
132
|
+
|
133
|
+
Style/BracesAroundHashParameters:
|
134
|
+
Enabled: false
|
135
|
+
|
136
|
+
Style/CaseEquality:
|
137
|
+
Enabled: false
|
138
|
+
|
139
|
+
Style/ClassAndModuleChildren:
|
140
|
+
Enabled: false
|
141
|
+
|
142
|
+
Style/CommentAnnotation:
|
143
|
+
Enabled: false
|
144
|
+
|
145
|
+
Style/Documentation:
|
146
|
+
Enabled: false
|
147
|
+
|
148
|
+
Style/DoubleNegation:
|
149
|
+
Enabled: false
|
150
|
+
|
151
|
+
Style/EmptyMethod:
|
152
|
+
EnforcedStyle: expanded
|
153
|
+
|
154
|
+
Style/ExpandPathArguments:
|
155
|
+
Enabled: false
|
156
|
+
|
157
|
+
Style/FormatStringToken:
|
158
|
+
Enabled: false
|
159
|
+
|
160
|
+
Style/FrozenStringLiteralComment:
|
161
|
+
EnforcedStyle: never
|
162
|
+
|
163
|
+
Style/GuardClause:
|
164
|
+
Enabled: false
|
165
|
+
|
166
|
+
Style/HashSyntax:
|
167
|
+
EnforcedStyle: ruby19_no_mixed_keys
|
168
|
+
|
169
|
+
Style/IfUnlessModifier:
|
170
|
+
Enabled: false
|
171
|
+
|
172
|
+
Style/InverseMethods:
|
173
|
+
Enabled: false
|
174
|
+
|
175
|
+
Style/MethodDefParentheses:
|
176
|
+
Enabled: false
|
177
|
+
|
178
|
+
Style/MultilineBlockChain:
|
179
|
+
Enabled: false
|
180
|
+
|
181
|
+
Style/MultilineTernaryOperator:
|
182
|
+
Enabled: false
|
183
|
+
|
184
|
+
Style/MultipleComparison:
|
185
|
+
Enabled: false
|
186
|
+
|
187
|
+
Style/MutableConstant:
|
188
|
+
Enabled: false
|
189
|
+
|
190
|
+
Style/NumericLiterals:
|
191
|
+
Enabled: false
|
192
|
+
|
193
|
+
Style/NumericPredicate:
|
194
|
+
Enabled: false
|
195
|
+
|
196
|
+
Style/RegexpLiteral:
|
197
|
+
Enabled: false
|
198
|
+
|
199
|
+
Style/RescueStandardError:
|
200
|
+
EnforcedStyle: implicit
|
201
|
+
|
202
|
+
Style/SignalException:
|
203
|
+
Enabled: false
|
204
|
+
|
205
|
+
Style/StringLiterals:
|
206
|
+
EnforcedStyle: double_quotes
|
207
|
+
|
208
|
+
Style/StringLiteralsInInterpolation:
|
209
|
+
EnforcedStyle: double_quotes
|
210
|
+
|
211
|
+
Style/StructInheritance:
|
212
|
+
Enabled: false
|
213
|
+
|
214
|
+
Style/SymbolArray:
|
215
|
+
Enabled: false
|
216
|
+
|
217
|
+
Style/TrailingCommaInArguments:
|
218
|
+
Enabled: false
|
219
|
+
|
220
|
+
Style/TrailingCommaInArrayLiteral:
|
221
|
+
EnforcedStyleForMultiline: consistent_comma
|
222
|
+
|
223
|
+
Style/TrailingCommaInHashLiteral:
|
224
|
+
EnforcedStyleForMultiline: consistent_comma
|
225
|
+
|
226
|
+
Style/WordArray:
|
227
|
+
Enabled: false
|
228
|
+
|
229
|
+
Style/ZeroLengthPredicate:
|
230
|
+
Enabled: false
|
data/config/ruby-1.8.yml
ADDED
data/config/ruby-1.9.yml
ADDED
data/config/ruby-2.2.yml
ADDED
data/exe/standard
ADDED
data/exe/standardrb
ADDED
data/lib/standard/cli.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require_relative "config"
|
2
|
+
|
3
|
+
module Standard
|
4
|
+
class Cli
|
5
|
+
SUCCESS_STATUS_CODE = 0
|
6
|
+
FAILURE_STATUS_CODE = 1
|
7
|
+
|
8
|
+
def initialize(argv)
|
9
|
+
@config = Config.new(argv)
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
rubocop_config = @config.to_rubocop
|
14
|
+
runner = RuboCop::Runner.new(
|
15
|
+
rubocop_config.options,
|
16
|
+
rubocop_config.config_store
|
17
|
+
)
|
18
|
+
|
19
|
+
run_succeeded = runner.run(rubocop_config.paths)
|
20
|
+
|
21
|
+
if run_succeeded
|
22
|
+
SUCCESS_STATUS_CODE
|
23
|
+
else
|
24
|
+
(runner.warnings + runner.errors).each do |message|
|
25
|
+
warn message
|
26
|
+
end
|
27
|
+
puts <<-CALL_TO_ACTION.gsub(/^ {10}/, "")
|
28
|
+
|
29
|
+
Notice: Disagree with these rules? While StandardRB is pre-1.0.0, feel free to submit suggestions to:
|
30
|
+
https://github.com/testdouble/standard/issues/new
|
31
|
+
CALL_TO_ACTION
|
32
|
+
FAILURE_STATUS_CODE
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require "rubocop"
|
2
|
+
require "pathname"
|
3
|
+
require "yaml"
|
4
|
+
require_relative "file_finder"
|
5
|
+
require_relative "formatter"
|
6
|
+
|
7
|
+
module Standard
|
8
|
+
class Config
|
9
|
+
RuboCopConfig = Struct.new(:paths, :options, :config_store)
|
10
|
+
|
11
|
+
def initialize(argv)
|
12
|
+
filtered_argv, fix_flag = parse_argv(argv)
|
13
|
+
@rubocop_options, @paths = RuboCop::Options.new.parse(filtered_argv)
|
14
|
+
@standard_yml_path = FileFinder.new.call(".standard.yml", Dir.pwd)
|
15
|
+
@standard_config = init_standard_config(@standard_yml_path, fix_flag)
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_rubocop
|
19
|
+
RuboCopConfig.new(
|
20
|
+
@paths,
|
21
|
+
wrap_rubocop_options(@rubocop_options),
|
22
|
+
RuboCop::ConfigStore.new.tap(&method(:mutate_config_store!))
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# Filtered b/c RuboCop will switch to --only Layout when --fix is set (undocumented behavior)
|
29
|
+
def parse_argv(argv)
|
30
|
+
filtered_argv = argv.dup
|
31
|
+
fix_flag = !!filtered_argv.delete("--fix")
|
32
|
+
[filtered_argv, fix_flag]
|
33
|
+
end
|
34
|
+
|
35
|
+
def init_standard_config(yml_path, fix_flag)
|
36
|
+
user_config = YAML.load_file(Pathname.new(Dir.pwd).join(yml_path)) if yml_path
|
37
|
+
user_config ||= {}
|
38
|
+
|
39
|
+
{
|
40
|
+
:fix => fix_flag || !!user_config["fix"],
|
41
|
+
:format => user_config["format"],
|
42
|
+
:ignore => expand_ignore_config(user_config["ignore"]),
|
43
|
+
:parallel => !!user_config["parallel"],
|
44
|
+
:ruby_version => ruby_version(user_config["ruby_version"] || RUBY_VERSION),
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def wrap_rubocop_options(rubocop_options)
|
49
|
+
{
|
50
|
+
:auto_correct => @standard_config[:fix],
|
51
|
+
:safe_auto_correct => @standard_config[:fix],
|
52
|
+
:formatters => [[@standard_config[:format] || "Standard::Formatter", nil]],
|
53
|
+
:parallel => @standard_config[:parallel],
|
54
|
+
}.merge(rubocop_options)
|
55
|
+
end
|
56
|
+
|
57
|
+
def mutate_config_store!(config_store)
|
58
|
+
config_store.options_config = rubocop_yaml_path(@standard_config[:ruby_version])
|
59
|
+
options_config = config_store.instance_variable_get("@options_config")
|
60
|
+
|
61
|
+
options_config["AllCops"]["TargetRubyVersion"] = floatify_version(
|
62
|
+
minimum_rubocop_supported_version(@standard_config[:ruby_version])
|
63
|
+
)
|
64
|
+
|
65
|
+
@standard_config[:ignore].each do |(path, cops)|
|
66
|
+
cops.each do |cop|
|
67
|
+
options_config[cop] ||= {}
|
68
|
+
options_config[cop]["Exclude"] ||= []
|
69
|
+
options_config[cop]["Exclude"] |= [Pathname.new(@standard_yml_path).dirname.join(path).to_s]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def rubocop_yaml_path(desired_version)
|
75
|
+
file_name = if desired_version < Gem::Version.new("1.9")
|
76
|
+
"ruby-1.8.yml"
|
77
|
+
elsif desired_version < Gem::Version.new("2.0")
|
78
|
+
"ruby-1.9.yml"
|
79
|
+
elsif desired_version < Gem::Version.new("2.3")
|
80
|
+
"ruby-2.2.yml"
|
81
|
+
else
|
82
|
+
"base.yml"
|
83
|
+
end
|
84
|
+
|
85
|
+
Pathname.new(__dir__).join("../../config/#{file_name}")
|
86
|
+
end
|
87
|
+
|
88
|
+
def expand_ignore_config(ignore_config)
|
89
|
+
arrayify(ignore_config).map { |rule|
|
90
|
+
if rule.is_a?(String)
|
91
|
+
[rule, ["AllCops"]]
|
92
|
+
elsif rule.is_a?(Hash)
|
93
|
+
rule.entries.first
|
94
|
+
end
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
def ruby_version(version)
|
99
|
+
Gem::Version.new(version)
|
100
|
+
end
|
101
|
+
|
102
|
+
def floatify_version(version)
|
103
|
+
major, minor = version.segments
|
104
|
+
"#{major}.#{minor}".to_f # lol
|
105
|
+
end
|
106
|
+
|
107
|
+
def minimum_rubocop_supported_version(desired_version)
|
108
|
+
rubocop_supported_version = Gem::Version.new("2.2")
|
109
|
+
if desired_version < rubocop_supported_version
|
110
|
+
rubocop_supported_version
|
111
|
+
else
|
112
|
+
desired_version
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def arrayify(object)
|
117
|
+
if object.nil?
|
118
|
+
[]
|
119
|
+
elsif object.respond_to?(:to_ary)
|
120
|
+
object.to_ary || [object]
|
121
|
+
else
|
122
|
+
[object]
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
module RuboCop::Cop
|
2
|
+
module Standard
|
3
|
+
class SemanticBlocks < RuboCop::Cop::Cop
|
4
|
+
include RuboCop::Cop::IgnoredMethods
|
5
|
+
|
6
|
+
def on_send(node)
|
7
|
+
return unless node.arguments?
|
8
|
+
return if node.parenthesized? || node.operator_method?
|
9
|
+
|
10
|
+
node.arguments.each do |arg|
|
11
|
+
get_blocks(arg) do |block|
|
12
|
+
# If there are no parentheses around the arguments, then braces
|
13
|
+
# and do-end have different meaning due to how they bind, so we
|
14
|
+
# allow either.
|
15
|
+
ignore_node(block)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def on_block(node)
|
21
|
+
return if ignored_node?(node) || proper_block_style?(node)
|
22
|
+
|
23
|
+
add_offense(node, :location => :begin)
|
24
|
+
end
|
25
|
+
|
26
|
+
def autocorrect(node)
|
27
|
+
return if correction_would_break_code?(node)
|
28
|
+
|
29
|
+
if node.single_line?
|
30
|
+
replace_do_end_with_braces(node.loc)
|
31
|
+
elsif node.braces?
|
32
|
+
replace_braces_with_do_end(node.loc)
|
33
|
+
else
|
34
|
+
replace_do_end_with_braces(node.loc)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def message(node)
|
41
|
+
if node.single_line?
|
42
|
+
"Prefer `{...}` over `do...end` for single-line blocks."
|
43
|
+
elsif node.loc.begin.source == "{"
|
44
|
+
"Prefer `do...end` over `{...}` for procedural blocks."
|
45
|
+
else
|
46
|
+
"Prefer `{...}` over `do...end` for functional blocks."
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def replace_braces_with_do_end(loc)
|
51
|
+
b = loc.begin
|
52
|
+
e = loc.end
|
53
|
+
|
54
|
+
lambda do |corrector|
|
55
|
+
corrector.insert_before(b, " ") unless whitespace_before?(b)
|
56
|
+
corrector.insert_before(e, " ") unless whitespace_before?(e)
|
57
|
+
corrector.insert_after(b, " ") unless whitespace_after?(b)
|
58
|
+
corrector.replace(b, "do")
|
59
|
+
corrector.replace(e, "end")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def replace_do_end_with_braces(loc)
|
64
|
+
b = loc.begin
|
65
|
+
e = loc.end
|
66
|
+
|
67
|
+
lambda do |corrector|
|
68
|
+
corrector.insert_after(b, " ") unless whitespace_after?(b, 2)
|
69
|
+
|
70
|
+
corrector.replace(b, "{")
|
71
|
+
corrector.replace(e, "}")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def whitespace_before?(range)
|
76
|
+
range.source_buffer.source[range.begin_pos - 1, 1] =~ /\s/
|
77
|
+
end
|
78
|
+
|
79
|
+
def whitespace_after?(range, length = 1)
|
80
|
+
range.source_buffer.source[range.begin_pos + length, 1] =~ /\s/
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_blocks(node, &block)
|
84
|
+
case node.type
|
85
|
+
when :block
|
86
|
+
yield node
|
87
|
+
when :send
|
88
|
+
get_blocks(node.receiver, &block) if node.receiver
|
89
|
+
when :hash
|
90
|
+
# A hash which is passed as method argument may have no braces
|
91
|
+
# In that case, one of the K/V pairs could contain a block node
|
92
|
+
# which could change in meaning if do...end replaced {...}
|
93
|
+
return if node.braces?
|
94
|
+
|
95
|
+
node.each_child_node { |child| get_blocks(child, &block) }
|
96
|
+
when :pair
|
97
|
+
node.each_child_node { |child| get_blocks(child, &block) }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def proper_block_style?(node)
|
102
|
+
method_name = node.method_name
|
103
|
+
|
104
|
+
if ignored_method?(method_name)
|
105
|
+
true
|
106
|
+
elsif node.single_line?
|
107
|
+
node.braces?
|
108
|
+
elsif node.braces?
|
109
|
+
functional_method?(method_name) || functional_block?(node)
|
110
|
+
else
|
111
|
+
procedural_method?(method_name) || !return_value_used?(node)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def correction_would_break_code?(node)
|
116
|
+
return unless node.keywords?
|
117
|
+
|
118
|
+
node.send_node.arguments? && !node.send_node.parenthesized?
|
119
|
+
end
|
120
|
+
|
121
|
+
def functional_method?(method_name)
|
122
|
+
cop_config["FunctionalMethods"].map(&:to_sym).include?(method_name)
|
123
|
+
end
|
124
|
+
|
125
|
+
def functional_block?(node)
|
126
|
+
return_value_used?(node) || return_value_of_scope?(node)
|
127
|
+
end
|
128
|
+
|
129
|
+
def procedural_method?(method_name)
|
130
|
+
cop_config["ProceduralMethods"].map(&:to_sym).include?(method_name)
|
131
|
+
end
|
132
|
+
|
133
|
+
def return_value_used?(node)
|
134
|
+
return unless node.parent
|
135
|
+
|
136
|
+
# If there are parentheses around the block, check if that
|
137
|
+
# is being used.
|
138
|
+
if node.parent.begin_type?
|
139
|
+
return_value_used?(node.parent)
|
140
|
+
else
|
141
|
+
node.parent.assignment? || node.parent.send_type?
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def return_value_of_scope?(node)
|
146
|
+
return unless node.parent
|
147
|
+
|
148
|
+
conditional?(node.parent) || array_or_range?(node.parent) ||
|
149
|
+
node.parent.children.last == node
|
150
|
+
end
|
151
|
+
|
152
|
+
def conditional?(node)
|
153
|
+
node.if_type? || node.or_type? || node.and_type?
|
154
|
+
end
|
155
|
+
|
156
|
+
def array_or_range?(node)
|
157
|
+
node.array_type? || node.irange_type? || node.erange_type?
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "rubocop"
|
2
|
+
|
3
|
+
module Standard
|
4
|
+
class Formatter < RuboCop::Formatter::BaseFormatter
|
5
|
+
def file_finished(file, offenses)
|
6
|
+
uncorrected_offenses = offenses.reject(&:corrected?)
|
7
|
+
print_header_once unless uncorrected_offenses.empty?
|
8
|
+
working_directory = Pathname.new(Dir.pwd)
|
9
|
+
|
10
|
+
uncorrected_offenses.each do |o|
|
11
|
+
absolute_path = Pathname.new(file)
|
12
|
+
relative_path = absolute_path.relative_path_from(working_directory)
|
13
|
+
output.printf(" %s:%d:%d: %s\n", relative_path, o.line, o.real_column, o.message.tr("\n", " "))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def print_header_once
|
20
|
+
return if @header_printed_already
|
21
|
+
command = if File.split($PROGRAM_NAME).last == "rake"
|
22
|
+
"rake standard:fix"
|
23
|
+
else
|
24
|
+
"standard --fix"
|
25
|
+
end
|
26
|
+
|
27
|
+
output.print <<-HEADER.gsub(/^ {8}/, "")
|
28
|
+
standard: Use Ruby Standard Style (https://github.com/testdouble/standard)
|
29
|
+
standard: Run `#{command}` to automatically fix some problems.
|
30
|
+
HEADER
|
31
|
+
@header_printed_already = true
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Standard
|
2
|
+
module RakeSupport
|
3
|
+
# Allow command line flags set in STANDARDOPTS (like MiniTest's TESTOPTS)
|
4
|
+
def self.argvify
|
5
|
+
if ENV["STANDARDOPTS"]
|
6
|
+
ENV["STANDARDOPTS"].split(/\s+/)
|
7
|
+
else
|
8
|
+
[]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "Lint with the Standard Ruby style guide"
|
15
|
+
task :standard do
|
16
|
+
require "standard"
|
17
|
+
exit_code = Standard::Cli.new(Standard::RakeSupport.argvify).run
|
18
|
+
fail unless exit_code == 0
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "Lint and automatically fix with the Standard Ruby style guide"
|
22
|
+
task :"standard:fix" do
|
23
|
+
require "standard"
|
24
|
+
exit_code = Standard::Cli.new(Standard::RakeSupport.argvify + ["--fix"]).run
|
25
|
+
fail unless exit_code == 0
|
26
|
+
end
|