tina4ruby 3.13.90 → 3.13.91

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bcacb51cc9aec287d69bb3d18d0d5736d4e72fd9f25e4b28145af7a8c3e69245
4
- data.tar.gz: 5cbe29c5b764594b014c386ab1df06e93d67cc8ad79ee321a2d5c03c5383cc73
3
+ metadata.gz: 3df8f30ccbf4fc6d984ec4af8fa3262045b16ac1f05c7516f6a6818691fad547
4
+ data.tar.gz: 1236689bdee9821f1994bc27d1a69684fd312cc774f33a2bba6b10fa57bd86d8
5
5
  SHA512:
6
- metadata.gz: b01320730d284fb8f8babdefdcd6c26fc3a4ae29e5ee3a2f700320276a1d211d5d3e88fc0c8de4e1722af814a60333a4056041428fd387ec70446b50f066a208
7
- data.tar.gz: 32077d83e0b6c457656915818683193f8a4ef9b3dfd505e3035d97f7b835b979d29a536f6993aa85d987138e9fe1aa229d1d002fec769879fb0c4ca1dbaef2fa
6
+ metadata.gz: c51b11ed1b2c9361c162ab6d54f999381d13b8b6be74f4cd94ebfa0d72492f0805f9428e9080ee06b2eb6efd52dc5fd72e1a9d073743d5ad03ec9582c3894b8b
7
+ data.tar.gz: 4f8265ec9da1f6bd427ed844d808e4e2c67ee55ec934a0d24ea37f40b1a88861ce86bc9c09b162cd534f6d879825ed31a05e0baf32e73322ea8584097d9b8346
data/lib/tina4/metrics.rb CHANGED
@@ -254,7 +254,7 @@ module Tina4
254
254
  end
255
255
 
256
256
  lines = source.lines.map(&:chomp)
257
- loc = lines.count { |l| !l.strip.empty? && !l.strip.start_with?('#') }
257
+ loc = lines.count { |l| _code_line?(l) }
258
258
 
259
259
  # Extract imports (require/require_relative)
260
260
  imports = _extract_imports(lines)
@@ -509,7 +509,7 @@ module Tina4
509
509
  end
510
510
 
511
511
  lines = source.lines.map(&:chomp)
512
- loc = lines.count { |l| !l.strip.empty? && !l.strip.start_with?('#') }
512
+ loc = lines.count { |l| _code_line?(l) }
513
513
 
514
514
  functions = _extract_functions(source, tokens, lines)
515
515
  functions.sort_by! { |f| -f["complexity"] }
@@ -763,6 +763,17 @@ module Tina4
763
763
  buffers
764
764
  end
765
765
 
766
+ # True for a line that counts toward LOC: not blank, not a comment.
767
+ #
768
+ # The single definition of the rule. Method LOC used to ignore it and return a
769
+ # raw line span while file LOC excluded blanks and comments, so `loc` meant
770
+ # two different things in one payload - the dashboard sized bubbles in one
771
+ # unit and printed the method table in the other.
772
+ def self._code_line?(line)
773
+ stripped = line.strip
774
+ !stripped.empty? && !stripped.start_with?("#")
775
+ end
776
+
766
777
  def self._extract_functions(source, _tokens, _lines)
767
778
  functions = []
768
779
  # Operate on a neutralised copy: string/regex/comment CONTENT is blanked
@@ -811,7 +822,9 @@ module Tina4
811
822
  # Find method end and calculate LOC
812
823
  method_start = i
813
824
  method_end = _find_method_end(lines, i)
814
- method_loc = method_end - method_start + 1
825
+ # Code lines over the method's span, by the same rule as file LOC.
826
+ # Floor of 1: a one-line body must never report 0.
827
+ method_loc = [1, lines[method_start..method_end].count { |l| _code_line?(l) }].max
815
828
 
816
829
  # Calculate complexity for this method's body
817
830
  method_lines = lines[method_start..method_end]
@@ -842,6 +855,51 @@ module Tina4
842
855
  i += 1
843
856
  end
844
857
 
858
+ _charge_nested_complexity_to_the_nested_function(functions)
859
+ end
860
+
861
+ # Stop a function being charged for the complexity of the functions nested
862
+ # inside it.
863
+ #
864
+ # Each function's raw score is measured over its whole span, so a branch
865
+ # inside a nested function landed on BOTH that function and every function
866
+ # enclosing it. The over-count compounded with depth: a wrapper around twenty
867
+ # inner handlers absorbed the entire file's complexity and topped the
868
+ # offenders list, hiding the genuine hot spots.
869
+ #
870
+ # The correction is exact. A raw score is 1 + every decision in the span, so
871
+ # (raw - 1) is the total decision count of a function's whole subtree.
872
+ # Subtracting that for each DIRECT child leaves the function's own branches:
873
+ #
874
+ # own(F) = raw(F) - sum over direct children C of (raw(C) - 1)
875
+ #
876
+ # Blocks and lambdas are deliberately unaffected: they are not reported as
877
+ # functions of their own, so nothing subtracts them and their decisions stay
878
+ # with the method that contains them - moved, never lost.
879
+ def self._charge_nested_complexity_to_the_nested_function(functions)
880
+ return functions if functions.length < 2
881
+
882
+ last_line = ->(f) { f["line"] + [1, f["loc"]].max - 1 }
883
+ contains = ->(outer, inner) do
884
+ inner["line"] > outer["line"] && last_line.call(inner) <= last_line.call(outer)
885
+ end
886
+
887
+ raw = functions.map { |f| f["complexity"] }
888
+ functions.each_with_index do |outer, i|
889
+ subtract = 0
890
+ functions.each_with_index do |inner, j|
891
+ next if i == j || !contains.call(outer, inner)
892
+
893
+ # Direct child only: skip it if another function sits between the two,
894
+ # or its complexity would be subtracted twice.
895
+ nested_deeper = functions.each_with_index.any? do |mid, k|
896
+ k != i && k != j && contains.call(outer, mid) && contains.call(mid, inner)
897
+ end
898
+ subtract += raw[j] - 1 unless nested_deeper
899
+ end
900
+ outer["complexity"] = [1, raw[i] - subtract].max
901
+ end
902
+
845
903
  functions
846
904
  end
847
905