Module::Lazy - postpone module loading until actually used

This module is designed to improve load times for applications with huge dependency footprint. It is somewhat similar to autouse, but more focused on object-oriented modules. See:

use Module::Lazy 'My::Module';

This creates a fake package My::Module with AUTOLOAD, DESTROY, can, and isa redefined.

my $object = My::Module->new;
my $value = My::Module::some_function();

Either of these triggers loading My::Module in full.

no Module::Lazy;

Preload all lazy methods right away, forbid further lazy-loading. This may be useful for long-running, mission-critical apps.

use Module::Lazy;
Module::Lazu->unimport();

Ditto, but at runtime (say after parsing command-line parameters and before daemonizing).

Sure, there are some caveats with using it, but maybe it's still helpful for your project. We managed to reduce test suite execution time from ~17 to ~9 minutes with this one.

namespace::local above, below, and around

My namespace::local module has got some new switches in v.0.04:

  • -above (0.04) emulates namespace::clean:

    package My::Package;
    use Lots::Of::Imports; # imports will only be available until end of scope
    use namespace::local -above;
    
    
    sub do_things { ... }; # this will not be hidden
    
  • -below (0.03) hides everything that follows it from outside view:

    package My::Package;
    sub public { ... };
    use namespace::local -below;
    sub private { ... }; # not available outside this module
    
  • default mode still confines imports and/or functions between the use line and end of scope:

    package My::Package;
    
    
    # cannot frobnicate here
    {
        use namespace::local;
        use Some::Crazy::DSL;
        frobnicate Foo => 42;
    }
    # can't frobnicate here, too
    

I also added a list of symbols that this module shall not be fiddling with, which is most likely incomplete.

Still it looks more like an Acme:: toy, to be honest. Who needs to hide their private functions? Just document the public ones to the point where nobody cares to look inside! =)

Have fun.

namespace::local: hiding utility functions in moo[se] roles

Ever since I came up with namespace::local, clearly inspired by namespace::clean, I was wondering who would need it in real life.

Now I seem to have found an actual application: roles. Roles must be very careful about what's in the namespace to avoid conflicts. So any private subs that are there to reduce repeating code should ideally be hidden from external observer.

And it is possible with namespace::local -below. The below switch is introduced in 0.03, and it allows the names defined below the use lines to propagate above the use line, but not past the end of scope. This can be seen as namespace::clean working in opposite direction.

Example: if you comment both use namespace::local lines, this code blows up.

#!perl

use 5.010;
use strictures;

{
    package Bar;
    use Moo::Role;

    sub bar {
        return _private(@_);
    };

    use namespace::local -below;    
    sub _private {
        return 42;
    };
};

{
    package Baz;
    use Moo::Role;

    sub baz {
        return _private(@_);
    };

    use namespace::local -below;
    sub _private {
        return 137;
    };
};

{
    package Foo;
    use Moo;

    with "Bar", "Baz";
};

my $foo = Foo->new;

say $foo->bar;
say $foo->baz;

Fave fun!

namespace::local - confine imports to current scope

namespace::clean (along with its cousins namespace::autoclean and namespace::sweep) allows to "forget" imported functions, only making them available for the current package. This is neat.

After looking at the inside of namespace::clean, I thought I could do an inside-out version that would erase imports that come after and not before it. A prototype turned out surprisingly easy to implement.

The usage is as follows:

package My::Package;

sub normal_funtion {
    # no traces of quux exist
};

sub function_with_import {
     use namespace::local;
     use Foo::Bar qw(quux); # some crazy prototyped DSL
     # quux available here
}; 

sub another_normal {
     # no traces of quux exist
};

I have at least one use case where importing a lot of functions into a single scope makes sense.

Do you have more?

Assert::Refute - a unified testing and assertion tool

Unit tests are great. They show that the code was actually designed to a given spec.

Runtime assertions are great. They show that the code is actually running the way it was designed when applied to real data.

Design by contract is a great concept, but it's a bit of an overkill for most projects.

However, sometimes I feel an urge to just rip several lines from a unit test and put them right into production code. Test::More doesn't help here much since my application isn't really meant to output TAP or run in a harness.

So I started out Assert::Refute to narrow the gap:

 # somewhere in production code
 use Assert::Refute qw(:all), { on_fail => 'carp' };

 # in the middle of a large sub
 refute_these {
      isa_ok $some_object, "My::Type", "Correct type detection after decode_json"; 
      is $fee + $price, $total, "Payment parts match";
      like $string, qr/f?o?r?m?a?t?/, "Output is really what we expect it to be";
 };

This would just run silently if everything meets the spec, and would emit a warning with TAP output included it it doesn't.

It is also worth noting that refute_these { ... } returns a report object (similar to Test::Builder, but not a singleton), and that the code block also receives it as first argument. (E.g. one can include more diagnostics if the test is already failing).

There is also a subcontract { ... } (not subtest) call for executing a group of checks together.

The rest can be found in documentation.

Why refute?

A successful prove run actually proves nothing. It's only the failures that are meaningful! This is similar to falsifiability concept in modern science: we don't prove a theory in experiment; instead, we try hard to refute it. Same goes for runtime assertions.

So the underlying mechanism of this module is a refute call:

$report->refute ("What exactly went wrong", "Why we care about it");

Although somewhat counterintuitive, it leads to more efficient code than a more common

 ok ("Everything was ok", "Why we care about it")
     or diag "What exactly went wrong";

Extending the arsenal

The package includes a builder to create new checks/conditions. Each such condition would be able to work under Test::More as well, provided that Test::More was loaded earlier than Assert::Refute.

There is also a small library including tests for arrays, hashes, error messages and warnings. It's currently much more scarce than Test::Most.

There is no easy way to import checks based on Test::Builder, but maybe one will be created in the future.

Performance impact

I was able to verify 10K refute_these blocks with 100 passing assertions each in 3.2 seconds on my 4500 bogomips laptop. Assert::Refute is optimized for happy path, for obvious reasons. There's still room for improvement though.

Intended usage

The most obvious use case is working on legacy software where Assert::Refute may act as both a prototype of unit tests and a safety net while in transition.

Still even in new code it may be feasible to know that certain invariants hold in production whatever real data is being processed by the code.

Conclusion

This module is still in development, so feel free to point out what you'd like to see there before it's too entrenched.