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
Calculator
for 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 – ditto rubocop:disable Metrics/CyclomaticComplexity – ditto rubocop:disable Metrics/MethodLength – ditto
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.to_h do |conf| [ conf[:name], conf.merge(stats: calculate_file_statistics(conf[:name], conf[:files])) ] end 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 – ditto rubocop:disable Metrics/CyclomaticComplexity – ditto rubocop:disable Metrics/AbcSize – ditto
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 |