whois-parser-next 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -1
  3. data/README.md +16 -8
  4. data/RELEASING.md +2 -2
  5. data/lib/whois/parser/version.rb +1 -1
  6. data/lib/whois/parsers/base_centralnic_icann.rb +12 -0
  7. data/lib/whois/parsers/base_cira_registry.rb +19 -0
  8. data/lib/whois/parsers/base_icann_compliant.rb +1 -1
  9. data/lib/whois/parsers/base_identity_digital.rb +12 -0
  10. data/lib/whois/parsers/base_jwhois.rb +48 -0
  11. data/lib/whois/parsers/base_nic_reserved_available.rb +17 -0
  12. data/lib/whois/parsers/base_reserved_registry.rb +27 -0
  13. data/lib/whois/parsers/base_top1000_icann.rb +39 -0
  14. data/lib/whois/parsers/base_top1000_retired.rb +26 -0
  15. data/lib/whois/parsers/base_unsupported_registry.rb +1 -1
  16. data/lib/whois/parsers/cwhois.cnnic.cn.rb +10 -0
  17. data/lib/whois/parsers/registry_response_safety.rb +2 -0
  18. data/lib/whois/parsers/whois.ax.rb +15 -3
  19. data/lib/whois/parsers/whois.cnnic.cn.rb +31 -3
  20. data/lib/whois/parsers/whois.dominio.gq.rb +11 -0
  21. data/lib/whois/parsers/whois.dotukr.com.rb +23 -0
  22. data/lib/whois/parsers/whois.gtld.knet.cn.rb +10 -0
  23. data/lib/whois/parsers/whois.kyregistry.ky.rb +10 -0
  24. data/lib/whois/parsers/whois.madrid.rs.corenic.net.rb +8 -0
  25. data/lib/whois/parsers/whois.mediaserv.net.rb +9 -0
  26. data/lib/whois/parsers/whois.ngtld.cn.rb +8 -0
  27. data/lib/whois/parsers/whois.nic.academy.rb +8 -0
  28. data/lib/whois/parsers/whois.nic.accountant.rb +8 -0
  29. data/lib/whois/parsers/whois.nic.actor.rb +8 -0
  30. data/lib/whois/parsers/whois.nic.agency.rb +8 -0
  31. data/lib/whois/parsers/whois.nic.airforce.rb +8 -0
  32. data/lib/whois/parsers/whois.nic.amsterdam.rb +8 -0
  33. data/lib/whois/parsers/whois.nic.apartments.rb +8 -0
  34. data/lib/whois/parsers/whois.nic.army.rb +8 -0
  35. data/lib/whois/parsers/whois.nic.associates.rb +8 -0
  36. data/lib/whois/parsers/whois.nic.auction.rb +8 -0
  37. data/lib/whois/parsers/whois.nic.aw.rb +33 -0
  38. data/lib/whois/parsers/whois.nic.baby.rb +8 -0
  39. data/lib/whois/parsers/whois.nic.bank.rb +29 -0
  40. data/lib/whois/parsers/whois.nic.bar.rb +8 -0
  41. data/lib/whois/parsers/whois.nic.barcelona.rb +8 -0
  42. data/lib/whois/parsers/whois.nic.barclays.rb +8 -0
  43. data/lib/whois/parsers/whois.nic.bargains.rb +8 -0
  44. data/lib/whois/parsers/whois.nic.basketball.rb +8 -0
  45. data/lib/whois/parsers/whois.nic.bayern.rb +8 -0
  46. data/lib/whois/parsers/whois.nic.beauty.rb +8 -0
  47. data/lib/whois/parsers/whois.nic.beer.rb +8 -0
  48. data/lib/whois/parsers/whois.nic.berlin.rb +8 -0
  49. data/lib/whois/parsers/whois.nic.bible.rb +8 -0
  50. data/lib/whois/parsers/whois.nic.bid.rb +8 -0
  51. data/lib/whois/parsers/whois.nic.bike.rb +8 -0
  52. data/lib/whois/parsers/whois.nic.bingo.rb +8 -0
  53. data/lib/whois/parsers/whois.nic.blog.rb +34 -0
  54. data/lib/whois/parsers/whois.nic.bmw.rb +8 -0
  55. data/lib/whois/parsers/whois.nic.bond.rb +8 -0
  56. data/lib/whois/parsers/whois.nic.boston.rb +8 -0
  57. data/lib/whois/parsers/whois.nic.broker.rb +8 -0
  58. data/lib/whois/parsers/whois.nic.build.rb +8 -0
  59. data/lib/whois/parsers/whois.nic.builders.rb +8 -0
  60. data/lib/whois/parsers/whois.nic.buzz.rb +8 -0
  61. data/lib/whois/parsers/whois.nic.bzh.rb +32 -0
  62. data/lib/whois/parsers/whois.nic.cafe.rb +8 -0
  63. data/lib/whois/parsers/whois.nic.cam.rb +8 -0
  64. data/lib/whois/parsers/whois.nic.camera.rb +8 -0
  65. data/lib/whois/parsers/whois.nic.canon.rb +11 -0
  66. data/lib/whois/parsers/whois.nic.capital.rb +8 -0
  67. data/lib/whois/parsers/whois.nic.cards.rb +8 -0
  68. data/lib/whois/parsers/whois.nic.careers.rb +8 -0
  69. data/lib/whois/parsers/whois.nic.casa.rb +8 -0
  70. data/lib/whois/parsers/whois.nic.cash.rb +8 -0
  71. data/lib/whois/parsers/whois.nic.center.rb +8 -0
  72. data/lib/whois/parsers/whois.nic.ceo.rb +8 -0
  73. data/lib/whois/parsers/whois.nic.charity.rb +8 -0
  74. data/lib/whois/parsers/whois.nic.city.rb +8 -0
  75. data/lib/whois/parsers/whois.nic.claims.rb +8 -0
  76. data/lib/whois/parsers/whois.nic.cleaning.rb +8 -0
  77. data/lib/whois/parsers/whois.nic.coach.rb +8 -0
  78. data/lib/whois/parsers/whois.nic.codes.rb +8 -0
  79. data/lib/whois/parsers/whois.nic.coffee.rb +8 -0
  80. data/lib/whois/parsers/whois.nic.computer.rb +8 -0
  81. data/lib/whois/parsers/whois.nic.condos.rb +8 -0
  82. data/lib/whois/parsers/whois.nic.construction.rb +8 -0
  83. data/lib/whois/parsers/whois.nic.contractors.rb +8 -0
  84. data/lib/whois/parsers/whois.nic.cooking.rb +8 -0
  85. data/lib/whois/parsers/whois.nic.cool.rb +8 -0
  86. data/lib/whois/parsers/whois.nic.coop.rb +18 -3
  87. data/lib/whois/parsers/whois.nic.creditcard.rb +8 -0
  88. data/lib/whois/parsers/whois.nic.cruises.rb +8 -0
  89. data/lib/whois/parsers/whois.nic.cyou.rb +8 -0
  90. data/lib/whois/parsers/whois.nic.dance.rb +8 -0
  91. data/lib/whois/parsers/whois.nic.data.rb +8 -0
  92. data/lib/whois/parsers/whois.nic.deals.rb +8 -0
  93. data/lib/whois/parsers/whois.nic.degree.rb +8 -0
  94. data/lib/whois/parsers/whois.nic.democrat.rb +8 -0
  95. data/lib/whois/parsers/whois.nic.diamonds.rb +8 -0
  96. data/lib/whois/parsers/whois.nic.directory.rb +8 -0
  97. data/lib/whois/parsers/whois.nic.doctor.rb +8 -0
  98. data/lib/whois/parsers/whois.nic.dog.rb +8 -0
  99. data/lib/whois/parsers/whois.nic.dvag.rb +8 -0
  100. data/lib/whois/parsers/whois.nic.eco.rb +8 -0
  101. data/lib/whois/parsers/whois.nic.education.rb +8 -0
  102. data/lib/whois/parsers/whois.nic.energy.rb +8 -0
  103. data/lib/whois/parsers/whois.nic.engineer.rb +8 -0
  104. data/lib/whois/parsers/whois.nic.equipment.rb +8 -0
  105. data/lib/whois/parsers/whois.nic.estate.rb +8 -0
  106. data/lib/whois/parsers/whois.nic.eus.rb +8 -0
  107. data/lib/whois/parsers/whois.nic.expert.rb +8 -0
  108. data/lib/whois/parsers/whois.nic.exposed.rb +8 -0
  109. data/lib/whois/parsers/whois.nic.express.rb +8 -0
  110. data/lib/whois/parsers/whois.nic.family.rb +8 -0
  111. data/lib/whois/parsers/whois.nic.fan.rb +8 -0
  112. data/lib/whois/parsers/whois.nic.fans.rb +8 -0
  113. data/lib/whois/parsers/whois.nic.feedback.rb +8 -0
  114. data/lib/whois/parsers/whois.nic.film.rb +8 -0
  115. data/lib/whois/parsers/whois.nic.fish.rb +8 -0
  116. data/lib/whois/parsers/whois.nic.fishing.rb +8 -0
  117. data/lib/whois/parsers/whois.nic.florist.rb +8 -0
  118. data/lib/whois/parsers/whois.nic.football.rb +8 -0
  119. data/lib/whois/parsers/whois.nic.forex.rb +8 -0
  120. data/lib/whois/parsers/whois.nic.foundation.rb +8 -0
  121. data/lib/whois/parsers/whois.nic.fox.rb +8 -0
  122. data/lib/whois/parsers/whois.nic.fr.rb +3 -0
  123. data/lib/whois/parsers/whois.nic.frl.rb +8 -0
  124. data/lib/whois/parsers/whois.nic.furniture.rb +8 -0
  125. data/lib/whois/parsers/whois.nic.futbol.rb +8 -0
  126. data/lib/whois/parsers/whois.nic.fyi.rb +8 -0
  127. data/lib/whois/parsers/whois.nic.gal.rb +8 -0
  128. data/lib/whois/parsers/whois.nic.gd.rb +4 -0
  129. data/lib/whois/parsers/whois.nic.gent.rb +8 -0
  130. data/lib/whois/parsers/whois.nic.giving.rb +8 -0
  131. data/lib/whois/parsers/whois.nic.glass.rb +8 -0
  132. data/lib/whois/parsers/whois.nic.gmbh.rb +8 -0
  133. data/lib/whois/parsers/whois.nic.graphics.rb +8 -0
  134. data/lib/whois/parsers/whois.nic.gratis.rb +8 -0
  135. data/lib/whois/parsers/whois.nic.guru.rb +8 -0
  136. data/lib/whois/parsers/whois.nic.hamburg.rb +8 -0
  137. data/lib/whois/parsers/whois.nic.haus.rb +8 -0
  138. data/lib/whois/parsers/whois.nic.holdings.rb +8 -0
  139. data/lib/whois/parsers/whois.nic.holiday.rb +8 -0
  140. data/lib/whois/parsers/whois.nic.house.rb +8 -0
  141. data/lib/whois/parsers/whois.nic.immo.rb +8 -0
  142. data/lib/whois/parsers/whois.nic.immobilien.rb +8 -0
  143. data/lib/whois/parsers/whois.nic.inc.rb +8 -0
  144. data/lib/whois/parsers/whois.nic.institute.rb +8 -0
  145. data/lib/whois/parsers/whois.nic.insure.rb +8 -0
  146. data/lib/whois/parsers/whois.nic.international.rb +8 -0
  147. data/lib/whois/parsers/whois.nic.jewelry.rb +8 -0
  148. data/lib/whois/parsers/whois.nic.kaufen.rb +8 -0
  149. data/lib/whois/parsers/whois.nic.kiwi.rb +8 -0
  150. data/lib/whois/parsers/whois.nic.kn.rb +8 -0
  151. data/lib/whois/parsers/whois.nic.kyoto.rb +8 -0
  152. data/lib/whois/parsers/whois.nic.land.rb +8 -0
  153. data/lib/whois/parsers/whois.nic.lat.rb +8 -0
  154. data/lib/whois/parsers/whois.nic.lawyer.rb +8 -0
  155. data/lib/whois/parsers/whois.nic.lease.rb +8 -0
  156. data/lib/whois/parsers/whois.nic.legal.rb +8 -0
  157. data/lib/whois/parsers/whois.nic.limited.rb +8 -0
  158. data/lib/whois/parsers/whois.nic.limo.rb +8 -0
  159. data/lib/whois/parsers/whois.nic.london.rb +8 -0
  160. data/lib/whois/parsers/whois.nic.love.rb +8 -0
  161. data/lib/whois/parsers/whois.nic.luxury.rb +8 -0
  162. data/lib/whois/parsers/whois.nic.maison.rb +8 -0
  163. data/lib/whois/parsers/whois.nic.makeup.rb +8 -0
  164. data/lib/whois/parsers/whois.nic.man.rb +8 -0
  165. data/lib/whois/parsers/whois.nic.management.rb +8 -0
  166. data/lib/whois/parsers/whois.nic.mba.rb +8 -0
  167. data/lib/whois/parsers/whois.nic.memorial.rb +8 -0
  168. data/lib/whois/parsers/whois.nic.men.rb +8 -0
  169. data/lib/whois/parsers/whois.nic.miami.rb +8 -0
  170. data/lib/whois/parsers/whois.nic.mobile.rb +8 -0
  171. data/lib/whois/parsers/whois.nic.moda.rb +8 -0
  172. data/lib/whois/parsers/whois.nic.moe.rb +8 -0
  173. data/lib/whois/parsers/whois.nic.money.rb +8 -0
  174. data/lib/whois/parsers/whois.nic.monster.rb +8 -0
  175. data/lib/whois/parsers/whois.nic.mortgage.rb +8 -0
  176. data/lib/whois/parsers/whois.nic.moscow.rb +8 -0
  177. data/lib/whois/parsers/whois.nic.museum.rb +8 -0
  178. data/lib/whois/parsers/whois.nic.nrw.rb +8 -0
  179. data/lib/whois/parsers/whois.nic.observer.rb +8 -0
  180. data/lib/whois/parsers/whois.nic.okinawa.rb +17 -0
  181. data/lib/whois/parsers/whois.nic.ooo.rb +8 -0
  182. data/lib/whois/parsers/whois.nic.partners.rb +8 -0
  183. data/lib/whois/parsers/whois.nic.photography.rb +8 -0
  184. data/lib/whois/parsers/whois.nic.photos.rb +8 -0
  185. data/lib/whois/parsers/whois.nic.pizza.rb +8 -0
  186. data/lib/whois/parsers/whois.nic.place.rb +8 -0
  187. data/lib/whois/parsers/whois.nic.plumbing.rb +8 -0
  188. data/lib/whois/parsers/whois.nic.pm.rb +3 -0
  189. data/lib/whois/parsers/whois.nic.press.rb +8 -0
  190. data/lib/whois/parsers/whois.nic.properties.rb +8 -0
  191. data/lib/whois/parsers/whois.nic.quebec.rb +8 -0
  192. data/lib/whois/parsers/whois.nic.quest.rb +8 -0
  193. data/lib/whois/parsers/whois.nic.racing.rb +8 -0
  194. data/lib/whois/parsers/whois.nic.radio.rb +8 -0
  195. data/lib/whois/parsers/whois.nic.realty.rb +8 -0
  196. data/lib/whois/parsers/whois.nic.recipes.rb +8 -0
  197. data/lib/whois/parsers/whois.nic.reisen.rb +8 -0
  198. data/lib/whois/parsers/whois.nic.rent.rb +8 -0
  199. data/lib/whois/parsers/whois.nic.rentals.rb +8 -0
  200. data/lib/whois/parsers/whois.nic.republican.rb +8 -0
  201. data/lib/whois/parsers/whois.nic.rest.rb +8 -0
  202. data/lib/whois/parsers/whois.nic.restaurant.rb +8 -0
  203. data/lib/whois/parsers/whois.nic.review.rb +8 -0
  204. data/lib/whois/parsers/whois.nic.rip.rb +8 -0
  205. data/lib/whois/parsers/whois.nic.rodeo.rb +8 -0
  206. data/lib/whois/parsers/whois.nic.ruhr.rb +8 -0
  207. data/lib/whois/parsers/whois.nic.saarland.rb +8 -0
  208. data/lib/whois/parsers/whois.nic.salon.rb +8 -0
  209. data/lib/whois/parsers/whois.nic.sap.rb +8 -0
  210. data/lib/whois/parsers/whois.nic.sarl.rb +8 -0
  211. data/lib/whois/parsers/whois.nic.sbs.rb +8 -0
  212. data/lib/whois/parsers/whois.nic.schule.rb +8 -0
  213. data/lib/whois/parsers/whois.nic.schwarz.rb +8 -0
  214. data/lib/whois/parsers/whois.nic.scot.rb +8 -0
  215. data/lib/whois/parsers/whois.nic.security.rb +8 -0
  216. data/lib/whois/parsers/whois.nic.select.rb +8 -0
  217. data/lib/whois/parsers/whois.nic.shoes.rb +8 -0
  218. data/lib/whois/parsers/whois.nic.shopping.rb +8 -0
  219. data/lib/whois/parsers/whois.nic.skin.rb +8 -0
  220. data/lib/whois/parsers/whois.nic.soccer.rb +8 -0
  221. data/lib/whois/parsers/whois.nic.solar.rb +8 -0
  222. data/lib/whois/parsers/whois.nic.sport.rb +8 -0
  223. data/lib/whois/parsers/whois.nic.ss.rb +36 -0
  224. data/lib/whois/parsers/whois.nic.storage.rb +8 -0
  225. data/lib/whois/parsers/whois.nic.study.rb +8 -0
  226. data/lib/whois/parsers/whois.nic.style.rb +8 -0
  227. data/lib/whois/parsers/whois.nic.support.rb +8 -0
  228. data/lib/whois/parsers/whois.nic.surf.rb +8 -0
  229. data/lib/whois/parsers/whois.nic.surgery.rb +8 -0
  230. data/lib/whois/parsers/whois.nic.swiss.rb +8 -0
  231. data/lib/whois/parsers/whois.nic.taipei.rb +8 -0
  232. data/lib/whois/parsers/whois.nic.tatar.rb +19 -0
  233. data/lib/whois/parsers/whois.nic.team.rb +8 -0
  234. data/lib/whois/parsers/whois.nic.tennis.rb +8 -0
  235. data/lib/whois/parsers/whois.nic.theater.rb +8 -0
  236. data/lib/whois/parsers/whois.nic.tickets.rb +8 -0
  237. data/lib/whois/parsers/whois.nic.tienda.rb +8 -0
  238. data/lib/whois/parsers/whois.nic.tips.rb +8 -0
  239. data/lib/whois/parsers/whois.nic.tires.rb +8 -0
  240. data/lib/whois/parsers/whois.nic.tirol.rb +8 -0
  241. data/lib/whois/parsers/whois.nic.town.rb +8 -0
  242. data/lib/whois/parsers/whois.nic.toyota.rb +8 -0
  243. data/lib/whois/parsers/whois.nic.toys.rb +8 -0
  244. data/lib/whois/parsers/whois.nic.trade.rb +8 -0
  245. data/lib/whois/parsers/whois.nic.training.rb +8 -0
  246. data/lib/whois/parsers/whois.nic.university.rb +8 -0
  247. data/lib/whois/parsers/whois.nic.uno.rb +8 -0
  248. data/lib/whois/parsers/whois.nic.vet.rb +8 -0
  249. data/lib/whois/parsers/whois.nic.viajes.rb +8 -0
  250. data/lib/whois/parsers/whois.nic.villas.rb +8 -0
  251. data/lib/whois/parsers/whois.nic.voyage.rb +8 -0
  252. data/lib/whois/parsers/whois.nic.webcam.rb +8 -0
  253. data/lib/whois/parsers/whois.nic.wedding.rb +8 -0
  254. data/lib/whois/parsers/whois.nic.wien.rb +8 -0
  255. data/lib/whois/parsers/whois.nic.wiki.rb +8 -0
  256. data/lib/whois/parsers/whois.nic.wtf.rb +8 -0
  257. data/lib/whois/parsers/whois.nic.xin.rb +8 -0
  258. data/lib/whois/parsers/whois.nic.xn--80adxhks.rb +8 -0
  259. data/lib/whois/parsers/whois.nic.xn--d1acj3b.rb +15 -0
  260. data/lib/whois/parsers/whois.nic.xn--mk1bu44c.rb +13 -0
  261. data/lib/whois/parsers/whois.nic.xn--t60b56a.rb +8 -0
  262. data/lib/whois/parsers/whois.nic.xn--tckwe.rb +39 -0
  263. data/lib/whois/parsers/whois.nic.yoga.rb +8 -0
  264. data/lib/whois/parsers/whois.nic.yokohama.rb +8 -0
  265. data/lib/whois/parsers/whois.nic.yt.rb +24 -0
  266. data/lib/whois/parsers/whois.online.rs.corenic.net.rb +8 -0
  267. data/lib/whois/parsers/whois.publicinterestregistry.net.rb +8 -0
  268. data/lib/whois/parsers/whois.ryce-rsp.com.rb +13 -0
  269. data/lib/whois/parsers/whois.teleinfo.cn.rb +16 -0
  270. metadata +276 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 64090073c595bd3cbd6e1a52628cf6d3481de3933b791d9338bf1793922dc6a4
4
- data.tar.gz: b15050ea47d7662aedb25a2f0e6e0e8997c7c825b2de70e149dce0f85fd7dd8c
3
+ metadata.gz: 54c1fc5d5bb3d8adda3cbe6b644a0f2982195267f46654c6025090b16b7f6643
4
+ data.tar.gz: 8b8e0ae4f21a313e6fa65c1d4868bf28326bbc57df15e3bbfa8256c4a38f3217
5
5
  SHA512:
6
- metadata.gz: 8946d38a18bdb012fc79661fc31fcf67f4e63b7cdd728e14dacf48c77a72317322f145544d89b97725f292d4e1860a2aa9ba4842824378745541aea0e9408eee
7
- data.tar.gz: 8d10ae4db2cfdf8aee03bc17d4867afd56e03dfa19ddcf4ca31610acbd4957bad49a34a3c6fbbbc2988c77ae42c7f86e1c4ae8e1f2a0bd1342ffe5febd68bbbe
6
+ metadata.gz: c1be7e51963fefa6a8571faa4577bbdab9ca95009bd1ccf8413b65a7816a7c53539d5f05d22f456154124ec12e8d79b1b86df9f1cc1633beb4d7532dbaaf273f
7
+ data.tar.gz: 4d07890e7c2e5bbf59a19f076820f276256453dd1bcdfb700df51d2a1c1581395125c12ab8c2a8d2c90864c960ca99bd9590932dca4c2fe71c04a85cda225203
data/CHANGELOG.md CHANGED
@@ -3,7 +3,21 @@
3
3
  This project uses [Semantic Versioning 2.0.0](http://semver.org/).
4
4
 
5
5
 
6
- #### Unreleased 0.1.0
6
+ #### Release 0.2.0 (2026-09-25)
7
+
8
+ - ADDED: Extended the usage-ranked audit and parser work through 1,000 ICANN
9
+ DNS Magnitude TLD strings from the 2026-09-12 snapshot.
10
+ - CLARIFIED: The 1,000 rows are observed TLD strings, not 1,000 guaranteed
11
+ working registries or domain-availability results. The audit keeps verified
12
+ parser evidence, explicit unavailable or unsupported responses,
13
+ unknown or unresolved endpoints, and classification-only rows distinct.
14
+ - ADDED: Preserved the source manifest, verification evidence, planning
15
+ inventory, and five implementation-package reports for ranks 301-1000.
16
+ - TESTED: The combined parser and audit suite passes 6,768 examples with 0
17
+ failures on Ruby 3.2.2 and 3.4.5.
18
+
19
+
20
+ #### Release 0.1.0 (2026-09-19)
7
21
 
8
22
  - CHANGED: Continued the project as `whois-parser-next`, with the original MIT
9
23
  license, attribution, and Git history preserved.
data/README.md CHANGED
@@ -38,8 +38,7 @@ of current WHOIS responses, explicit unknown states, registry-specific
38
38
  fixtures, and safe handling of malformed, rate-limited, retired, or changed
39
39
  server responses.
40
40
 
41
- The current development gem name is `whois-parser-next`. It has not yet been
42
- published to RubyGems.
41
+ The latest published RubyGems release is `0.2.0`.
43
42
 
44
43
  ## Compatibility
45
44
 
@@ -83,12 +82,21 @@ bundle exec rspec
83
82
 
84
83
  ## Coverage evidence
85
84
 
86
- The 2026-09-19 live audit covers the ICANN DNS Magnitude ordering through rank
87
- 300. Start with the [Top 20 review](docs/audits/top-20-tlds-2026-09-19.md) and
88
- [Top 100 audit](docs/audits/top-100-tlds-2026-09-19.md); the same directory
89
- contains the contiguous 25-TLD reports for ranks 101 through 300. Each report
90
- separates verified parsing from unavailable, retired, restricted, web-only,
91
- and unresolved WHOIS paths.
85
+ The 2026-09-19 integrated audit covers 1,000 observed TLD strings from the
86
+ ICANN DNS Magnitude snapshot dated 2026-09-12. These strings are not 1,000
87
+ guaranteed working WHOIS registries or domain-availability results. The audit
88
+ keeps verified parser evidence, explicit unavailable or unsupported
89
+ responses, unknown or unresolved endpoints, and classification-only rows
90
+ distinct.
91
+
92
+ Start with the [source verification report](docs/audits/top-1000-source-verification-2026-09-19.md),
93
+ the [Top 20 review](docs/audits/top-20-tlds-2026-09-19.md), and the [Top 100
94
+ audit](docs/audits/top-100-tlds-2026-09-19.md). The same directory contains
95
+ the contiguous reports for ranks 101 through 300, the [301-1000 work-package
96
+ plan](docs/audits/whois-parser-top1000-work-packages-2026-09-19.md), and the
97
+ five package audit reports. Each report preserves the evidence boundary and
98
+ does not turn unavailable, unsupported, unresolved, or classification-only
99
+ rows into availability claims.
92
100
 
93
101
  ## Join the work
94
102
 
data/RELEASING.md CHANGED
@@ -21,8 +21,8 @@ RubyGems API key to the repository or its Actions secrets.
21
21
  Create and push the annotated release tag only after the checks above pass:
22
22
 
23
23
  ```shell
24
- git tag -a v0.1.0 -m "whois-parser-next 0.1.0"
25
- git push origin v0.1.0
24
+ git tag -a v0.2.0 -m "whois-parser-next 0.2.0"
25
+ git push origin v0.2.0
26
26
  ```
27
27
 
28
28
  The release workflow repeats the full suite and package smoke test before it
@@ -1,6 +1,6 @@
1
1
  module Whois
2
2
  class Parser
3
3
  # The current library version.
4
- VERSION = "0.1.0".freeze
4
+ VERSION = "0.2.0".freeze
5
5
  end
6
6
  end
@@ -0,0 +1,12 @@
1
+ require_relative 'base_icann_compliant'
2
+
3
+ module Whois
4
+ class Parsers
5
+ # CentralNic registries that expose the ICANN key/value record shape.
6
+ class BaseCentralnicIcann < BaseIcannCompliant
7
+ self.scanner = Scanners::BaseIcannCompliant, {
8
+ pattern_available: /^The queried object does not exist:\s+DOMAIN NOT FOUND\s*$/i,
9
+ }
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,19 @@
1
+ require_relative 'whois.cira.ca'
2
+ require_relative 'registry_response_safety'
3
+
4
+ module Whois
5
+ class Parsers
6
+ # CIRA-shaped registries use the same record scanner, but an unexpected
7
+ # non-record response must remain unknown rather than becoming a parser
8
+ # error that callers might accidentally treat as registration.
9
+ class BaseCiraRegistry < WhoisCiraCa
10
+ include RegistryResponseSafety
11
+
12
+ property_supported :status do
13
+ super()
14
+ rescue ParserError
15
+ :unknown
16
+ end
17
+ end
18
+ end
19
+ end
@@ -54,7 +54,7 @@ module Whois
54
54
  end
55
55
 
56
56
  property_supported :registered? do
57
- [:registered, :reserved].include?(status)
57
+ status == :registered
58
58
  end
59
59
 
60
60
 
@@ -0,0 +1,12 @@
1
+ require_relative 'base_icann_compliant'
2
+
3
+ module Whois
4
+ class Parsers
5
+ # Shared ICANN key/value parser for Identity Digital registries.
6
+ #
7
+ # Individual registries differ only in the authoritative absence marker;
8
+ # host-specific subclasses keep those markers explicit.
9
+ class BaseIdentityDigital < BaseIcannCompliant
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,48 @@
1
+ require_relative 'base'
2
+ require_relative 'registry_response_safety'
3
+
4
+ module Whois
5
+ class Parsers
6
+ # Minimal parser contract for JWhoisServer responses used by the French
7
+ # overseas registries. Registration is reported only from a domain line;
8
+ # the registry's explicit NO OBJECT FOUND marker is the sole absence proof.
9
+ class BaseJwhois < Base
10
+ include RegistryResponseSafety
11
+
12
+ property_supported :domain do
13
+ content_for_scanner[/^domain:\s*(\S+)\s*$/i, 1]&.downcase
14
+ end
15
+
16
+ property_supported :status do
17
+ if available?
18
+ :available
19
+ elsif registered_evidence?
20
+ :registered
21
+ else
22
+ :unknown
23
+ end
24
+ end
25
+
26
+ property_supported :available? do
27
+ content_for_scanner.match?(/^NO OBJECT FOUND!\s*$/i)
28
+ end
29
+
30
+ property_supported :registered? do
31
+ status == :registered
32
+ end
33
+
34
+ property_supported :nameservers do
35
+ content_for_scanner.scan(/^nameserver:\s*(\S+)\s*$/i).flatten.map do |name|
36
+ Parser::Nameserver.new(name: name.downcase)
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def registered_evidence?
43
+ content_for_scanner.match?(/^domain:\s*\S+/i) &&
44
+ content_for_scanner.match?(/^(?:changed|nameserver):\s*\S+/i)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,17 @@
1
+ require_relative 'base_icann_compliant'
2
+
3
+ module Whois
4
+ class Parsers
5
+ # Shared parser for registries that use the ICANN response layout and
6
+ # report an exact `Available` line for an absent object.
7
+ class BaseNicReservedAvailable < BaseIcannCompliant
8
+ self.scanner = Scanners::BaseIcannCompliant, {
9
+ pattern_available: /^Available\s*$/i,
10
+ }
11
+
12
+ def reserved?
13
+ content_for_scanner.match?(/^Reserved:\s*/i)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,27 @@
1
+ require_relative 'base'
2
+
3
+ module Whois
4
+ class Parsers
5
+ # A registry response that explicitly reserves or prohibits the queried
6
+ # name. It is not evidence of either registration or availability.
7
+ class BaseReservedRegistry < Base
8
+ property_supported :status do
9
+ :unknown
10
+ end
11
+
12
+ property_supported :available? do
13
+ false
14
+ end
15
+
16
+ property_supported :registered? do
17
+ false
18
+ end
19
+
20
+ def response_unavailable?
21
+ content_for_scanner.match?(
22
+ /\A(?:Reserved Domain Name|This name is reserved by the Registry\b|The queried object does not exist:.*reserved list)/i
23
+ )
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,39 @@
1
+ require_relative 'base_icann_compliant'
2
+
3
+ module Whois
4
+ class Parsers
5
+ # Conservative ICANN-style parser shared by the package-3 registries.
6
+ # The absence markers are complete lines observed in current port-43
7
+ # responses. Empty, denied, and throttled responses remain unavailable via
8
+ # RegistryResponseSafety inherited from BaseIcannCompliant.
9
+ class BaseTop1000Icann < BaseIcannCompliant
10
+ AVAILABLE_MARKERS = [
11
+ /^No Data Found\s*$/i,
12
+ /^The queried object does not exist:\s*(?:DOMAIN NOT FOUND|no matching objects found)\s*$/i,
13
+ /^>>> Domain \S+ is available for registration\s*$/i,
14
+ /^Domain not found\s*$/i,
15
+ /^%% NOT FOUND\s*$/i,
16
+ ].freeze
17
+
18
+ RESERVED_MARKERS = [
19
+ /^Reserved Domain Name\s*$/i,
20
+ /^This name is reserved by the Registry\.\s*$/i,
21
+ ].freeze
22
+
23
+ property_supported :available? do
24
+ AVAILABLE_MARKERS.any? { |marker| content_for_scanner.match?(marker) }
25
+ end
26
+
27
+ property_supported :reserved? do
28
+ RESERVED_MARKERS.any? { |marker| content_for_scanner.match?(marker) }
29
+ end
30
+
31
+ # `reserved?` is intentionally a parser predicate rather than a public
32
+ # record property. BaseIcannCompliant consults it while determining the
33
+ # status of a reserved registry response.
34
+ def reserved?
35
+ RESERVED_MARKERS.any? { |marker| content_for_scanner.match?(marker) }
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,26 @@
1
+ require_relative 'base'
2
+
3
+ module Whois
4
+ class Parsers
5
+ # WHOIS endpoints that have retired port-43 service in favour of RDAP.
6
+ class BaseTop1000Retired < Base
7
+ property_supported :status do
8
+ :unknown
9
+ end
10
+
11
+ property_supported :available? do
12
+ false
13
+ end
14
+
15
+ property_supported :registered? do
16
+ false
17
+ end
18
+
19
+ def response_unavailable?
20
+ content_for_scanner.match?(
21
+ /^Notice: Effective May 1, 2026, the WHOIS service has been retired\b/i
22
+ )
23
+ end
24
+ end
25
+ end
26
+ end
@@ -21,7 +21,7 @@ module Whois
21
21
 
22
22
  def response_unavailable?
23
23
  content_for_scanner.match?(
24
- /^(?:TLD is not supported\.|No Data Found)\s*$/i
24
+ /\A(?:TLD is not supported\.|No Data Found)[ \t]*(?:\n|\z)/i
25
25
  )
26
26
  end
27
27
  end
@@ -0,0 +1,10 @@
1
+ require_relative 'whois.cnnic.cn'
2
+
3
+ module Whois
4
+ class Parsers
5
+ # The registry publishes both `cwhois.cnnic.cn` and the historical
6
+ # `whois.cnnic.cn` service name. Keep both names on the same parser.
7
+ class CwhoisCnnicCn < WhoisCnnicCn
8
+ end
9
+ end
10
+ end
@@ -22,6 +22,8 @@ module Whois
22
22
  def response_unavailable?
23
23
  response_incomplete? || content_for_scanner.match?(
24
24
  /^(?:\s*(?:%|#)\s*)?(?:requests of this client are not permitted|access to the whois service is denied|whois service is unavailable)\b/i
25
+ ) || content_for_scanner.match?(
26
+ /\ATLD is not supported\.[ \t]*(?:\n|\z)/i
25
27
  )
26
28
  end
27
29
  end
@@ -8,6 +8,7 @@
8
8
 
9
9
 
10
10
  require_relative 'base'
11
+ require_relative 'registry_response_safety'
11
12
 
12
13
 
13
14
  module Whois
@@ -23,21 +24,25 @@ module Whois
23
24
  # The Example parser for the list of all available methods.
24
25
  #
25
26
  class WhoisAx < Base
27
+ include RegistryResponseSafety
26
28
 
27
29
  property_supported :status do
28
30
  if available?
29
31
  :available
30
- else
32
+ elsif registered_evidence?
31
33
  :registered
34
+ else
35
+ :unknown
32
36
  end
33
37
  end
34
38
 
35
39
  property_supported :available? do
36
- !!(content_for_scanner =~ /^No records matching .+ found/)
40
+ !!(content_for_scanner =~ /^No records matching \S+ found\.\s*$/i ||
41
+ content_for_scanner =~ /^Domain not found\s*$/i)
37
42
  end
38
43
 
39
44
  property_supported :registered? do
40
- !available?
45
+ status == :registered
41
46
  end
42
47
 
43
48
 
@@ -58,6 +63,13 @@ module Whois
58
63
  end
59
64
  end
60
65
 
66
+ private
67
+
68
+ def registered_evidence?
69
+ content_for_scanner.match?(/^Domain Name:\s+\S+/i) &&
70
+ content_for_scanner.match?(/^(?:Created|Name Server \d):\s+\S+/i)
71
+ end
72
+
61
73
  end
62
74
 
63
75
  end
@@ -8,6 +8,7 @@
8
8
 
9
9
 
10
10
  require_relative 'base'
11
+ require_relative 'registry_response_safety'
11
12
  require 'whois/scanners/whois.cnnic.cn.rb'
12
13
 
13
14
 
@@ -16,10 +17,13 @@ module Whois
16
17
 
17
18
  # Parser for the whois.cnnic.cn server.
18
19
  class WhoisCnnicCn < Base
20
+ include RegistryResponseSafety
19
21
  include Scanners::Scannable
20
22
 
21
23
  self.scanner = Scanners::WhoisCnnicCn
22
24
 
25
+ RESPONSE_MARKER = /(?:^No matching record\.?\s*$|^The domain you requested is prohibited\.?\s*$|^Sorry, The domain you requested is in the reserved list\.?\s*$|^Domain Name:\s*\S+)/i
26
+
23
27
 
24
28
  property_not_supported :disclaimer
25
29
 
@@ -34,15 +38,26 @@ module Whois
34
38
 
35
39
 
36
40
  property_supported :status do
37
- Array.wrap node("Domain Status")
41
+ return [] if available? || reserved?
42
+ return :unknown unless recognized_response?
43
+
44
+ statuses = Array.wrap node("Domain Status")
45
+ if statuses.empty?
46
+ :unknown
47
+ else
48
+ statuses
49
+ end
38
50
  end
39
51
 
40
52
  property_supported :available? do
53
+ return true if content_for_scanner.match?(/^No matching record\.?\s*$/i)
54
+ return false unless recognized_response?
55
+
41
56
  !!node("status:available")
42
57
  end
43
58
 
44
59
  property_supported :registered? do
45
- !reserved? && !available?
60
+ status.is_a?(Array) && !status.empty? && registered_evidence?
46
61
  end
47
62
 
48
63
 
@@ -86,12 +101,25 @@ module Whois
86
101
 
87
102
  # NEWPROPERTY
88
103
  def reserved?
104
+ return true if content_for_scanner.match?(/^The domain you requested is prohibited\.?\s*$/i)
105
+ return true if content_for_scanner.match?(/^Sorry, The domain you requested is in the reserved list\.?\s*$/i)
106
+ return false unless recognized_response?
107
+
89
108
  !!node("status:reserved")
90
109
  end
91
110
 
92
-
93
111
  private
94
112
 
113
+ def registered_evidence?
114
+ !node("Domain Name").to_s.strip.empty? &&
115
+ !Array.wrap(node("Domain Status")).empty?
116
+ end
117
+
118
+ def recognized_response?
119
+ content_for_scanner.match?(RESPONSE_MARKER)
120
+ end
121
+
122
+
95
123
  def build_contact(element, type)
96
124
  node("#{element}") do |value|
97
125
  Parser::Contact.new(
@@ -0,0 +1,11 @@
1
+ require_relative 'base_unsupported_registry'
2
+
3
+ module Whois
4
+ class Parsers
5
+ class WhoisDominioGq < BaseUnsupportedRegistry
6
+ def response_unavailable?
7
+ super || content_for_scanner.match?(/\AThe domain you requested is not known in Freenoms database\.\n\nThis TLD has no whois server\./i)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ require_relative 'base'
2
+ require_relative 'registry_response_safety'
3
+
4
+ module Whois
5
+ class Parsers
6
+ # The .укр registry uses an exact "No match for domain" response.
7
+ class WhoisDotukrCom < Base
8
+ include RegistryResponseSafety
9
+
10
+ property_supported :status do
11
+ available? ? :available : :unknown
12
+ end
13
+
14
+ property_supported :available? do
15
+ !!(content_for_scanner =~ /^No match for domain\s+\S+\.?\s*$/i)
16
+ end
17
+
18
+ property_supported :registered? do
19
+ false
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'base_identity_digital'
2
+ module Whois
3
+ class Parsers
4
+ class WhoisGtldKnetCn < BaseIdentityDigital
5
+ self.scanner = Scanners::BaseIcannCompliant, {
6
+ pattern_available: /^The queried object does not exist:\s+[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?(?:\.[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?)+\s*$/i,
7
+ }
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'whois.nic.store'
2
+
3
+ module Whois
4
+ class Parsers
5
+ # The .ky registry uses the ICANN layout and Radix's exact availability
6
+ # sentence.
7
+ class WhoisKyregistryKy < WhoisNicStore
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'base_identity_digital'
2
+ module Whois
3
+ class Parsers
4
+ class WhoisMadridRsCorenicNet < BaseIdentityDigital
5
+ self.scanner = Scanners::BaseIcannCompliant, { pattern_available: /^The queried object does not exist: no matching objects found\s*$/i }
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ require_relative 'base_jwhois'
2
+
3
+ module Whois
4
+ class Parsers
5
+ # Parser for the JWhoisServer shared by .gf and .mq.
6
+ class WhoisMediaservNet < BaseJwhois
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'base_reserved_registry'
2
+
3
+ module Whois
4
+ class Parsers
5
+ class WhoisNgtldCn < BaseReservedRegistry
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'base_unsupported_registry'
2
+
3
+ module Whois
4
+ class Parsers
5
+ class WhoisNicAcademy < BaseUnsupportedRegistry
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'base_reserved_registry'
2
+
3
+ module Whois
4
+ class Parsers
5
+ class WhoisNicAccountant < BaseReservedRegistry
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'base_unsupported_registry'
2
+
3
+ module Whois
4
+ class Parsers
5
+ class WhoisNicActor < BaseUnsupportedRegistry
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'base_unsupported_registry'
2
+
3
+ module Whois
4
+ class Parsers
5
+ class WhoisNicAgency < BaseUnsupportedRegistry
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'base_unsupported_registry'
2
+
3
+ module Whois
4
+ class Parsers
5
+ class WhoisNicAirforce < BaseUnsupportedRegistry
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'base_identity_digital'
2
+ module Whois
3
+ class Parsers
4
+ class WhoisNicAmsterdam < BaseIdentityDigital
5
+ self.scanner = Scanners::BaseIcannCompliant, { pattern_available: /^Domain Status:\s*free\s*$/i }
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'base_unsupported_registry'
2
+
3
+ module Whois
4
+ class Parsers
5
+ class WhoisNicApartments < BaseUnsupportedRegistry
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'base_unsupported_registry'
2
+
3
+ module Whois
4
+ class Parsers
5
+ class WhoisNicArmy < BaseUnsupportedRegistry
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'base_unsupported_registry'
2
+
3
+ module Whois
4
+ class Parsers
5
+ class WhoisNicAssociates < BaseUnsupportedRegistry
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'base_unsupported_registry'
2
+
3
+ module Whois
4
+ class Parsers
5
+ class WhoisNicAuction < BaseUnsupportedRegistry
6
+ end
7
+ end
8
+ end