Given this input file, stored as "test.txt":
test
test
test
testing
test
and this sample code:
def remove_line(line_to_remove)
File.foreach("test.txt").with_index do |line, line_num|
line.gsub!(/[\r\n]+$/, '')
if line == line_to_remove
puts "removed successfully"
else
puts line
end
end
end
You can successfully run:
remove_line('testing')
and get this output:
test
test
test
removed successfully
test
The function takes the content of the line to remove, and opens the file in "line-by-line" fashion. This is idiomatic Ruby, and should be preferred over "slurping" files, as explained in the accepted answer to this SO question.
Once we have a line, it's necessary to strip the line endings from it. Since we don't know exactly which platform this will be run on (or the text file was created on), we use a regular expression to find all known line ending characters ('\r\n' is Windows, '\n' is Linux/Unix/Mac OS X, and '\r' is Mac Classic).
Then we check to see if the line matches what we want to remove. If it does match, we omit it from the output and instead print that it's been "removed successfully"; otherwise, we output the non-matching line.
This matches the original design intent, however, there are plenty of things to do to improve the design and make an overall more useful function. So why not go ahead and do that?
First, we'll make the function take a filename as an argument. This will remove the hardcoded "test.txt"
filename from the foreach
call. That will make this change happen:
def remove_line(filename, line_to_remove)
File.foreach(filename).with_index do |line, line_num|
line.gsub!(/[\r\n]+$/, '')
if line == line_to_remove
puts "removed successfully"
else
puts line
end
end
end
You can successfully run it this way, and it will produce the exact same output:
remove_line("test.txt", "testing")
Next, let's change how the output occurs, and we'll use a block to do this, because that's The Ruby Way. Here's what the function looks like with a block to output:
def remove_line(filename, line_to_remove, &block)
proc = block_given? ? block : lambda {|s| puts s }
File.foreach(filename).with_index do |line, line_num|
line.gsub!(/[\r\n]+$/, '')
if line == line_to_remove
proc.call "removed successfully"
else
proc.call line
end
end
end
This is built with an optional block argument, so you can call it exactly like the previous version to make it work exactly the same way, or you can call it with an explicit block and do something cool. This example of running it modifies the string slightly before calling puts
to print the line:
remove_line("test.txt", "testing") {|s| puts "#{s} in your pants" }
And with that extra pinch of childishness, you get this output:
test in your pants
test in your pants
test in your pants
removed successfully in your pants
test in your pants
You now have the power to do interesting things, built up from other interesting things. Use it wisely and keep doing it The Ruby Way.