【问题标题】:How to detect the end of a method chain in Ruby如何在 Ruby 中检测方法链的结束
【发布时间】:2009-08-26 04:58:29
【问题描述】:

我有一个不久前写的 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 的调用?

【问题讨论】:

    标签: ruby metaprogramming


    【解决方案1】:

    由于我想不出任何方法来检测最后的方法调用,我将建议一种不同的方法。它类似于 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 它或其他任何东西(任何数组方法)时获取数据。

    【讨论】:

    • 为什么在外部范围内使用“@flickr”?将其作为 Object 的实例变量与局部变量相比有什么优势?
    • 没有优势(在这种情况下)。只是一个脑残,没有特殊考虑:)
    • 是的,这是我看过的另一种方法。并在属性上使用记忆。我希望有一些我不知道的时髦方法。
    • 这不是我所希望的答案,但它看起来是我追求的最佳方式。
    • 请记住,实现method_missing 的类也应该实现respond_to_missing?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-12
    • 1970-01-01
    相关资源
    最近更新 更多