stylr 0.0.6

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.
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