Dist::Zilla - Maximum Overkill for CPAN Distributions
Upcoming SlideShare
Loading in...5
×
 

Dist::Zilla - Maximum Overkill for CPAN Distributions

on

  • 1,706 views

 

Statistics

Views

Total Views
1,706
Views on SlideShare
1,662
Embed Views
44

Actions

Likes
5
Downloads
18
Comments
0

1 Embed 44

http://blog.briang.org 44

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Dist::Zilla - Maximum Overkill for CPAN Distributions Dist::Zilla - Maximum Overkill for CPAN Distributions Presentation Transcript

    • Dist::Zilla raaaaaaaaar!Tuesday, December 14, 2010
    • What is Dist::Zilla?Tuesday, December 14, 2010This talk is about your life as a CPAN author.
    • AWESOMETuesday, December 14, 2010
    • Any Questions?Tuesday, December 14, 2010
    • RJBSTuesday, December 14, 2010ME!!!also awesome!I give away almost all my useful software on CPAN
    • RJBS - cake and pie (and doughnuts)Tuesday, December 14, 2010ME!!!also awesome!I give away almost all my useful software on CPAN
    • RJBS - cake and pie (and doughnuts) - cocktails and beerTuesday, December 14, 2010ME!!!also awesome!I give away almost all my useful software on CPAN
    • RJBS - cake and pie (and doughnuts) - cocktails and beer - shooting zombiesTuesday, December 14, 2010ME!!!also awesome!I give away almost all my useful software on CPAN
    • RJBS - cake and pie (and doughnuts) - cocktails and beer - shooting zombies - giving away useful softwareTuesday, December 14, 2010ME!!!also awesome!I give away almost all my useful software on CPAN
    • CPAN!Tuesday, December 14, 2010CPAN is awesome, too. We all know that.
    • being a CPAN author is hard! let’s go gemming!Tuesday, December 14, 2010who here is a CPAN author?what makes it a pain? let’s talk about it
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010this is all the crap in your working copy where you write this distmaking all these is a boring pain in the butt
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010and a bunch of semi-structured data is in Makefile.PL
    • ExtUtils::MakeMakerTuesday, December 14, 2010
    • WriteMakefile( NAME => ‘YourApp’, AUTHOR => ‘You <rjbs@cpan.org>’, VERSION_FROM => ‘lib/YourApp.pm’, ABSTRACT_FROM => ‘lib/YourApp.pm’, LICENSE => ‘perl’, PREREQ_PM => { ‘Lingua::EN::Inflect’ => 1.86, ‘Sub::Override’ => 0.07, ‘Test::More’ => 0, }, );Tuesday, December 14, 2010Then you have to put a bunch more information describing your distribution into Makefile.PL, if you’re usingExtUtils::MakeMaker.
    • WriteMakefile( NAME => ‘YourApp’, AUTHOR => ‘You <rjbs@cpan.org>’, VERSION_FROM => ‘lib/YourApp.pm’, ABSTRACT_FROM => ‘lib/YourApp.pm’, LICENSE => ‘perl’, PREREQ_PM => { ‘Lingua::EN::Inflect’ => 1.86, ‘Sub::Override’ => 0.07, ‘Test::More’ => 0, }, (eval { ExtUtils::MakeMaker->VERSION(6.46) } ? (META_MERGE => { resources => { Repository => ‘...’ } }) : ()), );Tuesday, December 14, 2010If you want to add more metadata, you start having to use really gross constructions, trying to avoid backcompat issues. In part,this is because even the data only needed for installing the dist (like your respository) is present and executed on the installinguser’s computer.
    • Module::InstallTuesday, December 14, 2010
    • use inc::Module::Install; all_from(‘lib/YourApp.pm’); requires(‘Lingua::EN::Inflect’ => 1.86); requires(‘Sub::Override’ => 0.07); requires(‘Test::More’ => 0); repository(...); WriteAll();Tuesday, December 14, 2010Module::Install lets you write this, instead. It does a lot more auto-detection by reading your Pod and trying to parse itsmeaning. Then it runs on the installer’s machine and uses the machinery of ExtUtils::MakeMaker to build a plain old Makefile forinstallation. So, it bundles itself with each dist that uses it, and it’s still beholden to the version of EUMM installed on the user’smachine. Still, it saves quite a lot of time in dealing with stupid crap in Makefile.PL.It just means you need to write a bunch of other stuff for it to scan, like:
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010You need to have your author in the main module to be detected, and the license. Then, because you want to keep the data ineach library, you have to keep that same data in each Perl module. Copy and paste!
    • Module::StarterTuesday, December 14, 2010
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/boilerplate.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010It can create all these files, Pod and all, *for* you so you don’t have to go through this drudgery. Unfortunately, some of thesefiles include stuff that you’re going to need to customize, replace, or delete immediately upon starting the dist. So many peopleused Module::Starter and then left in garbage data that we added a test to help stop them from doing so...
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/boilerplate.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010It looks for the stock content you should get rid of. Once this test passes, you are expected to delete it. Why have thatboilerplate crap at all?Worse, what if one of your boilerplate files has a typo? Or what if you want to change your default pod-coverage setup? Youneed to go update every file in all of your distributions, because that file actually exists in your source repository.
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010Dist::Zilla tries to solve all these problems: don’t repeat yourself; don’t store what you can compute; rely on the installing userhaving only the bare minimum of tools needed to install, and don’t bundle more if you can help it.It also tries hard to be easy to test, so that when you write extensions to DZ, they’re easy to write and easy to test. EUMM, M:I,and Starter are not.I’m going to show you how to eliminate as much of this as you can so there’s less to write, less to update, less to diff, and lessto think about in general.
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010(files we can get rid of entirely)
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010(files we can get rid of entirely)
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010(files we can get rid of entirely)
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010(files we can get rid of entirely)
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010(files we can get rid of entirely)
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010(files we can get rid of entirely)
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010(files we can get rid of entirely)
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010(files we can get rid of entirely)
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010(files we can get rid of entirely)
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010(files we can get rid of entirely)
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010(files we can get rid of entirely)
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010(files we can get rid of entirely)
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010(files from which we can prune lots of non-essential content)...and it can do more than just reduce the on-disk content...
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010(files from which we can prune lots of non-essential content)...and it can do more than just reduce the on-disk content...
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010(files from which we can prune lots of non-essential content)...and it can do more than just reduce the on-disk content...
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010(files from which we can prune lots of non-essential content)...and it can do more than just reduce the on-disk content...
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010(files from which we can prune lots of non-essential content)...and it can do more than just reduce the on-disk content...
    • ./Changes ./LICENSE ./MANIFEST.SKIP ./Makefile.PL ./README ./lib/YourApp.pm ./lib/YourApp/Reticulator.pm ./lib/YourApp/Util/mtfnpy.pm ./lib/YourApp/Xyzzy.pm ./t/unit-tests.t ./t/pod-coverage.t ./t/pod.tTuesday, December 14, 2010(files from which we can prune lots of non-essential content)...and it can do more than just reduce the on-disk content...
    • Tuesday, December 14, 2010...and that’s why
    • - updating version numbersTuesday, December 14, 2010...and that’s why
    • - updating version numbers - uploading to CPANTuesday, December 14, 2010...and that’s why
    • - updating version numbers - uploading to CPAN - committing, tagging releases in Git (VCS)Tuesday, December 14, 2010...and that’s why
    • - updating version numbers - uploading to CPAN - committing, tagging releases in Git (VCS) - determine prerequisitesTuesday, December 14, 2010...and that’s why
    • - updating version numbers - uploading to CPAN - committing, tagging releases in Git (VCS) - determine prerequisites - other stuff that is totally boringTuesday, December 14, 2010...and that’s why
    • Dist::Zilla is AWESOMETuesday, December 14, 2010...because it frees you up to do things that are much more interesting than distribution building, like...
    • Tuesday, December 14, 2010
    • - eating cake and pie (and donuts)Tuesday, December 14, 2010
    • - eating cake and pie (and donuts) - drinking cocktails and beerTuesday, December 14, 2010
    • - eating cake and pie (and donuts) - drinking cocktails and beer - shooting zombiesTuesday, December 14, 2010
    • - eating cake and pie (and donuts) - drinking cocktails and beer - shooting zombies - giving away useful softwareTuesday, December 14, 2010
    • Dist::Zilla is HUGETuesday, December 14, 2010
    • 106 prereqsTuesday, December 14, 2010
    • 106 prereqs (and counting)Tuesday, December 14, 2010
    • Tuesday, December 14, 2010
    • - Dist::Zilla only handles “make dist”Tuesday, December 14, 2010
    • - Dist::Zilla only handles “make dist” - it doesn’t handle “make install”Tuesday, December 14, 2010
    • - Dist::Zilla only handles “make dist” - it doesn’t handle “make install” - only authors need to install the 106 prereqsTuesday, December 14, 2010
    • - Dist::Zilla only handles “make dist” - it doesn’t handle “make install” - only authors need to install the 106 prereqs - your users don’t see Dist::ZillaTuesday, December 14, 2010
    • - Dist::Zilla only handles “make dist” - it doesn’t handle “make install” - only authors need to install the 106 prereqs - your users don’t see Dist::Zilla - they just see MakeMaker or Module::BuildTuesday, December 14, 2010
    • Dist::Zilla is also StupidTuesday, December 14, 2010like me!
    • It keeps its brains in plugins.Tuesday, December 14, 2010Almost all of the remainder of this talk is going to be about DZ plugins, because they do all the work. DZ itself just orchestratesthe interaction of plugins. When you use Dist::Zilla, you provide it with a configuration file that sets up your plugins.
    • dist.iniTuesday, December 14, 2010It’s almost always an INI file. INI is a nice simple format, and I’m going to just assume everybody understands it. Here’s asample dist.ini:
    • name = Your-Dist license = Perl_5 copyright_holder = J.builds a dist: # How Dist::Zilla Fred Bloggs [GatherDir] prepare; include_dotfiles = 1 gather_files; prune_files; [PruneCruft] munge_files; [MetaYAML] [MakeMaker] register_prereqs; [TestRelease] setup_installer; [ConfirmRelease] write_files; finish; [UploadToCPAN] user = JFB password = QwardRulesTuesday, December 14, 2010You can do lots of different things in really varied ways, and there are people who use Dist::Zilla with very different workflows tomine.But I’m going to talk about how I use Dist::Zilla, which by grand coincidence is the one reflected in the tutorial and is probablythe most common workflow.
    • name = Your-Dist license = Perl_5 copyright_holder = J.builds a dist: # How Dist::Zilla Fred Bloggs [GatherDir] prepare; include_dotfiles = 1 gather_files; prune_files; [PruneCruft] munge_files; [MetaYAML] [MakeMaker] register_prereqs; [TestRelease] setup_installer; [ConfirmRelease] write_files; finish; [UploadToCPAN] user = JFB password = QwardRulesTuesday, December 14, 2010the root section generally describes the dist itself, and is pretty short
    • name = Your-Dist license = Perl_5 copyright_holder = J.builds a dist: # How Dist::Zilla Fred Bloggs [GatherDir] prepare; include_dotfiles = 1 gather_files; prune_files; [PruneCruft] munge_files; [MetaYAML] [MakeMaker] register_prereqs; [TestRelease] setup_installer; [ConfirmRelease] write_files; finish; [UploadToCPAN] user = JFB password = QwardRulesTuesday, December 14, 2010here’s a section that defined a plugin, with one option set
    • name = Your-Dist license = Perl_5 copyright_holder = J.builds a dist: # How Dist::Zilla Fred Bloggs [GatherDir] prepare; include_dotfiles = 1 gather_files; prune_files; [PruneCruft] munge_files; [MetaYAML] [MakeMaker] register_prereqs; [TestRelease] setup_installer; [ConfirmRelease] write_files; finish; [UploadToCPAN] user = JFB password = QwardRulesTuesday, December 14, 2010and this line sets up a plugin with no args -- the next line is just another plugin
    • name = Dist-Zilla author = Ricardo SIGNES <rjbs@cpan.org> license = Perl_5 copyright_holder = Ricardo SIGNES [@Basic] [AutoPrereq] [AutoVersion] [PkgVersion] [MetaConfig] [MetaJSON] [NextRelease] [PodSyntaxTests] [Repository] [PodWeaver] [@Git]Tuesday, December 14, 2010RJBS: THESE THREE SLIDES ARE A SPEED RUN; detailed version to follow immediately
    • name = Dist-Zilla author = Ricardo SIGNES <rjbs@cpan.org> license = Perl_5 copyright_holder = Ricardo SIGNES [@Basic] [AutoPrereq] [AutoVersion] [PkgVersion] [MetaConfig] [MetaJSON] [NextRelease] [PodSyntaxTests] [Repository] [PodWeaver] [@Git]Tuesday, December 14, 2010@Basic means a bundle, and that bundle expands to this:
    • [GatherDir] [PruneCruft] [ManifestSkip] [MetaYAML] [License] [Readme] [ExtraTests] [ExecDir] [ShareDir] [MakeMaker] [Manifest] [TestRelease] [ConfirmRelease] [UploadToCPAN]Tuesday, December 14, 2010
    • name = Dist-Zilla author = Ricardo SIGNES <rjbs@cpan.org> license = Perl_5 copyright_holder = Ricardo SIGNES [@Basic] [AutoPrereq] [AutoVersion] [PkgVersion] [MetaConfig] [MetaJSON] [NextRelease] [PodSyntaxTests] [Repository] [PodWeaver] [@Git]Tuesday, December 14, 2010
    • Too much!Tuesday, December 14, 2010
    • Tuesday, December 14, 2010test is just build then “make test”install is just build then “cpan .”release is just build, then cpan-upload (mostly)
    • dzil buildTuesday, December 14, 2010test is just build then “make test”install is just build then “cpan .”release is just build, then cpan-upload (mostly)
    • dzil build dzil testTuesday, December 14, 2010test is just build then “make test”install is just build then “cpan .”release is just build, then cpan-upload (mostly)
    • dzil build dzil test dzil installTuesday, December 14, 2010test is just build then “make test”install is just build then “cpan .”release is just build, then cpan-upload (mostly)
    • dzil build dzil test dzil install dzil releaseTuesday, December 14, 2010test is just build then “make test”install is just build then “cpan .”release is just build, then cpan-upload (mostly)
    • How Dist::Zilla BuildsTuesday, December 14, 2010this is, obviously, a simplification -- but not as great a simplification as you might thinkto make any of these lines do anything useful, you need plugins; plugins contribute to these activities
    • How Dist::Zilla Builds sub build {Tuesday, December 14, 2010this is, obviously, a simplification -- but not as great a simplification as you might thinkto make any of these lines do anything useful, you need plugins; plugins contribute to these activities
    • How Dist::Zilla Builds sub build { my ($self) = @_;Tuesday, December 14, 2010this is, obviously, a simplification -- but not as great a simplification as you might thinkto make any of these lines do anything useful, you need plugins; plugins contribute to these activities
    • How Dist::Zilla Builds sub build { my ($self) = @_; my @files = $self->gather_files;Tuesday, December 14, 2010this is, obviously, a simplification -- but not as great a simplification as you might thinkto make any of these lines do anything useful, you need plugins; plugins contribute to these activities
    • How Dist::Zilla Builds sub build { my ($self) = @_; my @files = $self->gather_files; $self->munge_files( @files );Tuesday, December 14, 2010this is, obviously, a simplification -- but not as great a simplification as you might thinkto make any of these lines do anything useful, you need plugins; plugins contribute to these activities
    • How Dist::Zilla Builds sub build { my ($self) = @_; my @files = $self->gather_files; $self->munge_files( @files ); $self->collect_metadata;Tuesday, December 14, 2010this is, obviously, a simplification -- but not as great a simplification as you might thinkto make any of these lines do anything useful, you need plugins; plugins contribute to these activities
    • How Dist::Zilla Builds sub build { my ($self) = @_; my @files = $self->gather_files; $self->munge_files( @files ); $self->collect_metadata; $self->write_out( @files );Tuesday, December 14, 2010this is, obviously, a simplification -- but not as great a simplification as you might thinkto make any of these lines do anything useful, you need plugins; plugins contribute to these activities
    • How Dist::Zilla Builds sub build { my ($self) = @_; my @files = $self->gather_files; $self->munge_files( @files ); $self->collect_metadata; $self->write_out( @files ); }Tuesday, December 14, 2010this is, obviously, a simplification -- but not as great a simplification as you might thinkto make any of these lines do anything useful, you need plugins; plugins contribute to these activities
    • How do you pick plugins?Tuesday, December 14, 2010
    • There is no default config.Tuesday, December 14, 2010
    • @BasicTuesday, December 14, 2010...but don’t just rush to use @Basic without understanding it. You should understand what DZ is doing so that you canunderstand what goes wrong, if anything goes wrong -- and something will go wrong.There is *no* default configuration for Dist::Zilla. The @Basic bundle exists as a useful starting point, but I doubt anybodywould use only @Basic. There’s just too much that you can gain by adding on top of it.
    • The Basics [GatherDir] [PruneCruft] [Manifest] [ManifestSkip] [MakeMaker] [License] [Readme] [MetaYAML] [ExtraTests] [ExecDir] [ShareDir] [TestRelease] [ConfirmRelease] [UploadToCPAN]Tuesday, December 14, 2010@Basic’s goal is to do all the stuff almost everyone wants, and to let you delete files you don’t need, but @Basic will *not* touchany of your files on disk.
    • The Basics [GatherDir] [PruneCruft] [Manifest] [ManifestSkip] [MakeMaker] MANIFEST [License] [Readme] [MetaYAML] [ExtraTests] [ExecDir] [ShareDir] [TestRelease] [ConfirmRelease] [UploadToCPAN]Tuesday, December 14, 2010@Basic’s goal is to do all the stuff almost everyone wants, and to let you delete files you don’t need, but @Basic will *not* touchany of your files on disk.
    • The Basics [GatherDir] [PruneCruft] [Manifest] [ManifestSkip] [MakeMaker] MANIFEST [License] Makefile.PL [Readme] [MetaYAML] [ExtraTests] [ExecDir] [ShareDir] [TestRelease] [ConfirmRelease] [UploadToCPAN]Tuesday, December 14, 2010@Basic’s goal is to do all the stuff almost everyone wants, and to let you delete files you don’t need, but @Basic will *not* touchany of your files on disk.
    • The Basics [GatherDir] [PruneCruft] [Manifest] [ManifestSkip] [MakeMaker] MANIFEST [License] Makefile.PL [Readme] LICENSE [MetaYAML] [ExtraTests] [ExecDir] [ShareDir] [TestRelease] [ConfirmRelease] [UploadToCPAN]Tuesday, December 14, 2010@Basic’s goal is to do all the stuff almost everyone wants, and to let you delete files you don’t need, but @Basic will *not* touchany of your files on disk.
    • The Basics [GatherDir] [PruneCruft] [Manifest] [ManifestSkip] [MakeMaker] MANIFEST [License] Makefile.PL [Readme] LICENSE [MetaYAML] README [ExtraTests] [ExecDir] [ShareDir] [TestRelease] [ConfirmRelease] [UploadToCPAN]Tuesday, December 14, 2010@Basic’s goal is to do all the stuff almost everyone wants, and to let you delete files you don’t need, but @Basic will *not* touchany of your files on disk.
    • The Basics [GatherDir] [PruneCruft] [Manifest] [ManifestSkip] [MakeMaker] MANIFEST [License] Makefile.PL [Readme] LICENSE [MetaYAML] README [ExtraTests] META.yml [ExecDir] [ShareDir] [TestRelease] [ConfirmRelease] [UploadToCPAN]Tuesday, December 14, 2010@Basic’s goal is to do all the stuff almost everyone wants, and to let you delete files you don’t need, but @Basic will *not* touchany of your files on disk.
    • Cruft MinimizersTuesday, December 14, 2010
    • Cruft Minimizers [PkgVersion]Tuesday, December 14, 2010
    • Cruft Minimizers [PkgVersion] [PodSyntaxTests]Tuesday, December 14, 2010
    • Cruft Minimizers [PkgVersion] [PodSyntaxTests] [PodCoverageTests]Tuesday, December 14, 2010
    • Cruft Minimizers [PkgVersion] [PodSyntaxTests] [PodCoverageTests] [AutoPrereq]Tuesday, December 14, 2010
    • Cruft Minimizers [PkgVersion] [PodSyntaxTests] [PodCoverageTests] [AutoPrereq] [AutoVersion]Tuesday, December 14, 2010
    • Cruft Minimizers [PkgVersion] [PodSyntaxTests] [PodCoverageTests] [AutoPrereq] [AutoVersion] [NextRelease]Tuesday, December 14, 2010
    • Version Control [@Git] [@Subversion] [@Mercurial] [@SVK]Tuesday, December 14, 2010this is a place where it *might* be reasonable to use a bundle when you start
    • Pod::WeaverTuesday, December 14, 2010
    • package YourApp; =head1 NAME YourApp - my awesome app =head1 VERSION version 1.001 =cut our $VERSION = 0.001; =head1 DESCRIPTION This app is awesome. =head1 METHODS =head2 this_method This method does stuff. =cut method this_method { ... } =head2 that_method Also stuff. =cut method that_method { ... } =head1 AUTHOR Margo Yapp <myapp@example.com> =head1 LICENSE Copyright (C) 2008, Margo Yapp. This is distributed under the terms of the accidental death and dismemberment license and if you redistribuet this document you will be “accidentally” deathed or dismembered. You have been told. =cut 1;Tuesday, December 14, 2010Here’s a .pm file
    • package YourApp; =head1 NAME YourApp - my awesome app =head1 VERSION version 1.001 =cut our $VERSION = 0.001; =head1 DESCRIPTION This app is awesome. =head1 METHODS =head2 this_method This method does stuff. =cut method this_method { ... } =head2 that_method Also stuff. =cut method that_method { ... } =head1 AUTHOR Margo Yapp <myapp@example.com> =head1 LICENSE Copyright (C) 2008, Margo Yapp. This is distributed under the terms of the accidental death and dismemberment license and if you redistribuet this document you will be “accidentally” deathed or dismembered. You have been told. =cut 1;Tuesday, December 14, 2010Here’s a .pm file
    • package YourApp; =head1 NAME YourApp - my awesome app =head1 VERSION version 1.001 =cut our $VERSION = 0.001; =head1 DESCRIPTION This app is awesome. =head1 METHODS =head2 this_method This method does stuff. =cut method this_method { ... } =head2 that_method Also stuff. =cut method that_method { ... } =head1 AUTHOR Margo Yapp <myapp@example.com> =head1 LICENSE Copyright (C) 2008, Margo Yapp. This is distributed under the terms of the accidental death and dismemberment license and if you redistribuet this document you will be “accidentally” deathed or dismembered. You have been told. =cut 1;Tuesday, December 14, 2010The =name section is annoying.
    • package YourApp; # ABSTRACT: my awesome app =head1 VERSION version 1.001 =cut our $VERSION = 0.001; =head1 DESCRIPTION This app is awesome. =head1 METHODS =head2 this_method This method does stuff. =cut method this_method { ... } =head2 that_method Also stuff. =cut method that_method { ... } =head1 AUTHOR Margo Yapp <myapp@example.com> =head1 LICENSE Copyright (C) 2008, Margo Yapp. This is distributed under the terms of the accidental death and dismemberment license and if you redistribuet this document you will be “accidentally” deathed or dismembered. You have been told. =cut 1;Tuesday, December 14, 2010We’ll replace it with a comment.
    • package YourApp; # ABSTRACT: my awesome app =head1 VERSION version 1.001 =cut our $VERSION = 0.001; =head1 DESCRIPTION This app is awesome. =head1 METHODS =head2 this_method This method does stuff. =cut method this_method { ... } =head2 that_method Also stuff. =cut method that_method { ... } =head1 AUTHOR Margo Yapp <myapp@example.com> =head1 LICENSE Copyright (C) 2008, Margo Yapp. This is distributed under the terms of the accidental death and dismemberment license and if you redistribuet this document you will be “accidentally” deathed or dismembered. You have been told. =cut 1;Tuesday, December 14, 2010The =version section is redundant.
    • package YourApp; # ABSTRACT: my awesome app our $VERSION = 0.001; =head1 DESCRIPTION This app is awesome. =head1 METHODS =head2 this_method This method does stuff. =cut method this_method { ... } =head2 that_method Also stuff. =cut method that_method { ... } =head1 AUTHOR Margo Yapp <myapp@example.com> =head1 LICENSE Copyright (C) 2008, Margo Yapp. This is distributed under the terms of the accidental death and dismemberment license and if you redistribuet this document you will be “accidentally” deathed or dismembered. You have been told. =cut 1;Tuesday, December 14, 2010Drop it.
    • package YourApp; # ABSTRACT: my awesome app our $VERSION = 0.001; =head1 DESCRIPTION This app is awesome. =head1 METHODS =head2 this_method This method does stuff. =cut method this_method { ... } =head2 that_method Also stuff. =cut method that_method { ... } =head1 AUTHOR Margo Yapp <myapp@example.com> =head1 LICENSE Copyright (C) 2008, Margo Yapp. This is distributed under the terms of the accidental death and dismemberment license and if you redistribuet this document you will be “accidentally” deathed or dismembered. You have been told. =cut 1;Tuesday, December 14, 2010Even the $VERSION is redundant, since we want it constant across the dist.
    • package YourApp; # ABSTRACT: my awesome app =head1 DESCRIPTION This app is awesome. =head1 METHODS =head2 this_method This method does stuff. =cut method this_method { ... } =head2 that_method Also stuff. =cut method that_method { ... } =head1 AUTHOR Margo Yapp <myapp@example.com> =head1 LICENSE Copyright (C) 2008, Margo Yapp. This is distributed under the terms of the accidental death and dismemberment license and if you redistribuet this document you will be “accidentally” deathed or dismembered. You have been told. =cut 1;Tuesday, December 14, 2010our overarching METHOD section is dumb
    • package YourApp; # ABSTRACT: my awesome app =head1 DESCRIPTION This app is awesome. =method this_method This method does stuff. =cut method this_method { ... } =method that_method Also stuff. =cut method that_method { ... } =head1 AUTHOR Margo Yapp <myapp@example.com> =head1 LICENSE Copyright (C) 2008, Margo Yapp. This is distributed under the terms of the accidental death and dismemberment license and if you redistribuet this document you will be “accidentally” deathed or dismembered. You have been told. =cut 1;Tuesday, December 14, 2010let’s just use =method for them all
    • package YourApp; # ABSTRACT: my awesome app =head1 DESCRIPTION This app is awesome. =method this_method This method does stuff. =cut method this_method { ... } =method that_method Also stuff. =cut method that_method { ... } =head1 AUTHOR Margo Yapp <myapp@example.com> =head1 LICENSE Copyright (C) 2008, Margo Yapp. This is distributed under the terms of the accidental death and dismemberment license and if you redistribuet this document you will be “accidentally” deathed or dismembered. You have been told. =cut 1;Tuesday, December 14, 2010Repeating the author everywhere is annoying, too.
    • package YourApp; # ABSTRACT: my awesome app =head1 DESCRIPTION This app is awesome. =method this_method This method does stuff. =cut method this_method { ... } =method that_method Also stuff. =cut method that_method { ... } =head1 LICENSE Copyright (C) 2008, Margo Yapp. This is distributed under the terms of the accidental death and dismemberment license and if you redistribuet this document you will be “accidentally” deathed or dismembered. You have been told. =cut 1;Tuesday, December 14, 2010Drop it, use author info found in DZ config.
    • package YourApp; # ABSTRACT: my awesome app =head1 DESCRIPTION This app is awesome. =method this_method This method does stuff. =cut method this_method { ... } =method that_method Also stuff. method that_method { ... } =head1 LICENSE Copyright (C) 2008, Margo Yapp. This is distributed under the terms of the accidental death and dismemberment license and if you redistribuet this document you will be “accidentally” deathed or dismembered. You have been told. =cut 1;Tuesday, December 14, 2010The license is gigantic! Ugh!
    • package YourApp; # ABSTRACT: my awesome app =head1 DESCRIPTION This app is awesome. =method this_method This method does stuff. =cut method this_method { ... } =method that_method Also stuff. =cut method that_method { ... } =cut 1;Tuesday, December 14, 2010Drop it.
    • package YourApp; # ABSTRACT: my awesome app =head1 DESCRIPTION This app is awesome. =method this_method This method does stuff. =cut method this_method { ... } =method that_method Also stuff. =cut method that_method { ... } 1;Tuesday, December 14, 2010Now our file is simple, just the unique docs and code it needs. It fits on one legible slide!
    • package YourApp; # ABSTRACT: my awesome app =head1 DESCRIPTION This app is awesome. =method this_method This method does stuff. =cut method this_method { ... } =method that_method Also stuff. =cut method that_method { ... } 1;Tuesday, December 14, 2010And is about half Perl.and you get all of that stuff autogenerated by adding this to your dist.ini
    • [PodWeaver]Tuesday, December 14, 2010
    • Converting Your DistTuesday, December 14, 2010
    • Converting Your Dist - create dist.iniTuesday, December 14, 2010
    • Converting Your Dist - create dist.ini - remove a bunch of filesTuesday, December 14, 2010
    • Converting Your Dist - create dist.ini - remove a bunch of files - delete a bunch of stuff from leftover filesTuesday, December 14, 2010
    • Converting Your Dist - create dist.ini - remove a bunch of files - delete a bunch of stuff from leftover files - and Dist::Zooky, tooTuesday, December 14, 2010
    • Questions so far?Tuesday, December 14, 2010
    • Creating New DistsTuesday, December 14, 2010
    • dzil build dzil test dzil install dzil releaseTuesday, December 14, 2010so, we already talked about these commands, which all operate on an existing distribution directory to build a fleshed-out CPANdistribution. to mint a brand-new dist, we use...
    • dzil build dzil test dzil install dzil release dzil newTuesday, December 14, 2010dzil new!the big difference is that the first set of commands work on an existing dist, so there’s a dist.iniwe don’t have a dist.ini yet, because there’s no dist dir yet. we need a...
    • profile.iniTuesday, December 14, 2010this file sets up the plugins that you’ll use to mint a new dist(don’t worry, if you don’t make one, there *is* default behavior -- but it’s so incredibly simple that you probably don’t want it)
    • Tuesday, December 14, 2010to understand how this works, we need to look at how minting works
    • [GatherDir::Template]Tuesday, December 14, 2010to understand how this works, we need to look at how minting works
    • [GatherDir::Template] root = filesTuesday, December 14, 2010to understand how this works, we need to look at how minting works
    • [GatherDir::Template] root = files [DistINI]Tuesday, December 14, 2010to understand how this works, we need to look at how minting works
    • [GatherDir::Template] root = files [DistINI] [Git::Init]Tuesday, December 14, 2010to understand how this works, we need to look at how minting works
    • How Dist::Zilla MintsTuesday, December 14, 2010
    • How Dist::Zilla Mints sub mint {Tuesday, December 14, 2010
    • How Dist::Zilla Mints sub mint { my ($self) = @_;Tuesday, December 14, 2010
    • How Dist::Zilla Mints sub mint { my ($self) = @_; my @files = $self->gather_files;Tuesday, December 14, 2010
    • How Dist::Zilla Mints sub mint { my ($self) = @_; my @files = $self->gather_files; $self->munge_files( @files );Tuesday, December 14, 2010
    • How Dist::Zilla Mints sub mint { my ($self) = @_; my @files = $self->gather_files; $self->munge_files( @files ); $self->make_module( $module );Tuesday, December 14, 2010
    • How Dist::Zilla Mints sub mint { my ($self) = @_; my @files = $self->gather_files; $self->munge_files( @files ); $self->make_module( $module ); $self->write_out( @files );Tuesday, December 14, 2010
    • How Dist::Zilla Mints sub mint { my ($self) = @_; my @files = $self->gather_files; $self->munge_files( @files ); $self->make_module( $module ); $self->write_out( @files ); }Tuesday, December 14, 2010
    • Tuesday, December 14, 2010see how there’s no root section? We *could* add one, but it would probably be the same across multiple profiles we set up, sowe can put this stuff in another location:
    • [GatherDir::Template]Tuesday, December 14, 2010see how there’s no root section? We *could* add one, but it would probably be the same across multiple profiles we set up, sowe can put this stuff in another location:
    • [GatherDir::Template] root = filesTuesday, December 14, 2010see how there’s no root section? We *could* add one, but it would probably be the same across multiple profiles we set up, sowe can put this stuff in another location:
    • [GatherDir::Template] root = files [DistINI]Tuesday, December 14, 2010see how there’s no root section? We *could* add one, but it would probably be the same across multiple profiles we set up, sowe can put this stuff in another location:
    • [GatherDir::Template] root = files [DistINI] [Git::Init]Tuesday, December 14, 2010see how there’s no root section? We *could* add one, but it would probably be the same across multiple profiles we set up, sowe can put this stuff in another location:
    • config.iniTuesday, December 14, 2010global (per-user) configuration
    • ~/.dzil/config.iniTuesday, December 14, 2010
    • [%User] name = Ricardo Signes email = rjbs@example.org [%Rights] license_class = Perl_5 copyright_holder = Ricardo Signes [%PAUSE] username = RJBS password = PeasAreDeliciousTuesday, December 14, 2010these aren’t plugins; global configuration is loaded before we have a Dist::Zilla object to plug intoinstead, these are stashes; basically, hunks of data for plugins to look up; they can be shared, generic, referenced by name, etcetc etchere we see our default author, our default license/legal info, and default PAUSE upload credentials
    • dzil setupTuesday, December 14, 2010
    • Minting a New Dist - create config.ini (in ~/.dzil) - maybe configure or install a profile - run dzil newTuesday, December 14, 2010
    • Questions so far?Tuesday, December 14, 2010
    • Writing Plugins!Tuesday, December 14, 2010
    • Writing Plugins is Easy!Tuesday, December 14, 2010
    • Writing Plugins is Easy! (and awesome)Tuesday, December 14, 2010
    • How Dist::Zilla Builds sub build { my ($self) = @_; my @files = $self->gather_files; $self->munge_files( @files ); $self->collect_metadata; $self->write_out( @files ); }Tuesday, December 14, 2010This is what I showed, earlier, as a simplified example of how Dist::Zilla builds stuff. To understand how plugins work, we needto de-simplify a little.
    • How Dist::Zilla Builds $self->munge_files( @files );Tuesday, December 14, 2010Take this line... what happens is a bit more like this:
    • How Dist::Zilla Builds my @mungers = grep { $_->does(‘FileMunger’) } $self->plugins; for my $plugin (@mungers) { $plugin->munge_files( @files ); }Tuesday, December 14, 2010we call a method on a bunch of delegates, where the delegates are all of the (undifferentiated) plugins that perform a given rol
    • $obj->does( $role ) package Some::Class; use Moose; with ‘Some::Role’;Tuesday, December 14, 2010LEARN MOOSE
    • Roles to Make Plugins GoTuesday, December 14, 2010
    • Roles to Make Plugins Go BeforeBuildTuesday, December 14, 2010
    • Roles to Make Plugins Go BeforeBuild FileGathererTuesday, December 14, 2010
    • Roles to Make Plugins Go BeforeBuild FileGatherer FilePrunerTuesday, December 14, 2010
    • Roles to Make Plugins Go BeforeBuild FileGatherer FilePruner FileMungerTuesday, December 14, 2010
    • Roles to Make Plugins Go BeforeBuild FileGatherer FilePruner FileMunger PrereqSourceTuesday, December 14, 2010
    • Roles to Make Plugins Go BeforeBuild FileGatherer FilePruner FileMunger PrereqSource MetaProviderTuesday, December 14, 2010
    • Roles to Make Plugins Go BeforeBuild FileGatherer FilePruner FileMunger PrereqSource MetaProvider AfterBuildTuesday, December 14, 2010
    • Roles to Make Plugins Go BeforeBuild FileGatherer FilePruner FileMunger PrereqSource MetaProvider AfterBuild BeforeArchiveTuesday, December 14, 2010
    • Roles to Make Plugins Go BeforeBuild FileGatherer FilePruner FileMunger PrereqSource MetaProvider AfterBuild BeforeArchive BeforeReleaseTuesday, December 14, 2010
    • Roles to Make Plugins Go BeforeBuild FileGatherer FilePruner FileMunger PrereqSource MetaProvider AfterBuild BeforeArchive BeforeRelease ReleaserTuesday, December 14, 2010
    • Roles to Make Plugins Go BeforeBuild FileGatherer FilePruner FileMunger PrereqSource MetaProvider AfterBuild BeforeArchive BeforeRelease Releaser AfterReleaseTuesday, December 14, 2010
    • Let’s write a plugin!Tuesday, December 14, 2010
    • BuiltOnTuesday, December 14, 2010
    • BuiltOn package Dist::Zilla::Plugin::BuiltOn;Tuesday, December 14, 2010
    • BuiltOn package Dist::Zilla::Plugin::BuiltOn; use Moose;Tuesday, December 14, 2010
    • BuiltOn package Dist::Zilla::Plugin::BuiltOn; use Moose; with ‘Dist::Zilla::Role::FileGatherer’;Tuesday, December 14, 2010
    • BuiltOn package Dist::Zilla::Plugin::BuiltOn; use Moose; with ‘Dist::Zilla::Role::FileGatherer’; sub gather_files {Tuesday, December 14, 2010
    • BuiltOn package Dist::Zilla::Plugin::BuiltOn; use Moose; with ‘Dist::Zilla::Role::FileGatherer’; sub gather_files { my ($self) = @_;Tuesday, December 14, 2010
    • BuiltOn package Dist::Zilla::Plugin::BuiltOn; use Moose; with ‘Dist::Zilla::Role::FileGatherer’; sub gather_files { my ($self) = @_; my $file = Dist::Zilla::File::InMemory->new({Tuesday, December 14, 2010
    • BuiltOn package Dist::Zilla::Plugin::BuiltOn; use Moose; with ‘Dist::Zilla::Role::FileGatherer’; sub gather_files { my ($self) = @_; my $file = Dist::Zilla::File::InMemory->new({ name => ‘built-on.txt’,Tuesday, December 14, 2010
    • BuiltOn package Dist::Zilla::Plugin::BuiltOn; use Moose; with ‘Dist::Zilla::Role::FileGatherer’; sub gather_files { my ($self) = @_; my $file = Dist::Zilla::File::InMemory->new({ name => ‘built-on.txt’, content => scalar `uname -a`,Tuesday, December 14, 2010
    • BuiltOn package Dist::Zilla::Plugin::BuiltOn; use Moose; with ‘Dist::Zilla::Role::FileGatherer’; sub gather_files { my ($self) = @_; my $file = Dist::Zilla::File::InMemory->new({ name => ‘built-on.txt’, content => scalar `uname -a`, });Tuesday, December 14, 2010
    • BuiltOn package Dist::Zilla::Plugin::BuiltOn; use Moose; with ‘Dist::Zilla::Role::FileGatherer’; sub gather_files { my ($self) = @_; my $file = Dist::Zilla::File::InMemory->new({ name => ‘built-on.txt’, content => scalar `uname -a`, }); $self->add_file( $file );Tuesday, December 14, 2010
    • BuiltOn package Dist::Zilla::Plugin::BuiltOn; use Moose; with ‘Dist::Zilla::Role::FileGatherer’; sub gather_files { my ($self) = @_; my $file = Dist::Zilla::File::InMemory->new({ name => ‘built-on.txt’, content => scalar `uname -a`, }); $self->add_file( $file ); }Tuesday, December 14, 2010
    • BuiltOn [BuiltOn]Tuesday, December 14, 2010
    • package Dist::Zilla::Plugin::BuiltOn; use Moose; with ‘Dist::Zilla::Role::FileGatherer’; has filename => ( is => ‘ro’, default => ‘built-on.txt’, ); sub gather_files { my ($self) = @_; my $file = Dist::Zilla::File::InMemory->new({ name => $self->filename, content => scalar `uname -a`, }); $self->add_file( $file ); }Tuesday, December 14, 2010
    • BuiltOn [BuiltOn] filename = build-host.txtTuesday, December 14, 2010
    • BuiltOn [BuiltOn]Tuesday, December 14, 2010
    • Let’s write a another!Tuesday, December 14, 2010(this will talk about plugin ordering)
    • AddShebangsTuesday, December 14, 2010...and then just one more...
    • AddShebangs package Dist::Zilla::Plugin::AddShebangs;Tuesday, December 14, 2010...and then just one more...
    • AddShebangs package Dist::Zilla::Plugin::AddShebangs; use Moose;Tuesday, December 14, 2010...and then just one more...
    • AddShebangs package Dist::Zilla::Plugin::AddShebangs; use Moose; with ‘Dist::Zilla::Role::FileMunger’;Tuesday, December 14, 2010...and then just one more...
    • AddShebangs package Dist::Zilla::Plugin::AddShebangs; use Moose; with ‘Dist::Zilla::Role::FileMunger’; sub munge_file {Tuesday, December 14, 2010...and then just one more...
    • AddShebangs package Dist::Zilla::Plugin::AddShebangs; use Moose; with ‘Dist::Zilla::Role::FileMunger’; sub munge_file { my ($self, $file) = @_;Tuesday, December 14, 2010...and then just one more...
    • AddShebangs package Dist::Zilla::Plugin::AddShebangs; use Moose; with ‘Dist::Zilla::Role::FileMunger’; sub munge_file { my ($self, $file) = @_; next unless $file->name =~ /.pl$/;Tuesday, December 14, 2010...and then just one more...
    • AddShebangs package Dist::Zilla::Plugin::AddShebangs; use Moose; with ‘Dist::Zilla::Role::FileMunger’; sub munge_file { my ($self, $file) = @_; next unless $file->name =~ /.pl$/; my $content = “#!$^Xn”Tuesday, December 14, 2010...and then just one more...
    • AddShebangs package Dist::Zilla::Plugin::AddShebangs; use Moose; with ‘Dist::Zilla::Role::FileMunger’; sub munge_file { my ($self, $file) = @_; next unless $file->name =~ /.pl$/; my $content = “#!$^Xn” . $file->content;Tuesday, December 14, 2010...and then just one more...
    • AddShebangs package Dist::Zilla::Plugin::AddShebangs; use Moose; with ‘Dist::Zilla::Role::FileMunger’; sub munge_file { my ($self, $file) = @_; next unless $file->name =~ /.pl$/; my $content = “#!$^Xn” . $file->content; $file->content( $content );Tuesday, December 14, 2010...and then just one more...
    • AddShebangs package Dist::Zilla::Plugin::AddShebangs; use Moose; with ‘Dist::Zilla::Role::FileMunger’; sub munge_file { my ($self, $file) = @_; next unless $file->name =~ /.pl$/; my $content = “#!$^Xn” . $file->content; $file->content( $content ); }Tuesday, December 14, 2010...and then just one more...
    • AddBlameTuesday, December 14, 2010
    • AddBlame package Dist::Zilla::Plugin::AddBlame;Tuesday, December 14, 2010
    • AddBlame package Dist::Zilla::Plugin::AddBlame; use Moose;Tuesday, December 14, 2010
    • AddBlame package Dist::Zilla::Plugin::AddBlame; use Moose; with ‘Dist::Zilla::Role::FileMunger’;Tuesday, December 14, 2010
    • AddBlame package Dist::Zilla::Plugin::AddBlame; use Moose; with ‘Dist::Zilla::Role::FileMunger’; sub munge_file {Tuesday, December 14, 2010
    • AddBlame package Dist::Zilla::Plugin::AddBlame; use Moose; with ‘Dist::Zilla::Role::FileMunger’; sub munge_file { my ($self, $file) = @_;Tuesday, December 14, 2010
    • AddBlame package Dist::Zilla::Plugin::AddBlame; use Moose; with ‘Dist::Zilla::Role::FileMunger’; sub munge_file { my ($self, $file) = @_; next unless $file->name =~ /.p[lm]$/;Tuesday, December 14, 2010
    • AddBlame package Dist::Zilla::Plugin::AddBlame; use Moose; with ‘Dist::Zilla::Role::FileMunger’; sub munge_file { my ($self, $file) = @_; next unless $file->name =~ /.p[lm]$/; my $content = “# BUILD BY $ENV{USER}n”Tuesday, December 14, 2010
    • AddBlame package Dist::Zilla::Plugin::AddBlame; use Moose; with ‘Dist::Zilla::Role::FileMunger’; sub munge_file { my ($self, $file) = @_; next unless $file->name =~ /.p[lm]$/; my $content = “# BUILD BY $ENV{USER}n” . $file->content;Tuesday, December 14, 2010
    • AddBlame package Dist::Zilla::Plugin::AddBlame; use Moose; with ‘Dist::Zilla::Role::FileMunger’; sub munge_file { my ($self, $file) = @_; next unless $file->name =~ /.p[lm]$/; my $content = “# BUILD BY $ENV{USER}n” . $file->content; $file->content( $content );Tuesday, December 14, 2010
    • AddBlame package Dist::Zilla::Plugin::AddBlame; use Moose; with ‘Dist::Zilla::Role::FileMunger’; sub munge_file { my ($self, $file) = @_; next unless $file->name =~ /.p[lm]$/; my $content = “# BUILD BY $ENV{USER}n” . $file->content; $file->content( $content ); }Tuesday, December 14, 2010
    • [GatherDir] [PruneCruft]Tuesday, December 14, 2010
    • [GatherDir] [PruneCruft] [AddShebangs] [AddBlame]Tuesday, December 14, 2010this is actually a problem
    • [GatherDir] [PruneCruft] [AddShebangs] [AddBlame] print “Hello.n”;Tuesday, December 14, 2010If we start with this extremely powerful library file...
    • [GatherDir] [PruneCruft] [AddShebangs] [AddBlame] #!/usr/bin/perl print “Hello.n”;Tuesday, December 14, 2010The shebang gets added, just like we wanted.
    • [GatherDir] [PruneCruft] [AddShebangs] [AddBlame] # built by rjbs #!/usr/bin/perl print “Hello.n”;Tuesday, December 14, 2010then the comment -- meaning the shebang is no good, because it doesn’t start the file
    • [GatherDir] [PruneCruft] [AddBlame] [AddShebangs] #!/usr/bin/perl # built by rjbs print “Hello.n”;Tuesday, December 14, 2010then the comment -- meaning the shebang is no good, because it doesn’t start the file
    • In Conclusion...Tuesday, December 14, 2010
    • Dist::Zilla is..?Tuesday, December 14, 2010
    • Dist::Zilla is: - judges will accept: - awesome - huge - stupidTuesday, December 14, 2010
    • We are Friendly - irc.perl.org #distzilla - http://dzil.org/ - mailing list - http://rt.cpan.org/Tuesday, December 14, 2010we will try to answer your questions
    • Any Questions?Tuesday, December 14, 2010
    • Thank you! raaaaaaaaar!Tuesday, December 14, 2010