GrimoireJS-core **v1.0(beta)**がようやくリリースされようとしています。ようやく!
v1.0(beta)は今後のしっかりした後方互換性を保つべく、機能の整理と実装のリファクタリングを含むそこそこ大きな(互換性のない)変更になっています。
ほとんどの変更はプラグインを作成する場合くらいにしか影響しないマイナーなものですが、今回はその全変更点を黙々と紹介していきたいと思います。
ディレクトリ構成変更
期せずして過去最大の変更となったのはディレクトリ構成の大幅な改変です。(いままで適当すぎてごめんなさい)
ちゃんと意味的にあるべき位置にモジュールを再配置しました。
この変更は、typescript
でcoreのモジュールをimportする際のpathが変わることを意味します。
// before
import Component from "grimoirejs/ref/Node/Component";
// after
import Component from "grimoirejs/ref/Core/Component";
また、gr
に露出するインターフェースのパスも変化します。
// before
gr.Node.GomlLoader
// after
gr.Core.GomlLoader
と、このように移動しています。
ざっくりどこに何があるかというと、以下のように配置されるようになりました。
Core
GomlNode
, Component
,Attribute
など主要ロジックに関わるクラス。
GomlLoader
, Identity
, AttributeManager
などもここにあります。
Tool
IdResolver
,Utility
などの割と便利な汎用ツール群があります。
イチオシ関数はUtility.isCamelCase
です。
gr.Tool.Utility.isCamelCase("CamelCase");// true
Converter/Component
名の通り標準のコンバーターとコンポーネントが入ってます。
とはいえクラスを直接触る機会は少ないでしょう。
他にはインタフェースが定義されるInterface
,基底クラスのBase
がありますが普通使わないと思います。
ちなみに命名規則が地味に統一されすべてのディレクトリが 単数形になっています。
いくつかのインタフェースのリネーム
完全な差分は公式のドキュメントを参照してください。(まだありませんけど!)
GomlNode#nodeDeclaration
=>GomlNode#declaration
Attribute#BoundTo
=>Attribute#bindTo
などです。
GomlTreeがスクリプトタグに依存しなくなった
小さな変更ですが重要です。
今までGrimoireJSが扱うすべてのツリーはページ上の何処かのスクリプトタグに結びついている必要がありました。
これからはその制限がなくなり、完全にhtmlから独立したツリーを作成することもできるようになります。
動的なツリー構築がやりやすくなり、実装の自由度が高まります。
var source = "<goml></goml>"
var xml = gr.Tool.XMLReader.parseXML(source);
var tree = gr.Core.GomlParser.parse(xml);
gr.addRootNode(null, tree); // 第1引数(scriptTag)を省略可能に!
rootがgomlじゃなくても良くなった
これも自由度のための変更です。初期の実装上の都合で制限されていたrootノードに関する制約がなくなり、完全に任意のgomlを読み込むことができます。
Gomlの中間形式を導入した
gomlはいままで文字列表現しかなかったので、
var node = gr("*")("#container").first()
node.append('<mesh geometry="cube"/>')
みたいなコードを書いていました。
中間形式はGrimoireObjectModel
と呼ばる構造で、構造化されたgomlのデータ構造です。
interface IGrimoireNodeModel {
name: string;
attributes?: { [key: string]: string; };
optionalComponents?: IGrimoireComponentModel[];
children?: IGrimoireNodeModel[];
}
interface IGrimoireComponentModel {
name: string;
attributes?: { [key: string]: string; };
}
これによって、先程のコードは
node.append({
name:"mesh",
attributes:{
geometry:"cube"
}
})
と書けるようになります。
Attributeがgenericsになった
Attribute
クラスとComponent#getAttribute
メソッドがジェネリックになりました。
たとえば、以下のようなコンポーネントの場合、
class HogeComponent extends Component {
public static componentName = "Hoge";
public static attributes = {
a: {
converter: StringConverter,
default: null,
},
b: {
converter: BooleanConverter,
default: true,
},
};
属性取得は以下のように書けます。
const c = node.getComponent(HogeComponent)
const v = c.getAttribute<string>("a");
しかし、これでは型指定をわざわざしなくてはならないので今までと大して変わりません。
実はコンバータもジェネリッククラスになったことと、getAttribute
の引数にIAttributeDeclaration<T>
のオーバーロードが追加されたので、上のコードは以下のように書けます。
const c = node.getComponent(HogeComponent)
const v = c.getAttribute(HogeComponent.attributes.a); // v is string!
型推論によって、属性取得がタイプセーフに書けるようになりました!
この型推論は、属性のコンバータの型に依存することに注意してください。
gr.registerNodeでデフォルトコンポーネントにコンストラクタを指定できるようになった
シンプルにオーバーロードが増えました。
// before
GrimoireInterface.registerNode("hoge", ["HogeComponent"]);
// acter
GrimoireInterface.registerNode("hoge", [HogeComponent]);
より安全にregisterできます。
TemplateNode/Component追加
ノードの構造を再利用したりコンポーネントとして利用したいときに便利なノードが追加されました。
<template src="template.goml"/>
このノードは自身を指定されたgoml
で置き換えたのとほとんど同じように振る舞います。
その他
特に知る必要もないけど知っておくと役に立つかもしれないちょっとした変更。
メッセージレシーバのアクセス修飾子
コンポーネントのメッセージレシーバはprotected
に統一されました。(今まではpublic
だった)
GrimoireInterface.getRootNodeが存在しない場合nullを返す
今までは例外を投げていました。
MetaInfo
パッケージのメタ情報が参照できるようになりました。
index.ts
と同じ場所(root)にmetaInfo.ts
が生成されるようになります。
たとえばgrimoirejs-fundamental
の場合
import {
__NAMESPACE__, // "fundamental"
__NAME__, // "grimoirejs-fundamental"
__VERSION__ // "0.x.x"
} from "../metaInfo";
みたいな情報がとれます。