sub table { my ($tab,$opt) = @_; my @attributes; push @attributes, qq(id="$opt->{id}") if $opt->{id}; push @attributes, qq(class="$opt->{class}") if $opt->{class}; push @attributes, qq(style="$opt->{style}") if $opt->{style}; my $format = @attributes > 0 ? ' '.join(' ',@attributes) : ''; my $tag = 'table'.$format; line($tab,qq(<$tag>)); line($tab + 1,qq($opt->{caption})) if $opt->{caption}; row($tab + 1,'header',$opt->{headings}) if $opt->{headings}; $_->output($tab+1) for @{$opt->{rows} || []}; line($tab,q()); } { package MyCell; sub output { my $self = shift; my ($tab) = @_; ::line($tab, qq(@$self)); } } { package MyCell::Header; use base "MyCell"; sub output { my $self = shift; my ($tab) = @_; ::line($tab, qq(@$self)); } } { package MyRow; sub cells { my $self = shift; return map { bless [$_], "MyCell" } @$self; } sub output { my $self = shift; my ($tab) = @_; ::line($tab,qq()); $_->output($tab + 1) for $self->cells; ::line($tab,qq()); } } { package MyRow::WithHead; use base "MyRow"; sub cells { my $self = shift; my @cells = $self->SUPER::cells; bless $cells[0], "MyCell::Header"; return @cells; } } sub data { bless \@_, "MyRow" } sub whead { bless \@_, "MyRow::WithHead" } table(1, { id => 't1', headings => [qw/NAME STRENGTH COMMENT/], rows => [ whead(qw/1 2 no/), data( qw/2 3 yes/), whead(qw/10 20 another/), data( qw/100 200 comment/), ], });