【问题标题】:What is a better, more idiomatic way of writing this Ruby method?编写这个 Ruby 方法的更好、更惯用的方法是什么?
【发布时间】:2016-03-25 21:33:43
【问题描述】:

这是一种检查缓存并针对缓存未命中进行昂贵的 API 调用的简单方法。

    def search_for params
      cache = Cache.for( params )
      return cache if cache

      response = HTTParty.get( URL, params )
      Cache.set params, response

      response
    end

但它似乎罗嗦而不惯用。

【问题讨论】:

    标签: ruby caching refactoring


    【解决方案1】:

    Cache.set 是否返回设置的 Cache 对象?如果是这样,这可能会起作用:

    def search_for params
      Cache.for(params) || Cache.set(params, HTTParty.get( URL, params ))
    end
    

    【讨论】:

    • 虽然这很干净,但我不确定为什么 Cache#set 应该返回该值。依赖它似乎很奇怪......
    【解决方案2】:

    让我们做一些疯狂的事情。

    [][]= 添加到Cache

    Cache.instance_eval do
      alias_method :[], :for
      alias_method :[]=, :set
    end
    

    创建一个模块以重用

    module Cacheable
      def cached(key)
        Cache[key] ||= yield
      end
    
      def self.included(base)
        base.extend self
      end
    end
    

    使用Cacheable 模块

    class Foo
      include Cacheable
    
      # `cached` can be used in instance methods
      def search_for(params)
        cached(params) do
          HTTParty.get(URL, params)
        end
      end
    
      # `cached` can also be used in class methods
      def self.search_for(params)
        cached(params) do
          HTTParty.get(URL, params)
        end
      end
    end
    

    【讨论】:

    • 在某种程度上,似乎使用模块而不是缓存类可能会更好。我可以看到发出 API 请求的不同类是如何可缓存的。
    【解决方案3】:

    根据您的问题的另一个选项

    def search_for params
      unless response = Cache.for( params )
        response = HTTParty.get( URL, params )
        Cache.set params, response
      end
      response
    end
    

    【讨论】:

      【解决方案4】:

      如果您可以修改Cache#for 的实现并让它接受一个在缓存中找不到值时将执行的块,那么它可以将调用序列简化为如下所示:

      def search_for params
        return Cache.for( params ) { HTTParty.get( URL, params ) }
      end
      

      您可以添加修改后的for 方法,如下所示:

      class Cache
          # alias the original `for` as `lookup`
          singleton_class.send(:alias_method, :lookup, :for)
      
          def self.for params, &block
              value = lookup(params);
              if (block_given? and not value) then
                  value = block.call
                  set params, value
              end
              value
          end
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-04
        • 2020-07-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多