Break out of a conditional Statement - ruby

How can I get out of a conditional Statement? In the example below, is there any way to exit from the if statement and execute the else statement so that I need not write logic1 twice?
Without using any methods?
status_invoked? = true
order_present? = true
if status_invoked?
if order_present?
# compute logic2
else
# compute logic1
end
else
# compute logic1
end
I think in C we have something called setJump() which jumps out of if statement and executes the else statement.

probably an easier way is something like this:
def compute_logic
return unless status_invoked? #you could also throw an error here
return compute(logic2) if order_present?
compute(logic1)
end
def compute(logic)
...
end
and define order_present? and status_invoked? either on initialization or in a private method, depending on your needs and how they are used.

status_invoked? = true
order_present? = true
else_ecex=false
if status_invoked?
# check if order_present?
if order_present?
#compute logic2
#true else part
else_ecex = true
end
end
#check even else is true or false
if(else_ecex == true)
#Your Code
end

Ideally you would instead go with a solution similar to dax. As that solution makes use of good helper methods. allowing you to manipulate those helper methods depending on your needs.
However, a possible solution using your code is to simply not have the elses, and use a return in order_present?.
status_invoked? = true
order_present? = true
if status_invoked?
if order_present?
# return logic2 here.
end
end
# compute logic1
In this particular example, you only want to execute and return logic2 if status_invoked? and order_present? are both true, and you execute logic1 if you never reach the instructions inside of order_present?. However, even in this example, you would ideally create a helper methods, and pass logic1 and logic2 into it.
In my personal opinion, dax's method is the cleaner way to go. It reads clearer, as well as reads as a typical ruby formatting.

Related

Switch Case in Ruby

I am trying to do a case statement. The code looks like this:
def true?(verbosity)
verb = verbosity.to_s
case verb
when verb.match?('yes')
true
when verb.match?('y')
return true
when verb.match('ja')
true
when verb.match?('j')
true
when verb.to_i(10).eql?(1)
true
else
false
end
end
Regardless of what I write in the case statement, even when the debugger says options[:verbosity] is "yes", the case statement instantly jumps to false and leaves the function. I even added explicit casting to it as string.
How do I have to write the statement to get a valid evaluation?
In this form, when you want to evaluate all case conditions separately, you should omit verb in the beginning, like this:
case
when verb.match?('yes')
true
when verb.match?('ja')
true
# ...
that said, don't you think it would be easier to read and nicer if you used regular expression magic to make this whole method much shorter? I'm thinking of something like this:
def true?(verbosity)
verb = verbosity.to_s
verb.match?(/yes|y|ja|j/i) || verb.to_i.eql?(1)
end
Here's a direct fix:
def true?(verbosity)
verb = verbosity.to_s
# If you wish to reference `verb` below in the branches like this,
# then DON'T make it the subject of the `case` statement:
case
when verb.match?('yes')
true
when verb.match?('y')
return true
when verb.match('ja')
true
when verb.match?('j')
true
when verb.to_i(10).eql?(1)
true
else
false
end
end
Or, here's a cleaner use of a case statement (without changing any behaviour above):
def true?(verbosity)
case verbosity.to_s
when /yes/, /y/, /ja/, '1'
true
else
false
end
end
...But this is doesn't quite do what you want, since it will return true for e.g. "yellow", but false for e.g. "TRUE". So, how about:
def true?(verbosity)
case verbosity.to_s
when /\A(yes|y|ja|1)\z/i
true
else
false
end
end
..But at this point, you may be thinking - why bother with a case statement here at all?? The other answer has already shown how you can take this a step further by removing the case statement; or alternatively you could even do this in 1 line and without a regex:
def true?(verbosity)
%w[yes y ja j 1].include?(verbosity.to_s.downcase)
end
Also, I note that there is some ambiguity in your post about whether this parameter is supposed to be called options[:verbose] or options[:verbosity]. It's unclear whether or not this has manifested as a bug in your complete code, but I felt it's worth mentioning.

Is there a way to avoid calling a function multiple times in an 'elsif' branch?

I have a function that returns either nil or a non-nil value, and I use it in the following if-else clause:
if condition_that_doesnt_involve_my_func
# do stuff
elsif my_func(cur_line)
headers_found = my_func(cur_line)
end
I feel the above block is slightly wasteful because it calls the function twice and it could just save the result once and then use it in the following clause if the branch evaluates to non-nil.
Is there a way to rewrite this so that I only invoke the function once?
You can write:
elsif headers_found = my_func(cur_line)
I would not recommend that and Rubocop doesn't like that either.
Try this:
if condition_that_doesnt_involve_my_func
# do stuff
elsif answer = my_func(cur_line)
headers_found = answer
end
Not sure if rubocop will bark at this. I don't use it.
If you are worry about it assign the return value to headers_found. It will ended up being false (headers_found.present? #false) or containing the headers.
if condition_that_doesnt_involve_my_func
# do stuff
else
headers_found = my_func(cur_line)
end

Optimizing basic method memoization with early return

When implementing basic memoization in Ruby, is there a pattern or simple way to return the memoized instance var if the value predicates on a more complex evaluation before hand?
Say the assignment of something requires an intense calculation, is Ruby smart enough to return the instance variable if it's present, or will something always be assigned within the scope of that method before setting #some_value?
def some_value
#some_value if #some_value.present? # possible?
something = something_else.try(:method_name) || another_something.method_name # prevent this from evaluating after execution
#some_value ||= MyClass.new(property: something.property)
end
What would a better memoization pattern be to implement what I have?
Based on how your code is currently written, the "intense calculation" will always occur. Ruby uses implicit return unless you explicitly use the keyword return, so, even if #some_value is present, the code will still execute to the last line.
def some_value
return #some_value if #some_value.present? # possible?
something = something_else.try(:method_name) || another_something.method_name # prevent this from evaluating after execution
#some_value ||= MyClass.new(property: something.property)
end
So, if you want to return #some_value if it is present, and not run any code afterwards, you will want to use explicit return. See above.
Now, Ruby will check if #some_value is present, and if that is true, the value is returned, otherwise, it will continue with the calculation.

return early vs if in ruby code

I see two styles of writing the same thing:
def find_nest(animal)
return unless animal.bird?
GPS.find_nest(animal.do_crazy_stuff)
end
vs
def find_nest(animal)
if animal.bird?
GPS.find_nest(animal.do_crazy_stuff)
end
end
Which one is more correct/preferable/following-best-practises? Or it does not matter?
As per Ruby style guide,
Prefer a guard clause when you can assert invalid data. A guard clause
is a conditional statement at the top of a function that bails out as
soon as it can.
# bad
def compute_thing(thing)
if thing[:foo]
update_with_bar(thing)
if thing[:foo][:bar]
partial_compute(thing)
else
re_compute(thing)
end
end
end
# good
def compute_thing(thing)
return unless thing[:foo]
update_with_bar(thing[:foo])
return re_compute(thing) unless thing[:foo][:bar]
partial_compute(thing)
end
It is obviously a matter of personal preference. But I prefer the early return. Not only does it make code "flatter" and easier to read, it also scales well with the number of checks. For example:
def create_terms_of_service_notification
return if Rails.env.test?
return if current_user.accepted_tos?
# imagine 5 more checks here.
# Now imagine them as a mess of nested ifs.
# create the notification
end
This :}
def find_nest(animal)
GPS.find_nest(animal.do_crazy_stuff) if animal.bird?
end

Capture true/false result of an operation

My code looks like this, and it works:
if Target.find_by_shrunk(params[:shrunk])
#target = Target.find_by_shrunk(params[:shrunk])
else
# do something else
end
Target::find_by_shrunk(params[:shrunk]) gets called twice. In order to avoid this, I want to run Target.find_by_shrunk(params[:shrunk]) once, catch the true/false result, then use that variable in the conditional statement. I tried doing this:
does_it_exist = (this_target = Target.find_by_shrunk(params[:shrunk]))
if does_it_exist
#target = this_target
else
# do something else
end
But unfortunately that doesn't do what I want it to.
How do I simultaneously perform an assignment, and somehow capture the true/false result of performing that assignment, so i don't have to run the same (expensive) piece of code twice in a row?
You could do
unless #target = Target.find_by_shrunk(params[:shrunk])
# do something else
end
unless is the same as if not. An attribution returns the value attributed, and if it's different from nil and false, it evaluates to true.
This should work:
if this_target = Target.find_by_shrunk(params[:shrunk])
#target = this_target
else
#do something else
end
try this
something_else unless #target = Target.find_by_shrunk(params[:shrunk])
or, if you need the positive
do_something if #target = Target.find_by_shrunk(params[:shrunk])
You could initialise #target to nil, so when you come to test it, if it's nil, call find_by_shrunk and assign the result to #target.

Resources