From b4ce29a9520b98178489cccd4eefa91cf738d957 Mon Sep 17 00:00:00 2001 From: KAYLukas Date: Mon, 7 Apr 2014 14:58:03 +0200 Subject: [PATCH 01/22] Adds native record encoding --- json.applescript | 159 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 130 insertions(+), 29 deletions(-) diff --git a/json.applescript b/json.applescript index 3249de0..fdde265 100644 --- a/json.applescript +++ b/json.applescript @@ -1,40 +1,41 @@ on encode(value) set type to class of value - if type = integer + if type = integer then return value as text - else if type = text + else if type = text then return encodeString(value) - else if type = list + else if type = list then return encodeList(value) - else if type = script + else if type = script then return value's toJson() + else if type = record then + return encodeRecord(value) else error "Unknown type " & type - end -end - + end if +end encode on encodeList(value_list) set out_list to {} repeat with value in value_list copy encode(value) to end of out_list - end + end repeat return "[" & join(out_list, ", ") & "]" -end +end encodeList on encodeString(value) set rv to "" repeat with ch in value - if id of ch >= 32 and id of ch < 127 + if id of ch ≥ 32 and id of ch < 127 then set quoted_ch to ch else set quoted_ch to "\\u" & hex4(id of ch) - end + end if set rv to rv & quoted_ch - end + end repeat return "\"" & rv & "\"" -end +end encodeString on join(value_list, delimiter) @@ -43,7 +44,7 @@ on join(value_list, delimiter) set rv to value_list as text set AppleScript's text item delimiters to original_delimiter return rv -end +end join on hex4(n) @@ -52,39 +53,139 @@ on hex4(n) repeat until length of rv = 4 set digit to (n mod 16) set n to (n - digit) / 16 as integer - set rv to (character (1+digit) of digit_list) & rv - end + set rv to (character (1 + digit) of digit_list) & rv + end repeat return rv -end +end hex4 on createDictWith(item_pairs) set item_list to {} - + script Dict on setkv(key, value) copy {key, value} to end of item_list - end - + end setkv + on toJson() set item_strings to {} repeat with kv in item_list set key_str to encodeString(item 1 of kv) set value_str to encode(item 2 of kv) copy key_str & ": " & value_str to end of item_strings - end + end repeat return "{" & join(item_strings, ", ") & "}" - end - end - + end toJson + end script + repeat with pair in item_pairs Dict's setkv(item 1 of pair, item 2 of pair) - end - + end repeat + return Dict -end - +end createDictWith on createDict() return createDictWith({}) -end +end createDict + +on split(aString, aDelimiters) + set oldDelimiters to AppleScript's text item delimiters + set AppleScript's text item delimiters to aDelimiters + set theArray to every text item of aString + set AppleScript's text item delimiters to aDelimiters + return theArray +end split + +on recordToString(aRecord) + set oldClipboard to the clipboard + set the clipboard to aRecord + set str to (do shell script "osascript -e 'the clipboard as record'") + set the clipboard to oldClipboard + return str +end recordToString + +on getValueFromKey(aRecord, aKey) + set s to "on run {aRecord}" & return + set s to s & "get " & aKey & " of aRecord" & return + set s to s & "end" + return (run script s with parameters {aRecord}) +end getValueFromKey + +on recordKeys(value_record) + set str to recordToString(value_record) + set tokens to split(str, {":", ","}) + set possibleKeys to {} + repeat with token in tokens + set possibleKey to trim(change_case(token, "lower")) + if possibleKey is not in possibleKeys then + set end of possibleKeys to possibleKey + end if + end repeat + set recordKeyList to {} + repeat with possibleKey in possibleKeys + try + getValueFromKey(value_record, possibleKey) + --If not found we do not reach this + set end of recordKeyList to ("" & possibleKey) + end try + end repeat + if (count recordKeyList) is not (count value_record) then + error "recordKeys could not successfully recover all keys in the given record" + end if + return recordKeyList +end recordKeys + +on encodeRecord(value_record) + set keys to recordKeys(value_record) + set dictionary to createDict() + repeat with recordKey in keys + dictionary's setkv(recordKey, getValueFromKey(value_record, recordKey)) + end repeat + return encode(dictionary) +end encodeRecord + +on trim(someText) + repeat until someText does not start with " " + set someText to text 2 thru -1 of someText + end repeat + + repeat until someText does not end with " " + set someText to text 1 thru -2 of someText + end repeat + + return someText +end trim +property lower_alphabet : "abcdefghijklmnopqrstuvwxyz" +property upper_alphabet : "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +property white_space : {space, tab, return, ASCII character 10, ASCII character 13} +on change_case(this_text, this_case) + set new_text to "" + if this_case is not in {"UPPER", "lower", "Title", "Sentence"} then + return "Error: Case must be UPPER, lower, Title or Sentence" + end if + if this_case is "lower" then + set use_capital to false + else + set use_capital to true + end if + repeat with this_char in this_text + set x to offset of this_char in lower_alphabet + if x is not 0 then + if use_capital then + set new_text to new_text & character x of upper_alphabet as string + if this_case is not "UPPER" then + set use_capital to false + end if + else + set new_text to new_text & character x of lower_alphabet as string + end if + else + if this_case is "Title" and this_char is in white_space then + set use_capital to true + end if + set new_text to new_text & this_char as string + end if + end repeat + return new_text +end change_case From fdd37c0dd0d806f3e7f416d912357814514877d9 Mon Sep 17 00:00:00 2001 From: KAY Lukas Date: Mon, 7 Apr 2014 15:08:10 +0200 Subject: [PATCH 02/22] Test cases for encoding records --- json.applescript | 2 +- tests.applescript | Bin 1225 -> 2918 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/json.applescript b/json.applescript index fdde265..f242b51 100644 --- a/json.applescript +++ b/json.applescript @@ -27,7 +27,7 @@ end encodeList on encodeString(value) set rv to "" repeat with ch in value - if id of ch ≥ 32 and id of ch < 127 then + if id of ch ³ 32 and id of ch < 127 then set quoted_ch to ch else set quoted_ch to "\\u" & hex4(id of ch) diff --git a/tests.applescript b/tests.applescript index c3684e4f9e08d5e8e81b50b4984a32d73ba6ae1c..4beda053bc5e0d2ea02af4b12d7c83c5b42ff4bc 100644 GIT binary patch literal 2918 zcmcgu(QeZ~5M1%r`~h#l55*va8mBFy5^soK;GwB1+qGN3O{j5EB`d!U%-ni&wnJ#_ zO6ZhibKaYsnZ4ZQ_peGaDKMrI%Xf@IzDSC=!skksm=EL=;-y?6v&6TF9LNvE6`p-X z#H>rKf$Ago zK9}{z-Sgg)i^k#MHSCttlPblTn&Bkjsr?c6Ly9OwRqJXE4z@?^Hoa={>}Gfz@iSKN zh6$y{uzeCVJ10SX-q>rWceo{bw*-RSaZyZ-z5%?ILRB zIm_9)>1u#qjo!A@%qPa5`q}aE4n(cKQK#;6>L(}GQXlxv+4F`Izk62vri>Z+-}K*n zyl8pp|K*sXIclhzb%Vou+4p(#C+|GQWG O=XnkN?EE*pPvj2_`@^dM literal 1225 zcmaizQEr<+5Qd+gdlI_99sW`eWVg7VzFv!XpIL2 z_fUY}V=GouEY-7Ue=r^^ieO(kfTDWv_~rvtT!V@;2(2|1P0FzF7(D)U(Wiw909hasW6&4ygGpZ9Op=JW+h~8jAXBzSGl|v zJ&4h}iCc#9_JrjJ`haSg{`32c&eE?FJsWmN6UY+Sj2z@4+&nI|7dBOCQF;88p{4Z}1aswk9|<9KB^hT*Wzq#WkBgPdz}`Hxe!Xr*KV>1Iq| ykOeIVYE>HgQ!U-F{`kKDSx7)b-;q+n8F=|XO8HSLXW@&Ck5fu*ev;vf6n_B=33_w@ From 3d9de9db3810131bdd993cfa1fe4df72904ec369 Mon Sep 17 00:00:00 2001 From: KAY Lukas Date: Mon, 7 Apr 2014 23:44:13 +0200 Subject: [PATCH 03/22] Decode and encoding support Also various performance increases. Now uses python to perform the parsing. --- json.applescript | 187 ++++++++++++++++++++++++++-------------------- tests.applescript | Bin 2918 -> 3268 bytes 2 files changed, 106 insertions(+), 81 deletions(-) diff --git a/json.applescript b/json.applescript index f242b51..d8d74bd 100644 --- a/json.applescript +++ b/json.applescript @@ -1,4 +1,45 @@ +on decode(value) + set s to "import json" & return + set s to s & "def toAppleScript(pythonValue):" & return + set s to s & " output = ''" & return + set s to s & " if(pythonValue == None):" & return + set s to s & " output += 'null'" & return + set s to s & " elif (isinstance(pythonValue, dict)):" & return + set s to s & " output += '{'" & return + set s to s & " first = True" & return + set s to s & " for (key, value) in pythonValue.iteritems():" & return + set s to s & " if first:" & return + set s to s & " first = False" & return + set s to s & " else:" & return + set s to s & " output += ','" & return + set s to s & " output += key + ':' " & return + set s to s & " output += toAppleScript(value)" & return + set s to s & " output += '}'" & return + set s to s & " elif (isinstance(pythonValue, list)):" & return + set s to s & " output += '['" & return + set s to s & " first = True" & return + set s to s & " for value in pythonValue:" & return + set s to s & " if first:" & return + set s to s & " first = False" & return + set s to s & " else:" & return + set s to s & " output += ','" & return + set s to s & " output += toAppleScript(value)" & return + set s to s & " output += ']'" & return + set s to s & " else:" & return + set s to s & " output += json.dumps(pythonValue)" & return + set s to s & " return output" & return + set s to s & "print toAppleScript(json.loads(" & quoted form of value & "))" + set appleCode to do shell script "python2.7 -c " & quoted form of s + set s to "on run " & return + set s to s & appleCode & return + set s to s & "end" + return (run script s) +end decode + on encode(value) + if value = null then + return "null" + end if set type to class of value if type = integer then return value as text @@ -89,60 +130,73 @@ on createDict() return createDictWith({}) end createDict -on split(aString, aDelimiters) - set oldDelimiters to AppleScript's text item delimiters - set AppleScript's text item delimiters to aDelimiters - set theArray to every text item of aString - set AppleScript's text item delimiters to aDelimiters - return theArray -end split - on recordToString(aRecord) + try + set str to aRecord as text + on error errorMsg + set startindex to 1 + set eos to length of errorMsg + repeat until startindex is eos + if character startindex of errorMsg = "{" then + exit repeat + end if + set startindex to startindex + 1 + end repeat + set endindex to eos + repeat until endindex is 1 + if character endindex of errorMsg = "}" then + exit repeat + end if + set endindex to endindex - 1 + end repeat + set str to ((characters startindex thru endindex of errorMsg) as string) + if startindex < endindex then + return str + end if + end try set oldClipboard to the clipboard - set the clipboard to aRecord - set str to (do shell script "osascript -e 'the clipboard as record'") + set the clipboard to {aRecord} + set str to (do shell script "osascript -s s -e 'the clipboard as record'") set the clipboard to oldClipboard + set str to ((characters 8 thru -1 of str) as string) + set str to ((characters 1 thru -3 of str as string)) return str end recordToString -on getValueFromKey(aRecord, aKey) - set s to "on run {aRecord}" & return - set s to s & "get " & aKey & " of aRecord" & return - set s to s & "end" - return (run script s with parameters {aRecord}) -end getValueFromKey - -on recordKeys(value_record) - set str to recordToString(value_record) - set tokens to split(str, {":", ","}) - set possibleKeys to {} - repeat with token in tokens - set possibleKey to trim(change_case(token, "lower")) - if possibleKey is not in possibleKeys then - set end of possibleKeys to possibleKey - end if - end repeat - set recordKeyList to {} - repeat with possibleKey in possibleKeys - try - getValueFromKey(value_record, possibleKey) - --If not found we do not reach this - set end of recordKeyList to ("" & possibleKey) - end try - end repeat - if (count recordKeyList) is not (count value_record) then - error "recordKeys could not successfully recover all keys in the given record" - end if - return recordKeyList -end recordKeys - on encodeRecord(value_record) - set keys to recordKeys(value_record) - set dictionary to createDict() - repeat with recordKey in keys - dictionary's setkv(recordKey, getValueFromKey(value_record, recordKey)) - end repeat - return encode(dictionary) + set strRepr to recordToString(value_record) + set s to "import json, token, tokenize" & return + set s to s & "from StringIO import StringIO" & return + set s to s & "def appleScriptNotationToJSON (in_text):" & return + set s to s & " tokengen = tokenize.generate_tokens(StringIO(in_text).readline)" & return + set s to s & " depth = 0" & return + set s to s & " opstack = []" & return + set s to s & " result = []" & return + set s to s & " for tokid, tokval, _, _, _ in tokengen:" & return + set s to s & " if (tokid == token.NAME):" & return + set s to s & " if tokval not in ['true', 'false', 'null', '-Infinity', 'Infinity', 'NaN']:" & return + set s to s & " tokid = token.STRING" & return + set s to s & " tokval = u'\"%s\"' % tokval" & return + set s to s & " elif (tokid == token.STRING):" & return + set s to s & " if tokval.startswith (\"'\"):" & return + set s to s & " tokval = u'\"%s\"' % tokval[1:-1].replace ('\"', '\\\\\"')" & return + set s to s & " elif (tokid == token.OP) and ((tokval == '}') or (tokval == ']')):" & return + set s to s & " if (len(result) > 0) and (result[-1][1] == ','):" & return + set s to s & " result.pop()" & return + set s to s & " tokval = '}' if result[opstack[-1]][1] == '{' else ']'" & return + set s to s & " opstack.pop()" & return + set s to s & " elif (tokid == token.OP) and (tokval == '{' or tokval == ']'):" & return + set s to s & " tokval = '['" & return + set s to s & " opstack.append(len(result))" & return + set s to s & " elif (tokid == token.OP) and (tokval == ':') and result[opstack[-1]][1] != '}':" & return + set s to s & " result[opstack[-1]] = (result[opstack[-1]][0], '{')" & return + set s to s & " elif (tokid == token.STRING):" & return + set s to s & " if tokval.startswith (\"'\"):" & return + set s to s & " tokval = u'\"%s\"' % tokval[1:-1].replace ('\"', '\\\\\"')" & return + set s to s & " result.append((tokid, tokval))" & return + set s to s & " return tokenize.untokenize(result)" & return + set s to s & "print json.dumps(json.loads(appleScriptNotationToJSON(u" & quoted form of strRepr & " )))" & return + return (do shell script "python2.7 -c " & quoted form of s) end encodeRecord on trim(someText) @@ -154,38 +208,9 @@ on trim(someText) set someText to text 1 thru -2 of someText end repeat - return someText + return someText as string end trim -property lower_alphabet : "abcdefghijklmnopqrstuvwxyz" -property upper_alphabet : "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -property white_space : {space, tab, return, ASCII character 10, ASCII character 13} -on change_case(this_text, this_case) - set new_text to "" - if this_case is not in {"UPPER", "lower", "Title", "Sentence"} then - return "Error: Case must be UPPER, lower, Title or Sentence" - end if - if this_case is "lower" then - set use_capital to false - else - set use_capital to true - end if - repeat with this_char in this_text - set x to offset of this_char in lower_alphabet - if x is not 0 then - if use_capital then - set new_text to new_text & character x of upper_alphabet as string - if this_case is not "UPPER" then - set use_capital to false - end if - else - set new_text to new_text & character x of lower_alphabet as string - end if - else - if this_case is "Title" and this_char is in white_space then - set use_capital to true - end if - set new_text to new_text & this_char as string - end if - end repeat - return new_text -end change_case + +on toLowerCase(input) + return (do shell script ("echo " & quoted form of input & " | tr '[:upper:]' '[:lower:]'")) +end toLowerCase \ No newline at end of file diff --git a/tests.applescript b/tests.applescript index 4beda053bc5e0d2ea02af4b12d7c83c5b42ff4bc..11b5560410c59e5f51db70ffba2e94b015c70479 100644 GIT binary patch literal 3268 zcmcJR(N7aW5XLvY!GGY}V)+IkE_?p4CgybGE&#F=Oo#OV9D#wK(L% zppI|q#J~PnBZ)6%1G}D+9w8Vg-*I2&vI0ht9#2FS&cz?%AVqUVMZ8euz zrC5gO%SXcRot+h$GmBcREnz=3eX9|ExACQU`N+`8(232hMRbEy=)86Lzp*o|A{(9+ zp(r_;MeSmmm6x16vz~`aWXpWE#!OREW&2EA2hT(sBjckvU@5JN6UC zi(`EHB#hcyZjzg=Da-X)9brMyH|_tL8Bf?ftjru24A=MJ?-F-XbvP-zoFuvrb~uGQ zj2d|LSsj7F*NDHfP76JMQ;dqd>ojd+OLyFOuJb9(zPDTY4r{6fGms=XhU z`Q3?Zhibj8$o7z3vtBtWH9v69=J#6YQsJTQ0rk{1+jvp`)`Hs@OZ#T8U^6yfi?3tL zuDZL-R!GdM$fzI7`F_PnGZ&mqSI7r^4e4;ypY+jDW^QcNsS|S%Pw!b-`qz5(J=a+1 z*v?Y>Bx0YZe81;E#qSD;$JS5Dgo{r5dD^i`Alp>0b_kJLn=cFg91Y$Lm`kXVaNxPg$$)Yx&$bb0_3Fu*+mSwKvq7G4N?ih z#Xu6Iq5?>AF>nGQ%%miuO-f==;6pWPawnsusse)=*b0z?KrAI7R%Eb+vOpq0D>ffw zbY`8riA_l}oFNnFh71M`hH4;G0=qXKNb7(#Bmpfb0`h7ZY9}|ct50@d<(uroZZ-K8 zo6sZ Date: Mon, 7 Apr 2014 23:55:22 +0200 Subject: [PATCH 04/22] New functionality description --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index afe454f..7ccdd15 100644 --- a/README.md +++ b/README.md @@ -47,3 +47,25 @@ set my_dict_2 to json's createDictWith({ {"foo", "bar"}, {"baz", 22} }) json's encode(my_dict_2) -- {"foo": "bar", "baz": 22} ``` + +And also natively (which gives a small performance penalty): +```applescript +json's encode({glossary:¬ + {GlossDiv:¬ + {GlossList:¬ + {GlossEntry:¬ + {GlossDef:¬ + {GlossSeeAlso:¬ + ["GML", "XML"], para:"A meta-markup language, used to create markup languages such as DocBook."} ¬ + , GlossSee:"markup", Acronym:"SGML", GlossTerm:"Standard Generalized Markup Language", Abbrev:"ISO 8879:1986", SortAs:"SGML", id:¬ + "SGML"} ¬ + }, title:"S"} ¬ + , title:"example glossary"} ¬ + }) +``` + +Decoding is also available (dictionaries with keys which contain spaces are not supported): +```applescript +set dict to {foo:"bar"} +json's decode(json's encode(dict)) -- {foo: "bar"} +``` From f74b3f9136d29e39bd51e9ac695cd051c042adb9 Mon Sep 17 00:00:00 2001 From: KAY Lukas Date: Tue, 8 Apr 2014 01:32:00 +0200 Subject: [PATCH 05/22] Added null test case --- tests.applescript | Bin 3268 -> 3446 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests.applescript b/tests.applescript index 11b5560410c59e5f51db70ffba2e94b015c70479..85052d8c56ca982f619d89daf33b274310ce4816 100644 GIT binary patch delta 416 zcmX>i`Aup=0V8KBLlF?>GZbw;$QaHls>7hbP{NSPPz)rk81fiO8FCnMCfjq^YHBio z1gY5^%U;YVjYq-cSa#*f?>MHgu3_L};GEpZDe4YpF>nG6 zcL!RS5466R!G$4{p$up^Ob%7n2Pg}1Bto8Z@_tT9LnJS9`6IVE RFS6>|$sZY2C;Rb~0RRE_MFs!> delta 230 zcmew+bwqMQ0b^heLq0<~g91Y$0~Z4)5W@ILP<|>y5fJ7Bu>yks=NhD@rH<5>76A7JNV*8yv;-t5g@%s4rKU2gIp zjw!;`Kzl*96$4=+(ELgUtH~QVMJHe26r22sQvxXO4wrWU+K~p7x8{ Date: Tue, 8 Apr 2014 12:31:41 +0200 Subject: [PATCH 06/22] Big fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Better support for unicode: tests added ASUnit for testing Bug fix in encodeString — Escaping of quotes did not occur --- ASUnit/ASUnit.applescript | Bin 0 -> 107760 bytes Makefile | 5 ++- json.applescript | 67 ++++++++++++++++++++++++++++++-------- tests.applescript | Bin 3446 -> 15424 bytes 4 files changed, 57 insertions(+), 15 deletions(-) create mode 100644 ASUnit/ASUnit.applescript diff --git a/ASUnit/ASUnit.applescript b/ASUnit/ASUnit.applescript new file mode 100644 index 0000000000000000000000000000000000000000..b03b1c826672dfcb0c29a3209c0349a20df0bf74 GIT binary patch literal 107760 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

qqYP-R|Yeo$d11WO9vfjJI8s8%$97}sc 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 literal 0 HcmV?d00001 diff --git a/Makefile b/Makefile index 5bf1d64..4374ddc 100644 --- a/Makefile +++ b/Makefile @@ -2,4 +2,7 @@ json.scpt: json.applescript osacompile -o json.scpt json.applescript test: json.scpt - osascript tests.applescript + osacompile -o ASUnit/ASUnit.scpt -x ASUnit/ASUnit.applescript + cp `which osascript` osascript + ./osascript tests.applescript + rm osascript diff --git a/json.applescript b/json.applescript index d8d74bd..66af32c 100644 --- a/json.applescript +++ b/json.applescript @@ -1,5 +1,5 @@ on decode(value) - set s to "import json" & return + set s to "import json, sys" & return set s to s & "def toAppleScript(pythonValue):" & return set s to s & " output = ''" & return set s to s & " if(pythonValue == None):" & return @@ -25,11 +25,15 @@ on decode(value) set s to s & " output += ','" & return set s to s & " output += toAppleScript(value)" & return set s to s & " output += ']'" & return + set s to s & " elif(isinstance(pythonValue, basestring)):" & return + set s to s & " output += '\"' + pythonValue.replace('\"', '\\\\\"') + '\"'" & return set s to s & " else:" & return set s to s & " output += json.dumps(pythonValue)" & return set s to s & " return output" & return - set s to s & "print toAppleScript(json.loads(" & quoted form of value & "))" - set appleCode to do shell script "python2.7 -c " & quoted form of s + -- sys.stdout to be able to write utf8 to our buffer + set s to s & "sys.stdout.write(toAppleScript(json.loads(" & quoted form of value & ")).encode('utf8'))" + -- AppleScript translates new lines in old mac returns so we need to turn that off + set appleCode to do shell script "python2.7 -c " & quoted form of s without altering line endings set s to "on run " & return set s to s & appleCode & return set s to s & "end" @@ -37,12 +41,9 @@ on decode(value) end decode on encode(value) - if value = null then - return "null" - end if set type to class of value - if type = integer then - return value as text + if type = integer or type = real then + return replaceString(value as text, ",", ".") else if type = text then return encodeString(value) else if type = list then @@ -51,6 +52,8 @@ on encode(value) return value's toJson() else if type = record then return encodeRecord(value) + else if type = class and (value as text) = "null" then + return "null" else error "Unknown type " & type end if @@ -68,7 +71,9 @@ end encodeList on encodeString(value) set rv to "" repeat with ch in value - if id of ch ³ 32 and id of ch < 127 then + if id of ch = 34 or id of ch = 92 then + set quoted_ch to "\\" & ch + else if id of ch ³ 32 and id of ch < 127 then set quoted_ch to ch else set quoted_ch to "\\u" & hex4(id of ch) @@ -87,6 +92,15 @@ on join(value_list, delimiter) return rv end join +on replaceString(theText, oldString, newString) + set AppleScript's text item delimiters to oldString + set tempList to every text item of theText + set AppleScript's text item delimiters to newString + set theText to the tempList as string + set AppleScript's text item delimiters to "" + return theText +end replaceString + on hex4(n) set digit_list to "0123456789abcdef" @@ -104,9 +118,20 @@ on createDictWith(item_pairs) set item_list to {} script Dict - on setkv(key, value) + on setValue(key, value) + set i to 1 + set c to count item_list + repeat until i > c + set kv to item i of item_list + if item 1 of kv = key then + set item 2 of kv to value + set item i of item_list to kv + return + end if + set i to i + 1 + end repeat copy {key, value} to end of item_list - end setkv + end setValue on toJson() set item_strings to {} @@ -117,10 +142,23 @@ on createDictWith(item_pairs) end repeat return "{" & join(item_strings, ", ") & "}" end toJson + + on getValue(key) + repeat with kv in item_list + if item 1 of kv = key then + return item 2 of kv + end if + end repeat + error "No such key " & key & " found." + end getValue + + on toRecord() + return decode(toJson()) + end toRecord end script repeat with pair in item_pairs - Dict's setkv(item 1 of pair, item 2 of pair) + Dict's setValue(item 1 of pair, item 2 of pair) end repeat return Dict @@ -164,7 +202,8 @@ on recordToString(aRecord) end recordToString on encodeRecord(value_record) - set strRepr to recordToString(value_record) + -- json can be used to escape a string for python + set strRepr to encode(recordToString(value_record)) set s to "import json, token, tokenize" & return set s to s & "from StringIO import StringIO" & return set s to s & "def appleScriptNotationToJSON (in_text):" & return @@ -195,7 +234,7 @@ on encodeRecord(value_record) set s to s & " tokval = u'\"%s\"' % tokval[1:-1].replace ('\"', '\\\\\"')" & return set s to s & " result.append((tokid, tokval))" & return set s to s & " return tokenize.untokenize(result)" & return - set s to s & "print json.dumps(json.loads(appleScriptNotationToJSON(u" & quoted form of strRepr & " )))" & return + set s to s & "print json.dumps(json.loads(appleScriptNotationToJSON(" & strRepr & ")))" & return return (do shell script "python2.7 -c " & quoted form of s) end encodeRecord diff --git a/tests.applescript b/tests.applescript index 85052d8c56ca982f619d89daf33b274310ce4816..d8140d0dbbc62f56435eec20bd7730f408bc910c 100644 GIT binary patch literal 15424 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 delta 400 zcmX?5@lA^9|G&w7EM}8Wuv7@9GUPF&FeosTFr+f%03p}pNY-dhE(R`!e4vcNY9xrkmX@Rx>l2 cPX27IDFt#PC``G4A)L>U4t8xmLpIRO0FC=-?*IS* From 31f655778a41658345a2b53ac3ac95a3d05645dc Mon Sep 17 00:00:00 2001 From: KAY Lukas Date: Tue, 8 Apr 2014 12:32:45 +0200 Subject: [PATCH 07/22] Removed comment --- tests.applescript | Bin 15424 -> 13656 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests.applescript b/tests.applescript index d8140d0dbbc62f56435eec20bd7730f408bc910c..ddcebf7e156b8ebac7921274d7958dfeb0f25c61 100644 GIT binary patch delta 7 OcmX?5aU*L(ged?J>;t#} delta 299 zcmcbSb)aHHgef-{0~dn^gBFnFn#`}_E||zr41}o+MGPej@j$w8vZA2;|mlX*~vs`a-E5RXf4pun9c Date: Tue, 8 Apr 2014 13:32:07 +0200 Subject: [PATCH 08/22] Surrogate pair support --- json.applescript | 11 +++++++++-- tests.applescript | Bin 13656 -> 14658 bytes 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/json.applescript b/json.applescript index 66af32c..241bbb6 100644 --- a/json.applescript +++ b/json.applescript @@ -75,15 +75,22 @@ on encodeString(value) set quoted_ch to "\\" & ch else if id of ch ³ 32 and id of ch < 127 then set quoted_ch to ch - else + else if id of ch < 65536 then set quoted_ch to "\\u" & hex4(id of ch) + else + set v to id of ch + set v_ to v - 65536 + set vh to v_ / 1024 + set vl to v_ mod 1024 + set w1 to 55296 + vh + set w2 to 56320 + vl + set quoted_ch to "\\u" & hex4(w1) & "\\u" & hex4(w2) end if set rv to rv & quoted_ch end repeat return "\"" & rv & "\"" end encodeString - on join(value_list, delimiter) set original_delimiter to AppleScript's text item delimiters set AppleScript's text item delimiters to delimiter diff --git a/tests.applescript b/tests.applescript index ddcebf7e156b8ebac7921274d7958dfeb0f25c61..a2f394798e71d5c8caa1ff23a528439caabd32f3 100644 GIT binary patch delta 648 zcmbtSyGjE=6g`C&NfB@ff=w8wTcWUuiI}K_6q;5m3)f=VjT(t$+4YewA2AU82n%KZ zz^~XQA7NvwXLeYUSg0VEJIuLf=DyRLx9H`>>J_j}5jesaA^Pxf$1|Yi0Un09ClVMS z<{1-3lo77T>34#EJhG8`E$vSvn(4vpoSrVo98%ZhRE#kdAyvZ07Htx4rY^k&*uxH* zv=|f+`B?N|m^$jHQF7#m}n3DFTnoJYXHy zy!)&pgu(Lw{~r@m_`{g;0)HE)$!wlq%+kwa;ZSt&M4ok-bzs`!xBe%GIP& HYp;9(17LgK delta 30 mcmX?9bR%m+fY9bV;V{X`TzWy9U+62aP7W~^+bm(K#R34pEee(Z From 1d6d9d585c575ad178bf3a21437902ec448ad018 Mon Sep 17 00:00:00 2001 From: KAY Lukas Date: Tue, 8 Apr 2014 15:31:05 +0200 Subject: [PATCH 09/22] Support for decoding to dictionaries Allows decoding of spaces --- json.applescript | 66 +++++++++++++++++++++++++++++++++++++++++++--- tests.applescript | Bin 14658 -> 16686 bytes 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/json.applescript b/json.applescript index 241bbb6..7095b05 100644 --- a/json.applescript +++ b/json.applescript @@ -1,3 +1,61 @@ +on JSONRepresentation from variable + return encode(variable) +end JSONRepresentation + +on JSONValue of variable given NativeEncoding:recordBool + if recordBool then + return decode(variable) + else + return decodeWithDicts(variable) + end if +end JSONValue + +on Dictionary from variable + return createDictWith(variable) +end Dictionary + +on decodeWithDicts(value) + set s to "import json, sys" & return + set s to s & "def toAppleScript(pythonValue):" & return + set s to s & " output = ''" & return + set s to s & " if(pythonValue == None):" & return + set s to s & " output += 'null'" & return + set s to s & " elif (isinstance(pythonValue, dict)):" & return + set s to s & " output += 'json\\'s createDictWith({'" & return + set s to s & " first = True" & return + set s to s & " for (key, value) in pythonValue.iteritems():" & return + set s to s & " if first:" & return + set s to s & " first = False" & return + set s to s & " else:" & return + set s to s & " output += ','" & return + set s to s & " output += '{' + json.dumps(key) + ',' " & return + set s to s & " output += toAppleScript(value) + '}' " & return + set s to s & " output += '})'" & return + set s to s & " elif (isinstance(pythonValue, list)):" & return + set s to s & " output += '{'" & return + set s to s & " first = True" & return + set s to s & " for value in pythonValue:" & return + set s to s & " if first:" & return + set s to s & " first = False" & return + set s to s & " else:" & return + set s to s & " output += ','" & return + set s to s & " output += toAppleScript(value)" & return + set s to s & " output += '}'" & return + set s to s & " elif(isinstance(pythonValue, basestring)):" & return + set s to s & " output += '\"' + pythonValue.replace('\"', '\\\\\"') + '\"'" & return + set s to s & " else:" & return + set s to s & " output += json.dumps(pythonValue)" & return + set s to s & " return output" & return + -- sys.stdout to be able to write utf8 to our buffer + set s to s & "sys.stdout.write(toAppleScript(json.loads(" & quoted form of value & ")).encode('utf8'))" + -- AppleScript translates new lines in old mac returns so we need to turn that off + set appleCode to do shell script "python2.7 -c " & quoted form of s without altering line endings + set s to "on run {json}" & return + set s to s & appleCode & return + set s to s & "end" + return (run script s with parameters {me}) +end decodeWithDicts + on decode(value) set s to "import json, sys" & return set s to s & "def toAppleScript(pythonValue):" & return @@ -16,7 +74,7 @@ on decode(value) set s to s & " output += toAppleScript(value)" & return set s to s & " output += '}'" & return set s to s & " elif (isinstance(pythonValue, list)):" & return - set s to s & " output += '['" & return + set s to s & " output += '{'" & return set s to s & " first = True" & return set s to s & " for value in pythonValue:" & return set s to s & " if first:" & return @@ -24,7 +82,7 @@ on decode(value) set s to s & " else:" & return set s to s & " output += ','" & return set s to s & " output += toAppleScript(value)" & return - set s to s & " output += ']'" & return + set s to s & " output += '}'" & return set s to s & " elif(isinstance(pythonValue, basestring)):" & return set s to s & " output += '\"' + pythonValue.replace('\"', '\\\\\"') + '\"'" & return set s to s & " else:" & return @@ -127,8 +185,8 @@ on createDictWith(item_pairs) script Dict on setValue(key, value) set i to 1 - set c to count item_list - repeat until i > c + set C to count item_list + repeat until i > C set kv to item i of item_list if item 1 of kv = key then set item 2 of kv to value diff --git a/tests.applescript b/tests.applescript index a2f394798e71d5c8caa1ff23a528439caabd32f3..432b8f3ee7ac52e3cf65f7d36e303657ccfd44b5 100644 GIT binary patch delta 1056 zcmZ`&O-sW-5S=256%mV8D+;lxiiL_oi?v=#q2j?7(F$I?)Ec#DKTJ|lq$r-fjo^<^ zMDQPY6#s$XfAAOR+ce3hXjrm@oq2EGyxD!zpKk*%_hG(E&GXXe5Z@(+_(q+nl&DE% zs*pz0RHZuh6Z~J2N(ubesYRz)ZLBz!I8*70_OSaQMQqiJwCBm5c`BBWqfrj}4Rq<&<T$30eRE From 5ea393befd4ef2f3ecee84bf337d6643bfe098c0 Mon Sep 17 00:00:00 2001 From: KAY Lukas Date: Tue, 8 Apr 2014 15:44:24 +0200 Subject: [PATCH 10/22] Reverted JSONRepresentation and other fancy functions --- json.applescript | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/json.applescript b/json.applescript index 7095b05..31b7ad6 100644 --- a/json.applescript +++ b/json.applescript @@ -1,19 +1,3 @@ -on JSONRepresentation from variable - return encode(variable) -end JSONRepresentation - -on JSONValue of variable given NativeEncoding:recordBool - if recordBool then - return decode(variable) - else - return decodeWithDicts(variable) - end if -end JSONValue - -on Dictionary from variable - return createDictWith(variable) -end Dictionary - on decodeWithDicts(value) set s to "import json, sys" & return set s to s & "def toAppleScript(pythonValue):" & return From c9e3e411c4bab1f59f934c8872cf0a553c1ba0f5 Mon Sep 17 00:00:00 2001 From: KAY Lukas Date: Tue, 8 Apr 2014 17:20:08 +0200 Subject: [PATCH 11/22] Fixed osascript path to me bugs in testcases --- Makefile | 4 +--- tests.applescript | Bin 16686 -> 16990 bytes 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 4374ddc..fc221ac 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,4 @@ json.scpt: json.applescript test: json.scpt osacompile -o ASUnit/ASUnit.scpt -x ASUnit/ASUnit.applescript - cp `which osascript` osascript - ./osascript tests.applescript - rm osascript + osascript tests.applescript diff --git a/tests.applescript b/tests.applescript index 432b8f3ee7ac52e3cf65f7d36e303657ccfd44b5..d7c0c7692936e3df2b3ca34e61db9d2477b7ad19 100644 GIT binary patch delta 676 zcmah`yGjE=6g|6|B2$Q!ZcuOu7&eGlXrZPOLB;G|C7O(~4-Hpo=zY ze8mWmhe8@HG?*Lk^f2J38ST&$($dUp;TnDG&C^>Yf*^(TN6hw-CBp@dc}ra5Cb47! zowmf9<*^kspW;7U&JyepT=41?-{XH0b{XfWpomMDC#RH*(0*X7f#y+;7ojk8gN$ND%r%I7Sw!1P=%7Bld)ZRh=8?@* z8SMY*lQh{{m2VkNkHyNoE^L~bg86b+M_2Bin~@5 tvpwR9i#Wq6vZj(c5a6|Gqw$e5AB!2Y?kcnIE}6!PXO_KS^qD#=`~n#*fR+FN delta 335 zcmccD!nm%9k?H@x$$uC%G)owY7%CaK7&sY97*ZK>fKY)Uk)Z$xa~Luil7Z|JAf3;U zH<_PBme-Xb1;{G_@{1UhCfhO{o?OJLGC6=*f>C2~Et~YjFJY4xFMjH+NLnS7pE zbn*i>mdOiPL^l6oHesqKU Date: Tue, 8 Apr 2014 17:22:40 +0200 Subject: [PATCH 12/22] removed Loading --- tests.applescript | Bin 16990 -> 16958 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests.applescript b/tests.applescript index d7c0c7692936e3df2b3ca34e61db9d2477b7ad19..9902a0b43c34838f0f44cdb20f94aaae56c31b6d 100644 GIT binary patch delta 18 ZcmccD!nm)6af2S)pby delta 40 vcmdnj!g#NRaf2S4WDY|Sf From f7207edc6dd81b87bfc72326be669c6718c64de4 Mon Sep 17 00:00:00 2001 From: KAY Lukas Date: Tue, 8 Apr 2014 17:32:14 +0200 Subject: [PATCH 13/22] Small update to support .app with getParentFolder --- tests.applescript | Bin 16958 -> 17164 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests.applescript b/tests.applescript index 9902a0b43c34838f0f44cdb20f94aaae56c31b6d..daf6c7a4b8bd6b18963f956496021ce34e3fa426 100644 GIT binary patch delta 82 zcmdnj!r0TsIN^b&0z)Q48iN9Z217DK216o45fCRclrW?MSqcog42D25AEaWkAfqO) dCXi Date: Tue, 8 Apr 2014 22:46:57 +0200 Subject: [PATCH 14/22] Performance increase and bug fix Sometimes applescript will not throw errors when casting a record to text (which allows the user to see the record as raw bytes), a workaround is in place. Some bugs occurred when reading strings with single quotes, this is fixed by letting python read from the stdin Lastly the performance of encoding records is increased because its no longer needed to json encode the string representation. Also when encoding a list with records we use the encodeRecords method to reduce overhead of calling encodeRecords multiple times. --- json.applescript | 92 +++++++++++++++++++++++++++++++++------------- tests.applescript | Bin 17164 -> 17168 bytes 2 files changed, 67 insertions(+), 25 deletions(-) diff --git a/json.applescript b/json.applescript index 31b7ad6..206d38d 100644 --- a/json.applescript +++ b/json.applescript @@ -1,5 +1,6 @@ on decodeWithDicts(value) - set s to "import json, sys" & return + set s to "import json, sys, codecs" & return + set s to s & "sys.stdin = codecs.getreader('utf8')(sys.stdin)" & return set s to s & "def toAppleScript(pythonValue):" & return set s to s & " output = ''" & return set s to s & " if(pythonValue == None):" & return @@ -31,9 +32,9 @@ on decodeWithDicts(value) set s to s & " output += json.dumps(pythonValue)" & return set s to s & " return output" & return -- sys.stdout to be able to write utf8 to our buffer - set s to s & "sys.stdout.write(toAppleScript(json.loads(" & quoted form of value & ")).encode('utf8'))" + set s to s & "sys.stdout.write(toAppleScript(json.loads(sys.stdin.read())).encode('utf8'))" -- AppleScript translates new lines in old mac returns so we need to turn that off - set appleCode to do shell script "python2.7 -c " & quoted form of s without altering line endings + set appleCode to do shell script "echo " & quoted form of value & " |python2.7 -c " & quoted form of s without altering line endings set s to "on run {json}" & return set s to s & appleCode & return set s to s & "end" @@ -41,7 +42,8 @@ on decodeWithDicts(value) end decodeWithDicts on decode(value) - set s to "import json, sys" & return + set s to "import json, sys, codecs" & return + set s to s & "sys.stdin = codecs.getreader('utf8')(sys.stdin)" & return set s to s & "def toAppleScript(pythonValue):" & return set s to s & " output = ''" & return set s to s & " if(pythonValue == None):" & return @@ -73,9 +75,9 @@ on decode(value) set s to s & " output += json.dumps(pythonValue)" & return set s to s & " return output" & return -- sys.stdout to be able to write utf8 to our buffer - set s to s & "sys.stdout.write(toAppleScript(json.loads(" & quoted form of value & ")).encode('utf8'))" + set s to s & "sys.stdout.write(toAppleScript(json.loads(sys.stdin.read())).encode('utf8'))" -- AppleScript translates new lines in old mac returns so we need to turn that off - set appleCode to do shell script "python2.7 -c " & quoted form of s without altering line endings + set appleCode to do shell script "echo " & quoted form of value & " |python2.7 -c " & quoted form of s without altering line endings set s to "on run " & return set s to s & appleCode & return set s to s & "end" @@ -89,7 +91,11 @@ on encode(value) else if type = text then return encodeString(value) else if type = list then - return encodeList(value) + if listContainsRecord(value) then + return encodeRecord(value) + else + return encodeList(value) + end if else if type = script then return value's toJson() else if type = record then @@ -101,6 +107,20 @@ on encode(value) end if end encode +on listContainsRecord(value) + repeat with element in value + set type to class of element + if type = list then + if listContainsRecord(element) then + return true + end if + else if type = record then + return true + end if + end repeat + return false +end listContainsRecord + on encodeList(value_list) set out_list to {} repeat with value in value_list @@ -219,6 +239,14 @@ end createDict on recordToString(aRecord) try + set type to class of aRecord + --This ensures applescript knows about the type + if class of aRecord = list then + set aRecord to aRecord as list + else + set aRecord to aRecord as record + end if + set aRecord to aRecord set str to aRecord as text on error errorMsg set startindex to 1 @@ -252,9 +280,10 @@ end recordToString on encodeRecord(value_record) -- json can be used to escape a string for python - set strRepr to encode(recordToString(value_record)) - set s to "import json, token, tokenize" & return + set strRepr to recordToString(value_record) + set s to "import json, token, tokenize, sys, codecs" & return set s to s & "from StringIO import StringIO" & return + set s to s & "sys.stdin = codecs.getreader('utf8')(sys.stdin)" & return set s to s & "def appleScriptNotationToJSON (in_text):" & return set s to s & " tokengen = tokenize.generate_tokens(StringIO(in_text).readline)" & return set s to s & " depth = 0" & return @@ -283,22 +312,35 @@ on encodeRecord(value_record) set s to s & " tokval = u'\"%s\"' % tokval[1:-1].replace ('\"', '\\\\\"')" & return set s to s & " result.append((tokid, tokval))" & return set s to s & " return tokenize.untokenize(result)" & return - set s to s & "print json.dumps(json.loads(appleScriptNotationToJSON(" & strRepr & ")))" & return - return (do shell script "python2.7 -c " & quoted form of s) + set s to s & "print json.dumps(json.loads(appleScriptNotationToJSON(sys.stdin.read())))" & return + return (do shell script "echo " & quoted form of strRepr & " | python2.7 -c " & quoted form of s) end encodeRecord -on trim(someText) - repeat until someText does not start with " " - set someText to text 2 thru -1 of someText - end repeat - - repeat until someText does not end with " " - set someText to text 1 thru -2 of someText - end repeat - - return someText as string -end trim +set aList to {} +set dict3 to  + {glossary: + {GlossDiv: + {GlossList: + {GlossEntry: + {GlossDef: + {GlossSeeAlso: + ["GML", "XML"], para:"A 'meta-markup language, used to create markup languages such as DocBook."}  + , GlossSee:"markup", Acronym:"SGML", GlossTerm:"Standard Generalized Markup Language", Abbrev:"ISO 8879:1986", SortAs:"SGML", id: + "SGML"}  + }, title:"S"}  + , title:"example glossary"}  + } +repeat 100 times + set end of aList to dict3 +end repeat +set startTime to (get current date) +encode(aList) +set endTime to (get current date) +set duration to endTime - startTime +log duration -on toLowerCase(input) - return (do shell script ("echo " & quoted form of input & " | tr '[:upper:]' '[:lower:]'")) -end toLowerCase \ No newline at end of file +set startTime to (get current date) +encode({aList:aList}) +set endTime to (get current date) +set duration to endTime - startTime +log duration \ No newline at end of file diff --git a/tests.applescript b/tests.applescript index daf6c7a4b8bd6b18963f956496021ce34e3fa426..5ec2386a7b88c97a9954e8bd736a0e8fa5ccae57 100644 GIT binary patch delta 27 jcmeBaW1P^&xZ#%tqxxh=yNR2-EO)Rls&96*JIw+Bm8l9d delta 23 fcmbQx#@N%wxZ#(@=06r5tdsv(OxS$Q&WZ&9f~X3e From 73662e3f940367787ec718971f774497e84ccbce Mon Sep 17 00:00:00 2001 From: KAY Lukas Date: Tue, 8 Apr 2014 22:48:36 +0200 Subject: [PATCH 15/22] Removed test code in json.appleScript --- json.applescript | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/json.applescript b/json.applescript index 206d38d..8a383c4 100644 --- a/json.applescript +++ b/json.applescript @@ -315,32 +315,3 @@ on encodeRecord(value_record) set s to s & "print json.dumps(json.loads(appleScriptNotationToJSON(sys.stdin.read())))" & return return (do shell script "echo " & quoted form of strRepr & " | python2.7 -c " & quoted form of s) end encodeRecord - -set aList to {} -set dict3 to  - {glossary: - {GlossDiv: - {GlossList: - {GlossEntry: - {GlossDef: - {GlossSeeAlso: - ["GML", "XML"], para:"A 'meta-markup language, used to create markup languages such as DocBook."}  - , GlossSee:"markup", Acronym:"SGML", GlossTerm:"Standard Generalized Markup Language", Abbrev:"ISO 8879:1986", SortAs:"SGML", id: - "SGML"}  - }, title:"S"}  - , title:"example glossary"}  - } -repeat 100 times - set end of aList to dict3 -end repeat -set startTime to (get current date) -encode(aList) -set endTime to (get current date) -set duration to endTime - startTime -log duration - -set startTime to (get current date) -encode({aList:aList}) -set endTime to (get current date) -set duration to endTime - startTime -log duration \ No newline at end of file From 483023f7f49a0954214b5458d43f09942c63e54e Mon Sep 17 00:00:00 2001 From: KAY Lukas Date: Wed, 9 Apr 2014 01:02:17 +0200 Subject: [PATCH 16/22] Fixed newline bug + big string support New lines in records made decode crash. Big strings > 256 are now handled by python, due to slow string processing of AppleScript --- json.applescript | 59 +++++++++++++++++++++++++++++++++++----------- tests.applescript | Bin 17168 -> 17372 bytes 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/json.applescript b/json.applescript index 8a383c4..48bfe18 100644 --- a/json.applescript +++ b/json.applescript @@ -32,9 +32,11 @@ on decodeWithDicts(value) set s to s & " output += json.dumps(pythonValue)" & return set s to s & " return output" & return -- sys.stdout to be able to write utf8 to our buffer - set s to s & "sys.stdout.write(toAppleScript(json.loads(sys.stdin.read())).encode('utf8'))" + -- We can ignore newlines in JSON format freely, as our \n will convert into new lines in bash we will use the actual new lines as the string \n + set s to s & "sys.stdout.write(toAppleScript(json.loads(sys.stdin.read().replace(\"\\n\", \"\\\\n\"))).encode('utf8'))" + set value to replaceString(value, {return & linefeed, return, linefeed, character id 8233, character id 8232}, "") -- AppleScript translates new lines in old mac returns so we need to turn that off - set appleCode to do shell script "echo " & quoted form of value & " |python2.7 -c " & quoted form of s without altering line endings + set appleCode to do shell script "echo " & quoted form of value & " \"\\c\" |python2.7 -c " & quoted form of s without altering line endings set s to "on run {json}" & return set s to s & appleCode & return set s to s & "end" @@ -75,9 +77,11 @@ on decode(value) set s to s & " output += json.dumps(pythonValue)" & return set s to s & " return output" & return -- sys.stdout to be able to write utf8 to our buffer - set s to s & "sys.stdout.write(toAppleScript(json.loads(sys.stdin.read())).encode('utf8'))" + -- We can ignore newlines in JSON format freely, as our \n will convert into new lines in bash we will use the actual new lines as the string \n + set s to s & "sys.stdout.write(toAppleScript(json.loads(sys.stdin.read().replace(\"\\n\", \"\\\\n\"))).encode('utf8'))" + set value to replaceString(value, {return & linefeed, return, linefeed, character id 8233, character id 8232}, "") -- AppleScript translates new lines in old mac returns so we need to turn that off - set appleCode to do shell script "echo " & quoted form of value & " |python2.7 -c " & quoted form of s without altering line endings + set appleCode to do shell script "echo " & quoted form of value & " \"\\c\" |python2.7 -c " & quoted form of s without altering line endings set s to "on run " & return set s to s & appleCode & return set s to s & "end" @@ -91,7 +95,7 @@ on encode(value) else if type = text then return encodeString(value) else if type = list then - if listContainsRecord(value) then + if isBigList(value) then return encodeRecord(value) else return encodeList(value) @@ -107,11 +111,31 @@ on encode(value) end if end encode -on listContainsRecord(value) +-- skips BigList check +on _encode(value) + set type to class of value + if type = integer or type = real then + return replaceString(value as text, ",", ".") + else if type = text then + return encodeString(value) + else if type = list then + return encodeList(value) + else if type = script then + return value's toJson() + else if type = record then + return encodeRecord(value) + else if type = class and (value as text) = "null" then + return "null" + else + error "Unknown type " & type + end if +end _encode + +on isBigList(value) repeat with element in value set type to class of element if type = list then - if listContainsRecord(element) then + if isBigList(element) then return true end if else if type = record then @@ -119,18 +143,24 @@ on listContainsRecord(value) end if end repeat return false -end listContainsRecord +end isBigList on encodeList(value_list) set out_list to {} repeat with value in value_list - copy encode(value) to end of out_list + copy _encode(value) to end of out_list end repeat return "[" & join(out_list, ", ") & "]" end encodeList on encodeString(value) + if (count of value) ³ 256 then -- Large string manipulations are slow in AppleScript + set s to "import json, sys, codecs" & return + set s to s & "sys.stdin = codecs.getreader('utf8')(sys.stdin)" & return + set s to s & "sys.stdout.write(json.dumps(sys.stdin.read()))" + return do shell script "echo " & quoted form of value & " \"\\c\" | python2.7 -c " & quoted form of s + end if set rv to "" repeat with ch in value if id of ch = 34 or id of ch = 92 then @@ -186,7 +216,7 @@ end hex4 on createDictWith(item_pairs) set item_list to {} - script Dict + script dict on setValue(key, value) set i to 1 set C to count item_list @@ -227,10 +257,10 @@ on createDictWith(item_pairs) end script repeat with pair in item_pairs - Dict's setValue(item 1 of pair, item 2 of pair) + dict's setValue(item 1 of pair, item 2 of pair) end repeat - return Dict + return dict end createDictWith on createDict() @@ -285,6 +315,7 @@ on encodeRecord(value_record) set s to s & "from StringIO import StringIO" & return set s to s & "sys.stdin = codecs.getreader('utf8')(sys.stdin)" & return set s to s & "def appleScriptNotationToJSON (in_text):" & return + set s to s & " in_text = in_text.replace(\"\\n\", \"\\\\n\")" & return set s to s & " tokengen = tokenize.generate_tokens(StringIO(in_text).readline)" & return set s to s & " depth = 0" & return set s to s & " opstack = []" & return @@ -313,5 +344,5 @@ on encodeRecord(value_record) set s to s & " result.append((tokid, tokval))" & return set s to s & " return tokenize.untokenize(result)" & return set s to s & "print json.dumps(json.loads(appleScriptNotationToJSON(sys.stdin.read())))" & return - return (do shell script "echo " & quoted form of strRepr & " | python2.7 -c " & quoted form of s) -end encodeRecord + return (do shell script "echo " & quoted form of strRepr & "\"\\c\" | python2.7 -c " & quoted form of s) +end encodeRecord \ No newline at end of file diff --git a/tests.applescript b/tests.applescript index 5ec2386a7b88c97a9954e8bd736a0e8fa5ccae57..a4a8c1dccf3f927279497652543bed082351559a 100644 GIT binary patch delta 112 zcmbQx#(1Zlal;MC$-6YnIF%Tx8MqiY88|2BYbdfpSp6D`oM0A1ErZhJ_okwgwKT;x zzmxnX#mF_8Q$tZWhasOKok4*?i6Mm{lOdU*1gOkWvYR=EA#d_(jrz?jW?GCO&Sq`% Gr`!NAZ5$W? delta 37 vcmV+=0NVfDhXIg=0kGH^lh_Ovld1 Date: Wed, 9 Apr 2014 01:11:19 +0200 Subject: [PATCH 17/22] Test update --- tests.applescript | Bin 17372 -> 17550 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests.applescript b/tests.applescript index a4a8c1dccf3f927279497652543bed082351559a..8150bb6458a70066a6c8926f75778e5530582c0b 100644 GIT binary patch delta 91 zcmcc9&e+$;S> delta 43 zcmeC{WW3YPxM7dc<__a`Ou{(~`3&g{3JgjNDGZqm$qXe7N|PNWyEp$bo5BkKL$wXk From d5041714eed508268bdbd3efdfbf8f601deab9dc Mon Sep 17 00:00:00 2001 From: KAY Lukas Date: Wed, 9 Apr 2014 01:47:12 +0200 Subject: [PATCH 18/22] Special escape character sequence fix + test case --- json.applescript | 8 ++++---- tests.applescript | Bin 17550 -> 18136 bytes 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/json.applescript b/json.applescript index 48bfe18..88999ab 100644 --- a/json.applescript +++ b/json.applescript @@ -33,7 +33,7 @@ on decodeWithDicts(value) set s to s & " return output" & return -- sys.stdout to be able to write utf8 to our buffer -- We can ignore newlines in JSON format freely, as our \n will convert into new lines in bash we will use the actual new lines as the string \n - set s to s & "sys.stdout.write(toAppleScript(json.loads(sys.stdin.read().replace(\"\\n\", \"\\\\n\"))).encode('utf8'))" + set s to s & "sys.stdout.write(toAppleScript(json.loads(sys.stdin.read().replace(\"\\n\", \"\\\\n\").replace(\"\\b\", \"\\\\b\").replace(\"\\f\", \"\\\\f\").replace(\"\\t\", \"\\\\t\").replace(\"\\r\", \"\\\\r\"))).encode('utf8'))" set value to replaceString(value, {return & linefeed, return, linefeed, character id 8233, character id 8232}, "") -- AppleScript translates new lines in old mac returns so we need to turn that off set appleCode to do shell script "echo " & quoted form of value & " \"\\c\" |python2.7 -c " & quoted form of s without altering line endings @@ -78,8 +78,8 @@ on decode(value) set s to s & " return output" & return -- sys.stdout to be able to write utf8 to our buffer -- We can ignore newlines in JSON format freely, as our \n will convert into new lines in bash we will use the actual new lines as the string \n - set s to s & "sys.stdout.write(toAppleScript(json.loads(sys.stdin.read().replace(\"\\n\", \"\\\\n\"))).encode('utf8'))" - set value to replaceString(value, {return & linefeed, return, linefeed, character id 8233, character id 8232}, "") + set s to s & "sys.stdout.write(toAppleScript(json.loads(sys.stdin.read().replace(\"\\n\", \"\\\\n\").replace(\"\\b\", \"\\\\b\").replace(\"\\f\", \"\\\\f\").replace(\"\\t\", \"\\\\t\").replace(\"\\r\", \"\\\\r\"))).encode('utf8'))" + set value to replaceString(value, {return & linefeed, return, linefeed, character id 8233, character id 8232, character id 12, character id 9, character id 8}, "") -- AppleScript translates new lines in old mac returns so we need to turn that off set appleCode to do shell script "echo " & quoted form of value & " \"\\c\" |python2.7 -c " & quoted form of s without altering line endings set s to "on run " & return @@ -343,6 +343,6 @@ on encodeRecord(value_record) set s to s & " tokval = u'\"%s\"' % tokval[1:-1].replace ('\"', '\\\\\"')" & return set s to s & " result.append((tokid, tokval))" & return set s to s & " return tokenize.untokenize(result)" & return - set s to s & "print json.dumps(json.loads(appleScriptNotationToJSON(sys.stdin.read())))" & return + set s to s & "print json.dumps(json.loads(appleScriptNotationToJSON(sys.stdin.read()).replace(\"\\n\", \"\\\\n\").replace(\"\\b\", \"\\\\b\").replace(\"\\f\", \"\\\\f\").replace(\"\\t\", \"\\\\t\").replace(\"\\r\", \"\\\\r\")))" & return return (do shell script "echo " & quoted form of strRepr & "\"\\c\" | python2.7 -c " & quoted form of s) end encodeRecord \ No newline at end of file diff --git a/tests.applescript b/tests.applescript index 8150bb6458a70066a6c8926f75778e5530582c0b..b42f3724c84e7c94028873e3f3d374a331f26278 100644 GIT binary patch delta 400 zcmeC{WW3SKxWPx1k#q7xQR~TXboeGo3Dn0hC^5tUVIG()0h38!G7U@?G3WznB_PxU zLLCMLuzHA|QU(JsOa!Zh@hnkz7AU-A6kZC0{^UX-)5#46THMtPi45KhsSK42R+B$U z$~%(cu3EU;&`i-K$&|?#dE|prfgzF1kk60;bc+T1Noi!Fax@6@-mC6GE#%~M8 From 940fe5530d0808a0f0b36162f67c6b92b4281ad0 Mon Sep 17 00:00:00 2001 From: KAY Lukas Date: Wed, 9 Apr 2014 11:21:05 +0200 Subject: [PATCH 19/22] Bug fix --- json.applescript | 28 +++++++++++++++------------- tests.applescript | Bin 18136 -> 19046 bytes 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/json.applescript b/json.applescript index 88999ab..467dd45 100644 --- a/json.applescript +++ b/json.applescript @@ -1,4 +1,5 @@ on decodeWithDicts(value) + set value to replaceString(value, "\\", "\\\\") set s to "import json, sys, codecs" & return set s to s & "sys.stdin = codecs.getreader('utf8')(sys.stdin)" & return set s to s & "def toAppleScript(pythonValue):" & return @@ -13,8 +14,8 @@ on decodeWithDicts(value) set s to s & " first = False" & return set s to s & " else:" & return set s to s & " output += ','" & return - set s to s & " output += '{' + json.dumps(key) + ',' " & return - set s to s & " output += toAppleScript(value) + '}' " & return + set s to s & " output += '{\\\"' + key + '\\\",' " & return + set s to s & " output += toAppleScript(value) + '}'" & return set s to s & " output += '})'" & return set s to s & " elif (isinstance(pythonValue, list)):" & return set s to s & " output += '{'" & return @@ -33,10 +34,11 @@ on decodeWithDicts(value) set s to s & " return output" & return -- sys.stdout to be able to write utf8 to our buffer -- We can ignore newlines in JSON format freely, as our \n will convert into new lines in bash we will use the actual new lines as the string \n - set s to s & "sys.stdout.write(toAppleScript(json.loads(sys.stdin.read().replace(\"\\n\", \"\\\\n\").replace(\"\\b\", \"\\\\b\").replace(\"\\f\", \"\\\\f\").replace(\"\\t\", \"\\\\t\").replace(\"\\r\", \"\\\\r\"))).encode('utf8'))" - set value to replaceString(value, {return & linefeed, return, linefeed, character id 8233, character id 8232}, "") + set s to s & "sys.stdout.write(toAppleScript(json.loads(sys.stdin.read())).encode('utf8'))" + set value to replaceString(value, {return & linefeed, return, linefeed, character id 8233, character id 8232, character id 12, character id 9, character id 8}, "") -- AppleScript translates new lines in old mac returns so we need to turn that off - set appleCode to do shell script "echo " & quoted form of value & " \"\\c\" |python2.7 -c " & quoted form of s without altering line endings + set appleCode to do shell script "echo " & quoted form of value & " \"\\c\" |python2.7 -c " & quoted form of s without altering line endings + set appleCode to replaceString(appleCode, "\\", "\\\\") set s to "on run {json}" & return set s to s & appleCode & return set s to s & "end" @@ -44,6 +46,7 @@ on decodeWithDicts(value) end decodeWithDicts on decode(value) + set value to replaceString(value, "\\", "\\\\") set s to "import json, sys, codecs" & return set s to s & "sys.stdin = codecs.getreader('utf8')(sys.stdin)" & return set s to s & "def toAppleScript(pythonValue):" & return @@ -78,10 +81,11 @@ on decode(value) set s to s & " return output" & return -- sys.stdout to be able to write utf8 to our buffer -- We can ignore newlines in JSON format freely, as our \n will convert into new lines in bash we will use the actual new lines as the string \n - set s to s & "sys.stdout.write(toAppleScript(json.loads(sys.stdin.read().replace(\"\\n\", \"\\\\n\").replace(\"\\b\", \"\\\\b\").replace(\"\\f\", \"\\\\f\").replace(\"\\t\", \"\\\\t\").replace(\"\\r\", \"\\\\r\"))).encode('utf8'))" + set s to s & "sys.stdout.write(toAppleScript(json.loads(sys.stdin.read())).encode('utf8'))" set value to replaceString(value, {return & linefeed, return, linefeed, character id 8233, character id 8232, character id 12, character id 9, character id 8}, "") -- AppleScript translates new lines in old mac returns so we need to turn that off set appleCode to do shell script "echo " & quoted form of value & " \"\\c\" |python2.7 -c " & quoted form of s without altering line endings + set appleCode to replaceString(appleCode, "\\", "\\\\") set s to "on run " & return set s to s & appleCode & return set s to s & "end" @@ -311,11 +315,12 @@ end recordToString on encodeRecord(value_record) -- json can be used to escape a string for python set strRepr to recordToString(value_record) + set strRepr to replaceString(strRepr, "\\\\", "\\\\\\\\") set s to "import json, token, tokenize, sys, codecs" & return set s to s & "from StringIO import StringIO" & return set s to s & "sys.stdin = codecs.getreader('utf8')(sys.stdin)" & return set s to s & "def appleScriptNotationToJSON (in_text):" & return - set s to s & " in_text = in_text.replace(\"\\n\", \"\\\\n\")" & return + set s to s & " tokengen = tokenize.generate_tokens(StringIO(in_text).readline)" & return set s to s & " depth = 0" & return set s to s & " opstack = []" & return @@ -327,7 +332,7 @@ on encodeRecord(value_record) set s to s & " tokval = u'\"%s\"' % tokval" & return set s to s & " elif (tokid == token.STRING):" & return set s to s & " if tokval.startswith (\"'\"):" & return - set s to s & " tokval = u'\"%s\"' % tokval[1:-1].replace ('\"', '\\\\\"')" & return + set s to s & " tokval = u'\"%s\"' % tokval[1:-1]" & return set s to s & " elif (tokid == token.OP) and ((tokval == '}') or (tokval == ']')):" & return set s to s & " if (len(result) > 0) and (result[-1][1] == ','):" & return set s to s & " result.pop()" & return @@ -338,11 +343,8 @@ on encodeRecord(value_record) set s to s & " opstack.append(len(result))" & return set s to s & " elif (tokid == token.OP) and (tokval == ':') and result[opstack[-1]][1] != '}':" & return set s to s & " result[opstack[-1]] = (result[opstack[-1]][0], '{')" & return - set s to s & " elif (tokid == token.STRING):" & return - set s to s & " if tokval.startswith (\"'\"):" & return - set s to s & " tokval = u'\"%s\"' % tokval[1:-1].replace ('\"', '\\\\\"')" & return set s to s & " result.append((tokid, tokval))" & return set s to s & " return tokenize.untokenize(result)" & return - set s to s & "print json.dumps(json.loads(appleScriptNotationToJSON(sys.stdin.read()).replace(\"\\n\", \"\\\\n\").replace(\"\\b\", \"\\\\b\").replace(\"\\f\", \"\\\\f\").replace(\"\\t\", \"\\\\t\").replace(\"\\r\", \"\\\\r\")))" & return + set s to s & "print json.dumps(json.loads(appleScriptNotationToJSON(sys.stdin.read().replace(\"\\n\", \"\\\\n\").replace(\"\\b\", \"\\\\b\").replace(\"\\f\", \"\\\\f\").replace(\"\\t\", \"\\\\t\").replace(\"\\r\", \"\\\\r\"))))" & return return (do shell script "echo " & quoted form of strRepr & "\"\\c\" | python2.7 -c " & quoted form of s) -end encodeRecord \ No newline at end of file +end encodeRecord diff --git a/tests.applescript b/tests.applescript index b42f3724c84e7c94028873e3f3d374a331f26278..4fb3f1f889209d5325239df1c76f62a9928ed36e 100644 GIT binary patch delta 236 zcmcc7%lK>x96P}_PkldFL&Occc;WPOr2 hRlv+(1*@2RP+NBL8Znc}S*~(OB0S Date: Wed, 9 Apr 2014 11:28:05 +0200 Subject: [PATCH 20/22] bug fix --- json.applescript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json.applescript b/json.applescript index 467dd45..b45a189 100644 --- a/json.applescript +++ b/json.applescript @@ -14,7 +14,7 @@ on decodeWithDicts(value) set s to s & " first = False" & return set s to s & " else:" & return set s to s & " output += ','" & return - set s to s & " output += '{\\\"' + key + '\\\",' " & return + set s to s & " output += '{\\\"' + key.replace('\\\\', '\\\\\\\\').replace('\"', '\\\"') + '\\\",' " & return set s to s & " output += toAppleScript(value) + '}'" & return set s to s & " output += '})'" & return set s to s & " elif (isinstance(pythonValue, list)):" & return From dfc1891798ba4221c95a3c223cec38a045a6212e Mon Sep 17 00:00:00 2001 From: KAY Lukas Date: Wed, 9 Apr 2014 18:50:25 +0200 Subject: [PATCH 21/22] Fixes error when string contains a double quote --- json.applescript | 6 +++--- tests.applescript | Bin 19046 -> 19188 bytes 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/json.applescript b/json.applescript index b45a189..92c33b8 100644 --- a/json.applescript +++ b/json.applescript @@ -14,7 +14,7 @@ on decodeWithDicts(value) set s to s & " first = False" & return set s to s & " else:" & return set s to s & " output += ','" & return - set s to s & " output += '{\\\"' + key.replace('\\\\', '\\\\\\\\').replace('\"', '\\\"') + '\\\",' " & return + set s to s & " output += '{' + toAppleScript(key) + ',' " & return set s to s & " output += toAppleScript(value) + '}'" & return set s to s & " output += '})'" & return set s to s & " elif (isinstance(pythonValue, list)):" & return @@ -38,7 +38,7 @@ on decodeWithDicts(value) set value to replaceString(value, {return & linefeed, return, linefeed, character id 8233, character id 8232, character id 12, character id 9, character id 8}, "") -- AppleScript translates new lines in old mac returns so we need to turn that off set appleCode to do shell script "echo " & quoted form of value & " \"\\c\" |python2.7 -c " & quoted form of s without altering line endings - set appleCode to replaceString(appleCode, "\\", "\\\\") + set appleCode to replaceString(replaceString(appleCode, "\\", "\\\\"), "\\\"", "\"") set s to "on run {json}" & return set s to s & appleCode & return set s to s & "end" @@ -85,7 +85,7 @@ on decode(value) set value to replaceString(value, {return & linefeed, return, linefeed, character id 8233, character id 8232, character id 12, character id 9, character id 8}, "") -- AppleScript translates new lines in old mac returns so we need to turn that off set appleCode to do shell script "echo " & quoted form of value & " \"\\c\" |python2.7 -c " & quoted form of s without altering line endings - set appleCode to replaceString(appleCode, "\\", "\\\\") + set appleCode to replaceString(replaceString(appleCode, "\\", "\\\\"), "\\\"", "\"") set s to "on run " & return set s to s & appleCode & return set s to s & "end" diff --git a/tests.applescript b/tests.applescript index 4fb3f1f889209d5325239df1c76f62a9928ed36e..0f0958a6e5c25d36a17947ea56fa75f52bbe0656 100644 GIT binary patch delta 91 zcmaDhh4IT&#toNDC;NC9O`c$`z#qe)1caJEsKcPZpfp)gM0oQZ(;z`%bq0`>0s|KV UClG?k$@=b|*u*ziy1!)t0Pq_T)c^nh delta 31 mcmew|mGRjW#toNDH`|!S2u{|M5}CZu-3&+zY!>sl#{>Y?G7IPc From 10e4f072f2246cc6d0ad54a984b43c5f779085f2 Mon Sep 17 00:00:00 2001 From: KAY Lukas Date: Wed, 9 Apr 2014 19:13:43 +0200 Subject: [PATCH 22/22] Improved test case --- tests.applescript | Bin 19188 -> 19208 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests.applescript b/tests.applescript index 0f0958a6e5c25d36a17947ea56fa75f52bbe0656..66b37e5337ebc522ab85dcb0fc12690692f8dea0 100644 GIT binary patch delta 40 pcmew|m9b+Q