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.