Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No implicit conversion of file into string

Tags:

json

ruby

I am hoping to loop through a directory of json files and convert them into ruby hashes. My file looper function grabs every file successfully, and the files are in correct json format. Here is my code:

def self.update_server
  if Dir.exist?("log/order_errors") == true
    logger.debug "#{Dir.entries("log/order_errors")}"
    Dir.foreach("log/order_errors") { |f|
      logger.debug "Retrieved #{f}"
      File.open(f, "r") { |current_file|
        JSON.parse(current_file)
      }
    }
  else
    logger.error "Was unable to find the directory specified."
  end
end

Any idea of what is going on or what I need to do to tidy up my files so that they can be parsed correctly?

like image 865
James Avatar asked Feb 10 '23 20:02

James


1 Answers

JSON.parse() takes a string as an argument--not a file:

require 'json'

File.open('data.json') do |f|
  JSON.parse(f)
end

--output:--
...no implicit conversion of File into String (TypeError)...

This is the way to do it:

require 'json'

File.open('data.json') do |f|
  hash = JSON.parse(f.read)  #***HERE***
  p hash
end

--output:--
{"x"=>1, "y"=>2}

The json module's docs are horrible, which unfortunately is typical of ruby. The docs say that the argument to parse() is a JSON document, which certainly sounds more like a File than a String. What the docs should say is that the argument needs to be a String in json format.

By the way, in this line:

if Dir.exist?("log/order_errors") == true 

...the exist?() method call is replaced by its return value, so if the directory exists ruby will convert that line to:

if true == true

Then ruby has to do the comparison true == true, and ruby replaces the comparison with the result of the comparison, i.e. true to produce this:

if true

Now, what if you wrote this instead:

if Dir.exist?("log/order_errors")

Once again, the exist?() method call is replaced by its return value, and if the directory exists, you will get this:

if true

If the directory doesn't exist, the exist?() method call is replaced by false, producing this:

if false

Therefore, writing == true after the exist?() method call is both a waste of time to type, and it wastes processing time because it requires ruby to do an extra comparison. You'll get the same result without doing the comparison, as shown above. The rule is: if a method returns true or false, you don't need to write == true after it. And in ruby it is usually pretty easy to tell when a method returns true or false because the method name will end with a ?.

like image 149
7stud Avatar answered Feb 13 '23 22:02

7stud