如何在Ruby中检测方法链的结尾

时间:2009-08-26 04:58:30

标签: ruby metaprogramming

我有一个我前一段时间写过的Flickr界面,其中一部分困扰我,我想让它变得更好。它的工作方式是我使用方法缺失来从flickr对象上调用的方法构造flickr调用的url参数,例如。

@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更改更有弹性,因为我有没有硬编码方法。

令人恼火的是,在这个例子中,组ID被传递给getPhotos方法而不是groups方法。我宁愿它看起来像这样。

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

所以我的问题。在Ruby中是否有任何方法可以检测到最后一个方法已被调用,以便我可以触发对Flickr的调用?

1 个答案:

答案 0 :(得分:6)

由于我无法想出任何方法来检测最后一个方法调用,我将建议采用不同的方法。它类似于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"]

它仅在您eachmap或其他任何方式(任何数组方法)时获取数据。