This is a massive update that merges all changes from PsN_2_2_0_patches_serial. It...
[PsN.git] / lib / model / problem / record_subs.pm
blobe761ba5d82cd2e4f1d176dd5130f5d890b7ee5bf
1 # {{{ new
2 start new
4 # To construct an option you inly need to suply an array of
5 # strings containg the record block. _read_option then parses
6 # those strings.
7 $this -> _read_options;
8 delete $this -> {'record_arr'};
10 end new
11 # }}}
13 # {{{ option_count
15 start option_count
17 # record::option_count returns the number of options of the
18 # record.
20 $return_value = 0;
21 if( defined $self -> {'options'} )
22 $return_value += @{$self -> {'options'}};
24 end option_count
26 # }}}
28 # {{{ remove_option
30 start remove_option
32 my @options = @{$self -> {'options'}};
33 my @new_options = ();
34 foreach my $option ( @options ) {
35 next if ( $option -> name eq $name );
37 next if ( $fuzzy_match and index( $name, $option -> name ) > -1 );
39 push( @new_options, $option );
41 $self -> {'options'} = \@new_options;
43 end remove_option
45 # }}} remove_option
47 # {{{ _add_option
48 start _add_option
50 # Create a new option. $option_string should be of the form
51 # "option=value". TODO catch any error from below.
52 my $opt_obj =
53 model::problem::record::option -> new ( option_string => $option_string );
54 push( @{$self -> {'options'}}, $opt_obj ) if( $opt_obj );
56 end _add_option
57 # }}}
59 # {{{ _read_options
61 start _read_options
64 # record::_read_options
67 # This is a tricky method that parses options. The basic parsing
68 # is real easy, it loops over the records strings, for each
69 # string it looks for options of the form "option=value" or
70 # "option", those substrings are then used to creat options. But
71 # while the parser does this it keeps count of the number of
72 # options it has parsed, and pushes it on the "print_order"
73 # array (which has a bit missleading name) when it finds a
74 # comment. This is then used to remember where comments appear
75 # in the NONMEM modelfile. Unfortunataly this only holds for
76 # ordinary records, code records are cut verbatim from the
77 # modelfile, so they will also have their comments in place, but
78 # init records will loose any comments associated with them.
80 # TODO This is a hack, I admit, a nicer way would be to store
81 # comments with the option it was found near and defer
82 # formatting to the option class.
84 my @row = ();
85 my $order = 0;
87 # Loop over all given strings.
88 for( my $i = 0; $i <= $#{$self -> {'record_arr'}}; $i++ ) {
89 # Store it in $_ for all string matching to look nice
90 $_ = $self -> {'record_arr'} -> [$i];
92 if( /^\s*(\;.*)$/ ) {
93 # This is a comment on a line of its own.
94 if( $order == 0 ){
95 push(@{$self -> {'comment'}}, $1 . "\n");
96 } else {
97 push(@{$self -> {'comment'}},"\n" . $1 . "\n");
99 # Record after which option the comment appeared.
100 push( @{$self -> {'print_order'}}, $order );
101 } else {
102 # Get rid of $RECORD
103 s/^\s*\$\w+//;
104 # remove spaces near '=' and ','
105 s/\s*([\=\,])\s*/$1/g;
106 # remove spaces near paranthesis
107 s/\s*\)/\)/g;
108 s/\(\s*/\(/g;
110 # Find trailing comments.
111 my $comment;
112 if( /(\;.*)$/ ) {
113 # We find comments here, but we add it to 'the comment'
114 # member after we have parsed all options. Only so we can
115 # now how many options we found.
117 $comment = ' ' . $1 . "\n";
118 # Get rid of trailing comments
119 s/\;.*$//g;
121 @row = split;
122 for ( @row ) {
123 # Create options.
124 $self -> _add_option( option_string => $_ );
125 $order++;
127 if( length( $comment ) > 0 ) {
128 # This is a comment at the end of a line.
129 push( @{$self -> {'comment'}},' ' . $1 . "\n" );
130 push( @{$self -> {'print_order'}}, $order );
135 end _read_options
137 # }}}
139 # {{{ _format_record
140 start _format_record
143 # record::format_record
146 # This method might be even more trickier than _read_options,
147 # but don't worry, I'll walk you through it. You should read
148 # the comments in _read_options first though, it might help.
150 # Get the recordname from the class name.
151 my @class_names = split('::',ref($self));
152 my $fname = uc(pop(@class_names));
154 # Get some members from the object.
155 my @print_order = defined $self -> {'print_order'} ? @{$self -> {'print_order'}} : ();
156 my @comments = defined($self -> {'comment'}) ? @{$self -> {'comment'}} : () ;
157 my @options = defined($self -> {'options'}) ? @{$self -> {'options'}} : ();
159 # Each element of @print_order is a number which says how many
160 # options(since the previous comment was printed) that should
161 # be processed before the next comment should be
162 # printed. There will be one element in print order for each
163 # comment. So here we intialize $opts_before_comment which is
164 # the current number of options we should process. If
165 # $opts_before_comment is -1 no more comments will be expected
166 # nor printed.
168 my $opts_before_comment = scalar @print_order > 0 ? shift @print_order : -1;
170 # $last_is_option is a boolean which is true if we printed a
171 # option in the last iteration of the loop below and false if
172 # we printed a comment. It is used to see if we need to print
173 # an extra "\n" since comments is expected to have their own
174 # "\n" while options don't
176 my $last_is_option = 1;
177 my $line = 0;
179 # Loop over all options. Actually we loop one step to long,
180 # since we might have comments after the last option.
181 for( my $i = 0; $i <= scalar @options; $i++ ){
183 # See if we have processed enough options to print
184 # commments. It is a loop since we might have multiple lines
185 # of comments.
186 while( $i == $opts_before_comment ){
187 my $comment = shift(@comments);
188 # Check and add a linebreak if necessarry.
189 if ( length( $formatted[$line].' '.$comment ) > 70 ) {
190 $formatted[$line] .= "\n";
191 $line++;
193 # add the comment
194 $formatted[$line++] .= $comment;
196 # If we expect more options ($i <= $#options) and we have
197 # printed the recordname ($i > 0) we indent before
198 # printing the next option.
199 if( $i <= $#options and $i > 0 ){
200 $formatted[$line] .= ' ' x 11;
203 if( scalar @print_order > 0 ) {
204 $opts_before_comment = shift @print_order;
205 } else {
206 unless( scalar @comments > 0 ){
208 # If we have more comments, it likely mean that
209 # someone has appended comments manually. TODO This
210 # might become a mess and we should probably add a
211 # feature to add commments before or after the record.
213 $opts_before_comment = -1;
217 $last_is_option = 0;
220 # Print the record name (with indentation)
221 if( $i == 0 ){
222 push( @formatted , "\$".$fname . ' ' x (10 - length($fname)) );
225 # Check that we have not processed all options.
226 if( $i <= $#options ){
227 my $option = $options[$i];
228 # Let the option class format the option.
229 my $foption = $option -> _format_option;
231 # Check and add linebreak if necesary.
232 if ( length( $formatted[$line].' '.$foption ) > 70 ) {
233 $formatted[$line] .= "\n";
234 $line++;
235 # Indent for next option
236 push( @formatted, ' ' x 11 );
239 $formatted[$line] .= ' '.$foption;
240 $last_is_option = 1;
244 # Print a line break if the last item was an option (as oposed
245 # to a comment.
246 if( $last_is_option ){
247 $formatted[$line] .= "\n";
250 end _format_record
251 # }}}