Class: Countless::Statistics
- Inherits:
-
Object
- Object
- Countless::Statistics
- Defined in:
- lib/countless/statistics.rb
Overview
The source code statistics displaying handler.
Heavily stolen from: bit.ly/3qpvgfu
rubocop:disable Metrics/ClassLength because of the calculation
and formatting logic
Defined Under Namespace
Classes: Calculator
Instance Attribute Summary collapse
-
#dirs ⇒ Object
readonly
Make the extracted information accessible.
-
#statistics ⇒ Object
readonly
Make the extracted information accessible.
-
#total ⇒ Object
readonly
Make the extracted information accessible.
Instance Method Summary collapse
-
#calculate_code ⇒ Integer
Calculate the total lines of code.
-
#calculate_file_statistics(name, files) ⇒ Countless::Statistics::Calculator
Setup a new
Calculatorfor the given directory/pattern in order to extract the individual file statistics and calculate the sub-totals. -
#calculate_statistics ⇒ Hash{String => Hash{Symbol => Mixed}}
Calculate all statistics for the configured directories and pass back a named hash.
-
#calculate_tests ⇒ Integer
Calculate the total lines of testing code.
-
#calculate_total ⇒ Countless::Statistics::Calculator
Calculate the total statistics of all sub-statistics for the configured directories.
-
#code_test_stats_line ⇒ String
Return the final meta statistics line.
-
#initialize(*dirs) ⇒ Countless::Statistics
constructor
Initialize a new source code statistics displaying handler.
-
#to_s ⇒ String
Convert the code statistics to a formatted string buffer.
-
#to_table ⇒ Array<Array<String, Integer>, Symbol>
Convert the code statistics to a processable table structure.
Constructor Details
#initialize(*dirs) ⇒ Countless::Statistics
Initialize a new source code statistics displaying handler. When no configurations are passed in directly, we fallback to the configured statistics directories of the gem.
rubocop:disable Metrics/AbcSize because of the
directory/config resolving
rubocop:disable Metrics/PerceivedComplexity dito rubocop:disable Metrics/CyclomaticComplexity dito rubocop:disable Metrics/MethodLength dito
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/countless/statistics.rb', line 26 def initialize(*dirs) base_path = Countless.configuration.base_path # Resolve the given directory configurations to actual files dirs = (dirs.presence || Countless.statistic_directories) @dirs = dirs.each_with_object([]) do |cur, memo| copy = cur.deep_dup copy[:files] = Array(copy[:files]) if copy[:pattern].is_a? Regexp copy[:files] += Dir[ File.join(copy[:dir] || base_path, '**/*') ].select { |path| File.file?(path) && copy[:pattern].match?(path) } else copy[:files] += Dir[copy[:pattern]] end copy[:files].uniq! memo << copy if copy[:files].present? end @statistics = calculate_statistics @total = calculate_total if @dirs.length > 1 end |
Instance Attribute Details
#dirs ⇒ Object (readonly)
Make the extracted information accessible
12 13 14 |
# File 'lib/countless/statistics.rb', line 12 def dirs @dirs end |
#statistics ⇒ Object (readonly)
Make the extracted information accessible
12 13 14 |
# File 'lib/countless/statistics.rb', line 12 def statistics @statistics end |
#total ⇒ Object (readonly)
Make the extracted information accessible
12 13 14 |
# File 'lib/countless/statistics.rb', line 12 def total @total end |
Instance Method Details
#calculate_code ⇒ Integer
Calculate the total lines of code.
103 104 105 106 |
# File 'lib/countless/statistics.rb', line 103 def calculate_code @statistics.values.reject { |conf| conf[:test] } .map { |conf| conf[:stats].code_lines }.sum end |
#calculate_file_statistics(name, files) ⇒ Countless::Statistics::Calculator
Setup a new Calculator for the given directory/pattern in order to extract the individual file statistics and calculate the sub-totals.
We match the pattern against the individual file name and the relative file path. This allows top-level only matches.
92 93 94 95 96 97 98 |
# File 'lib/countless/statistics.rb', line 92 def calculate_file_statistics(name, files) Calculator.new(name: name).tap do |calc| Cloc.stats(*files).each do |path, stats| calc.add_by_file_path(path, **stats) end end end |
#calculate_statistics ⇒ Hash{String => Hash{Symbol => Mixed}}
Calculate all statistics for the configured directories and pass back a named hash.
71 72 73 74 75 76 77 78 79 |
# File 'lib/countless/statistics.rb', line 71 def calculate_statistics @dirs.map do |conf| [ conf[:name], conf.merge(stats: calculate_file_statistics(conf[:name], conf[:files])) ] end.to_h end |
#calculate_tests ⇒ Integer
Calculate the total lines of testing code.
111 112 113 114 |
# File 'lib/countless/statistics.rb', line 111 def calculate_tests @statistics.values.select { |conf| conf[:test] } .map { |conf| conf[:stats].code_lines }.sum end |
#calculate_total ⇒ Countless::Statistics::Calculator
Calculate the total statistics of all sub-statistics for the configured directories.
59 60 61 62 63 64 |
# File 'lib/countless/statistics.rb', line 59 def calculate_total calculator = Calculator.new(name: 'Total') @statistics.values.each_with_object(calculator) do |conf, total| total.add(conf[:stats]) end end |
#code_test_stats_line ⇒ String
Return the final meta statistics line.
189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/countless/statistics.rb', line 189 def code_test_stats_line code = calculate_code tests = calculate_tests ratio = tests.fdiv(code) ratio = '0' if ratio.nan? res = [ "Code LOC: #{code}", "Test LOC: #{tests}", "Code to Test Ratio: 1:#{format('%.1f', ratio)}" ].join(' ' * 5) " #{res}" end |
#to_s ⇒ String
Convert the code statistics to a formatted string buffer.
rubocop:disable Metrics/MethodLength because of the complex formatting
logic with fully dynamic columns widths
rubocop:disable Metrics/PerceivedComplexity dito rubocop:disable Metrics/CyclomaticComplexity dito rubocop:disable Metrics/AbcSize dito
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/countless/statistics.rb', line 125 def to_s col_sizes = {} rows = to_table.map do |row| next row unless row.is_a?(Array) row = row.map(&:to_s) cols = row.map(&:length).each_with_index.map { |len, idx| [idx, [len]] } col_sizes.deep_merge!(cols.to_h) { |_, left, right| left + right } row end # Calculate the correct column sizes col_sizes = col_sizes.values.each_with_object([]) do |widths, memo| memo << widths.max + 2 end # Enforce the correct column sizes per row splitter = ([0] + col_sizes + [0]).map { |size| '-' * size }.join('+') rows.each_with_object([]) do |row, memo| next memo << splitter if row == :splitter next memo << row if row.is_a?(String) cols = row.each_with_index.map do |col, idx| meth = idx.zero? ? :ljust : :rjust col.send(meth, col_sizes[idx] - 2) end memo << "| #{cols.join(' | ')} |" end.join("\n") end |
#to_table ⇒ Array<Array<String, Integer>, Symbol>
Convert the code statistics to a processable table structure. Each element in the resulting array is a single line, while array elements reflect columns. The special :splitter row value will be converted later by #to_s.
rubocop:disable Metrics/MethodLength because of the table construction
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/countless/statistics.rb', line 167 def to_table table = [ :splitter, %w[Name Lines LOC Comments Classes Methods M/C LOC/M], :splitter ] @statistics.each_value { |conf| table << conf[:stats].to_h.values } table << :splitter if @total table << @total.to_h.values table << :splitter end table << code_test_stats_line table end |