Class: Reek::Context::CodeContext

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Enumerable
Defined in:
lib/reek/context/code_context.rb

Overview

Superclass for all types of source code context. Each instance represents a code element of some kind, and each provides behaviour relevant to that code element. CodeContexts form a tree in the same way the code does, with each context holding a reference to a unique outer context.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(exp) ⇒ CodeContext

Initializes a new CodeContext.

Parameters:



29
30
31
32
33
34
# File 'lib/reek/context/code_context.rb', line 29

def initialize(exp)
  @exp                = exp
  @children           = []
  @statement_counter  = StatementCounter.new
  @refs               = AST::ObjectRefs.new
end

Instance Attribute Details

#childrenObject (readonly)

Returns the value of attribute children.



24
25
26
# File 'lib/reek/context/code_context.rb', line 24

def children
  @children
end

#expObject (readonly)

Returns the value of attribute exp.



24
25
26
# File 'lib/reek/context/code_context.rb', line 24

def exp
  @exp
end

#parentObject (readonly)

Returns the value of attribute parent.



24
25
26
# File 'lib/reek/context/code_context.rb', line 24

def parent
  @parent
end

#refsObject (readonly, private)

Returns the value of attribute refs.



166
167
168
# File 'lib/reek/context/code_context.rb', line 166

def refs
  @refs
end

#statement_counterObject (readonly)

Returns the value of attribute statement_counter.



24
25
26
# File 'lib/reek/context/code_context.rb', line 24

def statement_counter
  @statement_counter
end

Instance Method Details

#append_child_context(child) ⇒ Object

Register a context as a child context of this context. This is generally used by a child context to register itself with its parent.

Parameters:

  • child (CodeContext)

    the child context to register



108
109
110
111
# File 'lib/reek/context/code_context.rb', line 108

def append_child_context(child)
  children << child
  self
end

#apply_current_visibility(_current_visibility) ⇒ Object



160
161
162
# File 'lib/reek/context/code_context.rb', line 160

def apply_current_visibility(_current_visibility)
  # Nothing to do by default
end

#config_for(detector_class) ⇒ Object



143
144
145
146
# File 'lib/reek/context/code_context.rb', line 143

def config_for(detector_class)
  parent_config_for(detector_class).merge(
    configuration_via_code_commment[detector_class.smell_type] || {})
end

#configuration_via_code_commmentObject (private)



168
169
170
171
172
# File 'lib/reek/context/code_context.rb', line 168

def configuration_via_code_commment
  @configuration_via_code_commment ||= CodeComment.new(comment: full_comment,
                                                       line: exp.line,
                                                       source: exp.source).config
end

#each { ... } ⇒ Enumerator

Iterate over ‘self` and child contexts. The main difference (among others) to `local_nodes` is that we are traversing `CodeContexts` here, not AST nodes (see `Reek::AST::Node`).

Yields:

  • block that is executed for every node.

Returns:

  • (Enumerator)


53
54
55
56
57
58
59
60
# File 'lib/reek/context/code_context.rb', line 53

def each(&block)
  return enum_for(:each) unless block

  yield self
  children.each do |child|
    child.each(&block)
  end
end

#full_commentObject (private)



174
175
176
# File 'lib/reek/context/code_context.rb', line 174

def full_comment
  exp.full_comment || ''
end

#full_nameObject



139
140
141
# File 'lib/reek/context/code_context.rb', line 139

def full_name
  exp.full_name(parent ? parent.full_name : '')
end

#instance_method?Boolean

Returns:

  • (Boolean)


156
157
158
# File 'lib/reek/context/code_context.rb', line 156

def instance_method?
  false
end

#local_nodes(type, ignored = []) { ... } ⇒ Object

Iterate over each AST node (see ‘Reek::AST::Node`) of a given type for the current expression.

Parameters:

  • type (Symbol)

    the type of the nodes we are looking for, e.g. :defs.

Yields:

  • block that is executed for every node.



41
42
43
44
# File 'lib/reek/context/code_context.rb', line 41

def local_nodes(type, ignored = [], &blk)
  ignored |= [:class, :module]
  exp.each_node(type, ignored, &blk)
end

#matches?(candidates) ⇒ Boolean

Returns:

  • (Boolean)


131
132
133
134
135
136
137
# File 'lib/reek/context/code_context.rb', line 131

def matches?(candidates)
  my_fq_name = full_name
  candidates.any? do |candidate|
    candidate = Regexp.quote(candidate) if candidate.is_a?(String)
    /#{candidate}/ =~ my_fq_name
  end
end

#number_of_statementsObject



148
149
150
# File 'lib/reek/context/code_context.rb', line 148

def number_of_statements
  statement_counter.value
end

#parent_config_for(detector_class) ⇒ Object (private)



178
179
180
# File 'lib/reek/context/code_context.rb', line 178

def parent_config_for(detector_class)
  parent ? parent.config_for(detector_class) : {}
end

#record_call_to(exp) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
# File 'lib/reek/context/code_context.rb', line 115

def record_call_to(exp)
  receiver = exp.receiver
  type = receiver ? receiver.type : :self
  line = exp.line
  case type
  when :lvar, :lvasgn
    refs.record_reference(name: receiver.name, line: line) unless exp.object_creation_call?
  when :self
    refs.record_reference(name: :self, line: line)
  end
end

#record_use_of_selfObject



127
128
129
# File 'lib/reek/context/code_context.rb', line 127

def record_use_of_self
  refs.record_reference(name: :self)
end

#register_with_parent(parent) ⇒ Object

Link the present context to its parent.

For example, given the following code:

class Omg
  def foo(x)
    puts x
  end
end

The Reek::ContextBuilder object first instantiates a RootContext, which has no parent.

Next, it instantiates a ModuleContext, with exp looking like this:

(class
  (const nil :Omg) nil
  (def :foo
    (args
      (arg :x))
    (send nil :puts
      (lvar :x))))

It will then call #register_with_parent on the ModuleContext, passing in the parent RootContext.

Finally, Reek::ContextBuilder will instantiate a MethodContext. This time, exp is:

(def :foo
  (args
    (arg :x))
  (send nil :puts
    (lvar :x)))

Then it will call #register_with_parent on the MethodContext, passing in the parent ModuleContext.

Parameters:

  • parent (Reek::AST::Node)

    The parent context of the code described by this context



100
101
102
# File 'lib/reek/context/code_context.rb', line 100

def register_with_parent(parent)
  @parent = parent.append_child_context(self) if parent
end

#singleton_method?Boolean

Returns:

  • (Boolean)


152
153
154
# File 'lib/reek/context/code_context.rb', line 152

def singleton_method?
  false
end