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).

Category: Editor · Compare: Extract Interface (IntelliJ / Eclipse)

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

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

ArgumentTypeRequiredWhat it is
filestringThe EK9 source file - OPTIONAL when symbol is a construct name; required to anchor on a member or a use site.
lineinteger1-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).
membersarray of stringyesNames of PUBLIC methods on the class to extract into the trait.
namestringyesThe new trait's identifier (PascalCase by convention). Must not already exist in the file.
symbolstringyesThe 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