File Coverage

blib/lib/JCAMP/DX.pm
Criterion Covered Total %
statement 73 73 100.0
branch 13 16 81.2
condition 1 3 33.3
subroutine 7 7 100.0
pod 0 4 0.0
total 94 103 91.2


line stmt bran cond sub pod time code
1             #------------------------------------------------------------------------------
2             #$Author: andrius $
3             #$Date: 2018-11-21 13:22:13 +0200 (Tr, 21 lapkr. 2018) $
4             #$Revision: 33 $
5             #$URL: svn+ssh://www.crystallography.net/home/coder/svn-repositories/jcamp-dx/trunk/lib/JCAMP/DX.pm $
6             #------------------------------------------------------------------------------
7             #*
8             # Parser for JCAMP-DX format.
9             #**
10              
11             package JCAMP::DX;
12              
13 1     1   8816 use strict;
  1         10  
  1         30  
14 1     1   5 use warnings;
  1         2  
  1         44  
15              
16             our $VERSION = '0.01';
17              
18 1     1   424 use JCAMP::DX::ASDF qw(decode);
  1         3  
  1         1203  
19              
20             our @records_with_variable_lists = qw(
21             PEAKTABLE
22             XYDATA
23             XYPOINTS
24             );
25              
26             sub parse_jcamp_dx
27             {
28 2     2 0 824 my( $filename, $options ) = @_;
29 2         64 open( my $inp, $filename );
30              
31 2         29 my $title = <$inp>;
32 2         16 $title =~ s/^\s*##title=//i;
33 2         7 my $block = read_block( $inp, $options );
34 2         4 $block->{title} = $title;
35              
36 2         33 close $inp;
37 2         19 return $block;
38             }
39              
40             sub read_block
41             {
42 5     5 0 10 my( $inp, $options ) = @_;
43 5         36 my $block = {};
44 5         24 while( (my $line = <$inp>) !~ /^\s*##END=/ ) {
45 32         65 $line =~ s/\$\$.*$//; # removing comments
46 32         101 $line =~ s/\n$//; # removing newlines
47 32 100       115 next if $line =~ /^\s*$/;
48 28 100       111 if( $line =~ s/^\s*##title=//i ) {
    100          
    50          
49 3         10 my $inner_block = read_block( $inp, $options );
50 3         7 $inner_block->{title} = $line;
51 3         4 push @{$block->{blocks}}, $inner_block;
  3         11  
52             } elsif( $line =~ /^\s*##([^=]+)=(.*)$/ ) {
53 23         65 my( $label, $data_set ) = ( $1, $2 );
54 23         38 $label = canonicalise_label( $label );
55 23         32 push @{$block->{labels}}, $label;
  23         47  
56 23         28 push @{$block->{data}{$label}}, $data_set;
  23         114  
57             } elsif( $block->{labels} ) {
58 2         5 my $last_label = $block->{labels}[-1];
59 2         11 $block->{data}{$last_label}[0] .= "\n$line";
60             }
61             }
62              
63             # Converting records with variable lists
64 5         12 for (@records_with_variable_lists) {
65 15 100       29 next if !exists $block->{data}{$_};
66 1         15 $block->{data}{$_} = parse_AFFN_or_ASDF( $_, $block->{data}{$_}[0] );
67             }
68              
69 5         10 return $block;
70             }
71              
72             sub parse_AFFN_or_ASDF
73             {
74 1     1 0 4 my( $label, $record ) = @_;
75              
76 1         3 my $record_now = {};
77              
78             # Process variable list, if such exists:
79 1 50       2 if( grep { $_ eq $label } @records_with_variable_lists ) {
  3         10  
80 1         6 $record =~ s/^\s*(\S+)\s*\n//s;
81 1         4 $record_now->{variable_list} = $1;
82             }
83              
84 1         5 my @lines = split /\n/, $record;
85 1 50 33     10 if( $record_now->{variable_list} &&
86             $record_now->{variable_list} =~ /^\((.)\+\+\((.)\.\.\2\)\)$/ ) {
87             # (X++(Y..Y)) form
88 1         5 my @variables = ( $1, $2 );
89              
90             my @checkpoints =
91 1         2 map { s/^\s*([+-]?\d*\.?\d+([+-]?E\d*)?)//; $1 } @lines;
  2         9  
  2         6  
92             my @lines =
93 1         2 map { s/^\s+//; s/\s+$//; [ decode( $_ ) ] } @lines;
  2         7  
  2         9  
  2         7  
94 1         2 my $diff;
95 1         4 for my $i (0..$#checkpoints) {
96 2 100       5 if( $i < $#checkpoints ) {
97 1         5 $diff = ($checkpoints[$i+1] - $checkpoints[$i]) / @{$lines[$i]};
  1         3  
98             }
99 2         12 push @{$record_now->{$variables[0]}},
100 2         4 map { $checkpoints[$i] + $_ * $diff } 0..$#{$lines[$i]};
  18         34  
  2         7  
101 2         5 push @{$record_now->{$variables[1]}}, @{$lines[$i]};
  2         4  
  2         8  
102             }
103             }
104              
105 1         4 return $record_now;
106             }
107              
108             sub canonicalise_label
109             {
110 23     23 0 45 my( $label ) = @_;
111 23         40 $label = uc $label;
112 23         57 $label =~ s/[\s\-\/\\_]//g;
113 23         46 return $label;
114             }
115              
116             1;