Beginning Ruby Question:
I'm trying to see if a string variable's contents is either "personal" "email" or "password".
I'm trying:
if params[:action] == "password" || "email" || "personal"
foo
else
don't foo
end
But that doesn't work and returns strange results, and using IRB to play around with "or" statements I have no idea why the following happens:
irb(main):040:0> a = "email"
=> "email"
irb(main):041:0> a == "password" || "email"
=> "email"
irb(main):042:0> a == "email" || "password"
=> true
I just want something that if any of the 3 variables are true no matter what order they are in it returns true, if not it returns false. Anyone want to help this n00b out?
This specific problem will have many good solutions, but instead I will concentrate on the boolean logic for educational purpose
You'll want to do this:
(a == "password") || (a == "email) || (a == "password")
Programming languages aren't like English: it has a strict grammatical rule, and instead of saying:
"if x is 3 or 5"
in most programming languages, you have to say:
if x is 3 or x is 5
Similarly, where as it's common in mathematical notation to say:
"if a < b < c"
in most programming languages, you have to say:
if a < b and b < c
Let's see what happens with your experiment:
a == "password" || "email"
Due to what is called "operator precedence", this is parsed as:
(a == "password") || "email"
Now, since a == "email", this essentially evaluates to:
false || "email"
which is why this expression evaluates to "email".
Similarly, with:
a == "email" || "password"
This is essentially
true || "password"
and that's why it evaluates to true.
The case statement is also good for matching this or that or ...
case email
when "password", "email", "whatever"
puts "found a match: #{email}"
else
puts "no match"
end
Sometimes I use this version:
if ["password","email","personal"].include?(params[:action])
foo
else
don't foo
end
Related
I’m trying to create something like an inventory in ruby, so I can compare "params" against every line in that inventory, but I’m new to the language and I don’t know what might be the best way to do it.
Actually my code looks like this:
def parseParams(params)
max_length = "xxxxxxxxxxx".length
min_length = 2 #c1 for example
if (params.length == 0)
puts "[-] No parameters provided"
return false
elsif (params.length > max_length)
puts "[-] The parameters are too long/invalid"
return false
elsif (params.length < min_length)
puts "[-] The parameters are too short/invalid"
return false
else
if (params == "c1" || params == "c2" || params == "c3")
puts "[+] Valid parameters"
return true
end
end
end
What I want to do is simplify the code and just verify whether "params" exists in this inventory, otherwise, return error.
Someone knows how to do it?, thanks in advance.
To summarise the requirements of your question:
If params is equal to any line in inventory.txt then it's valid, otherwise it's invalid
You can do this:
def parseParams(params)
File.read('inventory.txt').split("\n").include?(params)
end
I am writing a quiz program where I need to store boolean statements as strings in an array and output them to the terminal as part of a question. I then want to evaluate the contents of these strings and return the value so that I can test whether I answered the question correctly. Here is what I'm trying to do:
questions = ["!true", "!false", "true || true", "true && false"...]
puts "Answer true or false"
puts questions[0]
answer = gets.chomp
# evaluate value of questions[0] and compare to answer
...
Storing just the statements doesn't work the way I need it to:
questions = [!true, !false, true || true, true && false...]
puts questions[3].to_s
It returns the evaluated statement, ie "false", not "true && false". Any ideas of how to approach this?
You are looking for eval. Here:
a = "true && false"
eval a
# => false
a = "true && true"
eval a
# => true
eval will let you "convert a boolean statement stored in a string into a format that can be evaluated". You will need to change your logic accordingly to use it.
I have made an if... else loop that's logically correct (I think), but still it calls a block of code even if I enter "N," which stands for a no.
Here's my code:
print "\n"
def reversal
puts "Hello! Let's reverse your name! (Avoid capitals!)\n"
name = gets.chomp
puts "YOUR REVERSED NAME IS!!\n"+name.reverse+"\n\n(Press enter to continue)"
input = gets.chomp
print "So, did you like it? Y or N!\n"
feedback = gets.chomp
end
reversal
if feedback = "Y" || feedback = "y" || feedback = "Yes" || feedback = "YES" || feedback = "yes"
puts "Cool! Would you like to try again? Y or N!\n"
nestedfeedback = gets.chomp
if nestedfeedback = "Y" || nestedfeedback = "y" || nestedfeedback = "Yes" || nestedfeedback = "yes" || nestedfeedback = "YES"
reversal
end
else
puts "I'm sorry for that..."
end
And I'm attaching a picture of what happens here (I'm entering N, but the code block/method is called anyway):
feedback=gets.chomp will define a local variable, only visible inside reversal. When you test it outside reversal, it would be nil, since it has not been defined in that context.
Also, if feedback="Y"... will define feedback to be "Y", not test if it is. Since "Y" and all the other varieties are all truthy, the if will always succeed.
Among many things you can do is:
Use the fact that feedback is a return value from reversal, and use this in the main code instead plain reversal:
feedback = reversal
Test your variables with == in the if.
why dont you make feedback
feedback.downcase!
so that you dont have to worry about cases.
I am starting to learn programming and I have chosen to learn Ruby using Codecademy. However, I was trying to consolidate my learning but I just can't get this to work!
print "What is 2 + 2 ="
sum_var = gets.chomp
sum_var.downcase!
if sum_var == "four" || 4
puts "Correct!"
else sum_var != "four" || 4
puts "Wrong! #{sum_var} is not the answer!"
end
It just returns 'Correct!' even if it is wrong.
You need write the code as below :
print "What is 2 + 2 ="
sum_var = gets.chomp
# don't need to apply the bang method like you did - sum_var.downcase!
if sum_var.downcase == "four" || sum_var == '4'
puts "Correct!"
else # else don't need condition checking, so I removed.
puts "Wrong! #{sum_var} is not the answer!"
end
sum_var = gets.chomp gives you a string, no where you are converting it to a number. So, evenif you are passing number from the console it became "4" or "7" etc.
Let me explain you also why always you got "Correct!" as a output
sum_var == "four" || 4 - In this expression, whenever sum_var is not equal to "four", your first expression was evaluated to false, but when control went to test the second expression, it found there 4. You know in Ruby all objects are true, except nil and false. So 4 is considered as true. Thus in your code always if block was getting executed, and you were keep getting as the output "Correct!".
Now in your code, some other mess you did, that I corrected in my above code.
The problem with your code lies in the line
if sum_var == "four" || 4
The == will usually return false, so the second part will be evaluated because the precedence of == is higher than the precedence of ||. Since all objects except false and nil are "truthy" in Ruby the expression will end up being true regardless of the users input. Correction as proposed by #ArupRakshit, just wanted to add some more reason to it.
I just saw this code:
method_name(ARGV.shift || "somefile.txt")
which basically should first evalute ARGV[0] and if it doesn't exist then read from "somefile.txt".
My question was, can the && operator be also used here, and in what situations?
Also, does this concept of "passing this or this argument" to a method in Ruby have a name?
The short answer, logical operators are going to return one of its operands based on if it's truthy or falsey. In practice, nearly everything in Ruby will evaluate to true except false or nil.
Examples:
expr1 || expr2 will return (expr1 if not falsey) or (expr2)
In other words, the first truthy value or the final operand,
expr1 && expr2 will return (expr1 if falsey) or (expr2).
In other words, the first falsey value or the final operand.
As for an actual use case, a similar example would be:
Using the && operator to check for a flag in ARGV then passing the file name.
method_name(ARGV.include?('-w') && "write_file.txt")
It should be noted that this is probably not a widely accepted practice. (see comments)
However, preferring a user supplied value over a default value, by using ||, in this manner would be.
If && is used, then the argument would be nil when there is no ARGV[0] and "somefile.txt" when there is ARGV[0]. Note that elements of ARGV, if any, would be strings, so there is no possibility of ARGV[0] being nil or false when there is an element passed.
Generally, || and && are called "(short circuit) disjunction" and "(short circuit) conjunction", respectively.
A typical use case of || is to provide a default value:
foo = potentially_falesy_value || default
A typical use case of && is to provide a value that depends on the truthness of another value:
foo = hash[:bar] && hash[:bar][:baz]
|| is using for providing default values. || returns first "true" value. "True" value -- value that is interpreted as true boolean value in ruby. So first "true" value in the chain will be as the result of the expression. && returns first "false" value. Complete analogy. But it does not have such graceful application.
Apart from the obvious Boolean operator functionality, && can be used like you could in some languages such as JavaScript:
a = cond1 && cond2 && value # a is now value if cond1 and cond2,
# else nil or false (depends on cond1 and cond2)
It's not very readable (IMHO) when assigning non-Boolean variables, but it works.
first evalute ARGV[0] and if it doesn't exist then read from "somefile.txt". My ques
You are correct. The ARGV.shift || "somefile.txt" expression will evaluate to ARGV.shift if it returns some non-falsy value, and "somefile.txt" otherwise. Some other examples:
puts nil || "foo" # => "foo"
puts "foo" || "bar" # => "foo"
puts "foo" || nil # => "foo"
puts "foo" || raise # => "foo"
# and doesn't blow up, because the 'raise'
# is never evaluated
can the && operator be also used here
Sure, but is arguably of less practical value. It might be clearer to use an if in that case:
puts foo && bar
# is the same as:
if foo
puts bar
end
# or:
puts bar if foo
does this concept of "passing this or this argument to a method in Ruby" has a name?
I'm not sure if it has any 'official' name, but I commonly see this pattern being called 'default value' or 'fallback value'.