This file is indexed.

/usr/share/perl5/Jifty/ClassLoader.pm is in libjifty-perl 1.10518+dfsg-3ubuntu1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
use warnings;
use strict;

package Jifty::ClassLoader;

our %AUTOGENERATED;

use overload '""' => \&stringify, fallback => 1;

=head1 NAME

Jifty::ClassLoader - Loads the application classes

=head1 DESCRIPTION

C<Jifty::ClassLoader> loads all of the application's model and action
classes, generating classes on the fly for Collections of pre-existing
models.

=head2 new

Returns a new ClassLoader object.  Doing this installs a hook into
C<@INC> that allows L<Jifty::ClassLoader> to dynamically create
needed classes if they do not exist already.  This works because if
use/require encounters a blessed reference in C<@INC>, it will
invoke the INC method with the name of the module it is searching
for on the reference.

Takes one mandatory argument, C<base>, which should be the the
application's or a plugin's base path; all of the classes under this will be
automatically loaded.

L<Jifty::ClassLoader> objects are singletons per C<base>. If you call C<new>
and a class loader for the given base has already been initialized, this will
return a reference to that object rather than creating a new one.

=cut

sub new {
    my $class = shift;
    my %args = @_;

    # Check to make sure this classloader hasn't been built yet and stop if so
    my @exist = grep {ref $_ eq $class and $_->{base} eq $args{base}} @INC;
    return $exist[0] if @exist;

    # It's a new one, build it
    my $self = bless {%args}, $class;
    push @INC, $self;
    return $self;
}

=head2 INC

The hook that is called when a module has been C<require>'d that
cannot be found on disk.  The following stub classes are
auto-generated the class loader. 

Here the "I<Application>" indicates the name of the application the class
loader is being applied to. However, this really just refers to the C<base>
argument passed to the constructor, so it could refer to a plugin class
or just about anything else.

=over

=item I<Application>

An empty application base class is created that doesn't provide any
methods or inherit from anything.

=item I<Application>::Action

An empty mixin class for all actions in your application.  Should
B<not> inherit from L<Jifty::Action>.

=item I<Application>::Action::I<[Verb]>I<[Something]>

If I<Application>::Model::I<Something> is a valid model class and I<Verb> is one of "Create", "Search", "Update", "Execute", or "Delete", then it creates a subclass of I<Application>::Action::Record::I<Verb>  Models can control which actions are generated by overriding L<Jifty::Record/autogenerate_action>.  See also L<Jifty::Record/is_private> and L<Jifty::Record/is_protected>.

=item I<Application>::Action::I<Something>

The class loader will search for a plugin I<Plugin> such that C<I<Plugin>::Action::I<Something>> exists. It will then create an empty class named I<Application>::Action::I<Something> that descends from I<Plugin>::Action::I<Something>.

This means that a plugin may be written to allow the application to override the default implementation used by the plugin as long as the plugin uses the application version of the class.

=item I<Application>::Action::Record::I<Something>

An empty class that descends from the matching Jifty class, Jifty::Action::Record::I<Something>. This is generally used to build application-specific descendants of L<Jifty::Action::Record::Create>, L<Jifty::Action::Record::Execute>, L<Jifty::Action::Record::Search>, L<Jifty::Action::Record::Update>, or L<Jifty::Action::Record::Delete>.

=item I<Application>::Bootstrap

An empty class that descends from L<Jifty::Bootstrap>.

=item I<Application>::Collection

An empty class that descends from L<Jifty::Collection> is created.

=item I<Application>::CurrentUser

An empty class that descends from L<Jifty::CurrentUser>.

=item I<Application>::Dispatcher

An empty class that descends from L<Jifty::Dispatcher>.

=item I<Application>::Event

An empty class that descends from L<Jifty::Event> is created.

=item I<Application>::Event::Model

An empty class that descents from L<Jifty::Event::Model> is created.

=item I<Application>::Event::Model::I<Something>

If I<Application>::Model::I<Something> is a valid model class, then it creates an empty descendant of I<Application>::Event::Model with the C<record_class> set to I<Application>::Model::I<Something>.

=item I<Application>::Handle

An empty class that descends from L<Jifty::Handle> is created.

=item I<Application>::Model::I<Something>

If C<I<Plugin>::Model::I<Something>> exists and is a model class, then it creates a subclass of it named C<I<Application>::Model::I<Something>> for the local application.

This allows an application to customize a model provided by a subclass (or choose not to). Plugins should be written to use the application's version.

=item I<Application>::Model::I<Something>Collection

If C<I<Application>::Model::I<Something>> is a valid model class, then
it creates a subclass of L<Jifty::Collection> whose C<record_class> is
C<I<Application>::Model::I<Something>>.

=item I<Application>::Notification

An empty class that descends from L<Jifty::Notification>.

=item I<Application>::Notification::I<Something>

The class loader will search for a plugin I<Plugin> such that I<Plugin>::Notification::I<Something> exists. It will then create an empty class named I<Application>::Notification::I<Something> that descends from I<Plugin>::Notification::I<Something>.

This allows an application to customize the email notification sent out by a plugin as long as the plugin defers to the application version of the class.

=item I<Application>::Record

An empty class that descends from L<Jifty::Record> is created.

=item I<Application>::Upgrade

An empty class that descends from L<Jifty::Upgrade>.

=item I<Application>::View

An empty class that descends from L<Jifty::View::Declare>.

=back

=cut

# This subroutine's name is fully qualified, as perl will ignore a 'sub INC'
sub Jifty::ClassLoader::INC {
    my ( $self, $module ) = @_;
    my $base = $self->{base};
    return undef unless ( $module and $base );

    # Canonicalize $module to :: style rather than / and .pm style;
    $module =~ s/.pm$//;
    $module =~ s{/}{::}g;

    # The quick check. We only want to handle things for our app
    return undef unless $module =~ /^$base/;

    # If the module is the same as the base, build the application class
    if ( $module =~ /^(?:$base)$/ ) {
        return $self->return_class( "package " . $base . ";\n");
    }

    # Handle most of the standard App::Class ISA Jifty::Class
    elsif ( $module =~ /^(?:$base)::(Record|Collection|Notification|
                                      Dispatcher|Bootstrap|Upgrade|CurrentUser|
                                      Handle|Event|Event::Model|
                                      Action::Record::\w+)$/x ) {
        $AUTOGENERATED{$module} = 1;
        return $self->return_class(
                  "package $module;\n"
                . "use base qw/Jifty::$1/; \n"
            );
    }

    # Autogenerate empty Action mixin
    elsif ( $module =~ /^(?:$base)::Action$/) {
        $AUTOGENERATED{$module} = 1;
        return $self->return_class(
            "package $module;\n"
        );
    }
    
    # Autogenerate an empty View if none is defined
    elsif ( $module =~ /^(?:$base)::View$/ ) {
        $AUTOGENERATED{$module} = 1;
        return $self->return_class(
                  "package $module;\n"
                . "use Jifty::View::Declare -base;\n"
            );
    } 

    # Autogenerate the Collection class for a Model
    elsif ( $module =~ /^(?:$base)::Model::([^\.]+)Collection$/ ) {
        $AUTOGENERATED{$module} = 1;
        return $self->return_class(
                  "package $module;\n"
                . "use base qw/@{[$base]}::Collection/;\n"
                . "sub record_class { '@{[$base]}::Model::$1' }\n"
            );
    } 
    
    # Autogenerate the the event class for model changes
    elsif ( $module =~ /^(?:$base)::Event::Model::([^\.]+)$/ ) {
        
        # Determine the model class and load it
        my $modelclass = $base . "::Model::" . $1;
        Jifty::Util->require($modelclass);

        # Don't generate an event unless it really is a model
        return undef unless eval { $modelclass->isa('Jifty::Record') };

        $AUTOGENERATED{$module} = 1;
        return $self->return_class(
                  "package $module;\n"
                . "use base qw/${base}::Event::Model/;\n"
                . "sub record_class { '$modelclass' };\n"
            );
    } 
    
    # Autogenerate the record actions for a model
    elsif ( $module =~ /^(?:$base)::Action::
                        (Create|Update|Delete|Search|Execute)([^\.]+)$/x ) {

        my $action = $1;
        my $model  = $2;

        # Determine the model class and load it
        my $modelclass = $base . "::Model::" . $model;
        Jifty::Util->_require( module => $modelclass, quiet => 1);

        # Don't generate the action unless it really is a model
        if ( eval { $modelclass->isa('Jifty::Record') } ) {
            if ($modelclass->autogenerate_action($action)) {

                # Skip autogenerated models; that is, those that are overridden
                # by plugins, the special case below should take care of it
                if (!$self->autogenerated($modelclass)) {
                    $AUTOGENERATED{$module} = 1;
                    return $self->return_class(
                        "package $module;\n"
                        . "use base qw/$base\::Action::Record::$action/;\n"
                        . "sub record_class { '$modelclass' };\n"
                    );
                }
            }
        }

    }

    # This is a little hard to grok, so pay attention. This next if checks to
    # see if the requested class belongs to an application (i.e., this class
    # loader does not belong to a plugin). If so, it will attempt to create an
    # application override of a plugin class, if the plugin provides the same
    # type of notification or action.
    #
    # This allows the application to customize what happens on a plugin action
    # or model or customize the email notification sent by a plugin. 
    #
    # However, this depends on the plugin being well-behaved and always using
    # the application version of actions, models, and notifications rather than
    # trying to use the plugin class directly.
    #
    # Of course, if the class loader finds such a case, then the application
    # has not chosen to override it and we're generating the empty stub to take
    # it's place.

    # N.B. This is if and not elsif on purpose. If the class name requested is
    # App::Action::(Create|Update|Search|Delete|Execute)Thing, but there is no such
    # model as App::Model::Thing, we may be trying to create a sub-class of
    # Plugin::Action::(Create|Update|Search|Delete|Execute)Thing for
    # Plugin::Model::Thing instead.
    
    # Requesting an application override of a plugin action or notification?
    if ( $module =~ /^(?:$base)::(Action|Model|Notification)::(.*)$/x and not grep {$_ eq $base} map {ref} Jifty->plugins ) {
        my $type = $1;
        my $item = $2;

        # Find a plugin with a matching action or notification
        foreach my $plugin (map {ref} Jifty->plugins) {
            next if ($plugin eq $base);
            my $class = $plugin."::".$type."::".$item;
            # Found it!
            if (Jifty::Util->try_to_require($class) ) {

                # Models need to load their other stuff, but to prevent deep
                # recursion, this must happen after the class is compiled.
                my $module_suffix = '';
                $module_suffix = "Jifty->class_loader"
                               . "->_require_model_related_classes("
                               . "'$module');\n"
                    if $type eq 'Model';

                # Generate the empty stub
                $AUTOGENERATED{$module} = 1;
                return $self->return_class(
                        "package $module;\n"
                        . "use base qw/$class/;\n"
                        . $module_suffix
                    );
            }
        }
    }

    # Didn't find a match
    return undef;
}

=head2 return_class CODE

A helper method; takes CODE as a string and returns an open filehandle
containing that CODE.

=cut

sub return_class {
    my $self = shift;
    my $content = shift;

    # ALWAYS use warnings; use strict!!!
    $content = "use warnings; use strict; ". $content  . "\n1;";

    # Magically turn the text into a file handle
    open my $fh, '<', \$content;
    return $fh;
}

=head2 require

Loads all of the application's Actions and Models.  It additionally
C<require>'s all Collections and Create/Update actions for each Model
base class -- which will auto-create them using the above code if they
do not exist on disk.

=cut

sub require {
    my $self = shift;
    my $base = $self->{base};

    # XXX It would be nice to have a comment here or somewhere in here
    # indicating when it's possible for a class loader to be missing it's base.
    # This is a consistent check in the class loader, but I don't know of an
    # example where this would be the case. -- Sterling

    # if we don't even have an application class, this trick will not work
    return unless ($base);

    # Always require the base and the base current user first
    Jifty::Util->require($base);
    Jifty::Util->require($base."::CurrentUser");

    # Use Module::Pluggable to help locate our models, actions, notifications,
    # and events
    Jifty::Module::Pluggable->import(
        # $base goes last so we pull in the view class AFTER the model classes
        search_path => [map { $base . "::" . $_ } ('Model', 'Action', 'Notification', 'Event')],
        require => 0,
        except  => qr/\.#/,
        inner   => 0
    );
    
    # Construct the list of models for the application for later reference
    my %models;
    for my $p ($self->plugins) {
        Jifty::Util->require($p);
        $models{$p} = 1 if $p =~ m/^($base)::Model::(.*)$/ and not $p =~ m/Collection(?:$||\:\:)/;
    }
    $self->models(sort keys %models);

    # Load all those models and model-related actions, notifications, and events
    for my $full ($self->models) {
        $self->_require_model_related_classes($full);
    }
}

# This class helps Jifty::ClassLoader::require() load each model, the model's
# collection and the model's create, update, delete, and search actions.
sub _require_model_related_classes {
    my $self = shift;
    my $full = shift;
    my $base = $self->{base};
    my($short) = $full =~ /::Model::(\w*)/;
    Jifty::Util->require($full . "Collection");
    Jifty::Util->require($base . "::Action::" . $_ . $short)
        for grep {$full->autogenerate_action($_)} qw/Create Update Delete Search Execute/;
}


=head2 require_classes_from_database

Jifty supports model classes that aren't files on disk but instead records
in your database. It's a little bit mind bending, but basically, you can
build an application entirely out of the database without ever writing a
line of code(*).

* As of early 2007, this forward looking statement is mostly a lie. But we're
working on it.

This method finds all database-backed models and instantiates jifty classes for
them it returns a list of class names of the models it created.

=cut

# XXX TODO FIXME Holy crap! This is in the trunk! See the virtual-models branch
# of Jifty if you really want to see this in action (unless it's finally been
# merged intot he trunk), which isn't the case as of August 13, 2007. 
# -- Sterling
sub require_classes_from_database {
    my $self = shift;
    my @instantiated;

    require Jifty::Model::ModelClassCollection;
    require Jifty::Model::ModelClass;
    my $models = Jifty::Model::ModelClassCollection->new(current_user => Jifty->app_class('CurrentUser')->superuser);
    $models->unlimit();
    while (my $model = $models->next) {
        $model->instantiate();
        $self->_require_model_related_classes($model->qualified_class);
    }
}

=head2 require_views

Load up C<$appname::View>, the view class for the application.

=cut

sub require_views {
    my $self = shift;
    my $base = $self->{base};

    # if we don't even have an application class, this trick will not work
    return unless ($base);
    Jifty::Util->require($base."::View");
}

=head2 models

Accessor to the list of models this application has loaded.

In scalar context, returns a mutable array reference; in list context,
return the content of the array.

=cut

sub models {
    my $self = shift;

    # If we have args, update the list of models
    if (@_) {
        $self->{models} = ref($_[0]) ? $_[0] : \@_;
    }

    # DWIM: return an array if they want a list, return an arrayref otherwise
    wantarray ? @{ $self->{models} ||= [] } : $self->{models};
}

=head2 stringify

ClassLoaders stringify as C<Jifty::ClassLoader(I<base class name>)>

=cut

sub stringify {
    my $self = shift;
    return "Jifty::ClassLoader(@{[$self->{base}]})";
}

=head2 DESTROY

When the ClassLoader gets garbage-collected, its entry in @INC needs
to be removed.

=cut

# The entries in @INC end up having SvTYPE == SVt_RV, but SvRV(sv) ==
# 0x0 and !SvROK(sv) (!?)  This may be something that perl should cope
# with more cleanly.
#
# We call this explictly in an END block in Jifty.pm, because
# otherwise the DESTROY block gets called *after* there's already a
# bogus entry in @INC

# This bug manifests itself as warnings that look like this:

# Use of uninitialized value in require at /tmp/7730 line 9 during global destruction.

sub DESTROY {
    my $self = shift;
    @INC = grep {defined $_ and not (ref $_ and Scalar::Util::refaddr($_) ne Scalar::Util::refaddr($self))} @INC;
}

=head2 autogenerated PACKAGE

Returns true if the package was autogenerated by a classloader.

=cut

sub autogenerated {
    my $class = shift;
    my $classname = shift;
    return $AUTOGENERATED{$classname};
}

=head1 WRITING YOUR OWN CLASSES

If you require more functionality than is provided by the classes created by
ClassLoader (which you'll almost certainly need to do if you want an
application that does more than display a pretty Pony) then you should create a
class with the appropriate name and add your extra logic to it.

For example you will almost certainly want to write your own
dispatcher, so something like:

 package MyApp::Dispatcher;
 use Jifty::Dispatcher -base;

If you want to add some application specific behaviour to a model's
collection class, say for the User model, create F<UserCollection.pm>
in your applications Model directory.

 package MyApp::Model::UserCollection;
 use base 'MyApp::Collection';

=head1 SEE ALSO

L<Jifty> and just about every other class that this provides an empty override for.

=head1 LICENSE

Jifty is Copyright 2005-2010 Best Practical Solutions, LLC.
Jifty is distributed under the same terms as Perl itself.

=cut

1;