<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>lib/adapters/fs/dir.rb</filename>
    </added>
    <added>
      <filename>lib/adapters/fs/file.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -0,0 +1,413 @@
+class FSO
+  # require 'adapters/fs/file'
+  
+  FSO::IOError = &quot;IOError: Cannot communicate with file.&quot;
+  attr_accessor :path, :permissions, :owner, :group
+  # Retuns a FSO (File System Object).  The path, permissions, ownership &amp; group can be 
+  # specified as attributes. The filesystem is not touched by this method.  The methods that 
+  # make changes to the filesystem are generally ending with an exclamation point (!) and the 
+  # methods that read from the filesystem are generally ending with a question mark (?).
+  #
+  # Examples:
+  #   FSO.new '/tmp/test'
+  #   FSO.new '/tmp/test', 755
+  #   FSO.new '/tmp/test', 755, 'joshaven'
+  #   FSO.new '/tmp/test', 755, 'joshaven', 'staff'
+  #   FSO.new '/tmp/test', nil, 'joshaven'     # The attributes are ordered, however they are ignored if nil.
+  def initialize(dir=nil, priv=nil, own=nil, grp=nil)
+    self.path        = File.expand_path(dir) unless dir.nil?
+    self.permissions = priv unless priv.nil?
+    self.owner       = own unless own.nil?
+    self.group       = grp unless grp.nil?
+  end
+
+  # Return the type of the FSO.  The answer will be one of: File, Dir, or nil
+  def type
+    # return File if File.file?(path || '')
+    # return Dir if File.directory?(path || '')
+    # nil
+    File.file?(path || '') ? File : (File.directory?(path || '') ? Dir : nil)
+  end
+
+  # Shortcut method to finding the type of a filesystem object without instantizing an FSO.
+  #
+  # Example:
+  #   FSO.type('/tmp')   #=&gt; Dir
+  def self.type(*args)
+    FSO.new(*args).send(:type)
+  end
+  
+  # Compares the type of the FSO with the given type.  Returns true or false.
+  #
+  # Example:
+  #   FSO.new('/tmp') === Dir  #=&gt; true
+  def ===(klass)
+    self.type == klass
+  end
+  
+  # Compares the given path string with the associated FSO path string. Returns true or false.
+  #
+  # Example:
+  #   FSO.new('/tmp') == '/tmp'  #=&gt; true
+  def ==(string)
+    self.path == string
+  end
+  
+  # Create a file or directory on the filesystem if it doesn't already exist and set permissions, owner,
+  # &amp; group if specified. See FSO::new for full param options.  They type paramter is required and must be 
+  # one of: [:file, :dir].  Returns an FSO instance.  See also the shortcut methods: :mkdir &amp; :touch
+  #
+  #
+  # Examples:
+  #   p=FSO.new  '/tmp/deleteme'        # this sets the path that is needed for the next command.
+  #   p.create! :file
+  #   # OR
+  #   FSO.create! :file, '/tmp/deleteme', {:sudo =&gt; 'superSecretPassword'}
+  #   p.destroy!                        # cleanup sample file!
+  def create!(type, pth=path, options={})
+    options, pth = pth, options if Hash === pth   # Swap arguments if arguments are backwards
+    pth = path if Hash === pth
+    
+    return false unless String === pth            # validate arg
+    path = pth                                    # ensure the path is set
+    
+    cmd_prefix = options.has_key?(:sudo) ? &quot;echo #{options[:sudo]}| sudo -S &quot; : ''
+    my_type = self.type  # minimize access to File.file? &amp; File.directory?
+    
+    if type == :dir &amp;&amp; !(self === Dir)
+      return false unless my_type == nil || my_type == File
+      raise(&quot;Could not touch file: #{path}&quot;) unless system_to_boolean(&quot;#{cmd_prefix} mkdir #{options[:arguments]} #{path}&quot;)
+    elsif type == :file
+      return false unless my_type == nil || my_type == File
+      raise(&quot;Could not mkdir directory: #{path}&quot;) unless system_to_boolean(&quot;#{cmd_prefix} touch #{options[:arguments]} #{path}&quot;) 
+    else
+      # bail with false if trying to make a dir into a file or a file into a dir
+      return false if (type == :dir &amp;&amp; self == File) || (type == :fie &amp;&amp; self == Dir)
+    end
+    
+    sudo_options = options.has_key?(:sudo) ? {:sudo =&gt; options[:sudo]} : {}
+    self.owner! sudo_options
+    self.group! sudo_options
+    self.permissions! sudo_options
+    
+    return self
+  end
+
+
+  
+  # Create a Directory on the filesystem if it doesn't already exist.  This is a shortcut to the :create! 
+  # method with specifying :dir.  Returns a FSO instance.  See also: create!
+  #
+  # Examples:
+  #   p=FSO.new  '/tmp/deleteme'
+  #   p.mkdir
+  #   # OR:
+  #   p = FSO.mkdir '/tmp/deleteme'
+  #   p.destroy!                      # cleanup test dir
+  def mkdir(pth=path, options={})
+    create! :dir, pth, options
+  end
+  
+  # Create a File on the filesystem if it doesn't already exist.  This is a shortcut to the :create! 
+  # method with specifying :file.  Returns a FSO instance.  See also: create!
+  #
+  # Examples:
+  #   p=FSO.new  '/tmp/deleteme'
+  #   p.touch
+  #   # OR:
+  #   p = FSO.touch '/tmp/deleteme'
+  #   p.destroy!                      # cleanup test file
+  def touch(pth=path, options={})
+    create! :file, pth, options
+  end
+  
+  
+  # Get or set the owner properity of a FSO Ruby object.  This does not change or query anything in the filesystem.  
+  # To make changes to the filesystem, call the :owner! method.
+  # To query the filesystem call the :group? method.
+  #
+  # Examples:
+  #   FSO.mkdir('/tmp/testing.txt')
+  #   FSO.owner 'joshaven'      #=&gt; 'joshaven'
+  #   FSO.owner                 #=&gt; 'joshaven' 
+  def owner(arg=nil)
+    arg.nil? ? @owner : @owner = arg.to_s
+  end
+  alias_method :owner=, :owner
+  
+  # Returns the current owner of the FSO or nil if it doesn't exitst.  This reads from the filesystem
+  #
+  # Examples:
+  #   p = FSO.mkdir '/tmp/my_test'   # =&gt; #&lt;FSO:0x10062dfd0 @permissions=nil, @path=&quot;/tmp/my_test&quot;, @group=nil&gt;
+  #   p.owner?                        # =&gt; &quot;joshaven&quot;  # or what ever your username is
+  #   p.destroy!                      # =&gt; true        # just a bit of cleanup
+  def owner?
+    # exists? ? `ls -al #{path} | grep '[0-9] \.$'`.split[2] : false
+    proprieties[:owner]
+  end
+  
+  # Sets the current owner of the FSO.  Returns true or false.
+  #
+  # options: options must be a hash with two optional keys:  :sudo &amp; :arguments
+  # * sudo: (optional) your sudo password
+  # * arguments: (optional) string containing valid chown options, ie: '-R' for recursive
+  #
+  # Examples:
+  #   p = FSO.mkdir '/tmp/my_test'  #
+  #   p.owner 'root'
+  #   # The following will issue the command `sudo chown -R root /tmp/my_test` and supplies the password
+  #   p.owner! {:sudo =&gt; 'mySecretPassword', :arguments =&gt; '-R'}  
+  def owner!(arg=owner, options={})
+    options, arg = arg, options if Hash === arg &amp;&amp; !arg.empty?  # Swap arguments if arguments seem to be backward
+    arg = owner if Hash === arg
+    
+    return false unless String === arg                          # validate arg
+    owner = arg
+    
+    return false if owner.nil? || !(Hash === options)
+    system_to_boolean &quot;#{'echo '+options[:sudo]+'|sudo -S ' if options.has_key?(:sudo)}chown #{options[:arguments]} #{owner} #{path}&quot; unless path.nil? || owner.nil?
+  end
+  
+  
+  # Get or set the group properity of a FSO Ruby object.  This does not change or query anything in the filesystem.  
+  # To make changes to the filesystem, call the :owner! method.
+  # To query the filesystem call the :group? method.
+  def group(arg=nil)
+    arg.nil? ? @group : @group = arg.to_s
+  end
+  alias_method :group=, :group
+  
+  
+  # Returns the current group of the filesystem object or nil if it doesn't exitst.  This reads from the filesystem.
+  #
+  # Examples:
+  #   FSO.group? '/tmp'    #=&gt; &quot;wheel&quot;
+  def group?
+    proprieties[:group]
+  end
+
+  # Sets the current group of the FSO.  Returns true or false.
+  #
+  # grp_name: optional group name as a string.  If not provided, the group setter will use the value of the @group 
+  # instance variable.
+  #
+  # options: options must be a hash with two optional keys:  :sudo &amp; :arguments
+  # - sudo: (optional) your sudo password
+  # - arguments: (optional) string containing valid chown options, ie: '-R' for recursive
+  #
+  # Examples:
+  #   p = FSO.mkdir '/tmp/my_test'
+  #   p.owner 'root'
+  #   # The following will issue the command `sudo chown -R root /tmp/my_test` and supplies the password
+  #   p.owner! {:sudo =&gt; 'mySecretPassword', :arguments =&gt; '-R'}
+  def group!(arg=group, options={})
+    options, arg = arg, options if Hash === arg &amp;&amp; !arg.empty?  # Swap arguments if arguments seem to be backward
+    arg = group if Hash === arg                                 # in the event that only options are given
+    
+    return false unless String === arg                      # validate arg
+    group(arg)
+    begin
+      if options.has_key? :sudo
+        system_to_boolean &quot;echo #{options[:sudo]}| sudo -S chgrp #{options[:arguments]} #{group} #{path}&quot;
+      else
+        system_to_boolean &quot;chgrp #{options[:arguments]} #{group} #{path}&quot; 
+      end
+    rescue
+      false
+    end
+  end
+
+  # Get or set the permissions properity of a FSO Ruby object.  This does not change or query anything in the filesystem.  
+  # To make changes to the filesystem, call the :permissions! method.
+  # To query the filesystem call the :permissions? method.
+  def permissions(arg=nil)
+    arg.nil? ? @permissions : @permissions = arg.to_s
+  end
+  alias_method :permissions=, :permissions
+  
+  # Returns an integer representation of the permissions or nil if SFO doesn't exist.
+  #
+  # Example: 
+  #   FSO('/tmp').permissions?   # =&gt; 777
+  def permissions?
+    proprieties[:permissions]
+  end
+  
+  # Sets the FSO permissions if the FSO &amp; permissions are valid.
+  # Returns false if given invalid permissions or directory is not in existence.
+  # The Permissions can be set via arguments or via the :permissions method.
+  #
+  # - arg: optional permission to set, can be inferred from the permissions instance variable if set.
+  # - options: optional hash with a sudo and/or arguments keys: p.destroy!({:sudo =&gt; 'superSecret', :arguments =&gt; '-R'})
+  def permissions!(arg=permissions, options={})
+    options, arg = arg, options if Hash === arg     # Swap arguments if arguments seem to be backward
+    arg = permissions if Hash == arg               # in the event that only options are given
+
+    return false unless Fixnum === arg &amp;&amp; /[0-7]{3}/ === arg.to_s # validate arg
+    permissions(arg)
+    
+    unless permissions.nil? || permissions? == permissions  # only proceed if there is something to do
+      begin
+        if options.has_key? :sudo
+          system_to_boolean &quot;echo #{options[:sudo]}| sudo -S chmod #{options[:arguments]} #{permissions} #{path}&quot;
+        else
+          system_to_boolean &quot;chmod #{options[:arguments]} #{permissions} #{path}&quot; 
+        end
+      rescue
+        false
+      end
+    end
+  end
+  
+  # Returns true or false.  Shortcut method to: FSO.new('/tmp').type != nil
+  #
+  # Examples:
+  #   FSO.exists?(&quot;/tmp&quot;)           #=&gt; true
+  def exists?
+    self.type != nil
+  end
+  
+  # Removes FSO from filesystem, returning true if successful or false if unsuccessful.
+  #
+  # Options:
+  # * options may contain a hash with a sudo key containing a password: p.destroy!({:sudo =&gt; 'superSecret'})
+  #
+  # Example:
+  # p = FSO.mkdir('/tmp/text')
+  # p.destroy!                          # =&gt; true
+  # p.destroy!                          # =&gt; false    # its already gone, but the FSO object remains.
+  # p.destroy! :sudo =&gt; 'superSecret'   # =&gt; false    # its already gone, but the FSO object remains.
+  # FSO.destroy!('/tmp/not_here_123')  # =&gt; false    # By the way, the method missing magic works here to.
+  def destroy!(options={})
+    begin
+      if options.has_key? :sudo
+        system_to_boolean &quot;echo #{options[:sudo]}| sudo -S rm #{'-r' if self === Dir} #{path}&quot;
+      else
+        system_to_boolean &quot;rm #{'-r' if self === Dir} #{path}&quot;
+      end
+    rescue
+      false
+    end
+  end
+
+  # Returns a hash of information on the FSO.  This method is dependent upon a Posix environment!
+  #
+  # Keys:
+  # :name, :permissions, :owner, :group, :size, :modified, :mkdird, :subordinates  (subordinates are number of items contained)
+  def proprieties
+    begin
+      looking_for = (self === Dir ? '.' : path)
+      file = File.new(path)
+      `ls -ahlT #{path}`.split(&quot;\n&quot;).collect { |line| # itterate through each line of the ls results looking for our record
+        i = line.split(' ')
+        return {
+          :name         =&gt; i[9],
+          :permissions  =&gt; permissions_as_fixnum(i[0]), #sprintf(&quot;%o&quot;, File.stat(path).mode)[- 3..-1].to_i, 
+          :subordinates =&gt; i[1],  # Number of subordant object... directory contains at least: (. &amp; ..), file contains 1: its self
+          :owner        =&gt; i[2],
+          :group        =&gt; i[3],
+          :size         =&gt; i[4],
+          :modified     =&gt; file.mtime, # 5-8 will be time but its easier to use the File object to retrieve the modified &amp; mkdird times
+          :mkdird      =&gt; file.ctime 
+        } if looking_for == i[9] || Regexp.new(&quot;#{path} -&gt;&quot;) === &quot;#{i[9]} #{i[10]}&quot;
+      }.compact
+    rescue
+      {}
+    end
+    return {}
+  end
+
+
+  def concat(data)
+    if self === File
+      begin
+        File.open(path, 'a') { |f| f.print data }
+        self
+      rescue
+        raise FSO::IOError
+      end
+    else
+      raise FSO::IOError
+    end
+  end
+  alias_method :&lt;&lt;, :concat
+
+  # Writes a string with an appended newline to to a file.    
+  #
+  # Example:
+  #   f = FSO.new 'path/to/file'
+  #   f.read   #=&gt; &quot;Line: 0\nLine: 1\n&quot;
+  def writeln(data)
+    concat &quot;#{data.chomp}\n&quot;
+  end
+  
+  # Returns the entire file as a string.
+  #
+  # Example:
+  #   f = FSO.new 'path/to/file'
+  #   f.read   #=&gt; &quot;Line: 0\nLine: 1\n&quot;
+  def read
+    File.read(path) # documented in IO class
+  end
+
+  # Returns a line as a String or a range of lines as an Array.  Given a 10 line file, the first line would be 0 and 
+  # the last line would be 9. Represented as a range this would be: file.readln(0..9)
+  # 
+  # Examples:
+  #   f = FSO.new 'path/to/file'
+  #   f.readln 0   #=&gt; &quot;Line: 0&quot;
+  #   f.readln(0..2)   #=&gt; [&quot;Line: 0&quot;, &quot;Line: 1&quot;, &quot;Line: 2&quot;]
+  def readln(line)
+    if Fixnum === line
+      str = File.readlines(path)[line]
+      String === str ? str.chomp : str
+    elsif Range === line
+      File.readlines(path)[line.first, line.last+1].collect {|str| str.chomp if String === str}
+    end
+  end
+
+  def to_s
+    path
+  end
+
+  # Cute little trick that mkdirs a new instance of FSO given the args and sends it the requested method...
+  # 
+  # Example:
+  #   FSO.mkdir('/tmp/test', 755)  # calls =&gt; FSO.new('/tmp/test', 755).mkdir
+  def self.method_missing(mth, *args)
+    self.new(*args).send(mth)
+  end
+
+  # This breaks out of the FSO wrapper and allows access to the standard objects: File, Dir
+  def method_missing(mth, *args)
+    # this assumes that a path is the standard input... this is not very protected... need to check Dile &amp; Dir API's
+    args = [path] if args.empty?
+    
+    my_type = self.type
+    if my_type == File
+      File.send(mth, *args) if File.methods.include? mth.to_s
+    elsif my_type == Dir
+      Dir.send(mth, *args) if Dir.methods.include? mth.to_s
+    end
+    
+  end
+
+private
+  def system_to_boolean(str)
+    &quot;0\n&quot; == `#{str} &gt;&amp; /dev/null; echo $?`
+  end
+
+  def permissions_as_fixnum(permissions_string)
+    permissions_string.slice(1..9).gsub('--x','1').gsub('-w-','2').gsub('-rx','3').gsub('r--','4').gsub('r-x','5').gsub('rw-','6').gsub('rwx','7').to_i
+  end
+end
+
+
+
+# make the :new method optional...  appends the Kernel object.
+
+module Kernel
+  def FSO(*params)
+    ::FSO.new *params
+  end
+end
\ No newline at end of file</diff>
      <filename>lib/fads.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,223 @@
 require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
 
-describe &quot;Fads&quot; do
-  it &quot;fails&quot; do
-    fail &quot;hey buddy, you should probably rename this file and start specing for real&quot;
+describe 'FSO' do
+  before :all do
+    # Enable the following and set your password to test things that require sudo
+    # @sudo_passwd = 'SuperSecret'
+    @test_path = '/tmp/deleteme'
   end
+
+  before :each do
+    FSO.destroy! @test_path
+  end
+  
+  # it 'Reminder to remove sudo password from setup block' {pending{fail}}
+  
+  it 'should instantize' do
+    FSO.new('/tmp').should === Dir
+    FSO('/tmp').should === Dir  # Wow, nice loverly thing!
+                                # Thanks to the ability to extend the Kernel without a conflict in naming with constants!
+  end
+  
+  it 'should answer exists?' do
+    # test dir
+    FSO.exists?('/tmp/').should be_true
+    FSO.exists?('/tmp/not/here/ever/12345678900987654321/').should be_false
+    FSO.new('/tmp').exists?.should be_true
+    FSO.new('/tmp/not/here/ever/12345678900987654321/').exists?.should be_false
+    # test file
+    FSO.touch @test_path
+    FSO.exists?(@test_path).should be_true
+  end
+  
+  it 'should handle :mkdir and :destroy for files or folders' do
+    FSO.exists?(@test_path).should be_false
+    p = FSO.mkdir @test_path   # creates a dir
+    p.exists?.should be_true
+    FSO.mkdir(@test_path).should be_true   # dir already exists so mkdir is true
+    p.destroy!
+    p.exists?.should be_false
+  end
+  
+  it 'should handle :touch' do
+    f = FSO.touch @test_path
+    f.should === File
+    FSO.touch(@test_path).should be_true  # You should be able to touch existing files...
+    f.destroy!
+    
+    d = FSO.mkdir @test_path
+    FSO.touch(@test_path).should be_false
+  end
+  
+  it &quot;should respond to proprieties&quot; do
+    # for dir
+    d = FSO.new '/tmp'
+    d.proprieties[:group].should =~ /wheel|root/
+    # for file
+    f = FSO.touch @test_path
+    f.proprieties[:group].should =~ /wheel|root/
+  end
+  
+  it 'should handle :permissions permissions? permissions!' do
+    passwd = FSO.new('/etc/passwd')
+    passwd.permissions?.should === 644
+    
+    # for dir
+    d = FSO.new '/tmp'
+    d.permissions.should be_nil
+    d.permissions?.should === 755
+    Integer.should === d.permissions?
+    d = FSO.new '/tmp/not_real/'
+    d.permissions?.should be_nil
+    
+    # set permissions
+    d=FSO.new('~/delete_me_dir')
+    d.destroy!
+    d.mkdir
+    d.permissions?.should === 755
+    d.permissions!(777).should be_true
+    d.permissions?.should === 777
+    d.destroy!
+    d.mkdir
+    d.permissions!({:arguments =&gt; '-R'}, 777).should be_true  # test swapped attributes
+    d.permissions?.should === 777
+    d.destroy!
+    
+    # for file
+    f=FSO.touch '~/deleteme'
+    Integer.should === f.permissions?
+    f.permissions?.should_not == 777
+    f.permissions!(777).should be_true
+    f.permissions?.should == 777
+  end
+  
+  it 'should handle :owner, :owner?, &amp; :owner!' do
+    # for dir
+    my_user_name = `whoami`.chomp
+
+    d = FSO.new @test_path
+    d.destroy!
+    d.owner?.should be_nil
+    d.mkdir
+    d.owner?.should == my_user_name
+    new_owner = my_user_name
+    d.owner new_owner
+    d.owner!.should be_true
+    d.destroy!.should be_true
+    d.destroy!.should be_false
+    if @sudo_passwd
+      d.mkdir
+      new_owner = 'root'
+      d.owner new_owner
+      d.owner.should == new_owner
+      d.owner?.should == my_user_name
+      d.owner!( :sudo =&gt; @sudo_passwd ).should be_true
+      d.owner?.should == new_owner
+      d.destroy! :sudo =&gt; @sudo_passwd
+      d.owner!.should be_false
+    end
+    
+    # for file
+    f = FSO.touch @test_path
+    f.owner?.should == my_user_name
+    f.destroy!
+    if @sudo_password
+      f.touch
+      f.owner!('root', {:sudo=&gt; @sudo_password}).should be_true
+      f.owner?.should == 'root'
+      f.destroy!({:sudo=&gt; @sudo_password}).should be_true
+    end
+  end
+  
+  it &quot;should handle :group, :group?, &amp; :group!&quot; do
+    # for dir
+    d = FSO.new @test_path
+    d.destroy! # Ensure we have a clean slate!
+    d.mkdir
+    d.group.should be_nil
+    d.group?.should =~ /wheel|root/
+    d.group! 'staff'
+    d.group?.should == 'staff'
+    # the following cannot be done without superuser, but it works when provided a password
+    if @sudo_passwd
+      d.group = FSO.group?('/tmp')
+      d.group!('everyone', {:sudo =&gt; @sudo_passwd}).should be_true
+      d.group?.should == 'everyone'
+    end
+    d.destroy!.should be_true
+    
+    # for File
+    f = FSO.new @test_path
+    f.destroy!
+    f.touch
+    f.group?.should =~ /wheel|root/
+    
+    f.group!('everyone').should be_true
+    f.group?.should == 'everyone'
+  end
+  
+  it 'should inherit permissions' do
+    d = FSO.mkdir '/tmp/deleteme/'
+    d.group?.should == FSO.group?('/tmp')
+    d.destroy!
+    
+    f = FSO.touch @test_path
+    f.group?.should == FSO.group?('/tmp')
+  end
+  
+  it 'should know to_s' do
+    p=FSO.new @test_path
+    p.to_s.should == @test_path
+  end  
+  
+  it 'should be able to pass missing methods to the file &amp; dir objects' do
+    f = FSO.touch @test_path
+    f.executable?.should == false  # should turn into:  File.executable?(file_name) =&gt; true or false
+    pending do  
+      # need to double check the method_missing instance method of FSO... some asumptions are being made
+      fail
+    end
+  end
+  
+  it 'should be able to read &amp; write files' do
+    f = FSO.touch @test_path
+    f.concat 'First'
+    f &lt;&lt; ' test!'
+    f.read.should == &quot;First test!&quot;
+    f &lt;&lt; &quot;\nSecond line.&quot;
+    f.read.should == &quot;First test!\nSecond line.&quot;
+  end
+  
+  it 'should return self when writing to a file or raise an error' do
+    lambda { FSO(@test_path) &lt;&lt; 'hello' }.should raise_error(FSO::IOError)
+  end
+  
+  it 'should write by line' do
+    f = FSO.touch @test_path
+    f.writeln &quot;First&quot;
+    f.writeln(&quot;Second&quot;).should be_true
+    f.read.should == &quot;First\nSecond\n&quot;
+  end
+  
+  it 'should read lines by number' do
+    f = FSO.touch @test_path
+    (0..4).to_a.each {|i| f.writeln &quot;Line: #{i}&quot;}
+    f.readln(0).should == &quot;Line: 0&quot;
+    f.readln(4).should == &quot;Line: 4&quot;
+    # There are only lines 0 through 4... line 5 is non-existant and so returns nil.
+    f.readln(5).should be_nil
+  end
+  
+  it 'should read lines by range' do
+    f = FSO.touch @test_path
+    (0..3).to_a.each {|i| f.writeln &quot;Line: #{i}&quot;}
+    f.readln((0..2)).should == [&quot;Line: 0&quot;, &quot;Line: 1&quot;, &quot;Line: 2&quot;]
+    # Should not go beyond the limits of the file... the following is equal to read: 
+    #   beginning at the third line through the next hundred lines...
+    f.readln((2..100)).should == [&quot;Line: 2&quot;, &quot;Line: 3&quot;]
+  end
+  
+  # it 'should have a FSO::File class' do
+  #   FSO::File.greet.should == &quot;Hello from FSO::File&quot;
+  # end
 end</diff>
      <filename>spec/fads_spec.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>2be271a4cd22b445f792daff54014b348dbe89b1</id>
    </parent>
  </parents>
  <author>
    <name>Joshaven Potter</name>
    <email>yourtech@gmail.com</email>
  </author>
  <url>http://github.com/joshaven/fsds/commit/73effeb04a65a187052bd583046d7e322f91bcd5</url>
  <id>73effeb04a65a187052bd583046d7e322f91bcd5</id>
  <committed-date>2009-10-22T14:32:51-07:00</committed-date>
  <authored-date>2009-10-22T14:32:51-07:00</authored-date>
  <message>Merge FSO into FSDS</message>
  <tree>f93b5ec46f1ea4171931b062b90feea87e2c9db9</tree>
  <committer>
    <name>Joshaven Potter</name>
    <email>yourtech@gmail.com</email>
  </committer>
</commit>
