File Coverage

lib/OODoc/Text/Subroutine.pm
Criterion Covered Total %
statement 15 131 11.4
branch 0 80 0.0
condition n/a
subroutine 5 20 25.0
pod 13 14 92.8
total 33 245 13.4


line stmt bran cond sub pod time code
1             # This code is part of Perl distribution OODoc version 3.05.
2             # The POD got stripped from this file by OODoc version 3.05.
3             # For contributors see file ChangeLog.
4              
5             # This software is copyright (c) 2003-2025 by Mark Overmeer.
6              
7             # This is free software; you can redistribute it and/or modify it under
8             # the same terms as the Perl 5 programming language system itself.
9             # SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later
10              
11              
12             package OODoc::Text::Subroutine;{
13             our $VERSION = '3.05';
14             }
15              
16 1     1   1437 use parent 'OODoc::Text';
  1         2  
  1         8  
17              
18 1     1   84 use strict;
  1         3  
  1         28  
19 1     1   4 use warnings;
  1         17  
  1         67  
20              
21 1     1   6 use Log::Report 'oodoc';
  1         3  
  1         8  
22 1     1   371 use Scalar::Util qw/blessed/;
  1         3  
  1         2521  
23              
24             #--------------------
25              
26             sub init($)
27 0     0 0   { my ($self, $args) = @_;
28              
29 0 0         exists $args->{name} or panic;
30 0 0         $self->SUPER::init($args) or return;
31              
32 0           $self->{OTS_param} = delete $args->{parameters};
33 0           $self->{OTS_options} = {};
34 0           $self->{OTS_defaults} = {};
35 0           $self->{OTS_diags} = [];
36 0           $self;
37             }
38              
39             sub _call($)
40 0     0     { my ($self, $exporter) = @_;
41 0           my $type = $self->type;
42 0           my $unique = $self->unique;
43 0           my $style = $exporter->markupStyle;
44              
45 0           my $name = $exporter->markupString($self->name);
46 0           my $paramlist = $exporter->markupString($self->parameters);
47              
48             ### Also implemented in the formatters...
49              
50 0 0         if($style eq 'html')
51 0           { my $call = qq[$name];
52 0 0         $type eq 'tie'
53             and return qq[tie $call, $paramlist];
54              
55 0 0         $call .= "( $paramlist )" if length $paramlist;
56              
57             return
58 0 0         $type eq 'i_method' ? qq[\$obj->$call]
    0          
    0          
    0          
    0          
59             : $type eq 'c_method' ? qq[\$class->$call]
60             : $type eq 'ci_method'? qq[\$any->$call]
61             : $type eq 'overload' ? qq[overload: $call]
62             : $type eq 'function' ? qq[$call]
63             : panic "Type $type? for $call";
64             }
65              
66 0 0         if($style eq 'pod')
67 0 0         { $type eq 'tie'
68             and return qq[tie B<$name>, $paramlist];
69              
70 0 0         my $params = !length $paramlist ? '()' :
    0          
71             $paramlist =~ m/^[\[<]|[\]>]$/ ? "( $paramlist )" : "($paramlist)";
72              
73             return
74 0 0         $type eq 'i_method' ? qq[\$obj-EB<$name>$params]
    0          
    0          
    0          
    0          
75             : $type eq 'c_method' ? qq[\$class-EB<$name>$params]
76             : $type eq 'ci_method'? qq[\$any-EB<$name>$params]
77             : $type eq 'function' ? qq[B<$name>$params]
78             : $type eq 'overload' ? qq[overload: B<$name>]
79             : panic $type;
80             }
81              
82 0           panic $style;
83             }
84              
85             sub publish($)
86 0     0 1   { my ($self, $args) = @_;
87 0 0         my $exporter = $args->{exporter} or panic;
88              
89 0           my $p = $self->SUPER::publish($args);
90 0           $p->{call} = $self->_call($exporter);
91              
92 0           my $opts = $self->collectedOptions; # = [ [ $option, $default ], ... ]
93 0 0         if(keys %$opts)
94             { my @options = map +[ map $_->publish($args)->{id}, @$_ ],
95 0           sort { $a->[0]->name cmp $b->[0]->name }
  0            
96             values %$opts;
97              
98 0           $p->{options}= \@options;
99             }
100              
101 0           my @d = map $_->publish($args)->{id}, $self->diagnostics;
102 0 0         $p->{diagnostics} = \@d if @d;
103 0           $p;
104             }
105              
106              
107              
108             sub extends($)
109 0     0 1   { my $self = shift;
110 0 0         @_ or return $self->SUPER::extends;
111              
112 0           my $super = shift;
113 0 0         if($self->type ne $super->type)
114 0           { my ($fn1, $ln1) = $self->where;
115 0           my ($fn2, $ln2) = $super->where;
116 0           my ($t1, $t2 ) = ($self->type, $super->type);
117              
118 0           warning __x"subroutine {name}() extended by different type:\n {type1} in {file1} line {line1}\n {type2} in {file2} line {line2}",
119             name => "$self",
120             type1 => $t1, file1 => $fn1, line1 => $ln1,
121             type2 => $t2, file2 => $fn2, line2 => $ln2;
122             }
123              
124 0           $self->SUPER::extends($super);
125             }
126              
127             #--------------------
128              
129 0     0 1   sub parameters() { $_[0]->{OTS_param} }
130              
131              
132              
133             sub location($)
134 0     0 1   { my ($self, $manual) = @_;
135 0           my $container = $self->container;
136 0 0         my $super = $self->extends
137             or return $container;
138              
139 0           my $superloc = $super->location;
140 0           my $superpath = $superloc->path;
141 0           my $mypath = $container->path;
142              
143 0 0         return $container if $superpath eq $mypath;
144              
145 0 0         if(length $superpath < length $mypath)
    0          
146 0 0         { return $container
147             if substr($mypath, 0, length($superpath)+1) eq "$superpath/";
148             }
149             elsif(substr($superpath, 0, length($mypath)+1) eq "$mypath/")
150 0 0         { return $self->manual->chapter($superloc->name)
151             if $superloc->isa("OODoc::Text::Chapter");
152              
153 0           my $chapter = $self->manual->chapter($superloc->chapter->name);
154              
155 0 0         return $chapter->section($superloc->name)
156             if $superloc->isa("OODoc::Text::Section");
157              
158 0           my $section = $chapter->section($superloc->section->name);
159              
160 0 0         return $section->subsection($superloc->name)
161             if $superloc->isa("OODoc::Text::SubSection");
162              
163 0           my $subsection = $section->subsection($superloc->subsection->name);
164              
165 0 0         return $subsection->subsubsection($superloc->name)
166             if $superloc->isa("OODoc::Text::SubSubSection");
167              
168 0           panic $superloc;
169             }
170              
171 0 0         unless($manual->inherited($self))
172 0           { my ($myfn, $myln) = $self->where;
173 0           my ($superfn, $superln) = $super->where;
174              
175 0           warning __x"subroutine {name}() location conflict:\n {path1} in {file1} line {line1}\n {path2} in {file2} line {line2}",
176             name => "$self",
177             path1 => $mypath, file1 => $myfn, line1 => $myln,
178             path2 => $superpath, file2 => $superfn, line2 => $superln;
179             }
180              
181 0           $container;
182             }
183              
184              
185 0     0 1   sub path() { $_[0]->container->path }
186              
187             #--------------------
188              
189             sub default($)
190 0     0 1   { my ($self, $it) = @_;
191             blessed $it
192 0 0         or return $self->{OTS_defaults}{$it};
193              
194 0           my $name = $it->name;
195 0           $self->{OTS_defaults}{$name} = $it;
196 0           $it;
197             }
198              
199              
200 0     0 1   sub defaults() { values %{ $_[0]->{OTS_defaults}} }
  0            
201              
202              
203             sub option($)
204 0     0 1   { my ($self, $it) = @_;
205             blessed $it
206 0 0         or return $self->{OTS_options}{$it};
207              
208 0           my $name = $it->name;
209 0           $self->{OTS_options}{$name} = $it;
210 0           $it;
211             }
212              
213              
214             sub findOption($)
215 0     0 1   { my ($self, $name) = @_;
216 0           my $option = $self->option($name);
217 0 0         return $option if $option;
218              
219 0 0         my $extends = $self->extends or return;
220 0           $extends->findOption($name);
221             }
222              
223              
224 0     0 1   sub options() { values %{ $_[0]->{OTS_options}} }
  0            
225              
226              
227             sub diagnostic($)
228 0     0 1   { my ($self, $diag) = @_;
229 0           push @{$self->{OTS_diags}}, $diag;
  0            
230 0           $diag;
231             }
232              
233              
234 0     0 1   sub diagnostics() { @{ $_[0]->{OTS_diags}} }
  0            
235              
236              
237             sub collectedOptions(@)
238 0     0 1   { my ($self, %args) = @_;
239 0           my @extends = $self->extends;
240 0           my %options;
241 0           foreach my $base ($self->extends)
242 0           { my $options = $base->collectedOptions(%args);
243 0           @options{keys %$options} = values %$options;
244             }
245              
246 0           $options{$_->name}[0] = $_ for $self->options;
247              
248 0           foreach my $default ($self->defaults)
249 0           { my $name = $default->name;
250              
251 0 0         unless(exists $options{$name})
252 0           { my ($fn, $ln) = $default->where;
253 0           warning __x"no option {name} for default in {file} line {linenr}", name => $name, file => $fn, linenr => $ln;
254 0           next;
255             }
256 0           $options{$name}[1] = $default;
257             }
258              
259 0           foreach my $option ($self->options)
260 0           { my $name = $option->name;
261 0 0         next if defined $options{$name}[1];
262              
263 0           my ($fn, $ln) = $option->where;
264 0           warning __x"no default for option {name} defined in {file} line {linenr}", name => $name, file => $fn, linenr => $ln;
265              
266 0           my $default = $options{$name}[1] =
267             OODoc::Text::Default->new(name => $name, value => 'undef', subroutine => $self, linenr => $ln);
268              
269 0           $self->default($default);
270             }
271              
272 0           \%options;
273             }
274              
275             1;