karenetheridge / Template-Tiny

Template Toolkit reimplemented in as little code as possible
https://metacpan.org/release/Template-Tiny/
Other
3 stars 1 forks source link

"strict" mode patch? #1

Closed Ovid closed 3 years ago

Ovid commented 3 years ago

I know the intent is to keep this project tiny. I've had to fork this for an internal project where it's critical that the template:

Forking wasn't a problem, but I thought it would be useful for others. I could release Template::Tiny::Strict, or submit patches here which allow:

my $template = Template::Tiny->new(
    TRIM          => 1, 
    forbid_undef  => 1,
    forbid_unused => 1,
);

Let me know which works better for you.

karenetheridge commented 3 years ago

What does the patch look like? Is it "tiny"?

Ovid commented 3 years ago

Whether or not it's tiny is subjective :)

The following is a patch I quickly extracted from our project. It's documented and tested in our project, but I haven't added that here yet:

diff --git a/lib/Template/Tiny.pm b/lib/Template/Tiny.pm
index 751fed3..3a84b29 100644
--- a/lib/Template/Tiny.pm
+++ b/lib/Template/Tiny.pm
@@ -69,9 +69,16 @@ my $CONDITION = qr/
    \[\%\s \1 \s\%\]
 /xs;

-sub new {
-   bless { @_[1..$#_] }, $_[0];
-}
+sub new {
+   my ( $class, %arg_for ) = @_;
+   bless {
+       TRIM          => $arg_for{TRIM},
+       forbid_undef  => $arg_for{forbid_undef},
+       forbid_unused => $arg_for{forbid_unused},
+       _undefined    => {},
+       _used         => {},
+   } => $class;
+}

 # Copy and modify
 sub preprocess {
@@ -85,6 +92,8 @@ sub process {
    my $self  = shift;
    my $copy  = ${shift()};
    my $stash = shift || {};
+   $self->{_undefined} = {};
+   $self->{_used}      = {};

    local $@  = '';
    local $^W = 0;
@@ -94,6 +103,26 @@ sub process {

    # Process down the nested tree of conditions
    my $result = $self->_process( $stash, $copy );
+   if ( $self->{forbid_undef} ) {
+       if ( my %errors = %{ $self->{_undefined} } ) {
+           my $errors = join "\n" => sort keys %errors;
+           require Carp;
+           Carp::croak($errors);
+       }
+   }
+   if ( $self->{forbid_unused} ) {
+       my @unused;
+       foreach my $var ( keys %$stash ) {
+           unless ( $self->{_used}{$var} ) {
+               push @unused => $var;
+           }
+       }
+       if ( my $unused = join ', ' => sort @unused ) {
+           require Carp;
+           Carp::croak("The following variables were passed to the template but unused: '$unused'");
+       }
+   }
+
    if ( @_ ) {
        ${$_[0]} = $result;
    } elsif ( defined wantarray ) {
@@ -183,6 +212,7 @@ sub _foreach {
 sub _expression {
    my $cursor = $_[1];
    my @path   = split /\./, $_[2];
+   $_[0]->{_used}{ $path[0] } = 1;
    foreach ( @path ) {
        # Support for private keys
        return undef if substr($_, 0, 1) eq '_';
@@ -200,6 +230,11 @@ sub _expression {
            return '';
        }
    }
+   if ( $_[0]->{forbid_undef} && !defined $cursor ) {
+       $_[0]->{_undefined}{"Undefined value in template path '@path'"} = 1;
+       return '';
+   }
+
    return $cursor;
 }
Ovid commented 3 years ago

Just want to say that if you'd like this as a separate module, I don't mind at all. Either way, let me know :)

karenetheridge commented 3 years ago

Given that Template::Tiny hasn't changed in quite a long time, new functionality might not be easily discoverable by others.. which makes me lean more towards packaging this in a separate module. I'll happily add a "SEE ALSO" to the pod as a forward reference.

Ovid commented 3 years ago

Fair enough. I'll do that and drop you a note when I get around to uploading it. I'm a bit distracted right now, so I'm unsure how soon that will be.

Ovid commented 3 years ago

I've forked it and it's on its way to the CPAN now.. Thank you!

karenetheridge commented 3 years ago

cool!

I noticed a few typos in the pod and went to send you a PR, but it looks like they got fixed in version 1.16... but that version didn't make it to cpan -- was there an upload error?

Ovid commented 3 years ago

Curious. I have PAUSE email for 1.16. However, 1.17 is out there now.