Dist::Zilla ~~Minting Profiles~~ Blueprints
We've all been there. We fire up a text editor with the dreaded blank screen staring back at us and we start dutifully typing:
!#/usr/bin/perl
Oops. No wait. SHA-bang...
#!/usr/bin/perl
use strict;
use warnings;
use Carp;
# plus the other usual boilerplate
You've done it 100 times and 95 times you have throught to yourself "I really
need to automate this." If you consider yourself a decent Perl developer, you're
probably already using a templating system for kicking off a project or even
rolled your own. Maybe they're adequate but odds are you are really missing out
on what Dist::Zilla can offer.
Dist::Zilla has one of the most powerful, customizable module templating
systems available. Unfortunately, the official documentation refers to them as
minting profiles. We hate the name and think it's confusing. Presumably the
term's aim is to get us thinking about "minting" coins. In any case, we will
avoid using the official terminology where possible with the hope the analogy
we've invented to conceptualize how Dist::Zilla works catches on.
A Better Name Than "Minting Profiles"
Previously, we used the analogy of a "work area" and imagined the dzil new
command set up a new work area on your factory floor for forging your module.
Each time you issue the new command, you set up a new work area in a new
directory on your computer for creating and distributing a new module.
But it gets even better than that. You can control not just what your work area
will initially look like but what manufacturing process will be used to package
your module with a custom dist.ini file. This is a powerful feature of
Dist::Zilla that takes you well beyond what you can do with a more typical
distribution generation systems using plain templates.
None of this really sounds like what goes into stamping out nickels so...
...instead of "minting profiles," we encourage you to think of them instead as
"blueprints" to better capture the essence of what the new command does: it
sets up and configures your module and the processes that will work on it
according to a plan. Where we use the term "profile" below, mentally replace
it with "blueprint" instead. Of course, if we have you type in profile, make
sure you actually type in profile.
Creating Your First Factory Blueprint
You first need to esablish a storage area for your default blueprint. The
default blueprint is what's used unless we specify a custom blueprint with the
new command.
First, create a default directory in the special directory .dzil created for
for storing ~~profiles~~ blueprints:
mkdir ~/.dzil/profiles/default
Inside the default directory, create a profile.ini file (which we cannot call
blueprint.ini). The primary job of this file is to tell Dist::Zilla how to
establish your work area. The file works very similarly to how the dist.ini
file works. But instead of processing modules, it sets up the template for your
main module, generates other supporting files, if any, and assembles your
dist.ini file.
Create the following profile.ini file in the default directory:
[TemplateModule/:DefaultModuleMaker]
template = Module.pm
[DistINI]
append_file = dist_ini.txt
[GatherDir::Template]
root = skel
The profile.ini file has three sections, one for each plugin that we use. We
pass in one parameter to each plugin. Don't worry exactly what it all means just
yet. We will explain it all when the time comes.
Next add the file that will act as a template for your new module. Create a
file called Module.pm which, you'll notice, happens to be the name used for
the template parameter above. Add the following lines to the file:
package {{$name}};
use strict;
use warnings;
# Module implementation goes here
1;
=head1 NAME
{{$name}} - Add the module abstract here
Don't be concern yourself with the funny-looking curly brackes now–more on templates later.
Lastly, we are going to add the dist_ini.txt file to your blueprint, the file
mentioned in the [DistINI] section of your profile.ini configuration file.
Create the dist_ini.txt file and add the following lines to it, which should
look familiar to you:
[@Starter]
[ReadmeAnyFromPod]
type = markdown
filename = README.md
location = root
If you guessed that the contents of dist_ini.txt will end up inside your
dist.ini file, you guessed right.
You should now have three files in the default directory. Together, they
comprise your first factory blueprint. Let's see if you cut and paste everything
correctly. Do a cd ~/dzil_projects and try creating a new work area:
dzil new Super::Greetings
If you see a new Super-Greetings directory and Dist::Zilla didn't throw any
errors at you, congratulations, you've successfully ~~minted~~ drafted and
processed your first ~~profile~~ blueprint. If something went wrong, go back and
inspect your three blueprint files for errors and try again.
Exploring Your New Factory
Look inside your new work area and you'll see that your dist.ini has all the
plugins and parameters you supplied in your plugins.ini file. The global
configuration parameters at the top of of the dist.ini file were added for you
as well. You might also notice something missing, though. More on that in a bit.
Now open the lib directory where your module lives. Inside of that directory is
the Super directory and inside of that directory is a Greetings directory
and inside of that directory we finally see your Greetings.pm module file.
Dist::Zilla created this nested directory structure from the name of your
module, Super::Greetings. Sweet.
Everything seems to be in place. See if you can build a distribution with the blueprint:
dzil build
Oops, Zilla monster not happy:
[DZ] beginning to build Super-Greetings
[DZ] no version was ever set
[DZ] no version was ever set at inline delegation in Dist::Zilla for
logger->log_fatal (attribute declared in
/usr/local/share/perl/5.20.2/Dist/Zilla.pm at line 768) line 18.
Fixing Your Blueprint
It looks like your blueprint has a fatal flaw, thanks to our bad advice. What went wrong, exactly?
Remember back when you added the # ABSTRACT comment to your module in the very
first tutorial? We added that to give the installer software an esssential bit
of information it needs in order to work. But instead of adding an # ABSTRACT
comment into the module, your new blueprint kept the installer happy by
supplying the NAME section in your documentation that Dist::Zilla used to
generate the ABSTRACT our installer required. This way, your blueprint killed
two birds with one stone by giving your module some documenation and keeping the
installer happy.
Though your installer now has an abstract, it is now demanding that we feed it a
version. What's the best way to do that? One way is to edit the module and add a
version number there, similar to the way we added the # ABSTRACT comment. But
since we're using Dist::Zilla, we'll add in version = 0.001 directly to the
dist.ini because it's easy.
However, this doesn't fix the real source of the problem, your flawed blueprint.
So the next time we create a new module, we are going to run into the same
issue. So let's also be sure to fix the blueprint, too. Open the dist_ini.txt
file in the default profile and add the following line to the top of it:
version = 0.001
Once you've fixed up both files, try to build the distribution again. If you did everything right, Zilla monster will please you with a new distribution. Super duper!
OK, let's plow forward with our exploration of blueprints in the next section of the tutorial.