Page 1 of 2 1 2 LastLast
Results 1 to 10 of 16

Thread: Veracity's Property Management Library - vprops.ash

  1. #1
    Developer Veracity's Avatar
    Join Date
    Mar 2006
    Location
    The Unseelie Court
    Posts
    11,389

    Default Veracity's Property Management Library - vprops.ash

    If we can have "zlib", why not "vprops"?

    This is a package of functions to make it easy to store and retrieve simple and complex datatypes in properties. It was inspired by the desire to let my script define all of its configuration variables with default values and associated properties, allowing the script user to either edit the script to change the default or set individual properties for specific users to override one or more defaults, but having actual properties set in your preferences file only if they override the script's default.

    If I have 50 script variable and you override 3 of them for user A and 2 for user B, user A will have 3 properties and user B will have 2.

    And it exists!

    Code:
    svn checkout https://svn.code.sf.net/p/veracity0/code/vprops
    Here is documentation, of sorts:

    Code:
    since r17892;
    
    // Properties are mappings from string to string: a (string) name has a (string) value.
    //
    // The string value can represent one of the following simple ASH data types:
    //
    // "string"
    // "boolean"	boolean to_boolean( string ); string to_string( boolean );
    // "int"	int to_int( string ); string to_string( int );
    // "float"	float to_float( string ); string to_string( float );
    // "item"	item to_item( string ); string to_string( item );
    // "location"	location to_location( string ); string to_string( location );
    // "class"	class to_class( string ); string to_string( class );
    // "stat"	stat to_stat( string ); string to_string( stat );
    // "skill"	skill to_skill( string ); string to_string( skill );
    // "effect"	effect to_effect( string ); string to_string( effect );
    // "familiar"	familiar to_familiar( string ); string to_string( familiar );
    // "monster"	monster to_monster( string ); string to_string( monster );
    // "element"	element to_element( string ); string to_string( element );
    // "phylum"	phylum to_phylum( string ); string to_string( phylum );
    // "coinmaster"	coinmaster to_coinmaster( string ); string to_string( coinmaster );
    // "thrall"	thrall to_thrall( string ); string to_string( thrall );
    // "bounty"	bounty to_bounty( string ); string to_string( bounty );
    // "servant"	servant to_servant( string ); string to_string( servant );
    // "vykea"	vykea to_vykea( string ); string to_string( vykea );
    //
    // They can also represent collections of those simple types:
    //
    // "list" -> TYPE [int] - an ordered collection, allowing duplicates.
    // "set" -> boolean [TYPE] - an unordered collection with no duplicates
    //
    // Collections are put into strings by listing them in the natural order
    // of the key, separated by a delimiter character. By default, the
    // delimiter is "|", but "," or ";" or anything else can be used
    //
    // (Internally, this uses split_string(), which takes a regex, not a
    // string. Since "|" is a special character in a regex, for convenience,
    // we turn "|" into "\\|". But you are welcome to use an actual regex,
    // rather than a "delimiter character" if you wish.)
    //
    // Since the key of a "list" is an int, the elements of the list are
    // ordered and duplicate values are allowed.
    //
    // Since the key of a "set" is any datatype, the elements of the set
    // are not ordered and duplicate keys are not allowed.
    
    // You can use the appropriate built-in ASH function to convert between
    // simple ASH data types and a string, or vice versa, as listed above.
    //
    // This package provides coercion functions for "list" and "set" types.
    // The versions without "delimiter" assume "|".
    
    // Sets:
    
    boolean [boolean] to_set_of_boolean( string set, string delimiter );
    boolean [boolean] to_set_of_boolean( string set );
    string to_string( boolean [boolean] set, string delimiter );
    string to_string( boolean [boolean] set );
    
    boolean [int] to_set_of_int( string set, string delimiter );
    boolean [int] to_set_of_int( string set );
    string to_string( boolean [int] set, string delimiter );
    string to_string( boolean [int] set );
    
    boolean [float] to_set_of_float( string set, string delimiter );
    boolean [float] to_set_of_float( string set );
    string to_string( boolean [float] set, string delimiter );
    string to_string( boolean [float] set );
    
    boolean [string] to_set_of_string( string set, string delimiter );
    boolean [string] to_set_of_string( string set );
    string to_string( boolean [string] set, string delimiter );
    string to_string( boolean [string] set );
    
    boolean [item] to_set_of_item( string set, string delimiter );
    boolean [item] to_set_of_item( string set );
    string to_string( boolean [item] set, string delimiter );
    string to_string( boolean [item] set );
    
    boolean [location] to_set_of_location( string set, string delimiter );
    boolean [location] to_set_of_location( string set );
    string to_string( boolean [location] set, string delimiter );
    string to_string( boolean [location] set );
    
    boolean [class] to_set_of_class( string set, string delimiter );
    boolean [class] to_set_of_class( string set );
    string to_string( boolean [class] set, string delimiter );
    string to_string( boolean [class] set );
    
    boolean [stat] to_set_of_stat( string set, string delimiter );
    boolean [stat] to_set_of_stat( string set );
    string to_string( boolean [stat] set, string delimiter );
    string to_string( boolean [stat] set );
    
    boolean [skill] to_set_of_skill( string set, string delimiter );
    boolean [skill] to_set_of_skill( string set );
    string to_string( boolean [skill] set, string delimiter );
    string to_string( boolean [skill] set );
    
    boolean [effect] to_set_of_effect( string set, string delimiter );
    boolean [effect] to_set_of_effect( string set );
    string to_string( boolean [effect] set, string delimiter );
    string to_string( boolean [effect] set );
    
    boolean [familiar] to_set_of_familiar( string set, string delimiter );
    boolean [familiar] to_set_of_familiar( string set );
    string to_string( boolean [familiar] set, string delimiter );
    string to_string( boolean [familiar] set );
    
    boolean [monster] to_set_of_monster( string set, string delimiter );
    boolean [monster] to_set_of_monster( string set );
    string to_string( boolean [monster] set, string delimiter );
    string to_string( boolean [monster] set );
    
    boolean [element] to_set_of_element( string set, string delimiter );
    boolean [element] to_set_of_element( string set );
    string to_string( boolean [element] set, string delimiter );
    string to_string( boolean [element] set );
    
    boolean [phylum] to_set_of_phylum( string set, string delimiter );
    boolean [phylum] to_set_of_phylum( string set );
    string to_string( boolean [phylum] set, string delimiter );
    string to_string( boolean [phylum] set );
    
    boolean [coinmaster] to_set_of_coinmaster( string set, string delimiter );
    boolean [coinmaster] to_set_of_coinmaster( string set );
    string to_string( boolean [coinmaster] set, string delimiter );
    string to_string( boolean [coinmaster] set );
    
    boolean [thrall] to_set_of_thrall( string set, string delimiter );
    boolean [thrall] to_set_of_thrall( string set );
    string to_string( boolean [thrall] set, string delimiter );
    string to_string( boolean [thrall] set );
    
    boolean [bounty] to_set_of_bounty( string set, string delimiter );
    boolean [bounty] to_set_of_bounty( string set );
    string to_string( boolean [bounty] set, string delimiter );
    string to_string( boolean [bounty] set );
    
    boolean [servant] to_set_of_servant( string set, string delimiter );
    boolean [servant] to_set_of_servant( string set );
    string to_string( boolean [servant] set, string delimiter );
    string to_string( boolean [servant] set );
    
    boolean [vykea] to_set_of_vykea( string set, string delimiter );
    boolean [vykea] to_set_of_vykea( string set );
    string to_string( boolean [vykea] set, string delimiter );
    string to_string( boolean [vykea] set );
    
    // Lists:
    
    boolean [int] to_list_of_boolean( string list, string delimiter );
    boolean [int] to_list_of_boolean( string list );
    string to_string( boolean [int] list, string delimiter );
    string to_string( boolean [int] list );
    
    int [int] to_list_of_int( string list, string delimiter );
    int [int] to_list_of_int( string list );
    string to_string( int [int] list, string delimiter );
    string to_string( int [int] list );
    
    float [int] to_list_of_float( string list, string delimiter );
    float [int] to_list_of_float( string list );
    string to_string( float [int] list, string delimiter );
    string to_string( float [int] list );
    
    string [int] to_list_of_string( string list, string delimiter );
    string [int] to_list_of_string( string list );
    string to_string( string [int] list, string delimiter );
    string to_string( string [int] list );
    
    item [int] to_list_of_item( string list, string delimiter );
    item [int] to_list_of_item( string list );
    string to_string( item [int] list, string delimiter );
    string to_string( item [int] list );
    
    location [int] to_list_of_location( string list, string delimiter );
    location [int] to_list_of_location( string list );
    string to_string( location [int] list, string delimiter );
    string to_string( location [int] list );
    
    class [int] to_list_of_class( string list, string delimiter );
    class [int] to_list_of_class( string list );
    string to_string( class [int] list, string delimiter );
    string to_string( class [int] list );
    
    stat [int] to_list_of_stat( string list, string delimiter );
    stat [int] to_list_of_stat( string list );
    string to_string( stat [int] list, string delimiter );
    string to_string( stat [int] list );
    
    skill [int] to_list_of_skill( string list, string delimiter );
    skill [int] to_list_of_skill( string list );
    string to_string( skill [int] list, string delimiter );
    string to_string( skill [int] list );
    
    effect [int] to_list_of_effect( string list, string delimiter );
    effect [int] to_list_of_effect( string list );
    string to_string( effect [int] list, string delimiter );
    string to_string( effect [int] list );
    
    familiar [int] to_list_of_familiar( string list, string delimiter );
    familiar [int] to_list_of_familiar( string list );
    string to_string( familiar [int] list, string delimiter );
    string to_string( familiar [int] list );
    
    monster [int] to_list_of_monster( string list, string delimiter );
    monster [int] to_list_of_monster( string list );
    string to_string( monster [int] list, string delimiter );
    string to_string( monster [int] list );
    
    element [int] to_list_of_element( string list, string delimiter );
    element [int] to_list_of_element( string list );
    string to_string( element [int] list, string delimiter );
    string to_string( element [int] list );
    
    phylum [int] to_list_of_phylum( string list, string delimiter );
    phylum [int] to_list_of_phylum( string list );
    string to_string( phylum [int] list, string delimiter );
    string to_string( phylum [int] list );
    
    coinmaster [int] to_list_of_coinmaster( string list, string delimiter );
    coinmaster [int] to_list_of_coinmaster( string list );
    string to_string( coinmaster [int] list, string delimiter );
    string to_string( coinmaster [int] list );
    
    thrall [int] to_list_of_thrall( string list, string delimiter );
    thrall [int] to_list_of_thrall( string list );
    string to_string( thrall [int] list, string delimiter );
    string to_string( thrall [int] list );
    
    bounty [int] to_list_of_bounty( string list, string delimiter );
    bounty [int] to_list_of_bounty( string list );
    string to_string( bounty [int] list, string delimiter );
    string to_string( bounty [int] list );
    
    servant [int] to_list_of_servant( string list, string delimiter );
    servant [int] to_list_of_servant( string list );
    string to_string( servant [int] list, string delimiter );
    string to_string( servant [int] list );
    
    vykea [int] to_list_of_vykea( string list, string delimiter );
    vykea [int] to_list_of_vykea( string list );
    string to_string( vykea [int] list, string delimiter );
    string to_string( vykea [int] list );
    
    // Values work best if they are "normalized".
    //
    // "seal tooth" is a normalized "item"
    // "seal t" is not normalized.
    // "snorkel|seal tooth" is a normalized "list" or "set" of "item"
    // "snork|seal t" is not normalized
    //
    // This package provides functions to normalize string values. Since
    // users can set properties to whatever they wish, it uses these
    // functions itself, but user programs can also use them if they want to
    // ensure that properties that they set are precise.
    
    string normalize_value( string value, string type );
    
    string normalize_list( string value, string type, string delimiter );
    string normalize_list( string value, string type );
    string normalize_set( string value, string type, string delimiter );
    string normalize_set( string value, string type );
    
    string normalize_value( string value, string type, string collection, string delimiter );
    string normalize_value( string value, string type, string collection );
    
    // define_property specifies that a particular property with NAME is of type TYPE.
    // Optionally, you can declare that the value is a COLLECTION (either "list" or "set") with a DELIMITER
    // NAME can be either built-in to KoLmafia or a custom user property.
    // If it is a custom property, you can specify a DEFAULT value
    //
    // If the property exists, define_property will fetch the value,
    // normalize it, and return it.
    //    If the property is custom and the value is not normalized,
    //    the property will be set with the normalized value.
    //    If the property is custom and the normalized value equals
    //    the normalized default value, the property will be removed.
    //
    // If the property does not exist, define_property will return the
    // (normalized) default value and the property will remain unset.
    
    string define_property( string name, string type, string def );
    string define_property( string name, string type, string def, string collection );
    string define_property( string name, string type, string def, string collection, string delimiter );
    
    // You can use these in conjunction with the appropriate coercion
    // function to extract the value of a property into the appropriate data
    // type. For example:
    //
    // int prop1 = define_property( "prop1", "int", "12" ).to_int();
    // boolean prop2 = define_property( "prop2", "boolean", "true" ).to_boolean();
    // item prop3 = define_property( "prop3", "item", "snorkel" ).to_item();
    // boolean [item] prop4 = define_property( "prop4", "item", "snorkel|seal tooth", "set" ).to_set_of_item();
    // string [int] prop5 =  define_property( "prop5", "string", "str1,str2,str3", "list", "," ).to_list_of_string( "," );
    Last edited by Veracity; 03-14-2017 at 09:59 PM. Reason: It's alive!
    Ph'nglui mglw'nafh Cthulhu
    R'lyeh wgah-nagl fhtagn.

  2. #2
    Developer Veracity's Avatar
    Join Date
    Mar 2006
    Location
    The Unseelie Court
    Posts
    11,389

    Default

    This is coming along quickly. I have all the coercion functions and the normalization functions.

    Code:
    > ash get_property( "_deckCardsSeen" )
    
    Returned: 1952 Mickey Mantle|Ancestral Recall|Island
    
    > ash import <vprops.ash>; to_list_of_string( get_property( "_deckCardsSeen" ) )
    
    Returned: aggregate string [int]
    0 => 1952 Mickey Mantle
    1 => Ancestral Recall
    2 => Island
    
    > ash import <vprops.ash>; to_set_of_string( get_property( "_deckCardsSeen" ) )
    
    Returned: aggregate boolean [string]
    1952 Mickey Mantle => true
    Ancestral Recall => true
    Island => true
    
    > ash import <vprops.ash>; to_set_of_string( get_property( "_deckCardsSeen" ) ).to_string( "," )
    
    Returned: 1952 Mickey Mantle,Ancestral Recall,Island
    Not all of the coercion functions are especially useful; who will ever have a "set of booleans", for example? That one has exactly four possible values:

    {}
    {false}
    {true}
    {false,true}

    But, for completeness, I allowed sets and lists of almost all of ASH's built-in data types.

    Now that I think about it, I probably should make that "all", rather than "almost all". I skipped the following because they didn't seem useful:

    coinmaster
    thrall
    bounty
    servant
    vykea

    but you know, I could user a vykea property in my own script.

    So I guess I will add them.
    Ph'nglui mglw'nafh Cthulhu
    R'lyeh wgah-nagl fhtagn.

  3. #3
    Developer Veracity's Avatar
    Join Date
    Mar 2006
    Location
    The Unseelie Court
    Posts
    11,389

    Default

    Code:
    > ash import <vprops.ash>; normalize_value( "snork|seal t", "item", "list" )
    
    Returned: snorkel|none
    
    > ash import <vprops.ash>; to_string( item [int] { 1: $item[seal t] , 2 : $item[snork ] } )
    Bad item value: "seal t" ()
    Returned: void
    
    > ash import <vprops.ash>; normalize_value( "snork|seal to", "item", "list" )
    
    Returned: snorkel|seal tooth
    
    > ash import <vprops.ash>; normalize_value( "snork|seal to", "item", "set" )
    
    Returned: seal tooth|snorkel
    
    > ash import <vprops.ash>; to_string( item [int] { 1: $item[seal to] , 2 : $item[snork ] } )
    
    Changing "seal to" to "seal tooth" would get rid of this message. ()
    Changing "snork" to "snorkel" would get rid of this message. ()
    Returned: seal tooth|snorkel
    normalize_value() calls to_item() to coerce strings to items.
    I suppose it could generate its own "friendly warnings". Or not.
    Ph'nglui mglw'nafh Cthulhu
    R'lyeh wgah-nagl fhtagn.

  4. #4
    Developer Veracity's Avatar
    Join Date
    Mar 2006
    Location
    The Unseelie Court
    Posts
    11,389

    Default

    This script:

    Code:
    import <vprops.ash>;
    
    int prop1 = define_property( "TVP.prop1", "int", "12" ).to_int();
    print( "TVP.prop1 exists = " + property_exists( "TVP.prop1" ) );
    print( "prop1 = " + prop1 );
    
    set_property( "TVP.prop1", "10" );
    prop1 = define_property( "TVP.prop1", "int", "12" ).to_int();
    print( "TVP.prop1 exists = " + property_exists( "TVP.prop1" ) );
    print( "prop1 = " + prop1 );
    
    set_property( "TVP.prop1", "12" );
    prop1 = define_property( "TVP.prop1", "int", "12" ).to_int();
    print( "TVP.prop1 exists = " + property_exists( "TVP.prop1" ) );
    print( "prop1 = " + prop1 );
    
    print( "" );
    
    boolean prop2 = define_property( "TVP.prop2", "boolean", "true" ).to_boolean();
    print( "TVP.prop2 exists = " + property_exists( "TVP.prop2" ) );
    print( "prop2 = " + prop2 );
    
    print( "" );
    
    item prop3 = define_property( "TVP.prop3", "item", "snorkel" ).to_item();
    print( "TVP.prop3 exists = " + property_exists( "TVP.prop3" ) );
    print( "prop3 = " + prop3 );
    
    print( "" );
    
    boolean [item] prop4 = define_property( "TVP.prop4", "item", "snorkel|seal tooth", "set" ).to_set_of_item();
    print( "TVP.prop4 exists = " + property_exists( "TVP.prop4" ) );
    print( "prop4 = " + prop4 );
    foreach key, val in prop4 {
        print( key + " => " + val );
    }
    
    print( "" );
    
    string [int] prop5 =  define_property( "TVP.prop5", "string", "str1,str2,str3", "list", "," ).to_list_of_string( "," );
    print( "TVP.prop5 exists = " + property_exists( "TVP.prop5" ) );
    print( "prop5 = " + prop5 );
    foreach key, val in prop5 {
        print( key + " => " + val );
    }
    
    print( "" );
    
    string [int] cards =  define_property( "_deckCardsSeen", "string", "str1,str2,str3", "list", "," ).to_list_of_string();
    print( "_deckCardsSeen exists = " + property_exists( "_deckCardsSeen" ) );
    print( "_deckCardsSeen = " + cards );
    foreach key, val in cards {
        print( key + " => " + val );
    }
    Yields this:

    Code:
    > test_vprops.ash
    
    TVP.prop1 exists = false
    prop1 = 12
    TVP.prop1 => 10
    TVP.prop1 exists = true
    prop1 = 10
    TVP.prop1 => 12
    TVP.prop1 exists = false
    prop1 = 12
    
    TVP.prop2 exists = false
    prop2 = true
    
    TVP.prop3 exists = false
    prop3 = snorkel
    
    TVP.prop4 exists = false
    prop4 = aggregate boolean [item]
    seal tooth => true
    snorkel => true
    
    TVP.prop5 exists = false
    prop5 = aggregate string [int]
    0 => str1
    1 => str2
    2 => str3
    
    _deckCardsSeen exists = true
    _deckCardsSeen = aggregate string [int]
    0 => 1952 Mickey Mantle
    1 => Ancestral Recall
    2 => Island
    I'll release this into the wild.
    Ph'nglui mglw'nafh Cthulhu
    R'lyeh wgah-nagl fhtagn.

  5. #5
    Developer Veracity's Avatar
    Join Date
    Mar 2006
    Location
    The Unseelie Court
    Posts
    11,389

    Default

    Bale, if you want to add this to the catalog, perhaps this will do:

    Code:
    {
      "repo": "https://svn.code.sf.net/p/veracity0/code/vprops/", 
      "author": "Veracity", 
      "name": "Veracity's Property Management Library", 
      "forumThread": "http://kolmafia.us/showthread.php?21593", 
      "shortDesc": "Functions to easily manage custom properties", 
      "category": "library", 
      "longDesc": "Functions to manage custom properties and convert back and forth between simple data types (and sets and lists of such) and a string representation which is suitable to store in such properties."
     }
    I guessed about the "category".
    Ph'nglui mglw'nafh Cthulhu
    R'lyeh wgah-nagl fhtagn.

  6. #6
    Minion Bale's Avatar
    Join Date
    Jun 2008
    Posts
    13,287

    Default

    I decided it was appropriate to make a few changes:

    Code:
     {
      "repo": "https://svn.code.sf.net/p/veracity0/code/vprops/", 
      "author": "Veracity", 
      "name": "vProps", 
      "forumThread": "http://kolmafia.us/showthread.php?21593-Veracity-s-Property-Management-Library-vprops-ash", 
      "shortDesc": "Veracity's property management library", 
      "category": "library", 
      "longDesc": "Functions to easily manage custom properties and convert back and forth between simple data types (and sets and lists of such) and a string representation which is suitable to store in such properties.<p style='text-align:center;font-style:italic'>This library script will not work by itself and may be automatically installed by other scripts.</p>"
     },
    I don't like names to be much longer than the default field size. Plus I use a default disclaimer for all library scripts.

  7. #7
    Developer Veracity's Avatar
    Join Date
    Mar 2006
    Location
    The Unseelie Court
    Posts
    11,389

    Default

    Thank you!
    Ph'nglui mglw'nafh Cthulhu
    R'lyeh wgah-nagl fhtagn.

  8. #8
    Minion Bale's Avatar
    Join Date
    Jun 2008
    Posts
    13,287

    Default

    I'd like to share something.

    Code:
    string normalize_value( string value, string type )
    {
    	if( $strings[boolean,int,float,item,location,class,stat,skill,effect,familiar,monster,element,phylum,coinmaster,thrall,bounty,servant,vykea] contains type )
    	{
    		string prog = "to_" + type;
    		return call string prog( value );
    	}
    	// If type is "string", or invalid, don't convert anything
    	return value;
    }
    I don't suppose anyone can imagine a way to check if something is a valid data type without hard-coding a list of them?
    Last edited by Bale; 03-16-2017 at 08:30 AM.

  9. #9
    Minion Bale's Avatar
    Join Date
    Jun 2008
    Posts
    13,287

    Default

    I've just moved this script from "Scripting Discussion" to "Informational Scripts" because it was created in a forum that isn't intended for discussing and supporting an active published script.

  10. #10
    Developer Veracity's Avatar
    Join Date
    Mar 2006
    Location
    The Unseelie Court
    Posts
    11,389

    Default

    I want to let you know that I am aware of your "few changes".

    I was at a job interview all day and am still psyched about it, so am not thinking deeply about this - but I will. Wish me luck!

    I don't, personally, like "call". Yes, I added it to ASH, and I see that it can shorten code, but, contrary to what you might think, I am not convinced it is more "efficient", since it pushes the method lookup from compile-time to run-time.

    I'll comment more later, but I'll say now: it is not a no-brainer (for me) to adopt your change.

    But I greatly appreciate your looking at my code and considering adopting (parts of) it!
    Ph'nglui mglw'nafh Cthulhu
    R'lyeh wgah-nagl fhtagn.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •