LoginSignup
3
2

More than 5 years have passed since last update.

GrimoireJSのノード・コンポーネントの仕様詳細

Last updated at Posted at 2016-12-14

(この記事はGrimoireJSアドベントカレンダー13日目の記事です。)

こんにちは、GrimoireJS-Coreのコアコミッターmoajoです。
GrimoireJS-Coreは、html上に埋め込まれたgomlをパースしてGOMツリーを構築し、GomlNodeの相互作用を管理するのが主なお仕事です。
今回はGrimoireJSの根幹であるGomlNode/Componentの細かい仕様についての話です。

新しいノード・コンポーネントを作る

GrimoireJSを拡張するときは、まず機能をComponentとしてモジュール化して、それらをコンポーネントやノードとしてまとめます
具体的には、

index.js
gr.registerComponent("Component1", {
    attributes: {
      hogehoge: {
        converter: "String",
        defaultValue: null
      }
    },
    $mount: function (arg) {
      console.log("mount");
    },
    $awake: function (arg) {
      console.log("awake");
    },
    $hoge: function (arg) {
      console.log(hoge);
    }
  });
gr.registerComponent("Component2", {
    attributes: {
      hugahuga: {
        converter: "Number",
        defaultValue: 0
      }
    },
    $huga: function (arg) {
      console.log(this.getAttribute("hogehoge").Value);
    }
  });
gr.registerNode("node1", ["Component1"]);
gr.registerNode("node2", ["Component2"], {hugahuga:100}, "node1")

ここではコンポーネントとノードを2つづつ登録してますが、こんな感じでGrimoireInterfaceに登録します。
登録はこれで完結してます。つまり、コンポーネント・ノードに必要な情報はすべてここに含まれてます。
コンポーネントの方から仕組みを見てみましょう

Componentの作成

gr.registerComponentの引数は、先頭から

  1. コンポーネント名
  2. コンポーネントのインスタンスかコンストラクタ
  3. 継承元コンポーネント名

です。

コンポーネント名

コンポーネント名は先頭大文字のCamelCaseが推奨です。基本的にそうしましょう。ノード名はsnake-caseです。

コンポーネントの属性

コンポーネントはattributesというフィールドで、そのコンポーネントが持つ属性を決めます
属性は、

index.js
attributes:{
  属性名:{
    converter:コンバータ名,
    defaultValue:デフォルト値
  }
}

というフォーマットです。
コンバータは、NumberStringBooleanEnumなどが最初からありますが、

index.js
gr.registerConverter("ConverterName", function(attr,val){
  console.log("this attribute is " + attr.name);
  console.log("value is " + val);
  if(typeof val ==="string"){
    return Number(val)
  }
  if(typeof val ==="number"){
    return val;
  }
});

という感じで追加できます。受け取った値を適切に変換して返すだけの関数ですね。
gomlで文字列で指定された属性は、属性に指定されたコンバータを通して変換され使われます
また、コンバータは属性値を設定した時ではなく、取得するときに遅延実行されます

コンポーネントの$関数

コンポーネントが$で始まる関数を持つとき、それらはGrimoireJSのメッセージレシーバとして扱われます。
GrimoireJSではコンポーネント間でメッセージのやりとりがありますが、それらの対象として扱われるのは先頭に$がつく関数のみです。
この関数内では、thisはこのコンポーネントのインスタンスにバインドされます

コンポーネントの継承

コンポーネントは継承できます
継承するとすべての属性と関数が引き継がれます。
また、ノードのgetComponent関数で継承元コンポーネントを指定したときに継承したコンポーネントも対象になります。つまり、ポリモーフィズムを持つことができます。

GomlNodeの作成

ノードは単純に複数のコンポーネントを入れる箱です。
コンポーネントとそれらの属性の初期値を決めて、タグとしてまとめられます。
gr.registerNodeの引数は、

  1. ノード名
  2. デフォルトコンポーネントのリスト
  3. 属性値
  4. 継承元コンポーネント名

です。
コンポーネントのリストはそれが最初から入っているというだけです。属性値もコンポーネントのデフォルト値を上書きしてるだけですね。

ノード名

さっきも書きましたが、snake-caseです。

ノードの継承

ノードも継承できますが、ここにポリモーフィズムはありません
継承によって、コンポーネントリストや属性値を引き継ぎますが、属性値を隠すこともできます。
ノードの継承は、単に追加機能にエイリアスを付けているだけという感じです。

その他

  • 属性値の優先順位は、goml>Nodeの初期値>Componentの初期値です。
  • コンポーネントやノードの継承関係は、gomlのパース時に評価されます。
  • コンバータは、変換できないときはundefinedを返します。
  • また、コンバータにundefinedを通そうとするのは許されず、例外を投げます。
    • 従って、属性初期値にundefinedは設定できません。
3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2