Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cosmetics and small refactoring #14

Merged
merged 12 commits into from
Jan 21, 2023
36 changes: 21 additions & 15 deletions Tests/TestJSONlib.sc
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
TestJSONlib : UnitTest {
// util
*prJsonFilePath {|fileName|
^this.class.filenameSymbol.asString.dirname +/+ "assets" +/+ fileName;
}

*prLoadJsonFile {|fileName|
^JSONlib.parseFile(TestJSONlib.prJsonFilePath(fileName));
}

// encoding tests
test_objectEncode {
Expand Down Expand Up @@ -243,17 +236,17 @@ TestJSONlib : UnitTest {
// decoding tests - taken from json.org
// we only test for valid json
test_objectDecode {
var j = TestJSONlib.prLoadJsonFile("object.json");
var j = this.prParseJsonFile("object.json");
this.assertEquals(j[\foo][\bar], "baz", "Parse nested objects");
}

test_arrayDecode {
var j = TestJSONlib.prLoadJsonFile("array.json");
var j = this.prParseJsonFile("array.json");
this.assertEquals(j, [20 , 30, 40], "JSON can contain also array as root");
}

test_valuesDecode {
var j = TestJSONlib.prLoadJsonFile("values.json");
var j = this.prParseJsonFile("values.json");
this.assertEquals(j[\string], "string", "Value can be strings");
this.assertEquals(j[\number], 10, "Value can be integer numbers");
this.assertEquals(j[\object][\foo], "bar", "Values can be objects");
Expand All @@ -265,7 +258,7 @@ TestJSONlib : UnitTest {
}

test_stringsDecode {
var j = TestJSONlib.prLoadJsonFile("strings.json");
var j = this.prParseJsonFile("strings.json");
this.assertEquals(j[\text], "lorem ipsum", "Standard text should be reproduced");
this.assertEquals(j[\quotationMark], "lorem\"ipsum", "Quotation needs to be escaped");
this.assertEquals(j[\reverseSolidus], "lorem\\ipsum", "Reverse Solidus needs to be escaped");
Expand All @@ -278,7 +271,7 @@ TestJSONlib : UnitTest {

// sc can not compare utf-8 chares so we make some extra steps
this.assertEquals(
j[\hexDigits].ascii[0..4].asAscii,
j[\hexDigits].ascii[0..4].collect(_.asAscii).join,
"lorem",
"Hex encoding should not affect ascii chars lorem",
);
Expand All @@ -291,14 +284,14 @@ TestJSONlib : UnitTest {
);

this.assertEquals(
j[\hexDigits].ascii[8..].asAscii,
j[\hexDigits].ascii[8..].collect(_.asAscii).join,
"ipsum",
"Hex encoding should not affect ascii chars ipsum",
);
}

test_numbersDecode {
var j = TestJSONlib.prLoadJsonFile("numbers.json");
var j = this.prParseJsonFile("numbers.json");
this.assertEquals(j[\integer], 10, "Positive integer");
this.assertEquals(j[\negativeInteger], -1 * 10, "Negative integer");
this.assertEquals(j[\float], 10.0, "float");
Expand All @@ -309,7 +302,7 @@ TestJSONlib : UnitTest {
}

test_jsonNullDecode {
var p = TestJSONlib.prJsonFilePath("values.json");
var p = this.prGetPathFor("values.json");
var j = JSONlib.parseFile(p, useEvent: true);
this.assert(j.keys.asArray.includes(\null), "Null ref value needs to have a key in event");
this.assertEquals(j[\null].value, nil, "As an Event can not store nil we wrap it in a Ref");
Expand Down Expand Up @@ -417,4 +410,17 @@ TestJSONlib : UnitTest {
"Test external method on an Event"
);
}


// private implementation
// util

prGetPathFor {|fileName|
^this.class.filenameSymbol.asString.dirname +/+ "assets" +/+ fileName
}

prParseJsonFile {|fileName|
^JSONlib.parseFile(this.prGetPathFor(fileName))
}

}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
31 changes: 15 additions & 16 deletions classes/JSONlib.sc
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,14 @@ JSONlib {
var <>customDecoder;

*new { |postWarnings = true, useEvent=true, customEncoder=nil, customDecoder=nil|
^super.newCopyArgs(
postWarnings,
useEvent,
customEncoder,
customDecoder,
);
^super.newCopyArgs(postWarnings, useEvent, customEncoder, customDecoder)
}

*convertToJSON {|object, customEncoder=nil, postWarnings=true|
if((object.isKindOf(Dictionary) or: (object.isKindOf(SequenceableCollection))).not) {
Error("Can only convert a Dictonary/Event/Array to JSON but received %".format(object.class)).throw
};
^this.new(postWarnings, customEncoder: customEncoder).prConvertToJson(object);
^this.new(postWarnings, customEncoder: customEncoder).prConvertToJson(object)
}

*convertToSC {|string, customDecoder=nil, useEvent=true, postWarnings=true|
Expand All @@ -37,25 +32,28 @@ JSONlib {
postWarnings,
customDecoder: customDecoder,
useEvent: useEvent,
).prConvertToSC(filePath.parseJSONFile);
).prConvertToSC(filePath.parseJSONFile)
}

prConvertToJson {|v|
var array;

if(customEncoder.notNil) {
var val = customEncoder.value(v);
if(val.notNil) {
^val;
};
^val
}
};

^case
{ v.isKindOf(Symbol) } { this.prConvertToJson(v.asString) }
// only check value if it is a ref
{ v.isNil or: { v.isKindOf(Ref) and: { v.value.isNil } } } { "null" }
// sc closely implements the JSON string, see https://www.json.org/json-en.html
// but the post window parses \n as linebreak etc. which makes copying of the JSON from
// the post window error prone
{ v.isString } { v
{ v.isString } {
v
.replace("\\", "\\\\") // reverse solidus
.replace("/", "\\/") // solidus
.replace($", "\\\"") // quoatition mark
Expand All @@ -69,8 +67,8 @@ JSONlib {
}
{ v.isNumber } {
case
{v==inf} { "inf".quote }
{v==inf.neg} { "-inf".quote }
{ v == inf } { "inf".quote }
{ v == inf.neg } { "-inf".quote }
{v.asCompileString};
}
{ v.isKindOf(Boolean) } { v.asBoolean }
Expand All @@ -96,7 +94,7 @@ JSONlib {
}
{
if(postWarnings) { "JSON file format will not recover % class, but instead a compile string".format(v.class.name).warn };
this.prConvertToJson(v.asCompileString);
this.prConvertToJson(v.asCompileString)
}
}

Expand All @@ -105,9 +103,10 @@ JSONlib {
if(customDecoder.notNil) {
var val = customDecoder.value(v);
if(val.notNil) {
^val;
};
^val
}
};

^case
{ v.isString and: { v.every { |x| x.isDecDigit } } } { v.asInteger }
// see https://www.json.org/json-en.html Number section and
Expand Down