Module: Phlex::Reactive::Inspector::Report
- Defined in:
- lib/phlex/reactive/inspector/report.rb
Overview
Renders the Inspector's read-only inventory for the phlex_reactive:actions
and phlex_reactive:find rake tasks (issue #168). Plain text by default,
JSON when asked — the SAME no-ANSI posture as Doctor (clean CI/log
capture). Reports NAMES/paths/schemas only, never tokens/secrets/state.
Class Method Summary collapse
- .action_detail(action) ⇒ Object
- .action_hash(action) ⇒ Object
-
.actions(components, format: :text) ⇒ Object
A plain-text table of every component × action, or a JSON array when
formatis :json. -
.actions_json(components) ⇒ Object
-- json -------------------------------------------------------------.
-
.actions_text(components) ⇒ Object
-- plain text -------------------------------------------------------.
-
.auth_str(action) ⇒ Object
The authorization heuristic as a short label — advisory only.
- .component_hash(info) ⇒ Object
- .component_rows(info) ⇒ Object
-
.detail_lines(info) ⇒ Object
-- find detail ------------------------------------------------------.
-
.find(matches, query) ⇒ Object
The find result: a ranked list header, then the TOP match in detail — each action's params, source location, authorization heuristic, and the full method-definition source.
- .format_row(row, widths) ⇒ Object
- .indent(text) ⇒ Object
-
.location_str(location) ⇒ Object
"file.rb:42", relative to Rails.root when possible.
-
.params_str(params) ⇒ Object
-- shared formatters ------------------------------------------------.
-
.render_table(headers, rows) ⇒ Object
A minimal fixed-column table: each column padded to its widest cell.
Class Method Details
.action_detail(action) ⇒ Object
80 81 82 83 84 85 86 |
# File 'lib/phlex/reactive/inspector/report.rb', line 80 def action_detail(action) header = " action :#{action.name}" header += " params: #{params_str(action.params)}" unless action.params.empty? header += " (#{location_str(action.source_location)}) auth: #{auth_str(action)}" body = action.definition ? indent(action.definition) : " (method not defined)" [header, body, ""] end |
.action_hash(action) ⇒ Object
108 109 110 111 112 113 114 115 |
# File 'lib/phlex/reactive/inspector/report.rb', line 108 def action_hash(action) { name: action.name, params: action.params, source_location: location_str(action.source_location), authorization_call_detected: action. } end |
.actions(components, format: :text) ⇒ Object
A plain-text table of every component × action, or a JSON array when
format is :json. One row per action: component, action, params,
file:line, authorization heuristic.
18 19 20 21 22 |
# File 'lib/phlex/reactive/inspector/report.rb', line 18 def actions(components, format: :text) return actions_json(components) if format == :json actions_text(components) end |
.actions_json(components) ⇒ Object
-- json -------------------------------------------------------------
94 95 96 |
# File 'lib/phlex/reactive/inspector/report.rb', line 94 def actions_json(components) JSON.pretty_generate(components.map { component_hash(it) }) end |
.actions_text(components) ⇒ Object
-- plain text -------------------------------------------------------
39 40 41 42 43 44 |
# File 'lib/phlex/reactive/inspector/report.rb', line 39 def actions_text(components) return "no reactive components found" if components.empty? rows = components.flat_map { component_rows(it) } render_table(%w[COMPONENT ACTION PARAMS FILE:LINE AUTH], rows) end |
.auth_str(action) ⇒ Object
The authorization heuristic as a short label — advisory only.
134 135 136 |
# File 'lib/phlex/reactive/inspector/report.rb', line 134 def auth_str(action) action. ? "authorized*" : "unverified" end |
.component_hash(info) ⇒ Object
98 99 100 101 102 103 104 105 106 |
# File 'lib/phlex/reactive/inspector/report.rb', line 98 def component_hash(info) { component: info.name, path: location_str(info.path), record_key: info.record_key, state_keys: info.state_keys, actions: info.actions.map { action_hash(it) } } end |
.component_rows(info) ⇒ Object
46 47 48 49 50 51 52 53 |
# File 'lib/phlex/reactive/inspector/report.rb', line 46 def component_rows(info) return [[info.name, "(no actions)", "", location_str(info.path), ""]] if info.actions.empty? info.actions.map do [info.name, it.name.to_s, params_str(it.params), location_str(it.source_location), auth_str(it)] end end |
.detail_lines(info) ⇒ Object
-- find detail ------------------------------------------------------
71 72 73 74 75 76 77 78 |
# File 'lib/phlex/reactive/inspector/report.rb', line 71 def detail_lines(info) lines = ["#{info.name} (#{location_str(info.path)})"] lines << " record: #{info.record_key}" if info.record_key lines << " state: #{info.state_keys.join(", ")}" if info.state_keys.any? lines << "" info.actions.each { lines.concat(action_detail(it)) } lines end |
.find(matches, query) ⇒ Object
The find result: a ranked list header, then the TOP match in detail — each action's params, source location, authorization heuristic, and the full method-definition source. Empty message when nothing matched.
27 28 29 30 31 32 33 34 35 |
# File 'lib/phlex/reactive/inspector/report.rb', line 27 def find(matches, query) return %(no component matched "#{query}") if matches.empty? lines = [%(#{matches.size} match#{"es" unless matches.size == 1} for "#{query}":)] matches.each { lines << " #{it.name}" } lines << "" lines.concat(detail_lines(matches.first)) lines.join("\n") end |
.format_row(row, widths) ⇒ Object
65 66 67 |
# File 'lib/phlex/reactive/inspector/report.rb', line 65 def format_row(row, widths) row.each_with_index.map { |cell, i| cell.to_s.ljust(widths[i]) }.join(" ").rstrip end |
.indent(text) ⇒ Object
88 89 90 |
# File 'lib/phlex/reactive/inspector/report.rb', line 88 def indent(text) text.each_line.map { " #{it}" }.join.rstrip end |
.location_str(location) ⇒ Object
"file.rb:42", relative to Rails.root when possible. nil location (a declared-but-missing method, or an unlocatable const) prints "?".
125 126 127 128 129 130 131 |
# File 'lib/phlex/reactive/inspector/report.rb', line 125 def location_str(location) return "?" unless location file, line = location file = file.delete_prefix("#{::Rails.root}/") if defined?(::Rails) && ::Rails.root line ? "#{file}:#{line}" : file end |
.params_str(params) ⇒ Object
-- shared formatters ------------------------------------------------
119 120 121 |
# File 'lib/phlex/reactive/inspector/report.rb', line 119 def params_str(params) params.empty? ? "" : params.inspect end |
.render_table(headers, rows) ⇒ Object
A minimal fixed-column table: each column padded to its widest cell. No ANSI, no external dependency.
57 58 59 60 61 62 63 |
# File 'lib/phlex/reactive/inspector/report.rb', line 57 def render_table(headers, rows) all = [headers] + rows # Two nested blocks (column index + row) need distinct named params — # `it` would collide, so name both. widths = headers.each_index.map { |col| all.map { |row| row[col].to_s.length }.max } # rubocop:disable Style/ItBlockParameter all.map { format_row(it, widths) }.join("\n") end |