stylr 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,2 @@
1
+ tags
2
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in stylr.gemspec
4
+ gemspec
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
@@ -0,0 +1,3 @@
1
+ module Stylr
2
+ VERSION = "0.0.6"
3
+ end
data/lib/stylr.rb ADDED
@@ -0,0 +1,8 @@
1
+ require "stylr/version"
2
+ require "stylr/file_parser"
3
+ require "stylr/lint"
4
+ require "stylr/dir_loader"
5
+
6
+ module Stylr
7
+ # Your code goes here...
8
+ end
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
@@ -0,0 +1,5 @@
1
+ class Foo
2
+ def initialize(foo)
3
+ puts foo
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Foo
2
+ def initialize bar
3
+ nil
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ class Foo
2
+ def initialize(bar)
3
+ @bar = bar
4
+ end
5
+
6
+ def some_bad_metaprogrammed_method(foo)
7
+ @bar.send("call_#{foo}")
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class Foo
2
+ def something_risky(bar)
3
+ begin
4
+ # doesn't matter
5
+ rescue
6
+ nil
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ class TextFail
2
+ STRING = <<-EOS
3
+ def initialize foo, bar
4
+ and for or
5
+ end
6
+ EOS
7
+
8
+ def puts_a_string
9
+ """this is
10
+ one dumb for and or
11
+ big def foo bar, baz
12
+ def foo bar, baz
13
+ multiline string"""
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ class Foo
2
+ """
3
+ TENLETTERSTENLETTERSTENLETTERSTENLETTERSTENLETTERSTENLETTERSTENLETTERSTENLETTERSTENLETTERSTENLETTERSTENLETTERS
4
+ """
5
+ end
@@ -0,0 +1,9 @@
1
+ class Foo
2
+ def initialize(bar)
3
+ @bar = bar
4
+ end
5
+
6
+ def some_string
7
+ "and or for wat does you mean"
8
+ end
9
+ end
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