#!/usr/bin/perl
use Getopt::Long;
use File::Slurp;
use Mason::Tidy;
use Pod::Usage;
use strict;
use warnings;

sub usage {
    my $msg = shift;
    print STDERR "$msg\n" if $msg;
    require Pod::Usage;
    Pod::Usage::pod2usage( { verbose => 1, output => \*STDERR } );
}

my %params;
Mason::Tidy->get_options( \@ARGV, \%params ) or usage();
Pod::Usage::pod2usage( { '-verbose' => 2 } ) if delete( $params{help} );
usage() if !@ARGV;
my $replace = delete( $params{replace} );
die "must pass -r/--replace with multiple filenames" if @ARGV > 1 && !$replace;

my $mt = Mason::Tidy->new(%params);
foreach my $file (@ARGV) {
    my $source = read_file($file);
    my $dest   = $mt->tidy($source);
    if ($replace) {
        write_file( $file, $dest );
    }
    else {
        print $dest;
    }
}

1;



=pod

=head1 NAME

masontidy - Tidy HTML::Mason / Mason components

=head1 VERSION

version 2.53

=head1 SYNOPSIS

    Tidy component, write to standard output:

    % masontidy file.mc

    Process component(s) in place:

    % masontidy -r file1.mc [file2.mc ...]

=head1 DESCRIPTION

masontidy tidies L<Mason 1|HTML::Mason> and L<Mason 2|Mason> components, using
L<perltidy|perltidy> to format the Perl code that can be embedded in various
places in the component.  masontidy does not (yet) attempt to tidy the HTML or
other non-Perl content in a component.

For example, this:

    <body>
    %if($contents||$allow_empty) {
      <ul>
    %foreach my $line (@lines) {
    %chomp($line);
      <li>
          <%2+(3-4)*6%>
      </li>
      <li><%  foo($.bar,$.baz,  $.bleah)%></li>
    %}
      </ul>
    %}
    </body>
    
    <%init>
    my @articles = @{Blog::Article::Manager->get_articles(sort_by=>"create_time",limit=>5)};
    </%init>  

becomes this:

    <body>
    % if ( $contents || $allow_empty ) {
      <ul>
    %     foreach my $line (@lines) {
    %         chomp($line);
      <li>
          <% 2 + ( 3 - 4 ) * 6 %>
      </li>
      <li><% foo( $.bar, $.baz, $.bleah) %></li>
    %     }
      </ul>
    %}
    </body>

    <%init>
    my @articles =
      @{ Blog::Article::Manager->get_articles
         ( sort_by => "create_time", limit => 5 ) };
    </%init>  

=head2 What gets tidied

=over

=item *

B<%-lines and C<< <%perl> >> blocks>. These are indented relative to each other
regardless of intervening non-Perl content, e.g. note the indentation of the
C<foreach> and C<chomp> lines above.

=item *

B<Other code blocks>. C<< <%init> >>, C<< <%once> >>, C<< <%class> >>, and C<<
<%filter> >> blocks are tidied in isolation from one another.

=item *

B<Perl expressions> inside C<< <% %> >> and C<< <& &> >> tags.

=back

=head1 INVOKING

There are two ways to invoke C<masontidy>:

=over

=item *

Specify a single file; the result will be written to standard output.

=item *

Specify one or more files with the -r/--replace flag; each file will be tidied
in place.

=back

For more advanced options, consider using C<masontidy> with L<tidyall|tidyall>;
it will let you read from standard input, write to files with a separate
extension, backup files before overwriting, etc.

=head1 COMMAND-LINE OPTIONS

=over

=item -r, --replace

Modify file(s) in place instead of sending to standard output.

=item --indent-perl-block

Number of spaces to initially indent all lines inside C<< <%perl> >> blocks.
The default is 2, so as to align with %-lines:

    % my $foo = get_foo();
    <%perl>
      if ($foo) {
          $bar = 6;
      }
    </%perl>

With --indent-perl-block 0:

    % my $foo = get_foo();
    <%perl>
    if ($foo) {
        $bar = 6;
    }
    </%perl>

Note that this is independent from perltidy's indentation settings.

=item --indent-block

Number of spaces to initially indent all lines inside code blocks other than
C<< <%perl> >> (C<< <%init> >>, C<< <%class> >>, C<< <%once> >>, and C<<
<%filter> >>).  The default is 0:

    <%init>
    if ($foo) {
        $bar = 6;
    }
    </%init>

With --indent-block 2:

    <%init>
      if ($foo) {
          $bar = 6;
      }
    </%init>

=item --perltidy-argv

C<perltidy> arguments to use everywhere. e.g.

    --perltidy-argv="-noll -l=78"

or

    --perltidy-argv " -noll -l=78"

=item --perltidy-line-argv

Additional C<perltidy> arguments to use for Perl lines.

=item --perltidy-block-argv

Additional C<perltidy> arguments to use for code blocks.

=item --perltidy-tag-argv

Additional C<perltidy> arguments to use for C<< <% %> >> and C<< <& &> >> tags.
For example, to ensure that these tags are never broken out onto multiple lines
regardless of how long they are:

    --perltidy-tag-argv="-fnl"  # short for --freeze-newlines

=item -h, --help       

Print help message

=back

=head1 ERRORS

Will throw a fatal error if a file cannot be tidied, such as when perltidy
encounters bad Perl syntax. However, C<masontidy> is not intended to be, and
should not be considered, a validator; it will remain silent on many syntax
errors.

=head1 LIBRARY API

You can use the L<Mason::Tidy|Mason::Tidy> API from inside another Perl
script/library instead of calling out to this script.

=head1 CAVEATS / KNOWN BUGS

=over

=item *

C<< <%perl> >> and C<< </%perl> >> tags must be on their own line, or else
their inner content will not be tidied.

=item *

C<< <% %> >> tags that span multiple lines are ignored.

=item *

A C<< %-line >> or C<< <% %> >> tag or any line inside a C<< <%perl> >> section
will never be split up into multiple lines regardless of how long it is.

=back

=head1 AUTHOR

Jonathan Swartz <swartz@pobox.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011 by Jonathan Swartz.

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

=cut


__END__

