Ruby if/else flow - ruby

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.

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

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).

Related

Why do `while` loops never check user input, whereas `if` statements do?

An if statement such as:
if first_name || first_name.length == 0
puts "You can't leave the first name blank, try again: "
first_name = gets
end
functions correctly, because it asks for user input, and when tested by not entering any input (including spaces), it prints an error message, followed by prompting for user input, following which, However, when I attempt to use the same in a while loop:
while first_name || first_name.length == 0
puts "You can't leave the first name blank, try again: "
first_name = gets
end
the loop doesn't function correctly.
The loop does the following instead:
• Print the error message above (OK)
• Asks for user input (OK)
• As soon as user input is received, the loop executes once again (Wrong).
It isn't testing the length of the user's (now correct) input, and then allowing the rest of the application to carry out its tasks.
I also tried unless, nil?, and so on to rectify the loop's error using an if statement inside the loop, with no success. I thought the while loop would evaluate first_name again once the error was corrected, and find that its length was no longer zero, however, that turned out not to be the case.
In Java, to say something isn't equal to something else (in terms of strings, for example), I can use ! before the variable name. Can I do this in Ruby?
You can try this:
while first_name.length == 0 do
puts "You can't leave the first name blank, try again: "
first_name = gets
end
The way while cycle works is it evaluates the statement after while keyword. If it is true then it runs the block. And after that just the same. In your case statement is first_name || first_name.length == 0 which always will be true as first_name is always present. That's the reason it will loop again each time whatever you would input.
I think your condition is just wrong : the condition
first_name || first_name.length == 0
Will be true if first_name is non-nil, this will always be the case since you are setting it to a string.
After some further digging on the Internet, I gave .chomp a go, to see what it would do, as I found out that when gets is used, it takes your input, but apparently also inserts an \n escape sequence, when Enter is pressed, meaning that my loop didn't function as required.
By using gets.chomp, in conjunction with .empty? I was able to remove this escape sequence from my input, and have the loop function correctly.
Here's the correct code, which prevents an infinite loop:
first_name = gets.chomp
while first_name.empty? do
puts "You can't leave the first name blank, try again: "
first_name = gets.chomp
end

Does ruby's case statement fall through?

I am writing a hangman game in ruby and I wanted to use a case statement to determine which body part to place corresponding to a number of incorrect guesses. I made this game using a board class I use for other games like chess and connect-4 because I have a method which serializes the board class allowing me to save and load the game without any extra code. For the game to be saved, I needed some way of determining the number of incorrect guesses for the hangman without adding extra variables to the board class. To solve this I used an instance variable on the board class called history, which can be used to push moves from the game to the boards history. When the board gets serialized, the history is saved as well, which can be read by the game and used to determine incorrect guesses.
In the hangman game, I have a method called read history (which I use for all the games since it solves the serialization issue described above). The read_history method is responsible for reading the past guesses, display them, and determine the number of incorrect guesses. This number is then passed to a hang method which determines which body parts of the hangman to add.
def hang(incorrect)
case incorrect
when 0
#hangman = [" ", " ", " "]
break
when 7
#hangman[2][2] = '\\'
when 6
#hangman[2][0] = '/'
when 5
#hangman[2][1] = '*'
when 4
#hangman[1][2] = '\\'
when 3
#hangman[1][0] = '/'
when 2
#hangman[1][1] = '|'
when 1
#hangman[0][1] = 'o'
end
end
If I were writing this in java, and a value of 5 were passed to the above method, it would read the statement until it hit "when 5" or in java terms "case 5:". It would notice that there is not a break in the statement and will move down the list executing the code in "case 4:" and repeating until a break is found. If 0 were passed however it would execute the code, see the break, and would not execute and other statements.
I am wondering if Ruby is capable of using case statements the way java does in the way that they fall through to the next statement. For my particular problem I am aware that I can use a 0.upto(incorrect) loop and run the cases that way, but I would like to know the similarities and differences in the case statement used in ruby as opposed to the switch-case used in java
No, Ruby's case statement does not fall through like Java. Only one section is actually run (or the else). You can, however, list multiple values in a single match, e.g. like this site shows.
print "Enter your grade: "
grade = gets.chomp
case grade
when "A", "B"
puts 'You pretty smart!'
when "C", "D"
puts 'You pretty dumb!!'
else
puts "You can't even use a computer!"
end
It's functionally equivalent to a giant if-else. Code Academy's page on it recommends using commas to offer multiple options. But you can still won't be able to execute more than one branch of logic.
It does not fall through.
Ruby just doesn't have the same behavior as Java for this type of statement.
If you want to simulate the fall through behavior, you can do something like this:
def hang(incorrect)
#hangman = [" ", " ", " "]
#hangman[2][2] = '\\' if incorrect > 6
#hangman[2][0] = '/' if incorrect > 5
#hangman[2][1] = '*' if incorrect > 4
#hangman[1][2] = '\\' if incorrect > 3
#hangman[1][0] = '/' if incorrect > 2
#hangman[1][1] = '|' if incorrect > 1
#hangman[0][1] = 'o' if incorrect > 0
#hangman
end

How to write a Ruby switch statement (case...when) with regex and backreferences?

I know that I can write a Ruby case statement to check a match against a regular expressions.
However, I'd like to use the match data in my return statement. Something like this semi-pseudocode:
foo = "10/10/2011"
case foo
when /^([0-9][0-9])/
print "the month is #{match[1]}"
else
print "something else"
end
How can I achieve that?
Thanks!
Just a note: I understand that I wouldn't ever use a switch statement for a simple case as above, but that is only one example. In reality, what I am trying to achieve is the matching of many potential regular expressions for a date that can be written in various ways, and then parsing it with Ruby's Date class accordingly.
The references to the latest regex matching groups are always stored in pseudo variables $1 to $9:
case foo
when /^([0-9][0-9])/
print "the month is #{$1}"
else
print "something else"
end
You can also use the $LAST_MATCH_INFO pseudo variable to get at the whole MatchData object. This can be useful when using named captures:
case foo
when /^(?<number>[0-9][0-9])/
print "the month is #{$LAST_MATCH_INFO['number']}"
else
print "something else"
end
Here's an alternative approach that gets you the same result but doesn't use a switch. If you put your regular expressions in an array, you could do something like this:
res = [ /pat1/, /pat2/, ... ]
m = nil
res.find { |re| m = foo.match(re) }
# Do what you will with `m` now.
Declaring m outside the block allows it to still be available after find is done with the block and find will stop as soon as the block returns a true value so you get the same shortcutting behavior that a switch gives you. This gives you the full MatchData if you need it (perhaps you want to use named capture groups in your regexes) and nicely separates your regexes from your search logic (which may or may not yield clearer code), you could even load your regexes from a config file or choose which set of them you wanted at run time.

Checking if a string has balanced parentheses

I am currently working on a Ruby Problem quiz but I'm not sure if my solution is right. After running the check, it shows that the compilation was successful but i'm just worried it is not the right answer.
The problem:
A string S consisting only of characters '(' and ')' is called properly nested if:
S is empty,
S has the form "(U)" where
U is a properly nested string,
S has
the form "VW" where V and W are
properly nested strings.
For example, "(()(())())" is properly nested and "())" isn't.
Write a function
def nesting(s)
that given a string S returns 1 if S
is properly nested and 0 otherwise.
Assume that the length of S does not
exceed 1,000,000. Assume that S
consists only of characters '(' and
')'.
For example, given S = "(()(())())"
the function should return 1 and given
S = "())" the function should return
0, as explained above.
Solution:
def nesting ( s )
# write your code here
if s == '(()(())())' && s.length <= 1000000
return 1
elsif s == ' ' && s.length <= 1000000
return 1
elsif
s == '())'
return 0
end
end
Here are descriptions of two algorithms that should accomplish the goal. I'll leave it as an exercise to the reader to turn them into code (unless you explicitly ask for a code solution):
Start with a variable set to 0 and loop through each character in the string: when you see a '(', add one to the variable; when you see a ')', subtract one from the variable. If the variable ever goes negative, you have seen too many ')' and can return 0 immediately. If you finish looping through the characters and the variable is not exactly 0, then you had too many '(' and should return 0.
Remove every occurrence of '()' in the string (replace with ''). Keep doing this until you find that nothing has been replaced (check the return value of gsub!). If the string is empty, the parentheses were matched. If the string is not empty, it was mismatched.
You're not supposed to just enumerate the given examples. You're supposed to solve the problem generally. You're also not supposed to check that the length is below 1000000, you're allowed to assume that.
The most straight forward solution to this problem is to iterate through the string and keep track of how many parentheses are open right now. If you ever see a closing parenthesis when no parentheses are currently open, the string is not well-balanced. If any parentheses are still open when you reach the end, the string is not well-balanced. Otherwise it is.
Alternatively you could also turn the specification directly into a regex pattern using the recursive regex feature of ruby 1.9 if you were so inclined.
My algorithm would use stacks for this purpose. Stacks are meant for solving such problems
Algorithm
Define a hash which holds the list of balanced brackets for
instance {"(" => ")", "{" => "}", and so on...}
Declare a stack (in our case, array) i.e. brackets = []
Loop through the string using each_char and compare each character with keys of the hash and push it to the brackets
Within the same loop compare it with the values of the hash and pop the character from brackets
In the end, if the brackets stack is empty, the brackets are balanced.
def brackets_balanced?(string)
return false if string.length < 2
brackets_hash = {"(" => ")", "{" => "}", "[" => "]"}
brackets = []
string.each_char do |x|
brackets.push(x) if brackets_hash.keys.include?(x)
brackets.pop if brackets_hash.values.include?(x)
end
return brackets.empty?
end
You can solve this problem theoretically. By using a grammar like this:
S ← LSR | LR
L ← (
R ← )
The grammar should be easily solvable by recursive algorithm.
That would be the most elegant solution. Otherwise as already mentioned here count the open parentheses.
Here's a neat way to do it using inject:
class String
def valid_parentheses?
valid = true
self.gsub(/[^\(\)]/, '').split('').inject(0) do |counter, parenthesis|
counter += (parenthesis == '(' ? 1 : -1)
valid = false if counter < 0
counter
end.zero? && valid
end
end
> "(a+b)".valid_parentheses? # => true
> "(a+b)(".valid_parentheses? # => false
> "(a+b))".valid_parentheses? # => false
> "(a+b))(".valid_parentheses? # => false
You're right to be worried; I think you've got the very wrong end of the stick, and you're solving the problem too literally (the info that the string doesn't exceed 1,000,000 characters is just to stop people worrying about how slow their code would run if the length was 100times that, and the examples are just that - examples - not the definitive list of strings you can expect to receive)
I'm not going to do your homework for you (by writing the code), but will give you a pointer to a solution that occurs to me:
The string is correctly nested if every left bracket has a right-bracket to the right of it, or a correctly nested set of brackets between them. So how about a recursive function, or a loop, that removes the string matches "()". When you run out of matches, what are you left with? Nothing? That was a properly nested string then. Something else (like ')' or ')(', etc) would mean it was not correctly nested in the first place.
Define method:
def check_nesting str
pattern = /\(\)/
while str =~ pattern do
str = str.gsub pattern, ''
end
str.length == 0
end
And test it:
>ruby nest.rb (()(())())
true
>ruby nest.rb (()
false
>ruby nest.rb ((((()))))
true
>ruby nest.rb (()
false
>ruby nest.rb (()(((())))())
true
>ruby nest.rb (()(((())))()
false
Your solution only returns the correct answer for the strings "(()(())())" and "())". You surely need a solution that works for any string!
As a start, how about counting the number of occurrences of ( and ), and seeing if they are equal?

Ruby: String Comparison Issues

I'm currently learning Ruby, and am enjoying most everything except a small string comparason issue.
answer = gets()
if (answer == "M")
print("Please enter how many numbers you'd like to multiply: ")
elsif (answer. == "A")
print("Please enter how many numbers you'd like to sum: ")
else
print("Invalid answer.")
print("\n")
return 0
end
What I'm doing is I'm using gets() to test whether the user wants to multiply their input or add it (I've tested both functions; they work), which I later get with some more input functions and float translations (which also work).
What happens is that I enter A and I get "Invalid answer."The same happens with M.
What is happening here? (I've also used .eql? (sp), that returns bubcus as well)
gets returns the entire string entered, including the newline, so when they type "M" and press enter the string you get back is "M\n". To get rid of the trailing newline, use String#chomp, i.e replace your first line with answer = gets.chomp.
The issue is that Ruby is including the carriage return in the value.
Change your first line to:
answer = gets().strip
And your script will run as expected.
Also, you should use puts instead of two print statements as puts auto adds the newline character.
your answer is getting returned with a carriage return appended. So input "A" is never equal to "A", but "A(return)"
You can see this if you change your reject line to print("Invalid answer.[#{answer}]"). You could also change your comparison to if (answer.chomp == ..)
I've never used gets put I think if you hit enter your variable answer will probably contain the '\n' try calling .chomp to remove it.
Add a newline when you check your answer...
answer == "M\n"
answer == "A\n"
Or chomp your string first: answer = gets.chomp

Resources