source: main/trunk/greenstone2/perllib/cpan/Mojo/IOLoop/Delay.pm@ 32205

Last change on this file since 32205 was 32205, checked in by ak19, 6 years ago

First set of commits to do with implementing the new 'paged_html' output option of PDFPlugin that uses using xpdftools' new pdftohtml. So far tested only on Linux (64 bit), but things work there so I'm optimistically committing the changes since they work. 2. Committing the pre-built Linux binaries of XPDFtools for both 32 and 64 bit built by the XPDF group. 2. To use the correct bitness variant of xpdftools, setup.bash now exports the BITNESS env var, consulted by gsConvert.pl. 3. All the perl code changes to do with using xpdf tools' pdftohtml to generate paged_html and feed it in the desired form into GS(3): gsConvert.pl, PDFPlugin.pm and its parent ConvertBinaryPFile.pm have been modified to make it all work. xpdftools' pdftohtml generates a folder containing an html file and a screenshot for each page in a PDF (as well as an index.html linking to each page's html). However, we want a single html file that contains each individual 'page' html's content in a div, and need to do some further HTML style, attribute and structure modifications to massage the xpdftool output to what we want for GS. In order to parse and manipulate the HTML 'DOM' to do this, we're using the Mojo::DOM package that Dr Bainbridge found and which he's compiled up. Mojo::DOM is therefore also committed in this revision. Some further changes and some display fixes are required, but need to check with the others about that.

File size: 6.6 KB
Line 
1package Mojo::IOLoop::Delay;
2use Mojo::Base 'Mojo::Promise';
3
4# DEPRECATED!
5use base 'Mojo::EventEmitter';
6
7sub begin {
8 my ($self, $offset, $len) = @_;
9 $self->{pending}++;
10 my $id = $self->{counter}++;
11 return sub { $self->_step($id, $offset // 1, $len, @_) };
12}
13
14sub pass { $_[0]->begin->(@_) }
15
16sub steps {
17 my ($self, @steps) = @_;
18 $self->{steps} = \@steps;
19 $self->ioloop->next_tick($self->begin);
20
21 # DEPRECATED!
22 $self->{deprecated} ||= $self->on(error => sub { });
23
24 return $self;
25}
26
27sub _step {
28 my ($self, $id, $offset, $len) = (shift, shift, shift, shift);
29
30 $self->{args}[$id]
31 = [@_ ? defined $len ? splice @_, $offset, $len : splice @_, $offset : ()];
32 return $self if $self->{fail} || --$self->{pending} || $self->{lock};
33 local $self->{lock} = 1;
34 my @args = map {@$_} @{delete $self->{args}};
35
36 $self->{counter} = 0;
37 if (my $cb = shift @{$self->{steps}}) {
38 unless (eval { $self->$cb(@args); 1 }) {
39 my $err = $@;
40 @{$self}{qw(fail steps)} = (1, []);
41 return $self->reject($err)->emit(error => $err);
42 }
43 }
44
45 ($self->{steps} = []) and return $self->resolve(@args)->emit(finish => @args)
46 unless $self->{counter};
47 $self->ioloop->next_tick($self->begin) unless $self->{pending};
48 return $self;
49}
50
511;
52
53=encoding utf8
54
55=head1 NAME
56
57Mojo::IOLoop::Delay - Promises/A+ and flow-control helpers
58
59=head1 SYNOPSIS
60
61 use Mojo::IOLoop::Delay;
62
63 # Synchronize multiple non-blocking operations
64 my $delay = Mojo::IOLoop::Delay->new;
65 $delay->steps(sub { say 'BOOM!' });
66 for my $i (1 .. 10) {
67 my $end = $delay->begin;
68 Mojo::IOLoop->timer($i => sub {
69 say 10 - $i;
70 $end->();
71 });
72 }
73 $delay->wait;
74
75 # Sequentialize multiple non-blocking operations
76 Mojo::IOLoop::Delay->new->steps(
77
78 # First step (simple timer)
79 sub {
80 my $delay = shift;
81 Mojo::IOLoop->timer(2 => $delay->begin);
82 say 'Second step in 2 seconds.';
83 },
84
85 # Second step (concurrent timers)
86 sub {
87 my ($delay, @args) = @_;
88 Mojo::IOLoop->timer(1 => $delay->begin);
89 Mojo::IOLoop->timer(3 => $delay->begin);
90 say 'Third step in 3 seconds.';
91 },
92
93 # Third step (the end)
94 sub {
95 my ($delay, @args) = @_;
96 say 'And done after 5 seconds total.';
97 }
98 )->wait;
99
100=head1 DESCRIPTION
101
102L<Mojo::IOLoop::Delay> adds flow-control helpers to L<Mojo::Promise>, which can
103help you avoid deep nested closures that often result from continuation-passing
104style.
105
106 use Mojo::IOLoop;
107
108 # These deep nested closures are often referred to as "Callback Hell"
109 Mojo::IOLoop->timer(3 => sub {
110 my loop = shift;
111
112 say '3 seconds';
113 Mojo::IOLoop->timer(3 => sub {
114 my $loop = shift;
115
116 say '6 seconds';
117 Mojo::IOLoop->timer(3 => sub {
118 my $loop = shift;
119
120 say '9 seconds';
121 Mojo::IOLoop->stop;
122 });
123 });
124 });
125
126 Mojo::IOLoop->start;
127
128The idea behind L<Mojo::IOLoop::Delay> is to turn the nested closures above into
129a flat series of closures. In the example below, the call to L</"begin"> creates
130a code reference that we can pass to L<Mojo::IOLoop/"timer"> as a callback, and
131that leads to the next closure in the series when executed.
132
133 use Mojo::IOLoop;
134
135 # Instead of nested closures we now have a simple chain of steps
136 my $delay = Mojo::IOLoop->delay(
137 sub {
138 my $delay = shift;
139 Mojo::IOLoop->timer(3 => $delay->begin);
140 },
141 sub {
142 my $delay = shift;
143 say '3 seconds';
144 Mojo::IOLoop->timer(3 => $delay->begin);
145 },
146 sub {
147 my $delay = shift;
148 say '6 seconds';
149 Mojo::IOLoop->timer(3 => $delay->begin);
150 },
151 sub {
152 my $delay = shift;
153 say '9 seconds';
154 }
155 );
156 $delay->wait;
157
158Another positive side effect of this pattern is that we do not need to call
159L<Mojo::IOLoop/"start"> and L<Mojo::IOLoop/"stop"> manually, because we know
160exactly when our chain of L</"steps"> has reached the end. So
161L<Mojo::Promise/"wait"> can stop the event loop automatically if it had to be
162started at all in the first place.
163
164=head1 ATTRIBUTES
165
166L<Mojo::IOLoop::Delay> inherits all attributes from L<Mojo::Promise>.
167
168=head1 METHODS
169
170L<Mojo::IOLoop::Delay> inherits all methods from L<Mojo::Promise> and implements
171the following new ones.
172
173=head2 begin
174
175 my $cb = $delay->begin;
176 my $cb = $delay->begin($offset);
177 my $cb = $delay->begin($offset, $len);
178
179Indicate an active event by incrementing the event counter, the returned
180code reference can be used as a callback, and needs to be executed when the
181event has completed to decrement the event counter again. When all code
182references generated by this method have been executed and the event counter has
183reached zero, L</"steps"> will continue.
184
185 # Capture all arguments except for the first one (invocant)
186 my $delay = Mojo::IOLoop->delay(sub {
187 my ($delay, $err, $stream) = @_;
188 ...
189 });
190 Mojo::IOLoop->client({port => 3000} => $delay->begin);
191 $delay->wait;
192
193Arguments passed to the returned code reference are spliced with the given
194offset and length, defaulting to an offset of C<1> with no default length. The
195arguments are then combined in the same order L</"begin"> was called, and passed
196together to the next step.
197
198 # Capture all arguments
199 my $delay = Mojo::IOLoop->delay(sub {
200 my ($delay, $loop, $err, $stream) = @_;
201 ...
202 });
203 Mojo::IOLoop->client({port => 3000} => $delay->begin(0));
204 $delay->wait;
205
206 # Capture only the second argument
207 my $delay = Mojo::IOLoop->delay(sub {
208 my ($delay, $err) = @_;
209 ...
210 });
211 Mojo::IOLoop->client({port => 3000} => $delay->begin(1, 1));
212 $delay->wait;
213
214 # Capture and combine arguments
215 my $delay = Mojo::IOLoop->delay(sub {
216 my ($delay, $three_err, $three_stream, $four_err, $four_stream) = @_;
217 ...
218 });
219 Mojo::IOLoop->client({port => 3000} => $delay->begin);
220 Mojo::IOLoop->client({port => 4000} => $delay->begin);
221 $delay->wait;
222
223=head2 pass
224
225 $delay = $delay->pass;
226 $delay = $delay->pass(@args);
227
228Shortcut for passing values between L</"steps">.
229
230 # Longer version
231 $delay->begin(0)->(@args);
232
233=head2 steps
234
235 $delay = $delay->steps(sub {...}, sub {...});
236
237Sequentialize multiple events, every time the event counter reaches zero a
238callback will run, the first one automatically runs during the next reactor tick
239unless it is delayed by incrementing the event counter. This chain will continue
240until there are no remaining callbacks, a callback does not increment the event
241counter or an exception gets thrown in a callback. Finishing the chain will also
242result in the promise being fulfilled, or if an exception got thrown it will be
243rejected.
244
245=head1 SEE ALSO
246
247L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
248
249=cut
Note: See TracBrowser for help on using the repository browser.