{
$Template::Liquid::Context::VERSION
=
'v1.0.3'
}
sub
new {
my
(
$class
,
%args
) =
@_
;
return
bless
{
scopes
=> [
$args
{assigns}],
template
=>
$args
{template},
errors
=> []
},
$class
;
}
sub
push
{
my
(
$s
,
$context
) =
@_
;
return
raise Template::Liquid::Error {
type
=>
'Stack'
,
message
=>
'Cannot push new scope!'
}
if
scalar
@{
$s
->{
'scopes'
}} == 100;
return
push
@{
$s
->{
'scopes'
}}, (
defined
$context
?
$context
: {});
}
sub
pop
{
my
(
$s
) =
@_
;
return
raise Template::Liquid::Error {
type
=>
'Stack'
,
message
=>
'Cannot pop scope!'
}
if
scalar
@{
$s
->{
'scopes'
}} == 1;
return
pop
@{
$s
->{
'scopes'
}};
}
sub
stack {
my
(
$s
,
$block
) =
@_
;
my
$old_scope
=
$s
->{scopes}[-1];
$s
->
push
();
$s
->merge(
$old_scope
);
my
$result
=
$block
->(
$s
);
$s
->
pop
;
return
$result
;
}
sub
merge {
my
(
$s
,
$new
) =
@_
;
return
$s
->{
'scopes'
}->[0] = __merge(
reverse
$s
->{scopes}[-1],
$new
);
}
sub
_merge {
my
(
$source
,
$target
) =
@_
;
my
$return
=
$target
;
for
(
keys
%$source
) {
if
(
'ARRAY'
eq
ref
$target
->{
$_
}
&& (
'ARRAY'
eq
ref
$source
->{
$_
}
|| !
ref
$source
->{
$_
})
)
{ @{
$return
->{
$_
}} = [@{
$target
->{
$_
}}, @{
$source
->{
$_
}}];
}
elsif
(
'HASH'
eq
ref
$target
->{
$_
}
&& (
'HASH'
eq
ref
$source
->{
$_
}
|| !
ref
$source
->{
$_
})
)
{
$return
->{
$_
} = _merge(
$source
->{
$_
},
$target
->{
$_
});
}
else
{
$return
->{
$_
} =
$source
->{
$_
}; }
}
return
$return
;
}
my
$merge_precedent
;
sub
__merge {
my
$return
=
$_
[1];
$merge_precedent
||= {
SCALAR
=> {
SCALAR
=>
sub
{
defined
$_
[0] ?
$_
[0] :
$_
[1] },
ARRAY
=>
sub
{
$_
[1] },
HASH
=>
sub
{
$_
[1] },
},
ARRAY
=> {
SCALAR
=>
sub
{
[@{
$_
[0]},
defined
$_
[1] ?
$_
[1] : ()];
},
ARRAY
=>
sub
{ [@{
$_
[0]}] },
HASH
=>
sub
{ [@{
$_
[0]},
values
%{
$_
[1]}] },
},
HASH
=> {
SCALAR
=>
sub
{
$_
[0] },
ARRAY
=>
sub
{
$_
[0] },
HASH
=>
sub
{ _merge(
$_
[0],
$_
[1],
$_
[2]) },
}
};
for
my
$key
(
keys
%{
$_
[0]}) {
my
(
$left_ref
,
$right_ref
)
=
map
{
ref
(
$_
->{
$key
}) =~ m[^(HASH|ARRAY)$]o ? $1 :
'SCALAR'
}
(
$_
[0],
$_
[1]);
$return
->{
$key
} =
$merge_precedent
->{
$left_ref
}{
$right_ref
}
->(
$_
[0]->{
$key
},
$_
[1]->{
$key
});
}
return
$return
;
}
sub
get {
my
(
$s
,
$var
) =
@_
;
return
if
!
defined
$var
;
return
$2
if
$var
=~ m[^(["'])(.+)\1$]o;
my
@path
=
split
$Template::Liquid::Utility::VariableAttributeSeparator
,
$var
;
my
$cursor
= \
$s
->{scopes}[-1];
return
$var
if
$var
=~ m[^-?\d+(\.\d+)?$]o
&& !
exists
$$cursor
->{
$path
[0]};
return
if
$var
eq
''
;
return
if
$var
eq
'null'
;
return
if
$var
eq
'nil'
;
return
if
$var
eq
'blank'
;
return
if
$var
eq
'empty'
;
return
!1
if
$var
eq
'false'
;
return
!!1
if
$var
eq
'true'
;
return
[
$s
->get($1) ..
$s
->get($2)]
if
$var
=~ m[^\((\S+)\.\.(\S+)\)$]o;
return
$s
->get($1)->[$2]
if
$var
=~ m
'^(.+)\[(\d+)\]$'
o;
return
$s
->get($1)->{$2}
if
$var
=~ m
'^(.+)\[(.+)\]$'
o;
STEP:
while
(
@path
) {
my
$crumb
=
shift
@path
;
my
$reftype
=
ref
$$cursor
;
if
(
$reftype
eq
'HASH'
) {
if
(
exists
$$cursor
->{
$crumb
}) {
return
$$cursor
->{
$crumb
}
if
!
@path
;
$cursor
= \
$$cursor
->{
$crumb
};
next
STEP;
}
return
();
}
elsif
(
$reftype
eq
'ARRAY'
) {
return
scalar
@{
$$cursor
}
if
$crumb
eq
'size'
;
$crumb
= 0
if
$crumb
eq
'first'
;
$crumb
= $
return
()
if
$crumb
=~ m[\D]o;
return
()
if
scalar
@
$$cursor
<
$crumb
;
return
$$cursor
->[
$crumb
]
if
!
scalar
@path
;
$cursor
= \
$$cursor
->[
$crumb
];
next
STEP;
}
return
();
}
}
sub
set {
my
(
$s
,
$var
,
$val
) =
@_
;
my
$var_reftype
=
ref
$val
;
my
@path
=
split
$Template::Liquid::Utility::VariableAttributeSeparator
,
$var
;
my
$cursor
= \
$s
->{scopes}[-1];
$cursor
= \
$$cursor
->{
shift
@path
}
if
(
exists
$$cursor
->{
$path
[0]});
STEP:
while
(
@path
) {
my
$crumb
=
shift
@path
;
my
$reftype
=
ref
$$cursor
;
if
(
$reftype
eq
'HASH'
) {
if
(!
@path
) {
if
(
exists
$$cursor
->{
$crumb
}) {
}
return
$$cursor
->{
$crumb
} =
$val
;
}
else
{
$$cursor
->{
$crumb
} =
$path
[0] =~ m[\D] ? {} : []
if
!
exists
$$cursor
->{
$crumb
};
$cursor
= \
$$cursor
->{
$crumb
};
next
STEP;
}
}
elsif
(
$reftype
eq
'ARRAY'
) {
if
(
$crumb
=~ m[\D]) {
}
if
(!
@path
) {
if
(
exists
$$cursor
->[
$crumb
]) {
}
return
$$cursor
->[
$crumb
] =
$val
;
}
else
{
$$cursor
->[
$crumb
] =
$path
[0] =~ m[\D] ? {} : []
if
!
exists
$$cursor
->[
$crumb
];
$cursor
= \
$$cursor
->[
$crumb
];
next
STEP;
}
}
else
{
if
(!
@path
) {
if
(
$crumb
=~ m[\D]) {
$$cursor
= {};
return
$$cursor
->{
$crumb
} =
$val
;
}
$$cursor
= [];
return
$$cursor
->[
$crumb
] =
$val
;
}
else
{
$$cursor
->{
$crumb
} =
$path
[0] =~ m[\D] ? {} : []
if
!
exists
$$cursor
->[
$crumb
];
$cursor
= \
$$cursor
->{
$crumb
};
next
STEP;
}
}
}
return
$$cursor
=
$val
;
}
1;