wool 0.5.1
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.
- data/.document +5 -0
- data/.gitignore +23 -0
- data/LICENSE +45 -0
- data/README.rdoc +17 -0
- data/Rakefile +77 -0
- data/TODO.md +17 -0
- data/VERSION +1 -0
- data/bin/wool +4 -0
- data/features/step_definitions/wool_steps.rb +39 -0
- data/features/support/env.rb +14 -0
- data/features/support/testdata/1_input +1 -0
- data/features/support/testdata/1_output +1 -0
- data/features/support/testdata/2_input +4 -0
- data/features/support/testdata/2_output +4 -0
- data/features/support/testdata/3_input +8 -0
- data/features/support/testdata/3_output +11 -0
- data/features/support/testdata/4_input +5 -0
- data/features/support/testdata/4_output +5 -0
- data/features/wool.feature +24 -0
- data/lib/wool.rb +40 -0
- data/lib/wool/advice/advice.rb +42 -0
- data/lib/wool/advice/comment_advice.rb +37 -0
- data/lib/wool/analysis/annotations.rb +34 -0
- data/lib/wool/analysis/annotations/next_annotation.rb +26 -0
- data/lib/wool/analysis/annotations/parent_annotation.rb +20 -0
- data/lib/wool/analysis/annotations/scope_annotation.rb +37 -0
- data/lib/wool/analysis/lexical_analysis.rb +165 -0
- data/lib/wool/analysis/protocol_registry.rb +32 -0
- data/lib/wool/analysis/protocols.rb +82 -0
- data/lib/wool/analysis/scope.rb +13 -0
- data/lib/wool/analysis/sexp_analysis.rb +98 -0
- data/lib/wool/analysis/signature.rb +16 -0
- data/lib/wool/analysis/symbol.rb +10 -0
- data/lib/wool/analysis/visitor.rb +36 -0
- data/lib/wool/analysis/wool_class.rb +47 -0
- data/lib/wool/rake/task.rb +42 -0
- data/lib/wool/runner.rb +156 -0
- data/lib/wool/scanner.rb +160 -0
- data/lib/wool/support/module_extensions.rb +84 -0
- data/lib/wool/third_party/trollop.rb +845 -0
- data/lib/wool/warning.rb +145 -0
- data/lib/wool/warnings/comment_spacing.rb +30 -0
- data/lib/wool/warnings/extra_blank_lines.rb +29 -0
- data/lib/wool/warnings/extra_whitespace.rb +15 -0
- data/lib/wool/warnings/line_length.rb +113 -0
- data/lib/wool/warnings/misaligned_unindentation.rb +16 -0
- data/lib/wool/warnings/operator_spacing.rb +63 -0
- data/lib/wool/warnings/rescue_exception.rb +41 -0
- data/lib/wool/warnings/semicolon.rb +24 -0
- data/lib/wool/warnings/useless_double_quotes.rb +37 -0
- data/spec/advice_specs/advice_spec.rb +69 -0
- data/spec/advice_specs/comment_advice_spec.rb +38 -0
- data/spec/advice_specs/spec_helper.rb +1 -0
- data/spec/analysis_specs/annotations_specs/next_prev_annotation_spec.rb +47 -0
- data/spec/analysis_specs/annotations_specs/parent_annotation_spec.rb +41 -0
- data/spec/analysis_specs/annotations_specs/spec_helper.rb +5 -0
- data/spec/analysis_specs/lexical_analysis_spec.rb +179 -0
- data/spec/analysis_specs/protocol_registry_spec.rb +58 -0
- data/spec/analysis_specs/protocols_spec.rb +49 -0
- data/spec/analysis_specs/scope_spec.rb +20 -0
- data/spec/analysis_specs/sexp_analysis_spec.rb +134 -0
- data/spec/analysis_specs/spec_helper.rb +2 -0
- data/spec/analysis_specs/visitor_spec.rb +53 -0
- data/spec/analysis_specs/wool_class_spec.rb +54 -0
- data/spec/rake_specs/spec_helper.rb +1 -0
- data/spec/rake_specs/task_spec.rb +67 -0
- data/spec/runner_spec.rb +171 -0
- data/spec/scanner_spec.rb +75 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +93 -0
- data/spec/support_specs/module_extensions_spec.rb +91 -0
- data/spec/support_specs/spec_helper.rb +1 -0
- data/spec/warning_spec.rb +95 -0
- data/spec/warning_specs/comment_spacing_spec.rb +57 -0
- data/spec/warning_specs/extra_blank_lines_spec.rb +70 -0
- data/spec/warning_specs/extra_whitespace_spec.rb +33 -0
- data/spec/warning_specs/line_length_spec.rb +165 -0
- data/spec/warning_specs/misaligned_unindentation_spec.rb +35 -0
- data/spec/warning_specs/operator_spacing_spec.rb +101 -0
- data/spec/warning_specs/rescue_exception_spec.rb +105 -0
- data/spec/warning_specs/semicolon_spec.rb +58 -0
- data/spec/warning_specs/spec_helper.rb +1 -0
- data/spec/warning_specs/useless_double_quotes_spec.rb +62 -0
- data/spec/wool_spec.rb +8 -0
- data/status_reports/2010/12/2010-12-14.md +163 -0
- data/test/third_party_tests/test_trollop.rb +1181 -0
- data/wool.gemspec +173 -0
- metadata +235 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
module Wool
|
2
|
+
module SexpAnalysis
|
3
|
+
# A single signature in the Wool protocol system. This is just
|
4
|
+
# a simple specification of a method that an object can receive,
|
5
|
+
# either explicitly or implicitly defined, and the protocols of the
|
6
|
+
# return type and all arguments.
|
7
|
+
class Signature < Struct.new(:name, :return_protocol, :argument_protocols)
|
8
|
+
include Comparable
|
9
|
+
|
10
|
+
def <=>(other)
|
11
|
+
[self.name, self.return_protocol, self.argument_protocols] <=>
|
12
|
+
[other.name, other.return_protocol, other.argument_protocols]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Wool
|
2
|
+
module SexpAnalysis
|
3
|
+
# This class represents a Symbol in Ruby. It may have a known protocol (type),
|
4
|
+
# class, value (if constant!), and a variety of other details.
|
5
|
+
class Symbol < Struct.new(:protocol, :class_used, :value, :scope, :name)
|
6
|
+
include Comparable
|
7
|
+
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Wool
|
2
|
+
module SexpAnalysis
|
3
|
+
# Visitor: a set of methods for visiting an AST. The
|
4
|
+
# default implementations visit each child and do no
|
5
|
+
# other processing. By including this module, and
|
6
|
+
# implementing certain methods, you can do your own
|
7
|
+
# processing on, say, every instance of a :rescue AST node.
|
8
|
+
# The default implementation will go arbitrarily deep in the AST
|
9
|
+
# tree until it hits a method you define.
|
10
|
+
module Visitor
|
11
|
+
def visit(node)
|
12
|
+
case node
|
13
|
+
when Sexp
|
14
|
+
case node[0]
|
15
|
+
when ::Symbol
|
16
|
+
send("visit_#{node[0]}", node)
|
17
|
+
when Array
|
18
|
+
node.each {|x| visit(x)}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def default_visit(node)
|
24
|
+
node.children.select {|x| Sexp === x}.each {|x| visit(x) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def method_missing(meth, *args, &blk)
|
28
|
+
if meth.to_s[0,6] == 'visit_'
|
29
|
+
default_visit args.first
|
30
|
+
else
|
31
|
+
raise
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Wool
|
2
|
+
module SexpAnalysis
|
3
|
+
# Wool representation of a class. I named it WoolClass so it wouldn't
|
4
|
+
# clash with regular Class. This links the class to its protocol. It
|
5
|
+
# has lists of methods, instance variables, and so on.
|
6
|
+
class WoolClass
|
7
|
+
attr_reader :path, :methods, :protocol, :scope, :class_object
|
8
|
+
attr_accessor :superclass
|
9
|
+
|
10
|
+
def initialize(full_path, scope = Scope::GlobalScope)
|
11
|
+
@path = full_path
|
12
|
+
@methods = {}
|
13
|
+
@protocol = Protocols::ClassProtocol.new(self)
|
14
|
+
@scope = scope
|
15
|
+
@class_object = Symbol.new(@protocol, self)
|
16
|
+
ProtocolRegistry.add_class_protocol(@protocol)
|
17
|
+
yield self if block_given?
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_method(method)
|
21
|
+
@methods[method.name] = method
|
22
|
+
end
|
23
|
+
|
24
|
+
def signatures
|
25
|
+
@methods.values.map(&:signatures).flatten
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Wool representation of a method. This name is tweaked so it doesn't
|
30
|
+
# collide with ::Method.
|
31
|
+
class WoolMethod
|
32
|
+
extend ModuleExtensions
|
33
|
+
attr_reader :name, :signatures
|
34
|
+
attr_accessor_with_default :pure, false
|
35
|
+
|
36
|
+
def initialize(name)
|
37
|
+
@name = name
|
38
|
+
@signatures = []
|
39
|
+
yield self if block_given?
|
40
|
+
end
|
41
|
+
|
42
|
+
def add_signature(return_proto, arg_protos)
|
43
|
+
@signatures << Signature.new(self.name, return_proto, arg_protos)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Wool
|
2
|
+
module Rake
|
3
|
+
class WoolTask
|
4
|
+
class Settings < Struct.new(:libs, :extras, :options, :using, :fix)
|
5
|
+
def initialize(*args)
|
6
|
+
super
|
7
|
+
self.libs ||= []
|
8
|
+
self.extras ||= []
|
9
|
+
self.options ||= ''
|
10
|
+
self.using ||= []
|
11
|
+
self.fix ||= []
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_accessor :settings
|
16
|
+
|
17
|
+
def initialize(task_name)
|
18
|
+
@settings = Settings.new
|
19
|
+
yield @settings if block_given?
|
20
|
+
@settings.using = [:all] if @settings.using.empty?
|
21
|
+
task task_name do
|
22
|
+
run
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def run
|
27
|
+
files = []
|
28
|
+
if @settings.libs.any?
|
29
|
+
@settings.libs.each do |lib|
|
30
|
+
Dir["#{lib}/**/*.rb"].each do |file|
|
31
|
+
files << file
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
runner = Wool::Runner.new(self.settings.options.split(/\s/) + files)
|
36
|
+
runner.using = self.settings.using
|
37
|
+
runner.fix = self.settings.fix
|
38
|
+
runner.run
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/wool/runner.rb
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
module Wool
|
2
|
+
class Runner
|
3
|
+
attr_accessor :using, :fix
|
4
|
+
|
5
|
+
def initialize(argv)
|
6
|
+
@argv = argv
|
7
|
+
@using = [:all]
|
8
|
+
@fix = [:all]
|
9
|
+
end
|
10
|
+
|
11
|
+
def run
|
12
|
+
settings, files = collect_options_and_arguments
|
13
|
+
settings[:__using__] = warnings_to_consider
|
14
|
+
settings[:__fix__] = warnings_to_fix
|
15
|
+
scanner = Scanner.new(settings)
|
16
|
+
warnings = collect_warnings(files, scanner)
|
17
|
+
display_warnings(warnings, settings) if settings[:display]
|
18
|
+
end
|
19
|
+
|
20
|
+
def collect_options_and_arguments
|
21
|
+
swizzling_argv do
|
22
|
+
settings = get_settings
|
23
|
+
handle_global_options(settings)
|
24
|
+
p settings if settings[:debug]
|
25
|
+
files = ARGV.dup
|
26
|
+
[settings, files]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Processes the global options, which includes picking which warnings to
|
31
|
+
# run against the source code. The settings provided determine what
|
32
|
+
# modifies the runner's settings.
|
33
|
+
#
|
34
|
+
# @param [Hash] settings the settings from the command-line to process.
|
35
|
+
# @option settings :only (String) a list of warning names or short names
|
36
|
+
# that will be the only warnings run. The names should be whitespace-delimited.
|
37
|
+
# @option settings :"line-length" (Integer) a maximum line length to
|
38
|
+
# generate a warning for. A common choice is 80/83.
|
39
|
+
def handle_global_options(settings)
|
40
|
+
if settings[:"line-length"]
|
41
|
+
@using << Wool.LineLengthWarning(settings[:"line-length"])
|
42
|
+
end
|
43
|
+
if (only_name = settings[:only])
|
44
|
+
@fix = @using = Warning.concrete_warnings.select do |w|
|
45
|
+
(w.name && w.name.index(only_name)) || (w.short_name && only_name.index(w.short_name))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
ARGV.replace(['(stdin)']) if settings[:stdin]
|
49
|
+
end
|
50
|
+
|
51
|
+
# Parses the command-line options using Trollop
|
52
|
+
#
|
53
|
+
# @return [Hash{Symbol => Object}] the settings entered by the user
|
54
|
+
def get_settings
|
55
|
+
warning_opts = get_warning_options
|
56
|
+
Trollop::options do
|
57
|
+
banner 'Ask Peeves - the Ruby Linter'
|
58
|
+
opt :fix, 'Should errors be fixed in-line?', :short => '-f'
|
59
|
+
opt :display, 'Should errors be displayed?', :short => '-b', :default => true
|
60
|
+
opt :"report-fixed", 'Should fixed errors be reported anyway?', :short => '-r'
|
61
|
+
opt :"line-length", 'Warn at the given line length', :short => '-l', :type => :int
|
62
|
+
opt :only, 'Only consider the given warning (by short or full name)', :short => '-O', :type => :string
|
63
|
+
opt :stdin, 'Read Ruby code from standard input', :short => '-s'
|
64
|
+
warning_opts.each { |warning| opt(*warning) }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Gets all the options from the warning plugins and collects them
|
69
|
+
# with overriding rules. The later the declaration is run, the higher the
|
70
|
+
# priority the option has.
|
71
|
+
def get_warning_options
|
72
|
+
all_options = Warning.all_warnings.inject({}) do |result, warning|
|
73
|
+
options = warning.options
|
74
|
+
options = [options] if options.any? && !options[0].is_a?(Array)
|
75
|
+
options.each do |option|
|
76
|
+
result[option.first] = option
|
77
|
+
end
|
78
|
+
result
|
79
|
+
end
|
80
|
+
all_options.values
|
81
|
+
end
|
82
|
+
|
83
|
+
# Converts a list of warnings and symbol shortcuts for warnings to just a
|
84
|
+
# list of warnings.
|
85
|
+
def convert_warning_list(list)
|
86
|
+
list.map do |list|
|
87
|
+
case list
|
88
|
+
when :all then Warning.all_warnings
|
89
|
+
when :whitespace
|
90
|
+
[ExtraBlankLinesWarning, ExtraWhitespaceWarning,
|
91
|
+
OperatorSpacing, MisalignedUnindentationWarning]
|
92
|
+
else list
|
93
|
+
end
|
94
|
+
end.flatten
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns the list of warnings the user has activated for use.
|
98
|
+
def warnings_to_consider
|
99
|
+
convert_warning_list(@using)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Returns the list of warnings the user has selected for fixing
|
103
|
+
def warnings_to_fix
|
104
|
+
convert_warning_list(@fix)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Sets the ARGV variable to the runner's arguments during the execution
|
108
|
+
# of the block.
|
109
|
+
def swizzling_argv
|
110
|
+
old_argv = ARGV.dup
|
111
|
+
ARGV.replace @argv
|
112
|
+
yield
|
113
|
+
ensure
|
114
|
+
ARGV.replace old_argv
|
115
|
+
end
|
116
|
+
|
117
|
+
# Collects warnings from all the provided files by running them through
|
118
|
+
# the scanner.
|
119
|
+
#
|
120
|
+
# @param [Array<String>] files the files to scan. If (stdin) is in the
|
121
|
+
# array, then data will be read from STDIN until EOF is reached.
|
122
|
+
# @param [Scanner] scanner the scanner that will look for warnings
|
123
|
+
# in the source text.
|
124
|
+
# @return [Array<Warning>] a set of warnings, ordered by file.
|
125
|
+
def collect_warnings(files, scanner)
|
126
|
+
full_list = files.map do |file|
|
127
|
+
data = file == '(stdin)' ? STDIN.read : File.read(file)
|
128
|
+
if scanner.settings[:fix]
|
129
|
+
scanner.settings[:output_file] = scanner.settings[:stdin] ? STDOUT : File.open(file, 'w')
|
130
|
+
end
|
131
|
+
results = scanner.scan(data, file)
|
132
|
+
scanner.settings[:output_file].close if scanner.settings[:fix] && !scanner.settings[:stdin]
|
133
|
+
results
|
134
|
+
end
|
135
|
+
full_list.flatten
|
136
|
+
end
|
137
|
+
|
138
|
+
# Displays warnings using user-provided settings.
|
139
|
+
#
|
140
|
+
# @param [Array<Warning>] warnings the warnings generated by the input
|
141
|
+
# files, ordered by file
|
142
|
+
# @param [Hash{Symbol => Object}] settings the user-set display settings
|
143
|
+
def display_warnings(warnings, settings)
|
144
|
+
num_fixable = warnings.select { |warn| warn.fixable? }.size
|
145
|
+
num_total = warnings.size
|
146
|
+
|
147
|
+
results = "#{num_total} warnings found. #{num_fixable} are fixable."
|
148
|
+
puts results
|
149
|
+
puts '=' * results.size
|
150
|
+
|
151
|
+
warnings.each do |warning|
|
152
|
+
puts "#{warning.file}:#{warning.line_number} #{warning.name} (#{warning.severity}) - #{warning.desc}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
data/lib/wool/scanner.rb
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
module Wool
|
2
|
+
class Scanner
|
3
|
+
attr_accessor :settings
|
4
|
+
attr_accessor :indent_stack
|
5
|
+
|
6
|
+
DEFAULT_SETTINGS = {:fix => false, :output => STDOUT, :indent_size => 2,
|
7
|
+
:__using__ => Wool::Warning.all_warnings,
|
8
|
+
:__fix__ => Wool::Warning.all_warnings}
|
9
|
+
|
10
|
+
# Initializes the scanner with the given settings
|
11
|
+
#
|
12
|
+
# @param [Hash] settings the settings to use to customize this scanner's
|
13
|
+
# scanning behavior
|
14
|
+
def initialize(settings = DEFAULT_SETTINGS)
|
15
|
+
@settings = DEFAULT_SETTINGS.merge(settings)
|
16
|
+
@settings[:__scanner__] = self
|
17
|
+
self.indent_stack = []
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns the list of warnings to use for scanning.
|
21
|
+
def using
|
22
|
+
@settings[:__using__]
|
23
|
+
end
|
24
|
+
|
25
|
+
# Should we use this warning?
|
26
|
+
def using?(warning)
|
27
|
+
@settings[:__using__].include? warning
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns the list of warnings to use for scanning.
|
31
|
+
def fix
|
32
|
+
@settings[:__fix__]
|
33
|
+
end
|
34
|
+
|
35
|
+
# Should we use this warning?
|
36
|
+
def fixing?(warning)
|
37
|
+
@settings[:__fix__].include? warning.class
|
38
|
+
end
|
39
|
+
|
40
|
+
# Scans the text for warnings.
|
41
|
+
#
|
42
|
+
# @param [String] text the input ruby file to scan
|
43
|
+
# @return [Array[Wool::Warnings]] the warnings generated by the code.
|
44
|
+
# If the code is clean, an empty array is returned.
|
45
|
+
def scan(text, filename='(none)')
|
46
|
+
warnings = scan_for_file_warnings(text, filename)
|
47
|
+
text = filter_fixable(warnings).inject(text) do |text, warning|
|
48
|
+
warning.fix(text)
|
49
|
+
end
|
50
|
+
with_fixing_piped_to_output do
|
51
|
+
text.split(/\n/).each_with_index do |line, number|
|
52
|
+
warnings.concat process_line(line, number + 1, filename)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
warnings
|
56
|
+
end
|
57
|
+
|
58
|
+
def with_fixing_piped_to_output
|
59
|
+
self.settings[:output_lines] = []
|
60
|
+
yield
|
61
|
+
if @settings[:fix]
|
62
|
+
self.settings[:output_file].write self.settings[:output_lines].join("\n")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Finds all matching warnings, and if the user wishes, fix a subset of them.
|
67
|
+
def process_line(line, line_number, filename)
|
68
|
+
warnings = all_warnings_for_line(line, line_number, filename)
|
69
|
+
fix_input(warnings, line, line_number, filename) if @settings[:fix]
|
70
|
+
warnings
|
71
|
+
end
|
72
|
+
|
73
|
+
# Tries to fix the given line with a set of matching warnings for that line.
|
74
|
+
# May recurse if there are multiple warnings on the same line.
|
75
|
+
def fix_input(warnings, line, line_number, filename)
|
76
|
+
fixable_warnings = filter_fixable warnings
|
77
|
+
if fixable_warnings.size == 1
|
78
|
+
self.settings[:output_lines] << fixable_warnings.first.fix rescue line
|
79
|
+
elsif fixable_warnings.size > 1
|
80
|
+
new_text = fixable_warnings.first.fix rescue line
|
81
|
+
process_line(new_text, line_number, filename)
|
82
|
+
else
|
83
|
+
self.settings[:output_lines] << line
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Returns all warnings that match the line
|
88
|
+
def all_warnings_for_line(line, line_number, filename)
|
89
|
+
new_warnings = check_for_indent_warnings!(line, filename)
|
90
|
+
new_warnings.concat scan_for_line_warnings(line, filename)
|
91
|
+
new_warnings.each {|warning| warning.line_number = line_number}
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns only the warnings that we should fix
|
95
|
+
def filter_fixable(warnings)
|
96
|
+
warnings.select {|warning| warning.fixable? && fixing?(warning) }
|
97
|
+
end
|
98
|
+
|
99
|
+
# Checks for new warnings based on indentation.
|
100
|
+
def check_for_indent_warnings!(line, filename)
|
101
|
+
return [] if line == ""
|
102
|
+
indent_size = get_indent_size line
|
103
|
+
if indent_size > current_indent
|
104
|
+
self.indent_stack.push indent_size
|
105
|
+
elsif indent_size < current_indent
|
106
|
+
previous = self.indent_stack.pop
|
107
|
+
if indent_size != current_indent &&
|
108
|
+
using.include?(MisalignedUnindentationWarning)
|
109
|
+
warnings_to_check = [MisalignedUnindentationWarning.new(filename, line, current_indent)]
|
110
|
+
return filtered_warnings_from_line(line, warnings_to_check)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
[]
|
114
|
+
end
|
115
|
+
|
116
|
+
# Gets the current indent size
|
117
|
+
def current_indent
|
118
|
+
self.indent_stack.last || 0
|
119
|
+
end
|
120
|
+
|
121
|
+
# Gets the indent size of a given line
|
122
|
+
def get_indent_size(line)
|
123
|
+
line.match(/^\s*/)[0].size
|
124
|
+
end
|
125
|
+
|
126
|
+
# Goes through all file warning subclasses and see what warnings the file
|
127
|
+
# generates as a whole.
|
128
|
+
def scan_for_file_warnings(file, filename)
|
129
|
+
scan_for_warnings(using & FileWarning.all_warnings, file, filename)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Goes through all line warning subclasses and checks if we got some new
|
133
|
+
# warnings for a given line
|
134
|
+
def scan_for_line_warnings(line, filename)
|
135
|
+
warnings = scan_for_warnings(using & LineWarning.all_warnings, line, filename)
|
136
|
+
filtered_warnings_from_line(line, warnings)
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
|
141
|
+
# Filters the list of warnings by checking the line for warnings to
|
142
|
+
# ignore. The line should contain "wool: ignore ClassToIgnore" in a comment,
|
143
|
+
# though you can omit the space between "wool:" and "ignore".
|
144
|
+
def filtered_warnings_from_line(line, warnings)
|
145
|
+
match = line.match(/#.*wool:\s*ignore\s+(.*)$/)
|
146
|
+
return warnings unless match && ignore_label = match[1]
|
147
|
+
class_names = ignore_label.split
|
148
|
+
result = warnings.reject do |warning|
|
149
|
+
class_names.include?(warning.class.name.gsub(/.*::(.*)/, '\1')) ||
|
150
|
+
class_names.include?(warning.class.short_name)
|
151
|
+
end
|
152
|
+
result
|
153
|
+
end
|
154
|
+
|
155
|
+
def scan_for_warnings(warnings, content, filename)
|
156
|
+
warnings.map! { |warning| warning.new(filename, content, @settings)}
|
157
|
+
warnings.map { |warning| warning.generated_warnings(warning.body)}.flatten.uniq
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|