Testing if an object is a string - ruby

I have a function that manipulates a string; however, sometimes my input isn't already a string. For example it could be a path object. I need to convert it to a string because I want to call methods like .gsub.
My question seems a bit simple, but I'm debating on the best approach for converting the object to a string.
I currently have two options:
str = str.to_s unless str.is_a? String
or
str = str.to_s
The second method is much simpler, but the first method actually describes what's going on. I'm wondering which of these two methods is better to use or if there's a better approach I haven't thought of?

I would prefer the second one.
I'd prefer the parameter/variable wasn't named str if it isn't a string.
Naming it str implies string, but then the code looks silly, and is harder to reason about.

I prefer second one. It is shorter, simplier and also describes what you want (any programmer will understand what will heppen). Also there is no notable difference in perfomance.

Go for the second approach without hesitation.
The first one is convoluted and doesn't really add any meaning.

Related

chaining ruby enumerator functions in a clean way

I just finished a course on ruby where the instructor takes a list of movies, groups them, then calls map, sort, and reverse. It works fine, but I don't find the syntax to be very readable and I'm trying to figure out if what I have in mind is valid. I come from a c# background.
#we can reformat our code to make it shorter
#note that a lot of people don't like calling functions on the
#end of function blocks. (I don't like the look, either)
count_by_month = movies.group_by do |movie|
movie.release_date.strftime("%B")
end.map do |month, list|
[month, list.size]
end.sort_by(&:last).reverse
What I am wondering is if I can do something like
#my question: can I do this?
count_by_month = movies.group_by(&:release_date.strftime("%B"))
.map(&:first, &:last.size)
.sort_by(&:last)
.reverse
#based on what I've seen online, I could maybe do something like
count_by_month = movies.groupBy({m -> m.release_date.strftime("%B")})
.map{|month, list| [month, list.size]}
.sort_by(&:last)
.reverse
As a number of people in the comments suggest, this is really a matter of style; that being said, I have to agree with the comments within the code and say that you want to avoid method chaining at the end of a do..end.
If you're going to split methods by line, use a do..end. {} and do...end are synonymous, as you know, but the braces are more often used (in my experience) for single-line pieces of code, and as 'mu is too short' pointed out, if you're set on using them, you may want to look into lambdas. But I'd stick to do..end in this case.
A general style rule I was taught that I follow is to split up chains if what is being worked with changes class in a way that might not be intuitive. ex: fizz = "buzz".split.reverse breaks up a string into an array, but it's clear what the code is doing.
In the example you provided, there's a lot going on that's a bit hard to follow; I like that you wrote out the group_by using hash notation in the last example because it's clear what the group_by is sorting by there and what the output is - I'd put it in a [well named] variable of its own.
grouped_by_month = movies.groupBy({m -> m.release_date.strftime("%B")})
count_by_month = grouped_by_month.map{|month, list| [month, list.size]}.sort_by(&:last).reverse
This splits up the code into one line that sets up the grouping hash and another line that manipulates it.
Again, this is style, so everyone has their own quirks; this is simply how I'd edit this based off a quick glance. You seem to be getting into Ruby quite well overall! Sometimes I just like the look of a chain of methods on one line, even if its against best practices (and I'm doing Project Euler or some other project of my own). I'd suggest looking at large projects on Github (ex: rails) to get a feel for how those far more experienced than myself write clean code. Good luck!

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

what exactly author wants me to understand?

"Inches/yard: #{12*3}"
"#{"Tora! "*3}"
The second example is confusing, unless you remember that everything is an object in
Ruby (yes, even string literals! They are of class String.). Since the string literal
creates a String object, you can act on it just like any other object. In this case,
multiplying a string by 3 simply does what you would think: makes three copies of the
string.
I read the above para in one of the ruby book. The first line says The second example is confusing, unless you remember that everything is an object in Ruby. What is there in the second example that i should remember ,everything is an object in ruby ? Isn't it just a feature that multiplying by 3 will print tora three times ?
I don't exactly understand what does the author want me to understand from the above paragraph
Well, yes you can consider it a feature maybe, but what the author is perhaps trying to explain (although not very clearly at least in this one paragraph), is that what actually is happening is this:
"Tora !" is an object of class String ("everything is an object")
"you can act on it just like any other object", meaning:
"you can call any method on it just like any other object".
In this case you are calling the method * (multiply).
So what ACTUALLY is happening is that the "Tora !" String gets called in a fashion like this:
"Tora ! ".*(3)
=> "Tora ! Tora ! Tora ! "
You see? The operator * is just a method on the String object.
In many simpler languages operators are actually "baked into" the language itself, and do not operate on the targets as method calls.
If you're not used to other languages you might not find it all that remarkable, since in Ruby it's just a normal everyday thing. You just never need to type 1.+(2), Ruby does it for you automatically when you type 1 + 2.
So this is what the author wants you to remember - all operators and operations are just essentially method calls on other objects.
"Tora! a" is an instance of the String class. You can call methods on it. This isn't possible in many languages, e.g. PHP.
('*' is just the method name)
"#{"Tora! "*3}"
"Isn't it just a feature that multiplying by 3 will print tora three times ?".
That is inexact. There is no such thing as a multiplying operator in Ruby. There is a method ".*" (and the parser treats "*" the same way) defined on both String and Numeric objects (but both don't print anything). They do very different things, but the result is what you'd expect.
Well, maybe this was not what the author wanted you to understand, it is important anyway.

Why is "#{String}" a common idiom in Ruby

A Ruby dev I know asked this; my answer is below... Are there other, better reasons?
Why do so many Ruby programmers do
"#{string}"
rather than
string
since the second form is simpler and more efficient?
Is this a common idiom for Ruby developers? I don't see it that much.
Smaller changes when you later need to do more than simply get the value of the string, but also prepend/append to it at the point of use seems to be the best motivation I can find for that idiom.
There is only one case where this is a recommended idiom :
fname = 'john'
lname = 'doe'
name = "#{fname} #{lname}"
The code above is more efficient than :
name = fname + ' ' + lname
or
name = [fname, lname].join(' ')
What's the broader context of some of the usages? The only thing I can come up with beyond what's already been mentioned is as a loose attempt at type safety; that is, you may receive anything as an argument, and this could ensure that whatever you pass in walks like a duck..or, well, a string (though string.to_s would arguably be clearer).
In general though, this is probably a code smell that someone along the way thought was Best Practices.
I use this kind of code, so that I can pass nil as string and it still will work on a string, rather than seeing some exceptions flying:
def short(string = nil)
"#{string}"[0..7]
end
And it's easier/faster to append some debug code, if it's already in quotes.
So in short: It's more convenient.
Interesting answers, everyone. I'm the developer who asked the original question. To give some more context, I see this occasionally at my current job, and also sometimes in sample code on the Rails list, with variables that are known in advance to contain strings. I could sort of understand it as a substitute for to_s, but I don't think that's what's going on here; I think people just forget that you don't need the interpolation syntax if you're just passing a string variable.
If anyone tried to tell me this was a best practice, I'd run away at top speed.
maybe it is easy way to convert any to string? Because it is the same as call to_s method. But it is quite strange way :).
a = [1,2,3]
"#{a}"
#=> "123"
a.to_s
#=> "123"
I could image this being useful in cases where the object being interpolated is not always a String, as the interpolation implicitly calls #to_s:
"#{'bla'}" => "bla"
"#{%r([a-z])}" => "(?-mix:[a-z])"
"#{{:bla => :blub}}" => "blablub"
May make sense when logging something, where you don't care so much about the output format, but never want an error because of a wrong argument type.

Ruby string mutability

This may be a bit of a nooby question, I have been trying to get better at ruby recently, and started reading the fantastic The Ruby Programming Language. Something that was mentioned is that string literals are considered mutable, so in a loop it is better to use a variable then a literal, as a new string will get instantiated at every iteration.
My question is why? At first I thought it was because of interpolation, but symbols are immutable and they support interpolation. Coming from a static background, it doesn't really make much sense to me.
EDIT:
After reading thenduks answer, I think I may have it. AFAIK, languages like Java or C# don't have destructive string methods (they use upcase, but not upcase!). Because of things like upcase! or <<, the literal cannot be immutable.
Not 100% sure on that, the other possibility is that it is a compile-time interning that happens, which is something that just doesn't happen in a scripting language.
Not really sure what exactly your question is, but consider the following code:
10.times { puts "abc".object_id }
This prints out 10 different id's. Why? Just because you know this string wont change doesn't mean Ruby does. If you think that "abc" should only be created once then what happens if you do:
10.times { puts "abc".upcase! }
The upcase! method mutates the string to be upper case, on the next iteration the string created in the first iteration isn't the same anymore.
Perhaps post a code example that is confusing to you?

Resources