Preferred style for displaying multiple lines using `puts` - ruby

I know there are several different ways of being able to combine puts statements into one. But more importantly, I'm trying to determine if there's a generally accepted/preferred style for this (I've only been able to dig up other people's clever ways of doing it, but no real reference on a preferred style).
I've seen things like this:
puts "This", "is", "fairly", "easy" # Each word goes on it's own line
or perhaps:
puts ["This", "seems", "convoluted"].join("\n") # Each word goes on it's own line
or an "ugly" way:
def ugly_puts
puts "Not using quotes
And using no code indentation to preserve output formatting"
end
or simply:
puts "This"
puts "Seems"
puts "Straightforward."
It makes most sense for me to use the last methodology, but I'm just curious if there's a common/preferred way I should go about dealing with multiple line output like this.

If the lines to be printed are short enough to be put together on a single line in the source, then I would go with your first option:
puts "This", "is", "fairly", "easy"
If they are long, then I would use a heredoc:
puts <<_.unindent
This Blah Blah ...
Seems Blah Blah ...
Straightforward. Blah Blah ...
_
where unindent is a method to unindent an indented heredoc along the lines suggested in Ruby indented multiline strings. Notice that in future versions of Ruby, it is likely that there will be a simpler way to unindent a heredoc, so this option will become more useful.
I see no point in using your second or fourth option. The third may be used, but it looks ugly.

TL;DR preference and readability
I've scoured the following ruby style guides:
Ruby Style Guide
bbatsov's Ruby Style Guide
Neither of them mention any specific or preferred method of printing multiple puts statements.
I think it's both situational and preferential. What is more readable in the situation? If you have several long puts statements as simply strings, split them into separate puts statements on several lines.
puts "Something very longgggggggggggg"
puts "Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an..."
puts "unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing..."
If you have for some reason stored your separate statements in variables, just puts them all on a single line: puts this, that, thing.
For storing puts statements in a method, it might be convenient for times you want to print several lines out in the console. For example, when making a program where the user would interact and use with via the terminal, you might want to store certain statements within a method and on users call, print them out (i.e. Printing out instructions, or printing out available commands).

Related

Difference between ways to use gets method

I saw two ways to use gets, a simple form:
print 'Insert your name: '
name = gets()
puts "Your name is #{name}"
and a form that drew my attention:
print 'Insert your name: '
STDOUT.flush
name = gets.chomp
puts "Your name is #{name}"
The second sample looks like perl in using the flush method of the default output stream. Perl makes explicit default output stream manipulating; the method flush is a mystery to me. It can behave different from what I'm inferring, and it uses chomp to remove the new line character.
What happens behind the scenes in the second form? What situation is it useful or necessary to use the second form?
"Flushing" the output ensures that it shows the printed message before it waits for your input; this may be just someone being certain unnecessarily, or it may be that on certain operating systems you need it. Alternatively you can use STDOUT.sync = true to force a flush after every output. (You may wonder, "Why wouldn't I always use this?" Well, if your code is outputting a lot of content, repeatedly flushing it may slow it down.)
chomp removes the newline from the end of the input. If you want the newline (the result of the user pressing "Enter" after typing their name) then don't chomp it.
Looking at some Github code I can see that STDOUT.flush is used mostly for server-side/multi-threaded jobs, and not in everyday use.
Generally speaking, when you want to accept input from the user, you'd want to use gets.chomp. Just remember, no matter what the user enters, Ruby will ALWAYS interprete that as a string.
To convert it to an integer, you need to call to_i, or to_f for a float. You don't need chomp in these cases, since to_i or to_f removes the "\n" automatically. There are a lot of subtle things going on implicitly as you'll see, and figuring them out is simply a matter of practice.
I've rarely seen someone use STDOUT.flush except in mutli-threading. Also it makes things confusing, defeating the whole purpose of writing elegant code.

Ruby regex to remove all consecutive letters from string

Here is the problem (from Codeforces)
Polycarp thinks about the meaning of life very often. He does this constantly, even when typing in the editor. Every time he starts brooding he can no longer fully concentrate and repeatedly presses the keys that need to be pressed only once. For example, instead of the phrase "how are you" he can type "hhoow aaaare yyoouu".
Polycarp decided to automate the process of correcting such errors. He decided to write a plug-in to the text editor that will remove pairs of identical consecutive letters (if there are any in the text). Of course, this is not exactly what Polycarp needs, but he's got to start from something!
Help Polycarp and write the main plug-in module. Your program should remove from a string all pairs of identical letters, which are consecutive. If after the removal there appear new pairs, the program should remove them as well. Technically, its work should be equivalent to the following: while the string contains a pair of consecutive identical letters, the pair should be deleted. Note that deleting of the consecutive identical letters can be done in any order, as any order leads to the same result.
Here is my solution.. For some reason it fails an extremely large test case. Mine seems to get rid of more letters than it is supposed to. Is this regular expression incorrect?
str = gets.chomp
while str =~ /(.)\1/
str.gsub!(/(.)\1+/,'')
end
puts str
EDIT -- This solution doesn't work because it gets rid of all consecutive groups of characters. It should only get rid of duplicates. If I do it this way, which I believe to be correct, it times out on extremely large strings:
str = gets.chomp
while str =~ /(.)\1/
str.gsub!(/(.)\1/,'')
end
puts str
Why does it have to be a regular expression?
'foobar'.squeeze
=> "fobar"
"hhoow aaaare yyoouu".squeeze
=> "how are you"
squeeze is a useful tool for compressing runs of all characters, or specific ones. Here are some examples from the documentation:
"yellow moon".squeeze #=> "yelow mon"
" now is the".squeeze(" ") #=> " now is the"
"putters shoot balls".squeeze("m-z") #=> "puters shot balls"
If "aab" becomes "b", then you're not following the example given in the question, which is "hhoow" turns into "how". By your statement it would be "w", and "yyoouu" would be "". I think you're reading too much into it and not understanding the problem based on their sample input and sample output.
ha, harder than I thought when I first read. What about
s = "hhoow aaaareer yyoouu"
while s.gsub!(/(.)\1+/, '')
end
puts s
which leaves s == 'w' if i understand the problem correctly.

Finding lines in a text file matching a regular expression

Can anyone explain how I could use regular expressions in Ruby to only return the matches of a string.
For example, if the code reads in a .txt file with a series of names in it:
John Smith
James Jones
David Brown
Tom Davidson
etc etc
..and the word to match is typed in as being 'ohn', it would then just return 'John Smith', but none of the other names.
Note: Instead of using File.each_line, use IO.foreach in modern Rubies instead. For instance:
[1] pry(main)> IO.foreach('./.bashrc') do |l|
[1] pry(main)* puts l
[1] pry(main)* end
export PATH=~/bin:$PATH
export EDITOR='vi'
export VISUAL=$EDITOR
Progress happens and things change.
Here are some different ways to get where you're going.
Notice first I'm using a more idiomatic way of writing the code for reading lines from a file. Ruby's IO and File libraries make it very easy to open, read and close the file in a nice neat package.
File.each_line('file.txt') do |li|
puts li if (li['ohn'])
end
That looks for 'ohn' anywhere in the line, but doesn't bother with a regular expression.
File.each_line('file.txt') do |li|
puts li if (li[/ohn/])
end
That looks for the same string, only it uses a regex to get there. Functionally it's the same as the first example.
File.each_line('file.txt') do |li|
puts li if (li[/ohn\b/])
end
This is a bit smarter way of looking for names that end with 'ohn'. It uses regex but also specifies that the pattern has to occur at the end of a word. \b means "word-boundary".
Also, when reading files, it's important to always think ahead about whether the file being read could ever exceed the RAM available to your app. It's easy to read an entire file into memory in one pass, then process it from RAM, but you can cripple or kill your app or machine if you exceed the physical RAM available to you.
Do you know if the code shown by the other answers is in fact loading the entire file into RAM or is somehow optimized by streaming from the readlines function to the select function?
From the IO#readlines documentation:
Reads the entire file specified by name as individual lines, and returns those lines in an array. Lines are separated by sep.
An additional consideration is memory allocation during a large, bulk read. Even if you have sufficient RAM, you can run into situations where a language chokes as it reads in the data, finds it hasn't allocated enough memory to the variable, and has to pause as it grabs more. That cycle repeats until the entire file is loaded.
I became sensitive to this many years ago when I was loading a very big data file into a Perl app on HP's biggest mini, that I managed. The app would pause for a couple seconds periodically and I couldn't figure out why. I dropped into the debugger and couldn't find the problem. Finally, by tracing the run using old-school print statements I isolated the pauses to a file "slurp". I had plenty of RAM, and plenty of processing power, but Perl wasn't allocating enough memory. I switched to reading line by line and the app flew through its processing. Ruby, like Perl, has good I/O, and can read a big file very quickly when it's reading line-by-line. I have never found a good reason for slurping a text file, except when it's possible to have content I want spread across several lines, but that is not a common occurrence.
Maybe I'm not understanding the problem fully, but you could do something like:
File.readlines("path/to/file.txt").select { |line| line =~ /ohn/ }
to get an array of all the lines that match your criteria.
query = 'ohn'
names = File.readlines('names.txt')
matches = names.select { |name| name[/#{query}/i] }
#=> ["John Smith"]
Remove the i at the end of the regex if you wish the query to be case sensitive.
Old question, but Array#grep can also be used to search a list of strings
File.readlines("names.txt").grep /#{query}/i

Multi-Line Comments in Ruby?

How can I comment multiple lines in Ruby?
#!/usr/bin/env ruby
=begin
Every body mentioned this way
to have multiline comments.
The =begin and =end must be at the beginning of the line or
it will be a syntax error.
=end
puts "Hello world!"
<<-DOC
Also, you could create a docstring.
which...
DOC
puts "Hello world!"
"..is kinda ugly and creates
a String instance, but I know one guy
with a Smalltalk background, who
does this."
puts "Hello world!"
##
# most
# people
# do
# this
__END__
But all forgot there is another option.
Only at the end of a file, of course.
This is how it looks (via screenshot) - otherwise it's hard to interpret how the above comments will look. Click to Zoom-in:
=begin
My
multiline
comment
here
=end
Despite the existence of =begin and =end, the normal and a more correct way to comment is to use #'s on each line. If you read the source of any ruby library, you will see that this is the way multi-line comments are done in almost all cases.
#!/usr/bin/env ruby
=begin
Between =begin and =end, any number
of lines may be written. All of these
lines are ignored by the Ruby interpreter.
=end
puts "Hello world!"
Using either:
=begin
This
is
a
comment
block
=end
or
# This
# is
# a
# comment
# block
are the only two currently supported by rdoc, which is a good reason to use only these I think.
=begin
comment line 1
comment line 2
=end
make sure =begin and =end is the first thing on that line (no spaces)
Here is an example :
=begin
print "Give me a number:"
number = gets.chomp.to_f
total = number * 10
puts "The total value is : #{total}"
=end
Everything you place in between =begin and =end will be treated as a comment regardless of how many lines of code it contains between.
Note: Make sure there is no space between = and begin:
Correct: =begin
Wrong: = begin
=begin
(some code here)
=end
and
# This code
# on multiple lines
# is commented out
are both correct. The advantage of the first type of comment is editability—it's easier to uncomment because fewer characters are deleted. The advantage of the second type of comment is readability—reading the code line by line, it's much easier to tell that a particular line has been commented out. Your call but think about who's coming after you and how easy it is for them to read and maintain.
In case someone is looking for a way to comment multiple lines in a html template in Ruby on Rails, there might be a problem with =begin =end, for instance:
<%
=begin
%>
... multiple HTML lines to comment out
<%= image_tag("image.jpg") %>
<%
=end
%>
will fail because of the %> closing the image_tag.
In this case, maybe it is arguable whether this is commenting out or not, but I prefer to enclose the undesired section with an "if false" block:
<% if false %>
... multiple HTML lines to comment out
<%= image_tag("image.jpg") %>
<% end %>
This will work.
def idle
<<~aid
This is some description of what idle does.
It does nothing actually, it's just here to show an example of multiline
documentation. Thus said, this is something that is more common in the
python community. That's an important point as it's good to also fit the
expectation of your community of work. Now, if you agree with your team to
go with a solution like this one for documenting your own base code, that's
fine: just discuss about it with them first.
Depending on your editor configuration, it won't be colored like a comment,
like those starting with a "#". But as any keyword can be used for wrapping
an heredoc, it is easy to spot anyway. One could even come with separated
words for different puposes, so selective extraction for different types of
documentation generation would be more practical. Depending on your editor,
you possibly could configure it to use the same syntax highlight used for
monoline comment when the keyword is one like aid or whatever you like.
Also note that the squiggly-heredoc, using "~", allow to position
the closing term with a level of indentation. That avoids to break the visual reading flow, unlike this far too long line.
aid
end
Note that at the moment of the post, the stackoverflow engine doesn't render syntax coloration correctly. Testing how it renders in your editor of choice is let as an exercise. ;)

Ruby Array#puts not using overridden implementation?

I am using Ruby 1.8.6 for the following code:
# Create an array and override the #to_s on that object
thing = [1,2,3]
def thing.to_s
'one'
end
print "Using print: "
print thing
puts
puts "Using puts: "
puts thing
Output:
Using print: one
Using puts:
1
2
3
So thing is an Array and I have overridden thing#to_s. print seems to use my overriden implementation while puts does not. Why?
I have followed the source code of Kernel#puts and Kernel#print (which are C-implementations) and see that they are very different implementations. I want to know what might be the design-decision (if any) behind this?
By the way, if I create thing as an instance of another class I wrote (or as a Hash/String/other-classes I tried), both print and puts use the overridden implementation of to_s.
Oh boy ... This has already been the topic of a countless number of endless threads on the ruby-talk mailinglist, the ruby-core mailinglist and a gazillion of blogs.
The gist of it is that puts special cases Arrays. Why it special cases those, why it special cases only those (as opposed to, say, all Enumerables), why it special cases those (and not, say, print), nobody really knows. It is the way it is.
BTW, since you mentioned the POLS: the Ruby community has always made it very clear that the POLS only applies to matz. So, Ruby is about not surprising matz. If you or me or anybody else is surprised, that doesn't count.
From the Ruby Programming Language:
alt text http://ecx.images-amazon.com/images/I/41n-JSlBHkL._SL75_.jpg
Output streams are appendable, like strings and arrays are, and you can write values to them with the << operator. puts is one of the most common output methods. It converts each of its arguments to a string, and writes each one to the stream. If the string does not already end with a newline character, it adds one. If any of the arguments to puts is an array, the array is recursively expanded, and each element is printed on its own line as if it were passed directly as an argument to puts. The print method converts its arguments to strings, and outputs them to the stream. If the global field separator $, has been changed from its default value of nil, then that value is output between each of the arguments to print. If the output record separator $/ has been changed from its default value of nil, then that value is output after all arguments are printed.
As for design decisions, that I do not know.

Resources