PROBLEM

  • クロスプラットフォーム用のクライアントソフトをつくるにあたり
    • 重たいフレームワークが多い
    • 汎用的な言語をつかってるものが多く、そのためライブラリー等の依存関係が多くなりやすい

-

SOLUTION

というわけで、年明け見つけたRedがシンプルだったのでつかってみた。題材は以前つくったEmacsライブラリ「esa.el」の移植だ。

https://github.com/nabinno/esa.red

やったこと

エディター

構文がすなおなので特にエディタは関係なさそうだったけど、慣れ親しんでるEmacsに「Skrylar/red.el」を適用した。その際、 red-font-lock-keywordsred-indent-line に足りない箇所があったのでオーバーライドした

糖衣構文の適用

RedはコマンドラインREPLがつかえるので、doc.red-lang.orgとred-by-example.orgをみながらひとつひとつ挙動を確認した。その中でどうしても慣れない表現が2つあったので糖衣構文を実装(nabinno/red-elixir)。

1. compose

ブロック内の変数を評価しブロックとして返す関数 compose は、VIDのフェイス更新によくつかわれる。HTML/JavaScripでいうところDOM更新にあたるものといえばわかるだろう。頻繁に「 compose [foo (bar)] 」のような表現がつづくとほかの変数や関数とまざり可読性がおちるので、Elixirのシジルを参考に compose 関数を省略した。こんな感じ。

;-- before
compose [foo (bar)]

;-- after
~c[foo (bar)]

2. 関数の入れ子

素のRedはイテレーター構文なので、関数の入れ子による可読性低下をおさえるため変数定義をよくつかう。個人的には変数は意味のあるものだけ使いたい派なので、パイプを導入した。といっても、フロントエンドの場合、データ加工はあまりやらないのでつかうケースはほぼなかった。あってもこのくらい。

;-- before
rejoin collect [
    foreach d data [
        keep rejoin [d "  "]
    ]
]

;-- after
data .[
    |> Series/map 'd [rejoin [d "  "]]
    |> rejoin
]

タスクランナーの用意

今回は上で実装したライブラリ「red-elixir」のほかにHTTPリクエスト・JSONパーサーライブラリをつかっている。ライブラリパッケージはインストールはgit submodulesでいいが、呼び出しも考えると実装が冗長的になるのでパッケージ管理とタスクランナーをあわせて用意した(nabinno/hotnabinno/mods)。

タスクランナーインストール後、パッケージのインストールから呼び出しまでの流れ

RedはGoとおなじくワンバイナリーなので、wgetやcurlだけでインストールが完了する。

> mkdir -p ~/.local/bin
> wget https://github.com/nabinno/hot/releases/download/0.0.3/hot-linux -O ~/.local/bin/hot
> chmod 744 ~/.local/bin/hot

パッケージ管理はElixirのmixを参考にタスクランナー管理ファイル内に定義する。

> hot cmd/install https://raw.githubusercontent.com/nabinno/mods/master/mods.red
> cat hots.red
Red []

hots: context [
    mods: [
        red-elixir #(init: %init.red git: https://github.com/nabinno/red-elixir)
        json #(init: %json.red git: https://github.com/rebolek/red-tools)
        http-tools #(init: %http-tools.red git: https://github.com/rebolek/red-tools)
    ]
]
> hot mods/get

ビルド時は #include をつかうのでパッケージ呼び出し機能はつかえないが、コマンドラインREPLで挙動確認している際は do/args %require をつかう。

> red
>> do/args %require [red-elixir]
>> 1 .. 10 .[
    |> Series/map 'i [i * 2]
    |> Series/map 'i [i + 1]
]
== [3 5 7 9 11 13 15 17 19 21]

-

WRAPUP

Redは既存のフレームワークと比べるとまだまだ機能不足感がぬぐえないが、それを補えるだけの表現力をもっていた。

-

以上 :red_circle: