NAME
Plack::Middleware::MangleEnv - Mangle request environment at will
VERSION
This document describes Plack::Middleware::MangleEnv version 0.001.
SYNOPSIS
use Plack::Middleware::MangleEnv;
my $mw = Plack::Middleware::MangleEnv->new(
# overriding is the default behaviour
# straight value, must be a plain SCALAR (no refs)
var_name => 'a simple, overriding value',
# any value can be wrapped, even refs
some_value => [ \@whatever ],
# or you can be just explicit
alternative => { value => $whatever },
# you can read stuff from %ENV
from_ENV => { ENV => 'PLACK_ENV' },
# or read other variables from $env
from_env => { env => 'psgi.url_scheme' },
# turn override into defaulting, works with value, env and ENV
de_fault => { value => $something, override => 0 },
# get rid of a variable, inconditionally. You can pass
# no value or be explicit about your intent
delete_pliz => [],
delete_me => { remove => 1 },
# use subroutines for maximum flexibility.
change_me1 => sub { ... },
change_me2 => { sub => sub { ... } },
);
# you can also pass the key/value pairs as a hash reference
# associated to a key named 'manglers'. This is necessary e.g. if
# you want to set a variable in $env with name 'app' (or 'manglers'
# itself)
my $mw2 = Plack::Middleware::MangleEnv->new(
manglers => {
what => 'EVER',
who => 'are you?',
}
);
# when evaluation order or repetition is important... use an array
# reference for 'manglers'
my $mw3 = Plack::Middleware::MangleEnv->new(
manglers => [
same_as => 'before', # set this at the beginning...
what => {env => 'same_as'},
...,
same_as => [], # ... and delete this at the end
]
);
DESCRIPTION
This module allows you to mangle Plack's $env
that is passed along to the sequence of apps, taking values from:
direct configuration;
values from
%ENV
;other values in
$env
itself;subroutines.
How Variables Are Set
The end goal of this middleware module is to manipulate $env
by adding, changing or deleting its items.
You can pass the different actions to be performed as key-value pairs. They can either appear directly upon invoking the middleware, as in the following example:
my $mw = Plack::Middleware::MangleEnv->new(
var_name => 'a simple, overriding value',
some_value => [ \@whatever ],
alternative => { value => $whatever },
# ... you get the idea
);
or wrap these pairs inside either an hash or an array reference whose key is manglers
, like in the following examples:
my $mw_h = Plack::Middleware::MangleEnv->new(
manglers => {
var_name => 'a simple, overriding value',
some_value => [ \@whatever ],
alternative => { value => $whatever },
# ... you get the idea
}
);
my $mw_a = Plack::Middleware::MangleEnv->new(
manglers => [
var_name => 'a simple, overriding value',
some_value => [ \@whatever ],
alternative => { value => $whatever },
# ... you get the idea
]
);
Although more verbose, this last approach with an array reference is important because it allows you to:
define the exact order of evaluation for mangling actions;
define multiple actions for the same key, possibly at different stages;
use keys
manglers
andapp
, if you need them.
There's a wide range of possible values that you can set associated to a key:
- Simple scalar
-
key => 'some simple, non-reference scalar',
a non-reference scalar is always taken as-is and then set in
$env
. - Array reference
-
key => [], key => [ { 'a non' => 'trivial scalar' } ],
when you pass an array reference, it can be either empty (in which case the associated key will be removed from
$env
) or contain exactly one value, which will be set into$env
.This alternative allows you to set any scalar, not just non-reference ones; so the following examples will do what they say:
# set key to an array ref with numbers 1..3 inside key => [ [1..3] ], # note: array ref inside array ref! # set key to a hash reference, literally key => [ { a => 'b', c => 'd' } ], # set key to a sub reference, literally key => [ sub { 'I go with key!' } ],
- Sub reference
-
key => sub { ... },
the sub reference will be called and its return value used to figure out the value to associate to the key. See "Sub Reference Interface" for details on the expected interface for the sub;
- Hash reference
-
allows you to be verbosely clear about what you want, in addition to giving you knobs to modify the behaviour. The allowed keys are the following:
env
-
points to a string that will be used to extract the value from
$env
itself. Useful if you want to change the name of a parameter; ENV
-
points to a string that will be used to extract the value from
%ENV
. Useful if you want to get some variables from the environment. list
-
points to a hash of configurations to build and handle a list of other sources (i.e.
env
,ENV
orvalue
).It collects data from a list of
sources
, optionallyflatten
inig them (if they are array or hash references), filtering them (e.g. to set default values forundef
or empty strings, or removing unwanted elements), then optionallyjoin
inig them or passing them tosprintf
. See "generate_hash_manglers_list" for the details on this hash and of each element insources
.For example, consider the following definition:
... connect_string => { list => { default => [], # remove undefined values join => ':', # join with ":" sources => [ {ENV => 'HOST'}, {ENV => 'PORT'} ], } } ...
The following applies:
%ENV = (HOST => 'localhost'); # leave PORT undefined --> $env->{connect_string} = 'localhost'; %ENV = (HOST => 'localhost', PORT => 80); --> $env->{connect_string} = 'localhost:80';
Something similar happens with
sprintf
, although the format is stricter in this case and we have to address this with defaults:... connect_string => { list => { default => [], # remove undefined values sprintf => '%s:%s', sources => [ {ENV => 'HOST', default => 'www.example.com'}, {ENV => 'PORT', default => 80}, ], } } ... %ENV = (); --> $env->{connect_string} = 'www.example.com:80'; %ENV = (HOST => 'localhost', PORT => 443); --> $env->{connect_string} = 'localhost:443';
In addition to plain strings, you can also set either
join
orsprintf
(never the two at the same time!) with a source specification withenv
,ENV
orvalue
:... sprintf_template => '%s:%s', # ends up in $env connect_string => { list => { default => [], # remove undefined values sprintf => {env => 'sprintf_template'}, sources => [ {ENV => 'HOST', default => 'www.example.com'}, {ENV => 'PORT', default => 80}, ], } } ... # same as before here
override
-
boolean flag that indicates whether the new value overrides a previous one, if any. Set to a false value to avoid overriding an existing value, while still being able to provide a default one if the key is missing from
$env
.Defaults to a true value;
sub
-
set a subroutine, see "Sub Reference Interface" for details;
value
-
set a value that is not a simple plain scalar:
# set key to an array ref with numbers 1..3 inside key => { value => [1..3] }, # set key to a hash reference, literally key => { value => { a => 'b', c => 'd' } }, # set key to a sub reference, literally key => { value => sub { 'I go with key!' } },
Exactly one of the keys
env
,ENV
,list
,sub
andvalue
MUST appear in the hash reference. For obvious reasons, you cannot provide more of them, otherwise a conflict would arise.
Sub Reference Interface
The most flexible way to mangle $env
is through a subroutine. It can be provided either directly associated to the key, or through the sub
sub-key in the hash associated to the key.
The provided subroutine reference will be called like this:
sub {
my ($current_value, $env, $key) = @_;
# do what you need
return @something;
}
The sub can modify $env
at will, e.g. by adding new keys or removing other ones based on your specific logic.
If you don't return anything, or the undef
value, the corresponding $key
in $env
will be left untouched, keeping its previous value (if any). Otherwise, you are supposed to return one single value that can be:
not an array reference, in which case it is used as the value associated to
$key
in$env
;an array reference. If the array is empty, the
$key
is removed from$env
; otherwise, it MUST contain exactly one value, used to set the key$key
in$env
(which also allows you to set as output an array reference, even an empty one).
Examples:
# nothing happens with this
sub { return }
# key is removed from $env
sub { return [] }
# key is set to an empty array in $env
sub { return [[]] }
METHODS
The following methods are implemented as part of the interface for a Plack middleware. Although you can override them... there's probably little sense in doing this!
- call
- prepare_app
Methods described in the following subsections can be overridden or used in derived classes. The various generate*_manglers
functions have the plural form because they can potentially return a list of manglers; in this module, anyway, each of them returns one single mangler per call.
generate_array_manglers
my @manglers = $obj->generate_array_manglers($key, $aref, $defaults);
generate manglers starting from an array definition. $aref
MUST be an ARRAY
reference. Depending on the number of elements in @$aref
:
if no element is present, a remove mangler is generated via "generate_remove_manglers"
if exactly one element is present, a value mangler is generated via "generate_immediate_manglers" with type
value
otherwise, an exception is thrown.
generate_code_manglers
my @manglers = $obj->generate_code_manglers($key, $sub, $defaults);
generate manglers from a sub definition. $sub
MUST be a CODE
reference.
The provided sub is wrapped using "wrap_code" to set the right behaviour around $sub
, then the output mangler is returned as follows:
[$key => {%$defaults, wrapsub => $wrapped_sub}]
generate_hash_manglers
my @manglers = $obj->generate_hash_manglers($key, $hash, $defaults);
generate manglers from a hash definition. $hash
MUST be a HASH
reference. This is actually a dispatcher for the different methods named generate_hash_manglers_*
, which can be overridden or added in derived classes to support further conversion types.
generate_hash_manglers_ENV
my @manglers = $obj->generate_hash_manglers_ENV($key, $name, $opts);
generate mangler for taking $ENV{$name}
.
generate_hash_manglers_env
my @manglers = $obj->generate_hash_manglers_env($key, $name, $opts);
generate mangler for taking $env-
{$name}>.
generate_hash_manglers_list
my @manglers = $obj->generate_hash_manglers_env($key, $cfg, $opts);
generate mangler for generating a list of elements from hash configuration %$cfg
. The following keys are supported:
default
-
a default value to assign if the source element is not present or has an undefined value. If it is an array reference, it follows the same rules explained at "Array reference". If an item in
sources
has adefault
configuration, that takes precedence. If not present, the same as setting[]
is assumed (i.e. undefined values will be removed). default_on_empty
-
boolean, apply the
default
above to empty values too, in addition to undefined values. Defaults to 0; flatten
-
boolean, turn array reference values into a list. Defaults to 0;
join
-
specification of a source (see below for the source specification provided for key
sources
) where it's possible to take a string for joining the elements of the list together. In this case, a single string will be returned. remove_if
-
array reference to strings that will be removed when found;
sources
-
array reference of hashes, explained below.
The different source specifications in sources
can take all the keys above as an overriding specialization (with the exception of sources
), and the following additional ones:
env
ENV
value
-
mutually exclusive keys indicating where the value should be taken from.
generate_hash_manglers_remove
Same as "generate_remove_manglers".
generate_hash_manglers_sub
Same as "generate_code_manglers".
generate_hash_manglers_value
my @manglers =
$obj->generate_hash_manglers_value($key, $value, $opts);
generate mangler for taking $value
.
generate_immediate_manglers
my @manglers =
$obj->generate_immediate_manglers($type, $key, $value, $opts);
generates this mangler:
[$key => {%$opts, $type => $value}]
i.e. the standard mangler for setting something immediately handled.
Note that this has the initial value for $type
, differently from other generate*_manglers
functions.
generate_manglers
my @manglers = $obj->generate_manglers($key, $value, $defaults);
Generate zero, one or more manglers, dispatching to the proper function depending on the type of $value
. $defaults
is a hash reference holding default values for the generated mangler, e.g. setting override
to 1 by default.
At the moment, all generation methods return exactly one mangler per call. This can of course change in derived classes, hence the returned value can contain any number of items.
This method does the following dispatching based on ref($value)
:
non-reference scalars: "generate_immediate_manglers" with type
value
array references: "generate_array_manglers"
hash references: "generate_hash_manglers"
code references: "generate_code_manglers"
anything else throws an exception.
If you want to override it (e.g. to add support for different types, or change the default ones described above) you might augment it like in the following example:
# suppose we want to do something with Regexp references
package Plack::Middleware::MangleEnv::Derived;
use parent 'Plack::Middleware::MangleEnv';
sub generate_manglers {
my $self = shift;
return $self->generate_regex_manglers(@_)
if ref($_[1]) eq 'Regexp';
return $self->SUPER::generate_manglers(@_);
}
sub generate_regex_manglers {
my ($self, $key, $regex, $defaults) = @_;
my $sub = sub {
defined(my $value = shift) or return; # do nothing if undef
my ($capture) = $value =~ m{$regex};
return $capture;
};
my $wrapsub = $self->wrap_code($sub);
return [$key => {%$defaults, wrapsub => $wrapsub}];
}
1;
generate_remove_manglers
my @manglers =
$obj->generate_remove_manglers($key, $value, $defaults);
convenience function to generate manglers for removing. Such manglers are supposed to have this form:
[ $key => { remove => 1 } ]
and this function does exactly this, ignoring $defaults
and checking that $value
is empty if it is a hash reference (it is used by "generate_hash_manglers" behind the scenes, so this checks that there are no further keys in the input mangler definition).
get_values_from_source
my @values = $obj->get_values_from_source($env, $spec);
runtime helper that expands the $spec
according to the rules explained in "generate_hash_manglers_list" for each source.
normalize_source
my $normal = $obj->normalize_source($source, $defaults);
normalizes a source (see "generate_hash_manglers_list") turning the pair with key env
, ENV
or value
into two pair, one with key type
and another one with key value
. Example:
{ env => 'whatever' } --> { type => 'env', value => 'whatever' }
Values for options (e.g. default
, default_on_empty
, etc.) are taken from hash reference $source
and, if absent, from $defaults
.
push_manglers
$obj->push_manglers->(@manglers);
add the provided @manglers
to the list of manglers that will be used at runtime.
Used by prepare_app
to populate the list of runtime manglers from the provided inputs. For every input definition of a mangler, "generate_manglers" is called and its output fed to this method, like this:
my @manglers = $obj->generate_manglers(...);
$obj->push_manglers(@manglers);
You might want to override this method if you want to further process all the generated manglers, like this:
package Plack::Middleware::MangleEnv::Derived;
use parent 'Plack::Middleware::MangleEnv';
sub push_manglers {
my $self = shift;
my @manglers = map { do_something($_) } @_;
return $self->SUPER::push_manglers(@manglers);
}
...
stringified_list
my @strings = $obj->stringified_list(@list);
convenience function to generate a list of strings suitable for logging. Defined element are escaped and put into single quotes, while undef
is rendered as the string undef
(without quoting).
wrap_code
my $wrapped_sub = $obj->wrap_code($sub);
wrap a code sub adhering to the "Sub Reference Interface" to implement the behaviour described in the same subsection. It is used by both "generate_code_manglers" and "generate_hash_manglers" to wrap input sub
s.
BUGS AND LIMITATIONS
Report bugs either through RT or GitHub (patches welcome).
SEE ALSO
Plack, Plack::Middleware::ForceEnv, Plack::Middleware::ReverseProxy, Plack::Middleware::SetEnvFromHeader, Plack::Middleware::SetLocalEnv.
AUTHOR
Flavio Poletti <polettix@cpan.org>
COPYRIGHT AND LICENSE
Copyright (C) 2016 by Flavio Poletti <polettix@cpan.org>
This module is free software. You can redistribute it and/or modify it under the terms of the Artistic License 2.0.
This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.