Squeak
  links to this page:    
View this PageEdit this PageUploads to this PageHistory of this PageTop of the SwikiRecent ChangesSearch the SwikiHelp Guide
Rio
Last updated at 6:55 pm UTC on 24 November 2008
A file IO interface inspired by http://rio.rubyforge.org , potentially replaces FileDirectory. See also: Rio-FileMan Comparison

Installation Notes

Package load order: Rio-Kernel, Rio-Grande, [Rio-Test, Rio-Debug]
The tests are written based upon the improved SUnit. see: SUnit for 3.10Keith Hodges

THIS PAGE NEEDS TO BE UPDATED

Rio = File Directory
asRio = asFile or asDirectory


Installer mantis ensureFix: 7219.
Installer ss project: 'Rio'; install: 'Rio-Kernel'; install: 'Rio-Grande'.


Rio Documentation

What is a Rio?

In its simplest form a Rio is a File/Directory reference. A Rio may be used to reference either files, directories, or other entities via url's. There is no requirement for the referenced item to exist in reality, since this can be ascertained later.

A Rio instance is a reference in relation to the system or container in which it resides, be it the 'RioLocalFileSystem', a remote ftp site, or a zip archive.

Once a Rio is obtained, it provides many functions for using, querying, or manipulating the item that it references and it is intended to be the main handle for using the referenced item.

Instantiating and Building Paths

The most concise method for creating a Rio is via: 1.below, the following are equivalent:
  1. 'myFile.txt' asFile
  2. Cwd / 'myFile.txt'
  3. Directory / 'myFile.txt'
  4. File new:'myFile.txt' - the verbose form
Rio's may be constucted using the #/ and #, operators like so.
Cwd / 'package-cache' / 'Rio-Core' , '-kph.20' , '.mcz'.

Deconstructing the Rio Path and File Name

Given myFile := Cwd / 'myFile.3.txt'.

Adjusting the Rio Path and File Name

Given myFile := Cwd / 'myFile.3.txt'.
(#parent: and #full: will set the path relative to the default directory).

File Versions Helpers

If there exists a file, Cwd / 'temp.4.txt'. Then there are some utilities for obtaining the latest and next version file rio's.

A Word About Style

Rio may be used in two distinct styles. In addition to the traditional smalltalk cascading messages style, Rio supports a sentence like 'sequential' style. Whenever an example below uses the 'sequential' style for conciseness, suffice to say there is a traditional equivalent.

sequential:
 'myFile.zip' asRio zip addAll: '/tmp/files' asRio all files

cascading:
 (Rio new: 'myFile) 
              setModeToZip;
              addAll: ((Rio new:'/tmp/files') 
                                  setModeToRecursive; 
                                  yourself) files;
              yourself.

Introducing Modes - 'Renaming' Mode

When a Rio is #setModeToRenaming, all of the above fileName and path manipulations are simultaneously actualized on disk. Below is an example using Rio's 'sequential' style for configuring modes:
When a mode is set using 'cascading' style, (e.g. #setModeToRenaming) the mode flag is set on the given instance as you would expect. In contrast, when a mode is set in sequential style, a new instance is created, making the mode setting temporary for the remainer of that 'sequential sentence'. This convention applies to all modes. e.g.

File Stat

All of the typical stat information about files and directories is directly obtainable from a Rio.

Directory Queries #select:ing

Internally the operating system provides the above stat data on entries of the parent directory. Rio implements many of its features by using one single function #select:. When #select: is performed upon a directory it traverses all of the directory entries collecting stat data. We can make use of this to perform a wide variety of directory queries.
Given myDir := Cwd / 'package-cache':

Directory Queries On Steroids aka. 'Recursive' Mode

Having explained how the world of directories, their entries and stats revolves around #select:, now is the time to announce one other little feature of #select: - it can perform its search recursively. All of the above queries become full tree searches with the addition of one little word: #recursively or #all (they are equivalent).

Essential Directory Operations

Reading and Writing Files - No Forcing

Obtaining a stream for reading and writing files without forcing a new file is as simple as this:

Reading and Writing - With Force.

One small modification to the above provides the equivalent of all of the #forceNewFileNamed: calls of old. (#assureNewFile is a synonym for #delete, but communicates different intent)

Copying Files - Introducing 'Binary' Mode

The basic file copying feature is implemented by a generic stream to stream copying function aPositionableStream-#copyTo:. The aim here being to eliminate many places where this, "copy from one stream to another stream via a buffer", code is duplicated. (e.g. GZReadStream-#saveContents:, GZWriteStream-compressFile: etc.) aPositionableStream-#copyTo: honours the setting of #binary mode on the input stream being copied. To make use of this Rio itself has a 'binary' mode of its own which is passed on to the streams that it uses for reading, writing and copying files.

Copying Files with Compression - Introducing Adaptors and 'GZip' Mode

'GZip' mode introduces a new Rio concept, Adaptors.

An adaptor is an additional protocol which is added to Rio as needed for a given mode. 'GZip' mode adds an adaptor that wraps the standard file readStream, and writeStreams with GZipReadStream, and GZipWriteStream respectively. Readers and writers can now be created directly onto compressed streams via the same API (note the binary setting is also honoured by compressed streams). This has additional benefits since, with the generic #copyTo: scheme (described above) in place, the act of (de)compressing files now becomes:
The GZip adaptor also adds some convenience methods to Rio as part of its protocol enabling the following:

Adding Files to an Existing Directory - The 'Dir' Adaptor

The 'Dir' Adaptor adds facilities for adding files, collections of files, or whole directory trees, into an existing directory.

Adding Files to Archives - The 'Archive' Adaptor.

The 'Archive' Adaptor is a specialisation of the 'Dir' adaptor, providing the exact same interface for copying files, selections of files, and directory trees into an archive file. Selecting #zip mode, sets the 'Archive' adaptor to generate a zip archive file. The zip file is not actually written until explicitly requested via a call to #commit, or the block form #commit:

Rio at Large

Rios may be compared for equality with other Rio's, or directly with Strings. Rios may be used in many situations where you would use Strings. For example, a Rio may be included directly in a String concatentation. Rios may be passed into, and obtained from the #name attribute of a StandardFileStream. To help with legacy integration, Rios may also be passed in to many of FileDirectory's standard public methods.


Nice Code

One of the things that leads you to think that you may be doing something right is when some task which others have made look difficult, becomes simple. Here are some of my favourites.

Rio-#entries

	^ self select: [:e | true ]


Equivalent to FileDirectory-#assureExistence and #assureExistenceOfPath:

aRioDir-#mkpath 
	self isDirectory ifTrue: [ ^self ].
	self parent mkpath.
	self executive createDirectory: self full value


Compare the method below and RioArchiveAdaptor-#add: aFileOrDir fromBase: aBaseDirectory 
to Archive-addTree: aFileNameOrDirectory removingFirstCharacters: n match: aBlock and friends.

aRio-linearRelativeTo: aDir
 
	value isEmpty ifTrue: [ ^ Rio new value: '/' ].
	self = aDirectory ifTrue: [ ^ Rio new: '' ].

	^ (self parent linearRelativeTo: aDirectory) / self fileName


aRio-#latestVersion

        ^ self copy base: nil version: (self versions last) ext: nil