File Coverage

blib/lib/Data/Hopen.pm
Criterion Covered Total %
statement 64 64 100.0
branch 24 24 100.0
condition 2 2 100.0
subroutine 18 18 100.0
pod 6 6 100.0
total 114 114 100.0


line stmt bran cond sub pod time code
1             #!perl
2             # lib/Data/Hopen.pm: utility routines for hopen(1). This file is also the
3             # source of the repo's README.md, which is autogenerated from this POD.
4              
5             package Data::Hopen;
6 22     22   131814 use strict;
  22         52  
  22         718  
7 22     22   552 use Data::Hopen::Base;
  22         47  
  22         127  
8              
9 22     22   4838 use parent 'Exporter';
  22         47  
  22         136  
10              
11             # TODO move more of these to a separate utility package?
12             # Probably keep hnew, hlog, $VERBOSE, and $QUIET here.
13             use vars::i {
14 22         196 '@EXPORT' => [qw(hnew hlog getparameters)],
15             '@EXPORT_OK' => [qw(loadfrom *VERBOSE *QUIET UNSPECIFIED NOTHING)],
16 22     22   9707 }; #^ * => can be localized
  22         16844  
17 22         194 use vars::i '%EXPORT_TAGS' => {
18             default => [@EXPORT],
19             v => [qw(*VERBOSE *QUIET)],
20             all => [@EXPORT, @EXPORT_OK],
21 22     22   3070 };
  22         51  
22              
23 22     22   11763 use Data::Hopen::Util::NameSet;
  22         63  
  22         671  
24 22     22   10745 use Getargs::Mixed;
  22         23048  
  22         1250  
25 22     22   16749 use Storable ();
  22         83122  
  22         1333  
26              
27             our $VERSION = '0.000019';
28              
29             # Docs {{{1
30              
31             =head1 NAME
32              
33             Data::Hopen - A dataflow library with first-class edges
34              
35             =head1 SYNOPSIS
36              
37             C is a dataflow library that runs actions you specify, moves data
38             between those actions, and permits transforming data as the data moves. It is
39             the underlying engine of the L cross-platform software build
40             generator, but can be used for any dataflow task that can be represented as a
41             directed acyclic graph (DAG).
42              
43             =head1 INSTALLATION
44              
45             Easiest: install C if you don't have it - see
46             L. Then run
47             C.
48              
49             Manually: clone or untar into a working directory. Then, in that directory,
50              
51             perl Makefile.PL
52             make
53             make test
54              
55             (you may need to install dependencies as well -
56             see L for resources).
57             If all the tests pass,
58              
59             make install
60              
61             If some of the tests fail, please check the issues and file a new one if
62             no one else has reported the problem yet.
63              
64             =head1 VARIABLES
65              
66             Not exported by default, except as noted.
67              
68             =head2 $VERBOSE
69              
70             Set to a positive integer to get debug output on stderr from hopen's internals.
71             The higher the value, the more output you are likely to get. See also L.
72              
73             =head2 $QUIET
74              
75             Set to truthy to suppress output. Quiet overrides L.
76              
77             =cut
78              
79             # }}}1
80              
81 22     22   730 our $VERBOSE; BEGIN { $VERBOSE = 0; }
82 22     22   18347 our $QUIET; BEGIN { $QUIET = false; }
83              
84             =head1 FUNCTIONS
85              
86             All are exported by default unless indicated.
87              
88             =head2 hnew
89              
90             Creates a new Data::Hopen instance. For example:
91              
92             hnew DAG => 'foo';
93              
94             is the same as
95              
96             Data::Hopen::G::DAG->new( name => 'foo' );
97              
98             The first parameter (C<$class>) is an abbreviated package name. It is tried
99             as the following, in order. The first one that succeeds is used.
100              
101             =over
102              
103             =item 1.
104              
105             C. This is tried only if C<$class>
106             does not include a double-colon.
107              
108             =item 2.
109              
110             C
111              
112             =item 3.
113              
114             C<$class>
115              
116             =back
117              
118             The second parameter
119             must be the name of the new instance. All other parameters are passed
120             unchanged to the relevant constructor.
121              
122             =cut
123              
124             sub hnew {
125 36 100   36 1 16792 my $class = shift or croak 'Need a class';
126 35         130 my @stems = ('Data::Hopen::G::', 'Data::Hopen::', '');
127 35 100       212 shift @stems if $class =~ /::/;
128              
129 35         83 my $found_class = false;
130              
131 35         90 foreach my $stem (@stems) {
132 37         2929 eval "require $stem$class";
133 37 100       327 next if $@;
134 34         101 $found_class = "$stem$class";
135 34         462 my $instance = "$found_class"->new('name', @_);
136             # put 'name' in front of the name parameter.
137 34 100       2588 return $instance if $instance;
138             }
139              
140 2 100       54 if($found_class) {
141 1         96 croak "Could not create instance for $found_class";
142             } else {
143 1         242 croak "Could not find class for $class";
144             }
145             } #hnew()
146              
147             =head2 hlog
148              
149             Log information if L is set. Usage:
150              
151             hlog { } [optional min verbosity level (default 1)];
152              
153             The items in the list are joined by C<' '> on output, and a C<'\n'> is added.
154             Each line is prefixed with C<'# '> for the benefit of test runs.
155              
156             The list is in C<{}> so that it won't be evaluated if logging is turned off.
157             It is a full block, so you can run arbitrary code to decide what to log.
158             If the block returns an empty list, hlog will not produce any output.
159             However, if the block returns at least one element, hlog will produce at
160             least a C<'# '>.
161              
162             The message will be output only if L is at least the given minimum
163             verbosity level (1 by default).
164              
165             If C<< $VERBOSE > 2 >>, the filename and line from which hlog was called
166             will also be printed.
167              
168             =cut
169              
170             sub hlog (&;$) {
171 440 100   440 1 20211 return if $QUIET;
172 427 100 100     1592 return unless $VERBOSE >= ($_[1] // 1);
173              
174 321         486 my @log = &{$_[0]}();
  321         680  
175 321 100       12616 return unless @log;
176              
177 320 100       964 chomp $log[$#log] if $log[$#log];
178             # TODO add an option to number the lines of the output
179 320         2489 my $msg = (join(' ', @log)) =~ s/^/# /gmr;
180 320 100       798 if($VERBOSE>2) {
181 314         2131 my ($package, $filename, $line) = caller;
182 314         1082 $msg .= " (at $filename:$line)";
183             }
184 320         30905 say STDERR $msg;
185             } #hlog()
186              
187             =head2 getparameters
188              
189             An alias of the C function from L, but with
190             C<-undef_ok> set.
191              
192             =cut
193              
194             my $GM = Getargs::Mixed->new(-undef_ok => true);
195              
196             sub getparameters {
197 2698     2698 1 6313 unshift @_, $GM;
198 2698         7582 goto &Getargs::Mixed::parameters;
199             } #getparameters()
200              
201             =head2 loadfrom
202              
203             (Not exported by default) Load a package given a list of stems. Usage:
204              
205             my $fullname = loadfrom($name[, @stems]);
206              
207             Returns the full name of the loaded package, or falsy on failure.
208             If C<@stems> is omitted, no stem is used, i.e., C<$name> is tried as-is.
209              
210             =cut
211              
212             sub loadfrom {
213 6 100   6 1 7017 my $class = shift or croak 'Need a class';
214              
215 5         14 foreach my $stem (@_, '') {
216 5     2   30 hlog { loadfrom => "$stem$class" } 3;
  2         8  
217 5         362 eval "require $stem$class";
218 5 100       138 if($@) {
219 2     1   15 hlog { loadfrom => "$stem$class", 'load result was', $@ } 3;
  1         4  
220             } else {
221 3         17 return "$stem$class";
222             }
223             }
224              
225 2         10 return undef;
226             } #loadfrom()
227              
228             =head1 CONSTANTS
229              
230             =head2 UNSPECIFIED
231              
232             A L that matches any non-empty string.
233             Always returns the same reference, so that it can be tested with C<==>.
234              
235             =cut
236              
237             my $_UNSPECIFIED = Data::Hopen::Util::NameSet->new(qr/.(*ACCEPT)/);
238 45     45 1 4932 sub UNSPECIFIED () { $_UNSPECIFIED };
239              
240             =head2 NOTHING
241              
242             A L that never matches. Always returns the
243             same reference, so that it can be tested with C<==>.
244              
245             =cut
246              
247             my $_NOTHING = Data::Hopen::Util::NameSet->new();
248 13     13 1 3928 sub NOTHING () { $_NOTHING };
249              
250             1; # End of Data::Hopen
251             __END__