-
Notifications
You must be signed in to change notification settings - Fork 279
/
instance_variable_assumption.rb
71 lines (58 loc) · 1.77 KB
/
instance_variable_assumption.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# frozen_string_literal: true
require_relative 'base_detector'
require_relative 'smell_warning'
module Reek
module SmellDetectors
#
# The +InstanceVariableAssumption+ class is responsible for
# detecting directly access of instance variables in a class
# that does not define them in its initialize method.
#
class InstanceVariableAssumption < BaseDetector
def self.contexts
[:class]
end
# Checks +klass+ for instance
# variables assumptions.
#
# @return [Array<SmellWarning>]
#
def sniff(ctx)
method_expressions = ctx.node_instance_methods
assumptions = (variables_from_context(method_expressions) -
variables_from_initialize(method_expressions)).uniq
assumptions.map do |assumption|
build_smell_warning(ctx, assumption)
end
end
private
def build_smell_warning(ctx, assumption)
message = "assumes too much for instance variable '#{assumption}'"
smell_warning(
context: ctx,
lines: [ctx.exp.line],
message: message,
parameters: { assumption: assumption.to_s })
end
# :reek:UtilityFunction
def variables_from_initialize(instance_methods)
initialize_exp = instance_methods.detect do |method|
method.name == :initialize
end
return [] unless initialize_exp
initialize_exp.each_node(:ivasgn).map(&:name)
end
def variables_from_context(instance_methods)
instance_methods.map do |method|
method.find_nodes(assumption_nodes, ignored_nodes).map(&:name)
end.flatten
end
def assumption_nodes
[:ivar]
end
def ignored_nodes
[:or_asgn]
end
end
end
end