How to use a regex without raising a RuboCop warning - ruby

This is a regex pattern:
(#location =~ /\A#[a-zA-Z0-9]*\Z/) == 0
RuboCop suggests to use .zero? instead of == 0. But when the regex does not match, it will return nil. Then nil.zero? will throw an "undefined method .zero? for nil" error. Any better way to do regex in ruby?

Not every tip from rubocop is a good tip.
In Ruby 2.4 :
#location.match? /\A#[a-zA-Z0-9]*\Z/
By the way, do you want /\Z/ (a line ending at the end of the string) or /\z/ (end of the string)?

Assuming you run ruby 2.3.0+:
(#location =~ /\A#[a-zA-Z0-9]*\Z/)&.zero?
Also as per your specific case, you seem to want to check that you have an exact match. Hence you don't need to check that the starting position is exactly 0 at all:
do_something if #location =~ /\A#[a-zA-Z0-9]*\Z/

You are trying to solve a problem that does not exist. Because of anchor \A there are exactly two possible returns: 0 and nil. That said:
!(#location =~ /\A#[a-zA-Z0-9]*\Z/).nil?
or even
!!(#location =~ /\A#[a-zA-Z0-9]*\Z/)
or even better:
#location[/\A#[a-zA-Z0-9]*\Z/]

This is a known false positive that happens because #=~ does not adhere to the principle of duck typing, i.e. it has incompatible return value signatures.
There are some good answers already regarding how you can rewrite your code, and this is really what RuboCop is all about, but sometimes rewriting will result in code that is worse. For those cases, the generic way of marking false positives is to use a disable:
(#location =~ /\A#[a-zA-Z0-9]*\Z/) == 0 # rubocop:disable Style/NumericPredicate

I'd propose the following solution:
/\A#[a-zA-Z0-9]*\Z/.match?(#location)
This will safeguard the case when #location is nil and will make rubocop happy.

Related

Rubocop, safe navigation, and negation

I've got constructs like the following that Rubocop complains about that I'm trying to appease
unless foo && !foo.empty? ...
(item exists and is not empty)
and
bar && !bar.positive?
(item exists and is not positive)
In both cases, Rubocop throws a Style/SafeNavigation and says I should use &. instead. However, there does not seem to be a way to write it.
In both cases part of the problem is that there is no concise way of expressing the opposite function - there is no "not empty" for strings, and no "negative or zero" for numbers. Writing bar&.negative? returns the opposite result for zero, for example.
In the other case, writing unless !foo&.empty? has Rubocop complain about unless+a negation, but again there's no way to rewrite it as an if foo&. with any operation that exists.
(btw this is straight Ruby, no Rails, so I don't have blank? and present?)
This:
next unless foo && !foo.empty?
Could be replaced with:
next if foo.nil? || foo.empty?
And similarly, this:
next unless bar && !bar.positive?
Could be replaced with:
next if bar.nil? || bar.positive?
The real code smell here, in my opinion, was the next unless ... not. The double negative indicates that there's probably a cleaner way to write it.
This is an oversight in RuboCop, because the suggested correction can not be guaranteed to have the same semantics. It will be fixed in the upcoming 0.50.1 patch, and the cop will ignore cases with negation.
In the meanwhile, if you're dealing with conditions where your variable could be nil, one option is to use the fact that nil responds to the coercion methods. Example, assuming foo is either an array or nil:
# With nil check
unless foo && !foo.empty?
# With array coercion
if foo.to_a.empty?

What's the purpose of using the suffix "if" statement in Ruby?

I know Ruby supports a suffix if like:
number = -42 if opposite
but what's the purpose of this? Why would it be used in place of the prefix if statement?
The suffix-style if and unless can also be good for "guard clauses", in the form of:
return if ...
return unless ...
Here's an example:
# suffix-style
def save
return false if invalid?
# go for it
true
end
Versus:
# indented style
def save
if valid?
# go for it
true
else
false
end
end
In the second example, the entire implementation of the method has to be shifted over by one indent due to the valid? check, and we need an extra else clause. With the suffix style, the invalid? check is considered an edge case that we handle and then bail out, and the rest of the method doesn't need an indent or an else clause.
This is sometimes called a "guard clause" and is recommended by the Ruby Style Guide.
It can make the code easier to read in some cases. I find this to be true especially in the case of unless, where you have some action you usually want to perform:
number = -42 unless some_unusual_circumstance_holds
Once you have it for unless, for symmetry it makes sense to support it for if as well.
number = -42 if opposite
is the same as
if opposite
number = -42
end
Some people prefer the one-liner for readability reasons. Imagine a line like:
process_payment if order_fulfilled?
Doesn't that read nice?
Postfix style does not have the else section. It is useful when you only want to do something with one of the two cases divided by the condition and don't want to mess with the other case.
It's the same as prefix but shorter. The only reason is to save vertical space in the text editor.

better way to do assignment and check result

I have to use String.scan function, which returns empty array if there is no match.
I wanted to assign a variable with the scan function and check it there is a match, but unfortunately I cannot do that because it won't return nil or false on no match.
I wanted to do this (1 line):
if ip = str.scan(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)
...
#use ip
end
but because it won't return nil on no match I must do:
ip_match = str.scan(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)
unless ip_match.empty?
#use ip
end
Is there some more elegant way to write this - to be able to do assignment and empty check at the same time or some other way to beautify the code?
Thanks
Since scan returns an array, and even if you are sure there would be only one result, you could do this.
str.scan(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/).each do |ip|
#use ip
end
There's a difference between elegant and cryptic or "concise".
In Perl you'll often see people write something equivalent to:
if (!(ip = str.scan(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)).empty?)
It's a bit more concise, terse, tight, whatever you want to call it. It also leads to maintenance issues because of the = (equate) vs. what should normally be an equality test. If the code is passed to someone who doesn't understand the logic, they might mistakenly "correct" that, and then break the code.
In Ruby it's idiomatic to not use equate in a conditional test, because of the maintenance issue, and instead use the assignment followed by a test. It's clearer code.
Personally, I prefer to not use unless in that sort of situation. It's an ongoing discussion whether unless helps generate more understandable code; I prefer if (!ip_match.empty?) because it reads more like we'd normally talk -- I seldom start a statement with unless in conversation. Your mileage might vary.
I would preferably do something like this using String helper match
ip_validator = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
# match return nil if no match
if str.match ip_validator
# blah blah blah.....
end
help me keep code dry and clean.
May be this is not the most elegant , looking for others if any :)
Your ip_validator regex seems to be week check this out Rails 3: Validate IP String

Why Ruby 1.9 allows overriding ! != !~?

There were two good reasons why Ruby 1.8 didn't support certain kinds of overloading like ||/or, &&/and, !/not, ?::
Short circuit semantics cannot be implemented with methods in Ruby without very extensive changes to the language.
Ruby is hard coded to treat only nil and false as false in boolean contexts.
The first reason doesn't apply to !/not but second still does. It's not like you can introduce your own kinds of boolean-like objects using just ! while &&/|| are still hard-coded. For other uses there's already complementarity operator ~ with &/|.
I can imagine there's a lot of code expecting !obj to be synonymous with obj ? false : true, and !!obj with obj ? true : false - I'm not even sure how is code supposed to deal with objects that evaluate to true in boolean context, but ! to something non-false.
It doesn't look like Ruby plans to introduce support for other false values. Nothing in Ruby stdlib seems to override ! so I haven't found any examples.
Does it have some really good use I'm missing?
Self-replying. I found one somewhat reasonable use so far. I can hack this to work in 1.9.2 in just a few lines:
describe "Mathematics" do
it "2 + 2 != 5" do
(2+2).should != 5
end
end
Before 1.9.2 Ruby this translates to:
describe "Mathematics" do
it "2 + 2 != 5" do
((2+2).should == 5) ? false : true
end
end
But as return value gets thrown away we have no ways of distinguishing == 5 from != 5 short of asking Ruby for block's parse tree. PositiveOperatorMatcher#==(5) would just raise ExpectationNotMetError exception and that would be it. It seems should !~ /pattern/, should !be_something etc. can also be made to work.
This is some improvement over (2+2).should_not == 5, but not really a big one. And there's no way to hack it further to get things like (2+2).should be_even or be_odd.
Of course the right thing to do here would be asking Ruby for parse tree and macro-expanding that. Or using debug hooks in Ruby interpreter. Are there use cases better than this one?
By the way, it wouldn't be enough to allow overrides for ! while translating !=/!~ the old way. For !((2+2).should == 5) to work #== cannot raise an exception before ! gets called. But if #== fails and ! doesn't get run execution will simply continue. We will be able to report assertion as failed after block exits, but at cost of executing test after the first failure. (unless we turn on ruby debug hooks just after failed assertion to see if the very next method call is !self, or something like that)

Is assignment in a conditional clause good ruby style?

In order to write more concisely, rather than do this:
test_value = method_call_that_might_return_nil()
if test_value
do_something_with test_value
end
I've been assigning in the conditional:
if test_value = method_call_that_might_return_nil()
do_something_with test_value
end
Is this bad style? The still-more-concise syntax:
do_something_with test_value if test_value = method_call_that_might_return_nil()
is not allowed, as discussed in another SO question, and will remain that way in 1.9, according to Matz (http://redmine.ruby-lang.org/issues/show/1141).
Given the possible confusion of assignment and comparison, does this make it too hard to read the code?
It is GOOD style to use assignments in conditionals. If you do so, wrap the condition in parentheses.
# bad (+ a warning)
if v = array.grep(/foo/)
do_something(v)
# some code
end
# good (MRI would still complain, but RuboCop won't)
if (v = array.grep(/foo/))
do_something(v)
# some code
end
# good
v = array.grep(/foo/)
if v
do_something(v)
# some code
end
See the community style guide for more information
One somewhat widespread idiom is to use and, which would look something like this:
tmp = method_call_that_might_return_nil and do_something_with tmp
Another possibility would be to call #nil? explicitly, that way the intent becomes a little bit clearer; in particular it is really obvious that you actually meant to assign instead of compare:
unless (tmp = method_call_that_might_return_nil).nil?
do_something_with tmp
end
Concise code is not necessarily better code. Concision is useful when it improves the communication of intended code behavior from author to future maintainers. I think enough of us come from backgrounds in which we've had accidental assignments in if blocks (when we meant to have an equality comparison) that we prefer styles in which it's absolutely clear that assignment is meant, rather than comparison. The .nil? idiom already mentioned has that property, and I'd consider it cleaner than having the bare assignment inside the if condition. Really, though, I don't see the harm in having the extra line of code for the assignment.
The functional-programming way to do this is to use andand. It's a readable way of chaining method calls so that a nil in the middle stops the chain. So your example would be something like:
method_call_that_might_return_nil.andand.tap {|obj| do_something_with obj}
## or, in the common case: ##
method_call_that_might_return_nil.andand.do_something
Yeah, I would say it's bad style due to the possible confusion between assignment and comparison. It's only one more line to assign and then test, and it avoids having someone in the future think that was a bug and patch it to use == instead.
C programmers do this a lot. I don't see a problem with it in Ruby either so long as it's clear what's happening.
I think it's fine. Aversion to assignment in a condition comes from knowing that a missed key stroke when typing == turns a comparison into an unintended assignment. A stylistic prohibition on using assignment in a condition makes such accidents stand out like to the eye (and sometimes to the language, as in C, where many compilers can be made to emit a warning if they encounter an assignment in a condition). On the other hand, tests also make such accidents stand out. If your code is well covered by tests, you can consider discarding such prohibitions.
Due to the warning, performing the assignment in the if clause has a quite pungent smell. If you do have an else case to handle then the case ... in ... pattern matching can offer something:
case method_call_that_might_return_nil
in nil
# handle nil case
in test_value # pattern match to a new variable
# handle non-nil case with return value of method assigned to test_value
end
Or...
case method_call_that_might_return_nil
in test_value if test_value # pattern match to a new variable if not nil
# handle non-nil case with return value of method assigned to test_value
else
# handle nil case
end

Resources