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   1440 use 5.018;
  1         2  
4              
5 1     1   5 use strict;
  1         1  
  1         16  
6 1     1   3 use warnings;
  1         2  
  1         28  
7              
8 1     1   4 use Exporter 'import';
  1         2  
  1         174  
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.03';
31              
32             # AUTHORITY
33              
34             our $AUTHORITY = 'cpan:AWNCORP';
35              
36             # FUNCTIONS
37              
38             sub call {
39 21     21 1 1891 my ($invocant, $routine, @arguments) = @_;
40 21 50       68 if (UNIVERSAL::isa($invocant, 'CODE')) {
41 0         0 return $invocant->(@arguments);
42             }
43 21 50       32 return if !$routine;
44 21 100       40 if (Scalar::Util::blessed($invocant)) {
45 8         49 return $invocant->$routine(@arguments);
46             }
47 13 100       22 if (ref($invocant) eq 'SCALAR') {
48 3         9 return $$invocant->$routine(@arguments);
49             }
50 10         17 my $package = load($invocant);
51 10 50       44 if (my $routine = $package->can($routine)) {
52 10         76 return $routine->(@arguments);
53             }
54 0 0       0 if ($package->can('AUTOLOAD')) {
55 1     1   6 no strict 'refs';
  1         1  
  1         367  
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 14 return if !@_;
63 1 50       3 return call((ref($_[0]) ? $_[0] : \$_[0]), 'can', $_[1]);
64             }
65              
66              
67             sub chain {
68 3     3 1 34 my ($invocant, @routines) = @_;
69 3 50       7 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         26 return $invocant;
74             }
75              
76             sub false {
77 2     2 1 3694 require Scalar::Util;
78 2         17 state $false = Scalar::Util::dualvar(0, "0");
79             }
80              
81             sub load {
82 10     10 0 14 my ($package) = @_;
83              
84 10 100       19 if ($$cached{$package}) {
85 8         13 return $package;
86             }
87              
88 2 50       4 if ($package eq 'main') {
89 0         0 return do {$$cached{$package} = 1; $package};
  0         0  
  0         0  
90             }
91              
92 2   33     21 my $failed = !$package || $package !~ /^\w(?:[\w:']*\w)?$/;
93 2         3 my $loaded;
94              
95 2 50       3 my $error = do {
96 2         2 local $@;
97 1     1   6 no strict 'refs';
  1         1  
  1         231  
98 2         12 $loaded = !!$package->can('new');
99 2 50       9 $loaded = !!$package->can('import') if !$loaded;
100 2 50       120 $loaded = eval "require $package; 1" if !$loaded;
101 2         7 $@;
102             }
103             if !$failed;
104              
105 2 0 33     13 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         4 $$cached{$package} = 1;
112              
113 2         3 return $package;
114             }
115              
116             sub make {
117 6 50   6 1 14 return if !@_;
118 6         13 return call($_[0], 'new', @_);
119             }
120              
121             sub roll {
122 2     2 1 29 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 3915 require Scalar::Util;
131 2         24 state $true = Scalar::Util::dualvar(1, "1");
132             }
133              
134             sub wrap {
135 7     7 1 10797 my ($package, $alias) = @_;
136 7 50       17 return if !$package;
137 7   66     27 my $moniker = $alias // $package =~ s/\W//gr;
138 7         12 my $caller = caller(0);
139 1     1   5 no strict 'refs';
  1         1  
  1         30  
140 1     1   5 no warnings 'redefine';
  1         2  
  1         152  
141 7 100   17   20 return *{"${caller}::${moniker}"} = sub { @_ ? make($package, @_) : $package };
  7         92  
  17         19072  
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.03
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             =cut
471              
472             =head2 true
473              
474             true() (Bool)
475              
476             The true function returns a truthy boolean value which is designed to be
477             practically indistinguishable from the conventional numerical C<1> value.
478              
479             I>
480              
481             =over 4
482              
483             =item true example 1
484              
485             package main;
486              
487             use Earth;
488              
489             my $true = true;
490              
491             # 1
492              
493             =back
494              
495             =over 4
496              
497             =item true example 2
498              
499             package main;
500              
501             use Earth;
502              
503             my $false = !true;
504              
505             # 0
506              
507             =back
508              
509             =cut
510              
511             =head2 wrap
512              
513             wrap(Str $package, Str $alias) (CodeRef)
514              
515             The wrap function installs a wrapper function in the calling package which when
516             called either returns the package string if no arguments are provided, or calls
517             L on the package with whatever arguments are provided and returns the
518             result. Unless an alias is provided as a second argument, special characters
519             are stripped from the package to create the function name.
520              
521             I>
522              
523             =over 4
524              
525             =item wrap example 1
526              
527             # given: synopsis
528              
529             my $coderef = wrap('Digest::SHA');
530              
531             # my $digest = DigestSHA();
532              
533             # "Digest::SHA"
534              
535             =back
536              
537             =over 4
538              
539             =item wrap example 2
540              
541             # given: synopsis
542              
543             my $coderef = wrap('Digest::SHA');
544              
545             # my $digest = DigestSHA(1);
546              
547             # bless(do{\(my $o = '...')}, 'Digest::SHA')
548              
549             =back
550              
551             =over 4
552              
553             =item wrap example 3
554              
555             # given: synopsis
556              
557             my $coderef = wrap('Digest::SHA', 'SHA');
558              
559             # my $digest = SHA;
560              
561             # "Digest::SHA"
562              
563             =back
564              
565             =over 4
566              
567             =item wrap example 4
568              
569             # given: synopsis
570              
571             my $coderef = wrap('Digest::SHA', 'SHA');
572              
573             # my $digest = SHA(1);
574              
575             # bless(do{\(my $o = '...')}, 'Digest::SHA')
576              
577             =back
578              
579             =cut
580              
581             =head1 AUTHORS
582              
583             Awncorp, C
584              
585             =cut