rlint 0.0.1

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.
Files changed (7) hide show
  1. data/bin/rlint +3 -0
  2. data/lib/parser.rb +149 -0
  3. data/lib/report.rb +10 -0
  4. data/lib/rlint.rb +33 -0
  5. data/lib/rule.rb +119 -0
  6. data/lib/runner.rb +88 -0
  7. metadata +59 -0
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'rlint'
@@ -0,0 +1,149 @@
1
+ require 'report'
2
+
3
+ class Parser
4
+ attr_reader :reports
5
+ def initialize
6
+ @reports = []
7
+ end
8
+
9
+ def see(line, file, num_line)
10
+ @file = file
11
+ @line = line
12
+ @num_line = num_line
13
+
14
+ check_line
15
+ end
16
+
17
+ def set_rule(rule)
18
+ @rule = rule
19
+ end
20
+
21
+ private
22
+
23
+ def check_line
24
+ check_def_line if line_is_def
25
+ check_simple_line if simple_line?
26
+ check_class_line if is_a_class?
27
+ end
28
+
29
+ def check_def_line
30
+ check_method_name
31
+ check_parameters
32
+ check_optional_parameters if has_optional_parameters?
33
+ check_columns
34
+ end
35
+
36
+ def check_class_line
37
+ check_class_name
38
+ check_columns
39
+ end
40
+
41
+ def check_simple_line
42
+ # Ignore lines with 'end' and only newline.
43
+ return if @line.match(/^(\n)+$|^(\t)+\n$|^(.)*end$/)
44
+ check_columns
45
+ check_method_call
46
+ check_columns
47
+ end
48
+
49
+ def line_is_def
50
+ return (@line.match(/def /))? true : false
51
+ end
52
+
53
+ def simple_line?
54
+ return (@line.match(/def |class |module /))? false : true
55
+ end
56
+
57
+ def is_a_class?
58
+ return (@line.match(/class |module /))? true : false
59
+ end
60
+
61
+ def has_optional_parameters?
62
+ return (@line.match(/\w+(.)*=(.)*[\{|"|d+]/))? true : false
63
+ end
64
+
65
+ def check_method_name
66
+ if !@line.match(@rule.method_name_rule)
67
+ report = Report.new()
68
+ report.line = @line
69
+ report.file = @file
70
+ report.num_line = @num_line
71
+ report.error = "Method isn't agreement with 'method name rule'"
72
+ @reports << report
73
+ end
74
+ end
75
+
76
+ def check_class_name
77
+ if !@line.match(@rule.class_name_rule)
78
+ report = Report.new()
79
+ report.line = @line
80
+ report.file = @file
81
+ report.num_line = @num_line
82
+ report.error = "Class/Module name isn't in accordance with rule."
83
+ @reports << report
84
+ end
85
+ end
86
+
87
+ def check_optional_parameters
88
+ if !@line.match(@rule.optional_parameter_rule)
89
+ report = Report.new()
90
+ report.line = @line
91
+ report.file = @file
92
+ report.num_line = @num_line
93
+ report.error = "Optional parameter isn't agreement with 'optional parameter rule'"
94
+ @reports << report
95
+ end
96
+ end
97
+
98
+ def check_parameters
99
+ if !@line.match(/\?/)
100
+ basic_method
101
+ else
102
+ ask_method
103
+ end
104
+ end
105
+
106
+ def basic_method
107
+ if !@line.match(@rule.parameter_rule)
108
+ report = Report.new()
109
+ report.line = @line
110
+ report.file = @file
111
+ report.num_line = @num_line
112
+ report.error = "Parameter isn't agreement with 'parameter rule'"
113
+ @reports << report
114
+ end
115
+ end
116
+
117
+ def ask_method
118
+ if !@line.match(@rule.ask_method_rule)
119
+ report = Report.new()
120
+ report.line = @line
121
+ report.file = @file
122
+ report.num_line = @num_line
123
+ report.error = "Parameter isn't agreement with 'ask method rule'"
124
+ @reports << report
125
+ end
126
+ end
127
+
128
+ def check_columns
129
+ if !@rule.check_columns(@line)
130
+ report = Report.new()
131
+ report.line = @line
132
+ report.file = @file
133
+ report.num_line = @num_line
134
+ report.error = "This line exceeded columns limit: #{@rule.column_width_rule}."
135
+ @reports << report
136
+ end
137
+ end
138
+
139
+ def check_method_call
140
+ if !@line.match(@rule.method_call_rule)
141
+ report = Report.new()
142
+ report.line = @line
143
+ report.file = @file
144
+ report.num_line = @num_line
145
+ report.error = "Incorrect method call."
146
+ @reports << report
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,10 @@
1
+ class Report
2
+ attr_accessor :line, :num_line, :error, :file
3
+
4
+ def to_s
5
+ "#{@error}\n".color(:red) +
6
+ "#{@file}".color(:yellow) + " - line #{@num_line}: #{@line.gsub(/\t/,'')}
7
+ "
8
+ end
9
+ end
10
+
@@ -0,0 +1,33 @@
1
+ require 'rubygems'
2
+ require 'runner'
3
+ require 'optparse'
4
+
5
+ options = {}
6
+ opts = OptionParser.new do |opt|
7
+ opt.banner = "Usage: rlint.rb [options]"
8
+
9
+ opt.on("-d dir", "--dir", "Code to analizy") do |f|
10
+ options[:dir] = f
11
+ end
12
+
13
+ opt.on("-r rule", "--rule", "File with rules") do |r|
14
+ options[:rule] = r
15
+ end
16
+
17
+ #opt.on_tail("-h", "--help", "Help") do
18
+ # puts opt
19
+ # exit
20
+ #end
21
+ end#.parse!
22
+
23
+ # Don't allow empty args
24
+ if ARGV.empty?
25
+ puts opts
26
+ exit -1
27
+ end
28
+
29
+ opts.parse!(ARGV)
30
+
31
+ Runner.run(options[:dir], options[:rule])
32
+
33
+
@@ -0,0 +1,119 @@
1
+ class Rule
2
+ attr_reader :method_name_rule, :optional_parameter_rule, :parameter_rule, :column_width_rule
3
+ attr_reader :ask_method_rule, :method_call_rule, :class_name_rule
4
+ attr_reader :tabs_size
5
+
6
+ def snakecase_method(value=true)
7
+ if value
8
+ @method_name_rule = /def ([a-z]|\_|\?|\!)*(\(| |\n)/
9
+ else
10
+ @method_name_rule = /def ([a-z]|\?|\!)*(\(| |\n)/
11
+ end
12
+ end
13
+
14
+ def parameters(whitespace)
15
+ if whitespace
16
+ @parameter_rule = /\(\w+\)|\(\w+\, (\w+|\w+\, |\w+(.)*=(.)*[\{|\}|\"|\'|\[|\]])*\)|^def (\w+$|\w+\(\)$)/
17
+ else
18
+ @parameter_rule = /\((\w+|\,|\w+(.)*\=\{(.)*\})*\)/
19
+ end
20
+ end
21
+
22
+ #
23
+ # Ask method rule
24
+ #
25
+ # 0 -> 'def method?' or 'def method? a' or def method?(a, b)' - OK
26
+ # 1 -> 'def method?' or 'def method?(a)' or 'def method?(a,b)' - OK
27
+ # 2 -> 'def method?' or 'def method?(a)' or 'def method?(a, b)' - OK
28
+ # 3 -> 'def method?' or 'def method? a' or 'def method? a, b' - OK
29
+ #
30
+ def ask_method(mode)
31
+ case mode
32
+ when 0
33
+ @ask_method_rule = /^def (\w+\?$|\w+\? \w+$|\w+\?\((\w+|\, \w+)*\)$)/
34
+ when 1
35
+ @ask_method_rule = /^def (\w+\?$|\w+\?\(\w+\)$|\w+\?\((\w+|\, \w+)*\)$)/
36
+ when 2
37
+ @ask_method_rule = /^def (\w+\?$|\w+\?\(\w+\)$|\w+\?\((\w+|\, \w+)*\)$)/
38
+ when 3
39
+ @ask_method_rule = /^def (\w+\?$|\w+\?\\w+\$|\w+\? (\w+|\, \w+)*$)/
40
+ end
41
+ end
42
+
43
+ #
44
+ # Optional parameter ruler
45
+ #
46
+ # Example
47
+ #
48
+ # 0 -> 'def method(a,b={})' - OK
49
+ # 1 -> 'def method(a,b = {})' - OK
50
+ # 2 -> 'def method(a,b= {})' - OK
51
+ # 3 -> 'def method(a,b ={})' - OK
52
+ #
53
+ def optional_parameter(whitespace)
54
+ case whitespace
55
+ when 0
56
+ @optional_parameter_rule = /([a-z]|\_)*\=[\{|\"|\d+]/
57
+ when 1
58
+ @optional_parameter_rule = /([a-z]|\_)* \= [\{|\"|\d+]/
59
+ when 2
60
+ @optional_parameter_rule = /([a-z]|\_)*\= [\{|\"|\d+]/
61
+ when 3
62
+ @optional_parameter_rule = /([a-z]|\_)* \=[\{|\"|\d+]/
63
+ end
64
+ end
65
+
66
+ def column_width(width)
67
+ @column_width_rule = width
68
+ end
69
+
70
+ def tabs_size(value)
71
+ @tabs_size = value
72
+ end
73
+
74
+ def check_columns(line)
75
+ if !@tabs_size.nil?
76
+ whitespace = ' ' * @tabs_size
77
+ new_line = line.gsub(/\t/, whitespace)
78
+ return new_line.size <= @column_width_rule
79
+ else
80
+ return line.size <= @column_width_rule
81
+ end
82
+ end
83
+
84
+ #
85
+ # 0 -> 'method(a)' or 'method(a,b)'
86
+ # 1 -> 'method(a)' or 'method(a, b)'
87
+ # 2 -> 'method a' or 'method(a,b)'
88
+ # 3 -> 'method a' or 'method(a, b)'
89
+ # 4 -> 'method a' or 'method a,b'
90
+ # 5 -> 'method a' or 'method a, b'
91
+ #
92
+ def method_call(mode)
93
+ case mode
94
+ when 0
95
+ @method_call_rule = /^\w+\((\w+|\,\w+)*\)/
96
+ when 1
97
+ @method_call_rule = /^\w+\((\w+|\, \w+)*\)/
98
+ when 2
99
+ @method_call_rule = /^\w+ \w+$|^\w+\((\w+\,)+\w+\)$/
100
+ when 3
101
+ @method_call_rule = /^\w+ \w+$|^\w+\((\w+\, )+\w+\)$/
102
+ when 4
103
+ @method_call_rule = /^\w+ (\w+|\,)*$/
104
+ when 5
105
+ @method_call_rule = /^\w+ (\w+|\, )*$/
106
+ end
107
+ end
108
+
109
+ def class_name(mode)
110
+ case mode
111
+ when :camel
112
+ @class_name_rule = /^class ([A-Z][a-z]*)*$/
113
+ when :snake
114
+ @class_name_rule = /^class [A-Z][a-z]*\_[a-z]*$/
115
+ when :camel_snake
116
+ @class_name_rule = /^class [A-Z][a-z]*\_[A-Z][a-z]*$/
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,88 @@
1
+ require 'rubygems'
2
+ require 'rainbow'
3
+ require 'rule'
4
+ require 'parser'
5
+ require 'fileutils'
6
+ require 'stringio'
7
+
8
+ class Runner
9
+ include ObjectSpace
10
+ def self.run(locate, rule)
11
+ @n_line = 0
12
+ @total_line = 0
13
+ @parser = Parser.new
14
+
15
+ my_rule = file_to_rule(rule)
16
+
17
+ self.read(locate, my_rule)
18
+
19
+ self.report
20
+ end
21
+
22
+ def self.report
23
+ puts
24
+ puts "Total of lines analyzed: ".color(:yellow) + "#{@total_line}".color(:red)
25
+ puts "Unconformities found: ".color(:yellow) + "#{@parser.reports.size}".color(:red)
26
+ puts
27
+
28
+ @parser.reports.each do |error|
29
+ puts error
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def self.read(locate, rule)
36
+ if File.directory?(locate)
37
+ self.directory(locate, rule)
38
+ else
39
+ file(locate, rule)
40
+ end
41
+ end
42
+
43
+ def self.file(f, rule)
44
+ File.open(f, "r") do |infile|
45
+ while (line = infile.gets)
46
+ @n_line += 1
47
+ @parser.set_rule(rule)
48
+ @parser.see(line, f, @n_line)
49
+ end
50
+ end
51
+ @total_line += @n_line
52
+ @n_line = 0
53
+ end
54
+
55
+ def self.directory(locate, rule)
56
+ dir = Dir.new(locate)
57
+ dir.each do |f|
58
+ next if f.to_s.match(/^\.\.$|^\.$/)
59
+
60
+ if !File.file?(f)
61
+ self.directory("#{locate}/"+f, rule)
62
+ else
63
+ file(f, rule)
64
+ end
65
+ end
66
+ end
67
+
68
+ def self.file_to_rule(rule)
69
+ if File.extname(rule) == ".rb"
70
+ require rule
71
+ ObjectSpace.each_object(Rule) do |obj|
72
+ return obj
73
+ end
74
+ else
75
+ str = ""
76
+ File.open(rule, "r") do |f|
77
+ while (line = f.gets)
78
+ str += line
79
+ end
80
+ end
81
+ eval(str.to_s)
82
+
83
+ ObjectSpace.each_object(Rule) do |obj|
84
+ return obj
85
+ end
86
+ end
87
+ end
88
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rlint
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Rodrigo Mello Nardi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2011-01-03 00:00:00 -02:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: rodrigomellonardi@gmail.com
18
+ executables:
19
+ - rlint
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - lib/report.rb
26
+ - lib/runner.rb
27
+ - lib/parser.rb
28
+ - lib/rule.rb
29
+ - lib/rlint.rb
30
+ has_rdoc: true
31
+ homepage: http://rubyhideoutprogramming.blogspot.com/
32
+ licenses: []
33
+
34
+ post_install_message:
35
+ rdoc_options: []
36
+
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ version:
51
+ requirements: []
52
+
53
+ rubyforge_project:
54
+ rubygems_version: 1.3.5
55
+ signing_key:
56
+ specification_version: 3
57
+ summary: Rlint is a coding standard analyzer. Used to check method/class name pattern, columns limit and others.(like Pylint)
58
+ test_files: []
59
+