rubocop 1.3.1 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +18 -2
- data/lib/rubocop.rb +1 -0
- data/lib/rubocop/cli/command/execute_runner.rb +26 -11
- data/lib/rubocop/config_regeneration.rb +1 -1
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +77 -7
- data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +2 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/missing_super.rb +7 -4
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +13 -4
- data/lib/rubocop/cop/metrics/method_length.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
- data/lib/rubocop/cop/mixin/visibility_help.rb +1 -3
- data/lib/rubocop/cop/style/documentation.rb +12 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -2
- data/lib/rubocop/cop/style/redundant_argument.rb +73 -0
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/variable_force/branch.rb +1 -1
- data/lib/rubocop/cop/variable_force/scope.rb +1 -1
- data/lib/rubocop/formatter/disabled_config_formatter.rb +21 -6
- data/lib/rubocop/options.rb +5 -0
- data/lib/rubocop/rake_task.rb +2 -2
- data/lib/rubocop/runner.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- metadata +4 -8
- data/assets/logo.png +0 -0
- data/assets/output.html.erb +0 -261
- data/bin/console +0 -10
- data/bin/rubocop-profile +0 -32
- data/bin/setup +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 840dbd224c26defdcf3fe6d5c48f6e495f4288141a38f5e79de74552a0a1d9d8
|
4
|
+
data.tar.gz: 381215eaceb9e62bdb1ba0df04880b4b8c702bfd4e11df78d0683b539451fb3c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3a563aeb426e7ae74dcc9dbc28d153e3b672d0abcae22bea62ff6077bb2bb7eff78cdacf3f4f9a384d09ddc417744135c3a47536145052bbbca985008514b5e
|
7
|
+
data.tar.gz: 0c832cf607fa6fe0bd5513dc82f315638285f225c7456a2a884830cd173bb740ca741b4ea2279e908b8a00ecb94e60f40c7b2064841efa2152f50ce6a40477a2
|
data/README.md
CHANGED
@@ -51,7 +51,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
|
|
51
51
|
in your `Gemfile`:
|
52
52
|
|
53
53
|
```rb
|
54
|
-
gem 'rubocop', '~> 1.
|
54
|
+
gem 'rubocop', '~> 1.4', require: false
|
55
55
|
```
|
56
56
|
|
57
57
|
See [versioning](https://docs.rubocop.org/rubocop/1.0/versioning.html) for further details.
|
data/config/default.yml
CHANGED
@@ -463,6 +463,10 @@ Layout/EmptyLineBetweenDefs:
|
|
463
463
|
StyleGuide: '#empty-lines-between-methods'
|
464
464
|
Enabled: true
|
465
465
|
VersionAdded: '0.49'
|
466
|
+
VersionChanged: '1.4'
|
467
|
+
EmptyLineBetweenMethodDefs: true
|
468
|
+
EmptyLineBetweenClassDefs: true
|
469
|
+
EmptyLineBetweenModuleDefs: true
|
466
470
|
# If `true`, this parameter means that single line method definitions don't
|
467
471
|
# need an empty line between them.
|
468
472
|
AllowAdjacentOneLineDefs: false
|
@@ -891,8 +895,8 @@ Layout/LineLength:
|
|
891
895
|
StyleGuide: '#max-line-length'
|
892
896
|
Enabled: true
|
893
897
|
VersionAdded: '0.25'
|
894
|
-
VersionChanged: '1.
|
895
|
-
AutoCorrect:
|
898
|
+
VersionChanged: '1.4'
|
899
|
+
AutoCorrect: true
|
896
900
|
Max: 120
|
897
901
|
# To make it possible to copy or click on URIs in the code, we allow lines
|
898
902
|
# containing a URI to be longer than Max.
|
@@ -1684,6 +1688,7 @@ Lint/MissingSuper:
|
|
1684
1688
|
without calls to `super`'.
|
1685
1689
|
Enabled: true
|
1686
1690
|
VersionAdded: '0.89'
|
1691
|
+
VersionChanged: '1.4'
|
1687
1692
|
|
1688
1693
|
Lint/MixedRegexpCaptureTypes:
|
1689
1694
|
Description: 'Do not mix named captures and numbered captures in a Regexp literal.'
|
@@ -3976,6 +3981,17 @@ Style/RandomWithOffset:
|
|
3976
3981
|
Enabled: true
|
3977
3982
|
VersionAdded: '0.52'
|
3978
3983
|
|
3984
|
+
Style/RedundantArgument:
|
3985
|
+
Description: 'Check for a redundant argument passed to certain methods.'
|
3986
|
+
Enabled: pending
|
3987
|
+
Safe: false
|
3988
|
+
VersionAdded: '1.4'
|
3989
|
+
Methods:
|
3990
|
+
# Array#join
|
3991
|
+
join: ''
|
3992
|
+
# String#split
|
3993
|
+
split: ' '
|
3994
|
+
|
3979
3995
|
Style/RedundantAssignment:
|
3980
3996
|
Description: 'Checks for redundant assignment before returning.'
|
3981
3997
|
Enabled: true
|
data/lib/rubocop.rb
CHANGED
@@ -529,6 +529,7 @@ require_relative 'rubocop/cop/style/preferred_hash_methods'
|
|
529
529
|
require_relative 'rubocop/cop/style/proc'
|
530
530
|
require_relative 'rubocop/cop/style/raise_args'
|
531
531
|
require_relative 'rubocop/cop/style/random_with_offset'
|
532
|
+
require_relative 'rubocop/cop/style/redundant_argument'
|
532
533
|
require_relative 'rubocop/cop/style/redundant_begin'
|
533
534
|
require_relative 'rubocop/cop/style/redundant_capital_w'
|
534
535
|
require_relative 'rubocop/cop/style/redundant_condition'
|
@@ -22,12 +22,13 @@ module RuboCop
|
|
22
22
|
def execute_runner(paths)
|
23
23
|
runner = Runner.new(@options, @config_store)
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
all_pass_or_excluded = with_redirect do
|
26
|
+
all_passed = runner.run(paths)
|
27
|
+
display_summary(runner)
|
28
|
+
all_passed || @options[:auto_gen_config]
|
29
|
+
end
|
29
30
|
|
30
|
-
|
31
|
+
maybe_print_corrected_source
|
31
32
|
|
32
33
|
if runner.aborting?
|
33
34
|
STATUS_INTERRUPTED
|
@@ -38,6 +39,25 @@ module RuboCop
|
|
38
39
|
end
|
39
40
|
end
|
40
41
|
|
42
|
+
def with_redirect
|
43
|
+
if @options[:stderr]
|
44
|
+
orig_stdout = $stdout.dup
|
45
|
+
$stdout.reopen($stderr)
|
46
|
+
|
47
|
+
result = yield
|
48
|
+
|
49
|
+
$stdout.reopen(orig_stdout)
|
50
|
+
result
|
51
|
+
else
|
52
|
+
yield
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def display_summary(runner)
|
57
|
+
display_warning_summary(runner.warnings)
|
58
|
+
display_error_summary(runner.errors)
|
59
|
+
end
|
60
|
+
|
41
61
|
def display_warning_summary(warnings)
|
42
62
|
return if warnings.empty?
|
43
63
|
|
@@ -69,14 +89,9 @@ module RuboCop
|
|
69
89
|
# See: https://github.com/rubocop-hq/rubocop/issues/8673
|
70
90
|
return if INTEGRATION_FORMATTERS.include?(@options[:format])
|
71
91
|
|
72
|
-
# If we are asked to autocorrect source code read from stdin, the only
|
73
|
-
# reasonable place to write it is to stdout
|
74
|
-
# Unfortunately, we also write other information to stdout
|
75
|
-
# So a delimiter is needed for tools to easily identify where the
|
76
|
-
# autocorrected source begins
|
77
92
|
return unless @options[:stdin] && @options[:auto_correct]
|
78
93
|
|
79
|
-
puts '=' * 20
|
94
|
+
(@options[:stderr] ? $stderr : $stdout).puts '=' * 20
|
80
95
|
print @options[:stdin]
|
81
96
|
end
|
82
97
|
end
|
@@ -48,7 +48,7 @@ module RuboCop
|
|
48
48
|
def autocorrect_multiline_words(node, escape, delimiters)
|
49
49
|
contents = process_multiline_words(node, escape, delimiters)
|
50
50
|
contents << end_content(node.source)
|
51
|
-
contents.join
|
51
|
+
contents.join
|
52
52
|
end
|
53
53
|
|
54
54
|
def autocorrect_words(node, escape, delimiters)
|
@@ -38,7 +38,7 @@ module RuboCop
|
|
38
38
|
|
39
39
|
def assertions_using_described_class_msg
|
40
40
|
described_class_msg(processed_source.ast).reject do |node|
|
41
|
-
node.ancestors.any?
|
41
|
+
node.ancestors.any? { |ancestor| rspec_expectation_on_msg?(ancestor) }
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
@@ -13,7 +13,8 @@ module RuboCop
|
|
13
13
|
# `AllowAdjacentOneLineDefs` configures whether adjacent
|
14
14
|
# one-line method definitions are considered an offense.
|
15
15
|
#
|
16
|
-
# @example
|
16
|
+
# @example EmptyLineBetweenMethodDefs: true (default)
|
17
|
+
# # checks for empty lines between method definitions.
|
17
18
|
#
|
18
19
|
# # bad
|
19
20
|
# def a
|
@@ -29,11 +30,57 @@ module RuboCop
|
|
29
30
|
#
|
30
31
|
# def b
|
31
32
|
# end
|
33
|
+
#
|
34
|
+
# @example EmptyLineBetweenClassDefs: true (default)
|
35
|
+
# # checks for empty lines between class definitions.
|
36
|
+
#
|
37
|
+
# # bad
|
38
|
+
# class A
|
39
|
+
# end
|
40
|
+
# class B
|
41
|
+
# end
|
42
|
+
# def b
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# @example
|
46
|
+
#
|
47
|
+
# # good
|
48
|
+
# class A
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# class B
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# def b
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# @example EmptyLineBetweenModuleDefs: true (default)
|
58
|
+
# # checks for empty lines between module definitions.
|
59
|
+
#
|
60
|
+
# # bad
|
61
|
+
# module A
|
62
|
+
# end
|
63
|
+
# module B
|
64
|
+
# end
|
65
|
+
# def b
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# @example
|
69
|
+
#
|
70
|
+
# # good
|
71
|
+
# module A
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# module B
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# def b
|
78
|
+
# end
|
32
79
|
class EmptyLineBetweenDefs < Base
|
33
80
|
include RangeHelp
|
34
81
|
extend AutoCorrector
|
35
82
|
|
36
|
-
MSG = 'Use empty lines between
|
83
|
+
MSG = 'Use empty lines between %<type>s definitions.'
|
37
84
|
|
38
85
|
def self.autocorrect_incompatible_with
|
39
86
|
[Layout::EmptyLines]
|
@@ -47,7 +94,7 @@ module RuboCop
|
|
47
94
|
def on_begin(node)
|
48
95
|
node.children.each_cons(2) do |prev, n|
|
49
96
|
nodes = [prev, n]
|
50
|
-
check_defs(nodes) if nodes.all?(
|
97
|
+
check_defs(nodes) if nodes.all? { |def_candidate| candidate?(def_candidate) }
|
51
98
|
end
|
52
99
|
end
|
53
100
|
|
@@ -57,8 +104,9 @@ module RuboCop
|
|
57
104
|
return if nodes.all?(&:single_line?) &&
|
58
105
|
cop_config['AllowAdjacentOneLineDefs']
|
59
106
|
|
60
|
-
|
61
|
-
|
107
|
+
correction_node = nodes.last
|
108
|
+
location = correction_node.loc.keyword.join(correction_node.loc.name)
|
109
|
+
add_offense(location, message: message(correction_node)) do |corrector|
|
62
110
|
autocorrect(corrector, *nodes)
|
63
111
|
end
|
64
112
|
end
|
@@ -83,10 +131,32 @@ module RuboCop
|
|
83
131
|
|
84
132
|
private
|
85
133
|
|
86
|
-
def
|
134
|
+
def candidate?(node)
|
87
135
|
return unless node
|
88
136
|
|
89
|
-
node
|
137
|
+
method_candidate?(node) || class_candidate?(node) || module_candidate?(node)
|
138
|
+
end
|
139
|
+
|
140
|
+
def method_candidate?(node)
|
141
|
+
cop_config['EmptyLineBetweenMethodDefs'] && (node.def_type? || node.defs_type?)
|
142
|
+
end
|
143
|
+
|
144
|
+
def class_candidate?(node)
|
145
|
+
cop_config['EmptyLineBetweenClassDefs'] && node.class_type?
|
146
|
+
end
|
147
|
+
|
148
|
+
def module_candidate?(node)
|
149
|
+
cop_config['EmptyLineBetweenModuleDefs'] && node.module_type?
|
150
|
+
end
|
151
|
+
|
152
|
+
def message(node)
|
153
|
+
type = case node.type
|
154
|
+
when :def, :defs
|
155
|
+
:method
|
156
|
+
else
|
157
|
+
node.type
|
158
|
+
end
|
159
|
+
format(MSG, type: type)
|
90
160
|
end
|
91
161
|
|
92
162
|
def multiple_blank_lines_groups?(first_def_node, second_def_node)
|
@@ -53,7 +53,8 @@ module RuboCop
|
|
53
53
|
def find_offense_node(node, regexp_receiver)
|
54
54
|
return node unless node.parent
|
55
55
|
|
56
|
-
if node.parent.send_type?
|
56
|
+
if (node.parent.send_type? && node.receiver) ||
|
57
|
+
method_chain_to_regexp_receiver?(node, regexp_receiver)
|
57
58
|
node = find_offense_node(node.parent, regexp_receiver)
|
58
59
|
end
|
59
60
|
|
@@ -95,7 +95,7 @@ module RuboCop
|
|
95
95
|
def autocorrected_value_for_array(node)
|
96
96
|
return node.source.gsub('"', '\"') unless node.percent_literal?
|
97
97
|
|
98
|
-
contents_range(node).source.split
|
98
|
+
contents_range(node).source.split.to_s.gsub('"', '\"')
|
99
99
|
end
|
100
100
|
|
101
101
|
# Does node print its own source when converted to a string?
|
@@ -6,6 +6,11 @@ module RuboCop
|
|
6
6
|
# This cop checks for the presence of constructors and lifecycle callbacks
|
7
7
|
# without calls to `super`.
|
8
8
|
#
|
9
|
+
# This cop does not consider `method_missing` (and `respond_to_missing?`)
|
10
|
+
# because in some cases it makes sense to overtake what is considered a
|
11
|
+
# missing method. In other cases, the theoretical ideal handling could be
|
12
|
+
# challenging or verbose for no actual gain.
|
13
|
+
#
|
9
14
|
# @example
|
10
15
|
# # bad
|
11
16
|
# class Employee < Person
|
@@ -43,15 +48,13 @@ module RuboCop
|
|
43
48
|
|
44
49
|
STATELESS_CLASSES = %w[BasicObject Object].freeze
|
45
50
|
|
46
|
-
OBJECT_LIFECYCLE_CALLBACKS = %i[method_missing respond_to_missing?].freeze
|
47
51
|
CLASS_LIFECYCLE_CALLBACKS = %i[inherited].freeze
|
48
52
|
METHOD_LIFECYCLE_CALLBACKS = %i[method_added method_removed method_undefined
|
49
53
|
singleton_method_added singleton_method_removed
|
50
54
|
singleton_method_undefined].freeze
|
51
55
|
|
52
|
-
CALLBACKS = (
|
53
|
-
|
54
|
-
METHOD_LIFECYCLE_CALLBACKS).to_set.freeze
|
56
|
+
CALLBACKS = (CLASS_LIFECYCLE_CALLBACKS +
|
57
|
+
METHOD_LIFECYCLE_CALLBACKS).to_set.freeze
|
55
58
|
|
56
59
|
def on_def(node)
|
57
60
|
return unless offender?(node)
|
@@ -54,6 +54,9 @@ module RuboCop
|
|
54
54
|
# value
|
55
55
|
# end
|
56
56
|
#
|
57
|
+
# # good, recursive
|
58
|
+
# keys.reduce(self) { |result, key| result[key] }
|
59
|
+
#
|
57
60
|
# # ignored as the return value cannot be determined
|
58
61
|
# enum.reduce do |acc, el|
|
59
62
|
# x = foo(acc, el)
|
@@ -131,7 +134,7 @@ module RuboCop
|
|
131
134
|
element_name = block_arg_name(block_node, 1)
|
132
135
|
message_opts = { method: block_node.method_name, accum: accumulator_name }
|
133
136
|
|
134
|
-
if (node = returned_accumulator_index(return_values, accumulator_name))
|
137
|
+
if (node = returned_accumulator_index(return_values, accumulator_name, element_name))
|
135
138
|
add_offense(node, message: format(MSG_INDEX, message_opts))
|
136
139
|
elsif potential_offense?(return_values, block_node.body, element_name, accumulator_name)
|
137
140
|
return_values.each do |return_val|
|
@@ -146,11 +149,17 @@ module RuboCop
|
|
146
149
|
node.arguments[index].node_parts[0]
|
147
150
|
end
|
148
151
|
|
149
|
-
# Look for an index of the accumulator being returned
|
152
|
+
# Look for an index of the accumulator being returned, except where the index
|
153
|
+
# is the element.
|
150
154
|
# This is always an offense, in order to try to catch potential exceptions
|
151
155
|
# due to type mismatches
|
152
|
-
def returned_accumulator_index(return_values, accumulator_name)
|
153
|
-
return_values.detect
|
156
|
+
def returned_accumulator_index(return_values, accumulator_name, element_name)
|
157
|
+
return_values.detect do |val|
|
158
|
+
next unless accumulator_index?(val, accumulator_name)
|
159
|
+
next true if val.method?(:[]=)
|
160
|
+
|
161
|
+
val.arguments.none? { |arg| lvar_used?(arg, element_name) }
|
162
|
+
end
|
154
163
|
end
|
155
164
|
|
156
165
|
def potential_offense?(return_values, block_body, element_name, accumulator_name)
|
@@ -36,7 +36,7 @@ module RuboCop
|
|
36
36
|
|
37
37
|
def on_def(node)
|
38
38
|
excluded_methods = cop_config['ExcludedMethods']
|
39
|
-
return if excluded_methods.
|
39
|
+
return if excluded_methods.any? { |m| m.match? String(node.method_name) }
|
40
40
|
|
41
41
|
check_code_length(node)
|
42
42
|
end
|
@@ -31,7 +31,7 @@ module RuboCop
|
|
31
31
|
# b c { block }. <-- b is indented relative to a
|
32
32
|
# d <-- d is indented relative to a
|
33
33
|
def left_hand_side(lhs)
|
34
|
-
lhs = lhs.parent while lhs.parent&.send_type?
|
34
|
+
lhs = lhs.parent while lhs.parent&.send_type? && lhs.parent.loc.dot
|
35
35
|
lhs
|
36
36
|
end
|
37
37
|
|
@@ -16,9 +16,7 @@ module RuboCop
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def find_visibility_start(node)
|
19
|
-
node.left_siblings
|
20
|
-
.reverse
|
21
|
-
.find(&method(:visibility_block?))
|
19
|
+
node.left_siblings.reverse.find { |sibling| visibility_block?(sibling) }
|
22
20
|
end
|
23
21
|
|
24
22
|
# Navigate to find the last protected method
|
@@ -55,6 +55,11 @@ module RuboCop
|
|
55
55
|
# Public = Class.new
|
56
56
|
# end
|
57
57
|
#
|
58
|
+
# # Macro calls
|
59
|
+
# module Namespace
|
60
|
+
# extend Foo
|
61
|
+
# end
|
62
|
+
#
|
58
63
|
class Documentation < Base
|
59
64
|
include DocumentationComment
|
60
65
|
|
@@ -83,15 +88,21 @@ module RuboCop
|
|
83
88
|
return if documentation_comment?(node) || nodoc_comment?(node)
|
84
89
|
return if compact_namespace?(node) &&
|
85
90
|
nodoc_comment?(outer_module(node).first)
|
91
|
+
return if macro_only?(body)
|
86
92
|
|
87
93
|
add_offense(node.loc.keyword, message: format(MSG, type: type))
|
88
94
|
end
|
89
95
|
|
96
|
+
def macro_only?(body)
|
97
|
+
body.respond_to?(:macro?) && body.macro? ||
|
98
|
+
body.respond_to?(:children) && body.children&.all? { |child| macro_only?(child) }
|
99
|
+
end
|
100
|
+
|
90
101
|
def namespace?(node)
|
91
102
|
return false unless node
|
92
103
|
|
93
104
|
if node.begin_type?
|
94
|
-
node.children.all?
|
105
|
+
node.children.all? { |child| constant_declaration?(child) }
|
95
106
|
else
|
96
107
|
constant_definition?(node)
|
97
108
|
end
|
@@ -74,7 +74,7 @@ module RuboCop
|
|
74
74
|
parent &&
|
75
75
|
(logical_operator?(parent) ||
|
76
76
|
parent.send_type? &&
|
77
|
-
parent.arguments.any?
|
77
|
+
parent.arguments.any? { |argument| logical_operator?(argument) })
|
78
78
|
end
|
79
79
|
|
80
80
|
def call_in_optional_arguments?(node)
|
@@ -110,7 +110,7 @@ module RuboCop
|
|
110
110
|
def hash_literal_in_arguments?(node)
|
111
111
|
node.arguments.any? do |n|
|
112
112
|
hash_literal?(n) ||
|
113
|
-
n.send_type? && node.descendants.any?
|
113
|
+
n.send_type? && node.descendants.any? { |descendant| hash_literal?(descendant) }
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'parser/current'
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Style
|
8
|
+
# This cop checks for a redundant argument passed to certain methods.
|
9
|
+
#
|
10
|
+
# Limitations:
|
11
|
+
#
|
12
|
+
# 1. This cop matches for method names only and hence cannot tell apart
|
13
|
+
# methods with same name in different classes.
|
14
|
+
# 2. This cop is limited to methods with single parameter.
|
15
|
+
# 3. This cop is unsafe if certain special global variables (e.g. `$;`) are set.
|
16
|
+
# That depends on the nature of the target methods, of course.
|
17
|
+
#
|
18
|
+
# Method names and their redundant arguments can be configured like this:
|
19
|
+
#
|
20
|
+
# Methods:
|
21
|
+
# join: ''
|
22
|
+
# split: ' '
|
23
|
+
# foo: 2
|
24
|
+
#
|
25
|
+
# @example
|
26
|
+
# # bad
|
27
|
+
# array.join('')
|
28
|
+
# [1, 2, 3].join("")
|
29
|
+
# string.split(" ")
|
30
|
+
# "first\nsecond".split(" ")
|
31
|
+
# A.foo(2)
|
32
|
+
#
|
33
|
+
# # good
|
34
|
+
# array.join
|
35
|
+
# [1, 2, 3].join
|
36
|
+
# string.split
|
37
|
+
# "first second".split
|
38
|
+
# A.foo
|
39
|
+
class RedundantArgument < Cop
|
40
|
+
MSG = 'Argument %<arg>s is redundant because it is implied by default.'
|
41
|
+
|
42
|
+
def on_send(node)
|
43
|
+
return unless redundant_argument?(node)
|
44
|
+
|
45
|
+
add_offense(node, message: format(MSG, arg: node.arguments.first.source))
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def redundant_argument?(node)
|
51
|
+
redundant_argument = redundant_arg_for_method(node.method_name.to_s)
|
52
|
+
return false if redundant_argument.nil?
|
53
|
+
|
54
|
+
node.arguments.first == redundant_argument
|
55
|
+
end
|
56
|
+
|
57
|
+
def redundant_arg_for_method(method_name)
|
58
|
+
return nil unless cop_config['Methods'].key?(method_name)
|
59
|
+
|
60
|
+
@mem ||= {}
|
61
|
+
@mem[method_name] ||=
|
62
|
+
begin
|
63
|
+
arg = cop_config['Methods'].fetch(method_name)
|
64
|
+
buffer = Parser::Source::Buffer.new('(string)', 1)
|
65
|
+
buffer.source = arg.inspect
|
66
|
+
builder = RuboCop::AST::Builder.new
|
67
|
+
Parser::CurrentRuby.new(builder).parse(buffer)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/rubocop/cop/util.rb
CHANGED
@@ -53,7 +53,7 @@ module RuboCop
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def on_node(syms, sexp, excludes = [], &block)
|
56
|
-
return to_enum(:on_node, syms, sexp, excludes) unless
|
56
|
+
return to_enum(:on_node, syms, sexp, excludes) unless block
|
57
57
|
|
58
58
|
yield sexp if Array(syms).include?(sexp.type)
|
59
59
|
return if Array(excludes).include?(sexp.type)
|
@@ -78,7 +78,7 @@ module RuboCop
|
|
78
78
|
end
|
79
79
|
|
80
80
|
def each_ancestor(include_self: false, &block)
|
81
|
-
return to_enum(__method__, include_self: include_self) unless
|
81
|
+
return to_enum(__method__, include_self: include_self) unless block
|
82
82
|
|
83
83
|
yield self if include_self
|
84
84
|
scan_ancestors(&block)
|
@@ -5,6 +5,8 @@ module RuboCop
|
|
5
5
|
# This formatter displays a YAML configuration file where all cops that
|
6
6
|
# detected any offenses are configured to not detect the offense.
|
7
7
|
class DisabledConfigFormatter < BaseFormatter
|
8
|
+
include PathUtil
|
9
|
+
|
8
10
|
HEADING = <<~COMMENTS
|
9
11
|
# This configuration was generated by
|
10
12
|
# `%<command>s`
|
@@ -195,15 +197,28 @@ module RuboCop
|
|
195
197
|
end
|
196
198
|
|
197
199
|
def excludes(offending_files, cop_name, parent)
|
198
|
-
# Exclude properties in .rubocop_todo.yml override default ones, as well
|
199
|
-
#
|
200
|
-
#
|
201
|
-
#
|
202
|
-
# just look at the current working directory
|
200
|
+
# Exclude properties in .rubocop_todo.yml override default ones, as well as any custom
|
201
|
+
# excludes in .rubocop.yml, so in order to retain those excludes we must copy them.
|
202
|
+
# There can be multiple .rubocop.yml files in subdirectories, but we just look at the
|
203
|
+
# current working directory.
|
203
204
|
config = ConfigStore.new.for(parent)
|
204
205
|
cfg = config[cop_name] || {}
|
205
206
|
|
206
|
-
(
|
207
|
+
if merge_mode_for_exclude?(config) || merge_mode_for_exclude?(cfg)
|
208
|
+
offending_files
|
209
|
+
else
|
210
|
+
cop_exclude = cfg['Exclude']
|
211
|
+
if cop_exclude && cop_exclude != default_config(cop_name)['Exclude']
|
212
|
+
warn "`#{cop_name}: Exclude` in `#{smart_path(config.loaded_path)}` overrides a " \
|
213
|
+
'generated `Exclude` in `.rubocop_todo.yml`. Either remove ' \
|
214
|
+
"`#{cop_name}: Exclude` or add `inherit_mode: merge: - Exclude`."
|
215
|
+
end
|
216
|
+
((cop_exclude || []) + offending_files).uniq
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def merge_mode_for_exclude?(cfg)
|
221
|
+
Array(cfg.to_h.dig('inherit_mode', 'merge')).include?('Exclude')
|
207
222
|
end
|
208
223
|
|
209
224
|
def output_exclude_path(output_buffer, exclude_path, parent)
|
data/lib/rubocop/options.rb
CHANGED
@@ -5,6 +5,7 @@ require 'shellwords'
|
|
5
5
|
|
6
6
|
module RuboCop
|
7
7
|
class IncorrectCopNameError < StandardError; end
|
8
|
+
|
8
9
|
class OptionArgumentError < StandardError; end
|
9
10
|
|
10
11
|
# This class handles command line options.
|
@@ -195,6 +196,7 @@ module RuboCop
|
|
195
196
|
|
196
197
|
option(opts, '--safe')
|
197
198
|
|
199
|
+
option(opts, '--stderr')
|
198
200
|
option(opts, '--[no-]color')
|
199
201
|
|
200
202
|
option(opts, '-v', '--version')
|
@@ -498,6 +500,9 @@ module RuboCop
|
|
498
500
|
extra_details: 'Display extra details in offense messages.',
|
499
501
|
lint: 'Run only lint cops.',
|
500
502
|
safe: 'Run only safe cops.',
|
503
|
+
stderr: ['Write all output to stderr except for the',
|
504
|
+
'autocorrected source. This is especially useful',
|
505
|
+
'when combined with --auto-correct and --stdin.'],
|
501
506
|
list_target_files: 'List all files RuboCop will inspect.',
|
502
507
|
auto_correct: 'Auto-correct offenses (only when it\'s safe).',
|
503
508
|
safe_auto_correct: '(same, deprecated)',
|
data/lib/rubocop/rake_task.rb
CHANGED
@@ -22,7 +22,7 @@ module RuboCop
|
|
22
22
|
|
23
23
|
task(name, *args) do |_, task_args|
|
24
24
|
RakeFileUtils.verbose(verbose) do
|
25
|
-
yield(*[self, task_args].slice(0, task_block.arity)) if
|
25
|
+
yield(*[self, task_args].slice(0, task_block.arity)) if task_block
|
26
26
|
run_cli(verbose, full_options)
|
27
27
|
end
|
28
28
|
end
|
@@ -66,7 +66,7 @@ module RuboCop
|
|
66
66
|
|
67
67
|
task(:auto_correct, *args) do |_, task_args|
|
68
68
|
RakeFileUtils.verbose(verbose) do
|
69
|
-
yield(*[self, task_args].slice(0, task_block.arity)) if
|
69
|
+
yield(*[self, task_args].slice(0, task_block.arity)) if task_block
|
70
70
|
options = full_options.unshift('--auto-correct-all')
|
71
71
|
options.delete('--parallel')
|
72
72
|
run_cli(verbose, options)
|
data/lib/rubocop/runner.rb
CHANGED
@@ -64,7 +64,7 @@ module RuboCop
|
|
64
64
|
# instances that each inspects its allotted group of files.
|
65
65
|
def warm_cache(target_files)
|
66
66
|
puts 'Running parallel inspection' if @options[:debug]
|
67
|
-
Parallel.each(target_files
|
67
|
+
Parallel.each(target_files) { |target_file| file_offenses(target_file) }
|
68
68
|
end
|
69
69
|
|
70
70
|
def find_target_files(paths)
|
data/lib/rubocop/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bozhidar Batsov
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2020-11-
|
13
|
+
date: 2020-11-23 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: parallel
|
@@ -169,11 +169,6 @@ extra_rdoc_files:
|
|
169
169
|
files:
|
170
170
|
- LICENSE.txt
|
171
171
|
- README.md
|
172
|
-
- assets/logo.png
|
173
|
-
- assets/output.html.erb
|
174
|
-
- bin/console
|
175
|
-
- bin/rubocop-profile
|
176
|
-
- bin/setup
|
177
172
|
- config/default.yml
|
178
173
|
- exe/rubocop
|
179
174
|
- lib/rubocop.rb
|
@@ -685,6 +680,7 @@ files:
|
|
685
680
|
- lib/rubocop/cop/style/proc.rb
|
686
681
|
- lib/rubocop/cop/style/raise_args.rb
|
687
682
|
- lib/rubocop/cop/style/random_with_offset.rb
|
683
|
+
- lib/rubocop/cop/style/redundant_argument.rb
|
688
684
|
- lib/rubocop/cop/style/redundant_assignment.rb
|
689
685
|
- lib/rubocop/cop/style/redundant_begin.rb
|
690
686
|
- lib/rubocop/cop/style/redundant_capital_w.rb
|
@@ -821,7 +817,7 @@ metadata:
|
|
821
817
|
homepage_uri: https://rubocop.org/
|
822
818
|
changelog_uri: https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md
|
823
819
|
source_code_uri: https://github.com/rubocop-hq/rubocop/
|
824
|
-
documentation_uri: https://docs.rubocop.org/rubocop/1.
|
820
|
+
documentation_uri: https://docs.rubocop.org/rubocop/1.4/
|
825
821
|
bug_tracker_uri: https://github.com/rubocop-hq/rubocop/issues
|
826
822
|
post_install_message:
|
827
823
|
rdoc_options: []
|
data/assets/logo.png
DELETED
Binary file
|
data/assets/output.html.erb
DELETED
@@ -1,261 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html>
|
3
|
-
<head>
|
4
|
-
<meta charset='UTF-8' />
|
5
|
-
<title>RuboCop Inspection Report</title>
|
6
|
-
<%# TODO: Clean up the messy markup and style definitions. %>
|
7
|
-
<style>
|
8
|
-
* {
|
9
|
-
-webkit-box-sizing: border-box;
|
10
|
-
-moz-box-sizing: border-box;
|
11
|
-
box-sizing: border-box;
|
12
|
-
}
|
13
|
-
|
14
|
-
body, html {
|
15
|
-
font-size: 62.5%;
|
16
|
-
}
|
17
|
-
body {
|
18
|
-
background-color: #ecedf0;
|
19
|
-
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
|
20
|
-
margin: 0;
|
21
|
-
}
|
22
|
-
code {
|
23
|
-
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
24
|
-
font-size: 85%;
|
25
|
-
}
|
26
|
-
#header {
|
27
|
-
background: #f9f9f9;
|
28
|
-
color: #333;
|
29
|
-
border-bottom: 3px solid #ccc;
|
30
|
-
height: 50px;
|
31
|
-
padding: 0;
|
32
|
-
}
|
33
|
-
#header .logo {
|
34
|
-
float: left;
|
35
|
-
margin: 5px 12px 7px 20px;
|
36
|
-
width: 38px;
|
37
|
-
height: 38px;
|
38
|
-
}
|
39
|
-
#header .title {
|
40
|
-
display: inline-block;
|
41
|
-
float: left;
|
42
|
-
height: 50px;
|
43
|
-
font-size: 2.4rem;
|
44
|
-
letter-spacing: normal;
|
45
|
-
line-height: 50px;
|
46
|
-
margin: 0;
|
47
|
-
}
|
48
|
-
|
49
|
-
.information, #offenses {
|
50
|
-
width: 100%;
|
51
|
-
padding: 20px;
|
52
|
-
color: #333;
|
53
|
-
}
|
54
|
-
#offenses {
|
55
|
-
padding: 0 20px;
|
56
|
-
}
|
57
|
-
|
58
|
-
.information .infobox {
|
59
|
-
border-left: 3px solid;
|
60
|
-
border-radius: 4px;
|
61
|
-
background-color: #fff;
|
62
|
-
-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
|
63
|
-
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
|
64
|
-
padding: 15px;
|
65
|
-
border-color: #0088cc;
|
66
|
-
font-size: 1.4rem;
|
67
|
-
}
|
68
|
-
.information .infobox .info-title {
|
69
|
-
font-size: 1.8rem;
|
70
|
-
line-height: 2.2rem;
|
71
|
-
margin: 0 0 0.5em;
|
72
|
-
}
|
73
|
-
.information .offenses-list li {
|
74
|
-
line-height: 1.8rem
|
75
|
-
}
|
76
|
-
.information .offenses-list {
|
77
|
-
padding-left: 20px;
|
78
|
-
margin-bottom: 0;
|
79
|
-
}
|
80
|
-
|
81
|
-
#offenses .offense-box {
|
82
|
-
border-radius: 4px;
|
83
|
-
margin-bottom: 20px;
|
84
|
-
background-color: #fff;
|
85
|
-
-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
|
86
|
-
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
|
87
|
-
}
|
88
|
-
.fixed .box-title {
|
89
|
-
position: fixed;
|
90
|
-
top: 0;
|
91
|
-
z-index: 10;
|
92
|
-
width: 100%;
|
93
|
-
}
|
94
|
-
.box-title-placeholder {
|
95
|
-
display: none;
|
96
|
-
}
|
97
|
-
.fixed .box-title-placeholder {
|
98
|
-
display: block;
|
99
|
-
}
|
100
|
-
#offenses .offense-box .box-title h3, #offenses .offense-box .box-title-placeholder h3 {
|
101
|
-
color: #33353f;
|
102
|
-
background-color: #f6f6f6;
|
103
|
-
font-size: 2rem;
|
104
|
-
line-height: 2rem;
|
105
|
-
display: block;
|
106
|
-
padding: 15px;
|
107
|
-
border-radius: 5px;
|
108
|
-
margin: 0;
|
109
|
-
}
|
110
|
-
#offenses .offense-box .offense-reports {
|
111
|
-
padding: 0 15px;
|
112
|
-
}
|
113
|
-
#offenses .offense-box .offense-reports .report {
|
114
|
-
border-bottom: 1px dotted #ddd;
|
115
|
-
padding: 15px 0px;
|
116
|
-
position: relative;
|
117
|
-
font-size: 1.3rem;
|
118
|
-
}
|
119
|
-
#offenses .offense-box .offense-reports .report:last-child {
|
120
|
-
border-bottom: none;
|
121
|
-
}
|
122
|
-
#offenses .offense-box .offense-reports .report pre code {
|
123
|
-
display: block;
|
124
|
-
background: #000;
|
125
|
-
color: #fff;
|
126
|
-
padding: 10px 15px;
|
127
|
-
border-radius: 5px;
|
128
|
-
line-height: 1.6rem;
|
129
|
-
}
|
130
|
-
#offenses .offense-box .offense-reports .report .location {
|
131
|
-
font-weight: bold;
|
132
|
-
}
|
133
|
-
#offenses .offense-box .offense-reports .report .message code {
|
134
|
-
padding: 0.3em;
|
135
|
-
background-color: rgba(0,0,0,0.07);
|
136
|
-
border-radius: 3px;
|
137
|
-
}
|
138
|
-
.severity {
|
139
|
-
text-transform: capitalize;
|
140
|
-
font-weight: bold;
|
141
|
-
}
|
142
|
-
.highlight {
|
143
|
-
padding: 2px;
|
144
|
-
border-radius: 2px;
|
145
|
-
font-weight: bold;
|
146
|
-
}
|
147
|
-
<%- SEVERITY_COLORS.each do |severity, color| %>
|
148
|
-
.severity.<%= severity %> {
|
149
|
-
color: <%= color %>;
|
150
|
-
}
|
151
|
-
.highlight.<%= severity %> {
|
152
|
-
background-color: <%= color.fade_out(0.4) %>;
|
153
|
-
border: 1px solid <%= color.fade_out(0.6) %>;
|
154
|
-
}
|
155
|
-
<%- end %>
|
156
|
-
footer {
|
157
|
-
margin-bottom: 20px;
|
158
|
-
margin-right: 20px;
|
159
|
-
font-size: 1.3rem;
|
160
|
-
color: #777;
|
161
|
-
text-align: right;
|
162
|
-
}
|
163
|
-
.extra-code {
|
164
|
-
color: #ED9C28
|
165
|
-
}
|
166
|
-
</style>
|
167
|
-
|
168
|
-
<script>
|
169
|
-
(function() {
|
170
|
-
// floating headers. requires classList support.
|
171
|
-
if (!('classList' in document.createElement("_"))) return;
|
172
|
-
|
173
|
-
var loaded = false,
|
174
|
-
boxes,
|
175
|
-
boxPositions;
|
176
|
-
|
177
|
-
window.onload = function() {
|
178
|
-
var scrollY = window.scrollY;
|
179
|
-
boxes = document.querySelectorAll('.offense-box');
|
180
|
-
boxPositions = [];
|
181
|
-
for (var i = 0; i < boxes.length; i++)
|
182
|
-
// need to add scrollY because the page might be somewhere other than the top when loaded.
|
183
|
-
boxPositions[i] = boxes[i].getBoundingClientRect().top + scrollY;
|
184
|
-
loaded = true;
|
185
|
-
};
|
186
|
-
|
187
|
-
window.onscroll = function() {
|
188
|
-
if (!loaded) return;
|
189
|
-
var i,
|
190
|
-
idx,
|
191
|
-
scrollY = window.scrollY;
|
192
|
-
for (i = 0; i < boxPositions.length; i++) {
|
193
|
-
if (scrollY <= boxPositions[i] - 1) {
|
194
|
-
idx = i;
|
195
|
-
break;
|
196
|
-
}
|
197
|
-
}
|
198
|
-
if (typeof idx == 'undefined') idx = boxes.length;
|
199
|
-
if (idx > 0)
|
200
|
-
boxes[idx - 1].classList.add('fixed');
|
201
|
-
for (i = 0; i < boxes.length; i++) {
|
202
|
-
if (i < idx) continue;
|
203
|
-
boxes[i].classList.remove('fixed');
|
204
|
-
}
|
205
|
-
};
|
206
|
-
})();
|
207
|
-
</script>
|
208
|
-
</head>
|
209
|
-
<body>
|
210
|
-
<div id="header">
|
211
|
-
<img class="logo" src="data:image/png;base64,<%= base64_encoded_logo_image %>" alt="">
|
212
|
-
<h1 class="title">RuboCop Inspection Report</h1>
|
213
|
-
</div>
|
214
|
-
<div class="information">
|
215
|
-
<div class="infobox">
|
216
|
-
<div class="total">
|
217
|
-
<%= pluralize(files.count, 'file') %> inspected,
|
218
|
-
<%= pluralize(summary.offense_count, 'offense', no_for_zero: true) %> detected:
|
219
|
-
</div>
|
220
|
-
<ul class="offenses-list">
|
221
|
-
<% files.each do |file| %>
|
222
|
-
<% next if file.offenses.none? %>
|
223
|
-
<li>
|
224
|
-
<a href="#offense_<%= relative_path(file.path) %>">
|
225
|
-
<%= relative_path(file.path) %> - <%= pluralize(file.offenses.count, 'offense') %>
|
226
|
-
</a>
|
227
|
-
</li>
|
228
|
-
<% end %>
|
229
|
-
</ul>
|
230
|
-
</div>
|
231
|
-
</div>
|
232
|
-
<div id="offenses">
|
233
|
-
<% files.each do |file| %>
|
234
|
-
<% if file.offenses.any? %>
|
235
|
-
<div class="offense-box" id="offense_<%= relative_path(file.path) %>">
|
236
|
-
<div class="box-title-placeholder"><h3> </h3></div>
|
237
|
-
<div class="box-title"><h3><%= relative_path(file.path) %> - <%= pluralize(file.offenses.count, 'offense') %></h3></div>
|
238
|
-
<div class="offense-reports">
|
239
|
-
<% file.offenses.each do |offense| %>
|
240
|
-
<div class="report">
|
241
|
-
<div class="meta">
|
242
|
-
<span class="location">Line #<%= offense.location.line %></span> –
|
243
|
-
<span class="severity <%= offense.severity %>"><%= offense.severity %>:</span>
|
244
|
-
<span class="message"><%= decorated_message(offense) %></span>
|
245
|
-
</div>
|
246
|
-
<% unless offense.location.source_line.strip.empty? %>
|
247
|
-
<pre><code><%= highlighted_source_line(offense) %></code></pre>
|
248
|
-
<% end %>
|
249
|
-
</div>
|
250
|
-
<% end %>
|
251
|
-
</div>
|
252
|
-
</div>
|
253
|
-
<% end %>
|
254
|
-
<% end %>
|
255
|
-
</div>
|
256
|
-
<footer>
|
257
|
-
Generated by <a href="https://github.com/rubocop-hq/rubocop">RuboCop</a>
|
258
|
-
<span class="version"><%= RuboCop::Version::STRING %></span>
|
259
|
-
</footer>
|
260
|
-
</body>
|
261
|
-
</html>
|
data/bin/console
DELETED
data/bin/rubocop-profile
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
if ARGV.include?('-h') || ARGV.include?('--help')
|
5
|
-
puts "Usage: same as main `rubocop` command but gathers profiling info"
|
6
|
-
puts "Additional option: `--memory` to print memory usage"
|
7
|
-
exit(0)
|
8
|
-
end
|
9
|
-
with_mem = ARGV.delete('--memory')
|
10
|
-
ARGV.unshift '--cache', 'false' unless ARGV.include?('--cache')
|
11
|
-
|
12
|
-
require 'stackprof'
|
13
|
-
if with_mem
|
14
|
-
require 'memory_profiler'
|
15
|
-
MemoryProfiler.start
|
16
|
-
end
|
17
|
-
StackProf.start
|
18
|
-
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
19
|
-
begin
|
20
|
-
load "#{__dir__}/../exe/rubocop"
|
21
|
-
ensure
|
22
|
-
delta = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
|
23
|
-
puts "Finished in #{delta.round(1)} seconds"
|
24
|
-
StackProf.stop
|
25
|
-
if with_mem
|
26
|
-
puts "Building memory report..."
|
27
|
-
report = MemoryProfiler.stop
|
28
|
-
end
|
29
|
-
Dir.mkdir('tmp') unless File.exist?('tmp')
|
30
|
-
StackProf.results('tmp/stackprof.dump')
|
31
|
-
report&.pretty_print(scale_bytes: true)
|
32
|
-
end
|