1

Good morning,

I'm starting on Ruby, wanted to create a small tool that fetches my public IP and sends it over by email. I'm stumbling on a basic problem with a string comparison and an if/else block that won't process.

Code is quite simple (see below). The problem comes at the string comparison at line 21. What I'd want is that whenever the IP address changed from what was recorded in a file, the new IP overwrites the one in the file, and other actions (not in the current code) will ensue.

It looks like that sometimes the comparison is not executed, thus the statements following the if do not execute.

I'd like to understand why is that. Line 21 has been changed at times for if (!oldIP == ip) to if (oldIP != ip), same result. I also suspect the return value to be ignored (dead code path ?) sometimes.

Here's the code

#!/usr/bin/env ruby

require "net/http"

puts "\e[H\e[2J"

def FetchIPAddress()
  oldIP = ""
  if File::exists?('/tmp/wanipaddress.txt')
    iFile = File.open('/tmp/wanipaddress.txt')
    oldIP = iFile.read()
    iFile.close()
  end

  oFile = File.open('/tmp/wanipaddress.txt', "w+")
  ip =  Net::HTTP.get(URI("https://api.ipify.org"))

  puts "old = " + oldIP
  puts "new = " + ip

  if (!oldIP == ip)
    puts "changed"
    oFile.puts ip
    oFile.close()
  else
    ip = "unchanged"
    puts "unchanged"
  end
  return ip
end

Really, I do see some erratic behaviour here; I suspect it's just me being a newbie with Ruby.

5
  • Are you certain if (oldIP != ip) does not correct the problem? Note you open the file for writing, but only write to it when the if clause is true. If the if clause is false the (then empty) file will be closed by Ruby when you return from the method. That is wrong but also will cause confusion when running your code. One moment your current IP is saved to file, the next it is no longer there! Try this (after removing ofile = ...): if (oldIP != ip); puts "changed"; File.write('/tmp/wanipaddress.txt', ip); else.... Commented Jan 21, 2017 at 22:50
  • Another problem is that oFile.puts ip adds a newline to the ip before writing it to file. For example, "154.5.147.124\n". When that is read it obviously will not match the current ip, which doesn't end with a newline. Note too that, by convention, "snake-case" is used when naming methods (and variables). Among other things, what means they begin with a lower-case letter. FetchIPAddress, though it works, is a constant because it begins with a capital letter. The snake-case equivalent is fetch_ip_address or fetch_IP_address. Commented Jan 21, 2017 at 23:16
  • "file will be closed by Ruby when you return from the method" — returning from a method does not close files. The dangling file is closed when the program ends or maybe when the object gets garbage collected. Commented Jan 21, 2017 at 23:58
  • @Cary thanks a lot. Regarding the exact logic behind where to open/close files, disregard my code; this is a truncated version of what is really going on in the tool; some parts were sniped. About the naming convention, I'll have to lookup on that; the names right now might look at best inconsistent. I should have thought about puts appending \n to my string. I was aware that puts() might not be the best solution for everything, and wasn't aware of PERL-era chomp() :). Thanks for pointing that out. Commented Jan 22, 2017 at 0:19
  • @akuhn, thank you for setting me straight. In this case it would be closed during garbage-collection. JörgWMittag has a good explanation of the process here. Commented Jan 22, 2017 at 0:20

2 Answers 2

2

Your file likely contains a line break.

Try this

if old_ip.chomp != ip.chomp
  ...
end

chomp removes a trailing linebreak.

Best use p to print values for debugging, this will escape whitespace and thus make trailing linebreaks visible. You should never use puts for debugging.


And here is why !a == b will never ever work.

!a == b is the same as a.!().==(b) and executed as follows

  • first the ! method is called on object a, which returns false for a string
  • then ==(b) method is called on the resulting boolean
  • and since a boolean is never equal to a string the comparison will always fail
Sign up to request clarification or add additional context in comments.

1 Comment

Noted, @akuhn, thanks for pointing it out. This one I should have figured, but somehow did not.
1

The problem with this line (if (!oldIP == ip)) is pretty simple - what you want it to do is check whether the oldIP is different from the new IP.
What you do instead is take oldIP, check whether it's true or false, then negate it (that's what the ! does), then compare it to ip. Since oldIP is a String, and thus always true, which gets negated to false, and ip is (I'm guessing) a String, it will always be true, your line essentially reads if (false == true).

To solve this problem, you could use the != comparison operator, like if oldIP != ip, or, if you like the negation, if !(oldIP == ip).

4 Comments

They mentioned that oldIP != ip didn't work either for them!
@akuhn, I'm skeptical about that. See my comments on the question.
It does not work for them because they don't chomp the input.
Actually, I did try if (!oldIP == ip) while my brain was turned off; I know it wouldn't give the expected result. I dropped oldIP != ip because.... because I don't remember, really.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.