lumitrace 0.1.2 → 0.3.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 +4 -4
- data/README.md +42 -11
- data/docs/spec.md +225 -0
- data/docs/supported_syntax.md +117 -0
- data/docs/tutorial.ja.md +359 -0
- data/docs/tutorial.md +359 -0
- data/exe/lumitrace +57 -73
- data/lib/lumitrace/enable_git_diff.rb +15 -67
- data/lib/lumitrace/env.rb +60 -0
- data/lib/lumitrace/generate_resulted_html.rb +262 -18
- data/lib/lumitrace/git_diff.rb +93 -0
- data/lib/lumitrace/record_instrument.rb +82 -5
- data/lib/lumitrace/record_require.rb +9 -3
- data/lib/lumitrace/version.rb +1 -1
- data/lib/lumitrace.rb +365 -9
- data/runv/README.md +53 -0
- data/runv/index.html +982 -0
- data/sample/Rakefile +8 -0
- data/sample/lumitrace_rake.html +235 -0
- data/sample/lumitrace_recorded.html +235 -0
- data/sample/lumitrace_results_01.html +183 -0
- data/sample/lumitrace_results_01.txt +62 -0
- data/sample/lumitrace_results_02.html +123 -0
- data/sample/lumitrace_results_02.txt +24 -0
- data/sample/sample.rb +35 -0
- data/sample/sample2.rb +11 -0
- data/sample/sample3.rb +9 -0
- data/test/test_lumitrace.rb +199 -23
- metadata +24 -6
- /data/{sample_project → sample/sample_project}/.github/workflows/lumitrace-sample.yml +0 -0
- /data/{sample_project → sample/sample_project}/Gemfile +0 -0
- /data/{sample_project → sample/sample_project}/Rakefile +0 -0
- /data/{sample_project → sample/sample_project}/test/test_sample_test.rb +0 -0
- /data/{sample_project → sample/sample_project}/test.rb +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8ffc13efecd8f5143486eff6929c93bf73aaa3934bf24fa57e906a2f90498e2c
|
|
4
|
+
data.tar.gz: df8ce2960f59409dc832d21f9d1df7a2b33cc431fde00c76633f1149a5da3ab3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2030ec337dc9a941f1c9878b1faa74e15e605a715e1d2049675115573c7c1357d821ded3a200b348521a9593faf6f719ff93766f5ffe1c623d9a9c6dcaa663b1
|
|
7
|
+
data.tar.gz: 68564fe5bde3b1d00edd5390211c922b72f3565069446affed3dfdf042fc86491949f8170e175df8cdd99c55b1c05f030adab69fe140ce05cfd003f3f3a51719
|
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.
|
|
@@ -10,29 +20,41 @@ Lumitrace hooks `RubyVM::InstructionSequence.translate` (when available) to rewr
|
|
|
10
20
|
|
|
11
21
|
### CLI
|
|
12
22
|
|
|
13
|
-
Run a script and emit
|
|
23
|
+
Run a script and emit text output (default):
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
lumitrace path/to/entry.rb
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Run another command via exec:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
lumitrace exec rake test
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Emit HTML output:
|
|
14
36
|
|
|
15
37
|
```bash
|
|
16
|
-
|
|
38
|
+
lumitrace -h path/to/entry.rb
|
|
17
39
|
```
|
|
18
40
|
|
|
19
41
|
Limit the number of recorded values per expression (defaults to 3):
|
|
20
42
|
|
|
21
43
|
```bash
|
|
22
|
-
LUMITRACE_VALUES_MAX=5
|
|
44
|
+
LUMITRACE_VALUES_MAX=5 lumitrace path/to/entry.rb
|
|
23
45
|
```
|
|
24
46
|
|
|
25
47
|
Write JSON output explicitly:
|
|
26
48
|
|
|
27
49
|
```bash
|
|
28
|
-
|
|
29
|
-
|
|
50
|
+
lumitrace -j path/to/entry.rb
|
|
51
|
+
lumitrace --json=out/lumitrace_recorded.json path/to/entry.rb
|
|
30
52
|
```
|
|
31
53
|
|
|
32
54
|
Restrict to specific line ranges:
|
|
33
55
|
|
|
34
56
|
```bash
|
|
35
|
-
|
|
57
|
+
lumitrace --range path/to/entry.rb:10-20,30-35 path/to/entry.rb
|
|
36
58
|
```
|
|
37
59
|
|
|
38
60
|
### Library
|
|
@@ -58,18 +80,27 @@ require "lumitrace/enable"
|
|
|
58
80
|
|
|
59
81
|
## Output
|
|
60
82
|
|
|
61
|
-
-
|
|
62
|
-
-
|
|
83
|
+
- Text: printed by default; use `--text=PATH` to write to a file.
|
|
84
|
+
- HTML: `lumitrace_recorded.html` by default, or `--html=PATH`.
|
|
85
|
+
- JSON: written only when `--json` (CLI) or `LUMITRACE_JSON` (library/CLI) is provided. Default filename is `lumitrace_recorded.json`.
|
|
86
|
+
- Fork/exec: merged by default. Child processes write fragments under `LUMITRACE_RESULTS_DIR`.
|
|
63
87
|
|
|
64
88
|
## Environment Variables
|
|
65
89
|
|
|
66
90
|
- `LUMITRACE_VALUES_MAX`: default max values per expression (default 3 if unset).
|
|
67
91
|
- `LUMITRACE_ROOT`: root directory used to decide which files are instrumented.
|
|
68
|
-
- `
|
|
69
|
-
- `
|
|
92
|
+
- `LUMITRACE_TEXT`: control text output. `1` forces text on, `0`/`false` disables. Any other value is treated as the text output path.
|
|
93
|
+
- `LUMITRACE_HTML`: enable HTML output; `1` uses the default path, otherwise treats the value as the HTML output path. `0`/`false` disables.
|
|
94
|
+
- `LUMITRACE_JSON`: enable JSON output; `1` uses the default path, otherwise treats the value as the JSON output path. `0`/`false` disables.
|
|
95
|
+
- `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!`.
|
|
96
|
+
- `LUMITRACE_VERBOSE`: when `1`/`true`, prints verbose logs to stderr.
|
|
97
|
+
- `LUMITRACE_RANGE`: semicolon-separated range specs (e.g. `a.rb:1-3,5-6;b.rb`).
|
|
98
|
+
- `LUMITRACE_RESULTS_DIR`: internal use. Shared results directory for fork/exec merge (default: `Dir.tmpdir/lumitrace_results/<user>_<parent_pid>`).
|
|
99
|
+
- `LUMITRACE_RESULTS_PARENT_PID`: internal use. Parent PID for fork/exec merge (auto-set).
|
|
70
100
|
- `LUMITRACE_GIT_DIFF=working|staged|base:REV|range:SPEC`: diff source for `enable_git_diff`.
|
|
71
101
|
- `LUMITRACE_GIT_DIFF_CONTEXT=N`: expand diff hunks by +/-N lines (default 3).
|
|
72
102
|
- `LUMITRACE_GIT_CMD`: git executable override (default `git`).
|
|
103
|
+
- `LUMITRACE_GIT_DIFF_UNTRACKED`: include untracked files in git diff ranges (`1` default). Set to `0` to exclude.
|
|
73
104
|
|
|
74
105
|
## Notes And Limitations
|
|
75
106
|
|
|
@@ -88,5 +119,5 @@ bundle install
|
|
|
88
119
|
Run the CLI locally:
|
|
89
120
|
|
|
90
121
|
```bash
|
|
91
|
-
|
|
122
|
+
lumitrace path/to/entry.rb
|
|
92
123
|
```
|
data/docs/spec.md
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
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="-t -h -j ..."` + `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
|
+
- `LUMITRACE_RANGE`: semicolon-separated range specs, e.g. `a.rb:1-3,5-6;b.rb`.
|
|
64
|
+
- `LUMITRACE_RESULTS_DIR`: internal use. Shared results directory for fork/exec merge (default: `Dir.tmpdir/lumitrace_results/<user>_<parent_pid>`).
|
|
65
|
+
- `LUMITRACE_RESULTS_PARENT_PID`: internal use. Parent PID for fork/exec merge (auto-set).
|
|
66
|
+
|
|
67
|
+
### `Lumitrace.disable!`
|
|
68
|
+
|
|
69
|
+
- Arguments: none.
|
|
70
|
+
- Returns: `nil`.
|
|
71
|
+
- Side effects: disables instrumentation (does not clear recorded events).
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
### `require "lumitrace/enable"`
|
|
75
|
+
|
|
76
|
+
- Arguments: none.
|
|
77
|
+
- Returns: nothing.
|
|
78
|
+
- Side effects: calls `Lumitrace.enable!` with default arguments.
|
|
79
|
+
|
|
80
|
+
### `require "lumitrace/enable_git_diff"`
|
|
81
|
+
|
|
82
|
+
- Arguments: none.
|
|
83
|
+
- Returns: nothing.
|
|
84
|
+
- Side effects:
|
|
85
|
+
- Computes `ranges_by_file` from `git diff` scoped to the current program file.
|
|
86
|
+
- Calls `Lumitrace.enable!` when diff is non-empty.
|
|
87
|
+
- Environment variables:
|
|
88
|
+
- `LUMITRACE_GIT_DIFF=working|staged|base:REV|range:SPEC` selects diff source.
|
|
89
|
+
- `LUMITRACE_GIT_DIFF_CONTEXT=N` expands hunks by +/-N lines (default 3; negative treated as 0).
|
|
90
|
+
- `LUMITRACE_GIT_CMD` overrides the git executable (default: `git`).
|
|
91
|
+
- `LUMITRACE_RANGE` can be used to pass explicit ranges via env.
|
|
92
|
+
|
|
93
|
+
## Instrumentation
|
|
94
|
+
|
|
95
|
+
### Activation
|
|
96
|
+
|
|
97
|
+
- Call `Lumitrace.enable!`.
|
|
98
|
+
- Hook `RubyVM::InstructionSequence.translate` to rewrite files at load time.
|
|
99
|
+
- Only instrument files under the configured root directory.
|
|
100
|
+
- Optional: restrict instrumentation to specific line ranges per file.
|
|
101
|
+
|
|
102
|
+
### Root Scope
|
|
103
|
+
|
|
104
|
+
- Root is `Dir.pwd` (or `ENV["LUMITRACE_ROOT"]` if set).
|
|
105
|
+
- Files outside root are ignored.
|
|
106
|
+
|
|
107
|
+
### Exclusions
|
|
108
|
+
|
|
109
|
+
- Tool files are excluded to avoid self-instrumentation:
|
|
110
|
+
- `record_instrument.rb`
|
|
111
|
+
- `record_require.rb`
|
|
112
|
+
- `generate_resulted_html.rb`
|
|
113
|
+
|
|
114
|
+
### Rewriting Strategy
|
|
115
|
+
|
|
116
|
+
- AST is parsed with Prism.
|
|
117
|
+
- For each node, if it matches “wrapable” expression classes, injects:
|
|
118
|
+
- `RecordInstrument.expr_record(file, start_line, start_col, end_line, end_col, (expr))`
|
|
119
|
+
- Insertions are done by offset to preserve original formatting.
|
|
120
|
+
|
|
121
|
+
### Range Filtering
|
|
122
|
+
|
|
123
|
+
- `ranges_by_file` is a hash like `{ "/path/to/file.rb" => [1..5, 10..12] }`.
|
|
124
|
+
- When provided, only files listed in the hash are instrumented.
|
|
125
|
+
- For a listed file, only expressions whose start line falls within the listed ranges are instrumented.
|
|
126
|
+
- If a listed file has `nil` or an empty array for ranges, the entire file is instrumented.
|
|
127
|
+
- HTML rendering respects the same ranges and only shows files that produced events.
|
|
128
|
+
|
|
129
|
+
### Wrap Targets
|
|
130
|
+
|
|
131
|
+
- `CallNode` (except those with block bodies)
|
|
132
|
+
- Variable reads:
|
|
133
|
+
- `LocalVariableReadNode`
|
|
134
|
+
- `ConstantReadNode`
|
|
135
|
+
- `InstanceVariableReadNode`
|
|
136
|
+
- `ClassVariableReadNode`
|
|
137
|
+
- `GlobalVariableReadNode`
|
|
138
|
+
- Literal nodes are excluded (e.g. integer, string, true/false, nil, etc.)
|
|
139
|
+
|
|
140
|
+
## Recording
|
|
141
|
+
|
|
142
|
+
- Results are stored per expression key:
|
|
143
|
+
- `(file, start_line, start_col, end_line, end_col)`
|
|
144
|
+
- Keep only the last N values (`max_values_per_expr`, default 3).
|
|
145
|
+
- Track `total` count for how many times the expression executed.
|
|
146
|
+
- Values are stored via `inspect` for non-primitive types.
|
|
147
|
+
- String values are truncated to 1000 bytes for storage.
|
|
148
|
+
|
|
149
|
+
## Fork/Exec Merge
|
|
150
|
+
|
|
151
|
+
- Fork/exec results are merged by default.
|
|
152
|
+
- The parent process writes final text/HTML/JSON.
|
|
153
|
+
- Child processes write JSON fragments under `LUMITRACE_RESULTS_DIR` and do not write final outputs.
|
|
154
|
+
- When `Process._fork` is available, Lumitrace hooks it to reset child events immediately after fork.
|
|
155
|
+
- `exec` inherits `LUMITRACE_RESULTS_DIR` and `LUMITRACE_RESULTS_PARENT_PID` via the environment. `Lumitrace.enable!` also appends `-rlumitrace` to `RUBYOPT` to ensure the exec'd process loads Lumitrace.
|
|
156
|
+
|
|
157
|
+
### Output JSON
|
|
158
|
+
|
|
159
|
+
`lumitrace_recorded.json` contains an array of entries:
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
{
|
|
163
|
+
"file": "/path/to/file.rb",
|
|
164
|
+
"start_line": 10,
|
|
165
|
+
"start_col": 4,
|
|
166
|
+
"end_line": 10,
|
|
167
|
+
"end_col": 20,
|
|
168
|
+
"values": ["..."],
|
|
169
|
+
"total": 123
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## CLI
|
|
174
|
+
|
|
175
|
+
### `lumitrace`
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
lumitrace [options] script.rb [ruby_opt]
|
|
179
|
+
lumitrace [options] exec CMD [args...]
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
- Text is rendered by default (from in-memory events; no JSON file is required).
|
|
183
|
+
- `-t` enables text output to stdout. `--text=PATH` writes to a file.
|
|
184
|
+
- `-h` enables HTML output (default path). `--html=PATH` writes to a file.
|
|
185
|
+
- `-j` enables JSON output (default path). `--json=PATH` writes to a file.
|
|
186
|
+
- `-g` enables git diff with `working` mode. `--git-diff=MODE` selects `staged|base:REV|range:SPEC`.
|
|
187
|
+
- `--max` sets max values per expression.
|
|
188
|
+
- `--range` restricts instrumentation per file (`FILE` or `FILE:1-5,10-12`). Can be repeated.
|
|
189
|
+
- `--git-diff=MODE` restricts instrumentation to diff hunks (`staged|base:REV|range:SPEC`).
|
|
190
|
+
- `--git-diff-context` expands hunks by +/-N lines.
|
|
191
|
+
- `--git-cmd` overrides the git executable.
|
|
192
|
+
- `--git-diff-no-untracked` excludes untracked files (untracked files are included by default).
|
|
193
|
+
- `--verbose` prints verbose logs to stderr.
|
|
194
|
+
- `LUMITRACE_VALUES_MAX` sets the default max values per expression.
|
|
195
|
+
- The CLI launches a child process (Ruby or `exec` target) with `RUBYOPT=-rlumitrace` and `LUMITRACE_*` env vars.
|
|
196
|
+
|
|
197
|
+
### Text Output (CLI)
|
|
198
|
+
|
|
199
|
+
- Text output starts with a header line: `=== Lumitrace Results (text) ===`.
|
|
200
|
+
- Each file is printed with a header: `### path/to/file.rb`.
|
|
201
|
+
- Each line is prefixed with a line number like ` 12| `.
|
|
202
|
+
- Skipped ranges are represented by a line containing `...`.
|
|
203
|
+
- 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)`).
|
|
204
|
+
- When `--text` is used and `--max` is not provided, `max_values` defaults to `1`.
|
|
205
|
+
- When `ranges_by_file` is provided, only files present in the hash are shown in text output.
|
|
206
|
+
|
|
207
|
+
## HTML Rendering
|
|
208
|
+
|
|
209
|
+
- `GenerateResultedHtml.render_all` renders all files in one page.
|
|
210
|
+
- Each file is shown in its own section.
|
|
211
|
+
- Expressions are marked with an inline icon.
|
|
212
|
+
- Hovering the icon shows recorded values.
|
|
213
|
+
- Only the last 3 values are shown in the tooltip; additional values are summarized as `... (+N more)`.
|
|
214
|
+
- Tooltip is scrollable horizontally for long values.
|
|
215
|
+
|
|
216
|
+
### Copy/Paste Behavior
|
|
217
|
+
|
|
218
|
+
- Inline icon uses a separate marker span to reduce copy/paste artifacts.
|
|
219
|
+
- Lines are rendered as inline spans with explicit `\n` inserted.
|
|
220
|
+
|
|
221
|
+
## Known Limitations
|
|
222
|
+
|
|
223
|
+
- Requires `RubyVM::InstructionSequence.translate` support in the Ruby build.
|
|
224
|
+
- Instrumentation is for debugging; semantics may change for unusual edge cases.
|
|
225
|
+
- 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.
|