2009-08-26 13 views
6

Mam interfejs Flickr, który napisałem jakiś czas temu, a część mnie zawodzi i chciałbym, żeby było ładniej. Sposób, w jaki to działa, to brakująca metoda do konstruowania parametrów adresu URL dla wywołania flickr z metod wywoływanych przez obiekt flickr, np.Jak wykryć koniec łańcucha metod w Ruby

@flickr.groups.pools.getPhotos(:user_id => "[email protected]", :group_id => "[email protected]") 

Te „wywołuje metodę” skonstruowania wywołanie API, które wygląda tak

http://api.flickr.com/services/rest/?method=groups.pools.getPhotos&user_id=1848466274& group_id= [email protected] 

(Zostawiłem wyłączyć bitowy klucz API) Czyni to poprzez zapamiętywanie każdym „metoda”, aż metody jest wywoływana z argumentami, w którym to czasie tworzy adres URL i wywołuje Flickr.

Powodem, dla którego podjąłem takie podejście, jest to, że kod ruby ​​pasuje do dokumentacji na stronie Flickr, można go skopiować i wkleić, i będzie to głównie działało, i mam nadzieję, że sprawi, że będzie ono bardziej odporne na zmiany API, ponieważ nie mają metod zakodowanych na sztywno.

Podrażnia to jednak tym, że w tym przykładzie identyfikator grupy jest przekazywany do metody getPhotos zamiast metody groups. Wolałbym, żeby tak wyglądało.

@flickr.groups(:group_id => "[email protected]").pools.getPhotos(:user_id => "[email protected]") 

Moje pytanie. Czy jest jakiś sposób w Rubim, że mogę wykryć, że ostatnia metoda została wywołana, abym mógł wywołać wywołanie do Flickr?

Odpowiedz

6

Ponieważ nie mogę wymyślić żadnego sposobu na wykrycie ostatniego wywołania metody, zamierzam zaproponować inne podejście. Jest podobny do tego, co robi ActiveRecord; klasa proxy, która buduje opcje i nie pobiera danych, dopóki nie wywołasz metody działającej na danych.

class Flickr 
    def initialize 
    @result = FlickrResult.new 
    end 

    def method_missing(method, *args, &block) 
    if @result.data.respond_to?(method) 
     @result.run(method, args, block) 
    else 
     @result.append(method, args[0]) 
     return self 
    end 
    end 

    class FlickrResult 
    attr_reader :data 

    def initialize 
     @data = [] 
     @keys = [] 
     @options = {} 
    end 

    def append(key, options) 
     @keys << key 
     @options.merge!(options) if options 
    end 

    def run(method, args, block) 
     if [email protected]_run 
     fetch_data 
     end 

     @data.send(method, *args, &block) 
    end 

    def fetch_data 
     puts "Only runs once!" 
     @url = @keys.join(".") + "?" + @options.map {|k, v| "#{k}=#{v}" }.join("&") 
     # use @url and fetch data.. 
     @data = ["foo", "bar"] 

     @did_run = true 
    end 
    end 
end 

@flickr = Flickr.new 
@flickr.groups(:group_id => "123").pools.thing.users(:user_id => "456") 

@flickr.each {|f| p f } 
# => "Only runs once!" 
# => "foo" 
# => "bar" 
p @flickr.map {|f| f.upcase } 
# => ["FOO", "BAR"] 

To tylko pobiera dane, gdy each lub map to czy cokolwiek (dowolny sposób array).

+0

Dlaczego "@ flickr" w zewnętrznym zakresie? Jaka jest korzyść z tego, że jest zmienną instancji obiektu w stosunku do zmiennej lokalnej? –

+0

Brak korzyści (w tym przypadku). To tylko móżdżek, nie ma w nim specjalnych rozważań :) –

+0

Tak, to była alternatywna metoda, na którą patrzyłem. I za pomocą memoizacji na atrybutach. Miałem nadzieję, że jest jakaś ostra metoda, której nie znam. – Henry

Powiązane problemy