Class: MonoVM::Whois::Parser::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/monovm/whois/parser/base.rb

Overview

Shared scaffolding for record parsers.

Subclasses say which responses they understand (#applicable?) and how to turn one into a Record (#parse). Date parsing lives here because it is the one job every registry does differently and none of them do well: the same field arrives as 2026-08-13T04:00:00Z, 13-Aug-2026, 2026.08.13 or 13/08/2026, and getting it wrong by a month is worse than returning nil.

Direct Known Subclasses

KeyValue, RdapJson

Constant Summary collapse

DATE_FORMATS =

Explicit formats, tried in order, before falling back to Ruby's parser.

Ordering matters for the ambiguous ones: 13/08/2026 is day-first everywhere that writes it with slashes in a WHOIS record, so that pattern comes before the month-first reading Time.parse would pick.

[
  "%Y-%m-%dT%H:%M:%S%z",
  "%Y-%m-%dT%H:%M:%SZ",
  "%Y-%m-%dT%H:%M:%S.%L%z",
  "%Y-%m-%d %H:%M:%S%z",
  "%Y-%m-%d %H:%M:%S",
  "%Y-%m-%d",
  "%Y.%m.%d %H:%M:%S",
  "%Y.%m.%d",
  "%Y/%m/%d",
  "%d-%b-%Y %H:%M:%S",
  "%d-%b-%Y",
  "%d.%m.%Y %H:%M:%S",
  "%d.%m.%Y",
  "%d/%m/%Y %H:%M:%S",
  "%d/%m/%Y",
  "%b %d %Y",
  "%d %b %Y",
  "%Y%m%d"
].freeze
PLAUSIBLE_YEARS =

Registration dates are never before the DNS existed and never centuries away. The range is what makes the ambiguous formats safe to try in order: "%Y.%m.%d" happily parses "12.5.2015" as year 12, month 5, day 2015 — rolling over into May of year 12 — and without this guard that nonsense wins before "%d.%m.%Y" is ever tried, silently misdating every European record.

(1980..2200)

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.snake_case(klass) ⇒ Object

IcannRdd becomes "icann_rdd". Handles an anonymous class, whose Module#name is nil — which a spec or a host application defining a parser inline would otherwise crash on.



36
37
38
39
40
# File 'lib/monovm/whois/parser/base.rb', line 36

def self.snake_case(klass)
  base = klass.name.to_s.split("::").last
  base = klass.inspect if base.nil? || base.empty?
  base.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
end

Instance Method Details

#applicable?(response) ⇒ Boolean

Parameters:

Returns:

  • (Boolean)

Raises:

  • (NotImplementedError)


19
20
21
# File 'lib/monovm/whois/parser/base.rb', line 19

def applicable?(response)
  raise NotImplementedError, "#{self.class} must implement #applicable?"
end

#nameObject



29
30
31
# File 'lib/monovm/whois/parser/base.rb', line 29

def name
  @name ||= Base.snake_case(self.class)
end

#parse(response) ⇒ Record

Parameters:

Returns:

Raises:

  • (NotImplementedError)


25
26
27
# File 'lib/monovm/whois/parser/base.rb', line 25

def parse(response)
  raise NotImplementedError, "#{self.class} must implement #parse"
end