reek 1.4.0 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +5 -0
- data/README.md +70 -92
- data/config/defaults.reek +3 -0
- data/features/samples.feature +24 -20
- data/features/step_definitions/reek_steps.rb +1 -1
- data/features/support/env.rb +7 -7
- data/lib/reek/core/code_context.rb +1 -1
- data/lib/reek/core/code_parser.rb +19 -18
- data/lib/reek/core/method_context.rb +8 -7
- data/lib/reek/core/module_context.rb +1 -1
- data/lib/reek/core/smell_repository.rb +1 -0
- data/lib/reek/core/sniffer.rb +3 -1
- data/lib/reek/rake/task.rb +1 -5
- data/lib/reek/smell_description.rb +26 -0
- data/lib/reek/smell_warning.rb +35 -49
- data/lib/reek/smells.rb +1 -0
- data/lib/reek/smells/attribute.rb +1 -1
- data/lib/reek/smells/control_parameter.rb +14 -7
- data/lib/reek/smells/data_clump.rb +1 -1
- data/lib/reek/smells/duplicate_method_call.rb +2 -9
- data/lib/reek/smells/module_initialize.rb +38 -0
- data/lib/reek/smells/nested_iterators.rb +1 -1
- data/lib/reek/smells/nil_check.rb +3 -3
- data/lib/reek/smells/repeated_conditional.rb +3 -2
- data/lib/reek/smells/smell_detector.rb +1 -1
- data/lib/reek/smells/too_many_instance_variables.rb +1 -1
- data/lib/reek/smells/too_many_methods.rb +1 -1
- data/lib/reek/smells/uncommunicative_method_name.rb +0 -4
- data/lib/reek/smells/uncommunicative_parameter_name.rb +0 -4
- data/lib/reek/smells/uncommunicative_variable_name.rb +11 -9
- data/lib/reek/smells/utility_function.rb +2 -2
- data/lib/reek/source/ast_node.rb +40 -0
- data/lib/reek/source/ast_node_class_map.rb +37 -0
- data/lib/reek/source/reference_collector.rb +3 -3
- data/lib/reek/source/sexp_extensions.rb +133 -59
- data/lib/reek/source/sexp_formatter.rb +10 -4
- data/lib/reek/source/sexp_node.rb +25 -17
- data/lib/reek/source/source_code.rb +21 -9
- data/lib/reek/source/tree_dresser.rb +10 -33
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +2 -4
- data/spec/matchers/smell_of_matcher.rb +9 -1
- data/spec/quality/reek_source_spec.rb +0 -35
- data/spec/reek/core/code_context_spec.rb +22 -8
- data/spec/reek/core/method_context_spec.rb +10 -10
- data/spec/reek/smell_description_spec.rb +43 -0
- data/spec/reek/smell_warning_spec.rb +0 -3
- data/spec/reek/smells/control_parameter_spec.rb +24 -0
- data/spec/reek/smells/feature_envy_spec.rb +50 -17
- data/spec/reek/smells/irresponsible_module_spec.rb +25 -17
- data/spec/reek/smells/module_initialize_spec.rb +20 -0
- data/spec/reek/smells/prima_donna_method_spec.rb +2 -2
- data/spec/reek/smells/repeated_conditional_spec.rb +10 -4
- data/spec/reek/smells/too_many_instance_variables_spec.rb +47 -21
- data/spec/reek/smells/too_many_statements_spec.rb +11 -1
- data/spec/reek/smells/uncommunicative_variable_name_spec.rb +1 -1
- data/spec/reek/smells/utility_function_spec.rb +26 -25
- data/spec/reek/source/sexp_extensions_spec.rb +164 -91
- data/spec/reek/source/sexp_formatter_spec.rb +13 -1
- data/spec/reek/source/sexp_node_spec.rb +5 -5
- data/spec/reek/source/source_code_spec.rb +18 -6
- data/spec/reek/source/tree_dresser_spec.rb +5 -5
- data/spec/spec_helper.rb +8 -4
- metadata +16 -50
@@ -85,7 +85,7 @@ module Reek
|
|
85
85
|
def initialize(ctx, min_clump_size, max_copies)
|
86
86
|
@min_clump_size = min_clump_size
|
87
87
|
@max_copies = max_copies
|
88
|
-
@candidate_methods = ctx.
|
88
|
+
@candidate_methods = ctx.node_instance_methods.map do |defn_node|
|
89
89
|
CandidateMethod.new(defn_node)
|
90
90
|
end
|
91
91
|
end
|
@@ -102,7 +102,6 @@ module Reek
|
|
102
102
|
def calls
|
103
103
|
result = Hash.new { |hash, key| hash[key] = FoundCall.new(key) }
|
104
104
|
collect_calls(result)
|
105
|
-
collect_assignments(result)
|
106
105
|
result.values.sort_by(&:call)
|
107
106
|
end
|
108
107
|
|
@@ -112,19 +111,13 @@ module Reek
|
|
112
111
|
|
113
112
|
private
|
114
113
|
|
115
|
-
def collect_assignments(result)
|
116
|
-
context.local_nodes(:attrasgn) do |asgn_node|
|
117
|
-
result[asgn_node].record(asgn_node) if asgn_node.args
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
114
|
def collect_calls(result)
|
122
|
-
context.
|
115
|
+
context.each_node(:send, [:mlhs]) do |call_node|
|
123
116
|
next if call_node.method_name == :new
|
124
117
|
next if !call_node.receiver && call_node.args.empty?
|
125
118
|
result[call_node].record(call_node)
|
126
119
|
end
|
127
|
-
context.local_nodes(:
|
120
|
+
context.local_nodes(:block) do |call_node|
|
128
121
|
result[call_node].record(call_node)
|
129
122
|
end
|
130
123
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'reek/smells/smell_detector'
|
2
|
+
require 'reek/smell_warning'
|
3
|
+
|
4
|
+
module Reek
|
5
|
+
module Smells
|
6
|
+
#
|
7
|
+
# a module is usually a mixin, so when initialize method is present it is
|
8
|
+
# hard to tell initialization order and parameters so having 'initialize'
|
9
|
+
# in a module is usually a bad idea
|
10
|
+
#
|
11
|
+
class ModuleInitialize < SmellDetector
|
12
|
+
SMELL_CLASS = smell_class_name
|
13
|
+
SMELL_SUBCLASS = SMELL_CLASS
|
14
|
+
|
15
|
+
def self.contexts # :nodoc:
|
16
|
+
[:module]
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Checks whether module has method 'initialize'.
|
21
|
+
#
|
22
|
+
# @return [Array<SmellWarning>]
|
23
|
+
#
|
24
|
+
def examine_context(module_ctx)
|
25
|
+
module_ctx.local_nodes(:def) do |node| # FIXME: also search for :defs?
|
26
|
+
if node.name.to_s == 'initialize'
|
27
|
+
return [
|
28
|
+
SmellWarning.new(SMELL_CLASS, module_ctx.full_name, [module_ctx.exp.line],
|
29
|
+
'has initialize method',
|
30
|
+
@source, SMELL_SUBCLASS, {})
|
31
|
+
]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
[]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -10,7 +10,7 @@ module Reek
|
|
10
10
|
SMELL_SUBCLASS = name.split(/::/)[-1]
|
11
11
|
|
12
12
|
def examine_context(ctx)
|
13
|
-
call_node_finder = NodeFinder.new(ctx, :
|
13
|
+
call_node_finder = NodeFinder.new(ctx, :send, NilCallNodeDetector)
|
14
14
|
case_node_finder = NodeFinder.new(ctx, :when, NilWhenNodeDetector)
|
15
15
|
smelly_nodes = call_node_finder.smelly_nodes + case_node_finder.smelly_nodes
|
16
16
|
|
@@ -58,7 +58,7 @@ module Reek
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def involves_nil?(call)
|
61
|
-
call.
|
61
|
+
call.participants.any? { |it| it.type == :nil }
|
62
62
|
end
|
63
63
|
|
64
64
|
def comparison_methods
|
@@ -71,7 +71,7 @@ module Reek
|
|
71
71
|
module_function
|
72
72
|
|
73
73
|
def detect(node)
|
74
|
-
node.condition_list.any?
|
74
|
+
node.condition_list.any? { |it| it.type == :nil }
|
75
75
|
end
|
76
76
|
end
|
77
77
|
end
|
@@ -23,6 +23,7 @@ module Reek
|
|
23
23
|
class RepeatedConditional < SmellDetector
|
24
24
|
SMELL_CLASS = 'SimulatedPolymorphism'
|
25
25
|
SMELL_SUBCLASS = name.split(/::/)[-1]
|
26
|
+
BLOCK_GIVEN_CONDITION = AST::Node.new(:send, [nil, :block_given?])
|
26
27
|
|
27
28
|
def self.contexts # :nodoc:
|
28
29
|
[:class]
|
@@ -65,8 +66,8 @@ module Reek
|
|
65
66
|
def conditional_counts(sexp)
|
66
67
|
result = Hash.new { |hash, key| hash[key] = [] }
|
67
68
|
collector = proc do |node|
|
68
|
-
condition = node.condition
|
69
|
-
next if condition
|
69
|
+
next unless (condition = node.condition)
|
70
|
+
next if condition == BLOCK_GIVEN_CONDITION
|
70
71
|
result[condition].push(condition.line)
|
71
72
|
end
|
72
73
|
[:if, :case].each { |stmt| sexp.local_nodes(stmt, &collector) }
|
@@ -45,7 +45,7 @@ module Reek
|
|
45
45
|
private
|
46
46
|
|
47
47
|
def check_num_ivars(ctx) # :nodoc:
|
48
|
-
count = ctx.local_nodes(:
|
48
|
+
count = ctx.local_nodes(:ivasgn).map { |ivasgn| ivasgn[1] }.uniq.length
|
49
49
|
return [] if count <= @max_allowed_ivars
|
50
50
|
smell = SmellWarning.new(SMELL_CLASS, ctx.full_name, [ctx.exp.line],
|
51
51
|
"has at least #{count} instance variables",
|
@@ -47,7 +47,7 @@ module Reek
|
|
47
47
|
private
|
48
48
|
|
49
49
|
def check_num_methods(ctx) # :nodoc:
|
50
|
-
actual = ctx.
|
50
|
+
actual = ctx.node_instance_methods.length
|
51
51
|
return [] if actual <= @max_allowed_methods
|
52
52
|
smell = SmellWarning.new(SMELL_CLASS, ctx.full_name, [ctx.exp.line],
|
53
53
|
"has at least #{actual} methods",
|
@@ -42,7 +42,7 @@ module Reek
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def self.contexts # :nodoc:
|
45
|
-
[:module, :class, :
|
45
|
+
[:module, :class, :def, :defs]
|
46
46
|
end
|
47
47
|
|
48
48
|
#
|
@@ -76,11 +76,11 @@ module Reek
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def find_assignment_variable_names(exp, accumulator)
|
79
|
-
assignment_nodes = exp.each_node(:
|
79
|
+
assignment_nodes = exp.each_node(:lvasgn, [:class, :module, :defs, :def])
|
80
80
|
|
81
81
|
case exp.first
|
82
82
|
when :class, :module
|
83
|
-
assignment_nodes += exp.each_node(:
|
83
|
+
assignment_nodes += exp.each_node(:ivasgn, [:class, :module])
|
84
84
|
end
|
85
85
|
|
86
86
|
assignment_nodes.each { |asgn| accumulator[asgn[1]].push(asgn.line) }
|
@@ -90,11 +90,12 @@ module Reek
|
|
90
90
|
arg_search_exp = case exp.first
|
91
91
|
when :class, :module
|
92
92
|
exp
|
93
|
-
when :defs, :
|
93
|
+
when :defs, :def
|
94
94
|
exp.body
|
95
95
|
end
|
96
96
|
|
97
|
-
|
97
|
+
return unless arg_search_exp
|
98
|
+
args_nodes = arg_search_exp.each_node(:args, [:class, :module, :defs, :def])
|
98
99
|
|
99
100
|
args_nodes.each do |args_node|
|
100
101
|
recursively_record_variable_names(accumulator, args_node)
|
@@ -102,11 +103,12 @@ module Reek
|
|
102
103
|
end
|
103
104
|
|
104
105
|
def recursively_record_variable_names(accumulator, exp)
|
105
|
-
exp
|
106
|
-
|
107
|
-
|
108
|
-
elsif subexp.first == :masgn
|
106
|
+
exp.children.each do |subexp|
|
107
|
+
case subexp.type
|
108
|
+
when :mlhs
|
109
109
|
recursively_record_variable_names(accumulator, subexp)
|
110
|
+
else
|
111
|
+
record_variable_name(exp, subexp.name, accumulator)
|
110
112
|
end
|
111
113
|
end
|
112
114
|
end
|
@@ -46,7 +46,7 @@ module Reek
|
|
46
46
|
|
47
47
|
class << self
|
48
48
|
def contexts # :nodoc:
|
49
|
-
[:
|
49
|
+
[:def]
|
50
50
|
end
|
51
51
|
|
52
52
|
def default_config
|
@@ -77,7 +77,7 @@ module Reek
|
|
77
77
|
end
|
78
78
|
|
79
79
|
def num_helper_methods(method_ctx)
|
80
|
-
method_ctx.local_nodes(:
|
80
|
+
method_ctx.local_nodes(:send).length
|
81
81
|
end
|
82
82
|
end
|
83
83
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'parser'
|
2
|
+
|
3
|
+
module Reek
|
4
|
+
module Source
|
5
|
+
# Base class for AST nodes extended with utility methods. Contains some
|
6
|
+
# methods to ease the transition from Sexp to AST::Node.
|
7
|
+
class AstNode < Parser::AST::Node
|
8
|
+
attr_reader :comments
|
9
|
+
|
10
|
+
def initialize(type, children = [], options = {})
|
11
|
+
@comments = options.fetch(:comments, [])
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def comments
|
16
|
+
@comments.map(&:text).join("\n")
|
17
|
+
end
|
18
|
+
|
19
|
+
# @deprecated
|
20
|
+
def [](index)
|
21
|
+
elements[index]
|
22
|
+
end
|
23
|
+
|
24
|
+
def line
|
25
|
+
loc.line
|
26
|
+
end
|
27
|
+
|
28
|
+
# @deprecated
|
29
|
+
def first
|
30
|
+
type
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def elements
|
36
|
+
[type, *children]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'reek/source/ast_node'
|
2
|
+
require 'reek/source/sexp_node'
|
3
|
+
require 'reek/source/sexp_extensions'
|
4
|
+
|
5
|
+
module Reek
|
6
|
+
module Source
|
7
|
+
# Maps AST node types to sublasses of AstNode extended with the relevant
|
8
|
+
# utility modules.
|
9
|
+
class AstNodeClassMap
|
10
|
+
def initialize
|
11
|
+
@klass_map = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def klass_for(type)
|
15
|
+
@klass_map[type] ||=
|
16
|
+
begin
|
17
|
+
klass = Class.new(AstNode)
|
18
|
+
klass.send :include, extension_map[type] if extension_map[type]
|
19
|
+
klass.send :include, SexpNode
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def extension_map
|
24
|
+
@extension_map ||=
|
25
|
+
begin
|
26
|
+
assoc = SexpExtensions.constants.map do |const|
|
27
|
+
[
|
28
|
+
const.to_s.sub(/Node$/, '').downcase.to_sym,
|
29
|
+
SexpExtensions.const_get(const)
|
30
|
+
]
|
31
|
+
end
|
32
|
+
Hash[assoc]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -6,7 +6,7 @@ module Reek
|
|
6
6
|
# of an abstract syntax tree.
|
7
7
|
#
|
8
8
|
class ReferenceCollector
|
9
|
-
STOP_NODES = [:class, :module, :
|
9
|
+
STOP_NODES = [:class, :module, :def, :defs]
|
10
10
|
|
11
11
|
def initialize(ast)
|
12
12
|
@ast = ast
|
@@ -14,10 +14,10 @@ module Reek
|
|
14
14
|
|
15
15
|
def num_refs_to_self
|
16
16
|
result = 0
|
17
|
-
[:self, :zsuper, :ivar, :
|
17
|
+
[:self, :zsuper, :ivar, :ivasgn].each do |node_type|
|
18
18
|
@ast.look_for(node_type, STOP_NODES) { result += 1 }
|
19
19
|
end
|
20
|
-
@ast.look_for(:
|
20
|
+
@ast.look_for(:send, STOP_NODES) do |call|
|
21
21
|
result += 1 unless call.receiver
|
22
22
|
end
|
23
23
|
result
|
@@ -3,51 +3,104 @@ require 'reek/source/sexp_node'
|
|
3
3
|
module Reek
|
4
4
|
module Source
|
5
5
|
module SexpExtensions
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
@name = name
|
6
|
+
# Base module for utility methods for argument nodes.
|
7
|
+
module ArgNodeBase
|
8
|
+
def name
|
9
|
+
children.first
|
11
10
|
end
|
12
11
|
|
12
|
+
# Other is a symbol?
|
13
13
|
def ==(other)
|
14
|
-
|
14
|
+
name == other
|
15
|
+
end
|
16
|
+
|
17
|
+
def marked_unused?
|
18
|
+
plain_name.start_with?('_')
|
19
|
+
end
|
20
|
+
|
21
|
+
def plain_name
|
22
|
+
name.to_s
|
15
23
|
end
|
16
24
|
|
17
25
|
def block?
|
18
|
-
|
26
|
+
false
|
27
|
+
end
|
28
|
+
|
29
|
+
def optional_argument?
|
30
|
+
false
|
19
31
|
end
|
20
32
|
|
21
33
|
def anonymous_splat?
|
22
|
-
|
34
|
+
false
|
23
35
|
end
|
36
|
+
end
|
24
37
|
|
25
|
-
|
26
|
-
|
38
|
+
# Utility methods for :arg nodes.
|
39
|
+
module ArgNode
|
40
|
+
include ArgNodeBase
|
41
|
+
end
|
42
|
+
|
43
|
+
# Utility methods for :optarg nodes.
|
44
|
+
module OptargNode
|
45
|
+
include ArgNodeBase
|
46
|
+
|
47
|
+
def optional_argument?
|
48
|
+
true
|
27
49
|
end
|
50
|
+
end
|
28
51
|
|
29
|
-
|
30
|
-
|
52
|
+
# Utility methods for :kwoptarg nodes.
|
53
|
+
module KwoptargNode
|
54
|
+
include ArgNodeBase
|
55
|
+
|
56
|
+
def optional_argument?
|
57
|
+
true
|
31
58
|
end
|
32
59
|
end
|
33
60
|
|
34
|
-
|
35
|
-
|
61
|
+
# Utility methods for :blockarg nodes.
|
62
|
+
module BlockargNode
|
63
|
+
include ArgNodeBase
|
64
|
+
def block?
|
65
|
+
true
|
66
|
+
end
|
67
|
+
end
|
36
68
|
|
37
|
-
|
38
|
-
|
69
|
+
# Utility methods for :restarg nodes.
|
70
|
+
module RestargNode
|
71
|
+
include ArgNodeBase
|
72
|
+
def anonymous_splat?
|
73
|
+
!name
|
39
74
|
end
|
40
75
|
end
|
41
76
|
|
42
|
-
# Utility methods for :
|
43
|
-
module
|
77
|
+
# Utility methods for :kwrestarg nodes.
|
78
|
+
module KwrestargNode
|
79
|
+
include ArgNodeBase
|
80
|
+
def anonymous_splat?
|
81
|
+
!name
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Base module for utility methods for :and and :or nodes.
|
86
|
+
module LogicOperatorBase
|
44
87
|
def condition() self[1] end
|
45
88
|
|
46
|
-
def
|
47
|
-
self[2]
|
89
|
+
def body_nodes(type, ignoring = [])
|
90
|
+
self[2].find_nodes type, ignoring
|
48
91
|
end
|
49
92
|
end
|
50
93
|
|
94
|
+
module AndNode
|
95
|
+
include LogicOperatorBase
|
96
|
+
end
|
97
|
+
|
98
|
+
# Utility methods for :or nodes
|
99
|
+
module OrNode
|
100
|
+
include LogicOperatorBase
|
101
|
+
end
|
102
|
+
|
103
|
+
# Utility methods for :attrasgn nodes
|
51
104
|
module AttrasgnNode
|
52
105
|
def args() self[3] end
|
53
106
|
end
|
@@ -56,20 +109,28 @@ module Reek
|
|
56
109
|
module CaseNode
|
57
110
|
def condition() self[1] end
|
58
111
|
|
59
|
-
def
|
60
|
-
|
112
|
+
def body_nodes(type, ignoring = [])
|
113
|
+
children[1..-1].compact.flat_map { |child| child.find_nodes(type, ignoring) }
|
114
|
+
end
|
115
|
+
|
116
|
+
def else_body
|
117
|
+
children.last
|
61
118
|
end
|
62
119
|
end
|
63
120
|
|
64
121
|
# Utility methods for :when nodes
|
65
122
|
module WhenNode
|
66
123
|
def condition_list
|
67
|
-
|
124
|
+
children[0..-2]
|
125
|
+
end
|
126
|
+
|
127
|
+
def body
|
128
|
+
children.last
|
68
129
|
end
|
69
130
|
end
|
70
131
|
|
71
|
-
# Utility methods for :
|
72
|
-
module
|
132
|
+
# Utility methods for :send nodes
|
133
|
+
module SendNode
|
73
134
|
def receiver() self[1] end
|
74
135
|
def method_name() self[2] end
|
75
136
|
def args() self[3..-1] end
|
@@ -83,34 +144,49 @@ module Reek
|
|
83
144
|
end
|
84
145
|
end
|
85
146
|
|
86
|
-
module
|
147
|
+
# Base module for utility methods for nodes representing variables.
|
148
|
+
module VariableBase
|
87
149
|
def name() self[1] end
|
88
150
|
end
|
89
151
|
|
152
|
+
# Utility methods for :cvar nodes.
|
153
|
+
module CvarNode
|
154
|
+
include VariableBase
|
155
|
+
end
|
156
|
+
|
90
157
|
CvasgnNode = CvarNode
|
91
158
|
CvdeclNode = CvarNode
|
92
159
|
|
160
|
+
# Utility methods for :ivar nodes.
|
161
|
+
module IvarNode
|
162
|
+
include VariableBase
|
163
|
+
end
|
164
|
+
|
165
|
+
# Utility methods for :ivasgn nodes.
|
166
|
+
module IvasgnNode
|
167
|
+
include VariableBase
|
168
|
+
end
|
169
|
+
|
93
170
|
module LvarNode
|
94
171
|
def var_name() self[1] end
|
95
172
|
end
|
96
173
|
|
97
|
-
module
|
174
|
+
# Base module for utility methods for :def and :defs nodes.
|
175
|
+
module MethodNodeBase
|
98
176
|
def arguments
|
99
|
-
|
177
|
+
parameters.reject(&:block?)
|
100
178
|
end
|
101
179
|
|
102
180
|
def arg_names
|
103
|
-
|
181
|
+
arguments.map(&:name)
|
104
182
|
end
|
105
183
|
|
106
184
|
def parameters
|
107
|
-
|
108
|
-
MethodParameter.new(param.is_a?(Sexp) ? param[1] : param)
|
109
|
-
end
|
185
|
+
argslist.children
|
110
186
|
end
|
111
187
|
|
112
188
|
def parameter_names
|
113
|
-
|
189
|
+
parameters.map(&:name)
|
114
190
|
end
|
115
191
|
|
116
192
|
def name_without_bang
|
@@ -120,16 +196,25 @@ module Reek
|
|
120
196
|
def ends_with_bang?
|
121
197
|
name[-1] == '!'
|
122
198
|
end
|
199
|
+
|
200
|
+
def body_nodes(types, ignoring = [])
|
201
|
+
if body
|
202
|
+
body.find_nodes(types, ignoring)
|
203
|
+
else
|
204
|
+
[]
|
205
|
+
end
|
206
|
+
end
|
123
207
|
end
|
124
208
|
|
125
|
-
|
209
|
+
# Utility methods for :def nodes.
|
210
|
+
module DefNode
|
126
211
|
def name() self[1] end
|
127
212
|
def argslist() self[2] end
|
128
213
|
|
129
214
|
def body
|
130
|
-
self[3
|
215
|
+
self[3]
|
131
216
|
end
|
132
|
-
include
|
217
|
+
include MethodNodeBase
|
133
218
|
def full_name(outer)
|
134
219
|
prefix = outer == '' ? '' : "#{outer}#"
|
135
220
|
"#{prefix}#{name}"
|
@@ -142,9 +227,10 @@ module Reek
|
|
142
227
|
def argslist() self[3] end
|
143
228
|
|
144
229
|
def body
|
145
|
-
self[4
|
230
|
+
self[4]
|
146
231
|
end
|
147
|
-
|
232
|
+
|
233
|
+
include MethodNodeBase
|
148
234
|
def full_name(outer)
|
149
235
|
prefix = outer == '' ? '' : "#{outer}#"
|
150
236
|
"#{prefix}#{SexpNode.format(receiver)}.#{name}"
|
@@ -155,12 +241,13 @@ module Reek
|
|
155
241
|
module IfNode
|
156
242
|
def condition() self[1] end
|
157
243
|
|
158
|
-
def
|
159
|
-
|
244
|
+
def body_nodes(type, ignoring = [])
|
245
|
+
children[1..-1].compact.flat_map { |child| child.find_nodes(type, ignoring) }
|
160
246
|
end
|
161
247
|
end
|
162
248
|
|
163
|
-
|
249
|
+
# Utility methods for :block nodes.
|
250
|
+
module BlockNode
|
164
251
|
def call() self[1] end
|
165
252
|
def args() self[2] end
|
166
253
|
def block() self[3] end
|
@@ -171,36 +258,23 @@ module Reek
|
|
171
258
|
end
|
172
259
|
end
|
173
260
|
|
174
|
-
# Utility methods for :nil nodes
|
175
|
-
module NilNode
|
176
|
-
def nil_node?
|
177
|
-
true
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
261
|
module LitNode
|
182
262
|
def value() self[1] end
|
183
263
|
end
|
184
264
|
|
185
|
-
|
186
|
-
|
187
|
-
self[2]
|
188
|
-
end
|
189
|
-
|
265
|
+
# Utility methods for :const nodes.
|
266
|
+
module ConstNode
|
190
267
|
def simple_name
|
191
|
-
|
192
|
-
name.simple_name
|
193
|
-
else
|
194
|
-
name
|
195
|
-
end
|
268
|
+
children.last
|
196
269
|
end
|
197
270
|
end
|
198
271
|
|
272
|
+
# Utility methods for :module nodes.
|
199
273
|
module ModuleNode
|
200
274
|
def name() self[1] end
|
201
275
|
|
202
276
|
def simple_name
|
203
|
-
name.is_a?(
|
277
|
+
name.is_a?(AST::Node) ? name.simple_name : name
|
204
278
|
end
|
205
279
|
|
206
280
|
def full_name(outer)
|