File Coverage

blib/lib/Earth.pm
Criterion Covered Total %
statement 70 79 88.6
branch 23 40 57.5
condition 5 12 41.6
subroutine 19 19 100.0
pod 9 10 90.0
total 126 160 78.7


line stmt bran cond sub pod time code
1             package Earth;
2              
3 1     1   1919 use 5.018;
  1         3  
4              
5 1     1   8 use strict;
  1         1  
  1         19  
6 1     1   4 use warnings;
  1         1  
  1         43  
7              
8 1     1   5 use Exporter 'import';
  1         2  
  1         195  
9              
10             our @EXPORT = qw(
11             call
12             can
13             chain
14             false
15             make
16             roll
17             then
18             true
19             wrap
20             );
21              
22             require Scalar::Util;
23              
24             # STASH
25              
26             state $cached = {};
27              
28             # VERSION
29              
30             our $VERSION = '0.02';
31              
32             # AUTHORITY
33              
34             our $AUTHORITY = 'cpan:AWNCORP';
35              
36             # FUNCTIONS
37              
38             sub call {
39 21     21 1 1896 my ($invocant, $routine, @arguments) = @_;
40 21 50       142 if (UNIVERSAL::isa($invocant, 'CODE')) {
41 0         0 return $invocant->(@arguments);
42             }
43 21 50       35 return if !$routine;
44 21 100       41 if (Scalar::Util::blessed($invocant)) {
45 8         60 return $invocant->$routine(@arguments);
46             }
47 13 100       23 if (ref($invocant) eq 'SCALAR') {
48 3         10 return $$invocant->$routine(@arguments);
49             }
50 10         16 my $package = load($invocant);
51 10 50       55 if (my $routine = $package->can($routine)) {
52 10         80 return $routine->(@arguments);
53             }
54 0 0       0 if ($package->can('AUTOLOAD')) {
55 1     1   6 no strict 'refs';
  1         1  
  1         398  
56 0         0 return &{"${package}::${routine}"}(@arguments);
  0         0  
57             }
58 0         0 die("call(@{[join(', ', map qq('$_'), @_)]}) failed");
  0         0  
59             }
60              
61             sub can {
62 1 50   1 1 16 return if !@_;
63 1 50       53 return call((ref($_[0]) ? $_[0] : \$_[0]), 'can', $_[1]);
64             }
65              
66              
67             sub chain {
68 3     3 1 38 my ($invocant, @routines) = @_;
69 3 50       6 return if !$invocant;
70 3 100       16 for my $next (map +(ref($_) eq 'ARRAY' ? $_ : [$_]), @routines) {
71 7         30 $invocant = call($invocant, @$next);
72             }
73 3         27 return $invocant;
74             }
75              
76             sub false {
77 2     2 1 3815 require Scalar::Util;
78 2         19 state $false = Scalar::Util::dualvar(0, "0");
79             }
80              
81             sub load {
82 10     10 0 15 my ($package) = @_;
83              
84 10 100       29 if ($$cached{$package}) {
85 8         127 return $package;
86             }
87              
88 2 50       3 if ($package eq 'main') {
89 0         0 return do {$$cached{$package} = 1; $package};
  0         0  
  0         0  
90             }
91              
92 2   33     22 my $failed = !$package || $package !~ /^\w(?:[\w:']*\w)?$/;
93 2         3 my $loaded;
94              
95 2 50       4 my $error = do {
96 2         2 local $@;
97 1     1   7 no strict 'refs';
  1         1  
  1         237  
98 2         13 $loaded = !!$package->can('new');
99 2 50       9 $loaded = !!$package->can('import') if !$loaded;
100 2 50       123 $loaded = eval "require $package; 1" if !$loaded;
101 2         7 $@;
102             }
103             if !$failed;
104              
105 2 0 33     12 die join " ", "Error attempting to load",
    50 33        
106             ($error ? ("$package: $error") : ($package))
107             if $error
108             or $failed
109             or not $loaded;
110              
111 2         5 $$cached{$package} = 1;
112              
113 2         2 return $package;
114             }
115              
116             sub make {
117 6 50   6 1 13 return if !@_;
118 6         13 return call($_[0], 'new', @_);
119             }
120              
121             sub roll {
122 2     2 1 34 return (@_[1,0,2..$#_]);
123             }
124              
125             sub then {
126 1     1 1 3 return ($_[0], call(@_));
127             }
128              
129             sub true {
130 2     2 1 3900 require Scalar::Util;
131 2         18 state $true = Scalar::Util::dualvar(1, "1");
132             }
133              
134             sub wrap {
135 7     7 1 11437 my ($package, $alias) = @_;
136 7 50       18 return if !$package;
137 7   66     28 my $moniker = $alias // $package =~ s/\W//gr;
138 7         14 my $caller = caller(0);
139 1     1   6 no strict 'refs';
  1         1  
  1         67  
140 1     1   6 no warnings 'redefine';
  1         2  
  1         171  
141 7 100   17   32 return *{"${caller}::${moniker}"} = sub { @_ ? make($package, @_) : $package };
  7         93  
  17         19795  
142             }
143              
144             1;
145              
146              
147             =head1 NAME
148              
149             Earth - FP Framework
150              
151             =cut
152              
153             =head1 ABSTRACT
154              
155             FP Framework for Perl 5
156              
157             =cut
158              
159             =head1 VERSION
160              
161             0.02
162              
163             =cut
164              
165             =head1 SYNOPSIS
166              
167             package main;
168              
169             use Earth;
170              
171             wrap 'Digest::SHA', 'SHA';
172              
173             call(SHA(), 'sha1_hex');
174              
175             # "da39a3ee5e6b4b0d3255bfef95601890afd80709"
176              
177             =cut
178              
179             =head1 DESCRIPTION
180              
181             Earth is a functional-programming framework for Perl 5. Perl is a
182             multi-paradigm programming language that also supports functional programming,
183             but, Perl has an intentionally limited standard library with an emphasis on
184             providing library support via the CPAN which is overwhelmingly object-oriented.
185             This makes developing in a functional style difficult as you'll eventually need
186             to rely on a CPAN library that requires you to switch over to object-oriented
187             programming. Earth facilitates functional programming for Perl 5 by providing
188             functions which enable indirect routine dispatching, allowing the execution of
189             both functional and object-oriented code.
190              
191             =cut
192              
193             =head1 FUNCTIONS
194              
195             This package provides the following functions:
196              
197             =cut
198              
199             =head2 call
200              
201             call(Str | Object | CodeRef $self, Any @args) (Any)
202              
203             The call function dispatches function and method calls to a package and returns
204             the result.
205              
206             I>
207              
208             =over 4
209              
210             =item call example 1
211              
212             # given: synopsis
213              
214             call(SHA, 'sha1_hex');
215              
216             # "da39a3ee5e6b4b0d3255bfef95601890afd80709"
217              
218             =back
219              
220             =over 4
221              
222             =item call example 2
223              
224             # given: synopsis
225              
226             call('Digest::SHA', 'sha1_hex');
227              
228             # "da39a3ee5e6b4b0d3255bfef95601890afd80709"
229              
230             =back
231              
232             =over 4
233              
234             =item call example 3
235              
236             # given: synopsis
237              
238             call(\SHA, 'new');
239              
240             # bless(do{\(my $o = '...')}, 'Digest::SHA')
241              
242             =back
243              
244             =over 4
245              
246             =item call example 4
247              
248             # given: synopsis
249              
250             wrap 'Digest';
251              
252             call(Digest('SHA'), 'reset');
253              
254             # "da39a3ee5e6b4b0d3255bfef95601890afd80709"
255              
256             =back
257              
258             =cut
259              
260             =head2 can
261              
262             can(Str | Object | CodeRef $self, Str $name) (CodeRef)
263              
264             The can function checks if the object or class has a routine matching the name
265             provided, and if so returns a coderef for that routine.
266              
267             I>
268              
269             =over 4
270              
271             =item can example 1
272              
273             # given: synopsis
274              
275             my $coderef = can(SHA(1), 'sha1_hex');
276              
277             # sub { ... }
278              
279             =back
280              
281             =cut
282              
283             =head2 chain
284              
285             chain(Str | Object | CodeRef $self, Str | ArrayRef[Str] @args) (Any)
286              
287             The chain function chains function and method calls to a package (and return
288             values) and returns the result.
289              
290             I>
291              
292             =over 4
293              
294             =item chain example 1
295              
296             # given: synopsis
297              
298             my $hex = chain(\SHA, 'new', 'sha1_hex');
299              
300             # "d3aed913fdc7f277dddcbde47d50a8b5259cb4bc"
301              
302             =back
303              
304             =over 4
305              
306             =item chain example 2
307              
308             # given: synopsis
309              
310             my $hex = chain(\SHA, 'new', ['add', 'hello'], 'sha1_hex');
311              
312             # "f47b0cd4b6336d07ab117d7ee3f47566c9799f23"
313              
314             =back
315              
316             =over 4
317              
318             =item chain example 3
319              
320             # given: synopsis
321              
322             wrap 'Digest';
323              
324             my $hex = chain(Digest('SHA'), ['add', 'hello'], 'sha1_hex');
325              
326             # "8575ce82b266fdb5bc98eb43488c3b420577c24c"
327              
328             =back
329              
330             =cut
331              
332             =head2 false
333              
334             false() (Bool)
335              
336             The false function returns a falsy boolean value which is designed to be
337             practically indistinguishable from the conventional numerical C<0> value.
338              
339             I>
340              
341             =over 4
342              
343             =item false example 1
344              
345             package main;
346              
347             use Earth;
348              
349             my $false = false;
350              
351             # 0
352              
353             =back
354              
355             =over 4
356              
357             =item false example 2
358              
359             package main;
360              
361             use Earth;
362              
363             my $true = !false;
364              
365             # 1
366              
367             =back
368              
369             =cut
370              
371             =head2 make
372              
373             make(Str $package, Any @args) (Any)
374              
375             The make function L<"calls"|Earth/call> the C routine on the invocant and
376             returns the result which should be a package string or an object.
377              
378             I>
379              
380             =over 4
381              
382             =item make example 1
383              
384             # given: synopsis
385              
386             my $string = make(SHA);
387              
388             # bless(do{\(my $o = '...')}, 'Digest::SHA')
389              
390             =back
391              
392             =over 4
393              
394             =item make example 2
395              
396             # given: synopsis
397              
398             my $string = make(Digest, 'SHA');
399              
400             # bless(do{\(my $o = '...')}, 'Digest::SHA')
401              
402             =back
403              
404             =cut
405              
406             =head2 roll
407              
408             roll(Str $name, Any @args) (Any)
409              
410             The roll function takes a list of arguments, assuming the first argument is
411             invokable, and reorders the list such that the routine name provided comes
412             after the invocant (i.e. the 1st argument), creating a list acceptable to the
413             L function.
414              
415             I>
416              
417             =over 4
418              
419             =item roll example 1
420              
421             package main;
422              
423             use Earth;
424              
425             my @list = roll('sha1_hex', SHA);
426              
427             # ("Digest::SHA", "sha1_hex")
428              
429             =back
430              
431             =over 4
432              
433             =item roll example 2
434              
435             package main;
436              
437             use Earth;
438              
439             my @list = roll('sha1_hex', call(SHA(1), 'reset'));
440              
441             # (bless(do{\(my $o = '...')}, 'Digest::SHA'), "sha1_hex")
442              
443             =back
444              
445             =cut
446              
447             =head2 then
448              
449             then(Str | Object | CodeRef $self, Any @args) (Any)
450              
451             The then function proxies the call request to the L function and returns
452             the result as a list, prepended with the invocant.
453              
454             I>
455              
456             =over 4
457              
458             =item then example 1
459              
460             package main;
461              
462             use Earth;
463              
464             my @list = then(SHA, 'sha1_hex');
465              
466             # ("Digest::SHA", "da39a3ee5e6b4b0d3255bfef95601890afd80709")
467              
468             =back
469              
470             =over 4
471              
472             =cut
473              
474             =head2 true
475              
476             true() (Bool)
477              
478             The true function returns a truthy boolean value which is designed to be
479             practically indistinguishable from the conventional numerical C<1> value.
480              
481             I>
482              
483             =over 4
484              
485             =item true example 1
486              
487             package main;
488              
489             use Earth;
490              
491             my $true = true;
492              
493             # 1
494              
495             =back
496              
497             =over 4
498              
499             =item true example 2
500              
501             package main;
502              
503             use Earth;
504              
505             my $false = !true;
506              
507             # 0
508              
509             =back
510              
511             =cut
512              
513             =head2 wrap
514              
515             wrap(Str $package, Str $alias) (CodeRef)
516              
517             The wrap function installs a wrapper function in the calling package which when
518             called either returns the package string if no arguments are provided, or calls
519             L on the package with whatever arguments are provided and returns the
520             result. Unless an alias is provided as a second argument, special characters
521             are stripped from the package to create the function name.
522              
523             I>
524              
525             =over 4
526              
527             =item wrap example 1
528              
529             # given: synopsis
530              
531             my $coderef = wrap('Digest::SHA');
532              
533             # my $digest = DigestSHA();
534              
535             # "Digest::SHA"
536              
537             =back
538              
539             =over 4
540              
541             =item wrap example 2
542              
543             # given: synopsis
544              
545             my $coderef = wrap('Digest::SHA');
546              
547             # my $digest = DigestSHA(1);
548              
549             # bless(do{\(my $o = '...')}, 'Digest::SHA')
550              
551             =back
552              
553             =over 4
554              
555             =item wrap example 3
556              
557             # given: synopsis
558              
559             my $coderef = wrap('Digest::SHA', 'SHA');
560              
561             # my $digest = SHA;
562              
563             # "Digest::SHA"
564              
565             =back
566              
567             =over 4
568              
569             =item wrap example 4
570              
571             # given: synopsis
572              
573             my $coderef = wrap('Digest::SHA', 'SHA');
574              
575             # my $digest = SHA(1);
576              
577             # bless(do{\(my $o = '...')}, 'Digest::SHA')
578              
579             =back
580              
581             =cut
582              
583             =head1 AUTHORS
584              
585             Awncorp, C
586              
587             =cut