MsOffice-Word-Template
view release on metacpan or search on metacpan
lib/MsOffice/Word/Template/Engine.pm view on Meta::CPAN
package MsOffice::Word::Template::Engine;
use 5.024;
use Moose;
use MooseX::AbstractMethod;
use MsOffice::Word::Surgeon::Utils qw(decode_entities);
use namespace::clean -except => 'meta';
our $VERSION = '2.05';
#======================================================================
# ATTRIBUTES
#======================================================================
# passed through the constructor
has 'word_template' => (is => 'ro', isa => 'MsOffice::Word::Template', required => 1, weak_ref => 1);
# lazily constructed, not received through the constructor
has 'xml_regexes' => (is => 'ro', isa => 'ArrayRef[RegexpRef]',
lazy => 1, builder => '_xml_regexes', init_arg => undef);
has 'compiled_template' => (is => 'ro', isa => 'HashRef',
lazy => 1, builder => '_compiled_template', init_arg => undef);
has '_constructor_args' => (is => 'bare', isa => 'HashRef', init_arg => undef);
#======================================================================
# ABSTRACT METHODS -- to be defined in subclasses
#======================================================================
abstract 'start_tag';
abstract 'end_tag';
abstract 'compile_template';
abstract 'process_part';
abstract 'process';
#======================================================================
# GLOBALS
#======================================================================
my $XML_COMMENT_FOR_MARKING_DIRECTIVES = '<!--TEMPLATE_DIRECTIVE_ABOVE-->';
#======================================================================
# INSTANCE CONSTRUCTION
#======================================================================
sub BUILD {
my ($self, $args) = @_;
$self->{_constructor_args} = $args; # stored to be available for lazy attr constructors in subclasses
}
#======================================================================
# LAZY ATTRIBUTE CONSTRUCTORS
#======================================================================
sub _xml_regexes {
my ($self) = @_;
# start and end character sequences for a template fragment
my $rx_start = quotemeta $self->start_tag;
my $rx_end = quotemeta $self->end_tag;
# Regexes for extracting template directives within the XML.
# Such directives are identified through a specific XML comment -- this comment is
# inserted by method "template_fragment_for_run()" below.
# The (*SKIP) instructions are used to avoid backtracking after a
# closing tag for the subexpression has been found. Otherwise the
# .*? inside could possibly match across boundaries of the current
# XML node, we don't want that.
# regex for matching directives to be treated outside the text flow.
my $rx_outside_text_flow = qr{
<w:r\b [^>]*> # start run node
(?: <w:rPr> .*? </w:rPr> (*SKIP) )? # optional run properties
<w:t\b [^>]*> # start text node
($rx_start .*? $rx_end) (*SKIP) # template directive
$XML_COMMENT_FOR_MARKING_DIRECTIVES # specific XML comment
</w:t> # close text node
</w:r> # close run node
}sx;
( run in 1.723 second using v1.01-cache-2.11-cpan-99c4e6809bf )