source: main/trunk/greenstone2/perllib/cpan/Mojo/Base.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: 9.1 KB
Line 
1package Mojo::Base;
2
3use strict;
4use warnings;
5use utf8;
6use feature ();
7
8# No imports because we get subclassed, a lot!
9use Carp ();
10use Scalar::Util ();
11
12# Defer to runtime so Mojo::Util can use "-strict"
13require Mojo::Util;
14
15# Only Perl 5.14+ requires it on demand
16use IO::Handle ();
17
18# Role support requires Role::Tiny 2.000001+
19use constant ROLES =>
20 !!(eval { require Role::Tiny; Role::Tiny->VERSION('2.000001'); 1 });
21
22# Protect subclasses using AUTOLOAD
23sub DESTROY { }
24
25sub attr {
26 my ($self, $attrs, $value) = @_;
27 return unless (my $class = ref $self || $self) && $attrs;
28
29 Carp::croak 'Default has to be a code reference or constant value'
30 if ref $value && ref $value ne 'CODE';
31
32 for my $attr (@{ref $attrs eq 'ARRAY' ? $attrs : [$attrs]}) {
33 Carp::croak qq{Attribute "$attr" invalid} unless $attr =~ /^[a-zA-Z_]\w*$/;
34
35 # Very performance-sensitive code with lots of micro-optimizations
36 if (ref $value) {
37 my $sub = sub {
38 return
39 exists $_[0]{$attr} ? $_[0]{$attr} : ($_[0]{$attr} = $value->($_[0]))
40 if @_ == 1;
41 $_[0]{$attr} = $_[1];
42 $_[0];
43 };
44 Mojo::Util::monkey_patch($class, $attr, $sub);
45 }
46 elsif (defined $value) {
47 my $sub = sub {
48 return exists $_[0]{$attr} ? $_[0]{$attr} : ($_[0]{$attr} = $value)
49 if @_ == 1;
50 $_[0]{$attr} = $_[1];
51 $_[0];
52 };
53 Mojo::Util::monkey_patch($class, $attr, $sub);
54 }
55 else {
56 Mojo::Util::monkey_patch($class, $attr,
57 sub { return $_[0]{$attr} if @_ == 1; $_[0]{$attr} = $_[1]; $_[0] });
58 }
59 }
60}
61
62sub import {
63 my ($class, $caller) = (shift, caller);
64 return unless my @flags = @_;
65
66 # Base
67 if ($flags[0] eq '-base') { $flags[0] = $class }
68
69 # Role
70 if ($flags[0] eq '-role') {
71 Carp::croak 'Role::Tiny 2.000001+ is required for roles' unless ROLES;
72 Mojo::Util::monkey_patch($caller, 'has', sub { attr($caller, @_) });
73 eval "package $caller; use Role::Tiny; 1" or die $@;
74 }
75
76 # Module and not -strict
77 elsif ($flags[0] !~ /^-/) {
78 no strict 'refs';
79 require(Mojo::Util::class_to_path($flags[0])) unless $flags[0]->can('new');
80 push @{"${caller}::ISA"}, $flags[0];
81 Mojo::Util::monkey_patch($caller, 'has', sub { attr($caller, @_) });
82 }
83
84 # Mojo modules are strict!
85 $_->import for qw(strict warnings utf8);
86 feature->import(':5.10');
87
88 # Signatures (Perl 5.20+)
89 if (($flags[1] || '') eq '-signatures') {
90 Carp::croak 'Subroutine signatures require Perl 5.20+' if $] < 5.020;
91 require experimental;
92 experimental->import('signatures');
93 }
94}
95
96sub new {
97 my $class = shift;
98 bless @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {}, ref $class || $class;
99}
100
101sub tap {
102 my ($self, $cb) = (shift, shift);
103 $_->$cb(@_) for $self;
104 return $self;
105}
106
107sub with_roles {
108 Carp::croak 'Role::Tiny 2.000001+ is required for roles' unless ROLES;
109 my ($self, @roles) = @_;
110
111 return Role::Tiny->create_class_with_roles($self,
112 map { /^\+(.+)$/ ? "${self}::Role::$1" : $_ } @roles)
113 unless my $class = Scalar::Util::blessed $self;
114
115 return Role::Tiny->apply_roles_to_object($self,
116 map { /^\+(.+)$/ ? "${class}::Role::$1" : $_ } @roles);
117}
118
1191;
120
121=encoding utf8
122
123=head1 NAME
124
125Mojo::Base - Minimal base class for Mojo projects
126
127=head1 SYNOPSIS
128
129 package Cat;
130 use Mojo::Base -base;
131
132 has name => 'Nyan';
133 has ['age', 'weight'] => 4;
134
135 package Tiger;
136 use Mojo::Base 'Cat';
137
138 has friend => sub { Cat->new };
139 has stripes => 42;
140
141 package main;
142 use Mojo::Base -strict;
143
144 my $mew = Cat->new(name => 'Longcat');
145 say $mew->age;
146 say $mew->age(3)->weight(5)->age;
147
148 my $rawr = Tiger->new(stripes => 38, weight => 250);
149 say $rawr->tap(sub { $_->friend->name('Tacgnol') })->weight;
150
151=head1 DESCRIPTION
152
153L<Mojo::Base> is a simple base class for L<Mojo> projects with fluent
154interfaces.
155
156 # Automatically enables "strict", "warnings", "utf8" and Perl 5.10 features
157 use Mojo::Base -strict;
158 use Mojo::Base -base;
159 use Mojo::Base 'SomeBaseClass';
160 use Mojo::Base -role;
161
162All four forms save a lot of typing. Note that role support depends on
163L<Role::Tiny> (2.000001+).
164
165 # use Mojo::Base -strict;
166 use strict;
167 use warnings;
168 use utf8;
169 use feature ':5.10';
170 use IO::Handle ();
171
172 # use Mojo::Base -base;
173 use strict;
174 use warnings;
175 use utf8;
176 use feature ':5.10';
177 use IO::Handle ();
178 push @ISA, 'Mojo::Base';
179 sub has { Mojo::Base::attr(__PACKAGE__, @_) }
180
181 # use Mojo::Base 'SomeBaseClass';
182 use strict;
183 use warnings;
184 use utf8;
185 use feature ':5.10';
186 use IO::Handle ();
187 require SomeBaseClass;
188 push @ISA, 'SomeBaseClass';
189 sub has { Mojo::Base::attr(__PACKAGE__, @_) }
190
191 # use Mojo::Base -role;
192 use strict;
193 use warnings;
194 use utf8;
195 use feature ':5.10';
196 use IO::Handle ();
197 use Role::Tiny;
198 sub has { Mojo::Base::attr(__PACKAGE__, @_) }
199
200On Perl 5.20+ you can also append a C<-signatures> flag to all three forms and
201enable support for L<subroutine signatures|perlsub/"Signatures">.
202
203 # Also enable signatures
204 use Mojo::Base -strict, -signatures;
205 use Mojo::Base -base, -signatures;
206 use Mojo::Base 'SomeBaseClass', -signatures;
207 use Mojo::Base -role, -signatures;
208
209This will also disable experimental warnings on versions of Perl where this
210feature was still experimental.
211
212=head1 FLUENT INTERFACES
213
214Fluent interfaces are a way to design object-oriented APIs around method
215chaining to create domain-specific languages, with the goal of making the
216readablity of the source code close to written prose.
217
218 package Duck;
219 use Mojo::Base -base;
220
221 has 'name';
222
223 sub quack {
224 my $self = shift;
225 my $name = $self->name;
226 say "$name: Quack!"
227 }
228
229L<Mojo::Base> will help you with this by having all attribute accessors created
230with L</"has"> (or L</"attr">) return their invocant (C<$self>) whenever they
231are used to assign a new attribute value.
232
233 Duck->new->name('Donald')->quack;
234
235In this case the C<name> attribute accessor is called on the object created by
236C<Duck-E<gt>new>. It assigns a new attribute value and then returns the C<Duck>
237object, so the C<quack> method can be called on it afterwards. These method
238chains can continue until one of the methods called does not return the C<Duck>
239object.
240
241=head1 FUNCTIONS
242
243L<Mojo::Base> implements the following functions, which can be imported with
244the C<-base> flag or by setting a base class.
245
246=head2 has
247
248 has 'name';
249 has ['name1', 'name2', 'name3'];
250 has name => 'foo';
251 has name => sub {...};
252 has ['name1', 'name2', 'name3'] => 'foo';
253 has ['name1', 'name2', 'name3'] => sub {...};
254
255Create attributes for hash-based objects, just like the L</"attr"> method.
256
257=head1 METHODS
258
259L<Mojo::Base> implements the following methods.
260
261=head2 attr
262
263 $object->attr('name');
264 SubClass->attr('name');
265 SubClass->attr(['name1', 'name2', 'name3']);
266 SubClass->attr(name => 'foo');
267 SubClass->attr(name => sub {...});
268 SubClass->attr(['name1', 'name2', 'name3'] => 'foo');
269 SubClass->attr(['name1', 'name2', 'name3'] => sub {...});
270
271Create attribute accessors for hash-based objects, an array reference can be
272used to create more than one at a time. Pass an optional second argument to set
273a default value, it should be a constant or a callback. The callback will be
274executed at accessor read time if there's no set value, and gets passed the
275current instance of the object as first argument. Accessors can be chained, that
276means they return their invocant when they are called with an argument.
277
278=head2 new
279
280 my $object = SubClass->new;
281 my $object = SubClass->new(name => 'value');
282 my $object = SubClass->new({name => 'value'});
283
284This base class provides a basic constructor for hash-based objects. You can
285pass it either a hash or a hash reference with attribute values.
286
287=head2 tap
288
289 $object = $object->tap(sub {...});
290 $object = $object->tap('some_method');
291 $object = $object->tap('some_method', @args);
292
293Tap into a method chain to perform operations on an object within the chain
294(also known as a K combinator or Kestrel). The object will be the first argument
295passed to the callback, and is also available as C<$_>. The callback's return
296value will be ignored; instead, the object (the callback's first argument) will
297be the return value. In this way, arbitrary code can be used within (i.e.,
298spliced or tapped into) a chained set of object method calls.
299
300 # Longer version
301 $object = $object->tap(sub { $_->some_method(@args) });
302
303 # Inject side effects into a method chain
304 $object->foo('A')->tap(sub { say $_->foo })->foo('B');
305
306=head2 with_roles
307
308 my $new_class = SubClass->with_roles('SubClass::Role::One');
309 my $new_class = SubClass->with_roles('+One', '+Two');
310 $object = $object->with_roles('+One', '+Two');
311
312Create a new class with one or more L<Role::Tiny> roles. If called on a class
313returns the new class, or if called on an object reblesses the object into the
314new class. For roles following the naming scheme C<MyClass::Role::RoleName> you
315can use the shorthand C<+RoleName>. Note that role support depends on
316L<Role::Tiny> (2.000001+).
317
318 # Create a new class with the role "SubClass::Role::Foo" and instantiate it
319 my $new_class = SubClass->with_roles('+Foo');
320 my $object = $new_class->new;
321
322=head1 SEE ALSO
323
324L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
325
326=cut
Note: See TracBrowser for help on using the repository browser.