Как определить конец цепочки методов в Ruby - PullRequest
6 голосов
/ 26 августа 2009

У меня есть интерфейс Flickr, который я написал некоторое время назад, и часть его беспокоит меня, и я хотел бы сделать его лучше. Как это работает, я использую метод отсутствия для создания параметров url для вызова flickr из методов, вызываемых для объекта flickr, например.

@flickr.groups.pools.getPhotos(:user_id => "12656878@N06", :group_id => "99404851@N00")

Эти "вызовы методов" создают вызов API, который выглядит следующим образом

http://api.flickr.com/services/rest/?method=groups.pools.getPhotos&user_id=1848466274& group_id= 99404851@N00

(я оставил бит ключа API) Это делается путем запоминания каждого «метода» до тех пор, пока метод не будет вызван с аргументами, и в этот момент он создает URL-адрес и выполняет вызов Flickr.

Причина, по которой я выбрал этот подход, состоит в том, что код ruby ​​соответствует документации на сайте Flickr, вы можете скопировать и вставить его, и он будет в основном работать, и, надеюсь, он сделает его немного более устойчивым к изменениям API, поскольку у меня есть нет жестко закодированных методов.

Что раздражает в этом, так это то, что в этом примере идентификатор группы передается в метод getPhotos, а не в методе groups. Я бы предпочел, чтобы это выглядело так.

@flickr.groups(:group_id => "99404851@N00").pools.getPhotos(:user_id => "12656878@N06")

Итак, мой вопрос. Есть ли способ в Ruby, который я могу обнаружить, что последний метод был вызван, чтобы я мог вызвать вызов Flickr?

1 Ответ

6 голосов
/ 26 августа 2009

Поскольку я не могу придумать какой-либо способ обнаружения последнего вызова метода, я собираюсь предложить другой подход. Это похоже на то, что делает ActiveRecord; прокси-класс, который создает параметры и не извлекает данные, пока вы не вызовете метод, который работает с данными.

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 !@did_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"]

Он извлекает данные только тогда, когда вы each или map извлекаете их или что-либо еще (любой метод массива).

...