in `%': Array can't be coerced into Fixnum (TypeError) Trying to reduce lines of Ruby Code - ruby

I got the above error when trying to reduce 5 lines to 1, using target.write:
target.write("%s \n %s \n %s \n") % [line1, line2, line3]
# target.write("\n")
# target.write(line2)
# target.write("\n")
# target.write(line3)
# target.write("\n")
The commented section ran(when the 1st line was target.write(line1), but this does not.
Why isn't the very first line the same as writing the commented out six lines? here is the whole script:
filename = ARGV.first
script = $0
puts "We're going to erase #{filename}."
puts "If you don't want that hit control C"
puts "If you do want that hit execute or return"
print "? "
STDIN.gets
puts "Opening the file..."
target = File.open(filename, 'w')
puts "Truncating the file. Goodbye!"
target.truncate(target.size)
puts "Now I'm going to ask you for three lines."
print "line1: "; line1 = STDIN.gets.chomp()
print "line2: "; line2 = STDIN.gets.chomp()
print "line3: "; line3 = STDIN.gets.chomp()
puts "I'm going to write these to the file."
target.write("%s \n %s \n %s \n") % [line1, line2, line3]
# target.write("\n")
# target.write(line2)
# target.write("\n")
# target.write(line3)
# target.write("\n")
puts "And finally we close it"
target.close()

The closing paren on the target.write line is in the wrong place. Try
target.write("%s \n %s \n %s \n" % [line1, line2, line3])

Your parenthesis are wrong. What you have:
target.write("%s \n %s \n %s \n") % [line1, line2, line3]
is equivalent to doing:
a = target.write("%s \n %s \n %s \n")
a % [line1, line2, line3]
Thus what you want is:
target.write("%s \n %s \n %s \n" % [line1, line2, line3])

Related

Reading a file after writing on it

I am doing exercise 16 at learnrubythehardway.org.
The name of a file is passed as argument to the following script, which asks the user to write three lines to the file:
filename = ARGV.first
puts "Opening the file..."
target = open(filename, 'w+')
puts "Now I am going to ask you for three lines."
print "line 1: "
line1 = $stdin.gets.chomp
print "line 2: "
line2 = $stdin.gets.chomp
print "line 3: "
line3 = $stdin.gets.chomp
puts "I am going to write these to the file."
target.write(line1)
target.write("\n")
target.write(line2)
target.write("\n")
target.write(line3)
target.write("\n")
puts "Here is your new file:"
print target.read
puts "And finally we close it"
target.close
Just before closing the file I would like the user be given the opportunity to see the content of the new file, however that part of the code is not processed. Why is that?
You have to rewind the file, if you want to read what you have just written.
target.write(line3)
target.write("\n")
target.rewind
target.read
Bonus content
Use puts, it writes the newline for you.
target.puts(line3)

Ruby - Reading a file causes an extra line while printing

How can I avoid a new line when I use puts line + "test"
Example code:
File.open("test.txt", "r") do |f|
f.each_line do |line|
puts line + "test" #=>line1\ntest
#puts "test" + line #=> testline1
end
end
When I use:
puts "test" + line`
It shows:
testline1
(line1 being the only thing in the test.txt)
However,
puts line + "test"
looks like:
test
line1
Is there anyway of stopping it from producing the extra line?
If you want to strip out the newline, use String#chomp to take care of it.
http://apidock.com/ruby/v1_9_3_392/String/chomp
puts line.chomp + "test"
Use String#strip to strip out all the leading and trailing whitespace characters (including new line):
puts line.strip + "test"
# => line1test
To delete only the trailing whitespaces, you can use String#rstrip:
puts line.rstrip + "test"
# => line1test

Ruby 'script = $0'

I was looking at a Ruby script and I came across script = $0. I have done some Googling but I have not found a definite answer as to what this does. I believe that it protects you from reading a file bigger than memory, is that correct?
Thanks, I have the full script below so you can see it in context:
# Takes the name of a file as an argument and assigns to filename
filename = ARGV.first
script = $0
puts "We're going to erase #{filename}."
puts "If you don't want that, hit CTRL-C (^C)."
puts "If you do want that, hit RETURN."
print "? "
STDIN.gets
puts "Opening the file..."
target = File.open(filename, 'w')
puts "Truncating the file. Goodbye!"
target.truncate(target.size)
puts "Now I'm going to ask you for three lines."
print "line 1: "; line1 = STDIN.gets.chomp()
print "line 2: "; line2 = STDIN.gets.chomp()
print "line 3: "; line3 = STDIN.gets.chomp()
puts "I'm going to write these to the file."
target.write(line1)
target.write("\n")
target.write(line2)
target.write("\n")
target.write(line3)
target.write("\n")
puts "And finally, we close it."
target.close()
$0 is one of Ruby's global variables. From here:
$0 -- Contains the name of the script being executed. May be assignable.
Oh the classic Zed Shaw books! lol
The $0 gets the input on the command line before the first argument. So say you were to run this through the command line using the ruby interpreter you could put "ruby (fileName) test.txt" and $0 will pick up the fileName and save it to the variable 'script'. I'm not really sure why your doing it here because you do use it later in the program, but that's it.
The way you could have tested this would be to print it on the screen using puts, perhaps add this bit of code to see it yourself somewhere in the code:
puts "The $0 has saved #{script} to it, I wonder where it got that."
and see it will name your file.

Building multi-line strings, programmatically, in Ruby

Here's something I often do when programming:
code = ''
code << "next line of code #{something}" << "\n"
code << "another line #{some_included_expression}" << "\n"
Is there some better way than having << "\n" or + "\n" on every line? This seems quite inefficient.
I'm interested in Ruby solutions, in particular. I'm thinking something like
code = string.multiline do
"next line of code #{something}"
"another line #{some_included_expression}"
end
If you're looking to build a block of text, the easy way to do it is to just use the % operator. For example:
code = %{First line
second line
Third line #{2 + 2}}
'code' will then be
"First line\n second line\n Third line 4"
This would be one way:
code = []
code << "next line of code #{something}"
code << "another line #{some_included_expression}"
code.join("\n")
Use <<- operator:
code = <<-CODE
var1 = "foo"
var2 = "bar"
CODE
It would work for you to just embed ...\n" in your strings, I suppose. Here is a fun way to do it:
class String
def / s
self << s << "\n"
end
end
then
f = "" # => ""
f / 'line one' # => "line one\n"
f / 'line two' # => "line one\nline two\n"
f / 'line three' # => "line one\nline two\nline three\n"
This would enable something like:
"" / "line 1" / "line 2" / "line 3" # => "line 1\nline 2\nline 3\n"
Or even:
f/
"line one"/
"line two"/
"line three" # => "line one\nline two\nline three\n"
Here's a method presented here:
str = <<end.margin
|This here-document has a "left margin"
|at the vertical bar on each line.
|
| We can do inset quotations,
| hanging indentions, and so on.
end
This is accomplished by using this:
class String
def margin
arr = self.split("\n") # Split into lines
arr.map! {|x| x.sub!(/\s*\|/,"")} # Remove leading characters
str = arr.join("\n") # Rejoin into a single line
self.replace(str) # Replace contents of string
end
end
I guess the question with this is: does the lack of portability / presence of monkey patching make this solution bad.
What's wrong with:
code = "next line of code #{something}\n"+
"another line #{some_included_expression}"
You could place your multi-line text in a file, and use ERB to parse it (note ERB is included with Ruby)
require 'erb'
multi_line_string = File.open("multi_line_string.erb", 'r').read
template = ERB.new(multi_line_string)
template.result(binding)
(ERB can access variables from a Binding, an object that provides access to the instance methods and variables that are owned by another object. By setting it to "binding" it points to itself)
Documentation here.

How to add string "\n" literally at the end of each line in Ruby?

Here is a string str:
str = "line1
line2
line3"
We would like to add string "\n" to the end of each line:
str = "line1 \n
line2 \n
line3 \n"
A method is defined:
def mod_line(str)
s = ""
str.each_line do |l|
s += l + '\\n'
end
end
The problem is that '\n' is a line feed and was not added to the end of the str even with escape \. What's the right way to add '\n' literally to each line?
String#gsub/String#gsub! plus a very simple regular expression can be used to achieve that:
str = "line1
line2
line3"
str.gsub!(/$/, ' \n')
puts str
Output:
line1 \n
line2 \n
line3 \n
The platform-independent solution:
str.gsub(/\R/) { " \\n#{$~}" }
It will search for line-feeds/carriage-returns and replace them with themselves, prepended by \n.
\n needs to be interpreted as a special character. You need to put it in double quotes.
"\n"
Your attempt:
'\\n'
only escapes the backslash, which is actually redundant. With or without escaping on the backslash, it gives you a backslash followed by the letter n.
Also, your method mod_line returns the result of str.each_line, which is the original string str. You need to return the modified string s:
def mod_line(str)
...
s
end
And by the way, be aware that each line of the original string already has "\n" at the end of each line, so you are adding the second "\n" to each line (making it two lines).
This is the closest I got to it.
def mod_line(str)
s = ""
str.each_line do |l|
s += l
end
p s
end
Using p instead of puts leaves the \n on the end of each line.

Resources