Capture true/false result of an operation - ruby

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.

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

Ruby 2.1.3 options hash cannot be assigned with fetch

Please explain to me why this is happening:
def resizeImage(event_file, resize_width, resize_height, options = {})
puts options
aspect_ratio = options.fetch(:maintain_aspect_ratio, true)
puts aspect_ratio
"return value"
end
resizeImage('event_file', 'resize_width', 'resize_height', {maintain_aspect_ratio: false} )
{:maintain_aspect_ratio=>false}
false
=> "return value"
I want to set a variable to = the fetch from the hash to make my code more readable. But for some reason it is nil when I call it. It almost looks like the fetch is asynchronous, but this ain't ajax.
This is a pretty elementary problem I know, but so far as I can tell I am doing things just as they are described in more than one guide to using options in ruby methods.
-- Update --
so now I have it returning something else to try to separate the problem. I see that the puts statement for aspect_ratio doesn't actually return anything at all. What is happening?
-- Update2 --
Okay, I got confused. It is returning false. So there is something else wrong in my real method. Thank you for your time, I will accept the most detailed answer but I appreciate both.
Remove this line from your method:
puts aspect_ratio
Your Ruby method is returning to the value of the final statement, i.e. the value of puts.
When you remove that line, then your method will return aspect_ratio.
You actually have the correct structure down, however the final puts in your method is causing the return value to be nil. Ruby utilizes an implicit return, so unless specified, it will return the last value of a method. remove the puts aspect_ratio from the method, or ensure the last line is aspect_ratio and the method will properly return your value
def resizeImage(event_file, resize_width, resize_height, options = {})
puts options
aspect_ratio = options.fetch(:maintain_aspect_ratio, true)
puts aspect_ratio #remove this line
aspect_ratio
end
this can end up being shortened to
def resizeImage(event_file, resize_width, resize_height, options = {})
options.fetch(:maintain_aspect_ratio, true)
end
#joelparkerhendersons answer is correct
Im going to explain whats happening.
Everything in ruby returns something(apart from a tiny minority). It can be forced by using return but by default the last line of the method is returned.
Your method resizeImage returns what puts returns. puts returns nil
Therefore as #joelparkerhendersons suggested remove the puts

Break out of a conditional Statement

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.

Using code block in ruby's if statement

is there a way to pass a code block as a ruby if condition?
I have a list of regular expressions and I want to check if a message matches any of them and then do something accordingly or else do something different.
Here is an example snippet for how I think it should be written:
msg_values.each do |msg|
if (SKIP_MSG_ARRAY.each { |regular_exp| return true if msg.match(regular_exp)})
# do something
else
# do something else
end
end
is it possible? or else what is the best way of writing something like this?
Use Enumerable#any?. See the reference docs: http://ruby-doc.org/core-2.0/Enumerable.html. This method (as well as Enumerable#all?) will return true or false.
Example:
msg_values.each do |msg|
if (SKIP_MSG_ARRAY.any? { |regular_exp| msg.match(regular_exp)})
# do something
else
# do something else
end
end

Resources