Recentemente ho avuto bisogno di implementare qualcosa di simile per rintracciare complicate cose riconducibili all'OO. Fondamentalmente, volevo rendere un metodo "tracciabile" senza inquinarlo troppo; quindi forse la soluzione potrebbe essere applicata anche qui.
In primo luogo, aggiungere una funzione che rende le altre funzioni tracciabile:
Function::trace = do ->
makeTracing = (ctorName, fnName, fn) ->
(args...) ->
console.log "#{ctorName}:#{fnName}"
fn.apply @, args
(arg) ->
for own name, fn of arg
@prototype[name] = makeTracing @name, name, fn
Quindi, per utilizzarlo, è sufficiente aggiungere un @trace
prima di ogni metodo che si desidera rintracciare:
class MyClass
@trace methodA: ->
@methodB 42
@trace methodB: ->
console.log "method b called with #{n}"
Oppure aggiungi @ traccia solo una volta e quindi indentare tutti i metodi tracciabili un altro livello:
class MyClass
@trace
methodA: ->
@methodB 42
methodB: (n) ->
console.log "method b called with #{n}"
Come potete vedere, trace
è un po 'un abusare della sintassi di CoffeeScript. method: -> 'foo'
all'interno di class MyClass
viene interpretata una definizione di metodo. Ma @trace method: -> 'foo'
viene interpretato chiamando la funzione trace
di MyClass
(che è un'istanza Function
, a cui è stata aggiunta la funzione trace
) passando un oggetto letterale con una chiave method
. In JavaScript sarebbe qualcosa come this.trace({method: function() {return 'foo';}})
.
La funzione trace
prenderà solo quell'oggetto e itererà le sue chiavi (i nomi dei metodi) e valori (i metodi) e aggiungerà funzioni al prototipo MyClass
che registra le loro chiamate e, a sua volta, chiama i metodi originali.
In ogni caso, l'uscita del (new MyClass).methodA()
sarà:
MyClass:methodA
MyClass:methodB
method b called with 42
Questa soluzione non funziona per i costruttori, però, in quanto non sono solo i metodi normali.
È possibile ottenere abbastanza fantasia con questo. È inoltre possibile registrare gli argomenti passati a ciascun metodo, il valore restituito e persino aggiungere il rientro per le chiamate annidate se lo si desidera (le tracce risultanti possono quindi essere molto utili se è necessario eseguire il debug di un problema complesso = D).
Aggiornamento: come un esempio più interessante, ecco una mini-versione del tipico esempio composite, figure geometriche e gruppi di figure: http://jsfiddle.net/2YuE7/ con una funzione di traccia più interessante. Tutte le cifre comprendono il metodo move
.Se abbiamo questa figura composita e chiamiamo move
su di esso:
f = new Composite [
new Rectangle 5, 10, 3, 4
new Composite [
new Circle 0, 0, 2
new Circle 0, 0, 4
new Circle 0, 0, 6
]
]
f.move 2, 3
L'output di analisi è:
(Composite[Rectangle[5,10,3,4],Composite[Circle[0,0,2],Circle[0,0,4],Circle[0,0,6]]]).move(2, 3)
| (Rectangle[5,10,3,4]).move(2, 3)
| -> Rectangle[7,13,3,4]
| (Composite[Circle[0,0,2],Circle[0,0,4],Circle[0,0,6]]).move(2, 3)
| | (Circle[0,0,2]).move(2, 3)
| | -> Circle[2,3,2]
| | (Circle[0,0,4]).move(2, 3)
| | -> Circle[2,3,4]
| | (Circle[0,0,6]).move(2, 3)
| | -> Circle[2,3,6]
| -> Composite[Circle[2,3,2],Circle[2,3,4],Circle[2,3,6]]
-> Composite[Rectangle[7,13,3,4],Composite[Circle[2,3,2],Circle[2,3,4],Circle[2,3,6]]]
Questo è molto cool. La possibilità di registrare argomenti era anche qualcosa a cui stavo pensando. Grazie! –
@FrankLoVecchio Cool. Ho aggiornato la risposta con un esempio che registra i parametri, restituisce i valori e fa rientrare i registri in base al livello di ricorsione = D – epidemian
Questa sarà una domanda StackOverflow molto utile :) –