JavaScript
ポエム
フレームワーク

俺のフレームワークが、1205行で実装できる訳がない!

すみません

タイトルは釣りですが、釣られて下さってありがとうございます。

書いたもの

_(losand)._
$(dsand).$()

基底ライブラリ: _(losand)._

最初は、モナドそのものの実験的な実装だけをやりました。
そのうち、javascriptがとり得る最低限の圏に対しての自己関手ぐらいは実装したものにしようという意欲が湧きました。
前作、de.jsより、既存コンストラクタのprototypeを出来る限り拡張しないでも実装出来ないだろうか?
全て、_で繋いで文脈を理解させるのも限界がある等、色々失敗した後だから色々試しました。失敗も多かったです。
例えば、JSONを丸渡ししてオブジェクトの振る舞いを書ければ…
なども候補にありました。
losandそのものはstateモナドとして実装されているのですが、使う側のことを考えたらstate側を明示で呼び出すのは苦しい言い訳がある(要は使いづらい)ので、モノイドをかなり意識しました。
最後に ._ で閉じるまでは、すべての命令を |> で繋いだ表現として書くことも可能です。

<script src="https://cdn.jsdelivr.net/npm/losand@1.2.0/losand.js"></script>

で読み込み出来ます。
以下は例です。

//ex
_({a: 1})
.draw({b: 3})
.map(
  o => _(o)
  .vals
  ._
  .reduce((a, b) => a + b, 0)
)
._
// 4

_({a: 1, b: 3, c: 5})
.hold("a", "c")
._

_記号にサンドイッチされた計算機構と考えたので、
losand
になりました。
これが460行です

VDOM on Pure Javascript $(dsand).$()

上述、losandを使って凝集度を上げに上げて作った結果、745行のVDOMまでを賄うフレームワークを書きました。

まずは読み込み…

<script src="https://cdn.jsdelivr.net/npm/dsand@0.3.5/dsand.js"></script>

最初に、\$.dataに閲覧可能な状態(state)を書き込みます。
閲覧対象の指定は、各 Render(後述します。) の持つ、markメソッドに、$.dataの持つプロパティ名を入れてあげることで、指定した閲覧を可能にします。

閲覧は、RenderFunctionの持つlookで出来ます。

_($.data).draw({
  test: {
    state: "success on load at test state"
  }
});

次に、役割のための振る舞いを記述します。
この振る舞いは、あるHTMLエレメントで指定されたイベントが発火したときに、
そのエレメントが持つclass名をキーにして実行されるように出来ています。
引数に渡されるのは、eventオブジェクトです。
ここには、MVCで言うところの Mの持つドメインロジックを記述していきます。

_($.role).draw({
  doTest (e) {
    alert($(e).look.state);
    return "marked data loaded on .look"
  }
});

次に、見た目を変更する記述をします。
これも、HTMLエレメントで指定されたイベントが発火したときに、
そのエレメントが持つclass名をキーにして実行されます。
第1引数はeventオブジェクトが渡りますが、
第2引数は、$.roleで行った振る舞いのreturn値が入ります。
生成されたエレメントの見た目をごっそり書き換えたい場合、
.seem が便利です。

ちなみに、packという名前の由来ですが、振る舞った後は、unpackされたという言語的概念に即してみました。

_($.pack).draw({
  doTest (e, d) {
    $(e).seem(d);
  }
});

いよいよレンダリングです。
各タグがそのままエレメントを返すためのgetメソッドとして機能しています。
\$.bodyはbodyタグを表し、.\$は基本的にappendを行います。

ちなみに、\$(Element).\$(undefined)なら、その要素をremoveします。

const myButton = button
.mark("test")
.class("doTest")
.$("load state data")

$.body.$(
  p.$(myButton)
);

745行ほどで、この実装が出来ています。
主なサポート対象はchromeで、phonegap を使ったSPAを素早く作れます。
AndroidアプリのwebViewで正常に動作するので、ネイティブっぽいSPAを作ることも可能です。
グローバルのgetメソッドに各タグの為のレンダーが当たっているのは、コンポーネントを実際に生成する場合は、グローバル領域を使わないようにして欲しいという気持ちがあります。

なお、formタグ内のname属性を持つElementに対してであれば、
.set({[name]: value})
で値の設定ができ
.get
で、オブジェクトが返ってきます。

返ってきたオブジェクトを

_(Object).json

とするだけで、JSON取れます(笑)

JSONStr.json._

でパースされて戻ってきますが、

JSONStr.json

で、losandに代入されたオブジェクトとして扱えます。
理由は…

_({a: 3}).json.json._

というstringifyしてparseするというところで明示をしたかったためです。

以上、お読みいただきありがとうございました。