Michael_Scharf
Michael_Scharf

Reputation: 34498

How to write a function in coffeescript that wraps around another function?

Suppose I want to wrap an arbitrary function to add something like logging (or anything else). The wrapper should be generic and work for any f which can be called with any kind of parameters.

createWrapper= (f) ->
   wrapper= -> 
     # do the logging or whatever I want before I call the original
     result= ???
     # do whatever after the original function call
     result

Usage would be:

g=createWrapper(f)

now g should be called in any way f would be called, like

result = g(1,2,3)

should return the same as

result = f(1,2,3)

And now I can use g wherever I would use f but it calls my wrapper function.

My question is: how should I call f to get the result?

Upvotes: 1

Views: 76

Answers (2)

Michael_Scharf
Michael_Scharf

Reputation: 34498

The answer is

f.apply @, arguments

Therefore the wrapper looks like

createWrapper= (f) ->
   -> 
     # do the logging or whatever I want before I call the original
     result= f.apply @, arguments
     # do whatever after the original function call
     result

or if you don't want to do anything after the call

createWrapper= (f) ->
   -> 
     # do the logging or whatever I want before I call the original
     f.apply @, arguments

or if you want to be a bit more explicit, you can use a splat. This has the advantage that the arguments are a list and you can apply list operations on the arguments.

createWrapper= (f) ->
   (args...) -> 
     # do the logging or whatever I want before I call the original
     result= f.apply @, args
     # do whatever after the original function call
     result

Here is some test code:

createWrapper= (f) ->
   (args...) -> 
     # do the logging or whatever I want before I call the original
     result= f.apply @, args
     # do whatever after the original function call
     result

class cl
   i: 10
   f: (x) ->
     x + @i
   getf: (x) ->
     (x)=>@f(x)

c =new cl
f1 = c.getf()
g1 = createWrapper(f1)
if f1(1)!=g1(1)
   throw new Error("failed f1 #{f1 1} != #{g1 1}")

f2 = (x) -> x+20
g2 = createWrapper(f2)
if f2(1)!=g2(1)
   throw new Error("failed f2 #{f2 1} != #{g2 1}")


f3 = (args...) -> "#{args}"
g3 = createWrapper(f3)
if f3(1,2,3)!=g3(1,2,3)
   throw new Error("failed f3 #{f3 1,2,3} != #{g3 1,2,3}")

f4 = -> arguments[0]
g4 = createWrapper(f4)
if f4(1)!=g4(1)
   throw new Error("failed f4 #{f4 1} != #{g4 1}")

f5 = c.f
g5 = createWrapper(f5)
if f5.apply(c,[1])!=g5.apply(c,[1])
   throw new Error("failed f5 #{f5.apply c,[1]} 1= #{g5.apply c,[1]}")

alert("""
Everything is OK:
   f1 #{f1 1} == #{g1 1} 
   f2 #{f2 1} == #{g2 1} 
   f3 #{f3 1,2,3} == #{g3 1,2,3} 
   f4 #{f4 1} == #{g4 1} 
   f5 #{f5.apply c,[1]} == #{g5.apply c,[1]} 
""")

Upvotes: 2

Valery Viktorovsky
Valery Viktorovsky

Reputation: 6726

Just run f()

createWrapper = (f) ->
  wrapper= -> 
    # do the logging or whatever I want before I call the original
    result= f()
    # do whatever after the original function call
    result

Upvotes: 0

Related Questions