stylr 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +37 -0
- data/LICENSE.txt +22 -0
- data/README.md +37 -0
- data/Rakefile +1 -0
- data/bin/stylr +33 -0
- data/lib/stylr/dir_loader.rb +16 -0
- data/lib/stylr/file_parser.rb +67 -0
- data/lib/stylr/lint.rb +129 -0
- data/lib/stylr/version.rb +3 -0
- data/lib/stylr.rb +8 -0
- data/spec/dir/one.rb +0 -0
- data/spec/dir/three.rb +0 -0
- data/spec/dir/two.rb +0 -0
- data/spec/dir_loader_spec.rb +26 -0
- data/spec/file_parser_spec.rb +83 -0
- data/spec/lint_spec.rb +313 -0
- data/spec/rdir/base.rb +0 -0
- data/spec/rdir/one/one.rb +0 -0
- data/spec/rdir/three/three.rb +0 -0
- data/spec/rdir/two/two.rb +0 -0
- data/spec/sdir/one_spec.rb +0 -0
- data/spec/txt/sample_1.rb +5 -0
- data/spec/txt/sample_fail.rb +5 -0
- data/spec/txt/sample_fail2.rb +9 -0
- data/spec/txt/sample_fail3.rb +9 -0
- data/spec/txt/sample_fail4.rb +15 -0
- data/spec/txt/sample_fail5.rb +5 -0
- data/spec/txt/sample_pass2.rb +9 -0
- data/stylr.gemspec +25 -0
- data/stylr.yml +21 -0
- metadata +151 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d24c550f19bdc73beb58ad28bc25ae1a10295d0b
|
4
|
+
data.tar.gz: c4eb18254875e21ac141c4fbaabf6488a82c9bbe
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: adc05ab742724d576381d07e498b8992fd4f0c34342d5e36ec5b0192e3c91bc61cf03975c07139000c38bb6d7d6fa0bf1b3e0f4fe76fb50813803b400c66eabb
|
7
|
+
data.tar.gz: e5502a2c101be36b9ecd344dec9da4ee4d4ba813f67e8374e1513f6e43988cc99305779a718236b4e207b41505be3fbf3ba704606c4463f9ffa1f34e0b088adf
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
stylr (0.0.4)
|
5
|
+
main (~> 5.2.0)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
arrayfields (4.9.0)
|
11
|
+
chronic (0.10.2)
|
12
|
+
diff-lcs (1.2.5)
|
13
|
+
fattr (2.2.1)
|
14
|
+
main (5.2.0)
|
15
|
+
arrayfields (>= 4.7.4)
|
16
|
+
chronic (>= 0.6.2)
|
17
|
+
fattr (>= 2.2.0)
|
18
|
+
map (>= 5.1.0)
|
19
|
+
map (6.5.1)
|
20
|
+
rake (10.1.1)
|
21
|
+
rspec (2.14.1)
|
22
|
+
rspec-core (~> 2.14.0)
|
23
|
+
rspec-expectations (~> 2.14.0)
|
24
|
+
rspec-mocks (~> 2.14.0)
|
25
|
+
rspec-core (2.14.7)
|
26
|
+
rspec-expectations (2.14.4)
|
27
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
28
|
+
rspec-mocks (2.14.4)
|
29
|
+
|
30
|
+
PLATFORMS
|
31
|
+
ruby
|
32
|
+
|
33
|
+
DEPENDENCIES
|
34
|
+
bundler (~> 1.3)
|
35
|
+
rake
|
36
|
+
rspec
|
37
|
+
stylr!
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Mark Billie & ThoughtWorks, Inc.
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
<h1>stylr</h1>
|
2
|
+
|
3
|
+
Check if source code conforms to some elements of the Github Ruby Style Guidelines ( https://github.com/styleguide/ruby )
|
4
|
+
|
5
|
+
Kind of raw still. Currently supports checking against the following:
|
6
|
+
|
7
|
+
* Line length (user-configurable)
|
8
|
+
* Missing parens around method definitions with parameters (ie, "def foo bar" is disallowed)
|
9
|
+
* Trailing whitespace of any kind
|
10
|
+
* Use of the 'and' or 'or' operators (&& and || are preferred)
|
11
|
+
* Use of 'then' on a multiline if/then construct
|
12
|
+
* Spacing around parens
|
13
|
+
* Spacing around brackets (this is a little broken on multi-line arrays)
|
14
|
+
* Spacing around curly braces (this is also a little broken)
|
15
|
+
* Using the keyword 'for'
|
16
|
+
* Spacing around commas
|
17
|
+
* Using tab characters instead of soft tabs
|
18
|
+
* Spacing around math operators (+, *, etc)
|
19
|
+
|
20
|
+
Optionally checks for some metaprogramming, which you might not want in a large, enterprise codebase with varied levels of skill on your development team. This is not a condemnation of these practices - most of them are good, idiomatic Ruby. You might not, however, want your junior developers checking in lots of metaprogrammed code. Pass the '--meta' flag to enable these checks.
|
21
|
+
|
22
|
+
* eval
|
23
|
+
* class_eval
|
24
|
+
* instance_eval
|
25
|
+
* module_eval
|
26
|
+
* define_method
|
27
|
+
* send
|
28
|
+
|
29
|
+
All of these things are configurable via yml. See "stylr.yml" in the repo, and place it in "~/.stylr.yml"
|
30
|
+
|
31
|
+
Checks all *.rb files in the specified directory and subdirectories, excluding _spec.rb and _test.rb
|
32
|
+
|
33
|
+
<b>Usage</b>
|
34
|
+
|
35
|
+
./stylr /path/to/directory # normal checks
|
36
|
+
|
37
|
+
./stylr /path/to/directory --meta # also check for use of metaprogramming
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/stylr
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'main'
|
4
|
+
require 'stylr'
|
5
|
+
|
6
|
+
module Stylr
|
7
|
+
Main {
|
8
|
+
|
9
|
+
argument('directory') {
|
10
|
+
description "The directory to be parsed."
|
11
|
+
cast :string
|
12
|
+
}
|
13
|
+
|
14
|
+
option('meta') {
|
15
|
+
default false
|
16
|
+
description "Check for metaprogramming violations. Defaults to false."
|
17
|
+
}
|
18
|
+
|
19
|
+
def run
|
20
|
+
directory = params['directory'].values.first
|
21
|
+
meta = params['meta'].values.first ? true : false
|
22
|
+
dir_loader = DirLoader.new
|
23
|
+
dir_loader.load_dir(directory)
|
24
|
+
|
25
|
+
dir_loader.filenames.each do |filename|
|
26
|
+
puts "Checking #{filename}..."
|
27
|
+
FileParser.new(filename, Lint.new, true).violations?(meta)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class DirLoader
|
2
|
+
attr_reader :filenames
|
3
|
+
|
4
|
+
DEPTH = "**/**/**/**/**/**/**/**/**/**/**/**" # lol wut
|
5
|
+
|
6
|
+
def load_dir(dir)
|
7
|
+
@filenames = Dir[File.expand_path(dir) + DEPTH].select do |f|
|
8
|
+
File.file?(f) &&
|
9
|
+
f =~ /\.rb$/
|
10
|
+
end.reject do |f|
|
11
|
+
f =~ /_spec\.rb$/ || f =~ /_test\.rb$/
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Stylr
|
2
|
+
class FileParser
|
3
|
+
attr_reader :lines
|
4
|
+
|
5
|
+
UniqueConstant = ";;;;;"
|
6
|
+
|
7
|
+
def initialize(file_path, lint, display = false)
|
8
|
+
@lines = []
|
9
|
+
@lint = lint
|
10
|
+
@display = display
|
11
|
+
@file_string = File.read(file_path)
|
12
|
+
end
|
13
|
+
|
14
|
+
def violations?(meta = false)
|
15
|
+
pre_multiline_string_removal_length_check!
|
16
|
+
remove_multiline_strings!
|
17
|
+
assign_lines_with_numbers!
|
18
|
+
|
19
|
+
@lines.each do |array|
|
20
|
+
line, number = array
|
21
|
+
@lint.violation?(line, number)
|
22
|
+
@lint.exception_violation?(line, number)
|
23
|
+
@lint.meta_violation?(line, number) if meta
|
24
|
+
end
|
25
|
+
|
26
|
+
if @lint.errors.any?
|
27
|
+
display_errors if @display
|
28
|
+
true
|
29
|
+
else
|
30
|
+
display_no_error_message if @display
|
31
|
+
false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def assign_lines_with_numbers!
|
36
|
+
@file_string.each_with_index do |line, number|
|
37
|
+
@lines << [line, number + 1]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def pre_multiline_string_removal_length_check!
|
42
|
+
@file_string.split(/\n/).each_with_index do |line, number|
|
43
|
+
@lint.line_too_long_violation?(line, number + 1)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def remove_multiline_strings!
|
48
|
+
@file_string = @file_string.gsub(/\n/, UniqueConstant)
|
49
|
+
@file_string = @lint.strip_multiline_strings(@file_string)
|
50
|
+
@file_string = @file_string.gsub(/#{UniqueConstant}/, "#{UniqueConstant}\n")
|
51
|
+
@file_string = @file_string.split(/#{UniqueConstant}/)
|
52
|
+
end
|
53
|
+
|
54
|
+
def display_no_error_message
|
55
|
+
puts "Your file is free of errors."
|
56
|
+
end
|
57
|
+
|
58
|
+
def display_errors
|
59
|
+
puts "You have the following errors:"
|
60
|
+
@lint.errors.each do |hash|
|
61
|
+
error = hash.keys.first
|
62
|
+
line_number = hash.values.first
|
63
|
+
puts "Line #{line_number}: #{@lint.send(error)}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/stylr/lint.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
class Lint
|
4
|
+
attr_reader :errors, :violations, :exception_violations, :metaprogramming_violations, :messages
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@errors = []
|
8
|
+
@config = YAML.load_file(ENV["HOME"] + "/.stylr.yml")
|
9
|
+
setup_class_values
|
10
|
+
end
|
11
|
+
|
12
|
+
def line_too_long_violation?(line, number = 1)
|
13
|
+
abstract_violation?(@line_too_long_violations, line, number)
|
14
|
+
end
|
15
|
+
|
16
|
+
def violation?(line, number = 1)
|
17
|
+
line = strip_strings(line)
|
18
|
+
abstract_violation?(@violations, line, number)
|
19
|
+
end
|
20
|
+
|
21
|
+
def meta_violation?(line, number = 1)
|
22
|
+
abstract_violation?(@metaprogramming_violations, line, number)
|
23
|
+
end
|
24
|
+
|
25
|
+
def exception_violation?(line, number = 1)
|
26
|
+
abstract_violation?(@exception_violations, line, number)
|
27
|
+
end
|
28
|
+
|
29
|
+
def strip_multiline_strings(string)
|
30
|
+
string.tap do |str|
|
31
|
+
str.gsub!(/""".*"""/, '""')
|
32
|
+
start = /<<-?[A-Z]+/
|
33
|
+
finish = (str[start] || "")[/[A-Z]+/]
|
34
|
+
regexp = /#{start}.*\b#{finish}\b/
|
35
|
+
str.gsub!(/#{str[regexp]}/,'""') if str[regexp]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def strip_strings(line)
|
40
|
+
line.gsub(/".*"/, '""').gsub(/'.*'/, "''")
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def abstract_violation?(list, line, number)
|
46
|
+
list.each do |pattern, error|
|
47
|
+
@commented_line.each do |comment|
|
48
|
+
return false if line[comment]
|
49
|
+
end
|
50
|
+
|
51
|
+
if line[pattern]
|
52
|
+
@errors << { error => number }
|
53
|
+
return true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
return false
|
57
|
+
end
|
58
|
+
|
59
|
+
def setup_class_values
|
60
|
+
@line_too_long_violations = {
|
61
|
+
/.{#{@config["line_length"]}}+/ => :line_too_long
|
62
|
+
}.delete_if { |_, v| !@config[v.to_s] }
|
63
|
+
|
64
|
+
@violations = {
|
65
|
+
/def (self\.)?\w+[!?]? .\w+/ => :missing_parens,
|
66
|
+
/( )+$/ => :trailing_whitespace,
|
67
|
+
/\band\b/ => :the_word_and,
|
68
|
+
/\bor\b/ => :the_word_or,
|
69
|
+
/\bfor\b/ => :the_word_for,
|
70
|
+
/\bif\b.*\bthen\b\n/ => :multiline_if_then,
|
71
|
+
/\(\s|\s\)/ => :paren_spacing,
|
72
|
+
/\[\s|\s\]/ => :bracket_spacing,
|
73
|
+
/[^\s][{}]|{[^\s]/ => :brace_spacing,
|
74
|
+
/,[^ \n]/ => :comma_spacing,
|
75
|
+
/\t/ => :no_soft_tabs,
|
76
|
+
/[^\s]\+/ => :no_operator_spaces,
|
77
|
+
/\+[^\s=]/ => :no_operator_spaces,
|
78
|
+
/[^\s]-/ => :no_operator_spaces
|
79
|
+
}.delete_if { |_, v| !@config[v.to_s] }
|
80
|
+
|
81
|
+
@exception_violations = {
|
82
|
+
/rescue\s*(Exception)?$/ => :rescue_class_exception
|
83
|
+
}.delete_if { |_, v| !@config[v.to_s] }
|
84
|
+
|
85
|
+
@metaprogramming_violations = {
|
86
|
+
/\beval\b/ => :used_eval,
|
87
|
+
/\bclass_eval\b/ => :used_class_eval,
|
88
|
+
/\bmodule_eval\b/ => :used_module_eval,
|
89
|
+
/\binstance_eval\b/ => :used_instance_eval,
|
90
|
+
/\bdefine_method\b/ => :used_define_method,
|
91
|
+
/\w+\.send.*".*#\{/ => :dynamic_invocation
|
92
|
+
}.delete_if { |_, v| !@config[v.to_s] }
|
93
|
+
|
94
|
+
@commented_line = [
|
95
|
+
/^\s*#/
|
96
|
+
]
|
97
|
+
|
98
|
+
@messages = {
|
99
|
+
:missing_parens => "You have omitted parentheses from a method definition with parameters.",
|
100
|
+
:line_too_long => "Line length of #{@config['line_length']} characters or more.",
|
101
|
+
:trailing_whitespace => "Trailing whitespace.",
|
102
|
+
:used_eval => "Used eval.",
|
103
|
+
:used_define_method => "Used define_method.",
|
104
|
+
:dynamic_invocation => "Dynamic invocation of a method.",
|
105
|
+
:rescue_class_exception => "Rescuing class Exception.",
|
106
|
+
:the_word_and => "Used 'and'; please use && instead.",
|
107
|
+
:the_word_or => "Used 'or'; please use || instead.",
|
108
|
+
:the_word_for => "Used 'for'; please use an enumerator, or else explain yourself adequately to the team.",
|
109
|
+
:multiline_if_then => "Used 'then' on a multiline if statement.",
|
110
|
+
:used_class_eval => "Used class_eval.",
|
111
|
+
:used_module_eval => "Used module_eval.",
|
112
|
+
:used_instance_eval => "Used instance_eval.",
|
113
|
+
:paren_spacing => "Space after ( or before ).",
|
114
|
+
:bracket_spacing => "Space after [ or before ].",
|
115
|
+
:brace_spacing => "No space around { or before }.",
|
116
|
+
:comma_spacing => "No space after a comma.",
|
117
|
+
:no_soft_tabs => "Used tab characters; please use soft tabs.",
|
118
|
+
:no_operator_spaces => "Please use spaces around operators."
|
119
|
+
}
|
120
|
+
end
|
121
|
+
|
122
|
+
def method_missing(method_name, *args, &block)
|
123
|
+
if @messages.keys.include?(method_name.to_sym)
|
124
|
+
@messages[method_name]
|
125
|
+
else
|
126
|
+
super(method_name, *args, &block)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
data/lib/stylr.rb
ADDED
data/spec/dir/one.rb
ADDED
File without changes
|
data/spec/dir/three.rb
ADDED
File without changes
|
data/spec/dir/two.rb
ADDED
File without changes
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "stylr"
|
2
|
+
|
3
|
+
module Stylr
|
4
|
+
describe DirLoader do
|
5
|
+
let(:d) { DirLoader.new }
|
6
|
+
|
7
|
+
it "loads all ruby files in a directory" do
|
8
|
+
dir = "/Users/Thoughtworker/stylr/spec/dir"
|
9
|
+
d.load_dir(dir)
|
10
|
+
d.filenames.should == ["#{dir}/one.rb", "#{dir}/two.rb", "#{dir}/three.rb"].sort
|
11
|
+
end
|
12
|
+
|
13
|
+
it "loads all files even in a recursive structure" do
|
14
|
+
dir = "/Users/Thoughtworker/stylr/spec/rdir"
|
15
|
+
d.load_dir(dir)
|
16
|
+
d.filenames.should == ["#{dir}/one/one.rb", "#{dir}/two/two.rb", "#{dir}/three/three.rb", "#{dir}/base.rb"].sort
|
17
|
+
end
|
18
|
+
|
19
|
+
it "ignores specs" do
|
20
|
+
dir = "/Users/Thoughtworker/stylr/spec/sdir"
|
21
|
+
d.load_dir(dir)
|
22
|
+
d.filenames.should == []
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require "stylr"
|
2
|
+
|
3
|
+
module Stylr
|
4
|
+
YAML_FILE_LOCATION = "/Users/Thoughtworker/stylr/stylr.yml"
|
5
|
+
describe FileParser do
|
6
|
+
context "sample_1" do
|
7
|
+
before(:each) do
|
8
|
+
@string = "/Users/Thoughtworker/stylr/spec/txt/sample_1.rb"
|
9
|
+
@f = FileParser.new(@string, Lint.new)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "checks the file for errors" do
|
13
|
+
@f.violations?.should be_false
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "sample_fail" do
|
18
|
+
before(:each) do
|
19
|
+
@string = "/Users/Thoughtworker/stylr/spec/txt/sample_fail.rb"
|
20
|
+
@f = FileParser.new(@string, Lint.new)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "knows when something has failed" do
|
24
|
+
@f.violations?.should be_true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "sample_pass2" do
|
29
|
+
before(:each) do
|
30
|
+
@string = "/Users/Thoughtworker/stylr/spec/txt/sample_pass2.rb"
|
31
|
+
@f = FileParser.new(@string, Lint.new)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "doesn't break when shit appears in strings" do
|
35
|
+
@f.violations?.should be_false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "sample_fail2" do
|
40
|
+
before(:each) do
|
41
|
+
@string = "/Users/Thoughtworker/stylr/spec/txt/sample_fail2.rb"
|
42
|
+
@f = FileParser.new(@string, Lint.new)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "knows when something has failed" do
|
46
|
+
@f.violations?(meta = true).should be_true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "sample_fail3" do
|
51
|
+
before(:each) do
|
52
|
+
@string = "/Users/Thoughtworker/stylr/spec/txt/sample_fail3.rb"
|
53
|
+
@f = FileParser.new(@string, Lint.new)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "knows when something has failed" do
|
57
|
+
@f.violations?.should be_true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "sample_fail4" do
|
62
|
+
before(:each) do
|
63
|
+
@string = "/Users/Thoughtworker/stylr/spec/txt/sample_fail4.rb"
|
64
|
+
@f = FileParser.new(@string, Lint.new)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "knows when something has failed" do
|
68
|
+
@f.violations?.should be_false
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "sample_fail5" do
|
73
|
+
before(:each) do
|
74
|
+
@string = "/Users/Thoughtworker/stylr/spec/txt/sample_fail5.rb"
|
75
|
+
@f = FileParser.new(@string, Lint.new)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "knows when something has failed" do
|
79
|
+
@f.violations?.should be_true
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/spec/lint_spec.rb
ADDED
@@ -0,0 +1,313 @@
|
|
1
|
+
require "stylr"
|
2
|
+
|
3
|
+
module Stylr
|
4
|
+
describe Lint do
|
5
|
+
let(:l) { Lint.new }
|
6
|
+
|
7
|
+
context "#violation?" do
|
8
|
+
context "missing_parens" do
|
9
|
+
it "wants parens around method definitions with args" do
|
10
|
+
l.violation?("def foo bar, baz").should be_true
|
11
|
+
end
|
12
|
+
|
13
|
+
it "does not need parens for methods with no args" do
|
14
|
+
l.violation?("def some_method").should be_false
|
15
|
+
end
|
16
|
+
|
17
|
+
it "using parens is good" do
|
18
|
+
l.violation?("def foo(bar, baz)").should be_false
|
19
|
+
end
|
20
|
+
|
21
|
+
it "using parens for methods with bang is the same" do
|
22
|
+
l.violation?("def foo!").should be_false
|
23
|
+
end
|
24
|
+
|
25
|
+
it "a bang method with args needs parens too" do
|
26
|
+
l.violation?("def foo! bar").should be_true
|
27
|
+
end
|
28
|
+
|
29
|
+
it "a question mark method without args is fine" do
|
30
|
+
l.violation?("def foo?").should be_false
|
31
|
+
end
|
32
|
+
|
33
|
+
it "a question mark method with args needs parens" do
|
34
|
+
l.violation?("def foo? bar").should be_true
|
35
|
+
end
|
36
|
+
|
37
|
+
it "class methods with bang+no args are fine" do
|
38
|
+
l.violation?("def self.foo!").should be_false
|
39
|
+
end
|
40
|
+
|
41
|
+
it "class methods with bang+args need parens" do
|
42
|
+
l.violation?("def self.foo! bar").should be_true
|
43
|
+
end
|
44
|
+
|
45
|
+
it "class methods with qmark+no args are fine" do
|
46
|
+
l.violation?("def self.foo?").should be_false
|
47
|
+
end
|
48
|
+
|
49
|
+
it "class methods with qmark+args need parens" do
|
50
|
+
l.violation?("def self.foo? bar").should be_true
|
51
|
+
end
|
52
|
+
|
53
|
+
it "positive case for bang" do
|
54
|
+
l.violation?("def foo!(bar)").should be_false
|
55
|
+
end
|
56
|
+
|
57
|
+
it "positive case for class method bang" do
|
58
|
+
l.violation?("def self.foo!(bar)").should be_false
|
59
|
+
end
|
60
|
+
|
61
|
+
it "positive case for qmark" do
|
62
|
+
l.violation?("def foo?(bar)").should be_false
|
63
|
+
end
|
64
|
+
|
65
|
+
it "positive case for class method qmark" do
|
66
|
+
l.violation?("def self.foo?(bar)").should be_false
|
67
|
+
end
|
68
|
+
|
69
|
+
it "acts the same for class methods" do
|
70
|
+
l.violation?("def self.something foo, bar").should be_true
|
71
|
+
end
|
72
|
+
|
73
|
+
it "no parens for class methods without args is fine too" do
|
74
|
+
l.violation?("def self.something").should be_false
|
75
|
+
end
|
76
|
+
|
77
|
+
it "arrays of args too need parens in the method def" do
|
78
|
+
l.violation?("def foo *args").should be_true
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context "operator spacing" do
|
83
|
+
it "spaces around + are good" do
|
84
|
+
l.violation?("2+2").should be_true
|
85
|
+
end
|
86
|
+
|
87
|
+
it "on both sides" do
|
88
|
+
l.violation?("2 +2").should be_true
|
89
|
+
end
|
90
|
+
|
91
|
+
it "but += is ok" do
|
92
|
+
l.violation?("x += 2").should be_false
|
93
|
+
end
|
94
|
+
|
95
|
+
it "same with -" do
|
96
|
+
l.violation?("2-2").should be_true
|
97
|
+
end
|
98
|
+
|
99
|
+
it "-= is fine" do
|
100
|
+
l.violation?("x -= 3").should be_false
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context "soft tabs" do
|
105
|
+
it "don't use actual tabs" do
|
106
|
+
l.violation?("\t").should be_true
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context "space after open paren/bracket or before close paren/bracket" do
|
111
|
+
it "space after open paren is bad" do
|
112
|
+
l.violation?("def foo( bar)").should be_true
|
113
|
+
end
|
114
|
+
|
115
|
+
it "space before close paren is also bad" do
|
116
|
+
l.violation?("def foo(bar )").should be_true
|
117
|
+
end
|
118
|
+
|
119
|
+
it "space after open bracket is bad" do
|
120
|
+
l.violation?("list = [ 1, 2, 3]").should be_true
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "space around { and } is good" do
|
125
|
+
it "no space before { is bad" do
|
126
|
+
l.violation?("lambda{puts :foo}").should be_true
|
127
|
+
end
|
128
|
+
|
129
|
+
it "no space before } is bad" do
|
130
|
+
l.violation?("lambda { puts :foo}").should be_true
|
131
|
+
end
|
132
|
+
|
133
|
+
it "no space after { is also bad" do
|
134
|
+
l.violation?("{:foo }").should be_true
|
135
|
+
end
|
136
|
+
|
137
|
+
it "no space after } is fine" do
|
138
|
+
l.violation?("lambda { puts :foo }.call").should be_false
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context "space after commas" do
|
143
|
+
it "should have a space after a comma" do
|
144
|
+
l.violation?("[1,2,3]").should be_true
|
145
|
+
end
|
146
|
+
|
147
|
+
it "can also pass..." do
|
148
|
+
l.violation?("[1, 2, 3]").should be_false
|
149
|
+
end
|
150
|
+
|
151
|
+
it "newline after a comma is fine" do
|
152
|
+
l.violation?(":a => 1,\n").should be_false
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
context "line_too_long" do
|
157
|
+
it "dislikes lines of >= 80 chars" do
|
158
|
+
l.line_too_long_violation?("#{'a' * 80}").should be_true
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context "trailing_whitespace" do
|
163
|
+
it "whitespace at the end of the line is a no-no" do
|
164
|
+
l.violation?("def foo(bar) ").should be_true
|
165
|
+
end
|
166
|
+
|
167
|
+
it "a newline is ok by itself" do
|
168
|
+
l.violation?("\n").should be_false
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
context "and and or" do
|
173
|
+
it "the word 'and' is banned" do
|
174
|
+
l.violation?("foo and bar").should be_true
|
175
|
+
end
|
176
|
+
|
177
|
+
it "the word 'or' is also banned" do
|
178
|
+
l.violation?("1 or nil").should be_true
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
context "for loops" do
|
183
|
+
it "generally you should not use for loops" do
|
184
|
+
l.violation?("for x in list do").should be_true
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
context "multiline if then" do
|
189
|
+
it "should not use then in multiline if" do
|
190
|
+
l.violation?("if foo then\nbar\nend").should be_true
|
191
|
+
end
|
192
|
+
|
193
|
+
it "single line if then end is ok" do
|
194
|
+
l.violation?("if true then false end").should be_false
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
context "multiline strings" do
|
199
|
+
it "ignores multiline strings" do
|
200
|
+
l.strip_multiline_strings("sql = <<-SQL for and or SQL").should == "sql = \"\""
|
201
|
+
end
|
202
|
+
|
203
|
+
it "ignores the other kind too" do
|
204
|
+
l.strip_multiline_strings('"""foo bar baz"""').should == '""'
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context "comments" do
|
209
|
+
it "ignores comments" do
|
210
|
+
l.violation?("# a comment").should be_false
|
211
|
+
end
|
212
|
+
|
213
|
+
it "ignores comments even when they otherwise violate the rules" do
|
214
|
+
l.violation?("# def foo bar").should be_false
|
215
|
+
end
|
216
|
+
|
217
|
+
it "does not care what violation the comment breaks" do
|
218
|
+
l.violation?("# and or def foo bar, baz").should be_false
|
219
|
+
end
|
220
|
+
|
221
|
+
it "ignores indented comments" do
|
222
|
+
l.violation?(" # def foo bar").should be_false
|
223
|
+
end
|
224
|
+
|
225
|
+
it "ignores comments indented with soft tabs" do
|
226
|
+
l.violation?(" # def foo bar").should be_false
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
context "#meta_violation?" do
|
232
|
+
it "can optionally check for metaprogramming" do
|
233
|
+
l.meta_violation?("eval").should be_true
|
234
|
+
end
|
235
|
+
|
236
|
+
it "fucking HATES define_method" do
|
237
|
+
l.meta_violation?("define_method").should be_true
|
238
|
+
end
|
239
|
+
|
240
|
+
it "dynamic method invocation via send is bad, mmkay?" do
|
241
|
+
l.meta_violation?('foo.send "foo_#{:bar}"').should be_true
|
242
|
+
end
|
243
|
+
|
244
|
+
it "class eval, why not?" do
|
245
|
+
l.meta_violation?("class_eval &block").should be_true
|
246
|
+
end
|
247
|
+
|
248
|
+
it "module eval is also naughty" do
|
249
|
+
l.meta_violation?("module_eval foo").should be_true
|
250
|
+
end
|
251
|
+
|
252
|
+
it "and even instance eval!" do
|
253
|
+
l.meta_violation?("instance_eval &block").should be_true
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
context "#exception_violation?" do
|
258
|
+
it "rescuing Exception is bad" do
|
259
|
+
l.exception_violation?("rescue Exception").should be_true
|
260
|
+
end
|
261
|
+
|
262
|
+
it "rescuing nothing is the same as rescuing Exception" do
|
263
|
+
l.exception_violation?("rescue ").should be_true
|
264
|
+
end
|
265
|
+
|
266
|
+
it "rescuing an exception that ends with Exception is ok" do
|
267
|
+
l.violation?("rescue MyCustomException").should be_false
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
context "string stripping" do
|
272
|
+
it "removes strings so it doesn't break on them" do
|
273
|
+
l.strip_strings("def foo(\"bar\")").should == "def foo(\"\")"
|
274
|
+
end
|
275
|
+
|
276
|
+
it "does the same with single-quoted strings" do
|
277
|
+
l.strip_strings("def foo('bar')").should == "def foo('')"
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
context "error messages" do
|
282
|
+
it "keeps track of your mistakes and their lines, defaulting to line #1" do
|
283
|
+
l.violation?("def foo bar")
|
284
|
+
l.errors.first.values.should == [1]
|
285
|
+
end
|
286
|
+
|
287
|
+
it "knows what line number you fucked up on" do
|
288
|
+
l.violation?("def foo bar", 3)
|
289
|
+
l.errors.first.values.should == [3]
|
290
|
+
end
|
291
|
+
|
292
|
+
it "everything has an error message" do
|
293
|
+
expect do
|
294
|
+
l.violations.values.each do |violation|
|
295
|
+
l.messages.fetch(violation)
|
296
|
+
end
|
297
|
+
l.exception_violations.values.each do |exception_violation|
|
298
|
+
l.messages.fetch(exception_violation)
|
299
|
+
end
|
300
|
+
l.metaprogramming_violations.values.each do |metaprogramming_violation|
|
301
|
+
l.messages.fetch(metaprogramming_violation)
|
302
|
+
end
|
303
|
+
end.to_not raise_error
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
context "#method_missing" do
|
308
|
+
it "implements method_missing intelligently" do
|
309
|
+
expect { l.foo }.to raise_error
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
data/spec/rdir/base.rb
ADDED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/stylr.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'stylr/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "stylr"
|
8
|
+
spec.version = Stylr::VERSION
|
9
|
+
spec.authors = ["Mark Billie"]
|
10
|
+
spec.email = ["mbillie1@gmail.com"]
|
11
|
+
spec.description = %q{An attempt at enforcing https://github.com/styleguide/ruby}
|
12
|
+
spec.summary = %q{stylr - enforcing Ruby coding style standards}
|
13
|
+
spec.homepage = "https://github.com/yaaase/stylr.git"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency "main", "~> 5.2.0"
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
end
|
data/stylr.yml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
line_length: 80
|
2
|
+
line_too_long: true
|
3
|
+
missing_parens: true
|
4
|
+
trailing_whitespace: true
|
5
|
+
the_word_and: true
|
6
|
+
the_word_or: true
|
7
|
+
the_word_for: true
|
8
|
+
multiline_if_then: true
|
9
|
+
paren_spacing: true
|
10
|
+
bracket_spacing: true
|
11
|
+
brace_spacing: true
|
12
|
+
comma_spacing: true
|
13
|
+
no_soft_tabs: true
|
14
|
+
no_operator_spaces: true
|
15
|
+
rescue_class_exception: true
|
16
|
+
used_eval: true
|
17
|
+
used_class_eval: true
|
18
|
+
used_module_eval: true
|
19
|
+
used_instance_eval: true
|
20
|
+
used_define_method: true
|
21
|
+
dynamic_invocation: true
|
metadata
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: stylr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mark Billie
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-12-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: main
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 5.2.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 5.2.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: An attempt at enforcing https://github.com/styleguide/ruby
|
70
|
+
email:
|
71
|
+
- mbillie1@gmail.com
|
72
|
+
executables:
|
73
|
+
- stylr
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- .gitignore
|
78
|
+
- Gemfile
|
79
|
+
- Gemfile.lock
|
80
|
+
- LICENSE.txt
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- bin/stylr
|
84
|
+
- lib/stylr.rb
|
85
|
+
- lib/stylr/dir_loader.rb
|
86
|
+
- lib/stylr/file_parser.rb
|
87
|
+
- lib/stylr/lint.rb
|
88
|
+
- lib/stylr/version.rb
|
89
|
+
- spec/dir/one.rb
|
90
|
+
- spec/dir/three.rb
|
91
|
+
- spec/dir/two.rb
|
92
|
+
- spec/dir_loader_spec.rb
|
93
|
+
- spec/file_parser_spec.rb
|
94
|
+
- spec/lint_spec.rb
|
95
|
+
- spec/rdir/base.rb
|
96
|
+
- spec/rdir/one/one.rb
|
97
|
+
- spec/rdir/three/three.rb
|
98
|
+
- spec/rdir/two/two.rb
|
99
|
+
- spec/sdir/one_spec.rb
|
100
|
+
- spec/txt/sample_1.rb
|
101
|
+
- spec/txt/sample_fail.rb
|
102
|
+
- spec/txt/sample_fail2.rb
|
103
|
+
- spec/txt/sample_fail3.rb
|
104
|
+
- spec/txt/sample_fail4.rb
|
105
|
+
- spec/txt/sample_fail5.rb
|
106
|
+
- spec/txt/sample_pass2.rb
|
107
|
+
- stylr.gemspec
|
108
|
+
- stylr.yml
|
109
|
+
homepage: https://github.com/yaaase/stylr.git
|
110
|
+
licenses:
|
111
|
+
- MIT
|
112
|
+
metadata: {}
|
113
|
+
post_install_message:
|
114
|
+
rdoc_options: []
|
115
|
+
require_paths:
|
116
|
+
- lib
|
117
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - '>='
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - '>='
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
requirements: []
|
128
|
+
rubyforge_project:
|
129
|
+
rubygems_version: 2.0.6
|
130
|
+
signing_key:
|
131
|
+
specification_version: 4
|
132
|
+
summary: stylr - enforcing Ruby coding style standards
|
133
|
+
test_files:
|
134
|
+
- spec/dir/one.rb
|
135
|
+
- spec/dir/three.rb
|
136
|
+
- spec/dir/two.rb
|
137
|
+
- spec/dir_loader_spec.rb
|
138
|
+
- spec/file_parser_spec.rb
|
139
|
+
- spec/lint_spec.rb
|
140
|
+
- spec/rdir/base.rb
|
141
|
+
- spec/rdir/one/one.rb
|
142
|
+
- spec/rdir/three/three.rb
|
143
|
+
- spec/rdir/two/two.rb
|
144
|
+
- spec/sdir/one_spec.rb
|
145
|
+
- spec/txt/sample_1.rb
|
146
|
+
- spec/txt/sample_fail.rb
|
147
|
+
- spec/txt/sample_fail2.rb
|
148
|
+
- spec/txt/sample_fail3.rb
|
149
|
+
- spec/txt/sample_fail4.rb
|
150
|
+
- spec/txt/sample_fail5.rb
|
151
|
+
- spec/txt/sample_pass2.rb
|