teksymmetry-reek 1.1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +131 -0
- data/README.txt +36 -0
- data/Rakefile +17 -0
- data/bin/reek +27 -0
- data/config/defaults.reek +51 -0
- data/lib/reek/block_context.rb +59 -0
- data/lib/reek/class_context.rb +68 -0
- data/lib/reek/code_context.rb +54 -0
- data/lib/reek/code_parser.rb +221 -0
- data/lib/reek/exceptions.reek +13 -0
- data/lib/reek/if_context.rb +25 -0
- data/lib/reek/method_context.rb +91 -0
- data/lib/reek/module_context.rb +33 -0
- data/lib/reek/name.rb +49 -0
- data/lib/reek/object_refs.rb +52 -0
- data/lib/reek/object_source.rb +53 -0
- data/lib/reek/options.rb +100 -0
- data/lib/reek/rake_task.rb +121 -0
- data/lib/reek/report.rb +81 -0
- data/lib/reek/sexp_formatter.rb +10 -0
- data/lib/reek/singleton_method_context.rb +27 -0
- data/lib/reek/smell_warning.rb +49 -0
- data/lib/reek/smells/control_couple.rb +61 -0
- data/lib/reek/smells/duplication.rb +50 -0
- data/lib/reek/smells/feature_envy.rb +58 -0
- data/lib/reek/smells/large_class.rb +69 -0
- data/lib/reek/smells/long_method.rb +43 -0
- data/lib/reek/smells/long_parameter_list.rb +43 -0
- data/lib/reek/smells/long_yield_list.rb +18 -0
- data/lib/reek/smells/nested_iterators.rb +28 -0
- data/lib/reek/smells/smell_detector.rb +66 -0
- data/lib/reek/smells/smells.rb +81 -0
- data/lib/reek/smells/uncommunicative_name.rb +97 -0
- data/lib/reek/smells/utility_function.rb +34 -0
- data/lib/reek/source.rb +127 -0
- data/lib/reek/spec.rb +146 -0
- data/lib/reek/stop_context.rb +50 -0
- data/lib/reek/yield_call_context.rb +12 -0
- data/lib/reek.rb +7 -0
- data/reek.gemspec +44 -0
- data/spec/reek/block_context_spec.rb +40 -0
- data/spec/reek/class_context_spec.rb +169 -0
- data/spec/reek/code_context_spec.rb +93 -0
- data/spec/reek/code_parser_spec.rb +34 -0
- data/spec/reek/config_spec.rb +42 -0
- data/spec/reek/if_context_spec.rb +17 -0
- data/spec/reek/method_context_spec.rb +66 -0
- data/spec/reek/module_context_spec.rb +38 -0
- data/spec/reek/name_spec.rb +13 -0
- data/spec/reek/object_refs_spec.rb +131 -0
- data/spec/reek/options_spec.rb +13 -0
- data/spec/reek/report_spec.rb +48 -0
- data/spec/reek/singleton_method_context_spec.rb +17 -0
- data/spec/reek/smells/control_couple_spec.rb +23 -0
- data/spec/reek/smells/duplication_spec.rb +81 -0
- data/spec/reek/smells/feature_envy_spec.rb +221 -0
- data/spec/reek/smells/large_class_spec.rb +87 -0
- data/spec/reek/smells/long_method_spec.rb +195 -0
- data/spec/reek/smells/long_parameter_list_spec.rb +85 -0
- data/spec/reek/smells/nested_iterators_spec.rb +33 -0
- data/spec/reek/smells/smell_spec.rb +24 -0
- data/spec/reek/smells/uncommunicative_name_spec.rb +123 -0
- data/spec/reek/smells/utility_function_spec.rb +93 -0
- data/spec/slow/inline_spec.rb +40 -0
- data/spec/slow/optparse_spec.rb +109 -0
- data/spec/slow/redcloth_spec.rb +101 -0
- data/spec/slow/reek_source_spec.rb +20 -0
- data/spec/slow/samples/inline.rb +704 -0
- data/spec/slow/samples/optparse.rb +1788 -0
- data/spec/slow/samples/redcloth.rb +1130 -0
- data/spec/slow/script_spec.rb +55 -0
- data/spec/slow/source_list_spec.rb +40 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +13 -0
- data/tasks/reek.rake +7 -0
- data/tasks/rspec.rake +22 -0
- metadata +163 -0
data/History.txt
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
== 1.1.4 (in git)
|
2
|
+
|
3
|
+
=== Minor Changes
|
4
|
+
* LongMethod now counts statements deeper into each method (#25)
|
5
|
+
* LongMethod no longer counts control structures, only their contained stmts
|
6
|
+
|
7
|
+
== 1.1.3 2009-05-19
|
8
|
+
|
9
|
+
=== Minor Changes
|
10
|
+
* No longer depends directly on the sexp_processor gem
|
11
|
+
|
12
|
+
=== Fixes
|
13
|
+
* LargeClass now relies only on the given source code (#26)
|
14
|
+
|
15
|
+
== 1.1.2 2009-05-18
|
16
|
+
|
17
|
+
=== Major Enhancements
|
18
|
+
* Switched from ParseTree to ruby_parser for source code parsing
|
19
|
+
* 'MyClass.should_not reek' now only possible if ParseTree gem installed
|
20
|
+
|
21
|
+
== 1.1.1 2009-05-08
|
22
|
+
|
23
|
+
=== Minor enhancements
|
24
|
+
* LargeClass now also warns about any class with > 9 instance variables (#6)
|
25
|
+
* Now depends on ruby2ruby, to display code better
|
26
|
+
* Duplication notices more repeated method calls
|
27
|
+
* Smells within blocks are now reported better
|
28
|
+
|
29
|
+
== 1.1.0 2009-04-10
|
30
|
+
|
31
|
+
=== Minor enhancements
|
32
|
+
* Now possible to write 'MyClass.should_not reek' (#33)
|
33
|
+
|
34
|
+
=== Fixes
|
35
|
+
* Now counts attr assignments ([]= etc) in feature envy calculations
|
36
|
+
* Doesn't attempt to find *.reek files when reading code from stdin
|
37
|
+
|
38
|
+
== 1.0.1 2009-04-06
|
39
|
+
|
40
|
+
=== Fixes
|
41
|
+
* Dir[...].to_source now creates a Report that can be browsed (#36)
|
42
|
+
|
43
|
+
== 1.0.0 2009-04-05
|
44
|
+
|
45
|
+
=== Major enhancements
|
46
|
+
* Use *.reek files in source tree to configure Reek's behaviour
|
47
|
+
* Added -f option to configure report format
|
48
|
+
* --sort_order replaced by -f, -c and -s
|
49
|
+
* Matchers provided for rspec; eg. foo.should_not reek
|
50
|
+
|
51
|
+
=== Minor enhancements
|
52
|
+
* Smells in singleton methods are now analysed
|
53
|
+
* Uncommunicative parameter names in blocks now reported
|
54
|
+
* Modules and blocks now reflected in scope of smell reports
|
55
|
+
|
56
|
+
=== Fixes
|
57
|
+
* Corrected false reports of long arg lists to yield
|
58
|
+
* A method can now be a UtilityFunction only when it includes a call
|
59
|
+
|
60
|
+
== 0.3.1 2008-11-17
|
61
|
+
|
62
|
+
=== Minor enhancements
|
63
|
+
* Uncommunicative Name now checks instance variables more thoroughly
|
64
|
+
* Uncommunicative Name now warns about names of the form 'x2'
|
65
|
+
* Added check for duplicated calls within a method
|
66
|
+
* Reduced scope of Feature Envy warnings to cover only overuse of lvars
|
67
|
+
* Added rdoc comments explaining what each smell is about
|
68
|
+
* Chained iterators are no longer mis-reported as nested
|
69
|
+
|
70
|
+
== 0.3.0 2008-11-02
|
71
|
+
|
72
|
+
=== Minor enhancements
|
73
|
+
* New smell: first naive checks for Control Couple
|
74
|
+
* reek now only checks sources passed on the command line
|
75
|
+
* Code snippets can be supplied on the commandline
|
76
|
+
* Added headings and warnings count when smells in multiple files
|
77
|
+
* Added Reek::RakeTask to run reek from rakefiles
|
78
|
+
|
79
|
+
=== Fixes
|
80
|
+
* Fixed: Returns exit status 2 when smells are reported
|
81
|
+
* Fixed: no longer claims an empty method is a Utility Function
|
82
|
+
|
83
|
+
== 0.2.3 2008-09-22
|
84
|
+
|
85
|
+
* Minor enhancements:
|
86
|
+
* Only reports Feature Envy when the method isn't a Utility Function
|
87
|
+
* General improvements to assessing Feature Envy
|
88
|
+
* Tweaks:
|
89
|
+
* Fixed: coping with parameterless yield call
|
90
|
+
* Fixed: copes with :self as an expression
|
91
|
+
* Fixed: displaying the receiver of many more kinds of Feature Envy
|
92
|
+
* Fixed: Large Class calculation for Object
|
93
|
+
|
94
|
+
== 0.2.2 2008-09-15
|
95
|
+
|
96
|
+
* Tweaks:
|
97
|
+
* Fixed --version!
|
98
|
+
|
99
|
+
== 0.2.1 2008-09-14
|
100
|
+
|
101
|
+
* Tweaks:
|
102
|
+
* Now works from the source code, instead of requiring each named file
|
103
|
+
* Added integration tests that run reek on a couple of gems
|
104
|
+
|
105
|
+
== 0.2.0 2008-09-10
|
106
|
+
|
107
|
+
* Minor enhancements:
|
108
|
+
* Added --help, --version options
|
109
|
+
* Added --sort option to sort the report by smell or by code location
|
110
|
+
|
111
|
+
== 0.1.1 2008-09-09
|
112
|
+
|
113
|
+
* Some tweaks:
|
114
|
+
* Fixed report printing for Feature Envy when the receiver is a block
|
115
|
+
* Fixed: successive iterators reported as nested
|
116
|
+
* Fixed: Long Method now reports the total length of the method
|
117
|
+
* Fixed: each smell reported only once
|
118
|
+
|
119
|
+
== 0.1.0 2008-09-09
|
120
|
+
|
121
|
+
* 1 minor enhancement:
|
122
|
+
* Added a check for nested iterators within a method
|
123
|
+
* Some tweaks:
|
124
|
+
* Begun adding some rdoc
|
125
|
+
* Split some of the specs into more meaningful chunks
|
126
|
+
* Updated the rakefile so that rcov is no longer the default
|
127
|
+
|
128
|
+
== 0.0.1 2008-09-08
|
129
|
+
|
130
|
+
* 1 major enhancement:
|
131
|
+
* Initial release
|
data/README.txt
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
== Reek
|
2
|
+
|
3
|
+
Code smell detection for Ruby.
|
4
|
+
|
5
|
+
The documentation is at http://wiki.github.com/kevinrutherford/reek
|
6
|
+
The code lives at http://github.com/kevinrutherford/reek/tree
|
7
|
+
|
8
|
+
|
9
|
+
== How to use Uncommunicative name verifier extension ?
|
10
|
+
|
11
|
+
* Create your configuration reek file under your source base (RAILS_ROOT/app/app.reek)
|
12
|
+
|
13
|
+
* Add the following configurations -
|
14
|
+
UncommunicativeName:
|
15
|
+
verifierExtention:
|
16
|
+
- <path to your ruby script file>
|
17
|
+
|
18
|
+
example -
|
19
|
+
UncommunicativeName:
|
20
|
+
verifierExtention:
|
21
|
+
- config/smells/strict_uncommunicative_variable_name_verifier
|
22
|
+
|
23
|
+
* Remember ruby class name and file name must be similar,
|
24
|
+
Use "_" for separating different words. ie SimpleVerifier => simple_verifier.rb
|
25
|
+
|
26
|
+
* Write following class -
|
27
|
+
class StrictUncommunicativeVariableNameVerifier
|
28
|
+
def accepted?(p_context, p_variable_name)
|
29
|
+
# do stuffs with variable name
|
30
|
+
# if it match your requirement
|
31
|
+
# return true, nil
|
32
|
+
# otherwise
|
33
|
+
# return false, "error message"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/clean'
|
3
|
+
|
4
|
+
$:.unshift File.dirname(__FILE__) + '/lib'
|
5
|
+
|
6
|
+
PROJECT_NAME = 'reek'
|
7
|
+
|
8
|
+
BUILD_DIR = 'build'; directory BUILD_DIR
|
9
|
+
PKG_DIR = "#{BUILD_DIR}/pkg"; directory PKG_DIR
|
10
|
+
RDOC_DIR = "#{BUILD_DIR}/rdoc"; directory RDOC_DIR
|
11
|
+
|
12
|
+
GEM_MANIFEST = "Manifest.txt"
|
13
|
+
VERSION_FILE = 'lib/reek.rb'
|
14
|
+
|
15
|
+
CLOBBER.include("#{BUILD_DIR}/*")
|
16
|
+
|
17
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
data/bin/reek
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Reek examines Ruby source code for smells.
|
4
|
+
# Visit http://reek.rubyforge.org/ for docs etc.
|
5
|
+
#
|
6
|
+
# Author: Kevin Rutherford
|
7
|
+
#
|
8
|
+
|
9
|
+
# Allow local access
|
10
|
+
if ARGV.include?("-TX")
|
11
|
+
ARGV.delete("-TX")
|
12
|
+
require File.join('~/projects/tekSymmetry/reek', 'lib/reek')
|
13
|
+
require File.join('~/projects/tekSymmetry/reek', 'lib/reek/source')
|
14
|
+
require File.join('~/projects/tekSymmetry/reek', 'lib/reek/options')
|
15
|
+
else
|
16
|
+
require 'reek'
|
17
|
+
require 'reek/source'
|
18
|
+
require 'reek/options'
|
19
|
+
end
|
20
|
+
|
21
|
+
exitstatus = 0
|
22
|
+
source = Reek::Options.parse(ARGV)
|
23
|
+
if source.smelly?
|
24
|
+
puts source.report
|
25
|
+
exitstatus = 2
|
26
|
+
end
|
27
|
+
exit(exitstatus)
|
@@ -0,0 +1,51 @@
|
|
1
|
+
---
|
2
|
+
LargeClass:
|
3
|
+
max_methods: 25
|
4
|
+
exclude: []
|
5
|
+
|
6
|
+
enabled: true
|
7
|
+
max_instance_variables: 9
|
8
|
+
LongParameterList:
|
9
|
+
max_params: 3
|
10
|
+
exclude: []
|
11
|
+
|
12
|
+
enabled: true
|
13
|
+
FeatureEnvy:
|
14
|
+
exclude:
|
15
|
+
- initialize
|
16
|
+
enabled: true
|
17
|
+
UncommunicativeName:
|
18
|
+
accept:
|
19
|
+
- Inline::C
|
20
|
+
exclude: []
|
21
|
+
|
22
|
+
enabled: true
|
23
|
+
reject:
|
24
|
+
- !ruby/regexp /^.[0-9]*$/
|
25
|
+
NestedIterators:
|
26
|
+
exclude: []
|
27
|
+
|
28
|
+
enabled: true
|
29
|
+
LongMethod:
|
30
|
+
max_statements: 5
|
31
|
+
exclude:
|
32
|
+
- initialize
|
33
|
+
enabled: true
|
34
|
+
Duplication:
|
35
|
+
exclude: []
|
36
|
+
|
37
|
+
enabled: true
|
38
|
+
max_calls: 1
|
39
|
+
UtilityFunction:
|
40
|
+
exclude: []
|
41
|
+
|
42
|
+
enabled: true
|
43
|
+
ControlCouple:
|
44
|
+
exclude:
|
45
|
+
- initialize
|
46
|
+
enabled: true
|
47
|
+
LongYieldList:
|
48
|
+
max_params: 3
|
49
|
+
exclude: []
|
50
|
+
|
51
|
+
enabled: true
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'reek/code_context'
|
3
|
+
|
4
|
+
module Reek
|
5
|
+
|
6
|
+
module ParameterSet
|
7
|
+
def names
|
8
|
+
return @names if @names
|
9
|
+
return (@names = []) if empty?
|
10
|
+
arg = slice(1)
|
11
|
+
case slice(0)
|
12
|
+
when :masgn
|
13
|
+
@names = arg[1..-1].map {|lasgn| Name.new(lasgn[1]) }
|
14
|
+
when :lasgn
|
15
|
+
@names = [Name.new(arg)]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def include?(name)
|
20
|
+
names.include?(name)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class BlockContext < CodeContext
|
25
|
+
|
26
|
+
def initialize(outer, exp)
|
27
|
+
super
|
28
|
+
@name = Name.new('block')
|
29
|
+
@parameters = exp[0] if exp
|
30
|
+
@parameters ||= []
|
31
|
+
@parameters.extend(ParameterSet)
|
32
|
+
@local_variables = Set.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def inside_a_block?
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
def has_parameter(name)
|
40
|
+
@parameters.include?(name) or @outer.has_parameter(name)
|
41
|
+
end
|
42
|
+
|
43
|
+
def nested_block?
|
44
|
+
@outer.inside_a_block?
|
45
|
+
end
|
46
|
+
|
47
|
+
def record_local_variable(sym)
|
48
|
+
@local_variables << Name.new(sym)
|
49
|
+
end
|
50
|
+
|
51
|
+
def outer_name
|
52
|
+
"#{@outer.outer_name}#{@name}/"
|
53
|
+
end
|
54
|
+
|
55
|
+
def variable_names
|
56
|
+
@parameters.names + @local_variables.to_a
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'reek/code_context'
|
3
|
+
|
4
|
+
class Class
|
5
|
+
def is_overriding_method?(sym)
|
6
|
+
instance_methods(false).include?(sym) and superclass.instance_methods(true).include?(sym)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module Reek
|
11
|
+
class ClassContext < CodeContext
|
12
|
+
|
13
|
+
def ClassContext.create(outer, exp)
|
14
|
+
res = Name.resolve(exp[1], outer)
|
15
|
+
ClassContext.new(res[0], res[1], exp[2])
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(outer, name, superclass = nil)
|
19
|
+
super(outer, nil)
|
20
|
+
@name = name
|
21
|
+
@superclass = superclass
|
22
|
+
@parsed_methods = []
|
23
|
+
@instance_variables = Set.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def myself
|
27
|
+
@myself ||= @outer.find_module(@name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def find_module(modname)
|
31
|
+
return nil unless myself
|
32
|
+
@myself.const_or_nil(modname.to_s)
|
33
|
+
end
|
34
|
+
|
35
|
+
def is_overriding_method?(name)
|
36
|
+
return false unless myself
|
37
|
+
@myself.is_overriding_method?(name.to_s)
|
38
|
+
end
|
39
|
+
|
40
|
+
def is_struct?
|
41
|
+
@superclass == [:const, :Struct]
|
42
|
+
end
|
43
|
+
|
44
|
+
def num_methods
|
45
|
+
@parsed_methods.length
|
46
|
+
end
|
47
|
+
|
48
|
+
def record_instance_variable(sym)
|
49
|
+
@instance_variables << Name.new(sym)
|
50
|
+
end
|
51
|
+
|
52
|
+
def record_method(name)
|
53
|
+
@parsed_methods << name.to_s
|
54
|
+
end
|
55
|
+
|
56
|
+
def outer_name
|
57
|
+
"#{@outer.outer_name}#{@name}#"
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_s
|
61
|
+
"#{@outer.outer_name}#{@name}"
|
62
|
+
end
|
63
|
+
|
64
|
+
def variable_names
|
65
|
+
@instance_variables
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class Module
|
2
|
+
|
3
|
+
def const_or_nil(sym)
|
4
|
+
const_defined?(sym) ? const_get(sym) : nil
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
module Reek
|
9
|
+
|
10
|
+
#
|
11
|
+
# Superclass for all types of source code context. Each instance represents
|
12
|
+
# a code element of some kind, and each provides behaviour relevant to that
|
13
|
+
# code element. CodeContexts form a tree in the same way the code does,
|
14
|
+
# with each context holding a reference to a unique outer context.
|
15
|
+
#
|
16
|
+
class CodeContext
|
17
|
+
|
18
|
+
attr_reader :name
|
19
|
+
|
20
|
+
def initialize(outer, exp)
|
21
|
+
@outer = outer
|
22
|
+
@exp = exp
|
23
|
+
@myself = nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def matches?(strings)
|
27
|
+
me = @name.to_s
|
28
|
+
strings.any? do |str|
|
29
|
+
re = /#{str}/
|
30
|
+
re === me or re === self.to_s
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Bounces messages up the context tree to the first enclosing context
|
36
|
+
# that knows how to deal with the request.
|
37
|
+
#
|
38
|
+
def method_missing(method, *args)
|
39
|
+
@outer.send(method, *args)
|
40
|
+
end
|
41
|
+
|
42
|
+
def num_methods
|
43
|
+
0
|
44
|
+
end
|
45
|
+
|
46
|
+
def outer_name
|
47
|
+
"#{@name}/"
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_s
|
51
|
+
"#{@outer.outer_name}#{@name}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,221 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sexp'
|
3
|
+
require 'reek/block_context'
|
4
|
+
require 'reek/class_context'
|
5
|
+
require 'reek/module_context'
|
6
|
+
require 'reek/stop_context'
|
7
|
+
require 'reek/if_context'
|
8
|
+
require 'reek/method_context'
|
9
|
+
require 'reek/singleton_method_context'
|
10
|
+
require 'reek/yield_call_context'
|
11
|
+
|
12
|
+
class Sexp
|
13
|
+
def children
|
14
|
+
find_all { |item| Sexp === item }
|
15
|
+
end
|
16
|
+
|
17
|
+
def is_language_node?
|
18
|
+
first.class == Symbol
|
19
|
+
end
|
20
|
+
|
21
|
+
def has_type?(type)
|
22
|
+
is_language_node? and first == type
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module Reek
|
27
|
+
|
28
|
+
class CodeParser
|
29
|
+
|
30
|
+
# Creates a new Ruby code checker. Any smells discovered
|
31
|
+
# will be stored in +report+.
|
32
|
+
def initialize(report, smells, ctx = StopContext.new)
|
33
|
+
@report = report
|
34
|
+
@smells = smells
|
35
|
+
@element = ctx
|
36
|
+
end
|
37
|
+
|
38
|
+
def process(exp)
|
39
|
+
meth = "process_#{exp[0]}"
|
40
|
+
meth = :process_default unless self.respond_to?(meth)
|
41
|
+
self.send(meth, exp)
|
42
|
+
@element
|
43
|
+
end
|
44
|
+
|
45
|
+
def process_default(exp)
|
46
|
+
exp[0..-1].each { |sub| process(sub) if Array === sub }
|
47
|
+
end
|
48
|
+
|
49
|
+
def process_module(exp)
|
50
|
+
push(ModuleContext.create(@element, exp)) do
|
51
|
+
process_default(exp)
|
52
|
+
check_smells(:module)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def process_class(exp)
|
57
|
+
push(ClassContext.create(@element, exp)) do
|
58
|
+
process_default(exp) unless @element.is_struct?
|
59
|
+
check_smells(:class)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def process_defn(exp)
|
64
|
+
handle_context(MethodContext, :defn, exp)
|
65
|
+
end
|
66
|
+
|
67
|
+
def process_defs(exp)
|
68
|
+
handle_context(SingletonMethodContext, :defs, exp)
|
69
|
+
end
|
70
|
+
|
71
|
+
def process_args(exp)
|
72
|
+
exp[1..-1].each {|sym| @element.record_parameter(sym) }
|
73
|
+
end
|
74
|
+
|
75
|
+
def process_attrset(exp)
|
76
|
+
@element.record_depends_on_self if /^@/ === exp[1].to_s
|
77
|
+
end
|
78
|
+
|
79
|
+
def process_lit(exp)
|
80
|
+
val = exp[1]
|
81
|
+
@element.record_depends_on_self if val == :self
|
82
|
+
end
|
83
|
+
|
84
|
+
def process_iter(exp)
|
85
|
+
process(exp[1])
|
86
|
+
handle_context(BlockContext, :iter, exp[2..-1])
|
87
|
+
end
|
88
|
+
|
89
|
+
def process_dasgn_curr(exp)
|
90
|
+
@element.record_parameter(exp[1])
|
91
|
+
process_default(exp)
|
92
|
+
end
|
93
|
+
|
94
|
+
def process_block(exp)
|
95
|
+
@element.count_statements(CodeParser.count_statements(exp))
|
96
|
+
process_default(exp)
|
97
|
+
end
|
98
|
+
|
99
|
+
def process_yield(exp)
|
100
|
+
handle_context(YieldCallContext, :yield, exp)
|
101
|
+
end
|
102
|
+
|
103
|
+
def process_call(exp)
|
104
|
+
@element.record_call_to(exp)
|
105
|
+
process_default(exp)
|
106
|
+
end
|
107
|
+
|
108
|
+
def process_cfunc(exp)
|
109
|
+
@element.record_depends_on_self
|
110
|
+
end
|
111
|
+
|
112
|
+
def process_attrasgn(exp)
|
113
|
+
process_call(exp)
|
114
|
+
end
|
115
|
+
|
116
|
+
def process_op_asgn1(exp)
|
117
|
+
process_call(exp)
|
118
|
+
end
|
119
|
+
|
120
|
+
def process_if(exp)
|
121
|
+
count_clause(exp[2])
|
122
|
+
count_clause(exp[3])
|
123
|
+
handle_context(IfContext, :if, exp)
|
124
|
+
@element.count_statements(-1)
|
125
|
+
end
|
126
|
+
|
127
|
+
def process_while(exp)
|
128
|
+
count_clause(exp[2])
|
129
|
+
process_default(exp)
|
130
|
+
@element.count_statements(-1)
|
131
|
+
end
|
132
|
+
|
133
|
+
def process_until(exp)
|
134
|
+
count_clause(exp[2])
|
135
|
+
process_default(exp)
|
136
|
+
@element.count_statements(-1)
|
137
|
+
end
|
138
|
+
|
139
|
+
def process_for(exp)
|
140
|
+
count_clause(exp[3])
|
141
|
+
process_default(exp)
|
142
|
+
@element.count_statements(-1)
|
143
|
+
end
|
144
|
+
|
145
|
+
def process_rescue(exp)
|
146
|
+
count_clause(exp[1])
|
147
|
+
process_default(exp)
|
148
|
+
@element.count_statements(-1)
|
149
|
+
end
|
150
|
+
|
151
|
+
def process_resbody(exp)
|
152
|
+
count_clause(exp[2])
|
153
|
+
process_default(exp)
|
154
|
+
end
|
155
|
+
|
156
|
+
def process_case(exp)
|
157
|
+
process_default(exp)
|
158
|
+
@element.count_statements(-1)
|
159
|
+
end
|
160
|
+
|
161
|
+
def process_when(exp)
|
162
|
+
count_clause(exp[2])
|
163
|
+
process_default(exp)
|
164
|
+
end
|
165
|
+
|
166
|
+
def process_ivar(exp)
|
167
|
+
process_iasgn(exp)
|
168
|
+
end
|
169
|
+
|
170
|
+
def process_lasgn(exp)
|
171
|
+
@element.record_local_variable(exp[1])
|
172
|
+
process_default(exp)
|
173
|
+
end
|
174
|
+
|
175
|
+
def process_iasgn(exp)
|
176
|
+
@element.record_instance_variable(exp[1])
|
177
|
+
@element.record_depends_on_self
|
178
|
+
process_default(exp)
|
179
|
+
end
|
180
|
+
|
181
|
+
def process_self(exp)
|
182
|
+
@element.record_depends_on_self
|
183
|
+
end
|
184
|
+
|
185
|
+
def count_clause(sexp)
|
186
|
+
if sexp and !sexp.has_type?(:block)
|
187
|
+
@element.count_statements(1)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def self.count_statements(exp)
|
192
|
+
stmts = exp[1..-1]
|
193
|
+
ignore = 0
|
194
|
+
ignore += 1 if stmts[1] == s(:nil)
|
195
|
+
stmts.length - ignore
|
196
|
+
end
|
197
|
+
|
198
|
+
private
|
199
|
+
|
200
|
+
def handle_context(klass, type, exp)
|
201
|
+
scope = klass.new(@element, exp)
|
202
|
+
push(scope) do
|
203
|
+
process_default(exp)
|
204
|
+
check_smells(type)
|
205
|
+
end
|
206
|
+
scope
|
207
|
+
end
|
208
|
+
|
209
|
+
def check_smells(type)
|
210
|
+
listeners = @smells[type]
|
211
|
+
listeners.each {|smell| smell.examine(@element, @report) } if listeners
|
212
|
+
end
|
213
|
+
|
214
|
+
def push(context)
|
215
|
+
orig = @element
|
216
|
+
@element = context
|
217
|
+
yield
|
218
|
+
@element = orig
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'reek/code_context'
|
2
|
+
|
3
|
+
module Reek
|
4
|
+
class IfContext < CodeContext
|
5
|
+
attr_reader :if_expr
|
6
|
+
|
7
|
+
def initialize(outer, exp)
|
8
|
+
@outer = outer
|
9
|
+
@exp = exp
|
10
|
+
@if_expr = exp[1]
|
11
|
+
end
|
12
|
+
|
13
|
+
def tests_a_parameter?
|
14
|
+
@if_expr[0] == :lvar and has_parameter(@if_expr[1])
|
15
|
+
end
|
16
|
+
|
17
|
+
def outer_name
|
18
|
+
@outer.outer_name
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
@outer.to_s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|