2011-11-22 3 views
7

Ho riscontrato un problema con le istanze mancanti e gli errori nilClass durante la chiamata ai percorsi. Dopo aver esplorato la fonte, sembra che la chiamata generate_method crei fondamentalmente un nuovo metodo usando il blocco del metodo iniziale.Come aggirare la mancanza di contesto nei metodi di route di Sinatra

get "/" do 
    @some_local_instance.do_something() 
end 

Così nel metodo sopra ci potrebbero benissimo essere una variabile locale all'interno di tale classe denominata some_local_instance, tuttavia quando il meccanico è effettivamente valutata non ha alcun contesto da cui è stato definito il metodo, così sarà sicuro.

Il motivo che mi chiedo è perché, come parte del mio scritto ho classi esterne che vengono caricati quando Sinatra è caricato che registrano i percorsi e quando questi percorsi sono chiamati ho bisogno di accedere ad alcune variabili locali su queste classi. Un esempio potrebbe essere:

class SomeRouteClass 
    def initialize(sinatra, calculator) 
     @calculator = calculator 
     @sinatra = sinatra 
    end 

    def setup_routes 
     @sinatra.get "/add" do 
      return @calculator.add(1,1) 
     end 
    end 
end 

class Calculator 
    def add(a,b) 
     return a+b; 
    end 
end 

sinatra = Sinatra.new 
calculator = Calculator.new 

routing_class = SomeRouteClass.new(sinatra, calculator) 
routing_class.setup_routes 

sinatra.run! 

Perdonate eventuali errori di ortografia/sintassi Questo è solo un esempio veloce, ma come si può vedere una classe registra percorsi e quando questo percorso viene colpito restituisce un valore generato da un'istanza della calcolatrice ci sono voluti quando è stato istanziato.

Problema che ho è che in questo esempio quando provo ed eseguo il percorso/add mi dice che @calculator è un nilClass, e credo che sia dovuto al modo in cui Sinatra prende solo il blocco del codice senza contesto. Questo sembra perfetto per qualsiasi semplice rendering di template, ma se hai bisogno di fare qualcosa di più stravagante, o vuoi mantenere il tuo codice modulare non usando statica e singleton, non sembra che tu abbia alcun modo per aggirare questo ...

Are le mie supposizioni sono corrette qui? e se è così, c'è un modo per mantenere il contesto come sembra che mi costringa a scrivere codice cattivo e difficile da mantenere se devo scrivere tutto come statica e singleton per interagire da una rotta.

== Modifica ==

hanno ristrutturato la questione e contenuti per riflettere più accuratamente il problema reale, ora che ho una comprensione più solida della biblioteca.

+1

Dopo guardando attraverso la fonte un po ', sembra che si limita a copiare e incollare il metodo che viene utilizzato con una rotta in un nuovo metodo usando define_method. Quindi non esiste un contesto al di fuori di quel metodo ... il che implica che l'unico modo per aggirare sarebbe quello di rendere tutto statico, che sembra solo sbagliato ... poiché è più difficile cambiarlo e testarlo in questo modo ... Potrei essere completamente sbagliato su ciò che sta facendo però come Ruby è ancora un nuovo linguaggio per me. – Grofit

+0

Ho cercato di usare il modello di oggetto const per aggirare questo, ma questo sta ancora rendendo le cose DAVVERO sgradevoli come TUTTO deve essere statico perché questo funzioni ... c'è un motivo per cui copiano il metodo body in un nuovo metodo quindi perde tutto il contesto? come non riesco a vedere alcun beneficio ad esso, solo inconvenienti ... anche se ancora una volta sono nuovo a questo, quindi potrebbe non comprendere appieno alcune complicazioni che richiede questo. L'unica cosa che posso pensare è che l'oggetto body del metodo può essere ripulito o il metodo può essere aggiornato o rimosso dall'istanza prima che venga chiamato, tuttavia ciò non sembra probabile – Grofit

risposta

0

io non accetto questa risposta, ma dopo aver fatto più ricerca è possibile che in un linguaggio dinamico come classi statiche di Ruby non sono tali da incubo dal punto di vista della manutenzione.

Sembra che la maggior parte delle librerie di Ruby funzionino contro istanze statiche (o derivazioni) che ottengono l'installazione poi utilizzata ... questo mi sembra ancora un po 'strano, come nel punto di vista del provider di database. È molto semplice chiamare la classe statica del database e connettersi al database e quindi avviare la query, ma se è necessario connettersi a 2 database separati contemporaneamente. Dovresti continuare a scambiare i server con la stessa classe statica che sarebbe problematica.

In ogni caso è sembra al momento, come la risposta è solo fare una costante per tutto ciò che è necessario per esporre su un percorso, quindi quando si prova basta impostare tale const su un finto. Sembra ancora un po 'pazzo chiamare queste cose come, quando in realtà non sono delle vere coscette nel vero senso della parola dato che possono essere cambiate in qualsiasi momento ... come molte cose ai nuovi sviluppatori di rubini, sembra solo confondere per il bene di it (es. elsif, @@ blah, caso variabile che definisce se è const o no).

Come ho detto, non accetterò questa risposta se qualcun altro può mostrarmi un modello migliore per farlo, ma per il momento gli darò qualche giorno in più.

+0

Sembra che con l'aiuto di un aiutante si possa inserire un po 'di logica all'interno, ma comunque non è piacevole. Sto guardando Padrino come se almeno fornisse un controller e un helper per controller con l'aspetto di esso, incapsulando meglio i tuoi dati e la logica, ma questo è tutto appena costruito su sinatra, quindi ci deve essere la possibilità di farlo all'interno di la build predefinita di Sinatra. – Grofit

-2
class SomeRouteClass 
    def initialize(sinatra, calculator) 
     @calculator = calculator 
     @sinatra = sinatra 
    end 

    def calculator 
     @calculator 
    end 

    def setup_routes 
     @sinatra.get "/add" do 
      return calculator.add(1,1) 
     end 
    end 
end 
+1

Provoca un'eccezione: variabile locale indefinita o calcolatrice 'del metodo 'for # <# : 0x29c9a60>, vedo cosa stai cercando di fare lì, ma sembra ancora strano. Come sicuramente quando registri un percorso che stai pronunciando per PATTERN-X, chiama METHOD-Y, ma Sinatra non fa altro che cogliere il metodo e classificare la classe intorno ad esso? quindi non ha più alcun contesto per l'ambito al di fuori di tale metodo? – Grofit

0

Il blocco passato a get viene valutato in un contesto diverso dall'oggetto Calculator. Probabilmente Sinatra chiama lo instance_eval o uno dei suoi cugini. Tuttavia, dovrebbe essere possibile catturare le variabili locali dal campo circostante, usando qualcosa come il seguente (ahimè non testato,) approccio:

def setup_routes 
    calculator = @calculator 
    @sinatra.get "/add" do 
     return calculator.add(1,1) 
    end 
end