Last week I had a head-scratching moment looking at the following code (from the google-api-ruby-client):
ClientOptions = Struct.new( :application_name, :application_version, :proxy_url, :open_timeout_sec, :read_timeout_sec, :send_timeout_sec, :log_http_requests, :transparent_gzip_decompression) # ... class ClientOptions # ... def self.default @options ||= ClientOptions.new end end
My initial confusion stemmed from the assumption that the first
ClientOptions declaration returned a regular object. A helpful colleague explained to me that
Struct.new actually returns a subclass of Struct. That meant the second
class ClientOptions declaration was actually re-opening the class to add a method, not to declare a new class.
Why would one want to do this? Well, one would get all the methods of a regular Struct (e.g. accessors, iterators)
for free at the cost of the inheritance hierarchy. This could be useful for ValueObjects.