File Coverage

lib/UR/Util.pm
Criterion Covered Total %
statement 215 332 64.7
branch 61 112 54.4
condition 17 30 56.6
subroutine 37 52 71.1
pod 9 29 31.0
total 339 555 61.0


line stmt bran cond sub pod time code
1              
2             package UR::Util;
3              
4 266     266   1243 use warnings;
  266         265  
  266         7254  
5 266     266   850 use strict;
  266         250  
  266         7963  
6             require UR;
7             our $VERSION = "0.46"; # UR $VERSION;
8 266     266   814 use Cwd;
  266         254  
  266         11830  
9 266     266   140429 use Data::Dumper;
  266         1795319  
  266         13766  
10 266     266   102302 use Clone::PP;
  266         152056  
  266         1253  
11 266     266   9163 use Config;
  266         343  
  266         10114  
12 266     266   113507 use Module::Runtime v0.014 qw(module_notional_filename);
  266         341886  
  266         1270  
13              
14             sub on_destroy(&) {
15 3     3 0 1229 my $sub = shift;
16 3 50       8 unless ($sub) {
17 0         0 Carp::confess("expected an anonymous sub!")
18             }
19 3         13 return bless($sub, "UR::Util::CallOnDestroy");
20             }
21              
22             # used only by the above sub
23             # the local $@ ensures that we this does not stomp on thrown exceptions
24 3     3   862 sub UR::Util::CallOnDestroy::DESTROY { local $@; shift->(); }
  3         14  
25              
26             sub d {
27 0     0 0 0 Data::Dumper->new([@_])->Terse(1)->Indent(0)->Useqq(1)->Dump;
28             }
29              
30       1899 0   sub null_sub { }
31              
32             sub used_libs {
33 9     9 0 13372 my @extra;
34 9         18 my @compiled_inc = UR::Util::compiled_inc();
35 9         52 my @perl5lib = split(':', $ENV{PERL5LIB});
36 9         13 map { $_ =~ s/\/+$// } (@compiled_inc, @perl5lib); # remove trailing slashes
  67         127  
37 9   33     9 map { $_ = Cwd::abs_path($_) || $_ } (@compiled_inc, @perl5lib);
  67         2220  
38 9         18 for my $inc (@INC) {
39 38         75 $inc =~ s/\/+$//;
40 38   33     1068 my $abs_inc = Cwd::abs_path($inc) || $inc; # should already be expanded by UR.pm
41 38 100       41 next if (grep { $_ =~ /^$abs_inc$/ } @compiled_inc);
  228         642  
42 28 100       28 next if (grep { $_ =~ /^$abs_inc$/ } @perl5lib);
  60         266  
43 11 50       105 next if ((File::Spec->splitdir($inc))[-1] eq $Config{archname});
44 11         26 push @extra, $inc;
45             }
46              
47 9 100       23 unshift @extra, ($ENV{PERL_USED_ABOVE} ? split(":", $ENV{PERL_USED_ABOVE}) : ());
48              
49 9         10 map { $_ =~ s/\/+$// } @extra; # remove trailing slashes again
  12         28  
50 9         18 @extra = _unique_elements(@extra);
51              
52 9         35 return @extra;
53             }
54              
55             sub _unique_elements {
56 9     9   13 my @list = @_;
57 9         13 my %seen = ();
58 9         11 my @unique = grep { ! $seen{$_} ++ } @list;
  12         30  
59 9         18 return @unique;
60             }
61              
62             sub used_libs_perl5lib_prefix {
63 0     0 0 0 my $prefix = "";
64 0         0 for my $i (used_libs()) {
65 0         0 $prefix .= "$i:";
66             }
67 0         0 return $prefix;
68             }
69              
70             sub touch_file {
71 0     0 0 0 my $filename = shift;
72 0         0 open(my $fh, '>>', $filename);
73             }
74              
75             my @compiled_inc;
76             BEGIN {
77 266     266   124813 use Config;
  266         420  
  266         50313  
78              
79 266     266   949 my @var_list = (
80             'updatesarch', 'updateslib',
81             'archlib', 'privlib',
82             'sitearch', 'sitelib', 'sitelib_stem',
83             'vendorarch', 'vendorlib', 'vendorlib_stem',
84             'extrasarch', 'extraslib',
85             );
86              
87 266         479 for my $var_name (@var_list) {
88 3192 100 66     26671 if ($var_name =~ /_stem$/ && $Config{$var_name}) {
89 266         1595 my @stem_list = (split(' ', $Config{'inc_version_list'}), '');
90 266         593 push @compiled_inc, map { $Config{$var_name} . "/$_" } @stem_list
  266         1803  
91             } else {
92 2926 100       108841 push @compiled_inc, $Config{$var_name} if $Config{$var_name};
93             }
94             }
95              
96             # UR locks in relative paths when loaded so instead of adding '.' we add cwd
97 266 50       517528 push @compiled_inc, Cwd::cwd() if (${^TAINT} == 0);
98              
99 266         1835 map { $_ =~ s/\/+/\//g } @compiled_inc;
  1596         8955  
100 266         6817 map { $_ =~ s/\/+$// } @compiled_inc;
  1596         140112  
101             }
102             sub compiled_inc {
103 19     19 0 114 return @compiled_inc;
104             }
105              
106             sub deep_copy {
107 670     670 0 2997 return Clone::PP::clone($_[0]);
108             }
109              
110             sub value_positions_map {
111 0     0 0 0 my ($array) = @_;
112 0         0 my %value_pos;
113 0         0 for (my $pos = 0; $pos < @$array; $pos++) {
114 0         0 my $value = $array->[$pos];
115 0 0       0 if (exists $value_pos{$value}) {
116 0         0 die "Array has duplicate values, which cannot unambiguously be given value positions!"
117             . Data::Dumper::Dumper($array);
118             }
119 0         0 $value_pos{$value} = $pos;
120             }
121 0         0 return \%value_pos;
122             }
123              
124             sub positions_of_values {
125             # my @pos = positions_of_values(\@unordered_crap, \@correct_order);
126             # my @fixed = @unordered_crap[@pos];
127 0     0 0 0 my ($unordered_array,$ordered_array) = @_;
128 0         0 my $map = value_positions_map($unordered_array);
129 0         0 my @translated_positions;
130 0         0 $#translated_positions = $#$ordered_array;
131 0         0 for (my $pos = 0; $pos < @$ordered_array; $pos++) {
132 0         0 my $value = $ordered_array->[$pos];
133 0         0 my $unordered_position = $map->{$value};
134 0         0 $translated_positions[$pos] = $unordered_position;
135             }
136             # self-test:
137             # my @now_ordered = @$unordered_array[@translated_positions];
138             # unless ("@now_ordered" eq "@$ordered_array") {
139             # Carp::confess()
140             # }
141 0         0 return @translated_positions;
142             }
143              
144              
145             # Get all combinations of values
146             # input is a list of listrefs of values
147             sub combinations_of_values {
148 99 100   99 0 240 return [] unless @_;
149              
150 40         45 my $first_values = shift;
151              
152 40 50 33     183 $first_values = [ $first_values ] unless (ref($first_values) and ref($first_values) eq 'ARRAY');
153              
154 40         33 my @retval;
155 40         103 foreach my $sub_combination ( &combinations_of_values(@_) ) {
156 40         55 foreach my $value ( @$first_values ) {
157 43         94 push @retval, [$value, @$sub_combination];
158             }
159             }
160              
161 40         92 return @retval;
162             }
163              
164             # generate a method
165             sub _define_method {
166 2926     2926   3270 my $class = shift;
167 2926         7376 my (%opts) = @_;
168              
169             # create method name
170 2926         5182 my $method = $opts{pkg} . '::' . $opts{property};
171              
172             # determine return value type
173 2926         2260 my $retval;
174 2926 100       4764 if (defined($opts{value}))
175             {
176 532         1376 my $refval = ref($opts{value});
177 532 50       1504 $retval = ($refval) ? $refval : 'SCALAR';
178             }
179             else
180             {
181 2394         2460 $retval = 'SCALAR';
182             }
183              
184             # start defining method
185 2926         4351 my $substr = "sub $method { my \$self = shift; ";
186              
187             # set default value
188 2926         4052 $substr .= "\$self->{$opts{property}} = ";
189 2926         12835 my $dd = Data::Dumper->new([ $opts{value} ]);
190 2926         65351 $dd->Terse(1); # do not print ``$VAR1 =''
191 2926         14143 $substr .= $dd->Dump;
192 2926         48221 $substr .= " unless defined(\$self->{$opts{property}}); ";
193              
194             # array or scalar?
195 2926 100       4880 if ($retval eq 'ARRAY') {
196 532 100       1888 if ($opts{access} eq 'rw') {
197             # allow setting of array
198 266         847 $substr .= "\$self->{$opts{property}} = [ \@_ ] if (\@_); ";
199             }
200              
201             # add return value
202 532         1467 $substr .= "return \@{ \$self->{$opts{property}} }; ";
203             }
204             else { # scalar
205 2394 100       4748 if ($opts{access} eq 'rw') {
206             # allow setting of scalar
207 532         1284 $substr .= "\$self->{$opts{property}} = \$_[0] if (\@_); ";
208             }
209              
210             # add return value
211 2394         3488 $substr .= "return \$self->{$opts{property}}; ";
212             }
213              
214             # end the subroutine definition
215 2926         2590 $substr .= "}";
216              
217             # actually define the method
218 266     266   2400 no warnings qw(redefine);
  266         444  
  266         409283  
219 2926 0   0 1 168983 eval($substr);
  0 50   13 1 0  
  0 50   0 1 0  
  0 0   0   0  
  0 0   0   0  
  13 0   0   18  
  13 0   154   34  
  13 50   0   20  
  13 50   0   36  
  0 0   43   0  
  0 0   19   0  
  0 50       0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  154         223  
  154         394  
  154         332  
  154         176  
  154         451  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  43         343  
  43         118  
  43         86  
  43         129  
  19         29  
  19         45  
  19         48  
220 2926 50       6512 if ($@) {
221             # fatal error since this is like a failed compilation
222 0         0 die("failed to defined method $method {$substr}:$@");
223             }
224 2926         16828 return 1;
225             }
226              
227             =pod
228              
229             =over
230              
231             =item path_relative_to
232              
233             $rel_path = UR::Util::path_relative_to($base, $target);
234              
235             Returns the pathname to $target relative to $base. If $base
236             and $target are the same, then it returns '.'. If $target is
237             a subdirectory of of $base, then it returns the portion of $target
238             that is unique compared to $base. If $target is not a subdirectory
239             of $base, then it returns a relative pathname starting with $base.
240              
241             =back
242              
243             =cut
244              
245             sub path_relative_to {
246 70     51 1 110 my($base,$target) = @_;
247              
248 51         1137 $base = Cwd::abs_path($base);
249 51         1783 $target = Cwd::abs_path($target);
250              
251 51         118 my @base_path_parts = split('/', $base);
252 51         87 my @target_path_parts = split('/', $target);
253 51         37 my $i;
254 51   66     711 for ($i = 0;
255             $i < @base_path_parts and $base_path_parts[$i] eq $target_path_parts[$i];
256             $i++
257             ) { ; }
258              
259 51         149 my $rel_path = '../' x (scalar(@base_path_parts) - $i)
260             .
261             join('/', @target_path_parts[$i .. $#target_path_parts]);
262 51 100       73 $rel_path = '.' unless length($rel_path);
263 51         400 return $rel_path;
264             }
265            
266             =pod
267              
268             =over
269              
270             =item generate_readwrite_methods
271              
272             UR::Util->generate_readwrite_methods
273             (
274             some_scalar_property => 1,
275             some_array_property => []
276             );
277              
278             This method generates accessor/set methods named after the keys of its
279             hash argument. The type of function generated depends on the default
280             value provided as the hash key value. If the hash key is a scalar, a
281             scalar method is generated. If the hash key is a reference to an
282             array, an array method is generated.
283              
284             This method does not overwrite class methods that already exist.
285              
286             =back
287              
288             =cut
289              
290             sub generate_readwrite_methods
291             {
292 266     266 1 602 my $class = shift;
293 266         762 my %properties = @_;
294              
295             # get package of caller
296 266         618 my $pkg = caller;
297              
298             # loop through properties
299 266         1063 foreach my $property (keys(%properties)) {
300             # do not overwrite defined methods
301 798 50       3257 next if $pkg->can($property);
302              
303             # create method
304             $class->_define_method
305             (
306             pkg => $pkg,
307             property => $property,
308 798         33047 value => $properties{$property},
309             access => 'rw'
310             );
311             }
312              
313 266         944 return 1;
314             }
315              
316             =pod
317              
318             =over
319              
320             =item generate_readwrite_methods_override
321              
322             UR::Util->generate_readwrite_methods_override
323             (
324             some_scalar_property => 1,
325             some_array_property => []
326             );
327              
328             Same as generate_readwrite_function except that we force the functions
329             into the namespace even if the function is already defined
330              
331             =back
332              
333             =cut
334              
335             sub generate_readwrite_methods_override
336             {
337 0     0 1 0 my $class = shift;
338 0         0 my %properties = @_;
339              
340             # get package of caller
341 0         0 my $pkg = caller;
342              
343             # generate the methods for each property
344 0         0 foreach my $property (keys(%properties)) {
345             # create method
346             $class->_define_method
347             (
348             pkg => $pkg,
349             property => $property,
350 0         0 value => $properties{$property},
351             access => 'rw'
352             );
353             }
354              
355 0         0 return 1;
356             }
357              
358             =pod
359              
360             =over
361              
362             =item generate_readonly_methods
363              
364             UR::Util->generate_readonly_methods
365             (
366             some_scalar_property => 1,
367             some_array_property => []
368             );
369              
370             This method generates accessor methods named after the keys of its
371             hash argument. The type of function generated depends on the default
372             value provided as the hash key value. If the hash key is a scalar, a
373             scalar method is generated. If the hash key is a reference to an
374             array, an array method is generated.
375              
376             This method does not overwrite class methods that already exist.
377              
378             =back
379              
380             =cut
381              
382             sub generate_readonly_methods
383             {
384 266     266 1 480 my $class = shift;
385 266         1987 my %properties = @_;
386              
387             # get package of caller
388 266         873 my ($pkg) = caller;
389              
390             # loop through properties
391 266         1070 foreach my $property (keys(%properties)) {
392             # do no overwrite already defined methods
393 2128 50       6507 next if $pkg->can($property);
394              
395             # create method
396             $class->_define_method
397             (
398             pkg => $pkg,
399             property => $property,
400 2128         70405 value => $properties{$property},
401             access => 'ro'
402             );
403             }
404              
405 266         983 return 1;
406             }
407              
408             =pod
409              
410             =over
411              
412             =item object
413              
414             my $o = UR::Util::object($something);
415              
416             Return the object form of the supplied argument. For regular objects, it
417             returns the argument unchanged. For singleton class names, it returns the
418             instance of the Singleton. For other class names, it throws an exception.
419              
420             =back
421              
422             =cut
423              
424             sub object {
425 1235     1235 1 2998 my $it = shift;
426              
427 1235 100       2659 unless (ref $it) {
428 1 50       6 if ($it->isa('UR::Singleton')) {
429 1         22 $it = $it->_singleton_object();
430             } else {
431 0         0 Carp::croak("Expected an object instance or Singleton class name, but got '$it'");
432             }
433             }
434 1235         1928 return $it;
435             }
436              
437             =pod
438              
439             =over
440              
441             =item mapreduce_grep
442              
443             my @matches = UR::Util->map_reduce_grep { shift->some_test } @candidates;
444              
445             Works similar to the Perl C builtin, but in a possibly-parallel fashion.
446             If the environment variable UR_NR_CPU is set to a number greater than one, it
447             will fork off child processes to perform the test on slices of the input
448             list, collect the results, and return the matching items as a list.
449              
450             The test function is called with a single argument, an item from the list to
451             be tested, and should return a true of false value.
452              
453             =back
454              
455             =cut
456              
457             sub mapreduce_grep($&@) {
458 0     0 1 0 my $class = shift;
459 0         0 my $subref = shift;
460             #$DB::single = 1;
461              
462              
463             # First check fast... should we do parallel at all?
464 0 0 0     0 if (!$ENV{'UR_NR_CPU'} or $ENV{'UR_NR_CPU'} < 2) {
465             #return grep { $subref->($_) } @_;
466 0         0 my @ret = grep { $subref->($_) } @_;
  0         0  
467 0         0 return @ret;
468             }
469              
470 0         0 my(@read_handles, @child_pids);
471             my $cleanup = sub {
472 0     0   0 foreach my $handle ( @read_handles ) {
473 0         0 $handle->close();
474             }
475              
476 0         0 kill 'TERM', @child_pids;
477              
478 0         0 foreach my $pid ( @child_pids ) {
479 0         0 waitpid($pid,0);
480             }
481 0         0 };
482              
483 0         0 my @things_to_check = @_;
484 0         0 my($children, $length,$parent_last);
485 0 0       0 if ($ENV{'UR_NR_CPU'}) {
486 0         0 $length = POSIX::ceil(scalar(@things_to_check) / $ENV{'UR_NR_CPU'});
487 0         0 $children = $ENV{'UR_NR_CPU'} - 1;
488             } else {
489 0         0 $children = 0;
490 0         0 $parent_last = $#things_to_check;
491             }
492              
493             # FIXME - There needs to be some code in here to disconnect datasources
494             # Oracle in particular (maybe all DBs?), stops working right unless you
495             # disconnect before forking
496              
497 0         0 my $start = $length; # First child starts checking after parent's range
498 0         0 $parent_last = $length - 1;
499 0         0 while ($children-- > 0) {
500 0         0 my $pipe = IO::Pipe->new();
501 0 0       0 unless ($pipe) {
502 0         0 Carp::carp("pipe() failed: $!\nUnable to create pipes to communicate with child processes to verify transact+ion, falling back to serial verification");
503 0         0 $cleanup->();
504 0         0 $parent_last = $#things_to_check;
505 0         0 last;
506             }
507              
508 0         0 my $pid = fork();
509 0 0       0 if ($pid) {
    0          
510 0         0 $pipe->reader();
511 0         0 push @read_handles, $pipe;
512 0         0 $start += $length;
513              
514             } elsif (defined $pid) {
515 0         0 $pipe->writer();
516 0         0 my $last = $start + $length;
517 0 0       0 $last = $#things_to_check if ($last > $#things_to_check);
518              
519             #my @objects = grep { $subref->($_) } @things_to_check[$start .. $last];
520 0         0 my @matching;
521 0         0 for (my $i = $start; $i <= $last; $i++) {
522 0 0       0 if ($subref->($things_to_check[$i])) {
523 0         0 push @matching, $i;
524             }
525             }
526             # FIXME - when there's a more general framework for passing objects between
527             # processes, use that instead
528             #$pipe->printf("%s\n%s\n",$_->class, $_->id) foreach @objects;
529 0         0 $pipe->print("$_\n") foreach @matching;
530              
531              
532 0         0 exit;
533              
534             } else {
535 0         0 Carp::carp("fork() failed: $!\nUnable to create child processes to ver+ify transaction, falling back to seri+al verification");
536 0         0 $cleanup->();
537 0         0 $parent_last = $#things_to_check;
538             }
539             }
540 0         0 my @matches = grep { $subref->($_) } @things_to_check[0 .. $parent_last];
  0         0  
541              
542 0         0 foreach my $handle ( @read_handles ) {
543             READ_FROM_CHILD:
544 0         0 while(1) {
545 0         0 my $match_idx = $handle->getline();
546 0 0       0 last READ_FROM_CHILD unless $match_idx;
547 0         0 chomp $match_idx;
548              
549 0         0 push @matches, $things_to_check[$match_idx];
550             #my $match_class = $handle->getline();
551             #last READ_FROM_CHILD unless $match_class;
552             #chomp($match_class);
553              
554             #my $match_id = $handle->getline();
555             #unless (defined $match_id) {
556             # Carp::carp("Protocol error. Tried to get object ID for class $match_class while verifying transaction"+);
557             # last READ_FROM_CHILD;
558             #}
559             #chomp($match_id);
560              
561             #push @objects, $match_class->get($match_id);
562             }
563 0         0 $handle->close();
564             }
565              
566 0         0 $cleanup->();
567              
568 0         0 return @matches;
569             }
570              
571              
572             # Used in several places when printing out hash-like parameters
573             # to the user, such as in error messages
574             sub display_string_for_params_list {
575 1     1 0 1 my $class = shift;
576              
577 1         2 my %params;
578 1 50       2 if (ref($_[0]) =~ 'HASH') {
579 0         0 %params = %{$_[0]};
  0         0  
580             } else {
581 1         3 %params = @_;
582             }
583              
584 1         1 my @strings;
585 1         5 foreach my $key ( keys %params ) {
586 1         1 my $val = $params{$key};
587 1 50       4 $val = defined($val) ? "'$val'" : '(undef)';
588 1         3 push @strings, "$key => $val";
589             }
590 1         223 return join(', ', @strings);
591             }
592              
593             # why isn't something like this in List::Util?
594             # Return a list of 3 listrefs:
595             # 0: items common to both lists
596             # 1: items in the first list only
597             # 2: items in the second list only
598             sub intersect_lists {
599 96     96 0 118 my ($m,$n) = @_;
600 96         119 my %shared;
601             my %monly;
602 0         0 my %nonly;
603 96         252 @monly{@$m} = @$m;
604 96         166 for my $v (@$n) {
605 121 100       227 if ($monly{$v}) {
606 120         250 $shared{$v} = delete $monly{$v};
607             }
608             else{
609 1         2 $nonly{$v} = $v;
610             }
611             }
612             return (
613 96         451 [ values %shared ],
614             [ values %monly ],
615             [ values %nonly ],
616             );
617             }
618              
619             sub is_valid_property_name {
620 95415     95415 0 65562 my $property_name = shift;
621 95415         259898 return $property_name =~ m/^[_[:alpha:]][_[:alnum:]]*$/;
622             }
623              
624             sub is_valid_class_name {
625 31     31 0 2528 my $class = shift;
626 31         132 return $class =~ m/^[[:alpha:]]\w*((::|')\w+)*$/;
627             }
628              
629             {
630             my %subclass_suffix_for_builtin_symbolic_operator = (
631             '=' => "Equals",
632             '<' => "LessThan",
633             '>' => "GreaterThan",
634             '[]' => "In",
635             'in []' => "In",
636             'ne' => "NotEquals",
637             '<=' => 'LessOrEqual',
638             '>=' => 'GreaterOrEqual',
639             );
640             my %subclass_suffix_for_builtin_symbolic_operator_negation = (
641             '<' => 'GreaterOrEqual', # 'not less than' is the same as GreaterOrEqual
642             '<=' => 'GreaterThan',
643             '>' => 'LessOrEqual',
644             '>=' => 'LessThan',
645             'ne' => 'Equals',
646             'false' => 'True',
647             'true' => 'False',
648             );
649              
650             sub class_suffix_for_operator {
651 6593     6593 0 6363 my $comparison_operator = shift;
652 6593         5794 my $not = 0;
653 6593 100 100     23057 if ($comparison_operator and $comparison_operator =~ m/^(\!|not)\s*(.*)/) {
654 181         237 $not = 1;
655 181         386 $comparison_operator = $2;
656             }
657              
658 6593 100 100     19380 if (!defined($comparison_operator) or $comparison_operator eq '') {
659 3930         4095 $comparison_operator = '=';
660             }
661              
662 6593         5635 my $suffix;
663 6593 100       9228 if ($not) {
664 181         342 $suffix = $subclass_suffix_for_builtin_symbolic_operator_negation{$comparison_operator};
665 181 100       369 unless ($suffix) {
666 109   66     460 $suffix = $subclass_suffix_for_builtin_symbolic_operator{$comparison_operator} || ucfirst(lc($comparison_operator));
667 109         189 $suffix = "Not$suffix";
668             }
669             } else {
670 6412   66     16784 $suffix = $subclass_suffix_for_builtin_symbolic_operator{$comparison_operator} || ucfirst(lc($comparison_operator));
671             }
672 6593         11827 return $suffix;
673             }
674             }
675              
676             # From DBI::quote()
677             # needed in a few places where we need to quote some SQL but don't
678             # have access to a database handle to call quote() on
679             sub sql_quote {
680 190     190 0 201 my $str = shift;
681 190 100       350 return "NULL" unless defined $str;
682 180         218 $str =~ s/'/''/g; # ISO SQL2
683 180         679 return "'$str'";
684             }
685              
686             # Module::Runtime's use_package_optimistically will not throw an exception if
687             # the package cannot be found or if it fails to compile but will if the package
688             # has upstream exceptions, e.g. a missing dependency. We're a little less
689             # "optimistic" so we check if the package is in %INC so we can report whether
690             # it was believed to be loaded or not.
691             sub use_package_optimistically {
692 5164     5164 0 14709 my $name = Module::Runtime::use_package_optimistically(shift);
693 5164         853086 my $file = module_notional_filename($name);
694 5164         74798 return $INC{$file};
695             }
696              
697             # return a hashref of subroutine names => coderefs
698             sub coderefs_for_package {
699 12943     12943 0 14617 my $package = shift;
700              
701 12943         13709 my %stash = do {
702 266     266   1498 no strict 'refs';
  266         389  
  266         49436  
703 12943         24371 my $stash_name = $package . '::';
704 12943         374945 %$stash_name;
705             };
706              
707 12943         119351 my %subs;
708 12943         13892 local $@;
709 12943         34916 foreach my $name ( keys %stash ) {
710 120273         201742 my $glob = $stash{$name};
711 120273 100       87425 next unless my $coderef = eval { *$glob{CODE} }; # constants are SCALAR refs, not typeglobs
  120273         403012  
712 81734         169012 $subs{$name} = $coderef;
713             }
714 12943         133721 return \%subs;
715             }
716              
717             # Given a key in a hashref, if the value is a scalar, wrap it in an arrayref
718             # used by the class initializer to allow some keys in a class definition to
719             # be specified as simple scalars that are normalized to be an arrayref.
720             # Returns false if the value isn't an arrayref or scalar.
721             sub ensure_arrayref {
722 49620     49620 0 52227 my($new_class, $key) = @_;
723              
724 49620 100       71460 if ($new_class->{$key}) {
725 1034 100       6492 if (!ref($new_class->{$key})) {
    50          
726             # If it's a plain string, wrap it into an arrayref
727 16         31 $new_class->{$key} = [ $new_class->{$key} ];
728             } elsif (ref($new_class->{$key}) ne 'ARRAY') {
729 0         0 my $class_name = $new_class->{class_name};
730 0         0 return 0;
731             }
732             } else {
733 48586         65618 $new_class->{$key} = [];
734             }
735 49620         122414 return 1;
736             }
737              
738              
739              
740             1;
741              
742             =pod
743              
744             =head1 NAME
745              
746             UR::Util - Collection of utility subroutines and methods
747              
748             =head1 DESCRIPTION
749              
750             This package contains subroutines and methods used by other parts of the
751             infrastructure. These subs are not likely to be useful to outside code.
752              
753             =cut
754