Data::Miscellany(3pm)

πŸ“¦
version 1.100850 Β· 2 versions
, in debian bookworm, debian trixie, ubuntu noble, ubuntu resolute, ubuntu stonking

πŸ’– Data::Miscellany πŸ’–

okay so bestie, welcome to Data::Miscellany β€” it's a Perl module, it lives in the User Contributed Perl Documentation section of your man pages (that's the 3pm part, iykyk), and it is literally just a collection of miscellaneous subroutines. like a junk drawer but make it ✨elegant✨.

version 1.100850 β€” write that down, it matters.


✨ SYNOPSIS ✨

use Data::Miscellany qw/set_push flex_grep/;

my @foo = (1, 2, 3, 4);
set_push @foo, 3, 1, 5, 1, 6;
# @foo is now (1, 2, 3, 4, 5, 6);

flex_grep('foo', [ qw/foo bar baz/ ]);                   # true
flex_grep('foo', [ qw/bar baz flurble/ ]);               # false
flex_grep('foo', 1..4, 'flurble', [ qw/foo bar baz/ ]);  # true
flex_grep('foo', 1..4, [ [ 'foo' ] ], [ qw/bar baz/ ]);  # false

🌸 DESCRIPTION 🌸

So this is a grab-bag. A collection of miscellaneous subroutines that are useful in wide but varying scenarios β€” basically the catch-all module for stuff that doesn't obviously belong anywhere else. And like, obviously "useful" is different for every person, no cap, but this particular little collection is meant to be useful in object-oriented frameworks. The manpage name-drops Class::Scaffold and Data::Conveyor specifically. Slay.


πŸŽ€ FUNCTIONS πŸŽ€

πŸ’… set_push(ARRAY, LIST)

It's giving push(), but with ✨boundaries✨. It only pushes the item(s) onto the list if the list doesn't already contain it. The list can be a list or a list ref β€” that's your first argument.

Example:

@foo = (1, 2, 3, 4);
set_push @foo, 3, 1, 5, 1, 6;
# @foo is now (1, 2, 3, 4, 5, 6)

πŸ¦‹ flatten()

Three moods, pick one:

  • If the first argument is an array reference β†’ it returns the dereferenced array. πŸ’«
  • If the first argument is undefined (or there are literally no arguments at all) β†’ it returns the empty list.
  • Otherwise β†’ the argument list is returned as is. no notes.

🌈 flex_grep(SCALAR, LIST)

grep(), but make it flexible πŸ’…. It compares the first argument to each flattened (see flatten() above, keep up bestie) version of each element of the list.

Examples:

flex_grep('foo', [ qw/foo bar baz/ ])                     # true
flex_grep('foo', [ qw/bar baz flurble/ ])                 # false
flex_grep('foo', 1..4, 'flurble', [ qw/foo bar baz/ ])    # true
flex_grep('foo', 1..4, [ [ 'foo' ] ], [ qw/bar baz/ ])    # false

🫢 is_deeply()

Like Test::More's is_deeply() except this version respects stringification overloads. Here's the tea: if a package overloads stringification, that means it's specifying how it wants to be compared. Recent versions of Test::More break this behaviour 😭, so here is a working version of is_deeply(). This subroutine only does the comparison β€” there are no test diagnostics or results recorded or printed anywhere. periodt.

πŸ’– eq_array()

Same situation, different subroutine: like Test::More's eq_array() except this version respects stringification overloads. If a package overloads stringification, it means it specifies how it wants to be compared. Recent versions of Test::More break this behaviour, so here is a working version of eq_array(). And again β€” this subroutine only does the comparison; there are no test diagnostics or results recorded or printed anywhere. πŸ‘‘

🌸 eq_hash()

You already know the vibe: like Test::More's eq_hash() except this version respects stringification overloads. If a package overloads stringification, it means it specifies how it wants to be compared. Recent versions of Test::More break this behaviour, so here is a working version of eq_hash(). This subroutine only does the comparison; there are no test diagnostics or results recorded or printed anywhere. fr fr.

🧚 is_defined(SCALAR)

A kind of defined() that's aware of Class::Value, which has its own opinions about what counts as a defined value and what doesn't. The whole issue came up because Class::Value objects are supposed to be used transparently, mixed right in with normal scalar values. BUT β€” and this is the plot twist β€” it is not possible to overload "definedness", and defined() used on a value object always returns true, since the object reference certainly exists. πŸ™ˆ

But like, what we actually want to know is whether the value encapsulated by the value object is defined. And on top of that, each value class can have its own ideas of when its encapsulated value is defined. So Class::Value has an is_defined() method.

This subroutine checks whether its argument is a value object and, if so, calls the value object's is_defined() method. Otherwise, the normal defined() is used. simple as that πŸ’…

πŸ’œ value_of(SCALAR)

Stringifies its argument, but returns undefined values (per is_defined() above) as undef.

⭐ str_value_of(SCALAR)

Stringifies its argument, but returns undefined values (per is_defined()) as the empty string. same energy, different output πŸŽ€

πŸ‘‘ class_map(SCALAR, HASH)

Takes an object or class name as the first argument β€” and if it's an object, the class name used will be the package name the object is blessed into. Takes a hash whose keys are class names as the second argument. The hash values are completely arbitrary.

It looks up the given class name in the hash and returns the corresponding value. If no such hash key is found, the class hierarchy for the given class name is traversed depth-first and checked against the hash keys in turn. The first value found gets returned. πŸ’«

If no key is found at all, a special key, UNIVERSAL, is used.

So like, as an example of how this might be used, imagine a hierarchy of exception classes. When evaluating each exception, we want to know how severe this exception is, so we define constants for RC_OK (meaning it's informational only), RC_ERROR (meaning some sort of action should be taken) and RC_INTERNAL_ERROR (meaning something has gone badly wrong and we might halt processing). In the following table assume that if you have names like Foo::Bar and Foo::Bar::Baz, then the latter subclasses the former.

%map = (
    'UNIVERSAL'                                => RC_INTERNAL_ERROR,
    'My::Exception::Business'                  => RC_ERROR,
    'My::Exception::Internal'                  => RC_INTERNAL_ERROR,
    'My::Exception::Business::ValueNormalized' => RC_OK,
);

Assuming that My::Exception::Business::IllegalValue exists and that it subclasses My::Exception::Business, here are some outcomes:

class_map('My::Exception::Business::IllegalValue', \%map)     # RC_ERROR
class_map('My::Exception::Business::ValueNormalzed', \%map)   # RC_OK

🌺 trim(STRING)

Trims off whitespace at the beginning and end of the string and returns the trimmed string. clean girl aesthetic πŸŽ€


🌟 INSTALLATION 🌟

See perlmodinstall for information and options on installing Perl modules. iykyk.


πŸ’€ BUGS AND LIMITATIONS πŸ’€

No bugs have been reported. 😌✨ (iconic behaviour honestly)

Please report any bugs or feature requests through the web interface at <http://rt.cpan.org/Public/Dist/Display.html?Name=Data-Miscellany>.


πŸ”₯ AVAILABILITY πŸ”₯

The latest version of this module is available from the Comprehensive Perl Archive Network (CPAN). Visit <http://www.perl.com/CPAN/> to find a CPAN site near you, or see <http://search.cpan.org/dist/Data-Miscellany/>.

The development version lives at <http://github.com/hanekomu/Data-Miscellany/>. And instead of sending patches, please fork this project using the standard git and github infrastructure. main character dev energy πŸ’…


πŸ’– AUTHOR πŸ’–

Marcel Gruenauer <marcel@cpan.org>

This software is copyright (c) 2004 by Marcel Gruenauer.

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


and that's the whole page bestie 🫢 go forth and set_push responsibly. this was documented with perl v5.36.0, dated 2022-12-04, and yeah β€” it's the Data::Miscellany(3pm) page, we ate πŸ’…βœ¨

πŸ“¦ where this page comes from