4 # To construct an option you inly need to suply an array of
5 # strings containg the record block. _read_option then parses
7 $this -> _read_options
;
8 delete $this -> {'record_arr'};
17 # record::option_count returns the number of options of the
21 if( defined $self -> {'options'} )
22 $return_value += @
{$self -> {'options'}};
32 my @options = @
{$self -> {'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;
49 # Create a new option. $option_string should be of the form
50 # "option=value". TODO catch any error from below.
52 model
::problem
::record
::option
-> new
( option_string
=> $option_string );
53 push( @
{$self -> {'options'}}, $opt_obj ) if( $opt_obj );
63 # record::_read_options
66 # This is a tricky method that parses options. The basic parsing
67 # is real easy, it loops over the records strings, for each
68 # string it looks for options of the form "option=value" or
69 # "option", those substrings are then used to creat options. But
70 # while the parser does this it keeps count of the number of
71 # options it has parsed, and pushes it on the "print_order"
72 # array (which has a bit missleading name) when it finds a
73 # comment. This is then used to remember where comments appear
74 # in the NONMEM modelfile. Unfortunataly this only holds for
75 # ordinary records, code records are cut verbatim from the
76 # modelfile, so they will also have their comments in place, but
77 # init records will loose any comments associated with them.
79 # TODO This is a hack, I admit, a nicer way would be to store
80 # comments with the option it was found near and defer
81 # formatting to the option class.
86 # Loop over all given strings.
87 for( my $i = 0; $i <= $#{$self -> {'record_arr'}}; $i++ ) {
88 # Store it in $_ for all string matching to look nice
89 $_ = $self -> {'record_arr'} -> [$i];
92 # This is a comment on a line of its own.
94 push(@
{$self -> {'comment'}}, $1 . "\n");
96 push(@
{$self -> {'comment'}},"\n" . $1 . "\n");
98 # Record after which option the comment appeared.
99 push( @
{$self -> {'print_order'}}, $order );
103 # remove spaces near '=' and ','
104 s/\s*([\=\,])\s*/$1/g;
105 # remove spaces near paranthesis
109 # Find trailing comments.
112 # We find comments here, but we add it to 'the comment'
113 # member after we have parsed all options. Only so we can
114 # now how many options we found.
116 $comment = ' ' . $1 . "\n";
117 # Get rid of trailing comments
123 $self -> _add_option
( option_string
=> $_ );
126 if( length( $comment ) > 0 ) {
127 # This is a comment at the end of a line.
128 push( @
{$self -> {'comment'}},' ' . $1 . "\n" );
129 push( @
{$self -> {'print_order'}}, $order );
142 # record::format_record
145 # This method might be even more trickier than _read_options,
146 # but don't worry, I'll walk you through it. You should read
147 # the comments in _read_options first though, it might help.
149 # Get the recordname from the class name.
150 my @class_names = split('::',ref($self));
151 my $fname = uc(pop(@class_names));
153 # Get some members from the object.
154 my @print_order = defined $self -> {'print_order'} ? @
{$self -> {'print_order'}} : ();
155 my @comments = defined($self -> {'comment'}) ? @
{$self -> {'comment'}} : () ;
156 my @options = defined($self -> {'options'}) ? @
{$self -> {'options'}} : ();
158 # Each element of @print_order is a number which says how many
159 # options(since the previous comment was printed) that should
160 # be processed before the next comment should be
161 # printed. There will be one element in print order for each
162 # comment. So here we intialize $opts_before_comment which is
163 # the current number of options we should process. If
164 # $opts_before_comment is -1 no more comments will be expected
167 my $opts_before_comment = scalar @print_order > 0 ?
shift @print_order : -1;
169 # $last_is_option is a boolean which is true if we printed a
170 # option in the last iteration of the loop below and false if
171 # we printed a comment. It is used to see if we need to print
172 # an extra "\n" since comments is expected to have their own
173 # "\n" while options don't
175 my $last_is_option = 1;
178 # Loop over all options. Actually we loop one step to long,
179 # since we might have comments after the last option.
180 for( my $i = 0; $i <= scalar @options; $i++ ){
182 # See if we have processed enough options to print
183 # commments. It is a loop since we might have multiple lines
185 while( $i == $opts_before_comment ){
186 my $comment = shift(@comments);
187 # Check and add a linebreak if necessarry.
188 if ( length( $formatted[$line].' '.$comment ) > 70 ) {
189 $formatted[$line] .= "\n";
193 $formatted[$line++] .= $comment;
195 # If we expect more options ($i <= $#options) and we have
196 # printed the recordname ($i > 0) we indent before
197 # printing the next option.
198 if( $i <= $#options and $i > 0 ){
199 $formatted[$line] .= ' ' x
11;
202 if( scalar @print_order > 0 ) {
203 $opts_before_comment = shift @print_order;
205 unless( scalar @comments > 0 ){
207 # If we have more comments, it likely mean that
208 # someone has appended comments manually. TODO This
209 # might become a mess and we should probably add a
210 # feature to add commments before or after the record.
212 $opts_before_comment = -1;
219 # Print the record name (with indentation)
221 push( @formatted , "\$".$fname . ' ' x
(10 - length($fname)) );
224 # Check that we have not processed all options.
225 if( $i <= $#options ){
226 my $option = $options[$i];
227 # Let the option class format the option.
228 my $foption = $option -> _format_option
;
230 # Check and add linebreak if necesary.
231 if ( length( $formatted[$line].' '.$foption ) > 70 ) {
232 $formatted[$line] .= "\n";
234 # Indent for next option
235 push( @formatted, ' ' x
11 );
238 $formatted[$line] .= ' '.$foption;
243 # Print a line break if the last item was an option (as oposed
245 if( $last_is_option ){
246 $formatted[$line] .= "\n";