File Coverage

blib/lib/Pod/Weaver/Plugin/Module/Features.pm
Criterion Covered Total %
statement 11 112 9.8
branch 0 38 0.0
condition 0 7 0.0
subroutine 4 7 57.1
pod 0 1 0.0
total 15 165 9.0


line stmt bran cond sub pod time code
1             package Pod::Weaver::Plugin::Module::Features;
2              
3 1     1   322247 use 5.010001;
  1         3  
4 1     1   654 use Moose;
  1         633898  
  1         9  
5             with 'Pod::Weaver::Role::AddTextToSection';
6             with 'Pod::Weaver::Role::Section';
7              
8             #has include_module => (is=>'rw');
9             #has exclude_module => (is=>'rw');
10              
11 1     1   11610 use Data::Dmp;
  1         3164  
  1         356  
12              
13             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
14             our $DATE = '2023-11-11'; # DATE
15             our $DIST = 'Pod-Weaver-Plugin-Module-Features'; # DIST
16             our $VERSION = '0.003'; # VERSION
17              
18             sub _md2pod {
19 0     0     require Markdown::To::POD;
20              
21 0           my ($self, $md) = @_;
22 0           my $pod = Markdown::To::POD::markdown_to_pod($md);
23             # make sure we add a couple of blank lines in the end
24 0           $pod =~ s/\s+\z//s;
25 0           $pod . "\n\n\n";
26             }
27              
28             sub _process_module {
29 1     1   10 no strict 'refs'; ## no critic: TestingAndDebugging::ProhibitNoStrict
  1         2  
  1         1875  
30              
31 0     0     my ($self, $document, $input, $package) = @_;
32              
33 0           my $filename = $input->{filename};
34              
35             LOAD_MODULE:
36             {
37             # XXX handle dynamically generated module (if there is such thing in the
38             # future)
39 0           local @INC = ("lib", @INC);
  0            
40 0           my $package_pm = $package;
41 0           $package_pm =~ s!::!/!g;
42 0           $package_pm .= ".pm";
43 0           require $package_pm;
44             }
45              
46             RENDER_FEATURE_SET_SPEC:
47             {
48 0 0         last unless $package =~ /^Module::Features::/;
  0            
49              
50 0           require Data::Sah::Util::Type;
51              
52 0           my $feature_set_spec = \%{"$package\::FEATURES_DEF"};
  0            
53 0 0         last unless keys %$feature_set_spec;
54              
55             # add Defined Features section
56             {
57 0           my @fnames = sort keys %{ $feature_set_spec->{features} };
  0            
58 0 0         last unless @fnames;
59 0           my @pod;
60 0           push @pod, "Features defined by this module:\n\n";
61 0           push @pod, "=over\n\n";
62 0           for my $fname (@fnames) {
63 0           my $fspec = $feature_set_spec->{features}{$fname};
64 0           push @pod, "=item * $fname\n\n";
65 0           my $req = $fspec->{req};
66 0 0         push @pod, $req ? "Required. " : "Optional. ";
67 0   0       my $type = Data::Sah::Util::Type::get_type($fspec->{schema} // 'bool');
68 0           push @pod, "Type: $type. ";
69 0 0         push @pod, "$fspec->{summary}. " if $fspec->{summary};
70 0 0         if ($fspec->{description}) {
71 0           push @pod, $self->_md2pod($fspec->{description});
72             } else {
73 0           push @pod, "\n\n";
74             }
75             }
76 0           push @pod, "=back\n\n";
77              
78 0           push @pod, "For more details on module features, see L<Module::Features>.\n\n";
79              
80 0           $self->add_text_to_section(
81             $document, join("", @pod), 'DEFINED FEATURES',
82             {
83             after_section => ['VERSION', 'NAME'],
84             before_section => 'DESCRIPTION',
85             ignore => 1,
86             });
87             } # Defined Features section
88              
89             # add Description section
90             {
91 0           my @pod;
  0            
  0            
92 0 0         push @pod, $self->_md2pod($feature_set_spec->{description}) if $feature_set_spec->{description};
93              
94 0           $self->add_text_to_section(
95             $document, join("", @pod), 'DESCRIPTION',
96             {
97             after_section => ['SYNOPSIS'],
98             ignore => 1,
99             });
100             } # Description section
101             } # RENDER_FEATURE_SET_SPEC
102              
103             RENDER_FEATURES_DECL:
104             {
105 0           require Data::Dmp;
  0            
106 0           require Data::Sah::Util::Type;
107 0           require Module::FeaturesUtil::Get;
108 0           require String::PodQuote;
109              
110 0           my $features_decl = Module::FeaturesUtil::Get::get_features_decl($package, 'load');
111 0           my $source = delete $features_decl->{'x.source'};
112 0 0 0       last unless $source && (keys %$features_decl);
113              
114 0           $source =~ s/^pm://;
115              
116             # add Declared Features section
117             {
118 0           my @fsetnames = sort keys %{ $features_decl->{features} };
  0            
  0            
119 0 0         last unless @fsetnames;
120 0           my @pod;
121 0           push @pod, "Features declared by this module";
122 0 0         push @pod, " (actually declared in L<$source>)" if $source ne $package;
123 0 0         push @pod, " (actually declared for L<$1>)" if $package =~ /^(.+)::_ModuleFeatures$/;
124 0           push @pod, ":\n\n";
125 0           for my $fsetname (@fsetnames) {
126 0           push @pod, "=head2 From feature set $fsetname\n\n";
127 0           push @pod, "Features from feature set L<$fsetname|Module::Features::$fsetname> declared by this module:\n\n";
128              
129 0           my $feature_set_spec = Module::FeaturesUtil::Get::get_feature_set_spec($fsetname, 'load');
130 0           my $set_features = $features_decl->{features}{$fsetname};
131 0           my @fnames = sort keys %$set_features;
132 0           push @pod, "=over\n\n";
133 0           for my $fname (@fnames) {
134 0           my $fspec = $feature_set_spec->{features}{$fname};
135 0           push @pod, "=item * $fname\n\n";
136 0 0         if (defined $fspec->{summary}) {
137 0           require String::PodQuote;
138 0           push @pod, String::PodQuote::pod_quote($fspec->{summary}), ".\n\n";
139             }
140 0 0         if ($fspec->{description}) {
141 0           require Markdown::To::POD;
142 0           push @pod, _md2pod($fspec->{description});
143             }
144 0   0       my $type = Data::Sah::Util::Type::get_type($fspec->{schema} // 'bool');
145 0           my $fdefhash = Module::FeaturesUtil::Get::get_feature_defhash($package, $fsetname, $fname);
146 0           my $fval;
147 0 0         if (!defined($fdefhash->{value})) {
    0          
148 0           $fval = "N/A (not defined)";
149             } elsif ($type eq 'bool') {
150 0 0         $fval = $fdefhash->{value} ? "yes" : "no";
151             } else {
152 0           $fval = Data::Dmp::dmp($fdefhash->{value});
153             }
154 0           push @pod, "Value: ".String::PodQuote::pod_escape($fval).".\n\n";
155 0 0         if ($fdefhash->{summary}) { push @pod, $self->_md2pod($fdefhash->{summary} . ".") }
  0            
156 0 0         if ($fdefhash->{description}) { push @pod, $self->_md2pod($fdefhash->{description}) }
  0            
157             } # for fname
158 0           push @pod, "=back\n\n";
159             } # for fsetname
160 0           push @pod, "For more details on module features, see L<Module::Features>.\n\n";
161              
162 0           $self->add_text_to_section(
163             $document, join("", @pod), 'DECLARED FEATURES',
164             {
165             after_section => ['VERSION', 'NAME'],
166             before_section => 'DESCRIPTION',
167             ignore => 1,
168             });
169             } # Declared Features section
170             } # RENDER_FEATURES_DECL
171              
172 0           $self->log(["Generated POD for '%s'", $filename]);
173             }
174              
175             sub weave_section {
176 0     0 0   my ($self, $document, $input) = @_;
177              
178 0           my $filename = $input->{filename};
179              
180 0           my $package;
181 0 0         if ($filename =~ m!(?:lib/)?(.+)\.pm$!) {
182 0           $package = $1;
183 0           $package =~ s!/!::!g;
184             #if ($self->include_module && @{ $self->include_module }) {
185             # return unless grep {$_ eq $package} @{ $self->include_module };
186             #}
187             #if ($self->exclude_module && @{ $self->exclude_module }) {
188             # return if grep {$_ eq $package} @{ $self->exclude_module };
189             #}
190 0           $self->_process_module($document, $input, $package);
191             }
192             }
193              
194             1;
195             # ABSTRACT: Plugin to use when building distribution that has feature definer or featurer declarer modules
196              
197             __END__
198              
199             =pod
200              
201             =encoding UTF-8
202              
203             =head1 NAME
204              
205             Pod::Weaver::Plugin::Module::Features - Plugin to use when building distribution that has feature definer or featurer declarer modules
206              
207             =head1 VERSION
208              
209             This document describes version 0.003 of Pod::Weaver::Plugin::Module::Features (from Perl distribution Pod-Weaver-Plugin-Module-Features), released on 2023-11-11.
210              
211             =head1 SYNOPSIS
212              
213             In your F<weaver.ini>:
214              
215             [-Module::Features]
216              
217             =head1 DESCRIPTION
218              
219             This plugin is to be used when building distribution that has feature definer or
220             featurer declarer modules. For more details on module features, see
221             L<Module::Features>. Currently it does the following:
222              
223             For feature defined modules (C<Module::Features::*> modules):
224              
225             =over
226              
227             =item * Add a description in the feature definer's Description section
228              
229             =item * Add a Defined Features section
230              
231             =back
232              
233             For feature defined modules:
234              
235             =over
236              
237             =item * Add a Declared Features section for a feature declarer module
238              
239             =back
240              
241             =for Pod::Coverage .*
242              
243             =head1 CONFIGURATION
244              
245             =head1 HOMEPAGE
246              
247             Please visit the project's homepage at L<https://metacpan.org/release/Pod-Weaver-Plugin-Module-Features>.
248              
249             =head1 SOURCE
250              
251             Source repository is at L<https://github.com/perlancar/perl-Pod-Weaver-Plugin-Module-Features>.
252              
253             =head1 SEE ALSO
254              
255             L<Module::Features>
256              
257             L<Dist::Zilla::Plugin::Module::Features>
258              
259             =head1 AUTHOR
260              
261             perlancar <perlancar@cpan.org>
262              
263             =head1 CONTRIBUTING
264              
265              
266             To contribute, you can send patches by email/via RT, or send pull requests on
267             GitHub.
268              
269             Most of the time, you don't need to build the distribution yourself. You can
270             simply modify the code, then test via:
271              
272             % prove -l
273              
274             If you want to build the distribution (e.g. to try to install it locally on your
275             system), you can install L<Dist::Zilla>,
276             L<Dist::Zilla::PluginBundle::Author::PERLANCAR>,
277             L<Pod::Weaver::PluginBundle::Author::PERLANCAR>, and sometimes one or two other
278             Dist::Zilla- and/or Pod::Weaver plugins. Any additional steps required beyond
279             that are considered a bug and can be reported to me.
280              
281             =head1 COPYRIGHT AND LICENSE
282              
283             This software is copyright (c) 2023, 2021 by perlancar <perlancar@cpan.org>.
284              
285             This is free software; you can redistribute it and/or modify it under
286             the same terms as the Perl 5 programming language system itself.
287              
288             =head1 BUGS
289              
290             Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Pod-Weaver-Plugin-Module-Features>
291              
292             When submitting a bug or request, please include a test-file or a
293             patch to an existing test-file that illustrates the bug or desired
294             feature.
295              
296             =cut