Fairly new to ruby, can someone explain why these 2 things respond differently?
a=["A","B","C"]
puts a
A
B
C
puts "#{a}"
ABC
a.to_s returns the same output as the templating output, but shouldn't the simple "puts a" do the same?
The specified behavior of puts is that it writes stuff out with a newline afterwards. If it's an array, it writes each element with a newline.
When you do puts a.to_s, it does the to_s first (resulting in a single string) and then outputs that single string with a newline afterward.
As discussed in this thread, and for no good reason, Arrays have magically inconsistent behavior when given to puts.
array.each {|e| puts e }
is the same as:
puts array
Related
This question already has answers here:
Why doesn't puts() print in a single line?
(3 answers)
Closed 5 years ago.
This is from the irb:
irb(main):001:0> puts "abc"
abc
=> nil
irb(main):002:0> puts "abc\n"
abc
=> nil
irb(main):003:0> puts "abc\n\n"
abc
=> nil
As you can see, puts "abc" puts a newline after "abc", as it should. However, puts "abc\n" also puts a single newline, whereas I would expect that there would be two newlines.
To me, the output of puts "abc\n\n" is what I would expect from puts "abc\n".
Why is this the case?
After reading Cary Swoveland's comment I've realized that it is not at all obvious how puts works, because its documentation is quite scarce:
puts(obj, ...) → nil
Equivalent to
$stdout.puts(obj, ...)
It doesn't even bother to explain what $stdout is, nor does it provide a link.
$stdout is one of Ruby's pre-defined global variables. It refers to the standard output which in Ruby happens to be an instance of IO:
$stdout
#=> #<IO:<STDOUT>>
So "Equivalent to $stdout.puts(obj, ...)" means that we have to read the documentation for IO#puts:
Writes the given object(s) to ios. Writes a newline after any that do not already end with a newline sequence. Returns nil.
There you go: puts only adds a newline if the object does not already ends with one.
To get the expected multi-line output, you can simply call puts for each line:
puts 'abc'
or
puts 'abc'
puts
or
puts 'abc'
puts
puts
That's just how puts works. It prevents you from needing to append a newline everytime you call puts.
Given no newline, one will be added
Given a trailing newline, an additional one will not be added
Source: http://ruby-doc.org/core-2.4.1/IO.html#method-i-puts
I'd like to create ruby one liner that prints some information to stdout and gets data from stdin. I've got some code:
["This should be shown first", "This second: #{gets.chomp}"].each{|i| puts "#{i}"}
...but apparently, get.chomp is evaluated in the same time when whole array is evaluated, before iteration of each element.
In result, I'm first prompted for input, and then each element is printed.
Can I somehow evaluate it lazily, print array in order and still have whole thing in one line?
One way to achieve lazy evaluation is to use procs. Something like this (multiple lines for readability):
[
-> { puts "This should be shown first" },
-> { print "This second: "; puts gets.chomp },
].each(&:call)
I don't really see the advantage of making this a one-liner since it becomes pretty unreadable, but nevertheless:
[ ->{ "This should be shown first" },
->{ "This second: #{gets.chomp}" }
].each {|line| puts line.call }
P.S. Never do "#{foo}". Use string interpolation (#{...}) when you want to, well, interpolate strings, as on the second line above. If you want to turn a non-string into a string, do foo.to_s. If you know it's already a string (or don't care if it is) just use it directly: foo. But puts automatically calls to_s on its arguments, so just do puts foo.
If you dont mind the repetiton of puts:
['puts "This should be shown first"', 'puts "This second: #{gets.chomp}"'].each{|i| eval i}
This is just to show you could use a method rather than a proc.
def line2
"#{["cat","dog"].sample}"
end
["Line 1", :line2, "line 3"].each { |l| puts (l.is_a? Symbol) ? method(l).call : l }
#=> dog
I noticed the difference in printing array with and without interpolation:
Source code:
uuu="a b c d e f g";
o=uuu.split(' ');
puts "Interpolation:#{o}";
puts "Without interpolation";
puts o;
Output:
Interpolation:["a", "b", "c", "d", "e", "f", "g"]
Without interpolation
a
b
c
d
e
f
g
I don't understand why those differences happen.
When you call puts in the main context without an explicit receiver, you are calling Kernel#puts, and that calls $stdout.puts. Usually, $stdout.puts outputs the result of applying to_s to its argument. However, array is exceptional in that each element of it is printed in a separate line. From the doc:
puts(obj, ...) → nil
Writes the given objects to ios as with IO#print. Writes a record separator (typically a newline) after any that do not already end with a newline sequence. If called with an array argument, writes each element on a new line. If called without arguments, outputs a single record separator.
In your first example, you interpolated a string with an array, which applies to_s to it, and ends up with a string of the format ["a", "b", ...], which is passed to puts. In your second example, you passed an array directly to puts, to which the exceptional behaviour on arrays explained above applies.
This doesn't really have anything to do with how interpolation behaves. It's not interpolation that's giving you a difference in output, it's that your supply a string vs an array to puts.
The same results occur if you simply do this:
puts o.to_s
puts o
puts handles strings and arrays differently. In the first instance, you're giving it a string, into which an array has been interpolated. Interpolation invokes to_s on the value being interpolated, and when you invoke to_s on an array, it gives you the format you see in your output. For example [1, 2, 3].to_s is the string "[1, 2, 3]".
When you give puts an array as its argument, it prints the items in the array, one per line.
def say(arg)
"Hello, #{arg}.\n"
end
say("ABC") # => "Hello, ABC.\n"
Why here \n is printed instead of a newline?
because say returns a String. it doesn't print anything.
If you want to print something you should try:
def say(arg)
puts "Hello, #{arg}.\n"
end
You're most likely trying this in irb which displays the Ruby representation of a string. Compare:
irb(main):007:0> puts say("ABC") + say("ABC")
Hello, ABC.
Hello, ABC.
=> nil
irb(main):008:0> puts "ABC" + "ABC"
ABCABC
=> nil
It is actually never printed to stdio or anything like that, you are simply returning a string from a function.
I'll make the assumption that you are evaluating this in IRB, IRB prints out the result of every expression.
use puts or similar.
In the book I'm reading to learn Rails (RailsSpace) , the author creates two functions (below) to turn all caps city names like LOS ANGELES into Los Angeles. There's something I don't get about the first function, below, however.
Namely, where does "word" come from? I understand that "word" is a local/block variable that disappears after the function has been completed, but what is being passed into/assigned to "word." IN other words, what is being split?
I would have expected there to have been some kind of argument taking an array or hash passed into this function...and then the "each" function run over that..
def capitalize_each
space = " "
split(space).each{ |word| word.capitalize! }.join(space)
end
# Capitalize each word in place.
def capitalize_each!
replace capitalize_each end
end
Let's break this up.
split(space)
turns the string into a list of would-be words. (Actually, if the string has two spaces in a row, the list will have an empty string in it. but that doesn't matter for this purpose.) I assume this is an instance method in String; otherwise, split wouldn't be defined.
.each { |word| word.capitalize! }
.each takes each thing in the list (returned by split), and runs the following block on it, passing the thing as an arg to the block. The |word| says that this block is going to call the arg "word". So effectively, what this does is capitalize each word in the string (and each blank string and lonely bit of punctuation too, but again, that's not important -- capitalization doesn't change characters that have no concept of case).
.join(space)
glues the words back together, reinserting the space that was used to separate them before. The string it returns is the return value of the function as well.
At first I thought that the method was incomplete because of the absence of self at the beginning but it seems that even without it split is being called over the string given, space would simply be a default separator. This is how the method could look with explicit self.
class String
def capitalize_each(separator = ' ')
self.split(separator).each{|word| word.capitalize!}.join(separator)
end
end
puts "LOS ANGELES".capitalize_each #=> Los Angeles
puts "LOS_ANGELES".capitalize_each('_') #=> Los_Angeles
The string is being split by spaces, i.e. into words.
So the 'each' iterator goes through all the words, one by one, each time the word is in the 'word' object. So then for that object (word) it uses the capitalize function for it. Finally it all gets joined back together With Spaces. So The End Result is Capitalized.
These methods are meant to be defined in the String class, so what is being split is whatever string you are calling the capitalize_each method on.
Some example usage (and a slightly better implementation):
class String
def capitalize_each
split(/\s+/).each{ |word| word.capitalize! }.join " "
end
def capitalize_each!
replace capitalize_each
end
end
puts "hi, i'm a sentence".capitalize_each #=> Hi, I'm A Sentence
Think of |word| word.capitalize! as a function whch you're passing into the each method. The function has one argument (word) and simply evaluates .capitalize! on it.
Now what the each method is doing is taking each item in split(space) and evaluating your function on it. So:
"abcd".each{|x| print x}
will evaluate, in order, print "a", print "b", print "c".
http://www.ruby-doc.org/core/classes/Array.html#M000231
To demystify this behavior a bit, it helps to understand exactly what it means to "take each item in __". Basically, any object which is enumerable can be .eached in this way.
If you're referring to how it gets into your block in the first place, it's yielded into the block. #split returns an Array, and it's #each method is doing something along the lines of:
for object in stored_objects
yield object
end
This works, but if you want to turn one array into another array, it's idiomatically better to use map instead of each, like this:
words.map{|word|word.capitalize}
(Without the trailing !, capitalize makes a new string instead of modifying the old string, and map collects those new strings into a new array. In contrast, each returns the old array.)
Or, following gunn's lead:
class String
def capitalize_each
self.split(/\s/).map{|word|word.capitalize}.join(' ')
end
end
"foo bar baz".capitalize_each #=> "Foo Bar Baz"
by default, split splits on strings of spaces, but by passing a regular expression it matches each individual space characters even if they're in a row.