module HTTPClient::IncludeClient
def include_http_client(*args, &block)
def include_http_client(*args, &block) # We're going to dynamically define a class # to hold our state, namespaced, as well as possibly dynamic # name of cover method. method_name = (args.last.delete(:method_name) if args.last.kind_of? Hash) || :http_client args.pop if args.last == {} # if last arg was named methods now empty, remove it. # By the amazingness of closures, we can create these things # in local vars here and use em in our method, we don't even # need iVars for state. client_instance = nil client_mutex = Mutex.new client_args = args client_block = block # to define a _class method_ on the specific class that's currently # `self`, we have to use this bit of metaprogramming, sorry. (class << self; self ; end).instance_eval do define_method(method_name) do # implementation copied from ruby stdlib singleton # to create this global obj thread-safely. return client_instance if client_instance client_mutex.synchronize do return client_instance if client_instance # init HTTPClient with specified args/block client_instance = HTTPClient.new(*client_args) client_block.call(client_instance) if client_block end return client_instance end end # And for convenience, an _instance method_ on the class that just # delegates to the class method. define_method(method_name) do self.class.send(method_name) end end