To generate code, I used to use templates like the following (contrived example):
```smalltalk
template := 'method1
^ {returnValue}'.
template format: { #returnValue -> 2 } asDictionary
```
This is *okay* for simple cases, but can get unwieldy, and doesn't benefit from e.g. (early) compiler warnings. It is also lacking when one wants to offer the behavior as a method and also as a script with no dependencies (maybe for CI).
To overcome some of these limitations, I started saving the code template as an actual method and transforming the AST, e.g.:
```smalltalk
"Convert baseline##: method"
methodTree := (self methodNamed: selector) parseTree.
methodTree selector: #baseline:.
methodTree pragmas at: 1 put: (RBPragmaNode selector: #baseline arguments: #()).
commonBlockBody := methodTree statements first arguments last body.
commonBlockBody statements
detect: [ :e | e selector = #repository: ]
ifFound: [ :repoSetter | commonBlockBody removeNode: repoSetter ].
"Compile baseline method"
baseline compile: methodTree newSource classified: 'baseline'
```
When I started doing this, I noticed two things:
1. There were idioms that were repeated over and over.
2. It still isn't super easy to turn a method into a script with no dependencies (e.g. self sends)
So, I did a spike to wrap a few common idioms for this use case. It works like this. Say you have a method like this:
```
SmallRemoteGitRepository>>#addRemote: urlString as: nameString
"Assumes repo is loaded"
| repo remote |
repo := IceRepository registry detect: [ :e | e name = self projectName ].
remote := IceGitRemote name: nameString url: urlString.
repo addRemote: remote.
remote fetch
```
And you want to also provide it as source code for a script with no dependencies. You can do:
```
SmallRemoteGitRepository >>#scriptToAddRemote: urlString as: nameString
| method transformer |
method := SmallRemoteGitRepository methodNamed: #addRemote:as:.
transformer := method peAST_Transformer
beScript;
addStatementFirst: #projectName , ' := ' , self projectName printString;
addStatementFirst: #nameString , ' := ' , nameString printString;
addStatementFirst: #urlString , ' := ' , urlString printString;
replaceNodeDetect: [ :e | e isMessage and: [ e selector = #projectName ] ]
withNode: (RBVariableNode named: #projectName).
^ transformer newSource
```
which would generate (for example, for a particular instance):
```
| repo remote projectName |
urlString := 'git@github.com:magritte-metamodel/magritte.git'.
nameString := 'upstream'.
projectName := 'Magritte'.
repo := IceRepository registry detect: [ :e | e name = projectName ].
remote := IceGitRemote name: nameString url: urlString.
repo addRemote: remote.
remote fetch
```
So my questions are:
- Does something like this already exist?
- Are there better ways to solve this problem?
- Does this solution look promising/generally-helpful?