=head1 NAME NameHandler - create indices of feature names =head1 SYNOPSIS # instantiate with a callback that gives the directory to use for a # given reference sequence my $nameHandler = NameHandler->new( sub { "$trackDir/" . $_[0] . "/" . $track->{"track"}; }; ); for my $name ( @feature_names ) { $nameHandler->addName( $name ); } # write out the finished names index $nameHandler->finish; =head1 METHODS =cut package NameHandler; use strict; use warnings; use Carp; use File::Path; use IO::File; use JSON 2; # index of the refseq name in the name array # TODO: find a central place to put this knowledge our $chromIndex = 3; my $nameFile = "names.txt"; =head1 new( \&directory_callback ) Make a new NameHandler. Takes a subroutine reference that should take a reference sequence name as an argument and return the path to the directory that should contain the name index we generate. =cut sub new { my ($class, $trackDirForChrom) = @_; my $self = { trackDirForChrom => $trackDirForChrom, nameFiles => {} }; bless $self, $class; return $self; } =head1 addName( \@name_record ) Name record (an arrayref) to add to the names index. =cut sub addName { my ($self, $nameArr) = @_; my $chrom = $nameArr->[$chromIndex]; unless (defined($chrom)) { carp "chrom not defined in " . JSON::to_json($nameArr) . "\n"; } my $nameFile = $self->{nameFiles}->{$chrom} ||= $self->_newChrom($chrom); $nameFile->print( JSON::to_json( $nameArr, {pretty => 0} ), "\n" ) or die "couldn't write to file for $chrom: $!"; } # Given the name of the reference sequence, opens and returns a filehandle to the # proper name index file. Makes a new directory to hold the file if # necessary. sub _newChrom { my ($self, $chrom) = @_; my $chromDir = $self->{trackDirForChrom}->($chrom); mkpath( $chromDir ) unless -e $chromDir; my $namefile = "$chromDir/$nameFile"; my $fh = IO::File->new( $namefile, '>' ) or die "$! writing $namefile"; return $fh; } =head1 finish Finalize and flush to disk any currently open name index. =cut sub finish { my ($self) = @_; foreach my $chrom (keys %{$self->{nameFiles}}) { my $fh = $self->{nameFiles}->{$chrom}; if( $fh && $fh->opened ) { $fh->close or die "$! closing names file for ref seq $chrom"; } } } sub DESTROY { shift->finish }