File Coverage

blib/lib/Bio/JBrowse/Store/NCList/ArrayRepr.pm
Criterion Covered Total %
statement 82 95 86.3
branch 12 18 66.6
condition 9 17 52.9
subroutine 15 18 83.3
pod 0 11 0.0
total 118 159 74.2


line stmt bran cond sub pod time code
1             package Bio::JBrowse::Store::NCList::ArrayRepr;
2             BEGIN {
3 3     3   106568 $Bio::JBrowse::Store::NCList::ArrayRepr::AUTHORITY = 'cpan:RBUELS';
4             }
5             {
6             $Bio::JBrowse::Store::NCList::ArrayRepr::VERSION = '0.1';
7             }
8             #ABSTRACT: compact array-based serialization of hashrefs
9              
10 3     3   29 use strict;
  3         8  
  3         203  
11 3     3   19 use warnings;
  3         5  
  3         107  
12 3     3   22 use Carp;
  3         13  
  3         5120  
13              
14              
15             sub new {
16 2     2 0 464 my ($class, $classes) = @_;
17 2   100     14 $classes ||= [];
18              
19             # fields is an array of (map from attribute name to attribute index)
20 2         3 my @fields;
21 2         9 for my $attributes ( map $_->{attributes}, @$classes ) {
22 3         5 my $field_index = 1;
23 3         6 push @fields, { map { $_ => $field_index++ } @$attributes };
  13         27  
24             }
25              
26 3         16 my $self = {
27             fields => \@fields,
28             classes => $classes,
29             classes_by_fingerprint => {
30 2         10 map { join( '-', @{$_->{attributes}} ) => $_ } @$classes
  3         4  
31             }
32             };
33              
34 2         8 bless $self, $class;
35 2         17 return $self;
36             }
37              
38             # convert a feature hashref into array representation
39             sub convert_hashref {
40 2     2 0 4 my ( $self, $hashref ) = @_;
41 2         3 delete $hashref->{seq_id};
42 2         8 my $class = $self->getClass( $hashref );
43 2         4 my $a = [ $class->{index}, map { $hashref->{$_} } @{$class->{attributes}} ];
  10         18  
  2         4  
44 2 50       8 if( defined( my $sub_idx = $class->{attr_idx}{subfeatures} ) ) {
45 0         0 $a->[$sub_idx] = [ map { $self->convert_hashref( $_ ) } @{$a->[$sub_idx]} ];
  0         0  
  0         0  
46             }
47 2         9 return $a;
48             }
49              
50             # convert a stream of hashrefs into a stream of arrays
51             sub convert_hashref_stream {
52 1     1 0 10 my ( $self, $in_stream ) = @_;
53             return sub {
54 3     3   21 my $f = $in_stream->();
55 3 100       15 return unless $f;
56 2         10 return $self->convert_hashref( $f );
57 1         12 };
58             }
59              
60             my %skip_field = map { $_ => 1 } qw( start end );
61             sub getClass {
62 2     2 0 4 my ( $self, $feature ) = @_;
63              
64 2         9 my @attrs = keys %$feature;
65 2         7 my $attr_fingerprint = join '-', @attrs;
66              
67 2   33     15 return $self->{classes_by_fingerprint}{$attr_fingerprint} ||= do {
68 2         11 my @attributes = ( 'start', 'end', ( grep !$skip_field{$_}, @attrs ) );
69 2         4 my $i = 0;
70 10         30 my $class = {
71             attributes => \@attributes,
72 0         0 attr_idx => { map { $_ => ++$i } @attributes },
73             # assumes that if a field is an array for one feature, it will be for all of them
74 2         5 isArrayAttr => { map { $_ => 1 } grep ref($feature->{$_}) eq 'ARRAY', @attrs }
75             };
76 2         5 push @{ $self->{fields} }, $class->{attr_idx};
  2         5  
77 2         3 push @{ $self->{classes} }, $class;
  2         4  
78 2         3 $class->{index} = $#{ $self->{classes} };
  2         6  
79 2         9 $class;
80             };
81             }
82              
83              
84             sub get {
85 28462     28462 0 38397 my ($self, $obj, $attr) = @_;
86 28462         47233 my $fields = $self->{'fields'}->[$obj->[0]];
87 28462 100 66     110860 if (defined($fields) && defined($fields->{$attr})) {
88 25881         105797 return $obj->[$fields->{$attr}];
89             } else {
90 2581         4125 my $cls = $self->{'classes'}->[$obj->[0]];
91 2581 50       4811 return unless defined($cls);
92 2581         2796 my $adhocIndex = $#{$cls->{'attributes'}} + 2;
  2581         4831  
93 2581 100 66     3170 if (($adhocIndex > $#{$obj})
  2581         6672  
94             or (not defined($obj->[$adhocIndex]->{$attr})) ) {
95 2568 50 33     5892 if (defined($cls->{'proto'})
96             and (defined($cls->{'proto'}->{$attr})) ) {
97 0         0 return $cls->{'proto'}->{$attr};
98             }
99 2568         8031 return undef;
100             }
101 13         82 return $obj->[$adhocIndex]->{$attr};
102             }
103             }
104              
105             sub fastGet {
106             # this method can be used if the attribute is guaranteed to be in
107             # the attributes array for the object's class
108 0     0 0 0 my ($self, $obj, $attr) = @_;
109 0         0 return $obj->[ $self->{fields}->[$obj->[0]]->{$attr} ];
110             }
111              
112             sub set {
113 13     13 0 23 my ($self, $obj, $attr, $val) = @_;
114 13         30 my $fields = $self->{'fields'}->[$obj->[0]];
115 13 50 33     69 if (defined($fields) && defined($fields->{$attr})) {
116 0         0 $obj->[$fields->{$attr}] = $val;
117             } else {
118 13         33 my $cls = $self->{'classes'}->[$obj->[0]];
119 13 50       35 return unless defined($cls);
120 13         19 my $adhocIndex = $#{$cls->{'attributes'}} + 2;
  13         36  
121 13 50       43 if ($adhocIndex > $#{$obj}) {
  13         33  
122 13         31 $obj->[$adhocIndex] = {}
123             }
124 13         86 $obj->[$adhocIndex]->{$attr} = $val;
125             }
126             }
127              
128             sub descriptor {
129 0     0 0 0 [ map { { attributes => $_->{attributes}, isArrayAttr => $_->{isArrayAttr} } } @{shift->{classes}} ]
  0         0  
  0         0  
130             }
131              
132             sub fastSet {
133             # this method can be used if the attribute is guaranteed to be in
134             # the attributes array for the object's class
135 0     0 0 0 my ($self, $obj, $attr, $val) = @_;
136 0         0 $obj->[$self->{'fields'}->[$obj->[0]]->{$attr}] = $val;
137             }
138              
139             sub makeSetter {
140 1     1 0 2 my ($self, $attr) = @_;
141             return sub {
142 13     13   21 my ($obj, $val) = @_;
143 13         44 $self->set($obj, $attr, $val);
144 1         10 };
145             }
146              
147             sub makeGetter {
148 74     74 0 115 my ($self, $attr) = @_;
149             return sub {
150 28459     28459   35889 my ($obj) = @_;
151 28459         53863 return $self->get($obj, $attr);
152 74         378 };
153             }
154              
155             1;
156              
157             __END__