Implement Python decorators in CoffeeScript

After wondering about expressive coffeescript support for metaprogramming, we've found with @fredZen some pattern for simulating some features like decorators, as found in Python
What is a decorator in python : simply a wrapper for a function, (a function which takes a function as parameter and returns a function, no wizardry here, coffeescript can do it), so let's write our wrapper :

# wrap is like a python decorator
wrap = (func) ->
    rf = (args...)-> # declare a function to wrap func
        alert "before func"
    rf.wrapped = true # Tag our wrapped function (for a later use)
    rf # Returns the wrapped function

So here we have a simple function for wrapping, we can use it in a class like this :

class Toto # class Toto has metaclass 'registered'
    func1: wrap -> # decorator wrap of func1
        alert "hello func1"

# Example run
toto = new Toto() 

Running this will alert a first message : 'before func' then another alert 'hello func1'.

It's a first step for wrapping function, but we can go further and use the flag by wrapping the class declaration :

# Registered acts as a wrapper for class declatation, it occurs after type construction
registered = (klass) ->
    klassName = klass.toString().match(/function ([^\(]+)/)[1] # Grab name of the class
    for name, f of klass.prototype
       if f.wrapped
          alert klassName + 'has wrapped func ' + name
registered class Toto # wrapping class Toto
    func1: wrap -> # decorator wrap of func1
        alert "hello func1"
    func2: ->
        alert "hello func2"

toto = new Toto()
Running this will alert :
  • 'Toto  has wrapped func func1'
  • 'before func'
  • 'hello func1'
  •  'hello func2'
It's some solution to the problem I have in my previous post, but it doesn't solve everything, as the class wrapper is just a wrapper, i'd like to have any extended class from Toto running the wrapping code without specifying the wrapper before class declaration, just like in metaprogramming.

Aucun commentaire: