reek 0.3.1 → 1.0.0
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.
- data/History.txt +20 -0
- data/README.txt +4 -80
- data/Rakefile +15 -4
- data/bin/reek +10 -16
- data/config/defaults.reek +53 -0
- data/lib/reek.rb +1 -21
- data/lib/reek/block_context.rb +37 -0
- data/lib/reek/class_context.rb +73 -0
- data/lib/reek/code_context.rb +47 -0
- data/lib/reek/code_parser.rb +204 -0
- data/lib/reek/exceptions.reek +13 -0
- data/lib/reek/if_context.rb +25 -0
- data/lib/reek/method_context.rb +85 -0
- data/lib/reek/module_context.rb +34 -0
- data/lib/reek/name.rb +42 -0
- data/lib/reek/object_refs.rb +3 -6
- data/lib/reek/options.rb +60 -40
- data/lib/reek/rake_task.rb +20 -29
- data/lib/reek/report.rb +16 -27
- data/lib/reek/sexp_formatter.rb +52 -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 +21 -13
- data/lib/reek/smells/duplication.rb +23 -27
- data/lib/reek/smells/feature_envy.rb +18 -25
- data/lib/reek/smells/large_class.rb +32 -17
- data/lib/reek/smells/long_method.rb +24 -16
- data/lib/reek/smells/long_parameter_list.rb +25 -18
- data/lib/reek/smells/long_yield_list.rb +7 -9
- data/lib/reek/smells/nested_iterators.rb +13 -9
- data/lib/reek/smells/smell_detector.rb +66 -0
- data/lib/reek/smells/smells.rb +71 -10
- data/lib/reek/smells/uncommunicative_name.rb +49 -41
- data/lib/reek/smells/utility_function.rb +18 -18
- data/lib/reek/source.rb +116 -0
- data/lib/reek/spec.rb +146 -0
- data/lib/reek/stop_context.rb +62 -0
- data/lib/reek/yield_call_context.rb +14 -0
- data/reek.gemspec +42 -0
- data/spec/integration/reek_source_spec.rb +20 -0
- data/spec/{script_spec.rb → integration/script_spec.rb} +11 -24
- data/spec/reek/class_context_spec.rb +198 -0
- data/spec/reek/code_context_spec.rb +92 -0
- data/spec/reek/code_parser_spec.rb +44 -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 +52 -0
- data/spec/reek/module_context_spec.rb +38 -0
- data/spec/reek/options_spec.rb +2 -28
- data/spec/reek/report_spec.rb +6 -40
- data/spec/reek/sexp_formatter_spec.rb +31 -0
- data/spec/reek/singleton_method_context_spec.rb +17 -0
- data/spec/reek/smells/control_couple_spec.rb +10 -18
- data/spec/reek/smells/duplication_spec.rb +53 -32
- data/spec/reek/smells/feature_envy_spec.rb +87 -49
- data/spec/reek/smells/large_class_spec.rb +45 -4
- data/spec/reek/smells/long_method_spec.rb +25 -41
- data/spec/reek/smells/long_parameter_list_spec.rb +30 -76
- data/spec/reek/smells/nested_iterators_spec.rb +19 -29
- data/spec/reek/smells/smell_spec.rb +9 -18
- data/spec/reek/smells/uncommunicative_name_spec.rb +88 -53
- data/spec/reek/smells/utility_function_spec.rb +45 -44
- data/spec/samples/inline_spec.rb +40 -0
- data/spec/samples/optparse_spec.rb +100 -0
- data/spec/samples/redcloth_spec.rb +93 -0
- data/spec/spec_helper.rb +3 -1
- data/tasks/reek.rake +1 -10
- data/tasks/rspec.rake +16 -35
- metadata +43 -46
- data/lib/reek/checker.rb +0 -66
- data/lib/reek/class_checker.rb +0 -25
- data/lib/reek/file_checker.rb +0 -20
- data/lib/reek/method_checker.rb +0 -198
- data/lib/reek/printer.rb +0 -154
- data/lib/reek/smells/smell.rb +0 -56
- data/lib/reek/version.rb +0 -9
- data/setup.rb +0 -1585
- data/spec/integration_spec.rb +0 -30
- data/spec/reek/class_checker_spec.rb +0 -48
- data/spec/reek/method_checker_spec.rb +0 -67
- data/spec/reek/printer_spec.rb +0 -30
- data/spec/reek_source_spec.rb +0 -12
- data/spec/samples/inline.reek +0 -27
- data/spec/samples/optparse.reek +0 -79
- data/spec/samples/optparse/date.rb +0 -17
- data/spec/samples/optparse/shellwords.rb +0 -6
- data/spec/samples/optparse/time.rb +0 -10
- data/spec/samples/optparse/uri.rb +0 -6
- data/spec/samples/optparse/version.rb +0 -70
- data/spec/samples/redcloth.reek +0 -65
- data/tasks/samples.rake +0 -17
- data/website/index.html +0 -71
- data/website/index.txt +0 -40
- data/website/javascripts/rounded_corners_lite.inc.js +0 -285
- data/website/stylesheets/screen.css +0 -138
- data/website/template.rhtml +0 -48
data/History.txt
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
== 1.0.0 2009-04-05
|
2
|
+
|
3
|
+
=== Major enhancements:
|
4
|
+
|
5
|
+
* Use *.reek files in source tree to configure Reek's behaviour
|
6
|
+
* Added -f option to configure report format
|
7
|
+
* --sort_order replaced by -f, -c and -s
|
8
|
+
* Matchers provided for rspec; eg. foo.should_not reek
|
9
|
+
|
10
|
+
=== Minor enhancements:
|
11
|
+
|
12
|
+
* Smells in singleton methods are now analysed
|
13
|
+
* Uncommunicative parameter names in blocks now reported
|
14
|
+
* Modules and blocks now reflected in scope of smell reports
|
15
|
+
|
16
|
+
=== Fixes:
|
17
|
+
|
18
|
+
* Corrected false reports of long arg lists to yield
|
19
|
+
* A method can now be a UtilityFunction only when it includes a call
|
20
|
+
|
1
21
|
== 0.3.1 2008-11-17
|
2
22
|
|
3
23
|
* Minor enhancements:
|
data/README.txt
CHANGED
@@ -1,82 +1,6 @@
|
|
1
|
-
=
|
1
|
+
= Reek
|
2
2
|
|
3
|
-
|
4
|
-
* mailto:kevin@rutherford-software.com
|
3
|
+
Code smell detection for Ruby.
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
Reek is a tool that examines Ruby classes, modules and methods and
|
9
|
-
reports any code smells it finds.
|
10
|
-
|
11
|
-
=== SUPPORTED CODE SMELLS:
|
12
|
-
|
13
|
-
Reek currently includes very naive checks for the following smells:
|
14
|
-
|
15
|
-
* Long Method
|
16
|
-
* Large Class
|
17
|
-
* Feature Envy
|
18
|
-
* Uncommunicative Name
|
19
|
-
* Long Parameter List
|
20
|
-
* Utility Function
|
21
|
-
* Nested Iterators
|
22
|
-
* Control Couple
|
23
|
-
* Duplication
|
24
|
-
|
25
|
-
== FEATURES/PROBLEMS:
|
26
|
-
|
27
|
-
* Most of the current checks are quite naive.
|
28
|
-
* Not many smells checked right now; more coming soon.
|
29
|
-
* The current Feature Envy check is probably over zealous.
|
30
|
-
* There's no convenient programmer's API just yet.
|
31
|
-
|
32
|
-
== SYNOPSIS:
|
33
|
-
|
34
|
-
$ reek [options] sources
|
35
|
-
|
36
|
-
(See `reek --help` for details.)
|
37
|
-
|
38
|
-
== DEPENDENCIES:
|
39
|
-
|
40
|
-
Reek makes use of the following other gems:
|
41
|
-
|
42
|
-
* ParseTree
|
43
|
-
* sexp_processor
|
44
|
-
|
45
|
-
== INSTALL:
|
46
|
-
|
47
|
-
Get the latest version of the gem:
|
48
|
-
|
49
|
-
$ gem install reek
|
50
|
-
|
51
|
-
Or get the latest source code from:
|
52
|
-
|
53
|
-
$ git clone git://github.com/kevinrutherford/reek.git
|
54
|
-
|
55
|
-
or
|
56
|
-
|
57
|
-
$ git clone git://rubyforge.org/reek.git
|
58
|
-
|
59
|
-
== LICENSE:
|
60
|
-
|
61
|
-
(The MIT License)
|
62
|
-
|
63
|
-
Copyright (c) 2008 Kevin Rutherford, Rutherford Software Ltd
|
64
|
-
|
65
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
66
|
-
a copy of this software and associated documentation files (the
|
67
|
-
'Software'), to deal in the Software without restriction, including
|
68
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
69
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
70
|
-
permit persons to whom the Software is furnished to do so, subject to
|
71
|
-
the following conditions:
|
72
|
-
|
73
|
-
The above copyright notice and this permission notice shall be
|
74
|
-
included in all copies or substantial portions of the Software.
|
75
|
-
|
76
|
-
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
77
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
78
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
79
|
-
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
80
|
-
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
81
|
-
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
82
|
-
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
5
|
+
The documentation is at http://wiki.github.com/kevinrutherford/reek
|
6
|
+
The code lives at http://github.com/kevinrutherford/reek/tree
|
data/Rakefile
CHANGED
@@ -1,6 +1,17 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/clean'
|
3
3
|
|
4
|
-
|
4
|
+
$:.unshift File.dirname(__FILE__) + '/lib'
|
5
5
|
|
6
|
-
|
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
CHANGED
@@ -1,25 +1,19 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
#
|
3
|
-
#
|
4
|
-
#
|
3
|
+
# Reek examines Ruby source code for smells.
|
4
|
+
# Visit http://reek.rubyforge.org/ for docs etc.
|
5
|
+
#
|
6
|
+
# Author: Kevin Rutherford
|
5
7
|
#
|
6
8
|
|
7
|
-
require
|
8
|
-
require
|
9
|
+
require 'reek'
|
10
|
+
require 'reek/source'
|
11
|
+
require 'reek/options'
|
9
12
|
|
10
|
-
sources = Reek::Options.parse(ARGV)
|
11
13
|
exitstatus = 0
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
if sources.size == 1
|
16
|
-
puts smells.to_s
|
17
|
-
else
|
18
|
-
puts "\"#{src}\" -- #{smells.length} warnings:"
|
19
|
-
puts smells.to_s
|
20
|
-
puts
|
21
|
-
end
|
14
|
+
source = Reek::Options.parse(ARGV)
|
15
|
+
if source.smelly?
|
16
|
+
puts source.report
|
22
17
|
exitstatus = 2
|
23
18
|
end
|
24
|
-
|
25
19
|
exit(exitstatus)
|
@@ -0,0 +1,53 @@
|
|
1
|
+
---
|
2
|
+
LargeClass:
|
3
|
+
max_methods: 25
|
4
|
+
exclude:
|
5
|
+
- Array
|
6
|
+
- Hash
|
7
|
+
- Module
|
8
|
+
- String
|
9
|
+
enabled: true
|
10
|
+
LongParameterList:
|
11
|
+
max_params: 3
|
12
|
+
exclude: []
|
13
|
+
|
14
|
+
enabled: true
|
15
|
+
FeatureEnvy:
|
16
|
+
exclude:
|
17
|
+
- initialize
|
18
|
+
enabled: true
|
19
|
+
UncommunicativeName:
|
20
|
+
accept:
|
21
|
+
- Inline::C
|
22
|
+
exclude: []
|
23
|
+
|
24
|
+
enabled: true
|
25
|
+
reject:
|
26
|
+
- !ruby/regexp /^.[0-9]*$/
|
27
|
+
NestedIterators:
|
28
|
+
exclude: []
|
29
|
+
|
30
|
+
enabled: true
|
31
|
+
LongMethod:
|
32
|
+
max_statements: 5
|
33
|
+
exclude:
|
34
|
+
- initialize
|
35
|
+
enabled: true
|
36
|
+
Duplication:
|
37
|
+
exclude: []
|
38
|
+
|
39
|
+
enabled: true
|
40
|
+
max_calls: 1
|
41
|
+
UtilityFunction:
|
42
|
+
exclude: []
|
43
|
+
|
44
|
+
enabled: true
|
45
|
+
ControlCouple:
|
46
|
+
exclude:
|
47
|
+
- initialize
|
48
|
+
enabled: true
|
49
|
+
LongYieldList:
|
50
|
+
max_params: 3
|
51
|
+
exclude: []
|
52
|
+
|
53
|
+
enabled: true
|
data/lib/reek.rb
CHANGED
@@ -1,25 +1,5 @@
|
|
1
1
|
$:.unshift File.dirname(__FILE__)
|
2
2
|
|
3
|
-
require 'reek/file_checker'
|
4
|
-
require 'reek/report'
|
5
|
-
|
6
3
|
module Reek # :doc:
|
7
|
-
|
8
|
-
#
|
9
|
-
# Analyse the given source, looking for code smells.
|
10
|
-
# The source can be a filename or a String containing Ruby code.
|
11
|
-
# Returns a +Report+ listing the smells found.
|
12
|
-
#
|
13
|
-
def self.analyse(src) # :doc:
|
14
|
-
report = Report.new
|
15
|
-
source = Reek.get_source(src)
|
16
|
-
FileChecker.new(report).check_source(source)
|
17
|
-
report
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def self.get_source(src)
|
23
|
-
File.exists?(src) ? IO.readlines(src).join : src
|
24
|
-
end
|
4
|
+
VERSION = '1.0.0'
|
25
5
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'reek/code_context'
|
2
|
+
|
3
|
+
module Reek
|
4
|
+
class BlockContext < CodeContext
|
5
|
+
|
6
|
+
def initialize(outer, exp)
|
7
|
+
super
|
8
|
+
@parameters = []
|
9
|
+
@local_variables = []
|
10
|
+
@name = Name.new('block')
|
11
|
+
end
|
12
|
+
|
13
|
+
def inside_a_block?
|
14
|
+
true
|
15
|
+
end
|
16
|
+
|
17
|
+
def has_parameter(name)
|
18
|
+
@parameters.include?(name) or @outer.has_parameter(name)
|
19
|
+
end
|
20
|
+
|
21
|
+
def nested_block?
|
22
|
+
@outer.inside_a_block?
|
23
|
+
end
|
24
|
+
|
25
|
+
def record_parameter(sym)
|
26
|
+
@parameters << Name.new(sym)
|
27
|
+
end
|
28
|
+
|
29
|
+
def outer_name
|
30
|
+
"#{@outer.outer_name}#{@name}/"
|
31
|
+
end
|
32
|
+
|
33
|
+
def variable_names
|
34
|
+
@parameters + @local_variables
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'reek/code_context'
|
2
|
+
|
3
|
+
class Class
|
4
|
+
def non_inherited_methods
|
5
|
+
instance_methods(false) + private_instance_methods(false)
|
6
|
+
end
|
7
|
+
|
8
|
+
def is_overriding_method?(sym)
|
9
|
+
instance_methods(false).include?(sym) and superclass.instance_methods(true).include?(sym)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module Reek
|
14
|
+
class ClassContext < CodeContext
|
15
|
+
|
16
|
+
def ClassContext.create(outer, exp)
|
17
|
+
res = Name.resolve(exp[1], outer)
|
18
|
+
ClassContext.new(res[0], res[1], exp[2])
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(outer, name, superclass = nil)
|
22
|
+
super(outer, nil)
|
23
|
+
@name = name
|
24
|
+
@superclass = superclass
|
25
|
+
@parsed_methods = []
|
26
|
+
@instance_variables = []
|
27
|
+
end
|
28
|
+
|
29
|
+
def myself
|
30
|
+
@myself ||= @outer.find_module(@name)
|
31
|
+
end
|
32
|
+
|
33
|
+
def find_module(modname)
|
34
|
+
sym = modname.to_s
|
35
|
+
return nil unless myself
|
36
|
+
myself.const_defined?(sym) ? myself.const_get(sym) : nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def is_overriding_method?(name)
|
40
|
+
return false unless myself
|
41
|
+
myself.is_overriding_method?(name.to_s)
|
42
|
+
end
|
43
|
+
|
44
|
+
def is_struct?
|
45
|
+
@superclass == [:const, :Struct]
|
46
|
+
end
|
47
|
+
|
48
|
+
def num_methods
|
49
|
+
meths = myself ? myself.non_inherited_methods : @parsed_methods
|
50
|
+
meths.length
|
51
|
+
end
|
52
|
+
|
53
|
+
def record_instance_variable(sym)
|
54
|
+
@instance_variables << Name.new(sym)
|
55
|
+
end
|
56
|
+
|
57
|
+
def record_method(name)
|
58
|
+
@parsed_methods << name.to_s
|
59
|
+
end
|
60
|
+
|
61
|
+
def outer_name
|
62
|
+
"#{@outer.outer_name}#{@name}#"
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_s
|
66
|
+
"#{@outer.outer_name}#{@name}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def variable_names
|
70
|
+
@instance_variables
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Reek
|
2
|
+
|
3
|
+
#
|
4
|
+
# Superclass for all types of source code context. Each instance represents
|
5
|
+
# a code element of some kind, and each provides behaviour relevant to that
|
6
|
+
# code element. CodeContexts form a tree in the same way the code does,
|
7
|
+
# with each context holding a reference to a unique outer context.
|
8
|
+
#
|
9
|
+
class CodeContext
|
10
|
+
|
11
|
+
attr_reader :name
|
12
|
+
|
13
|
+
def initialize(outer, exp)
|
14
|
+
@outer = outer
|
15
|
+
@exp = exp
|
16
|
+
@myself = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def matches?(strings)
|
20
|
+
me = @name.to_s
|
21
|
+
strings.any? do |str|
|
22
|
+
re = /#{str}/
|
23
|
+
re === me or re === self.to_s
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
# Bounces messages up the context tree to the first enclosing context
|
29
|
+
# that knows how to deal with the request.
|
30
|
+
#
|
31
|
+
def method_missing(method, *args)
|
32
|
+
@outer.send(method, *args)
|
33
|
+
end
|
34
|
+
|
35
|
+
def num_methods
|
36
|
+
0
|
37
|
+
end
|
38
|
+
|
39
|
+
def outer_name
|
40
|
+
"#{@name}/"
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_s
|
44
|
+
"#{@outer.outer_name}#{@name}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'parse_tree'
|
3
|
+
require 'sexp_processor'
|
4
|
+
require 'reek/block_context'
|
5
|
+
require 'reek/class_context'
|
6
|
+
require 'reek/module_context'
|
7
|
+
require 'reek/stop_context'
|
8
|
+
require 'reek/if_context'
|
9
|
+
require 'reek/method_context'
|
10
|
+
require 'reek/singleton_method_context'
|
11
|
+
require 'reek/yield_call_context'
|
12
|
+
|
13
|
+
module Reek
|
14
|
+
|
15
|
+
class CodeParser < SexpProcessor
|
16
|
+
|
17
|
+
def self.parse_tree_for(code) # :nodoc:
|
18
|
+
ParseTree.new.parse_tree_for_string(code)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Creates a new Ruby code checker. Any smells discovered by
|
22
|
+
# +check_source+ or +check_object+ will be stored in +report+.
|
23
|
+
def initialize(report, smells, ctx = StopContext.new)
|
24
|
+
super()
|
25
|
+
@report = report
|
26
|
+
@smells = smells
|
27
|
+
@element = ctx
|
28
|
+
@unsupported -= [:cfunc]
|
29
|
+
@default_method = :process_default
|
30
|
+
@require_empty = @warn_on_default = false
|
31
|
+
end
|
32
|
+
|
33
|
+
# Analyses the given Ruby source +code+ looking for smells.
|
34
|
+
# Any smells found are saved in the +Report+ object that
|
35
|
+
# was passed to this object's constructor.
|
36
|
+
def check_source(code)
|
37
|
+
check_parse_tree(CodeParser.parse_tree_for(code))
|
38
|
+
end
|
39
|
+
|
40
|
+
# Analyses the given Ruby object +obj+ looking for smells.
|
41
|
+
# Any smells found are saved in the +Report+ object that
|
42
|
+
# was passed to this object's constructor.
|
43
|
+
def check_object(obj)
|
44
|
+
check_parse_tree(ParseTree.new.parse_tree(obj))
|
45
|
+
end
|
46
|
+
|
47
|
+
def process_default(exp)
|
48
|
+
exp[1..-1].each { |sub| process(sub) if Array === sub }
|
49
|
+
s(exp)
|
50
|
+
end
|
51
|
+
|
52
|
+
def process_module(exp)
|
53
|
+
push(ModuleContext.create(@element, exp)) do
|
54
|
+
process_default(exp)
|
55
|
+
check_smells(:module)
|
56
|
+
end
|
57
|
+
s(exp)
|
58
|
+
end
|
59
|
+
|
60
|
+
def process_class(exp)
|
61
|
+
push(ClassContext.create(@element, exp)) do
|
62
|
+
process_default(exp) unless @element.is_struct?
|
63
|
+
check_smells(:class)
|
64
|
+
end
|
65
|
+
s(exp)
|
66
|
+
end
|
67
|
+
|
68
|
+
def process_defn(exp)
|
69
|
+
handle_context(MethodContext, :defn, exp)
|
70
|
+
end
|
71
|
+
|
72
|
+
def process_defs(exp)
|
73
|
+
handle_context(SingletonMethodContext, :defs, exp)
|
74
|
+
end
|
75
|
+
|
76
|
+
def process_args(exp)
|
77
|
+
exp[1..-1].each {|sym| @element.record_parameter(sym) }
|
78
|
+
s(exp)
|
79
|
+
end
|
80
|
+
|
81
|
+
def process_attrset(exp)
|
82
|
+
@element.record_depends_on_self if /^@/ === exp[1].to_s
|
83
|
+
s(exp)
|
84
|
+
end
|
85
|
+
|
86
|
+
def process_lit(exp)
|
87
|
+
val = exp[1]
|
88
|
+
@element.record_depends_on_self if val == :self
|
89
|
+
s(exp)
|
90
|
+
end
|
91
|
+
|
92
|
+
def process_iter(exp)
|
93
|
+
process(exp[1])
|
94
|
+
handle_context(BlockContext, :iter, exp[1..-1])
|
95
|
+
end
|
96
|
+
|
97
|
+
def process_dasgn_curr(exp)
|
98
|
+
@element.record_parameter(exp[1])
|
99
|
+
process_default(exp)
|
100
|
+
end
|
101
|
+
|
102
|
+
def process_block(exp)
|
103
|
+
@element.count_statements(CodeParser.count_statements(exp))
|
104
|
+
process_default(exp)
|
105
|
+
end
|
106
|
+
|
107
|
+
def process_yield(exp)
|
108
|
+
handle_context(YieldCallContext, :yield, exp)
|
109
|
+
end
|
110
|
+
|
111
|
+
def process_call(exp)
|
112
|
+
@element.record_call_to(exp)
|
113
|
+
process_default(exp)
|
114
|
+
end
|
115
|
+
|
116
|
+
def process_fcall(exp)
|
117
|
+
@element.record_depends_on_self
|
118
|
+
@element.refs.record_reference_to_self
|
119
|
+
process_default(exp)
|
120
|
+
end
|
121
|
+
|
122
|
+
def process_cfunc(exp)
|
123
|
+
@element.record_depends_on_self
|
124
|
+
s(exp)
|
125
|
+
end
|
126
|
+
|
127
|
+
def process_vcall(exp)
|
128
|
+
@element.record_depends_on_self
|
129
|
+
@element.refs.record_reference_to_self
|
130
|
+
s(exp)
|
131
|
+
end
|
132
|
+
|
133
|
+
def process_if(exp)
|
134
|
+
handle_context(IfContext, :if, exp)
|
135
|
+
end
|
136
|
+
|
137
|
+
def process_ivar(exp)
|
138
|
+
process_iasgn(exp)
|
139
|
+
end
|
140
|
+
|
141
|
+
def process_lasgn(exp)
|
142
|
+
@element.record_local_variable(exp[1])
|
143
|
+
process(exp[2])
|
144
|
+
s(exp)
|
145
|
+
end
|
146
|
+
|
147
|
+
def process_iasgn(exp)
|
148
|
+
@element.record_instance_variable(exp[1])
|
149
|
+
@element.record_depends_on_self
|
150
|
+
process_default(exp)
|
151
|
+
end
|
152
|
+
|
153
|
+
def process_self(exp)
|
154
|
+
@element.record_depends_on_self
|
155
|
+
s(exp)
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
|
160
|
+
def self.count_statements(exp)
|
161
|
+
stmts = exp[1..-1]
|
162
|
+
ignore = 0
|
163
|
+
ignore = 1 if is_expr?(stmts[0], :args)
|
164
|
+
ignore += 1 if stmts[1] == s(:nil)
|
165
|
+
stmts.length - ignore
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.is_expr?(exp, type)
|
169
|
+
Array === exp and exp[0] == type
|
170
|
+
end
|
171
|
+
|
172
|
+
def self.is_global_variable?(exp)
|
173
|
+
is_expr?(exp, :gvar)
|
174
|
+
end
|
175
|
+
|
176
|
+
def handle_context(klass, type, exp)
|
177
|
+
push(klass.new(@element, exp)) do
|
178
|
+
process_default(exp)
|
179
|
+
check_smells(type)
|
180
|
+
end
|
181
|
+
s(exp)
|
182
|
+
end
|
183
|
+
|
184
|
+
def check_smells(type)
|
185
|
+
@smells[type].each {|smell| smell.examine(@element, @report) }
|
186
|
+
end
|
187
|
+
|
188
|
+
def push(context)
|
189
|
+
orig = @element
|
190
|
+
@element = context
|
191
|
+
yield
|
192
|
+
@element = orig
|
193
|
+
end
|
194
|
+
|
195
|
+
def pop(exp)
|
196
|
+
@element = @element.outer
|
197
|
+
s(exp)
|
198
|
+
end
|
199
|
+
|
200
|
+
def check_parse_tree(sexp) # :nodoc:
|
201
|
+
sexp.each { |exp| process(exp) }
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|