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 )