Data-Section-Writer

 view release on metacpan or  search on metacpan

lib/Data/Section/Writer.pm  view on Meta::CPAN

  use File::Temp ();

  sub BUILD ($self, $) {

    # use the callers filename if not provided.
    unless(defined $self->perl_filename) {
      my(undef, $fn) = caller 2;
      $self->perl_filename($fn);
    }

    # upgrade to Path::Tiny if it is not already
    unless(is_blessed_ref $self->perl_filename && $self->isa('Path::Tiny')) {
      $self->perl_filename(Path::Tiny->new($self->perl_filename));
    }

    $self->_files({});
    $self->_formats({});

  }


  sub add_file ($self, $filename, $content, $encoding=undef) {
    Carp::croak("Unknown encoding $encoding") if defined $encoding && $encoding ne 'base64';
    $self->_files->{"$filename"} = [ $content, $encoding ];
    return $self;
  }

  sub _render_file ($self, $filename, $data) {
    my $text = "@@ $filename";
    $text .= " (" . $data->[1] . ")" if defined $data->[1];
    $text .= "\n";

    my $content = $data->[0];

    if($filename =~ /\.(.*?)\z/ && ($self->_formats->{$1} // [])->@*) {
        my $ext = $1;
        $content = $_->($self, $content) for $self->_formats->{$ext}->@*;
    }

    if(defined $data->[1] && $data->[1] eq 'base64') {
        $text .= encode_base64($data->[0]);
    } else {
        $text .= $content;
    }
    chomp $text;
    return $text;
  }


  sub render_section ($self) {
    my $files = $self->_files;
    return "__DATA__\n" unless %$files;
    return join("\n",
      "__DATA__",
      (map { $self->_render_file($_, $files->{$_}) } sort keys $files->%*),
      ''
    );
  }


  sub update_file ($self) {
    my $perl;
    my $orig;

    if(-f $self->perl_filename) {
      $orig = $perl = $self->perl_filename->slurp_utf8;

      if($perl =~ /^__DATA__/) {
        $perl = '';
      } else {
        # read the file in, removing __DATA__ and everything after that
        # if there is no __DATA__ section then leave unchanged.
        $perl =~ s/(?<=\n)__DATA__.*//s;

        # Add a new line at the end if it doesn't already exist.
        $perl .= "\n" unless $perl =~ /\n\z/s;
      }

    } else {
      $perl = '';
    }

    $perl .= $self->render_section;

    if(defined $orig && $orig eq $perl) {
      $self->_same(1);
      return $self;
    } else {
      $self->_same(0);
    }

    if(-f $self->perl_filename) {
      use autodie qw( truncate close );
      # re-write the perl to the file, using the existing inode
      my $backup = Path::Tiny->new(File::Temp::tempnam($self->perl_filename->parent, $self->perl_filename->basename));
      $self->perl_filename->copy($backup) if -f $self->perl_filename;
      my $fh = $self->perl_filename->openrw_utf8;
      truncate $fh, 0;
      print $fh $perl or die "unable to write to @{[ $self->perl_filename ]} $!";
      close $fh;
      $backup->remove if -f $backup;
    } else {
      $self->perl_filename->spew_utf8($perl);
    }

    return $self;
  }


  sub unchanged ($self) {
      return $self->_same;
  }


    sub add_format ($self, $ext, $cb) {
        Carp::croak("callback is not a code reference") unless is_coderef $cb;
        push $self->_formats->{$ext}->@*, $cb;
        return $self;
    }




( run in 1.644 second using v1.01-cache-2.11-cpan-39bf76dae61 )