File Coverage

blib/lib/MooX/NonOO.pm
Criterion Covered Total %
statement 53 54 98.1
branch 5 6 83.3
condition 4 7 57.1
subroutine 10 10 100.0
pod 1 1 100.0
total 73 78 93.5


line stmt bran cond sub pod time code
1             package MooX::NonOO;
2             $MooX::NonOO::VERSION = 'v0.1.0';
3             # ABSTRACT: Use Moo methods as functions with an implicit singleton
4              
5 1     1   26082 use strict;
  1         2  
  1         28  
6 1     1   4 use warnings;
  1         2  
  1         21  
7              
8 1     1   13 use feature qw/ state /;
  1         1  
  1         86  
9              
10 1     1   3 use Exporter qw/ import /;
  1         1  
  1         30  
11 1     1   420 use Package::Stash;
  1         4284  
  1         31  
12 1     1   7 use Scalar::Util qw/ blessed /;
  1         1  
  1         57  
13              
14             {
15 1     1   392 use version;
  1         1341  
  1         5  
16             $MooX::NonOO::VERSION = version->declare('v0.1.0');
17             }
18              
19             # RECOMMEND PREREQ: Package::Stash::XS 0
20              
21             =head1 NAME
22              
23             MooX::NonOO - Use Moo methods as functions with an implicit singleton
24              
25             =for readme plugin version
26              
27             =head1 SYNOPSYS
28              
29             In a module:
30              
31             package MyModule;
32              
33             use Moo;
34             use MooX::NonOO;
35              
36             ...
37              
38             sub my_method {
39             my ($self, @args) = @_;
40             ...
41             }
42              
43             as_function
44             export => [ 'my_method' ], # methods to export
45             args => [ ]; # constructor args
46              
47             The module can be be used with a function calling style:
48              
49             use MyModule;
50              
51             ...
52              
53             my_method(@args);
54              
55             =begin :readme
56              
57             =head1 INSTALLATION
58              
59             See
60             L.
61              
62             =for readme plugin requires heading-level=2 title="Required Modules"
63              
64             =for readme plugin changes
65              
66             =end :readme
67              
68             =head1 DESCRIPTION
69              
70             This module allows you to turn a class into a module that exports
71             methods as functions that use an implicit singleton.
72              
73             =head1 EXPORTS
74              
75             =head2 C
76              
77             as_function
78             exports => \@methods,
79             args => \@args;
80              
81             This wraps methods in a function that checks the first argument. If
82             the argument is an instance of the class, then it assumes it is a
83             normal method call. Otherwise it assumes it is a function call, and
84             it calls the method with the singleton instance.
85              
86             Note that this will not work properly on methods that take an instance
87             of the class as the first argument.
88              
89             =cut
90              
91             our @EXPORT = qw/ as_function _MooX_NonOO_instance /;
92              
93             sub _MooX_NonOO_instance {
94 3     3   4 my $class = shift;
95 3         3 state $symbol = '$_MooX_NonOO';
96 3         22 my $stash = Package::Stash->new($class);
97 3 100       20 if (my $instance = $stash->get_symbol($symbol)) {
98 2         2 return ${$instance};
  2         7  
99             } else {
100 1         24 my $instance = $class->new(@_);
101 1         17 $stash->add_symbol($symbol, \$instance);
102 1         3 return $instance;
103             }
104             }
105              
106             sub as_function {
107 1     1 1 17677 my %opts = @_;
108              
109 1   50     2 my @args = @{ $opts{args} // [] };
  1         5  
110 1   50     1 my @names = @{ $opts{export} // [] };
  1         4  
111 1         3 foreach my $name (@names) {
112              
113 3         8 my ($caller) = caller;
114 3         56 my $stash = Package::Stash->new($caller);
115              
116 3         20 $stash->add_symbol( '&import', \&Exporter::import );
117              
118 3         7 my $symbol = '&' . $name;
119 3 50       11 if ( my $method = $stash->get_symbol($symbol) ) {
120              
121 3         13 my $export = $stash->get_or_add_symbol('@EXPORT');
122 3         9 my $export_ok = $stash->get_or_add_symbol('@EXPORT_OK');
123              
124             my $new = sub {
125 20 100 66 20   3799 if ( blessed( $_[0] ) && $_[0]->isa($caller) ) {
126 15         68 return $method->(@_);
127             }
128             else {
129 5         11 state $self = $caller->_MooX_NonOO_instance(@args);
130 5         18 return $self->$method(@_);
131             }
132 3         10 };
133 3         9 $stash->add_symbol( $symbol, $new );
134              
135 3         2 push @{$export}, $name;
  3         4  
136 3         3 push @{$export_ok}, $name;
  3         13  
137             }
138             else {
139 0           die "No method named ${name}";
140             }
141             }
142             }
143              
144             =head1 AUTHOR
145              
146             Robert Rothenberg, C<< >>
147              
148             =head1 LICENSE AND COPYRIGHT
149              
150             Copyright 2015 Robert Rothenberg.
151              
152             This program is free software; you can redistribute it and/or modify it
153             under the terms of the the Artistic License (2.0). You may obtain a
154             copy of the full license at:
155              
156             L
157              
158             =for readme stop
159              
160             Any use, modification, and distribution of the Standard or Modified
161             Versions is governed by this Artistic License. By using, modifying or
162             distributing the Package, you accept this license. Do not use, modify,
163             or distribute the Package, if you do not accept this license.
164              
165             If your Modified Version has been derived from a Modified Version made
166             by someone other than you, you are nevertheless required to ensure that
167             your Modified Version complies with the requirements of this license.
168              
169             This license does not grant you the right to use any trademark, service
170             mark, tradename, or logo of the Copyright Holder.
171              
172             This license includes the non-exclusive, worldwide, free-of-charge
173             patent license to make, have made, use, offer to sell, sell, import and
174             otherwise transfer the Package with respect to any patent claims
175             licensable by the Copyright Holder that are necessarily infringed by the
176             Package. If you institute patent litigation (including a cross-claim or
177             counterclaim) against any party alleging that the Package constitutes
178             direct or contributory patent infringement, then this Artistic License
179             to you shall terminate on the date that such litigation is filed.
180              
181             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
182             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
183             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
184             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
185             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
186             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
187             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
188             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
189              
190             =for readme continue
191              
192             =cut
193              
194             1;