File Coverage

blib/lib/Web/Library.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Web::Library;
2 1     1   5810 use MooseX::Singleton;
  0            
  0            
3             use Params::Validate qw(:all);
4             use Web::Library::Item;
5             our $VERSION = '0.06';
6             has 'libraries' => (
7             traits => ['Array'],
8             is => 'ro',
9             isa => 'ArrayRef[Web::Library::Item]',
10             default => sub { [] },
11             handles => {
12             all_libraries => 'elements',
13             push_library => 'push',
14             reset => 'clear',
15             },
16             );
17              
18             sub mount_library {
19             my $self = shift;
20             my %args = validate(@_, { name => 1, version => 0 });
21             $self->push_library(Web::Library::Item->new(%args));
22             }
23              
24             sub include_paths {
25             my $self = shift;
26             my @paths = map { $_->include_path } $self->all_libraries;
27             wantarray ? @paths : \@paths;
28             }
29              
30             sub library_map {
31             my ($self, $code, @libs) = @_;
32             my %lib_by_name = map { $_->name => $_ } $self->all_libraries;
33             my @result;
34             for my $lib (@libs) {
35             my $item = $lib_by_name{$lib} // die "unknown library [$lib]";
36             local $_ = $item; # so you can use $_ as well as $_[0] in $code
37             push @result, $code->($item);
38             }
39             @result;
40             }
41              
42             sub css_assets_for {
43             my ($self, @libs) = @_;
44             $self->library_map(sub { $_->css_assets }, @libs);
45             }
46              
47             sub javascript_assets_for {
48             my ($self, @libs) = @_;
49             $self->library_map(sub { $_->javascript_assets }, @libs);
50             }
51              
52             sub css_link_tags_for {
53             my ($self, @libs) = @_;
54             join "\n",
55             map { qq!<link href="$_" rel="stylesheet">! }
56             $self->css_assets_for(@libs);
57             }
58              
59             sub script_tags_for {
60             my ($self, @libs) = @_;
61             join "\n",
62             map { qq!<script src="$_" type="text/javascript"></script>! }
63             $self->javascript_assets_for(@libs);
64             }
65             1;
66              
67             =pod
68              
69             =head1 NAME
70              
71             Web::Library - Manager for wrappers around client-side libraries
72              
73             =head1 SYNOPSIS
74              
75             # in your Catalyst application:
76              
77             my $library_manager = Web::Library->instance;
78              
79             $library_manager->mount_library({ name => 'jQuery' });
80             $library_manager->mount_library(
81             { name => 'Bootstrap', version => '2.3.0' });
82              
83             __PACKAGE__->config(
84             'Plugin::Static::Simple' => {
85             include_path => [ $library_manager->include_paths ] },
86             ...
87             );
88              
89             # in an HTML template
90              
91             <head>
92             ...
93             [% web_library.css_link_tags_for('Bootstrap', 'jQuery') %]
94             </head>
95             <body>
96             ...
97             [% web_library.script_tags_for('Bootstrap', 'jQuery') %]
98             </body>
99              
100             =head1 DESCRIPTION
101              
102             There are well-established ways for web applications to manage server-side
103             dependencies, like C<Makefile.PL> or C<cpanfile> - but what about client-side
104             dependencies?
105              
106             So you develop and maintain a number of web applications, and all of them use
107             some client-side libraries like jQuery or Twitter Bootstrap or Underscore.js.
108             You have to copy the relevant JavaScript, CSS and image files to a directory
109             containing static files for each web application. This involves quite a bit of
110             copying around and version maintenance. Web::Library can help you.
111              
112             The idea behind Web::Library and its related distributions is that client-side
113             libraries are installed as shared files of standard CPAN distributions.
114             Web::Library itself is a manager for those libraries. A web application that
115             wishes to use one or more client-side libraries can tell Web::Library to
116             include either the latest or a specific version of those libraries. These
117             managed libraries can then be used as static files with web application
118             frameworks. In the case of L<Catalyst> you might use
119             L<Catalyst::Plugin::Static::Simple> as shown in the synopsis.
120              
121             Web::Library is a singleton object, so you can add client-side libraries in
122             different parts of your application. For example, you might have common
123             librares that are included in all of your web applications, but then also want
124             to manage application-specific libraries.
125              
126             Only client-side libraries whose license permits redistribution can be managed
127             this way. Forunately, most, if not all, popular client-side libraries have such
128             permissive licenses.
129              
130             =head1 METHODS
131              
132             =over 4
133              
134             =item instance
135              
136             Returns the singleton Web::Library object that manages all client-side libraries.
137              
138             =item mount_library
139              
140             Adds a specific version of a client-side library to the list of managed
141             libraries. Takes a hashref of named parameters. Valid parameters are:
142              
143             =over 4
144              
145             =item name
146              
147             The name of the client-side library. The manager will try to load the
148             C<Web::Library::$name> class. For example, L<Web::Library::Bootstrap> is a
149             distribution wrapper for Twitter Bootstrap.
150              
151             =item version
152              
153             A distribution wrapper will contain various versions of the wrapped client-side
154             library. Using this parameter you can specify the version you want. Refer to
155             the relevant distribution's documentation to see which versions are available.
156             This parameter is optional; if omitted, the latest version is used.
157              
158             =back
159              
160             =item include_paths
161              
162             Client-side library files are installed as shared files as described in
163             L<File::ShareDir>. The C<include_paths> method returns the absolute paths to
164             shared directories for all managed libraries.
165              
166             Returns a list in list context and an array reference in scalar context.
167              
168             =item reset
169              
170             Clears all mounted libraries.
171              
172             =back
173              
174             =head2 ASSET-RELATED METHODS
175              
176             Web::Library can also help you with including a library's CSS and JavaScript
177             files in the web page templates.
178              
179             If you expose an instance of Web::Library to your templates, you can add the
180             relevant C<< <link> >> and C<< <script> >> tags as shown in the synopsis.
181              
182             This is convenient, but it's only intended for some basic default set of CSS
183             and JavaScript files. For example, if the library provides responsive versions
184             or other customized versions, you can still use them by writing the HTML tags
185             manually. A list of which files are included for each version is found in the
186             documentation of the wrapper distributions like L<Web::Library::Bootstrap>.
187              
188             =over 4
189              
190             =item css_assets_for
191              
192             Takes a list of library names like those you give to C<mount_library()> and
193             returns a list of CSS files for the specific versions of the mounted libraries.
194              
195             For example:
196              
197             $manager->css_link_tags_for('Bootstrap', 'jQueryUI');
198              
199             might return:
200              
201             qw(/css/bootstrap.min.css /css/jquery-ui.min.css)
202              
203             =item javascript_assets_for
204              
205             Takes a list of library names like those you give to C<mount_library()> and
206             returns a list of JavaScript files for the specific versions of the mounted
207             libraries.
208              
209             For example:
210              
211             $manager->javascript_assets_for('Bootstrap', 'jQueryUI');
212              
213             might return:
214              
215             qw(/js/bootstrap.min.js /js/jquery-ui.min.js)
216              
217             =item css_link_tags_for
218              
219             Takes a list of library names like those you give to C<mount_library()> and
220             returns a string containing C<< <link> >> tags for the CSS files for the
221             specific versions of the mounted libraries.
222              
223             For example:
224              
225             $manager->css_link_tags_for('Bootstrap', 'jQueryUI');
226              
227             might return:
228              
229             <link href="/css/bootstrap.min.css" rel="stylesheet">
230             <link href="/css/jquery-ui.min.css" rel="stylesheet">
231              
232             =item script_tags_for
233              
234             Takes a list of library names like those you give to C<mount_library()> and
235             returns a string containing C<< <script> >> tags for the JavaScript files for
236             the specific versions of the mounted libraries.
237              
238             For example:
239              
240             $manager->script_tags_for('Bootstrap', 'jQueryUI');
241              
242             might return:
243              
244             <script src="/js/bootstrap.min.js" type="text/javascript></script>
245             <script src="/js/jquery-ui.min.js" type="text/javascript></script>
246              
247             =back
248              
249             =head1 WRITING YOUR OWN LIBRARY DISTRIBUTION
250              
251             If you want to write a distribution wrapper for a client-side library, it will
252             be easiest if you look at existing library distributions such as the ones
253             mentioned below and follow their example.
254              
255             Make sure that the library's license allows you to redistribute it and provide
256             a link to the library's web site and include other relevant attribution.
257              
258             Only add the files that are actually necessary - the bare minimum of CSS,
259             JavaScript and image files.
260              
261             =head1 SEE ALSO
262              
263             =over 4
264              
265             =item L<Web::Library::jQuery>
266              
267             =item L<Web::Library::jQueryUI>
268              
269             =item L<Web::Library::Bootstrap>
270              
271             =item L<Web::Library::DataTables>
272              
273             =item L<Web::Library::UnderscoreJS>
274              
275             =back
276              
277             =head1 AUTHORS
278              
279             The following person is the author of all the files provided in
280             this distribution unless explicitly noted otherwise.
281              
282             Marcel Gruenauer C<< <marcel@cpan.org> >>, L<http://marcelgruenauer.com>
283              
284             =head1 COPYRIGHT AND LICENSE
285              
286             The following copyright notice applies to all the files provided in
287             this distribution, including binary files, unless explicitly noted
288             otherwise.
289              
290             This software is copyright (c) 2013 by Marcel Gruenauer.
291              
292             This is free software; you can redistribute it and/or modify it under
293             the same terms as the Perl 5 programming language system itself.
294