HTML-AutoTag

 view release on metacpan or  search on metacpan

lib/HTML/AutoTag.pm  view on Meta::CPAN

    } else {
        # simple attrs can bypass being tied
        $attr_str = '';
        my @keys = $SORTED ? sort keys %$attr : keys %$attr;
        for my $key (@keys) {
            $attr_str .= ' ' . Tie::Hash::Attribute::_key( $key ) . '="' . Tie::Hash::Attribute::_val( $attr->{$key} ) . '"';
        }
    }

    # emtpy tag
    unless (defined $args{cdata}) {
        return ( $INDENT x $LEVEL )
            . "<$args{tag}"
            . ( defined( $attr_str ) ? $attr_str : scalar( %$attr ) )
            . " />$NEWLINE"
        ;
    }

    my $cdata;
    my $no_post_indent;
    if (ref($args{cdata}) eq 'ARRAY') {

        if (ref($args{cdata}[0]) eq 'HASH') {

            $LEVEL++;
            $cdata = $NEWLINE;
            for (0 .. $#{ $args{cdata} }) {
                $cdata .= $self->tag( %{ $args{cdata}[$_] } );
            }
            $LEVEL--;

        } else {
            my $str = '';
            for (@{ $args{cdata} }) {
                $str .= $self->tag( tag => $args{tag}, attr => $attr, cdata => $_);
            }
            return $str;
        }

    } elsif (ref($args{cdata}) eq 'HASH') {
        $LEVEL++;
        $cdata = $NEWLINE . $self->tag( %{ $args{cdata} } );
        $LEVEL--;

    } else {
        $cdata = $ENCODE ? HTML::Entities::encode_entities( $args{cdata}, $ENCODES ) : $args{cdata};
        $no_post_indent = 1;
    }

    return ( $INDENT x $LEVEL )
        . "<$args{tag}" . ( defined( $attr_str ) ? $attr_str : scalar( %$attr ) )
        . ">$cdata"
        . ( $no_post_indent ? '' : ( $INDENT x $LEVEL ) )
        . "</$args{tag}>$NEWLINE"
    ;
}

1;

__END__
=head1 NAME

lib/HTML/AutoTag.pm  view on Meta::CPAN

  use HTML::AutoTag;

  my $auto = HTML::AutoTag->new( indent => '    ', encode => 1 );

  my %attr = ( style => { color => [qw(red green)] } );
  my @data = qw( one two three four five six seven eight );

  print $auto->tag(
      tag   => 'ol', 
      attr  => {qw( reversed reversed )},
      cdata => [
          map { tag => 'li', attr => \%attr, cdata => $_ }, @data
      ]
  );

=head1 DESCRIPTION

Generate nested HTML (HTML4, XHTML and HTML5) tags with custom indentation,
custom encoding and automatic attribute value rotation.

=head1 METHODS

lib/HTML/AutoTag.pm  view on Meta::CPAN

Accepts three arguments:

=over 8

=item * C<tag>

The name of the tag. String.

  tag => 'table'

=item * C<cdata>

The value inbetween the tag. Types allowed are:

=over 12

=item * scalar - the string to be wrapped in tags

  cdata => 'hello world'

=item * hash ref - another tag with its own cdata and attributes

  cdata => { tag => 'td', attr => {}, cdata => 'value' }

=item * AoH - multiple tags as hash references.

  cdata => [
      { tag => 'td', attr => {}, cdata => 'value1' }
      { tag => 'td', attr => {}, cdata => 'value2' }
  ]

=back

=item * C<attr>

The attributes and values to write out for the tag. Hash reference.

  attr => { border => 1 }

lib/HTML/AutoTag.pm  view on Meta::CPAN

=head1 EXAMPLES

The following will render a table with rotating attributes:

  my $auto = HTML::AutoTag->new( indent => "    " );
  my %tr_attr = ( class => [qw(odd even)] );
  
  print $auto->tag(
      tag => 'table',
      attr => { class => 'spreadsheet' },
      cdata => [
          {
              tag => 'tr',
              attr => \%tr_attr,
              cdata => {
                  tag => 'td',
                  attr => { style => { color => [qw(red green)] } },
                  cdata => [qw(one two three four five six)],
              },
          },
          {
              tag => 'tr',
              attr => \%tr_attr,
              cdata => {
                  tag => 'td',
                  attr => { style => { color => [qw(green red)] } },
                  cdata => [qw(seven eight nine ten eleven twelve)],
              },
          },
          {
              tag => 'tr',
              attr => \%tr_attr,
              cdata => {
                  tag => 'td',
                  attr => { style => { color => [qw(red green)] } },
                  cdata => [qw(thirteen fourteen fifteen sixteen seventeen eighteen)],
              },
          },
      ]
  );

The following will emulate CGI.pm's C<scrolling_list()> output:

  my $auto = HTML::AutoTag->new( indent => "    " );

  print $auto->tag(
      tag   => 'select',
      attr  => { name => 'widgets', size => 3, multiple => 'multiple' },
      cdata => [
          { tag => 'option', cdata => 'foo', attr => { value => 1, } },
          { tag => 'option', cdata => 'bar', attr => { value => 2, selected => 'selected' } },
          { tag => 'option', cdata => 'baz', attr => { value => 3, selected => 'selected' } },
      ]
  );

Or in a more programatic way:

  my $auto = HTML::AutoTag->new( indent => "    " );

  my @selected = (2, 3);
  my @options  = (
      [ 1, 'foo' ],

lib/HTML/AutoTag.pm  view on Meta::CPAN


  my $selected = [];
  for my $o (@options) {
     push @$selected, (grep $_ eq $o->[0], @selected) ? 'selected' : undef;
  }
  my %attr = ( value => [ map $_->[0], @options ], selected => $selected );

  print $auto->tag(
      tag   => 'select',
      attr  => { name => 'widgets', size => scalar @options, multiple => 'multiple' },
      cdata => [ map { tag => 'option', attr => \%attr, cdata => $_->[1] }, @options ],
  );

See tests in C<t/> from the distribution or github for more examples:
L<https://github.com/jeffa/HTML-AutoTag/tree/master/t>

=head1 INSPIRATION

This module was the unintentional result of efforts to refactor
L<DBIx::XHTML_Table> into L<DBIx::HTML> and L<Spreadsheet::HTML>. The need
to reimplement what CGI and HTML::Element (and a slew of others out there

readme.md  view on Meta::CPAN

use HTML::AutoTag;

my $auto = HTML::AutoTag->new( indent => '    ', encode => 1 );

my %attr = ( style => { color => [qw(red green)] } );
my @data = qw( one two three four five six seven eight );

print $auto->tag(
    tag   => 'ol', 
    attr  => {qw( reversed reversed )},
    cdata => [
        map { tag => 'li', attr => \%attr, cdata => $_ }, @data
    ]
);
```

Installation
------------
To install this module, you should use CPAN. A good starting
place is [How to install CPAN modules](http://www.cpan.org/modules/INSTALL.html).

If you truly want to install from this github repo, then

t/00-load.t  view on Meta::CPAN

use Test::More tests => 9;

use_ok 'HTML::AutoTag';

my $auto = new_ok 'HTML::AutoTag';

is $auto->tag( tag => 'foo' ),
    '<foo />',
    "tag with no attributes or children";

is $auto->tag( tag => 'foo', cdata => 'bar' ),
    '<foo>bar</foo>',
    "tag with one child";

is $auto->tag( tag => 'foo', attr => { class => 'baz' } ),
    '<foo class="baz" />',
    "tag with only attributes";

is $auto->tag( tag => 'foo', attr => { class => 'baz' }, cdata => 'bar' ),
    '<foo class="baz">bar</foo>',
    "tag with attributes and one child";

is $auto->tag( tag => 'foo', cdata => [qw(bar baz qux)] ),
    '<foo>bar</foo><foo>baz</foo><foo>qux</foo>',
    "tag with multiple children";

is $auto->tag( tag => 'foo', attr => { col => [1..3] }, cdata => [qw(one two three four)] ),
    '<foo col="1">one</foo><foo col="2">two</foo><foo col="3">three</foo><foo col="1">four</foo>',
    "tag with multiple children and rotating attributes";

is $auto->tag( tag => 'bar', cdata => { tag => 'foo', attr => { col => [1..3] }, cdata => [qw(one two three four)] } ),
    '<bar><foo col="1">one</foo><foo col="2">two</foo><foo col="3">three</foo><foo col="1">four</foo></bar>',
    "nested tag with multiple children and rotating attributes";

t/01-indentation.t  view on Meta::CPAN

use warnings FATAL => 'all';
use Test::More tests => 7;

use_ok 'HTML::AutoTag';

my $auto = HTML::AutoTag->new( indent => '    ' );
is $auto->tag( tag => 'foo' ),
    "<foo />\n",
    "correct indentation for closed tag";

is $auto->tag( tag => 'foo', cdata => 'bar' ),
    "<foo>bar</foo>\n",
    "correct indentation for tag with scalar cdata";

is $auto->tag( tag => 'foo', cdata => [qw(bar baz qux)] ),
    "<foo>bar</foo>
<foo>baz</foo>
<foo>qux</foo>
",
    "correct indentation for tag with array ref cdata";

is $auto->tag( tag => 'foo', cdata => { tag => 'bar' } ),
    "<foo>
    <bar />
</foo>
",
    "correct indentation for tag with empty tag cdata";

is $auto->tag( tag => 'bar', cdata => { tag => 'foo', attr => { col => [1..3] }, cdata => [qw(one two three four)] } ),
    '<bar>
    <foo col="1">one</foo>
    <foo col="2">two</foo>
    <foo col="3">three</foo>
    <foo col="1">four</foo>
</bar>
',
    "correct indentation for cdata as array ref";

is $auto->tag(
    tag => 'bar',
    cdata => { 
        tag => 'foo', 
        cdata => [ map { tag => 'bar', }, 1.. 4 ]
    }
), '<bar>
    <foo>
        <bar />
        <bar />
        <bar />
        <bar />
    </foo>
</bar>
',
    "correct indentation for cdata as hash ref";

t/02-list.t  view on Meta::CPAN

use warnings FATAL => 'all';
use Test::More tests => 1;

use HTML::AutoTag;

my $auto = HTML::AutoTag->new( indent => '    ' );
my %attr = ( class => [qw(odd even)] );
my @data = qw( one two three four five six seven eight );
is $auto->tag(
    tag   => 'ol', 
    cdata => [
        map { tag => 'li', attr => \%attr, cdata => $_ }, @data
    ]
), '<ol>
    <li class="odd">one</li>
    <li class="even">two</li>
    <li class="odd">three</li>
    <li class="even">four</li>
    <li class="odd">five</li>
    <li class="even">six</li>
    <li class="odd">seven</li>
    <li class="even">eight</li>

t/03-table.t  view on Meta::CPAN

use Test::More tests => 1;

use HTML::AutoTag;

my $auto = HTML::AutoTag->new( indent => '    ' );
my %tr_attr = ( class => [qw(odd even)] );

is $auto->tag(
    tag => 'table',
    attr => { class => 'spreadsheet' },
    cdata => [
        {
            tag => 'tr',
            attr => \%tr_attr,
            cdata => {
                tag => 'td',
                attr => { style => { color => [qw(red green)] } },
                cdata => [qw(one two three four five six)],
            },
        },
        {
            tag => 'tr',
            attr => \%tr_attr,
            cdata => {
                tag => 'td',
                attr => { style => { color => [qw(red green)] } },
                cdata => [qw(seven eight nine ten eleven twelve)],
            },
        },
        {
            tag => 'tr',
            attr => \%tr_attr,
            cdata => {
                tag => 'td',
                attr => { style => { color => [qw(red green)] } },
                cdata => [qw(thirteen fourteen fifteen sixteen seventeen eighteen)],
            },
        },
    ]
), '<table class="spreadsheet">
    <tr class="odd">
        <td style="color: red">one</td>
        <td style="color: green">two</td>
        <td style="color: red">three</td>
        <td style="color: green">four</td>
        <td style="color: red">five</td>

t/04-deep-nest.t  view on Meta::CPAN

use strict;
use warnings FATAL => 'all';
use Test::More tests => 1;

use HTML::AutoTag;

my $auto = HTML::AutoTag->new( indent => '    ' );

is $auto->tag(
    tag => 'aaa',
    cdata => {
        tag => 'bbb',
        cdata => {
            tag => 'ccc',
            cdata => {
                tag => 'ddd',
                cdata => {
                    tag => 'eee',
                    cdata => {
                        tag => 'fff',
                        cdata => {
                            tag => 'ggg',
                            cdata => {
                                tag => 'hhh',
                                cdata => ':D',
                            }
                        }
                    }
                }
            }
        }
    }
), '<aaa>
    <bbb>
        <ccc>

t/05-encodes.t  view on Meta::CPAN

#!perl -T
use 5.006;
use strict;
use warnings FATAL => 'all';
use Test::More tests => 8;

use HTML::AutoTag;

my $auto = HTML::AutoTag->new();

is $auto->tag( tag => 'foo', cdata => '<bar baz="qux">' ),
    '<foo><bar baz="qux"></foo>',
    "encodes turned off by default";

$auto = HTML::AutoTag->new( encode => 1 );
is $auto->tag( tag => 'foo', cdata => '<bar baz="qux">' ),
    '<foo>&lt;bar baz=&quot;qux&quot;&gt;</foo>',
    "setting encode to true encodes default chars";

$auto = HTML::AutoTag->new( encode => 1, encodes => '' );
is $auto->tag( tag => 'foo', cdata => '<bar baz="qux">' ),
    '<foo>&lt;bar baz=&quot;qux&quot;&gt;</foo>',
    "setting encodes to '' with encode set to true encodes default";

$auto = HTML::AutoTag->new( encode => 1, encodes => undef );
is $auto->tag( tag => 'foo', cdata => '<bar baz="qux">' ),
    '<foo>&lt;bar baz=&quot;qux&quot;&gt;</foo>',
    "setting encodes to undef with encode set to true encodes default";

$auto = HTML::AutoTag->new( encodes => 0 );
is $auto->tag( tag => 'foo', cdata => '<bar baz="0">' ),
    '<foo><bar baz="&#48;"></foo>',
    "encodes turned on for character 0";

$auto = HTML::AutoTag->new( encodes => '<=' );
is $auto->tag( tag => 'foo', cdata => '<bar baz="qux">' ),
    '<foo>&lt;bar baz&#61;"qux"></foo>',
    "encodes turned on for specific chars";

$auto = HTML::AutoTag->new( encode => 0, encodes => '<=' );
is $auto->tag( tag => 'foo', cdata => '<bar baz="qux">' ),
    '<foo><bar baz="qux"></foo>',
    "encodes turned off when encode is 0";

$auto = HTML::AutoTag->new( encode => '', encodes => '<=' );
is $auto->tag( tag => 'foo', cdata => '<bar baz="qux">' ),
    '<foo><bar baz="qux"></foo>',
    "encodes turned off when encode is ''";

t/10-tagset.t  view on Meta::CPAN

        ( keys %HTML::Tagset::isHeadOrBodyElement ),
        ( keys %HTML::Tagset::isKnown ),
    );
    %containers = map { $_ => undef } @containers;
}

my $auto = HTML::AutoTag->new( indent => '', sorted => 1 );

my @given;
push @given, $auto->tag( tag => $_ ) for sort keys %empty;
push @given, $auto->tag( tag => $_, cdata => '' ) for sort keys %containers;

for (sort keys %HTML::Tagset::linkElements) {
    my $attr = { map { $_ => 'value' } @{ $HTML::Tagset::linkElements{$_} } };
    push @given, $auto->tag( tag => $_, attr => $attr, cdata => '' );
}

for (sort keys %HTML::Tagset::boolean_attr) {
    my $thingy = $HTML::Tagset::boolean_attr{$_};
    my $attr = ref($thingy) eq 'HASH' ? $thingy : { $thingy => 1 };
    push @given, $auto->tag( tag => $_, attr => $attr, cdata => '' );
}

for (sort @given) {
    chomp( $_ );
    is "$_\n", <DATA>,  "correctly formed: $_";
}

__DATA__
<a href="value"></a>
<a></a>

t/11-svg.t  view on Meta::CPAN

use warnings FATAL => 'all';
use Test::More tests => 1;

use HTML::AutoTag;

my $auto = HTML::AutoTag->new( sorted => 1 );

is $auto->tag(
    tag => 'svg',
    attr => { width=>"12cm", height=>"4cm", viewBox=>"0 0 1200 400", xmlns=>"http://www.w3.org/2000/svg", version=>"1.1" },
    cdata => [
        {
            tag => 'desc',
            cdata => 'Example circle01 - circle filled with red and stroked with blue',
        },
        {
            tag => 'rect',
            attr => { x=>"1", y=>"1", width=>"1198", height=>"398", fill=>"none", stroke=>"blue", 'stroke-width'=>"2" },
        },
        {
            tag => 'circle',
            attr => { cx=>"600", cy=>"200", r=>"100", fill=>"red", stroke=>"blue", 'stroke-width'=>"10" },
        },
    ]



( run in 0.692 second using v1.01-cache-2.11-cpan-e1769b4cff6 )