Until loop keeps runing even when the phrase is true? - ruby

I have the following code:
until (#world.exists? decision || decision == '')
UiHandler.print_error(UiHandler::NO_TILE)
UiHandler.print_turn_message
decision = gets.chomp
end
which should allow the player to skip a turn by entering an empty line. But for some reason the until loop keeps running even when the condition is true
i.e. passing in '1 1' does work and stop the loop, since it exists in world, but passing nothing doesn't, even though puts (#world.exists? decision || decision == '') gives 'true'
What would cause an until loop not to stop even when the condition is met?

Fix is
(#world.exists?(decision) || decision == '')
Otherwise - #world.exists? decision || decision == '' is being treated as #world.exists?(decision || decision == ''), which is not correct expression, you intended to write.
As decision is a string object, which in Ruby is considered as truth value, decision || decision == '' (in the code written by you) will be evaluated as true too. This decision will be passed as a method argument to the method #world.exists? always.

Related

How do the "if and (ne)" operators work in helm?

I'm working with a chart that has the following structure at the beginning but I'm having a hard time understanding when does this evaluate to true.
{{- if and .Values.vpceIngress.enabled .Values.http.paths (ne .Values.vpceIngress.class "traefik2") }}
I believe that both enabled and paths must be true, but the ne throws me off after that.
and and ne are functions in go templates.
and
Returns the boolean AND of its arguments by returning the
first empty argument or the last argument, that is,
"and x y" behaves as "if x then y else x". All the
arguments are evaluated.
ne
Returns the boolean truth of arg1 != arg2
So the template line equates to a more psuedo codish
if (
.Values.vpceIngress.enabled
&& .Values.http.paths
&& .Values.vpceIngress.class != "traefik2"
)
The truthiness of the plain .Value.key is basically a "is this field/key not the zero value for the data type. This also works for maps as 'is this field/key defined' due to a map without that path equating to nil or non value (Note that this only works when the parent map is actually defined! Otherwise the template errors)

Will `&&` always run before `if` on the same line in Ruby

Will every && run before if on the same line in Ruby?
For example:
#building.approved = params[:approved] if xyz && abc && mno...
Can an unlimited number of && be used on the right side of an if without using parentheses?
I'm inclined to use parentheses but I'd like to understand the default behaviour.
Everything after the if must be part of the condition by virtue of the syntax. The only way to get around this is to be really specific:
(#building.approved = params[:approved] if xyz) && abc && ...
Which is obviously not what you're intending here.
Operator binding strength isn't an issue here since if is a syntax element not an operator, so it has the absolute lowest priority.
The only conditions that will be evaluated are the ones that produce a logically false value, or come after one that was logically true as the first one to return logically false will halt the chain.
That is:
if a && b && c
Will stop at a if that is a logically-false value. b and c will not be evaluated. There's no intrinsic limit on chaining though.

Stuck on Learnstreet Ruby lesson 7.9 Introducing || Operator

Attempting to learn Ruby as my first programming language. I was understanding everything fine to this point, but I am drawing a blank at this exercise and not sure where to even get started with this and could use some help.
9: Introducing || operator
Similar to the logical and operator &&, we have a logical or operator ||. The character | is located right above your enter key on the keyboard and is called a pipe. Similar to double ampersand, this one is also commonly referred to as double pipe. The || operator is used if any of the conditions can be true. For example - if number == 1 || number == 3 returns true if number is either 1 or 3. Simple right? Implement a method dinner_choice as per the instructions in the code editor.
This function should return:
"steak" if celebrity is "brad pitt" or "angelina jolie"
"italian" if celebrity is "ashton kutcher" or "demi moore"
"french" if celebrity is none of the above
This is my attempt.
def dinner_choice(celebrity)
return "steak" if celebrity == "brad pitt" || celebrity == "angelina jolie"
return "italian" if celebrity == "ashton kutcher" || celebrity == "demi moore"
else return "french"
end
end
You were close, this is what you want
def dinner_choice(celebrity)
return "steak" if celebrity == "brad pitt" || celebrity == "angelina jolie"
return "italian" if celebrity == "ashton kutcher" || celebrity == "demi moore"
return "french"
end
You don't want the last else at the end. You can simply use return "french" because if any of the statements above it match, it won't get to that line.
The general form you're looking for is to write statements like this:
def dinner_choice celebrity
return "steak" if celebrity == "Brad Pitt"
return "foo" if # add programming here
end
You'll check the celebrity variable to see if it's something your method knows how to handle, and give the result that goes with the input.
The explicit return tells the Ruby interpreter to stop evaluating the rest of the code in the method and give the result specified.
You could also experiment with case statements, but IMO they're ugly and hard to maintain in most situations.

Refactoring conditional variable assignment

I'm working on a project. Currently I have a fairly large conditional statement, that assigns a value to a variable based on some input parameters. So, I have something like this.
if some condition
x = some value
elsif another condition
x = a different value
...
What's the best way to refactor this? I'm hoping that I might end up with something like
x = some value if some condition || another value if another condition
Is there a pattern for this sort of thing?
Just put the assignment outside the if.
x = if some condition
some value
elsif another condition
a different value
Or you could use a Hash.
x = dict[some condition]
It's not a pattern, but an operator. The one you're referring to is the ternary operator:
If Condition is true ? Then value X : Otherwise value Y
Here is an example:
speed = 90
speed > 55 ? puts("I can't drive 55!") : puts("I'm a careful driver")
Using the ternary statement is short, sweet, and does the job.
x = some condition ? some value :
another condition ? a different value : ...
A conditional statement is also an expression, so one of the first things you can do, if the variable is the same in each condition, is:
x = if cond1
expr1
elsif cond2
expr2
....
end
If the conditions are all states of a single expression, you can make this even neater, using a case statement.
However, the next most obvious re-factoring exercise is to get the big conditional isolated into a method, which should be fed the bare minimum data required to evaluate all the conditions and expressions.
E.g.
# Where conditional is currently, and x assigned, assuming the conditionals
# need a couple of variables . . .
x = foo param1, param2
# Elsewhere
private
def foo p1, p2
if cond1
expr1
elsif cond2
expr2
....
end
end
If you want to refactor for code clarity and flexibility, consider the replacing conditional with polymorphism refactor.
There's not enough detail in your question to go much further with recommendations, but this refactor will make your code base much more resistant to change. If you receive a new requirement, it's bad form to break open the conditional and modify it (more prone to introducing bugs, more difficult to do); it's preferable to create a new object that you can plug into the existing codebase. This flexibility what the Open/Closed Principle (the "O" in the SOLID acronym) describes.

Does the || operator evaluate the second argument even if the first argument is true?

I'm trying to evaluate the expression (a=10) || (rr=20) while the rr variable is not defined
so typing rr in the ruby console before evaluating the previous expression returns
rr
NameError: undefined local variable or method `rr' for main:Object
from (irb):1
from :0
When I write the expression (a=10) || (rr=20) it returns 10, and when I write rr afterwards it says nil
(a=10) || (rr=20)
rr # => nil
so, why is this happening? Shouldn't rr be defined only if the second argument of the || operator is evaluated, which should be never based on the documentation?
This happens because the ruby interpreter defines a variable when it sees an assignment to it (but before it executes the actual line of code). You can read more about it in this answer.
Boolean OR (||) expression will evaluate to the value of left hand expression if it is not nil and not false, else || will evaluate to the value of right hand expression.
In your example the ruby interpreter sees an assignment to a and rr (but it doesn't execute this line yet), and initializes (defines, creates) a and rr with nil. Then it executes the || expression. In this || expression, a is assigned to 10 and 10 is returned. r=20 is not evaluated, and rr is not changed (it is still nil). This is why in the next line rr is nil.
As #DOC said, && and || are known as short circuited conditional operators.
In case of ||, if the left part of || expression returns true, the right part won't be executed. That means the right part will be executed only if the left part of || expression returns false.
In case of &&, right part of the&&expression will be executed only if left part of && returns true.
In the given scenario (a=10) || (rr=20), rr=20 won't be executed since the ruby expression a=10 returns true. Note that in ruby assignment expression returns true except nil and false.
I think variable definement happens at the parsing stage, not the execution moment. So when it evaluates the line, it parses the whole thing and the variable is defined, but unassigned.
When the parser discovers a variable it is automatically valid within the context it's defined in. Evaluating rr on its own is not valid. Evaluating rr=20 is sufficient to cause a definition even if the value assignment never occurs.
This is a quirk of how Ruby tries to discern between variables and method calls. It's imperfect but usually works out for the best.

Resources