Dancer::Plugin::Adapter

Today's article introduces David Golden's new plugin, Dancer::Plugin::Adapter, designed to provide a clean DSL keyword to obtain a suitably configured instance of a class, in a similar way to, for example, the database keyword from Dancer::Plugin::Database.

The problem: you want to use some perl class in your Dancer app, but there's no plugin for it.

The solution: as long as the class needs only static data to construct an object, then Dancer::Plugin::Adapter can do the wrapping for you. Think of it as a "just-in-time" plugin (or maybe a poor-man's Bread::Board).

Here's an example: you want to send emails via Postmark using WWW::Postmark.

In your config.yml, you put this:

plugins:
  Adapter:
    postmark:
      class: WWW::Postmark
      options: POSTMARK_API_TEST

In your production config.yml, you can replace 'POSTMARK_API_TEST' with your real Postmark API key.

Then, in your application, here's how you use it:

get '/' => sub {
  eval {
    service("postmark")->send(
      from    => 'me@domain.tld',
      to      => 'you@domain.tld, them@domain.tld',
      subject => 'an email message',
      body    => "hi guys, what's up?"
    );
  };
 
  return $@ ? "Error: $@" : "Mail sent";
};

Dancer::Plugin::Adapter takes care of constructing and caching the WWW::Postmark object based on the configuration data, and lets you access the object with the service() function.

CONFIGURATION

One or more objects are defined by NAME => HASHREF pairs. The hash reference for each NAME must contain a 'class' key, whose value is the class to wrap.

If the hash reference contains an 'options' key, its value will be dereferenced (if it is a hash or array reference) and passed to new() when the object is created. Note that if the class requires a reference for the constructor, you have to wrap it in an extra array. E.g.

# config.yml:
plugins:
  Adapter:
    foo:
      class: Foo::Bar
      options:
        -
          wibble: wobble
          biff: boff
 
# constructor called as:
Foo::Bar->new( { wibble => wobble, biff => boff } );

If the class does not use 'new' as the name of its constructor, an alternate can be specified with the 'constructor' key.

# config.yml:
plugins:
  Adapter:
    tmpdir:
      class: File::Temp
      constructor: newdir
 
# constructor called as:
File::Temp->newdir()

USAGE

service

service($name);

This function returns the object corresponding to the name defined in the configuration file. The object is created on demand and cached for future use.

AUTHOR

David Golden (dagolden / xdg)