Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Almost certainly a module documentation issue

by dd-b (Monk)
on Oct 13, 2017 at 21:37 UTC ( [id://1201350] : perlquestion . print w/replies, xml ) Need Help??

dd-b has asked for the wisdom of the Perl Monks concerning the following question:

The Email::Sender::Transport::Print module has very sparse documentation. It does say you can pass a file-handle object in as the attribute "fh". Looking at other Email::Sender::Transport implementations, it appears to me that passing a hash to new with the attributes as name/value pairs is the way it's done (there's a rather startlingly complete shortage of examples of Email::Sender::Transport::Print usage on the web).

The code is:

open (my $sm, '>> :encoding(UTF-8)', 'out.txt') or die "Failed to open out.txt: $!"; $transport = Email::Sender::Transport::Print->new({ fh => $sm, });

($transport is declared outside the bit quoted, but it is declared.)

When I do that, I get the error "isa check for "fh" failed: GLOB(0x806897840) is not blessed". This seems to imply that it noticed that I was in fact passing something as attribute fh, at least!

In the debugger, it seems to me that $sm, the thing passed in as the value of attribute fh, is in fact blessed.

DB<3> x $sm 0 GLOB(0x806897840) -> *main::$sm FileHandle({*main::$sm}) => fileno(7) DB<4> n isa check for "fh" failed: GLOB(0x806897840) is not blessed at (eval 7 +8)[/home/ddb/perl5/lib/perl5/Sub/Quote.pm:3] line 59, <$if> line 2. eval {...} called at (eval 78)[/home/ddb/perl5/lib/perl5/Sub/Quote +.pm:3] line 58 Email::Sender::Transport::Print::new("Email::Sender::Transport::Pr +int", HASH(0x80213c8e8)) called at /home/ddb/smbshare/Documents/Fando +m/Minicon/Mc53/mc53_pr1_001.pl line 178M

I am now wondering WTF. A preliminary attempt to look at the source code of the module foundered; it appears there is none, it's generated on-the-fly using moo or something? Which I'm not familiar with, and while in theory I could study it up and then figure out for sure what's expected, that's starting to look like a large amount of work.

Ideas?

Replies are listed 'Best First'.
Re: Almost certainly a module documentation issue
by ferreira (Chaplain) on Oct 13, 2017 at 23:27 UTC

    Sometimes code involving IO handles can be confusing that is because IO handles are of many kinds in Perl, like globs (the old way), glob refs, IO handles in scalar variables (produced with open and other IO operations), and legit objects which derive from IO::Handle, IO::File, etc.

    The code in Email::Sender::Transport::Print wants an IO::Handle, or something that satisfies

     $fh->isa('IO::Handle')

    This is far from ideal something more TIMTOWTDI, would be a check like the one of Scalar::Util::openhandle()

    As you discovered, $fh is a glob ref, and does not satisfy this precondition. But that does

     *{$fh}{IO}->isa('IO::Handle')

    This fact is kind of sparse in perl documentation. For example, you can read that suggested at item 7 at Making References

    You may use it in your code right now and / or submit a patch to Email::Sender::Transport::Print maintainer.

      that is because IO handles are of many kinds in Perl

      Indeed! A question that tobyink tackled a while back, leading to the creation of IO::Detect.

Re: Almost certainly a module documentation issue
by haukex (Archbishop) on Oct 14, 2017 at 06:50 UTC
    A preliminary attempt to look at the source code of the module foundered

    It's here, the bit of code that is relevant here is "has 'fh' => ( isa => InstanceOf['IO::Handle'], ..." (and yes, this is from Moo).

    To put 1nickt's suggestion into code - if you modify your code like the following, it works for me:

    use IO::Handle; my $sm = IO::Handle->new; open ($sm, ...

      This worked. This code ran, and the result was acceptable to Email::Sender::Transport::Print->new().

      In some ways I'm more confused than ever, though, because when I display the filehandle in perldb the new code shows me

      DB<4> x $sm 0 IO::Handle=GLOB(0x80695a1c8) -> *Symbol::GEN0 FileHandle({*Symbol::GEN0}) => fileno(7) DB<5> n

      while isn't IO::Handle anywhere, and duplicates the FileHandle shown in the original code (but wrapped a level down). Still, it's clearly different, and it works, so I won't complain :-).

        while isn't IO::Handle anywhere, and duplicates the FileHandle shown in the original code

        It's an object of type IO::Handle, as shown in the first line of the dump. Basically IO::Handle->new boils down to blessing a new symbol as returned by Symbol::gensym (which explains the second line of the dump) into the class IO::Handle (source). If you step through the code, you should see the following:

        **Before** the open() 0 IO::Handle=GLOB(0x1948fb2) -> *Symbol::GEN0 **After** the open() 0 IO::Handle=GLOB(0x1948fb2) -> *Symbol::GEN0 FileHandle({*Symbol::GEN0}) => fileno(7)

        So the FileHandle appears to be the result of opening the file.

Re: Almost certainly a module documentation issue
by 1nickt (Canon) on Oct 13, 2017 at 21:46 UTC

    Hi, the doc for Email::Sender::Transport::Print is indeed sparse, but it does say:

    By default, it will print to STDOUT, but it can be given any IO::Handle object to print to as its fh attribute.

    You don't appear to be using IO::Handle to create your filehandle. Have you tried that, or allowing the default?


    The way forward always starts with a minimal test.

      Ouch, I got sloppy looking at the types; been away from Perl a bit too long and forgot just how messy the IO space is these days.

      I'm sure this and the other details provided by later responses will be enough to resolve this (but I'll confirm that when I've actually resolved it).

      Thanks to you and everybody else; all the responses are useful, and I don't recall that any two have completely identical utility even!