Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Re (tilly) 1: Passing parameters to a module's import function

by tilly (Archbishop)
on Feb 12, 2001 at 04:34 UTC ( [id://57816]=note: print w/replies, xml ) Need Help??


in reply to Passing parameters to a module's import function

Careful before saying that no such facility exists in Exporter. There are, in fact, at least 3 ways to do this while using Exporter.
  1. Use the export_to_level method.
  2. Do like Carp does and have flags listed in @EXPORT_FAIL and processed in an export_fail function.
  3. Write a custom import that looks like this:
    sub import { my $self = shift; my @out; foreach (@_) { if (ref($_)) { # Do one thing } else { push @out, $_; } } @_ = ($self, @out); goto &Exporter::import; }

UPDATE
Two quick notes. First of all I had put the case of Exporter wrong. Oops. Secondly the point here is that you can preprocess the list of arguments being imported in any way you please before Exporter sees them. (eg Take references out of the list and do something useful with them.)

Replies are listed 'Best First'.
(tye)Re: Passing parameters to a module's import function
by tye (Sage) on Feb 12, 2001 at 08:46 UTC

    Um, tilly, in the sample usage:

    use MyModule { foo => 1, bar => 'two' };

    are you suggesting that having Exporter.pm know about not just "foo" and "bar" but also "1" and "two" and all other possible parameter values and then having it either export them or report them as failing one at a time is somehow useful? (And your third option seems to have little to do with what was being asked.) (:

    No, Exporter.pm does not provide any way of dealing with such options. You can look at Win32::TieRegistry for an example of how to parse such options while still supporting standard exporting (and non-standard exporting). But you'll probably want to ignore most of the code in Win32::TieRegistry::import as I doubt you'll want to support the strange exporting that is supported there. You might have more luck looking at Win32::TieRegistry::SetOptions.

    Update: I hate this font. () and {} are nearly identical. The stuff I was talking about deals with this:

    use MyModule ( foo => 1, bar => 'two' );

    kind of stuff. ):

            - tye (but my friends call me "Tye")
      I gave 3 methods.

      One of which I specifically said is only useful for flags.

      The other two, including my actual code sample (which was very specifically designed to handle an anonymous hash as a case) work just fine.

Re: Re (tilly) 1: Passing parameters to a module's import function
by rrwo (Friar) on Feb 13, 2001 at 06:44 UTC

    I've already been experimenting with something like the import function you've shown. But by "no such facility exists in Exporter" I mean that you can't have the following in your module:

    package MyModule; use Exporter; @ISA = qw( Exporter ); @EXPORT_OK = qw( mysub anothersub ); @ATTRIBUTES = qw( foo bar );

    so that in your module you could use:

    use MyModule qw( anothersub ), { foo => 1 };

    It would be a good feature for Exporter. (Ideally one would specify required attributes and maybe specify types, default values, etc.).

    UPDATE: Ok, I've corrected the formatting. Didn't realize CODE was converted to PRE.

      First of all please use <code> tags rather than doing your own formatting. (Cleaner, people can download your code, etc.)

      Anyways this feature makes me deeply suspicious. What is this for? Personally I like using modules that are designed to be used multiple times in multiple places. This looks like it would be used to initialize a number of globals in the module. That would mean that if I used modules A and B which both used C, I could get hosed. But I shouldn't need to know anything about what A and B do internally. Therefore C should be designed so that can be used by multiple modules at the same time without any conflict.

      Hmmmm..

      I could be very wrong, but my inclination would be to ask how your module is structured, and ask whether there is a cleaner design that could be used. For instance use an OO style where you pass parameters into new()...

      Incidentally your comment about specifying types raises another design flag for me. Perl is untyped, and does not have a type system in the sense that you see in other languages. Trying to mix concepts from a type system with Perl is generally a sign that you are doing something wrong (or using the wrong tool).

      I don't mean to sound so down on your feature request. Why don't you describe in more detail what a sample problem is where you would find this useful, and we can see whether there is another way to organize this?

        Your point about multiple modules using it is a good one. However, this module is not likely to be used by anything other than a main program (it's a version of Win32::EventLog::Carp which traps warnings and fatals and posts them in the Windows NT event log; I'd like to give the option of specifying a different source name, so that related scripts can show up in the logs using one name than each individual script's file name.)

        I'm experimenting with various ways to handling this. By specifying these options upon importing, compilation errors and warnings will be logged under the parameters specified--as "FooProject" rather than "index.pl" and logged in the System log rather than Application log, for instance.

        This is a very specialized case, so it probably would make more sense in a separate module which extends Exporter rather than Exporter. But there are cases where one may want to pass some configuration information to the module.

        As for specifying types, that feature isn't important to me. Sometimes people want it.

An alternate way of implementing import with options
by rrwo (Friar) on Feb 13, 2001 at 20:57 UTC

    An aside. Here's another way of coding it:

    sub import { my $self = shift; my @exports = grep { "HASH" ne ref($_) } @_; my @options = grep { "HASH" eq ref($_) } @_; foreach (@options) { # handle options here } @_ = ($self, @exports); goto &Exporter::import; }

    Question: will grep interfere with @_ (making the above a bit dangerous)?

      grep() won't do anything bad to @_, but I am personally against doing two operations in a row like you did that are complements.

      That being said, I'd rewrite the @_-filtering line as:
      my %args; push @{ $args{ref($_) eq 'HASH' ? 'opt' : 'ext'} }, $_ for @_;
      Or, I might even do a moving-splice() trick:
      sub import { my $self = shift; my ($i,$j,@options); for (@_) { if (++$j, ref($_) eq 'HASH') { push @options, splice(@_, $j + --$i, 1); $_ = $_[$j+$i], redo if $j + $i < @_; } } # handle @options # @_ now only holds elements which aren't hash refs $self->SUPER::import(@_); }
      </code>

      japhy -- Perl and Regex Hacker
        That fails. The point of the goto in the original is that Exporter checks caller to figure out what package to export symbols to. You have to use export_to_level() instead, and my experience suggests that that function is more likely to cause warning messages to come from the wrong place than I like. (Also with 5.6+ it will force you to load Exporter::Heavy which is slower. If that matters to you.)

        Aside from that, I don't like using explicit indexes if I can avoid it...

        That is morally the same as my original version. In fact before I posted I had thought about having 2 arrays, and then I thought that instead of tracking options, it probably made more sense to process in place. :-)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://57816]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (4)
As of 2024-04-25 16:05 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found