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(), or is_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 = $x copies the value but not the magic. $y will 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)