Perl Lib Rant


By Donovan Jones

Sound familiar?

  • You are writing tools that need to be deployed to a bunch of servers or used by a distributed team
  • You find a module that seems to do what you want and its packaged for your distro
  • Then you find its missing something really basic that you want to do nearly every time you use the lib
  • You wonder why did he miss something so obvious, surely everyone wants that feature
  • Then you find an extension module to the first one that specifically adds the feature
  • The extension module is not packaged by distros

What do you do?

  • Use an xcpan shell (or make, make test, make install) and expect whoever wants to use your script to install the module themselves
  • Use dh-make-perl and distribute the package yourself
  • Go the python route and never use OS packages (aka Martyns solution)
  • Rewrite the functionality yourself and end up cut and pasting it whenever you want to use the functionality
  • Rewrite as a perl module which is deployed with the rest of your code

What did I do?

  • Rewrite the functionality myself and so far its only in one place
  • I promise to make a module as soon as I want to reuse it

What doe sit do?

./ -q --name
| content     |                    |
| created_on  | 2014-12-30T03:07:55.029624Z      |
| id          | 8d261ca383a0d80466eb2a4da9118be6 |
| locked      | 0                                |
| modified_on | 2014-12-30T09:11:45.412155Z      |
| name        |                      |
| proxiable   | 1                                |
| proxied     | 1                                |
| ttl         | 1                                |
| type        | CNAME                            |
| zone_id     | c3780704dbf4777fdb87690ac384978e |
| zone_name   |                          |

Because we need code examples


sub _display_record {
    my $self   = shift;
    my $record = shift;

    my $table;
    foreach my $key (sort keys %{ $record }) {
        next if $key eq 'meta';
        push @{ $table->{rows} }, [ $key, $record->{$key} ];
    print "Info for $record->{name}:\n";

Because we need code examples

More Code

sub _display_records {
    my $self    = shift;
    my $records = shift;

    my $table;
    push @{ $table->{header} }, (
        'Record ID',
    foreach my $record (@{ $records }) {
        push @{ $table->{rows} }, [
    $self->draw_table($table, 4, 80);

Because we need code examples

Even More Code

sub draw_table {
    my $self  = shift;
    my $table = shift;
    my $dex   = shift;
    my $width = shift;

    #my $table = {
    #    header => ['Foo', 'Bar', 'Baz'],
    #    rows   => [
    #        [1,2,3],
    #        [1,2,3],
    #        [1,2,3],
    #        [1,2,3],
    #        [1,2,3],
    #    ],

    # work out the column widths
    my @column_widths;

    my $head_index = 0;
    foreach my $heading (@{ $table->{header} }) {
        my $length = length $heading;
        $column_widths[$head_index] = $length unless defined $column_widths[$head_index];
        $column_widths[$head_index] = $length if $length > $column_widths[$head_index];

    foreach my $row (@{ $table->{rows} }) {
        my $col_index = 0;
        foreach my $col (@{ $row }) {
            my $length = length $col;
            $column_widths[$col_index] = $length unless defined $column_widths[$col_index];
            $column_widths[$col_index] = $length if $length > $column_widths[$col_index];

    # if we have a header replace the width with a headers and a width in an
    # array ref for Text::SimpleTable
    if ($head_index) {
        foreach my $index ( 0 .. ($head_index - 1) ) {
            if (defined $dex and $dex == $index) {
                $column_widths[$index] = [
                    ${ $table->{header} }[$index],
            else {
                $column_widths[$index] = [
                    ${ $table->{header} }[$index],

    my $t1 = Text::SimpleTable->new(@column_widths);
    foreach my $row (@{ $table->{rows} }) {
        $t1->row(@{ $row });
    print $t1->draw;

Because we need code examples

The offenders


Vertical Slides

Slides can be nested inside of each other.

Use the Space key to navigate through all slides.

Down arrow

Basement Level 1

Nested slides are useful for adding additional detail underneath a high level horizontal slide.

Basement Level 2

That's it, time to go back up.

Up arrow


Not a coder? Not a problem. There's a fully-featured visual editor for authoring these, try it out at

Point of View

Press ESC to enter the slide overview.

Hold down alt and click on any element to zoom in on it using zoom.js. Alt + click anywhere to zoom back out.

Touch Optimized

Presentations look great on touch devices, like mobile phones and tablets. Simply swipe through your slides.


Hit the next arrow...

... to step through ...

... a fragmented slide.

Fragment Styles

There's different types of fragments, like:








Transition Styles

You can select from different transitions, like:
None - Fade - Slide - Convex - Concave - Zoom


reveal.js comes with a few themes built in:
Black (default) - White - League - Sky - Beige - Simple
Serif - Night - Moon - Solarized

Slide Backgrounds

Set data-background="#dddddd" on a slide to change the background color. All CSS color formats are supported.

Down arrow

Image Backgrounds

<section data-background="image.png">

Tiled Backgrounds

<section data-background="image.png" data-background-repeat="repeat" data-background-size="100px">

Video Backgrounds

<section data-background-video="video.mp4,video.webm">

Background Transitions

Different background transitions are available via the backgroundTransition option. This one's called "zoom".

Reveal.configure({ backgroundTransition: 'zoom' })

Background Transitions

You can override background transitions per-slide.

<section data-background-transition="zoom">

Pretty Code

function linkify( selector ) {
  if( supports3DTransforms ) {

    var nodes = document.querySelectorAll( selector );

    for( var i = 0, len = nodes.length; i < len; i++ ) {
      var node = nodes[i];

      if( !node.className ) {
        node.className += ' roll';

Code syntax highlighting courtesy of highlight.js.

Marvelous List

  • No order here
  • Or here
  • Or here
  • Or here

Fantastic Ordered List

  1. One is smaller than...
  2. Two is smaller than...
  3. Three!

Tabular Tables

Item Value Quantity
Apples $1 7
Lemonade $2 18
Bread $3 2

Clever Quotes

These guys come in two forms, inline: “The nice thing about standards is that there are so many to choose from” and block:

“For years there has been a theory that millions of monkeys typing at random on millions of typewriters would reproduce the entire works of Shakespeare. The Internet has proven this theory to be untrue.”

Intergalactic Interconnections

You can link between slides internally, like this.

Speaker View

There's a speaker view. It includes a timer, preview of the upcoming slide as well as your speaker notes.

Press the S key to try it out.

Export to PDF

Presentations can be exported to PDF, here's an example:

Global State

Set data-state="something" on a slide and "something" will be added as a class to the document element when the slide is open. This lets you apply broader style changes, like switching the page background.

State Events

Additionally custom events can be triggered on a per slide basis by binding to the data-state name.

Reveal.addEventListener( 'customevent', function() {
	console.log( '"customevent" has fired' );
} );

Take a Moment

Press B or . on your keyboard to pause the presentation. This is helpful when you're on stage and want to take distracting slides off the screen.

Much more


- Try the online editor
- Source code & documentation