File Coverage

blib/lib/WebDyne/Constant.pm
Criterion Covered Total %
statement 119 157 75.8
branch 27 42 64.2
condition 15 26 57.6
subroutine 13 14 92.8
pod 0 5 0.0
total 174 244 71.3


line stmt bran cond sub pod time code
1             #
2             # This file is part of WebDyne.
3             #
4             # This software is copyright (c) 2026 by Andrew Speer .
5             #
6             # This is free software; you can redistribute it and/or modify it under
7             # the same terms as the Perl 5 programming language system itself.
8             #
9             # Full license text is available at:
10             #
11             #
12             #
13             package WebDyne::Constant;
14              
15              
16             # Pragma
17             #
18 9     9   66 use strict qw(vars);
  9         16  
  9         430  
19 9     9   52 use vars qw($VERSION %Constant %Package);
  9         16  
  9         514  
20 9     9   51 use warnings;
  9         17  
  9         462  
21 9     9   70 no warnings qw(uninitialized);
  9         17  
  9         424  
22              
23              
24             # External modules
25             #
26 9     9   54 use WebDyne::Util;
  9         20  
  9         51  
27 9     9   91 use File::Spec;
  9         19  
  9         1569  
28 9     9   88 use Data::Dumper;
  9         17  
  9         21757  
29             $Data::Dumper::Indent=1;
30             require Opcode;
31              
32              
33             # Version information
34             #
35             $VERSION='2.075';
36              
37              
38             # Get mod_perl version taking intio account legacy strings. Clear $@ after evals
39             #
40             eval {require mod_perl2 if (defined($ENV{'MOD_PERL_API_VERSION'}) && ($ENV{'MOD_PERL_API_VERSION'} == 2))} ||
41             eval {require Apache2 if (defined($ENV{'MOD_PERL'}) && ($ENV{'MOD_PERL'}=~/1.99/))} ||
42             eval {require mod_perl if $ENV{'MOD_PERL'}};
43             eval {} if $@;
44             my $MP_version=$mod_perl::VERSION || $mod_perl2::VERSION || $ENV{MOD_PERL_API_VERSION};
45             my $MP2=(defined($MP_version) && ($MP_version > 1.99)) ? 1 : 0;
46              
47              
48             # Temp location to hold vars we propagate into multiple constants below.
49             #
50             my %constant_temp;
51              
52              
53             # Hash of constants
54             #
55             %Constant=(
56              
57              
58             # Array structure index abstraction. Do not change or bad
59             # things will happen.
60             #
61             WEBDYNE_NODE_NAME_IX => 0,
62             WEBDYNE_NODE_ATTR_IX => 1,
63             WEBDYNE_NODE_CHLD_IX => 2,
64             WEBDYNE_NODE_SBST_IX => 3,
65             WEBDYNE_NODE_LINE_IX => 4,
66             WEBDYNE_NODE_LINE_TAG_END_IX => 5,
67             WEBDYNE_NODE_SRCE_IX => 6,
68              
69              
70             # Container structure
71             #
72             WEBDYNE_CONTAINER_META_IX => 0,
73             WEBDYNE_CONTAINER_DATA_IX => 1,
74              
75              
76             # Where compiled scripts are stored. Scripts are stored in
77             # here with a the inode of the source file as the cache
78             # file name.
79             #
80             WEBDYNE_CACHE_DN => &cache_dn,
81              
82              
83             # Empty cache files at startup ? Default is yes (psp files wil be
84             # recompiled again after a server restart)
85             #
86             WEBDYNE_STARTUP_CACHE_FLUSH => 1,
87              
88              
89             # How often to check cache for excess entries, clean to
90             # low_water if > high_water entries, based on last used
91             # time or frequency.
92             #
93             # clean_method 0 = clean based on last used time (oldest
94             # get cleaned)
95             #
96             # clean_method 1 = clean based on frequency of use (least
97             # used get cleaned)
98             #
99             WEBDYNE_CACHE_CHECK_FREQ => 256,
100             WEBDYNE_CACHE_HIGH_WATER => 64,
101             WEBDYNE_CACHE_LOW_WATER => 32,
102             WEBDYNE_CACHE_CLEAN_METHOD => 1,
103              
104              
105             # Type of eval code to run - use Safe module, or direct. Direct
106             # is default, but may allow subversion of code
107             #
108             # 1 = Safe # Not tested much - don't assume it is really safe !
109             # 0 = Direct (UnSafe)
110             #
111             WEBDYNE_EVAL_SAFE => 0,
112              
113              
114             # Prefix eval code with strict pragma. Can be undef'd to remove
115             # this behaviour, or altered to suit local taste
116             #
117             WEBDYNE_EVAL_USE_STRICT => 'use strict qw(vars);',
118              
119              
120             # Global opcode set, only these opcodes can be used if using a
121             # safe eval type. Uncomment the full_opset line if you want to
122             # be able to use all perl opcodes. Ignored if using direct eval
123             #
124             #WEBDYNE_EVAL_SAFE_OPCODE_AR => [&Opcode::full_opset()],
125             #WEBDYNE_EVAL_SAFE_OPCODE_AR => [&Opcode::opset(':default')],
126             WEBDYNE_EVAL_SAFE_OPCODE_AR => [':default'],
127              
128              
129             # Use strict var checking, eg will check that a when ${varname} param
130             # exists with a HTML page that the calling perl code (a) supplies a
131             # "varname" hash parm, and (b) that param is not undef
132             #
133             WEBDYNE_STRICT_VARS => 1,
134              
135              
136             # When a perl method loaded by a user calls another method within
137             # that just-loaded package (eg sub foo { shift()->bar() }), the
138             # WebDyne AUTOLOAD method gets called to work out where "bar" is,
139             # as it is not in the WebDyne ISA stack.
140             #
141             # By default, this gets done every time the routine is called,
142             # which can add up when done many times. By setting the var below
143             # to 1, the AUTOLOAD method will pollute the WebDyne class with
144             # a code ref to the method in question, saving a run through
145             # AUTOLOAD if it is ever called again. The downside - it is
146             # forever, and if your module has a method of the same name as
147             # one in the WebDyne class, it will clobber the WebDyne one, probably
148             # bringing the whole lot crashing down around your ears.
149             #
150             # The upside. A speedup of about 10% on modules that use AUTOLOAD
151             # heavily
152             #
153             WEBDYNE_AUTOLOAD_POLLUTE => 0,
154              
155              
156             # Dump flag. Set to 1 if you want the tag to display the
157             # current CGI status
158             #
159             WEBDYNE_DUMP_FLAG => 0,
160              
161              
162             # Encoding
163             #
164             WEBDYNE_HTML_CHARSET => do {
165             $constant_temp{'webdyne_html_charset'}='UTF-8'
166             },
167              
168              
169             # Content-type for text/html. Combined with charset to produce Content-type header
170             #
171             WEBDYNE_CONTENT_TYPE_HTML => do {
172             $constant_temp{'webdyne_content_type_html'}='text/html'
173             },
174             WEBDYNE_CONTENT_TYPE_HTML_ENCODED => do {
175             $constant_temp{'webdyne_content_type_html_encoded'}=sprintf('%s; charset=%s', @constant_temp{qw(webdyne_content_type_html webdyne_html_charset)})
176             },
177              
178              
179             # Content-type for text/plain. As above
180             #
181             WEBDYNE_CONTENT_TYPE_TEXT => do {
182             $constant_temp{'webdyne_content_type_text'}='text/plain'
183             },
184             WEBDYNE_CONTENT_TYPE_TEXT_ENCODED =>
185             sprintf('%s; charset=%s', @constant_temp{qw(webdyne_content_type_text webdyne_html_charset)}),
186              
187              
188             # And JSON
189             #
190             WEBDYNE_CONTENT_TYPE_JSON => do {
191             $constant_temp{'webdyne_content_type_json'}='application/json'
192             },
193             WEBDYNE_CONTENT_TYPE_JSON_ENCODED =>
194             sprintf('%s; charset=%s', @constant_temp{qw(webdyne_content_type_json webdyne_html_charset)}),
195            
196            
197             # Script types which are executable so we won't subst strings in them
198             #
199             WEBDYNE_SCRIPT_TYPE_EXECUTABLE_HR => { map { $_=>1 } qw(
200             text/javascript
201             application/javascript
202             module
203             )},
204              
205              
206             # DTD to use when generating HTML
207             #
208             WEBDYNE_DTD => '',
209             WEBDYNE_META => {
210            
211             # Set to 'chareset=UTF-8' => undef to get result we want
212             'charset='.$constant_temp{'webdyne_html_charset'} => undef,
213            
214             # Set viewport by default
215             'viewport' => 'width=device-width, initial-scale=1.0'
216             },
217              
218              
219             # Include a Content-Type meta tag ?
220             #
221             WEBDYNE_CONTENT_TYPE_HTML_META => 0,
222              
223              
224             # Default tag paramaters, eg { lang =>'en-US' }
225             #
226             WEBDYNE_HTML_PARAM => {lang => 'en' },
227            
228              
229             # Default params for tag
230             #
231             # E.g. WEBDYNE_START_HTML_PARAM => { include_style=>['foo.css', 'bar.css'] },
232              
233             #
234             WEBDYNE_START_HTML_PARAM => {},
235            
236            
237             # Make include/other sections in start_html tag static, i.e. load them at compile
238             # time and they never change. Make undef to force re-include every page load
239             #
240             WEBDYNE_START_HTML_PARAM_STATIC => 1,
241            
242            
243             # Shortcut attributes for start_html
244             #
245             WEBDYNE_START_HTML_SHORTCUT_HR => {
246            
247             pico => { style => 'https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css' },
248             htmx => { script => 'https://cdn.jsdelivr.net/npm/htmx.org@2.0.8/dist/htmx.min.js' }
249            
250             # Commented out for now, left as syntax examples
251             #
252              
253             #bootstrap => {
254             # style => 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css',
255             # script => 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js'
256             #},
257             #alpine => { script => 'https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js#defer' },
258             #tailwind => { style => 'https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4' },
259             #alpine_ajax => { script => [
260             # 'https://cdn.jsdelivr.net/npm/@imacrayon/alpine-ajax@0.12.6/dist/cdn.min.js#defer',
261             # 'https://cdn.jsdelivr.net/npm/alpinejs@3.14.1/dist/cdn.min.js#defer'
262             #]}
263            
264             },
265            
266            
267             # Anything that should be added in section. Will be inserted verbatim before
268             # . No interpolation or variables, simple text string only. Useful for setting
269             # global stylesheet, e.g.
270             #
271             # WEBDYNE_HEAD_INSERT => ''
272             #
273             # Will be added to all sections universally.
274             #
275             WEBDYNE_HEAD_INSERT => '',
276            
277            
278             # Ignore ignorable whitespace in compile. Play around with these settings if
279             # you don't like the formatting of the compiled HTML. See HTML::TreeBuilder
280             # man page for details here
281             #
282             WEBDYNE_COMPILE_IGNORE_WHITESPACE => 1,
283             WEBDYNE_COMPILE_NO_SPACE_COMPACTING => 0,
284              
285              
286             # Other Compile settings
287             #
288             WEBDYNE_COMPILE_P_STRICT => 1,
289             WEBDYNE_COMPILE_IMPLICIT_BODY_P_TAG => 1,
290              
291              
292             # Store and render comments ?
293             #
294             WEBDYNE_STORE_COMMENTS => 1,
295              
296              
297             # Send no-cache headers ?
298             #
299             WEBDYNE_NO_CACHE => 1,
300              
301              
302             # Render blocks outside of perl code
303             #
304             #WEBDYNE_DELAYED_BLOCK_RENDER => 1,
305              
306              
307             # Are warnings fatal ?
308             #
309             WEBDYNE_WARNINGS_FATAL => 0,
310              
311              
312             # CGI disable uploads default, max post size default
313             #
314             WEBDYNE_CGI_DISABLE_UPLOADS => 0,
315             WEBDYNE_CGI_POST_MAX => (512*1024), #512Kb
316              
317              
318             # Expand CGI parameters found in CGI values, e.g. button with submit=1&name=2 will get those
319             # CGI params set.
320             #
321             WEBDYNE_CGI_PARAM_EXPAND => 1,
322              
323              
324             # Disable CGI autoescape of form fields ?
325             #
326             WEBDYNE_CGI_AUTOESCAPE => 0,
327              
328              
329             # Error handling. Use text errors rather than HTML ?
330             #
331             WEBDYNE_ERROR_TEXT => 0,
332              
333              
334             # Show errors ? Extended shows additional information with granularity as per following
335             # section.
336             #
337             WEBDYNE_ERROR_SHOW => 1,
338             WEBDYNE_ERROR_SHOW_EXTENDED => 0,
339              
340              
341             # Show error, source file context, number of lines pre and post. Only applicable
342             # for extended + HTML error output.
343             #
344             WEBDYNE_ERROR_SOURCE_CONTEXT_SHOW => 1,
345             WEBDYNE_ERROR_SOURCE_CONTEXT_LINES_PRE => 4,
346             WEBDYNE_ERROR_SOURCE_CONTEXT_LINES_POST => 4,
347              
348             # Max length of source line to show in ouput. 0 for unlimited.
349             WEBDYNE_ERROR_SOURCE_CONTEXT_LINE_FRAGMENT_MAX => 80,
350              
351             # Show filename (FULL for full filesystem path)
352             WEBDYNE_ERROR_SOURCE_FILENAME_SHOW => 1,
353             WEBDYNE_ERROR_SOURCE_FILENAME_FULL => 0,
354              
355             # Show backtrace, show full or brief backtrace
356             WEBDYNE_ERROR_BACKTRACE_SHOW => 1,
357             WEBDYNE_ERROR_BACKTRACE_SHORT => 0,
358             # Skip (eval) and __ANON__ methods unless set to 1
359             WEBDYNE_ERROR_BACKTRACE_FULL => 0,
360              
361             # Show eval trace. Uses SOURCE_CONTEXT_LINES to determine number of lines to show
362             WEBDYNE_ERROR_EVAL_CONTEXT_SHOW => 1,
363              
364             # CGI and other info
365             WEBDYNE_ERROR_CGI_PARAM_SHOW => 1,
366             WEBDYNE_ERROR_ENV_SHOW => 1,
367             WEBDYNE_ERROR_WEBDYNE_CONSTANT_SHOW => 1,
368              
369             # URI and version
370             WEBDYNE_ERROR_URI_SHOW => 1,
371             WEBDYNE_ERROR_VERSION_SHOW => 1,
372             WEBDYNE_ERROR_INTERNAL_SHOW => 0,
373              
374             # Internal indexes for error eval handler array
375             #
376             #WEBDYNE_ERROR_EVAL_TEXT_IX => 0,
377             #WEBDYNE_ERROR_EVAL_EMBEDDED_IX => 1,
378             #WEBDYNE_ERROR_EVAL_LINE_NO_IX => 2,
379              
380              
381             # Alternate error message if WEBDYNE_ERROR_SHOW disabled
382             #
383             WEBDYNE_ERROR_SHOW_ALTERNATE =>
384             'error display disabled - enable WEBDYNE_ERROR_SHOW to show errors, or review web server error log.',
385              
386             # Default title
387             #
388             WEBDYNE_HTML_DEFAULT_TITLE => 'Untitled Document',
389              
390              
391             # HTML Tiny mode, XML or HTML
392             #
393             WEBDYNE_HTML_TINY_MODE => 'html',
394              
395              
396             # Development mode - recompile loaded modules
397             #
398             WEBDYNE_RELOAD => 0,
399              
400              
401             # Use JSON canonical. pretty mode ?
402             #
403             WEBDYNE_JSON_CANONICAL => 1,
404             WEBDYNE_JSON_PRETTY => 0,
405            
406            
407             # Enable the API mode ?
408             #
409             WEBDYNE_API_ENABLE => 1,
410            
411            
412             # Enable Alpine/Vue hack
413             #
414             WEBDYNE_ALPINE_VUE_ATTRIBUTE_HACK_ENABLE => 'x-on',
415            
416            
417             # Request headers for HTMX and Alpine Ajax
418             #
419             WEBDYNE_HTTP_HEADER_AJAX_HR => { map { $_=> 1} @{$_=[qw(
420             hx-request
421             x-alpine-request
422             )]}},
423             WEBDYNE_HTTP_HEADER_AJAX_AR => $_,
424            
425            
426             # Force run of tag even if no hx-request header
427             #
428             WEBDYNE_HTMX_FORCE => 0,
429              
430              
431             # Headers
432             #
433             WEBDYNE_HTTP_HEADER => {
434              
435             #'Content-Type' => sprintf('%s; charset=%s', @constant_temp{qw(webdyne_content_type_html webdyne_html_charset)}),
436             'Content-Type' => $constant_temp{'webdyne_content_type_html_encoded'},
437             'Cache-Control' => 'no-cache, no-store, must-revalidate',
438             'Pragma' => 'no-cache',
439             'Expires' => '0',
440             'X-Content-Type-Options' => 'nosniff',
441             'X-Frame-Options' => 'SAMEORIGIN'
442            
443             # Set other options here, e.g.
444             #
445             #'Strict-Transport-Security' => 'max-age=31536000; includeSubDomains; preload',
446             #'Content-Security-Policy' => "default-src 'self'; style-src 'self' https://cdn.jsdelivr.net https://fonts.googleapis.com/ 'unsafe-inline'; font-src https://fonts.gstatic.com",
447             #'Referrer-Policy' => 'strict-origin-when-cross-origin',
448              
449             },
450            
451            
452             # Webdyne PSGI serves static files ?
453             #
454             WEBDYNE_PSGI_STATIC => 1,
455            
456            
457             # WebDyne default extension and length, used in susbtr as faster than regex. Update - too slow, retiring and going to fixed
458             # string .psp extension
459             #
460             WEBDYNE_PSP_EXT => ($constant_temp{'webdyne_psp_ext'}='.psp'),
461             WEBDYNE_PSP_EXT_RE => qr/\Q$constant_temp{'webdyne_psp_ext'}\E/,
462            
463            
464             # Very minimal MIME type hash used by lookup_file function
465             #
466             WEBDYNE_MIME_TYPE_HR => {
467             'html' => 'text/html',
468             'htm' => 'text/html',
469             'txt' => 'text/plain',
470             'jpg' => 'image/jpeg',
471             'jpeg' => 'image/jpeg',
472             'png' => 'image/png',
473             'gif' => 'image/gif',
474             'css' => 'text/css',
475             'js' => 'application/javascript',
476             'json' => 'application/json',
477             'pdf' => 'application/pdf',
478             'svg' => 'image/svg+xml',
479             'yml' => 'application/x-yaml',
480             'yaml' => 'application/x-yaml',
481             'xml' => 'application/xml',
482             'toml' => 'application/toml',
483             'md' => 'text/markdown'
484             },
485            
486            
487             # Other file extenstions the PSGI indexer is allowed to open
488             #
489             WEBDYNE_INDEX_EXT_ALLOWED_HR => { map {$_=>1} qw(
490             psp
491             pm
492             pl
493             )},
494              
495              
496             # And raw file names. Should be regexp, todo
497             #
498             WEBDYNE_INDEX_FN_ALLOWED_HR => { map {$_=>1} qw(
499             LICENSE
500             MANIFEST
501             Makefile
502             cpanfile
503             cpanfile.snapshot
504             Dockerfile
505             )},
506            
507            
508             # Dir_config can be loaded from here if not in Apache
509             #
510             WEBDYNE_DIR_CONFIG => undef,
511            
512            
513             # Dir_config can be loaded from each directory via webdyne.conf.pl
514             # if desired, only under Plack at the moment
515             #
516             WEBDYNE_DIR_CONFIG_CWD_LOAD => 1,
517            
518            
519             # Local constant path names. Used as marker only, updated dynamically
520             # by &local_constant_load;
521             #
522             WEBDYNE_CONF_HR => undef,
523            
524            
525             # Config file name
526             #
527             WEBDYNE_CONF_FN => 'webdyne.conf.pl',
528            
529            
530             # Tidy output ? Will require HTML::Tidy5 and all dependencies to be installed
531             #
532             WEBDYNE_HTML_TIDY => 0,
533            
534            
535             # HTML::Tidy5 config
536             #
537             WEBDYNE_HTML_TIDY_CONFIG_HR => {
538              
539             'indent' => 0, # enable indentation
540             'indent-spaces' => 2, # 2 spaces per indent level
541             'wrap' => 0, # don't wrap lines
542             'tidy-mark' => 'no', # don't add a tidy comment
543             'clean' => 'no', # don't clean embedded styles
544             'drop-empty-elements' => 'no', # don't remove empty elements
545             'hide-comments' => 'no', # keep HTML comments
546             'fix-uri' => 'no', # don't alter URIs
547             'output-html' => 'yes', # output as HTML
548             'show-warnings' => 'no', # suppress warnings
549              
550             },
551            
552            
553             # Add some linefeeds via "\n" to output
554             #
555             WEBDYNE_HTML_NEWLINE => 0,
556              
557              
558             # Mod_perl level. Do not change unless you know what you are
559             # doing.
560             #
561             MP2 => $MP2,
562             MOD_PERL => $MP_version,
563              
564              
565             );
566              
567              
568             sub local_constant_fn {
569              
570              
571             # Where local constants reside
572             #
573 51     51 0 116 my @local_constant_fn;
574 51         152 my $local_constant_fn=$Constant{'WEBDYNE_CONF_FN'};
575 51 50       231 if ($^O=~/MSWin[32|64]/) {
576 0   0     0 my $dn=$ENV{'WEBDYNE_HOME'} || $ENV{'WEBDYNE'} || $ENV{'WINDIR'};
577 0   0     0 push @local_constant_fn, ($ENV{'WEBDYNE_CONF'} ||
578             File::Spec->catfile($dn, $local_constant_fn))
579             }
580             else {
581 51   66     786 push @local_constant_fn, ($ENV{'WEBDYNE_CONF'} ||
582             File::Spec->catfile(
583             File::Spec->rootdir(), 'etc', $local_constant_fn
584             ))
585             }
586 51 100       212 unless ($ENV{'WEBDYNE_CONF'}) {
587 20         698 push @local_constant_fn, glob(sprintf('~/.%s', $local_constant_fn));
588             }
589 51         100 0 && debug('local_constant_fn: %s, env: %s', Dumper(\@local_constant_fn, \%ENV));
590 51         170 return \@local_constant_fn;
591              
592             }
593              
594              
595             sub cache_dn {
596              
597              
598             # Where the cache directory should be located
599             #
600 9     9 0 16 my $cache_dn;
601 9 50       40 if ($ENV{'PAR_TEMP'}) {
602 0         0 $cache_dn=$ENV{'PAR_TEMP'}
603             }
604              
605              
606             # Used to set like this - now leave the installer to
607             # find and set an appropriate location
608             #
609             #else {
610             #require File::Temp;
611             #$cache_dn=&File::Temp::tempdir( CLEANUP=> 1 );
612             #}
613             #elsif ($prefix) {
614             # $cache_dn=File::Spec->catdir($prefix, 'cache');
615             #}
616             #elsif ($^O=~/MSWin[32|64]/) {
617             # $cache_dn=File::Spec->catdir($ENV{'SYSTEMROOT'}, qw(TEMP webdyne))
618             #}
619             #else {
620             # $cache_dn=File::Spec->catdir(
621             # File::Spec->rootdir(), qw(var cache webdyne));
622             #}
623 9         28 return $cache_dn
624              
625             }
626              
627              
628             sub hashref {
629              
630 0     0 0 0 my $class=shift();
631 0         0 return \%{"${class}::Constant"};
  0         0  
632              
633             }
634              
635              
636              
637             sub local_constant_load {
638              
639              
640             # Load constants from override files.
641             #
642 61     61 0 184 my ($class, $local_constant_fn)=@_;
643 61         125 0 && debug("class: $class, local_constant_fn: $local_constant_fn");
644            
645            
646             # Var to hold hash ref we load
647             #
648 61         112 my $constant_hr;
649            
650            
651             # Now load, making sure we don't reload already loaded file - with bonus of creating
652             # var that tracks/shows loaded files - WEBDYNE_CONF_HR
653             #
654 61         91 0 && debug("attempt load local_constant_fn: $local_constant_fn");
655 61 100 66     1137 if (-f $local_constant_fn && !$Constant{'WEBDYNE_CONF_HR'}{$local_constant_fn}++) {
656             #if (-f $local_constant_fn && !$Package{'file'}{$local_constant_fn}++) {
657 4         7 0 && debug("file exists, about to load from: $local_constant_fn (%s)", File::Spec->rel2abs($local_constant_fn));
658 4         9 $Constant{'WEBDYNE_CONF_HR'}{$local_constant_fn}++;
659 4   33     1707 $constant_hr=do(File::Spec->rel2abs($local_constant_fn)) ||
660             warn("unable to read local constant file, $!");
661             }
662              
663              
664             # Now from environment vars - override anything in config file
665             #
666 61         3719 my %constant_class=%{"${class}::Constant"};
  61         2792  
667 61         883 foreach my $key (keys %constant_class) {
668 5006 100       9672 if (defined $ENV{$key}) {
669 2         5 my $val=$ENV{$key};
670 2         3 0 && debug("using environment value $val for key: $key");
671 2         33 $constant_hr->{$class}{$key}=$val;
672             }
673             }
674              
675              
676             # Load up Apache config - only if running under mod_perl
677             #
678 61 50       431 if (my $server_or=&server_or()) {
679 0         0 my $table_or=$server_or->dir_config();
680 0         0 while (my ($key, $val)=each %{$table_or}) {
  0         0  
681 0         0 0 && debug("installing value $val for Apache directive: $key");
682 0 0       0 $constant_hr->{$class}{$key}=$val if exists $constant_class{$key}
683             }
684             }
685              
686              
687             # Done - return constant hash ref
688             #
689 61         747 return $constant_hr;
690              
691             }
692              
693              
694             sub server_or {
695              
696            
697             # Get the apache server object if available
698             #
699 61 100   61 0 221 unless (exists($Package{'server_or'})) {
700            
701            
702             # Var to hold any server object found
703             #
704 9         17 my $server_or;
705            
706            
707             # Only do checks if running under mod_perl
708             #
709 9 50       30 if ($MP_version) {
710              
711              
712             # Ignore die's for the moment so don't get caught by error handler
713             #
714 0         0 0 && debug("detected mod_perl version $MP_version - loading Apache directives");
715 0         0 local $SIG{'__DIE__'}=undef;
716 0         0 my $server_or;
717 0         0 eval {
718             # Modern mod_perl 2
719 0         0 require Apache2::ServerUtil;
720 0         0 require APR::Table;
721 0         0 $server_or=Apache2::ServerUtil->server();
722             };
723 0 0       0 $@ && eval {
724              
725             # Interim mod_perl 1.99x
726 0         0 require Apache::ServerUtil;
727 0         0 require APR::Table;
728 0         0 $server_or=Apache::ServerUtil->server();
729             };
730 0 0       0 $@ && eval {
731              
732             # mod_perl 1x ?
733 0         0 require Apache::Table;
734 0         0 $server_or=Apache->server();
735             };
736              
737             # Clear any eval errors, set via dir_config now (overrides env)
738             #
739 0 0       0 $@ && do {
740 0         0 eval {undef}; errclr()
  0         0  
  0         0  
741             };
742 0         0 0 && debug("loaded server_or: $server_or");
743            
744             }
745             else {
746 9         16 0 && debug('skip server_or load, not running under mod_perl');
747             }
748            
749            
750             # Save away so don't have to do this again
751             #
752 9         51 $Package{'server_or'}=$server_or;
753            
754             }
755            
756            
757             # Return it
758             #
759 61         202 return $Package{'server_or'};
760            
761             }
762              
763              
764             sub import {
765            
766              
767             # Get caller
768             #
769 51     51   236068 my ($class, $local_constant_fn)=@_;
770            
771            
772             # Check for dump flag, reserved word
773             #
774 51         108 my $dump_fg;
775 51 50 100     409 if (($local_constant_fn ||= '') eq 'dump') {
776 0         0 $dump_fg++;
777 0         0 $local_constant_fn=undef;
778             }
779            
780            
781             # Get array of local files also
782             #
783 51         218 my $local_constant_fn_ar=&local_constant_fn();
784 51         84 0 && debug("local_constant_fn_ar: %s", Dumper($local_constant_fn_ar));
785            
786            
787             # Load files if neccessary, get hash of constants to be applied
788             #
789 51         92 my @class_constant_hr;
790 51         96 foreach my $fn (grep {$_} (@{$local_constant_fn_ar}, $local_constant_fn)) {
  122         319  
  51         157  
791            
792            
793             # Don't process twice
794             #
795 72   100     320 my $fn_hr=$Package{'import'}{$fn} ||= do {
796            
797             # Need to load in file, haven't seen it yet/
798             #
799 61         92 0 && debug("loading file: $fn");
800            
801            
802             # If here need to read hash ref in from file
803             #
804 61         178 &local_constant_load($class, $fn);
805            
806             };
807 72         158 0 && debug("local_constant_load hr: $fn_hr, %s", Dumper($fn_hr));
808            
809            
810             # Any constants for this class into array for loading
811             #
812 72 100       282 if (my $class_constant_hr=$fn_hr->{$class}) {
813            
814            
815             # Yes, save for later processing
816             #
817 13         19 0 && debug("adding class_constant_hr: $class_constant_hr for processing, %s", Dumper($class_constant_hr));
818 13         36 push @class_constant_hr, $class_constant_hr;
819            
820             }
821             else {
822            
823 59         155 0 && debug("skip $fn, no class: $class component in hash ref");
824            
825             }
826            
827             }
828              
829            
830             # Debug what we have
831             #
832 51         115 0 && debug('class_constant_hr: %s', Dumper(\@class_constant_hr));
833            
834            
835             # Get hash ref of Constants file from class calling us - calling
836             # module needs to declare a %Class:Name::Constant variable in
837             # global space.
838             #
839 51         79 my $class_constant_hr=\%{"${class}::Constant"};
  51         217  
840            
841              
842             # We want to load variable into namespace. Get the parent class and who is
843             # calling us/
844             #
845 51         353 (my $class_parent=$class)=~s/::Constant$//;
846 51         153 my $caller = caller(0);
847 51         85 0 && debug("caller: $caller");
848            
849            
850             # Remember caller
851             #
852 51         188 $Package{'caller'}{$class}{$caller}++;
853            
854              
855             # Now start iterating over and loading
856             #
857 51         119 foreach $caller (keys %{$Package{'caller'}{$class}}) {
  51         231  
858 163         375 foreach my $constant_hr ($class_constant_hr, @class_constant_hr) {
859            
860              
861             # Now iterate across all callers and load vars into namespace. Turn off warnings as
862             # we may have to redefine some variables
863             #
864 9     9   80 no warnings qw(once redefine);
  9         13  
  9         6560  
865 203         268 0 && debug("importing for caller: $caller");
866            
867            
868             # Don't load hash ref into caller if already done. This probably needs to be reworked ..
869             #
870 203 50       325 if (my $var_test= (keys(%{$constant_hr}))[0] ) {
  203         3242  
871 203         325 0 && debug("picking var: $var_test as test, exists *{${caller}::${var_test}}: %s", defined(*{"${caller}::${var_test}"}));
872 203 100 66     899 if ($Package{'caller'}{$caller}{$constant_hr}++ && defined(*{"${caller}::${var_test}"})) {
  138         715  
873 138         193 0 && debug("skip, already applied $constant_hr to caller: $caller");
874 138         830 next;
875             }
876             else {
877 65         118 0 && debug('continue');
878             }
879             }
880             else {
881 0         0 0 && debug('no test var found in constant_hr: %s', Dumper($constant_hr));
882             }
883            
884            
885             # Start iterating over all constants in class
886             #
887 65         303 while (my($k, $v)=each %{$class_constant_hr}) {
  5538         18260  
888            
889             # Override ?
890             #
891 5473 100 100     20232 if (defined($constant_hr->{$k}) && ($constant_hr ne $class_constant_hr)) {
892            
893             # Yes
894             #
895 47         57 0 && debug('override constant_hr $k value: %s with file value: %s', $v, $constant_hr->{$k});
896 47         84 $v=$class_constant_hr->{$k}=$constant_hr->{$k};
897              
898             }
899 5473         6799 0 && debug("caller: $caller, class: $class set:$k value:$v");
900              
901              
902             # Used to do just
903             #
904             # *{"${caller}::${k}"}=\$v;
905             #
906             # Make a bit more sophisticated so if the
907             # var is updated anywhere it is used all
908             # modules see + put a hash called Constant in
909             # the parent module so we don't have to do
910             #
911             # %WebDyne::Constant::Constant
912             #
913             # now just
914             #
915             # %WebDyne::Constant
916             #
917 5473 100       9996 if ($caller eq $class_parent) {
918 961         1166 *{"${caller}::${k}"}=\$v;
  961         2944  
919             #*{"${caller}::Constant"}=$hr; # Pulled for moment, bit polluting without ability to ref constant scalars in hash values
920             }
921             else {
922 4512 100       6836 if (defined *{"${class_parent}::${k}"}) {
  4512         13180  
923 4230         5261 *{"${caller}::${k}"} = *{"${class_parent}::${k}"};
  4230         18076  
  4230         7890  
924             }
925             else {
926 282         464 *{"${caller}::${k}"} = \$v;
  282         1050  
927             }
928             # Used to be this
929             #*{"${caller}::${k}"}=\${"${class_parent}::${k}"};
930             }
931 5473         7054 0 && debug("caller: $caller, set:$k value:$v");
932             #next if ref($v); # Not needed, stop Regexp conversion
933 5473 100       15480 if ($v=~/^\d+$/) {
934 3494         4351 0 && debug("using sub() ${caller}::${k}=$v");
935 3494         181589 *{"${caller}::${k}"}=eval("sub () { $v }");
  3494         24858  
936             }
937             else {
938 1979         2577 0 && debug("fall through, using sub() ${caller}::${k}=q($v)");
939 1979         107153 *{"${caller}::${k}"}=eval("sub () { q($v) }");
  1979         13812  
940             }
941            
942             }
943             }
944             }
945            
946            
947             # Check if just dumping for view, or actually loading into caller
948             # namespace
949             #
950 51 50       26811 if ($dump_fg) {
951              
952             # We just to want to see what they are
953             #
954 0           local $Data::Dumper::Indent=1;
955 0           local $Data::Dumper::Terse=1;
956 0           local $Data::Dumper::Sortkeys=1;
957 0           CORE::print Dumper($class_constant_hr);
958 0           exit 0;
959             }
960            
961             }
962              
963              
964             1;
965              
966              
967             __END__