Last active
July 10, 2020 08:17
-
-
Save DelPyth/cdfd055080f8359746c1ba3d8d6644f5 to your computer and use it in GitHub Desktop.
Java Properties Styled Data Management
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* ========================================================================================================== * | |
* Author .........: Delta Pythagorean | |
* Name ...........: Properties.ahk | |
* Description ....: Java Properties styled parsing and dumping class. | |
* Date ...........: 2020-07-08 (YYYY-MM-DD) | |
* Version ........: 1.0.0 | |
* Language .......: English (United States) | |
* AHK-Version ....: 1.1.32.00 | |
* AHK-Codepage ...: Unicode | |
* AHK-Bit ........: 64 | |
* ========================================================================================================== * | |
* Example ........: ; Read a file into an object. | |
* ................: MyObject := Properties.Parse(A_ScriptDir . "\settings.properties") | |
* ................: ; Parse an object into a file. | |
* ................: Properties.Dump(MyObject, A_ScriptDir . "\settings.properties") | |
* ========================================================================================================== * | |
*/ | |
Class Properties { | |
Class Parse Extends Properties.Functor { | |
Call(FileOrStr) { | |
ReturnObj := {} | |
; If the input is a file, then read it. | |
If (IsObject(FileOrStr) && (FileOrStr.__Handle != Null)) { | |
FileOrStr := FileOrStr.Read() | |
} Else { | |
If (FileExist(FileOrStr)) { | |
FileRead, FileOrStr, % FileOrStr | |
} | |
} | |
; Combine multiple lines together if they have \ at the end of the line. | |
FileOrStr := RegExReplace(FileOrStr, "\s\\\R\s*", "\n") | |
For Index, Line in StrSplit(FileOrStr, "`n", "`r") { | |
; Trim the line down from any trailing or starting spaces. | |
Line := Trim(Line) | |
; Remove comments. | |
Line := RegExReplace(Line, "im)((?:[\t ]+|)\#.*)$") | |
If (Line == Null) { | |
Continue | |
} | |
; Determine the keys and values by this: KEY = VALUE | |
RegExMatch(Line, "Oi)^(?<Key>.+?)\s*=\s*(?<Value>.+)$", Match) | |
; We save the values to variables instead of using the actual variables because as far as I've tested the match object is read-only. | |
Key := Match["Key"] | |
Value := Match["Value"] | |
; We split the input by a dot because AHK is nice and automatically makes the values into objects if they don't exist already. | |
Obj := StrSplit(Trim(Key), ".") | |
; Trim the VALUE from any trailing or leading spaces. | |
Value := Trim(Value) | |
; Check if the value is True or False, then set the value like so. | |
; If it's null. Then set it to be "Null". | |
; Otherwise modify it to use escapes. | |
Switch (Value) { | |
Case "True", "False": { | |
ReturnObj[Obj*] := %Value% + 0 | |
} | |
Case "Null": { | |
; Technically there isn't a Null constant in AHK, but I use use it as a substitute of "" (empty string). | |
ReturnObj[Obj*] := Null | |
} | |
Default: { | |
Value := StrReplace(Value, "\\", "\") | |
Value := StrReplace(Value, "\b", "`b") | |
Value := StrReplace(Value, "\f", "`f") | |
Value := StrReplace(Value, "\n", "`n") | |
Value := StrReplace(Value, "\r", "`r") | |
Value := StrReplace(Value, "\t", "`t") | |
; Thanks to Lexikos from: https://autohotkey.com/board/topic/63263-unicode-escaped-string-convert-u00/ | |
If (Value ~= "\\u[A-Fa-f0-9]{1,4}") { | |
i := 1 | |
While (j := RegExMatch(Value, "\\u[A-Fa-f0-9]{1,4}", m, i)) { | |
e .= SubStr(Value, i, j - i) . Chr("0x" SubStr(m, 3)) | |
i := j + StrLen(m) | |
} | |
Value := e . SubStr(Value, i) | |
} | |
ReturnObj[Obj*] := Value | |
} | |
} | |
} | |
Return (ReturnObj) | |
} | |
} | |
Class Dump Extends Properties.Functor { | |
Call(Object, File := False, LineEnd := "`r`n", __PathTo := False) { | |
ReturnStr := Null | |
If (!IsObject(Object)) { | |
Throw Exception("Parameter must be an object", -2, Object) | |
Return (False) | |
} | |
For Key, Value in Object { | |
If (IsObject(Value)) { | |
ReturnStr .= Properties.Dump(Value, False, LineEnd, (((__PathTo != False) ? (__PathTo . ".") : (Null)) . Key)) | |
} Else { | |
Value := StrReplace(Value, "\", "\\") | |
Value := StrReplace(Value, "`b", "\b") | |
Value := StrReplace(Value, "`f", "\f") | |
Value := StrReplace(Value, "`n", "\n") | |
Value := StrReplace(Value, "`r", "\r") | |
Value := StrReplace(Value, "`t", "\t") | |
ReturnStr .= ((__PathTo != False) ? (__PathTo . ".") : (Null)) . (Key . " = " . Value . LineEnd) | |
} | |
} | |
If (File == False) { | |
Return (ReturnStr) | |
} Else { | |
If ((IsObject(File)) && (File.__Handle != Null)) { | |
File.Write(ReturnStr) | |
} Else { | |
FileAppend, % ReturnStr, % File | |
} | |
Return ((ErrorLevel == True) ? (True) : (ReturnStr)) | |
} | |
} | |
} | |
Class Functor { | |
__Call(Method, Args*) { | |
Return (New This).Call(Args*) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment