wegolint 0.0.1 → 0.0.3
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/.rspec +3 -0
- data/Gemfile.lock +1 -1
- data/Rakefile +6 -0
- data/bin/wegolint +6 -0
- data/lib/wegolint/dsl.rb +37 -0
- data/lib/wegolint/rule.rb +42 -0
- data/lib/wegolint/rule_registry.rb +57 -0
- data/lib/wegolint/rules/general.rb +15 -0
- data/lib/wegolint/rules/ruby.rb +27 -0
- data/lib/wegolint/wegolinter.rb +79 -0
- data/lib/wegolint.rb +4 -101
- data/spec/rule_registry_spec.rb +49 -0
- data/spec/rule_spec.rb +120 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/wegolint_bin_spec.rb +77 -0
- data/spec/wegolinter_spec.rb +54 -0
- data/wegolint.gemspec +2 -2
- metadata +14 -4
- data/lib/init.rb +0 -1
- data/spec/wegolint_spec.rb +0 -199
data/.rspec
ADDED
data/Gemfile.lock
CHANGED
data/Rakefile
ADDED
data/bin/wegolint
CHANGED
data/lib/wegolint/dsl.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module WegoLint
|
2
|
+
module DSL
|
3
|
+
module RuleDirectives
|
4
|
+
@@collapse_quotes = false
|
5
|
+
|
6
|
+
def included(klass)
|
7
|
+
@@pattern = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
def pattern(pattern = nil)
|
11
|
+
@@pattern = pattern if pattern
|
12
|
+
@@pattern
|
13
|
+
end
|
14
|
+
|
15
|
+
def collapse_quotes
|
16
|
+
@@collapse_quotes = true
|
17
|
+
end
|
18
|
+
|
19
|
+
def collapse_quotes?
|
20
|
+
@@collapse_quotes
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def language(name, &block)
|
25
|
+
WegoLint::RuleRegistry.instance.language_context = name
|
26
|
+
yield
|
27
|
+
WegoLint::RuleRegistry.instance.language_context = :general
|
28
|
+
end
|
29
|
+
|
30
|
+
def rule(description, &rule_block)
|
31
|
+
rule = WegoLint::RuleRegistry.instance.add_rule(description, rule_block)
|
32
|
+
rule
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
extend WegoLint::DSL
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module WegoLint; end
|
2
|
+
|
3
|
+
class WegoLint::Rule
|
4
|
+
|
5
|
+
attr_accessor :errors, :language, :description
|
6
|
+
|
7
|
+
@@pattern = nil
|
8
|
+
|
9
|
+
def initialize(description, language = :general)
|
10
|
+
@errors = []
|
11
|
+
@language = language
|
12
|
+
@output = ""
|
13
|
+
@description = description
|
14
|
+
end
|
15
|
+
|
16
|
+
def run(text)
|
17
|
+
text.split("\n").each_with_index do |line, index|
|
18
|
+
line = collapse_quotes(line) if self.class.collapse_quotes?
|
19
|
+
if line =~ self.class.pattern
|
20
|
+
@errors << {message: description, line_number: index + 1 }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
##############################################################################
|
26
|
+
private
|
27
|
+
|
28
|
+
def self.block_not_padded
|
29
|
+
# This won't work with chained blocks on one line
|
30
|
+
no_space_beginning_block = /\{[\w\|'"].*\}/
|
31
|
+
no_space_end_block = /\{.*[\w'"]\}/
|
32
|
+
/(#{no_space_beginning_block}|#{no_space_end_block})/
|
33
|
+
end
|
34
|
+
|
35
|
+
def collapse_quotes(line)
|
36
|
+
newline = line
|
37
|
+
['"', "'"].each do |char|
|
38
|
+
newline.gsub!(/#{char}.+?#{char}/, "#{char}TEST#{char}")
|
39
|
+
end
|
40
|
+
newline
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module WegoLint; end
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
|
5
|
+
class WegoLint::RuleRegistry
|
6
|
+
include Singleton
|
7
|
+
|
8
|
+
@@rule_count = 0
|
9
|
+
|
10
|
+
def self.rule_count
|
11
|
+
@@rule_count
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.rule_count=(rule_count)
|
15
|
+
@@rule_count = rule_count
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_accessor :language_context, :rules
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@rule_id = 0
|
22
|
+
@rules = {}
|
23
|
+
@language_context = :general
|
24
|
+
end
|
25
|
+
|
26
|
+
def find_by_description(description)
|
27
|
+
rules.keys.each do |key|
|
28
|
+
match = rules[key].find {|rule| rule.description == description }
|
29
|
+
return match if match
|
30
|
+
end
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def load_rules
|
35
|
+
Dir[File.dirname(__FILE__) + '/rules/*'].each { |rule| require rule }
|
36
|
+
end
|
37
|
+
|
38
|
+
# Pattern stolen from rspec
|
39
|
+
def add_rule(description, block)
|
40
|
+
WegoLint::RuleRegistry::rule_count += 1
|
41
|
+
klass = WegoLint::RuleRegistry.const_set("Rule_#{WegoLint::RuleRegistry::rule_count}",
|
42
|
+
subclass(WegoLint::Rule, block))
|
43
|
+
@rules[@language_context] = [] unless @rules[@language_context]
|
44
|
+
rule = klass.new(description, @language_context)
|
45
|
+
@rules[@language_context] << rule
|
46
|
+
rule
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def subclass(parent, block)
|
52
|
+
subclass = Class.new(parent)
|
53
|
+
subclass.send(:extend, WegoLint::DSL::RuleDirectives.clone)
|
54
|
+
subclass.module_eval(&block) if block
|
55
|
+
subclass
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
rule "More than eighty characters" do
|
2
|
+
pattern /^.{80}.+$/
|
3
|
+
end
|
4
|
+
|
5
|
+
rule "Hard tabs (use soft tabs)" do
|
6
|
+
pattern /\t/
|
7
|
+
end
|
8
|
+
|
9
|
+
rule "Whitespace at end of line" do
|
10
|
+
pattern /^.*\w+.*\s+$/
|
11
|
+
end
|
12
|
+
|
13
|
+
rule "Opening curly brace on its own line" do
|
14
|
+
pattern /^\s*\{\s*$/
|
15
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
language :ruby do
|
2
|
+
rule 'Space should be around block { |param| foo }' do
|
3
|
+
pattern /[\.\s]#{block_not_padded}/
|
4
|
+
|
5
|
+
collapse_quotes
|
6
|
+
end
|
7
|
+
|
8
|
+
rule 'No spaces after (, [ or before ], )' do
|
9
|
+
collapse_quotes
|
10
|
+
|
11
|
+
def self.no_spaces_padding_parens
|
12
|
+
space = /[ ]/
|
13
|
+
left_parens = /[\[\(]/
|
14
|
+
right_parens = /[\]\)]/
|
15
|
+
space_after_left_parens = /#{left_parens}#{space}/
|
16
|
+
space_before_right_parens =
|
17
|
+
/^(?!\s+#{right_parens}).*#{space}#{right_parens}/
|
18
|
+
/(?:#{space_after_left_parens}|#{space_before_right_parens})/
|
19
|
+
end
|
20
|
+
|
21
|
+
pattern no_spaces_padding_parens
|
22
|
+
end
|
23
|
+
|
24
|
+
rule 'Parentheses should be around function parameters' do
|
25
|
+
pattern /def \w+ \w/
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module WegoLint; end
|
2
|
+
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
class WegoLint::WegoLinter
|
6
|
+
def initialize(filename)
|
7
|
+
@filename = filename
|
8
|
+
@filetype = File.extname(@filename)
|
9
|
+
@ruleset = @filetype == '.js' ? :javascript : :ruby
|
10
|
+
@output = ''
|
11
|
+
end
|
12
|
+
|
13
|
+
def lint!
|
14
|
+
@output = run_language_parser
|
15
|
+
parse_file
|
16
|
+
end
|
17
|
+
|
18
|
+
def rules
|
19
|
+
WegoLint::RuleRegistry.instance.rules
|
20
|
+
end
|
21
|
+
|
22
|
+
def output
|
23
|
+
@output
|
24
|
+
end
|
25
|
+
|
26
|
+
def load_rules
|
27
|
+
WegoLint::RuleRegistry.instance.load_rules
|
28
|
+
end
|
29
|
+
|
30
|
+
##############################################################################
|
31
|
+
private
|
32
|
+
|
33
|
+
def parse_file
|
34
|
+
File.open(@filename, 'r') do |file|
|
35
|
+
text = file.read
|
36
|
+
apply_rules(text, :general)
|
37
|
+
apply_rules(text, @ruleset)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def run_language_parser
|
42
|
+
if @filetype == ".js"
|
43
|
+
command = 'jsl -nologo -nofilelisting -nosummary -nocontext -process'
|
44
|
+
`#{command} #{@filename} 2>&1`
|
45
|
+
else
|
46
|
+
`ruby -w -T1 -c #{@filename} 2>&1`
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# The real algorithm for this has to find the first instance of any pair,
|
51
|
+
# strip it, start over, find the second instance, strip it, start over, etc.
|
52
|
+
def collapse_quotes(line)
|
53
|
+
newline = line
|
54
|
+
['"', "'"].each do |char|
|
55
|
+
newline.gsub!(/#{char}.+?#{char}/, "#{char}TEST#{char}")
|
56
|
+
end
|
57
|
+
newline
|
58
|
+
end
|
59
|
+
|
60
|
+
def apply_rules(text, ruleset = :general)
|
61
|
+
return unless rules[ruleset]
|
62
|
+
rules[ruleset].each do |rule|
|
63
|
+
rule.run(text)
|
64
|
+
@output += format_errors(rule.errors) + "\n" unless rule.errors.empty?
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def format_errors(errors)
|
69
|
+
errors.collect { |error| format_error(error) }.join("\n")
|
70
|
+
end
|
71
|
+
|
72
|
+
def format_error(error)
|
73
|
+
if @ruleset == :ruby
|
74
|
+
"#{@filename}:#{error[:line_number]}: syntax error, #{error[:message]}"
|
75
|
+
elsif @ruleset == :javascript
|
76
|
+
"#{@filename}:#{error[:line_number]}: error: #{error[:message]}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/wegolint.rb
CHANGED
@@ -1,102 +1,5 @@
|
|
1
1
|
module WegoLint; end
|
2
|
-
|
3
|
-
require '
|
4
|
-
|
5
|
-
|
6
|
-
def initialize(filename)
|
7
|
-
@filename = filename
|
8
|
-
@filetype = File.extname(@filename)
|
9
|
-
@ruleset = @filetype == '.js' ? :javascript : :ruby
|
10
|
-
@output = ''
|
11
|
-
end
|
12
|
-
|
13
|
-
def lint!
|
14
|
-
@output = run_language_parser
|
15
|
-
parse_file
|
16
|
-
end
|
17
|
-
|
18
|
-
def rules
|
19
|
-
@rules ||= {
|
20
|
-
general: [
|
21
|
-
{ name: 'More than eighty characters', pattern: /^.{80}.+$/ },
|
22
|
-
{ name: 'Curly brace on its own line', pattern: /^\s*(\{|\})\s*$/ },
|
23
|
-
{ name: "Hard tabs (use soft tabs)", pattern: /\t/ },
|
24
|
-
{ name: 'Whitespace at end of line', pattern: /^.*\w+.*\s+\n$/ }],
|
25
|
-
|
26
|
-
ruby: [
|
27
|
-
{ name: 'Space should be around block { |param| foo }',
|
28
|
-
pattern: /[\.\s]#{block_not_padded}/, collapse_quotes: true },
|
29
|
-
{ name: 'No spaces after (, [ or before ], )',
|
30
|
-
pattern: no_spaces_padding_parens, collapse_quotes: true },
|
31
|
-
{ name: 'No parentheses around function parameters',
|
32
|
-
pattern: /def \w+ \w/}]}
|
33
|
-
end
|
34
|
-
|
35
|
-
def output
|
36
|
-
@output
|
37
|
-
end
|
38
|
-
|
39
|
-
##############################################################################
|
40
|
-
private
|
41
|
-
|
42
|
-
def parse_file
|
43
|
-
File.open(@filename, 'r') do |file|
|
44
|
-
line_number = 0
|
45
|
-
file.each_line do |line|
|
46
|
-
line_number += 1
|
47
|
-
apply_rules(line, line_number)
|
48
|
-
apply_rules(line, line_number, @ruleset)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def run_language_parser
|
54
|
-
if @filetype == ".js"
|
55
|
-
`jsl -nologo -nofilelisting -nosummary -nocontext -process #{@filename} 2>&1`
|
56
|
-
else
|
57
|
-
`ruby -w -T1 -c #{@filename} 2>&1`
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def block_not_padded
|
62
|
-
# This won't work with chained blocks on one line
|
63
|
-
no_space_beginning_block = /\{[\w\|'"].*\}[\.\s]$/
|
64
|
-
no_space_end_block = /\{.*[\w'"]\}[\.\s]$/
|
65
|
-
/(#{no_space_beginning_block}|#{no_space_end_block})/
|
66
|
-
end
|
67
|
-
|
68
|
-
def no_spaces_padding_parens
|
69
|
-
space = /[ ]/
|
70
|
-
left_parens = /[\[\(]/
|
71
|
-
right_parens = /[\]\)]/
|
72
|
-
space_after_left_parens = /#{left_parens}#{space}/
|
73
|
-
space_before_right_parens = /^(?!\s+#{right_parens}).*#{space}#{right_parens}/
|
74
|
-
/(?:#{space_after_left_parens}|#{space_before_right_parens})/
|
75
|
-
end
|
76
|
-
|
77
|
-
# The real algorithm for this has to find the first instance of any pair,
|
78
|
-
# strip it, start over, find the second instance, strip it, start over, etc.
|
79
|
-
def collapse_quotes(line)
|
80
|
-
newline = line
|
81
|
-
['"', "'"].each do |char|
|
82
|
-
newline.gsub!(/#{char}.+?#{char}/, "#{char}TEST#{char}")
|
83
|
-
end
|
84
|
-
newline
|
85
|
-
end
|
86
|
-
|
87
|
-
def apply_rules(line, line_number, ruleset = :general)
|
88
|
-
return unless rules[ruleset]
|
89
|
-
|
90
|
-
rules[ruleset].each do |rule|
|
91
|
-
line = collapse_quotes(line) if rule[:collapse_quotes]
|
92
|
-
if line =~ rule[:pattern]
|
93
|
-
if @filetype == ".js"
|
94
|
-
full_path = File.realpath(@filename)
|
95
|
-
@output += "#{full_path}(#{line_number}): SyntaxError: #{rule[:name]}\n"
|
96
|
-
else
|
97
|
-
@output += "#{@filename}:#{line_number}: syntax error, #{rule[:name]}\n"
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
2
|
+
require 'wegolint/rule_registry'
|
3
|
+
require 'wegolint/rule'
|
4
|
+
require 'wegolint/dsl'
|
5
|
+
require 'wegolint/wegolinter'
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
include WegoLint
|
4
|
+
|
5
|
+
describe RuleRegistry do
|
6
|
+
let(:description) { 'A new rule' }
|
7
|
+
let(:block) { proc do
|
8
|
+
pattern /foo/
|
9
|
+
end }
|
10
|
+
let(:rule_registry) { RuleRegistry.clone.instance }
|
11
|
+
|
12
|
+
describe ".add_rule" do
|
13
|
+
|
14
|
+
let!(:subject) { rule_registry.add_rule(description, block) }
|
15
|
+
|
16
|
+
it "creates a subclass of Rule" do
|
17
|
+
subject.should be_a Rule
|
18
|
+
end
|
19
|
+
|
20
|
+
it "creates a rule with the specified pattern" do
|
21
|
+
subject.class.pattern.should == /foo/
|
22
|
+
end
|
23
|
+
|
24
|
+
context "when there are more than two rules" do
|
25
|
+
before do
|
26
|
+
rule_registry.add_rule('Another rule', proc { pattern /bar/ } )
|
27
|
+
end
|
28
|
+
|
29
|
+
it "creates a rule with the specified pattern" do
|
30
|
+
subject.class.pattern.should == /foo/
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe ".rules" do
|
36
|
+
it "rule is added to the general rules list when language is not set" do
|
37
|
+
rule_registry.add_rule(description, block)
|
38
|
+
rule = rule_registry.rules[:general].first
|
39
|
+
rule.description.should == 'A new rule'
|
40
|
+
end
|
41
|
+
|
42
|
+
it "rule is added to the language rules list when language is set" do
|
43
|
+
rule_registry.language_context = :ruby
|
44
|
+
rule_registry.add_rule('Another rule', block)
|
45
|
+
rule = rule_registry.rules[:ruby].first
|
46
|
+
rule.description.should == 'Another rule'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/spec/rule_spec.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
include WegoLint
|
4
|
+
|
5
|
+
describe Rule do
|
6
|
+
let(:rule_registry) { RuleRegistry.instance }
|
7
|
+
let(:subject) { rule_registry.find_by_description(description) }
|
8
|
+
|
9
|
+
before do
|
10
|
+
rule_registry.load_rules
|
11
|
+
subject.run(code)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "General errors" do
|
15
|
+
context "hard tab" do
|
16
|
+
let(:description) { "Hard tabs (use soft tabs)" }
|
17
|
+
let(:code) { "\t" }
|
18
|
+
|
19
|
+
it { should_have_error description, 1, :ruby }
|
20
|
+
end
|
21
|
+
|
22
|
+
context "whitespace at end of line" do
|
23
|
+
let(:description) { "Whitespace at end of line" }
|
24
|
+
let(:code) { "'foo' \n" }
|
25
|
+
|
26
|
+
it { should_have_error description, 1, :ruby }
|
27
|
+
end
|
28
|
+
|
29
|
+
context "80 character limit" do
|
30
|
+
let(:description) { "More than eighty characters" }
|
31
|
+
let(:code) do
|
32
|
+
<<-EOF
|
33
|
+
a = 1
|
34
|
+
"kjkjkjkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk"
|
35
|
+
b = 3
|
36
|
+
EOF
|
37
|
+
end
|
38
|
+
|
39
|
+
it { should_have_error description, 2, :ruby }
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "Ruby errors" do
|
45
|
+
context "curly brace on its own line" do
|
46
|
+
let(:description) { "Opening curly brace on its own line" }
|
47
|
+
let(:code) do
|
48
|
+
<<-EOF
|
49
|
+
q = 1
|
50
|
+
{
|
51
|
+
b = 1
|
52
|
+
}
|
53
|
+
c = a+b
|
54
|
+
EOF
|
55
|
+
end
|
56
|
+
|
57
|
+
it { should_have_error description, 2, :ruby }
|
58
|
+
it { should_not_have_error description, 4, :ruby }
|
59
|
+
end
|
60
|
+
|
61
|
+
context "no space on inside of block" do
|
62
|
+
let(:description) { 'Space should be around block { |param| foo }' }
|
63
|
+
let(:code) do
|
64
|
+
<<-EOF
|
65
|
+
a = 1
|
66
|
+
['a','b','c'].each {|item| puts item }
|
67
|
+
['a','b','c'].each { |item| puts item}
|
68
|
+
b = 2
|
69
|
+
EOF
|
70
|
+
end
|
71
|
+
|
72
|
+
it { should_have_error description, 2, :ruby }
|
73
|
+
it { should_have_error description, 3, :ruby }
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'No spaces after (, [ or before ], )' do
|
77
|
+
let(:description) { 'No spaces after (, [ or before ], )' }
|
78
|
+
let(:code) do
|
79
|
+
<<-EOF
|
80
|
+
b = [ 'a' ]
|
81
|
+
def something( foo )
|
82
|
+
c = " [ a ] "
|
83
|
+
c = ' [ ] '
|
84
|
+
[ 'a', 'b' ].each { |line| puts " [ ] " }
|
85
|
+
end
|
86
|
+
doSomething(bar: 'baz', baz: 'bar', foo: 'bar', fa: 'lalalalalalaalalalalalala'
|
87
|
+
)
|
88
|
+
EOF
|
89
|
+
end
|
90
|
+
|
91
|
+
it { should_have_error description, 1, :ruby }
|
92
|
+
it { should_have_error description, 2, :ruby }
|
93
|
+
|
94
|
+
context "when embedded in strings" do
|
95
|
+
it { should_not_have_error description, 3, :ruby }
|
96
|
+
it { should_not_have_error description, 4, :ruby }
|
97
|
+
it { should_have_error description, 5, :ruby }
|
98
|
+
it { should_not_have_error description, 8, :ruby }
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context "No parentheses around function parameters" do
|
103
|
+
let(:description) { 'Parentheses should be around function parameters' }
|
104
|
+
let(:code) do
|
105
|
+
<<-EOF
|
106
|
+
def something(foo)
|
107
|
+
end
|
108
|
+
def something foo, bar
|
109
|
+
end
|
110
|
+
def something
|
111
|
+
end
|
112
|
+
EOF
|
113
|
+
end
|
114
|
+
|
115
|
+
it { should_not_have_error description, 1, :ruby }
|
116
|
+
it { should_have_error description, 3, :ruby }
|
117
|
+
it { should_not_have_error description, 5, :ruby }
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,3 +2,20 @@ RSpec.configure do |config|
|
|
2
2
|
config.treat_symbols_as_metadata_keys_with_true_values = true
|
3
3
|
config.run_all_when_everything_filtered = true
|
4
4
|
end
|
5
|
+
|
6
|
+
require 'wegolint'
|
7
|
+
|
8
|
+
def should_have_error message, line_number, language
|
9
|
+
message = build_error_message message, line_number, language
|
10
|
+
subject.errors.should include message
|
11
|
+
end
|
12
|
+
|
13
|
+
def should_not_have_error message, line_number, language
|
14
|
+
message = build_error_message message, line_number, language
|
15
|
+
subject.errors.should_not include message
|
16
|
+
end
|
17
|
+
|
18
|
+
def build_error_message message, line_number, language
|
19
|
+
{ message: message, line_number: line_number }
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,77 @@
|
|
1
|
+
describe "wegolint bin" do
|
2
|
+
let(:file) { '/tmp/wegolint_spec/foo.rb' }
|
3
|
+
let(:args) { file }
|
4
|
+
let(:subject) { `bundle exec wegolint #{args} 2>&1` }
|
5
|
+
let(:code) { '' }
|
6
|
+
|
7
|
+
before do
|
8
|
+
FileUtils.mkdir_p '/tmp/wegolint_spec/'
|
9
|
+
File.open(file, 'w+') do |f|
|
10
|
+
f.write(code)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
after do
|
15
|
+
File.unlink(file)
|
16
|
+
FileUtils.rmdir('/tmp/wegolint_spec')
|
17
|
+
end
|
18
|
+
|
19
|
+
context "without a file argument" do
|
20
|
+
let(:args) { '' }
|
21
|
+
it "without a file argument it provides usage instructions" do
|
22
|
+
subject.should =~ /USAGE:/
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "with a file that has no errors (ruby)" do
|
27
|
+
let(:code) do
|
28
|
+
<<-EOF
|
29
|
+
def something
|
30
|
+
puts "hello world"
|
31
|
+
end
|
32
|
+
EOF
|
33
|
+
end
|
34
|
+
|
35
|
+
it "outputs a success message" do
|
36
|
+
subject.should == "Syntax OK\n"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "with a file that has errors (ruby)" do
|
41
|
+
let(:code) do
|
42
|
+
<<-EOF
|
43
|
+
a = "Loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"
|
44
|
+
EOF
|
45
|
+
end
|
46
|
+
|
47
|
+
it "outputs ruby syntax parser format error message" do
|
48
|
+
subject.should == "Syntax OK\n#{file}:1: syntax error, More than eighty characters\n"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "with a file that has no errors (javascript)" do
|
53
|
+
let(:file) { '/tmp/wegolint_spec/foo.js' }
|
54
|
+
let(:code) do
|
55
|
+
<<-EOF
|
56
|
+
var something ='foo';
|
57
|
+
EOF
|
58
|
+
end
|
59
|
+
|
60
|
+
it "outputs a success message" do
|
61
|
+
subject.should == "\n"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "with a file that has errors (javascript)" do
|
66
|
+
let(:file) { '/tmp/wegolint_spec/foo.js' }
|
67
|
+
let(:code) do
|
68
|
+
<<-EOF
|
69
|
+
var a = "Loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong";
|
70
|
+
EOF
|
71
|
+
end
|
72
|
+
|
73
|
+
it "outputs ruby syntax parser format error message" do
|
74
|
+
subject.should == "#{file}:1: error: More than eighty characters\n"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
include WegoLint
|
4
|
+
|
5
|
+
describe WegoLinter do
|
6
|
+
|
7
|
+
let(:wegolinter) { WegoLinter.new('/tmp/wegolint_spec/foo.rb') }
|
8
|
+
|
9
|
+
before do
|
10
|
+
wegolinter.load_rules
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#rules" do
|
14
|
+
let(:subject) { wegolinter.rules }
|
15
|
+
|
16
|
+
it "loads rules from rules/ directory" do
|
17
|
+
subject.should_not be_empty
|
18
|
+
end
|
19
|
+
|
20
|
+
it "sorts rules into language groups" do
|
21
|
+
subject[:general].should_not be_empty
|
22
|
+
subject[:ruby].should_not be_empty
|
23
|
+
subject[:general].first.should be_a Rule
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#lint!" do
|
28
|
+
context "ruby parser syntax errors" do
|
29
|
+
let(:subject) { wegolinter.output }
|
30
|
+
let(:code) do
|
31
|
+
<<-EOF
|
32
|
+
Foo
|
33
|
+
end
|
34
|
+
EOF
|
35
|
+
end
|
36
|
+
|
37
|
+
before do
|
38
|
+
FileUtils.mkdir_p '/tmp/wegolint_spec/'
|
39
|
+
File.open('/tmp/wegolint_spec/foo.rb', 'w+') do |file|
|
40
|
+
file.write(code)
|
41
|
+
end
|
42
|
+
wegolinter.lint!
|
43
|
+
end
|
44
|
+
|
45
|
+
after do
|
46
|
+
File.unlink('/tmp/wegolint_spec/foo.rb')
|
47
|
+
FileUtils.rmdir('/tmp/wegolint_spec')
|
48
|
+
end
|
49
|
+
|
50
|
+
it { should include
|
51
|
+
"foo.rb:2: syntax error, unexpected keyword_end, expecting $end" }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/wegolint.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'wegolint'
|
3
|
-
s.version = '0.0.
|
4
|
-
s.date = '2012-09-
|
3
|
+
s.version = '0.0.3'
|
4
|
+
s.date = '2012-09-30'
|
5
5
|
s.summary = 'Parses code for style guide violations'
|
6
6
|
s.description = <<-EOF
|
7
7
|
Validates code according to style guide rules for an organization and outputs
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wegolint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-30 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ! 'Validates code according to style guide rules for an organization
|
15
15
|
and outputs
|
@@ -24,14 +24,24 @@ extensions: []
|
|
24
24
|
extra_rdoc_files: []
|
25
25
|
files:
|
26
26
|
- .gitignore
|
27
|
+
- .rspec
|
27
28
|
- Gemfile
|
28
29
|
- Gemfile.lock
|
29
30
|
- README.md
|
31
|
+
- Rakefile
|
30
32
|
- bin/wegolint
|
31
|
-
- lib/init.rb
|
32
33
|
- lib/wegolint.rb
|
34
|
+
- lib/wegolint/dsl.rb
|
35
|
+
- lib/wegolint/rule.rb
|
36
|
+
- lib/wegolint/rule_registry.rb
|
37
|
+
- lib/wegolint/rules/general.rb
|
38
|
+
- lib/wegolint/rules/ruby.rb
|
39
|
+
- lib/wegolint/wegolinter.rb
|
40
|
+
- spec/rule_registry_spec.rb
|
41
|
+
- spec/rule_spec.rb
|
33
42
|
- spec/spec_helper.rb
|
34
|
-
- spec/
|
43
|
+
- spec/wegolint_bin_spec.rb
|
44
|
+
- spec/wegolinter_spec.rb
|
35
45
|
- wegolint.gemspec
|
36
46
|
homepage: ''
|
37
47
|
licenses: []
|
data/lib/init.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'wegolint'
|
data/spec/wegolint_spec.rb
DELETED
@@ -1,199 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require_relative '../lib/wegolint'
|
3
|
-
|
4
|
-
include WegoLint
|
5
|
-
|
6
|
-
describe WegoLinter do
|
7
|
-
let(:test_data_dir) { '/tmp/wegolint_spec'}
|
8
|
-
let(:wegolinter) { WegoLinter.new(file) }
|
9
|
-
|
10
|
-
subject { wegolinter.output }
|
11
|
-
|
12
|
-
before do
|
13
|
-
FileUtils.mkdir_p test_data_dir
|
14
|
-
File.open(file, 'w+') do |f|
|
15
|
-
f.write(code)
|
16
|
-
end
|
17
|
-
wegolinter.lint!
|
18
|
-
end
|
19
|
-
|
20
|
-
after do
|
21
|
-
File.unlink(file)
|
22
|
-
FileUtils.rmdir test_data_dir
|
23
|
-
end
|
24
|
-
|
25
|
-
describe "General errors" do
|
26
|
-
let(:file) { test_data_dir + '/foo.rb' }
|
27
|
-
|
28
|
-
context "hard tab" do
|
29
|
-
let(:code) { "\t" }
|
30
|
-
|
31
|
-
it { should_have_error "Hard tabs (use soft tabs)", 1, :ruby }
|
32
|
-
end
|
33
|
-
|
34
|
-
context "whitespace at end of line" do
|
35
|
-
let(:code) { "'foo' \n" }
|
36
|
-
|
37
|
-
it { should_have_error "Whitespace at end of line", 1, :ruby }
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
describe "Ruby errors" do
|
42
|
-
let(:file) { test_data_dir + '/foo.rb' }
|
43
|
-
|
44
|
-
context "ruby parser syntax errors" do
|
45
|
-
let(:code) do
|
46
|
-
<<-EOF
|
47
|
-
Foo
|
48
|
-
end
|
49
|
-
EOF
|
50
|
-
end
|
51
|
-
|
52
|
-
it { should_have_error "unexpected keyword_end, expecting $end",2, :ruby }
|
53
|
-
end
|
54
|
-
|
55
|
-
context "80 character limit" do
|
56
|
-
let(:code) do
|
57
|
-
<<-EOF
|
58
|
-
a = 1
|
59
|
-
"kjkjkjkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk"
|
60
|
-
b = 3
|
61
|
-
EOF
|
62
|
-
end
|
63
|
-
|
64
|
-
it { should_have_error "More than eighty characters", 2, :ruby }
|
65
|
-
end
|
66
|
-
|
67
|
-
context "curly brace on its own line" do
|
68
|
-
let(:code) do
|
69
|
-
<<-EOF
|
70
|
-
q = 1
|
71
|
-
{
|
72
|
-
b = 1 }
|
73
|
-
c = a+b
|
74
|
-
EOF
|
75
|
-
end
|
76
|
-
|
77
|
-
it { should_have_error "Curly brace on its own line", 2, :ruby }
|
78
|
-
end
|
79
|
-
|
80
|
-
context "no space on inside of block" do
|
81
|
-
let(:code) do
|
82
|
-
<<-EOF
|
83
|
-
a = 1
|
84
|
-
['a','b','c'].each {|item| puts item }
|
85
|
-
['a','b','c'].each { |item| puts item}
|
86
|
-
b = 2
|
87
|
-
EOF
|
88
|
-
end
|
89
|
-
|
90
|
-
it { should_have_error "Space should be around block", 2, :ruby }
|
91
|
-
it { should_have_error "Space should be around block", 3, :ruby }
|
92
|
-
end
|
93
|
-
|
94
|
-
context "no spaces after (, [ or before ], )" do
|
95
|
-
let(:code) do
|
96
|
-
<<-EOF
|
97
|
-
b = [ 'a' ]
|
98
|
-
def something( foo )
|
99
|
-
c = " [ a ] "
|
100
|
-
c = ' [ ] '
|
101
|
-
[ 'a', 'b' ].each { |line| puts " [ ] " }
|
102
|
-
end
|
103
|
-
doSomething(bar: 'baz', baz: 'bar', foo: 'bar', fa: 'lalalalalalaalalalalalala'
|
104
|
-
)
|
105
|
-
EOF
|
106
|
-
end
|
107
|
-
|
108
|
-
it { should_have_error "No spaces after (", 1, :ruby }
|
109
|
-
it { should_have_error "No spaces after (", 2, :ruby }
|
110
|
-
|
111
|
-
context "when embedded in strings" do
|
112
|
-
it { should_not_have_error "No spaces after (", 3, :ruby }
|
113
|
-
it { should_not_have_error "No spaces after (", 4, :ruby }
|
114
|
-
it { should_have_error "No spaces after (", 5, :ruby }
|
115
|
-
it { should_not_have_error "No spaces after (", 8, :ruby }
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
context "No parentheses around function parameters" do
|
120
|
-
let(:code) do
|
121
|
-
<<-EOF
|
122
|
-
def something(foo)
|
123
|
-
end
|
124
|
-
def something foo, bar
|
125
|
-
end
|
126
|
-
def something
|
127
|
-
end
|
128
|
-
EOF
|
129
|
-
end
|
130
|
-
|
131
|
-
it { should_not_have_error "No parentheses around", 1, :ruby }
|
132
|
-
it { should_have_error "No parentheses around", 3, :ruby }
|
133
|
-
it { should_not_have_error "No parentheses around", 5, :ruby }
|
134
|
-
end
|
135
|
-
|
136
|
-
end
|
137
|
-
|
138
|
-
describe "Javascript errors" do
|
139
|
-
let(:file) { test_data_dir + '/foo.js' }
|
140
|
-
|
141
|
-
context "ruby parser syntax errors" do
|
142
|
-
let(:code) do
|
143
|
-
<<-EOF
|
144
|
-
fah {
|
145
|
-
}
|
146
|
-
EOF
|
147
|
-
end
|
148
|
-
|
149
|
-
it { should_have_error 'missing ; before statement', 1, :javascript }
|
150
|
-
end
|
151
|
-
|
152
|
-
context "80 character limit" do
|
153
|
-
let(:code) do
|
154
|
-
<<-EOF
|
155
|
-
var a = 1;
|
156
|
-
"kjkjkjkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk";
|
157
|
-
var b = 2;
|
158
|
-
EOF
|
159
|
-
end
|
160
|
-
|
161
|
-
it { should_have_error "More than eighty characters", 2, :javascript }
|
162
|
-
end
|
163
|
-
|
164
|
-
context "curly brace on its own line" do
|
165
|
-
let(:code) do
|
166
|
-
<<-EOF
|
167
|
-
var func = function()
|
168
|
-
{
|
169
|
-
var b = 1; }
|
170
|
-
EOF
|
171
|
-
end
|
172
|
-
|
173
|
-
it { should_have_error "Curly brace on its own line", 2, :javascript }
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
def should_have_error message, line_number, language
|
178
|
-
message = build_error_message message, line_number, language
|
179
|
-
subject.should include message
|
180
|
-
end
|
181
|
-
|
182
|
-
def should_not_have_error message, line_number, language
|
183
|
-
message = build_error_message message, line_number, language
|
184
|
-
subject.should_not include message
|
185
|
-
end
|
186
|
-
|
187
|
-
def build_error_message message, line_number, language
|
188
|
-
if language == :ruby
|
189
|
-
name = "foo.rb"
|
190
|
-
line_number = ":#{line_number}:"
|
191
|
-
prefix = " syntax error,"
|
192
|
-
else
|
193
|
-
name = "foo.js"
|
194
|
-
line_number = "(#{line_number}):"
|
195
|
-
prefix = " SyntaxError:"
|
196
|
-
end
|
197
|
-
"#{name}#{line_number}#{prefix} #{message}"
|
198
|
-
end
|
199
|
-
end
|