File Coverage

lib/BoutrosLab/TSVStream/IO/Role/Fixed.pm
Criterion Covered Total %
statement 45 47 95.7
branch 4 8 50.0
condition 2 6 33.3
subroutine 15 15 100.0
pod 0 3 0.0
total 66 79 83.5


line stmt bran cond sub pod time code
1             package BoutrosLab::TSVStream::IO::Role::Fixed;
2              
3             # safe Perl
4 8     8   15620 use warnings;
  8         13  
  8         241  
5 8     8   27 use strict;
  8         11  
  8         124  
6 8     8   34 use Carp;
  8         7  
  8         486  
7              
8 8     8   30 use Moose::Role;
  8         9  
  8         45  
9 8     8   27558 use namespace::autoclean;
  8         11  
  8         50  
10              
11 8     8   486 use Moose::Util qw(find_meta);
  8         10  
  8         45  
12              
13 8     8   4144 use BoutrosLab::TSVStream::IO::Reader::Fixed;
  8         20  
  8         325  
14 8     8   4476 use BoutrosLab::TSVStream::IO::Writer::Fixed;
  8         21  
  8         3287  
15              
16             =head1 NAME
17              
18             BoutrosLab::TSVStream::IO::Role::Fixed
19              
20             =head1 SYNOPSIS
21              
22             # in a Moose class definition...
23             use MooseX::ClassAttribute
24              
25             class_has '_fields' => (
26             is => 'ro',
27             isa => 'ArrayRef',
28             default => sub { [qw(foo bar)] }
29             );
30              
31             # # or, without using MooseX::ClassAttribute
32             # my $_fields = [ qw(foo bar) ];
33             # sub _fields { return $_fields }
34              
35             with 'BoutrosLab::TSVStream::IO::Role::Fixed';
36              
37             has 'foo' => ( ... );
38             has 'bar' => ( ... );
39             ...
40              
41             =head1 DESCRIPTION
42              
43             This role provides methods to create a file/iostream reader/writer
44             for a class, using a stream of lines with tab separated fields for
45             each record, converting to/from an object of the class. Usually,
46             the stream will start with an initial line that has the field names
47             as a tab separated record.
48              
49             This role is also provided a BUILDARGS wrapper that alows the
50             constructor to be given one element pair in the parameter list:
51             (field_values=>[val1,val2,...]) instead of providing each field
52             explicitly by name as (fld1=>val1, fld2=>val2, ...). In such a
53             case, the values in the B<field_values> array must be in the same
54             order as they are listed in the B<_fields> class attribute.
55              
56             =cut
57              
58             has [qw(_tsvinternal_pre_header _tsvinternal_pre_comments _tsvinternal_post_comments)] => (
59             is => 'ro',
60             isa => 'ArrayRef[Str]',
61             default => sub { [] }
62             );
63              
64             sub _reader_class {
65 32     32   116 return 'BoutrosLab::TSVStream::IO::Reader::Fixed';
66             }
67              
68             sub _writer_class {
69 10     10   37 return 'BoutrosLab::TSVStream::IO::Writer::Fixed';
70             }
71              
72             sub _hashlist_opt_attr {
73 153     153   156 my $self = shift;
74 153         165 my $attr = shift;
75 153         597 my $can = $self->can($attr);
76 153 100       5840 return $can ? %{ $self->$attr } : ();
  16         629  
77             }
78              
79             sub reader {
80 143     143 0 231801 my $self = shift;
81 143   33     568 my $class = ref($self) || $self;
82 143         402 return $self->_reader_class()
83             ->new( { $self->_hashlist_opt_attr('_reader_args'), @_, class => $class } );
84             }
85              
86             sub writer {
87 10     10 0 7451 my $self = shift;
88 10   33     59 my $class = ref($self) || $self;
89 10         53 return $self->_writer_class()
90             ->new( { $self->_hashlist_opt_attr('_writer_args'), @_, class => $class } );
91             }
92              
93             around BUILDARGS => sub {
94             my $orig = shift;
95             my $class = shift;
96             my $arg = ref($_[0]) ? $_[0] : { @_ };
97              
98             if (my $field_values = delete $arg->{field_values}) {
99             my @v = @$field_values;
100             $arg->{$_} = shift @v for @{ $class->_fields };
101             $arg->{dyn_values} = \@v if scalar(@v);
102             }
103             $class->$orig( $arg );
104             };
105              
106             sub BUILD {
107 55     55 0 4917 my $self = shift;
108 55         55 $self->_check_dups( @{ $self->_fields } );
  55         1255  
109             }
110              
111             sub _check_dups {
112 139     139   448 my $self = shift;
113 139         116 my %seen;
114             my @dups;
115 139         184 for my $hdr (@_) {
116 305 50       694 push @dups, $hdr if $seen{$hdr}++;
117             }
118 139 50       1420 if (@dups) {
119 0 0         my $s = (@dups == 1) ? '' : 's';
120 0           croak "field name$s ("
121             . join( ', ', @dups)
122             . ") seen multiple times in headers ("
123             . join( ', ', @_)
124             . ")";
125             }
126             }
127              
128              
129             =head1 AUTHOR
130              
131             John Macdonald - Boutros Lab
132              
133             =head1 ACKNOWLEDGEMENTS
134              
135             Paul Boutros, Phd, PI - Boutros Lab
136              
137             The Ontario Institute for Cancer Research
138              
139             =cut
140              
141             1;
142