ek9_extract_trait
Appends a new 'defines trait' block declaring the chosen methods as abstract, adds 'with trait of <Name>' to the class header and 'override' to each method; answers status, edits[] and summary, a non-extractable member as conflicts[] (member-not-extractable-to-trait).
When to use it
'Pull validate out of CustomerOrder into a Validatable trait' is one call with symbol:'CustomerOrder', members:['validate'] and name:'Validatable'.
When not to use it
- Extracting a CODE BLOCK into a method on the SAME class, not a method into a trait - use
ek9_extract_method. - The trait already EXISTS and you want to add its implementation on a class that declares it - use
ek9_implement_methods. - The class should DELEGATE to a trait via a field ('with trait of T by field'), not BE the impl - use
ek9_generate_delegation. - Promoting a method to a SUPERCLASS rather than a separate trait - use
ek9_pull_up. - The member is private/protected - traits are public-only (E07270); raise visibility first with
ek9_change_visibility, or keep it on the class.
Details
Class targets only - records/components/functions error. A named method that is not a public, non-operator method of the class (not found, private/protected, an operator, or a field per E07075) returns status:'conflicts' (kind 'member-not-extractable-to-trait'), not an error. 'override' is always prepended on the class per E05120 - no opt-out; V1 appends the new 'defines trait' block to the SAME file, declaring the methods 'as abstract' (the class keeps its bodies).
Arguments
| Argument | Type | Required | What it is |
|---|---|---|---|
file | string | The EK9 source file - OPTIONAL when symbol is a construct name; required to anchor on a member or a use site. | |
line | integer | 1-based line of the declaration or a reference - OMIT it and pass symbol:'<name>' to let the tool find the line (a model counting lines in a file miscounts); if you do count, use ek9_read_file(lineNumbers:true). | |
members | array of string | yes | Names of PUBLIC methods on the class to extract into the trait. |
name | string | yes | The new trait's identifier (PascalCase by convention). Must not already exist in the file. |
symbol | string | yes | The class whose methods move to the trait - a bare name ('CustomerOrder') finds its file and declaration workspace-wide; 'mod::CustomerOrder' when the name is declared in two modules. |
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.
Non class error
Request
{
"file" : "rec.ek9",
"line" : 6,
"methods" : [ "x" ],
"traitName" : "HasPoint"
}
Response
{
"conflicts" : [ ],
"edits" : [ ],
"error" : {
"message" : "'Point' is a record — extract-trait targets classes only"
},
"meta" : {
"serverMs" : "<timing>"
},
"status" : "error",
"summary" : "'Point' is a record — extract-trait targets classes only",
"wouldBeDiagnostics" : [ ],
"written" : false
}
Name collision conflict
Request
{
"file" : "payment.ek9",
"line" : 6,
"methods" : [ "process" ],
"traitName" : "PaymentProcessor"
}
Response
{
"conflicts" : [ {
"kind" : "name-collision-with-existing-trait",
"message" : "Pick a different trait name — 'PaymentProcessor' is already declared"
} ],
"edits" : [ ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 0,
"lineCount" : 0,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "conflicts",
"summary" : "A construct named 'PaymentProcessor' already exists in this file",
"workspaceHash" : "<workspace-hash>",
"wouldBeDiagnostics" : [ ],
"written" : false
}
Apply creates trait
Request
{
"file" : "payment.ek9",
"line" : 6,
"methods" : [ "process", "refund" ],
"traitName" : "Payment"
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"after" : "\n defines trait\n Payment\n\n process() as abstract\n -> amount as Float\n <- rtn as Boolean?\n\n refund() as abstract\n -> amount as Float\n <- rtn as Boolean?\n",
"endLine" : 14,
"file" : "payment.ek9",
"startLine" : 14,
"type" : "insert"
}, {
"after" : " PaymentProcessor with trait of Payment",
"before" : " PaymentProcessor",
"endLine" : 6,
"file" : "payment.ek9",
"startLine" : 6,
"type" : "replace"
}, {
"after" : " override process()",
"before" : " process()",
"endLine" : 7,
"file" : "payment.ek9",
"startLine" : 7,
"type" : "replace"
}, {
"after" : " override refund()",
...
Cut short here: 23 more lines. The whole recorded call.
See also
- Show me in the IDE: Extract Trait