I have a class which is essentially a collection of methods for some data transformations. In another words I have some data in my files and I use a few different code snippets to transform the textual data into something that I can easily query.
Now the methods often reuse each-other and as the core data is changing I'd like to simply cache the results of each method, for the speed reasons.
I don't want to change each method by adding:
^ methodsCache ifNil: [ methodsCache := "compute" ]
I want to use the power of Pharo reflection to accomplish my task without touching much of code.
One idea that I had is if I can run some code before each method, thing I can either return a cached value or continue the execution of the method and cache it's result
You could use the Reflectivity framework to add pre and post meta links to your methods. A link could check a cache before execution transparently.
link := MetaLink new
metaObject: self;
selector: #cachedExecute:;
arguments: #(selector);
control: #before.
(MyClass>>#myMethodSelector) ast link: link.
This code will install a meta link that sends #cachedExecute:
to a MyClass
object with the argument #myMethodSelector
. The link is installed on the first AST node of the compiled method (of that same method selector, but could be on another method). The #control:
message ensures that the link will be executed before the AST node is executed.
You can of course install multiple meta links that influence each other.
Note that in the above example you must not send the same message (#myMethodSelector
) again inside of the #cachedExecute:
method since you'd end up in a loop.
Update
There's actually an error in the code above (now fixed). The #arguments:
message takes a list of symbols that define the parameters of the method specified via #selector:
. Those arguments will be reified from the context. To pass the method selector you's use the #selector
reification, for the method context the #context
reification and for method arguments #arguments
. To see which reifications are available, look at the #key
on the class side of the subclasses of RFReification
.