Sunday 28 August 2016

Blimey, a CFML-centric article

G'day:
But it's nothing that interesting. I submitted my answer ("Friday puzzle: my PHP answer") for the Friday Code Puzzle yesterday, deciding to use PHP, given it's what I do for a crust these days, and I could best visualise the solution in PHP.

But the puzzle was from a CFML chat group, so I figured I might blow the dust of my CFML skills and see how closely a CFML answer would approximate my PHP one. The answer is "quite closely!". Here's a CFML transliteration of the PHP answer:

component {

    parents = {};

    function init() {
        parents[0]["children"] = [];

        return this;
    }

    static function loadFromCsv(filePath) {
        var dataFile = fileOpen(filePath, "read");

        var tree = new Tree();
        while(!fileIsEof(dataFile)){
            var line = fileReadLine(dataFile);
            tree.addNode(
                nodeText = line.listLast(),
                id = line.listFirst(),
                parent = line.listGetAt(2, ",", true)
            );
        }

        return tree;
    }

    private function addNode(nodeText, id, parent) {
        parent = parent == "" ? 0 : parent;

        parents[id].nodeText = nodeText;
        parents[parent].children = parents[parent].children ?: [];
        parents[parent].children.append(parents[id]);
    }

    function serializeJson() {
        return serializeJson(parents[0]["children"]);
    }
}

Note that this is using Lucee 5's CFML vernacular, and this will not run on ColdFusion for a coupla reasons:

  • ColdFusion still doesn't support static methods;
  • It has a new bug with the ?: operator which breaks some of my shortcuts there.

I did not write the full test suite, but I wrote a small test rig and ran all the test variations manually. Here's the trickiest one:

dataFile = expandPath("../../test/testfiles/notOrdered/data.csv");

tree = Tree::loadFromCsv(dataFile);
treeAsJson = tree.serializeJson();

jsonAsArray = deserializeJson(treeAsJson);
writeDump(jsonAsArray);

And it yields the goods:




For completeness, here's the variation I had to do to make this work on ColdFusion:

static function loadFromCsv(filePath) {
    var dataFile = fileOpen(filePath, "read");

    var tree = new Tree();
    while(!fileIsEof(dataFile)){
        var line = fileReadLine(dataFile);
        tree.addNode(
            nodeText = line.listLast(),
            id = line.listFirst(),
            parent = line.listGetAt(2, ",", true)
        );
    }
    return this;
}

private function addNode(nodeText, id, parent) {
    parent = parent == "" ? 0 : parent;

    parents[id] = parents.keyExists(id) ? parents[id] : {};
    parents[id].nodeText = nodeText;
    
    parents[parent] = parents.keyExists(parent) ? parents[parent] : {};
    parents[parent].children = parents[parent].keyExists("children") ? parents[parent].children : [];
    parents[parent].children.append(parents[id]);
}

  • ColdFusion does not yet support static methods, so I cannot use a static factory method to create the tree, I need to instantiate an empty tree and then get it to load itself. Not ideal, but not the end of the world either.
  • Because of various bugs in ColdFusion's implementation of implicitly creating "deep" data structures, and also with the ?: operator, I had to be more explicit with stepping through creation of intermediary structs, and also use keyExists instead of ?:

This isn't bad, and I don't fault ColdFusion for its lack of static yet, but I'm annoyed by finding yet more bugs in ColdFusion when all I want is to run some code.

Back to the Lucee version: I think it demonstrates CFML syntax is a bit tidier than PHP's, as it's not quite so in love with the punctuation, and punctuation is just noise to achieving good Clean Code. But in this example it's much of a muchness, innit?

Anyway, I have little else to add other than that. The approach is identical to the PHP one I did: I just wanted to compare the two languages.

Job done.

Righto.

--
Adam