atma-io

File / Directory Classes

Features:

  • File Class
  • Directory Class
  • File read/write Middleware
  • Sync + Async

In comparison to NodeJS sync-async contract: all functions with generic name are synchronous, and the **Async are asynchronous with the same interface and return deferred object. Sync versions never throw exceptions and are designed to be used in not performance critical applications, like bash scripts, etc.

This library is included into Atma.Toolkit, so creating custom scripts, you can use this API.

var file = new io.File('test.txt');

Path is always relative to the cwd (except windows os, when drive letter is used). To specify system absolute path, use file:// protocol.

Read file's content. If encoding is set to null raw Buffer is returned. For each read middleware pipeline is used, to skip it, set skipHooks to true.

var content = file.read( <?Object> {
    encoding: String | null, //> 'utf8' 
    skipHooks: Boolean //> false 
});
file
    .readAsync( <?Object> {
        encoding: String | null, //> 'utf8' 
        skipHooks: Boolean //> false 
    })
    .done(function(contentfile))
    .fail(function(error))
file.write(String | Buffer, <?Object>{
    skipHooks: Boolean
})
file
    .writeAsync(String | Buffer, <?Object>{
        skipHooks: Boolean
    })
    .done(function())
    .fail(function(error))
file.exists() //> Boolean; 
file.copyTo(<String> path) //> Boolean; 
file.copyToAsync(<String> path) //> Deferred; 
file.rename(<String> filename)
file.renameAsync(<String> filename) //> Deferred 
 
##### replace
Reads the content as string, replaces the matches and writes the result.
 
`@arguments`: same as for JavaScripts String `replace`.
 
`@return`: new content
```javascript
var str = file.replace('foo', 'bar');
file
    .replaceAsync('foo', 'bar')
    .done(function(newContent) {})
    .fail(function(error) {});
##### remove
```javascript
file.remove()
file.removeAsync() //> Deferred 
file.watch(callback)

Watch file for changes

file.unwatch(callback) //> Boolean; 

Each read will be cached. To control cache behaviour use next methods:

io.File.clearCache(<?String> path);

When path is null, then all cache is dropped.

io.File.disableCache();
io.File.disableCache();

There are some static methods, so that there is no need to initialize the File instance.

io.File[method] //> Function(filepath, [..args]) 
// methods: 
        'exists'
        'existsAsync'
        'read'
        'readAsync'
        'write'
        'writeAsync'
        'remove'
        'removeAsync',
        'replace',
        'replaceAsync',
        'rename'
        'renameAsync'
        'copyTo'
        'copyToAsync'
 
// sample 
io
    .File
    .readAsync('/baz.txt')
    .done(function(content){
        console.log(content);
    })
    .fail(function(error){
        console.error(error);
    })
    ;

Middleware pattern is used for all reads and writes. It can be used, for example, to compile coffee script to javascript on the fly. Or when reading *.yml file, the resulted content is not a YAML string, but already parsed object.

To get the idea, look at the hook definition sample:

io.File.registerExtensions({
    'coffee':[
        'conditions:read',
        'coffee-compiler:read',
        'uglify:write'
    ]
});

Each middleware has unique name and is registerd in this way:

io.File.middleware['coffee'] = {
    readfunction(<io.File> file, <Object> config){
        var coffee = require('coffee-script');
        file.content = coffee.compile(file.content);
    },
    writefunction(<io.File> file, <Object> config){
        // ... do smth with `content` before disk write 
    }
};
io
    .File
    .getHookHandler()
    .register({
        regexp: <RegExp>,
        method: <'read'|'write'>,
        handler: <Function | Object> handler,
        zIndex: <?Number> // default: 0 
    });

Path is matched by the regexp. The greater zIndex ist the later it is called in a pipeline, otherwise the handlers are called in the order they were registerd.

Lately will be converted into plugins, @see Plugins

  • read

    • coffee ( -> javascript )
    • markdown ( -> html )
    • jshint ( -> run jshint )
    • json ( -> JSON.parse is used )
    • yml ( -> YAML parser is used )
  • write

    • uglify ( -> Minify source before write)
    • cssmin ( -> Minify source before write)
    • yml ( -> Stringify object to yml string )
    • json ( -> Stringify object to json )

There additional read/write middlewares as atma plugins:

  • atma-loader-traceur - Traceur
  • atma-loader-less - Less

For example, you want to use Traceur middelware and jshint for reading js files: via javascript

io.File.registerExtensions({
    js: ['hint:read', 'atma-loader-traceur:read' /* ... */],
})

via package.json

...
"atma"{
    "settings" : {
        "io": {
            "extensions": {
                "js": [ "hint:read", "atma-loader-traceur:read" ]
            }
        }
    }
}

Define with RegExp a File Handler to completely override the read/write/exists/remove behaviour.

io
    .File
    .getFactory()
    .registerHandler(/defaults\.json$/i, Class({
        existsfunction(){
            return true;
        },
        readfunction(){
            return { foo: 'bar' };
        }
    }));
 
var dir = new io.Directory('src/');

Path is always relative to the cwd (except windows os, when drive letter is used). To specify system absolute path, use file:// protocol.

dir.exists()//> Boolean 
dir.existsAsync()//> Deferred 
dir.readFiles(<?String> pattern).files // Array<io.Files> 

Get list of all files in the directory. pattern is a glob pattern.

// all javascript files, also from sub-directories 
pattern = '*.js';
// only from base directory 
pattern = '/*.js'
// only from sub-directories 
pattern = '**/*.js'
 
dir.readFiles(pattern).files
dir
    .readFilesAsync(<?String> pattern)
    .done(function(files))
    .fail(function(error))

Copy files to destination directory. Before copying dir.readFiles can be called to copy only specific files.

dir.copyTo(<String> destination)
dir.copyToAsync(<String> destination) //> Deferred 
dir.rename(<String> folderName);
dir.renameAsync(<String> folderName) //> Deferred 

Removes all content recursively and the folder itself

dir.remove() //> Boolean 
dir.removeAsync()
dir.ensure()

Creates directory structure, if not already exists.

dir.ensureAsync()
dir.watch(callback)

Watch directory for changes

dir.unwatch(callback)

There are some static methods, so that there is no need to initialize the Directory instance.

io.Directory[method] //> Function(dirpath, [..args]) 
// methods: 
    'exists'
    'existsAsync'
    'readFiles'
    'readFilesAsync'
    'ensure'
    'ensureAsync'
    'remove'
    'removeAsync'
    'copyTo'
    'copyToAsync'
    
// sample 
io
    .Directory
    .readFilesAsync('sub/', '**.js')
    .done(function(files))
    .fail(function(error))

(c) MIT - Atma.js Project