Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add optionnable sorting capability #2

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ node_modules
legacy
npm-debug.log
coverage
*.swp
/.project
/.*.md.html

21 changes: 18 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ with help of [filer](https://github.com/filerjs/filer "Node-like file system for
```js
const readify = require('readify');

radify('/', (error, data) => {
// basic
readify('/', (error, data) => {
console.log(data);
// output
{
Expand All @@ -45,12 +46,13 @@ radify('/', (error, data) => {
size: '4.22kb',
date: '20.02.2016',
owner: 'coderaiser',
mode: 'rw- rw- r--'
mode: 'rw- rw- r--',
}]
}
});

radify('/', 'raw', (error, data) => {
// raw output
readify('/', 'raw', (error, data) => {
console.log(data);
// output
{
Expand All @@ -64,6 +66,19 @@ radify('/', 'raw', (error, data) => {
}]
}
});

// sort output
// available sort option: name, size, owner, date
// available order option: asc, desc
readify('/', {sort: 'size', order: 'desc'}, (error, data) => {
console.log(data);
});

// all together
readify('/', {sort: 'size', order: 'desc', type: 'raw'}, (error, data) => {
console.log(data);
});

```

`browser` example:
Expand Down
81 changes: 67 additions & 14 deletions lib/readify.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,79 @@ const nicki = !WIN && !BROWSER && require('nicki/legacy');

const readdir = promisify(fs.readdir, fs);

// http://www.jstips.co/en/sorting-strings-with-accented-characters/
const sortFiles = sort((a, b) => {
return a.name.localeCompare(b.name);
/* sorting on Win and node v0.8.0 */
const sortFiles = currify((attr, order, array) => {
const cmpCallbacks = {
'numeric': (a, b) => (+a - +b),
// http://www.jstips.co/en/sorting-strings-with-accented-characters/
'local_string': (a, b) => a.localeCompare(b),
'default': (a, b) => (a > b ? 1 : -1),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What difference between default and numeric sorting?
What purpose of localeCompare? As I understand from mdn without locales argument it will work in the same way as default sorting.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not much, it enforces the numeric cast with the dir value. But since I've switched formatting it maybe useless now.

localCompare is for accents. I'm french and I deal with accentuated letters like é è ë ê. Those letters have the same rank than e. Standard comparison put them after z.

http://www.jstips.co/en/sorting-strings-with-accented-characters/

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

localCompare is for accents. I'm french and I deal with accentuated letters like é è ë ê.

That is interesting. Did not know about it.
Can you show me please how ls -lha sorts accents?

};
switch (order) {
case 'asc':
// nothing
break;
case 'desc':
// nothing
break;
default:
order = 'asc';
}
var cmp;
switch (attr) {
case 'size':
cmp = cmpCallbacks.numeric;
break;
case 'date':
cmp = cmpCallbacks['default'];
break;
case 'owner':
cmp = cmpCallbacks['default'];
break;
case 'name':
cmp = cmpCallbacks.local_string;
break;
default:
attr = 'name';
cmp = cmpCallbacks.local_string;
}
return sort((a, b) => {
var res = cmp(a[attr], b[attr]);
if (order === 'desc') {
res = -res;
}
return res;
}, array);
});
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think sort-by can be used for sorting. It can simplify code a little bit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not but no commit since 1 year ?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sort-on uses dot-prop which is es2015 (and it requires to up major version of all modules which uses readify and drop support of old node.js versions). Maybe you know other modules which does the same?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sort by seams very straightforward. We could fork it and write a backport with 'classic' attribute access.


const good = (f) => (...a) => f(null, ...a);

module.exports = readify;

function readify(path, type, fn) {
function readify(path, options, fn) {
if (!fn) {
fn = type;
type = '';
fn = options;
options = '';
}
if (typeof options !== 'object') {
options = {
type: options,
};
}
if (typeof options.sort === 'undefined') {
options.sort = '';
}
if (typeof options.order === 'undefined') {
options.order = '';
}
if (typeof options.type === 'undefined') {
options.type = '';
}

check(path, fn);

readdir(path)
.then(getAllStats(path, type))
.then(getAllStats(path, options))
.then(good(fn))
.catch(fn);
}
Expand All @@ -68,20 +122,20 @@ function check(path, callback) {
* @param path
* @param names
*/
function _getAllStats(path, type, names, callback) {
function _getAllStats(path, options, names, callback) {
const length = names.length;
const dir = format.addSlashToEnd(path);

if (!length)
return fillJSON(dir, [], type, callback);
return fillJSON(dir, [], options, callback);

const funcs = names.map((name) => {
return getStat(name, dir + name);
});

exec.parallel(funcs, (...args) => {
const files = args.slice(1);
fillJSON(dir, files, type, callback);
fillJSON(dir, files, options, callback);
});
}

Expand Down Expand Up @@ -144,16 +198,16 @@ function parseStat(type, stat) {
*
* @param params - { files, stats, path }
*/
function fillJSON(path, stats, type, callback) {
const processFiles = squad(changeOrder, sortFiles, parseAllStats(type));
function fillJSON(path, stats, options, callback) {
const processFiles = squad(changeOrder, parseAllStats(options.type), sortFiles(options.sort, options.order));
const json = {
path: '',
files: processFiles(stats)
};

json.path = format.addSlashToEnd(path);

if (type === 'raw')
if (options.type === 'raw')
return callback(null, json);

changeUIDToName(json, (error, files) => {
Expand Down Expand Up @@ -208,4 +262,3 @@ function replaceFromList(obj, prop, array) {
});
});
}

1 change: 1 addition & 0 deletions test/dir/1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
111
1 change: 1 addition & 0 deletions test/dir/2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2
1 change: 1 addition & 0 deletions test/dir/3.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
33
88 changes: 87 additions & 1 deletion test/readify.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,10 @@ test('readify: result: no owner', (t) => {
update();

readify('.', (error, result) => {
delete result.files[0].owner;
result.files = result.files.map(function(file) {
delete file.owner;
return file;
});
t.deepEqual(result, expected, 'should get raw values');

fs.readdir = readdir;
Expand Down Expand Up @@ -493,6 +496,89 @@ test('readify stat: error', (t) => {
});
});

test('readify sort: name asc', (t) => {
const files = [
'1.txt',
'2.txt',
'3.txt'
];

readify('./test/dir', {sort: 'name'}, (error, data) => {
t.notOk(error, 'no error');
data.files = data.files.map(function(file) {
return file.name;
});
t.deepEqual(data.files, files, 'correct order');
t.end();
});
});

test('readify sort: name desc', (t) => {
const files = [
'3.txt',
'2.txt',
'1.txt'
];

readify('./test/dir', {sort: 'name', order: 'desc'}, (error, data) => {
t.notOk(error, 'no error');
data.files = data.files.map(function(file) {
return file.name;
});
t.deepEqual(data.files, files, 'correct order');
t.end();
});
});

test('readify sort: size asc', (t) => {
const files = [
'2.txt',
'3.txt',
'1.txt'
];

readify('./test/dir', {sort: 'size', order: 'asc'}, (error, data) => {
t.notOk(error, 'no error');
data.files = data.files.map(function(file) {
return file.name;
});
t.deepEqual(data.files, files, 'correct order');
t.end();
});
});

test('readify sort: size asc raw', (t) => {
const files = [
'2.txt',
'3.txt',
'1.txt'
];

readify('./test/dir', {sort: 'size', type: 'raw'}, (error, data) => {
t.notOk(error, 'no error');
data.files = data.files.map(function(file) {
return file.name;
});
t.deepEqual(data.files, files, 'correct order');
t.end();
});
});

// no comment
test('readify sort: owner', (t) => {
readify('./test/dir', {sort: 'owner'}, (error) => {
t.notOk(error, 'no error');
t.end();
});
});

test('readify sort: date', (t) => {
readify('./test/dir', {sort: 'date'}, (error) => {
t.notOk(error, 'no error');
t.end();
});
});

test('browser: filer', (t) => {
const Filer = {
FileSystem: sinon.stub()
Expand Down