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   16164 use warnings;
  8         16  
  8         280  
5 8     8   35 use strict;
  8         8  
  8         145  
6 8     8   36 use Carp;
  8         9  
  8         484  
7              
8 8     8   32 use Moose::Role;
  8         8  
  8         54  
9 8     8   29499 use namespace::autoclean;
  8         12  
  8         61  
10              
11 8     8   548 use Moose::Util qw(find_meta);
  8         11  
  8         49  
12              
13 8     8   4180 use BoutrosLab::TSVStream::IO::Reader::Fixed;
  8         21  
  8         433  
14 8     8   4562 use BoutrosLab::TSVStream::IO::Writer::Fixed;
  8         24  
  8         3522  
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   137 return 'BoutrosLab::TSVStream::IO::Reader::Fixed';
66             }
67              
68             sub _writer_class {
69 10     10   36 return 'BoutrosLab::TSVStream::IO::Writer::Fixed';
70             }
71              
72             sub _hashlist_opt_attr {
73 153     153   192 my $self = shift;
74 153         172 my $attr = shift;
75 153         734 my $can = $self->can($attr);
76 153 100       6103 return $can ? %{ $self->$attr } : ();
  16         583  
77             }
78              
79             sub reader {
80 143     143 0 268461 my $self = shift;
81 143   33     695 my $class = ref($self) || $self;
82 143         513 return $self->_reader_class()
83             ->new( { $self->_hashlist_opt_attr('_reader_args'), @_, class => $class } );
84             }
85              
86             sub writer {
87 10     10 0 7880 my $self = shift;
88 10   33     57 my $class = ref($self) || $self;
89 10         56 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 6165 my $self = shift;
108 55         60 $self->_check_dups( @{ $self->_fields } );
  55         1225  
109             }
110              
111             sub _check_dups {
112 139     139   504 my $self = shift;
113 139         133 my %seen;
114             my @dups;
115 139         205 for my $hdr (@_) {
116 305 50       1004 push @dups, $hdr if $seen{$hdr}++;
117             }
118 139 50       1347 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