Syntax-Feature-With

 view release on metacpan or  search on metacpan

META.json  view on Meta::CPAN

      },
      "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"
         }
      }

META.yml  view on Meta::CPAN

  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 },

README.md  view on Meta::CPAN


    # 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}

README.md  view on Meta::CPAN

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 );

README.md  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;
    };

## 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 {

README.md  view on Meta::CPAN

        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

cpanfile  view on Meta::CPAN

# 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 *

t/with.t  view on Meta::CPAN

#!/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 2.038 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )