| 1 |
=for gpg |
|---|
| 2 |
-----BEGIN PGP SIGNED MESSAGE----- |
|---|
| 3 |
Hash: SHA1 |
|---|
| 4 |
|
|---|
| 5 |
- -----BEGIN PGP SIGNED MESSAGE----- |
|---|
| 6 |
Hash: SHA1 |
|---|
| 7 |
|
|---|
| 8 |
=head1 NAME |
|---|
| 9 |
|
|---|
| 10 |
Readonly - Facility for creating read-only scalars, arrays, hashes. |
|---|
| 11 |
|
|---|
| 12 |
=head1 VERSION |
|---|
| 13 |
|
|---|
| 14 |
This documentation describes version 1.03 of Readonly.pm, April 20, 2004. |
|---|
| 15 |
|
|---|
| 16 |
=cut |
|---|
| 17 |
|
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 |
use 5.005; |
|---|
| 21 |
use strict; |
|---|
| 22 |
|
|---|
| 23 |
|
|---|
| 24 |
|
|---|
| 25 |
package Readonly; |
|---|
| 26 |
$Readonly::VERSION = '1.03'; |
|---|
| 27 |
|
|---|
| 28 |
|
|---|
| 29 |
|
|---|
| 30 |
sub croak |
|---|
| 31 |
{ |
|---|
| 32 |
require Carp; |
|---|
| 33 |
goto &Carp::croak; |
|---|
| 34 |
} |
|---|
| 35 |
|
|---|
| 36 |
|
|---|
| 37 |
sub is_sv_readonly ($) { 0 } |
|---|
| 38 |
sub make_sv_readonly ($) { die "make_sv_readonly called but not overridden" } |
|---|
| 39 |
use vars qw/$XSokay/; |
|---|
| 40 |
|
|---|
| 41 |
|
|---|
| 42 |
use 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 |
|
|---|
| 48 |
$Readonly::XS::MAGIC_COOKIE = "Do NOT use or require Readonly::XS unless you're me."; |
|---|
| 49 |
eval 'use Readonly::XS'; |
|---|
| 50 |
|
|---|
| 51 |
|
|---|
| 52 |
|
|---|
| 53 |
|
|---|
| 54 |
|
|---|
| 55 |
package Readonly::Scalar; |
|---|
| 56 |
|
|---|
| 57 |
sub TIESCALAR |
|---|
| 58 |
{ |
|---|
| 59 |
my $whence = (caller 2)[3]; |
|---|
| 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 |
|
|---|
| 69 |
sub FETCH |
|---|
| 70 |
{ |
|---|
| 71 |
my $self = shift; |
|---|
| 72 |
return $$self; |
|---|
| 73 |
} |
|---|
| 74 |
|
|---|
| 75 |
*STORE = *UNTIE = |
|---|
| 76 |
sub {Readonly::croak $Readonly::MODIFY}; |
|---|
| 77 |
|
|---|
| 78 |
|
|---|
| 79 |
|
|---|
| 80 |
|
|---|
| 81 |
|
|---|
| 82 |
package Readonly::Array; |
|---|
| 83 |
|
|---|
| 84 |
sub TIEARRAY |
|---|
| 85 |
{ |
|---|
| 86 |
my $whence = (caller 1)[3]; |
|---|
| 87 |
Readonly::croak "Invalid tie" unless $whence =~ /^Readonly::Array1?$/; |
|---|
| 88 |
my $class = shift; |
|---|
| 89 |
my @self = @_; |
|---|
| 90 |
|
|---|
| 91 |
return bless \@self, $class; |
|---|
| 92 |
} |
|---|
| 93 |
|
|---|
| 94 |
sub FETCH |
|---|
| 95 |
{ |
|---|
| 96 |
my $self = shift; |
|---|
| 97 |
my $index = shift; |
|---|
| 98 |
return $self->[$index]; |
|---|
| 99 |
} |
|---|
| 100 |
|
|---|
| 101 |
sub FETCHSIZE |
|---|
| 102 |
{ |
|---|
| 103 |
my $self = shift; |
|---|
| 104 |
return scalar @$self; |
|---|
| 105 |
} |
|---|
| 106 |
|
|---|
| 107 |
BEGIN { |
|---|
| 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; |
|---|
| 116 |
} |
|---|
| 117 |
|
|---|
| 118 |
*STORE = *STORESIZE = *EXTEND = *PUSH = *POP = *UNSHIFT = *SHIFT = *SPLICE = *CLEAR = *UNTIE = |
|---|
| 119 |
sub {Readonly::croak $Readonly::MODIFY}; |
|---|
| 120 |
|
|---|
| 121 |
|
|---|
| 122 |
|
|---|
| 123 |
|
|---|
| 124 |
|
|---|
| 125 |
package Readonly::Hash; |
|---|
| 126 |
|
|---|
| 127 |
sub TIEHASH |
|---|
| 128 |
{ |
|---|
| 129 |
my $whence = (caller 1)[3]; |
|---|
| 130 |
Readonly::croak "Invalid tie" unless $whence =~ /^Readonly::Hash1?$/; |
|---|
| 131 |
|
|---|
| 132 |
my $class = shift; |
|---|
| 133 |
|
|---|
| 134 |
Readonly::croak $Readonly::ODDHASH unless (@_ %2 == 0); |
|---|
| 135 |
|
|---|
| 136 |
my %self = @_; |
|---|
| 137 |
return bless \%self, $class; |
|---|
| 138 |
} |
|---|
| 139 |
|
|---|
| 140 |
sub FETCH |
|---|
| 141 |
{ |
|---|
| 142 |
my $self = shift; |
|---|
| 143 |
my $key = shift; |
|---|
| 144 |
|
|---|
| 145 |
return $self->{$key}; |
|---|
| 146 |
} |
|---|
| 147 |
|
|---|
| 148 |
sub EXISTS |
|---|
| 149 |
{ |
|---|
| 150 |
my $self = shift; |
|---|
| 151 |
my $key = shift; |
|---|
| 152 |
return exists $self->{$key}; |
|---|
| 153 |
} |
|---|
| 154 |
|
|---|
| 155 |
sub FIRSTKEY |
|---|
| 156 |
{ |
|---|
| 157 |
my $self = shift; |
|---|
| 158 |
my $dummy = keys %$self; |
|---|
| 159 |
return scalar each %$self; |
|---|
| 160 |
} |
|---|
| 161 |
|
|---|
| 162 |
sub 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 |
|
|---|
| 174 |
|
|---|
| 175 |
|
|---|
| 176 |
package Readonly; |
|---|
| 177 |
use Exporter; |
|---|
| 178 |
use vars qw/@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS/; |
|---|
| 179 |
push @ISA, 'Exporter'; |
|---|
| 180 |
push @EXPORT, qw/Readonly/; |
|---|
| 181 |
push @EXPORT_OK, qw/Scalar Array Hash Scalar1 Array1 Hash1/; |
|---|
| 182 |
|
|---|
| 183 |
|
|---|
| 184 |
sub Scalar ($$); |
|---|
| 185 |
sub Array (\@;@); |
|---|
| 186 |
sub Hash (\%;@); |
|---|
| 187 |
|
|---|
| 188 |
|
|---|
| 189 |
|
|---|
| 190 |
sub _is_badtype |
|---|
| 191 |
{ |
|---|
| 192 |
my $type = $_[0]; |
|---|
| 193 |
return lc $type if $type =~ s/^Readonly:://; |
|---|
| 194 |
return; |
|---|
| 195 |
} |
|---|
| 196 |
|
|---|
| 197 |
|
|---|
| 198 |
sub 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 |
|
|---|
| 205 |
if ($XSokay) |
|---|
| 206 |
{ |
|---|
| 207 |
$_[0] = $_[1]; |
|---|
| 208 |
make_sv_readonly $_[0]; |
|---|
| 209 |
return; |
|---|
| 210 |
} |
|---|
| 211 |
|
|---|
| 212 |
|
|---|
| 213 |
my $tieobj = eval {tie $_[0], 'Readonly::Scalar', $_[1]}; |
|---|
| 214 |
if ($@) |
|---|
| 215 |
{ |
|---|
| 216 |
croak "$REASSIGN scalar" if substr($@,0,43) eq $MODIFY; |
|---|
| 217 |
die $@; |
|---|
| 218 |
} |
|---|
| 219 |
return $tieobj; |
|---|
| 220 |
} |
|---|
| 221 |
|
|---|
| 222 |
|
|---|
| 223 |
sub 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 |
|
|---|
| 233 |
sub Hash1 (\%;@) |
|---|
| 234 |
{ |
|---|
| 235 |
my $badtype = _is_badtype (ref tied $_[0]); |
|---|
| 236 |
croak "$REASSIGN $badtype" if $badtype; |
|---|
| 237 |
|
|---|
| 238 |
my $href = shift; |
|---|
| 239 |
|
|---|
| 240 |
|
|---|
| 241 |
if (@_ == 1 && ref $_[0] eq 'HASH') |
|---|
| 242 |
{ |
|---|
| 243 |
return tie %$href, 'Readonly::Hash', %{$_[0]}; |
|---|
| 244 |
} |
|---|
| 245 |
|
|---|
| 246 |
|
|---|
| 247 |
croak $ODDHASH unless (@_%2 == 0); |
|---|
| 248 |
|
|---|
| 249 |
return tie %$href, 'Readonly::Hash', @_; |
|---|
| 250 |
} |
|---|
| 251 |
|
|---|
| 252 |
|
|---|
| 253 |
sub 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 |
|
|---|
| 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 |
|
|---|
| 270 |
if ($XSokay) |
|---|
| 271 |
{ |
|---|
| 272 |
$_[0] = $value; |
|---|
| 273 |
make_sv_readonly $_[0]; |
|---|
| 274 |
return; |
|---|
| 275 |
} |
|---|
| 276 |
|
|---|
| 277 |
|
|---|
| 278 |
my $tieobj = eval {tie $_[0], 'Readonly::Scalar', $value}; |
|---|
| 279 |
if ($@) |
|---|
| 280 |
{ |
|---|
| 281 |
croak "$REASSIGN scalar" if substr($@,0,43) eq $MODIFY; |
|---|
| 282 |
die $@; |
|---|
| 283 |
} |
|---|
| 284 |
return $tieobj; |
|---|
| 285 |
} |
|---|
| 286 |
|
|---|
| 287 |
|
|---|
| 288 |
sub 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 |
|
|---|
| 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 |
|
|---|
| 304 |
return tie @$aref, 'Readonly::Array', @values; |
|---|
| 305 |
} |
|---|
| 306 |
|
|---|
| 307 |
|
|---|
| 308 |
sub 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 |
|
|---|
| 317 |
if (@_ == 1 && ref $_[0] eq 'HASH') |
|---|
| 318 |
{ |
|---|
| 319 |
@values = %{$_[0]}; |
|---|
| 320 |
} |
|---|
| 321 |
|
|---|
| 322 |
|
|---|
| 323 |
croak $ODDHASH unless (@values %2 == 0); |
|---|
| 324 |
|
|---|
| 325 |
|
|---|
| 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 |
|
|---|
| 338 |
eval 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 |
|
|---|
| 349 |
if ($@) |
|---|
| 350 |
{ |
|---|
| 351 |
croak $MODIFY if $@ =~ /^$MODIFY at/; |
|---|
| 352 |
die "$@\n"; |
|---|
| 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 |
} |
|---|
| 376 |
SUB_READONLY |
|---|
| 377 |
|
|---|
| 378 |
|
|---|
| 379 |
1; |
|---|
| 380 |
__END__ |
|---|
| 381 |
|
|---|
| 382 |
=head1 SYNOPSIS |
|---|
| 383 |
|
|---|
| 384 |
use Readonly; |
|---|
| 385 |
|
|---|
| 386 |
|
|---|
| 387 |
Readonly::Scalar $sca => $initial_value; |
|---|
| 388 |
Readonly::Scalar my $sca => $initial_value; |
|---|
| 389 |
|
|---|
| 390 |
|
|---|
| 391 |
Readonly::Array @arr => @values; |
|---|
| 392 |
Readonly::Array my @arr => @values; |
|---|
| 393 |
|
|---|
| 394 |
|
|---|
| 395 |
Readonly::Hash %has => (key => value, key => value, ...); |
|---|
| 396 |
Readonly::Hash my %has => (key => value, key => value, ...); |
|---|
| 397 |
|
|---|
| 398 |
Readonly::Hash %has => {key => value, key => value, ...}; |
|---|
| 399 |
|
|---|
| 400 |
|
|---|
| 401 |
print $sca; |
|---|
| 402 |
$something = $sca + $arr[2]; |
|---|
| 403 |
next if $has{$some_key}; |
|---|
| 404 |
|
|---|
| 405 |
|
|---|
| 406 |
$sca = 7; |
|---|
| 407 |
push @arr, 'seven'; |
|---|
| 408 |
delete $has{key}; |
|---|
| 409 |
|
|---|
| 410 |
attempted" |
|---|
| 411 |
|
|---|
| 412 |
|
|---|
| 413 |
|
|---|
| 414 |
|
|---|
| 415 |
|
|---|
| 416 |
|
|---|
| 417 |
|
|---|
| 418 |
|
|---|
| 419 |
|
|---|
| 420 |
|
|---|
| 421 |
|
|---|
| 422 |
|
|---|
| 423 |
|
|---|
| 424 |
|
|---|
| 425 |
|
|---|
| 426 |
|
|---|
| 427 |
|
|---|
| 428 |
|
|---|
| 429 |
|
|---|
| 430 |
|
|---|
| 431 |
|
|---|
| 432 |
|
|---|
| 433 |
|
|---|
| 434 |
|
|---|
| 435 |
|
|---|
| 436 |
|
|---|
| 437 |
|
|---|
| 438 |
|
|---|
| 439 |
|
|---|
| 440 |
|
|---|
| 441 |
|
|---|
| 442 |
|
|---|
| 443 |
|
|---|
| 444 |
|
|---|
| 445 |
|
|---|
| 446 |
use constant" |
|---|
| 447 |
|
|---|
| 448 |
use |
|---|
| 449 |
constant" pragma. There are several problems with this pragma. |
|---|
| 450 |
|
|---|
| 451 |
=over 2 |
|---|
| 452 |
|
|---|
| 453 |
=item * |
|---|
| 454 |
|
|---|
| 455 |
The constants created have no leading $ or @ character. |
|---|
| 456 |
|
|---|
| 457 |
=item * |
|---|
| 458 |
|
|---|
| 459 |
These constants cannot be interpolated into strings. |
|---|
| 460 |
|
|---|
| 461 |
=item * |
|---|
| 462 |
|
|---|
| 463 |
Syntax 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 |
|
|---|
| 471 |
You have to be very careful in places where barewords are allowed. |
|---|
| 472 |
For 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 |
|
|---|
| 483 |
C<use constant> works for scalars and arrays, not hashes. |
|---|
| 484 |
|
|---|
| 485 |
=item * |
|---|
| 486 |
|
|---|
| 487 |
These constants are global ot the package in which they're declared; |
|---|
| 488 |
cannot be lexically scoped. |
|---|
| 489 |
|
|---|
| 490 |
=item * |
|---|
| 491 |
|
|---|
| 492 |
Works only at compile time. |
|---|
| 493 |
|
|---|
| 494 |
=item * |
|---|
| 495 |
|
|---|
| 496 |
Can 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 |
|
|---|
| 506 |
It is very difficult to make and use deep structures (complex data |
|---|
| 507 |
structures) with C<use constant>. |
|---|
| 508 |
|
|---|
| 509 |
=back |
|---|
| 510 |
|
|---|
| 511 |
=head1 COMPARISON WITH TYPEGLOB CONSTANTS |
|---|
| 512 |
|
|---|
| 513 |
Another popular way to create read-only scalars is to modify the symbol |
|---|
| 514 |
table entry for the variable by using a typeglob: |
|---|
| 515 |
|
|---|
| 516 |
*a = \'value'; |
|---|
| 517 |
|
|---|
| 518 |
This works fine, but it only works for global variables ("my" |
|---|
| 519 |
variables have no symbol table entry). Also, the following similar |
|---|
| 520 |
constructs 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 |
|
|---|
| 527 |
Readonly.pm, on the other hand, will work with global variables and |
|---|
| 528 |
with lexical ("my") variables. It will create scalars, arrays, or |
|---|
| 529 |
hashes, all of which look and work like normal, read-write Perl |
|---|
| 530 |
variables. You can use them in scalar context, in list context; you |
|---|
| 531 |
can take references to them, pass them to functions, anything. |
|---|
| 532 |
|
|---|
| 533 |
Readonly.pm also works well with complex data structures, allowing you |
|---|
| 534 |
to tag the whole structure as nonmodifiable, or just the top level. |
|---|
| 535 |
|
|---|
| 536 |
Also, Readonly variables may not be reassigned. The following code |
|---|
| 537 |
will die: |
|---|
| 538 |
|
|---|
| 539 |
Readonly::Scalar $pi => 3.14159; |
|---|
| 540 |
... |
|---|
| 541 |
Readonly::Scalar $pi => 2.71828; |
|---|
| 542 |
|
|---|
| 543 |
=head1 CONS |
|---|
| 544 |
|
|---|
| 545 |
Readonly.pm does impose a performance penalty. It's pretty slow. How |
|---|
| 546 |
slow? Run the C<benchmark.pl> script that comes with Readonly. On my |
|---|
| 547 |
test system, "use constant", typeglob constants, and regular |
|---|
| 548 |
read/write Perl variables were all about the same speed, and |
|---|
| 549 |
Readonly.pm constants were about 1/20 the speed. |
|---|
| 550 |
|
|---|
| 551 |
However, there is relief. There is a companion module available, |
|---|
| 552 |
Readonly::XS. If it is installed on your system, Readonly.pm uses it |
|---|
| 553 |
to make read-only scalars much faster. With Readonly::XS, Readonly |
|---|
| 554 |
scalars are as fast as the other types of variables. Readonly arrays |
|---|
| 555 |
and hashes will still be relatively slow. But it's likely that most |
|---|
| 556 |
of your Readonly variables will be scalars. |
|---|
| 557 |
|
|---|
| 558 |
If you can't use Readonly::XS (for example, if you don't have a C |
|---|
| 559 |
compiler, or your perl is statically linked and you don't want to |
|---|
| 560 |
re-link it), you have to decide whether the benefits of Readonly |
|---|
| 561 |
variables outweigh the speed issue. For most configuration variables |
|---|
| 562 |
(and other things that Readonly is likely to be useful for), the speed |
|---|
| 563 |
issue is probably not really a big problem. But benchmark your |
|---|
| 564 |
program if it might be. If it turns out to be a problem, you may |
|---|
| 565 |
still want to use Readonly.pm during development, to catch changes to |
|---|
| 566 |
variables that should not be changed, and then remove it for |
|---|
| 567 |
production: |
|---|
| 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 |
|
|---|
| 588 |
Creates a nonmodifiable scalar, C<$var>, and assigns a value of |
|---|
| 589 |
C<$value> to it. Thereafter, its value may not be changed. Any |
|---|
| 590 |
attempt to modify the value will cause your program to die. |
|---|
| 591 |
|
|---|
| 592 |
A value I<must> be supplied. If you want the variable to have |
|---|
| 593 |
C<undef> as its value, you must specify C<undef>. |
|---|
| 594 |
|
|---|
| 595 |
If C<$value> is a reference to a scalar, array, or hash, then this |
|---|
| 596 |
function will mark the scalar, array, or hash it points to as being |
|---|
| 597 |
Readonly as well, and it will recursively traverse the structure, |
|---|
| 598 |
marking the whole thing as Readonly. Usually, this is what you want. |
|---|
| 599 |
However, if you want only the C<$value> marked as Readonly, use |
|---|
| 600 |
C<Scalar1>. |
|---|
| 601 |
|
|---|
| 602 |
If $var is already a Readonly variable, the program will die with |
|---|
| 603 |
an error about reassigning Readonly variables. |
|---|
| 604 |
|
|---|
| 605 |
=item Readonly::Array @arr => (value, value, ...); |
|---|
| 606 |
|
|---|
| 607 |
Creates a nonmodifiable array, C<@arr>, and assigns the specified list |
|---|
| 608 |
of values to it. Thereafter, none of its values may be changed; the |
|---|
| 609 |
array may not be lengthened or shortened or spliced. Any attempt to |
|---|
| 610 |
do so will cause your program to die. |
|---|
| 611 |
|
|---|
| 612 |
If any of the values passed is a reference to a scalar, array, or hash, |
|---|
| 613 |
then this function will mark the scalar, array, or hash it points to as |
|---|
| 614 |
being Readonly as well, and it will recursively traverse the structure, |
|---|
| 615 |
marking the whole thing as Readonly. Usually, this is what you want. |
|---|
| 616 |
However, if you want only the hash C<%@arr> itself marked as Readonly, |
|---|
| 617 |
use C<Array1>. |
|---|
| 618 |
|
|---|
| 619 |
If @arr is already a Readonly variable, the program will die with |
|---|
| 620 |
an 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 |
|
|---|
| 626 |
Creates a nonmodifiable hash, C<%h>, and assigns the specified keys |
|---|
| 627 |
and values to it. Thereafter, its keys or values may not be changed. |
|---|
| 628 |
Any attempt to do so will cause your program to die. |
|---|
| 629 |
|
|---|
| 630 |
A list of keys and values may be specified (with parentheses in the |
|---|
| 631 |
synopsis above), or a hash reference may be specified (curly braces in |
|---|
| 632 |
the synopsis above). If a list is specified, it must have an even |
|---|
| 633 |
number of elements, or the function will die. |
|---|
| 634 |
|
|---|
| 635 |
If any of the values is a reference to a scalar, array, or hash, then |
|---|
| 636 |
this function will mark the scalar, array, or hash it points to as |
|---|
| 637 |
being Readonly as well, and it will recursively traverse the |
|---|
| 638 |
structure, marking the whole thing as Readonly. Usually, this is what |
|---|
| 639 |
you want. However, if you want only the hash C<%h> itself marked as |
|---|
| 640 |
Readonly, use C<Hash1>. |
|---|
| 641 |
|
|---|
| 642 |
If %h is already a Readonly variable, the program will die with |
|---|
| 643 |
an 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 |
|
|---|
| 653 |
The C<Readonly> function is an alternate to the C<Scalar>, C<Array>, |
|---|
| 654 |
and C<Hash> functions. It has the advantage (if you consider it an |
|---|
| 655 |
advantage) of being one function. That may make your program look |
|---|
| 656 |
neater, if you're initializing a whole bunch of constants at once. |
|---|
| 657 |
You may or may not prefer this uniform style. |
|---|
| 658 |
|
|---|
| 659 |
It has the disadvantage of having a slightly different syntax for |
|---|
| 660 |
versions of Perl prior to 5.8. For earlier versions, you must supply |
|---|
| 661 |
a 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 |
|
|---|
| 668 |
You 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 |
|
|---|
| 678 |
These alternate functions create shallow Readonly variables, instead |
|---|
| 679 |
of 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 |
|
|---|
| 742 |
By default, this module exports the following symbol into the calling |
|---|
| 743 |
program's namespace: |
|---|
| 744 |
|
|---|
| 745 |
Readonly |
|---|
| 746 |
|
|---|
| 747 |
The following symbols are available for import into your program, if |
|---|
| 748 |
you 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 |
|
|---|
| 765 |
Thanks to Slaven Rezic for the idea of one common function |
|---|
| 766 |
(Readonly) for all three types of variables (13 April 2002). |
|---|
| 767 |
|
|---|
| 768 |
Thanks to Ernest Lergon for the idea (and initial code) for |
|---|
| 769 |
deeply-Readonly data structures (21 May 2002). |
|---|
| 770 |
|
|---|
| 771 |
Thanks to Damian Conway for the idea (and code) for making the |
|---|
| 772 |
Readonly function work a lot smoother under perl 5.8+. |
|---|
| 773 |
|
|---|
| 774 |
|
|---|
| 775 |
=head1 AUTHOR / COPYRIGHT |
|---|
| 776 |
|
|---|
| 777 |
Eric J. Roode, roode@cpan.org |
|---|
| 778 |
|
|---|
| 779 |
Copyright (c) 2001-2004 by Eric J. Roode. All Rights Reserved. This |
|---|
| 780 |
module is free software; you can redistribute it and/or modify it under |
|---|
| 781 |
the same terms as Perl itself. |
|---|
| 782 |
|
|---|
| 783 |
If you have suggestions for improvement, please drop me a line. If |
|---|
| 784 |
you make improvements to this software, I ask that you please send me |
|---|
| 785 |
a copy of your changes. Thanks. |
|---|
| 786 |
|
|---|
| 787 |
Readonly.pm is made from 100% recycled electrons. No animals were |
|---|
| 788 |
harmed during the development and testing of this module. Not sold |
|---|
| 789 |
in stores! Readonly::XS sold separately. Void where prohibited. |
|---|
| 790 |
|
|---|
| 791 |
=cut |
|---|
| 792 |
|
|---|
| 793 |
=begin gpg |
|---|
| 794 |
|
|---|
| 795 |
-----BEGIN PGP SIGNATURE----- |
|---|
| 796 |
Version: GnuPG v1.2.4 (MingW32) |
|---|
| 797 |
|
|---|
| 798 |
iD8DBQFAhaGCY96i4h5M0egRAg++AJ0ar4ncojbOp0OOc2wo+E/1cBn5cQCg9eP9 |
|---|
| 799 |
qTzAC87PuyKB+vrcRykrDbo= |
|---|
| 800 |
=39Ny |
|---|
| 801 |
-----END PGP SIGNATURE----- |
|---|
| 802 |
|
|---|
| 803 |
=cut |
|---|