pboin has asked for the wisdom of the Perl Monks concerning the following question:

I want to write a good module, one that does its job well, and will serve me for a long time. I'm going to call it from at least two programs now, and from who knows how many in the future...

What it needs to do is examine a file to see if it has ASA (mainframe) carriage control. If it does not have it, insert the carriage control and return, no big deal.

I'm OK with the process at the bits-n-bytes level, but I always struggle with abstraction. Do I want to pass my module:

And more importantly, why?

This is where I really wish I had some formal CS training. What might a good monk read regarding design (esp. in the context of perl) verses implementation details?

Replies are listed 'Best First'.
Re: Ideal way to pass a file to a module
by Old_Gray_Bear (Bishop) on Apr 12, 2004 at 19:41 UTC
    Probably you want to pass the name of the file, because your routine will have to rebuild it with ASA controls pre-pended to each line. Something like this pseudo-code:
    add_asa_ctl_char { file = shift; open file; # I said it was pseudo-code! open temp_file; while <read file} { write temp_file asa_ctl+input_line } close(file, temp_file) return(temp_file) }
    In your calling module you decide whether you want to replace the original file with the temp-file, or not. (How lucky do you feel?) You may also have to take into consideration the difference between fixed and variable length records in your module. That determines where in your output string the asa-ctl char physically goes. (Before the data, of course, but where in the input string does the data start -- is there a rcw or a srcw you have to account for and adjust?)

    The real question is: what are you going to use for the asa-ctl character? I'd not suggest '1'.....

    ----
    I Go Back to Sleep, Now.

    OGB

      The real question is: what are you going to use for the asa-ctl character? I'd not suggest '1'.....

      Hmm... Why not I wonder?

      I've got a bunch of reports coming out of a NT box that will eventually be FTP'd to MVS VBA datasets and re-archived on the 'frame.

      What I'm looking at now 'cause I don't know w/ 100% certainty that all files have (or don't have) ASA CC is this:

      Scan the file top to bottom, looking for /^[0-9ABCVW-+\x5A]/. If that's all I find, and I find at least one '1' per 100 lines, then for our purposes it *has* ASA CC and should be left alone. If I find any illegal byte in the first column, or if there aren't enough top-of-pages, the file needs to have ASA control inserted.

      The insertion will be as simple as possible, basically, space pre-pended to every line except those lines with \x0C., which is DOS FormFeed. In that case, delete the \xOC and use a '1' in the first position.

      Thanks for your time in responding, especially with the MVS side of the house -- tough combination to find w/ Perl.

Re: Ideal way to pass a file to a module
by mirod (Canon) on Apr 12, 2004 at 19:26 UTC

    Why not go for all of these?

    sub add_cr { my %source= @_; my $content; # I suppose eventually that's what you want if( $source{content} { # content is in $source{content} } elsif( my $content_ref= $source{ref}) { # content in $$content_ref } elsif( my $filename= $source{filename}) { # you get the idea?...

    Pass a hash <type of source> => <data> to the function, and get the real data based on the type of source.

      Why not go for all of this?

      I agree, but I'd suggest a different interface: use separate functions for the different cases, and implement them in terms of one another. That allows users to import and call just those functions that they need.

      sub add_cr_to_str { # ... implementation goes here } sub add_cr_to_str_ref { add_cr_to_str( ${$_[0]} ) } sub add_cr_to_fh { add_cr_to_str( do { local $/; <$_[0]> } ) } sub add_cr_to_fn { require FileHandle; add_cr_to_sh( FileHandle->new( @_ ) ) }

      Most of those are just convenience functions, but if you later change your mind about which implementations are "primary", it's pretty easy to shuffle things around while maintaining the same interface.

      sub add_cr_to_str { add_cr_to_str_ref( \($_[0]) ) } sub add_cr_to_str_ref { # ... implementation goes here }
Re: Ideal way to pass a file to a module
by BrowserUk (Patriarch) on Apr 12, 2004 at 21:53 UTC

    Personally, I'd leave the error handling associate with the locating and opening the file to the calling module. The caller has greater knowledge of the application and can better decide how that error handling should be treated. For example, it will be able to couch error messages in terms that the users of the application will better understand.

    The application writer (caller) also knows best about where to obtain the file handle; what are appropriate defaults; extensions, locations, open shared, locked, exclusive etc.

    So, I would probably pass an open file handle to the module. The module writer knows best how to deal with the data it is expecting; read line-by-line; or fixed length records; or tab delimited etc.

    Since 5.8.0, if it makes sense to use a big string for the data, then you can always use a "memory file handle".


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail