How can I redefine marco and recompile code for subclass
Let's say I have Macro.Parent class:
Include Parent
Class Macro.Parent
{
ClassMethod Test()
{
write "Class: " _ $classname() _ $c(10,13) _ "Value: " _ $$$name
}
}
which references Parent.inc macro name:
#define name "Parent"
Now, I want in my subclass Macro.Child to have Test method with the same code, but to redefine value of name macro.
Currently I have Child.inc with macro name:
#define name "Child"
And Macro.Child class:
Class Macro.Child Extends Macro.Parent
{
ClassMethod Test() [ CodeMode = objectgenerator ]
{
set parent = ##class(%Dictionary.MethodDefinition).IDKEYOpen(%class.Super, %method.Name)
do %code.WriteLine(" #include Child")
do %code.CopyFrom(parent.Implementation)
}
}So the idea is to have a subclassed method generator that injects the new macro value. Here's how that works:
>do ##class(Macro.Parent).Test() Class: Macro.Parent Value: Parent >do ##class(Macro.Child).Test() Class: Macro.Child Value: Child
But that approach has several drawbacks, such as:
- Need to write a method for each method I want to redefine
- Seems rather crude
Is there any better way to achieve that? I can't modify Macro.Parent class or Parent.inc macro.
Comments
Macro.Parent.cls:
<FONT COLOR="#000080">Include </FONT><FONT COLOR="#ff0000">ParentMacro.Child.cls:</FONT><FONT COLOR="#000080">Class Macro.Parent </FONT><FONT COLOR="#000000">{
</FONT><FONT COLOR="#000080">ClassMethod </FONT><FONT COLOR="#000000">Test() { </FONT><FONT COLOR="#0000ff">write </FONT><FONT COLOR="#008000">"Class: " </FONT><FONT COLOR="#000000">, </FONT><FONT COLOR="#0000ff">$classname</FONT><FONT COLOR="#000000">() , ! , </FONT><FONT COLOR="#008000">"Value: " </FONT><FONT COLOR="#000000">, </FONT><FONT COLOR="#0000ff">$$$name </FONT><FONT COLOR="#000000"> }
}</FONT>
<FONT COLOR="#000080">Include </FONT><FONT COLOR="#ff0000">ChildParent.inc:</FONT><FONT COLOR="#000080">Class Macro.Child Extends Macro.Parent </FONT><FONT COLOR="#000000">{
</FONT><FONT COLOR="#000080">ClassMethod </FONT><FONT COLOR="#000000">Test() { </FONT><FONT COLOR="#0000ff">write </FONT><FONT COLOR="#008000">"Class: " </FONT><FONT COLOR="#000000">, </FONT><FONT COLOR="#0000ff">$classname</FONT><FONT COLOR="#000000">() , ! , </FONT><FONT COLOR="#008000">"Value: " </FONT><FONT COLOR="#000000">, </FONT><FONT COLOR="#0000ff">$$$name </FONT><FONT COLOR="#000000"> }
}</FONT>
<FONT COLOR="#0000ff">#ifndef </FONT><FONT COLOR="#000000">name </FONT><FONT COLOR="#0000ff">#define </FONT><FONT COLOR="#000000">name </FONT><FONT COLOR="#008000">"Parent" </FONT><FONT COLOR="#0000ff">#endif name</FONT>Child.inc:
<FONT COLOR="#0000ff">#define </FONT><FONT COLOR="#000000">name </FONT><FONT COLOR="#008000">"Child"</FONT>Result:
>do ##class(Macro.Parent).Test() Class: Macro.Parent Value: Parentdo ##class(Macro.Child).Test() Class: Macro.Child Value: Child
Interesting,
Sorry, that I didn't specify it earlier, but I can't modify Parent.inc too.
Then this:
<FONT COLOR="#000080">Include </FONT><FONT COLOR="#ff0000">Childor this:</FONT><FONT COLOR="#000080">Class Macro.Child Extends Macro.Parent </FONT><FONT COLOR="#000000">{
</FONT><FONT COLOR="#000080">ClassMethod </FONT><FONT COLOR="#000000">first() { </FONT><FONT COLOR="#0000ff">#include </FONT><FONT COLOR="#000000">Child }
</FONT><FONT COLOR="#000080">ClassMethod </FONT><FONT COLOR="#000000">Test() [ </FONT><FONT COLOR="#000080">PlaceAfter </FONT><FONT COLOR="#000000">= first ] { </FONT><FONT COLOR="#0000ff">write </FONT><FONT COLOR="#008000">"Class: " </FONT><FONT COLOR="#000000">, </FONT><FONT COLOR="#0000ff">$classname</FONT><FONT COLOR="#000000">() , ! , </FONT><FONT COLOR="#008000">"Value: " </FONT><FONT COLOR="#000000">, </FONT><FONT COLOR="#0000ff">$$$name </FONT><FONT COLOR="#000000">}
}</FONT>
<FONT COLOR="#000080">ClassMethod </FONT><FONT COLOR="#000000">Test()
{
</FONT><FONT COLOR="#0000ff">#include </FONT><FONT COLOR="#000000">Child
</FONT><FONT COLOR="#0000ff">write </FONT><FONT COLOR="#008000">"Class: " </FONT><FONT COLOR="#000000">, </FONT><FONT COLOR="#0000ff">$classname</FONT><FONT COLOR="#000000">() , ! , </FONT><FONT COLOR="#008000">"Value: " </FONT><FONT COLOR="#000000">, </FONT><FONT COLOR="#0000ff">$$$name
</FONT><FONT COLOR="#000000">}</FONT>Class include is not required (and does not seem to affect anything) and can be omitted
Include Child
Why that happens, as methods generators are compiled before methods?
As for the second approach, I'd like to avoid duplicating code (in a real case I have about 20 methods 1-50 lines long).
Class include is not required (and does not seem to affect anything) and can be omittedYeah, I just forgot to delete that line.
Here's another way (without PlaceAfter):
<FONT COLOR="#000080">Class Macro.Child Extends Macro.Parent
</FONT><FONT COLOR="#000000">{
</FONT><FONT COLOR="#000080">ClassMethod </FONT><FONT COLOR="#000000">%inc() [ </FONT><FONT COLOR="#000080">Internal</FONT><FONT COLOR="#000000">, </FONT><FONT COLOR="#000080">Private </FONT><FONT COLOR="#000000">]
{
</FONT><FONT COLOR="#0000ff">#include </FONT><FONT COLOR="#000000">Child
}
</FONT><FONT COLOR="#000080">ClassMethod </FONT><FONT COLOR="#000000">Test()
{
</FONT><FONT COLOR="#0000ff">write </FONT><FONT COLOR="#008000">"Class: " </FONT><FONT COLOR="#000000">, </FONT><FONT COLOR="#0000ff">$classname</FONT><FONT COLOR="#000000">() , ! , </FONT><FONT COLOR="#008000">"Value: " </FONT><FONT COLOR="#000000">, </FONT><FONT COLOR="#0000ff">$$$name
</FONT><FONT COLOR="#000000">}
}</FONT>