Using ! on a method in Ruby - 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.

Related

Match multiple conditions for a long method call without repeating it

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.

Ruby proper if structure

I'm working on a web scraper. There are few variants of a page, and the program should work a little bit differently on each. I need to alternate the way it processes pages depending on what are on the page. I can do nested ifs:
if str=data.css('div#imgTag').to_s
str.delete('#')
#do something
elsif str=data.css('span#Title').to_s
#do something else
elseif str=data.css('span#block').to_s
#do something
end
return str
but the code above does not always work. I think there is a flaw, and I'm looking for a better way to address it. I'm looking for more elegant, construction.
You can use a case when instead of if, it is more practical when your several ifs are about the same variable : http://www.techotopia.com/index.php/The_Ruby_case_Statement
Otherwise, I don't really know what you can do better. You should add more details about the context of your program and what's not working.
EDIT : #Aetherus is right in the comments, you're comparing using = instead of ==, which assigns a value to your variable instead of testing it, so it is always true.
EDIT AGAIN : #Stefan also have a point. If your data.css() returns nil, to_s will return an empty string which is always true. You can use try(:to_s) to return nil if called on a nil object (http://www.rubydoc.info/docs/rails/Object%3Atry).
Your code becomes :
case str
when data.css('div#imgTag').try(:to_s)
str.delete('#')
#do something
when data.css('span#Title').try(:to_s)
#do something else
when data.css('span#block').try(:to_s)
#do something
end
return str

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.

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.

RegEx in Ruby: Just one match?

I'm trying to figure out how to check if a string matches a regular expression, but I want to know if the entire string matches just once. Here's my code but it seems absurdly long
def single_match(test_me, regex)
ret_val = false
test = regex.match(test_me)
if (test.length==1 && test[0].length == test_me.length)
ret_val = true
end
return ret_val
end
is there an easier way to do this?
P.S. Here's the method I'm really trying to write, since people always seem to ask why I want the gun these days:
def is_int(test_me)
return single_match(test_me, /[0-9]*/)
end
Edit Thanks everybody. Here's where I'm really using it, but this regex stuff is always interesting to go through. Thanks for the great and educational answers.
You don't need to do this, your method can be replaced by using the regular expression of /^[0-9]*$/. The ^ tells it match start of a line and $ tells it match end of the line. So it will match: start of line, 0 to any in range of 0 to 9, and finally end of line.
def is_int(test_me)
test_me =~ /^[0-9]*$/
end
And you don't need the return statements, Ruby implicitly returns the last statement.
Edit:
It probably would be easier and look better to use the to_i instance method of String class.
def is_int(test_me)
test_me.to_i.to_s == test_me
end
Edit: (did some tests)
Comparing the performance between the two methods shows that .to_i.to_s == way is 5% faster. So it is up to personal preference to which ever looks better and if you want to handle leading zeroes.
To do what you really want should be even simpler
def is_int(test_me)
test_me.to_i.to_s == test_me
end
This?
def single_match(str, regex)
str.match(regex).to_s == str
end
To answer your original question, for the sake of people finding this page in a search, "scan" will return an array of matches, so if you want to find out how many times some regexp matches, e.g. how many runs of digits there are, you can do:
mystring.scan(/\d+/).size

Resources