Class: Reek::Smells::UtilityFunction

Inherits:
SmellDetector show all
Defined in:
lib/reek/smells/utility_function.rb

Overview

A Utility Function is any instance method that has no dependency on the state of the instance.

Currently UtilityFunction will warn about any method that:

  • is non-empty, and

  • does not override an inherited method, and

  • calls at least one method on another object, and

  • doesn't use any of self's instance variables, and

  • doesn't use any of self's methods

A Utility Function often arises because it must manipulate other objects (usually its arguments) to get them into a useful form; one force preventing them (the arguments) doing this themselves is that the common knowledge lives outside the arguments, or the arguments are of too basic a type to justify extending that type. Therefore there must be something which 'knows' about the contents or purposes of the arguments. That thing would have to be more than just a basic type, because the basic types are either containers which don't know about their contents, or they are single objects which can't capture their relationship with their fellows of the same type. So, this thing with the extra knowledge should be reified into a class, and the utility method will most likely belong there.

Constant Summary collapse

HELPER_CALLS_LIMIT_KEY =

The name of the config field that sets the maximum number of calls permitted within a helper method. Any method with more than this number of method calls on other objects will be considered a candidate Utility Function.

'max_helper_calls'
DEFAULT_HELPER_CALLS_LIMIT =
1

Constants inherited from SmellDetector

SmellDetector::DEFAULT_EXCLUDE_SET, SmellDetector::EXCLUDE_KEY

Instance Attribute Summary

Attributes inherited from SmellDetector

#smell_category, #smell_type, #smells_found, #source

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from SmellDetector

#config_for, #configure_with, default_smell_category, #enabled?, #enabled_for?, #examine, #exception?, #initialize, #register, #report_on, smell_type, #value

Constructor Details

This class inherits a constructor from Reek::Smells::SmellDetector

Class Method Details

.contextsObject

:nodoc:


48
49
50
# File 'lib/reek/smells/utility_function.rb', line 48

def contexts      # :nodoc:
  [:def]
end

.default_configObject


52
53
54
# File 'lib/reek/smells/utility_function.rb', line 52

def default_config
  super.merge(HELPER_CALLS_LIMIT_KEY => DEFAULT_HELPER_CALLS_LIMIT)
end

.smell_categoryObject


43
44
45
# File 'lib/reek/smells/utility_function.rb', line 43

def self.smell_category
  'LowCohesion'
end

Instance Method Details

#examine_context(method_ctx) ⇒ Array<SmellWarning>

Checks whether the given method is a utility function.

Returns:


62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/reek/smells/utility_function.rb', line 62

def examine_context(method_ctx)
  return [] if method_ctx.num_statements == 0
  return [] if depends_on_instance?(method_ctx.exp)
  return [] if num_helper_methods(method_ctx) <= value(HELPER_CALLS_LIMIT_KEY,
                                                       method_ctx,
                                                       DEFAULT_HELPER_CALLS_LIMIT)

  [SmellWarning.new(self,
                    context: method_ctx.full_name,
                    lines: [method_ctx.exp.line],
                    message: "doesn't depend on instance state")]
end