Advertisement
Guest User

Untitled

a guest
Oct 11th, 2020
143
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 9.46 KB | None | 0 0
  1. use warnings;
  2. use strict;
  3. use autodie;
  4. use Exporter::Auto;
  5.  
  6.  
  7. package My::FH {
  8.     use feature 'state';
  9.     use List::Util qw(max);
  10.     use Data::Dumper;
  11.     use Moose;
  12.     use Type::Params qw(compile);
  13.     use Type::Utils;
  14.     use Types::Standard qw(Str FileHandle Int HashRef ArrayRef Maybe);
  15.  
  16.  
  17.     my $t_validFilename =
  18.     declare as Str,
  19.     where { -f $_ },
  20.     message { "Non existent path [$_]\n" };
  21.  
  22.     my $t_validMode = enum [qw( r w a r+ w+ a+ >> +>> +< +> < >)];
  23.  
  24.    
  25.     my $t_validPosition =
  26.     declare as HashRef[ArrayRef];
  27.    
  28.     has 'filename' => (is => 'ro',
  29.                isa => $t_validFilename,
  30.                required => 1);
  31.  
  32.     has 'availableModes'=> (is => 'ro',
  33.                 isa => HashRef,
  34.                 required => 0,
  35.                 default => sub { {'r' => '<', 'w' => '>', 'a' => '>>', 'r+' => '+<', 'w+' => '+>', 'a+' => '+>>'} });
  36.  
  37.     has 'status' => (is => 'rw',
  38.              isa => Int,
  39.              required  => 0,
  40.              default => sub { 0 });
  41.    
  42.     has 'mode' => (is => 'rw',
  43.            isa => $t_validMode,
  44.            default => 'r',
  45.            required => 0);
  46.  
  47.     has 'position' => (is => 'rw',
  48.                isa => $t_validPosition,  #[bytes offset, line number]
  49.                required => 0,
  50.                default => sub { {'r' => [0,0], 'w' => [0,0] } });
  51.  
  52.     has 'allPositions' => (is => 'rw',
  53.                isa => HashRef[ArrayRef],
  54.                required => 0,
  55.                default => sub { { 'r' => [], 'w' => [] }});
  56.  
  57.     has 'allLines' => (is => 'rw',
  58.                isa => ArrayRef[Str],
  59.                required => 0,
  60.                default => sub { [] });
  61.  
  62.     has 'file' => (is => 'rw',
  63.            isa => Maybe[FileHandle],
  64.            required => 0,
  65.            default => sub { undef });
  66.  
  67.     has 'lastCommand' => (is => 'rw',
  68.               isa => Str,
  69.               required => 0,
  70.               default => '');
  71.  
  72.     has 'slurp' => (is => 'ro',
  73.             isa => Int,
  74.             required => 0,
  75.             default => 0);
  76.  
  77.    
  78.     # if true than use 'seek' to adjust the pointers at every update
  79.     # if no then send a generator like function that stays static at every write operation
  80.     has 'autoUpdate' => (is => 'ro',
  81.              isa => Int,
  82.              required => 0,
  83.              default => 1);
  84.  
  85.     # changes read|write_only to a+
  86.     has 'autoChangeMode' => (is => 'ro',
  87.                  isa => Int,
  88.                  required => 0,
  89.                  default => 0);
  90.  
  91.     ##############################
  92.    
  93.     sub Open {
  94.     my $self = shift;
  95.     my $mode = $self->availableModes->{$self->mode};
  96.     open my $fh, $mode, $self->filename;
  97.     $self->file($fh);
  98.     $self->status(1);
  99.     }
  100.    
  101.     around 'Open' => sub {
  102.     my $orig = shift;
  103.     my $self = shift;
  104.     die 'Open(): Too many args.\n' if scalar @_ > 1;
  105.     state $check = compile($t_validMode);
  106.  
  107.     close $self->file if defined $self->file;
  108.    
  109.     my $mode = shift;
  110.     $check->($mode);
  111.     $self->mode($mode);
  112.     $self->$orig();
  113.     };
  114.    
  115.     ##############################
  116.    
  117.     sub Close {
  118.     my $self = shift;
  119.     close $self->file;
  120.     $self->status(0);
  121.     }
  122.  
  123.     around 'Close' => sub {
  124.     my ($orig, $self) = (shift, shift);
  125.     scalar( @_ > 0) and die "Close(): Too many args.\n";
  126.     if (defined $self->file) {
  127.         $self->$orig();
  128.     }
  129.     };
  130.  
  131.     ##############################
  132.    
  133.     sub SetMode {
  134.     my $self = shift;
  135.     my $mode = shift;
  136.     close $self->file;
  137.     open $self->file, $mode->[1], $self->filename;
  138.     $self->mode($mode->[0]);
  139.     }
  140.  
  141.     around 'SetMode' => sub {
  142.     my ($orig, $self) = (shift, shift);
  143.     die 'SetMode(): Too many args.\n' if scalar @_ > 1;
  144.     return if !defined $self->file;
  145.     state $check = compile($t_validMode);
  146.     my $mode = shift;
  147.     $check->($mode);
  148.     $mode =  [$mode, $self->availableModes->{$mode}];
  149.     $self->$orig($mode);
  150.     };
  151.  
  152.     ##############################
  153.  
  154.     sub WriteLines {
  155.     my $self = shift;
  156.     my $string = shift;
  157.     my $countDelimeter = shift;
  158.     my $fh = $self->file;
  159.     print $fh $string . "\n";
  160.    
  161.     $self->position->{'w'} =
  162.         [tell $self->file,
  163.          $self->position->{'w'}->[1] + $countDelimeter];
  164.    
  165.     push @{$self->allPositions->{'w'}}, $self->position->{'w'};
  166.     $self->lastCommand('w')
  167.     }
  168.  
  169.     around 'WriteLines' => sub {
  170.     my ($orig, $self) = (shift, shift);
  171.     die 'WriteLines(): Too many args.\n' if scalar @_ > 2;
  172.  
  173.     if ($self->autoChangeMode) {
  174.         if ($self->mode eq 'r') {
  175.         $self->SetMode('a+');
  176.         }
  177.     } else {
  178.         die "Write(): Incorrect mode set : " . $self->mode . "\n" if $self->mode eq 'r';
  179.     }
  180.  
  181.     state $check = compile(ArrayRef);
  182.     return if !defined $self->file;
  183.    
  184.     my $stringRef = shift;
  185.    
  186.     $check->($stringRef);
  187.  
  188.     my $delimeter = scalar @_ == 1 ? shift : "\n";
  189.     my $countDelimeter =  scalar @$stringRef;
  190.     $self->$orig(join($delimeter, @{$stringRef}), $countDelimeter);
  191.     };
  192.  
  193.     sub Write {
  194.     my $self = shift;
  195.     my $string = shift;
  196.     my $delimeter = shift;
  197.     $self->WriteLines($string, $delimeter);
  198.     }
  199.  
  200.     around 'Write' => sub {
  201.     my ($orig, $self) = (shift, shift);
  202.     die 'Write(): Too many args.\n' if scalar @_ > 2;
  203.    
  204.     if ($self->autoChangeMode) {
  205.         if ($self->mode eq 'r') {
  206.         $self->SetMode('a+');
  207.         }
  208.     } else {
  209.         die "Write(): Incorrect mode set : " . $self->mode . "\n" if $self->mode eq 'r';
  210.     }
  211.  
  212.     my $string = shift;
  213.     my $delim = scalar @_ == 0 ? "\n" : shift;
  214.     $self->$orig(["$string"], $delim);
  215.     };
  216.  
  217.     ##############################
  218.  
  219.     sub Readline {
  220.     my $self = shift;
  221.     my $additionalParameters = shift if scalar @_ == 1;
  222.    
  223.     if ($self->slurp) {
  224.         my $lines = $self->allLines;
  225.         my $fh = $self->file;
  226.         while (my $each = <$fh>) {
  227.         push @$lines, chomp $each;
  228.         }
  229.         $self->Close();
  230.         $self->status(0);
  231.         $self->lastCommand('r');
  232.         $self->position->{'r'} = [tell $fh, 0];
  233.         push @{$self->allPositions->{'r'}}, $self->position;
  234.        
  235.         # just a reference.
  236.         return $lines;
  237.     }
  238.  
  239.     my $fh = $self->file;
  240.     my $newline = <$fh>;
  241.    
  242.     my $before = $self->position->{'r'};
  243.    
  244.     $self->position->{'r'} = [tell $fh, $before->[1]+1];
  245.     push @{$self->allPositions->{'r'}}, $self->position->{'r'};
  246.     $self->lastCommand('r');
  247.  
  248.     return $newline;
  249.     }
  250.  
  251.     around 'Readline' => sub {
  252.     my ($orig, $self) = (shift, shift);
  253.     die "Readline(): Does not require any args.\n" if scalar @_ > 0;
  254.    
  255.     my $fh = $self->file;
  256.  
  257.     if ($self->autoChangeMode) {
  258.         if ($self->mode =~ /(r|w)(?!\+)/) {
  259.         $self->SetMode('a+');
  260.         }
  261.     } else {
  262.         die "Write(): Incorrect mode set : " . $self->mode . "\n" if $self->mode eq 'w';
  263.     }
  264.  
  265.  
  266.     if (not $self->slurp) {
  267.     # if last command is a write, reset the pointer to the last read location
  268.         if ($self->lastCommand eq 'w') {
  269.         # imagine running this command for the first time after a write operation. You don't want it to be set at the end right?
  270.         # seek to the beginning
  271.         my $posAfterWrite = tell $fh;
  272.        
  273.         # position in bytes
  274.         my $before = $self->position->{'r'}->[0];
  275.         print "\nbefore: ", $before;
  276.        
  277.         # reopen the file
  278.         # $self->Open($self->mode) if $self->mode =~ ;
  279.         # $fh = $self->file;
  280.  
  281.         print " after: ", $posAfterWrite;
  282.        
  283.         # reset to the previous pointer
  284.         print "\nResetting to $before.\n";
  285.         seek $fh, $before, 0;
  286.  
  287.         return $self->$orig();
  288.  
  289.         # send an updated generator at every write op.
  290.         # you can ignore this if you wish to have distinct FH at distinct positions
  291.         if (not $self->autoUpdate) {
  292.             my $gen = sub {
  293.             return 0 if eof $fh;
  294.             return $self->$orig();
  295.             };
  296.             return $gen;
  297.         }
  298.        
  299.         } else {
  300.         if (not $self->autoUpdate) {
  301.             my $gen = sub {
  302.             return 0 if eof $fh;
  303.             return $self->$orig();
  304.             };
  305.             return $gen;
  306.         } else {
  307.             return $self->$orig();
  308.         }
  309.         }
  310.     } else {
  311.         if (not defined $self->allLines->[0]) {
  312.         # autocloses FH after slurping
  313.         return $self->$orig();
  314.         } else {
  315.         # file's already slurped. just send the reference
  316.         return $self->allLines;
  317.         }
  318.     }
  319.     };
  320.  
  321.  
  322.     sub Read {
  323.     my $self = shift;
  324.     my $send = "";
  325.  
  326.     return $self->Readline() if $self->slurp;
  327.    
  328.     while (my $line = $self->Readline()) {
  329.         $send .= "$line";
  330.     }
  331.     return int $send if $send =~ /^0$/;
  332.     return $send;
  333.     }
  334.  
  335.  
  336.     ##############################
  337.    
  338.     sub Goto {
  339.     my ($self, $line) = (shift, shift);
  340.    
  341.     die "Goto(): File has not been opened yet or has been closed.\n" if ! defined $self->file;
  342.  
  343.     if ($self->slurp) {
  344.         die "Goto(): Slurp mode enabled: File has not been slurped yet.\n" if ! defined $self->allLines->[0];
  345.         my $maxlines = scalar @{$self->allLines};
  346.         die "Goto(): Not in range 1 - $maxlines : " . $line if $line <= 0 or $line > $maxlines;
  347.         --$line;
  348.         return $self->allLines->[$line];
  349.     }
  350.  
  351.     # why seperate? Because we have not read the whole file yet.
  352.     # if mode eq 'r' then look in in 'r' arr or else 'w' arr (for r+ a+ a w w+)
  353.     my $lookin = $self->mode eq 'r' ? 'r' : 'w';
  354.     my $maxlines = max(map { $_->[1] } @{$self->allPositions->{$lookin}});
  355.  
  356.     # one indexed
  357.  
  358.     die "Goto(): Not in range 1 - $maxlines : " . $line if $line <= 0 or $line > $maxlines;
  359.     --$line;
  360.     my $bytesPos = $self->allPositions->{$lookin}->[$line]->[0];
  361.     print $bytesPos, "\n";
  362.     print Dumper $self->allPositions->{'w'};
  363.     my $fh = $self->file;
  364.     seek $fh, $bytesPos, 0;
  365.  
  366.     }
  367.  
  368.  
  369.    
  370.     __PACKAGE__->meta->make_immutable;
  371. };
  372.  
  373.  
  374. # use Data::Dumper;
  375.  
  376. # my $test = My::FH->new(filename => '/home/caligian/Programming/Perl/test1234');
  377. # $test->Open('a+');
  378. # $test->Write('1:');
  379. # $test->Write("2:");
  380. # print $test->Readline();
  381. # print $test->Readline();
  382. # $test->Write("3:");
  383. # print $test->Readline();
  384. # $test->Write("4:");
  385. # print $test->Readline();
  386. # $test->Goto(1);
  387.  
  388. # $test->Close();
  389.  
  390.  
  391.  
  392.    
  393. 1 # End of My::FileIO
  394.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement