wegolint 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :rubygems
2
+ gemspec
3
+ gem 'rspec'
4
+ gem 'debugger'
data/Gemfile.lock ADDED
@@ -0,0 +1,33 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ wegolint (0.0.1)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ columnize (0.3.6)
10
+ debugger (1.2.0)
11
+ columnize (>= 0.3.1)
12
+ debugger-linecache (~> 1.1.1)
13
+ debugger-ruby_core_source (~> 1.1.3)
14
+ debugger-linecache (1.1.2)
15
+ debugger-ruby_core_source (>= 1.1.1)
16
+ debugger-ruby_core_source (1.1.3)
17
+ diff-lcs (1.1.3)
18
+ rspec (2.11.0)
19
+ rspec-core (~> 2.11.0)
20
+ rspec-expectations (~> 2.11.0)
21
+ rspec-mocks (~> 2.11.0)
22
+ rspec-core (2.11.1)
23
+ rspec-expectations (2.11.3)
24
+ diff-lcs (~> 1.1.3)
25
+ rspec-mocks (2.11.2)
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ debugger
32
+ rspec
33
+ wegolint!
data/README.md ADDED
@@ -0,0 +1,23 @@
1
+ ## What is it?
2
+ This is a tool that validates a code file for a set of style guide rules. These
3
+ rules are run along with the standard parser for the given language. The main
4
+ use for this tool is to pass errors and line numbers to the [Syntastic Vim
5
+ plugin](https://github.com/scrooloose/syntastic).
6
+
7
+ ## Installation Steps
8
+ 1. Install syntastic fork into `~/.vim/bundle/`:
9
+ `git clone git://github.com/tristil/syntastic.git` (you should be using
10
+ [pathogen](https://github.com/tpope/vim-pathogen) if you aren't already)
11
+ 2. Install the `wegolint` gem: `gem install wegolint`
12
+ 3. Put these lines in your `.vimrc`:
13
+
14
+ ```vim
15
+ let syntastic_auto_loc_list=1
16
+ let g:syntastic_quiet_warnings=1
17
+ let g:syntastic_ruby_checker='wegolint'
18
+ let g:syntastic_javascript_checker='wegolint'
19
+ ```
20
+ (first two are optional but recommended for using Syntastic)
21
+
22
+ ## Screenshot with Syntastic
23
+ ![Screenshot](http://dl.dropbox.com/u/48928587/Screenshots/h.png)
data/bin/wegolint ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'wegolint'
4
+
5
+ linter = WegoLint::WegoLinter.new(ARGV[0])
6
+ linter.lint!
7
+ puts linter.output
data/lib/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'wegolint'
data/lib/wegolint.rb ADDED
@@ -0,0 +1,102 @@
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
+ @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
@@ -0,0 +1,4 @@
1
+ RSpec.configure do |config|
2
+ config.treat_symbols_as_metadata_keys_with_true_values = true
3
+ config.run_all_when_everything_filtered = true
4
+ end
@@ -0,0 +1,199 @@
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
data/wegolint.gemspec ADDED
@@ -0,0 +1,16 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'wegolint'
3
+ s.version = '0.0.1'
4
+ s.date = '2012-09-16'
5
+ s.summary = 'Parses code for style guide violations'
6
+ s.description = <<-EOF
7
+ Validates code according to style guide rules for an organization and outputs
8
+ them as error statements that can be consumed by another program.
9
+ EOF
10
+ s.authors = ["Joseph Method"]
11
+ s.email = 'jmethod@wegowise.com'
12
+ s.files = `git ls-files`.split("\n")
13
+ s.homepage = ''
14
+ s.require_paths = ['lib']
15
+ s.executables = ['wegolint']
16
+ end
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wegolint
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Joseph Method
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-16 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: ! 'Validates code according to style guide rules for an organization
15
+ and outputs
16
+
17
+ them as error statements that can be consumed by another program.
18
+
19
+ '
20
+ email: jmethod@wegowise.com
21
+ executables:
22
+ - wegolint
23
+ extensions: []
24
+ extra_rdoc_files: []
25
+ files:
26
+ - .gitignore
27
+ - Gemfile
28
+ - Gemfile.lock
29
+ - README.md
30
+ - bin/wegolint
31
+ - lib/init.rb
32
+ - lib/wegolint.rb
33
+ - spec/spec_helper.rb
34
+ - spec/wegolint_spec.rb
35
+ - wegolint.gemspec
36
+ homepage: ''
37
+ licenses: []
38
+ post_install_message:
39
+ rdoc_options: []
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirements: []
55
+ rubyforge_project:
56
+ rubygems_version: 1.8.24
57
+ signing_key:
58
+ specification_version: 3
59
+ summary: Parses code for style guide violations
60
+ test_files: []