How to detect the end of a method chain in Ruby

前端 未结 1 1588
轮回少年
轮回少年 2021-02-04 19:05

I have a Flickr interface that I wrote a while ago and part of it bothers me and I\'d like to make it nicer. The way it works is I use method missing to construct the url parame

相关标签:
1条回答
  • 2021-02-04 19:53

    Since I can't think of any way to detect the last method call, I'm going to suggest a different approach. It is similar to what ActiveRecord does; a proxy class that builds the options and doesn't fetch the data until you call a method that operates on the data.

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

    It only fetches the data when you each or map it or whatever (any array method).

    0 讨论(0)
提交回复
热议问题