2012-01-06 21 views
9

Biorąc pod uwagę klejnot, który definiuje klasy najwyższego poziomu, które kolidują z pisanym przeze mnie kodem, możliwe jest wymaganie klejnotu w taki sposób, aby wszystkie jego klasy zostały zgrupowane w module Mogę zdefiniować? Na przykład, jeśli unsafe_gem definiuje klasę:Załaduj klejnotu ruby ​​do przestrzeni nazw zdefiniowanej przez użytkownika

class Word 
    # ... some code 
end 

musiałbym coś takiego:

class Word 
    # My word class. 
end 

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

tak, że można rozróżnić:

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

niektórych dalszych szczegółów: Mój kod (np. Klasa "Word") jest już zapakowany w swoją własną przestrzeń nazw. Chciałbym jednak móc udostępnić użytkownikowi opcję włączania formy "cukru syntaktycznego", dzięki czemu niektóre klasy są bezpośrednio dostępne w obszarze nazw najwyższego poziomu. Powoduje to jednak konflikt nazwy z jednym z klejnotów, z których korzystam, który definiuje klasę najwyższego poziomu. Żadne z obecnie proponowanych rozwiązań nie działa, ponieważ gem faktycznie opiera się na swojej globalnie zdefiniowanej klasie; więc undefining klasy łamie klejnot. Oczywiście klejnot ma więcej niż jeden plik, a indywidualne zapotrzebowanie na jego pliki w module wydaje się bardzo kruchym rozwiązaniem. Obecnie jedyne obejście, które znalazłem, to:

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 

Nie wiem dlaczego, ale to powoduje, że moje paznokcie się zwijają. Ktoś ma lepsze rozwiązanie?

Odpowiedz

4

Kolejna, prawdopodobnie lepsza odpowiedź, pochodzi z pytania: this.

skorzystać z faktu, że klasy i moduły są tylko obiekty, tak jak poniżej:

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 

Musisz upewnić się, że unsafe_gem definiuje tylko jedną klasę i że require to zanim definiować własne klasy i moduły, aby przypadkowo nie ustawić własnych rzeczy na nil.

1

Myślę, że najlepiej jest zawinąć własny kod w moduł. W zależności od tego, ile napisałeś kodu, może to być bolesne lub nie. Jednak jest to najlepszy sposób, aby upewnić się, że Twój kod nie będzie kolidował z cudzymi.

Więc twoja klasa Word staje

module LoismsProject 
    class Word 
    #some awesome code 
    end 
end 

ten sposób można bezpiecznie require 'unsafe_gem'.

0

Prosta odpowiedź brzmi „nie”

Jeśli mamy plik „word.rb”;

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

i staramy i require go, to zawsze ładować w zasięgu globalnym.

Jeśli wiedziałeś, że klejnot to tylko pojedynczy plik, możesz wykonać następujące czynności.

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

, ale jest mało prawdopodobne, aby zadziałało w twoim przypadku.

Powiązane problemy