スクリプト言語 KINX/【雑多なこと】その後サポートした機能

# はじめに

「**見た目は JavaScript**、**頭脳(中身)は Ruby**、（**安定感は AC/DC**）」になっているかはさておき。

解説ばっかりで疲れてきたので、解説とは別に雑多な話題をご提供。いくつか機能をサポートしました。ドキュメントをそろえてバージョン 1 を何とかリリースしたいところ。

# その後サポートした機能

構文的な追加とライブラリの追加をしました。

## 構文

### module

`module` と `mixin` という予約語で、後から機能をアタッチできる仕組み。

```javascript
module Printable {
    public print() {
        System.print(@value); // `this` is not Printable's instance but host class's instance.
                              // In this case, this means Value's instance.
    }
    public println() {
        System.println(@value);
    }
}

class Value(v) {
    mixin Printable;
    private initialize() {
        @value = v;
    }
}

var v = new Value(100);
v.println();    // 100
```

### namespace

名前空間。クラスとモジュールは自動的に名前空間に属し、名前空間を経由してアクセス可能。

```javascript
namespace Name1 {

    class X {
        public methodX() {
            System.println("x1");
        }
    }

    var x = new X();
    x.methodX(); // x1

    namespace Name2 {
        class X {
            public methodX() {
                System.println("x2");
            }
        }

        var x = new X();
        x.methodX(); // x2
    } // namespace Name2

} // namespace Name1

var x1 = new Name1.X();
x1.methodX(); // x1

var x2 = new Name1.Name2.X();
x2.methodX(); // x2
```

## ライブラリ

下記のサンプルは[リポジトリ](https://github.com/Kray-G/kinx) にもコミットしてある。

### Zip

Zip による圧縮・解凍をサポート。試してないが、使ったライブラリの説明によれば Zip64 もいける（自動的に対処される）はず。WinZIP の AES アルゴリズムには対応されているのを確認した。ただし、AES 暗号化を有効にしてしまうと Windows の Explorer で解凍できなくなるが強固にはなる。こんな感じ。

```javascript
import Zip;

var zip = new Zip("examples/zip/ziptest.zip", File.READ|File.WRITE);
zip.setPassword("text");
zip.addFile("README.md", {
    method: "bzip2",
    aes: true,
});
zip.addFile("README.md");
zip.addString("test/test1.txt", {
    content: "test/test\n",
    aes: true,  // Can not use aes option for addString, that means no effect for addString.
});
zip.addString("test/test2.txt", {
    content: "test/test\n",
    password: "text2",
});

System.println("totalFiles = ", zip.totalFiles);
zip.each(function(e) {
    System.println("%s:" % e.filename);
    e.keySet().each(&(key) => {
        if (e[key].isFunction || e[key].isObject || e[key].isUndefined) {
            return;
        }
        if (key == "crc32") {
            System.println("    %-14d = %10X" % key % e[key]);
        } else if (key != "time" && key != "filename") {
            System.println("    %-14d = %10d" % key % e[key]);
        }
    });
    e.time.keySet().each(&(k) => {
        System.println("      time.%-7d = %10d" % k % e.time[k]);
    });
    // if (e.filename == "README.md") {
    //     e.extractTo("READMEXX.md", { password: "text", overwrite: true });
    // }
});

var file = zip.read("README.md", { password: "text" });
System.println(file);
zip.find("README.md")
    .extractTo("READMEXX.md", { password: "text", skip: true });
```

### SQLite3

SQLite3 データベースの読み書きをサポート。トランザクションもサポート。何か他にも気にするところがあったような。。。`SQLITE_BUSY` が返ってきたときの挙動とかかな。追々確認しよう。今はこんな感じ。

```javascript
import SQLite;

var db = new SQLite("database.db", 3000);
db.exec("CREATE TABLE IF NOT EXISTS mytable "
    "("
        "id INTEGER PRIMARY KEY AUTOINCREMENT, "
        "name TEXT NOT NULL"
    ")"
);
db.transaction(&{
    var ins = db.prepare("INSERT INTO mytable (name) VALUES (?)");
    for (var i = 0; i < 20; ++i) {
        ins.bind("name(%{i})").exec();
    }
});

var c, r = db.prepare("SELECT * FROM mytable WHERE (id > ? AND id < ?) OR id = ?")
            .bind(2)
            .bind(8, 10)    // bind() can be separated.
            .query();       // do binding & ready to next().

while (c = r.next()) {
    var cols = c.columnName;
    var vals = c.value;
    System.println("Record[%d]" % vals[0]);
    for (var i = 0, len = cols.length(); i < len; ++i) {
        System.println("    %-8s = %s" % cols[i] % vals[i]);
    }
}
```

### Xml

Xml 文書の読み書きをサポート。XPath も使える。ちょっと長いがこんな感じ。

```javascript
import Xml;

function displayXml(doc, node, indent) {
    System.print("  " * indent);
    if (node.type == Xml.ELEMENT_NODE) {
        System.print("ELEM %s" % node.name);
    } else if (node.type == Xml.TEXT_NODE) {
        System.print("TEXT %s" % node.value.trim());
    }

    var attr = node.attributes();
    for (var i = 0, len = attr.length(); i < len; ++i) {
        System.print("[%s=%s]" % attr[i].name % attr[i].value);
    }
    System.println("");

    var child = node.firstChild();
    while (child) {
        displayXml(doc, child, indent + 1);
        child = child.nextSibling();
    }
}

var doc = Xml.parseString(%{
<?xml version="1.0" encoding="UTF-8" ?>
<artists>
  <artist country="US" id="1">
    <name>BON JOVI</name>
    <price>2400</price>
    <img file="bonjovi.jpg"/>
  </artist>
  <artist country="US" id="2">
    <name>GUNS N ROSES</name>
    <price>21000</price>
    <img file="GNR.jpg"/>
  </artist>
  <artist country="DE" id="3">
    <name>Helloween</name>
    <price>2400</price>
    <img file="helloween.jpg"/>
  </artist>
</artists>
});
var root = doc.documentElement();
displayXml(doc, root);

var el = root.getElementById("3");
if (el) {
    el.remove();
}

System.println("");
System.println("getElementByTagName:");
var els = root.getElementByTagName("img");
if (els.isArray) {
    els.each(&(el) => displayXml(doc, el));
}

System.println("");
System.println("XPath:");
var nodes = doc.xpath("//car").xpath("price");
if (nodes.isArray) {
    nodes.each(&(el) => displayXml(doc, el));
}

var xmlWriter = new Xml.Writer(System);
xmlWriter.write(doc);
xmlWriter.write(root);
```

# おわりに

だいぶ実用に近づいてきた。もうちょっとだから頑張ろう。ドキュメント書かないとね。

* 最初の動機は [スクリプト言語 KINX（ご紹介）](https://qiita.com/Kray-G/items/ca08b6fb40d15dd0ec76) を参照してください（もし宜しければ**「いいね」**ボタンをポチっと）。
* リポジトリは [ここ（https://github.com/Kray-G/kinx）](https://github.com/Kray-G/kinx) です。こちらももし宜しければ★をポチっと。