Refactor travis testing

This commit is contained in:
2021-06-07 12:36:22 -06:00
parent 32698b2d5b
commit 610a977b7c
77 changed files with 76 additions and 116 deletions

View File

@@ -0,0 +1,12 @@
package nat;
import sys.FileSystem;
import kiss.Prelude;
import sys.io.File;
import tink.Json;
import uuid.Uuid;
using haxe.io.Path;
@:build(kiss.Kiss.build())
class Archive {}

View File

@@ -0,0 +1,42 @@
(defnew [&prop :String archiveDir]
[:Array<System> systems
[]
:Map<String,Template> templates
(new Map)
:Map<String,Entry> entries
(let [entryFiles (FileSystem.readDirectory (Path.join [archiveDir "entries"]))]
(for file entryFiles =>(file.withoutExtension) ~(the Entry (Json.parse (File.getContent (Path.join [archiveDir "entries" file]))))))])
(defmethod addSystem [:System system]
// Assign entries to the Systems that care about them
(doFor =>id entry entries
(system.checkEntryInOrOut this entry))
(systems.push system))
(defmethod addTemplate [name template]
(dictSet templates name template))
(defmethod :Entry createEntry [template]
(let [e (_newEntry)]
(.prepareEntry (dictGet templates template) e)
(doFor system systems
(system.checkEntryInOrOut this e))
e))
(defmethod saveEntry [:Entry e]
(File.saveContent
(Path.join [archiveDir "entries" (e.id.withExtension "json")])
(Json.stringify e))
// TODO save its components? but it's not obvious how, because it only knows the string keys of them.
// Better yet, retrieving components with mutable access should be done through a
// (withComponent...) macro that serializes the component after the block is done.
//
)
(defun :Entry _newEntry []
(object
id (Uuid.v4)
components (new Map)
files []))

View File

@@ -0,0 +1,20 @@
package nat;
import kiss.KissInterp;
import hscript.Parser;
import kiss.Prelude;
@:build(kiss.Kiss.build())
class BoolExpInterp extends KissInterp {
public function new() {
super();
}
override function resolve(id:String):Dynamic {
return try {
super.resolve(id);
} catch (e:Dynamic) {
false;
}
}
}

View File

@@ -0,0 +1,9 @@
(defun eval [:String expStr :Array<String> activeConditions]
(let [hscriptExp
(.parseString (new Parser)
(Prelude.convertToHScript expStr))
interp
(new BoolExpInterp)]
(doFor condition activeConditions
(interp.variables.set condition true))
?(interp.execute hscriptExp)))

View File

@@ -0,0 +1,7 @@
package nat;
typedef Entry = {
id:String,
components:Map<String, String>,
files:Array<String>
};

View File

@@ -0,0 +1,11 @@
package nat;
import kiss.Prelude;
import sys.io.File;
import tink.Json;
import uuid.Uuid;
using haxe.io.Path;
@:build(kiss.Kiss.build())
class Lib {}

View File

@@ -0,0 +1,20 @@
// Lib is its own class because, while it would make sense to group its functions and macros in Archive.kiss,
// other files would not be able to (load "Archive.kiss") for the macro definitions without taking on Archive's constructor.
(defmacro hasComponent [e componentType]
`(.exists .components ,e ,(symbolName componentType)))
// TODO add to the documentation a hint that macros should use fully qualified paths so macro caller classes don't need to import everything
(defmacro getComponent [archive e componentType]
`(the nat.components ,componentType
(tink.Json.parse
(sys.io.File.getContent
(haxe.io.Path.join [.archiveDir (the nat.Archive ,archive) "components" (+ (dictGet (the Map<String,String> .components ,e) ,(symbolName componentType)) ".json")])))))
(defun tagList [archive e]
(let [t
(getComponent archive e Tags)]
(collect (t.keys))))
(defun tagsMatch [archive e tagsBoolExp]
(BoolExpInterp.eval tagsBoolExp (tagList archive e)))

View File

@@ -0,0 +1,9 @@
package nat;
import kiss.Prelude;
typedef EntryChecker = (Archive, Entry) -> Bool;
typedef EntryProcessor = (Archive, Entry) -> Void;
@:build(kiss.Kiss.build())
class System {}

View File

@@ -0,0 +1,13 @@
(defprop :Map<String,Entry> entries (new Map))
(defmethod :Void process [:Archive archive]
(doFor e (entries.iterator) (processEntry archive e)))
(defnew [&prop :EntryChecker canProcessEntry
&prop :EntryProcessor processEntry]
[])
(defmethod :Void checkEntryInOrOut [:Archive archive :Entry e]
(if (canProcessEntry archive e)
(dictSet entries e.id e)
(entries.remove e.id)))

View File

@@ -0,0 +1,5 @@
package nat;
interface Template {
function prepareEntry(e:Entry):Void;
}

View File

@@ -0,0 +1,3 @@
package nat.components;
typedef Tags = Map<String, Date>;

View File

@@ -0,0 +1,4 @@
package nat.components;
typedef Name = String;
typedef Author = String;

View File

@@ -0,0 +1,3 @@
package nat.components;
typedef Tags = Map<String, Int>;

View File

@@ -0,0 +1,6 @@
package nat.systems;
import kiss.Prelude;
@:build(kiss.Kiss.build())
class TagSystem extends System {}

View File

@@ -0,0 +1,9 @@
(load "../Lib.kiss")
// TODO make a &super annotation that passes an argument to the super constructor
(defnew [&prop :String tagFilterString
&prop :EntryProcessor processor]
[]
(super
(lambda [:Archive archive :Entry e] (tagsMatch archive e tagFilterString))
processor))

View File

@@ -0,0 +1,11 @@
package test;
import kiss.Kiss;
import kiss.Prelude;
import nat.BoolExpInterp;
import nat.Archive;
import nat.Lib;
import nat.components.*;
@:build(kiss.Kiss.build())
class TestMain {}

View File

@@ -0,0 +1,28 @@
// TODO external programs need to be able to find and (load) this path to get the macros:
// ^ That should be solved by allowing an optional first argument to load that is a symbol
// of a library name that can be used to resolve the source dir in the user's Haxelib maybe?
(load "../nat/Lib.kiss")
(defun :Void main []
(assert (BoolExpInterp.eval "true" []))
(assert !(BoolExpInterp.eval "false" []))
(assert !(BoolExpInterp.eval "flag" []))
(assert (BoolExpInterp.eval "flag" ["flag"]))
(assert !(BoolExpInterp.eval "(and flag false)" ["flag"]))
(assert (BoolExpInterp.eval "(or flag otherFlag)" ["otherFlag"]))
//trace(error);
(let [archive
(new Archive "src/test/example-archive")
song1
(dictGet archive.entries "song1")
song2
(dictGet archive.entries "song2")]
(assert (hasComponent song1 Tags))
(assert (hasComponent song2 Tags))
(assert (tagsMatch archive song1 "(and song western)"))
(assert !(tagsMatch archive song1 "(and song religious)"))
(assert (tagsMatch archive song2 "(and song religious)"))
(assert !(tagsMatch archive song2 "(and song western)"))
))

View File

@@ -0,0 +1 @@
"Rafael Krux"

View File

@@ -0,0 +1 @@
"Kevin MacLeod"

View File

@@ -0,0 +1 @@
"Adventure"

View File

@@ -0,0 +1 @@
"Ancient Rite"

View File

@@ -0,0 +1,4 @@
[
["song", 1],
["western", 1]
]

View File

@@ -0,0 +1,4 @@
[
["song", 1],
["religious", 1]
]

View File

@@ -0,0 +1,11 @@
{
"id": "song1",
"components": [
["Name", "name1"],
["Author", "author1"],
["Tags", "tags1"]
],
"files": [
"Adventure.mp3"
]
}

View File

@@ -0,0 +1,11 @@
{
"id": "song2",
"components": [
["Name", "name2"],
["Author", "author2"],
["Tags", "tags2"]
],
"files": [
"Ancient Rite.mp3"
]
}