http://www.perlmonks.org?node_id=1010759

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

Dear monks,

I wrote a function that loops through a scalarref line by line in order to make some modifications (in-place), because I was unable to find a Perl feature for that.
So I'd find it interesting if somebody had a simple solution for that trivial task, but my question is:
How could I put this self-made loop (based on a while loop) into a separate package so I can use it to do all kinds of modifications per line?
If that thing was a class, I could instantiate an object but I wouldn't know how to wrap such an object around the individual code which is responsible for the line modifications?

Replies are listed 'Best First'.
Re: Where to put self-made loop logic (separate module)?
by blue_cowdawg (Monsignor) on Dec 28, 2012 at 23:29 UTC
        If that thing was a class,

    Before I start writing a class module to do something I usually ask myself a few questions:

    • Is this thing complicated enough to justify the overhead?
      While there isn't much overhead in a module given that a module can be as simple as:
      package Foo; 1;
      but a properly written module does have some inherent overhead to it. For one thing if you are going to write a module then it deserves to have pod embedded into it so that six months later when your smoking a different brand of crack you can remember why you wrote the module and how it works.
    • Am I going to use this again?
      I am forever writing modules that I think I'm going to use later and disappoint myself when I don't. Worse I forget that I wrote the darn thing and I write another one that does the same thing. But that's me. I suffer from C.R.A.F.T. and get like a squirrel burying nuts at times.
      If you are going to go to the trouble of writing a module make sure you're going to get use out of it.
    • Is someone else going to use this?
      If I am writing code at work I normally presume that someone else may use it down the line. If it is a Perl programming gig then there is absolute certainty about this. This makes for an even larger burden to make sure that this module is useful, properly crafted, and properly documented. If you are coding in a corporate environment then there may be programming and documentation standards for you to adhere to. If not maybe you can pioneer them with buy-in from your management and other members of your team.

    From other folks comments and what you described to me this is not a good candidate for a separate module and could in fact obfuscate your code. That's abuse of the module system in my opinion. :-)

    If you get to the point you are writing modules that the larger Perl community can benefit from consider becoming a contributor to CPAN.


    Peter L. Berghold -- Unix Professional
    Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg
Re: Where to put self-made loop logic (separate module)?
by davido (Cardinal) on Dec 29, 2012 at 00:05 UTC

    Show what you've come up with so far. If it's compelling enough, and can be generalized enough, it might be a reasonable candidate for addition to a module that houses a bunch of useful and similar utilities, such as List::EVENMoreUtils (j/k about the name).

    It doesn't sound like something that comprises a large amount of code, so let's have a look at it.


    Dave

      Wow, so many answers already. :-)

      The best way to find out if this should be a separate module is probably to let you guys decide, so here's the code...
      This code parses some special list markup (similar to Wiki markup).
      The scalarref ($text) is directly modified (I don't want to copy it and go $$text = $newtext).
      If I wanted to write another parser function which does even more complicated modifications (which cannot be replaced by a regex), I'd have some duplicate code if this loop was not a separate module.
      I know this isn't the prettiest piece of code mankind has written, but it seems to work (even with 3 byte UTF-8 characters / note that the line length changes).
      I'd be happy if you could help me improve my code (even if there's a one-line alternative).

      sub parseLists { my $self = shift; my $text = \$self->{_text}; # So we want to loop through the text line by line # and be able to modify some lines, # but we don't want to rebuild/copy the whole text. my $lf = "\n"; # linebreak my $lflen = length $lf; # 1 my $pos1 = 0; # left line offset my $pos2 = 0; # right line offset (1st char after line) my $len = 0; # line length my $lendif = 0; # line length difference my $inlist; open my $fh, "<:utf8", $text; # Note how we open in UTF-8 mode # while (<$fh>) # Gets confused when line length changes # Using seek() is risky, because it reads bytes, not chars! # However, substr() always counts chars, not bytes. while (<$fh>) { # Get line string without newline character my $line = substr $_, 0, -$lflen; my $oldline = $line; # Calculate offsets $len = length $line; $pos1 = $pos2; $pos2 += $len + $lflen; # Modify line # START (not part of loop structure) my $isasterisk = $line =~ m/^\* /; my $isindented = $line =~ m/^\ /; my $isfirst; if (!$inlist) { if ($isasterisk) { $isfirst = 1; $inlist = 1; } } if ($inlist) { if (!$isindented && !$isasterisk) { substr $line, 0, 0, "</ul>\n"; $inlist = 0; } elsif ($isindented) { $line =~ s/^\ (.*)/<li class="nobullet">$1<\/li>/; } elsif ($isasterisk) { $line =~ s/^\* (.*)/<li>$1<\/li>/; substr $line, 0, 0, "<ul>\n" if $isfirst; } } # END # Write new line back substr $$text, $pos1, $len, $line; # Calculate diff $lendif = (length $line) - ((length $_) - ($lflen)); # Adjust our and Perl's (!) position counter $pos2 += $lendif; # That's our counter seek $fh, $lendif, 1; # That's from Perl / SEEK_CUR } }

        Does the format of the input data have a name? Is the input data format documented somewhere?


        Dave

Re: Where to put self-made loop logic (separate module)?
by NetWallah (Canon) on Dec 28, 2012 at 23:09 UTC
    Good questions - all of which have extensive documentation easily available. You can start at perlootut.

    If you post your code here, we could help you with the OO encapsulation, or suggest alternatives.

    Don't be afraid to post early, or semi working code, and request help - everyone learns form that activity, and we are quite happy to do that.

                 "By three methods we may learn wisdom: First, by reflection, which is noblest; Second, by imitation, which is easiest; and third by experience, which is the bitterest."           -Confucius

Re: Where to put self-made loop logic (separate module)?
by Anonymous Monk on Dec 28, 2012 at 23:06 UTC
      haha ;) //gm not /s
Re: Where to put self-made loop logic (separate module)?
by CountZero (Bishop) on Dec 30, 2012 at 09:14 UTC
    Something like this?
    package My::Cunning::Module; use Modern::Perl; use Exporter qw/import/; our @EXPORT_OK = qw/looper/; sub looper { #admire my cunningly crafted loop logic function ... } 1;
    And you then call your function as follows:
    use Modern::Perl; use My::Cunning::Module qw/looper/; # somewhere in your program looper($data) or die 'It did not work';

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

    My blog: Imperial Deltronics