whois 0.5.3 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/CHANGELOG.rdoc +55 -0
  2. data/Manifest +43 -8
  3. data/README.rdoc +53 -20
  4. data/lib/whois.rb +69 -1
  5. data/lib/whois/answer.rb +126 -0
  6. data/lib/whois/answer/contact.rb +55 -0
  7. data/lib/whois/answer/parser.rb +110 -0
  8. data/lib/whois/answer/parser/README.rdoc +21 -0
  9. data/lib/whois/answer/parser/base.rb +144 -0
  10. data/lib/whois/answer/parser/blank.rb +45 -0
  11. data/lib/whois/answer/parser/whois.crsnic.net.rb +209 -0
  12. data/lib/whois/answer/parser/whois.denic.de.rb +202 -0
  13. data/lib/whois/answer/parser/whois.nic.it.rb +330 -0
  14. data/lib/whois/answer/parser/whois.publicinterestregistry.net.rb +232 -0
  15. data/lib/whois/answer/part.rb +35 -0
  16. data/lib/whois/answer/registrar.rb +42 -0
  17. data/lib/whois/answer/super_struct.rb +57 -0
  18. data/lib/whois/client.rb +6 -0
  19. data/lib/whois/definitions/tlds.rb +2 -2
  20. data/lib/whois/errors.rb +25 -8
  21. data/lib/whois/server.rb +0 -1
  22. data/lib/whois/server/adapters/afilias.rb +5 -5
  23. data/lib/whois/server/adapters/base.rb +31 -4
  24. data/lib/whois/server/adapters/formatted.rb +3 -1
  25. data/lib/whois/server/adapters/none.rb +20 -1
  26. data/lib/whois/server/adapters/pir.rb +5 -5
  27. data/lib/whois/server/adapters/standard.rb +13 -2
  28. data/lib/whois/server/adapters/verisign.rb +5 -5
  29. data/lib/whois/server/adapters/web.rb +15 -0
  30. data/lib/whois/version.rb +2 -2
  31. data/lib/whois/whois.rb +2 -2
  32. data/test/answer/parser/base_test.rb +27 -0
  33. data/test/answer/parser/blank_test.rb +19 -0
  34. data/test/answer/parser/whois_crsnic_net_test.rb +175 -0
  35. data/test/answer/parser/whois_denic_de_test.rb +209 -0
  36. data/test/answer/parser/whois_nic_it_test.rb +255 -0
  37. data/test/answer/parser/whois_publicinterestregistry_net_test.rb +210 -0
  38. data/test/answer/parser_test.rb +77 -0
  39. data/test/answer_test.rb +99 -0
  40. data/test/client_test.rb +3 -3
  41. data/test/integration_test.rb +31 -0
  42. data/test/{adapters → server/adapters}/afilias_test.rb +10 -5
  43. data/test/server/adapters/base_test.rb +15 -0
  44. data/test/server/adapters/formatted_test.rb +26 -0
  45. data/test/{adapters → server/adapters}/none_test.rb +0 -0
  46. data/test/{adapters → server/adapters}/not_implemented_test.rb +0 -0
  47. data/test/{adapters → server/adapters}/pir_test.rb +10 -5
  48. data/test/server/adapters/standard_test.rb +29 -0
  49. data/test/{adapters → server/adapters}/verisign_test.rb +10 -5
  50. data/test/{adapters → server/adapters}/web_test.rb +0 -0
  51. data/test/server_test.rb +5 -1
  52. data/test/testcases/responses/super_struct_test.rb +25 -0
  53. data/test/testcases/responses/whois.crsnic.net/available.txt +43 -0
  54. data/test/testcases/responses/whois.crsnic.net/registered.txt +57 -0
  55. data/test/testcases/responses/whois.denic.de/available.txt +30 -0
  56. data/test/testcases/responses/whois.denic.de/registered.txt +77 -0
  57. data/test/testcases/responses/whois.nic.it/available.txt +2 -0
  58. data/test/testcases/responses/{it.txt → whois.nic.it/registered.txt} +1 -0
  59. data/test/testcases/responses/whois.nic.it/status_active.txt +53 -0
  60. data/test/testcases/responses/whois.nic.it/status_available.txt +2 -0
  61. data/test/testcases/responses/whois.publicinterestregistry.net/available.txt +1 -0
  62. data/test/testcases/responses/whois.publicinterestregistry.net/registered.txt +85 -0
  63. data/test/whois_test.rb +23 -1
  64. data/utils/bm_delegation_vs_inheritance.rb +150 -0
  65. data/whois.gemspec +6 -6
  66. metadata +78 -18
  67. data/test/adapters/standard_test.rb +0 -23
@@ -1,6 +1,61 @@
1
1
  = Changelog
2
2
 
3
3
 
4
+ == Release 0.8.0
5
+
6
+ * FIXED: Server definition with :format doesn't use the Formatted adapter (closes #305)
7
+
8
+ * ADDED: whois.denic.de (.de TLD) parser [Aaron Mueller]
9
+
10
+ * ADDED: introduced support for multipart answers and Parser proxy class. This is useful in case of thin servers such as .com or .net because the parser needs to know all different responses in order to load all single scanners.
11
+
12
+ * ADDED: whois.crsnic.net (.com, .net, ... TLDs) parser.
13
+
14
+ * CHANGED: extracted all scanners into separated classes in order to make easier extract shared features.
15
+
16
+ * CHANGED: renamed Whois::Response to Whois::Answer. This change is required to avoid confusion between query-answer and server request-response. A Whois::Answer is composed by one or more parts, corresponding to single server answers.
17
+
18
+ * REMOVED: Whois::Answer#i_am_feeling_lucky (formerly Whois::Answer#i_am_feeling_lucky) become obsolete since the introduction of Answer parsers.
19
+
20
+
21
+ == Release 0.6.0
22
+
23
+ * ADDED: new more convenient method to query a whois server in addition to the existing Whois::whois method.
24
+
25
+ Whois::query("domain.com")
26
+ # same as Whois::whois but added to normalize application interfaces.
27
+
28
+ Whois::available?("domain.com")
29
+ # returns true if the domain is available.
30
+
31
+ Whois::registered?("domain.com")
32
+ # returns true if the domain is registered.
33
+
34
+ * ADDED: Experimental support for whois response parsing. This release is shipped with two parsers for the .it and .net TLD.
35
+
36
+ r = Whois::query("google.it")
37
+ r.available?
38
+ # => false
39
+ r.created_on
40
+ # => Time.parse("1999-12-10 00:00:00")
41
+ r.Nameservers
42
+ # => ["ns1.google.com", "ns2.google.com", ...]
43
+
44
+ * CHANGED: A whois query now returns a custom Whois::Response object instead of a simple string.
45
+ The previous interface is still supported, so you can continue to compare the response with Strings
46
+ but this behavior will be deprecated in a future release.
47
+
48
+ r = Whois::query("domain.com")
49
+ # supported but deprecated in a future version
50
+ r == "NOT FOUND"
51
+ # explicitly cast the object to string instead
52
+ r.to_s == "NOT FOUND"
53
+ # or use one of the other Whois::Response methods.
54
+
55
+ Note. This is an experimental version (EAP) and it should not be considered production-ready.
56
+ API might change at any time without previous notice.
57
+
58
+
4
59
  == Release 0.5.3
5
60
 
6
61
  FIXED: self.valid_ipv6?(addr) references valid_v4? instead of valid_ipv4? (closes #300)
data/Manifest CHANGED
@@ -6,6 +6,19 @@ data/make_ip6_del.pl
6
6
  data/make_ip_del.pl
7
7
  data/make_tld_serv.pl
8
8
  data/tld_serv_list
9
+ lib/whois/answer/contact.rb
10
+ lib/whois/answer/parser/base.rb
11
+ lib/whois/answer/parser/blank.rb
12
+ lib/whois/answer/parser/README.rdoc
13
+ lib/whois/answer/parser/whois.crsnic.net.rb
14
+ lib/whois/answer/parser/whois.denic.de.rb
15
+ lib/whois/answer/parser/whois.nic.it.rb
16
+ lib/whois/answer/parser/whois.publicinterestregistry.net.rb
17
+ lib/whois/answer/parser.rb
18
+ lib/whois/answer/part.rb
19
+ lib/whois/answer/registrar.rb
20
+ lib/whois/answer/super_struct.rb
21
+ lib/whois/answer.rb
9
22
  lib/whois/client.rb
10
23
  lib/whois/definitions/ipv4.rb
11
24
  lib/whois/definitions/ipv4.txt
@@ -33,22 +46,44 @@ Manifest
33
46
  Rakefile
34
47
  README.rdoc
35
48
  tasks/server.rake
36
- test/adapters/afilias_test.rb
37
- test/adapters/none_test.rb
38
- test/adapters/not_implemented_test.rb
39
- test/adapters/pir_test.rb
40
- test/adapters/standard_test.rb
41
- test/adapters/verisign_test.rb
42
- test/adapters/web_test.rb
49
+ test/answer/parser/base_test.rb
50
+ test/answer/parser/blank_test.rb
51
+ test/answer/parser/whois_crsnic_net_test.rb
52
+ test/answer/parser/whois_denic_de_test.rb
53
+ test/answer/parser/whois_nic_it_test.rb
54
+ test/answer/parser/whois_publicinterestregistry_net_test.rb
55
+ test/answer/parser_test.rb
56
+ test/answer_test.rb
43
57
  test/client_test.rb
44
58
  test/deprecated_test.rb
59
+ test/integration_test.rb
60
+ test/server/adapters/afilias_test.rb
61
+ test/server/adapters/base_test.rb
62
+ test/server/adapters/formatted_test.rb
63
+ test/server/adapters/none_test.rb
64
+ test/server/adapters/not_implemented_test.rb
65
+ test/server/adapters/pir_test.rb
66
+ test/server/adapters/standard_test.rb
67
+ test/server/adapters/verisign_test.rb
68
+ test/server/adapters/web_test.rb
45
69
  test/server_test.rb
46
70
  test/test_helper.rb
47
71
  test/testcases/referrals/afilias.bz.txt
48
72
  test/testcases/referrals/crsnic.com.txt
49
73
  test/testcases/referrals/niccc.cc.txt
50
74
  test/testcases/referrals/pir.org.txt
51
- test/testcases/responses/it.txt
75
+ test/testcases/responses/super_struct_test.rb
76
+ test/testcases/responses/whois.crsnic.net/available.txt
77
+ test/testcases/responses/whois.crsnic.net/registered.txt
78
+ test/testcases/responses/whois.denic.de/available.txt
79
+ test/testcases/responses/whois.denic.de/registered.txt
80
+ test/testcases/responses/whois.nic.it/available.txt
81
+ test/testcases/responses/whois.nic.it/registered.txt
82
+ test/testcases/responses/whois.nic.it/status_active.txt
83
+ test/testcases/responses/whois.nic.it/status_available.txt
84
+ test/testcases/responses/whois.publicinterestregistry.net/available.txt
85
+ test/testcases/responses/whois.publicinterestregistry.net/registered.txt
52
86
  test/whois_test.rb
87
+ utils/bm_delegation_vs_inheritance.rb
53
88
  utils/bm_shell_vs_pure.rb
54
89
  utils/tlds.txt
@@ -1,21 +1,24 @@
1
1
  = Whois
2
2
 
3
- Whois is an intelligent pure Ruby WHOIS client.
3
+ Whois is an intelligent pure Ruby WHOIS client and parser.
4
4
 
5
5
  It is a os-independent library and doesn't require external C libraries or GEMS: it is a 100% Ruby software with all the advantages and disadvantages that it involves.
6
6
 
7
- This software was developed to power RoboDomain[http://www.robodomain.com] and, despite it has been using in a production environment since July 2009, it should not be considered production-ready yet. It is currently in its beta stage.
7
+ This software was developed to power RoboDomain[http://www.robodomain.com] and, since July 2009, it run more than thousands requests.
8
8
 
9
9
  An extensive test suite is available to verify the library correctness but you must be aware that registrant might change Whois interfaces without notice and at any time causing queries to specific hosts to stop working.
10
10
 
11
11
 
12
12
  == Features
13
13
 
14
- * Written in pure Ruby without any additional dependency
15
- * Flexible and extensible with custom server
14
+ * Pure Ruby library without any external dependency other than Ruby itself
15
+ * Intelligent Ruby client
16
+ * Flexible and extensible configuration with support for user-defined servers
17
+ * Powerful whois response parser
16
18
  * Support for ipv6, ipv4 and top level domain whois queries
17
19
  * Object oriented design
18
20
  * Compatible with older Whois version (Whois 0.4.2, see below)
21
+ * Compatible with Ruby 1.8.6 and greater, including Ruby 1.9
19
22
 
20
23
 
21
24
  == Requirements
@@ -43,26 +46,28 @@ You might need administrator privileges on your system to install it.
43
46
 
44
47
  == Getting Started
45
48
 
46
- Note. This section covers only the essentials for getting started with the Whois library. If you want to take the full advantage of all its features, visit the {documentation page}[http://code.simonecarletti.com/wiki/whois].
49
+ Note. This section covers only the essentials for getting started with the Whois library. The {documentation}[http://code.simonecarletti.com/wiki/whois] provides a more accurate explanation including tutorials, more examples and technical details about the client/server/answer/parser architecture.
47
50
 
48
- Whois provides the ability to get whois information for hostnames, ipv4 and ipv6 ip addresses. The client is smart enough to guess the best whois server according to given query, send the request and return the response.
51
+ === Querying the Server
52
+
53
+ Whois provides the ability to get WHOIS information for hostnames, ipv4 and ipv6 ip addresses. The client is smart enough to guess the best WHOIS server according to given query, send the request and return the response.
49
54
 
50
55
  Checkout the following examples:
51
56
 
52
57
  # Domain Whois
53
58
  w = Whois::Client.new
54
59
  w.query("google.com")
55
- # => whois response for google.com
60
+ # => #<Whois::Answer>
56
61
 
57
62
  # IPv4 Whois
58
63
  w = Whois::Client.new
59
64
  w.query("74.125.67.100")
60
- # => whois response for 74.125.67.100
65
+ # => #<Whois::Answer>
61
66
 
62
67
  # IPv6 Whois
63
68
  w = Whois::Client.new
64
69
  w.query("2001:db8::1428:57ab")
65
- # => whois response for 2001:db8::1428:57ab
70
+ # => #<Whois::Answer>
66
71
 
67
72
  The query method is stateless. For this reason, you can safely re-use the same client instance for multiple queries.
68
73
 
@@ -72,6 +77,43 @@ The query method is stateless. For this reason, you can safely re-use the same c
72
77
  w.query("2001:db8::1428:57ab")
73
78
  w.query("google.it")
74
79
 
80
+ If you just need a WHOIS response and you don't care about a full control of the WHOIS Client, Whois comes with a simple method called whois. This is the simplest way to send a WHOIS request.
81
+
82
+ Whois.whois("google.com")
83
+ # => #<Whois::Answer>
84
+
85
+ === Consuming the Answer
86
+
87
+ As of release 0.8, a WHOIS query no longer returns a simple string. Instead, you get a full Whois::Answer instance and this is just the beginning of the story.
88
+
89
+ Whois::Answer is a super powerful object. It encapsulates the full WHOIS answer and it provides you the ability to parse the WHOIS response with a full object oriented notation.
90
+
91
+ a = Whois.whois("google.it")
92
+ # => #<Whois::Answer>
93
+
94
+ a.available?
95
+ # => false
96
+ a.registered?
97
+ # => true
98
+
99
+ a.created_on
100
+ # => Fri Dec 10 00:00:00 +0100 1999
101
+
102
+ t = a.techinical
103
+ # => #<Whois::Answer::Contact>
104
+ t.id
105
+ # => "TS7016-ITNIC"
106
+ t.name
107
+ # => "Technical Services"
108
+
109
+ a.nameservers.each do |nameserver|
110
+ puts nameserver
111
+ end
112
+
113
+ This feature is made possible by the Whois answer parsers. Unfortunately, due to the lack of a global standard, each WHOIS server requires a specific parser. For this reason, the library doesn't support all existing WHOIS servers.
114
+
115
+ If you create a new parser, please consider releasing it to the public so that it can be included in a next version.
116
+
75
117
  === Timeout
76
118
 
77
119
  By default, each query run though the client has a timeout value of 5 seconds. If the execution exceeds timeout limit, the client raises a <tt>Timeout::Error</tt> exception.
@@ -101,7 +143,7 @@ The parser architecture (yet to come) has been inspired by the PHPWhois[http://p
101
143
  Despite I spent weeks reading source code from the available whois libraries, Ruby Whois has been built from scratch trying to focus on long-term maintainability and flexibility and cannot be considered a Ruby port of any of other existing Whois libraries.
102
144
 
103
145
 
104
- == Notice for users of Whois 0.4.2 (or previous version)
146
+ == Notice for users of Whois 0.4 (or previous version)
105
147
 
106
148
  As of release 0.5.0, the Whois GEM has been completely rewritten. As I explained in the Acknowledgment section, Cyril Mougel (the author of the original Whois package) yield me the privilege to use the Whois RubyForge project for my new Whois client.
107
149
 
@@ -117,7 +159,7 @@ Copyright (c) 2007 by Cyril Mougel (cyril.mougel@gmail.com)
117
159
  == Credits
118
160
 
119
161
  Author:: {Simone Carletti}[http://www.simonecarletti.com/] <weppos@weppos.net>
120
- First Whois Version:: {Cyril Mougel}[http://blog.shingara.fr/] <cyril.mougel@gmail.com>
162
+ Author (Whois 0.4):: {Cyril Mougel}[http://blog.shingara.fr/] <cyril.mougel@gmail.com>
121
163
 
122
164
 
123
165
  == FeedBack and Bug reports
@@ -132,8 +174,6 @@ Bug reports and Feature suggestions {are welcomed}[http://code.simonecarletti.co
132
174
  * {Homepage}[http://code.simonecarletti.com/whois]
133
175
  * {GitHub}[http://github.com/weppos/whois]
134
176
  * {RubyForge}[http://rubyforge.org/projects/whois/]
135
-
136
- * {Documentation}[http://code.simonecarletti.com/wiki/whois]
137
177
  * {API}[http://whois.rubyforge.org/]
138
178
  * {Discussion Group}[http://groups.google.com/group/ruby-whois]
139
179
 
@@ -143,13 +183,6 @@ Bug reports and Feature suggestions {are welcomed}[http://code.simonecarletti.co
143
183
  See the CHANGELOG.rdoc file for details.
144
184
 
145
185
 
146
- == Roadmap
147
-
148
- * Implement intelligent Whois response parsing
149
-
150
- For more details visit the {roadmap page}[http://code.simonecarletti.com/projects/roadmap/whois].
151
-
152
-
153
186
  == License
154
187
 
155
188
  Copyright (c) 2009 Simone Carletti, Whois is released under the MIT license.
@@ -18,6 +18,7 @@ require 'whois/version'
18
18
  require 'whois/errors'
19
19
  require 'whois/client'
20
20
  require 'whois/server'
21
+ require 'whois/answer'
21
22
  require 'whois/whois'
22
23
 
23
24
 
@@ -26,8 +27,75 @@ module Whois
26
27
  NAME = 'Whois'
27
28
  GEM = 'whois'
28
29
  AUTHORS = ['Simone Carletti <weppos@weppos.net>']
29
-
30
+
31
+
32
+ # Queries the right whois server for <tt>qstring</tt> and returns
33
+ # a <tt>Whois::Answer</tt> instance containing the response from the server.
34
+ #
35
+ # Whois.query("google.com")
36
+ # # => #<Whois::Answer>
37
+ #
38
+ # This is equivalent to
39
+ #
40
+ # Whois::Client.new.query("google.com")
41
+ # # => #<Whois::Answer>
42
+ #
30
43
  def self.whois(qstring)
44
+ query(qstring)
45
+ end
46
+
47
+ # Returns <tt>true</tt> whether <tt>qstring</tt> is available.
48
+ # <tt>qstring</tt> is intended to be a domain name,
49
+ # otherwise this method may return unexpected responses.
50
+ #
51
+ # Whois.available?("google.com")
52
+ # # => false
53
+ #
54
+ # Whois.available?("google-is-not-available-try-again-later.com")
55
+ # # => true
56
+ #
57
+ # Warning: this method is only available if a Whois parser exists
58
+ # for <tt>qstring</tt> top level domain. Otherwise you'll get a warning message
59
+ # and the method will return <tt>nil</tt>.
60
+ # This is a technical limitation. Browse the lib/whois/answer/parsers folder
61
+ # to view all available parsers.
62
+ #
63
+ def self.available?(qstring)
64
+ query(qstring).available?
65
+ rescue ParserNotFound => e
66
+ $stderr.puts "This method is not available for this kind of object.\n" +
67
+ "Use Whois.query('#{qstring}') instead."
68
+ nil
69
+ end
70
+
71
+ # Returns <tt>true</tt> whether <tt>qstring</tt> is registered.
72
+ # <tt>qstring</tt> is intended to be a domain name,
73
+ # otherwise this method may return unexpected responses.
74
+ #
75
+ # Whois.registered?("google.com")
76
+ # # => true
77
+ #
78
+ # Whois.registered?("google-is-not-available-try-again-later.com")
79
+ # # => false
80
+ #
81
+ # Warning: this method is only available if a Whois parser exists
82
+ # for <tt>qstring</tt> top level domain. Otherwise you'll get a warning message
83
+ # and the method will return <tt>nil</tt>.
84
+ # This is a technical limitation. Browse the lib/whois/answer/parsers folder
85
+ # to view all available parsers.
86
+ #
87
+ def self.registered?(qstring)
88
+ query(qstring).registered?
89
+ rescue ParserNotFound => e
90
+ $stderr.puts "This method is not available for this kind of object.\n" +
91
+ "Use Whois.query('#{qstring}') instead."
92
+ nil
93
+ end
94
+
95
+
96
+ # See Whois#whois.
97
+ def self.query(qstring)
31
98
  Client.new.query(qstring)
32
99
  end
100
+
33
101
  end
@@ -0,0 +1,126 @@
1
+ #
2
+ # = Ruby Whois
3
+ #
4
+ # An intelligent pure Ruby WHOIS client.
5
+ #
6
+ #
7
+ # Category:: Net
8
+ # Package:: Whois
9
+ # Author:: Simone Carletti <weppos@weppos.net>
10
+ # License:: MIT License
11
+ #
12
+ #--
13
+ #
14
+ #++
15
+
16
+
17
+ require 'whois/answer/parser'
18
+ require 'whois/answer/parser/base'
19
+
20
+
21
+ module Whois
22
+
23
+ class Answer
24
+
25
+ attr_reader :server
26
+ attr_reader :parts
27
+
28
+ def initialize(server, parts)
29
+ @parts = parts
30
+ @server = server
31
+ end
32
+
33
+
34
+ def to_s
35
+ content.to_s
36
+ end
37
+
38
+ def inspect
39
+ content.inspect
40
+ end
41
+
42
+ # Invokes <tt>match</tt> on answer <tt>@content</tt>
43
+ # and returns the <tt>MatchData</tt> or <tt>nil</tt>.
44
+ def match(pattern)
45
+ content.match(pattern)
46
+ end
47
+
48
+ # Returns true if the <tt>object</tt> is the same object,
49
+ # or is a string and has the same content.
50
+ def ==(other)
51
+ (other.equal?(self)) ||
52
+ # This option should be deprecated
53
+ (other.instance_of?(String) && other == self.to_s) ||
54
+ (other.instance_of?(Answer) && other.to_s == self.to_s)
55
+ end
56
+
57
+ # Delegates to ==.
58
+ def eql?(other)
59
+ self == other
60
+ end
61
+
62
+
63
+ # Returns the content of this answer as a string.
64
+ # This method joins all answer parts into a single string
65
+ # and separates each response with a newline character.
66
+ #
67
+ # answer = Whois::Answer.new([Whois::Answer::Part.new("First answer.")])
68
+ # answer.content
69
+ # # => "First answer."
70
+ #
71
+ # answer = Whois::Answer.new([Whois::Answer::Part.new("First answer."), Whois::Answer::Part.new("Second answer.")])
72
+ # answer.content
73
+ # # => "First answer.\nSecond answer."
74
+ #
75
+ def content
76
+ @content ||= parts.map { |part| part.response }.join("\n")
77
+ end
78
+
79
+ # Returns whether this answer changed compared to <tt>other</tt>.
80
+ #
81
+ # Comparing the Answer contents is not always as trivial as it seems.
82
+ # Whois servers sometimes inject dynamic method into the whois answer such as
83
+ # the timestamp the request was generated.
84
+ # This causes two answers to be different even if they actually should be considered equal
85
+ # because the registry data didn't change.
86
+ #
87
+ # This method should provide a bulletproof way to detect whether this answer
88
+ # changed if compared with <tt>other</tt>.
89
+ def changed?(other)
90
+ !unchanged?(other)
91
+ end
92
+
93
+ # The opposite of <tt>changed?</tt>.
94
+ def unchanged?(other)
95
+ self == other ||
96
+ parser.unchanged?(other.parser)
97
+ end
98
+
99
+
100
+ # Invokes <tt>match</tt> and returns <tt>true</tt> if <tt>pattern</tt>
101
+ # matches <tt>@content</tt>, <tt>false</tt> otherwise.
102
+ def match?(pattern)
103
+ !content.match(pattern).nil?
104
+ end
105
+
106
+
107
+ # Lazy-loads and returns a <tt>Whois::Answer::Parser</tt> proxy for current answer.
108
+ def parser
109
+ @parser ||= Parser.new(self)
110
+ end
111
+
112
+
113
+ protected
114
+
115
+ # Delegates all method calls to the internal parser.
116
+ def method_missing(method, *args, &block)
117
+ if Parser.registrable_methods.include?(method)
118
+ parser.send(method, *args, &block)
119
+ else
120
+ super
121
+ end
122
+ end
123
+
124
+ end
125
+
126
+ end