Using code block in ruby's if statement - ruby

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

Related

Else block in Ruby

I just started learning ruby, but there's something I noticed.
In JavaScript the else block isn't really needed. So you can do something like
if (condition){
// do something
return
}
//do something else
return
instead of
if (condition){
// do something
return
} else {
//do something else
return
}
is this possible in Ruby ?
Yes, it is possible to use if without else in Ruby.
Here are some examples
class Demo
def example1
if condition
do_something
end
continue
end
def example2
do_something if condition # as modifier
continue
end
def example3
do_something unless condition # syntactic sugar for if !(condition)
continue
end
end
For a full tutorial please have a look here.
Please keep in mind, that example1 is (sometimes) concidered a bad coding style by the Ruby Style Guide.

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

How to convert this if condition to unless?

if array.present?
puts "hello"
end
There is no else part to this.
How to write the above if condition using unless.
I'm asking this question because of this lint error:
Use a guard clause instead of wrapping the code inside a conditional expression
Regarding your comment:
I'm asking this question because of this lint error
Use a guard clause instead of wrapping the code inside a conditional expression
This means that instead of:
def foo(array)
if array.present?
puts "hello"
end
end
You are supposed to use:
def foo(array)
return unless array.present?
puts "hello"
end
See https://github.com/bbatsov/ruby-style-guide#no-nested-conditionals
If this is a Rails question (is it?), you can also use blank?:
def foo(array)
return if array.blank?
puts "hello"
end
There's no reason to.
Remember: unless is the inverse of if (or !if if you rather), and is only intended to make your code easier to read.
Using unless with your expression would be incredibly awkward, because you're now moving the actual body of work to an else statement...
unless array.present?
return
else
puts "hello"
end
...which doesn't make your code any easier to read if you had stuck with a negated if:
if !array.present?
return
else
puts "hello"
end
Don't use unless here. You lose readability in exchange for virtually nothing.
One-liner:
puts "hello" unless !array.present?
However, I would recommend:
puts "hello" if array.present?
unless array.present?
return
else
puts "hello"
end
OP requested one-liner modification:
Pseudocode:
something unless condition
Therefore:
puts "hello" unless !array.present?

Ruby equivalent for Python's for / else

I've always been searching for something like Python's while / else struct in Ruby to improve my code.
That means that the loop is executed and if the condition in the loop hasn't been true any time, then it returns the value in the else statement.
In ruby, I can do like this :
if #items.empty?
"Empty"
else
#items.each do |item|
item
end
end
So is there a way to improve this ?
Thank you in advance.
Remember that the iterator block returns what you put into it, which can be tested for further use.
if arr.each do |item|
item.some_action(some_arg)
end.empty?
else_condition_here
end
Hm, you could write it as a ternary:
#items.empty? ? 'Empty' : #items.each { |item| item }
You may want to do something more useful in your block though, since each is executed for its side effects and returns the original receiver.
Update as per your comment: I guess the closest you could get is something like
unless #items.empty?
#items.each { |item| p item }
else
'Empty'
end
Since we are in Ruby, let's have fun. Ruby has powerful case construct, which could be used such as this:
case items
when -:empty? then "Empty"
else items.each { |member|
# do something with each collection member
}
end
But to make the above code work, we have to modify the native class Symbol first. Modification of native classes is Ruby specialty. This needs to be done only once, typically in a library (gem), and it helps you ever after. In this case, the modification will be:
class Symbol
def -#
Object.new
.define_singleton_method :=== do |o| o.send self end
end
end
This code overloads the unary minus (-) operator of Symbol class in such way, that saying -:sym returns a new empty object monkey patched with :=== method, that is used behind the scenes by the case statement.
A more or less functional way:
empty_action = { true => proc{ "Empty"},
false => proc{ |arr| arr.each { |item| item }} }
empty_action[#items.empty?][#items]

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