ek9_extract_variable
Inserts `name <- expression` before the first occurrence and replaces every matching occurrence in the enclosing block with the name; answers status, edits[] and summary, a side-effecting multi-occurrence expression as conflicts[].
When to use it
'Name the repeated items.sum() * taxRate as subtotal' is one call with file, expression:'items.sum() * taxRate' and name:'subtotal' - no line or column.
When not to use it
- A LITERAL that belongs in the module `defines constant` block - use
ek9_extract_constant. - A multi-statement BLOCK of code, not a single expression - use
ek9_extract_method. - The value should outlive the local - a class FIELD (use
ek9_introduce_field) or a PARAMETER propagated to call sites (useek9_introduce_parameter). - Collapsing an existing local back into its uses (the inverse) - use
ek9_inline_variable.
Details
Anchored by the outermost expression parse-node that EXACTLY spans the located text (its first occurrence outside a comment, on 'line' when given, or the IDE's 1-based startColumn..endColumn); a misaligned span returns status:'conflicts' (kind 'expression-spans-statement-boundaries'), a line outside any body is an error. Replacement is whitespace-insensitive and confined to the anchor's nearest enclosing instruction block (nested sub-blocks included). A call-bearing expression with multiple occurrences under replaceAll returns status:'conflicts' (kind 'expression-has-side-effects-and-multiple-occurrences' - the call would run once instead of N times); set replaceAll:false to take just the anchor; a name colliding in scope conflicts as 'name-collision'.
Arguments
| Argument | Type | Required | What it is |
|---|---|---|---|
endColumn | integer | 1-based EXCLUSIVE column of the END of the span (an IDE selection). Omit it - pass the text instead. | |
explicitType | string | Optional. Emits `name as <Type>: expression` instead of the inferred `name <- expression` form. | |
expression | string | yes | The expression exactly as written in the source ('base * base'); its first occurrence is the anchor. |
file | string | yes | The .ek9 source file (workspace-relative; an absolute path inside the workspace is accepted). |
line | integer | Optional 1-based line of the occurrence to anchor on. Omit it - the expression text is enough. | |
name | string | yes | Identifier for the new local. camelCase by EK9 convention; placeholder names (temp/data/value/…) are rejected. |
replaceAll | boolean | When true (default) replaces EVERY matching occurrence in the enclosing block; when false replaces only the located occurrence. | |
startColumn | integer | 1-based column of the START of the span on 'line' (an IDE selection). Omit it - pass the text instead. |
It also takes the arguments every tool takes.
Recorded calls
Real calls, recorded against small projects and checked on every build - a changed answer fails it. 3 of the 4 recorded are shown.
Expression in two functions no line refused
Request
{
"expression" : "price * rate",
"file" : "task.ek9",
"name" : "charge"
}
Response
{
"conflicts" : [ ],
"edits" : [ ],
"error" : {
"message" : "expression 'price * rate' is on lines [11, 18], in different bodies - pass line (one of [11, 18]) to say which one to extract."
},
"meta" : {
"serverMs" : "<timing>"
},
"status" : "error",
"summary" : "expression 'price * rate' is on lines [11, 18], in different bodies - pass line (one of [11, 18]) to say which one to extract.",
"wouldBeDiagnostics" : [ ],
"written" : false
}
Occurrence after a write not replaced
Request
{
"expression" : "total * 2",
"file" : "task.ek9",
"name" : "doubled"
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"after" : " doubled <- total * 2",
"endLine" : 9,
"file" : "task.ek9",
"startLine" : 9,
"type" : "insert"
}, {
"after" : " stdout.println($ doubled)",
"before" : " stdout.println($ (total * 2))",
"endLine" : 9,
"file" : "task.ek9",
"startLine" : 9,
"type" : "replace"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 2,
...
Cut short here: 9 more lines. The whole recorded call.
Return initialiser extracted
Request
{
"expression" : "price * (1.0 + rate)",
"file" : "task.ek9",
"name" : "gross"
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"after" : " <- rtn as String?",
"before" : " <- rtn as String: `net ${price} gross ${price * (1.0 + rate)} tax ${price * (1.0 + rate) - price}`",
"endLine" : 10,
"file" : "task.ek9",
"startLine" : 10,
"type" : "replace"
}, {
"after" : " gross <- price * (1.0 + rate)\n rtn: `net ${price} gross ${gross} tax ${gross - price}`",
"endLine" : 11,
"file" : "task.ek9",
"startLine" : 11,
"type" : "insert"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 2,
...
Cut short here: 9 more lines. The whole recorded call.
See also
- Show me in the IDE: Chapter 2: values, reshaped
- Show me in the IDE: Extract Variable
- Fixes E11064