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/name_check'
2
+
3
+ module Simplabs
4
+
5
+ module Excellent
6
+
7
+ module Checks
8
+
9
+ # This check reports classes with bad names. Badly named classes make reading and understanding the code much harder. Class names regarded as bad
10
+ # are for example:
11
+ #
12
+ # * names that are not Pascal cased (camel cased, starting with an upper case letter)
13
+ #
14
+ # ==== Applies to
15
+ #
16
+ # * classes
17
+ class ClassNameCheck < NameCheck
18
+
19
+ DEFAULT_PATTERN = /^[A-Z]{1}[a-zA-Z0-9]*$/
20
+
21
+ def initialize(options = {}) #:nodoc:
22
+ pattern = options[:pattern] || DEFAULT_PATTERN
23
+ super([:class], pattern)
24
+ end
25
+
26
+ protected
27
+
28
+ def warning_args(context) #:nodoc:
29
+ [context, 'Bad class name {{class}}.', { :class => context.full_name }]
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,35 @@
1
+ require 'simplabs/excellent/checks/base'
2
+
3
+ module Simplabs
4
+
5
+ module Excellent
6
+
7
+ module Checks
8
+
9
+ # This check reports methods that check the value of a parameter to decide which execution path to take. Control Coupling introduces a
10
+ # dependency between the caller and the callee. Any changes to the possible values of the parameter must be reflected at the caller side
11
+ # as well as at the called method.
12
+ #
13
+ # ==== Applies to
14
+ #
15
+ # * methods
16
+ class ControlCouplingCheck < Base
17
+
18
+ def initialize #:nodoc:
19
+ super
20
+ @interesting_nodes = [:if, :case]
21
+ end
22
+
23
+ def evaluate(context) #:nodoc:
24
+ if tested_parameter = context.tests_parameter?
25
+ add_warning(context, '{{method}} is coupled to {{argument}}.', { :method => context.parent.full_name, :argument => tested_parameter.to_s }, -2)
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,48 @@
1
+ require 'simplabs/excellent/checks/cyclomatic_complexity_check'
2
+
3
+ module Simplabs
4
+
5
+ module Excellent
6
+
7
+ module Checks
8
+
9
+ # This check reports blocks with a cyclomatic complexity metric score that is higher than the threshold. The cyclomatic complexity metric counts
10
+ # the number of linearly independent paths through the code. This is basically the number of the following statements + 1:
11
+ #
12
+ # * +if+
13
+ # * +else+
14
+ # * +unless+
15
+ # * +while+
16
+ # * +until+
17
+ # * +for+
18
+ # * +rescue+
19
+ # * +case+
20
+ # * +when+
21
+ # * +and+
22
+ # * +or+
23
+ #
24
+ # ==== Applies to
25
+ #
26
+ # * blocks
27
+ class CyclomaticComplexityBlockCheck < CyclomaticComplexityCheck
28
+
29
+ DEFAULT_THRESHOLD = 4
30
+
31
+ def initialize(options = {}) #:nodoc:
32
+ threshold = options[:threshold] || DEFAULT_THRESHOLD
33
+ super([:iter], threshold)
34
+ end
35
+
36
+ def evaluate(context) #:nodoc:
37
+ unless context.cc_score <= @threshold
38
+ add_warning(context, '{{block}} has cyclomatic complexity of {{score}}.', { :block => context.full_name, :score => context.cc_score })
39
+ end
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+
48
+ end
@@ -0,0 +1,23 @@
1
+ require 'simplabs/excellent/checks/base'
2
+
3
+ module Simplabs
4
+
5
+ module Excellent
6
+
7
+ module Checks
8
+
9
+ class CyclomaticComplexityCheck < Base #:nodoc:
10
+
11
+ def initialize(interesting_nodes, threshold)
12
+ super()
13
+ @interesting_nodes = interesting_nodes
14
+ @threshold = threshold
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,48 @@
1
+ require 'simplabs/excellent/checks/cyclomatic_complexity_check'
2
+
3
+ module Simplabs
4
+
5
+ module Excellent
6
+
7
+ module Checks
8
+
9
+ # This check reports methods with a cyclomatic complexity metric score that is higher than the threshold. The cyclomatic complexity metric counts
10
+ # the number of linearly independent paths through the code. This is basically the number of the following statements + 1:
11
+ #
12
+ # * +if+
13
+ # * +else+
14
+ # * unless
15
+ # * +while+
16
+ # * +until+
17
+ # * +for+
18
+ # * +rescue+
19
+ # * +case+
20
+ # * +when+
21
+ # * +and+
22
+ # * +or+
23
+ #
24
+ # ==== Applies to
25
+ #
26
+ # * methods
27
+ class CyclomaticComplexityMethodCheck < CyclomaticComplexityCheck
28
+
29
+ DEFAULT_THRESHOLD = 8
30
+
31
+ def initialize(options = {}) #:nodoc:
32
+ threshold = options[:threshold] || DEFAULT_THRESHOLD
33
+ super([:defn, :defs], threshold)
34
+ end
35
+
36
+ def evaluate(context) #:nodoc:
37
+ unless context.cc_score <= @threshold
38
+ add_warning(context, '{{method}} has cyclomatic complexity of {{score}}.', { :method => context.full_name, :score => context.cc_score })
39
+ end
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+
48
+ end
@@ -0,0 +1,31 @@
1
+ require 'simplabs/excellent/checks/base'
2
+
3
+ module Simplabs
4
+
5
+ module Excellent
6
+
7
+ module Checks
8
+
9
+ # This check reports empty +rescue+ blocks. Empty +rescue+ blocks suppress all errors which is usually not a good technique.
10
+ #
11
+ # ==== Applies to
12
+ #
13
+ # * +rescue+ blocks
14
+ class EmptyRescueBodyCheck < Base
15
+
16
+ def initialize #:nodoc:
17
+ super
18
+ @interesting_nodes = [:resbody]
19
+ end
20
+
21
+ def evaluate(context) #:nodoc:
22
+ add_warning(context, 'Rescue block is empty.', {}, -1) unless context.has_statements?
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,40 @@
1
+ require 'simplabs/excellent/checks/flog_check'
2
+
3
+ module Simplabs
4
+
5
+ module Excellent
6
+
7
+ module Checks
8
+
9
+ # This check reports blocks with a Flog metric score that is higher than the threshold. The Flog metric is very similar to the cyclomatic complexity
10
+ # measure but also takes Ruby specific statements into account. For example, calls to metaprogramming methods such as +define_method+ or
11
+ # +class_eval+ are weighted higher than regular method calls.
12
+ #
13
+ # Excellent does not calculate the score exactly the same way as Flog does, so scores may vary. For Flog also see
14
+ # http://github.com/seattlerb/flog.
15
+ #
16
+ # ==== Applies to
17
+ #
18
+ # * blocks
19
+ class FlogBlockCheck < FlogCheck
20
+
21
+ DEFAULT_THRESHOLD = 15
22
+
23
+ def initialize(options = {}) #:nodoc:
24
+ threshold = options[:threshold] || DEFAULT_THRESHOLD
25
+ super([:iter], threshold)
26
+ end
27
+
28
+ protected
29
+
30
+ def warning_args(context) #:nodoc:
31
+ [context, '{{block}} has flog score of {{score}}.', { :block => context.full_name, :score => context.flog_score }]
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,27 @@
1
+ require 'simplabs/excellent/checks/base'
2
+
3
+ module Simplabs
4
+
5
+ module Excellent
6
+
7
+ module Checks
8
+
9
+ class FlogCheck < Base #:nodoc:
10
+
11
+ def initialize(interesting_nodes, threshold)
12
+ super()
13
+ @interesting_nodes = interesting_nodes
14
+ @threshold = threshold
15
+ end
16
+
17
+ def evaluate(context)
18
+ add_warning(*warning_args(context)) unless context.flog_score <= @threshold
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,40 @@
1
+ require 'simplabs/excellent/checks/flog_check'
2
+
3
+ module Simplabs
4
+
5
+ module Excellent
6
+
7
+ module Checks
8
+
9
+ # This check reports classes with a Flog metric score that is higher than the threshold. The Flog metric is very similar to the cyclomatic complexity
10
+ # measure but also takes Ruby specific statements into account. For example, calls to metaprogramming methods such as +define_method+ or
11
+ # +class_eval+ are weighted higher than regular method calls.
12
+ #
13
+ # Excellent does not calculate the score exactly the same way as Flog does, so scores may vary. For Flog also see
14
+ # http://github.com/seattlerb/flog.
15
+ #
16
+ # ==== Applies to
17
+ #
18
+ # * classes
19
+ class FlogClassCheck < FlogCheck
20
+
21
+ DEFAULT_THRESHOLD = 300
22
+
23
+ def initialize(options = {}) #:nodoc:
24
+ threshold = options[:threshold] || DEFAULT_THRESHOLD
25
+ super([:class], threshold)
26
+ end
27
+
28
+ protected
29
+
30
+ def warning_args(context) #:nodoc:
31
+ [context, '{{class}} has flog score of {{score}}.', { :class => context.full_name, :score => context.flog_score }]
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,40 @@
1
+ require 'simplabs/excellent/checks/flog_check'
2
+
3
+ module Simplabs
4
+
5
+ module Excellent
6
+
7
+ module Checks
8
+
9
+ # This check reports methods with a Flog metric score that is higher than the threshold. The Flog metric is very similar to the cyclomatic complexity
10
+ # measure but also takes Ruby specific statements into account. For example, calls to metaprogramming methods such as +define_method+ or
11
+ # +class_eval+ are weighted higher than regular method calls.
12
+ #
13
+ # Excellent does not calculate the score exactly the same way as Flog does, so scores may vary. For Flog also see
14
+ # http://github.com/seattlerb/flog.
15
+ #
16
+ # ==== Applies to
17
+ #
18
+ # * methods
19
+ class FlogMethodCheck < FlogCheck
20
+
21
+ DEFAULT_THRESHOLD = 30
22
+
23
+ def initialize(options = {}) #:nodoc:
24
+ threshold = options[:threshold] || DEFAULT_THRESHOLD
25
+ super([:defn, :defs], threshold)
26
+ end
27
+
28
+ protected
29
+
30
+ def warning_args(context) #:nodoc:
31
+ [context, '{{method}} has flog score of {{score}}.', { :method => context.full_name, :score => context.flog_score }]
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,42 @@
1
+ require 'simplabs/excellent/checks/base'
2
+
3
+ module Simplabs
4
+
5
+ module Excellent
6
+
7
+ module Checks
8
+
9
+ # This check reports code that uses +for+ loops as in:
10
+ #
11
+ # for user in @users
12
+ # do_something(user)
13
+ # end
14
+ #
15
+ # The use of for loops in Ruby is contrary to the language's basic concept of iterators. The above statement would better be written as:
16
+ #
17
+ # @users.each do |user|
18
+ # do_something(user)
19
+ # end
20
+ #
21
+ # ==== Applies to
22
+ #
23
+ # * +for+ loops
24
+ class ForLoopCheck < Base
25
+
26
+ def initialize #:nodoc:
27
+ super
28
+ @interesting_nodes = [:for]
29
+ @interesting_files = [/\.rb$/, /\.erb$/]
30
+ end
31
+
32
+ def evaluate(context) #:nodoc:
33
+ add_warning(context, 'For loop used.')
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+
42
+ 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 global variables. Global variables introduce strong dependencies between otherwise unrelated parts of code and their use is
10
+ # usually considered extremely bad style.
11
+ #
12
+ # ==== Applies to
13
+ #
14
+ # * global variables
15
+ class GlobalVariableCheck < Base
16
+
17
+ def initialize #:nodoc:
18
+ super
19
+ @interesting_nodes = [:gvar, :gasgn]
20
+ @interesting_files = [/\.rb$/, /\.erb$/]
21
+ end
22
+
23
+ def evaluate(context) #:nodoc:
24
+ add_warning(context, 'Global variable {{variable}} used.', { :variable => context.full_name })
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+
33
+ end