lumitrace 0.1.2 → 0.2.0

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: e03b4d880369e5f87e97dc3d9512afe78f27e310efd2b960a1b2ce545e3a70d1
4
- data.tar.gz: '0970a1a220cf484be1d75aa1d51f6004c08ce7bc1154857180247edc44253353'
3
+ metadata.gz: 638e44a364f468bd57003d05c60492dc697f31faba607292dfa5768b8ede47d2
4
+ data.tar.gz: a930badbf11444cd914765dde643a13347414511e1401aad4bf2da55e3e8159b
5
5
  SHA512:
6
- metadata.gz: 28a83ebc1a957b33da7a9421a78176f4d348cd3963d702f2b926eba5fa3e1b1fb7277d1a8e9635644a71af25c63e5072829ba32e7c3671636d956d266b2eb22a
7
- data.tar.gz: 83956ce933a06f9cfd128e35146b7745410215a392b9bcd22008ae26b4568db8369cafdbb93d48bdb7d92785ccb7f342fe3445f4cf38fbba985c392b95637825
6
+ metadata.gz: 3997b1814e8861e98e5b8dbd2489eab974f8d1671424a190bc2b82e37c65a6a3253eeb47074c507a1984ef5a3db19cb0aa84520e7f54a757d133f510d260c5c5
7
+ data.tar.gz: 935834bd5c818a528307f1359815faead6f793ffa5deaf78b039a7fb9dd5b570dd0b07ce1b1bf00edf0c4e51a39edfcb2f4fbddae5c85a6a54e7ff3ae036b699
data/README.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  Lumitrace instruments Ruby source code at load time, records expression results, and renders an HTML view that overlays recorded values on your code. It is designed for quick, local “what happened here?” inspection during test runs or scripts.
4
4
 
5
+ ## Useful links
6
+
7
+ - [runv/](https://ko1.github.io/lumitrace/runv/): Lumitrace demonstration Ruby playground with inlined tracing
8
+ - [Tutorial](https://ko1.github.io/lumitrace/docs/tutorial.html)
9
+ - [Tutorial in Japanese](https://ko1.github.io/lumitrace/docs/tutorial.ja.html)
10
+ - [Spec](https://ko1.github.io/lumitrace/docs/spec.html)
11
+ - [Supported Syntax](https://ko1.github.io/lumitrace/docs/supported_syntax.html)
12
+ - [GitHub repository](https://github.com/ko1/lumitrace)
13
+
14
+
5
15
  ## How It Works
6
16
 
7
17
  Lumitrace hooks `RubyVM::InstructionSequence.translate` (when available) to rewrite files at require-time. It records expression results and renders an HTML view that shows them inline. Only the last N values per expression are kept to avoid huge output.
data/docs/#spec.md# ADDED
@@ -0,0 +1,248 @@
1
+ # Lumitrace Spec
2
+
3
+ ## Overview
4
+
5
+ Lumitrace instruments Ruby source code at load time (via `RubyVM::InstructionSequence.translate` when available), records expression results, and renders an HTML view that overlays recorded values on your code. It is designed for local “what happened here?” inspection.
6
+
7
+ ## Goals
8
+
9
+ - Record expression results with minimal friction.
10
+ - Limit recorded data size (keep only the last N values per expression).
11
+ - Show recorded values inline on a per-file HTML view.
12
+ - Support require-time instrumentation for multiple files.
13
+
14
+ ## Non-Goals
15
+
16
+ - Production-safe tracing.
17
+ - Perfect semantic preservation for all Ruby edge cases.
18
+
19
+ ## Library API
20
+
21
+ ### `require "lumitrace"`
22
+
23
+ - Arguments: none.
24
+ - Returns: nothing.
25
+ - Side effects: loads core code only (no instrumentation, no `at_exit`).
26
+
27
+ ### `Lumitrace.enable!(max_values: nil, ranges_by_file: nil, root: nil, at_exit: true)`
28
+
29
+ - Arguments:
30
+ - `max_values`: integer or nil. Sets maximum values stored per expression.
31
+ - `ranges_by_file`: hash or nil. `{ "/path/to/file.rb" => [1..5, 10..12] }`.
32
+ - `at_exit`: boolean. When true, registers HTML output at exit.
33
+ - Returns: `nil`.
34
+ - Side effects:
35
+ - Loads `record_require` if needed and enables require-time instrumentation.
36
+ - Registers a single `at_exit` hook (if `at_exit: true`).
37
+ - Fixes the HTML output directory to the `Dir.pwd` at call time.
38
+
39
+ ### `Lumitrace.disable!`
40
+
41
+ - Arguments: none.
42
+ - Returns: `nil`.
43
+ - Side effects: disables instrumentation (does not clear recorded events).
44
+
45
+ ### `Lumitrace.dump!(path = nil)`
46
+
47
+ - Arguments:
48
+ - `path`: string or nil. Output JSON path when provided.
49
+ - Returns: the path used.
50
+ - Side effects: writes JSON to disk immediately.
51
+
52
+ ### `require "lumitrace/enable"`
53
+
54
+ - Arguments: none.
55
+ - Returns: nothing.
56
+ - Side effects: calls `Lumitrace.enable!` with default arguments.
57
+
58
+ ### `require "lumitrace/enable_git_diff"`
59
+
60
+ - Arguments: none.
61
+ - Returns: nothing.
62
+ - Side effects:
63
+ - Computes `ranges_by_file` from `git diff` scoped to the current program file.
64
+ - Calls `Lumitrace.enable!` when diff is non-empty.
65
+
66
+ Environment variables for `enable_git_diff`:
67
+
68
+ - `LUMITRACE_GIT_DIFF=working|staged|base:REV|range:SPEC` selects diff source.
69
+ - `LUMITRACE_GIT_DIFF_CONTEXT=N` expands hunks by +/-N lines (default 3; negative treated as 0).
70
+ - `LUMITRACE_GIT_CMD` overrides the git executable (default: `git`).
71
+
72
+ ### `RecordRequire.enable(max_values: nil, ranges_by_file: nil, root: nil)`
73
+
74
+ - Arguments:
75
+ - `max_values`: integer or nil. Sets maximum values stored per expression.
76
+ - `ranges_by_file`: hash or nil. `{ "/path/to/file.rb" => [1..5, 10..12] }`.
77
+ - Returns: `nil`.
78
+ - Side effects: enables require-time instrumentation immediately.
79
+
80
+ ### `RecordInstrument.instrument_source(src, ranges, file_label: nil, record_method: "Lumitrace::RecordInstrument.expr_record")`
81
+
82
+ - Arguments:
83
+ - `src`: string. Ruby source.
84
+ - `ranges`: array of `[start_line, end_line]` pairs.
85
+ - `file_label`: string or nil. File label to record into events.
86
+ - `record_method`: string. Wrapper method name.
87
+ - Returns: rewritten Ruby source as a string.
88
+ - Side effects: none.
89
+
90
+ ### `RecordInstrument.expr_record(file, start_line, start_col, end_line, end_col, value)`
91
+
92
+ - Arguments: expression location and value.
93
+ - Returns: `value`.
94
+ - Side effects: appends value into the in-memory event store and updates totals.
95
+
96
+ ### `RecordInstrument.dump_json(path = default)`
97
+
98
+ - Arguments:
99
+ - `path`: string or nil. When nil, defaults to `Dir.pwd/lumitrace_recorded.json`.
100
+ - Returns: the path used.
101
+ - Side effects: writes JSON to disk.
102
+
103
+ ### `RecordInstrument.events`
104
+
105
+ - Arguments: none.
106
+ - Returns: array of event hashes.
107
+ - Side effects: none.
108
+
109
+ ### `RecordInstrument.max_values_per_expr` / `max_values_per_expr=`
110
+
111
+ - Arguments: none / integer.
112
+ - Returns: current max values per expression.
113
+ - Side effects: setter changes recording limit.
114
+
115
+ ### `GenerateResultedHtml.render(source_path, events_path, ranges: nil)`
116
+
117
+ - Arguments:
118
+ - `source_path`: file path.
119
+ - `events_path`: JSON path.
120
+ - `ranges`: array of `[start_line, end_line]` pairs or nil.
121
+ - Returns: HTML string.
122
+ - Side effects: none.
123
+
124
+ ### `GenerateResultedHtml.render_all(events_path, root: Dir.pwd, ranges_by_file: nil)`
125
+
126
+ - Arguments:
127
+ - `events_path`: JSON path.
128
+ - `root`: root directory for file headings.
129
+ - `ranges_by_file`: hash or nil.
130
+ - Returns: HTML string.
131
+ - Side effects: none.
132
+
133
+ ### `GenerateResultedHtml.render_all_from_events(events, root: Dir.pwd, ranges_by_file: nil)`
134
+
135
+ - Arguments:
136
+ - `events`: array of event hashes.
137
+ - `root`: root directory for file headings.
138
+ - `ranges_by_file`: hash or nil.
139
+ - Returns: HTML string.
140
+ - Side effects: none.
141
+
142
+ ## Instrumentation
143
+
144
+ ### Activation
145
+
146
+ - Require `lumitrace/record_require` and call `RecordRequire.enable`.
147
+ - Hook `RubyVM::InstructionSequence.translate` to rewrite files at load time.
148
+ - Only instrument files under the configured root directory.
149
+ - Optional: restrict instrumentation to specific line ranges per file.
150
+
151
+ ### Root Scope
152
+
153
+ - Root is `root` if set, otherwise `ENV[LUMITRACE_ROOT]` if set, otherwise `Dir.pwd`.
154
+ - Files outside root are ignored.
155
+
156
+ ### Exclusions
157
+
158
+ - Tool files are excluded to avoid self-instrumentation:
159
+ - `record_instrument.rb`
160
+ - `record_require.rb`
161
+ - `generate_resulted_html.rb`
162
+
163
+ ### Rewriting Strategy
164
+
165
+ - AST is parsed with Prism.
166
+ - For each node, if it matches “wrapable” expression classes, injects:
167
+ - `RecordInstrument.expr_record(file, start_line, start_col, end_line, end_col, (expr))`
168
+ - Insertions are done by offset to preserve original formatting.
169
+
170
+ ### Range Filtering
171
+
172
+ - `ranges_by_file` is a hash like `{ "/path/to/file.rb" => [1..5, 10..12] }`.
173
+ - When provided, only files listed in the hash are instrumented.
174
+ - For a listed file, only expressions whose start line falls within the listed ranges are instrumented.
175
+ - If a listed file has `nil` or an empty array for ranges, the entire file is instrumented.
176
+ - HTML rendering respects the same ranges and only shows the listed lines/files.
177
+
178
+ ### Wrap Targets
179
+
180
+ - `CallNode` (except those with block bodies)
181
+ - Variable reads:
182
+ - `LocalVariableReadNode`
183
+ - `ConstantReadNode`
184
+ - `InstanceVariableReadNode`
185
+ - `ClassVariableReadNode`
186
+ - `GlobalVariableReadNode`
187
+ - Literal nodes are excluded (e.g. integer, string, true/false, nil, etc.)
188
+
189
+ ## Recording
190
+
191
+ - Results are stored per expression key:
192
+ - `(file, start_line, start_col, end_line, end_col)`
193
+ - Keep only the last N values (`max_values_per_expr`, default 3).
194
+ - Track `total` count for how many times the expression executed.
195
+ - Values are stored via `inspect` for non-primitive types.
196
+ - String values are truncated to 1000 bytes for storage.
197
+
198
+ ### Output JSON
199
+
200
+ `lumitrace_recorded.json` contains an array of entries:
201
+
202
+ ```json
203
+ {
204
+ "file": "/path/to/file.rb",
205
+ "start_line": 10,
206
+ "start_col": 4,
207
+ "end_line": 10,
208
+ "end_col": 20,
209
+ "values": ["..."],
210
+ "total": 123
211
+ }
212
+ ```
213
+
214
+ ## CLI
215
+
216
+ ### `exe/lumitrace`
217
+
218
+ ```
219
+ lumitrace FILE [--html PATH] [--json [PATH]] [--max N] [--range SPEC]
220
+ ```
221
+
222
+ - HTML is rendered by default (from in-memory events; no JSON file is required).
223
+ - `--html` specifies the HTML output path.
224
+ - JSON is written only when `--json` is provided.
225
+ - `--json` writes JSON output (default: `lumitrace_recorded.json`).
226
+ - `--max` sets max values per expression.
227
+ - `--range` restricts instrumentation per file (`FILE` or `FILE:1-5,10-12`). Can be repeated.
228
+ - `LUMITRACE_VALUES_MAX` sets the default max values per expression.
229
+
230
+ ## HTML Rendering
231
+
232
+ - `GenerateResultedHtml.render_all` renders all files in one page.
233
+ - Each file is shown in its own section.
234
+ - Expressions are marked with an inline icon.
235
+ - Hovering the icon shows recorded values.
236
+ - Only the last 3 values are shown in the tooltip; additional values are summarized as `... (+N more)`.
237
+ - Tooltip is scrollable horizontally for long values.
238
+
239
+ ### Copy/Paste Behavior
240
+
241
+ - Inline icon uses a separate marker span to reduce copy/paste artifacts.
242
+ - Lines are rendered as inline spans with explicit `\n` inserted.
243
+
244
+ ## Known Limitations
245
+
246
+ - Requires `RubyVM::InstructionSequence.translate` support in the Ruby build.
247
+ - Instrumentation is for debugging; semantics may change for unusual edge cases.
248
+ - Tool does not attempt to preserve file encoding comments.
data/docs/spec.md ADDED
@@ -0,0 +1,211 @@
1
+ ---
2
+ ---
3
+
4
+ # Lumitrace Spec
5
+
6
+ ## Overview
7
+
8
+ Lumitrace instruments Ruby source code at load time (via `RubyVM::InstructionSequence.translate` when available), records expression results, and renders text or HTML output that overlays recorded values on your code. It is designed for local “what happened here?” inspection.
9
+
10
+ ## Goals
11
+
12
+ - Record expression results with minimal friction.
13
+ - Limit recorded data size (keep only the last N values per expression).
14
+ - Show recorded values inline on a per-file HTML view.
15
+ - Support require-time instrumentation for multiple files.
16
+
17
+ ## Non-Goals
18
+
19
+ - Production-safe tracing.
20
+ - Perfect semantic preservation for all Ruby edge cases.
21
+
22
+ ## Public API
23
+
24
+ ### `require "lumitrace"`
25
+
26
+ - Arguments: none.
27
+ - Returns: nothing.
28
+ - Side effects: loads core code only (no instrumentation, no `at_exit`).
29
+
30
+ ### Library entry points (common usage)
31
+
32
+ - `require "lumitrace"` + `Lumitrace.enable!(...)`
33
+ - `require "lumitrace/enable"` (calls `Lumitrace.enable!`)
34
+ - `require "lumitrace/enable_git_diff"` (diff-scoped `Lumitrace.enable!`)
35
+ - `LUMITRACE_ENABLE=1` + `require "lumitrace"` (auto-`enable!`)
36
+ - `LUMITRACE_ENABLE="--text --html --json ..."` + `require "lumitrace"` (CLI-style options parsed and passed to `enable!`)
37
+
38
+ ### `Lumitrace.enable!(max_values: nil, ranges_by_file: nil, root: nil, text: nil, html: nil, json: nil, verbose: nil, at_exit: true)`
39
+
40
+ - Arguments:
41
+ - `max_values`: integer, string, or nil.
42
+ - `ranges_by_file`: hash or nil. `{ "/path/to/file.rb" => [1..5, 10..12] }`.
43
+ - `text`: boolean or string or nil. When nil, determined from environment variables. When string, uses it as the text output path.
44
+ - `html`: boolean or string or nil. When nil, determined from environment variables.
45
+ - `json`: boolean or string or nil. When nil, determined from environment variables.
46
+ - `verbose`: boolean or nil. When nil, determined from `LUMITRACE_VERBOSE`.
47
+ - `at_exit`: boolean. When true, registers output at exit.
48
+ - Returns: `nil`.
49
+ - Side effects:
50
+ - Enables require-time instrumentation.
51
+ - Registers a single `at_exit` hook (if `at_exit: true`).
52
+ - Fixes the HTML output directory to the `Dir.pwd` at call time.
53
+ - Root scope for instrumentation uses `root` if provided, otherwise `ENV["LUMITRACE_ROOT"]` if set, otherwise `Dir.pwd`.
54
+ - Environment variables (resolved by `Lumitrace.enable!`):
55
+ - `LUMITRACE_VALUES_MAX`: default max values per expression when `max_values` is nil (default 3 if unset).
56
+ - `LUMITRACE_ROOT`: root directory used to decide which files are instrumented.
57
+ - `LUMITRACE_HTML`: enable HTML output; `1` uses the default path, otherwise treats the value as the HTML output path. `0`/`false` disables.
58
+ - `LUMITRACE_TEXT`: control text output. `1` forces text on, `0`/`false` disables. If unset, text is enabled only when both HTML and JSON are disabled. Any other value is treated as the text output path.
59
+ - `LUMITRACE_JSON`: enable JSON output; `1` uses the default path, otherwise treats the value as the JSON output path. `0`/`false` disables.
60
+ - `LUMITRACE_GIT_DIFF_UNTRACKED`: include untracked files in git diff ranges (`1` default). Set to `0` to exclude.
61
+ - `LUMITRACE_VERBOSE`: when `1`/`true`, prints verbose logs to stderr.
62
+ - `LUMITRACE_ENABLE`: when `1`/`true`, `require "lumitrace"` will call `Lumitrace.enable!`. When set to a non-boolean string, it is parsed as CLI-style arguments and passed to `enable!`.
63
+
64
+ ### `Lumitrace.disable!`
65
+
66
+ - Arguments: none.
67
+ - Returns: `nil`.
68
+ - Side effects: disables instrumentation (does not clear recorded events).
69
+
70
+
71
+ ### `require "lumitrace/enable"`
72
+
73
+ - Arguments: none.
74
+ - Returns: nothing.
75
+ - Side effects: calls `Lumitrace.enable!` with default arguments.
76
+
77
+ ### `require "lumitrace/enable_git_diff"`
78
+
79
+ - Arguments: none.
80
+ - Returns: nothing.
81
+ - Side effects:
82
+ - Computes `ranges_by_file` from `git diff` scoped to the current program file.
83
+ - Calls `Lumitrace.enable!` when diff is non-empty.
84
+ - Environment variables:
85
+ - `LUMITRACE_GIT_DIFF=working|staged|base:REV|range:SPEC` selects diff source.
86
+ - `LUMITRACE_GIT_DIFF_CONTEXT=N` expands hunks by +/-N lines (default 3; negative treated as 0).
87
+ - `LUMITRACE_GIT_CMD` overrides the git executable (default: `git`).
88
+
89
+ ## Instrumentation
90
+
91
+ ### Activation
92
+
93
+ - Call `Lumitrace.enable!`.
94
+ - Hook `RubyVM::InstructionSequence.translate` to rewrite files at load time.
95
+ - Only instrument files under the configured root directory.
96
+ - Optional: restrict instrumentation to specific line ranges per file.
97
+
98
+ ### Root Scope
99
+
100
+ - Root is `Dir.pwd` (or `ENV["LUMITRACE_ROOT"]` if set).
101
+ - Files outside root are ignored.
102
+
103
+ ### Exclusions
104
+
105
+ - Tool files are excluded to avoid self-instrumentation:
106
+ - `record_instrument.rb`
107
+ - `record_require.rb`
108
+ - `generate_resulted_html.rb`
109
+
110
+ ### Rewriting Strategy
111
+
112
+ - AST is parsed with Prism.
113
+ - For each node, if it matches “wrapable” expression classes, injects:
114
+ - `RecordInstrument.expr_record(file, start_line, start_col, end_line, end_col, (expr))`
115
+ - Insertions are done by offset to preserve original formatting.
116
+
117
+ ### Range Filtering
118
+
119
+ - `ranges_by_file` is a hash like `{ "/path/to/file.rb" => [1..5, 10..12] }`.
120
+ - When provided, only files listed in the hash are instrumented.
121
+ - For a listed file, only expressions whose start line falls within the listed ranges are instrumented.
122
+ - If a listed file has `nil` or an empty array for ranges, the entire file is instrumented.
123
+ - HTML rendering respects the same ranges and only shows files that produced events.
124
+
125
+ ### Wrap Targets
126
+
127
+ - `CallNode` (except those with block bodies)
128
+ - Variable reads:
129
+ - `LocalVariableReadNode`
130
+ - `ConstantReadNode`
131
+ - `InstanceVariableReadNode`
132
+ - `ClassVariableReadNode`
133
+ - `GlobalVariableReadNode`
134
+ - Literal nodes are excluded (e.g. integer, string, true/false, nil, etc.)
135
+
136
+ ## Recording
137
+
138
+ - Results are stored per expression key:
139
+ - `(file, start_line, start_col, end_line, end_col)`
140
+ - Keep only the last N values (`max_values_per_expr`, default 3).
141
+ - Track `total` count for how many times the expression executed.
142
+ - Values are stored via `inspect` for non-primitive types.
143
+ - String values are truncated to 1000 bytes for storage.
144
+
145
+ ### Output JSON
146
+
147
+ `lumitrace_recorded.json` contains an array of entries:
148
+
149
+ ```json
150
+ {
151
+ "file": "/path/to/file.rb",
152
+ "start_line": 10,
153
+ "start_col": 4,
154
+ "end_line": 10,
155
+ "end_col": 20,
156
+ "values": ["..."],
157
+ "total": 123
158
+ }
159
+ ```
160
+
161
+ ## CLI
162
+
163
+ ### `exe/lumitrace`
164
+
165
+ ```
166
+ lumitrace FILE [--text [PATH]] [--html [PATH]] [--json [PATH]] [--max N] [--range SPEC] [--git-diff [MODE]] [--git-diff-context N] [--git-cmd PATH] [--git-diff-no-untracked]
167
+ ```
168
+
169
+ - Text is rendered by default (from in-memory events; no JSON file is required).
170
+ - `--text` writes text output to stdout (default). When a PATH is provided, writes text output to that file.
171
+ - `--html` enables HTML output; optionally specify the output path.
172
+ - JSON is written only when `--json` is provided.
173
+ - `--json` writes JSON output (default: `lumitrace_recorded.json`).
174
+ - `--max` sets max values per expression.
175
+ - `--range` restricts instrumentation per file (`FILE` or `FILE:1-5,10-12`). Can be repeated.
176
+ - `--git-diff` restricts instrumentation to diff hunks (`working` default; `staged|base:REV|range:SPEC`).
177
+ - `--git-diff-context` expands hunks by +/-N lines.
178
+ - `--git-cmd` overrides the git executable.
179
+ - `--git-diff-no-untracked` excludes untracked files (untracked files are included by default).
180
+ - `--verbose` prints verbose logs to stderr.
181
+ - `LUMITRACE_VALUES_MAX` sets the default max values per expression.
182
+
183
+ ### Text Output (CLI)
184
+
185
+ - Text output starts with a header line: `=== Lumitrace Results (text) ===`.
186
+ - Each file is printed with a header: `### path/to/file.rb`.
187
+ - Each line is prefixed with a line number like ` 12| `.
188
+ - Skipped ranges are represented by a line containing `...`.
189
+ - Only the last value is shown per expression; if an expression ran multiple times, the last value is annotated with the ordinal run (e.g., `#=> 2 (3rd run)`).
190
+ - When `--text` is used and `--max` is not provided, `max_values` defaults to `1`.
191
+ - When `ranges_by_file` is provided, only files present in the hash are shown in text output.
192
+
193
+ ## HTML Rendering
194
+
195
+ - `GenerateResultedHtml.render_all` renders all files in one page.
196
+ - Each file is shown in its own section.
197
+ - Expressions are marked with an inline icon.
198
+ - Hovering the icon shows recorded values.
199
+ - Only the last 3 values are shown in the tooltip; additional values are summarized as `... (+N more)`.
200
+ - Tooltip is scrollable horizontally for long values.
201
+
202
+ ### Copy/Paste Behavior
203
+
204
+ - Inline icon uses a separate marker span to reduce copy/paste artifacts.
205
+ - Lines are rendered as inline spans with explicit `\n` inserted.
206
+
207
+ ## Known Limitations
208
+
209
+ - Requires `RubyVM::InstructionSequence.translate` support in the Ruby build.
210
+ - Instrumentation is for debugging; semantics may change for unusual edge cases.
211
+ - Tool does not attempt to preserve file encoding comments.
@@ -0,0 +1,117 @@
1
+ ---
2
+ ---
3
+
4
+ # Supported Syntax
5
+
6
+ Lumitrace instruments Ruby source by wrapping selected expression nodes with
7
+ `Lumitrace::RecordInstrument.expr_record(...)`. It does **not** rewrite the
8
+ entire AST, so coverage is best described as "expressions that are safe to wrap
9
+ in parentheses and call-position contexts."
10
+
11
+ This document lists what is supported today, and what is intentionally skipped
12
+ to avoid breaking valid Ruby syntax.
13
+
14
+ ## Supported (Instrumented)
15
+
16
+ The following node kinds are instrumented when they appear in normal expression
17
+ positions:
18
+
19
+ - Method calls (`Prism::CallNode`)
20
+ - Example:
21
+ ```ruby
22
+ foo(bar)
23
+ ```
24
+ - Local variable reads (`Prism::LocalVariableReadNode`)
25
+ - Example:
26
+ ```ruby
27
+ x
28
+ ```
29
+ - Numbered block parameter reads (`Prism::ItLocalVariableReadNode`)
30
+ - Example:
31
+ ```ruby
32
+ it
33
+ ```
34
+ - Constant reads (`Prism::ConstantReadNode`)
35
+ - Example:
36
+ ```ruby
37
+ SomeConst
38
+ ```
39
+ - Instance variable reads (`Prism::InstanceVariableReadNode`)
40
+ - Example:
41
+ ```ruby
42
+ @value
43
+ ```
44
+ - Class variable reads (`Prism::ClassVariableReadNode`)
45
+ - Example:
46
+ ```ruby
47
+ @@count
48
+ ```
49
+ - Global variable reads (`Prism::GlobalVariableReadNode`)
50
+ - Example:
51
+ ```ruby
52
+ $stdout
53
+ ```
54
+
55
+ Notes:
56
+ - Nodes that are not expression reads/calls are generally left as-is (e.g.,
57
+ definitions, control flow, assignment statements, etc.).
58
+
59
+ ## Not Supported (Skipped)
60
+
61
+ These are intentionally skipped to keep output valid Ruby:
62
+
63
+ - Definitions and structural nodes (the entire node is never wrapped):
64
+ - `def`, `class`, `module`, `if`, `case`, `while`, `begin`, `rescue`, etc.
65
+ - Example:
66
+ ```ruby
67
+ def foo
68
+ bar
69
+ end
70
+ ```
71
+
72
+ - Literals (not wrapped):
73
+ - `1`, `"str"`, `:sym`, `true`, `false`, `nil`
74
+
75
+ - Method calls that have a block with body (`do ... end` / `{ ... }`) are
76
+ instrumented at the call expression level. Example:
77
+ ```ruby
78
+ items.each do |x|
79
+ x + 1
80
+ end
81
+ ```
82
+
83
+ - Alias statements (both aliasing globals and methods):
84
+ - `alias $ERROR_INFO $!`
85
+ - `alias old_name new_name`
86
+
87
+ - The receiver part of a singleton method definition:
88
+ - Example:
89
+ ```ruby
90
+ def Foo.bar
91
+ 1
92
+ end
93
+ ```
94
+ - `Foo` is **not** instrumented here.
95
+
96
+ - Embedded variable nodes inside interpolated strings:
97
+ - Example:
98
+ ```ruby
99
+ "#@path?#@query"
100
+ ```
101
+ - `@path` and `@query` inside the interpolation are **not** instrumented.
102
+
103
+ - Implicit keyword argument values (`token:` style):
104
+ - Example:
105
+ ```ruby
106
+ ec2_metadata_request(EC2_IAM_INFO, token:)
107
+ ```
108
+ - The implicit `token` read is **not** instrumented.
109
+
110
+ ## Rationale
111
+
112
+ All skips above correspond to syntactic positions where wrapping the token with
113
+ `expr_record(...)` would change the Ruby grammar (e.g., alias operands, method
114
+ name positions, or implicit keyword arguments).
115
+
116
+ If you want additional coverage, we can add more targeted rewrites, but they
117
+ must preserve valid syntax in those special contexts.