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

Dear Monks,

I solved my earlier split file problem by creating a new module as you suggested. This module is called "Include" and it works exacly like #include works in C.

Now i can put all headers like
use 5.010; use strict; use warnings; use Carp;
in a single header file called "header.pi" and put only one line of code
use Include 'header.pi'
instead of writing same lines to every file. I can also put my big sub to separate file and say
use Include 'agent.pi'
where it was originally.
package Include; use 5.010; use strict; use warnings; use Carp; use Filter::Util::Call; sub import { my (undef, @files) = @_; my (undef, $origin, $line) = caller; filter_add sub { filter_del(); while (defined (my $file = shift(@files))) { $_ .= "\n# line 1 $file\n"; local $/; undef $!; unless (open FH, "<", $file and $_ .= <FH> and !$!) { carp "Can not include '$file':$!"; return -1; } close FH; } ++$line; $_ .= "\n# line $line $origin\n"; return 1; }; } 1;
Nice to have some modern techniques in Perl - huh? I may send this to CPAN some day (if no one has not already done it).

Your comments are welcome.

Replies are listed 'Best First'.
Re: Solved: splitting source file
by ambrus (Abbot) on Feb 22, 2010 at 13:18 UTC
Re: Solved: splitting source file
by cdarke (Prior) on Feb 22, 2010 at 14:27 UTC
    Would be nice to honour @INC as use, require, and do. For example:
    use File::Spec; # cdarke added use Filter::Util::Call; sub import { my (undef, @files) = @_; @files = find_files(@files); # cdarke added my (undef, $origin, $line) = caller; filter_add sub { # No change, but see below return 1; }; } # cdarke added sub find_files { my @in = @_; my @out; for my $file (@in) { my $found = 0; for my $dir (@INC) { my $path = File::Spec->catfile ($dir, $file); if (-r $path) { push @out,$path; $found = 1; last; } push @out,$path unless $found; } } return @out; } 1;
    Personally I would prefer to use a lexical file handle, and to have some control over error handling?

    Update: corrected inner loop - non-existant files were being ignored.
Re: Solved: splitting source file
by ww (Archbishop) on Feb 22, 2010 at 13:46 UTC

    Re "Include.pi": It certainly is modular... but in the interest of readability (among other things), saving the keystrokes might be better done with a macro in your editor. Were I to read code such as you might write using this, I suspect I'd be expecting something on the order of 3.1416....

    While C and perl have many relationships, perl does NOT always benefit from using C-style constructs: think for loops, for example.

Re: Solved: splitting source file
by chromatic (Archbishop) on Feb 22, 2010 at 22:31 UTC

    Does David Golden's Toolset already handles this in a safer way than using source filters?

      Toolset maybe intented to be used at least some of this kind of situations. But what makes including not safe? I understand that trying to modify source by filtering is a hazardous operation but including a file does not modify the original source. It is just like a "symbol" which expands to something else. There seems to be practically no performance hit because the whole file is included in a single operation during the compilation phase without looping at all.
        But what makes including not safe?

        You end up compiling and running modified source code.

        I understand that trying to modify source by filtering is a hazardous operation but including a file does not modify the original source.

        Technically correct, but you're not running the original source code. You're running the modified source code. (If you weren't modifying the source code and running that, your code wouldn't work, because its sole purpose is to modify the source code you actually run.)

        I'm not telling you not to use this, but I am telling you that I believe David's solution already exists, is already tested, and uses a less fragile technique.

Re: Solved: splitting source file
by cdarke (Prior) on Feb 22, 2010 at 15:28 UTC
    Also need something to prevent recursion (file1 includes file2 includes file1), for example:
    package Include; ... my $sanity_count = 0; sub import { my (undef, @files) = @_; @files = find_files(@files); # cdarke added $sanity_count?croak ("Possible recursion!: @files"):$sanity_count+ ++; ...
    This also protects against use Include $0;