excellent 1.5.4

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 (106) hide show
  1. data/History.txt +69 -0
  2. data/README.rdoc +72 -0
  3. data/VERSION.yml +4 -0
  4. data/bin/excellent +34 -0
  5. data/lib/simplabs/excellent.rb +16 -0
  6. data/lib/simplabs/excellent/checks.rb +33 -0
  7. data/lib/simplabs/excellent/checks/abc_metric_method_check.rb +43 -0
  8. data/lib/simplabs/excellent/checks/assignment_in_conditional_check.rb +39 -0
  9. data/lib/simplabs/excellent/checks/base.rb +62 -0
  10. data/lib/simplabs/excellent/checks/case_missing_else_check.rb +34 -0
  11. data/lib/simplabs/excellent/checks/class_line_count_check.rb +36 -0
  12. data/lib/simplabs/excellent/checks/class_name_check.rb +38 -0
  13. data/lib/simplabs/excellent/checks/control_coupling_check.rb +35 -0
  14. data/lib/simplabs/excellent/checks/cyclomatic_complexity_block_check.rb +48 -0
  15. data/lib/simplabs/excellent/checks/cyclomatic_complexity_check.rb +23 -0
  16. data/lib/simplabs/excellent/checks/cyclomatic_complexity_method_check.rb +48 -0
  17. data/lib/simplabs/excellent/checks/empty_rescue_body_check.rb +31 -0
  18. data/lib/simplabs/excellent/checks/flog_block_check.rb +40 -0
  19. data/lib/simplabs/excellent/checks/flog_check.rb +27 -0
  20. data/lib/simplabs/excellent/checks/flog_class_check.rb +40 -0
  21. data/lib/simplabs/excellent/checks/flog_method_check.rb +40 -0
  22. data/lib/simplabs/excellent/checks/for_loop_check.rb +42 -0
  23. data/lib/simplabs/excellent/checks/global_variable_check.rb +33 -0
  24. data/lib/simplabs/excellent/checks/line_count_check.rb +27 -0
  25. data/lib/simplabs/excellent/checks/method_line_count_check.rb +36 -0
  26. data/lib/simplabs/excellent/checks/method_name_check.rb +38 -0
  27. data/lib/simplabs/excellent/checks/module_line_count_check.rb +36 -0
  28. data/lib/simplabs/excellent/checks/module_name_check.rb +38 -0
  29. data/lib/simplabs/excellent/checks/name_check.rb +27 -0
  30. data/lib/simplabs/excellent/checks/nested_iterators_check.rb +34 -0
  31. data/lib/simplabs/excellent/checks/parameter_number_check.rb +38 -0
  32. data/lib/simplabs/excellent/checks/rails.rb +22 -0
  33. data/lib/simplabs/excellent/checks/rails/attr_accessible_check.rb +38 -0
  34. data/lib/simplabs/excellent/checks/rails/attr_protected_check.rb +39 -0
  35. data/lib/simplabs/excellent/checks/rails/custom_initialize_method_check.rb +37 -0
  36. data/lib/simplabs/excellent/checks/rails/instance_var_in_partial_check.rb +37 -0
  37. data/lib/simplabs/excellent/checks/rails/params_hash_in_view_check.rb +38 -0
  38. data/lib/simplabs/excellent/checks/rails/session_hash_in_view_check.rb +38 -0
  39. data/lib/simplabs/excellent/checks/rails/validations_check.rb +36 -0
  40. data/lib/simplabs/excellent/checks/singleton_variable_check.rb +33 -0
  41. data/lib/simplabs/excellent/command_line_runner.rb +37 -0
  42. data/lib/simplabs/excellent/extensions/sexp.rb +21 -0
  43. data/lib/simplabs/excellent/extensions/string.rb +28 -0
  44. data/lib/simplabs/excellent/formatters.rb +13 -0
  45. data/lib/simplabs/excellent/formatters/base.rb +49 -0
  46. data/lib/simplabs/excellent/formatters/html.rb +153 -0
  47. data/lib/simplabs/excellent/formatters/text.rb +40 -0
  48. data/lib/simplabs/excellent/parsing.rb +10 -0
  49. data/lib/simplabs/excellent/parsing/abc_measure.rb +52 -0
  50. data/lib/simplabs/excellent/parsing/block_context.rb +43 -0
  51. data/lib/simplabs/excellent/parsing/call_context.rb +52 -0
  52. data/lib/simplabs/excellent/parsing/case_context.rb +31 -0
  53. data/lib/simplabs/excellent/parsing/class_context.rb +99 -0
  54. data/lib/simplabs/excellent/parsing/code_processor.rb +165 -0
  55. data/lib/simplabs/excellent/parsing/conditional_context.rb +25 -0
  56. data/lib/simplabs/excellent/parsing/cvar_context.rb +28 -0
  57. data/lib/simplabs/excellent/parsing/cyclomatic_complexity_measure.rb +73 -0
  58. data/lib/simplabs/excellent/parsing/flog_measure.rb +192 -0
  59. data/lib/simplabs/excellent/parsing/for_loop_context.rb +15 -0
  60. data/lib/simplabs/excellent/parsing/gvar_context.rb +21 -0
  61. data/lib/simplabs/excellent/parsing/if_context.rb +38 -0
  62. data/lib/simplabs/excellent/parsing/ivar_context.rb +32 -0
  63. data/lib/simplabs/excellent/parsing/method_context.rb +50 -0
  64. data/lib/simplabs/excellent/parsing/module_context.rb +29 -0
  65. data/lib/simplabs/excellent/parsing/parser.rb +35 -0
  66. data/lib/simplabs/excellent/parsing/resbody_context.rb +39 -0
  67. data/lib/simplabs/excellent/parsing/scopeable.rb +34 -0
  68. data/lib/simplabs/excellent/parsing/sexp_context.rb +125 -0
  69. data/lib/simplabs/excellent/parsing/singleton_method_context.rb +55 -0
  70. data/lib/simplabs/excellent/parsing/until_context.rb +24 -0
  71. data/lib/simplabs/excellent/parsing/while_context.rb +24 -0
  72. data/lib/simplabs/excellent/rake.rb +1 -0
  73. data/lib/simplabs/excellent/rake/excellent_task.rb +61 -0
  74. data/lib/simplabs/excellent/runner.rb +143 -0
  75. data/lib/simplabs/excellent/warning.rb +53 -0
  76. data/spec/checks/abc_metric_method_check_spec.rb +122 -0
  77. data/spec/checks/assignment_in_conditional_check_spec.rb +90 -0
  78. data/spec/checks/case_missing_else_check_spec.rb +42 -0
  79. data/spec/checks/class_line_count_check_spec.rb +62 -0
  80. data/spec/checks/class_name_check_spec.rb +48 -0
  81. data/spec/checks/control_coupling_check_spec.rb +103 -0
  82. data/spec/checks/cyclomatic_complexity_block_check_spec.rb +47 -0
  83. data/spec/checks/cyclomatic_complexity_method_check_spec.rb +210 -0
  84. data/spec/checks/empty_rescue_body_check_spec.rb +170 -0
  85. data/spec/checks/flog_block_check_spec.rb +28 -0
  86. data/spec/checks/flog_class_check_spec.rb +28 -0
  87. data/spec/checks/flog_method_check_spec.rb +46 -0
  88. data/spec/checks/for_loop_check_spec.rb +52 -0
  89. data/spec/checks/global_variable_check_spec.rb +66 -0
  90. data/spec/checks/method_line_count_check_spec.rb +49 -0
  91. data/spec/checks/method_name_check_spec.rb +112 -0
  92. data/spec/checks/module_line_count_check_spec.rb +48 -0
  93. data/spec/checks/module_name_check_spec.rb +61 -0
  94. data/spec/checks/nested_iterators_check_spec.rb +44 -0
  95. data/spec/checks/parameter_number_check_spec.rb +97 -0
  96. data/spec/checks/rails/attr_accessible_check_spec.rb +79 -0
  97. data/spec/checks/rails/attr_protected_check_spec.rb +77 -0
  98. data/spec/checks/rails/custom_initialize_method_check_spec.rb +58 -0
  99. data/spec/checks/rails/instance_var_in_partial_check_spec.rb +40 -0
  100. data/spec/checks/rails/params_hash_in_view_check_spec.rb +40 -0
  101. data/spec/checks/rails/session_hash_in_view_check_spec.rb +40 -0
  102. data/spec/checks/rails/validations_check_spec.rb +81 -0
  103. data/spec/checks/singleton_variable_check_spec.rb +66 -0
  104. data/spec/extensions/string_spec.rb +13 -0
  105. data/spec/spec_helper.rb +13 -0
  106. metadata +189 -0
@@ -0,0 +1,38 @@
1
+ require 'simplabs/excellent/checks/base'
2
+
3
+ module Simplabs
4
+
5
+ module Excellent
6
+
7
+ module Checks
8
+
9
+ module Rails
10
+
11
+ # This check reports views (and partials) that access the +params+ hash. Accessing the +params+ hash directly in views can result in security
12
+ # problems if the value is printed to the HTML output and in general is a bad habit because the controller, which is actually the part of the
13
+ # application that is responsible for dealing with parameters, is circumvented.
14
+ #
15
+ # ==== Applies to
16
+ #
17
+ # * partials and regular views
18
+ class ParamsHashInViewCheck < Base
19
+
20
+ def initialize #:nodoc:
21
+ super
22
+ @interesting_nodes = [:call]
23
+ @interesting_files = [/^.*\.(erb|rhtml)$/]
24
+ end
25
+
26
+ def evaluate(context) #:nodoc:
27
+ add_warning(context, 'Params hash used in view.') if (context.full_name == 'params')
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,38 @@
1
+ require 'simplabs/excellent/checks/base'
2
+
3
+ module Simplabs
4
+
5
+ module Excellent
6
+
7
+ module Checks
8
+
9
+ module Rails
10
+
11
+ # This check reports views (and partials) that access the +session+ hash. Accessing the +session+ hash directly in views can result in security
12
+ # problems if the value is printed to the HTML output and in general is a bad habit because the controller, which is actually the part of the
13
+ # application that is responsible for dealing with session data, is circumvented.
14
+ #
15
+ # ==== Applies to
16
+ #
17
+ # * partials and regular views
18
+ class SessionHashInViewCheck < Base
19
+
20
+ def initialize #:nodoc:
21
+ super
22
+ @interesting_nodes = [:call]
23
+ @interesting_files = [/^.*\.(erb|rhtml)$/]
24
+ end
25
+
26
+ def evaluate(context) #:nodoc:
27
+ add_warning(context, 'Session hash used in view.') if (context.full_name == 'session')
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,36 @@
1
+ require 'simplabs/excellent/checks/base'
2
+
3
+ module Simplabs
4
+
5
+ module Excellent
6
+
7
+ module Checks
8
+
9
+ module Rails
10
+
11
+ # This check reports +ActiveRecord+ models that do not validate anything. Not validating anything in the model is usually not intended and has
12
+ # most likely just been forgotten. For more information on validations and why to use them, see http://guides.rubyonrails.org/activerecord_validations_callbacks.html#why-use-validations.
13
+ #
14
+ # ==== Applies to
15
+ #
16
+ # * +ActiveRecord+ models
17
+ class ValidationsCheck < Base
18
+
19
+ def initialize #:nodoc:
20
+ super
21
+ @interesting_nodes = [:class]
22
+ end
23
+
24
+ def evaluate(context) #:nodoc:
25
+ add_warning(context, '{{class}} does not validate any attributes.', { :class => context.full_name }) if context.active_record_model? && !context.validating?
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,33 @@
1
+ require 'simplabs/excellent/checks/base'
2
+
3
+ module Simplabs
4
+
5
+ module Excellent
6
+
7
+ module Checks
8
+
9
+ # This check reports class variables. Class variables in Ruby have a very complicated inheritance policy that often leads to errors. Usually class
10
+ # variables can be replaced with another construct which will also lead to better design.
11
+ #
12
+ # ==== Applies to
13
+ #
14
+ # * class variables
15
+ class SingletonVariableCheck < Base
16
+
17
+ def initialize #:nodoc:
18
+ super
19
+ @interesting_nodes = [:cvar]
20
+ @interesting_files = [/\.rb$/, /\.erb$/]
21
+ end
22
+
23
+ def evaluate(context) #:nodoc:
24
+ add_warning(context, 'Singleton variable {{variable}} used.', { :variable => context.full_name })
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,37 @@
1
+ require 'simplabs/excellent/runner'
2
+ require 'simplabs/excellent/formatters'
3
+
4
+ module Simplabs
5
+
6
+ module Excellent
7
+
8
+ class CommandLineRunner < Runner #:nodoc:
9
+
10
+ def initialize(*checks)
11
+ super
12
+ @formatter = Formatters::Text.new
13
+ @formatter.start
14
+ end
15
+
16
+ def check_paths(paths)
17
+ paths.each do |path|
18
+ if File.file?(path)
19
+ check_file(path)
20
+ elsif File.directory?(path)
21
+ Dir.glob(File.join(path, '**/*.rb')).each { |file| check_file(file) }
22
+ else
23
+ next
24
+ end
25
+ end
26
+ end
27
+
28
+ def check_file(filename)
29
+ super
30
+ @formatter.file(filename, (@checks || []).collect { |check| check.warnings }.flatten)
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,21 @@
1
+ module Simplabs
2
+
3
+ module Excellent
4
+
5
+ module Extensions #:nodoc:
6
+
7
+ ::Sexp.class_eval do
8
+
9
+ def children
10
+ sexp_body.select { |child| child.is_a?(Sexp) }
11
+ rescue
12
+ []
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,28 @@
1
+ module Simplabs
2
+
3
+ module Excellent
4
+
5
+ module Extensions #:nodoc:
6
+
7
+ ::String.class_eval do
8
+
9
+ def underscore
10
+ to_s.gsub(/::/, '/').
11
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
12
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
13
+ tr("-", "_").
14
+ downcase
15
+ end
16
+
17
+ def lpad(to, with = ' ')
18
+ return self if self.length >= to
19
+ "#{with * (to - self.length)}#{self}"
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,13 @@
1
+ module Simplabs
2
+
3
+ module Excellent
4
+
5
+ module Formatters #:nodoc:
6
+ end
7
+
8
+ end
9
+
10
+ end
11
+
12
+ require 'simplabs/excellent/formatters/text'
13
+ require 'simplabs/excellent/formatters/html'
@@ -0,0 +1,49 @@
1
+ module Simplabs
2
+
3
+ module Excellent
4
+
5
+ module Formatters
6
+
7
+ # The base class for all formatters.
8
+ class Base
9
+
10
+ # Initializes the formatter.
11
+ #
12
+ # Always call +super+ in custom formatters!
13
+ def initialize(stream)
14
+ @stream = stream
15
+ end
16
+
17
+ # Called when the Simplabs::Excellent::Runner starts processing code.
18
+ #
19
+ # The text formatter renders the heading here ('Excellent result')
20
+ def start
21
+ end
22
+
23
+ # Called whenever the Simplabs::Excellent::Runner processes a file. Yields the formatter
24
+ #
25
+ # You have to <tt>yield self</tt> in custom formatters. +file+ is called like that by the runner:
26
+ #
27
+ # formatter.file(filename) do |formatter|
28
+ # warnings.each { |warning| formatter.warning(warning) }
29
+ # end
30
+ def file(filename)
31
+ end
32
+
33
+ # Called when the Simplabs::Excellent::Runner found a warning. This warning will always refer to the last filename, +file+ was invoked with.
34
+ def warning(warning)
35
+ end
36
+
37
+ # Called when the Simplabs::Excellent::Runner ends processing code.
38
+ #
39
+ # The text formatter renders the footer here ('Found <x> warnings').
40
+ def end
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+
49
+ end
@@ -0,0 +1,153 @@
1
+ require 'simplabs/excellent/formatters/base'
2
+
3
+ module Simplabs
4
+
5
+ module Excellent
6
+
7
+ module Formatters
8
+
9
+ class Html < Base #:nodoc:
10
+
11
+ def initialize(stream = $stdout)
12
+ super
13
+ end
14
+
15
+ def start
16
+ @stream.write(HEADER_TEMPLATE)
17
+ end
18
+
19
+ def file(filename)
20
+ @stream.write(START_FIlE_TAMPLATE.sub('{{filename}}', filename))
21
+ yield self
22
+ @stream.write(END_FIlE_TAMPLATE)
23
+ end
24
+
25
+ def warning(warning)
26
+ @stream.write(WARNING_TEMPLATE.sub('{{line_number}}', warning.line_number.to_s).sub('{{message}}', warning.message))
27
+ end
28
+
29
+ def end
30
+ @stream.write(FOOTER_TEMPLATE)
31
+ end
32
+
33
+ HEADER_TEMPLATE = <<-END
34
+ <?xml version="1.0" encoding="UTF-8"?>
35
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
36
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
37
+ <head>
38
+ <title>Excellent result</title>
39
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
40
+ <style type="text/css">
41
+ body {
42
+ margin: 0;
43
+ padding: 0;
44
+ background: #fff;
45
+ font-size: 80%;
46
+ font-family: "Lucida Grande", Helvetica, sans-serif;
47
+ }
48
+
49
+ #header {
50
+ background: #ccc;
51
+ color: #000;
52
+ height: 4em;
53
+ }
54
+
55
+ #header h1 {
56
+ font-size: 1.8em;
57
+ margin: 0px 10px 0px 10px;
58
+ padding: 10px;
59
+ position: absolute;
60
+ }
61
+
62
+ #results {
63
+ margin: 0px 10px 5px;
64
+ }
65
+
66
+ dt {
67
+ background: #ccc;
68
+ padding: 5px;
69
+ font-weight: bold;
70
+ margin: 30px 0 0 0;
71
+ }
72
+
73
+ dd {
74
+ margin: 5px 0px 5px 20px;
75
+ }
76
+
77
+ dd.warning {
78
+ background: #faf834;
79
+ }
80
+
81
+ dd.warning span.lineNumber {
82
+ background: #ccc;
83
+ font-weight: bold;
84
+ padding: 3px;
85
+ display: inline-block;
86
+ margin: 0 10px 0 0;
87
+ }
88
+
89
+ dd.warning span.number {
90
+ width: 30px;
91
+ text-align: right;
92
+ display: inline-block;
93
+ }
94
+
95
+ #footer {
96
+ margin: 20px 0 20px 0;
97
+ padding: 5px;
98
+ text-align: center;
99
+ }
100
+
101
+ #footer a {
102
+ color: #000;
103
+ background-color: #ddd;
104
+ text-decoration: none;
105
+ padding: 0 2px 0 2px;
106
+ }
107
+
108
+ #footer a:active, #footer a:hover {
109
+ color: #fff;
110
+ background-color: #222;
111
+ }
112
+ </style>
113
+ </head>
114
+ <body>
115
+ <div id="header">
116
+ <div id="label">
117
+ <h1>Excellent result</h1>
118
+ </div>
119
+ </div>
120
+ <div id="results">
121
+ END
122
+
123
+ START_FIlE_TAMPLATE = <<-END
124
+ <div class="file">
125
+ <dl>
126
+ <dt>{{filename}}</dt>
127
+ END
128
+
129
+ END_FIlE_TAMPLATE = <<-END
130
+ </dl>
131
+ </div>
132
+ END
133
+
134
+ WARNING_TEMPLATE = <<-END
135
+ <dd class="warning"><span class="lineNumber">Line <span class="number">{{line_number}}</span></span>{{message}}</dd>
136
+ END
137
+
138
+ FOOTER_TEMPLATE = <<-END
139
+ </div>
140
+ <div id="footer">
141
+ <a href="http://github.com/simplabs/excellent" title="Excellent at github">Excellent</a> by <a href="http://simplabs.com" title="simplabs">simplabs</a>
142
+ </div>
143
+ </body>
144
+ </html>
145
+ END
146
+
147
+ end
148
+
149
+ end
150
+
151
+ end
152
+
153
+ end