cujojs/meld

Adding Advices for AMD modules

Closed this issue · 5 comments

I didn't see any examples/references to this for whether this is possible. It would be a nice to have some documentation stating the interoperability between meld and amd modules. Although this has to do more with the module loaders than meld itself, I do believe this use case is especially important considering modules are in many ways the analogue of java object encapsulation.

I'd like to know this myself: if the module returns a constructor function, could the api be used to add advices around that? What about when it returns an object?

Thanks

Hey @Badunk,

Using advice on things should be the same no matter where you get them from. :)

Here's an example from the docs with a simplified CommonJS/AMD wrapper:

define(function (require) {
    var meld = require('meld');
    var MyClass = require('myApp/MyClass');
    var anObject = require('myApp/anObject');
    var advisedFunction = meld.before(anObject, 'someFunction', beforeFunction);
    var AdvisedConstructor = meld.before(MyClass, beforeFunction);
    // ... do something amazing here!
});

Does that answer your question?

-- John

Thanks for the quick response!

From what I understand, advisedFunction and AdvisedConstructor are kept in that scope of that particular example. This means that in order for me to use the advised functions, I would have to execute them here. While surely this does not affect that module's original function, it also doesn't solve the problem of cross cutting concerns if I wish to reuse this advice in other modules.

I wish to use meld across modules to provide logging capabilities (for example) in other modules' methods. Is there a way to do that?

Hi @Badunk, you are correct that advising pure functions doesn't modify the original. There's no way in pure Javascript to change a function's behavior via a direct reference to that function. When advising methods on an object, meld does replace the original method.

There are a few options that might help here, though, depending on your situation.

First, you could create a wrapper module for the function that loads the original function, applies advice to it with meld, then returns the newly advised function. This doesn't scale well, and doesn't really address cross-cutting, but for small things, it'd work.

Second, you could look into creating an loader plugin or transform that would do broader cross-cutting weaving at the AMD module level. For example, in curl.js (cujojs's AMD loader), you could create something that intercepts module loading, applies advices via pointcuts, and then passes through a new module definition. This would effectively be AMD load-time weaving, and would be very cool. We haven't tackled this yet, because ...

wire.js, cujojs's IOC container includes wire-time weaving via its wire/aop plugin (which uses meld internally), which can cross-cut with pointcuts. So the third option would be to look into wire.js. I realize that may or may not be a realistic option for you, but wanted to at least bring it up.

Do any of those help?

Hi @briancavalier, I did consider the second option and just before you posted, I had realized that wire.js does actually addresses my needs there - very cool!

This is really clear now, but of course left without a real solution without switching to wire.js unfortunately. I'll look into whether I could do that. Thanks!

I am no expert in this, but just as a comment on how you might be able to get a direct reference to the function:

From what I know, AOP in Java utilizes lower level capabilities of the language by going outside and patching things to the compiler. AOP in actionscript has been brought up in a similar fashion by modifying byte code etc.. While javascript itself is a pretty loose/flexibile language without many of the same constraints, it could be interesting to look at esprima (http://esprima.org/) to perform reflection on javascript modules.

Thanks!

Yep, doing AST level weaving would be a very interesting option. Since we can't (yet) get at bytecode, AST is probably the next best thing :) We've toyed with the idea, but haven't had time to experiment with it. I'd love to try it sometime, though.

Great discussion, thanks.