Builder

 view release on metacpan or  search on metacpan

lib/Builder/XML.pm  view on Meta::CPAN

}

sub AUTOLOAD {
    my ( $self ) = shift;
    my @args = @_;

    if ( $AUTOLOAD =~ /.*::(.*)/ ) {
        my $elt = $1;
        my $attr = undef;
        
        # sub args get resent as callback
        if ( wantarray ) {
             return sub { $self->$elt( @args ) };
        }
        
        # if first arg is hasharray then its attributes!
        $attr = shift @args  if ref $args[0] eq 'HASH';
        
        if ( ref $args[0] eq 'CODE' ) { 
            $self->__element__( context => 'start', element => $elt, attr => $attr );
            for my $inner ( @args ) {
                if ( ref $inner eq 'CODE' ) { $inner->() }
                else { $self->__push__( sub { $inner } ) }
            }
            $self->__element__( context => 'end', element => $elt );
            return;
        }
        
        # bog standard element         
        $self->__element__( element => $elt, attr => $attr, text => "@args" );
    }
    
    $self;
}


######################################################
# methods

sub __render__ {
    my $self = shift;
    my $render;
    
    # render subs just for this block
    my @this_block = Builder::Utils::yank { $_->[0] == $self->{block_id} } @{ $self->{stack} };    
    while ( my $block = shift @this_block ) {
        my ( $block_id, $code ) = @$block;
        $render.= $code->();
    }
    return $render;
}

sub __element__ {
    my ( $self, %param ) = @_;
    $param{ text    } ||= '';
    $param{ context } ||= 'element';
    $self->{ context }->{ $param{ context } }->( $self, \%param );
    return;
}

sub __cdata__ {
    my $self = shift;
    return $_[0]  if $self->{ cdata } == 1;
    return $self->__cdatax__( $_[0] );
}

sub __cdatax__ {
    my $self = shift;
    return q{<![CDATA[} . $_[0] . q{]]>};
}

sub __say__ {
    my ( $self, @say ) = @_;
    for my $said ( @say ) { $self->__push__( sub { $said } ) }
    $self;
}

sub __push__ {
    my ( $self, $code ) = @_;
    
    # straight to output stream if provided
    if ( $self->{ _output } ) {
        print { $self->{ _output } } $code->();
        return;
    }
    
    # else add to stack
    push @{ $self->{ stack } }, [ $self->{ block_id }, $code ];
}

sub __inc__ { $_[0]->{ _inc }->() }

sub __dec__ { $_[0]->{ _dec }->() }

sub __level__ { $_[0]->{ _level }->() }

sub __tab__ {
    my $self = shift;
    my $tab = q{};
    $tab = q{ } x $self->{ pre_indent }                     if $self->{ pre_indent };
    $tab.= q{ } x ( $self->{ indent } * $self->__level__ )  if $self->{ indent };
    return $tab;
}

sub __start_tab__ { $_[0]->__tab__ }

sub __end_tab__ {
    my $self = shift;
    return q{}  if $self->{ newline } && ! $self->{ open_newline };
    $self->__tab__;
}

sub __open_newline__ {
    my $self = shift;
    return $self->{cr} if $self->{ open_newline };
    return q{};
}

sub __close_newline__ {
    my $self = shift;
    return $self->{cr} if $self->{ close_newline };
    return q{};
}

sub DESTROY {
    my $self = shift;
    $self = undef;

lib/Builder/XML.pm  view on Meta::CPAN

    $xm->div(
        $xm->div(
            xm->span( 'hi there'),
        ),
    );
    
    # => <div><div><span>hi there</span></div></div>


=head2 Gotchas?

TODO: XML entities not implemented

TODO: invalid method calls...  $xm->flip-flop, $xm->DESTROY, $xm->AUTOLOAD

TODO: Fix / workaround for attribute ordering


=head1 EXPORT

None.


=head1 METHODS

All methods are prefix/postfixed with __ so that ambigious method calls wont clash 
and can be turned successfully into XML elements.

Below is a complete list of defined methods in Builder::XML.
NB. Most of these are private methods and only listing here for reference.


=head2 __new__

Private. 

This is the contructor called by the Builder object when creating a block...

    $xm = $builder->block( 'Builder::XML' );
    
All arguments are passed from Builder->block method straight to Builder::XML->__new__
 

=head2 __render__

Will immediately render the building block.  
Can be useful in some cases...

    # provide example here of it working
    
    # and then provide example of what can go wrong!

...but recommend $builder->render for best practise.


=head2 __element__

Private


=head2 __cdata__

Wraps content in <![CDATA[ ]]> element.  
Useful for quick ditties like....

    $xm->span( $xm->__cdata__( 'yada yada' ) );
    
    # => <span><!CDATA[yada yada]]></span>
    
But for best practise you probably still find building a block more useful in the long run...

    my $xm = $builder->block( 'Builder::XML', { cdata => 1 } );
    
    $xm->span( 'yada yada' );


=head2 __cdatax__

PRIVATE - used with __cdata__


=head2 __say__

Really a Private method but as mentioned in I<Gotchas> it can be useful for working around some implementation issues.

=head2 __push__

Private


=head2 __inc__

Private


=head2 __dec__

Private


=head2 __level__

Private


=head2 __tab__

Private


=head2 __start_tab__

Private


=head2 __end_tab__

Private


=head2 __open_newline__

Private


=head2 __close_newline__

Private


=head2 AUTOLOAD

Used in method to XML element resolution.   

Therefore at present AUTOLOAD cannot be used as a XML element.


=head2 DESTROY



( run in 0.543 second using v1.01-cache-2.11-cpan-6aa56a78535 )