A Ruby module which provides the interface of IO objects to classes providing a few simple methods.
Ruby
Switch branches/tags
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
examples
lib/io
spec
.gitignore
CONTRIBUTORS Added Jarred to the contributors list Feb 22, 2009
GPL
HACKING
LEGAL Added modified IO specs from the rubyspec project Mar 10, 2009
LICENSE
LICENSE.rubyspec Added modified IO specs from the rubyspec project Mar 10, 2009
MANIFEST
NEWS
README
Rakefile
ruby.1.8.mspec Added magic encoding comment to all Ruby source files Mar 20, 2011
spec_helper.rb Added magic encoding comment to all Ruby source files Mar 20, 2011

README

= IO::Like - in the Likeness of IO

The IO::Like module provides all of the methods of typical IO implementations
such as File; most importantly the read, write, and seek series of methods.  A
class which includes IO::Like needs to provide only a few methods in order to
enable the higher level methods.  Buffering is automatically provided by default
for the methods which normally provide it in IO.

See the documentation for IO::Like for more details regarding the necessary
methods.


== License

Copyright © 2008,2009 Jeremy Bopp <jeremy at bopp dot net>

Licensed under the same terms as Ruby -- See the included LICENSE file for
details

Some parts licensed under the same terms as the rubyspec project -- See the
included LEGAL and LICENSE.rubyspec files for details


== Installation/Removal

Download the GEM file and install it with:
  % sudo gem install io-like-VERSION.gem

or directly with:
  % sudo gem install io-like

Removal is the same in either case:
  % sudo gem uninstall io-like


== Example
More examples can be found in the +examples+ directory of the source
distribution.

A simple ROT13 codec:
  gem 'io-like'  # Use require_gem for rubygems versions older than 0.9.0.
  require 'io/like'

  class ROT13Filter
    include IO::Like

    def self.open(delegate_io)
      filter = new(delegate_io)
      return filter unless block_given?

      begin
        yield(filter)
      ensure
        filter.close unless filter.closed?
      end
    end

    def initialize(delegate_io)
      @delegate_io = delegate_io
    end

    private

    def encode_rot13(string)
      result = string.dup
      0.upto(result.length) do |i|
        case result[i]
        when 65..90
          result[i] = (result[i] - 52) % 26 + 65
        when 97..122
          result[i] = (result[i] - 84) % 26 + 97
        end
      end
      result
    end

    def unbuffered_read(length)
      encode_rot13(@delegate_io.sysread(length))
    end

    def unbuffered_seek(offset, whence = IO::SEEK_SET)
      @delegate_io.sysseek(offset, whence)
    end

    def unbuffered_write(string)
      @delegate_io.syswrite(encode_rot13(string))
    end
  end

  File.open('normal_file.txt', 'w') do |f|
    f.puts('This is a test')
  end

  File.open('rot13_file.txt', 'w') do |f|
    ROT13Filter.open(f) do |rot13|
      rot13.puts('This is a test')
    end
  end

  File.open('normal_file.txt') do |f|
    ROT13Filter.open(f) do |rot13|
      puts(rot13.read)                      # -> Guvf vf n grfg
    end
  end

  File.open('rot13_file.txt') do |f|
    ROT13Filter.open(f) do |rot13|
      puts(rot13.read)                      # -> This is a test
    end
  end

  File.open('normal_file.txt') do |f|
    ROT13Filter.open(f) do |rot13|
      rot13.pos = 5
      puts(rot13.read)                      # -> vf n grfg
    end
  end

  File.open('rot13_file.txt') do |f|
    ROT13Filter.open(f) do |rot13|
      rot13.pos = 5
      puts(rot13.read)                      # -> is a test
    end
  end

  File.open('normal_file.txt') do |f|
    ROT13Filter.open(f) do |rot13|
      ROT13Filter.open(rot13) do |rot26|    # ;-)
        puts(rot26.read)                    # -> This is a test
      end
    end
  end


== Known Bugs/Limitations

1. Only versions 1.8.6 and 1.8.7 of Ruby's IO interface are implemented.
   Version 1.9.1 support is planned.
2. Ruby's finalization capabilities fall a bit short in a few respects, and as a
   result, it is impossible to cause the close, close_read, or close_write
   methods to be called automatically when an including class is garbage
   collected.  Define a class open method in the manner of File.open which
   guarantees that an appropriate close method will be called after executing a
   block.  Other than that, be diligent about calling the close methods.


== Contributing

Contributions for bug fixes, documentation, extensions, tests, etc. are
encouraged.  Please read the file HACKING for details.