# This chunk of stuff was generated by App::FatPacker. To find the original
# file's code, look for the end of this BEGIN block or the string 'FATPACK'
BEGIN {
my %fatpacked;

$fatpacked{"App/Mypp.pm"} = <<'APP_MYPP';
  package App::Mypp;
  
  =head1 NAME
  
  App::Mypp - Maintain Your Perl Project
  
  =head1 VERSION
  
  0.11
  
  =head1 DESCRIPTION
  
  C<mypp> is a result of me getting tired of doing the same stuff - or
  rather forgetting to do the same stuff - for each of my Perl projects.
  mypp does not feature the same things as L<Dist::Zilla>, but I would
  like to think of mypp vs dzil as cpanm vs CPAN - or at least that
  is what I'm aiming for. (!) What I don't want to do is configure
  anything, so 1) it should just work 2) it might not work as you want it to.
  
  Want to try it out? Run the line below in your favourite terminal:
  
      wget -q http://github.com/jhthorsen/app-mypp/raw/master/script/mypp-packed -O - | perl -
  
  Running that line will start the experimental code from github - meaning
  the latest release. Run at own risk - and don't forget to put your files
  under version control first!
  
  =head1 SYNOPSIS
  
  Actions are also available with out "--", such as "init", "update", "test",
  "clean", "build" and "share".
  
      mypp [action];
      mypp --action;
      mypp --force update Makefile.PL
      mypp update t/00-load.t
  
  =head1 SAMPLE CONFIG FILE
  
      ---
      # Default to a converted version of top_module
      name: Foo-Bar
  
      # Default to a converted version of the project folder
      # Example: ./foo-bar/lib/Foo/Bar.pm, were "foo-bar" is the
      # project folder.
      top_module: lib/Foo/Bar.pm
  
      # Default to a converted version of top_module.
      top_module_name: Foo::Bar
  
      # Default to CPAN::Uploader. Can also be set through
      # MYPP_SHARE_MODULE environment variable.
      share_extension: AnyModuleName
  
      # Not in use if share_extension == CPAN::Uploader. Usage:
      # share_extension->upload_file($dist_file, share_params);
      share_params: [ { answer: 42 } ]
  
  All config params are optional, since mypp tries to figure out the
  information for you.
  
  =head1 SHARING THE MODULE
  
  By default the L<CPAN::Uploader> module is used to upload the module to CPAN.
  This module uses C<$HOME/.pause> to find login details:
  
      user your_pause_username
      password your_secret_pause_password
  
  It also uses git to push changes and tag a new release:
  
      git commit -a -m "$message_from_changes_file"
      git tag "$latest_version_in_changes_file"
      git push origin $current_branch
      git push --tags origin
  
  The commit and tagging is done with C<-dist>, while pushing the changes to
  origin is done with C<-share>.
  
  =head1 CHANGES FILE
  
  The expected format in C<Changes> is:
  
      Some random header, for Example:
      Revision history for Foo-Bar
  
      0.02
         * Fix something
         * Add something else
  
      0.01 Tue Apr 20 19:34:15 2010
         * First release
         * Add some feature
  
  C<mypp> automatically adds the date before creating a dist.
  
  =cut
  
  use strict;
  use warnings;
  use Cwd;
  use File::Basename;
  use File::Find;
  
  our $VERSION = eval '0.11';
  our $SILENT = $ENV{'MYPP_SILENT'} || $ENV{'SILENT'} || 0;
  our $PAUSE_FILENAME = $ENV{'HOME'} .'/.pause';
  our $VERSION_RE = qr/\d+ \. [\d_]+/x;
  
  open my $OLDOUT, '>&STDOUT';
  open my $OLDERR, '>&STDERR';
  
  sub _from_config ($&) {
      my($name, $sub) = @_;
  
      no strict 'refs';
  
      *$name = sub {
          my $self = shift;
          return $self->{$name} ||= $self->config->{$name} || $self->$sub(@_);
      };
  }
  
  sub _attr ($&) {
      my($name, $sub) = @_;
  
      no strict 'refs';
  
      *$name = sub {
          my $self = shift;
          return $self->{$name} ||= $self->$sub(@_);
      };
  }
  
  =head1 ATTRIBUTES
  
  =head2 config
  
   $hash = $self->config;
  
  Holds the config from C<mypp.yml> or C<MYPP_CONFIG> environment variable.
  
  =cut
  
  _attr config => sub {
      my $self = shift;
      my $file = $ENV{'MYPP_CONFIG'} || 'mypp.yml';
      my $config;
  
      return {} unless(-e $file);
  
      eval "use YAML::Tiny; 1;" or do {
          die <<"ERROR";
  
  YAML::Tiny is not installed, meaning '$file' will not be read.
  Use one of the commands below to install it:
  
  \$ aptitude install libyaml-tiny-perl
  \$ wget -q http://xrl.us/cpanm -O - | perl - YAML::Tiny
  
  ERROR
      };
  
      $config = YAML::Tiny->read($file);
  
      return $config->[0] if($config and $config->[0]);
      return {};
  };
  
  =head2 name
  
  Holds the project name. The project name is extracted from the
  L</top_module>, unless set in config file. Example: C<foo-bar>.
  
  =cut
  
  _from_config name => sub {
      my $self = shift;
      my $name;
  
      $name = join '-', split '/', $self->top_module;
      $name =~ s,^.?lib-,,;
      $name =~ s,\.pm$,,;
  
      return $name;
  };
  
  =head2 repository
  
  Holds the project repository url. The url is extracted from the origin git repo
  unless set.
  
  =cut
  
  _from_config repository => sub {
      my $repo = (qx/git remote show -n origin/ =~ /URL: (.*)$/m)[0] || 'git://github.com/';
      chomp $repo;
      return $repo;
  };
  
  =head2 top_module
  
  Holds the top module location. This path is extracted from either
  C<name> in the config file or the basename of the project. Example value:
  C<lib/Foo/Bar.pm>.
  
  The project might look like this:
  
   ./foo-bar/lib/Foo/Bar.pm
  
  Where "foo-bar" is the basename.
  
  =cut
  
  _from_config top_module => sub {
      my $self = shift;
      my $name = $self->config->{'name'} || basename getcwd;
      my @path = split /-/, $name;
      my $path = 'lib';
      my $file;
  
      $path[-1] .= '.pm';
  
      for my $p (@path) {
          opendir my $DH, $path or die "Cannot find top module from project name '$name': $!\n";
          for my $f (readdir $DH) {
              if(lc $f eq lc $p) {
                  $path = "$path/$f";
                  last;
              }
          }
      }
  
      unless(-f $path) {
          die "Cannot find top module from project name '$name': $path is not a plain file\n";
      }
  
      return $path;
  };
  
  =head2 top_module_name
  
  Returns the top module name, extracted from L</top_module>. Example value:
  C<Foo::Bar>.
  
  =cut
  
  _from_config top_module_name => sub {
      local $_ = $_[0]->top_module;
      s,\.pm,,; s,^/?lib/,,g; s,/,::,g;
      return $_;
  };
  
  =head2 changes
  
  Holds the latest information from C<Changes>. Example:
  
      {
          text => qq(0.03 .... \n * Something has changed),
          version => 0.03,
      }
  
  =cut
  
  _attr changes => sub {
      my $self = shift;
      my($text, $version);
  
      $self->_generate_file_from_template('Changes');
      open my $CHANGES, '<', 'Changes' or die "Read Changes: $!\n";
  
      while(<$CHANGES>) {
          if($text) {
              if(/^$/) {
                  last;
              }
              else {
                  $text .= $_;
              }
          }
          elsif(/^($VERSION_RE)/) {
              $version = $1;
              $text = $_;
          }
      }
  
      unless($text and $version) {
          die "Could not find commit message nor version info from Changes\n";
      }
  
      return {
          text => $text,
          version => $version,
      };
  };
  
  =head2 dist_file
  
  Returns the name of the target dist file.
  
  =cut
  
  _attr dist_file => sub {
      my $self = shift;
      return sprintf '%s-%s.tar.gz', $self->name, $self->changes->{'version'};
  };
  
  =head2 pause_info
  
  Holds information from C<$HOME/.pause>. See L<CPAN::Uploader> for details.
  Example:
  
      {
          user => 'johndoe',
          password => 's3cret',
      }
  
  =cut
  
  _attr pause_info => sub {
      open my $PAUSE, '<', $PAUSE_FILENAME or die "Read $PAUSE_FILENAME: $!\n";
      my %info = map { my($k, $v) = split /\s+/, $_, 2; chomp $v; ($k, $v) } <$PAUSE>;
  
      $info{'user'} or die "'user <name>' is not set in $PAUSE_FILENAME\n";
      $info{'password'} or die "'password <mysecret>' is not set in $PAUSE_FILENAME\n";
  
      return \%info;
  };
  
  =head2 share_extension
  
  Holds the classname of the module which should be used for sharing. This
  value can either come from the config file or the C<MYPP_SHARE_MODULE> environment
  variable, or fallback to L<CPAN::Uploader>.
  
  =cut
  
  _attr share_extension => sub {
      my $self = shift;
  
      return $ENV{'MYPP_SHARE_MODULE'} if($ENV{'MYPP_SHARE_MODULE'});
      return $self->config->{'share_extension'} if($self->config->{'share_extension'});
      return 'CPAN::Uploader';
  };
  
  =head2 share_params
  
  This attribute must hold an array ref, since it is flattened into a list when
  used as an argument to L</share_extension>'s C<upload_file()> method.
  
  =cut
  
  _from_config share_params => sub {
      return;
  };
  
  =head2 force
  
  Set by C<--force>
  
  =cut
  
  sub force { 0 }
  
  my %TEMPLATES;
  sub _templates {
      unless(%TEMPLATES) {
          my($key, $text);
          while(<DATA>) {
              if(/\%\% (\S+)/) {
                  $TEMPLATES{$key} = $text if($key);
                  $key = $1;
                  $text = '';
              }
              else {
                  $text .= $_;
              }
          }
          $TEMPLATES{$key} = $text
      }
      return \%TEMPLATES;
  }
  
  sub _build {
      my $self = shift;
      my(@rollback, $e);
  
      $self->_make('reset');
  
      eval {
          $self->_update_version_info;
          $self->_generate_file_from_template('MANIFEST.skip');
          $self->_system(sprintf '%s %s > %s', 'perldoc -tT', $self->top_module, 'README');
          eval { $self->_system('rm ' .$self->name .'* 2>/dev/null') }; # don't care if this fail
  
          push @rollback, sub { rename 'Changes.old', 'Changes' };
          $self->_timestamp_to_changes;
  
          push @rollback, sub { $self->_git(reset => 'HEAD^') };
          $self->_git(commit => -a => -m => $self->changes->{'text'});
  
          push @rollback, sub { $self->_git(tag => -d => $self->changes->{'version'}) };
          $self->_git(tag => $self->changes->{'version'});
  
          $self->_make('manifest');
          $self->_make('dist');
          1;
      } or do {
          $e = $@ || 'Not sure what went wrong';
          $_->() for reverse @rollback;
          die $e;
      };
  }
  
  sub _timestamp_to_changes {
      my $self = shift;
      my $date = localtime;
      my($changes, $pm);
  
      rename 'Changes', 'Changes.old' or die $!;
      open my $OLD, '<', 'Changes.old' or die "Read Changes.old: $!\n";
      open my $NEW, '>', 'Changes' or die "Write Changes: $!\n";
      { local $/; $changes = <$OLD> };
  
      if($changes =~ s/\n($VERSION_RE)\s*$/{ sprintf "\n%-7s  %s", $1, $date }/em) {
          print $NEW $changes;
          $self->_log("Add timestamp '$date' to Changes");
          return 1;
      }
  
      die "Unable to update Changes with timestamp\n";
  }
  
  sub _update_version_info {
      my $self = shift;
      my $top_module = $self->top_module;
      my $version = $self->changes->{'version'};
      my $top_module_text;
  
      open my $MODULE, '+<', $top_module or die "Read/write $top_module: $!\n";
      { local $/; $top_module_text = <$MODULE> }
      seek $MODULE, 0, 0;
  
      $top_module_text =~ s/=head1 VERSION.*?\n=/=head1 VERSION\n\n$version\n\n=/s;
      $top_module_text =~ s/^((?:our)?\s*\$VERSION)\s*=.*$/$1 = eval '$version';/m;
  
      print $MODULE $top_module_text;
      $self->_log("Update version in $top_module to $version");
  
      return 1;
  }
  
  sub _requires {
      my $self = shift;
      my(%requires, %test_requires, @requires, $corelist);
      my $wanted = sub {
                      return if(!-f $_);
                      return if(/\.swp/);
                      open my $REQ, '-|', "$^X -MApp::Mypp::ShowINC '$_' 2>/dev/null";
                      while(<$REQ>) {
                          my($m, $v) = split /=/;
                          chomp $v;
                          $_[0]->{$m} = $v unless($requires{$m});
                      }
                  };
  
      # required to skip core modules
      eval "use Module::CoreList; 1" and $corelist = 1;
  
      finddepth({ no_chdir => 1, wanted => sub { $wanted->(\%requires) } }, 'bin') if(-d 'bin');
      finddepth({ no_chdir => 1, wanted => sub { $wanted->(\%requires) } }, 'lib');
      finddepth({ no_chdir => 1, wanted => sub { $wanted->(\%test_requires) } }, 't');
  
      for my $m (sort keys %requires) {
          my $v = $requires{$m};
          next if($self->_got_parent_module($m, \%requires));
          next if($corelist and Module::CoreList->first_release($m));
          push @requires, $v ? "requires q($m) => $v;" : "# requires q($m) => ??;";
      }
  
      if(%test_requires) {
          push @requires, '';
      }
  
      for my $m (sort keys %test_requires) {
          my $v = $test_requires{$m};
          next if($self->_got_parent_module($m, \%requires));
          next if($corelist and Module::CoreList->first_release($m));
          push @requires, $v ? "test_requires q($m) => $v;" : "# test_requires q($m) => ??;";
      }
  
      return join "\n", @requires;
  }
  
  sub _got_parent_module {
      my($self, $module, $map) = @_;
  
      for my $m (keys %$map) {
          next unless($map->{$m});
          next unless($module =~ /^$m\::/);
          next unless(!$map->{$module} or $map->{$module} eq $map->{$m});
          return 1;
      }
  
      return;
  }
  
  sub _share_via_extension {
      my $self = shift;
      my $file = $self->dist_file;
      my $share_extension = $self->share_extension;
  
      eval "use $share_extension; 1" or die "This feature requires $share_extension to be installed";
  
      # might die...
      if($share_extension eq 'CPAN::Uploader') {
          $share_extension->upload_file($file, {
              user => $self->pause_info->{'user'},
              password => $self->pause_info->{'password'},
          });
      }
      else {
          $share_extension->upload_file($file, @{ $self->share_params || [] });
      }
  
      return 1;
  }
  
  sub _generate_file_from_template {
      my($self, $file) = @_;
      my $content;
  
      if(-e $file and !$self->force) {
          $self->_log("$file already exists. (Skipping)");
          return;
      }
  
      $content = $self->_templates->{$file} or die "No such template defined: $file";
      $content =~ s!\$\{(\w+)\}!{ $self->$1 }!ge;
      mkdir dirname $file;
      open my $FH, '>', $file or die "Write $file: $!";
      print $FH $content;
      $self->_log("$file was generated");
  }
  
  sub _system {
      shift->_log("\$ @_");
      open STDERR, '>', '/dev/null' if($SILENT);
      open STDOUT, '>', '/dev/null' if($SILENT);
      system @_ and die "system(@_) == $?";
      open STDERR, '>&', $OLDERR if($SILENT);
      open STDOUT, '>&', $OLDOUT if($SILENT);
      return 1;
  }
  
  sub _git {
      shift->_system(git => @_);
  }
  
  sub _make {
      my $self = shift;
      $self->_generate_file_from_template('Makefile.PL');
      $self->_system(perl => 'Makefile.PL') unless(-e 'Makefile');
      $self->_system(make => @_);
      return 1;
  }
  
  sub _log {
      return if $SILENT;
      print $_[1], "\n";
  }
  
  =head1 SEE ALSO
  
  =over
  
  =item * L<App::Cpanminus>
  
  =item * L<Dist::Zilla>
  
  =item * L<Shipit>
  
  =item * L<http://jhthorsen.github.com/app-mypp>
  
  =back
  
  =head1 BUGS
  
  Report bugs and issues at L<http://github.com/jhthorsen/app-mypp/issues>.
  
  =head1 COPYRIGHT & LICENSE
  
  Copyright 2007-2010 Jan Henning Thorsen, all rights reserved.
  
  This program is free software; you can redistribute it and/or modify it
  under the same terms as Perl itself.
  
  =head1 AUTHOR
  
  Jan Henning Thorsen, C<jhthorsen at cpan.org>
  
  =cut
  
  1;
  __DATA__
  %% t/00-load.t ==============================================================
  use lib 'lib';
  use Test::More;
  eval 'use Test::Compile; 1' or plan skip_all => 'Test::Compile required';
  all_pm_files_ok();
  %% t/00-pod.t ===============================================================
  use lib 'lib';
  use Test::More;
  eval 'use Test::Pod; 1' or plan skip_all => 'Test::Pod required';
  all_pod_files_ok();
  %% t/00-pod-coverage.t ======================================================
  use lib 'lib';
  use Test::More;
  eval 'use Test::Pod::Coverage; 1' or plan skip_all => 'Test::Pod::Coverage required';
  all_pod_coverage_ok({ also_private => [ qr/^[A-Z_]+$/ ] });
  %% MANIFEST.skip ============================================================
  ^mypp.yml
  .git
  \.old
  \.swp
  ~$
  ^blib/
  ^Makefile$
  ^MANIFEST.*
  ^${name}
  %% .gitignore ===============================================================
  /META.yml
  /MYMETA.*
  /blib/
  /inc/
  /pm_to_blib
  /MANIFEST
  /MANIFEST.bak
  /Makefile
  /Makefile.old
  *.old
  *.swp
  ~$
  /${name}*tar.gz
  %% Changes ==================================================================
  Revision history for ${name}
  
  0.01
         * Started project
         * Add cool feature
  %% Makefile.PL ==============================================================
  use inc::Module::Install;
  
  name q(${name});
  all_from q(${top_module});
  
  ${_requires}
  
  bugtracker q(http://rt.cpan.org/NoAuth/Bugs.html?Dist=${name});
  homepage q(https://metacpan.org/release/${name});
  repository q(${repository});
  
  # install_script glob('bin/*');
  auto_install;
  WriteAll;
APP_MYPP

$fatpacked{"App/Mypp/ShowINC.pm"} = <<'APP_MYPP_SHOWINC';
  package App::Mypp::ShowINC;
  
  =head1 NAME
  
  App::Mypp::ShowINC - Figure out what modules a script requires
  
  =head1 DESCRIPTION
  
  This module will print which dependencies a script or module has.
  
  =head1 SYNOPSIS
  
      perl -MApp::Mypp::ShowINC some/script/or/module.nn
  
  =cut
  
  use strict;
  use warnings;
  
  CHECK {
      for my $m (keys %INC) {
          $m =~ s!/!::!g;
          $m =~ s!\.pm$!!;
          next if($m eq __PACKAGE__);
          printf "%s=%s\n", $m, eval { $m->VERSION } || '0';
      }
      die '%INC was printed'
  }
  
  =head1 AUTHOR
  
  See L<App::Mypp>.
  
  =cut
  
  1;
APP_MYPP_SHOWINC

$fatpacked{"Applify.pm"} = <<'APPLIFY';
  package Applify;
  
  =head1 NAME
  
  Applify - Write object oriented scripts with ease
  
  =head1 VERSION
  
  0.01
  
  =head1 DESCRIPTION
  
  This module should keep all the noise away and let you write scripts
  very easily. These scripts can even be unittested even though they
  are define directly in the script file and not in a module.
  
  =head1 SYNOPSIS
  
      #!/usr/bin/perl
      use Applify;
  
      option file => input_file => 'File to read from';
      option dir => output_dir => 'Directory to write files to';
      option flag => dry_run => 'Use --no-dry-run to actually do something', 1;
  
      documentation __FILE__;
      version 1.23;
  
      sub app::generate_exit_value => sub {
          return int rand 100;
      };
  
      app {
          my($self, @extra) = @_;
          my $exit_value = 0;
  
          print "Extra arguments: @extra\n" if(@extra);
          print "Will read from: ", $self->input_file, "\n";
          print "Will write files to: ", $self->output_dir, "\n";
  
          if($self->dry_run) {
              die 'Will not run script';
          }
  
          return $self->generate_exit_value;
      };
  
  =head1 APPLICATION CLASS
  
  This module will generate an application class, which C<$self> inside the
  L</app> block refere to. This class will have:
  
  =over 4
  
  =item * new()
  
  An object constructor. This method will not be auto generated if any of
  the classes given to L</extends> has the method C<new()>.
  
  =item * run()
  
  This method is basically the code block given to L</app>.
  
  =item * Other methods
  
  Other methods must be defined in the C<app::> namespace.
  
  =item * _script()
  
  This is an accessor which return the L<Applify> object which
  is refered to as C<$self> in this documentation.
  
  NOTE: This accessor starts with an underscore to prevent conflicts
  with L</options>.
  
  =item * Other accessors
  
  Any L</option> (application switch) will be available as an accessor on the
  application object.
  
  =back
  
  =cut
  
  use strict;
  use warnings;
  use File::Basename ();
  use Getopt::Long ();
  
  use constant SUB_NAME_IS_AVAILABLE
      => $INC{'App/FatPacker/Trace.pm'} ? 0 # this will be true when running under "fatpack"
       : eval 'use Sub::Name; 1'        ? 1
       :                                  0;
  
  our $VERSION = eval '0.01';
  our $PERLDOC = 'perldoc';
  my $ANON = 1;
  
  sub __new_sub {
      my($fqn, $code) = @_;
      no strict 'refs';
      *$fqn = Sub::Name::subname($fqn, $code) if SUB_NAME_IS_AVAILABLE;
      *$fqn = $code unless SUB_NAME_IS_AVAILABLE;
  }
  
  =head1 EXPORTED FUNCTIONS
  
  =head2 option
  
      option $type => $name => $documentation;
      option $type => $name => $documentation, $default;
      option $type => $name => $documentation, $default, @args;
      option $type => $name => $documentation, @args;
  
  This function is used to define options which can be given to this
  application. See L</SYNOPSIS> for example code. This function can also be
  called as a method on C<$self>.
  
  =over 4
  
  =item * $type
  
  Used to define value types for this input.
  
  =over 4
  
  =item bool, flag
  
  =item inc
  
  =item str
  
  =item int
  
  =item num
  
  =item file (TODO)
  
  =item dir (TODO)
  
  =back
  
  =item * $name
  
  The name of an application switch. This name will also be used as
  accessor name inside the application. Example:
  
      # define an application switch:
      option file => some_file => '...';
  
      # call the application from command line:
      > myapp.pl --some-file /foo/bar
  
      # run the application code:
      app {
          my $self = shift;
          print $self->some_file # prints "/foo/bar"
          return 0;
      };
  
  =item * C<$documentation>
  
  Used as description text when printing the usage text.
  
  =item * C<@args>
  
  =over 4
  
  =item * C<required>
  
  The script will not start if a required field is omitted.
  
  =item * C<n_of>
  
  Allow the option to hold a list of values. Examples: "@", "4", "1,3".
  See L<Getopt::Long/Options-with-multiple-values> for details.
  
  =item * Other
  
  Any other L<Moose> attribute argument may/will be supported in
  future release.
  
  =back
  
  =back
  
  =cut
  
  sub option {
      my $self = shift;
      my $type = shift or die 'Usage: option $type => ...';
      my $name = shift or die 'Usage: option $type => $name => ...';
      my $documentation = shift or die 'Usage: option $type => $name => $documentation, ...';
      my($default, @args);
  
      if(@_ % 2) {
          $default = shift;
          @args = @_;
      }
      else {
          @args = @_;
      }
  
      push @{ $self->{'options'} }, {
          default => $default,
          @args,
          type => $type,
          name => $name,
          documentation => $documentation,
      };
  
      return $self;
  }
  
  =head2 documentation
  
      documentation __FILE__; # current file
      documentation '/path/to/file';
      documentation 'Some::Module';
  
  Specifies where to retrieve documentaion from when giving the C<--man>
  switch to your script.
  
  =cut
  
  sub documentation {
      return $_[0]->{'documentation'} if(@_ == 1);
      $_[0]->{'documentation'} = $_[1] or die 'Usage: documentation $file|$module_name;';
      return $_[0];
  }
  
  =head2 version
  
      version 'Some::Module';
      version $num;
  
  Specifies where to retrieve the version number from when giving the
  C<--version> switch to your script.
  
  =cut
  
  sub version {
      return $_[0]->{'version'} if(@_ == 1);
      $_[0]->{'version'} = $_[1] or die 'Usage: version $module_name|$num;';
      return $_[0];
  }
  
  =head2 extends
  
      extends @classes;
  
  Specify which classes this application should inherit from. These
  classes can be L<Moose> based.
  
  =cut
  
  sub extends {
      my $self = shift;
      $self->{'extends'} = [@_];
      return $self;
  }
  
  =head2 app
  
      app CODE;
  
  This function will define the code block which is called when the application
  is started. See L</SYNOPSIS> for example code. This function can also be
  called as a method on C<$self>.
  
  IMPORTANT: This function must be the last function called in the script file
  for unittests to work. Reason for this is that this function runs the
  application in void context (started from command line), but returns the
  application object in list/scalar context (from L<perlfunc/do>).
  
  =cut
  
  sub app {
      my($self, $code) = @_;
      my $app = {};
      my $parser = $self->_option_parser;
      my(@options_spec, $application_class);
  
      for my $option (@{ $self->{'options'} }) {
          my $switch = $self->_attr_to_option($option->{'name'});
          push @options_spec, $self->_calculate_option_spec($option);
          $app->{$switch} = $option->{'default'} if(exists $option->{'default'});
      }
  
      unless($parser->getoptions($app, @options_spec, $self->_default_options)) {
          $self->_exit(1);
      }
  
      if($app->{'help'}) {
          $self->print_help;
          $self->_exit('help');
      }
      elsif($app->{'man'}) {
          system $PERLDOC => $self->documentation;
          $self->_exit($? >> 8);
      }
      elsif($app->{'version'}) {
          $self->print_version;
          $self->_exit('version');
      }
  
      $application_class = $self->_generate_application_class($code);
      $app = $application_class->new({
                  map { my $k = $self->_option_to_attr($_); $k => $app->{$_} } keys %$app,
              });
  
      return $app if(defined wantarray); # $app = do $script_file;
      $self->_exit($app->run(@ARGV));
  }
  
  sub _calculate_option_spec {
      my($self, $option) = @_;
      my $spec = $self->_attr_to_option($option->{'name'});
  
      if($option->{'type'} =~ /^(?:bool|flag)/i) { $spec .= '!' }
      elsif($option->{'type'} =~ /^inc/) { $spec .= '+' }
      elsif($option->{'type'} =~ /^str/) { $spec .= '=s' }
      elsif($option->{'type'} =~ /^int/i) { $spec .= '=i' }
      elsif($option->{'type'} =~ /^num/i) { $spec .= '=f' }
      elsif($option->{'type'} =~ /^file/) { $spec .= '=s' } # TODO
      elsif($option->{'type'} =~ /^dir/) { $spec .= '=s' } # TODO
      else { die 'Usage: option {bool|flag|inc|str|int|num|file|dir} ...' }
  
      if(my $n_of = $option->{'n_of'}) {
          $spec .= $n_of eq '@' ? $n_of : "{$n_of}";
          $option->{'default'} and ref $option->{'default'} ne 'ARRAY' and die 'Usage option ... default => [Need to be an array ref]';
          $option->{'default'} ||= [];
      }
  
      return $spec;
  }
  
  sub _default_options {
      my $self = shift;
      my @default;
  
      push @default, 'help';
      push @default, 'man' if($self->documentation);
      push @default, 'version' if($self->version);
  
      return @default;
  }
  
  sub _generate_application_class {
      my($self, $code) = @_;
      my $application_class = $self->{'caller'}[1];
      my $extends = $self->{'extends'} || [];
      my @required;
  
      $application_class =~ s!\W!_!g;
      $application_class = join '::', ref($self), "__ANON__${ANON}__", $application_class;
      $ANON++;
  
      eval qq[
          package $application_class;
          use base qw/ @$extends /;
          1;
      ] or die "Failed to generate class: $@";
  
      {
          no strict 'refs';
          my $methods = \%{'app::'};
  
          __new_sub "$application_class\::new" => sub { my $class = shift; bless shift, $class } unless(grep { $_->can('new') } @$extends);
          __new_sub "$application_class\::_script" => sub { $self };
          __new_sub "$application_class\::run" => sub {
              my($app, @extra) = @_;
  
              if(@required = grep { not defined $app->{$_} } @required) {
                  my $required = join ', ', map { '--' .$self->_attr_to_option($_) } @required;
                  $app->_script->print_help;
                  die "Required attribute missing: $required\n";
              }
  
              return $app->$code(@extra);
          };
  
          for my $option (@{ $self->{'options'} }) {
              my $name = $option->{'name'};
              my $fqn = join '::', $application_class, $option->{'name'};
              __new_sub $fqn => sub { @_ == 2 and $_[0]->{$name} = $_[1]; $_[0]->{$name} };
              push @required, $name if($option->{'required'});
          }
  
          
          for my $name (keys %$methods) {
              my $code = *{$methods->{$name}}{'CODE'} or next;
              my $fqn = join '::', $application_class, $name;
              __new_sub $fqn => $code;
              delete $methods->{$name}; # may be a bit too destructive?
          }
      }
  
      return $application_class;
  }
  
  =head1 ATTRIBUTES
  
  =head2 options
  
      $array_ref = $self->options;
  
  Holds the application options given to L</option>.
  
  =cut
  
  sub options { $_[0]->{'options'} }
  sub _option_parser { $_[0]->{'_option_parser'} ||= Getopt::Long::Parser->new(config => [ qw( no_auto_help no_auto_version pass_through ) ]) }
  
  =head1 METHODS
  
  =head2 new
  
      $self = $class->new({ options => $array_ref, ... });
  
  Object constructor. Creates a new object representing the script meta
  information.
  
  =cut
  
  sub new {
      my($class, $args) = @_;
      my $self = bless $args, $class;
  
      $self->{'options'} ||= [];
      $self->{'caller'} or die 'Usage: $self->new({ caller => [...], ... })';
  
      return $self;
  }
  
  =head2 print_help
  
  Will print L</options> to selected filehandle (STDOUT by default) in
  a normalized matter. Example:
  
      Usage:
         --foo      Foo does this and that
       * --bar      Bar does something else
  
         --help     Print this help text
         --man      Display manual for this application
         --version  Print application name and version
  
  =cut
  
  sub print_help {
      my $self = shift;
      my @options = @{ $self->{'options'} };
      my $width = 0;
  
      push @options, { name => '' };
      push @options, { name => 'help', documentation => 'Print this help text' };
      push @options, { name => 'man', documentation => 'Display manual for this application' } if($self->documentation);
      push @options, { name => 'version', documentation => 'Print application name and version' } if($self->version);
      push @options, { name => '' };
  
      $self->_print_synopsis;
  
      OPTION:
      for my $option (@options) {
          my $length = length $option->{'name'};
          $width = $length if($width < $length);
      }
  
      print "Usage:\n";
  
      OPTION:
      for my $option (@options) {
          my $name = $self->_attr_to_option($option->{'name'}) or do { print "\n"; next OPTION };
  
          printf(" %s --%-${width}s  %s\n",
              $option->{'required'} ? '*' : ' ',
              $name,
              $option->{'documentation'},
          );
      }
  
      return $self;
  }
  
  sub _print_synopsis {
      my $self = shift;
      my $documentation = $self->documentation or return;
      my $print;
  
      unless(-e $documentation) {
          eval "use $documentation; 1" or die "Could not load $documentation: $@";
          $documentation =~ s!::!/!g;
          $documentation = $INC{"$documentation.pm"};
      }
  
      open my $FH, '<', $documentation or die "Failed to read synopsis from $documentation: $@";
  
      while(<$FH>) {
          last if($print and /^=(?:cut|head1)/);
          print if($print);
          $print = 1 if(/^=head1 SYNOPSIS/);
      }
  }
  
  =head2 print_version
  
  Will print L</version> to selected filehandle (STDOUT by default) in
  a normalized matter. Example:
  
      some-script.pl version 1.23
  
  =cut
  
  sub print_version {
      my $self = shift;
      my $version = $self->version or die 'Cannot print version without version()';
  
      unless($version =~ m!^\d!) {
          eval "use $version; 1" or die "Could not load $version: $@";
          $version = $version->VERSION;
      }
  
      printf "%s version %s\n", File::Basename::basename($0), $version;
  }
  
  sub _exit {
      my($self, $reason) = @_;
      exit 0 unless($reason =~ /^\d+$/); # may change without warning...
      exit $reason;
  }
  
  sub _attr_to_option {
      local $_ = $_[1] or return;
      s!_!-!g;
      $_;
  }
  
  sub _option_to_attr {
      local $_ = $_[1] or return;
      s!-!_!g;
      $_;
  }
  
  =head2 import
  
  Will export the functions listed under L</EXPORTED FUNCTIONS>. The functions
  will act on a L<Applify> object created by this method.
  
  =cut
  
  sub import {
      my $class = shift;
      my @caller = CORE::caller(1);
      my $self = $class->new({ caller => \@caller });
  
      strict->import;
      warnings->import;
  
      no strict 'refs';
      no warnings 'redefine'; # need to allow redefine when loading a new app
      *{"$caller[0]\::app"} = sub (&) { $self->app(@_) };
      *{"$caller[0]\::option"} = sub { $self->option(@_) };
      *{"$caller[0]\::version"} = sub { $self->version(@_) };
      *{"$caller[0]\::documentation"} = sub { $self->documentation(@_) };
      *{"$caller[0]\::method"} = sub { $self->method(@_) };
      *{"$caller[0]\::extends"} = sub { $self->extends(@_) };
  }
  
  =head1 COPYRIGHT & LICENSE
  
  This library is free software. You can redistribute it and/or modify
  it under the same terms as Perl itself.
  
  =head1 AUTHOR
  
  Jan Henning Thorsen
  
  =cut
  
  1;
APPLIFY

s/^  //mg for values %fatpacked;

unshift @INC, sub {
  if (my $fat = $fatpacked{$_[1]}) {
    open my $fh, '<', \$fat
      or die "FatPacker error loading $_[1] (could be a perl installation issue?)";
    return $fh;
  }
  return
};

} # END OF FATPACK CODE
#!/usr/bin/env perl
use Applify;

option bool => init => 'Alias for --update';
option str => update => 'Update repository files' => n_of => '0,';
option bool => test => 'Run unittests';
option bool => build => 'Build a distribution';
option bool => share => 'Push built distribution to CPAN and origin git repo';
option bool => clean => 'Remove generated files by make';
option bool => force => 'Force action, such as overwriting files';

documentation 'App::Mypp';
version 'App::Mypp';
extends 'App::Mypp';

app {
    my $self = shift;
    my $action = shift || '__UNDEF__';

    if($action and $self->can($action)) {
        $self->$action($action eq 'update' ? [keys %{ $self->_templates }] : 1);
    }

    if(@{ $self->update } or $self->init) {
        $self->update([keys %{ $self->_templates }]) unless(grep { /\w/ } @{ $self->update });
        $self->_generate_file_from_template($_) for reverse sort @{ $self->update };
        $self->_system(sprintf '%s %s > %s', 'perldoc -tT', $self->top_module, 'README');
    }
    elsif($self->test) {
        $self->_make('reset');
        $self->_generate_file_from_template($_) for grep { m!^t/! } keys %{ $self->_templates };
        $self->_make('test');
    }
    elsif($self->build) {
        $self->_build;
    }
    elsif($self->share) {
        my $branch = (qx/git branch/ =~ /\* (.*)$/m)[0];
        chomp $branch;
        $self->_share_via_extension;
        $self->_git(push => origin => $branch);
        $self->_git(push => '--tags' => 'origin');
    }
    elsif($self->clean) {
        $self->_make('reset');
    }
    else {
        $self->_script->print_help;
    }
 
    return 0;
};
