using Exporter::export_fail

Discussion in 'Perl Misc' started by A. Sicken, Jul 21, 2013.

  1. A.  Sicken

    A. Sicken Guest

    Hello,

    I want to use the Exporter::export_fail-method to set some internal
    debugging vars like:

    use MyModul qw/enable_debug/; # to enable debugging messages

    in following code example:

    # --- CODE ---

    use strict;
    use 5.008; # and/or above version

    package MyModul;

    use Exporter;

    our @ISA = qw/Exporter/; # to avoid namespace pollution

    our @EXPORT_OK = qw/Some Symbols go here/;
    our @EXPORT_FAIL = qw/enable_debug/;
    our %EXPORT_TAGS = ( 'tag' => [@EXPORT_OK] };

    our $VERSION = 1;

    sub export_fail {
    my $class = shift;
    my $sym_name;
    my @sym_fail;
    while ($sym_name = shift) {
    if ($sym_name eq 'enable_debug') {
    # set var to use it later in module code
    }else{
    push @sym_fail, sym_name;
    }#end_if
    }#end_while
    @sym_fail;
    }#end_sub export_fail

    # some module code goes hereafter

    1;

    __END__

    # --- CODE ---

    Now my questions: Is there a way to use the export_fail method without
    declaring it within my module MyModul (or to destroy it after its first
    invokation), because this means anyone can call this method as if it would
    be a real method?
    To clarify: I'm writing an oo-style framework/library and it seems
    unnesseccary to me to provide this method as a real method for objects.

    Maybe there is an easy way around this problem that takes inheritance into
    account?

    Thank you for your help and please excuse bad english.

    A. Sicken
     
    A. Sicken, Jul 21, 2013
    #1
    1. Advertising

  2. A.  Sicken

    A. Sicken Guest

    Ben Morrow wrote:

    > No. If you must, you can get rid of the method on it's first invocation
    > by deleting the glob from the symbol table, but I wouldn't recommend
    > doing that.
    >
    > You could alternatively write your own import method, which removes
    > enable_debug from the symbol list and calls Exporter->export_to_level to
    > do the actual exporting.
    >


    Ok. The method I want to get rid of is the export_fail-method (not the local
    tied enable_debug var or the symbol) because you can call it on every object
    created through this modul. Manipulation of the glob-table is a messy job
    and very error prone; and it does not take modul inheritance into account.

    The other way around (for inheritance only) I guess would be to write
    export_fail-stubs for every single modul (currently about 20) which is also
    a messy job :-( - and it would make it worse - because then every modul
    would need to have an export_fail method which is completely unneccessary
    for the object stuff.

    Somehow I was hoping to scope the usage to a BEGIN{} block, so it will
    invoked only once and then goes out of scope. The real annoying thing is
    that the objects itself have debugging capability for their state and
    contents whereas the debugging I reffered to is to trace the methods in a
    certain module itself and I need this functionallity because of the very
    nature of frameworks and their deep nested calling stack.

    To use the export_to_level method isn't an option so far to me because I do
    not know where to export; a caller based reference doesn't work all the
    time, so I have to inspect @ISA to find the modul where to export to.

    It seems a long way to go und feels frustrating.

    Do you have any knowlege about fitting cpan modules or maybe
    references/links where I can search for.

    Thanx for your help.

    Andreas
    > Ben

    ..
     
    A. Sicken, Jul 21, 2013
    #2
    1. Advertising

  3. A.  Sicken

    A. Sicken Guest

    Ben Morrow wrote:

    > No. If you must, you can get rid of the method on it's first invocation
    > by deleting the glob from the symbol table, but I wouldn't recommend
    > doing that.
    >
    > You could alternatively write your own import method, which removes
    > enable_debug from the symbol list and calls Exporter->export_to_level to
    > do the actual exporting.
    >


    Ok. The method I want to get rid of is the export_fail-method (not the local
    tied enable_debug var or the symbol) because you can call it on every object
    created through this modul. Manipulation of the glob-table is a messy job
    and very error prone; and it does not take modul inheritance into account.

    The other way around (for inheritance only) I guess would be to write
    export_fail-stubs for every single modul (currently about 20) which is also
    a messy job :-( - and it would make it worse - because then every modul
    would need to have an export_fail method which is completely unneccessary
    for the object stuff.

    Somehow I was hoping to scope the usage to a BEGIN{} block, so it will
    invoked only once and then goes out of scope. The real annoying thing is
    that the objects itself have debugging capability for their state and
    contents whereas the debugging I reffered to is to trace the methods in a
    certain module itself and I need this functionallity because of the very
    nature of frameworks and their deep nested calling stack.

    To use the export_to_level method isn't an option so far to me because I do
    not know where to export; a caller based reference doesn't work all the
    time, so I have to inspect @ISA to find the modul where to export to.

    It seems a long way to go und feels frustrating.

    Do you have any knowlege about fitting cpan modules or maybe
    references/links where I can search for.

    Thanx for your help.

    Andreas
    > Ben


    EDIT: Maybe I am thinking in the wrong direction! When is the export_fail
    method called? Before or after any BEGIN-block? Or is there any run-state
    that can be called right after export_fail (as hook for example)?
     
    A. Sicken, Jul 21, 2013
    #3
  4. "A. Sicken" <> writes:
    > Ben Morrow wrote:
    >> No. If you must, you can get rid of the method on it's first invocation
    >> by deleting the glob from the symbol table, but I wouldn't recommend
    >> doing that.
    >>
    >> You could alternatively write your own import method, which removes
    >> enable_debug from the symbol list and calls Exporter->export_to_level to
    >> do the actual exporting.

    >
    > Ok. The method I want to get rid of is the export_fail-method (not the local
    > tied enable_debug var or the symbol) because you can call it on every object
    > created through this modul.


    And what's the problem with that? 'class modules' I'm using usually
    also contain auxiliary subroutines which could also be called 'on
    every object' except that this wouldn't be particularly useful: If
    you're creating modules supposed to be used by other people and a
    significant minority of these use them in ways you originally
    considered to be 'useless', that indicates your 'public interface' is
    lacking.

    [...]

    > The other way around (for inheritance only) I guess would be to write
    > export_fail-stubs for every single modul (currently about 20) which is also
    > a messy job :-( - and it would make it worse - because then every modul
    > would need to have an export_fail method which is completely unneccessary
    > for the object stuff.


    Leaving the issue mentioned above aside, you could create a single
    'export fail stub' module, put the subroutine into @EXPORT and then do
    a

    use export_fail_stub;

    to import it as method into every module/ class supposed to utilize
    it.
     
    Rainer Weikusat, Jul 22, 2013
    #4
  5. A.  Sicken

    A. Sicken Guest

    Rainer Weikusat wrote:

    > "A. Sicken" <> writes:
    >> Ben Morrow wrote:
    >>> No. If you must, you can get rid of the method on it's first invocation
    >>> by deleting the glob from the symbol table, but I wouldn't recommend
    >>> doing that.
    >>>
    >>> You could alternatively write your own import method, which removes
    >>> enable_debug from the symbol list and calls Exporter->export_to_level to
    >>> do the actual exporting.

    >>
    >> Ok. The method I want to get rid of is the export_fail-method (not the
    >> local tied enable_debug var or the symbol) because you can call it on
    >> every object created through this modul.

    >
    > And what's the problem with that? 'class modules' I'm using usually
    > also contain auxiliary subroutines which could also be called 'on
    > every object' except that this wouldn't be particularly useful: If
    > you're creating modules supposed to be used by other people and a
    > significant minority of these use them in ways you originally
    > considered to be 'useless', that indicates your 'public interface' is
    > lacking.
    >

    Many modules are base-class modules to many oher modules - either directly
    (as parent) or indirectly (as grand parent).
    The potentional down side for the import method is to get unwanted
    functionallity... you mostly can ignore that. Beside: Does anyone use the
    import-method within a given class modul unless in pragmas to extend perls
    bahavior (directly without use-statement)?
    The export method - I asume - will be likely more often called. For example
    if you want to provide defaults, constants or such thing and that is the
    problem - the export-fail method is implicite called if it exists and it
    will exists by all module siblings (in case of inheritance). The export_fail
    method is usaully used to degrade (more or less gracefull) functionallity
    and that as side effect will be pain in the a.. - not only if you need to
    find the source of the problem.

    > [...]
    >
    >> The other way around (for inheritance only) I guess would be to write
    >> export_fail-stubs for every single modul (currently about 20) which is
    >> also a messy job :-( - and it would make it worse - because then every
    >> modul would need to have an export_fail method which is completely
    >> unneccessary for the object stuff.

    >
    > Leaving the issue mentioned above aside, you could create a single
    > 'export fail stub' module, put the subroutine into @EXPORT and then do
    > a


    Ok, the problem for both solutions is messy, because in both cases (either
    deleting globs and or build method stubs) means, you have to find a way to
    traverse @ISA to find the right parent, caller or what ever make sence.
    Some of my modules use Object as their method arguments and decide to work
    in different ways upon what comes in...

    >
    > use export_fail_stub;
    >
    > to import it as method into every module/ class supposed to utilize
    > it.


    I do use this kind of stuff very often (as often as I can :), but as a
    stateted above, sometimes this will not work...

    So I guess I can close the thread as not so well solved but informative and
    I will leave this problem untouched - I know: someday it will hunt me...

    Thanks for your help, comments and advices.

    Andreas
     
    A. Sicken, Jul 22, 2013
    #5
  6. A.  Sicken

    A. Sicken Guest

    Ben Morrow wrote:


    > I agree it's a bad idea.
    >
    >> The other way around (for inheritance only) I guess would be to write
    >> export_fail-stubs for every single modul (currently about 20) which is
    >> also a messy job :-( - and it would make it worse - because then every
    >> modul would need to have an export_fail method which is completely
    >> unneccessary for the object stuff.

    >
    > This package you are exporting from is a base class? Certainly, that
    > would be messy.

    Most of them, you guessed right.
    >
    > Incidentally, are you inheriting from Exporter or importing its import
    > method? If you are inheriting then you've just scquired a whole lot of
    > methods anyway.

    No, no - I use ONLY the import method in my own classes this way:

    use Exorter qw/import/;
    >
    >> Somehow I was hoping to scope the usage to a BEGIN{} block, so it will
    >> invoked only once and then goes out of scope. The real annoying thing is
    >> that the objects itself have debugging capability for their state and
    >> contents whereas the debugging I reffered to is to trace the methods in a
    >> certain module itself and I need this functionallity because of the very
    >> nature of frameworks and their deep nested calling stack.

    >
    > A further alternative would be not to use a 'use' parameter at all but
    > simply to provide a function or method to turn this debugging on. Given
    > that it has global effect, I doubt you'll want to do this very often.

    That is the point: I can not decide at this point, where and when classes
    will be used - so having a global sitting around will work perfectly except
    for cases where you deal with stuff like web-frontend, pg-backend and so
    on... my modules will work as type of connectors or templates.
    >
    >> To use the export_to_level method isn't an option so far to me because I
    >> do not know where to export; a caller based reference doesn't work all
    >> the time, so I have to inspect @ISA to find the modul where to export to.

    >
    > I don't understand what you mean here. If you're currently using
    > Exporter::import then writing your own import method which calls
    > Exporter->export_to_level(1, @exports) will do the same thing.

    Sorry my fault. Most modules work like connectors and they are somehow aware
    what to do. For example: I have written two modules - one
    (Ext::Data::Object::Float) does stuff like defining what a float number
    should look alike (size, precision, minimum and many things more) - the
    other (PgSerializer) stuff things into an Postgres-Table and or Database.
    Now if you define a Float-object and provide it to PGSerializer it will use
    the given definitions to create a fitting table - even SQL-constraints. Same
    goes for a String object. But if you provide an PgSerializer object to a
    Float object (Ex. Ext::Data::Object::Float->new($PgSerializer) ) it will
    simply create a Float object with meating definitions.
    For both objects exists a dumper class: If you call that with Float it will
    behave in default menor (writing some xml) but if you put the Float object
    wrapped in PgSerializer in it, it will pass handling the stuff to
    PgSerializer.
    In short you can call them nested and depending on how they are nested you
    get functionality.
    This works because of a well defined object and method api that carry
    required information. One leg to it is to reuse code (where inheritance come
    in).

    >
    >> It seems a long way to go und feels frustrating.

    >
    > Is any of this important? Does it actually matter that your objects have
    > an extra method? After all, they have a useless 'import' method already.

    To Rainer I have explained before why the import method do not bother me
    (much) and why the export and the allways implicite called export_failed
    method is in such a case different.
    >
    >> Do you have any knowlege about fitting cpan modules or maybe
    >> references/links where I can search for.

    >
    > There are other Exporters on CPAN; possible one will do what you want.
    >
    >> EDIT: Maybe I am thinking in the wrong direction! When is the export_fail
    >> method called? Before or after any BEGIN-block? Or is there any run-state
    >> that can be called right after export_fail (as hook for example)?

    >
    > export_fail is called from Exporter::export, which is called from
    > Exporter::import or Exporter::export_to_level.

    I need a run-state like exporter is called right after its own begin-blocks
    but before your modul begin-blocks. In that case I can simply use a begin-
    block to override or delete my own eport_fail method and resolve any
    depending problem at once...

    So far I haven't found information about when export is called.

    >
    > Ben


    Also to you many thanks for your help.

    Andreas
     
    A. Sicken, Jul 22, 2013
    #6
  7. "A. Sicken" <> writes:
    > Rainer Weikusat wrote:
    >> "A. Sicken" <> writes:


    [...]

    >>> Ok. The method I want to get rid of is the export_fail-method (not the
    >>> local tied enable_debug var or the symbol) because you can call it on
    >>> every object created through this modul.

    >>
    >> And what's the problem with that? 'class modules' I'm using usually
    >> also contain auxiliary subroutines which could also be called 'on
    >> every object' except that this wouldn't be particularly useful


    [...]

    > Many modules are base-class modules to many oher modules - either directly
    > (as parent) or indirectly (as grand parent).


    [...]

    > the export-fail method is implicite called if it exists and it
    > will exists by all module siblings (in case of inheritance).


    This is not quite true: According to the documentation,
    Exporter::import will end up calling the export_fail method when an
    import of a symbol listed in @EXPORT_FAIL is attempted. Modules/
    classes not using that would be unaffected. For others, the default
    behaviour of turning every attempt to import something on @EXPORT_FAIL
    into a compile-time error would change. A workaround for that could be
    to add

    return &Exporter::export_fail unless $_[0] eq __PACKAGE__;

    as first line to your export_fail method. This would forward the call
    to the default implementation unless the method was called 'directly'
    via the module/ class defining it.
     
    Rainer Weikusat, Jul 22, 2013
    #7
  8. A.  Sicken

    A. Sicken Guest

    Re: using Exporter::export_fail - SOLVED

    Rainer Weikusat wrote:

    > This is not quite true: According to the documentation,
    > Exporter::import will end up calling the export_fail method when an
    > import of a symbol listed in @EXPORT_FAIL is attempted. Modules/
    > classes not using that would be unaffected. For others, the default
    > behaviour of turning every attempt to import something on @EXPORT_FAIL
    > into a compile-time error would change. A workaround for that could be
    > to add
    >
    > return &Exporter::export_fail unless $_[0] eq __PACKAGE__;
    >

    With this you made my day: Thanks. So Exporter does, what I want to avoid
    for my self - it traverse the calling tree to find its right member
    export_fail.

    The part where @EXPORT_FAIL must exist, does not actually help, because i
    will implement it to all my modules as trigger/hook to enable debugging code
    - but as the return line above show: Only if the given classename (by
    caller) is not equal to the static class name, which implements export_fail
    you have to call Exporter::export_fail staticly to defere the handling
    stuff. So no inheritance - and that is exactly what I wanted. I tested it so
    far and you are totally right.

    Out of curiousity: My docs (perldoc 5.16.3) do not cite this... gush...

    Many many thanks for your help: Problem solved!

    Andreas

    > as first line to your export_fail method. This would forward the call
    > to the default implementation unless the method was called 'directly'
    > via the module/ class defining it.
     
    A. Sicken, Jul 22, 2013
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Olivier Ricou

    RMI, Exporter and Runnable

    Olivier Ricou, Jul 29, 2003, in forum: Java
    Replies:
    3
    Views:
    6,216
  2. Jonathan

    DXL exporter and VB.net

    Jonathan, Jul 28, 2004, in forum: XML
    Replies:
    0
    Views:
    987
    Jonathan
    Jul 28, 2004
  3. mac
    Replies:
    3
    Views:
    523
    LILkillaBEE aka Nikola
    Jun 24, 2005
  4. Peter Michael

    defined(&func) and Exporter

    Peter Michael, Dec 30, 2003, in forum: Perl Misc
    Replies:
    4
    Views:
    163
    Brian McCauley
    Jan 2, 2004
  5. Amanda

    Help: exporter is "internal" class

    Amanda, Apr 9, 2004, in forum: Perl Misc
    Replies:
    0
    Views:
    129
    Amanda
    Apr 9, 2004
Loading...

Share This Page