Class: RubyMaat::Analysis::LogicalCoupling

Inherits:
BaseAnalysis show all
Defined in:
lib/ruby_maat/analysis/logical_coupling.rb

Overview

Logical coupling analysis - finds modules that tend to change together This identifies hidden dependencies between code modules

Instance Method Summary collapse

Instance Method Details

#analyze(dataset, options = {}) ⇒ Object



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
# File 'lib/ruby_maat/analysis/logical_coupling.rb', line 8

def analyze(dataset, options = {})
  min_revs = options[:min_revs] || 1
  min_shared_revs = options[:min_shared_revs] || 1
  min_coupling = options[:min_coupling] || 1
  max_coupling = options[:max_coupling] || 100
  max_changeset_size = options[:max_changeset_size] || 30
  verbose_results = options[:verbose_results] || false

  # Get co-changing entities by revision
  co_changing_entities = get_co_changing_entities(dataset, max_changeset_size)

  # Calculate coupling frequencies
  coupling_frequencies = calculate_coupling_frequencies(co_changing_entities)

  # Calculate revision counts per entity
  entity_revisions = calculate_entity_revisions(dataset)

  # Generate coupling results
  results = []

  coupling_frequencies.each do |(entity1, entity2), shared_revs|
    entity1_revs = entity_revisions[entity1] || 0
    entity2_revs = entity_revisions[entity2] || 0

    avg_revs = average(entity1_revs, entity2_revs)
    coupling_degree = percentage(shared_revs, avg_revs)

    # Apply thresholds
    next unless avg_revs >= min_revs
    next unless shared_revs >= min_shared_revs
    next unless coupling_degree >= min_coupling
    next unless coupling_degree <= max_coupling

    result = {
      entity: entity1,
      coupled: entity2,
      degree: coupling_degree,
      "average-revs": avg_revs.ceil
    }

    if verbose_results
      result.merge!(
        "first-entity-revisions": entity1_revs,
        "second-entity-revisions": entity2_revs,
        "shared-revisions": shared_revs
      )
    end

    results << result
  end

  # Sort by coupling degree (descending), then by average revisions (descending)
  results.sort! do |a, b|
    comparison = b[:degree] <=> a[:degree]
    comparison.zero? ? b[:"average-revs"] <=> a[:"average-revs"] : comparison
  end

  columns = [:entity, :coupled, :degree, :"average-revs"]
  columns += [:"first-entity-revisions", :"second-entity-revisions", :"shared-revisions"] if verbose_results

  to_csv_data(results, columns)
end