New in Whois: Applying the Principle of Least Surprise

In the past weeks I've been working to improve the Ruby Whois Gem. While most of the effort is actually focused on creating new WHOIS parsers for the existing registries which are more than 400, I also took the time to add some new features.

One important change is strictly focused on applying the principle of least surprise in the Whois::Answer design. Prior the changes, calling a method on a Whois::Answer instance to read a property value might result in 3 different behaviors:

# the property is supported, return the value
a = Whois.query "google.it"
a.created_on?
# => Fri Dec 10 00:00:00 +0100 1999

# the property is supported but blank, return the value
a = Whois.query "notregistered.it"
a.created_on?
# => nil

# the property is not supported, raise an exception
a = Whois.query "google.it"
a.domain_id?
# => PropertyNotSupported

Whether the parser supports a property depends on the WHOIS record. For instance, a .name WHOIS response doesn't contain the domain expiration thus the property expires_on is not supported. Contrariwise, the .it WHOIS response contains that value thus you can safely call expires_on to get the property value.

How do you deal with supported/unsupported properties? With the old Whois version you would have to check whether a property is supported before actually calling the getter method.

# the property is supported, return the value
a = Whois.query "google.it"
if a.property_supported?(:domain_id)
  a.domain_id
end

That worked well but was… horrible. Dogfooding the library working on RoboDomain I ended up with the conclusion this wasn't the behavior an user would expect. For this reason, the new Whois version returns the value if the property is supported, nil otherwise regardless property status.

This change only affects the answer object. If for some reason you need to know whether a property is supported, you can always use the property_supported? method or access the underlying parser implementation.

a = Whois.query "google.it"

a.domain_id
# => nil

a.supported?(:domain_id)
# => false

a.parser.domain_id
# => PropertyNotSupported