Search code examples
rubymetaprogramminghttparty

Inherit HTTParty module


How can I inherit HTTParty module to set some default values?

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

I need to have some customized module, that can be included in client classes and behave like native HTTParty module.


Solution

  • If the only intent is to set default values and not to re-define methods the following would do the trick:

    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
    

    When you include SuperClient it will then include HTTParty and set some defaults. If this is the only functionality you need this is your answer if you're also planning on re-defining methods read further.


    This does not work if you're planning to redefine methods. HTTParty will be added to the ancestor stack before SuperClient. When calling methods defined by both SuperClient and HTTParty the HTTParty variant will be called first, meaning the SuperClient variant will never be reached.

    This might be more info than you need, but the above issue can be solved by doing:

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

    By including InstanceMethods and extending ClassMethods after including HTTParty they will sit higher up the stack, allowing you to re-define methods and call 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