Class: Solidarity::SolidEvaluator

Inherits:
Object
  • Object
show all
Defined in:
lib/solidarity/solid_evaluator.rb

Instance Method Summary collapse

Constructor Details

#initialize(graph) ⇒ SolidEvaluator

Returns a new instance of SolidEvaluator.



3
4
5
# File 'lib/solidarity/solid_evaluator.rb', line 3

def initialize(graph)
  @graph = graph
end

Instance Method Details

#evaluate_allObject



64
65
66
67
68
69
70
71
72
# File 'lib/solidarity/solid_evaluator.rb', line 64

def evaluate_all
  { 
    srp: evaluate_srp,
    ocp: evaluate_ocp,
    lsp: evaluate_lsp,
    isp: evaluate_isp,
    dip: evaluate_dip
  }
end

#evaluate_dipObject



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/solidarity/solid_evaluator.rb', line 43

def evaluate_dip
  # Dependency Inversion Principle (DIP)
  # Heuristic: High-level modules should depend on abstractions, not concretions.
  # We can look for dependencies from concrete classes to other concrete classes as a potential violation.
  # This requires distinguishing between abstract/concrete classes, which railroady doesn't explicitly provide.
  dip_score = 100
  # For now, a very simplistic view: count edges between concrete classes.
  # This needs significant refinement to be meaningful.
  # concrete_to_concrete_dependencies = 0 # Placeholder
  # @graph.edges.each do |edge|
  #   source_node = @graph.find_node(edge.source)
  #   target_node = @graph.find_node(edge.target)
  #   if source_node&.type == :class && target_node&.type == :class # Assuming :class is concrete
  #     concrete_to_concrete_dependencies += 1
  #   end
  # end
  # dip_score = (100 - concrete_to_concrete_dependencies * 5).clamp(0, 100)

  { score: dip_score, details: "DIP assessment requires distinguishing abstract from concrete classes." }
end

#evaluate_ispObject



36
37
38
39
40
41
# File 'lib/solidarity/solid_evaluator.rb', line 36

def evaluate_isp
  # Interface Segregation Principle (ISP)
  # Heuristic: Could look for modules included by many classes but with few used methods by each class.
  # Requires method-level analysis, which is not available from railroady's DOT output.
  { score: 70, details: "ISP is difficult to assess without method-level dependency analysis." }
end

#evaluate_lspObject



29
30
31
32
33
34
# File 'lib/solidarity/solid_evaluator.rb', line 29

def evaluate_lsp
  # Liskov Substitution Principle (LSP)
  # Very hard to evaluate statically from a dependency graph. Requires behavioral analysis.
  # Placeholder: Assume a perfectly flat hierarchy (no deep inheritance) is better, but this is a very weak heuristic.
  { score: 70, details: "LSP is difficult to assess statically from a dependency graph." }
end

#evaluate_ocpObject



19
20
21
22
23
24
25
26
27
# File 'lib/solidarity/solid_evaluator.rb', line 19

def evaluate_ocp
  # Open/Closed Principle (OCP)
  # Heuristic: Presence of inheritance/module inclusions. Hard to measure purely from dependency graph.
  # A higher number of classes participating in inheritance/module inclusion might suggest better OCP.
  ocp_score = 0
  inheriting_nodes = @graph.edges.count { |edge| edge.type == :inheritance || edge.type == :includes }
  ocp_score = (inheriting_nodes > @graph.nodes.count / 4) ? 100 : (inheriting_nodes * 100.0 / (@graph.nodes.count / 4)).clamp(0, 100)
  { score: ocp_score, details: "Number of inheritance/inclusion relationships: #{inheriting_nodes}" }
end

#evaluate_srpObject



7
8
9
10
11
12
13
14
15
16
17
# File 'lib/solidarity/solid_evaluator.rb', line 7

def evaluate_srp
  # Single Responsibility Principle (SRP)
  # Heuristic: High outgoing edges might indicate multiple responsibilities.
  # For a more accurate measure, we'd need to analyze method calls/dependencies within each class.
  srp_scores = {}
  @graph.nodes.each do |node|
    outgoing_count = @graph.outgoing_edges(node.name).count
    srp_scores[node.name] = outgoing_count < 5 ? 100 : (100 - (outgoing_count - 5) * 10).clamp(0, 100)
  end
  { score: srp_scores.values.sum / srp_scores.size.to_f, details: srp_scores }
end