Replacing a class in Perl (“overriding”/“extending” a class with same name)?

核能气质少年 提交于 2019-12-25 18:29:08

问题


I am trying to Iterate directories in Perl, getting introspectable objects as result, mostly so I can print fields like mtime when I'm using Dumper on the returns from IO::All.

I have discovered, that it can be done, if in the module IO::All::File (for me, /usr/local/share/perl/5.10.1/IO/All/File.pm), I add the line field mtimef => undef;, and then modify its sub file so it runs $self->mtimef($self->mtime); (note, this field cannot have the same name (mtime) as the corresponding method/property, as those are dynamically assigned in IO::All). So, in essence, I'm not interested in "overloading", as in having the same name for multiple function signatures - I'd want to "replace" or "override" a class with its extended version (not sure how this is properly called), but under the same name; so all other classes that may use it, get on to using the extended version from that point on.

The best approach for me now would be, if I could somehow "replace" the IO::All::File class, from my actual "runnable" Perl script -- if somehow possible, by using the mechanisms for inheritance, so I can just add what is "extra". To show what I mean, here is an example:

use warnings;
use strict;

use Data::Dumper;
my @targetDirsToScan = ("./");

use IO::All -utf8 ;                          # Turn on utf8 for all io

# try to "replace" the IO::All::File class

{ # recursive inheritance!
  package IO::All::File;
  use IO::All::File -base;

  # hacks work if directly in /usr/local/share/perl/5.10.1/IO/All/File.pm

  field mtimef => undef; # hack

  sub file {
    my $self = shift;
    bless $self, __PACKAGE__;
    $self->name(shift) if @_;
    $self->mtimef($self->mtime); # hack
    return $self->_init;
  }

  1;
}

# main script start

my $io = io(@targetDirsToScan);
my @contents = $io->all(0);                    # Get all contents of dir
for my $contentry ( @contents ) {
  print Dumper \%{*$contentry};
}

... which fails with "Recursive inheritance detected in package 'IO::All::Filesys' at /usr/local/share/perl/5.10.1/IO/All/Base.pm line 13."; if you comment out the "recursive inheritance" section, it all works.

I'm sort of clear on why this happens with this kind of syntax - however, is there a syntax, or a way, that can be used to "replace" a class with its extended version but of the same name, similar to how I've tried it above? Obviously, I want the same name, so that I wouldn't have to change anything in IO::All (or any other files in the package). Also, I would preferably do this in the "runner" Perl script (so that I can have everything in a single script file, and I don't have to maintain multiple files) - but if the only way possible is to have a separate .pm file, I'd like to know about it as well.

So, is there a technique I could use for something like this?


回答1:


Well, I honestly have no idea what is going on, but I poked around with the code above, and it seems all that is required, is to remove the -base from the use IO::All::File statement; and the code otherwise seems to work as I expect it - that is, the package does get "overriden" - if you change this snippet in the code above:

# ...
{ # no more recursive inheritance!? IO::All::File gets overriden with this?!
  package IO::All::File;
  use IO::All::File; # -base; # just do not use `-base` here?!

  # hacks work if directly in /usr/local/share/perl/5.10.1/IO/All/File.pm

  field mtimef => undef; # hack

  sub file {
    my $self = shift;
    bless $self, __PACKAGE__;
    $self->name(shift) if @_;
    $self->mtimef($self->mtime); # hack
    print("!! *haxx0rz'd* file() reporting in\n");
    return $self->_init;
  }

  1;
}
# ...

I found this so unbelievable, I even added the print() there to make sure it is the "overriden" function that runs, and sure enough, it is; this is what I get in output:

...
!! *haxx0rz'd* file() reporting in
$VAR1 = {
          '_utf8' => 1,
          'mtimef' => 1394828707,
          'constructor' => sub { "DUMMY" },
          'is_open' => 0,
          'io_handle' => undef,
          'name' => './test.blg',
          '_encoding' => 'utf8',
          'package' => 'IO::All'
        };
...

... and sure enough,the field is there, as expected, too...

Well - I hope someone eventually puts a more qualified answer here; for the time being, I hope this is as good as a fix to my problems :) ...



来源:https://stackoverflow.com/questions/24726359/replacing-a-class-in-perl-overriding-extending-a-class-with-same-name

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!