in reply to patchable settings

To continue on from our CB conversation id like to see getVars() and setVars() bullet proofed. Currently its too possible to pollute the data. I propose switching to a new robust encoding (thats fast as well) and putting a version code on the strings. Something like '===01' as a magic number to start the strings (since this cant occur currently if I understand things right). Then convert to the new system on write. That way so long as folks use getVars() and setVars() they will always get their data through. This would resolve a longstanding nit of mine with settings. As I said before I had to rename Q&A_Section to QandASection to put it in the settings, likewise we've had trouble in the past with categorized answer and categorized question and underlining, deunderlining etc. Setting need/could need to store non \w chars all the time.

Sorry, a bit of free thought there for you...


---
demerphq

    First they ignore you, then they laugh at you, then they fight you, then you win.
    -- Gandhi

    Flux8


Replies are listed 'Best First'.
Re^2: patchable settings
by ysth (Canon) on Sep 28, 2004 at 03:34 UTC
    I'd rather not have versioned strings if we can avoid it. Could you run a dumper prompt to see if there are currently any keys containing "%"? (Select nodes with vars containing '%' and check grep /%/, keys %{getVars($N)} .)

    Update: also check for '+'

      I don't understand why people are reluctant to use techniques like version codes here. (I say this because ive noticed others also dislike version codes.) To me a settings field is just a data format which is really a file format. And its usually better to code version strings into such systems early while its easy. The flexibility such a mechanism offers in a situation like here is quite nice if you ever have reason to change the way things work. And I've had call to use it elsewhere on PM to good effect already.

      # note that these two vars go together to a certain extent. my $magic="===&01"; my $escape="%=&"; sub unpack_hash { my ($str)=shift; my %hash; if (substr($str,0,6) eq $magic) { substr($str,0,6)=''; %hash=map { map { s/%(\d)/substr($escape,$1,1)/ge; $_ } split /=/,$_ } split /&/,$str; } else { # old getVars() support... } } sub pack_hash { my $hash=shift; return $magic.join("&",map { join "=",map { (my $v=$_)=~s/([$escape])/'%'.index($escape,$1)/ge $v } $_ => $hash{$_} } sort keys %$hash); }

      Since bullet proofing getVars() probably means it faster to do than the current method, I personally dont see why we shouldn't do it.


      ---
      demerphq

        First they ignore you, then they laugh at you, then they fight you, then you win.
        -- Gandhi

        Flux8


      • Update:  
      Note that only a sliver of extra code would allow using Data::Dumper for the values if requested to do so (with only a tiny overhead were the hash values reference free). Ultimately that would be where I would go. Encode the keys with extra info when packed to indicate their value needs thawing. Anyway.... :-)


        My reluctance is based on two things, both very minor; first, it means taking really short simple code and making it less so; second, it reduces the readability of the raw data.

        It's your call; if you say so, I'll take what you have above and integrate it with my unpackVars/packVars (though I'd much prefer just to use the escape() and unescape() that are already there).

        How does this look (patch is on top of [id://patchable settings;displaycode|previous patch]):
        --- Everything.pm 2004-10-05 11:28:38.716515200 -0700 +++ Everything.pm.new 2004-10-05 11:31:58.093204800 -0700 @@ -261,13 +261,28 @@ sub unescape sub unpackVars { my ($vars) = @_; + my $format_version = "00"; + + # version 00: original format + # version 01: keys are escaped, not just values + $format_version = $1 if $vars =~ s/^==(\d\d)&//; return {} unless $vars; - my %vars = map { split /=/ } split (/&/, $vars); - foreach (keys %vars) { - unescape $vars{$_}; - if ($vars{$_} eq ' ') { $vars{$_} = ""; } + my %vars; + + for (split /&/, $vars) { + my ($k,$v) = split /=/; + + if ($format_version > 0) { + unescape( $k, $v ); + } else { + unescape( $v ); + } + + $v = '' if $v eq ' '; + + $vars{$k} = $v; } return \%vars; @@ -296,7 +311,9 @@ sub packVars $$varsref{$_} = " " unless $$varsref{$_}; } - return join("&", map( $_."=".escape($$varsref{$_}), keys %$varsre +f) ); + # current format version: 01 + return join("&", "==01", + map( escape($_)."=".escape($$varsref{$_}), keys %$varsref) ); } ##################################################################### +########
        I think I've placed more emphasis (or at least tried to) on readability and reuse than what you had suggested. I'm guessing it will be about as fast as the existing code. If you are ok with this, I'll try it out on the test server.