Syntax-Feature-With
view release on metacpan or search on metacpan
},
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : "6.64"
}
},
"runtime" : {
"requires" : {
"Carp" : "0",
"Exporter" : "0",
"PadWalker" : "0",
"perl" : "5.008"
}
},
"test" : {
"requires" : {
"Test::DescribeMe" : "0",
"Test::Most" : "0",
"Test::Needs" : "0"
}
}
url: http://module-build.sourceforge.net/META-spec-v1.4.html
version: '1.4'
name: Syntax-Feature-With
no_index:
directory:
- t
- inc
requires:
Carp: '0'
Exporter: '0'
PadWalker: '0'
perl: '5.008'
resources:
bugtracker: https://rt.cpan.org/Public/Dist/Display.html?Name=Syntax-Feature-With
homepage: https://metacpan.org/pod/Syntax::Feature::With
repository: git://github.com/nigelhorne/Syntax-Feature-With.git
version: '0.02'
x_serialization_backend: 'CPAN::Meta::YAML version 0.020'
Makefile.PL view on Meta::CPAN
NAME => 'Syntax::Feature::With',
ABSTRACT_FROM => 'lib/Syntax/Feature/With.pm',
VERSION_FROM => 'lib/Syntax/Feature/With.pm',
AUTHOR => 'Nigel Horne (njh@nigelhorne.com)',
((defined($ExtUtils::MakeMaker::VERSION) && ($ExtUtils::MakeMaker::VERSION >= 6.3002))
? ('LICENSE'=> 'GPL')
: ()),
PREREQ_PM => {
'Carp' => 0,
'Exporter' => 0,
'PadWalker' => 0,
}, CONFIGURE_REQUIRES => {
'ExtUtils::MakeMaker' => 6.64, # Minimum version for TEST_REQUIRES
}, TEST_REQUIRES => {
'Test::DescribeMe' => 0,
'Test::Most' => 0,
'Test::Needs' => 0,
}, dist => $dist,
clean => { FILES => 'Syntax-Feature-With-*' },
META_MERGE => { # https://perldoc.perl.org/CPAN::Meta::Spec
'meta-spec' => { version => 2 },
# Convenience wrapper
with_hash %h => sub {
say $a;
};
# DESCRIPTION
`with()` provides a simple, predictable way to temporarily alias hash
keys into lexical variables inside a coderef.
It is implemented using [PadWalker](https://metacpan.org/pod/PadWalker) and requires no XS, no parser hooks, and no syntax changes.
# FEATURES
## Read/write aliasing
Lexicals declared in the outer scope become aliases to hash entries:
my ($a);
with \%h, sub { $a = 10 }; # updates $h{a}
If a lexical is missing, `-strict` throws an error before the block runs.
## Strict Keys (keys must have lexicals)
Require that every visible key has a corresponding lexical:
my %cfg = ( host => 'localhost', port => 3306 );
my ($host, $port);
with_hash -strict_keys => \%cfg, sub {
() = $host; # ensure PadWalker sees it
() = $port;
};
This is the inverse of `-strict`.
## Renaming Keys
Expose hash keys under different lexical names:
my %cfg = ( 'http-status' => 200, 'user_id' => 42 );
Use it when you already have a validated
hashref and want direct control:
my %cfg = ( x => 10, y => 20 );
my ($x, $y);
with \%cfg, sub {
$x += $y;
};
## Forcing PadWalker to See a Lexical
PadWalker only reports lexicals that the coderef actually closes over.
To ensure a lexical is visible under `-strict_keys`, use:
() = $debug;
This evaluates the variable in void context, ensuring that PadWalker
treats it as closed over without warnings.
## with\_hash
with_hash \%hash, sub {
say $foo; # reads $hash{foo}
$bar = 123; # writes to $hash{bar}
};
with_hash strict => a => 1, b => 2, sub {
sub { ... };
If `%config` contains a key that does not map to a declared lexical (after
renaming), an error is thrown.
This mode is useful for catching unexpected or misspelled keys in
configuration hashes or user input.
#### A note on `-strict_keys` and unused lexicals
`-strict_keys` relies on ["closed\_over" in PadWalker](https://metacpan.org/pod/PadWalker#closed_over) to determine which
lexical variables are visible to the coderef. PadWalker only reports
lexicals that the coderef actually closes over. A lexical that is
declared in the outer scope but never referenced inside the block is
not considered "closed over" and therefore will not appear in the pad.
This means that under `-strict_keys`, a declared lexical must be
\*mentioned\* inside the block, otherwise it will be treated as missing:
my ($host, $port, $debug);
with_hash -strict_keys => \%cfg, sub {
say $host; # ok
# $port is declared but unused - PadWalker does not report it
# $debug is declared but unused - also not reported
};
The above will die with:
strict_keys mode: hash key 'port' has no lexical $port
To force a lexical to be recognised without producing warnings, use the
standard idiom:
() = $port;
() = $debug;
This evaluates the variable in void context, ensuring that PadWalker
treats it as closed over, without affecting program behaviour.
This is a limitation of Perl's closure model rather than of this module.
# AUTHOR
Nigel Horne, `<njh at nigelhorne.com>`
# LIMITATIONS
`with()` uses PadWalker to manipulate lexical pads.
This is fast enough for normal use, but not intended for tight loops or high-frequency calls.
- Lexicals must be declared in the outer scope.
- Only hashrefs are supported.
- Only keys matching `/^[A-Za-z_]\w*$/` are eligible.
# AUTHOR
Nigel Horne
# Generated from Makefile.PL using makefilepl2cpanfile
requires 'perl', '5.008';
requires 'Carp';
requires 'Exporter';
requires 'PadWalker';
on 'configure' => sub {
requires 'ExtUtils::MakeMaker', '6.64';
};
on 'test' => sub {
requires 'Test::DescribeMe';
requires 'Test::Most';
requires 'Test::Needs';
};
on 'develop' => sub {
lib/Syntax/Feature/With.pm view on Meta::CPAN
package Syntax::Feature::With;
use strict;
use warnings;
use Carp 'croak';
use Exporter 'import';
use PadWalker qw(closed_over set_closed_over);
our @EXPORT_OK = qw(with with_hash);
our @EXPORT = qw(with with_hash);
our $VERSION = '0.02';
# Track nested with() depth for trace/debug output
my $WITH_DEPTH = 0;
=head1 NAME
lib/Syntax/Feature/With.pm view on Meta::CPAN
# Convenience wrapper
with_hash %h => sub {
say $a;
};
=head1 DESCRIPTION
C<with()> provides a simple, predictable way to temporarily alias hash
keys into lexical variables inside a coderef.
It is implemented using L<PadWalker> and requires no XS, no parser hooks, and no syntax changes.
=head1 FEATURES
=head2 Read/write aliasing
Lexicals declared in the outer scope become aliases to hash entries:
my ($a);
with \%h, sub { $a = 10 }; # updates $h{a}
lib/Syntax/Feature/With.pm view on Meta::CPAN
If a lexical is missing, C<-strict> throws an error before the block runs.
=head2 Strict Keys (keys must have lexicals)
Require that every visible key has a corresponding lexical:
my %cfg = ( host => 'localhost', port => 3306 );
my ($host, $port);
with_hash -strict_keys => \%cfg, sub {
() = $host; # ensure PadWalker sees it
() = $port;
};
This is the inverse of C<-strict>.
=head2 Renaming Keys
Expose hash keys under different lexical names:
my %cfg = ( 'http-status' => 200, 'user_id' => 42 );
lib/Syntax/Feature/With.pm view on Meta::CPAN
Use it when you already have a validated
hashref and want direct control:
my %cfg = ( x => 10, y => 20 );
my ($x, $y);
with \%cfg, sub {
$x += $y;
};
=head2 Forcing PadWalker to See a Lexical
PadWalker only reports lexicals that the coderef actually closes over.
To ensure a lexical is visible under C<-strict_keys>, use:
() = $debug;
This evaluates the variable in void context, ensuring that PadWalker
treats it as closed over without warnings.
=cut
# ------------------------------------------------------------
# with() â main entry point
# ------------------------------------------------------------
sub with {
my @args = @_;
lib/Syntax/Feature/With.pm view on Meta::CPAN
sub { ... };
If C<%config> contains a key that does not map to a declared lexical (after
renaming), an error is thrown.
This mode is useful for catching unexpected or misspelled keys in
configuration hashes or user input.
=head4 A note on C<-strict_keys> and unused lexicals
C<-strict_keys> relies on L<PadWalker/closed_over> to determine which
lexical variables are visible to the coderef. PadWalker only reports
lexicals that the coderef actually closes over. A lexical that is
declared in the outer scope but never referenced inside the block is
not considered "closed over" and therefore will not appear in the pad.
This means that under C<-strict_keys>, a declared lexical must be
*mentioned* inside the block, otherwise it will be treated as missing:
my ($host, $port, $debug);
with_hash -strict_keys => \%cfg, sub {
say $host; # ok
# $port is declared but unused - PadWalker does not report it
# $debug is declared but unused - also not reported
};
The above will die with:
strict_keys mode: hash key 'port' has no lexical $port
To force a lexical to be recognised without producing warnings, use the
standard idiom:
() = $port;
() = $debug;
This evaluates the variable in void context, ensuring that PadWalker
treats it as closed over, without affecting program behaviour.
This is a limitation of Perl's closure model rather than of this module.
=cut
sub with_hash {
my @args = @_;
# 1. Boolean flags
lib/Syntax/Feature/With.pm view on Meta::CPAN
1;
__END__
=head1 AUTHOR
Nigel Horne, C<< <njh at nigelhorne.com> >>
=head1 LIMITATIONS
C<with()> uses PadWalker to manipulate lexical pads.
This is fast enough for normal use, but not intended for tight loops or high-frequency calls.
=over 4
=item *
Lexicals must be declared in the outer scope.
=item *
#!/usr/bin/perl
use strict;
use warnings;
use Test::More;
# We are testing a PadWalker-based implementation of:
#
# with(\%hash, sub { ... });
#
# Contract:
# - First arg: hashref
# - Second arg: coderef
# - Lexicals to be aliased (e.g. $a, $x) must be declared
# in the *outer* scope and closed over by the coderef.
#
# Example:
# my %h = ( a => 'b' );
# my ($a);
# with(\%h, sub { print $a }); # $a aliases $h{a}
#
# This is required because PadWalker::closed_over only sees
# lexicals that are closed over, not those declared inside
# the coderef itself.
use_ok('Syntax::Feature::With');
# ----------------------------------------------------------------------
# Basic aliasing: $a should alias $h{a}
# ----------------------------------------------------------------------
{
( run in 0.648 second using v1.01-cache-2.11-cpan-39bf76dae61 )