standard 0.0.10

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.

data/config/base.yml ADDED
@@ -0,0 +1,234 @@
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
+ AutoCorrect: true
30
+ EnforcedStyleAlignWith: variable
31
+
32
+ Layout/FirstParameterIndentation:
33
+ EnforcedStyle: consistent
34
+
35
+ Lint/HandleExceptions:
36
+ Enabled: false
37
+
38
+ Layout/IndentHash:
39
+ EnforcedStyle: consistent
40
+
41
+ Layout/IndentArray:
42
+ EnforcedStyle: consistent
43
+
44
+ Layout/MultilineMethodCallIndentation:
45
+ EnforcedStyle: indented
46
+
47
+ # Disabled without this:
48
+ # http://github.com/rubocop-hq/rubocop/issues/6446
49
+ Layout/SpaceInsideBlockBraces:
50
+ Enabled: false
51
+
52
+ Layout/SpaceInsideHashLiteralBraces:
53
+ EnforcedStyle: no_space
54
+
55
+ Lint/ScriptPermission:
56
+ Enabled: false
57
+
58
+ Metrics/AbcSize:
59
+ Enabled: false
60
+
61
+ Metrics/BlockLength:
62
+ Enabled: false
63
+
64
+ Metrics/BlockNesting:
65
+ Enabled: false
66
+
67
+ Metrics/ClassLength:
68
+ Enabled: false
69
+
70
+ Metrics/CyclomaticComplexity:
71
+ Enabled: false
72
+
73
+ Metrics/LineLength:
74
+ Enabled: false
75
+
76
+ Metrics/MethodLength:
77
+ Enabled: false
78
+
79
+ Metrics/ModuleLength:
80
+ Enabled: false
81
+
82
+ Metrics/ParameterLists:
83
+ Enabled: false
84
+
85
+ Metrics/PerceivedComplexity:
86
+ Enabled: false
87
+
88
+ Naming/PredicateName:
89
+ Enabled: false
90
+
91
+ Naming/UncommunicativeMethodParamName:
92
+ Enabled: false
93
+
94
+ Naming/VariableNumber:
95
+ Enabled: false
96
+
97
+ Performance/TimesMap:
98
+ Enabled: false
99
+
100
+ Security/MarshalLoad:
101
+ Enabled: false
102
+
103
+ Standard/SemanticBlocks:
104
+ ProceduralMethods:
105
+ - benchmark
106
+ - bm
107
+ - bmbm
108
+ - create
109
+ - each_with_object
110
+ - measure
111
+ - new
112
+ - realtime
113
+ - tap
114
+ - with_object
115
+ FunctionalMethods:
116
+ - let
117
+ - let!
118
+ - subject
119
+ - watch
120
+ - Given
121
+ - Given!
122
+ - Invariant
123
+ - Then
124
+ - And
125
+ IgnoredMethods:
126
+ - lambda
127
+ - proc
128
+ - it
129
+ - When
130
+
131
+ Style/AsciiComments:
132
+ Enabled: false
133
+
134
+ Style/BlockDelimiters:
135
+ Enabled: false
136
+
137
+ Style/BracesAroundHashParameters:
138
+ Enabled: false
139
+
140
+ Style/CaseEquality:
141
+ Enabled: false
142
+
143
+ Style/ClassAndModuleChildren:
144
+ Enabled: false
145
+
146
+ Style/CommentAnnotation:
147
+ Enabled: false
148
+
149
+ Style/Documentation:
150
+ Enabled: false
151
+
152
+ Style/DoubleNegation:
153
+ Enabled: false
154
+
155
+ Style/EmptyMethod:
156
+ EnforcedStyle: expanded
157
+
158
+ Style/ExpandPathArguments:
159
+ Enabled: false
160
+
161
+ Style/FormatStringToken:
162
+ Enabled: false
163
+
164
+ Style/FrozenStringLiteralComment:
165
+ EnforcedStyle: never
166
+
167
+ Style/GuardClause:
168
+ Enabled: false
169
+
170
+ Style/HashSyntax:
171
+ EnforcedStyle: ruby19_no_mixed_keys
172
+
173
+ Style/IfUnlessModifier:
174
+ Enabled: false
175
+
176
+ Style/InverseMethods:
177
+ Enabled: false
178
+
179
+ Style/MethodDefParentheses:
180
+ Enabled: false
181
+
182
+ Style/MultilineBlockChain:
183
+ Enabled: false
184
+
185
+ Style/MultilineTernaryOperator:
186
+ Enabled: false
187
+
188
+ Style/MultipleComparison:
189
+ Enabled: false
190
+
191
+ Style/MutableConstant:
192
+ Enabled: false
193
+
194
+ Style/NumericLiterals:
195
+ Enabled: false
196
+
197
+ Style/NumericPredicate:
198
+ Enabled: false
199
+
200
+ Style/RegexpLiteral:
201
+ Enabled: false
202
+
203
+ Style/RescueStandardError:
204
+ EnforcedStyle: implicit
205
+
206
+ Style/SignalException:
207
+ Enabled: false
208
+
209
+ Style/StringLiterals:
210
+ EnforcedStyle: double_quotes
211
+
212
+ Style/StringLiteralsInInterpolation:
213
+ EnforcedStyle: double_quotes
214
+
215
+ Style/StructInheritance:
216
+ Enabled: false
217
+
218
+ Style/SymbolArray:
219
+ Enabled: false
220
+
221
+ Style/TrailingCommaInArguments:
222
+ Enabled: false
223
+
224
+ Style/TrailingCommaInArrayLiteral:
225
+ EnforcedStyleForMultiline: consistent_comma
226
+
227
+ Style/TrailingCommaInHashLiteral:
228
+ EnforcedStyleForMultiline: consistent_comma
229
+
230
+ Style/WordArray:
231
+ Enabled: false
232
+
233
+ Style/ZeroLengthPredicate:
234
+ Enabled: false
@@ -0,0 +1,8 @@
1
+ inherit_from: ./ruby-1.9.yml
2
+
3
+ Style/Lambda:
4
+ Enabled: false
5
+
6
+ Style/HashSyntax:
7
+ EnforcedStyle: hash_rockets
8
+
@@ -0,0 +1,4 @@
1
+ inherit_from: ./ruby-2.2.yml
2
+
3
+ Style/Encoding:
4
+ Enabled: false
@@ -0,0 +1,8 @@
1
+ inherit_from: ./base.yml
2
+
3
+ AllCops:
4
+ TargetRubyVersion: 2.2
5
+
6
+ Layout:
7
+ IndentHeredoc:
8
+ Enabled: false
data/exe/standard ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift("#{__dir__}/../lib")
4
+
5
+ require "standard"
6
+
7
+ exit Standard::Cli.new(ARGV).run
data/exe/standardrb ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift("#{__dir__}/../lib")
4
+
5
+ require "standard"
6
+
7
+ exit Standard::Cli.new(ARGV).run
@@ -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,13 @@
1
+ require "pathname"
2
+
3
+ module Standard
4
+ class FileFinder
5
+ def call(name, search_path)
6
+ Pathname.new(search_path).expand_path.ascend do |path|
7
+ if (file = path + name).exist?
8
+ return file.to_s
9
+ end
10
+ end
11
+ end
12
+ end
13
+ 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,11 @@
1
+ require "pathname"
2
+
3
+ module Standard
4
+ class Railtie < Rails::Railtie
5
+ railtie_name :standard
6
+
7
+ rake_tasks do
8
+ load Pathname.new(__dir__).join("rake.rb")
9
+ end
10
+ end
11
+ 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
@@ -0,0 +1,7 @@
1
+ module RuboCop
2
+ class Cop::Lint::AssignmentInCondition
3
+ def message(_)
4
+ "Wrap assignment in parentheses if intentional"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module Standard
2
+ VERSION = "0.0.10"
3
+ end