File Coverage

blib/lib/PomBase/Chobo/ParseOBO.pm
Criterion Covered Total %
statement 105 122 86.0
branch 46 60 76.6
condition 14 20 70.0
subroutine 5 7 71.4
pod 0 3 0.0
total 170 212 80.1


line stmt bran cond sub pod time code
1             package PomBase::Chobo::ParseOBO;
2              
3             =head1 NAME
4              
5             PomBase::Chobo::ParseOBO - Parse the bits of an OBO file needed for
6             loading Chado
7              
8             =head1 SYNOPSIS
9              
10             =head1 AUTHOR
11              
12             Kim Rutherford C<< >>
13              
14             =head1 BUGS
15              
16             Please report any bugs or feature requests to C.
17              
18             =head1 SUPPORT
19              
20             You can find documentation for this module with the perldoc command.
21              
22             perldoc PomBase::Chobo::ParseOBO
23              
24             =over 4
25              
26             =back
27              
28             =head1 COPYRIGHT & LICENSE
29              
30             Copyright 2012 Kim Rutherford, all rights reserved.
31              
32             This program is free software; you can redistribute it and/or modify it
33             under the same terms as Perl itself.
34              
35             =head1 FUNCTIONS
36              
37             =cut
38              
39             our $VERSION = '0.037'; # VERSION
40              
41 4     4   211411 use Mouse;
  4         74819  
  4         18  
42 4     4   3082 use FileHandle;
  4         28736  
  4         21  
43              
44 4     4   2808 use PomBase::Chobo::OntologyData;
  4         13  
  4         6174  
45              
46             sub die_line
47             {
48 0     0 0 0 my $filename = shift;
49 0         0 my $linenum = shift;
50 0         0 my $message = shift;
51              
52 0         0 die "$filename:$linenum:$message\n";
53             }
54              
55             sub _finish_stanza
56             {
57 72     72   99 my $filename = shift;
58 72         91 my $current = shift;
59 72         86 my $terms_ref = shift;
60 72         92 my $metadata_ref = shift;
61              
62 72 50 66     171 if ($current->{is_obsolete} && $current->{is_relationshiptype}) {
63 0         0 return;
64             }
65              
66 72 50       134 if (!defined $current->{id}) {
67 0         0 die_line $filename, $current->{line}, "stanza has no id\n";
68 0         0 return;
69             }
70              
71 72 100       149 if ($current->{is_obsolete}) {
72 4         8 delete $current->{alt_id};
73             }
74              
75 72         133 $current->{metadata} = $metadata_ref;
76 72         224 $current->{source_file} = $filename;
77 72   100     304 $current->{relationship} //= [];
78              
79 72         102 my $namespace_from_metadata = 0;
80              
81 72 100       146 if (!defined $current->{namespace}) {
82             $current->{namespace} =
83             $metadata_ref->{'default-namespace'} //
84             $metadata_ref->{'ontology'} //
85 34   66     119 $current->{source_file} . '::' . $current->{id} =~ s/:.*//r;
      33        
86              
87 34 100       71 if ($current->{namespace} eq 'ro') {
88 4         9 $current->{namespace} = 'relations';
89             }
90              
91 34         51 $namespace_from_metadata = 1;
92             }
93              
94 72 100       132 if ($current->{is_a}) {
95             map {
96 54         64 push @{$current->{relationship}},
  54         182  
97             {
98             'relationship_name' => 'is_a',
99             'other_term' => $_,
100             };
101 47         58 } @{$current->{is_a}};
  47         99  
102              
103 47         92 delete $current->{is_a};
104             }
105              
106 72 100       149 if ($current->{synonym}) {
107 35         61 my %seen_synonyms = ();
108              
109             $current->{synonym} = [
110             map {
111              
112 60         99 my $seen_synonym = $seen_synonyms{$_->{synonym}};
113 60 100 66     117 if ($seen_synonym && lc $seen_synonym->{scope} eq 'exact') {
114             # keep it
115             } else {
116 58         216 $seen_synonyms{$_->{synonym}} = $_;
117             }
118 35         53 } @{$current->{synonym}}
  35         68  
119             ];
120              
121 35         178 $current->{synonym} = [sort { $a->{synonym} cmp $b->{synonym} } values %seen_synonyms];
  31         85  
122             }
123              
124 72         142 my $options = { namespace_from_metadata => $namespace_from_metadata };
125              
126 72         265 my $new_term = PomBase::Chobo::OntologyTerm->make_object($current, $options);
127              
128 72         182 push @$terms_ref, $new_term;
129             }
130              
131             sub fatal
132             {
133 0     0 0 0 my $message = shift;
134              
135 0         0 die "fatal: $message\n";
136             }
137              
138             my %interesting_metadata = (
139             'default-namespace' => 1,
140             'ontology' => 1,
141             'date' => 1,
142             'data-version' => 1,
143             );
144              
145             sub parse
146             {
147 11     11 0 1381 my $self = shift;
148 11         45 my %args = @_;
149              
150 11         29 my $filename = $args{filename};
151 11 50       37 if (!defined $filename) {
152 0         0 die 'no filename passed to parse()';
153             }
154              
155 11         25 my $ontology_data = $args{ontology_data};
156 11 50       30 if (!defined $ontology_data) {
157 0         0 die 'no ontology_data passed to parse()';
158             }
159              
160 11         21 my %metadata = ();
161 11         23 my @terms = ();
162              
163 11         18 my $current = undef;
164 11         34 my @synonyms = ();
165              
166 11         19 my %meta = ();
167              
168 11 50       83 my $fh = FileHandle->new($filename, 'r') or die "can't open $filename: $!";
169              
170 11         1546 my $line_number = 0;;
171              
172 11         432 while (defined (my $line = <$fh>)) {
173 819         1057 $line_number++;
174 819         934 chomp $line;
175 819         1271 $line =~ s/![^"\n]*$//;
176 819         1747 $line =~ s/\s+$//;
177 819         1027 $line =~ s/^\s+//;
178              
179 819 100       1402 next if length $line == 0;
180              
181 745 100       1572 if ($line =~ /^\[(.*)\]$/) {
182 72         138 my $stanza_type = $1;
183              
184 72 100       114 if (defined $current) {
185 61         139 _finish_stanza($filename, $current, \@terms, \%metadata);
186             }
187              
188 72         108 my $is_relationshiptype = 0;
189              
190 72 100       129 if ($stanza_type eq 'Typedef') {
191 10         13 $is_relationshiptype = 1;
192             } else {
193 62 50       115 if ($stanza_type ne 'Term') {
194 0         0 die "unknown stanza type '[$stanza_type]'\n";
195             }
196             }
197 72         286 $current = {
198             is_relationshiptype => $is_relationshiptype,
199             source_file_line_number => $line_number,
200             };
201             } else {
202 673 100       968 if ($current) {
203 576         1173 my @bits = split /: /, $line, 2;
204 576 50       853 if (@bits == 2) {
205 576         729 my $field_name = $bits[0];
206 576         632 my $field_value = $bits[1];
207              
208             # ignored for now
209 576         595 my $modifier_string;
210              
211 576 100       917 if ($field_value =~ /\}$/) {
212 2         10 $field_value =~ s/(.*)\{(.*)\}$/$1/;
213 2         14 $modifier_string = $2;
214 2         6 $field_value =~ s/\s+$//;
215             }
216              
217 576         810 my $field_conf = $PomBase::Chobo::OntologyConf::field_conf{$field_name};
218              
219 576 100       1088 if (defined $field_conf) {
220 430 100       679 if (defined $field_conf->{process}) {
221 201         249 eval {
222 201         433 $field_value = $field_conf->{process}->($field_value);
223             };
224 201 50       355 if ($@) {
225 0         0 warn qq(warning "$@" at $filename line $.\n);
226             }
227             }
228 430 50       602 if (defined $field_value) {
229 430 100 100     1372 if (defined $field_conf->{type} &&
      66        
230             ($field_conf->{type} eq 'SINGLE' || $field_conf->{type} eq 'SINGLE_HASH')) {
231 260         1014 $current->{$field_name} = $field_value;
232             } else {
233 170         191 push @{$current->{$field_name}}, $field_value;
  170         814  
234             }
235             }
236             }
237             } else {
238 0         0 die "can't parse line - no colon: $line\n";
239             }
240             } else {
241             # we're parsing metadata
242 97 50       270 if ($line =~ /^(.+?):\s*(.*)/) {
243 97         241 my ($key, $value) = ($1, $2);
244              
245 97 100       325 if ($interesting_metadata{$key}) {
246 34 50       79 if (defined $metadata{$key}) {
247 0         0 warn qq(metadata key "$key" occurs more than once in header\n);
248             } else {
249 34         112 $metadata{$key} = $value;
250             }
251             }
252             } else {
253 0         0 fatal "can't parse header line: $line";
254             }
255             }
256             }
257             }
258              
259 11 50       47 if (defined $current) {
260 11         43 _finish_stanza($filename, $current, \@terms, \%metadata);
261             }
262              
263 11 50       210 close $fh or die "can't close $filename: $!";
264              
265 11         30 eval {
266 11         184 $ontology_data->add(metadata => \%metadata,
267             terms => \@terms);
268             };
269 11 50       158 if ($@) {
270 0           die "failed while reading $filename: $@\n";
271             }
272             }
273              
274             1;