The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Hash::Map - Manipulate hashes map like

VERSION

0.001

SYNOPSIS

OO style

    require Hash::Map;

    my $obj = Hash::Map->new;

    # set target hash
    $obj = $obj->target(a => 1);
    $obj = $obj->target_ref({a => 1});

    # get target hash
    $target = $obj->target;
    $target = $obj->target_ref;

    # set source hash
    $obj = $obj->source(b => 2, c => 3);
    $obj = $obj->source_ref({b => 2, c => 3});

    # get source hash
    $source = $obj->source;
    $source = $obj->source_ref;

    # clone target
    $obj = $obj->clone_target;

    # clone source
    $obj = $obj->clone_source;

    # delete keys in target
    $obj = $obj->delete_keys( qw(x y) );
    $obj = $obj->delete_keys_ref([ qw(x y) ]);

    # copy data from source to target using keys
    $obj = $obj->copy_keys(qw(b c))
    $obj = $obj->copy_keys_ref([ qw(b c) ]);
    # including a key rewrite rule as code reference
    $obj = $obj->copy_keys(
        qw(b c),
        sub {
            my $obj = shift;
            my $key = $_;
            return "new $key";
        },
    );
    $obj = $obj->copy_keys_ref(
        [ qw(b c) ],
        sub {
            my $obj = shift;
            my $key = $_;
            return "new $key";
        },
    );

    # copy data from source (key of map) to target (value of map)
    $obj = $obj->map_keys(b => 'bb', c => 'cc');
    $obj = $obj->map_keys_ref({b => 'bb', c => 'cc'});

    # merge the given hash into target hash (possible overwrite some keys)
    $obj = $obj->merge_hash(d => 4, e => 5);
    $obj = $obj->merge_hashref({d => 4, e => 5});

    # modify target inplace by given code
    $obj = $obj->modify(
        f => sub {
            my $obj = shift;
            my $current_value_of_key_f_in_target = $_;
            return; # $target{f} will be undef because of scalar context
        },
        ...
    );
    $obj = $obj->modify_ref({
        f => sub {
            my $obj   = shift;
            my $current_value_of_key_f_in_target = $_;
            return "new $value";
        },
        ...
    });

Functional style

    use Hash::Map qw(hash_map hashref_map);

    %target_hash = hash_map(
        \%source_hash,
        # The following references are sorted anyway.
        # Running in order like written.
        [ qw(key1 key2) ],               # copy_keys from source to target hash
        [ qw(key3 key4), $code_ref ],    # copy_keys, code_ref to rename keys
        {
            source_key1 => 'target_key', # map_keys from source to target hash
            source_key2 => $code_ref,    # modify values in target hash
        },
    );

Similar, only the method name and return value has chenged.

    $target_hashref = hashref_map(
        $source_hashref,
        ...
    );

DESCRIPTION

For array manipulation we have map, for hashes not really. This was the reason to create this module.

The fuctional interface is wrapped around the OO inferface. Not all can be implemented functional.

Code example

Don't be shocked about the fully examples.

If you have nearly 1 type of each mapping. Map it like before. Otherwise the module helps you to prevent: Don't repeat yourself.

Often we read in code something like that:

    foo(
        street         => $form->{street},
        city           => $form->{city},
        country_code   => $form->{country_code} eq 'D'
                          ? 'DE'
                          : $form->{country_code},
        zip_code       => $form->{zip},
        name           => "$form->{first_name} $form->{family_name}",
        account        => $bar->get_account,
        mail_name      => $mail->{name},
        mail_address   => $mail->{address},

    );

OO interface

Now we can write:

    foo(
        Hash::Map
            ->new
            ->source_ref($form)
            ->copy_keys(
                qw(street city country_code)
            )
            ->modify(
                country_code => sub {
                    return $_ eq 'D' ? 'DE' : $_;
                },
            ->map_keys(
                zip => zip_code,
            )
            ->merge_hash(
                name => "$form->{first_name} $form->{family_name}",
            )
            ->source_ref($bar)
            ->copy_keys(
                qw(account),
                sub {
                    my $obj = shift;
                    my $method = "get_$_";
                    return $obj->source_ref->$method,
                },
            )
            ->source_ref($mail)
            ->copy_keys(
                qw(name address),
                sub {
                   return "mail_$_";
                },
            )
            ->target
    );

Functional interface

Now we can write:

    foo(
        hash_map(
            $form,
            [ qw(street city country_code) ],
            {
                country_code => sub {
                    return $_ eq 'D' ? 'DE'; $_;
                },
                zip_code     => 'zip',
            },
        ),
        name => "$form->{first_name} $form->{family_name}",
        hash_map(
            $bar,
            [
                qw(account),
                sub {
                    my $obj    = shift;
                    my $method = "get_$key";
                    return $obj->source_ref->$method;
                },
            ]
        ),
        hash_map(
            $mail,
            [
                qw(name address),
                sub {
                    return "mail_$_";
                },
            ],
        ),
    );

SUBROUTINES/METHODS

method new

A simple constructor without any parameters.

    my $obj = Hash::Map->new;

method target

Set or get the target hash.

Can not set an empty hash, but this is the default. Otherwise use method target_ref.

    $obj = $obj->target(%target);

    %target = $obj->target;

method target_ref

Set or get the target hash using a hash reference.

    $obj = $obj->target_ref($target_hashref);

    $target_hashref = $obj->target_ref;

method source

Set or get the source hash.

Can not set an empty hash, but this is the default. Otherwise use method target_ref.

    $obj = $obj->source(%source);

    %source = $obj->source;

method source_ref

Set or get the source hash using a hash reference.

    $obj = $obj->source_ref($source_hashref);

    $source_hashref = $obj->source_ref;

method clone_target

Using Module Clone to clone the target hash.

    $obj = $obj->clone_target;

method clone_source

Using Module Clone to clone the source hash.

    $obj = $obj->clone_source;

method delete_keys

Delete keys in target hash.

    $obj = $obj->delete_keys(@keys);

method delete_keys_ref

Delete keys in target hash.

    $obj = $obj->delete_keys_ref($keys_array_ref);

method copy_keys

Copy data from source to target hash using keys.

    $obj = $obj->copy_keys(@keys);

And rename all keys during copy.

    $obj = $obj->copy_keys(
        @keys,
        sub {
            my $obj = shift;
            my $key = $_;
            return "new $key";
        },
    );

The first parameter of the callback subroutine is the object itself. The current key is in $_. Return the new key.

method copy_keys_ref

Copy data from source to target hash using keys.

    $obj = $obj->copy_keys_ref($keys_array_ref);

And rename all keys during copy.

    $obj = $obj->copy_keys_ref(
        $keys_array_ref,
        sub {
            my $obj = shift;
            my $key = $_;
            return "new $key";
        },
    );

The first parameter of the callback subroutine is the object itself. The current key is in $_. Return the new key.

method map_keys

Copy data from source hash (key is key of map) to target hash (key is value of map).

    $obj = $obj->map_keys(%map);

method map_keys_ref

Copy data from source hash (key is key of map) to target hash (key is value of map).

    $obj = $obj->map_keys_ref($map_hashref);

method merge_hash

Merge the given hash into the target hash.

    $obj = $obj->merge_hash(%hash);

method merge_hashref

Merge the given hash into the target hash.

    $obj = $obj->merge_hashref($hashref);

method modify

Modify the target hash inplace by given key and code for.

The first parameter of the callback subroutine is the object itself. The old value of the target hash is in $_; Return the new value.

    $obj = $obj->modify(key1 => $code_ref1, ...);

method modify_ref

Similar to method modify. Only the given parameter is a hash reference and not a hash.

    $obj = $obj->modify_ref({key1 => $code_ref1, ...});

subroutine hash_map

This subroutine is for the fuctional interface only.

    %target_hash = hash_map(
        \%source_hash,
        # The following references are sorted anyway.
        # Running in order like written.
        [ qw(key1 key2) ],               # copy_keys from source to target hash
        [ qw(key3 key4), $code_ref ],    # copy_keys, code_ref to rename keys
        {
            source_key1 => 'target_key', # map_keys from source to target hash
            source_key2 => $code_ref,    # modify values in target hash
        },
    );

subroutine hashref_map

Similar, only the method name and return value has chenged.

    $target_hashref = hashref_map(
        $source_hashref,
        ...
    );

DIAGNOSTICS

nothing

CONFIGURATION AND ENVIRONMENT

nothing

DEPENDENCIES

Carp

Clone

Perl6::Export::Attrs

Try::Tiny

INCOMPATIBILITIES

none

BUGS AND LIMITATIONS

none

SEE ALSO

map

AUTHOR

Steffen Winkler

inspired by: Andreas Specht <ACID@cpan.org>

LICENSE AND COPYRIGHT

Copyright (c) 2012, Steffen Winkler <steffenw at cpan.org>. All rights reserved.

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.