File Coverage

lib/HTTP/Promise/Body.pm
Criterion Covered Total %
statement 134 166 80.7
branch 8 26 30.7
condition 6 30 20.0
subroutine 48 59 81.3
pod 7 9 77.7
total 203 290 70.0


line stmt bran cond sub pod time code
1             ##----------------------------------------------------------------------------
2             ## Asynchronous HTTP Request and Promise - ~/lib/HTTP/Promise/Entity/Body.pm
3             ## Version v0.1.0
4             ## Copyright(c) 2022 DEGUEST Pte. Ltd.
5             ## Author: Jacques Deguest <jack@deguest.jp>
6             ## Created 2022/04/19
7             ## Modified 2022/04/19
8             ## All rights reserved
9             ##
10             ## This program is free software; you can redistribute it and/or modify it
11             ## under the same terms as Perl itself.
12             ##----------------------------------------------------------------------------
13             package HTTP::Promise::Body;
14             BEGIN
15             {
16 12     12   86 use strict;
  12         27  
  12         424  
17 12     12   95 use warnings;
  12         28  
  12         351  
18 12     12   74 use parent qw( Module::Generic );
  12         30  
  12         90  
19 12     12   801 use vars qw( $VERSION $EXCEPTION_CLASS );
  12         51  
  12         641  
20 12     12   84 use HTTP::Promise::Exception;
  12         82  
  12         127  
21 12     12   3822 our $EXCEPTION_CLASS = 'HTTP::Promise::Exception';
22 12         275 our $VERSION = 'v0.1.0';
23             };
24              
25 12     12   73 use strict;
  12         30  
  12         270  
26 12     12   68 use warnings;
  12         34  
  12         8369  
27              
28             sub as_lines
29             {
30 3     3 1 65434 my $self = shift( @_ );
31 3   50     22 my $io = $self->open( 'r' ) || return( $self->pass_error );
32 3         5024 my $lines = $self->new_array;
33 3         65 local $_;
34 3         20 while( defined( $_ = $io->getline ) )
35             {
36 9         1317 $lines->push( $_ );
37             }
38 3         255 $io->close;
39 3         267 return( $lines );
40             }
41              
42             # Very dangerous to use indiscriminately when dealing with large data stored on file
43             sub as_string
44             {
45 19     19 1 589 my $self = shift( @_ );
46 19         95 my $opts = $self->_get_args_as_hash( @_ );
47 19         2678 my $str = $self->new_scalar;
48 19         680 my $params = {};
49 19         78 for( qw( binmode debug ) )
50             {
51 38 50 66     301 $params->{ $_ } = $opts->{ $_ } if( exists( $opts->{ $_ } ) && $opts->{ $_ } );
52             }
53            
54 19         61 my( $pos, $io );
55 19 50 66     194 if( $self->can( 'opened' ) && ( $io = $self->opened ) )
56             {
57 0         0 $pos = $self->tell;
58             # Rewind
59 0         0 $self->seek(0,0);
60             }
61             else
62             {
63 19   50     2269 $io = $self->open( 'r', ( scalar( keys( %$params ) ) ? $params : () ) ) || return( $self->pass_error );
64             }
65 19         5314 my( $buff, $nread );
66 19         95 while( $nread = $io->read( $buff, 8192 ) )
67             {
68 19         2340 $$str .= $buff;
69             }
70 19 50       1707 if( defined( $pos ) )
71             {
72 0         0 $self->seek( $pos, 0 );
73             }
74 19         162 return( $str );
75             }
76              
77             # sub binmode { return( shift->_set_get_boolean( 'binmode', @_ ) ); }
78              
79 0     0 1 0 sub data { return( shift->as_string( @_ ) ); }
80              
81 0     0 1 0 sub dup { return( shift->clone( @_ ) ); }
82              
83             # sub open { return; }
84              
85 0     0 1 0 sub path { return; }
86              
87             sub print
88             {
89 0     0 1 0 my $self = shift( @_ );
90 0         0 my $fh = shift( @_ );
91 0         0 my $opts = $self->_get_args_as_hash( @_ );
92 0         0 my $nread;
93              
94             # Get output filehandle, and ensure that it's a printable object
95 0 0 0     0 return( $self->error( "Filehandle provided ($fh) is not a proper filehandle and its not a HTTP::Promise::IO object." ) ) if( !$self->_is_glob( $fh ) && !$self->_is_a( $fh => 'HTTP::Promise::IO' ) );
96              
97 0         0 my $params = {};
98 0 0 0     0 $params->{binmode} = $opts->{binmode} if( exists( $opts->{binmode} ) && $opts->{binmode} );
99             # Write it
100 0         0 my $buff = '';
101 0   0     0 my $io = $self->open( 'r', ( scalar( keys( %$params ) ) ? $params : () ) ) || return( $self->pass_error );
102 0         0 while( $nread = $io->read( $buff, 8192 ) )
103             {
104 0 0       0 print( $fh $buff ) || return( $self->error( "Unable to write to filehandle '$fh': $!" ) );
105             }
106 0         0 $io->close;
107 0         0 return( defined( $nread ) );
108             }
109              
110 0     0 1 0 sub purge { return; }
111              
112             # NOTE: sub FREEZE is inherited
113              
114 4     4 0 161 sub STORABLE_freeze { CORE::return( CORE::shift->FREEZE( @_ ) ); }
115              
116 6     6 0 6997 sub STORABLE_thaw { CORE::return( CORE::shift->THAW( @_ ) ); }
117              
118             # NOTE: sub THAW is inherited
119              
120            
121             # NOTE: HTTP::Promise::Body::File package
122             package HTTP::Promise::Body::File;
123             BEGIN
124             {
125 12     12   97 use strict;
  12         20  
  12         376  
126 12     12   68 use warnings;
  12         22  
  12         428  
127 12     12   3813 use Module::Generic::File;
  12         202862  
  12         300  
128 12     12   3074 use parent -norequire, qw( HTTP::Promise::Body Module::Generic::File );
  12         63  
  12         83  
129 12     12   719 use vars qw( $EXCEPTION_CLASS );
  12         139  
  12         599  
130 12     12   327 our $EXCEPTION_CLASS = 'HTTP::Promise::Exception';
131             };
132              
133 12     12   79 use strict;
  12         23  
  12         291  
134 12     12   66 use warnings;
  12         40  
  12         2748  
135              
136 32     32   763806 sub new { return( shift->Module::Generic::File::new( @_ ) ); }
137              
138             sub init
139             {
140 32     32   3412 my $self = shift( @_ );
141 32         496 $self->{_init_strict_use_sub} = 1;
142 32         221 $self->{_exception_class} = $EXCEPTION_CLASS;
143 32 50       363 $self->Module::Generic::File::init( @_ ) || return( $self->pass_error );
144 32         1389342 return( $self );
145             }
146              
147 0     0   0 sub path { return( shift->filename( @_ ) ); }
148              
149 0     0   0 sub purge { return( shift->unlink ); }
150              
151 2     2   61 sub FREEZE { CORE::return( CORE::shift->Module::Generic::File::FREEZE( @_ ) ); }
152              
153 2     2   289 sub STORABLE_freeze { CORE::return( CORE::shift->Module::Generic::File::STORABLE_freeze( @_ ) ); }
154              
155             # NOTE: sub STORABLE_thaw is inherited
156              
157             # NOTE: sub THAW is inherited
158              
159            
160             # NOTE: HTTP::Promise::Body::Scalar package
161             package HTTP::Promise::Body::Scalar;
162             BEGIN
163             {
164 12     12   91 use strict;
  12         26  
  12         330  
165 12     12   85 use warnings;
  12         28  
  12         428  
166 12     12   4736 use Module::Generic::Scalar;
  12         370635  
  12         612  
167 12     12   118 use parent -norequire, qw( HTTP::Promise::Body Module::Generic::Scalar );
  12         25  
  12         61  
168 12     12   724 use vars qw( $EXCEPTION_CLASS );
  12         38  
  12         1079  
169             use overload (
170 98     98   57370 '""' => sub{ $_[0] },
171 550     550   4521 bool => sub{1},
172 12         136 fallback => 1,
173 12     12   91 );
  12         31  
174 12     12   1294 our $EXCEPTION_CLASS = 'HTTP::Promise::Exception';
175             };
176              
177 12     12   68 use strict;
  12         24  
  12         270  
178 12     12   61 use warnings;
  12         34  
  12         4218  
179              
180             # sub new { return( shift->Module::Generic::Scalar::new( @_ ) ); }
181             sub new
182             {
183 76     76   486436 my $this = shift( @_ );
184 76         432 my $new = $this->Module::Generic::Scalar::new( @_ );
185 76 50       1845 return( $this->pass_error( $this->Module::Generic::Scalar::error ) ) if( !defined( $new ) );
186 76         302 return( $new );
187             }
188              
189 54 100   54   3087 sub as_string { return( @_ > 1 ? shift->SUPER::as_string( @_ ) : $_[0]->new_scalar( $_[0] ) ); }
190              
191             sub checksum_md5
192             {
193 13     13   51 my $self = shift( @_ );
194 13 50       134 $self->_load_class( 'Crypt::Digest::MD5' ) || return( $self->pass_error );
195 13         5369 return( Crypt::Digest::MD5::md5_hex( $$self ) );
196             }
197              
198 0     0   0 sub error { return( shift->Module::Generic::Scalar::error( @_ ) ); }
199              
200 0     0   0 sub pass_error { return( shift->Module::Generic::Scalar::pass_error( @_ ) ); }
201              
202 0     0   0 sub purge { return( shift->Module::Generic::Scalar::reset( @_ ) ); }
203              
204 24     24   209 sub set { return( shift->Module::Generic::Scalar::set( @_ ) ); }
205              
206 4     4   35 sub FREEZE { return( shift->Module::Generic::Scalar::FREEZE( @_ ) ); }
207              
208             # NOTE: sub STORABLE_freeze is inherited
209              
210             # NOTE: sub STORABLE_thaw is inherited
211              
212 4     4   36 sub THAW { return( shift->Module::Generic::Scalar::THAW( @_ ) ); }
213              
214            
215             # NOTE: HTTP::Promise::Body::InCore package
216             package HTTP::Promise::Body::InCore;
217             BEGIN
218             {
219 12     12   109 use strict;
  12         27  
  12         400  
220 12     12   65 use warnings;
  12         26  
  12         440  
221 12     12   105 use parent -norequire, qw( HTTP::Promise::Body::Scalar );
  12         38  
  12         84  
222 12     12   682 use vars qw( $EXCEPTION_CLASS );
  12         25  
  12         590  
223 12     12   287 our $EXCEPTION_CLASS = 'HTTP::Promise::Exception';
224             };
225              
226 12     12   91 use strict;
  12         27  
  12         307  
227 12     12   76 use warnings;
  12         36  
  12         2155  
228              
229             sub init
230             {
231 0     0     my $self = shift( @_ );
232 0           my $data = shift( @_ );
233             # nothing
234 0 0 0       if( !defined( $data ) ||
    0 0        
      0        
      0        
235             # simple scalar or a scalar object
236             ( !ref( $data ) || ( $self->_is_scalar( $data ) && overload::Method( $data => '""' ) ) ) ||
237             # or a scalar reference
238             ref( $data ) eq 'SCALAR' )
239             {
240             # pass through
241             }
242             elsif( $self->_is_array( $data ) )
243             {
244 0           $data = join( '', @$data );
245             }
246             else
247             {
248 0           return( $self->error( "Data of type '", ref( $data ), "' is unsupported." ) );
249             }
250 0 0         $self->SUPER::init( $data, @_ ) || return( $self->pass_error );
251 0           return( $self );
252             }
253              
254             1;
255             # NOTE: POD
256             __END__
257              
258             =encoding utf-8
259              
260             =head1 NAME
261              
262             HTTP::Promise::Body - HTTP Message Body Class
263              
264             =head1 SYNOPSIS
265              
266             use HTTP::Promise::Body;
267             my $body = HTTP::Promise::Body->new ||
268             die( HTTP::Promise::Body->error, "\n" );
269              
270             =head1 VERSION
271              
272             v0.1.0
273              
274             =head1 DESCRIPTION
275              
276             This class represents an entity body.
277              
278             Here is how it fits in overall relation with other classes.
279            
280             +-------------------------+ +--------------------------+
281             | | | |
282             | HTTP::Promise::Request | | HTTP::Promise::Response |
283             | | | |
284             +------------|------------+ +-------------|------------+
285             | |
286             | |
287             | |
288             | +------------------------+ |
289             | | | |
290             +--- HTTP::Promise::Message |---+
291             | |
292             +------------|-----------+
293             |
294             |
295             +------------|-----------+
296             | |
297             | HTTP::Promise::Entity |
298             | |
299             +------------|-----------+
300             |
301             |
302             +------------|-----------+
303             | |
304             | HTTP::Promise::Body |
305             | |
306             +------------------------+
307              
308             =head1 METHODS
309              
310             =head2 as_lines
311              
312             Returns a new L<array object|Module::Generic::Array> containing the body lines.
313              
314             =head2 as_string
315              
316             Returns the body data as a L<scalar object|Module::Generic::Scalar>.
317              
318             Be mindful about the size of the body before you load it all in memory. You can get the size of the body with C<< $body->length >>
319              
320             =head2 data
321              
322             This is just an alias for L</as_string>
323              
324             =head2 dup
325              
326             This is an alias for L<Module::Generic/clone>, which is inherited by this class.
327              
328             =head2 path
329              
330             This is a no-op and is superseded by inheriting classes.
331              
332             =head2 print
333              
334             Provided with a filehandle, or an L<HTTP::Promise::IO> object and an hash or hash reference of options and this will print the body data to and returns true if it was successful, or sets an L<error|Module::Generic/error> and returns C<undef>
335              
336             =head2 purge
337              
338             This is a no-op and is superseded by inheriting classes.
339              
340             =head1 AUTHOR
341              
342             Jacques Deguest E<lt>F<jack@deguest.jp>E<gt>
343              
344             =head1 SEE ALSO
345              
346             L<HTTP::Promise>, L<HTTP::Promise::Request>, L<HTTP::Promise::Response>, L<HTTP::Promise::Message>, L<HTTP::Promise::Entity>, L<HTTP::Promise::Headers>, L<HTTP::Promise::Body>, L<HTTP::Promise::Body::Form>, L<HTTP::Promise::Body::Form::Data>, L<HTTP::Promise::Body::Form::Field>, L<HTTP::Promise::Status>, L<HTTP::Promise::MIME>, L<HTTP::Promise::Parser>, L<HTTP::Promise::IO>, L<HTTP::Promise::Stream>, L<HTTP::Promise::Exception>
347              
348             L<Module::Generic::File>, L<Module::Generic::Scalar>, L<Module::Generic::File::IO>, L<Module::Generic::Scalar::IO>
349              
350             L<PerlIO::scalar>
351              
352             =head1 COPYRIGHT & LICENSE
353              
354             Copyright(c) 2022 DEGUEST Pte. Ltd.
355              
356             All rights reserved.
357              
358             This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
359              
360             =cut