andand chain not working properly - ruby

im trying to refactor this code of mine:
test_cases.select{ |x| x.script && x.script.versions && !x.script.versions.empty? }
and use the andand gem. Basic usage just tells us that we substitute andand to the &&(thus the name) so i tried this:
test_cases.select{ |x| !x.andand.script.andand.script_versions.andand.empty? }
but it seems it is NOT-ing the whole statement(i just realized this now while writing the question)
Does this mean I have to separate the empty? clause? Is there an andand function that checks for not(but only the last one?)

You could always do
test_cases.select{ |x| x.andand.script.andand.script_version } unless x.empty?
On the topic of andand: while we use it in our project and I generally quite like it, I found that spurious use of andand can hide problems that should be properly addressed. Like many good tools it has to be used with caution.

I actually used this clause and it works:
test_cases.map{ |x| x.script.andand.versions && !x.script.versions.empty? }.none?
only one andand call and used map instead of select

When x is not nil it works well, I guess. The problem is when x is nil because ...empty? returns also nil, and !nil -> true. Then this x is wrongly selected. I'd propose an explicit check of the boolean value:
test_cases.select { |x| x.andand.script.andand.versions.andand.empty? == false }
Or probably better use blank/present without a last andand:
test_cases.select { |x| x.andand.script.andand.versions.present? }
test_cases.reject { |x| x.andand.script.andand.versions.blank? }
Note: it's not related with the problem here, but I prefer Ick's maybe over andand, as only nil is treated as "void" (false is a legitimate value which I think should not be proxied).

Related

Does 'any?' break from the loop when a match is found? [duplicate]

This question already has answers here:
Do all? and any? guarantee short-circuit evaluation?
(3 answers)
Closed 4 years ago.
Does any? break from the loop when a match is found?
The following is the any? source code, but I don't understand it.
static VALUE
enum_any(VALUE obj)
{
VALUE result = Qfalse;
rb_block_call(obj, id_each, 0, 0, ENUMFUNC(any), (VALUE)&result);
return result;
}
Yes, it does break the loop. One does not need to dig into c code to check that:
[1,2,3].any? { |e| puts "Checking #{e}"; e == 2 }
# Checking 1
# Checking 2
#⇒ true
The term is "short-circuiting" and yes, any? does that. After it finds a match, it doesn't look any further.
Does any? break from the loop when a match is found?
The documentation is unclear about that:
The method returns true if the block ever returns a value other than false or nil.
Note: it does not say "when the block ever returns a value other than false or nil" or "as soon as the block ever returns a value other than false or nil".
This can be interpreted either way, or it can be interpreted as making no guarantees at all. If you go by this documentation, then you can neither guarantee that it will short-ciruit, nor can you guarantee that it won't short-circuit.
Generally speaking, this is typical for API specifications: make the minimum amount of guarantees, giving the API implementor maximum freedom in how to implement the API.
There is somewhere else we can look: the ISO Ruby Programming Language Specification (bold emphasis mine):
15.3.2.2.2 Enumerable#any?
any?(&block)
Visibility: public
Behavior:
a) Invoke the method each on the receiver
b) For each element X which each yields
If block is given, call block with X as the argument.
If this call results in a trueish object, return true
As you can see, again it only says "if", but not "when" or "as soon as". This sentence can be interpreted in two ways: "Return true as the result of the method" (no indication of how often the block gets called, only that the method will return true at the end) or "return true when you encounter an invocation of the block that evaluates to a trueish value".
Try #3: The Ruby Spec:
it "stops iterating once tähe return value is determined" do
So, yes, we can indeed rely on the fact that the block is only evaluated until the first truthy value is encountered.
The following is the any? source code, but I don't understand it.
Note: by looking at the source code, you can not determine how something behaves in Ruby. You can only determine how something behaves in that specific version of that specific implementation of Ruby. Different implementations may behave differently (for example, in YARV, Ruby threads cannot run at the same time, in JRuby, they can). Even different versions of the same implementation can behave differently.
It is usually not a good idea to make assumptions about the behavior of a programming language by just looking at a single version of a single implementation.
However, if you really want to look at some implementation, and are fully aware about the limitations of this approach, then I would suggest to look at Rubinius, Topaz, Opal, IronRuby, or JRuby. They are (in my opinion) better organized and easier to read than YARV.
For example, this is the code for Enumerable#any? in Rubinius:
def any?
if block_given?
each { |*element| return true if yield(*element) }
else
each { return true if Rubinius.single_block_arg }
end
false
end
This looks rather clear and readable, doesn't it?
This is the definition in Topaz:
def any?(&block)
if block
self.each { |*e| return true if yield(*e) }
else
self.each_entry { |e| return true if e }
end
false
end
This also looks fairly readable.
The soure in Opal is a little bit more complex, but only marginally so:
def any?(pattern = undefined, &block)
if `pattern !== undefined`
each do |*value|
comparable = `comparableForPattern(value)`
return true if pattern.public_send(:===, *comparable)
end
elsif block_given?
each do |*value|
if yield(*value)
return true
end
end
else
each do |*value|
if Opal.destructure(value)
return true
end
end
end
false
end
[Note the interesting use of overriding the ` method for injecting literal ECMAScript into the compiled code.]
Most of the added complexity compared to the Rubinius and Topaz versions stems from the fact that Opal already supports the third overload of any? taking a pattern which was introduced in Ruby 2.5, whereas Rubinius and Topaz only support the two overloads with a block and without any arguments at all.
IronRuby's implementation implements the short-circuiting like this:
if (predicate.Yield(item, out blockResult)) {
result = blockResult;
return selfBlock.PropagateFlow(predicate, blockResult);
}
JRuby's implementation is a little bit more involved still, but you can see that as soon as it encounters a truthy block value, it breaks out of the loop by throwing a SPECIAL_JUMP exception and catching it to return true.
Yes and it's easy to prove:
irb(main):009:0> %w{ant bear cat}.any? {|word| puts "hello"; word.length >= 4}
hello
hello
=> true
It has printed only twice. If it did not break it would print 3 times.

Is it possible for an undeclared enumerable object to be able to call itself within a block?

I recently asked a question today (Equality test on three or more objects) where I was trying to determine an elegant way to run an equality test on a set of 3 or more objects. One of the solutions turned out to be something like this:
array = [1,1,1,1]
array.all? {|x| x == array.first }
I'm wondering if it would be possible to reduce this to just one line, so that I could do something that would be interpreted like this:
[1,1,1,1].all? {|x| x == [1,1,1,1].first }
#=> true
where somehow I'm able to reference the initial object being called on by the block without first having to declare that object in a previous line. In pseudo-code what I'm trying to do is something like this:
[1,1,1,1].all? {|x| x == object_being_called_on_by_block.first }
#=> true
I've also tried this, but did not work:
[1,1,1,1].all? { |x| x == self.first }
This has been frequently asked on SO, and is frequently requested as a feature on Ruby core. So far, a Ruby core developer recommends this:
[1,1,1,1].tap{|a| break a.all?{|x| x == a.first}}
If you don't mind about performance, you can do:
[1,1,1,1].instance_eval{all?{|x| x == first}}

Is there a { |x| x } shorthand in ruby?

I often use .group_by{ |x| x } and .find{ |x| x }
The latter is to find the first item in an array which is true.
Currently I'm just using .compact.first but I feel like there must be an elegant way to use find here, like find(&:to_bool) or .find(true) that I'm missing.
Using .find(&:nil?) works but is the opposite of what I want, and I couldn't find a method that was the opposite of #find or #detect, or a method like #true?
So is there a more elegant way to write .find{ |x| x }? If not, I'll stick with .compact.first
(I know compact won't remove false but that's not a problem for me, also please avoid rails methods for this)
Edit: For my exact case it is used on arrays of only strings and nils e.g.
[nil, "x", nil, nil, nil, nil, "y", nil, nil, nil, nil] => "x"
If you do not care about what is returned you can sometimes use the hash method.
Thw feature you are asking for is not available in Ruby yet, however. it is present in the Ruby road-map:
https://bugs.ruby-lang.org/issues/6373
Expected to be implemented before 2035-12-25, can you wait?
That being said, how much typing is group_by{|x|x} ?
Edit:
As Stefan pointed out, my answer is now longer valid for Ruby 2.2 and above since the introduction of Object#itself.
There’s not.
If tap worked without a block you could do:
array.detect(&:tap)
But it doesn’t. Either way, I think what you have is extremely concise, idiomatic, and happens to be the same number of characters as the non-working above alternative, and thus you should stick with that:
array.compact.first
You could monkey-patch your way to getting a shorter version, but then it becomes unclear to anyone otherwise familiar with Ruby, which probably isn’t worth the minor “savings”.
As a curiosity, if you happened to want array.detect { |x| !x } (the opposite) you could do:
array.detect(&:!)
This works because !x is actually shorthand for x.!. Of course this would only ever give you nil or false, which is probably not very useful.
No, there is not. I personally have a utility library I include in all my projects which has something like
IDENTITIY = -> x { x }
Then you would have
.group_by(&IDENTITY)
There is also Object#itself that simply returns self:
.group_by(&:itself)
Although the tag is for ruby - with Rails (more specifically ActiveSupport) you are given a method presence which will work for anything that responds positively to present? (that would exclude blank strings, arrays, hashes, etc):
array.find(&:presence)
It's not quite equivalent to the preferred result, but it will work for most cases I've come across.
I frequently use group_by, map, select, sort_by, and other various hash methods. I discovered this useful little extension yesterday by fiddling around with another answer on a similar question:
class Hash
def method_missing(n)
if has_key? n
self[n]
else
raise NoMethodError
end
end
end
For any hash created by ruby, or any data that has been jsonified by as_json, this addition allows me to write code which is a little shorter. Example:
# make yellow cells
yellow = red = false
tube_steps_status.group_by(&:step_ordinal).each do |type|
group = type.last.select(&:completed).sort_by(&:completed)
red = true if group.last.step_status == 'red' if group.any?
yellow = true if group.map(&:step_status).include?('red')
end
tube_summary_status = 'yellow' if yellow unless red

Converting an empty string into nil in Ruby

I have a string called word and a function called infinitive such that
word.infinitive would return another string on some occasions and an empty string otherwise
I am trying to find an elegant ruby one line expression for the code-snippet below
if word.infinitive == ""
return word
else return word.infinitive
Had infinitive returned nil instead of "", I could have done something like
(word.infinitive or word)
But since it does not, I can't take advantage of the short-circuit OR
Ideally I would want
1) a single expression that I could easily embed in other code
2) the function infinitive being called only once
3) to not add any custom gems or plugins into my code
The ActiveSupport presence method converts an empty (or blank?) string to nil. It's designed for your exact use case:
word.infinitive.presence || word
Note that you can easily use ActiveSupport outside of rails:
require 'active_support/core_ext/object/blank'
You can use a regex like this article suggests
(word.infinitive[/.+/m] or word) #Fancy way to convert "" to nil
If you're not ashamed of monkeypatching and abusing syntax, this would work:
class String
def | x
if empty? then x else self end
end
end
Then you can say word.infinitive | word, which actually scans fairly naturally, if you ask me.
However, I think a better idea would be to modify the infinitive method, or add a version of it that returns the word unchanged.
Edit: Here's a possibly more elegant solution:
[word.infinitive, word].find {|x| not x.empty?}
Do the right thing - fix infinitive so that it returns nils instead of blank strings, or wrap it with your own interface if you really can't touch it.
Or you can monkeypatch a new function to String without having to abuse syntax.
class String
def squash
self.empty? ? nil : self
end
end
Now you can do
puts var.squash or "default text"
I'm not a native english speaker so I don't know if squash is the best word. Is there a word that would better convey the idea of "turn into nil only if empty"?
You could use the ternary operator (boolean ? true-val : false-val) with String#empty?
return word.infinitive.empty? ? word : word.infinitive
if you only want to call infinitive once:
return (inf = word.infinitive).empty? ? word : inf
You may also want to consider adding some memoization to your code.

Best ruby idiom for "nil or zero"

I am looking for a concise way to check a value to see if it is nil or zero. Currently I am doing something like:
if (!val || val == 0)
# Is nil or zero
end
But this seems very clumsy.
Objects have a nil? method.
if val.nil? || val == 0
[do something]
end
Or, for just one instruction:
[do something] if val.nil? || val == 0
From Ruby 2.3.0 onward, you can combine the safe navigation operator (&.) with Numeric#nonzero?. &. returns nil if the instance was nil and nonzero? - if the number was 0:
unless val&.nonzero?
# Is nil or zero
end
Or postfix:
do_something unless val&.nonzero?
If you really like method names with question marks at the end:
if val.nil? || val.zero?
# do stuff
end
Your solution is fine, as are a few of the other solutions.
Ruby can make you search for a pretty way to do everything, if you're not careful.
First off I think that's about the most concise way you can check for that particular condition.
Second, to me this is a code smell that indicates a potential flaw in your design. Generally nil and zero shouldn't mean the same thing. If possible you should try to eliminate the possibility of val being nil before you hit this code, either by checking that at the beginning of the method or some other mechanism.
You might have a perfectly legitimate reason to do this in which case I think your code is good, but I'd at least consider trying to get rid of the nil check if possible.
You can use the Object.nil? to test for nil specifically (and not get caught up between false and nil). You can monkey-patch a method into Object as well.
class Object
def nil_or_zero?
return (self.nil? or self == 0)
end
end
my_object = MyClass.new
my_object.nil_or_zero?
==> false
This is not recommended as changes to Object are difficult for coworkers to trace, and may make your code unpredictable to others.
nil.to_i returns zero, so I often do this:
val.to_i.zero?
However, you will get an exception if val is ever an object that does not respond_to #to_i.
I believe your code is incorrect; it will in fact test for three values: nil, false, and zero. This is because the !val expression is true for all values that are false, which in Ruby is nil and false.
The best I can come up with right now is
if val == nil || val == 0
# do stuff
end
Which of course is not very clever, but (very) clear.
My solution also use Refinements, minus the conditionals.
module Nothingness
refine Numeric do
alias_method :nothing?, :zero?
end
refine NilClass do
alias_method :nothing?, :nil?
end
end
using Nothingness
if val.nothing?
# Do something
end
Short and clear
[0, nil].include?(val)
Shortest and best way should be
if val&.>(0)
# do something
end
For val&.>(0)
it returns nil when val is nil since > basically is also a method, nil equal to false in ruby. It return false when val == 0.
Rails does this via attribute query methods, where in addition to false and nil, 0 and "" also evaluate to false.
if (model.attribute?) # => false if attribute is 0 and model is an ActiveRecord::Base derivation
However it has its share of detractors. http://www.joegrossberg.com/archives/002995.html
To be as idiomatic as possible, I'd suggest this.
if val.nil? or val == 0
# Do something
end
Because:
It uses the nil? method.
It uses the "or" operator, which is preferable to ||.
It doesn't use parentheses, which are not necessary in this case. Parentheses should only be used when they serve some purpose, such as overriding the precedence of certain operators.
I deal with this by defining an "is?" method, which I can then implement differently on various classes. So for Array, "is?" means "size>0"; for Fixnum it means "self != 0"; for String it means "self != ''". NilClass, of course, defines "is?" as just returning nil.
You can use case if you like:
case val with nil, 0
# do stuff
end
Then you can use anything that works with ===, which is nice sometimes. Or do something like this:
not_valid = nil, 0
case val1 with *not_valid
# do stuff
end
#do other stuff
case val2 with *not_valid, false #Test for values that is nil, 0 or false
# do other other stuff
end
It's not exactly good OOP, but it's very flexible and it works. My ifs usually end up as cases anyway.
Of course Enum.any?/Enum.include? kind of works too ... if you like to get really cryptic:
if [0, nil].include? val
#do stuff
end
The right thing to do is of course to define a method or function. Or, if you have to do the same thing with many values, use a combination of those nice iterators.
I really like Rails blank? method for that kind of things, but it won't return true for 0. So you can add your method:
def nil_zero?
if respond_to?(:zero?)
zero?
else
!self
end
end
And it will check if some value is nil or 0:
nil.nil_zero?
=> true
0.nil_zero?
=> true
10.nil_zero?
=> false
if val.nil_zero?
#...
end
Instead of monkey patching a class, you could use refinements starting in Ruby 2.1. Refinements are similar to monkey patching; in that, they allow you to modify the class, but the modification is limited to the scope you wish to use it in.
This is overkill if you want to do this check once, but if you are repeating yourself it's a great alternative to monkey patching.
module NilOrZero
refine Object do
def nil_or_zero?
nil? or zero?
end
end
end
using NilOrZero
class Car
def initialize(speed: 100)
puts speed.nil_or_zero?
end
end
car = Car.new # false
car = Car.new(speed: nil) # true
car = Car.new(speed: 0) # true
Refinements were changed in the last minute to be scoped to the file. So earlier examples may have shown this, which will not work.
class Car
using NilOrZero
end
This is very concise:
if (val || 0) == 0
# Is nil, false, or zero.
end
It works as long as you don't mind treating false the same as nil. In the projects I've worked on, that distinction only matters once in a while. The rest of the time I personally prefer to skip .nil? and have slightly shorter code.
[Update: I don't write this sort of thing any more. It works but is too cryptic. I have tried to set right my misdeeds by changing the few places where I did it.]
By the way, I didn't use .zero? since this raises an exception if val is, say, a string. But .zero? would be fine if you know that's not the case.
This evaluates to true for nil and zero: nil.to_s.to_d == 0
unless (val || 0).zero?
# do stufff
end
In a single stretch you can do this:
[do_something] if val.to_i == 0
nil.to_i will return 0
Another solution:
if val.to_i == 0
# do stuff
end
val ||= 0
if val == 0
# do something here
end

Resources