2009-08-26 10 views
6

Tengo una interfaz de Flickr que escribí hace un tiempo y parte de eso me molesta y me gustaría hacerlo más agradable. La forma en que funciona es utilizar el método que falta para construir los parámetros url para la llamada flickr de los métodos llamados en el objeto flickr, por ejemplo.Cómo detectar el final de una cadena de métodos en Ruby

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

Estos 'método llama' construir una llamada a la API que tiene este aspecto

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

(He dejado fuera de la barba de la llave API) Para ello, recordando cada uno 'método' hasta que un método se invoca con argumentos en cuyo momento construye la url y hace la llamada a Flickr.

La razón por la que tomé este enfoque es para que el código de rubí coincida con la documentación en el sitio de Flickr, puede copiarlo y pegarlo y funcionará principalmente, y con suerte lo hará un poco más resistente a los cambios de API porque no tiene métodos codificados

Lo que irrita acerca de esto es que en este ejemplo, la identificación del grupo se pasa al método getPhotos en lugar del método de grupos. Preferiría que se viera así.

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

Así que mi pregunta. ¿Hay alguna forma en Ruby en la que pueda detectar que se ha llamado al último método para poder activar la llamada a Flickr?

Respuesta

6

Como no se me ocurre ninguna manera de detectar la última llamada al método, voy a sugerir un enfoque diferente. Es similar a lo que ActiveRecord hace; una clase de proxy que crea las opciones y no busca los datos hasta que se llama a un método que opera en los datos.

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"] 

Sólo recoge los datos cuando each o map o lo que sea (cualquier método de matriz).

+0

¿Por qué "@flickr" en el ámbito externo? ¿Cuál es la ventaja de convertirlo en una variable de instancia de Object frente a una variable local? –

+0

Sin ventaja (en este caso). Simplemente un brainfart, no hay consideraciones especiales en él :) –

+0

Sí, este era un método alternativo que había examinado. Y usando memoization en los atributos. Esperaba que hubiera algún método funky del que no tengo conocimiento. – Henry

Cuestiones relacionadas