NAME
Tlaloc - Wetness magic on Perl scalars, blessed by the Aztec rain god
VERSION
Version 0.02
SYNOPSIS
use Tlaloc 'all';
my $scalar = "hello";
wet($scalar); # wetness = 50, evap_rate = 10
drench($scalar); # wetness = 100
print wetness($scalar); # 90 (each call costs evap_rate)
print wetness($scalar); # 80
print is_wet($scalar); # 1
print is_dry($scalar); # 0
# Custom evaporation rate
wet($scalar, 5); # wetness = 50, evap_rate = 5
drench($scalar, 20); # wetness = 100, evap_rate = 20
evap_rate($scalar, 1); # change evap_rate to 1
print evap_rate($scalar); # 1
dry($scalar);
print is_dry($scalar); # 1
print $scalar; # hello (value always unchanged)
DESCRIPTION
Tlaloc attaches invisible "wetness" metadata to any Perl scalar using Perl's internal MAGIC system (PERL_MAGIC_ext with a custom MGVTBL vtable). The wetness level (0-100) decreases by a configurable evaporation rate (default 10) on each access -- whether that is an explicit call to wetness(), is_wet(), or is_dry(), or a Perl-level read of the variable (string interpolation, numeric conversion, etc.) which fires the mg_get vtable callback.
When wetness reaches zero, the scalar is dry.
EXPORTS
Nothing is exported by default. Use 'all' to import everything:
use Tlaloc 'all';
Or import individual functions:
use Tlaloc qw( wet is_dry );
FUNCTIONS
wet($scalar)
wet($scalar, $evap_rate)
Makes $scalar wet with a wetness of 50. If $scalar is already wet, tops up by 50, capped at 100. If $evap_rate is provided, sets the evaporation rate (default 10).
drench($scalar)
drench($scalar, $evap_rate)
Drenches $scalar, setting wetness to exactly 100 regardless of its current level. If $evap_rate is provided, sets the evaporation rate.
dry($scalar)
Removes all wetness magic from $scalar. After this call is_dry will return true and wetness will return 0.
wetness($scalar)
Returns the current wetness level as an integer (0-100). Each call counts as one access and decrements wetness by the evaporation rate (default 10).
is_wet($scalar)
Returns 1 if $scalar currently has wetness greater than 0, 0 otherwise. Counts as one access.
is_dry($scalar)
Returns 1 if $scalar has wetness equal to 0 or has no wetness magic attached. Returns 0 otherwise. Counts as one access.
evap_rate($scalar)
evap_rate($scalar, $new_rate)
Gets or sets the evaporation rate for $scalar. Without a second argument, returns the current rate. With a second argument, sets the rate and returns the new value. Does NOT count as an access (no evaporation occurs). Returns 0 if the scalar has no wetness magic.
TIED WRAPPERS
For arrays and hashes, the magic-based wetness only evaporates when you explicitly call wetness(), is_wet(), or is_dry(). Element access ($arr[0], $hash{key}) does NOT trigger evaporation.
To get passive evaporation on element access, use tied wrappers:
use Tlaloc 'all';
my @arr = (1, 2, 3);
my $tied = wet_tie(\@arr, 5); # tie with evap_rate=5
my $x = $arr[0]; # evaporates!
my $y = $arr[1]; # evaporates!
print $tied->wetness, "\n"; # 85 (100 - 5 - 5 - 5)
untie_wet(\@arr); # restore normal array
wet_tie(\@array)
wet_tie(\@array, $evap_rate)
wet_tie(\%hash)
wet_tie(\%hash, $evap_rate)
Ties the array or hash with wetness tracking. Returns the tied object, which you can use to call wetness(), is_wet(), is_dry(), evap_rate(), drench(), wet() methods.
Element access (FETCH), existence checks, iterations, size checks, and removal operations (POP, SHIFT, SPLICE) all trigger evaporation. Stores and additions (STORE, PUSH, UNSHIFT) do NOT evaporate.
my @arr = (1, 2, 3);
my $tied = wet_tie(\@arr, 10);
# These evaporate:
my $x = $arr[0]; # FETCH
my $len = scalar @arr; # FETCHSIZE
for (@arr) { } # iteration (FETCH per element)
exists $arr[0]; # EXISTS
my $p = pop @arr; # POP
my $s = shift @arr; # SHIFT
# These do NOT evaporate:
$arr[0] = 99; # STORE
push @arr, 4; # PUSH
unshift @arr, 0; # UNSHIFT
untie_wet(\@array)
untie_wet(\%hash)
Removes the tie and restores the original array/hash data.
Tied Object Methods
The tied object supports these methods:
my $tied = wet_tie(\@arr);
$tied->wetness(); # current wetness (evaporates)
$tied->is_wet(); # true if wetness > 0 (evaporates)
$tied->is_dry(); # true if wetness == 0 (evaporates)
$tied->evap_rate(); # get current rate (no evaporation)
$tied->evap_rate(5); # set rate to 5
$tied->drench(); # set wetness to 100
$tied->drench(20); # set wetness to 100, evap_rate to 20
$tied->wet(); # add 50 wetness (capped at 100)
$tied->wet(3); # add 50, set evap_rate to 3
EVAPORATION
Wetness decrements by the evaporation rate (default 10) per access. An "access" is:
Any call to
wetness(),is_wet(), oris_dry()Any Perl-level read of the scalar (string interpolation, numeric context, assignment to another variable, use in a Perl built-in such as
join,sprintf,substr,split, regex match, etc.)
A drenched scalar (100) with default evap_rate (10) will be dry after 10 accesses. A wet scalar (50) with default evap_rate (10) will be dry after 5 accesses. With evap_rate of 1, a drenched scalar takes 100 accesses to dry.
CAVEATS
Passing a literal (
wet(42)) attaches magic to a temporary SV that is immediately freed. Only use variables, not literals.Magic is per-SV. Assigning
$y = $xcopies the value but not the magic.$ywill be dry.Not thread-safe across interpreter threads.
AUTHOR
LNATION <email@lnation.org>
BUGS
Please report bugs at https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Tlaloc.
LICENSE AND COPYRIGHT
This software is Copyright (c) 2026 by LNATION <email@lnation.org>.
This is free software, licensed under:
The Artistic License 2.0 (GPL Compatible)