Help us understand the problem. What is going on with this article?

メンバ転送で内部DSLをつくる

More than 5 years have passed since last update.

 やっはろー。もう日付は過ぎていますけど、飛び入りで参加します。

 Ruby の method_missing や Scala の applyDinamic のように、D言語でも opDispatch を定義することで存在しないメソッドを呼んだときの動作をフックすることができます。

import std.stdio, std.string;

struct Foo {
    string opDispatch(string name)() const {
        return ["Call", name, "!"].join(" ");
    }

    string opDispatch(string name)(string arg) const {
        return ["Call", name, "with", arg, "!"].join(" ");
    }
}

void main() {
    auto foo = new Foo();
    writeln(foo.bar()); // Call bar !
    writeln(foo.baz("qux")); // Call baz with qux !
}

テンプレートの第一引数にメソッド名を取る他は普通のメソッドと同じです。

 これを利用して、XML を出力する内部 DSL を書いてみました。

import std.algorithm, std.ascii, std.range, std.regex, std.string;

struct XMLGenerator {
    struct XMLElement {
        string elem;
        string[string] attr;
        string text;
        XMLElement[] children;

        string toString(int level = 0) const {
            auto indent = "  ".repeat(level).join;
            auto attribute = (attr.length)? " " ~ attr.keys.map!(k => k ~ `="` ~ attr[k] ~ `"`).join(" "): "";

            return [
                indent ~ "<" ~ elem ~ attribute ~ ">",
                (text.length)? indent ~ "  " ~ text: null,
                children.map!(x => x.toString(level + 1)).join(newline),
                indent ~ "</" ~ elem ~ ">"
            ].filter!(x => x).join(newline);
        }
    }

    alias E = XMLElement;

    static E opDispatch(string elem)(E[] children) const {
        return XMLGenerator.opDispatch!elem(null, null, children);
    }

    static E opDispatch(string elem)(string text, E[] children = null) const {
        return XMLGenerator.opDispatch!elem(null, text, children);
    }

    static E opDispatch(string elem)(string[string] attribute = null, string text = null, E[] children = null) const {
        return E(elem.replaceAll(regex("^_"), ""), attribute, text, children);
    }
}

こんな感じで使います。

import std.stdio;

void main() {
    alias XML = XMLGenerator;
    writeln(
        XML.html([
            XML.head([
                XML.title("D Programming Language")
            ]),
            XML._body([
                XML.h1([
                    XML.font(["color": "#ff0000"], "D "),
                    XML.span("Programming Language")
                ]),
                XML.b("Hello world!")
            ])
        ])
    );
}
<html>
  <head>
    <title>
      D Programming Language
    </title>
  </head>
  <body>
    <h1>
      <font color="#ff0000">
        D 
      </font>
      <span>
        Programming Language
      </span>
    </h1>
    <b>
      Hello world!
    </b>
  </body>
</html>

mixin と組み合わせたら化けそうです。お粗末さまでした。

Operator Overloading - D Programming Language

woxtu
世界の上にタンポポをのせる仕事をしています。
qiitadon
Qiitadon(β)から生まれた Qiita ユーザー・コミュニティです。
https://qiitadon.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away