Class: ReekAnalyzer

Inherits:
Object
  • Object
show all
Includes:
ScoringStrategies
Defined in:
lib/base/reek_analyzer.rb

Constant Summary collapse

REEK_ISSUE_INFO =
{
  'Uncommunicative Name' =>
    {'link' => 'http://wiki.github.com/kevinrutherford/reek/uncommunicative-name',
     'info' => 'An Uncommunicative Name is a name that doesn’t communicate its intent well enough.'},
  'Class Variable' =>
    {'link' => 'http://wiki.github.com/kevinrutherford/reek/class-variable',
     'info' => 'Class variables form part of the global runtime state, and as such make it ' +
               'easy for one part of the system to accidentally or inadvertently depend on ' +
               'another part of the system.'},
  'Duplication' =>
    {'link' =>'http://wiki.github.com/kevinrutherford/reek/duplication',
     'info' => 'Duplication occurs when two fragments of code look nearly identical, or when ' +
               'two fragments of code have nearly identical effects at some conceptual level.'},
  'Low Cohesion' =>
    {'link' => 'http://en.wikipedia.org/wiki/Cohesion_(computer_science)',
     'info' => 'Low cohesion is associated with undesirable traits such as being difficult to ' +
               'maintain, difficult to test, difficult to reuse, and even difficult to understand.'},
  'Nested Iterators' =>
    {'link' =>'http://wiki.github.com/kevinrutherford/reek/nested-iterators',
     'info' => 'Nested Iterator occurs when a block contains another block.'},
  'Control Couple' =>
    {'link' =>'http://wiki.github.com/kevinrutherford/reek/control-couple',
     'info' => 'Control coupling occurs when a method or block checks the value of a parameter in ' +
               'order to decide which execution path to take. The offending parameter is often called a “Control Couple”.'},
  'Irresponsible Module' =>
    {'link' =>'http://wiki.github.com/kevinrutherford/reek/irresponsible-module',
     'info' => 'Classes and modules are the units of reuse and release. It is therefore considered ' +
               'good practice to annotate every class and module with a brief comment outlining its responsibilities.'},
  'Long Parameter List' =>
    {'link' =>'http://wiki.github.com/kevinrutherford/reek/long-parameter-list',
     'info' => 'A Long Parameter List occurs when a method has more than one or two parameters, ' +
               'or when a method yields more than one or two objects to an associated block.'},
  'Data Clump' =>
    {'link' =>'http://wiki.github.com/kevinrutherford/reek/data-clump',
     'info' => 'In general, a Data Clump occurs when the same two or three items frequently appear ' +
               'together in classes and parameter lists, or when a group of instance variable names ' +
               'start or end with similar substrings.'},
  'Simulated Polymorphism' =>
    {'link' =>'http://wiki.github.com/kevinrutherford/reek/simulated-polymorphism',
     'info' => 'Simulated Polymorphism occurs when, code uses a case statement (especially on a ' +
               'type field) or code uses instance_of?, kind_of?, is_a?, or === to decide what code to execute'},
  'Large Class' =>
    {'link' =>'http://wiki.github.com/kevinrutherford/reek/large-class',
     'info' => 'A Large Class is a class or module that has a large number of instance variables, ' +
               'methods or lines of code in any one piece of its specification.'},
  'Long Method' =>
    {'link' =>'http://wiki.github.com/kevinrutherford/reek/long-method',
     'info' => 'Long methods can be hard to read and understand. They often are harder to test and ' +
               'maintain as well, which can lead to buggier code.'},
  'Feature Envy' =>
    {'link' =>'http://wiki.github.com/kevinrutherford/reek/feature-envy',
     'info' => 'Feature Envy occurs when a code fragment references another object more often than ' +
               'it references itself, or when several clients do the same series of manipulations ' +
               'on a particular type of object.'},
  'Utility Function' =>
    {'link' =>'http://wiki.github.com/kevinrutherford/reek/utility-function',
     'info' => 'A Utility Function is any instance method that has no dependency on the state of the ' +
               'instance. It reduces the code’s ability to communicate intent. Code that “belongs” on ' +
               'one class but which is located in another can be hard to find.'},
  'Attribute' =>
    {'link' => 'http://wiki.github.com/kevinrutherford/reek/attribute',
     'info' => 'A class that publishes a getter or setter for an instance variable invites client ' +
               'classes to become too intimate with its inner workings, and in particular with its ' +
               'representation of state.'}
}
COLUMNS =

Note that in practice, the prefix reek__ is appended to each one This was a partially implemented idea to avoid column name collisions but it is only done in the ReekAnalyzer

%w{type_name message value value_description comparable_message}

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ScoringStrategies

#average, #identity, #percentile, #present, #sum

Class Method Details



77
78
79
# File 'lib/base/reek_analyzer.rb', line 77

def self.issue_link(issue)
  REEK_ISSUE_INFO[issue]
end

.numeric_smell?(type) ⇒ Boolean

Returns:

  • (Boolean)


126
127
128
# File 'lib/base/reek_analyzer.rb', line 126

def self.numeric_smell?(type)
  ["Large Class", "Long Method", "Long Parameter List"].include?(type)
end

Instance Method Details

#columnsObject



81
82
83
# File 'lib/base/reek_analyzer.rb', line 81

def columns
  COLUMNS.map{|column| "#{name}__#{column}"}
end

#generate_records(data, table) ⇒ Object



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/base/reek_analyzer.rb', line 101

def generate_records(data, table)
  return if data==nil
  data[:matches].each do |match|
    file_path = match[:file_path]
    match[:code_smells].each do |smell|
      location = MetricFu::Location.for(smell[:method])
      smell_type = smell[:type]
      message = smell[:message]
      table << {
        "metric" => name, # important
        "file_path" => file_path, # important
        # NOTE: ReekAnalyzer is currently different than other analyzers with regard
        # to column name. Note the COLUMNS constant and #columns method
        "reek__message" => message,
        "reek__type_name" => smell_type,
        "reek__value" => parse_value(message),
        "reek__value_description" => build_value_description(smell_type, message),
        "reek__comparable_message" => comparable_message(smell_type, message),
        "class_name" => location.class_name, # important
        "method_name" => location.method_name, # important
      }
    end
  end
end

#map(row) ⇒ Object



89
90
91
# File 'lib/base/reek_analyzer.rb', line 89

def map(row)
  ScoringStrategies.present(row)
end

#nameObject



85
86
87
# File 'lib/base/reek_analyzer.rb', line 85

def name
  :reek
end

#reduce(scores) ⇒ Object



93
94
95
# File 'lib/base/reek_analyzer.rb', line 93

def reduce(scores)
  ScoringStrategies.sum(scores)
end

#score(metric_ranking, item) ⇒ Object



97
98
99
# File 'lib/base/reek_analyzer.rb', line 97

def score(metric_ranking, item)
  ScoringStrategies.percentile(metric_ranking, item) 
end