はじめに
私はElixirというプログラミング言語が好きです。
好きが高じて、autoracexというコミュニティを作りました。
海外からも参加してくださる方がいらっしゃいます。
そんな中のお一人、CamiloさんのElixirCL/wren-livebookを動かすことを楽しみます。
ElixirCL/wren-livebookは、wrenというプログラミング言語をLivebookの上でSmart cellを使って動かしちゃうというものです。
What is wren ?
私ははじめて知りました。
Wren is a small, fast, class-based concurrent scripting language
Think Smalltalk in a Lua-sized package with a dash of Erlang and wrapped up in a familiar, modern syntax.
なんだかスゴそう! 速そうです
System.print("Hello, world!")
class Wren {
flyTo(city) {
System.print("Flying to %(city)")
}
}
var adjectives = Fiber.new {
["small", "clean", "fast"].each {|word| Fiber.yield(word) }
}
while (!adjectives.isDone) System.print(adjectives.call())
動かしてみます
リポジトリのポイントは次の2点です。
- Livebookで動かせる
wren.livemd
があります -
bin/
以下にwren
の実行コマンド(バイナリ)が入っています(電池付き )
Dockerを使います。
git clone https://github.com/ElixirCL/wren-livebook.git
cd wren-livebook
docker run -p 8080:8080 -p 8081:8081 --pull always -u $(id -u):$(id -g) -v $(pwd):/data livebook/livebook
ブラウザで、迷わずアクセスしてください。
Visit: http://0.0.0.0:8080/?token=mymb5cototlctb5osmvxrybirqfqwkcd
※ token
の値は都度変わりますので、ターミナルに表示された通りの値を使ってください。
あとは、wren.livemdをOpenしてポチポチです。
@current @macos
を @current @unix
に変更するのみで、Dockerコンテナ上で動きます。
動画を撮っておきました。
気づいたこと
すべてを理解したわけではありません。
私の関心がおもむいたところを3点紹介しておきます。
- ①独自Smart Cell
- ②
#{Wren.path()} #{path}
- ③
trap "rm -f #{path}" 0 2 3 15
①独自Smart Cell
独自にSmart Cellが作れるようです。
詳しくはよくわかっていませんが、関係ありそうなところを https://raw.githubusercontent.com/ElixirCL/wren-livebook/main/wren.livemd から抜き出しておきます。
defmodule KinoGuide.WrenCell do
use Kino.JS
use Kino.JS.Live
use Kino.SmartCell, name: "Wren script"
@impl true
def init(_attrs, ctx) do
{:ok, ctx, editor: [attribute: "source", language: "javascript"]}
end
@impl true
def handle_connect(ctx) do
{:ok, %{}, ctx}
end
@impl true
def to_attrs(_ctx) do
%{}
end
@impl true
def to_source(attrs) do
quote do
path = Temp.path!()
File.write!(path, unquote(attrs["source"]))
System.shell(
"""
trap "rm -f #{path}" 0 2 3 15
#{Wren.path()} #{path}
""",
into: IO.stream(),
stderr_to_stdout: true
)
|> elem(1)
end
|> Kino.SmartCell.quoted_to_string()
end
asset "main.js" do
"""
export function init(ctx, payload) {
ctx.importCSS("main.css");
root.innerHTML = `
<div class="app">
Wren script
</div>
`;
}
"""
end
asset "main.css" do
"""
.app {
padding: 8px 16px;
border: solid 1px #cad5e0;
border-radius: 0.5rem 0.5rem 0 0;
border-bottom: none;
}
"""
end
end
Kino.SmartCell.register(KinoGuide.WrenCell)
<!-- livebook:{"attrs":{"source":"System.print(\"Hello, world!\")\n\nclass Wren {\n flyTo(city) {\n System.print(\"Flying to %(city)\")\n }\n}\n\nvar adjectives = Fiber.new {\n [\"small\", \"clean\", \"fast\"].each {|word| Fiber.yield(word) }\n}\n\nwhile (!adjectives.isDone) System.print(adjectives.call())"},"kind":"Elixir.KinoGuide.WrenCell","livebook_object":"smart_cell"} -->
<!-- livebook:{"attrs":{"source":"for (yPixel in 0...24) {\n var y = yPixel / 12 - 1\n for (xPixel in 0...80) {\n var x = xPixel / 30 - 2\n var x0 = x\n var y0 = y\n var iter = 0\n while (iter < 11 && x0 * x0 + y0 * y0 <= 4) {\n var x1 = (x0 * x0) - (y0 * y0) + x\n var y1 = 2 * x0 * y0 + y\n x0 = x1\n y0 = y1\n iter = iter + 1\n }\n System.write(\" .-:;+=xX$& \"[iter])\n }\n System.print(\"\")\n}"},"kind":"Elixir.KinoGuide.WrenCell","livebook_object":"smart_cell"} -->
②#{Wren.path()} #{path}
#{Wren.path()} #{path}
で、wrenというプログラミング言語を実行しています。
path
変数には、Temp.path/1で取得したテンポラリファイルのパスが入ります。
#{Wren.path()}
には実行環境にあわせたwrenの実行バイナリが入っています。
wren <file_path>
ということです。
Elixirに例えると、elixir sample.exs
みたいなものです。
③trap "rm -f #{path}" 0 2 3 15
#{Wren.path()} #{path}
の前にこれが書いてあります。
ファイルを消してそうだけど、実行する前に消しちゃうの?、0 2 3 15
って何? となりました。
trap 0 2 3 15
でググって最初にでたページです。
詳しくはこちらに譲るとして、要はwrenというプログラミング言語を実行したあとに、テンポラリファイルを消すということをやっています。
お行儀良いです。
心配りが行き届いています。
Niceです! Camiloさん!!!
おわりに
ElixirCL/wren-livebookを動かすことを楽しみました。
wrenというプログラミング言語を私ははじめて知りました。
Smart cellを独自に定義できることを知りました。
Camiloさん、ありがとうございます!