package Mousse::Maker;
use strict;
use warnings;

use 5.008003;

use Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(make_mousse);

our $VERSION = '0.14';

sub make_mousse {
    my $module = shift(@ARGV)
        or die "make_mousse requires a module name argument";
    die "'$module' doesn't look like a module name"
        unless $module =~ /^\w(\w|::)+$/;
    make_from_mousse($module, @ARGV);
}

sub make_from_mousse {
    my $Mousse = shift;
    my $MousseFile = shift || '';
    require Mousse;
    my $file = $INC{'Mousse.pm'};
    my $contents = slurp($file);

    my $Mousse2 = $Mousse;
    $Mousse2 =~ s/::/\//g;

    $contents =~ s/Mousse(.)/(($1 eq '\/' or $1 eq '.') ? $Mousse2 : $Mousse) .$1/ge;
    my $handle;
    if ($MousseFile) {
        my $MousseDir = $MousseFile;
        $MousseDir =~ s/(.*[\\\/]).*/$1/ and File::Path::mkpath($MousseDir);
        open $handle, ">$MousseFile"
            or die "Can't open $MousseFile for output";
    }
    else {
        $handle = \*STDOUT;
    }

    print { $handle } $contents;
}

# This is a modified version of tool/generate-mouse-tiny.pl
# from git://git.moose.perl.org/Mouse.git 
sub make_from_mouse {
    my $Mousse = shift;
    my $MousseFile = shift || '';
    require Mouse;
    my $lib = $INC{'Mouse.pm'};
    $lib =~ s/[\\\/]Mouse\.pm$//;

    use File::Find;
    use Fatal qw(open close);
    use File::Path;

    sub uniq{
        my %seen;
        return grep{ !$seen{$_}++ } @_;
    }

    require "$lib/Mouse/Spec.pm";

    my @files;

    find({
        wanted => sub {
            push @files, $_
                if -f $_
                &&  /\.pm$/
                &&  /\bMouse\b/
                & !/Squirrel/
                && !/Tiny/
                && !/Test/         # only for testing
                && !/Spec/         # has no functionality
                && !/TypeRegistry/ # deprecated
                && !/\bouse/       # ouse.pm
        },
        no_chdir => 1,
    }, $lib);

    my $mousse = '';

    for my $file (uniq
            "$lib/Mouse/PurePerl.pm",
            "$lib/Mouse/Exporter.pm",
            "$lib/Mouse/Util.pm",
            "$lib/Mouse/Meta/TypeConstraint.pm",
            "$lib/Mouse/Util/TypeConstraints.pm",
                sort @files) {

        my $module = $file;
        $module =~ s/^\Q$lib\E\/(.*)\.pm/$1/;
        $module =~ s/\//::/g;
        my $contents = slurp($file);

        fixups($module, \$contents);

        $contents =~ s/__END__\b.*//s;          # remove documentation
        $contents =~ s/1;\n*$//;                # remove success indicator

        $contents =~ s/Mouse/$Mousse/g;

        $contents =~ s{^( (?:[ ]{4})+ )}{ "\t" x (length($1) / 4) }xmsge; # spaces to tabs

        $mousse .= "# Contents of $module\n";
        $mousse .= $contents;
    }

    my $handle;
    if ($MousseFile) {
        open $handle, ">$MousseFile";
    }
    else {
        $handle = \*STDOUT;
    }

    print { $handle } << "EOF";
# This file was generated by Mousse::Maker $VERSION from Mouse $Mouse::Spec::VERSION.
#
# ANY CHANGES MADE HERE WILL BE LOST!
use strict;
use warnings;

# tell Perl we already have all of the Mousse files loaded:
EOF

    print { $handle } "BEGIN {\n";
    for my $file (@files) {
        $file =~ s/Mouse/$Mousse/g;
        (my $inc = $file) =~ s{^\Q$lib\E/}{};
        printf { $handle } "\t%-45s = __FILE__;\n", "\$INC{'$inc'}";
    }

    print { $handle } <<"END_OF_MOUSSE";
}

# and now their contents

$mousse;

package $Mousse;

our \$VERSION = '$Mousse::Maker::VERSION';

$Mousse\::Exporter->setup_import_methods(also => '$Mousse\::TOP');

1;
END_OF_MOUSSE

    close $handle;
}

sub fixups {
    my ($module, $contents) = @_;
    if ($module eq 'Mouse') {
        $$contents =~ s/Mouse/Mouse::TOP/m or die;
    }
    elsif (
        $module eq 'Mouse::Util' or
        $module eq 'Mouse::Meta::Module' or
        $module eq 'Mouse::Meta::Class'
    ) {
        $$contents =~ s/\n\n/\nno warnings 'once';\n\n/m or die;
    }
}

sub slurp {
    open my $in, '<', $_[0];
    local $/;
    return scalar <$in>;
}

1;

=encoding utf-8

=head1 NAME

Mousse::Maker - Make Your Own Mousse Module

=head1 SYNOPSIS

In your C<Makefile.PL>:

    use inc::Module::Install;
    name 'Chocolate';
    use_mousse 'Chocolate::Mousse';

or (if you don't use Module::Install):

    perl -MMousse::Maker -e make_mousse 'Chocolate::Mousse' > lib/Chocolate/Mousse.pm

=head1 DESCRIPTION

Mousse::Maker is the module that Module::Install::Mousse uses to generate your own Mousse OO base class module. You can also use it by hand in a Perl one liner (shown above) if your CPAN module doesn't use Module::Install for its Makefile.PL.

=head1 AUTHOR

Ingy döt Net <ingy@cpan.org>

=head1 COPYRIGHT

Copyright (c) 2010, 2011. Ingy döt Net.

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

See http://www.perl.com/perl/misc/Artistic.html

=cut
