2008-10-16 18 views
5

Mam nadzieję, że źle zrozumiałem znaczenie "pisania na maszynie", ale z tego, co przeczytałem, wynika, że ​​powinienem napisać kod na podstawie tego, jak obiekt reaguje na metody, a nie na jaki typ/klasę.Czy mogę poprawić tę metodę za pomocą typowania kaczego?

Oto kod:

def convert_hash(hash) 
    if hash.keys.all? { |k| k.is_a?(Integer) } 
    return hash 
    elsif hash.keys.all? { |k| k.is_a?(Property) } 
    new_hash = {} 
    hash.each_pair {|k,v| new_hash[k.id] = v} 
    return new_hash 
    else 
    raise "Custom attribute keys should be ID's or Property objects" 
    end 
end 

Co chcę jest, aby upewnić się, że skończę z mieszania, gdzie klucze są liczbą całkowitą reprezentującą identyfikator obiektu ActiveRecord. Nie jestem szczególnie zadowolony z konieczności powtórzenia przez klawisze mieszające dwukrotnie z all?, aby określić, czy muszę pobrać identyfikator.

Oczywiście, ja przyjmuję jakieś inne sugestie, aby poprawić ten kod, jak również :)

+0

Nigdy nawet słyszał „kaczka wpisując” wcześniej. Gdzie się z tym spotkałeś? –

+0

@Brian, http://en.wikipedia.org/wiki/Duck_typing –

Odpowiedz

11

Jak piszesz tej metody powinien zależeć od tego, czy można oczekiwać wyjątek być wyrzucane w trakcie normalnego wykonywania programu. Jeśli chcesz uzyskać czytelny komunikat wyjątku, ponieważ może to zobaczyć użytkownik końcowy, to ręczne rzucenie go ma sens. W przeciwnym razie, to bym po prostu zrobić coś takiego:

def convert(hash) 
    new_hash = {} 
    hash.each_pair { |k,v| new_hash[ k.is_a?(Integer) ? k : k.id ] = v } 
    return new_hash 
end 

Będzie to osiągnąć dokładnie to samo, a ty wciąż wyjątek, jeśli klucz tablicy nie ma pola id. Co więcej, wykorzystuje to trochę więcej pisania na klawiaturze, ponieważ teraz wszystko, co ma pole id, będzie akceptowalne, co jest lepsze niż jawne sprawdzanie, czy coś jest Własnością. Dzięki temu Twój kod jest bardziej elastyczny, szczególnie podczas testowania urządzenia.

Nadal mamy wyraźne sprawdzanie obiektów całkowitych, ale ten rodzaj przypadkowego specjalnego przypadku jest zwykle akceptowalny, szczególnie podczas sprawdzania wbudowanych typów danych.

+1

Świetna, opisowa odpowiedź z pewnym bardzo rubinowym kodem, Eli. Dziękuję bardzo za odpowiedź. –

+1

Problem polega na tym, że KAŻDY obiekt w Ruby ma metodę #id. Jest zdefiniowany w Object i daje unikalne odniesienie w tłumaczu Ruby do tego obiektu. Jest on jednak przestarzały, więc gdy otrzymasz ostrzeżenie, nie dostaniesz wyjątku. – madlep

3

Pisanie na maszynie to naprawdę zniuansowana wersja polimorfizmu. W statycznie napisanym języku, takim jak Java, musiałbyś stworzyć wyraźny interfejs, który poinformował kompilator o wszystkich metodach akceptowanych przez daną zmienną. W dynamicznym języku, jakim jest Ruby, interfejsy wciąż istnieją w abstrakcyjnym sensie, są po prostu niejawne.

Problem polega na tym, że akceptujesz dwie różne struktury danych w jedną metodę. Sposób pisania kaczek polega na tym, że wszystkie obiekty, które zostaną przekazane do Twojej metody, muszą być zgodne z tą samą umową (tj. Zawsze jest to mieszanie liczb całkowitych z obiektami [Foo].) Proces przekształcania skrótu klawiszami Property w poprawna struktura powinna być zadaniem kodu klienta. Można to zrobić bardzo łatwo za pomocą prostej klasy wrapper lub funkcji konwersji składającej się tylko z treści klauzuli elseif.

Najważniejsze, że to facet, który wywołuje metodę, aby upewnić się, że jego parametry są tak proste, jak twoja metoda oczekuje od nich szarości. Jeśli tego nie robią, to on musi się dowiedzieć, jak sprawić, by jego indyk był jak kaczka, a nie ty.

0

Co chcę jest, aby upewnić się, że skończę z mieszania, gdzie klucze są liczbą całkowitą reprezentującą identyfikator obiektu ActiveRecord.

Powinieneś prawdopodobnie sprawdzić, kiedy tworzysz/wstawiasz do hasza. Można spróbować czegoś takiego:

 
h = {} 
def h.put obj 
    self[obj.id]=obj 
end 

czy może

 
h = {} 
def h.[]= key, value 
    raise "hell" unless key == value.id 
    super 
end 
Powiązane problemy