1=for gpg 2-----BEGIN PGP SIGNED MESSAGE----- 3Hash: SHA1 4 5- -----BEGIN PGP SIGNED MESSAGE----- 6Hash: SHA1 7 8=head1 NAME 9 10Readonly - Facility for creating read-only scalars, arrays, hashes. 11 12=head1 VERSION 13 14This documentation describes version 1.03 of Readonly.pm, April 20, 2004. 15 16=cut 17 18# Rest of documentation is after __END__. 19 20use 5.005; 21use strict; 22#use warnings; 23#no warnings 'uninitialized'; 24 25package Readonly; 26$Readonly::VERSION = '1.03'; # Also change in the documentation! 27 28# Autocroak (Thanks, MJD) 29# Only load Carp.pm if module is croaking. 30sub croak 31{ 32 require Carp; 33 goto &Carp::croak; 34} 35 36# These functions may be overridden by Readonly::XS, if installed. 37sub is_sv_readonly ($) { 0 } 38sub make_sv_readonly ($) { die "make_sv_readonly called but not overridden" } 39use vars qw/$XSokay/; # Set to true in Readonly::XS, if available 40 41# Common error messages, or portions thereof 42use vars qw/$MODIFY $REASSIGN $ODDHASH/; 43$MODIFY = 'Modification of a read-only value attempted'; 44$REASSIGN = 'Attempt to reassign a readonly'; 45$ODDHASH = 'May not store an odd number of values in a hash'; 46 47# See if we can use the XS stuff. 48$Readonly::XS::MAGIC_COOKIE = "Do NOT use or require Readonly::XS unless you're me."; 49eval 'use Readonly::XS'; 50 51 52# ---------------- 53# Read-only scalars 54# ---------------- 55package Readonly::Scalar; 56 57sub TIESCALAR 58{ 59 my $whence = (caller 2)[3]; # Check if naughty user is trying to tie directly. 60 Readonly::croak "Invalid tie" unless $whence && $whence =~ /^Readonly::(?:Scalar1?|Readonly)$/; 61 my $class = shift; 62 Readonly::croak "No value specified for readonly scalar" unless @_; 63 Readonly::croak "Too many values specified for readonly scalar" unless @_ == 1; 64 65 my $value = shift; 66 return bless \$value, $class; 67} 68 69sub FETCH 70{ 71 my $self = shift; 72 return $$self; 73} 74 75*STORE = *UNTIE = 76 sub {Readonly::croak $Readonly::MODIFY}; 77 78 79# ---------------- 80# Read-only arrays 81# ---------------- 82package Readonly::Array; 83 84sub TIEARRAY 85{ 86 my $whence = (caller 1)[3]; # Check if naughty user is trying to tie directly. 87 Readonly::croak "Invalid tie" unless $whence =~ /^Readonly::Array1?$/; 88 my $class = shift; 89 my @self = @_; 90 91 return bless \@self, $class; 92} 93 94sub FETCH 95{ 96 my $self = shift; 97 my $index = shift; 98 return $self->[$index]; 99} 100 101sub FETCHSIZE 102{ 103 my $self = shift; 104 return scalar @$self; 105} 106 107BEGIN { 108 eval q{ 109 sub EXISTS 110 { 111 my $self = shift; 112 my $index = shift; 113 return exists $self->[$index]; 114 } 115 } if $] >= 5.006; # couldn't do "exists" on arrays before then 116} 117 118*STORE = *STORESIZE = *EXTEND = *PUSH = *POP = *UNSHIFT = *SHIFT = *SPLICE = *CLEAR = *UNTIE = 119 sub {Readonly::croak $Readonly::MODIFY}; 120 121 122# ---------------- 123# Read-only hashes 124# ---------------- 125package Readonly::Hash; 126 127sub TIEHASH 128{ 129 my $whence = (caller 1)[3]; # Check if naughty user is trying to tie directly. 130 Readonly::croak "Invalid tie" unless $whence =~ /^Readonly::Hash1?$/; 131 132 my $class = shift; 133 # must have an even number of values 134 Readonly::croak $Readonly::ODDHASH unless (@_ %2 == 0); 135 136 my %self = @_; 137 return bless \%self, $class; 138} 139 140sub FETCH 141{ 142 my $self = shift; 143 my $key = shift; 144 145 return $self->{$key}; 146} 147 148sub EXISTS 149{ 150 my $self = shift; 151 my $key = shift; 152 return exists $self->{$key}; 153} 154 155sub FIRSTKEY 156{ 157 my $self = shift; 158 my $dummy = keys %$self; 159 return scalar each %$self; 160} 161 162sub NEXTKEY 163{ 164 my $self = shift; 165 return scalar each %$self; 166} 167 168*STORE = *DELETE = *CLEAR = *UNTIE = 169 sub {Readonly::croak $Readonly::MODIFY}; 170 171 172# ---------------------------------------------------------------- 173# Main package, containing convenience functions (so callers won't 174# have to explicitly tie the variables themselves). 175# ---------------------------------------------------------------- 176package Readonly; 177use Exporter; 178use vars qw/@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS/; 179push @ISA, 'Exporter'; 180push @EXPORT, qw/Readonly/; 181push @EXPORT_OK, qw/Scalar Array Hash Scalar1 Array1 Hash1/; 182 183# Predeclare the following, so we can use them recursively 184sub Scalar ($$); 185sub Array (\@;@); 186sub Hash (\%;@); 187 188# Returns true if a string begins with "Readonly::" 189# Used to prevent reassignment of Readonly variables. 190sub _is_badtype 191{ 192 my $type = $_[0]; 193 return lc $type if $type =~ s/^Readonly:://; 194 return; 195} 196 197# Shallow Readonly scalar 198sub Scalar1 ($$) 199{ 200 croak "$REASSIGN scalar" if is_sv_readonly $_[0]; 201 my $badtype = _is_badtype (ref tied $_[0]); 202 croak "$REASSIGN $badtype" if $badtype; 203 204 # xs method: flag scalar as readonly 205 if ($XSokay) 206 { 207 $_[0] = $_[1]; 208 make_sv_readonly $_[0]; 209 return; 210 } 211 212 # pure-perl method: tied scalar 213 my $tieobj = eval {tie $_[0], 'Readonly::Scalar', $_[1]}; 214 if ($@) 215 { 216 croak "$REASSIGN scalar" if substr($@,0,43) eq $MODIFY; 217 die $@; # some other error? 218 } 219 return $tieobj; 220} 221 222# Shallow Readonly array 223sub Array1 (\@;@) 224{ 225 my $badtype = _is_badtype (ref tied $_[0]); 226 croak "$REASSIGN $badtype" if $badtype; 227 228 my $aref = shift; 229 return tie @$aref, 'Readonly::Array', @_; 230} 231 232# Shallow Readonly hash 233sub Hash1 (\%;@) 234{ 235 my $badtype = _is_badtype (ref tied $_[0]); 236 croak "$REASSIGN $badtype" if $badtype; 237 238 my $href = shift; 239 240 # If only one value, and it's a hashref, expand it 241 if (@_ == 1 && ref $_[0] eq 'HASH') 242 { 243 return tie %$href, 'Readonly::Hash', %{$_[0]}; 244 } 245 246 # otherwise, must have an even number of values 247 croak $ODDHASH unless (@_%2 == 0); 248 249 return tie %$href, 'Readonly::Hash', @_; 250} 251 252# Deep Readonly scalar 253sub Scalar ($$) 254{ 255 croak "$REASSIGN scalar" if is_sv_readonly $_[0]; 256 my $badtype = _is_badtype (ref tied $_[0]); 257 croak "$REASSIGN $badtype" if $badtype; 258 259 my $value = $_[1]; 260 261 # Recursively check passed element for references; if any, make them Readonly 262 foreach ($value) 263 { 264 if (ref eq 'SCALAR') {Scalar my $v => $$_; $_ = \$v} 265 elsif (ref eq 'ARRAY') {Array my @v => @$_; $_ = \@v} 266 elsif (ref eq 'HASH') {Hash my %v => $_; $_ = \%v} 267 } 268 269 # xs method: flag scalar as readonly 270 if ($XSokay) 271 { 272 $_[0] = $value; 273 make_sv_readonly $_[0]; 274 return; 275 } 276 277 # pure-perl method: tied scalar 278 my $tieobj = eval {tie $_[0], 'Readonly::Scalar', $value}; 279 if ($@) 280 { 281 croak "$REASSIGN scalar" if substr($@,0,43) eq $MODIFY; 282 die $@; # some other error? 283 } 284 return $tieobj; 285} 286 287# Deep Readonly array 288sub Array (\@;@) 289{ 290 my $badtype = _is_badtype (ref tied @{$_[0]}); 291 croak "$REASSIGN $badtype" if $badtype; 292 293 my $aref = shift; 294 my @values = @_; 295 296 # Recursively check passed elements for references; if any, make them Readonly 297 foreach (@values) 298 { 299 if (ref eq 'SCALAR') {Scalar my $v => $$_; $_ = \$v} 300 elsif (ref eq 'ARRAY') {Array my @v => @$_; $_ = \@v} 301 elsif (ref eq 'HASH') {Hash my %v => $_; $_ = \%v} 302 } 303 # Lastly, tie the passed reference 304 return tie @$aref, 'Readonly::Array', @values; 305} 306 307# Deep Readonly hash 308sub Hash (\%;@) 309{ 310 my $badtype = _is_badtype (ref tied %{$_[0]}); 311 croak "$REASSIGN $badtype" if $badtype; 312 313 my $href = shift; 314 my @values = @_; 315 316 # If only one value, and it's a hashref, expand it 317 if (@_ == 1 && ref $_[0] eq 'HASH') 318 { 319 @values = %{$_[0]}; 320 } 321 322 # otherwise, must have an even number of values 323 croak $ODDHASH unless (@values %2 == 0); 324 325 # Recursively check passed elements for references; if any, make them Readonly 326 foreach (@values) 327 { 328 if (ref eq 'SCALAR') {Scalar my $v => $$_; $_ = \$v} 329 elsif (ref eq 'ARRAY') {Array my @v => @$_; $_ = \@v} 330 elsif (ref eq 'HASH') {Hash my %v => $_; $_ = \%v} 331 } 332 333 return tie %$href, 'Readonly::Hash', @values; 334} 335 336 337# Common entry-point for all supported data types 338eval q{sub Readonly} . ( $] < 5.008 ? '' : '(\[$@%]@)' ) . <<'SUB_READONLY'; 339{ 340 if (ref $_[0] eq 'SCALAR') 341 { 342 croak $MODIFY if is_sv_readonly ${$_[0]}; 343 my $badtype = _is_badtype (ref tied ${$_[0]}); 344 croak "$REASSIGN $badtype" if $badtype; 345 croak "Readonly scalar must have only one value" if @_ > 2; 346 347 my $tieobj = eval {tie ${$_[0]}, 'Readonly::Scalar', $_[1]}; 348 # Tie may have failed because user tried to tie a constant, or we screwed up somehow. 349 if ($@) 350 { 351 croak $MODIFY if $@ =~ /^$MODIFY at/; # Point the finger at the user. 352 die "$@\n"; # Not a modify read-only message; must be our fault. 353 } 354 return $tieobj; 355 } 356 elsif (ref $_[0] eq 'ARRAY') 357 { 358 my $aref = shift; 359 return Array @$aref, @_; 360 } 361 elsif (ref $_[0] eq 'HASH') 362 { 363 my $href = shift; 364 croak $ODDHASH if @_%2 != 0 && !(@_ == 1 && ref $_[0] eq 'HASH'); 365 return Hash %$href, @_; 366 } 367 elsif (ref $_[0]) 368 { 369 croak "Readonly only supports scalar, array, and hash variables."; 370 } 371 else 372 { 373 croak "First argument to Readonly must be a reference."; 374 } 375} 376SUB_READONLY 377 378 3791; 380__END__ 381 382=head1 SYNOPSIS 383 384 use Readonly; 385 386 # Read-only scalar 387 Readonly::Scalar $sca => $initial_value; 388 Readonly::Scalar my $sca => $initial_value; 389 390 # Read-only array 391 Readonly::Array @arr => @values; 392 Readonly::Array my @arr => @values; 393 394 # Read-only hash 395 Readonly::Hash %has => (key => value, key => value, ...); 396 Readonly::Hash my %has => (key => value, key => value, ...); 397 # or: 398 Readonly::Hash %has => {key => value, key => value, ...}; 399 400 # You can use the read-only variables like any regular variables: 401 print $sca; 402 $something = $sca + $arr[2]; 403 next if $has{$some_key}; 404 405 # But if you try to modify a value, your program will die: 406 $sca = 7; 407 push @arr, 'seven'; 408 delete $has{key}; 409 # The error message is "Modification of a read-only value 410attempted" 411 412 # Alternate form (Perl 5.8 and later) 413 Readonly $sca => $initial_value; 414 Readonly my $sca => $initial_value; 415 Readonly @arr => @values; 416 Readonly my @arr => @values; 417 Readonly %has => (key => value, key => value, ...); 418 Readonly my %has => (key => value, key => value, ...); 419 # Alternate form (for Perls earlier than v5.8) 420 Readonly \$sca => $initial_value; 421 Readonly \my $sca => $initial_value; 422 Readonly \@arr => @values; 423 Readonly \my @arr => @values; 424 Readonly \%has => (key => value, key => value, ...); 425 Readonly \my %has => (key => value, key => value, ...); 426 427 428=head1 DESCRIPTION 429 430This is a facility for creating non-modifiable variables. This is 431useful for configuration files, headers, etc. It can also be useful 432as a development and debugging tool, for catching updates to variables 433that should not be changed. 434 435If any of the values you pass to C<Scalar>, C<Array>, or C<Hash> are 436references, then those functions recurse over the data structures, 437marking everything as Readonly. Usually, this is what you want: the 438entire structure nonmodifiable. If you want only the top level to be 439Readonly, use the alternate C<Scalar1>, C<Array1> and C<Hash1> 440functions. 441 442Please note that most users of Readonly will also want to install a 443companion module Readonly::XS. See the L</CONS> section below for more 444details. 445 446=head1 COMPARISON WITH "use constant" 447 448Perl provides a facility for creating constant values, via the "use 449constant" pragma. There are several problems with this pragma. 450 451=over 2 452 453=item * 454 455The constants created have no leading $ or @ character. 456 457=item * 458 459These constants cannot be interpolated into strings. 460 461=item * 462 463Syntax can get dicey sometimes. For example: 464 465 use constant CARRAY => (2, 3, 5, 7, 11, 13); 466 $a_prime = CARRAY[2]; # wrong! 467 $a_prime = (CARRAY)[2]; # right -- MUST use parentheses 468 469=item * 470 471You have to be very careful in places where barewords are allowed. 472For example: 473 474 use constant SOME_KEY => 'key'; 475 %hash = (key => 'value', other_key => 'other_value'); 476 $some_value = $hash{SOME_KEY}; # wrong! 477 $some_value = $hash{+SOME_KEY}; # right 478 479(who thinks to use a unary plus when using a hash?) 480 481=item * 482 483C<use constant> works for scalars and arrays, not hashes. 484 485=item * 486 487These constants are global ot the package in which they're declared; 488cannot be lexically scoped. 489 490=item * 491 492Works only at compile time. 493 494=item * 495 496Can be overridden: 497 498 use constant PI => 3.14159; 499 ... 500 use constant PI => 2.71828; 501 502(this does generate a warning, however, if you have warnings enabled). 503 504=item * 505 506It is very difficult to make and use deep structures (complex data 507structures) with C<use constant>. 508 509=back 510 511=head1 COMPARISON WITH TYPEGLOB CONSTANTS 512 513Another popular way to create read-only scalars is to modify the symbol 514table entry for the variable by using a typeglob: 515 516 *a = \'value'; 517 518This works fine, but it only works for global variables ("my" 519variables have no symbol table entry). Also, the following similar 520constructs do B<not> work: 521 522 *a = [1, 2, 3]; # Does NOT create a read-only array 523 *a = { a => 'A'}; # Does NOT create a read-only hash 524 525=head1 PROS 526 527Readonly.pm, on the other hand, will work with global variables and 528with lexical ("my") variables. It will create scalars, arrays, or 529hashes, all of which look and work like normal, read-write Perl 530variables. You can use them in scalar context, in list context; you 531can take references to them, pass them to functions, anything. 532 533Readonly.pm also works well with complex data structures, allowing you 534to tag the whole structure as nonmodifiable, or just the top level. 535 536Also, Readonly variables may not be reassigned. The following code 537will die: 538 539 Readonly::Scalar $pi => 3.14159; 540 ... 541 Readonly::Scalar $pi => 2.71828; 542 543=head1 CONS 544 545Readonly.pm does impose a performance penalty. It's pretty slow. How 546slow? Run the C<benchmark.pl> script that comes with Readonly. On my 547test system, "use constant", typeglob constants, and regular 548read/write Perl variables were all about the same speed, and 549Readonly.pm constants were about 1/20 the speed. 550 551However, there is relief. There is a companion module available, 552Readonly::XS. If it is installed on your system, Readonly.pm uses it 553to make read-only scalars much faster. With Readonly::XS, Readonly 554scalars are as fast as the other types of variables. Readonly arrays 555and hashes will still be relatively slow. But it's likely that most 556of your Readonly variables will be scalars. 557 558If you can't use Readonly::XS (for example, if you don't have a C 559compiler, or your perl is statically linked and you don't want to 560re-link it), you have to decide whether the benefits of Readonly 561variables outweigh the speed issue. For most configuration variables 562(and other things that Readonly is likely to be useful for), the speed 563issue is probably not really a big problem. But benchmark your 564program if it might be. If it turns out to be a problem, you may 565still want to use Readonly.pm during development, to catch changes to 566variables that should not be changed, and then remove it for 567production: 568 569 # For testing: 570 Readonly::Scalar $Foo_Directory => '/usr/local/foo'; 571 Readonly::Scalar $Bar_Directory => '/usr/local/bar'; 572 # $Foo_Directory = '/usr/local/foo'; 573 # $Bar_Directory = '/usr/local/bar'; 574 575 # For production: 576 # Readonly::Scalar $Foo_Directory => '/usr/local/foo'; 577 # Readonly::Scalar $Bar_Directory => '/usr/local/bar'; 578 $Foo_Directory = '/usr/local/foo'; 579 $Bar_Directory = '/usr/local/bar'; 580 581 582=head1 FUNCTIONS 583 584=over 4 585 586=item Readonly::Scalar $var => $value; 587 588Creates a nonmodifiable scalar, C<$var>, and assigns a value of 589C<$value> to it. Thereafter, its value may not be changed. Any 590attempt to modify the value will cause your program to die. 591 592A value I<must> be supplied. If you want the variable to have 593C<undef> as its value, you must specify C<undef>. 594 595If C<$value> is a reference to a scalar, array, or hash, then this 596function will mark the scalar, array, or hash it points to as being 597Readonly as well, and it will recursively traverse the structure, 598marking the whole thing as Readonly. Usually, this is what you want. 599However, if you want only the C<$value> marked as Readonly, use 600C<Scalar1>. 601 602If $var is already a Readonly variable, the program will die with 603an error about reassigning Readonly variables. 604 605=item Readonly::Array @arr => (value, value, ...); 606 607Creates a nonmodifiable array, C<@arr>, and assigns the specified list 608of values to it. Thereafter, none of its values may be changed; the 609array may not be lengthened or shortened or spliced. Any attempt to 610do so will cause your program to die. 611 612If any of the values passed is a reference to a scalar, array, or hash, 613then this function will mark the scalar, array, or hash it points to as 614being Readonly as well, and it will recursively traverse the structure, 615marking the whole thing as Readonly. Usually, this is what you want. 616However, if you want only the hash C<%@arr> itself marked as Readonly, 617use C<Array1>. 618 619If @arr is already a Readonly variable, the program will die with 620an error about reassigning Readonly variables. 621 622=item Readonly::Hash %h => (key => value, key => value, ...); 623 624=item Readonly::Hash %h => {key => value, key => value, ...}; 625 626Creates a nonmodifiable hash, C<%h>, and assigns the specified keys 627and values to it. Thereafter, its keys or values may not be changed. 628Any attempt to do so will cause your program to die. 629 630A list of keys and values may be specified (with parentheses in the 631synopsis above), or a hash reference may be specified (curly braces in 632the synopsis above). If a list is specified, it must have an even 633number of elements, or the function will die. 634 635If any of the values is a reference to a scalar, array, or hash, then 636this function will mark the scalar, array, or hash it points to as 637being Readonly as well, and it will recursively traverse the 638structure, marking the whole thing as Readonly. Usually, this is what 639you want. However, if you want only the hash C<%h> itself marked as 640Readonly, use C<Hash1>. 641 642If %h is already a Readonly variable, the program will die with 643an error about reassigning Readonly variables. 644 645=item Readonly $var => $value; 646 647=item Readonly @arr => (value, value, ...); 648 649=item Readonly %h => (key => value, ...); 650 651=item Readonly %h => {key => value, ...}; 652 653The C<Readonly> function is an alternate to the C<Scalar>, C<Array>, 654and C<Hash> functions. It has the advantage (if you consider it an 655advantage) of being one function. That may make your program look 656neater, if you're initializing a whole bunch of constants at once. 657You may or may not prefer this uniform style. 658 659It has the disadvantage of having a slightly different syntax for 660versions of Perl prior to 5.8. For earlier versions, you must supply 661a backslash, because it requires a reference as the first parameter. 662 663 Readonly \$var => $value; 664 Readonly \@arr => (value, value, ...); 665 Readonly \%h => (key => value, ...); 666 Readonly \%h => {key => value, ...}; 667 668You may or may not consider this ugly. 669 670=item Readonly::Scalar1 $var => $value; 671 672=item Readonly::Array1 @arr => (value, value, ...); 673 674=item Readonly::Hash1 %h => (key => value, key => value, ...); 675 676=item Readonly::Hash1 %h => {key => value, key => value, ...}; 677 678These alternate functions create shallow Readonly variables, instead 679of deep ones. For example: 680 681 Readonly::Array1 @shal => (1, 2, {perl=>'Rules', java=>'Bites'}, 4, 5); 682 Readonly::Array @deep => (1, 2, {perl=>'Rules', java=>'Bites'}, 4, 5); 683 684 $shal[1] = 7; # error 685 $shal[2]{APL}='Weird'; # Allowed! since the hash isn't Readonly 686 $deep[1] = 7; # error 687 $deep[2]{APL}='Weird'; # error, since the hash is Readonly 688 689 690=back 691 692 693=head1 EXAMPLES 694 695 # SCALARS: 696 697 # A plain old read-only value 698 Readonly::Scalar $a => "A string value"; 699 700 # The value need not be a compile-time constant: 701 Readonly::Scalar $a => $computed_value; 702 703 704 # ARRAYS: 705 706 # A read-only array: 707 Readonly::Array @a => (1, 2, 3, 4); 708 709 # The parentheses are optional: 710 Readonly::Array @a => 1, 2, 3, 4; 711 712 # You can use Perl's built-in array quoting syntax: 713 Readonly::Array @a => qw/1 2 3 4/; 714 715 # You can initialize a read-only array from a variable one: 716 Readonly::Array @a => @computed_values; 717 718 # A read-only array can be empty, too: 719 Readonly::Array @a => (); 720 Readonly::Array @a; # equivalent 721 722 723 # HASHES 724 725 # Typical usage: 726 Readonly::Hash %a => (key1 => 'value1', key2 => 'value2'); 727 728 # A read-only hash can be initialized from a variable one: 729 Readonly::Hash %a => %computed_values; 730 731 # A read-only hash can be empty: 732 Readonly::Hash %a => (); 733 Readonly::Hash %a; # equivalent 734 735 # If you pass an odd number of values, the program will die: 736 Readonly::Hash %a => (key1 => 'value1', "value2"); 737 --> dies with "May not store an odd number of values in a hash" 738 739 740=head1 EXPORTS 741 742By default, this module exports the following symbol into the calling 743program's namespace: 744 745 Readonly 746 747The following symbols are available for import into your program, if 748you like: 749 750 Scalar Scalar1 751 Array Array1 752 Hash Hash1 753 754 755=head1 REQUIREMENTS 756 757 Perl 5.000 758 Carp.pm (included with Perl) 759 Exporter.pm (included with Perl) 760 761 Readonly::XS is recommended but not required. 762 763=head1 ACKNOWLEDGEMENTS 764 765Thanks to Slaven Rezic for the idea of one common function 766(Readonly) for all three types of variables (13 April 2002). 767 768Thanks to Ernest Lergon for the idea (and initial code) for 769deeply-Readonly data structures (21 May 2002). 770 771Thanks to Damian Conway for the idea (and code) for making the 772Readonly function work a lot smoother under perl 5.8+. 773 774 775=head1 AUTHOR / COPYRIGHT 776 777Eric J. Roode, roode@cpan.org 778 779Copyright (c) 2001-2004 by Eric J. Roode. All Rights Reserved. This 780module is free software; you can redistribute it and/or modify it under 781the same terms as Perl itself. 782 783If you have suggestions for improvement, please drop me a line. If 784you make improvements to this software, I ask that you please send me 785a copy of your changes. Thanks. 786 787Readonly.pm is made from 100% recycled electrons. No animals were 788harmed during the development and testing of this module. Not sold 789in stores! Readonly::XS sold separately. Void where prohibited. 790 791=cut 792 793=begin gpg 794 795-----BEGIN PGP SIGNATURE----- 796Version: GnuPG v1.2.4 (MingW32) 797 798iD8DBQFAhaGCY96i4h5M0egRAg++AJ0ar4ncojbOp0OOc2wo+E/1cBn5cQCg9eP9 799qTzAC87PuyKB+vrcRykrDbo= 800=39Ny 801-----END PGP SIGNATURE----- 802 803=cut