Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use warnings;
- use strict;
- use autodie;
- use Exporter::Auto;
- package My::FH {
- use feature 'state';
- use List::Util qw(max);
- use Data::Dumper;
- use Moose;
- use Type::Params qw(compile);
- use Type::Utils;
- use Types::Standard qw(Str FileHandle Int HashRef ArrayRef Maybe);
- my $t_validFilename =
- declare as Str,
- where { -f $_ },
- message { "Non existent path [$_]\n" };
- my $t_validMode = enum [qw( r w a r+ w+ a+ >> +>> +< +> < >)];
- my $t_validPosition =
- declare as HashRef[ArrayRef];
- has 'filename' => (is => 'ro',
- isa => $t_validFilename,
- required => 1);
- has 'availableModes'=> (is => 'ro',
- isa => HashRef,
- required => 0,
- default => sub { {'r' => '<', 'w' => '>', 'a' => '>>', 'r+' => '+<', 'w+' => '+>', 'a+' => '+>>'} });
- has 'status' => (is => 'rw',
- isa => Int,
- required => 0,
- default => sub { 0 });
- has 'mode' => (is => 'rw',
- isa => $t_validMode,
- default => 'r',
- required => 0);
- has 'position' => (is => 'rw',
- isa => $t_validPosition, #[bytes offset, line number]
- required => 0,
- default => sub { {'r' => [0,0], 'w' => [0,0] } });
- has 'allPositions' => (is => 'rw',
- isa => HashRef[ArrayRef],
- required => 0,
- default => sub { { 'r' => [], 'w' => [] }});
- has 'allLines' => (is => 'rw',
- isa => ArrayRef[Str],
- required => 0,
- default => sub { [] });
- has 'file' => (is => 'rw',
- isa => Maybe[FileHandle],
- required => 0,
- default => sub { undef });
- has 'lastCommand' => (is => 'rw',
- isa => Str,
- required => 0,
- default => '');
- has 'slurp' => (is => 'ro',
- isa => Int,
- required => 0,
- default => 0);
- # if true than use 'seek' to adjust the pointers at every update
- # if no then send a generator like function that stays static at every write operation
- has 'autoUpdate' => (is => 'ro',
- isa => Int,
- required => 0,
- default => 1);
- # changes read|write_only to a+
- has 'autoChangeMode' => (is => 'ro',
- isa => Int,
- required => 0,
- default => 0);
- ##############################
- sub Open {
- my $self = shift;
- my $mode = $self->availableModes->{$self->mode};
- open my $fh, $mode, $self->filename;
- $self->file($fh);
- $self->status(1);
- }
- around 'Open' => sub {
- my $orig = shift;
- my $self = shift;
- die 'Open(): Too many args.\n' if scalar @_ > 1;
- state $check = compile($t_validMode);
- close $self->file if defined $self->file;
- my $mode = shift;
- $check->($mode);
- $self->mode($mode);
- $self->$orig();
- };
- ##############################
- sub Close {
- my $self = shift;
- close $self->file;
- $self->status(0);
- }
- around 'Close' => sub {
- my ($orig, $self) = (shift, shift);
- scalar( @_ > 0) and die "Close(): Too many args.\n";
- if (defined $self->file) {
- $self->$orig();
- }
- };
- ##############################
- sub SetMode {
- my $self = shift;
- my $mode = shift;
- close $self->file;
- open $self->file, $mode->[1], $self->filename;
- $self->mode($mode->[0]);
- }
- around 'SetMode' => sub {
- my ($orig, $self) = (shift, shift);
- die 'SetMode(): Too many args.\n' if scalar @_ > 1;
- return if !defined $self->file;
- state $check = compile($t_validMode);
- my $mode = shift;
- $check->($mode);
- $mode = [$mode, $self->availableModes->{$mode}];
- $self->$orig($mode);
- };
- ##############################
- sub WriteLines {
- my $self = shift;
- my $string = shift;
- my $countDelimeter = shift;
- my $fh = $self->file;
- print $fh $string . "\n";
- $self->position->{'w'} =
- [tell $self->file,
- $self->position->{'w'}->[1] + $countDelimeter];
- push @{$self->allPositions->{'w'}}, $self->position->{'w'};
- $self->lastCommand('w')
- }
- around 'WriteLines' => sub {
- my ($orig, $self) = (shift, shift);
- die 'WriteLines(): Too many args.\n' if scalar @_ > 2;
- if ($self->autoChangeMode) {
- if ($self->mode eq 'r') {
- $self->SetMode('a+');
- }
- } else {
- die "Write(): Incorrect mode set : " . $self->mode . "\n" if $self->mode eq 'r';
- }
- state $check = compile(ArrayRef);
- return if !defined $self->file;
- my $stringRef = shift;
- $check->($stringRef);
- my $delimeter = scalar @_ == 1 ? shift : "\n";
- my $countDelimeter = scalar @$stringRef;
- $self->$orig(join($delimeter, @{$stringRef}), $countDelimeter);
- };
- sub Write {
- my $self = shift;
- my $string = shift;
- my $delimeter = shift;
- $self->WriteLines($string, $delimeter);
- }
- around 'Write' => sub {
- my ($orig, $self) = (shift, shift);
- die 'Write(): Too many args.\n' if scalar @_ > 2;
- if ($self->autoChangeMode) {
- if ($self->mode eq 'r') {
- $self->SetMode('a+');
- }
- } else {
- die "Write(): Incorrect mode set : " . $self->mode . "\n" if $self->mode eq 'r';
- }
- my $string = shift;
- my $delim = scalar @_ == 0 ? "\n" : shift;
- $self->$orig(["$string"], $delim);
- };
- ##############################
- sub Readline {
- my $self = shift;
- my $additionalParameters = shift if scalar @_ == 1;
- if ($self->slurp) {
- my $lines = $self->allLines;
- my $fh = $self->file;
- while (my $each = <$fh>) {
- push @$lines, chomp $each;
- }
- $self->Close();
- $self->status(0);
- $self->lastCommand('r');
- $self->position->{'r'} = [tell $fh, 0];
- push @{$self->allPositions->{'r'}}, $self->position;
- # just a reference.
- return $lines;
- }
- my $fh = $self->file;
- my $newline = <$fh>;
- my $before = $self->position->{'r'};
- $self->position->{'r'} = [tell $fh, $before->[1]+1];
- push @{$self->allPositions->{'r'}}, $self->position->{'r'};
- $self->lastCommand('r');
- return $newline;
- }
- around 'Readline' => sub {
- my ($orig, $self) = (shift, shift);
- die "Readline(): Does not require any args.\n" if scalar @_ > 0;
- my $fh = $self->file;
- if ($self->autoChangeMode) {
- if ($self->mode =~ /(r|w)(?!\+)/) {
- $self->SetMode('a+');
- }
- } else {
- die "Write(): Incorrect mode set : " . $self->mode . "\n" if $self->mode eq 'w';
- }
- if (not $self->slurp) {
- # if last command is a write, reset the pointer to the last read location
- if ($self->lastCommand eq 'w') {
- # imagine running this command for the first time after a write operation. You don't want it to be set at the end right?
- # seek to the beginning
- my $posAfterWrite = tell $fh;
- # position in bytes
- my $before = $self->position->{'r'}->[0];
- print "\nbefore: ", $before;
- # reopen the file
- # $self->Open($self->mode) if $self->mode =~ ;
- # $fh = $self->file;
- print " after: ", $posAfterWrite;
- # reset to the previous pointer
- print "\nResetting to $before.\n";
- seek $fh, $before, 0;
- return $self->$orig();
- # send an updated generator at every write op.
- # you can ignore this if you wish to have distinct FH at distinct positions
- if (not $self->autoUpdate) {
- my $gen = sub {
- return 0 if eof $fh;
- return $self->$orig();
- };
- return $gen;
- }
- } else {
- if (not $self->autoUpdate) {
- my $gen = sub {
- return 0 if eof $fh;
- return $self->$orig();
- };
- return $gen;
- } else {
- return $self->$orig();
- }
- }
- } else {
- if (not defined $self->allLines->[0]) {
- # autocloses FH after slurping
- return $self->$orig();
- } else {
- # file's already slurped. just send the reference
- return $self->allLines;
- }
- }
- };
- sub Read {
- my $self = shift;
- my $send = "";
- return $self->Readline() if $self->slurp;
- while (my $line = $self->Readline()) {
- $send .= "$line";
- }
- return int $send if $send =~ /^0$/;
- return $send;
- }
- ##############################
- sub Goto {
- my ($self, $line) = (shift, shift);
- die "Goto(): File has not been opened yet or has been closed.\n" if ! defined $self->file;
- if ($self->slurp) {
- die "Goto(): Slurp mode enabled: File has not been slurped yet.\n" if ! defined $self->allLines->[0];
- my $maxlines = scalar @{$self->allLines};
- die "Goto(): Not in range 1 - $maxlines : " . $line if $line <= 0 or $line > $maxlines;
- --$line;
- return $self->allLines->[$line];
- }
- # why seperate? Because we have not read the whole file yet.
- # if mode eq 'r' then look in in 'r' arr or else 'w' arr (for r+ a+ a w w+)
- my $lookin = $self->mode eq 'r' ? 'r' : 'w';
- my $maxlines = max(map { $_->[1] } @{$self->allPositions->{$lookin}});
- # one indexed
- die "Goto(): Not in range 1 - $maxlines : " . $line if $line <= 0 or $line > $maxlines;
- --$line;
- my $bytesPos = $self->allPositions->{$lookin}->[$line]->[0];
- print $bytesPos, "\n";
- print Dumper $self->allPositions->{'w'};
- my $fh = $self->file;
- seek $fh, $bytesPos, 0;
- }
- __PACKAGE__->meta->make_immutable;
- };
- # use Data::Dumper;
- # my $test = My::FH->new(filename => '/home/caligian/Programming/Perl/test1234');
- # $test->Open('a+');
- # $test->Write('1:');
- # $test->Write("2:");
- # print $test->Readline();
- # print $test->Readline();
- # $test->Write("3:");
- # print $test->Readline();
- # $test->Write("4:");
- # print $test->Readline();
- # $test->Goto(1);
- # $test->Close();
- 1 # End of My::FileIO
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement