Whois Parser
The Whois::Record::Parser
object, as the name suggest, actually belongs to the Whois::Record
namespace. However, this element is such important to deserve its own documentation section.
The parser architecture allows you to access the WHOIS responses as an object. The parsers decompose the response String
and offers a standardized API to access its content. For instance, to get the date the record has been created, just call the created_on
method, no matter you are querying the .com
or .net
database.
# Example: Accessing a WHOIS record, the object oriented way
r = Whois.whois("google.it")
r.created_on
# => Fri Dec 10 00:00:00 +0100 1999
r.expires_on
# => Sat Nov 27 00:00:00 +0100 2010
The Problem with WHOIS Record Parsing
As explained in the Whois::Record
section, an record is composed by one or more parts
. Each part represents the response from a specific WHOIS server. Because the WHOIS doesn't force WHOIS servers to follow an unique response layout, each server needs its own dedicated parser.
Have a look at the following records to better understand the differences.
*********************************************************************
* Please note that the following result could be a subgroup of *
* the data contained in the database. *
* *
* Additional information can be visualized at: *
* http://www.nic.it/cgi-bin/Whois/whois.cgi *
*********************************************************************
Domain: google.it
Status: ACTIVE
Created: 1999-12-10 00:00:00
Last Update: 2009-12-13 00:03:01
Expire Date: 2010-11-27
Registrant
Name: Google Ireland Holdings
Organization: Google Ireland Holdings
ContactID: GOOG175-ITNIC
Address: 30 Herbert Street
Dublin
2
IE
IE
Created: 2008-11-27 16:47:22
Last Update: 2008-11-27 16:47:22
Whois Server Version 2.0
Domain names in the .com and .net domains can now be registered
with many different competing registrars. Go to http://www.internic.net
for detailed information.
Domain Name: AISCUNEO.COM
Registrar: GODADDY.COM, INC.
Whois Server: whois.godaddy.com
Referral URL: http://registrar.godaddy.com
Name Server: NS1.DREAMHOST.COM
Name Server: NS2.DREAMHOST.COM
Name Server: NS3.DREAMHOST.COM
Status: clientDeleteProhibited
Status: clientRenewProhibited
Status: clientTransferProhibited
Status: clientUpdateProhibited
Updated Date: 21-jan-2010
Creation Date: 24-jan-2009
Expiration Date: 24-jan-2011
>>> Last update of whois database: Fri, 05 Mar 2010 21:53:17 UTC <<<
Moreover, if you consider the Thin
data model, a single .com
query often requires at least two parsers. One for the Verisign request and one for the final registrar.
I know what you are thinking and the record is yes: in order to support all existing WHOIS servers and registrars, the Whois
library should provide more than 500 different parsers. And this is exactly one of the major development goal. Unfortunately, as you might imagine, this requires a huge development effort.
God save the Standards!
Basics
The Whois::Record::Parser
object acts as a proxy
between the Whois::Record
object and the Whois::Record::Part
-level parsers.
As explained in the section above, a Whois::Record
is composed by one or more parts
and each Whois::Record::Part
has its own custom parser. Whois::Record::Part
-level parsers must implements the Whois::Record::Parser::Base
abstract class.
Parsers define a standard API and two parsers can actually overlaps. For instance, if a .com
response contains two parts and each parser supports the nameservers
property, then you need an element to forward the request to the most appropriate endpoint. That's the Whois::Record::Parser
.
The Whois::Record::Parser
knows about all Whois::Record::Part
-level parsers and automatically returns the most appropriate value for a specific property.
# Example: Using the Whois::Record::Parser to access the Whois::Record data
r = Whois.whois("google.it")
p = r.parser
p.created_on
# => Fri Dec 10 00:00:00 +0100 1999
p.expires_on
# => Sat Nov 27 00:00:00 +0100 2010
Properties
The Whois::Record::Parser
defines a specific list of record properties. The list is designed in order to include the most common information available in a WHOIS response. Whois::Record::Parser::PROPERTIES
returns the current list.
# Example: Getting the list of defined record properties
Whois::Record::Parser::PROPERTIES
=> [:disclaimer, :domain, :domain_id, :referral_whois, :referral_url, :status, :registered?, :available?, :created_on, :updated_on, :expires_on, :registrar, :registrant, :admin, :technical, :nameservers]
Here's the full list of available properties.
You can access each of this property using the corresponding instance method.
# Example: Accessing record properties using the instance methods
r = Whois.whois("google.it")
p = r.parser
p.disclaimer
# => "..."
p.domain_id
# => nil
The method can either return the value or raise a Whois::ParserError
exception, depending whether the value is supported or not.
Returned Values
When you access a property, you can expect two different behaviors:
- the method value
- an exception
The first case is the most simple. If at least one Whois::Record::Part
-level parser supports the specified property, then the the last parser which implements it wins and the value is returned.
Have a look at the following examples.
# Example: The Record contains two parts corresponding to the responses
from the following WHOIS servers:
whois.foo.com supports #domain, #domain_id
whois.bar.com supports #domain, #disclaimer
p = Whois.whois("google.it").parser
# both parsers support the property, last value returned
p.domain
# => value from whois.bar.com
# the first parser supports the property, value returned
p.domain_id
# => value from whois.foo.com
# the second parser supports the property, value returned
p.disclaimer
# => value from whois.bar.com
# the property is not supported, exception raised
p.created_on
The last statement raises an Exception because the property is not supported nor not available. There's a slight difference between a not supported and not available property. View the (yet to come) Whois::Record::Parser::Base
base for a detailed explanation.
For now, you just need to know that a property might raise 2 different exceptions according to its flag:
Whois::AttributeNotImplemented
Whois::AttributeNotSupported
All these exceptions inherits from Whois::ParserError
.
Record#property vs Parser#property
As you probably already noticed from the examples you read so far, you can either access an record property from the Whois::Record
object or from the underlying Whois::Record::Parser
proxy.
# Example: Accessing an record properties from
# Whois::Record and Whois::Record::Parser objects
r = Whois.whois("google.it")
r.created_on
# => Fri Dec 10 00:00:00 +0100 1999
r.parser.created_on
# => Fri Dec 10 00:00:00 +0100 1999
The values are absolutely equivalent.
# Example: Demonstrating the equality between
# Whois::Record and Whois::Record::Parser properties
r = Whois.whois("google.it")
r.created_on == a.parser.created_on
# => true
However, there's a technical difference between the two methods.
In the section above you learnt a property can either return a value or raise an exception. You can check whether a property is supported or not using the #property_supported?
method.
# Example: Checking if the property is supported
r = Whois.whois("google.it")
r.property_supported?(:domain)
# => false
r.parser.property_supported?(:domain)
# => false
The main difference between accessing a property at Whois::Record
level or Whois::Record::Parser
level is that the former never raises exceptions. Instead, if a property is not supported the Whois::Record
silently returns nil
.
# Example: Checking if the property is supported
r = Whois.whois("google.it")
r.domain
# => nil
r.parser.domain
# => AttributeNotSupported
Usually, it's more convenient to access a property at record level unless you need a more granular control.