Missing the each_line method in FakeFS version 0.2.1? Add it!
Posted on May 06, 2010 by Scott Leberknight
Recently we have been using the excellent FakeFS (fake filesystem) gem in some specs to test code that reads and writes files on the filesystem. We are using the latest release version of this gem which is 0.2.1 as I am writing this. Some of the code under test uses the IO
each_line
method to iterate lines in relatively largish files. But we found out quickly that is a problem, since in version 0.2.1 the FakeFS::File
class does not extend StringIO
and so you don't get all its methods such as each_line
. (The version on master in GitHub as I write this does extend StringIO
, but it is not yet released as a formal version.)
As an example suppose we have the following code that prints out the size of each line in a file as stars (asterisks):
def lines_to_stars(file_path) File.open(file_path, 'r').each_line { |line| puts '*' * line.size } end
Let's say we use FakeFS to create a fake file like this:
require 'fakefs/safe' require 'stringio' FakeFS.activate! File.open('/tmp/foo.txt', 'w') do |f| f.write "The quick brown fox jumped over the lazy dog\n" f.write "The quick red fox jumped over the sleepy cat\n" f.write "Jack be nimble, Jack be quick, Jack jumped over the candle stick\n" f.write "Twinkle, twinkle little star, how I wonder what you are\n" f.write "The End." end
So far, so good. But now if we call lines_to_stars
we get an error:
NoMethodError: undefined method `each_line' for #<FakeFS::File:0x000001012c22b8>
Oops. No each_line
. If you don't want to use an unreleased version of the gem, you can add each_line
onto FakeFS::File using the following code:
module FakeFS class File def each_line File.readlines(self.path).each { |line| yield line } end end end
Basically all it does is define each_line
so that it reads all the lines from a (fake) file on the (fake) filesystem and then yields them up one by one, so you can have code under test that iterates a file and work as expected. So now calling lines_to_stars
gives a nice pretty bar chart containing the line sizes represented by stars:
******************************************** ******************************************** *************************************************************** ******************************************************* ********
Since we're using RSpec, to make this work nicely we added the above code that defines each_line
into a file named fakefs.rb
in the spec/support
directory, since spec_helper
requires supporting files in the spec/support
directory and its subdirectories. So now all our specs automatically get the each_line
behavior when using FakeFS.