lib/javonet-ruby-sdk/Binaries/Perl/Linux/X64/deps/lib/perl5/Nice/Try.pm in javonet-ruby-sdk-2.5.4 vs lib/javonet-ruby-sdk/Binaries/Perl/Linux/X64/deps/lib/perl5/Nice/Try.pm in javonet-ruby-sdk-2.5.5

- old
+ new

@@ -1,12 +1,12 @@ ##---------------------------------------------------------------------------- ## A real Try Catch Block Implementation Using Perl Filter - ~/lib/Nice/Try.pm -## Version v1.3.13 +## Version v1.3.15 ## Copyright(c) 2024 DEGUEST Pte. Ltd. ## Author: Jacques Deguest <jack@deguest.jp> ## Created 2020/05/17 -## Modified 2024/09/06 +## Modified 2024/11/07 ## All rights reserved ## ## This program is free software; you can redistribute it and/or modify it ## under the same terms as Perl itself. ##---------------------------------------------------------------------------- @@ -24,11 +24,11 @@ use PPI 1.277; use Filter::Util::Call; use Scalar::Util (); use List::Util (); use Want (); - our $VERSION = 'v1.3.13'; + our $VERSION = 'v1.3.15'; our $ERROR; our( $CATCH, $DIED, $EXCEPTION, $FINALLY, $HAS_CATCH, @RETVAL, $SENTINEL, $TRY, $WANTARRAY ); } use strict; @@ -45,10 +45,12 @@ $hash->{debug} = 0 if( !CORE::exists( $hash->{debug} ) ); $hash->{no_filter} = 0 if( !CORE::exists( $hash->{no_filter} ) ); $hash->{debug_code} = 0 if( !CORE::exists( $hash->{debug_code} ) ); $hash->{debug_dump} = 0 if( !CORE::exists( $hash->{debug_dump} ) ); $hash->{dont_want} = 0 if( !CORE::exists( $hash->{dont_want} ) ); + # We use the $class to process the __DATA__ or __END__ token section + $hash->{class} = $class; # We check if we are running under tie and if so we cannot use Want features, # because they would trigger a segmentation fault. $hash->{is_tied} = 0; if( $class->can( 'TIESCALAR' ) || $class->can( 'TIEHASH' ) || $class->can( 'TIEARRAY' ) ) { @@ -121,15 +123,21 @@ # Make sure there is at least a space at the beginning $code = ' ' . $code; if( index( $code, 'try' ) != -1 ) { $self->_message( 4, "Processing $line lines of code." ) if( $self->{debug} >= 4 ); + $self->_message( 4, "Processing code:\n${code}" ) if( $self->{debug} >= 5 ); my $doc = PPI::Document->new( \$code, readonly => 1 ) || die( "Unable to parse: ", PPI::Document->errstr, "\n$code\n" ); # Remove pod # $doc->prune('PPI::Token::Pod'); $self->_browse( $doc ) if( $self->{debug_dump} ); - if( $doc = $self->_parse( $doc ) ) + # It is easy for us to do a simple check as to whether there is potentially a __DATA__ or a __END__ token, + # so we avoid wasting resources and time checking it using PPI::Element::find() + if( $doc = $self->_parse( $doc, + { + has_data => ( ( CORE::index( $code, '__DATA__' ) != -1 || CORE::index( $code, '__END__' ) != -1 ) ? 1 : 0 ), + }) ) { $_ = $doc->serialize; # $doc->save( "./dev/debug-parsed.pl" ); # $status = 1; } @@ -159,10 +167,11 @@ $self->_message( 4, "Reading more line: $_" ) if( $self->{debug} >= 4 ); return( $status ) if( $status < 0 ); $line++; } } +# $self->_message( 4, "Resulting code:\n${_}" ) if( $self->{debug} >= 5 ); if( $self->{debug_file} ) { if( open( my $fh, ">$self->{debug_file}" ) ) { binmode( $fh, ':utf8' ); @@ -281,10 +290,11 @@ sub _parse { my $self = shift( @_ ); my $elem = shift( @_ ); + my $opts = shift( @_ ); no warnings 'uninitialized'; if( !Scalar::Util::blessed( $elem ) || !$elem->isa( 'PPI::Node' ) ) { return( $self->_error( "Element provided to parse is not a PPI::Node object" ) ); } @@ -1471,11 +1481,119 @@ my $e = $nodes_to_replace->[$k]; $e->delete || warn( "Could not remove node No $k: '$e'\n" ); } } # End foreach catch found + + # NOTE: Do we have a __DATA__ or __END__ token ? + if( $opts->{has_data} ) + { + my $ref = $elem->find(sub + { + my( $top, $this ) = @_; + return( ( $this->class eq 'PPI::Statement::Data' || $this->class eq 'PPI::Statement::End' ) ? 1 : 0 ); + }); + warn( "Warning only: Failed to find any __DATA__ or __END__ token." ) if( !defined( $ref ) && warnings::enabled() ); + my $class = $self->{class}; + my $name = 'DATA'; + $self->_message( 4, "Found ", scalar( @$ref ), " DATA tokens." ); + # There must be only one: either __DATA__ or __END__, so we process it, and exit the loop. + foreach my $this ( @$ref ) + { + $self->_message( 4, "DATA or END token found." ); + $self->_browse( $this ) if( $self->{debug} >= 5 ); + my $tokens = $this->find(sub + { + my( $top, $this ) = @_; + # PPI::Token::End + return( ( $this->class eq 'PPI::Token::Data' || $this->class eq 'PPI::Token::End' ) ? 1 : 0 ); + }); + next if( !$tokens || ( defined( $tokens ) && ref( $tokens ) && !scalar( @$tokens ) ) ); + my $token = $tokens->[0]; + my $token_name_ref = $this->find( 'PPI::Token::Separator' ); + my $token_name; + if( $token_name_ref && ref( $token_name_ref ) eq 'ARRAY' && scalar( @$token_name_ref ) ) + { + $token_name = $token_name_ref->[0]->content; + } + else + { + warn( "Could not find the __END__ or __DATA__ separator." ) if( warnings::enabled() ); + last; + } + + # my $io = $token->handle; + my $raw_data_str = $token->content; + $self->_message( 5, "Found DATA to be:\n${raw_data_str}" ); + + # Create a new string that holds only non-POD data + my $filtered_data_str = ''; + + if( $raw_data_str =~ /\S+/ ) + { + # Parse the data as a PPI document to filter POD content + $self->_message( 5, "Parsing the DATA, and check for POD to skip." ); + # Force it to be __END__ so PPI can handle properly the POD data + # FYI, PPI only handles POD data when the token is __END__, and not when it is __DATA__ + if( $token_name eq '__DATA__' ) + { + my $data_str = "__END__\n" . $raw_data_str; + require PPI::Tokenizer; + my $tokenizer = PPI::Tokenizer->new( \$data_str ); + my $tokens = $tokenizer->all_tokens; + foreach my $token ( @$tokens ) + { + $filtered_data_str .= "${token}" if( $token->class eq 'PPI::Token::End' ); + } + } + else + { + $filtered_data_str = $raw_data_str; + } + } + + # Now $filtered_data_str holds only the non-POD data content + $self->_message( 5, "Creating BEGIN block to set DATA with value:\n${filtered_data_str}" ); + + # Define the BEGIN block code with the filtered data + my $begin_block_code = <<"END_CODE"; +CHECK +{ + my \$nice_try_data_block_str = <<'END_OF_DATA'; +${filtered_data_str} +END_OF_DATA + require Symbol; + my \$fh = Symbol::geniosym(); + open( \$fh, '<:scalar', \\\$nice_try_data_block_str ) || die( \$! ); + no strict 'refs'; + no warnings 'redefine'; + *{ __PACKAGE__ . '::DATA' } = \$fh; +}; + +END_CODE + $self->_message( 5, "BEGIN block is:\n${begin_block_code}" ); + my $begin_block = PPI::Token->new( $begin_block_code ) || die( "Unable to create token" ); + $self->_message( 5, "Inserting BEGIN element object '", overload::StrVal( $begin_block ), "', before '", overload::StrVal( $this ), "'" ); + my $rv = $this->__insert_before( $begin_block ); + if( !defined( $rv ) ) + { + warn( "BEGIN block object (", overload::StrVal( $begin_block ), ") to be inserted before the DATA token is not a valid object." ) if( warnings::enabled() ); + last; + } + elsif( !$rv ) + { + warn( "Somehow, the BEGIN block object (", overload::StrVal( $begin_block ), ") could not be inserted before the DATA token." ) if( warnings::enabled() ); + last; + } + # $self->_message( 5, "BEGIN block object (", overload::StrVal( $begin_block ), ") was successfully inserted." ); + # We end here, because there can be only one __DATA__ or __END__ token + last; + } + } + + # $self->_message( 5, "Code now is: $elem" ); return( $elem ); } # .Element: [11] class PPI::Token::Word, value caller # .Element: [11] class PPI::Structure::List, value (1) @@ -2160,11 +2278,11 @@ print( "Unknown error: $default\n" ); } =head1 VERSION - v1.3.13 + v1.3.15 =head1 DESCRIPTION L<Nice::Try> is a lightweight implementation of Try-Catch exception trapping block using L<perl filter|perlfilter>. It behaves like you would expect. @@ -2547,10 +2665,12 @@ Also, the C<use feature 'try'> expression must be in the relevant block where you use C<try-catch>. You cannot just put it in your C<BEGIN> block at the beginning of your script. If you have 3 subroutines using C<try-catch>, you need to put C<use feature 'try'> in each of them. See L<perl documentation on lexical effect|https://perldoc.perl.org/feature#Lexical-effect> for more explanation on this. It is probably a matter of time until this is fully implemented in perl as a regular non-experimental feature. +As of perl C<v5.40.0>. the C<try-catch> block L<is now only partly experimental|https://perldoc.perl.org/5.40.0/perldelta#try/catch-feature-is-no-longer-experimental>, but you still need to load it with C<use feature 'try'>. However, at least no warning of it being experimental will be emitted. Still, L<no exception filtering by class though|https://perldoc.perl.org/5.40.0/perlsyn#Try-Catch-Exception-Handling> + See more information about perl's featured implementation of try-catch in L<perlsyn|https://perldoc.perl.org/perlsyn#Try-Catch-Exception-Handling> So, L<Nice::Try> is quite unique and fills the missing features, and since it uses XS modules for a one-time filtering, it is quite fast. =head1 FINALLY @@ -2919,9 +3039,99 @@ use Nice::Try dont_want => 1; When there is an update to correct this bug from L<Want>, I will issue a new version. The use of L<Want> is also automatically disabled when running under a package that use overloading. + +=head1 __DATA__ and __END__ sections + +Due to a limitation to the way source filter works with L<Filter::Util::Call>, normally, it is not possible to make the data available after the C<__DATA__> or C<__END__> token accessible with the special glob C<DATA>, but with C<Nice::Try>, it is possible. Thus, the following would work as you would expect: + + #!/usr/bin/env perl + use strict; + use warnings; + use Nice::Try; + + try + { + print "Poem by Pierre de Ronsard (1545)\n"; + + print while( <DATA> ); + } + catch($e) + { + print( "Oh no: $e\n" ); + } + + __END__ + Mignonne, allons voir si la rose + Qui ce matin avoit desclose + Sa robe de pourpre au Soleil, + A point perdu ceste vesprée + Les plis de sa robe pourprée, + Et son teint au vostre pareil. + +The same would work if the C<__DATA__> were used instead of C<__END__> + +And, if you mix POD, it will ignore it to only make available in the C<DATA> glob the non-POD data. For example: + + #!/usr/bin/env perl + use strict; + use warnings; + use Nice::Try; + + try + { + print "Poem by Pierre de Ronsard (1545)\n"; + + print while( <DATA> ); + } + catch($e) + { + print( "Oh no: $e\n" ); + } + + __END__ + Mignonne, allons voir si la rose + Qui ce matin avoit desclose + Sa robe de pourpre au Soleil, + A point perdu ceste vesprée + Les plis de sa robe pourprée, + Et son teint au vostre pareil. + + =encoding utf-8 + + =head1 NAME + + French::Poetry - Pierre de Ronsard, Ode à Cassandre + + =head1 DESCRIPTION + + This famous poem was made by Pierre de Ronsard after he met Cassandre Salviati, daughter of an Italian banker, at the court in 1545. + + This poem is the epitome of Epicureanism (Carpe diem). + + =cut + + Las ! voyez comme en peu d'espace, + Mignonne, elle a dessus la place, + Las ! las ! ses beautés laissé choir ! + Ô vraiment marâtre Nature, + Puisqu'une telle fleur ne dure + Que du matin jusques au soir ! + + Donc, si vous me croyez, mignonne, + Tandis que votre âge fleuronne + En sa plus verte nouveauté, + Cueillez, cueillez votre jeunesse : + Comme à cette fleur, la vieillesse + Fera ternir votre beauté. + +This would yield the entire poem of 3 paragraph, while skipping the POD in-between. Of course, the same would work with C<__DATA__> + +The C<DATA> is actually an C<IO::File> object generated with C<Symbol::geniosym()> + +See also L<perldata/"Special-Literals"> for more information. =head1 LIMITATIONS Before version C<v1.3.5>, there was a limitation on using signature on a subroutine, but since version C<v1.3.5>, it has been fixed and there is no more any limitation. Thus the following works nicely too.