wool 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|