Ruby unless vs if logic - ruby

Can someone please explain this behavior? Why does nil return true when result = true if i but returns false when result = false unless i
unless case screenshot
def my_all?(pattern = nil)
result = true
my_each do |i|
case pattern
when nil
p result, i
result = false unless i
when Regexp
result = false unless i.to_s.match(pattern)
when Class
result = false unless i.is_a?(pattern)
when String, Numeric
result = false unless i == pattern
end
result = yield(i) if block_given? && pattern.nil?
break if !result
end
result
end
if case screenshot
def my_all?(pattern = nil)
result = false
my_each do |i|
case pattern
when nil
p result, i
result = true if i
when Regexp
result = true if i.to_s.match(pattern)
when Class
result = true if i.is_a?(pattern)
when String, Numeric
result = true if i == pattern
end
result = yield(i) if block_given? && pattern.nil?
break if !result
end
result
end

In your second example, once result is set to true, nothing ever sets it to false again. So if the first value yielded from my_each is truthy, then the my_all? method will return true.
This second example seems like more like an implementation of any?, rather than all?. Except it is actually only checking the first element. If the first i is falsey, then the loop will be broken and it will return false. If the first i is truthy, then it will be set to true and nothing will set it back to false, and the method will return `true.
See these two examples, where the only difference is the values yielded by my_each:
Returns true (first value is truthy)
Returns false (first value is falsey)

Related

Hardcoding Ruby Enumerable#reduce - I have two methods, but only one works. Why?

I'm a novice, and as an exercise, I have to hardcode a method that takes an array as an argument, and if ALL elements in that array are truthy, return true. If not, false.
def reduce_to_all_true(array)
array.each do |index|
if !index
return false
end
return true
end
end
This returns true if ANY element is true...
Meanwhile, the following:
def reduce_to_all_true(array)
array.length.times { |index|
if !array[index]
return false
end }
return true
end
Behaves as expected. What I can't work out, is WHY? In my admittedly limited understanding, they are equivalent solutions. Can someone help me understand this? Thank you!
In the first method the return true is inside the #each loop so it will check only the first element and return either true or false. In the second one it's after the loop, so it will return true only if the loop finishes completely wihtout finding any element that's false.
def reduce_to_all_true(array)
array.each do |index| # each loop starts here
if !index
return false
end
return true # this will return true if the first element of array is true
end # and ends here
end
def reduce_to_all_true(array)
array.length.times { |index| # times loop starts here
if !array[index]
return false
end } #and ends here
return true #this will return true only if the times loop finishes
end

Determinate which method returns true in or operator

I have:
def user_validation
first_user_valid? || second_user_valid?
end
and I don't only want to return true/false but also want to return which method returns the true (maybe both?). I do have:
def user_validation
return true if first_user_valid?
return true if second_user_valid?
end
so far. But this does not seem very intuitive to me.
Thanks
You can return an array of responses:
def user_validation
[first_user_valid?, second_user_valid?]
end
This way you can know that the first returned true, and the other false...
# => [true, false]
If i were you, i change the return from boolean to int. Doing that, you can handle which statment returning specifics numbers for that.
Why not call the method itself separately for the different users?
def user_validation(user)
return user_valid?
end
if(user_validation(user_1))
//user_1 is valid
end
if(user_validation(user_2))
//user_2 is valid
end
Just out of curiosity:
result = %w|first_user_valid second_user_valid|.inject(nil) |memo, m|
(memo ||= []) << m.tr('_', ' ') if public_send("#{m}?")
memo
end
if result # at least one is valid
puts result.join ', '
else # none is valid
puts 'None is valid :('
end
Result here might be either nil (falsey), or the string like:
"first user valid, second user valid"
def user_validation
valid = ((which = :first) && first_user_valid?) ||
((which = :second) && second_user_valid?)
which = :neither unless valid
[valid, which]
end
To illustrate:
def first_user_valid?; true; end
def second_user_valid?; true; end
user_validation #=> [true, :first]
def first_user_valid?; false; end
user_validation #=> [true, :second]
def second_user_valid?; false; end
user_validation #=> [false, :neither]
In general, when using ||, you don't want to evaluate the second expression if the first evaluates true, as in some cases that may raise an exception (e.g. division by zero), have undesirable side effects (e.g., deleting a needed file) or initiate a lengthy calculation.

Boolean behaving strange, logic issue

I'm having an issue with boolean expected behavior. I can make the desired result but I'm not sure why the strange behavior occurs. This produces a wrong result:
def palindrome?(string)
rev = string.reverse
if rev == string
true
else
false
end
end
palindrome?("abc") == false # => true
palindrome?("abcba") == true # => true
palindrome?("z") == true # => true
while this produces the correct result:
def palindrome?(string)
rev = string.reverse
if rev == string
true
end
end
palindrome?("abc") == false # => false
palindrome?("abcba") == true # => true
palindrome?("z") == true # => true
The following might be similar:
def nearby_az(string)
counter = 0
string = string.split("")
if string.count == 1
false
elsif (string.index("z") - string.index("a")) <= 3
true
else
false
end
end
nearby_az("a") == false # => true
nearby_az("z") == false # => true
Because Ruby method will return the result of executing the last expression. For this if statement:
if rev == string
true
end
it will return nil if rev != string.
Actually, your first function is producing the correct result. The problem is the second formula. It returns nothing if the string is not a palindrome; it only returns true if the string is a palindrome. Therefore,
palindrome?("abc") == false
for the second equation returns false because palindrome?("abc") returns nothing because "abc" is not a palindrome, and so it is not equal to false.
The second implementation of palindrome? will return nil if it is not a palindrome. Thus nil == false # => false. In Ruby, all functions return something although it may be nil.

Ruby - return false unless a value is true in which case return the value

If a = false and b = 2 is there a concise way to accomplish this? Using just return a unless b returns 'nil' instead of '2'.
I have
def checkit
return a unless b
b
end
Will this statement call b twice?
A real life case for this is:
def current_user
#current_user ||= authenticate_user
end
def authenticate_user
head :unauthorized unless authenticate_from_cookie
end
def authenticate_from_cookie
.
if user && secure_compare(user.cookie, cookie)
return user
else
return nil
end
end
Try this:
( b == true ) ? a : false
where a is a value you need to return
I do not know why you have false stored in the variable a, so I omitted that. As I understand, you want to pass a value to the method checkit, which should return the value if its boolean value is true (which means everything except values nil and false), and otherwise return the value. In that case, just use this:
def checkit(value)
value || false
end
checkit(1) # => 1
checkit(false) # => false
checkit('value') # => "value"
checkit(nil) # => false

Use case for `&&=`

I have seen and used by myself lots of ||= in Ruby code, but I have almost never seen or used &&= in practical application. Is there a use case for &&=?
Not to be glib, but the obvious use case is any time you would say x && foo and desire the result stored back into x. Here's one:
list = [[:foo,1],[:bar,2]]
result = list.find{ |e| e.first == term }
result &&= result.last # nil or the value part of the found tuple
any sort of iteration where you want to ensure that the evaluation of a boolean condition on all elements returns true for all the elements.
e.g.
result = true
array.each do |elem|
# ...
result &&= condition(elem) # boolean condition based on element value
end
# result is true only if all elements return true for the given condition
Validation of the document such as,
a = {'a' => ['string',123]}
where the element in a['a'] should be a String. To validate them, I think you can use,
def validate(doc, type)
valid = true
doc.each{|x|
valid &&= x.is_a? type
}
valid
end
1.9.3p392 :010 > validate(a['a'],String) => false

Resources