File Coverage

lib/UR/ModuleBase.pm
Criterion Covered Total %
statement 169 208 81.2
branch 51 74 68.9
condition 7 27 25.9
subroutine 92 95 96.8
pod 8 8 100.0
total 327 412 79.3


line stmt bran cond sub pod time code
1             # A base class supplying error, warning, status, and debug facilities.
2              
3             package UR::ModuleBase;
4              
5 266     266   108325 use Sub::Name;
  266         127356  
  266         12388  
6 266     266   103490 use Sub::Install;
  266         334091  
  266         923  
7              
8             BEGIN {
9 266     266   7968 use Class::Autouse;
  266         347  
  266         2537  
10             # the file above now does this, but just in case:
11             # subsequent uses of this module w/o the special override should just do nothing...
12 266     266   541 $INC{"Class/Autouse_1_99_02.pm"} = 1;
13 266         454 $INC{"Class/Autouse_1_99_04.pm"} = 1;
14 266     266   9694 no strict;
  266         332  
  266         4560  
15 266     266   849 no warnings;
  266         285  
  266         11046  
16            
17             # ensure that modules which inherit from this never fall into the
18             # replaced UNIVERSAL::can/isa
19 266         702 *can = $Class::Autouse::ORIGINAL_CAN;
20 266         5952 *isa = $Class::Autouse::ORIGINAL_ISA;
21             }
22              
23             =pod
24              
25             =head1 NAME
26              
27             UR::ModuleBase - Methods common to all UR classes and object instances.
28              
29             =head1 DESCRIPTION
30              
31             This is a base class for packages, classes, and objects which need to
32             manage basic functionality in the UR framework such as inheritance,
33             AUTOLOAD/AUTOSUB methods, error/status/warning/etc messages.
34              
35             UR::ModuleBase is in the @ISA list for UR::Object, but UR::ModuleBase is not
36             a formal UR class.
37              
38             =head1 METHODS
39              
40             =cut
41              
42             # set up package
43             require 5.006_000;
44 266     266   954 use warnings;
  266         285  
  266         4786  
45 266     266   782 use strict;
  266         300  
  266         6895  
46             our $VERSION = "0.46"; # UR $VERSION;;
47              
48             # set up module
49 266     266   834 use Carp;
  266         312  
  266         11152  
50 266     266   126687 use IO::Handle;
  266         1211935  
  266         9797  
51 266     266   1376 use UR::Util;
  266         330  
  266         2343  
52              
53             =pod
54              
55             =over
56              
57             =item C
58              
59             $class = $obj->class;
60              
61             This returns the class name of a class or an object as a string.
62             It is exactly equivalent to:
63              
64             (ref($self) ? ref($self) : $self)
65              
66             =cut
67              
68             sub class
69             {
70 643     643 1 584 my $class = shift;
71 643 50       1120 $class = ref($class) if ref($class);
72 643         1301 return $class;
73             }
74              
75             =pod
76              
77             =item C
78              
79             $sub_ref = $obj->super_can('func');
80              
81             This method determines if any of the super classes of the C<$obj>
82             object can perform the method C. If any one of them can,
83             reference to the subroutine that would be called (determined using a
84             depth-first search of the C<@ISA> array) is returned. If none of the
85             super classes provide a method named C, C is returned.
86              
87             =cut
88              
89             sub super_can
90             {
91 34     34 1 149 my $class = shift;
92            
93 34         131 foreach my $parent_class ( $class->parent_classes )
94             {
95 36         164 my $code = $parent_class->can(@_);
96 36 100       366 return $code if $code;
97             }
98 0         0 return;
99             }
100              
101             =pod
102              
103             =item C
104              
105             @classes = $obj->inheritance;
106              
107             This method returns a depth-first list of all the classes (packages)
108             that the class that C<$obj> was blessed into inherits from. This
109             order is the same order as is searched when searching for inherited
110             methods to execute. If the class has no super classes, an empty list
111             is returned. The C class is not returned unless explicitly
112             put into the C<@ISA> array by the class or one of its super classes.
113              
114             =cut
115              
116             sub inheritance {
117 347734     347734 1 269052 my $self = $_[0];
118 347734   66     767030 my $class = ref($self) || $self;
119 347734 100       395567 return unless $class;
120 266     266   30400 no strict;
  266         372  
  266         24095  
121 347733         215677 my @parent_classes = @{$class . '::ISA'};
  347733         839463  
122              
123 347733         219198 my @ordered_inheritance;
124 347733         294217 foreach my $parent_class (@parent_classes) {
125 270807 50       430740 push @ordered_inheritance, $parent_class, ($parent_class eq 'UR' ? () : inheritance($parent_class) );
126             }
127              
128 347733         639948 return @ordered_inheritance;
129             }
130              
131             =pod
132              
133             =item C
134              
135             MyClass->parent_classes;
136              
137             This returns the immediate parent class, or parent classes in the case
138             of multiple inheritance. In no case does it follow the inheritance
139             hierarchy as ->inheritance() does.
140              
141             =cut
142              
143             sub parent_classes
144             {
145 41     41 1 48 my $self = $_[0];
146 41   66     213 my $class = ref($self) || $self;
147 266     266   1037 no strict 'refs';
  266         354  
  266         47944  
148 41         49 my @parent_classes = @{$class . '::ISA'};
  41         188  
149 41 50       126 return (wantarray ? @parent_classes : $parent_classes[0]);
150             }
151              
152             =pod
153              
154             =item C
155              
156             MyModule->base_dir;
157              
158             This returns the base directory for a given module, in which the modules's
159             supplemental data will be stored, such as config files and glade files,
160             data caches, etc.
161              
162             It uses %INC.
163              
164             =cut
165              
166             sub base_dir
167             {
168 0     0 1 0 my $self = shift;
169 0   0     0 my $class = ref($self) || $self;
170 0         0 $class =~ s/\:\:/\//g;
171 0   0     0 my $dir = $INC{$class . '.pm'} || $INC{$class . '.pl'};
172 0 0       0 die "Failed to find module $class in \%INC: " . Data::Dumper(%INC) unless ($dir);
173 0         0 $dir =~ s/\.p[lm]\s*$//;
174 0         0 return $dir;
175             }
176              
177             =pod
178              
179             =item methods
180              
181             Undocumented.
182              
183             =cut
184              
185             sub methods
186             {
187 0     0 1 0 my $self = shift;
188 0         0 my @methods;
189             my %methods;
190 0         0 my ($class, $possible_method, $possible_method_full, $r, $r1, $r2);
191 266     266   1250 no strict;
  266         313  
  266         5119  
192 266     266   1155 no warnings;
  266         319  
  266         84203  
193              
194 0         0 for $class (reverse($self, $self->inheritance()))
195             {
196 0         0 print "$class\n";
197 0         0 for $possible_method (sort grep { not /^_/ } keys %{$class . "::"})
  0         0  
  0         0  
198             {
199 0         0 $possible_method_full = $class . "::" . $possible_method;
200            
201 0         0 $r1 = $class->can($possible_method);
202 0 0       0 next unless $r1; # not implemented
203            
204 0         0 $r2 = $class->super_can($possible_method);
205 0 0       0 next if $r2 eq $r1; # just inherited
206            
207             {
208 0         0 push @methods, $possible_method_full;
  0         0  
209 0         0 push @{ $methods{$possible_method} }, $class;
  0         0  
210             }
211             }
212             }
213 0         0 print Dumper(\%methods);
214 0         0 return @methods;
215             }
216              
217             =pod
218              
219             =item C
220              
221             return MyClass->context_return(@return_values);
222              
223             Attempts to return either an array or scalar based on the calling context.
224             Will die if called in scalar context and @return_values has more than 1
225             element.
226              
227             =cut
228              
229             sub context_return {
230 867080     867080 1 633522 my $class = shift;
231 867080 100       1164740 return unless defined wantarray;
232 867075 100       1054025 return @_ if wantarray;
233 859761 100       1062534 if (@_ > 1) {
234 1         11 my @caller = caller(1);
235 1         255 Carp::croak("Method $caller[3] on $class called in scalar context, but " . scalar(@_) . " items need to be returned");
236             }
237 859760         2942315 return $_[0];
238             }
239              
240             =pod
241              
242             =back
243              
244             =head1 C
245              
246             This package implements AUTOLOAD so that derived classes can use
247             AUTOSUB instead of AUTOLOAD.
248              
249             When a class or object has a method called which is not found in the
250             final class or any derived classes, perl checks up the tree for
251             AUTOLOAD. We implement AUTOLOAD at the top of the tree, and then
252             check each class in the tree in order for an AUTOSUB method. Where a
253             class implements AUTOSUB, it will receive a function name as its first
254             parameter, and it is expected to return either a subroutine reference,
255             or undef. If undef is returned then the inheritance tree search will
256             continue. If a subroutine reference is returned it will be executed
257             immediately with the @_ passed into AUTOLOAD. Typically, AUTOSUB will
258             be used to generate a subroutine reference, and will then associate
259             the subref with the function name to avoid repeated calls to AUTOLOAD
260             and AUTOSUB.
261              
262             Why not use AUTOLOAD directly in place of AUTOSUB?
263              
264             On an object with a complex inheritance tree, AUTOLOAD is only found
265             once, after which, there is no way to indicate that the given AUTOLOAD
266             has failed and that the inheritance tree trek should continue for
267             other AUTOLOADS which might implement the given method.
268              
269             Example:
270              
271             package MyClass;
272             our @ISA = ('UR');
273             ##- use UR;
274            
275             sub AUTOSUB
276             {
277             my $sub_name = shift;
278             if ($sub_name eq 'foo')
279             {
280             *MyClass::foo = sub { print "Calling MyClass::foo()\n" };
281             return \&MyClass::foo;
282             }
283             elsif ($sub_name eq 'bar')
284             {
285             *MyClass::bar = sub { print "Calling MyClass::bar()\n" };
286             return \&MyClass::bar;
287             }
288             else
289             {
290             return;
291             }
292             }
293              
294             package MySubClass;
295             our @ISA = ('MyClass');
296            
297             sub AUTOSUB
298             {
299             my $sub_name = shift;
300             if ($sub_name eq 'baz')
301             {
302             *MyClass::baz = sub { print "Calling MyClass::baz()\n" };
303             return \&MyClass::baz;
304             }
305             else
306             {
307             return;
308             }
309             }
310              
311             package main;
312            
313             my $obj = bless({},'MySubClass');
314             $obj->foo;
315             $obj->bar;
316             $obj->baz;
317              
318             =cut
319              
320             our $AUTOLOAD;
321             sub AUTOLOAD {
322            
323 5     5   8 my $self = $_[0];
324            
325             # The debugger can't see $AUTOLOAD. This is just here for debugging.
326 5         7 my $autoload = $AUTOLOAD;
327            
328 5         28 $autoload =~ /(.*)::([^\:]+)$/;
329 5         15 my $package = $1;
330 5         9 my $function = $2;
331              
332 5 50       18 return if $function eq 'DESTROY';
333              
334 5 50       12 unless ($package) {
335 0         0 Carp::confess("Failed to determine package name from autoload string $autoload");
336             }
337              
338             # switch these to use Class::AutoCAN / CAN?
339 266     266   1180 no strict;
  266         305  
  266         5465  
340 266     266   831 no warnings;
  266         341  
  266         436473  
341 5         23 my @classes = grep {$_} ($self, inheritance($self) );
  5         15  
342 5         14 for my $class (@classes) {
343 4 50       21 if (my $AUTOSUB = $class->can("AUTOSUB"))
344             # FIXME The above causes hard-to-read error messages if $class isn't really a class or object ref
345             # The 2 lines below should fix the problem, but instead make other more impoartant things not work
346             #my $AUTOSUB = eval { $class->can('AUTOSUB') };
347             #if ($AUTOSUB) {
348             {
349 0 0       0 if (my $subref = $AUTOSUB->($function,@_)) {
350 0         0 goto $subref;
351             }
352             }
353             }
354              
355 5 50 33     226 if ($autoload and $autoload !~ /::DESTROY$/) {
356 5         10 my $subref = \&Carp::confess;
357 5         22 @_ = ("Can't locate object method \"$function\" via package \"$package\" (perhaps you forgot to load \"$package\"?)");
358 5         995 goto $subref;
359             }
360             }
361              
362              
363             =pod
364              
365             =head1 MESSAGING
366              
367             UR::ModuleBase implements several methods for sending and storing error, warning and
368             status messages to the user.
369              
370             # common usage
371              
372             sub foo {
373             my $self = shift;
374             ...
375             if ($problem) {
376             $self->error_message("Something went wrong...");
377             return;
378             }
379             return 1;
380             }
381              
382             unless ($obj->foo) {
383             print LOG $obj->error_message();
384             }
385              
386             =head2 Messaging Methods
387              
388             =over 4
389              
390             =item message_types
391              
392             @types = UR::ModuleBase->message_types;
393             UR::ModuleBase->message_types(@more_types);
394              
395             With no arguments, this method returns all the types of messages that
396             this class handles. With arguments, it adds a new type to the
397             list.
398              
399             Standard message types are fatal, error, status, warning, debug and usage.
400              
401             Note that the addition of new types is not fully supported/implemented
402             yet.
403              
404             =back
405              
406             =cut
407              
408             my $create_subs_for_message_type; # filled in lower down
409             my @message_types = qw(error status warning debug usage fatal);
410             sub message_types
411             {
412 266     266 1 6115 my $self = shift;
413 266 50       5941 if (@_)
414             {
415 0         0 foreach my $msg_type ( @_ ) {
416 0 0       0 if (! $self->can("${msg_type}_message")) {
417             # This is a new one
418 0         0 $create_subs_for_message_type->($self, $msg_type);
419 0         0 push @message_types, $msg_type;
420             }
421             }
422             } else {
423 266         2799 return grep { $self->can($_ . '_message') } @message_types;
  1596         8967  
424             }
425             }
426              
427              
428             # Most defaults are false
429             my %default_messaging_settings;
430             $default_messaging_settings{dump_error_messages} = 1;
431             $default_messaging_settings{dump_warning_messages} = 1;
432             $default_messaging_settings{dump_status_messages} = 1;
433             $default_messaging_settings{dump_fatal_messages} = 1;
434              
435             #
436             # Implement error_mesage/warning_message/status_message in a way
437             # which handles object-specific callbacks.
438             #
439             # Build a set of methods for getting/setting/printing error/warning/status messages
440             # $class->dump_error_messages() Turn on/off printing the messages to STDERR
441             # error and warnings default to on, status messages default to off
442             # $class->queue_error_messages() Turn on/off queueing of messages
443             # defaults to off
444             # $class->error_message("blah"): set an error message
445             # $class->error_message() return the last message
446             # $class->error_messages() return all the messages that have been queued up
447             # $class->error_messages_arrayref() return the reference to the underlying
448             # list messages get queued to. This is the method for truncating the list
449             # or altering already queued messages
450             # $class->error_messages_callback() Specify a callback for when error
451             # messages are set. The callback runs before printing or queueing, so
452             # you can alter @_ and change the message that gets printed or queued
453             # And then the same thing for status and warning messages
454              
455             =pod
456              
457             For each message type, several methods are created for sending and retrieving messages,
458             registering a callback to run when messages are sent, controlling whether the messages
459             are printed on the terminal, and whether the messages are queued up.
460              
461             For example, for the "error" message type, these methods are created:
462              
463             =over 4
464              
465             =item error_message
466              
467             $obj->error_message("Something went wrong...");
468             $obj->error_message($format, @list);
469             $msg = $obj->error_message();
470              
471             When called with one or more arguments, it sends an error message to the
472             object. The error_message_callback will be run, if one is registered, and the
473             message will be printed to the terminal. When given a single argument, it will
474             be passed through unmodified. When given multiple arguments, error_message will
475             assume the first is a format string and the remainder are parameters to
476             sprintf. When called with no arguments, the last message sent will be
477             returned. If the message is C then no message is printed or queued, and
478             the next time error_message is run as an accessor, it will return
479             undef.
480              
481             Note that C will throw an exception at the point it appears
482             in the program. This exception, like others, is trappable bi C.
483              
484             =item dump_error_messages
485              
486             $obj->dump_error_messages(0);
487             $flag = $obj->dump_error_messages();
488              
489             Get or set the flag which controls whether messages sent via C
490             is printed to the terminal. This flag defaults to true for warning and error
491             messages, and false for others.
492              
493             Note that C messages and exceptions do not honor the value of
494             C, and always print their message and throw their
495             exception unless trapped with an C.
496              
497             =item queue_error_messages
498              
499             $obj->queue_error_messages(0);
500             $flag = $obj->queue_error_messages();
501              
502             Get or set the flag which control whether messages send via C
503             are saved into a list. If true, every message sent is saved and can be retrieved
504             with L or L. This flag defaults to
505             false for all message types.
506              
507             =item error_messages_callback
508              
509             $obj->error_messages_callback($subref);
510             $subref = $obj->error_messages_callback();
511              
512             Get or set the callback run whenever an error_message is sent. This callback
513             is run with two arguments: The object or class error_message() was called on,
514             and a string containing the message. This callback is run before the message
515             is printed to the terminal or queued into its list. The callback can modify
516             the message (by writing to $_[1]) and affect the message that is printed or
517             queued. If $_[1] is set to C, then no message is printed or queued,
518             and the last recorded message is set to undef as when calling error_message
519             with undef as the argument.
520              
521             =item error_messages
522              
523             @list = $obj->error_messages();
524              
525             If the queue_error_messages flag is on, then this method returns the entire list
526             of queued messages.
527              
528             When called as an instance method, it returns the errors queued only on that
529             object. When called as a class method, it returns the errors queued on that
530             class, all it's subclasses, and all instances of that class or subclasses.
531              
532             =item error_messages_arrayref
533              
534             $listref = $obj->error_messages_arrayref();
535              
536             If the queue_error_messages flag is on, then this method returns a reference to
537             the actual list where messages get queued. This list can be manipulated to add
538             or remove items.
539              
540             =item error_message_source
541              
542             %source_info = $obj->error_message_source
543              
544             Returns a hash of information about the most recent call to error_message.
545             The key "error_message" contains the message. The keys error_package,
546             error_file, error_line and error_subroutine contain info about the location
547             in the code where error_message() was called.
548              
549             =item error_package
550              
551             =item error_file
552              
553             =item error_line
554              
555             =item error_subroutine
556              
557             These methods return the same data as $obj->error_message_source().
558              
559             =back
560              
561             =cut
562              
563             our $stderr = \*STDERR;
564             our $stdout = \*STDOUT;
565             my %message_settings;
566              
567             # This sub creates the settings mutator subs for each message type
568             # For example, when passed in 'error', it creates the subs error_messages_callback,
569             # queue_error_messages, dump_error_messages, etc
570             $create_subs_for_message_type = sub {
571             my($self, $type) = @_;
572              
573             my $class = ref($self) ? $self->class : $self;
574              
575             my $save_setting = sub {
576             my($self, $name, $val) = @_;
577             if (ref $self) {
578             $message_settings{ $self->class . '::' . $name . '_by_id' }->{$self->id} = $val;
579             } else {
580             $message_settings{ $self->class . '::' . $name } = $val;
581             }
582             };
583             my $get_setting = sub {
584             my($self, $name) = @_;
585             if (ref $self) {
586             return exists($message_settings{ $self->class . '::' . $name . '_by_id' })
587             ? $message_settings{ $self->class . '::' . $name . '_by_id' }->{$self->id}
588             : undef;
589             } else {
590             return $message_settings{ $self->class . '::' . $name };
591             }
592             };
593              
594             my $make_mutator = sub {
595             my $name = shift;
596             return sub {
597 6044     6044   31225 my $self = shift;
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
        6044      
598              
599 6044 100       7887 if (@_) {
600             # setting the value
601 1535         2395 $save_setting->($self, $name, @_);
602              
603             } else {
604             # getting the value
605 4509         4961 my $val = $get_setting->($self, $name);
606 4509 100       6588 if (defined $val) {
    100          
607 1038         2098 return $val;
608              
609             } elsif (ref $self) {
610             # called on an object and no value set, try the class
611 271         516 return $self->class->$name();
612              
613             } else {
614             # called on a class name
615 3200         37279 my @super = $self->inheritance();
616 3200         3369 foreach my $super ( @super ) {
617 2581 50       5509 if (my $super_sub = $super->can($name)) {
618 2581         14890 return $super_sub->($super);
619             }
620             }
621             # None of the parent classes implement it, or there aren't
622             # any parent classes
623 619         3209 return $default_messaging_settings{$name};
624             }
625             }
626             };
627             };
628              
629             foreach my $base ( qw( %s_messages_callback queue_%s_messages %s_package
630             %s_file %s_line %s_subroutine )
631             ) {
632             my $method = sprintf($base, $type);
633             my $full_name = $class . '::' . $method;
634              
635             my $method_subref = Sub::Name::subname $full_name => $make_mutator->($method);
636             Sub::Install::install_sub({
637             code => $method_subref,
638             into => $class,
639             as => $method,
640             });
641             }
642              
643             my $should_dump_messages = "dump_${type}_messages";
644             my $dump_mutator = $make_mutator->($should_dump_messages);
645             my @dump_env_vars = map { $_ . uc($should_dump_messages) } ('UR_', 'UR_COMMAND_');
646             my $should_dump_messages_subref = Sub::Name::subname $class . '::' . $should_dump_messages => sub {
647 1007     1007   61450 my $self = shift;
        1007      
        1007      
        1007      
        1007      
        1007      
648 1007 100       1673 if (@_) {
649 131         318 return $dump_mutator->($self, @_);
650             }
651 876         900 foreach my $varname ( @dump_env_vars ) {
652 1752 50       3051 return $ENV{$varname} if (defined $ENV{$varname});
653             }
654 876         1177 return $dump_mutator->($self);
655             };
656             Sub::Install::install_sub({
657             code => $should_dump_messages_subref,
658             into => $class,
659             as => $should_dump_messages,
660             });
661              
662              
663             my $messages_arrayref = "${type}_messages_arrayref";
664             my $message_arrayref_sub = Sub::Name::subname "${class}::${messages_arrayref}" => sub {
665 104     104   110 my $self = shift;
        104      
        104      
        104      
        104      
        104      
666 104         150 my $a = $get_setting->($self, $messages_arrayref);
667 104 100       218 if (! defined $a) {
668 20         57 $save_setting->($self, $messages_arrayref, $a = []);
669             }
670 104         149 return $a;
671             };
672             Sub::Install::install_sub({
673             code => $message_arrayref_sub,
674             into => $class,
675             as => $messages_arrayref,
676             });
677              
678             my $array_subname = "${type}_messages";
679             my $array_subref = Sub::Name::subname "${class}::${array_subname}" => sub {
680 177     177   23060 my $self = shift;
        177      
        177      
        177      
        177      
        177      
681 177 100       701 my @search = ref($self)
682             ? $self
683             : ( $self, $self->__meta__->subclasses_loaded, $self->is_loaded() );
684 177         218 my %seen;
685             my @all_messages;
686 177         204 foreach my $thing ( @search ) {
687 182 50       517 next if $seen{$thing}++;
688 182         282 my $a = $get_setting->($thing, $messages_arrayref);
689 182 100       426 push @all_messages, $a ? @$a : ();
690             }
691 177         700 return @all_messages;
692             };
693             Sub::Install::install_sub({
694             code => $array_subref,
695             into => $class,
696             as => $array_subname,
697             });
698              
699              
700             my $messageinfo_subname = "${type}_message_source";
701             my @messageinfo_keys = map { $type . $_ } qw( _message _package _file _line _subroutine );
702             my $messageinfo_subref = Sub::Name::subname "${class}::${messageinfo_subname}" => sub {
703 36     36   12322 my $self = shift;
        36      
        36      
        36      
        36      
        36      
704 36         60 return map { $_ => $self->$_ } @messageinfo_keys;
  180         300  
705             };
706             Sub::Install::install_sub({
707             code => $messageinfo_subref,
708             into => $class,
709             as => $messageinfo_subname,
710             });
711              
712             # usage messages go to STDOUT, others to STDERR
713             my $default_fh = $type eq 'usage' ? \$stdout : \$stderr;
714              
715             my $should_queue_messages = "queue_${type}_messages";
716             my $check_callback = "${type}_messages_callback";
717             my $message_text_prefix = ($type eq 'status' or $type eq 'usage') ? '' : uc($type) . ': ';
718             my $message_package = "${type}_package";
719             my $message_file = "${type}_file";
720             my $message_line = "${type}_line";
721             my $message_subroutine = "${type}_subroutine";
722              
723             my $messaging_action = $type eq 'fatal'
724             ? sub { Carp::croak($message_text_prefix . $_[1]) }
725             : sub {
726             my($self, $msg) = @_;
727             if (my $fh = $self->$should_dump_messages()) {
728             $fh = $$default_fh unless (ref $fh);
729              
730             $fh->print($message_text_prefix . $msg . "\n");
731             }
732             };
733              
734             my $logger_subname = "${type}_message";
735             my $logger_subref = Sub::Name::subname "${class}::${logger_subname}" => sub {
736 571     571   83754 my $self = shift;
        571      
        571      
        571      
        571      
        571      
737              
738 571 100       1265 if (@_) {
739 383         457 my $msg = shift;
740              
741             # if given multiple arguments, assume it's a format string
742 383 100       803 if(@_) {
743 42         94 $msg = _carp_sprintf($msg, @_);
744             }
745              
746 383 100       1007 defined($msg) && chomp($msg);
747              
748             # old-style callback registered with error_messages_callback
749 383 100       1205 if (my $code = $self->$check_callback()) {
750 188 50       374 if (ref $code) {
751 188         419 $code->($self, $msg);
752             } else {
753 0         0 $self->$code($msg);
754             }
755             }
756              
757             # New-style callback registered as an observer
758             # Some non-UR classes inherit from UR::ModuleBase, and can't __signal
759 383 50 33     2564 if ($UR::initialized && $self->can('__signal_observers__')) {
760 383         3293 $self->__signal_observers__($logger_subname, $msg);
761             }
762              
763 383         804 $save_setting->($self, $logger_subname, $msg);
764             # If the callback set $msg to undef with "$_[1] = undef", then they didn't want the message
765             # processed further
766 383 100       883 if (defined $msg) {
767 272 100       818 if ($self->$should_queue_messages()) {
768 66         195 my $a = $self->$messages_arrayref();
769 66         104 push @$a, $msg;
770             }
771              
772 272         801 my ($package, $file, $line, $subroutine) = caller;
773 272         1015 $self->$message_package($package);
774 272         766 $self->$message_file($file);
775 272         751 $self->$message_line($line);
776 272         739 $self->$message_subroutine($subroutine);
777              
778 272         532 $self->$messaging_action($msg);
779              
780             }
781             }
782              
783 544         3596 return $get_setting->($self, $logger_subname);
784             };
785             Sub::Install::install_sub({
786             code => $logger_subref,
787             into => $class,
788             as => $logger_subname,
789             });
790              
791             # "Register" the message type as a valid signal.
792             $UR::Object::Type::STANDARD_VALID_SIGNALS{$logger_subname} = 1;
793             };
794              
795             sub _carp_sprintf {
796 42     42   43 my $format = shift;
797 42         69 my @list = @_;
798              
799             # warnings weren't very helpful because they wouldn't tell you who passed
800             # in the "bad" format string
801 42         44 my $formatted_string;
802             my $warn_msg;
803             {
804 42         42 local $SIG{__WARN__} = sub {
805 6     6   6 my $msg = $_[0];
806 6         11 my ($filename, $line) = (caller)[1, 2];
807 6         57 my $short_msg = ($msg =~ /(.*) at $filename line $line./)[0];
808 6   33     45 $warn_msg = ($short_msg || $msg);
809 42         242 };
810 42         312 $formatted_string = sprintf($format, @list);
811             }
812 42 100       82 if ($warn_msg) {
813 3         528 Carp::carp($warn_msg);
814             }
815              
816 42         369 return $formatted_string;
817             }
818              
819              
820             # at init time, make messaging subs for the initial message types
821             $create_subs_for_message_type->(__PACKAGE__, $_) foreach @message_types;
822              
823              
824             sub _current_call_stack
825             {
826 0     0     my @stack = reverse split /\n/, Carp::longmess("\t");
827              
828             # Get rid of the final line from carp, showing the line number
829             # above from which we called it.
830 0           pop @stack;
831              
832             # Get rid any other function calls which are inside of this
833             # package besides the first one. This allows wrappers to
834             # get_message to look at just the external call stack.
835             # (i.e. AUTOSUB above, set_message/get_message which called this,
836             # and AUTOLOAD in UniversalParent)
837 0   0       pop(@stack) while ($stack[-1] =~ /^\s*(UR::ModuleBase|UR)::/ && $stack[-2] && $stack[-2] =~ /^\s*(UR::ModuleBase|UR)::/);
      0        
838              
839 0           return \@stack;
840             }
841              
842              
843             1;
844             __END__