Match multiple conditions for a long method call without repeating it - ruby

I'm wondering if there is a better way to handle multiple matches on longer method calls than repeating the long call in a piped statement. Example:
if value == ''
return nil
elsif class.method[:key].select(id: id).first.nil? || class.method[:key].select(id: id).first == 1
return nil
end
Ideally I'd like to one line this since it returns the same result, so the if/elsif is useless, but I'm not sure if I can match .nil? and == 1 on the same thing without repeating it or setting it as a variable beforehand.

Assuming your code otherwise works as posted, you can do what you want by storing the result of the chained method in a variable before performing your comparisons. For example:
return nil if value.empty?
result = class.method[:key].select(id: id).first
return nil if result.nil? || result.eql?(1)
The semantics here will do what you expect without having to repeat the method chain. There are certainly other ways to express the idea, such as a case statement, but this should do what you expect in a very compact way.

Related

Returning a value of ruby is strange

could anyone tell me the return value of this function give the parameter listed blew:
def sequence(*enumerables)
enumerables.each do |enumerable|
print "#{enumerable},"
end
end
a,b,c = [1,2,3],4..6,'a'..'e'
value = sequence(a,b,c)
print value
why the value is evaluated to be:
[[1,2,3],4..6,"a".."e"]
Remember that the last thing left on the stack is the return value of your method. This is always the case. If the return value is important, you must pay close attention to how you exit from your method.
The each method returns what it has been iterating over. Since the each is the last statement in your method, stack-wise, that value gets returned.
You can fix this by returning nothing:
def sequence(*enumerables)
enumerables.each do |enumerable|
print "#{enumerable},"
end
return
end
This approach is generally frowned on as the return method seems out of place. If the caller of this method is not expecting any particular return value, then it's not necessary.
The alternative is to return something useful:
def sequence(*enumerables)
enumerables.join(",")
end
puts sequence(a,b,c)
It's often the case that methods which do not set an expectation for a particular return value may return an arbitrary one.
enumerables is an array. The splat (*) operator causes this.
The return value of sequence is the return value of enumerables.each which is enumerables
A simple example:
def foo(*args)
args
end
foo(1,2,3,4) == [1,2,3,4] # true
You're returning enumerables, which is an array containing all the arguments to the method.
What did you expect value to contain? You haven't made any explicit attempt to return anything, so whatever value the last statement in the method resolves to "falls off" the method to become its return value.

Best way to prevent returning last evaluated expression

Suppose I want to write a method in ruby whose last line is a method call but I do not want to return its return value. Is there a more elegant way to accomplish this other than adding a nil after the call?
def f(param)
# some extra logic with param
g(param) # I don't want to return the return of g
end
If you want to make it "poke you in the eye" explicit, just say "this method doesn't return anything":
def f(param)
# some extra logic with param
g(param) # I don't want to return the return of g
return
end
f(x) will still evaluate to nil but a bare return is an unambiguous way to say "this method doesn't return anything of interest", a trailing nil means that "this method explicitly returns nil" and that's not quite the same as not returning anything of use.
No, but if it is important that f indeed returns nil, and not whatever g(param) returns, then nothing is more elegant than spelling that out with a nil on the last line. Why would you want to obfuscate this away? Most of the time, elegance is in the explicit and the obvious.
A few tenants from The Zen of Python come to mind:
Explicit is better than implicit.
Simple is better than complex.
Readability counts.
No. If you want to return nil, the last expression has to evaluate to nil. You can do this with a terminating nil line or by surrounding the method body in nil.tap {} or however else you like, but it's pretty straightforward — the last expression evaluated gets returned.
As the others have said, no. However, if you want to avoid adding another line, you have a couple of options:
g(param); nil
g(param) && nil
The first will always cause f to return nil; the second will return false (if g returns false) or nil (if g returns a truthy value).
No, there is no other way than to either explicitly return nil or evaluate some other expression which implicitly evaluates to nil (e.g. ()).
If you want to add some kind of semantic marker that shows that you explicitly want to ignore the return value, you could invent some convention for that, e.g.:
def f(param)
# some extra logic with param
g(param) # I don't want to return the return of g
()
end
or
def f(param)
# some extra logic with param
g(param) # I don't want to return the return of g
_=_
end
which will make those cases easily grepable but probably won't aid much in understanding.
This is a design choice of Ruby which it shares with many other expression-based languages: the value of a block/subroutine/procedure/function/method is the value of the last expression evaluated inside the block. That's how it works in Lisp, for example.
Note that there are other choices as well. E.g. in Smalltalk, the return value of a method must be explicitly returned using the ↑ operator, otherwise the return value is nil. In E, which is heavily focused on security, this is even a conscious design choice: automatically returning the value of the last expression is considered a potential information leak.

Using ! on a method in Ruby

I am currently using capitalize!:
user_input.capitalize!
But, if the input is capitalized, it returns a nil.
I know I can use the method without !, but it will make a copy of the object and pass that instead of changing the object.
user_input.capitalize
How can I use !, but have it work for all cases?
I tried to downcase everything, then capitalize but the same problem exists in some cases.
What is the best way to capitalize all entries?
This is the context:
The user inputs "works", "Works", "WORKS", or "WoRkS"
case 1) user_input = "works"
case 2) user_input = "Works"
case 3) user_input = "WORKS"
case 4) user_input = "WoRkS"
user_input.capitalize! (case 1,3,4 = "Works"; case 2 = nil)
! methods, by convention, modify the receiver and return nil if they make no changes. The safest way to do it is to use two lines:
user_name.capitalize!
user_name
or #tap:
user_name.tap do |s|
s.capitalize!
end
Although, #tap is overkill here.
If all you care about is that the input gets capitalized, use capitalize! and don't worry about the nil.
If you can't have a nil at a certain point in your code (for some reason), don't use capitalize!. Instead do this:
user_input = user_input.capitalize
At the end of the day, either way is fine, idiomatic and will get the input into the state you want it. In and of itself, a nil return value isn't a bad thing - although you may not always want it as a final return value.

what does nil mean/represent here?

Following are the simple statements in the irb shell. What does nilin the output mean ? Why does it accompany the print statement in the if block ?
irb(main):062:0> if(x==20 && y==30)
irb(main):063:1> print("if statement working !")
irb(main):064:1> else
irb(main):065:1* print("else statement working !!")
irb(main):066:1> end
if statement working !=> nil # what does nil represent here ?
In Ruby, all expressions return values, even if it's nil. Blocks and methods simply return the value of the last expression evaluated. There are many ways to use this effectively. For example, this is the reason explicit returns are often not used. Also, you can do this:
print if x == 20 && y == 30
'if statement working!'
else
'else statement working!'
end
Regarding your example: in addition to printing the string as you instructed, irb will display the value it received from the if-else blocks. Since print always returns nil, both branches will return the same value.
It means that your if-block does not return a value (which it can, actually). For instance, the following is perfectly legal and viable:
foo = if bar > 10
42
else
0
end
# now, foo is either 42 or 0

Returning the value of a block over an Enumeration when not nil

I have a bit of an odd use-case for a Ruby Enumerable, it seems. I am attempting to do something like the following:
result = my_strategies.some_method do |strategy|
strategy.get_result
end
The method some_method is just a placeholder, but is the basis behind the rest of this question.
The enumerable my_strategies contains an ordered list of strategies for retrieving a value from a remote service; a more preferable strategy is run before a less preferable strategy,
Sometimes the more preferable strategy will fail, in a way that retries alone won't correct. In that case, the strategy will return nil.
I can see a way of doing this by relying on an each block, thusly:
result = nil
my_strategies.each do |strategy|
result = strategy.get_result
if not r.nil?
break
end
end
This seems unnecessarily noisy. I'm wondering if there is a method I can substitute some_method for in my first example; something similar to .any?, but returning the value that caused the block to be true, instead of just returning true.
Alternate approaches to what I am trying to do are also welcome.
EDIT: I originally asked this question because I had tried this block of code:
result = my_strategies.find do |strategy|
strategy.get_result
end
Except that this returned me the strategy that succeeded, instead of the value it returned when it did. I don't care about which strategy got me the value, I just want to know what the value is.
Your need is very common but unfortunately there is no such abstraction in the core. However, Facets guys identified this gap a long time ago and implemented Enumerable#find_yield (a.k.a Enumerable#map_detect):
result = my_strategies.map_detect { |strategy| strategy.get_result }
Or simply: result = my_strategies.map_detect(&:get_result). Ruby 2.0 implements lazy enumerables (for early versions use enumerable-lazy) so now we can write:
result = my_strategies.lazy.map(&:get_result).reject(&:nil?).first
You can use Enumerable#find to iterate through the array until you get your result:
result = nil
my_strategies.find do |strategy|
result = strategy.get_result
end
An alternate approach to doing this (without using a block):
result = nil
num = 0
while result.nil?
result = my_strategies[num].get_result
num += 1
end

Resources