A concise mtime sorted directory listing application
Today we will focus on a simple task: listing the files contained in a directory, sort them by modification time (mtime) and display the result in a JSON array.
We are gonna use Mojo::File for the file system part and Mojolicious::Lite to expose those data on a simple but effective JSON API.
Prerequisites#
apt install libmojolicious-perl
touch mtime.pl && chmod +x mtime.pl
The code#
Our lite application is separated in two main parts:
- a helper, the
get_paths_by_ctime()method - an unique route that returns an array reference containing our file list
#!/usr/bin/env perl
# Automagically import Mojo::Base -base
use Mojolicious::Lite -signatures;
use Mojo::File 'path';
helper get_paths_by_mtime => sub {
my $files_list = path( '/tmp' )->list;
# Returns an array of Mojo::File
my @files = sort { $a->stat->mtime <=> $b->stat->mtime }
map { $_ } $files_list->each;
# Returns an array of paths sorted by modification date
return map { $_->realpath->to_string } @files;
};
get '/' => sub( $c ) {
$c->render( json => \$c->app->get_paths_by_mtime );
};
app->start;
Starting the app#
Mojolicious comes with the morbo HTTP and WebSocket development server
morbo mtime.pl
Server available at http://127.0.0.1:3000
If you visit this adress in your browser, it should display the list of files contained in the /tmp directory of your computer. On mine it returns:
[
"/tmp/sddm-:0-RweLaZ",
"/tmp/xauth-1000-_0",
"/tmp/cpan_install_3QQI.txt",
"/tmp/!home!sfeu!.emacs.d!savefile!ido.hist~",
"/tmp/!home!sfeu!.emacs.d!savefile!recentf~",
"/tmp/!home!sfeu!dev!processing-perl!etc!crontab~",
"/tmp/!home!sfeu!.emacs.d!personal!custom.el~",
"/tmp/!home!sfeu!dev!processing!.env~",
"/tmp/liste_desabonnement_20200218.csv",
"/tmp/!home!sfeu!dev!processing!.git!COMMIT_EDITMSG~",
"/tmp/!home!sfeu!scripts!mtime.pl~"
]
It is just a bunch of temporary files, mostly those I edit in my text editor. Note that the directories and special files (., ..) are not listed.
Releasing the power of Mojo::File#
Retrieving a list of files#
Mojolicious provide a lot of utilities that makes your Perl programmer life almost bearable. Note that Mojolicious needs zero dependencies, this is the reason it comes with a great toolkit for doing simple tasks. Mojo::File is one of those. Let’s see how to use it.
use Mojo::File 'path';
By using Mojo::File and loading it’s path function, you will be able to construct a Mojo::File object by passing it any kind of path:
my $files_list = path( '/tmp' )->list;
The list method called on a Mojo::File directory will return all files contained in this directory. The returned object is a Mojo::Collection object, an array-based container for collections.
Sorting the objects by modification date#
To read the following code, start by the end.
my @files = sort {
$a->stat->mtime <=> $b->stat->mtime
} $files_list->each;
- first, you return all the elements of the collection by using
each - it will return an array, that can be passed to
sort
sort is being passed a comparison function. In our case we will compare by mtime (modification time). The reason we can access to mtime from the array of Mojo::Files is that this module got it’s own stat method that returns itself a File::stat object for the path. This is where the magic happend!
Retrieving the files paths#
By using a simple map function and the Mojo::File chainedrealpath->to_string methods we will transform our array of objects to a simple array of strings:
return map { $_->realpath->to_string } @files;
The route#
The result of our helper is then rendered as JSON (must be passed to the front as an arrayref).
Making it even more concise#
Marcus Ramberg explained me how to make this even more concise by using Mojo::Collection->sort
The helper can be rewritten:
helper get_paths_by_mtime => sub {
return path( '/tmp' )->list
->sort( sub { $a->stat->mtime <=> $b->stat->mtime })
->map('realpath');
};
Conclusion#
The conciseness and readability of this program is quite surprising thanks to the effective tools used.
I hope you enjoyed reading this presentation and that it gave you the wish to use the formidable Mojolicious framework and it’s utilities.
Acknowledgments#
Thanks to Marcus Ramberg who read this, improved and simplified the code.