2012-01-06 18 views
9

Data una gemma che definisce le classi di livello superiore che si scontrano con il codice che ho scritto, è possibile richiedere la gemma in modo tale che tutte le sue classi siano raggruppate all'interno di un modulo Posso definire? Ad esempio, se un unsafe_gem definisce una classe:Carica Ruby gem in uno spazio dei nomi definito dall'utente

class Word 
    # ... some code 
end 

avrei bisogno di qualcosa di simile:

class Word 
    # My word class. 
end 

module SafeContainer 
    # This obviously doesn't work 
    # (i.e. the gem still defines ::Word). 
    require 'unsafe_gem' 
end 

In modo che posso distinguere tra:

Word.new # => The class I defined. 
SafeContainer::Word.new # => The class defined by the gem. 

Alcuni ulteriori dettagli: Il mio codice (ad esempio la classe 'Word') è già incluso nel proprio spazio dei nomi. Tuttavia, voglio essere in grado di fornire all'utente la possibilità di abilitare una forma di "zucchero sintattico", che rende alcune classi direttamente accessibili sotto lo spazio dei nomi di primo livello. Questo, tuttavia, crea un conflitto di nomi con una delle gemme che sto usando, che definisce una classe di alto livello. Nessuna delle soluzioni attualmente proposte funziona perché la gemma si basa effettivamente sulla sua classe globalmente definita; così indefinendo la classe si rompe la gemma. Naturalmente, la gemma ha più di un file, e singolarmente richiedendo i suoi file in un modulo sembra essere una soluzione molto fragile. Attualmente, l'unica soluzione che ho trovato è questo:

begin 
    # Require the faulty gem. 
    require 'rbtagger' 
rescue 
    # If syntactic sugar is enabled... 
    if NAT.edulcorated? 
    # Temporarily remove the sugar for the clashing class. 
    Object.const_unset(:Word); retry 
    else; raise; end 
ensure 
    # Restore syntactic sugar for the clashing class. 
    if NAT.edulcorated? 
    Object.const_set(:Word, NAT::Entities::Word) 
    end 
end 

Non so perché, ma questo rende le unghie dei piedi curl. Qualcuno ha una soluzione migliore?

risposta

4

Un'altra risposta, possibilmente migliore, viene dalla domanda this.

Approfittate del fatto che le classi ei moduli sono solo oggetti, in questo modo:

require 'unsafe_gem' 
namespaced_word = Word 
Word = nil 


# now we can use namespaced_word to refer to the Word class from 'unsafe_gem' 

#now your own code 
class Word 
    #awesome code 
end 

Bisogna fare in modo che unsafe_gem definisce una sola classe, e che si require prima di definire le proprie classi e moduli in modo da non impostare accidentalmente le tue cose su nil.

1

Penso che la soluzione migliore sia quella di avvolgere il proprio codice in un modulo. A seconda della quantità di codice che hai scritto, questo può o non può essere un enorme dolore. Tuttavia, è il modo migliore per essere sicuro che il tuo codice non si scontrerà con quello di qualcun altro.

Quindi la classe Word diventa

module LoismsProject 
    class Word 
    #some awesome code 
    end 
end 

In questo modo si può tranquillamente require 'unsafe_gem'.

0

La semplice risposta è "no"

Se abbiamo un file 'word.rb';

class Word 
    def say 
    puts "I'm a word" 
    end 
end 

e cerchiamo di require, esso sarà sempre caricare in ambito globale.

Se si sapeva che la gemma era solo un singolo file, si potrebbe, tuttavia, eseguire quanto segue.

module SafeContainer 
    module_eval(File.read("word.rb")) 
end 

ma è improbabile che funzioni nel tuo caso.

Problemi correlati