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   84 use strict;
  12         28  
  12         392  
17 12     12   64 use warnings;
  12         24  
  12         376  
18 12     12   63 use parent qw( Module::Generic );
  12         21  
  12         78  
19 12     12   830 use vars qw( $VERSION $EXCEPTION_CLASS );
  12         31  
  12         695  
20 12     12   69 use HTTP::Promise::Exception;
  12         38  
  12         128  
21 12     12   3914 our $EXCEPTION_CLASS = 'HTTP::Promise::Exception';
22 12         278 our $VERSION = 'v0.1.0';
23             };
24              
25 12     12   74 use strict;
  12         23  
  12         318  
26 12     12   90 use warnings;
  12         36  
  12         8341  
27              
28             sub as_lines
29             {
30 3     3 1 65343 my $self = shift( @_ );
31 3   50     21 my $io = $self->open( 'r' ) || return( $self->pass_error );
32 3         4937 my $lines = $self->new_array;
33 3         78 local $_;
34 3         15 while( defined( $_ = $io->getline ) )
35             {
36 9         1338 $lines->push( $_ );
37             }
38 3         257 $io->close;
39 3         265 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 548 my $self = shift( @_ );
46 19         125 my $opts = $self->_get_args_as_hash( @_ );
47 19         2713 my $str = $self->new_scalar;
48 19         684 my $params = {};
49 19         74 for( qw( binmode debug ) )
50             {
51 38 50 66     305 $params->{ $_ } = $opts->{ $_ } if( exists( $opts->{ $_ } ) && $opts->{ $_ } );
52             }
53            
54 19         90 my( $pos, $io );
55 19 50 66     196 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     2228 $io = $self->open( 'r', ( scalar( keys( %$params ) ) ? $params : () ) ) || return( $self->pass_error );
64             }
65 19         5318 my( $buff, $nread );
66 19         123 while( $nread = $io->read( $buff, 8192 ) )
67             {
68 19         2232 $$str .= $buff;
69             }
70 19 50       1785 if( defined( $pos ) )
71             {
72 0         0 $self->seek( $pos, 0 );
73             }
74 19         152 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 159 sub STORABLE_freeze { CORE::return( CORE::shift->FREEZE( @_ ) ); }
115              
116 6     6 0 6469 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   110 use strict;
  12         24  
  12         340  
126 12     12   80 use warnings;
  12         33  
  12         465  
127 12     12   3990 use Module::Generic::File;
  12         202197  
  12         263  
128 12     12   3068 use parent -norequire, qw( HTTP::Promise::Body Module::Generic::File );
  12         66  
  12         75  
129 12     12   760 use vars qw( $EXCEPTION_CLASS );
  12         124  
  12         616  
130 12     12   207 our $EXCEPTION_CLASS = 'HTTP::Promise::Exception';
131             };
132              
133 12     12   70 use strict;
  12         34  
  12         320  
134 12     12   65 use warnings;
  12         31  
  12         2624  
135              
136 32     32   728991 sub new { return( shift->Module::Generic::File::new( @_ ) ); }
137              
138             sub init
139             {
140 32     32   3676 my $self = shift( @_ );
141 32         385 $self->{_init_strict_use_sub} = 1;
142 32         171 $self->{_exception_class} = $EXCEPTION_CLASS;
143 32 50       286 $self->Module::Generic::File::init( @_ ) || return( $self->pass_error );
144 32         1371723 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   59 sub FREEZE { CORE::return( CORE::shift->Module::Generic::File::FREEZE( @_ ) ); }
152              
153 2     2   231 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   85 use strict;
  12         28  
  12         292  
165 12     12   69 use warnings;
  12         42  
  12         414  
166 12     12   4802 use Module::Generic::Scalar;
  12         365909  
  12         615  
167 12     12   119 use parent -norequire, qw( HTTP::Promise::Body Module::Generic::Scalar );
  12         23  
  12         93  
168 12     12   712 use vars qw( $EXCEPTION_CLASS );
  12         40  
  12         1188  
169             use overload (
170 98     98   59470 '""' => sub{ $_[0] },
171 550     550   4467 bool => sub{1},
172 12         156 fallback => 1,
173 12     12   95 );
  12         27  
174 12     12   1314 our $EXCEPTION_CLASS = 'HTTP::Promise::Exception';
175             };
176              
177 12     12   84 use strict;
  12         24  
  12         235  
178 12     12   61 use warnings;
  12         31  
  12         4255  
179              
180             # sub new { return( shift->Module::Generic::Scalar::new( @_ ) ); }
181             sub new
182             {
183 76     76   485976 my $this = shift( @_ );
184 76         453 my $new = $this->Module::Generic::Scalar::new( @_ );
185 76 50       2012 return( $this->pass_error( $this->Module::Generic::Scalar::error ) ) if( !defined( $new ) );
186 76         324 return( $new );
187             }
188              
189 54 100   54   3259 sub as_string { return( @_ > 1 ? shift->SUPER::as_string( @_ ) : $_[0]->new_scalar( $_[0] ) ); }
190              
191             sub checksum_md5
192             {
193 13     13   71 my $self = shift( @_ );
194 13 50       129 $self->_load_class( 'Crypt::Digest::MD5' ) || return( $self->pass_error );
195 13         5261 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   206 sub set { return( shift->Module::Generic::Scalar::set( @_ ) ); }
205              
206 4     4   46 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   32 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   93 use strict;
  12         30  
  12         327  
220 12     12   62 use warnings;
  12         46  
  12         465  
221 12     12   89 use parent -norequire, qw( HTTP::Promise::Body::Scalar );
  12         33  
  12         85  
222 12     12   755 use vars qw( $EXCEPTION_CLASS );
  12         44  
  12         640  
223 12     12   258 our $EXCEPTION_CLASS = 'HTTP::Promise::Exception';
224             };
225              
226 12     12   68 use strict;
  12         29  
  12         351  
227 12     12   64 use warnings;
  12         45  
  12         2190  
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