Skip to content
This repository has been archived by the owner on Oct 28, 2024. It is now read-only.

Custom Element

Mutsuha Asada edited this page Aug 2, 2022 · 6 revisions

概要

mumlが提供するmumlBuilderマクロを利用することで、開発者は新しい独自のElementを追加することができます。
このマクロはCustom Elementの型を与えることで、フィールドを読み出すための煩雑なJSON解析処理を自動生成します。 独自のElementとそれに対するフレーム処理はmock-upのプラグイン上で統合されます。

Custom ElementはmumlRootElement型を継承するref objectである必要があります。これは、全てのElementをイテレータによって取得することができるようにするためです。
一方で、Custom Elementのフィールドとして存在する構造体はobject型であることが推奨されます。ref object型でも動作しますが、今後のアップデートでコンパイルエラーを検出するように変更する予定です。

type
  myEnum = enum
    me1, me2, me3

  nest2 = object
    nest2_field1: int8
    nest2_field2: myEnum

  nest1 = object
    nest1_field1: float
    nest1_field2: nest2
  
  newElement = ref object of mumlRootElement
    field1: Animation[int]
    field2: string
    field3: nest1

mumlBuilder(newElement)

次のようなJSONを上のnewElementに変換することができます。

let newElementMuml = %* {
  "field1": [1, 2, 3],
  "field2": "hello!",
  "field3": {
    "nest1_field1": 2.5,
    "nest1_field2": {
      "nest2_field1": 10,
      "nest2_field2": "me1"
    }
  }
}

echo newElement(parse_newElement(newElementMuml))[]
# => (field1: @[1, 2, 3], field2: "hello!", field3: (nest1_field1: 2.5, nest1_field2: (nest2_field1: 10, nest2_field2: me1)), default_content: "")

現在、mumlがサポートしている型は以下の通りです。構造体は何度ネストしても解釈できますが、以下の型のみで構成されている必要があります。

int, int8, float, string, enum

Animation

動的配列seq[T]型の別名である、Animation[T]型を提供しています。
Custom Elementが持つフィールドのうち、フレーム再生により値が変化するものはAnimation型で包む必要があります。

マクロの詳細

IMG_9FF2DD1AF91C-1

mumlBuilderマクロは大きく分けて2つの仕事をします。
1つ目は与えられた型を解析してdeserializeルールを作成すること、2つ目はルールを用いてCustom Elementのパーザを生成することです。先ほどのnewElement型のルールは以下のように出力されます。

{
  "type": "newElement",
  "@field1": "int",
  "field2": "string",
  "field3": {
    "type": "nest1",
    "nest1_field1": "float",
    "nest1_field2": {
      "type": "nest2",
      "nest2_field1": "int8",
      "nest2_field2": "enum:myEnum"
    }
  }
}

出力されるパーザはparse_xxxnewElement型の場合はparse_newElement)プロシージャと命名されます。
せっかくなので出力されるプロシージャも眺めてみます(変数名は環境によって異なる場合があります)。

proc parse_newElement(muml`gensym17: mumlNode): mumlRootElement =
  var resultElement_627027 = newElement()
  for key_627027, val_627027 in pairs(muml`gensym17):
    case key_627027
    of "field1":
      for jsonArrayElement`gensym18 in items(val_627027):
        add(resultElement_627027.field1, getInt(jsonArrayElement`gensym18, 0))
    of "field2":
      resultElement_627027.field2 = removeDoubleQuotation(getStr(val_627027, ""))
    of "field3":
      var resultElement_919749 = nest1()
      for key_919749, val_919749 in pairs(val_627027):
        case key_919749
        of "nest1_field1":
          resultElement_919749.nest1_field1 = getFloat(val_919749, 0.0)
        of "nest1_field2":
          var resultElement_353555 = nest2()
          for key_353555, val_353555 in pairs(val_919749):
            case key_353555
            of "nest2_field1":
              resultElement_353555.nest2_field1 = int8(getInt(val_353555, 0))
            of "nest2_field2":
              resultElement_353555.nest2_field2 = parseEnum(
                  removeDoubleQuotation(getStr(val_353555, "")))
          resultElement_919749.nest1_field2 = resultElement_353555
      resultElement_627027.field3 = resultElement_919749
  result = resultElement_627027
Clone this wiki locally