October 2011 Archives

Perl and Dubstep

In the past year, I have come to quite like dubstep, a burgeoning electronic music genre. Perhaps this is a more interesting introduction than an article. Dubstep's current phase reminds me of generalized techno (mostly house & dance) during the mid-90's--a huge variety of styles, many small artists, much of it distributed through non-traditional channels. In the late 90's the distribution was via early filesharing networks, most notably Napster. For Dubstep, YouTube, Mixcloud, and Soundcloud seem to be the preferred ways of getting new tracks out.

To chronicle and share this growth of a genre, I started @DailyWub, a Twitter account that posts a new dubstep track every day. Being an engineer, I found the idea of manually keeping a queue and posting a track every day to be a dreadful task. For some time, the account has been powered by Buffer, a simple webapp that allows you to create a queue of tweets that are metered out at a schedule of your choosing. Buffer is ok, but they limit the queue to 10 tweets, and at some point started shortening URLs even when not needed, which breaks the YouTube thumbnails in many Twitter clients. Having a queue that is regularly plucked from and emitted to Twitter is a fairly simple operation, so I wrote my own program to do it--Net::Twitter::Queue.

Net::Twitter::Queue is a simple Perl module that employs Net::Twitter to do the heavy lifting. To use it, I have a queue of tweets in a file, tweets.yaml:

- Caspa - Where's My Money? http://www.youtube.com/watch?v=myZU2DZoD9w
- Skrillex - First Of The Year http://www.youtube.com/watch?v=2cXDgFwE13g
- Rusko - Everyday http://www.youtube.com/watch?v=xDAX2aVWAag

When run, Net::Twitter::Queue will remove the top item from that YAML file and post it to Twitter using the account information specified in config.yaml:

consumer_key: [consumer_key]
consumer_secret: [consumer_secret]
access_token: [access_token]
access_token_secret: [access_token_secret]

Where do those values come from? Two places: the consumer information is on the page for your application at dev.twitter.com (go ahead, make one!) and the access tokens are specific to the account you want to post as. To generate them, I used Twurl. With the consumer key & secret in hand, simply run Twurl:

Titus:~/$ twurl authorize --consumer-key [consumer_key] \
--consumer-secret [consumer_secret]

Twurl will respond with a URL that you can visit in a web browser, login to Twitter with the account you want to post as, and get a PIN back. Give the PIN to Twurl and it will complete the authentication process, saving the access token & associated secret in your ~/.twurlrc. Grab those two, toss them into config.yaml and run Net::Twitter::Queue from the directory that has config.yaml & tweets.yaml in it:

caligula:~/twitter/dailywub$ ls
config.yaml  tweets.yaml
caligula:~/twitter/dailywub$ perl -MNet::Twitter::Queue -e \
'$q=Net::Twitter::Queue->new->tweet'

Easy as that--the top entry in tweets.yaml has been popped and posted to Twitter.

Bookmark and Share

Creating a Perl Module in Modern Style

One of the very best things about Perl is CPAN, a repository of modules to do everything from browse the web to manipulating image files. CPAN provides a consistent method for installing modules (install cpanminus and then cpanm <Module::Name>) and the largest number of modules of all the scripting languages. More often than not, what you are trying to do has already been done and exists as a CPAN module. In the event you are doing something new, the best way to give back to the community and get free help is to encapsulate your work and distribute it as a module on CPAN.

Historically, creating a module suitable for general consumption was a confusing. Tutorials from years past abound, each one longer than the previous, and always employing a different toolchain, making synthesis of common concepts impossible. These days, however, things are much easier. In the past 6 years or so the Perl community has tried on a number of methods for building modules. The focus of this article will be a recent (circa late 2009...the Perl ecosystem takes a measured pace) build system, Dist::Zilla.

Whereas ExtUtils::MakeMaker and Module::Build are systems for building, testing, and installing a release, Dist::Zilla sits at a higher level. With Dist::Zilla, you create a single file that controls the build & test flow (using ExtUtils::MakeMaker under the hood) but also provide functionality for generating semi-boilerplate files (LICENSE, MANIFEST, META.yml) and releasing the code via CPAN. The configuration file, dist.ini, is easy-to-read and short in contrast to prior build systems.

To start using Dist::Zilla, install it using the standard CPAN shell command (cpan -i Dist::Zilla) or with cpanminus (cpanm Dist::Zilla). You utilize Dist::Zilla through the command dzil; if that's not in your path (which dzil), then you'll want to find it and symlink it somewhere useful or add it to your path. Global setup of dzil is done by invoking dzil setup and answering the questions it poses. With that done you can very easily mint a new distribution:

Titus:~/sandbox$ dzil new Number::Cruncher
[DZ] making target dir /Users/dinomite/Dropbox/sandbox/Number-Cruncher
[DZ] writing files to /Users/dinomite/Dropbox/sandbox/Number-Cruncher
[DZ] dist minted in ./Number-Cruncher

In the newly created Number-Cruncher directory you'll find a lib directory containing Number/Cruncher.pm and a dist.ini :

name    = Number-Cruncher
author  = Drew Stephens [drew@dinomite.net]
license = Perl_5
copyright_holder = Drew Stephens
copyright_year   = 2011

version = 0.001

[@Basic]

At this point, code and tests are the only things needed to have a Perl module. Here's some simple code for lib/Number/Cruncher.pm:

use strict;
use warnings;
package Number::Cruncher;

=head1 NAME

Number::Cruncher - crunch numbers

=cut

sub new {
    my $class = shift;
    my $self = {
        first => shift,
        second => shift,
    };
    bless $self, $class;
    return $self;
}

sub crunch {
    my $self = shift;
    return $self->{first} + $self->{second};
}

1;

And the associated test file that I created, t/number-cruncher.t:

#!/usr/bin/env perl
use strict;
use warnings;

use Test::More tests => 2;

BEGIN { use_ok 'Number::Cruncher'; }

my $first = 1;
my $second = 7;
my $cruncher = Number::Cruncher->new($first, $second);
ok (($first + $second) == $cruncher->crunch());

In three files--dist.ini, lib/Number/Cruncher.pm, and t/number-cruncher.t--we have a module. Run the test with dzil test and you'll see Dist::Zilla build your module into a temporary directory and run the test suite from there:

Titus:~/sandbox/Number-Cruncher$ dzil test
[DZ] building test distribution under .build/mgJsQhkFi6
[DZ] beginning to build Number-Cruncher
[DZ] guessing dist's main_module is lib/Number/Cruncher.pm
[DZ] extracting distribution abstract from lib/Number/Cruncher.pm
[DZ] writing Number-Cruncher in .build/mgJsQhkFi6
Checking if your kit is complete...
Looks good
Writing Makefile for Number::Cruncher
cp lib/Number/Cruncher.pm blib/lib/Number/Cruncher.pm
Manifying blib/man3/Number::Cruncher.3
PERL_DL_NONLAZY=1 /usr/local/Cellar/perl/5.12.3/bin/perl "-MExtUtils::Command::MM" "-e" "test_harness(0, 'blib/lib', 'blib/arch')" t/*.t
t/number-cruncher.t .. ok   
All tests successful.
Files=1, Tests=2,  0 wallclock secs ( 0.02 usr  0.01 sys +  0.02 cusr  0.00 csys =  0.05 CPU)
Result: PASS
[DZ] all's well; removing .build/mgJsQhkFi6

To build a distributable tarball, just run dzil build:

Titus:~/sandbox/Number-Cruncher$ dzil build
[DZ] beginning to build Number-Cruncher
[DZ] guessing dist's main_module is lib/Number/Cruncher.pm
[DZ] extracting distribution abstract from lib/Number/Cruncher.pm
[DZ] writing Number-Cruncher in Number-Cruncher-0.001
[DZ] building archive with Archive::Tar::Wrapper
[DZ] writing archive to Number-Cruncher-0.001.tar.gz
Titus:~/sandbox/Number-Cruncher$ ls Number-Cruncher-0.001*
Number-Cruncher-0.001.tar.gz

Number-Cruncher-0.001:
LICENSE     META.yml    README      lib
MANIFEST    Makefile.PL dist.ini    t

If you already have a PAUSE account, you can use dzil release to upload that tarball to PAUSE for inclusion in CPAN. If you haven't authored a Perl module before, request an account for uploading modules to CPAN. With PAUSE and Dist::Zilla, creating widely-available Perl modules is easy.

See Also

Bookmark and Share

About this Archive

This page is an archive of entries from October 2011 listed from newest to oldest.

May 2011 is the previous archive.

March 2012 is the next archive.

Find recent content on the main index or look in the archives to find all content.

Powered by Movable Type 5.1