File Coverage

blib/lib/App/Fetchware/CreateConfigOptions.pm
Criterion Covered Total %
statement 52 52 100.0
branch 9 12 75.0
condition n/a
subroutine 13 13 100.0
pod n/a
total 74 77 96.1


line stmt bran cond sub pod time code
1             package App::Fetchware::CreateConfigOptions;
2             our $VERSION = '1.016'; # VERSION: generated by DZP::OurPkgVersion
3             # ABSTRACT: Used by fetchware extensions to create their configuration options.
4 3     3   708 use strict;
  3         3  
  3         65  
5 3     3   9 use warnings;
  3         3  
  3         60  
6              
7             # CPAN modules making Fetchwarefile better.
8 3     3   8 use Sub::Mage;
  3         3  
  3         13  
9              
10             # App::Fetchware::CreateConfigOptions uses _make_config_sub() from
11             # App::Fetchware, so I must use() it, so I can use it.
12 3     3   2771 use App::Fetchware;
  3         6  
  3         426  
13              
14             # Enable Perl 6 knockoffs, and use 5.10.1, because smartmatching and other
15             # things in 5.10 were changed in 5.10.1+.
16 3     3   51 use 5.010001;
  3         6  
17              
18             # Don't use Exporter's import; instead, provide your own. This is all ExportAPI
19             # does. Provide an import() method, so that it can set up correct exports, and
20             # ensure that your fetchware extension implementes all of fetchware's API
21             # subroutines at compile time.
22              
23              
24              
25             sub import {
26 14     14   2462 my ($class, @opts) = @_;
27              
28             # Just return success if user specified no options, because that just means
29             # the user wanted to load the module, but not actually import() anything.
30 14 100       40 return 'Success' if @opts == 0;
31              
32 13         18 my $caller = caller;
33              
34             # Forward call to _create_config_options(), which does all the work.
35             # Note how the caller of import() is forwarded on to
36             # _create_config_options().
37 13         19 _create_config_options($caller, @opts);
38             }
39              
40              
41              
42             # Make _export_api() "invisible." users should only ever actually use import(),
43             # and technically they should never even use import; instead, they should just
44             # use ExportAPI, and Perl will call import() for them.
45             #=head2 _create_config_options()
46             #
47             # # _create_config_options() *must* be called in a BEGIN block, because it
48             # # creates subroutines that have prototypes, and prototypes *must* be known
49             # # about at compile time not run time!
50             # BEGIN {
51             # _create_config_options(
52             # $callers_package,
53             # ONE => [qw(
54             # page_name
55             # html_page_url
56             # user_agent
57             # html_treebuilder_callback
58             # download_links_callback
59             # )],
60             # BOOLEAN => [qw(
61             # keep_destination_directory
62             # )],
63             # IMPORT => [qw(
64             # temp_dir
65             # )],
66             # );
67             # }
68             #
69             #Creates configuration options of the same types App::Fetchware uses. These
70             #are:
71             #
72             #=over
73             #
74             #=item 1. ONE - Stores one and only ever one value. If the configuration option
75             #is used more than once, an exception is thrown.
76             #
77             #=item 2. ONEARRREF - Stores one or more values. But only stores a list when
78             #provided a list when you call it such as
79             #C would create a
80             #configuration option with three values. However, if a ONEARRREF is called more
81             #than once, and exception is also thrown.
82             #
83             #=item 3. MANY - Stores many values one at a time just like ONEARRREF, but can
84             #also be called any number of times, and values are appended to any already
85             #existing ones.
86             #
87             #=item 4. BOOLEAN - Stores true or false values such as C or
88             #C or C
89             #
90             #=back
91             #
92             #In addition to App::Fetchware's types, _create_config_options() features an
93             #additional type:
94             #
95             #=over
96             #
97             #=item 5. IMPORT - This option is documented only for completness, because it is
98             #recommended that you use L, and any
99             #App::Fetchware API subroutines that you C<'KEEP'>
100             #L will automatically call
101             #_create_config_options() for you to import any fetchware API subroutines that
102             #you want your fetchware extension to reuse. See L for
103             #details. You can specify the C option,
104             #C<_create_config_options(..., NOIMPORT =E 1);>, to avoid the automatic
105             #importing of App::Fetchware configuration options.
106             #
107             #=back
108             #
109             #Note: you must prepend your options with the $callers_package, which is the
110             #package that you want the specified subroutines to be created in.
111             #
112             #Just use any of C, C, C, or C as faux hash keys
113             #being sure to wrap their arguments in a array reference brackets C<[]>
114             #
115             #_create_config_options() also takes the faux hash key C this hash key
116             #does not create new configuration options, but instead imports already defined
117             #ones from App::Fetchware allowing you to reuse popular configuration options
118             #like C or C in your fetchware extension.
119             #
120             #=over
121             #
122             #=item LIMITATION
123             #
124             #_create_config_options() creates subroutines that have prototypes, but in order
125             #for perl to honor those prototypes perl B know about them at compile-time;
126             #therefore, that is why _create_config_options() must be called inside a C
127             #block.
128             #
129             #=back
130             #
131             #=cut
132              
133             sub _create_config_options {
134 26     26   982 my ($callers_package, %opts) = @_;
135              
136 26         50 for my $value_key (keys %opts) {
137 39         26 for my $sub_name (@{$opts{$value_key}}) {
  39         65  
138              
139             # IMPORT subroutines are not actually "imported." Instead, they are
140             # "made" in the correct package by App::Fetchware's config subroutine
141             # function factory, _make_config_sub().
142 130 100       172 if ($value_key ne 'IMPORT') {
143 76         126 App::Fetchware::_make_config_sub($sub_name, $value_key,
144             $callers_package);
145             } else {
146 54 50       1172 die <
  9756         10151  
147             App-Fetchware-Util: App::Fetchware has not been loaded. How can you import a
148             subroutine from App::Fetchware if you have not yet loaded it yet? Please load
149             App::Fetchware [use App::Fetchware;] and try again.
150             EOD
151 54 50       404 clone($sub_name => (from => 'App::Fetchware', to => $callers_package))
152             or die <
153             App-Fetchware-Util: Failed to clone the specified subroutine [$sub_name] from
154             App::Fetchware into your namespace [$callers_package]. You probably just need to
155             load fetchware [use App::Fetchware;] inside your fetchware extension.
156             EOD
157             }
158              
159             # Be sure to @EXPORT the newly minted subroutine.
160 130         1769 _add_export($sub_name, $callers_package);
161              
162              
163              
164             }
165             }
166             }
167              
168              
169             # Hide it's POD since it's an '_' hidden subroutine I don't want fetchware
170             # extensions to use.
171             #=head2 _add_export()
172             #
173             # _add_export(start => caller);
174             #
175             #Adds the specified subroutine to the specified caller's @EXPORT variable, so
176             #that when the specified package is imported the specified subroutine is imported
177             #as well.
178             #
179             #=cut
180              
181             sub _add_export {
182 179     179   157 my ($sub_to_export, $caller) = @_;
183              
184             {
185 3     3   16 no strict 'refs';
  3         6  
  3         373  
  179         116  
186              
187             # If the $caller has not declared @EXPORT for us, then we'll do it here
188             # ourselves, so you don't need to declare a variable in your fetchware
189             # extension that you never even use yourself.
190             #
191             #The crazy *{...} contraption looks up @$caller::EXPORT up in the stash,
192             #and checks if it's defined in the stash, and if there's a stash entry,
193             #then it has been defined, and if not, then the variable is undeclared,
194             #so then delare it using the crazy eval.
195             #
196             #Also, note that use vars is used in favor of our, because our variables
197             #are bizarrely lexically scoped, which is insane. Why would a global be
198             #lexically scoped it's a global isn't it. But if you think that's
199             #bizarre, check this out, use vars is file scoped. Again, how is a
200             #global file scoped? Perhaps just the variable you declare with our or
201             #use vars is lexical or file scoped, but the stash entry it creates
202             #actually is global???
203 179 100       116 unless (defined *{ $caller . '::EXPORT' }{ARRAY}) {
  179         429  
204 7         8 my $eval = 'use vars @$caller::EXPORT; 1;';
205 7         17 $eval =~ s/\$caller/$caller/;
206 3 50   3   12 eval $eval or die <
  3     2   5  
  3     1   41  
  2     1   9  
  2         2  
  2         23  
  1         5  
  1         1  
  1         11  
  1         5  
  1         2  
  1         11  
  7         357  
207             App-Fetchware-Util: Huh?!? For some reason fetchware failed to create the
208             necessary \@EXPORT variable in the specified caller's package [$caller]. This
209             just shouldn't happen, and is probably an internal bug in fetchware. Perhaps
210             the package specified in [$caller] has not been defined. Exception:
211             [$@]
212             EOD
213             }
214            
215             # export *all* @api_subs.
216 179         169 push @{"${caller}::EXPORT"}, $sub_to_export;
  179         265849  
217             }
218             }
219              
220              
221              
222             1;
223              
224             =pod
225              
226             =head1 NAME
227              
228             App::Fetchware::CreateConfigOptions - Used by fetchware extensions to create their configuration options.
229              
230             =head1 VERSION
231              
232             version 1.016
233              
234             =head1 SYNOPSIS
235              
236             use App::Fetchware::ExportAPI KEEP => [qw(start end)],
237             OVERRIDE =>
238             [qw(lookup download verify unarchive build install uninstall)];
239              
240             =head1 DESCRIPTION
241              
242             App::Fetchware::ExportAPI is a utility helper class for fetchware extensions. It
243             makes it easy to ensure that your fetchware extension implements or imports all
244             of App::Fetchware's required API subroutines.
245              
246             See section L in App::Fetchware's
247             documentation for more information on how to create your very own fetchware
248             extension.
249              
250             =head1 CREATECONFIGOPTIONS'S API METHODS
251              
252             App::Fetchware::CreateConfigOptions (CreateConfigOptions) has only one
253             user-servicable part--it's import() method. It works just like L's
254             import() method except it takes arguments differently, and checks it's arguments
255             more thuroughly.
256              
257             =head2 import()
258              
259             # You don't actually call import() unless you're doing something weird.
260             # Instead, use calls import for you.
261             use App::Fetchware::CreateConfigOptions
262             ONE => [qw(
263             page_name
264             html_page_url
265             user_agent
266             html_treebuilder_callback
267             download_links_callback
268             )],
269             BOOLEAN => [qw(
270             keep_destination_directory
271             )],
272             IMPORT => [qw(
273             temp_dir
274             )],
275             ;
276              
277             Creates configuration options of the same types App::Fetchware uses. These
278             are:
279              
280             =over
281              
282             =item 1. ONE - Stores one and only ever one value. If the configuration option
283             is used more than once, an exception is thrown.
284              
285             =item 2. ONEARRREF - Stores one or more values. But only stores a list when
286             provided a list when you call it such as
287             C would create a
288             configuration option with three values. However, if a ONEARRREF is called more
289             than once, and exception is also thrown.
290              
291             =item 3. MANY - Stores many values one at a time just like ONEARRREF, but can
292             also be called any number of times, and values are appended to any already
293             existing ones.
294              
295             =item 4. BOOLEAN - Stores true or false values such as C or
296             C or C
297              
298             =back
299              
300             In addition to App::Fetchware's types, import() features an
301             additional type:
302              
303             =over
304              
305             =item 5. IMPORT - the C this hash key does not create new configuration
306              
307             options, but instead imports already defined ones from App::Fetchware allowing
308             you to reuse popular configuration options like C or C in
309             your fetchware extension.
310              
311             =back
312              
313             Just use any of C, C, C, or C as faux hash keys
314             being sure to wrap their arguments in array reference brackets C<[]>
315              
316             =over
317              
318             =item LIMITATION
319              
320             import() creates subroutines that have prototypes, but in order
321             for perl to honor those prototypes perl B know about them at compile-time;
322             therefore, that is why import() must be called inside a C
323             block. The best and most obvious way of doing that is use
324             C.
325              
326             =back
327              
328             =head1 ERRORS
329              
330             As with the rest of App::Fetchware, App::Fetchware::ExportAPI does not return
331             any error codes; instead, all errors are die()'d if it's Test::Fetchware's error,
332             or croak()'d if its the caller's fault.
333              
334             =head1 AUTHOR
335              
336             David Yingling
337              
338             =head1 COPYRIGHT AND LICENSE
339              
340             This software is copyright (c) 2016 by David Yingling.
341              
342             This is free software; you can redistribute it and/or modify it under
343             the same terms as the Perl 5 programming language system itself.
344              
345             =cut
346              
347             __END__