This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
lib/Perldoc.pm patch for Cygwin Bleadperl
[perl5.git] / lib / Locale / Maketext.pm
CommitLineData
9378c581 1
953b749f 2# Time-stamp: "2003-04-18 22:03:06 AHDT"
9378c581
JH
3
4require 5;
5package Locale::Maketext;
6use strict;
7use vars qw( @ISA $VERSION $MATCH_SUPERS $USING_LANGUAGE_TAGS
8 $USE_LITERALS);
9use Carp ();
10use I18N::LangTags 0.21 ();
11
12#--------------------------------------------------------------------------
13
14BEGIN { unless(defined &DEBUG) { *DEBUG = sub () {0} } }
15 # define the constant 'DEBUG' at compile-time
16
953b749f 17$VERSION = "1.05";
9378c581
JH
18@ISA = ();
19
20$MATCH_SUPERS = 1;
21$USING_LANGUAGE_TAGS = 1;
22 # Turning this off is somewhat of a security risk in that little or no
23 # checking will be done on the legality of tokens passed to the
24 # eval("use $module_name") in _try_use. If you turn this off, you have
25 # to do your own taint checking.
26
27$USE_LITERALS = 1 unless defined $USE_LITERALS;
28 # a hint for compiling bracket-notation things.
29
30my %isa_scan = ();
31
32###########################################################################
33
34sub quant {
35 my($handle, $num, @forms) = @_;
36
37 return $num if @forms == 0; # what should this mean?
38 return $forms[2] if @forms > 2 and $num == 0; # special zeroth case
39
40 # Normal case:
41 # Note that the formatting of $num is preserved.
42 return( $handle->numf($num) . ' ' . $handle->numerate($num, @forms) );
43 # Most human languages put the number phrase before the qualified phrase.
44}
45
46
47sub numerate {
48 # return this lexical item in a form appropriate to this number
49 my($handle, $num, @forms) = @_;
50 my $s = ($num == 1);
51
52 return '' unless @forms;
53 if(@forms == 1) { # only the headword form specified
54 return $s ? $forms[0] : ($forms[0] . 's'); # very cheap hack.
55 } else { # sing and plural were specified
56 return $s ? $forms[0] : $forms[1];
57 }
58}
59
60#--------------------------------------------------------------------------
61
62sub numf {
63 my($handle, $num) = @_[0,1];
64 if($num < 10_000_000_000 and $num > -10_000_000_000 and $num == int($num)) {
65 $num += 0; # Just use normal integer stringification.
66 # Specifically, don't let %G turn ten million into 1E+007
67 } else {
68 $num = CORE::sprintf("%G", $num);
69 # "CORE::" is there to avoid confusion with the above sub sprintf.
70 }
71 while( $num =~ s/^([-+]?\d+)(\d{3})/$1,$2/s ) {1} # right from perlfaq5
72 # The initial \d+ gobbles as many digits as it can, and then we
73 # backtrack so it un-eats the rightmost three, and then we
74 # insert the comma there.
75
76 $num =~ tr<.,><,.> if ref($handle) and $handle->{'numf_comma'};
77 # This is just a lame hack instead of using Number::Format
78 return $num;
79}
80
81sub sprintf {
82 no integer;
83 my($handle, $format, @params) = @_;
84 return CORE::sprintf($format, @params);
85 # "CORE::" is there to avoid confusion with myself!
86}
87
88#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#
89
90use integer; # vroom vroom... applies to the whole rest of the module
91
92sub language_tag {
93 my $it = ref($_[0]) || $_[0];
94 return undef unless $it =~ m/([^':]+)(?:::)?$/s;
95 $it = lc($1);
96 $it =~ tr<_><->;
97 return $it;
98}
99
100sub encoding {
101 my $it = $_[0];
102 return(
103 (ref($it) && $it->{'encoding'})
104 || "iso-8859-1" # Latin-1
105 );
106}
107
108#--------------------------------------------------------------------------
109
110sub fallback_languages { return('i-default', 'en', 'en-US') }
111
112sub fallback_language_classes { return () }
113
114#--------------------------------------------------------------------------
115
116sub fail_with { # an actual attribute method!
117 my($handle, @params) = @_;
118 return unless ref($handle);
119 $handle->{'fail'} = $params[0] if @params;
120 return $handle->{'fail'};
121}
122
123#--------------------------------------------------------------------------
124
125sub failure_handler_auto {
126 # Meant to be used like:
127 # $handle->fail_with('failure_handler_auto')
128
129 my($handle, $phrase, @params) = @_;
130 $handle->{'failure_lex'} ||= {};
131 my $lex = $handle->{'failure_lex'};
132
133 my $value;
134 $lex->{$phrase} ||= ($value = $handle->_compile($phrase));
135
136 # Dumbly copied from sub maketext:
137 {
138 local $SIG{'__DIE__'};
139 eval { $value = &$value($handle, @_) };
140 }
141 # If we make it here, there was an exception thrown in the
142 # call to $value, and so scream:
143 if($@) {
144 my $err = $@;
145 # pretty up the error message
146 $err =~ s<\s+at\s+\(eval\s+\d+\)\s+line\s+(\d+)\.?\n?>
147 <\n in bracket code [compiled line $1],>s;
148 #$err =~ s/\n?$/\n/s;
149 Carp::croak "Error in maketexting \"$phrase\":\n$err as used";
150 # Rather unexpected, but suppose that the sub tried calling
151 # a method that didn't exist.
152 } else {
153 return $value;
154 }
155}
156
157#==========================================================================
158
159sub new {
160 # Nothing fancy!
161 my $class = ref($_[0]) || $_[0];
162 my $handle = bless {}, $class;
163 $handle->init;
164 return $handle;
165}
166
167sub init { return } # no-op
168
169###########################################################################
170
171sub maketext {
172 # Remember, this can fail. Failure is controllable many ways.
173 Carp::croak "maketext requires at least one parameter" unless @_ > 1;
174
175 my($handle, $phrase) = splice(@_,0,2);
176
177 # Look up the value:
178
179 my $value;
180 foreach my $h_r (
181 @{ $isa_scan{ref($handle) || $handle} || $handle->_lex_refs }
182 ) {
183 print "* Looking up \"$phrase\" in $h_r\n" if DEBUG;
184 if(exists $h_r->{$phrase}) {
185 print " Found \"$phrase\" in $h_r\n" if DEBUG;
186 unless(ref($value = $h_r->{$phrase})) {
187 # Nonref means it's not yet compiled. Compile and replace.
188 $value = $h_r->{$phrase} = $handle->_compile($value);
189 }
190 last;
191 } elsif($phrase !~ m/^_/s and $h_r->{'_AUTO'}) {
192 # it's an auto lex, and this is an autoable key!
193 print " Automaking \"$phrase\" into $h_r\n" if DEBUG;
194
195 $value = $h_r->{$phrase} = $handle->_compile($phrase);
196 last;
197 }
198 print " Not found in $h_r, nor automakable\n" if DEBUG > 1;
199 # else keep looking
200 }
201
202 unless(defined($value)) {
203 print "! Lookup of \"$phrase\" in/under ", ref($handle) || $handle,
204 " fails.\n" if DEBUG;
205 if(ref($handle) and $handle->{'fail'}) {
206 print "WARNING0: maketext fails looking for <$phrase>\n" if DEBUG;
207 my $fail;
208 if(ref($fail = $handle->{'fail'}) eq 'CODE') { # it's a sub reference
209 return &{$fail}($handle, $phrase, @_);
210 # If it ever returns, it should return a good value.
211 } else { # It's a method name
212 return $handle->$fail($phrase, @_);
213 # If it ever returns, it should return a good value.
214 }
215 } else {
216 # All we know how to do is this;
217 Carp::croak("maketext doesn't know how to say:\n$phrase\nas needed");
218 }
219 }
220
221 return $$value if ref($value) eq 'SCALAR';
222 return $value unless ref($value) eq 'CODE';
223
224 {
225 local $SIG{'__DIE__'};
226 eval { $value = &$value($handle, @_) };
227 }
228 # If we make it here, there was an exception thrown in the
229 # call to $value, and so scream:
230 if($@) {
231 my $err = $@;
232 # pretty up the error message
233 $err =~ s<\s+at\s+\(eval\s+\d+\)\s+line\s+(\d+)\.?\n?>
234 <\n in bracket code [compiled line $1],>s;
235 #$err =~ s/\n?$/\n/s;
236 Carp::croak "Error in maketexting \"$phrase\":\n$err as used";
237 # Rather unexpected, but suppose that the sub tried calling
238 # a method that didn't exist.
239 } else {
240 return $value;
241 }
242}
243
244###########################################################################
245
246sub get_handle { # This is a constructor and, yes, it CAN FAIL.
247 # Its class argument has to be the base class for the current
248 # application's l10n files.
249 my($base_class, @languages) = @_;
250 $base_class = ref($base_class) || $base_class;
251 # Complain if they use __PACKAGE__ as a project base class?
252
253 unless(@languages) { # Calling with no args is magical! wooo, magic!
254 if(length( $ENV{'REQUEST_METHOD'} || '' )) { # I'm a CGI
f918d677
JH
255 @languages = $base_class->_http_accept_langs;
256 # it's off in its own routine because it's complicated
9378c581
JH
257
258 } else { # Not running as a CGI: try to puzzle out from the environment
259 if(length( $ENV{'LANG'} || '' )) {
260 push @languages, split m/[,:]/, $ENV{'LANG'};
261 # LANG can be only /one/ locale as far as I know, but what the hey.
262 }
263 if(length( $ENV{'LANGUAGE'} || '' )) {
264 push @languages, split m/[,:]/, $ENV{'LANGUAGE'};
265 }
266 print "Noting ENV LANG ", join(',', @languages),"\n" if DEBUG;
267 # Those are really locale IDs, but they get xlated a few lines down.
268
269 if(&_try_use('Win32::Locale')) {
270 # If we have that module installed...
271 push @languages, Win32::Locale::get_language()
272 if defined &Win32::Locale::get_language;
273 }
274 }
275 }
276
277 #------------------------------------------------------------------------
278 print "Lgs1: ", map("<$_>", @languages), "\n" if DEBUG;
279
280 if($USING_LANGUAGE_TAGS) {
281 @languages = map &I18N::LangTags::locale2language_tag($_), @languages;
282 # if it's a lg tag, fine, pass thru (untainted)
283 # if it's a locale ID, try converting to a lg tag (untainted),
284 # otherwise nix it.
285
ff5ad48a 286 push @languages, map I18N::LangTags::super_languages($_), @languages
9378c581
JH
287 if $MATCH_SUPERS;
288
ff5ad48a 289 @languages = map { $_, I18N::LangTags::alternate_language_tags($_) }
9378c581
JH
290 @languages; # catch alternation
291
ff5ad48a
JH
292 push @languages, I18N::LangTags::panic_languages(@languages)
293 if defined &I18N::LangTags::panic_languages;
294
9378c581
JH
295 push @languages, $base_class->fallback_languages;
296 # You are free to override fallback_languages to return empty-list!
297
298 @languages = # final bit of processing:
299 map {
300 my $it = $_; # copy
301 $it =~ tr<-A-Z><_a-z>; # lc, and turn - to _
302 $it =~ tr<_a-z0-9><>cd; # remove all but a-z0-9_
303 $it;
304 } @languages
305 ;
306 }
307 print "Lgs2: ", map("<$_>", @languages), "\n" if DEBUG > 1;
308
309 push @languages, $base_class->fallback_language_classes;
310 # You are free to override that to return whatever.
311
312
313 my %seen = ();
314 foreach my $module_name ( map { $base_class . "::" . $_ } @languages )
315 {
316 next unless length $module_name; # sanity
317 next if $seen{$module_name}++ # Already been here, and it was no-go
318 || !&_try_use($module_name); # Try to use() it, but can't it.
319 return($module_name->new); # Make it!
320 }
321
322 return undef; # Fail!
323}
324
325###########################################################################
326#
327# This is where most people should stop reading.
328#
329###########################################################################
330
f918d677
JH
331sub _http_accept_langs {
332 # Deal with HTTP "Accept-Language:" stuff. Hassle.
333 # This code is more lenient than RFC 3282, which you must read.
334 # Hm. Should I just move this into I18N::LangTags at some point?
335 no integer;
336
337 my $in = (@_ > 1) ? $_[1] : $ENV{'HTTP_ACCEPT_LANGUAGE'};
338 # (always ends up untainting)
339
340 return() unless defined $in and length $in;
341
342 $in =~ s/\([^\)]*\)//g; # nix just about any comment
343
344 if( $in =~ m/^\s*([a-zA-Z][-a-zA-Z]+)\s*$/s ) {
345 # Very common case: just one language tag
346 return lc $1;
347 } elsif( $in =~ m/^\s*[a-zA-Z][-a-zA-Z]+(?:\s*,\s*[a-zA-Z][-a-zA-Z]+)*\s*$/s ) {
348 # Common case these days: just "foo, bar, baz"
349 return map lc($_), $in =~ m/([a-zA-Z][-a-zA-Z]+)/g;
350 }
351
352 # Else it's complicated...
353
354 $in =~ s/\s+//g; # Yes, we can just do without the WS!
355 my @in = $in =~ m/([^,]+)/g;
356 my %pref;
357
358 my $q;
359 foreach my $tag (@in) {
360 next unless $tag =~
361 m/^([a-zA-Z][-a-zA-Z]+)
362 (?:
363 ;q=
364 (
365 \d* # a bit too broad of a RE, but so what.
366 (?:
367 \.\d+
368 )?
369 )
370 )?
371 $
372 /sx
373 ;
374 $q = (defined $2 and length $2) ? $2 : 1;
375 #print "$1 with q=$q\n";
376 push @{ $pref{$q} }, lc $1;
377 }
378
379 return # Read off %pref, in descending key order...
380 map @{$pref{$_}},
381 sort {$b <=> $a}
382 keys %pref;
383}
384
385###########################################################################
386
9378c581
JH
387sub _compile {
388 # This big scarp routine compiles an entry.
389 # It returns either a coderef if there's brackety bits in this, or
390 # otherwise a ref to a scalar.
391
392 my $target = ref($_[0]) || $_[0];
393
394 my(@code);
395 my(@c) = (''); # "chunks" -- scratch.
396 my $call_count = 0;
397 my $big_pile = '';
398 {
399 my $in_group = 0; # start out outside a group
400 my($m, @params); # scratch
401
402 while($_[1] =~ # Iterate over chunks.
403 m<\G(
404 [^\~\[\]]+ # non-~[] stuff
405 |
406 ~. # ~[, ~], ~~, ~other
407 |
ff5ad48a 408 \[ # [ presumably opening a group
9378c581 409 |
ff5ad48a 410 \] # ] presumably closing a group
9378c581 411 |
ff5ad48a 412 ~ # terminal ~ ?
9378c581
JH
413 |
414 $
415 )>xgs
416 ) {
417 print " \"$1\"\n" if DEBUG > 2;
418
419 if($1 eq '[' or $1 eq '') { # "[" or end
420 # Whether this is "[" or end, force processing of any
421 # preceding literal.
422 if($in_group) {
423 if($1 eq '') {
424 $target->_die_pointing($_[1], "Unterminated bracket group");
425 } else {
426 $target->_die_pointing($_[1], "You can't nest bracket groups");
427 }
428 } else {
429 if($1 eq '') {
430 print " [end-string]\n" if DEBUG > 2;
431 } else {
432 $in_group = 1;
433 }
434 die "How come \@c is empty?? in <$_[1]>" unless @c; # sanity
435 if(length $c[-1]) {
436 # Now actually processing the preceding literal
437 $big_pile .= $c[-1];
ff5ad48a
JH
438 if($USE_LITERALS and (
439 (ord('A') == 65)
440 ? $c[-1] !~ m<[^\x20-\x7E]>s
441 # ASCII very safe chars
442 : $c[-1] !~ m/[^ !"\#\$%&'()*+,\-.\/0-9:;<=>?\@A-Z[\\\]^_`a-z{|}~\x07]/s
443 # EBCDIC very safe chars
444 )) {
9378c581
JH
445 # normal case -- all very safe chars
446 $c[-1] =~ s/'/\\'/g;
447 push @code, q{ '} . $c[-1] . "',\n";
448 $c[-1] = ''; # reuse this slot
449 } else {
450 push @code, ' $c[' . $#c . "],\n";
451 push @c, ''; # new chunk
452 }
453 }
454 # else just ignore the empty string.
455 }
456
457 } elsif($1 eq ']') { # "]"
458 # close group -- go back in-band
459 if($in_group) {
460 $in_group = 0;
461
462 print " --Closing group [$c[-1]]\n" if DEBUG > 2;
463
464 # And now process the group...
465
466 if(!length($c[-1]) or $c[-1] =~ m/^\s+$/s) {
467 DEBUG > 2 and print " -- (Ignoring)\n";
468 $c[-1] = ''; # reset out chink
469 next;
470 }
471
472 #$c[-1] =~ s/^\s+//s;
473 #$c[-1] =~ s/\s+$//s;
474 ($m,@params) = split(",", $c[-1], -1); # was /\s*,\s*/
475
ff5ad48a
JH
476 # A bit of a hack -- we've turned "~,"'s into DELs, so turn
477 # 'em into real commas here.
478 if (ord('A') == 65) { # ASCII, etc
479 foreach($m, @params) { tr/\x7F/,/ }
480 } else { # EBCDIC (1047, 0037, POSIX-BC)
481 # Thanks to Peter Prymmer for the EBCDIC handling
482 foreach($m, @params) { tr/\x07/,/ }
483 }
9378c581 484
ff5ad48a 485 # Special-case handling of some method names:
9378c581
JH
486 if($m eq '_*' or $m =~ m<^_(-?\d+)$>s) {
487 # Treat [_1,...] as [,_1,...], etc.
488 unshift @params, $m;
489 $m = '';
ff5ad48a
JH
490 } elsif($m eq '*') {
491 $m = 'quant'; # "*" for "times": "4 cars" is 4 times "cars"
492 } elsif($m eq '#') {
493 $m = 'numf'; # "#" for "number": [#,_1] for "the number _1"
9378c581
JH
494 }
495
496 # Most common case: a simple, legal-looking method name
497 if($m eq '') {
498 # 0-length method name means to just interpolate:
499 push @code, ' (';
500 } elsif($m =~ m<^\w+(?:\:\:\w+)*$>s
501 and $m !~ m<(?:^|\:)\d>s
502 # exclude starting a (sub)package or symbol with a digit
503 ) {
504 # Yes, it even supports the demented (and undocumented?)
505 # $obj->Foo::bar(...) syntax.
506 $target->_die_pointing(
507 $_[1], "Can't (yet?) use \"SUPER::\" in a bracket-group method",
508 2 + length($c[-1])
509 )
510 if $m =~ m/^SUPER::/s;
511 # Because for SUPER:: to work, we'd have to compile this into
512 # the right package, and that seems just not worth the bother,
513 # unless someone convinces me otherwise.
514
515 push @code, ' $_[0]->' . $m . '(';
516 } else {
517 # TODO: implement something? or just too icky to consider?
518 $target->_die_pointing(
519 $_[1],
520 "Can't use \"$m\" as a method name in bracket group",
521 2 + length($c[-1])
522 );
523 }
524
525 pop @c; # we don't need that chunk anymore
526 ++$call_count;
527
528 foreach my $p (@params) {
529 if($p eq '_*') {
530 # Meaning: all parameters except $_[0]
531 $code[-1] .= ' @_[1 .. $#_], ';
532 # and yes, that does the right thing for all @_ < 3
533 } elsif($p =~ m<^_(-?\d+)$>s) {
534 # _3 meaning $_[3]
535 $code[-1] .= '$_[' . (0 + $1) . '], ';
ff5ad48a
JH
536 } elsif($USE_LITERALS and (
537 (ord('A') == 65)
538 ? $p !~ m<[^\x20-\x7E]>s
539 # ASCII very safe chars
540 : $p !~ m/[^ !"\#\$%&'()*+,\-.\/0-9:;<=>?\@A-Z[\\\]^_`a-z{|}~\x07]/s
541 # EBCDIC very safe chars
542 )) {
9378c581
JH
543 # Normal case: a literal containing only safe characters
544 $p =~ s/'/\\'/g;
545 $code[-1] .= q{'} . $p . q{', };
546 } else {
547 # Stow it on the chunk-stack, and just refer to that.
548 push @c, $p;
549 push @code, ' $c[' . $#c . "], ";
550 }
551 }
552 $code[-1] .= "),\n";
553
554 push @c, '';
555 } else {
556 $target->_die_pointing($_[1], "Unbalanced ']'");
557 }
558
559 } elsif(substr($1,0,1) ne '~') {
560 # it's stuff not containing "~" or "[" or "]"
561 # i.e., a literal blob
562 $c[-1] .= $1;
563
564 } elsif($1 eq '~~') { # "~~"
565 $c[-1] .= '~';
566
567 } elsif($1 eq '~[') { # "~["
568 $c[-1] .= '[';
569
570 } elsif($1 eq '~]') { # "~]"
571 $c[-1] .= ']';
572
573 } elsif($1 eq '~,') { # "~,"
574 if($in_group) {
ff5ad48a
JH
575 # This is a hack, based on the assumption that no-one will actually
576 # want a DEL inside a bracket group. Let's hope that's it's true.
577 if (ord('A') == 65) { # ASCII etc
578 $c[-1] .= "\x7F";
579 } else { # EBCDIC (cp 1047, 0037, POSIX-BC)
580 $c[-1] .= "\x07";
581 }
9378c581
JH
582 } else {
583 $c[-1] .= '~,';
584 }
585
586 } elsif($1 eq '~') { # possible only at string-end, it seems.
587 $c[-1] .= '~';
588
589 } else {
590 # It's a "~X" where X is not a special character.
591 # Consider it a literal ~ and X.
592 $c[-1] .= $1;
593 }
594 }
595 }
596
597 if($call_count) {
598 undef $big_pile; # Well, nevermind that.
599 } else {
600 # It's all literals! Ahwell, that can happen.
601 # So don't bother with the eval. Return a SCALAR reference.
602 return \$big_pile;
603 }
604
605 die "Last chunk isn't null??" if @c and length $c[-1]; # sanity
606 print scalar(@c), " chunks under closure\n" if DEBUG;
607 if(@code == 0) { # not possible?
608 print "Empty code\n" if DEBUG;
609 return \'';
610 } elsif(@code > 1) { # most cases, presumably!
611 unshift @code, "join '',\n";
612 }
613 unshift @code, "use strict; sub {\n";
614 push @code, "}\n";
615
616 print @code if DEBUG;
617 my $sub = eval(join '', @code);
618 die "$@ while evalling" . join('', @code) if $@; # Should be impossible.
619 return $sub;
620}
621
622# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
623
624sub _die_pointing {
625 # This is used by _compile to throw a fatal error
626 my $target = shift; # class name
627 # ...leaving $_[0] the error-causing text, and $_[1] the error message
628
629 my $i = index($_[0], "\n");
630
631 my $pointy;
632 my $pos = pos($_[0]) - (defined($_[2]) ? $_[2] : 0) - 1;
633 if($pos < 1) {
634 $pointy = "^=== near there\n";
635 } else { # we need to space over
636 my $first_tab = index($_[0], "\t");
637 if($pos > 2 and ( -1 == $first_tab or $first_tab > pos($_[0]))) {
638 # No tabs, or the first tab is harmlessly after where we will point to,
639 # AND we're far enough from the margin that we can draw a proper arrow.
640 $pointy = ('=' x $pos) . "^ near there\n";
641 } else {
642 # tabs screw everything up!
643 $pointy = substr($_[0],0,$pos);
644 $pointy =~ tr/\t //cd;
645 # make everything into whitespace, but preseving tabs
646 $pointy .= "^=== near there\n";
647 }
648 }
649
650 my $errmsg = "$_[1], in\:\n$_[0]";
651
652 if($i == -1) {
653 # No newline.
654 $errmsg .= "\n" . $pointy;
655 } elsif($i == (length($_[0]) - 1) ) {
656 # Already has a newline at end.
657 $errmsg .= $pointy;
658 } else {
659 # don't bother with the pointy bit, I guess.
660 }
661 Carp::croak( "$errmsg via $target, as used" );
662}
663
664###########################################################################
665
666my %tried = ();
667 # memoization of whether we've used this module, or found it unusable.
668
669sub _try_use { # Basically a wrapper around "require Modulename"
670 # "Many men have tried..." "They tried and failed?" "They tried and died."
671 return $tried{$_[0]} if exists $tried{$_[0]}; # memoization
672
673 my $module = $_[0]; # ASSUME sane module name!
674 { no strict 'refs';
675 return($tried{$module} = 1)
676 if defined(%{$module . "::Lexicon"}) or defined(@{$module . "::ISA"});
677 # weird case: we never use'd it, but there it is!
678 }
679
680 print " About to use $module ...\n" if DEBUG;
681 {
682 local $SIG{'__DIE__'};
683 eval "require $module"; # used to be "use $module", but no point in that.
684 }
685 if($@) {
686 print "Error using $module \: $@\n" if DEBUG > 1;
687 return $tried{$module} = 0;
688 } else {
689 print " OK, $module is used\n" if DEBUG;
690 return $tried{$module} = 1;
691 }
692}
693
694#--------------------------------------------------------------------------
695
696sub _lex_refs { # report the lexicon references for this handle's class
697 # returns an arrayREF!
698 no strict 'refs';
699 my $class = ref($_[0]) || $_[0];
700 print "Lex refs lookup on $class\n" if DEBUG > 1;
701 return $isa_scan{$class} if exists $isa_scan{$class}; # memoization!
702
703 my @lex_refs;
704 my $seen_r = ref($_[1]) ? $_[1] : {};
705
706 if( defined( *{$class . '::Lexicon'}{'HASH'} )) {
707 push @lex_refs, *{$class . '::Lexicon'}{'HASH'};
708 print "%" . $class . "::Lexicon contains ",
709 scalar(keys %{$class . '::Lexicon'}), " entries\n" if DEBUG;
710 }
711
ff5ad48a
JH
712 # Implements depth(height?)-first recursive searching of superclasses.
713 # In hindsight, I suppose I could have just used Class::ISA!
9378c581
JH
714 foreach my $superclass (@{$class . "::ISA"}) {
715 print " Super-class search into $superclass\n" if DEBUG;
716 next if $seen_r->{$superclass}++;
717 push @lex_refs, @{&_lex_refs($superclass, $seen_r)}; # call myself
718 }
719
720 $isa_scan{$class} = \@lex_refs; # save for next time
721 return \@lex_refs;
722}
723
724sub clear_isa_scan { %isa_scan = (); return; } # end on a note of simplicity!
725
726###########################################################################
7271;
728
f918d677
JH
729__END__
730
731HEY YOU! You need some FOOD!
732
733
734 ~~ Tangy Moroccan Carrot Salad ~~
735
736* 6 to 8 medium carrots, peeled and then sliced in 1/4-inch rounds
737* 1/4 teaspoon chile powder (cayenne, chipotle, ancho, or the like)
738* 1 tablespoon ground cumin
739* 1 tablespoon honey
740* The juice of about a half a big lemon, or of a whole smaller one
741* 1/3 cup olive oil
742* 1 tablespoon of fresh dill, washed and chopped fine
743* Pinch of salt, maybe a pinch of pepper
744
745Cook the carrots in a pot of boiling water until just tender -- roughly
746six minutes. (Just don't let them get mushy!) Drain the carrots.
747
748In a largish bowl, combine the lemon juice, the cumin, the chile
749powder, and the honey. Mix well.
750Add the olive oil and whisk it together well. Add the dill and stir.
751
752Add the warm carrots to the bowl and toss it all to coat the carrots
753well. Season with salt and pepper, to taste.
754
755Serve warm or at room temperature.
756
757The measurements here are very approximate, and you should feel free to
758improvise and experiment. It's a very forgiving recipe. For example,
759you could easily halve or double the amount of cumin, or use chopped mint
760leaves instead of dill, or lime juice instead of lemon, et cetera.
761
762[end]