NAME
Parse::Eyapp::Base - Emulates local &function = sub { ... };
SYNOPSIS
use Parse::Eyapp::Base qw(:all);
sub tutu { "tutu" }
sub plim {
push_method('tutu', sub { "titi" });
print &tutu()."\n"; # Prints "titi"
pop_method('tutu');
}
plim();
print &tutu()."\n"; # Prints "tutu"
INTRODUCTION
Parse::Eyapp::Base
holds a set of utility functions that give support to the other modules that made Parse::Eyapp
. Several of them are related to the dynamic use of methods and subroutines. Namely, push_method
and pop_method
allows to emulate what it will be something like an extension of local
to functions, i.e. something like:
sub tutu { "tutu" }
sub plim {
local &tutu = sub { "titi" };
print &tutu()."\n"; # It will print "titi"
}
print &tutu()."\n"; # It will print "tutu"
It will be nice to have such feature in a future Perl release. Among other uses it makes room for some sort of dynamic scope privacy for Perl subroutines. Meanwhile we can do:
use strict;
use Parse::Eyapp::Base qw(:all);
sub tutu { "tutu" }
sub plim {
push_method('tutu', sub { "titi" });
print &tutu()."\n"; # Prints "titi"
pop_method('tutu');
}
plim();
print &tutu()."\n"; # Prints "tutu"
SUBROUTINES
Function insert_method
Function insert_method
receives as arguments a list of class names, the name of the method that will be inserted in such classes and a reference to the code implementing such method.
insert_method( qw{CLASS1 CLASS2 ... }, 'subname', sub { ... } )
It inserts the method in the specified classes. A second way to call it is without the last argument, the handler:
insert_method( qw{CLASS1 CLASS2 ... }, 'subname' )
In such case the function is deleted from all the specified classes and it no longer exists.
The caller class is assumed if no classes are specified:
insert_method('subname', sub { ... } )
See the following session with the debugger:
pl@nereida:~/src/perl/YappWithDefaultAction/lib/Parse/Eyapp$ perl -wde 0
main::(-e:1): 0
DB<1> use Parse::Eyapp::Base qw(:all)
DB<2> insert_method( qw{PLUS MINUS TIMES }, 'printclass', sub { print "$_[0]\n" } )
DB<3> $_->printclass for qw{PLUS MINUS TIMES }
PLUS
MINUS
TIMES
DB<4> insert_method( qw{PLUS MINUS TIMES }, 'printclass')
DB<5> print $_->can('printclass')?"Yes\n":"No\n" for qw{PLUS MINUS TIMES }
No
No
No
Function insert_function
It works as insert_method
(see section "Function insert_method"), only that instead of classes receives the full names of the functions to install and a reference to the code implementing such function. See an example of call:
insert_function(
qw{ FUNCTIONCALL::type_info VARARRAY::type_info VAR::type_info },
\&type_info
);
Function empty_method
The call to
empty_method(qw{CLASSES ... }, 'subname')
is equivalent to
insert_method(qw{CLASSES ... }, 'subname', sub {})
Consequently empty_method
replaces the current CODE
for function subname
by an empty subroutine
Function push_method
The call
push_method( qw{CLASS1 CLASS2 ... }, 'subname', sub { ... } )
saves the current methods CLASS1::subname
, CLASS2::subname
, etc. in a stack and proceeds to install the new handler specified through the last argument. See an example:
pl@nereida:~/src/perl/YappWithDefaultAction/lib/Parse/Eyapp$ perl -wde 0
main::(-e:1): 0
DB<1> use Parse::Eyapp::Base qw(:all)
DB<2> sub Tutu::titi { print "Inside first Tutu::titi!\n" }
DB<3> push_method('Tutu', 'titi', sub { print "New titi!\n" })
DB<4> Tutu::titi()
New titi!
DB<5> pop_method('Tutu', 'titi')
DB<6> Tutu::titi()
Inside first Tutu::titi!
DB<7> push_method('Tutu', 'titi') # No handler: sub Tutu::titi no longer exists
DB<8> print "Can't titi\n" unless Tutu->can('titi')
Can't titi
DB<9> pop_method('Tutu', 'titi') # Give me the old sub
DB<10> Tutu::titi()
Inside first Tutu::titi!
The caller class is assumed if no classes are specified.
In list context the push_method
function returns an array of pointers to the old versions of the function. In a scalar context returns the first CODE
reference. See the following example:
pl@nereida:~/src/perl/YappWithDefaultAction/examples$ cat -n returnedbypushmethod.pl
1 #!/usr/local/bin/perl -w
2 use strict;
3 use Parse::Eyapp::Base qw(:all);
4
5 sub tutu { "tutu" }
6 sub Chum::tutu { "chum" }
7
8 my @classes = qw{main Cham Chum};
9
10 my %oldf;
11 our $tutu = 5;
12 our @tutu = 9..12;
13 $Cham::tutu = 8;
14 @Cham::tutu = 1..3;
15
16 @oldf{@classes} = push_method(@classes, 'tutu', sub { "titi" });
17
18 print "Calling new function 'tutu':".&tutu()."\n";
19
20 for (@classes) {
21 if (defined($oldf{$_})) {
22 print "Old function 'tutu' in $_ gives: ".$oldf{$_}->()."\n";
23 }
24 else {
25 print "Function 'tutu' wasn't defined in $_\n";
26 }
27 }
When executed with the debugger we can see that
Package variables with the same name like
$tutu
or@tutu
aren't changed byinsert_method
References to the old versions of function
tutu
are returned byinsert_method
See the session with the debugger:
pl@nereida:~/LEyapp/examples$ perl -wd returnedbypushmethod.pl
main::(returnedbypushmethod.pl:8):
8: my @classes = qw{main Cham Chum};
DB<1> c 18
main::(returnedbypushmethod.pl:18):
18: print "Calling new function 'tutu':".&tutu()."\n";
DB<2> n
Calling new function 'tutu':titi
main::(returnedbypushmethod.pl:20):
20: for (@classes) {
DB<2> x @tutu
0 9
1 10
2 11
3 12
DB<3> x @Cham::tutu
0 1
1 2
2 3
DB<4> p $Cham::tutu
8
DB<5> c
Old function 'tutu' in main gives: tutu
Function 'tutu' wasn't defined in Cham
Old function 'tutu' in Chum gives: chum
Function pop_method
The call
pop_method(qw{CLASS1 CLASS2 ... }, 'subname' )
pops the methods in the tops of the stacks associated with CLASS1::subname
, CLASS2::subname
, etc. See the example in the section push_method above.
The caller class is assumed if no classes are specified.
In list context the pop_method
function returns an array of pointers to the old versions of the function. In a scalar context returns the first function reference. When the stack is empty the function(s) are deleted. See the following example:
pl@nereida:~/src/perl/YappWithDefaultAction/examples$ cat returnedbypopmethod.pl
#!/usr/local/bin/perl -w
use strict;
use Parse::Eyapp::Base qw(:all);
sub tutu { "tutu" }
my $old = pop_method('tutu');
print "Can't Call function 'tutu'\n" unless main->can('tutu');
print "Old function 'tutu' gives: ".$old->()."\n";
When executed gives the following output:
pl@nereida:~/src/perl/YappWithDefaultAction/examples$ returnedbypopmethod.pl
Can't Call function 'tutu'
Old function 'tutu' gives: tutu
Function compute_lines
The call
compute_lines(\$text, $filename, $pattern)
Substitutes all the ocurrences of $pattern
by #line $number $filename
in string $text
. where $number
is the line number.
Function slurp_file
The call
my $input = slurp_file($filename, "c");
returns a string with the contents of the file $filename
assuming extension "c"
.
pl@nereida:~/src/perl/YappWithDefaultAction/lib/Parse/Eyapp$ perl -wde 0
main::(-e:1): 0
DB<1> use Parse::Eyapp::Base qw(:all)
DB<2> !!ls *yp # There are two files with extension .yp in this directory
Parse.yp Treeregexp.yp
DB<3> $x = slurp_file('Parse', 'yp') # read the whole file
DB<4> p $x =~ tr/\n// # file Parse.yp has 1038 lines
1038
Function valid_keys
The call
valid_keys(%hash)
Returns a string with the keys of the %hash
separated by commas:
pl@nereida:~/src/perl/YappWithDefaultAction/lib/Parse/Eyapp$ perl -wde 0
main::(-e:1): 0
DB<1> use Parse::Eyapp::Base qw(:all)
DB<2> %h = ( SCOPE_NAME => 'STRING', ENTRY_NAME => 'STRING', SCOPE_DEPTH => 'STRING')
DB<3> $x = valid_keys(%h)
DB<4> p $x
ENTRY_NAME, SCOPE_DEPTH, SCOPE_NAME
Function invalid_keys
It is called with two hash references:
DB<5> p invalid_keys(\%h, { SCOPE_NAME => 'a', ENTRY_NAMe => 'b', SCOPE_DEPTH => 'c'})
ENTRY_NAMe
It returns the first key in the second hash that does not appear in the first hash. See a more complete example:
pl@nereida:~/src/perl/YappWithDefaultAction/lib/Parse/Eyapp$ head -31 Scope.pm | cat -n
1 package Parse::Eyapp::Scope;
2 use strict;
3 use warnings;
4 use Carp;
5 use List::MoreUtils qw(part);
6 use Parse::Eyapp::Base qw(valid_keys invalid_keys);
7
8 my %_new_scope = (
9 SCOPE_NAME => 'STRING',
10 ENTRY_NAME => 'STRING',
11 SCOPE_DEPTH => 'STRING',
12 );
13 my $valid_scope_keys = valid_keys(%_new_scope);
14
15 sub new {
16 my $class = shift;
17 my %args = @_;
18
19 if (defined($a = invalid_keys(\%_new_scope, \%args))) {
20 croak("Parse::Eyapp::Scope::new Error!:\n"
21 ."unknown argument $a. Valid arguments for new are:\n $valid_scope_keys")
22 }
23 $args{ENTRY_NAME} = 'entry' unless defined($args{ENTRY_NAME});
24 $args{SCOPE_NAME} = 'scope' unless defined($args{SCOPE_NAME});
25 $args{SCOPE_DEPTH} = '' unless defined($args{SCOPE_DEPTH});
26 $args{PENDING_DECL} = [];
27 $args{SCOPE_MARK} = 0;
28 $args{DEPTH} = -1; # first depth is 0
29
30 bless \%args, $class;
31 }
Function write_file
Simply writes the referenced by $text
into the file referenced by outputfilehandler
write_file($outputfilehandler, \$text)
Function numbered
The call
numbered($input)
Returns a string like $input
but with lines numbered and the numbers correctly indented. See an example:
DB<1> use Parse::Eyapp::Base qw(:all)
DB<2> $input = "Another line!\n"x12
DB<3> $output = numbered($input)
DB<4> p $output
1 Another line!
2 Another line!
3 Another line!
4 Another line!
5 Another line!
6 Another line!
7 Another line!
8 Another line!
9 Another line!
10 Another line!
11 Another line!
12 Another line!
SEE ALSO
AUTHOR
Casiano Rodriguez-Leon (casiano@ull.es)
ACKNOWLEDGMENTS
This work has been supported by CEE (FEDER) and the Spanish Ministry of Educación y Ciencia through Plan Nacional I+D+I number TIN2005-08818-C04-04 (ULL::OPLINK project http://www.oplink.ull.es/). Support from Gobierno de Canarias was through GC02210601 (Grupos Consolidados). The University of La Laguna has also supported my work in many ways and for many years.
A large percentage of code is verbatim taken from Parse::Yapp 1.05. The author of Parse::Yapp is Francois Desarmenien.
I wish to thank Francois Desarmenien for his Parse::Yapp
module, to my students at La Laguna and to the Perl Community. Special thanks to my family and Larry Wall.
LICENCE AND COPYRIGHT
Copyright (c) 2006-2007 Casiano Rodriguez-Leon (casiano@ull.es). All rights reserved.
Parse::Yapp copyright is of Francois Desarmenien, all rights reserved. 1998-2001
These modules are free software; you can redistribute it and/or modify it under the same terms as Perl itself. See perlartistic.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1 POD Error
The following errors were encountered while parsing the POD:
- Around line 410:
Non-ASCII character seen before =encoding in 'I<Educación'. Assuming UTF-8