【问题标题】:Inherit HTTParty module继承 HTTParty 模块
【发布时间】:2020-05-06 07:10:36
【问题描述】:

如何继承 HTTParty 模块来设置一些默认值?

module SuperClient
  include HTTParty

  headers 'Auth' => 'Basic'
end

module ServiceApiClient
  include SuperClient

  headers 'X-Prop' => 'Some specific data'
  base_uri 'https://example.com'

  def self.posts
    self.get '/posts'
    # Expected to send headers Auth and X-Prop
  end
end

我需要有一些自定义模块,可以包含在客户端类中,并且表现得像原生 HTTParty 模块。

【问题讨论】:

    标签: ruby metaprogramming httparty


    【解决方案1】:

    如果唯一的目的是设置默认值而不是重新定义方法,则以下方法可以解决问题:

    module SuperClient
      def self.included(base)
        base.include HTTParty
    
        # defaults
        base.headers 'Auth' => 'Basic'
        # or
        base.class_eval do
          headers 'Auth' => 'Basic'
        end
      end
    end
    

    当您包含SuperClient 时,它将包含HTTParty 并设置一些默认值。如果这是您需要的唯一功能,如果您还计划重新定义方法,这就是您的答案,请进一步阅读。


    如果您打算重新定义方法,这不会起作用。 HTTParty 将被添加到 SuperClient 之前的祖先堆栈中。当调用SuperClientHTTParty 定义的方法时,将首先调用HTTParty 变体,这意味着永远不会到达SuperClient 变体。

    这可能比您需要的更多信息,但上述问题可以通过以下方式解决:

    module SuperClient
      def self.included(base)
        base.include HTTParty
        base.include InstanceMethods
        base.extend  ClassMethods
    
        # defaults
        # ...
      end
    
      module InstanceMethods
        # ...
      end
    
      module ClassMethods
        # ...
      end
    end
    

    通过包含InstanceMethods 并在包含HTTParty 之后扩展ClassMethods,它们将位于堆栈的更高位置,允许您重新定义方法并调用super

    class C
      include SuperClient
    end
    
    # methods are search for from top to bottom
    puts C.ancestors
    # C
    # SuperClient::InstanceMethods
    # HTTParty::ModuleInheritableAttributes
    # HTTParty
    # SuperClient
    # Object
    # JSON::Ext::Generator::GeneratorMethods::Object
    # Kernel
    # BasicObject
    
    puts C.singleton_class.ancestors
    # #<Class:C>
    # SuperClient::ClassMethods
    # HTTParty::ModuleInheritableAttributes::ClassMethods
    # HTTParty::ClassMethods
    # #<Class:Object>
    # #<Class:BasicObject>
    # Class
    # Module
    # Object
    # JSON::Ext::Generator::GeneratorMethods::Object
    # Kernel
    # BasicObject
    

    【讨论】:

    • 我的最终目标不是在 SuperClient 和 ServiceApiClient 中都退出 HTTParty 的 DSL。并通过单个包含语句实现它。但我现在明白了,HTTParty 并不是为此类操作而设计的。
    • “HTTParty 的 DSL” 是什么意思?你的意思是在base.headers 'Auth' =&gt; 'Basic' 中你不想要base?因为那是可以解决的。查看更新的答案。
    【解决方案2】:

    您可以将 SuperClient 保留为一个类并从中继承其他客户端。像这样的东西。标头“Auth”和“X-Prop”都将包含在请求中。

    require 'httparty'
    
    class SuperClient 
        include HTTParty
    
        headers 'Auth' => 'Basic'
        # Uncomment below line to print logs in terminal
        # debug_output STDOUT
    end
    
    class ServiceApiClient < SuperClient
    
        headers 'X-Prop' => 'Some specific data'
        base_uri 'https://example.com'
    
        def posts
            self.class.get '/posts'
            # Expected to send headers Auth and X-Prop
      end
    end         
    
    client = ServiceApiClient.new
    
    client.posts()
    

    【讨论】:

    • 我的 ServiceApiClient 应该从其他业务类继承。这就是我寻找模块化解决方案的原因。
    猜你喜欢
    • 2023-03-21
    • 1970-01-01
    • 2016-06-24
    • 2014-01-02
    • 2020-06-27
    • 2018-02-25
    • 2012-09-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多