Ruby object declared as constant
I'd propose a 3rd way: Make it a method:

def client
  @client ||= HTTPClient.new
end

def read_page(url)
  client.get(url).body
end


There are some advantages to this:


You get the same scoping as with a constant (which you wouldn't get with a $-global), as well as visibility modifiers.
It's flexible. You can return anything that fulfils the API contract. It's the Dependency Inversion Principle (the D in SOLID) of relying on an abstraction. It also allows you to stub/mock the method and return value in tests much more easily.
If you want it to be shared across instances, use object composition (e.g. PageReader.new(existing_client)); if you want different instances to have their own client, use the implementation above.


I'd agree that constants should for be kept "primitive" - or at any rate, they should be data-only. E.g. a Hash, while not "primitive" per se, used as constant lookup table is fine. But a HTTP client instance is a bit much.

A 4th option is to make it a singleton, which is more or less a "constant instance". It'd probably require you to wrap (or extend) the HTTPClient class, e.g.:

require 'singleton'

class Client
  include Singleton

  def initialize
    @client = HTTPClient.new
  end

  def get(url)
    @client.get(url)
  end
end

# ...

def read_page(url)
  Client.instance.get(url).body
end