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
EOT } elsif( exists( $all_objects->{ $type } ) ) { $type = '"Net::API::Telegram::' . $type . '"'; } $fh->print( <<EOT ); =item ${field}( $type )
$desc
EOT } $fh->print( <<EOT ); =back
COPYRIGHT
Copyright (c) 2000-2019 DEGUEST Pte. Ltd.
AUTHOR
Jacques Deguest <jack\@deguest.jp>
SEE ALSO
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__
3 POD Errors
The following errors were encountered while parsing the POD:
- Around line 613:
You forgot a '=back' before '=head1'
- Around line 668:
'=item' outside of any '=over'
=over without closing =back
- Around line 680:
=over without closing =back