File Coverage

blib/lib/WWW/Shopify/Liquid/Optimizer.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3 13     13   37138 use strict;
  13         24  
  13         469  
4 13     13   60 use warnings;
  13         22  
  13         417  
5              
6 13     13   473 use WWW::Shopify::Liquid;
  0            
  0            
7              
8             package WWW::Shopify::Liquid::Optimizer;
9             use base 'WWW::Shopify::Liquid::Pipeline';
10             use WWW::Shopify::Liquid::Security;
11              
12             use Clone qw(clone);
13             sub new {
14             my $package = shift;
15             my $self = bless {
16             clone_hash => 1,
17             remove_assignment => 0,
18             max_unrolling => 1000,
19             max_inclusion_depth => 5,
20             timeout => undef,
21             inclusion_context => undef,
22             inclusion_depth => 0,
23             security => WWW::Shopify::Liquid::Security->new,
24             conditional_state => [],
25             @_
26             }, $package;
27             return $self;
28             }
29             sub clone_hash { $_[0]->{clone_hash} = $_[1] if defined $_[1]; return $_[0]->{clone_hash}; }
30             sub security { $_[0]->{security} = $_[1] if defined $_[1]; return $_[0]->{security}; }
31             sub max_inclusion_depth { $_[0]->{max_inclusion_depth} = $_[1] if defined $_[1]; return $_[0]->{max_inclusion_depth}; }
32             sub inclusion_context { $_[0]->{inclusion_context} = $_[1] if defined $_[1]; return $_[0]->{inclusion_context}; }
33             sub inclusion_depth { $_[0]->{inclusion_depth} = $_[1] if defined $_[1]; return $_[0]->{inclusion_depth}; }
34             # If we're inside a non-fully-resolved branch, then this is flagged as true; means we can't actually assign things.
35             sub push_conditional_state {
36             my ($self) = @_;
37             push(@{$self->{conditional_state}}, { });
38             }
39             sub conditional_state {
40             return undef unless int(@{$_[0]->{conditional_state}}) > 0;
41             return $_[0]->{conditional_state}->[-1];
42             }
43             # Removes the variable from the hash, preventing further optimization, as post unevaluated conditional block, the status of the variable will be uncertain.
44             sub flag_conditional_uncertainty {
45             my ($self, $idarray) = @_;
46             my $state = $self->conditional_state;
47             return undef unless defined $state;
48             my $id = join(".", @$idarray);
49             $state->{$id} = $idarray;
50             }
51             sub pop_conditional_state {
52             my ($self, $hash) = @_;
53             my $state = pop(@{$self->{conditional_state}});
54             for (values(%$state)) {
55             my ($reference, $parent) = $self->variable_reference($hash, $_);
56             # If the parent is a hash, remove the element from the hash.
57             delete $parent->{$_->[-1]} if ref($parent) eq 'HASH';
58             }
59             }
60             # Depending on the type of optimization, you may or may not want to remove assignment or capture blocks.
61             # In cases where this liquid may be inserted inside other liquid, you may want to set this to 0, as the assignments may affect external objects.
62             # In cases where the liquid is the only thing being evaluated, with no outside context, it's fine to set this 1.
63             sub remove_assignment { $_[0]->{remove_assignment} = $_[1] if defined $_[1]; return $_[0]->{remove_assignment}; }
64             sub timeout { $_[0]->{timeout} = $_[1] if defined $_[1]; return $_[0]->{timeout}; }
65              
66             sub optimize {
67             my ($self, $hash, $ast) = @_;
68             return undef unless $ast;
69             my $hash_clone = $self->clone_hash && $self->clone_hash == 1 ? clone($hash) : $hash;
70             my $result;
71             {
72             local $SIG{ALRM} = sub { die new WWW::Shopify::Liquid::Exception::Timeout(); };
73             alarm $self->timeout if $self->timeout;
74             $result = $ast->optimize($self, $hash_clone);
75             alarm 0;
76             }
77             return !ref($result) ? WWW::Shopify::Liquid::Token::Text->new(undef, defined $result ? $result : '') : $result;
78             }
79              
80             1;