Class: Rigor::ModuleGraph::CLI::StatsCmd
- Inherits:
-
Object
- Object
- Rigor::ModuleGraph::CLI::StatsCmd
- Includes:
- EdgeFilters
- Defined in:
- lib/rigor/module_graph/cli.rb
Overview
‘stats` reports the fan-out / fan-in / internal / nodes numbers per namespace. Same filter flags as the renderers so a focused subgraph can be summarised without regenerating the JSONL.
Constant Summary collapse
- FORMATS =
%w[text json].freeze
- HEADERS =
%w[namespace nodes fan-out fan-in internal total].freeze
Constants included from EdgeFilters
EdgeFilters::VALID_CONFIDENCES, EdgeFilters::VALID_DIRECTIONS, EdgeFilters::VALID_EDGE_SCOPES, EdgeFilters::VALID_KINDS
Instance Method Summary collapse
- #format_row(row, widths) ⇒ Object
-
#format_table(metrics) ⇒ Object
A space-padded text table sized to the widest cell per column.
-
#initialize(stdout:, stderr:, stdin:) ⇒ StatsCmd
constructor
A new instance of StatsCmd.
- #parse_options!(argv) ⇒ Object
- #render(metrics) ⇒ Object
- #run(argv) ⇒ Object
Methods included from EdgeFilters
#add_filter_options, #apply_filters, #validate!
Constructor Details
#initialize(stdout:, stderr:, stdin:) ⇒ StatsCmd
Returns a new instance of StatsCmd.
859 860 861 862 863 864 865 866 867 868 |
# File 'lib/rigor/module_graph/cli.rb', line 859 def initialize(stdout:, stderr:, stdin:) @stdout = stdout @stderr = stderr @stdin = stdin @state = { kinds: nil, confidences: nil, from: nil, depth: nil, direction: :both, edge_scope: :cluster, grouping_depth: 1, format: "text", limit: nil } end |
Instance Method Details
#format_row(row, widths) ⇒ Object
952 953 954 955 956 |
# File 'lib/rigor/module_graph/cli.rb', line 952 def format_row(row, widths) row.each_with_index.map do |cell, idx| idx.zero? ? cell.ljust(widths[idx]) : cell.rjust(widths[idx]) end.join(" ") end |
#format_table(metrics) ⇒ Object
A space-padded text table sized to the widest cell per column. Numeric columns are right-aligned so a quick eye-scan finds the hotspots.
934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 |
# File 'lib/rigor/module_graph/cli.rb', line 934 def format_table(metrics) if metrics.empty? return "(no edges)\n" end rows = metrics.map do |m| [m.namespace, m.nodes.to_s, m.fan_out.to_s, m.fan_in.to_s, m.internal.to_s, m.total.to_s] end widths = HEADERS.zip(*rows).map { |col| col.map(&:length).max } out = +"" out << format_row(HEADERS, widths) << "\n" out << ("-" * widths.sum { |w| w + 2 }) << "\n" rows.each { |row| out << format_row(row, widths) << "\n" } out end |
#parse_options!(argv) ⇒ Object
898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 |
# File 'lib/rigor/module_graph/cli.rb', line 898 def (argv) parser = OptionParser.new do |opts| opts. = "Usage: rigor-module-graph stats [options] [FILE]" opts.on("--grouping-depth N", Integer, "How many leading namespace segments to group by (default: 1)") do |n| @state[:grouping_depth] = n end opts.on("--limit N", Integer, "Show only the top N namespaces by fan-out") do |n| @state[:limit] = n end opts.on("--format FORMAT", FORMATS, "Output format (#{FORMATS.join("/")}; default: text)") do |fmt| @state[:format] = fmt end (opts, @state) opts.on("-h", "--help") do @stdout.puts opts exit 0 end end parser.parse!(argv) end |
#render(metrics) ⇒ Object
922 923 924 925 926 927 928 929 |
# File 'lib/rigor/module_graph/cli.rb', line 922 def render(metrics) case @state[:format] when "json" @stdout.puts(JSON.pretty_generate(metrics.map(&:to_h))) when "text" @stdout.print(format_table(metrics)) end end |
#run(argv) ⇒ Object
870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 |
# File 'lib/rigor/module_graph/cli.rb', line 870 def run(argv) argv = argv.dup (argv) path, = argv io = path ? File.open(path, "r") : @stdin begin edges = EdgeIO.read(io) ensure io.close if path && !io.closed? end edges = apply_filters( edges, kinds: @state[:kinds], confidences: @state[:confidences], from: @state[:from], depth: @state[:depth], direction: @state[:direction], edge_scope: @state[:edge_scope] ) metrics = Stats.compute(edges, depth: @state[:grouping_depth]) metrics = metrics.first(@state[:limit]) if @state[:limit] render(metrics) 0 rescue OptionParser::ParseError => e @stderr.puts "rigor-module-graph stats: #{e.}" 2 end |