Badger
view release on metacpan or search on metacpan
lib/Badger/Codecs.pm view on Meta::CPAN
sub _export_hook {
my ($class, $target, $key, $symbols) = @_;
croak "You didn't specify a value for the '$key' load option."
unless @$symbols;
my $method = "export_$key";
$class->$method($target, shift @$symbols);
}
sub export_codec {
my ($class, $target, $name, $alias) = @_;
my $codec = $class->codec($name);
my $cmethod = $alias || CODEC_METHOD;
my $emethod = $alias ? join('_', ENCODE_METHOD, $alias) : ENCODE_METHOD;
my $dmethod = $alias ? join('_', DECODE_METHOD, $alias) : DECODE_METHOD;
no strict 'refs';
# prefix target class onto above method names
$_= "${target}::$_" for ($cmethod, $emethod, $dmethod);
$class->debug("exporting $codec codec to $target\n") if $DEBUG;
# NOTE: I think it's more correct to attempt the export regardless of
# any existing sub and allow a redefine warning to be raised. This is
# better than silently failing to export the requested items.
my $temp = $codec; # make sure this is a constant on 5.22
*{$cmethod} = sub() { $temp }; # unless defined &{$cmethod};
*{$emethod} = $codec->encoder; # unless defined &{$emethod};
*{$dmethod} = $codec->decoder; # unless defined &{$dmethod};
}
sub export_codecs {
my ($class, $target, $names) = @_;
if (ref $names eq HASH) {
while (my ($key, $value) = each %$names) {
$class->export_codec($target, $value, $key);
}
}
else {
$names = [ split(DELIMITER, $names) ] unless ref $names eq ARRAY;
$class->export_codec($target, $_, $_) for @$names;
}
}
1;
__END__
=head1 NAME
Badger::Codecs - modules for encoding and decoding data
=head1 SYNOPSIS
# using class methods
use Badger::Codecs;
$encoded = Badger::Codecs->encode( base64 => $original );
$decoded = Badger::Codecs->decode( base64 => $encoded );
# creating a single codec object
$codec = Badger::Codecs->codec('base64');
$encoded = $codec->encode($original);
$decoded = $codec->decode($encoded);
# creating a codecs collection
$codecs = Badger::Codecs->new(
base => ['My::Codec', 'Badger::Codec'],
codecs => {
# most codec names are grokked automatigally from the
# base defined above - this hash is for any exceptions
wibble => 'Ferret::Codec::Wibble',
frusset => 'Stoat::Codec::Frusset',
}
);
# encode/decode via codecs collective
$encoded = $codecs->encode( wibble => $original );
$decoded = $codecs->decode( wibble => $encoded );
# or via a specific codec
$codec = $codecs->codec('wibble');
$encoded = $codec->encode($original);
$decoded = $codec->decode($encoded);
# importing a single codec
use Badger::Codecs
codec => 'url';
# codec() returns a Badger::Codec::URL object
$encoded = codec->encode($text);
$decoded = codec->decode($encoded);
# encode() and decode() are imported subroutines
$encoded = encode($text);
$decoded = decode($encoded);
# import multiple codecs
use Badger::Codecs
codecs => 'base64 storable';
# codec objects
base64->encode(...); base64->decode(...);
storable->encode(...); storable->decode(...);
# imported subroutines
encode_base64(...); decode_base64(...);
encode_storable(...); decode_storable(...);
# import a codec chain
use Badger::Codecs
codec => 'storable+base64';
# as before, now both codecs are applied
codec->encode(...);
codec->decode(...);
encode(...);
decode(...)
# multiple codecs with various options
use Badger::Codecs
codecs => {
link => 'url+html',
str64 => 'storable+base64',
};
# codec objects
link->encode(...); link->decode(...);
str64->encode(...); str64->decode(...);
# subroutines
encode_link(...); decode_link(...);
encode_str64(...); decode_str64(...);
# accessing codecs via Badger::Class
use Badger::Class
codec => 'base64';
codec(); encode(...); decode(...);
use Badger::Class
codecs => 'base64 storable';
base64(); encode_base64(...); decode_base64(...);
storable(); encode_storable(...); decode_storable(...);
=head1 DESCRIPTION
A I<codec> is an object responsible for encoding and decoding data.
This module implements a codec manager to locate, load and instantiate
codec objects.
=head2 Using Codecs
First you need to load the C<Badger::Codecs> module.
use Badger::Codecs;
It can be used in regular OO style by first creating a C<Badger::Codecs>
object and then calling methods on it.
my $codecs = Badger::Codecs->new();
my $codec = $codecs->codec('url');
my $encoded = $codec->encode($original);
my $decoded = $codec->decode($encoded);
You can also call class methods directly.
my $codec = Badger::Codecs->codec('url');
my $encoded = $codec->encode($original);
my $decoded = $codec->decode($encoded);
Or like this:
my $encoded = Badger::Codecs->encode(url => $original);
my $decoded = Badger::Codecs->decode(url => $encoded);
These examples are the equivalent of:
use Badger::Codec::URL;
my $codec = Badger::Codec::URL->new;
my $encoded = $codec->encode($original);
my $decoded = $codec->decode($encoded);
C<Badger::Codecs> will do its best to locate and load the correct codec module
for you. It defines a module base path (containing C<Badger::Codec> and
C<BadgerX::Codec> by default) to which the name of the requested codec is
appended in various forms.
It first tries the name exactly as specified. If no corresponding codec
module is found then it tries a capitalised version of the name, followed
by an upper case version of the name. So if you ask for a C<foo> codec,
then you'll get back a C<Badger::Codec::foo>, C<Badger::Codec::Foo>,
C<Badger::Codec::FOO> or an error will be thrown if none of these can be
found.
NOTE: the above paragaph is incorrect. It now tries the capitalised version
first to work around Apple's case-insensitive file system. This is subject
to change.
my $codec = Badger::Codecs->code('url');
# tries: Badger::Codec + url = Badger::Codec::url # Nope
# tries: Badger::Codec + Url = Badger::Codec::Url # Nope
# tries: Badger::Codec + URL = Badger::Codec::URL # Yay!
=head2 Chained Codecs
Codecs can be chained together in sequence. Specify the names of the
individual codes separated by C<+> characters. Whitespace between the names
and C<+> is optional. The codec chain returned (L<Badger::Codec::Chain>)
behaves exactly like any other codec. The only difference being that it
is apply several codecs in sequence.
my $codec = Badger::Codecs->codec('storable+base64');
$encoded = $codec->encode($data); # encode storable then base64
$decoded = $codec->decode($encoded); # decode base64 then storable
Note that the decoding process for a chain happens in reverse order
to ensure that a round trip between L<encode()> and L<decode()> returns
the original unencoded data.
=head2 Import Hooks
The C<codec> and C<codecs> import hooks can be used to load and define
codec subroutines into another module.
package My::Module;
use Badger::Codecs
codec => 'base64';
The C<codec> import hook defines a C<codec()> subroutine which returns a
reference to a codec object. It also defined C<encode()> and C<decode()>
subroutines which are mapped to the codec.
# using the codec reference
$encoded = codec->encode($original);
$decoded = codec->decode($encoded);
# using the encode/decode subs
$encoded = encode($original);
$decoded = decode($encoded);
The C<codecs> import hook allows you to define several codecs at once. A
subroutine is generated to reference each codec, along with encoding and
decoding subroutines.
use Badger::Codecs
codecs => 'base64 storable';
# codec objects
$encoded = base64->encode($original);
$decoded = base64->decode($encoded);
$encoded = storable->encode($original);
$decoded = storable->decode($encoded);
# imported subroutines
$encoded = encode_base64($original);
$decoded = decode_base64($encoded);
$encoded = encode_storable($original);
$decoded = decode_storable($encoded);
You can define alternate names for codecs by providing a reference to a
hash array.
use Badger::Codecs
codecs => {
text => 'base64',
data => 'storable+base64',
};
# codec objects
$encoded = text->encode($original);
$decoded = text->decode($encoded);
$encoded = data->encode($original);
$decoded = data->decode($encoded);
# imported subroutines
$encoded = encode_text($original);
$decoded = decode_text($encoded);
$encoded = encode_data($original);
$decoded = decode_data($encoded);
=head1 IMPORTABLE SUBROUTINES
=head2 Codec()
This subroutine can be used as a shortcut to the L<codec> method.
use Badger::Codecs 'Codec';
my $yaml = Codec('YAML');
print $yaml->encode($some_data);
=head1 METHODS
=head2 new()
Constructor method to create a new C<Badger::Codecs> object.
my $codecs = Badger::Codecs->new();
my $encoded = $codecs->encode( url => $source );
See L<CONFIGURATION OPTIONS> for details of the configuration options
that can be specified.
=head2 base(@modules)
The L<base()> method can be used to set the base module path. It
can be called as an object or class method.
# object method
my $codecs = Badger::Codecs->new;
$codecs->base('My::Codec');
$codecs->encode( Foo => $data ); # My::Codec::Foo
# class method
Badger::Codecs->base('My::Codec');
Badger::Codecs->encode( Foo => $data ); # My::Codec::Foo
Multiple items can be specified as a list of arguments or by reference
to a list.
$codecs->base('Ferret::Codec', 'Stoat::Codec');
$codecs->base(['Ferret::Codec', 'Stoat::Codec']);
=head2 codecs(\%new_codecs)
The L<codecs()> method can be used to add specific codec mappings
to the internal C<codecs> lookup table. It can be called as an object
method or a class method.
# object method
$codecs->codecs(
wam => 'Ferret::Codec::Wam',
bam => 'Stoat::Codec::Bam',
);
my $codec = $codecs->codec('wam'); # Ferret::Codec::Wam
# class method
Badger::Codecs->codecs(
wam => 'Ferret::Codec::Wam',
bam => 'Stoat::Codec::Bam',
);
my $codec = Badger::Codecs->codec('bam'); # Stoat::Codec::Bam
=head2 codec($type, %config)
Creates and returns a C<Badger::Codec> object for the specified
C<$type>. Any additional arguments are forwarded to the codec's
constructor method.
my $codec = Badger::Codecs->codec('storable');
my $encoded = $codec->encode($original);
my $decoded = $codec->decode($encoded);
If the named codec cannot be found then an error is thrown.
=head2 chain($type, %config)
Creates a new L<Badger::Codec::Chain> object to represent a chain of codecs.
=head2 encode($type, $data)
All-in-one method for encoding data via a particular codec.
# class method
Badger::Codecs->encode( url => $source );
# object method
my $codecs = Badger::Codecs->new();
$codecs->encode( url => $source );
=head2 decode($type, $data)
All-in-one method for decoding data via a particular codec.
# class method
Badger::Codecs->decode( url => $encoded );
# object method
my $codecs = Badger::Codecs->new();
$codecs->decode( url => $encoded );
=head2 export_codec($package,$name,$alias)
Loads a single codec identified by C<$name> and exports the C<codec>,
C<encode> and C<decode> functions into the C<$package> namespace.
package Your::Module;
use Badger::Codecs;
Badger::Codecs->export_code('Your::Module', 'base64');
# base64() returns the codec
base64->encode($data);
base64->decode($data)
# encode() and decode() are shortcuts
encode($data)
decode($data);
An C<$alias> can be provided which will be used instead of C<codec> and
appended to the names of the C<encode> and C<decode> functions.
package Your::Module;
use Badger::Codecs;
Badger::Codecs->export_codec('Your::Module', 'base64', 'munger');
# munged() returns the codec
munger->encode($data);
munger->decode($data)
# encode_munger() and decode_munger() are shortcuts
encode_munger($data)
decode_munger($data);
( run in 1.259 second using v1.01-cache-2.11-cpan-39bf76dae61 )