The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Net::API::Telegram::${name} - ${shortDesc}

SYNOPSIS

        my \$msg = Net::API::Telegram::${name}->new( \%data ) || 
        die( Net::API::Telegram::${name}->error, "\\n" );

DESCRIPTION

Net::API::Telegram::${name} is a Telegram Message Object as defined here $ref-{link}>

This module has been automatically generated from Telegram API documentation by the script scripts/telegram-doc2perl-methods.pl.

METHODS

new( {INIT HASH REF}, \%PARAMETERS )

new() will create a new object for the package, pass any argument it might receive to the special standard routine init that must exist. Then it returns what returns init().

The valid parameters are as follow. Methods available here are also parameters to the new method.

  • verbose

  • debug

EOT

                if( !scalar( keys( %$def ) ) )
                {
                        $fh->print( "There is no other method available.\n\n" );
                }
                FIELD: foreach my $field ( sort( keys( %$def ) ) )
                {
                        my $this = $def->{ $field };
                        my $desc = $this->{desc};
                        $desc =~ s/\x{201c}([^\x{201d}]+)\x{201d}/I<$1>/gs;
                        my $type = $this->{type};
                        if( $field eq 'download' )
                        {
                                $fh->print( <<EOT );
=item B<download>( file_id, [ file extension ] )

Given a file id like ${example_ids_str}, this will call the getFile() method from the parent Net::API::Telegram package and receive a Net::API::Telegram::File object in return, which contains a file path valid for only one hour according to Telegram api here https://core.telegram.org/bots/api#getfile. With this file path, this download method will issue a http get request and retrieve the file and save it locally in a temproary file generated by File::Temp. If an extension is provided, it will be appended to the temproary file name such as myfile.jpg otherwise the extension will be gussed from the mime type returned by the Telegram http server, if any.

This method returns undef() on error and sets a Net::API::Telegram::Error or, on success, returns a hash reference with the following properties:

filepath

The full path to the temporary file

mime

The mime type returned by the server.

response

The HTTP::Response

size

The size in bytes of the file fetched

$desc

EOT } $fh->print( <<EOT ); =back

COPYRIGHT

Copyright (c) 2000-2019 DEGUEST Pte. Ltd.

AUTHOR

Jacques Deguest <jack\@deguest.jp>

SEE ALSO

Net::API::Telegram

COPYRIGHT & LICENSE

Copyright (c) 2018-2019 DEGUEST Pte. Ltd.

You can use, copy, modify and redistribute this package and associated files under the same terms as Perl itself.

${meth}(${has_params})

${meth_desc}

Reference: $ref-{link}>

EOT if( length( $has_params ) ) { $fh->print( <<EOT ); This methods takes the following parameters:

    EOT my $packages_to_require = []; my $def = {}; foreach my $this ( @{$ref->{definition}} ) { $def->{ $this->{field} } = $this; } PARAM: foreach my $field ( sort( keys( %$def ) ) ) { my $this = $def->{ $field }; my $is_required_or_not = $this->{required} eq 'Optional' ? 'optional' : 'required'; my $type = $this->{type}; ## $type could be: String, Integer, Boolean, Float, Float number, an object like InputFile ## or an array of objects like "Array of InlineQueryResult" ## or an array of objects with multiple possibilities like "Array of InputMediaPhoto and InputMediaVideo" ## or multiple object possibilities like "InlineKeyboardMarkup or ReplyKeyboardMarkup or ReplyKeyboardRemove or ForceReply" $fh->print( <<EOT ); =item ${field}

    EOT if( lc( $this->{required} ) eq 'yes' ) { $fh2->print( <<EOT ); return( \$self->error( "Missing parameter ${field}" ) ) if( !exists( \$opts->{ '${field}' } ) ); EOT }

                                    if( exists( $all_objects->{ $type } ) )
                                    {
                                            push( @$packages_to_require, $type );
                                            $fh->print( <<EOT );
    This parameter type is an object L<Net::API::Telegram::$this->{type}> and is ${is_required_or_not}.
    EOT
                                            if( $is_required_or_not eq 'required' )
                                            {
                                                    $fh2->print( <<EOT );
            return( \$self->error( "Value provided for ${field} is not a Net::API::Telegram::$this->{type} object." ) ) if( ref( \$opts->{ '${field}' } ) ne 'Net::API::Telegram::$this->{type}' );
    EOT
                                            }
                                            else
                                            {
                                                    $fh2->print( <<EOT );
            return( \$self->error( "Value provided for ${field} is not a Net::API::Telegram::$this->{type} object." ) ) if( length( \$opts->{ '${field}' } ) && ref( \$opts->{ '${field}' } ) ne 'Net::API::Telegram::$this->{type}' );
    EOT
                                            }
                                    }
                                    elsif( $type =~ /^Array[[:blank:]]+of[[:blank:]]+(.*?)$/ )
                                    {
                                            my $objects_found = $1;
                                            ## Set this by default
                                            my $word = 'and';
                                            if( $objects_found =~ /[[:blank:]]+(and|or)[[:blank:]]+/ )
                                            {
                                                    $word = $1;
                                            }
                                            my @those_objects = grep{ exists( $all_objects->{ $_ } ) } split( /[[:blank:]]+$word[[:blank:]]+/, $objects_found );
                                            push( @$packages_to_require, @those_objects );
                                            my @formatted = map( sprintf( 'L<Net::API::Telegram::%s>', $_ ), @those_objects );
                                            my $formatted_objects = join( " $word ", @formatted );
                                            $fh->print( <<EOT );
    This parameter type is an array of $formatted_objects and is ${is_required_or_not}.
    EOT
                                            my $object_pattern = join( '|', map( sprintf( 'Net::API::Telegram::%s', $_ ), @those_objects ) );
                                            my $object_list = join( ', ', @those_objects );
                                            if( lc( $this->{required} ) eq 'yes' )
                                            {
                                                    $fh2->print( <<EOT );
            return( \$self->error( "Value provided for ${field} is not an array reference." ) ) if( ref( \$opts->{ '${field}' } ) ne 'ARRAY' );
    EOT
                                                    if( scalar( @those_objects ) )
                                                    {
                                                            $fh2->print( <<EOT );
            return( \$self->error( "Value provided is not an array of either of this objects: ${object_list}" ) ) if( !\$self->_param_check_array_object( qr\/^\(\?\:${object_pattern}\)\$/, \@_ ) );
    EOT
                                                    }
                                            }
                                            else
                                            {
                                                    $fh2->print( <<EOT );
            return( \$self->error( "Value provided for ${field} is not an array reference." ) ) if( length( \$opts->{ '${field}' } ) && ref( \$opts->{ '${field}' } ) ne 'ARRAY' );
    EOT
                                                    if( scalar( @those_objects ) )
                                                    {
                                                            $fh2->print( <<EOT );
            return( \$self->error( "Value provided is not an array of either of this objects: ${object_list}" ) ) if( length( \$opts->{ '${field}' } ) && !\$self->_param_check_array_object( qr\/^\(\?\:${object_pattern}\)\$/, \@_ ) );
    EOT
                                                    }
                                            }
                                    }
                                    elsif( $type =~ /^(\S+)[[:blank:]](and|or)[[:blank:]]+/ )
                                    {
                                            my $word = $2;
                                            # $out->print( "Type found is '$type' and word is '$word'\n" );
                                            my @those_objects = split( /[[:blank:]]+${word}[[:blank:]]+/, $type );
                                            ## my @formatted = map( sprintf( 'L<Net::API::Telegram::%s>', $_ ), @those_objects );
                                            my @formatted = ();
                                            foreach my $o ( @those_objects )
                                            {
                                                    # $out->print( "Checking if '$o' is an object: ", exists( $all_objects->{ $o } ) ? 'yes' : 'no', "\n" );
                                                    if( exists( $all_objects->{ $o } ) )
                                                    {
                                                            push( @formatted, sprintf( 'L<%s>', $o ) );
                                                    }
                                                    else
                                                    {
                                                            push( @formatted, $o );
                                                    }
                                            }
                                            my $formatted_objects = join( " $word ", @formatted );
                                            $fh->print( <<EOT );
    This parameter type is one of the following $formatted_objects and is ${is_required_or_not}.
    EOT
                                            my $object_pattern = join( '|', map( sprintf( 'Net::API::Telegram::%s', $_ ), grep{ exists( $all_objects->{ $_ } ) } @those_objects ) );
                                            push( @$packages_to_require, grep{ exists( $all_objects->{ $_ } ) } @those_objects );
                                            my $object_list = join( ', ', @those_objects );
                                            ## Empty pattern means all of the objects are actually String, Integer or Boolean, ie non-objects
                                            if( !length( $object_pattern ) )
                                            {
                                                    if( lc( $this->{required} ) eq 'yes' )
                                                    {
                                                            $fh2->print( <<EOT );
            return( \$self->error( "Value provided for ${field} is not a valid value. I was expecting one of the following: ${object_list}" ) ) if( !length( \$opts->{ '${field}' } ) );
    EOT
                                                    }
                                            }
                                            else
                                            {
                                                    if( lc( $this->{required} ) eq 'yes' )
                                                    {
                                                            $fh2->print( <<EOT );
            return( \$self->error( "Value provided for ${field} is not a valid object. I was expecting one of the following: ${object_list}" ) ) if( ref( \$opts->{ '${field}' } ) !~ \/^\(\?\:${object_pattern})\$/ );
    EOT
                                                    }
                                                    else
                                                    {
                                                            $fh2->print( <<EOT );
            return( \$self->error( "Value provided for ${field} is not a valid object. I was expecting one of the following: ${object_list}" ) ) if( length( \$opts->{ '${field}' } ) && ref( \$opts->{ '${field}' } ) !~ \/^\(\?\:${object_pattern})\$/ );
    EOT
                                                    }
                                            }
                                    }
                                    else
                                    {
                                            $fh->print( <<EOT );
    This parameter type is $this->{type} and is ${is_required_or_not}.

    EOT } $fh->print( <<EOT ); $this->{desc}

    EOT } $fh->print( "=back\n\n" ); if( scalar( @$packages_to_require ) ) { $fh2->printf( " \$self->_load( [qw( %s )] ) || return( undef() );\n", join( ' ', map( 'Net::API::Telegram::' . $_, @$packages_to_require ) ) ); } } ## No parameter for this method else { $fh->print( "This method does not take any parameter.\n\n" ); } my $methReturn = $ref->{return}; chomp( $methReturn ); $fh2->print( <<EOT ); my \$form = \$self->_options2form( \$opts ); my \$hash = \$self->query({ 'method' => '${meth}', 'data' => \$form, }) || return( \$self->error( "Unable to make post query for method ${meth}: ", \$self->error->message ) ); ${methReturn} }

    EOT } $fh->print( "=back\n\n" ); $fh->close; $fh2->close; my $exit_value = 0; if( !defined( my $res = qx{perl -c $script_dir/methods.pl} ) ) { $out->print( "Error found in $script_dir/methods.pl\n" ); $exit_value = 1; } my $pod_checker = Pod::Checker->new( %options ); $pod_checker->parse_from_file( "$script_dir/methods.pod", \*STDERR ); if( $pod_checker->num_errors ) { $out->printf( "%d errors found in $script_dir/methods.pod\n", $pod_checker->num_errors ); $exit_value = 1; } else { $out->print( "$script_dir/methods.pod syntaxt OK\n" ); } $out->printf( "%d warnings found in $script_dir/methods.pod\n", $pod_checker->num_warnings ) if( $pod_checker->num_warnings );

            if( !$exit_value )
            {
                    my $main_file = "$basedir/lib/Net/API/Telegram.pm";
                    my $new_file = "$basedir/lib/Net/API/Telegram-new.pm";
                    my $fh_perl = IO::File->new( "<$script_dir/methods.pl" ) || die( "Unable to open the auto generated methods perl code: $!\n" );
                    my $fh_pod = IO::File->new( "<$script_dir/methods.pod" ) || die( "Unable to open the auto generated methods pod documentation: $!\n" );
                    my $fh_in = IO::File->new( "<$main_file" ) || die( "Unable to open Telegram.pm in read mode: $!\n" );
                    my $fh_out = IO::File->new( ">$new_file" ) || die( "Unable to create new Telegram.pm file in $new_file: $!\n" );
                    $fh_perl->binmode( ':utf8' );
                    $fh_pod->binmode( ':utf8' );
                    $fh_in->binmode( ':utf8' );
                    $fh_out->binmode( ':utf8' );
                    my $l;
                    ## 0 = not inside the are yet; 1 = inside; 2 = done; 3 = reached the end limit
                    my $method_status = 0;
                    my $pod_status = 0;
                    while( defined( $l = $fh_in->getline ) )
                    {
                            if( $l =~ /^## START DYNAMICALLY GENERATED METHODS/ )
                            {
                                    $method_status = 1;
                                    $fh_out->print( $l );
                            }
                            elsif( $l =~ /^## END DYNAMICALLY GENERATED METHODS/ )
                            {
                                    $method_status = 3;
                                    $fh_out->print( $l );
                            }
                            elsif( $l =~ /^=head1 API METHODS/ )
                            {
                                    $pod_status = 1;
                                    ## This is not an oversight, the generated pod file contains this line already
                            }
                            elsif( $l =~ /^=head1 COPYRIGHT/ )
                            {
                                    $pod_status = 3;
                                    $fh_out->print( $l );
                            }
                            elsif( $method_status == 1 )
                            {
                                    $fh_out->print( $_ ) while( defined( $_ = $fh_perl->getline ) );
                                    $method_status = 2;
                            }
                            elsif( $method_status == 2 || $pod_status == 2 )
                            {
                                    next;
                            }
                            elsif( $pod_status == 1 )
                            {
                                    my $found_start = 0;
                                    while( defined( $_ = $fh_pod->getline ) )
                                    {
                                            $found_start++ if( /^=head1 API METHODS/ );
                                            next if( !$found_start && $_ !~ /^=head1 API METHODS/ );
                                            $fh_out->print( $_ );
                                    }
                                    $pod_status = 2;
                            }
                            else
                            {
                                    $fh_out->print( $l );
                            }
                    }
                    $fh_out->close;
                    $fh_in->close;
                    $fh_perl->close;
                    $fh_pod->close;
                    if( !$method_status )
                    {
                            $out->print( "** Failed to find the markeer for the start of auto generated perl methods insertion.\n" );
                            $exit_value = 1;
                    }
                    elsif( !$pod_status )
                    {
                            $out->print( "** Failed to find the start (=head1 API METHODS) for auto generated pod insertion.\n" );
                            $exit_value = 1;
                    }
                    elsif( -z( $new_file ) )
                    {
                            $out->print( "** Newly generated Telegram.pm file $new_file is empty!\n" );
                            $exit_value = 1;
                    }
    #               elsif( -s( $new_file ) < -s( $main_file ) )
    #               {
    #                       $out->print( "** Newly created file size is smaller than previous one, which is not normal\n" );
    #                       $exit_value = 1;
    #               }
                    elsif( !defined( my $res = qx{perl -I${basedir}/lib -c $new_file} ) )
                    {
                            $out->print( "** Error found in $new_file\n" );
                            $exit_value = 1;
                    }
                    elsif( !rename( $main_file, "$main_file.bak" ) )
                    {
                            $out->print( "** Unable to move original Telegram.pn file to $main_file.bak\n" );
                            $exit_value = 1;
                    }
                    elsif( !rename( $new_file, $main_file ) )
                    {
                            $out->print( "** Unable to move new Telegram.pn file to $main_file\n" );
                            $exit_value = 1;
                    }
            }
            exit( $exit_value );
    }

    sub explore { my $telegramAPIURL = 'https://core.telegram.org/bots/api'; my $uri = URI->new( $telegramAPIURL ); $ua->default_header( 'Content_Type' => 'multipart/form-data' ); my $cache_file = "$script_dir/telegram-api.html"; my $html; if( -e( $cache_file ) && -s( _ ) ) { $out->print( "Re-using cached html\n" ); my $tmp = IO::File->new( "<$cache_file" ) || die( "$cache_file: $!\n" ); $tmp->binmode( ':utf8' ); $html = join( '', $tmp->getlines ); $tmp->close; } else { my $resp = $ua->get( $uri ) || die( $ua->error, "\n" ); if( !$resp->is_success ) { die( sprintf( "Unable to access $uri: %s (%s)\n", $resp->message, $resp->code ) ); } $html = $resp->decoded_content; $out->print( "Saving html fetched\n" ); my $tmp = IO::File->new( ">$cache_file" ) || die( "$cache_file: $!\n" ); $tmp->binmode( ':utf8' ); $tmp->autoflush( 1 ); $tmp->print( $html ); $tmp->close; } my $t = HTML::TreeBuilder->new; $t->parse( $html ); $t->eof();

            my @h4 = $t->look_down( '_tag' => 'h4' );
            my @anchors = ();
            foreach my $title ( @h4 )
            {
                    my $a = $title->look_down( '_tag' => 'a', 'name' => qr/\S+/ );
                    push( @anchors, { 'name' => $title, 'link' => $a } ) if( defined( $a ) );
            }
            $out->printf( "Found %d anchors\n", scalar( @anchors ) );
            $out->print( "Now checking which one is an anchor for an object definition...\n" );
            my $objects = [];
            my $methods = [];
            ANCHOR: foreach my $info ( @anchors )
            {
                    #my $txt = $a->as_trimmed_text;
                    my $name = $info->{name};
                    my $txt  = $info->{name}->as_trimmed_text;
                    my $link = $uri->clone;
                    #$link->path( $link->path . $info->{link}->attr( 'href' ) );
                    $link->fragment( substr( $info->{link}->attr( 'href' ), 1 ) );
                    #$out->printf( "Checking anchor '$txt' (%s)...\n", $a->as_HTML( '' ) );
                    $out->printf( "Checking anchor '$txt' (%s)...\n", $link );
                    ## Object name start with upper case. Methods start with lower case
                    if( $txt =~ /^[A-Z]\S+$/ )
                    {
                            $out->print( "\tok, name looks like an object\n\tChecking for a table in following elements...\n" );
                            my $hash = { 'name' => $txt, 'link' => $link, 'type' => 'object' };
                            ## Now let's look for a table definition that follows...
                            ## The anchor is contained inside a h4 tag
                            #my @next = $a->parent->right;
                            my @next = $name->right;
                            $out->printf( "\t\tFound %d following elements\n", scalar( @next ) );
                            ## Let's look for a table within the next 10 rightmost sibllings
                            KINS: for( my $i = 0; $i < 10; $i++ )
                            {
                                    my $this = $next[$i];
                                    next if( !ref( $this ) );
                                    $out->printf( "\t\t\tChecking tag %s\n", $this->tag );
                                    if( $this->tag eq 'table' )
                                    {
                                            $out->print( "\t" x 4, "Found a table, checking if this is an object definition one...\n" );
                                            my @ths = $this->look_down( '_tag' => 'th' );
                                            if( !scalar( @ths ) )
                                            {
                                                    $out->print( "\tCould not find any th tags in this table for anchor '$txt'\n" );
                                                    next;
                                            }
                                            ## Yeah, we have a winner !
                                            my @header = map( $_->as_trimmed_text, @ths );
                                            $out->printf( ( "\t" x 4 ) . "th1 => '%s', th2 => '%s' and th3 => '%s'\n", @header );
                                            if( $header[0] eq 'Field' && $header[1] eq 'Type' && $header[2] eq 'Description' )
                                            {
                                                    my @tds = $this->look_down( '_tag' => 'td' );
                                                    if( scalar( @tds ) % 3 )
                                                    {
                                                            $out->printf( "\tI found a candidate table for object '$txt', but there are %d columns, and I was expecting a multiplier of 3!\n", scalar( @tds ) );
                                                    }
                                                    my $all = [];
                                                    for( my $j = 0; $j < scalar( @tds ); $j += 3 )
                                                    {
                                                            my $def = {};
                                                            $def->{field} = $tds[$j]->as_trimmed_text;
                                                            $def->{type} = $tds[$j+1]->as_trimmed_text;
                                                            $def->{desc} = $tds[$j+2]->as_trimmed_text;
                                                            push( @$all, $def );
                                                    }
                                                    $hash->{definition} = $all;
                                                    ## Post processing description
                                                    if( scalar( @{$hash->{description}} ) > 1 )
                                                    {
                                                            my @parts = map( $_->as_HTML( '' ), @{$hash->{description}} );
                                                            ## I don't know how else to merger HTML::Element
                                                            my $t = HTML::TreeBuilder->new;
                                                            $t->parse( join( '', @parts ) );
                                                            $t->eof();
                                                            $hash->{description} = $t;
                                                    }
                                                    else
                                                    {
                                                            $hash->{description} = $hash->{description}->[0];
                                                    }
                                                    push( @$objects, $hash );
                                                    $out->printf( "Adding %d types definition for object '$txt'\n", scalar( @$all ) );
                                                    next ANCHOR;
                                            }
                                            else
                                            {
                                                    $out->print( "\t" x 4, "Nope, not the right one\n" );
                                            }
                                    }
                                    elsif( $this->tag eq 'p' && !exists( $hash->{description} ) )
                                    {
                                            $out->printf( ( "\t" x 4 ) . "Found tag p with text: '%s'\n", $this->as_trimmed_text );
                                            ## $hash->{description} = $this;
                                            $hash->{description} = [] if( !exists( $hash->{description} ) );
                                            push( @{$hash->{description}}, $this );
                                    }
                            }
                            
                            ## I have a description, but no table found. This is likely to be an object with no parameter like InputFile
                            if( $hash->{description} && !exists( $hash->{definition} ) )
                            {
                                    ## Post processing description
                                    if( scalar( @{$hash->{description}} ) > 1 )
                                    {
                                            my @parts = map( $_->as_HTML( '' ), @{$hash->{description}} );
                                            ## I don't know how else to merger HTML::Element
                                            my $t = HTML::TreeBuilder->new;
                                            $t->parse( join( '', @parts ) );
                                            $t->eof();
                                            $hash->{description} = $t;
                                    }
                                    else
                                    {
                                            $hash->{description} = $hash->{description}->[0];
                                    }
                                    push( @$objects, $hash );
                                    $out->printf( "Adding object '$txt', but with no definition\n", scalar( @$all ) );
                                    next ANCHOR;
                            }
                    }
                    ## e.g. answerPreCheckoutQuery
                    elsif( $txt =~ /^[a-z]+[A-Z][a-z]+?(?:[a-z]+[A-Z][a-z]+?)*$/ )
                    {
                            $out->print( "\tok, name looks like a method\n\tChecking for a table in following elements...\n" );
                            my $hash = { 'name' => $txt, 'link' => $link, 'type' => 'method' };
                            my @next = $name->right;
                            $out->printf( "\t\tFound %d following elements\n", scalar( @next ) );
                            ## Let's look for a table within the next 10 rightmost sibllings
                            KINS: for( my $i = 0; $i < 10; $i++ )
                            {
                                    my $this = $next[$i];
                                    next if( !ref( $this ) );
                                    $out->printf( "\t\t\tChecking tag %s\n", $this->tag );
                                    ## We stumbled upon another method definition, so we stop right here
                                    if( $this->tag eq 'h4' && defined( my $next_anchor = $this->look_down( '_tag' => 'a', 'name' => qr/\S+/ ) ) )
                                    {
                                            $out->print( "\t" x 4, "Stopping here, because I hit a next element.\n" );
                                            if( ref( $hash->{description} ) eq 'ARRAY' )
                                            {
                                                    ## Post processing description
                                                    if( scalar( @{$hash->{description}} ) > 1 )
                                                    {
                                                            my @parts = map( $_->as_HTML( '' ), @{$hash->{description}} );
                                                            ## I don't know how else to merger HTML::Element
                                                            my $t = HTML::TreeBuilder->new;
                                                            $t->parse( join( '', @parts ) );
                                                            $t->eof();
                                                            $hash->{description} = $t;
                                                    }
                                                    else
                                                    {
                                                            $hash->{description} = $hash->{description}->[0];
                                                    }
                                            }
                                            push( @$methods, $hash );
                                            $out->printf( "Adding %d types definition for object '$txt'\n", scalar( @$all ) );
                                            last;
                                    }
                                    if( $this->tag eq 'table' )
                                    {
                                            $out->print( "\t" x 4, "Found a table, checking if this is an object definition one...\n" );
                                            my @ths = $this->look_down( '_tag' => 'th' );
                                            if( !scalar( @ths ) )
                                            {
                                                    $out->print( "\tCould not find any th tags in this table for anchor '$txt'\n" );
                                                    next;
                                            }
                                            ## Yeah, we have a winner !
                                            my @header = map( $_->as_trimmed_text, @ths );
                                            $out->printf( ( "\t" x 4 ) . "th1 => '%s', th2 => '%s' and th3 => '%s'\n", @header );
                                            if( $header[0] eq 'Parameter' && $header[1] eq 'Type' && $header[2] eq 'Required' && $header[3] eq 'Description' )
                                            {
                                                    my @tds = $this->look_down( '_tag' => 'td' );
                                                    if( scalar( @tds ) % 4 )
                                                    {
                                                            $out->printf( "\tI found a candidate table for object '$txt', but there are %d columns, and I was expecting a multiplier of 4!\n", scalar( @tds ) );
                                                    }
                                                    my $all = [];
                                                    for( my $j = 0; $j < scalar( @tds ); $j += 4 )
                                                    {
                                                            my $def = {};
                                                            $def->{field} = $tds[$j]->as_trimmed_text;
                                                            $def->{type} = $tds[$j+1]->as_trimmed_text;
                                                            $def->{required} = $tds[$j+2]->as_trimmed_text;
                                                            $def->{desc} = $tds[$j+3]->as_trimmed_text;
                                                            push( @$all, $def );
                                                    }
                                                    $hash->{definition} = $all;
                                                    ## Post processing description
                                                    if( scalar( @{$hash->{description}} ) > 1 )
                                                    {
                                                            my @parts = map( $_->as_HTML( '' ), @{$hash->{description}} );
                                                            ## I don't know how else to merger HTML::Element
                                                            my $t = HTML::TreeBuilder->new;
                                                            $t->parse( join( '', @parts ) );
                                                            $t->eof();
                                                            $hash->{description} = $t;
                                                    }
                                                    else
                                                    {
                                                            $hash->{description} = $hash->{description}->[0];
                                                    }
                                                    push( @$methods, $hash );
                                                    $out->printf( "Adding %d types definition for object '$txt'\n", scalar( @$all ) );
                                                    next ANCHOR;
                                            }
                                            else
                                            {
                                                    $out->print( "\t" x 4, "Nope, not the right one\n" );
                                            }
                                    }
                                    elsif( $this->tag eq 'p' )
                                    {
                                            $out->printf( ( "\t" x 4 ) . "Found tag p with text: '%s'\n", $this->as_trimmed_text );
                                            $hash->{description} = [] if( !exists( $hash->{description} ) );
                                            push( @{$hash->{description}}, $this );
                                    }
                            }
                    }
            }
    #       $out->printf( "Found %d objects\n", scalar( @$objects ) );
    #       foreach my $ref ( @$objects )
    #       {
    #               $out->printf( "%s => %d type definitions, link => %s, description => '%s'\n", $ref->{name}, scalar( @{$ref->{definition}} ), $ref->{link}, $ref->{description}->as_trimmed_text );
    #       }
            return( { 'objects' => $objects, 'methods' => $methods } );
    }

    __EMD__

4 POD Errors

The following errors were encountered while parsing the POD:

Around line 582:

=back doesn't take any parameters, but you said =back EOT } elsif( exists( $all_objects->{ $type } ) ) { $type = 'L<Net::API::Telegram::' . $type . '>'; } $fh->print( <<EOT ); =item B<${field}>( $type )

Around line 599:

You forgot a '=back' before '=head1'

Around line 654:

'=item' outside of any '=over'

=over without closing =back

Around line 666:

=over without closing =back