in reply to Re^2: require() @INC hooks problem
in thread require() @INC hooks problem

First things first

> > "Why do you even need a hook if your require happens right away?"

a require is basically a

instead of a hook you can simply eval your template and update %INC.

> I don't need to write individual X/Y/Z.pm modules for require X::Y::Z statements.

you don't need to save them to a file.

Just eval the code and update %INC

> > "Why are you installing multiple hooks?"

A hook is an abstraction of a directory path in @INC, which are searched sequentially.

Either a path includes a requested module (SUCCESS) or the next is searched (FAIL)

But your hook in the OP always returned the same code of the first module, no matter which module was requested. It should have signaled a FAIL, to allow the next path/hook to handle the request.

And each of your hooks is only returning one file, which is an overkill and "littering" @INC with hooks.

> Perhaps you would share your understanding.

If you want you can look into the working example I wrote for HaukeX' webperl project:

[WEBPERL] dynamically importing non-bundled modules via http

you just have to adapt the coderef $fetch and %INC_FETCH to your needs.

BUT as I said, you don't even need hooks if you eval those modules right away.

Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery

Replies are listed 'Best First'.
Re^4: require() @INC hooks problem
by kcott (Archbishop) on Dec 28, 2020 at 16:13 UTC

    I got a few ideas from the code to which you linked. Thanks for that. Here's a modified MooselessRequireHookTest.pm:

    package MooselessRequireHookTest; use 5.032; use warnings; sub new { my ($class) = @_; return bless {} => $class; } sub dynamic_require { my ($self, $ns_extension) = @_; state $hook_source = {}; state $inc_updated = 0; my $class = join '::', __PACKAGE__, $ns_extension; my $filename_key = $class =~ s{::}{/}gr . '.pm'; unless (exists $hook_source->{$filename_key}) { my $source = <<~EOF; package $class; use parent 'MooselessRequireHookTest'; 1; EOF $hook_source->{$filename_key} = \$source; } state sub inc_hook { my ($coderef, $filename) = @_; warn "\$coderef[$coderef] \$filename[$filename]\n"; return $hook_source->{$filename}; }; unless ($inc_updated) { push @INC, \&inc_hook; $inc_updated = 1; } eval "require $class;"; return; } 1;

    I added this to the end of sscce_mooseless_require_hook_test.t:

    warn '-' x 10, ' @INC ', '-' x 10, "\n"; warn "$_\n" for @INC; warn '-' x 26, "\n";

    Here's a new, sample prove run:

    $ prove -v sscce_mooseless_require_hook_test.t sscce_mooseless_require_hook_test.t .. 1..8 ok 1 - Test MooselessRequireHookTest::->new() ok 2 - 'Test MooselessRequireHookTest::->new() ISA' isa 'MooselessRequ +ireHookTest' ok 3 - Test MooselessRequireHookTest::Test1->new() ok 4 - 'Test MooselessRequireHookTest::Test1->new() ISA' isa 'Mooseles +sRequireHookTest::Test1' ok 5 - Test MooselessRequireHookTest::Test2->new() ok 6 - 'Test MooselessRequireHookTest::Test2->new() ISA' isa 'Mooseles +sRequireHookTest::Test2' ok 7 - Test MooselessRequireHookTest::A::B::C->new() ok 8 - 'Test MooselessRequireHookTest::A::B::C->new() ISA' isa 'Moosel +essRequireHookTest::A::B::C' $coderef[CODE(0x600867f00)] $filename[MooselessRequireHookTest/Test1.p +m] $coderef[CODE(0x600867f00)] $filename[MooselessRequireHookTest/Test2.p +m] $coderef[CODE(0x600867f00)] $filename[MooselessRequireHookTest/A/B/C.p +m] ---------- @INC ---------- /home/ken/tmp/pm_sscce_require_hook/lib /home/ken/perl5/perlbrew/perls/perl-5.32.0/lib/site_perl/5.32.0/cygwin +-thread-multi /home/ken/perl5/perlbrew/perls/perl-5.32.0/lib/site_perl/5.32.0 /home/ken/perl5/perlbrew/perls/perl-5.32.0/lib/5.32.0/cygwin-thread-mu +lti /home/ken/perl5/perlbrew/perls/perl-5.32.0/lib/5.32.0 CODE(0x600867f00) -------------------------- ok All tests successful. Files=1, Tests=8, 0 wallclock secs ( 0.02 usr 0.01 sys + 0.08 cusr + 0.05 csys = 0.15 CPU) Result: PASS

    So, the CODEREF is only run once for each invocation and @INC only has one hook. Compare that output with what I previously showed in "Re^6: require() @INC hooks problem [non-Moose]".

    I put the changes (not the warn statements) into the original module: all (98) tests passed without any problems.

    With regard to your suggestion of "Just eval the code and update %INC", I'm not following you in terms of how that might be implemented. Could you provide a code example?

    I notice you're referencing the OP code. Please see the sub-thread starting at "Re^4: require() @INC hooks problem [non-Moose]". Moose was never an issue here but, given your request, and stated aversion to Moose, that provides a non-Moose version of the SSCCE code.

    I was hoping for an answer to "Why is it calling the subroutine with all the previous CODEREF values then the newly created CODEREF?" (see "Re^2: require() @INC hooks problem").

    — Ken

      > "Why is it calling the subroutine with all the previous CODEREF values then the newly created CODEREF?"

      I don't know what that means.

      > With regard to your suggestion of "Just eval the code and update %INC", I'm not following you in terms of how that might be implemented. Could you provide a code example?

      something like (totally untested)

      sub create_class { my ($class) = @_; my $source = <<~EOF; package $class; use parent 'MooselessRequireHookTest'; 1; EOF eval $source; my $name = $class =~ s(::)(\/)gr; $INC{"$name.pm"} = 'imported via eval'; }

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

        here tested code
        use strict; use warnings; use Data::Dump qw/pp dd/; sub create_class { my ($class) = @_; my $source = <<"__CODE__"; package $class; sub import { warn "$class imported"; } __CODE__ eval $source; my $name = $class =~ s(::)(\/)gr; $INC{"$name.pm"} = 'imported via eval'; } BEGIN { create_class('Jabba::Dabba'); } pp \%INC; use Jabba::Dabba;

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

        I wrote my last reply at 3.13am (my time). I did see your response about 10 minutes later but my eyes were getting pretty blurry by then: I decided some sleep was in order before looking into that further. :-)

        Twelve hours later, and much refreshed, I see you've posted a lot more code. Thanks for that — I'll look into it and see how that fits with my existing code.

        — Ken