2

I am very new to ruby and rails. I am trying to output all the parsed whois info to json output. I have the following:

class WhoisController < ApplicationController
  def index
    c = Whois::Client.new
    record = c.lookup("google.com")
    parser = record.parser
    created = parser.created_on
    msg = {:created => created}
    render :json => msg
  end
end

Output:

{"created":"1997-09-15T00:00:00.000-07:00"}

However, the parser has a LOT more info available....without knowing all the fields available, how do I dump all the keys/values to json?

I've tried:

class WhoisController < ApplicationController
  def index
    c = Whois::Client.new
    record = c.lookup("google.com")
    parser = record.parser
    msg = {:whois => parser}
    render :json => msg
  end
end

But end up getting:

SystemStackError in WhoisController#index

EDIT:

I've also tried:

parser.attributes.each do |attr_name, attr_value|
  puts attr_name
end

But end up getting another error:

undefined method `attributes' for #<Whois::Parser:0x00007fc030d74018>

Both Python and Go (through reflection) can do this. What is the Ruby way to achieve this?

EDIT:

class WhoisController < ApplicationController
    def index
        c = Whois::Client.new
        record = c.lookup("google.com")
        parser = record.parser
        msg = {}
        for x_prop in Whois::Parser::PROPERTIES
            msg[x_prop] = parser.send(x_prop)
        end
        render :json => msg
    end
end

This works ONLY if all the properties exist on parser. However, some domain names don't have all the properties and will result in:

Unable to find a parser for property `registrant_contacts'

I then try to set it only if that property exists:

msg = {}
for x_prop in Whois::Parser::PROPERTIES
  parser.has_attribute?(:x_prop) 
    msg[x_prop] = parser.send(x_prop) 
end
render :json => msg

I get another error:

undefined method `has_attribute?'

EDIT #3:

I've also tried:

msg = {}
for prop in Whois::Parser::PROPERTIES
  msg[prop] = parser.send(prop) if parser.respond_to?(prop)
end
render :json => msg

This still fails if the property is missing in parser. ;(

user_78361084
  • 3,538
  • 22
  • 85
  • 147

3 Answers3

2
class WhoisController < ApplicationController
    def index
        c = Whois::Client.new
        record = c.lookup("google.com")
        parser = record.parser
        msg = {}
        for x_prop in Whois::Parser::PROPERTIES
            msg[x_prop] = parser.send(x_prop)
        end
        render :json => msg
    end
end

in few cases something properties can be empty and cause an error, to escape this:

begin
    msg[x_prop] = parser.send(x_prop)
rescue
    # do nothing
end
thiaguerd
  • 807
  • 1
  • 7
  • 16
  • On a couple of them I get "Unable to find a parser for property `registrant_contacts' " – user_78361084 Feb 04 '19 at 00:22
  • parser.has_attribute?(:prop) msg[prop] = parser.send(prop) I get undefined method `has_attribute?' – user_78361084 Feb 04 '19 at 00:36
  • @MarissaLevy just use a try catch, like my edit on answe – thiaguerd Feb 04 '19 at 05:57
  • thx for helping a newb....another bounty coming your way when I am allowed to reward it. – user_78361084 Feb 04 '19 at 22:26
  • 1
    The question here is: Why use a *for* loop when you can use [`#each`](http://ruby-doc.org/core-2.6.1/Array.html#method-i-each)? Or [`#each_with_object`](http://ruby-doc.org/core-2.6.1/Enumerable.html#method-i-each_with_object) for that matter. – 3limin4t0r Feb 05 '19 at 17:30
  • `for...in` is very unidiomatic for Ruby. It's not wrong, but using iterators such as @JohanWentholt's suggestion generally leads to more concise and comprehensible code. Also, checking for the ability to perform a task (`if..else..end`) is generally more performant to to the point than rescuing. Rescue is better used to catch `exceptions`, that which is unexpected, not to handle expected failures. – Tom Feb 07 '19 at 04:12
  • 1
    The other issue with `for...in` is that it doesn't create a new scope. All variables set in the scope (including `x_prop`) are still available after iteration. This can lead to some unexpected behaviour at times. Whereas using an iterator will add a new scope over the current scope, allowing you to shadow outer variables or set variables that are only available while iterating. In some cases you might want to use `for...in`, but generally speaking if you don't have a valid reason you use `#each`. – 3limin4t0r Feb 07 '19 at 10:13
0

For SystemStackError in WhoisController#index:

I think it is because you are calling whois with Whois again at record = Whois.whois("google.com"). Try record = whois("google.com").

For undefined method `attributes' for #<Whois::Parser:0x00007fc030d74018>: attributes method does not exit for the whois parser. See https://whoisrb.org/docs/v3/parser-properties/ .

Aaditya Maheshwari
  • 714
  • 1
  • 5
  • 16
  • Whois.whois is valid...also whois.lookup is also valid. I was mixing and matching. I've edited the samples. – user_78361084 Feb 02 '19 at 18:06
  • so, there is no way to iterate through all the fields? In python and go there are ways to do it. – user_78361084 Feb 02 '19 at 21:12
  • @MarissaLevy I wouldn't say there is no way. But you will have to write the loop yourself to iterate over the parser properties. Sometimes some libraries have minor differences across the functions/methods they provide for multiple languages. – Aaditya Maheshwari Feb 03 '19 at 00:35
-2

You can use methods or inspect.

    c = Whois::Client.new
    record = c.lookup("google.com")
    parser = record.parser
    render json: parser.methods.to_json
    render json: parser.inspect.to_json
mogbee
  • 208
  • 2
  • 5