hashira 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +86 -0
- data/README.md +90 -30
- data/lib/hashira/analysis/finding.rb +2 -2
- data/lib/hashira/analysis/syntax.rb +6 -2
- data/lib/hashira/churn.rb +1 -1
- data/lib/hashira/ci/ratchet.rb +5 -9
- data/lib/hashira/cli/command_line.rb +10 -49
- data/lib/hashira/cli/fail_on.rb +9 -5
- data/lib/hashira/cli/flag.rb +29 -0
- data/lib/hashira/cli/flags.rb +50 -0
- data/lib/hashira/cli/format.rb +13 -0
- data/lib/hashira/cli/options.rb +2 -0
- data/lib/hashira/cli/run.rb +8 -4
- data/lib/hashira/cli/usage.rb +20 -21
- data/lib/hashira/cli.rb +1 -1
- data/lib/hashira/complexity/boolean_run.rb +5 -3
- data/lib/hashira/complexity/cognitive_score.rb +21 -14
- data/lib/hashira/complexity/if_chain.rb +14 -14
- data/lib/hashira/complexity/method_finding.rb +4 -19
- data/lib/hashira/complexity/rescue_scan.rb +9 -9
- data/lib/hashira/complexity/{analyzer.rb → scores.rb} +6 -5
- data/lib/hashira/coupling/audiences.rb +49 -0
- data/lib/hashira/{analysis → coupling}/catalog.rb +3 -3
- data/lib/hashira/{analysis → coupling}/census.rb +17 -8
- data/lib/hashira/{analysis → coupling}/constant_registry.rb +11 -6
- data/lib/hashira/coupling/cycle_findings.rb +31 -0
- data/lib/hashira/{analysis → coupling}/cycle_search.rb +1 -1
- data/lib/hashira/{analysis → coupling}/cycles.rb +2 -2
- data/lib/hashira/{analysis → coupling}/definition.rb +6 -2
- data/lib/hashira/{analysis → coupling}/definitions.rb +5 -2
- data/lib/hashira/{analysis → coupling}/edge.rb +1 -1
- data/lib/hashira/{analysis → coupling}/edge_map.rb +10 -10
- data/lib/hashira/{analysis → coupling}/folder_placement.rb +2 -2
- data/lib/hashira/{analysis → coupling}/folding.rb +4 -2
- data/lib/hashira/{analysis → coupling}/graph.rb +18 -8
- data/lib/hashira/{analysis → coupling}/metric.rb +1 -1
- data/lib/hashira/coupling/mixed_audience_findings.rb +32 -0
- data/lib/hashira/{analysis → coupling}/namespace_placement.rb +3 -3
- data/lib/hashira/{analysis → coupling}/namespace_prefix.rb +1 -1
- data/lib/hashira/{analysis → coupling}/naming.rb +2 -2
- data/lib/hashira/{analysis → coupling}/no_folding.rb +1 -1
- data/lib/hashira/{analysis → coupling}/placement.rb +3 -3
- data/lib/hashira/coupling/references.rb +55 -0
- data/lib/hashira/coupling/report.rb +28 -0
- data/lib/hashira/coupling/roll_call.rb +45 -0
- data/lib/hashira/coupling/roll_call_findings.rb +30 -0
- data/lib/hashira/{analysis → coupling}/roster.rb +6 -2
- data/lib/hashira/{analysis → coupling}/rule.rb +1 -1
- data/lib/hashira/{analysis/resolver.rb → coupling/scope.rb} +7 -3
- data/lib/hashira/{analysis → coupling}/sdp_check.rb +1 -1
- data/lib/hashira/coupling/sdp_violation_findings.rb +25 -0
- data/lib/hashira/coupling/wide_edge_findings.rb +25 -0
- data/lib/hashira/coupling/words.rb +29 -0
- data/lib/hashira/diagram/{renderer.rb → source.rb} +2 -2
- data/lib/hashira/duplication/{analyzer.rb → clones.rb} +3 -3
- data/lib/hashira/duplication/{clusterer.rb → clusters.rb} +3 -3
- data/lib/hashira/duplication/delta.rb +6 -14
- data/lib/hashira/duplication/duplication_finding.rb +8 -10
- data/lib/hashira/duplication/{extractor.rb → harvest.rb} +1 -1
- data/lib/hashira/duplication/sequence.rb +3 -1
- data/lib/hashira/duplication/similarity.rb +5 -1
- data/lib/hashira/duplication/variance.rb +3 -3
- data/lib/hashira/hotspots/rollup.rb +1 -1
- data/lib/hashira/pipeline.rb +18 -10
- data/lib/hashira/report/complexity_table.rb +1 -1
- data/lib/hashira/report/finding_lines.rb +1 -1
- data/lib/hashira/report/json.rb +5 -3
- data/lib/hashira/report/phrases.rb +98 -0
- data/lib/hashira/report/smell_phrases.rb +68 -0
- data/lib/hashira/smells/census.rb +32 -0
- data/lib/hashira/smells/check.rb +34 -0
- data/lib/hashira/smells/conditions.rb +44 -0
- data/lib/hashira/smells/contexts.rb +64 -0
- data/lib/hashira/smells/control_parameter.rb +22 -0
- data/lib/hashira/smells/data_clump.rb +32 -0
- data/lib/hashira/smells/duplicate_method_call.rb +54 -0
- data/lib/hashira/smells/feature_envy.rb +17 -0
- data/lib/hashira/smells/instance_variable_assumption.rb +46 -0
- data/lib/hashira/smells/manual_dispatch.rb +16 -0
- data/lib/hashira/smells/module_initialize.rb +11 -0
- data/lib/hashira/smells/nil_check.rb +32 -0
- data/lib/hashira/smells/param_check.rb +51 -0
- data/lib/hashira/smells/refs.rb +53 -0
- data/lib/hashira/smells/repeated_conditional.rb +31 -0
- data/lib/hashira/smells/report.rb +34 -0
- data/lib/hashira/smells/scope.rb +29 -0
- data/lib/hashira/smells/too_many_instance_variables.rb +26 -0
- data/lib/hashira/smells/utility_function.rb +13 -0
- data/lib/hashira/smells/visibility.rb +64 -0
- data/lib/hashira/version.rb +1 -1
- data/lib/hashira.rb +68 -30
- metadata +63 -31
- data/lib/hashira/analysis/cycle_findings.rb +0 -38
- data/lib/hashira/analysis/references.rb +0 -40
- data/lib/hashira/analysis/sdp_violation_findings.rb +0 -29
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "rule"
|
|
4
|
-
|
|
5
|
-
class Hashira::Analysis::CycleFindings < Hashira::Analysis::Rule
|
|
6
|
-
KIND = "cycle"
|
|
7
|
-
|
|
8
|
-
def list
|
|
9
|
-
loops.map { entry(it) }
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
private
|
|
13
|
-
|
|
14
|
-
def loops
|
|
15
|
-
cycles = graph.cycles
|
|
16
|
-
graph.packages.select { cycles.through?(it) }.sort.map { cycles.path(it) }.uniq { it[..-2].sort }
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def entry(path)
|
|
20
|
-
package = path.first
|
|
21
|
-
finding(
|
|
22
|
-
package:, cycle: path, evidence: evidence(path),
|
|
23
|
-
message: message(package, path, graph.cycles.weakest(path))
|
|
24
|
-
)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def message(package, path, weak_edge)
|
|
28
|
-
from, to = weak_edge
|
|
29
|
-
weight = graph.weight(from, to)
|
|
30
|
-
"#{package} can reach itself: #{path.join(" -> ")} — any change may ripple back " \
|
|
31
|
-
"around. The lightest edge on this cycle is #{from} -> #{to} " \
|
|
32
|
-
"(#{weight} ref#{"s" unless weight == 1})."
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def evidence(path)
|
|
36
|
-
path.each_cons(2).flat_map { |from, to| graph.evidence(from, to).to_a.first(2) }
|
|
37
|
-
end
|
|
38
|
-
end
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "prism"
|
|
4
|
-
|
|
5
|
-
module Hashira
|
|
6
|
-
module Analysis
|
|
7
|
-
module References
|
|
8
|
-
module_function
|
|
9
|
-
|
|
10
|
-
def list(tree)
|
|
11
|
-
sightings(tree).map(&:first)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def sightings(tree, roots = nil)
|
|
15
|
-
[].tap { collect(tree, [], it, roots) }
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def collect(node, nesting, accumulator, roots, home = nesting)
|
|
19
|
-
return unless node
|
|
20
|
-
return accumulator << sighting(node, nesting, home) if constant?(node)
|
|
21
|
-
return enter(node, nesting, accumulator, roots) if definition?(node)
|
|
22
|
-
node.compact_child_nodes.each { collect(it, nesting, accumulator, roots, home) }
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def sighting(node, nesting, home)
|
|
26
|
-
[Syntax.segments(node), node.location.start_line, Syntax.cbase?(node) ? nil : nesting, home]
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def constant?(node) = node.is_a?(Prism::ConstantPathNode) || node.is_a?(Prism::ConstantReadNode)
|
|
30
|
-
|
|
31
|
-
def definition?(node) = node.is_a?(Prism::ClassNode) || node.is_a?(Prism::ModuleNode)
|
|
32
|
-
|
|
33
|
-
def enter(node, nesting, accumulator, roots)
|
|
34
|
-
opened = nesting + [Syntax.anchor(nesting, Syntax.segments(node.constant_path), roots)]
|
|
35
|
-
collect(node.superclass, nesting, accumulator, roots, opened) if node.is_a?(Prism::ClassNode)
|
|
36
|
-
collect(node.body, opened, accumulator, roots)
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "rule"
|
|
4
|
-
|
|
5
|
-
class Hashira::Analysis::SdpViolationFindings < Hashira::Analysis::Rule
|
|
6
|
-
KIND = "sdp_violation"
|
|
7
|
-
|
|
8
|
-
def list
|
|
9
|
-
ranked.map { |from, to| violation(from, to) }
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
private
|
|
13
|
-
|
|
14
|
-
def ranked = graph.violations.sort_by { |from, to| instability(from) - instability(to) }
|
|
15
|
-
|
|
16
|
-
def violation(from, to)
|
|
17
|
-
finding(package: from, evidence: graph.evidence(from, to).to_a.first(5), message: message(from, to))
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def message(from, to)
|
|
21
|
-
"#{from} (I=#{label(from)}) depends on the LESS stable #{to} " \
|
|
22
|
-
"(I=#{label(to)}) — churn in #{to} will force churn in #{from}. " \
|
|
23
|
-
"Invert the edge or extract the stable part of #{to} that #{from} needs."
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def instability(package) = metrics[package].instability
|
|
27
|
-
|
|
28
|
-
def label(package) = format("%.2f", instability(package))
|
|
29
|
-
end
|