#private to parser sub.
sub doInstruction { my ($self,$e,$t,$v) = @_;
my $DO_ENABLED = $self->{'DO_ENABLED'}; my $priority = 0;
+ $e = $t if not defined $e;
$t = "" if not defined $t;
if($t eq 'CONST' or $t eq 'CONSTANT'){#Single constant with mulit-line value;
# It is NOT allowed to overwrite constant.
foreach my $line(split '\n', $v) {
my $isMETAConst = $line =~ s/$meta_const//se;
$line =~ s/^\s+|\s+$//; # strip unwanted spaces
+ next if $line =~ m/^[\/\#]+/; #skip this line its a comment dud.
$line =~ s/\s*>$//;
- $line =~ m/([\$\w]*)(\s*=\s*)(.*)/g;
+ $line =~ m/([\$\w]*)(\s*[=:]\s*)(.*)/g;
my $name = $1;
- $line = $3; $line =~ s/^\s*(['"])(.*)\g{1}$/$2/ if $line;#strip quotes
+ $line = $3;
+ $line =~ s/\s*\#.*$//g; #strip any perl comment at end of line.
+ $line =~ s/^\s*(['"])(.*)\g{1}$/$2/ if $line;#strip quotes
if(defined $name){
if($isVar && not $isMETAConst){
$anons ->{$name} = $line if $line
}else{
$name =~ s/^\$// if $isMETAConst;
# It is NOT allowed to overwrite a constant, so check an issue warning.
- if($line and not $self->{$name}){
+ if(defined $line and not defined $self->{$name}){
$self->{$name} = $line;
}else{ my
$w = "Skipping and keeping a previously set constance of -> [$name] in ". $self->{CNF_CONTENT}." the new value ";
- $w .= ($line eq $self->{$name})?"matches it":"dosean't match -> $line."; $self->warn($w)
+ $w .= ($line eq $self->{$name})?"matches it":"dosean't match ($.) -> $line."; $self->warn($w)
}
}
}
}
}else{
- doInstruction($self,$v,$t,undef);
+ doInstruction($self,undef,$t,$v);
}
}else{
$v =~ s/\s*>$//;
}
}
### Utility way to obtain CNFNodes from a configuration.
+# Reference to the node is returned access like: my $tree = $cnf.getTree(..); my $attr = $$tree->{attribute};
sub getTree {
my ($self, $name) = @_;
return $NODES{$name} if exists $NODES{$name};
--- /dev/null
+###
+# This is a Classic CNF Application setup and wiring implementation. To provide proper syncing and priorities of setting, based on application defaults,
+# script implemented change (release or user changed) and in user or application changed settings, that can now be now in a store,
+# a rather retrieved change from there.
+#
+# Application provided app settings have also the benefit to rather keyword access properties directly avoiding method calls in the code.
+# Further explanations is that this module, sets up in a standard way the settings from some application based or from package provided defaults.
+# With by transition from what is in the script or not, comparing with expected defaults of settings. i.e. the app has English defaults for values.
+# But we changed constants to a Japanese translation and feed it to the app, now not having to change the whole codebase.
+#
+# Or the config script might be missing a property setting, but the application package settings (this file package)
+# will have the default. Use this module as a template to provide own settings for transitions or app requirements.
+#
+# Or only more commonly, employ the static ClassicAppSettings::_set_defaults method before initiating or calling the parser with a script.
+# Containing a <<MySettings<APP_SETTINGS>...>> instruction.
+#
+# App Settings Transition Flow
+#
+# App.Defaults -> ClassicAppSettings -> CNF Merge Default -> ClassicAppSettings [<-> App.StoreSynch Resolve] optional -> App.Settings
+#
+# The app has a configuration file to obtain settings, if missing gets them from assigned code defaults. And if the settings have changed or stored.
+# They get retrieved and replaced regardless what is in code default or in the configuration script. Is this complex?
+# @TODO Also, what happens if script based settings are changed (by admin) and should have higher priority as from the old setting and/or the one in the store?
+# This also happens when we have an new Application release having new settings or worse changed defaults, and an an upgrade shall merge.
+# Can or does JSON do all this stuff too, that CNF is designed for? The answer is NO!
+###
+package ClassicAppSettings;
+
+use strict;use warnings;
+use feature qw(signatures);
+
+
+use constant VERSION => '1.0';
+our %global_defaults;
+our $gl_clone_constances = 0;
+
+sub _set_defaults(%defaults){
+ %global_defaults = %defaults
+}
+sub _set_clone_constances(){
+ $gl_clone_constances = 1
+}
+
+##
+# Called by the parser internally for the APP_Settings instruction.
+##
+sub new {
+ my ($class, $attrs, $self) = @_;
+ $self = {};
+ if ($attrs){
+ foreach(keys %$attrs)
+ { $self -> {$_} = $attrs -> {$_} if $_ !~ 'package|subroutine|property' }
+ }
+ bless $self, $class;
+}
+
+my $global_config;
+my %sync_state;
+
+sub global($this){
+ return $$global_config
+}
+
+sub expect($this){
+ return \%global_defaults
+}
+
+sub setConstant($this, $config, $CONSTANT){
+ if($config->{$CONSTANT} && not $this ->{$CONSTANT}){
+ $this ->{$CONSTANT} = $config->{$CONSTANT}
+ }
+}
+##
+# Possible synch type status changes that can be detected.
+# APP_SETTINGS_SYNC == 1 - Scripted setting not found as an default.
+# APP_SETTINGS_SYNC == 2 - New Setting in script not declared.
+# APP_SETTINGS_SYNC == 3 - Scripted setting changed from default.
+# APP_SETTINGS_SYNC == 4 - Constance not programatically properly wired.
+# APP_SETTINGS_SYNC == 5 - Constance synched in, can't be changed with store synch.
+# APP_SETTINGS_SYNC == 6 - Added new during store synch.
+# APP_SETTINGS_SYNC == 7 - Changed from scipt default during store synch..
+##
+sub setup_with($this, $config, %constants){
+
+ $this->setConstant($config,'APP_NAME');
+ $this->setConstant($config,'APP_VERSION');
+ if($gl_clone_constances){
+ foreach (%{$config}){
+ if($_ =~ m/^[A-Z_0-9]+$/) {$this -> setConstant($config, $_); $sync_state{$_} = 5}
+ }
+ }
+ foreach my $key(keys %{$this}){
+ if(not exists $global_defaults{$key}){
+ $sync_state{$key} = 1;
+ }
+ }
+ foreach my $key(keys %global_defaults){
+ if(not exists $this->{$key}){
+ $this->{$key} = $global_defaults{$key};
+ $sync_state{$key} = 2;
+ }else{
+ my $v = $global_defaults{$key};
+ if(not defined($this->{$key})){
+ $sync_state{$key} = 4;
+ $this->{$key} = $global_defaults{$key};
+ }elsif($this->{$key} ne $v){
+ #Default changed in script
+ $sync_state{$key} = 3;
+ }
+ }
+ }
+ $global_config = \$config;
+}
+###
+# Must be called by obtainer of this, that also handles the store.
+# Just befoer the App uses the settings.
+###
+sub sync_with($this, %store){
+ foreach my $key ( keys %store ) {
+ if(not exists $this->{$key}){
+ $sync_state{$key} = 6;
+ }else{
+ $sync_state{$key} = 7;
+ }
+ $this -> {$key} = $store{$key}
+ }
+ return \%sync_state;
+}
+
+1;
+
+=begin copyright
+Programed by : Will Budic
+EContactHash : 990MWWLWM8C2MI8K (https://github.com/wbudic/EContactHash.md)
+Source : https://github.com/wbudic/PerlCNF.git
+Documentation : Specifications_For_CNF_ReadMe.md
+ This source file is copied and usually placed in a local directory, outside of its repository project.
+ So it could not be the actual or current version, can vary or has been modiefied for what ever purpose in another project.
+ Please leave source of origin in this file for future references.
+Open Source Code License -> https://github.com/wbudic/PerlCNF/blob/master/ISC_License.md
+=cut copyright
\ No newline at end of file