ruby output to file is causing unwanted line breaks - ruby

My ruby program is causing unwanted line breaks when calling a variable within a string.
The string is then printed to a text file. In this text file there are lot of unwanted line breaks.
Heres my code.
puts 'What is the 2nd Octet?'
second_octet = gets
puts 'What is the 3rd Octet?'
third_octet = gets
puts 'What is the vlan number?'
vlan_number = gets
vrf_number = <<-eos
123#{vlan_number}
eos
router_config = <<-eos
interface Bundle-Ether7.#{vlan_number}
description * #{description_name} *
mtu 9216
vrf #{vrf_number}
ipv4 address 10.#{second_octet}.#{third_octet}.252 255.255.255.0
eos
File.open(config, 'w') { |file| file.write(router_config) }`
I'm getting line breaks after I call the variables so there are gaps between lines, this is extremely annoying with the second_octet and third_octet variables as it splits the ip address across multiple lines.
Any help would be great! Thanks!

The string returned by gets includes the newline character (\n or \r\n) from the return/enter key. You need to do gets.chomp to take off the trailing newline, or gets.strip to get rid of leading and trailing whitespace. Either one should work in your case.

Related

How can I print a string contained in an object as literal with Ruby?

I'm trying to write a program which will detect if a file has \n or \r\n line endings and then fix them. I'm hoping to have the script output some messages to a console, but I'm running into trouble. I can't figure out how to print the line endings as literals.
Here is my method which checks for the line ending type:
def determine_line_ending(filename)
File.open(filename, 'r') do |file|
return file.readline[/\r?\n$/]
end
end
ending = determine_line_ending(ARGV.first)
Supposedly this method will return either \n or \r\n if it matches one of those patterns on the first line of the file.
I would like to then print to the console which ending type was detected but if I use puts ending then it just adds a line ending to the console. I know that if I used puts '\r\n' then it will print them literal, or if I use double quotes I just have to escape the backslashes. But I'm pretty new to Ruby and I'm having a hard time just finding a way to print my variable as a literal instead of a string.
If I'm understanding you well, you want to print the "\r" string if the line ending is \r and "\r\n" if \r\n.
In this case you can use the dump function is what you need:
puts ending.dump // => "\r" or "\r\n"
I would use method String#inspect:
s = "abc\n\rdef"
puts s
puts s.inspect
This is very handy method that is defined on all objects. You can print hashes, arrays, whatever.

Ruby unable to create directories

I'm trying to read a file having string values, line by line and create respective folder/directory for every string value.
#require 'fileutils'
value=File.open('D:\\exercise\\list.txt').read
value.gsub!(/\r\n?/, "\n")
value.each_line do |line|
line.chomp
print "FOlder names:#{line}"
Dir.mkdir("D:\\exercise\\#{line}")
end
and I'm getting the below error:
read_folders_svn.rb:8:in `mkdir': Invalid argument - Australia (Errno::EINVAL)
from read_folders_svn.rb:8:in `block in <main>'
list.txt file's content below
Australia
USA
EUrope
Africa
ANtartica
I tried printing the values and its working fine, while creating the respective directories facing the above issue and even tried using fileutils (fileutils.mkdir) option but still the same issue.
Any suggestions please. Thanks
The error is in the line:
line.chomp
It strips the newline from the tail of line and returns a value that is ignored. It doesn't change the value of line. It still ends with "\n" and this is a character that is not allowed in file names on Windows. The code runs fine on Linux and creates directories whose names end in "\n".
The solution is also simple. Use #chomp! instead:
#require 'fileutils'
value=File.open('D:\\exercise\\list.txt').read
value.gsub!(/\r\n?/, "\n")
value.each_line do |line|
line.chomp!
print "FOlder names:#{line}"
Dir.mkdir("D:\\exercise\\#{line}")
end
(It might still produce errors, however, because of empty lines in the input).
Have you checked that the line doesn't contain extra characters? Where line.chomp! will solve your problem but line.strip! is probably the more robust variant, esp if you have windows line-endings of \r\n.
Difference between chomp and strip
String#chomp operates on the end of strings, while String#strip
operates on the start and end of strings. String#chomp takes an
optional 'record separator' argument, while String#strip takes no
arguments. If String#chomp is given no arguments it will remove
carriage returns characters from the end of the string being operated
on (\r, \n or \r\n). If String#chomp is passed a string as an
argument, that string is removed from the end of the string being
operated on. String#strip will remove leading and trailing null and
whitespace characters from the string being operated on.
"Cadel Evans".chomp(' Evans') # => "Cadel"
"Cadel Evans\r\n".chomp # => "Cadel Evans"
"\tRobbie McEwen\r\n".strip # => "Robbie McEwen"

How to use "gets" and "gets.chomp" in Ruby

I learned that gets creates a new line and asks the user to input something, and gets.chomp does the same thing except that it does not create a new line. gets must return an object, so you can call a method on it, right? If so, lets name that object returned by gets as tmp, then you can call the chomp method of tmp. But before gets returns tmp, it should print a new line on the screen. So what does chomp do? Does it remove the new line after the gets created it?
Another way to re-expound my question is: Are the following actions performed when I call gets.chomp?
gets prints a new line
gets returns tmp
tmp.chomp removes the new line
User input
Is this the right order?
gets lets the user input a line and returns it as a value to your program. This value includes the trailing line break. If you then call chomp on that value, this line break is cut off. So no, what you have there is incorrect, it should rather be:
gets gets a line of text, including a line break at the end.
This is the user input
gets returns that line of text as a string value.
Calling chomp on that value removes the line break
The fact that you see the line of text on the screen is only because you entered it there in the first place. gets does not magically suppress output of things you entered.
The question shouldn't be "Is this the right order?" but more "is this is the right way of approaching this?"
Consider this, which is more or less what you want to achieve:
You assign a variable called tmp the return value of gets, which is a String.
Then you call String's chomp method on that object and you can see that chomp removed the trailing new-line.
Actually what chomp does, is remove the Enter character ("\n") at the end of your string. When you type h e l l o, one character at a time, and then press Enter gets takes all the letters and the Enter key's new-line character ("\n").
1. tmp = gets
hello
=>"hello\n"
2. tmp.chomp
"hello"
gets is your user's input. Also, it's good to know that *gets means "get string" and puts means "put string". That means these methods are dealing with Strings only.
chomp is the method to remove trailing new line character i.e. '\n' from the the string.
whenever "gets" is use to take i/p from user it appends new line character i.e.'\n' in the end of the string.So to remove '\n' from the string 'chomp' is used.
str = "Hello ruby\n"
str = str.chomp
puts str
o/p
"Hello ruby"
chomp returns a new String with the given record separator removed from the end of str (if present).
See the Ruby String API for more information.
"gets" allows user input but a new line will be added after the string (string means text or a sequence of characters)
"gets.chomp" allows user input as well just like "gets", but there is
not going to be a new line that is added after the string.
Proof that there are differences between them:
Gets.chomp
puts "Enter first text:"
text1 = gets.chomp
puts "Enter second text:"
text2 = gets.chomp
puts text1 + text2
Gets:
puts "Enter first text:"
text1 = gets
puts "Enter second text:"
text2 = gets
puts text1 + text2
Copy paste the code I gave you, run and you will see and know that they are both different.
For example:
x = gets
y = gets
puts x+y
and
x = gets.chomp
y = gets.chomp
puts x+y
Now run the two examples separately and see the difference.

Ruby regex gsub a line in a text file

I need to match a line in an inputted text file string and wrap that captured line with a character for example.
For example imagine a text file as such:
test
foo
test
bar
I would like to use gsub to output:
XtestX
XfooX
XtestX
XbarX
I'm having trouble matching a line though. I've tried using regex starting with ^ and ending with $, but it doesn't seem to work. Any ideas?
I have a text file that has the following in it:
test
foo
test
bag
The text file is being read in as a command line argument.
So I got
string = IO.read(ARGV[0])
string = string.gsub(/^(test)$/,'X\1X')
puts string
It outputs the exact same thing that is in the text file.
If you're trying to match every line, then
gsub(/^.*$/, 'X\&X')
does the trick. If you only want to match certain lines, then replace .* with whatever you need.
Update:
Replacing your gsub with mine:
string = IO.read(ARGV[0])
string = string.gsub(/^.*$/, 'X\&X')
puts string
I get:
$ gsub.rb testfile
XtestX
XfooX
XtestX
XbarX
Update 2:
As per #CodeGnome, you might try adding chomp:
IO.readlines(ARGV[0]).each do |line|
puts "X#{line.chomp}X"
end
This works equally well for me. My understanding of ^ and $ in regular expressions was that chomping wouldn't be necessary, but maybe I'm wrong.
You can do it in one line like this:
IO.write(filepath, File.open(filepath) {|f| f.read.gsub(//<appId>\d+<\/appId>/, "<appId>42</appId>"/)})
IO.write truncates the given file by default, so if you read the text first, perform the regex String.gsub and return the resulting string using File.open in block mode, it will replace the file's content in one fell swoop.
I like the way this reads, but it can be written in multiple lines too of course:
IO.write(filepath, File.open(filepath) do |f|
f.read.gsub(//<appId>\d+<\/appId>/, "<appId>42</appId>"/)
end
)
If your file is input.txt, I'd do as following
File.open("input.txt") do |file|
file.lines.each do |line|
puts line.gsub(/^(.*)$/, 'X\1X')
end
end
(.*) allows to capture any characters and makes it a variable Regexp
\1 in the string replacement is that captured group
If you prefer to do it in one line on the whole content, you can do it as following
File.read("input.txt").gsub(/^(.*)$/, 'X\1X')
string.gsub(/^(matchline)$/, 'X\1X')
Uses a backreference (\1) to get the first capture group of the regex, and surround it with X
Example:
string = "test\nfoo\ntest\nbar"
string.gsub!(/^test$/, 'X\&X')
p string
=> "XtestX\nfoo\nXtestX\nbar"
Chomp Line Endings
Your lines probably have newline characters. You need to handle this one way or another. For example, this works fine for me:
$ ruby -ne 'puts "X#{$_.chomp}X"' /tmp/corpus
XtestX
XfooX
XtestX
XbarX

How to receive data from user without ruby adding an extra newline

I am trying to create a program that alphabetizes a users' word entries. However, inspection of the users entries reveals that ruby is for some reason adding a newline character to each word. For instance, If i enter Dog, Cat, Rabbit the program returns ["Cat\n", "Dog\n", "Rabbit\n"] How do i prevent this from happening?
words = []
puts "Enter a word: "
until (word = gets).to_s.chomp.empty?
puts "Enter a word: "
words << word
end
puts words.sort.inspect
Change your code to:
until (word = gets.chomp).empty?
The way you're doing it now:
(word = gets).to_s.chomp.empty?
gets the string from the keyboard input, but it isn't returned to your code until the user presses Return, which adds the new-line, or carriage-return + new-line on Windows.
to_s isn't necessary because you're already getting the value from the keyboard as a string.
chomp needs to be tied to gets if you want all the input devoid of the trailing new-line or new-line/carriage-return. That will work fine when testing for empty?.
Ruby 2.4 has a solution for this:
input = gets(chomp: true)
# "abc"

Resources