Test2:...::Util(3pm)

πŸŽ€ NAME πŸŽ€

Test2::Harness::Util β€” the general utility functions module, bestie. πŸ’– This is a section 3pm manpage (that's Perl module docs, iykyk) from the User Contributed Perl Documentation, and it's literally just a big grab-bag of helpful little functions that Test2::Harness leans on all day. πŸ¦‹


✨ DESCRIPTION ✨

Okay so the DESCRIPTION section is giving nothing β€” zero words, no notes, not even a vibe. It just immediately goes into the methods. Which is lowkey iconic of it, honestly. Main character behavior: skip the small talk, get straight to business. πŸ’…


πŸ”₯ METHODS πŸ”₯

🌸 MISC 🌸

🫢 apply_encoding($fh, $enc)

Puts the encoding you picked onto the filehandle. That's it, that's the function. ✨

Justification: PERLBUG 31923 β€” https://rt.perl.org/Public/Bug/Display.html?id=31923 β€” because if utf8 is what you asked for, we use ':utf8' instead of ':encoding(utf8)' specifically so we can avoid the thread segfault. πŸ’€ No cap, that's the whole reason.

This is a reusable implementation of exactly this:

sub apply_encoding {
    my ($fh, $enc) = @_;
    return unless $enc;
    return binmode($fh, ":utf8") if $enc =~ m/^utf-?8$/i;
    binmode($fh, ":encoding($enc)");
}

🧚 $clean = clean_path($path)

Hand it a file path and it tidies it up into a minimal absolute path, if it can. It always returns a path though β€” if it can't clean it up, you just get it back unchanged. No drama, no exception. 🌸

πŸŽ€ $hashref = find_libraries($search, @paths)

If you don't pass any @paths, then @INC gets used instead. Defaults, we love her. πŸ’–

$search should be a module name with "*" wildcards standing in for sections. Like:

find_libraries('Foo::*::Baz')
find_libraries('*::Bar::Baz')
find_libraries('Foo::Bar::*')

All of these go hunting for modules that match the search, which is a genuinely great way to find plugins or other pattern-y stuff. πŸ¦‹

The result is a hashref shaped like "{ $module => $path }". And if a module shows up in more than one search path, the first one wins.

🌟 $mod = fqmod($prefix, $mod)

This auto-sticks $prefix onto $mod, joining them with '::'. But β€” plot twist β€” if $mod starts with the '+' character, that character gets removed and the result comes back without $prefix prepended. πŸ™ˆ

🚫 hub_truth

This is an internal implementation detail. Do not use it. I said what I said. βœ‹

πŸ‘‘ $hashref = parse_exit($?)

Parses the exit value the way it's typically stored in $?.

The resulting hash is giving:

{
    sig => ($? & 127), # Signal value if the exit was caused by a signal
    err => ($? >> 8),  # Actual exit code, if any.
    dmp => ($? & 128), # Was there a core dump?
    all => $?,         # Original exit value, unchanged
}

🌈 @list = process_includes(%PARAMS)

This method builds up a list of include dirs that's fit for @INC. The returned list should contain only unique values, in the proper order. So organized. So clean. ✨

Params:

  • list => \@START β€” the paths to start the new list off with. Optional, no pressure.
  • ch_dir => $path β€” a prefix to prepend to all paths in the "list" param. Has no effect at all without an initial list, so don't bother otherwise. πŸ’…
  • include_current => $bool β€” this adds all the paths from @INC onto the output, after the initial list. Heads up: '.', if it happens to be in @INC, gets moved to the end of the final output.
  • clean => $bool β€” if you include this, all paths except '.' get cleaned using clean_path().
  • include_dot => $bool β€” if true, '.' gets appended to the end of the output.
Note: even if this is set to false, '.' may still end up included β€” if it was in the initial list, or if it was in @INC and @INC got included via the "include_current" parameter. πŸ‘€

πŸ¦‹ FOR DEALING WITH MODULE <-> FILE CONVERSION πŸ¦‹

These ones convert between module names like "Foo::Bar" and filenames like "Foo/Bar.pm". The glow-up is bidirectional, bestie. πŸ’«

  • $file = mod2file($mod)
  • $mod = file2mod($file)

πŸ“ FOR READING/WRITING FILES πŸ“

πŸ’– $fh = open_file($path, $mode)

πŸ’– $fh = open_file($path)

If you don't hand over a mode, < is assumed. Default queen behavior. πŸ‘‘

This opens the file at $path and gives you back a filehandle.

An exception will be thrown if the file can't be opened. No silent failure here, she will tell you. 😭

NOTE: this will automatically use IO::Uncompress::Bunzip2 or IO::Uncompress::Gunzip to uncompress the file if it has a .bz2 or .gz extension. Unzipping on the sly, we love that for her. πŸŽ€

🌸 $text = read_file($file)

This opens the file at $path and returns all of its contents. The whole thing. Every crumb. 🧚

An exception will be thrown if the file can't be opened.

NOTE: this will automatically use IO::Uncompress::Bunzip2 or IO::Uncompress::Gunzip to uncompress the file if it has a .bz2 or .gz extension.

✨ $fh = maybe_open_file($path)

✨ $fh = maybe_open_file($path, $mode)

If no mode is provided, < is assumed.

This opens the file at $path and returns a filehandle.

But the "maybe" is doing heavy lifting β€” "undef" gets returned if the file can't be opened. Chill, no exception, just a lil undef. 🫢

NOTE: this will automatically use IO::Uncompress::Bunzip2 or IO::Uncompress::Gunzip to uncompress the file if it has a .bz2 or .gz extension.

πŸ’œ $text = maybe_read_file($path)

This opens the file at $path and returns all of its contents.

And again: this returns "undef" if the file can't be opened. Soft launch, no explosion. πŸŒ™

NOTE: this will automatically use IO::Uncompress::Bunzip2 or IO::Uncompress::Gunzip to uncompress the file if it has a .bz2 or .gz extension.

πŸ”₯ @content = write_file($path, @content)

Writes content to the file you named. It opens the file with mode '>', writes the content, then closes the file. Simple, effective, ate. πŸ’…

An exception will be thrown if any part of that fails.

🌈 @content = write_file_atomic($path, @content)

This one opens a temporary file, writes the content, closes the file, and then renames the file to the $path you wanted. It's essentially an atomic write β€” $file won't even exist until all the content is written, which stops other processes from doing a partial read while @content is still being written. Obsessed with the attention to detail, fr fr. πŸ‘‘


πŸ’« SOURCE πŸ’«

The source code repository for Test2-Harness lives at http://github.com/Test-More/Test2-Harness/. Go peek, bestie. πŸ¦‹


🌟 MAINTAINERS 🌟

Chad Granum <exodist@cpan.org>


πŸŽ€ AUTHORS πŸŽ€

Chad Granum <exodist@cpan.org>


Copyright 2020 Chad Granum <exodist7@gmail.com>.

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

See http://dev.perl.org/licenses/


and that's the whole page, bestie πŸ’– this was perl v5.40.1, dated 2026-05-10, and it's the Test2:...::Util(3pm) page β€” you're all caught up, go write some slay Perl πŸŽ€πŸ¦‹βœ¨

πŸ“¦ where this page comes from