LoginSignup
10
2

Elixir OSSハック②【Livebook②】:Livebookコードブロックの実行付近を特定し、改造

Last updated at Posted at 2023-12-23

この記事は、Elixir Advent Calendar 2023 シリーズ12 の20日目です


piacere です、ご覧いただいてありがとございます :bow:

今回も、前回に引き続き、下記の追体験 … つまり「Livebookの改造」をするコラムで、今回は、Elixirコードを実行できる「Livebookコードブロック」についてハックしていきます

みんなでコードを眺めて、震えて、納涼するイベント、LiveViewJP#21「Livebookコードを眺めてみんなで震えて納涼する会」 のコラム版です

ちな、私もマトモにLivebookコードを読んだことが無かったので、会が成立しない位、グダグダになったらゴメンナサイ … と予め謝った上で開催しました

結果的には、新たなLiveViewデバッグ機能も使い倒す、ステキなElixir printfデバッグ(正確にはIO.inspectだがw)のシェア会になりましたので、その一端をコラムでも共有します 😋
あと、このコラムが、面白かったり、役に立ったら、image.png をお願いします :bow:

Elixirコードを実行できる「Livebookコードブロック」

実は、Elixir標準モジュールの仕様を知っていると、ここはクイックハックできます

Code モジュールです
image.png

Code モジュールには、下記のようなElixirコードを実行し、その結果を返す関数があるので、これで当たりを付けていきます

  • Code.eval_file
  • Code.eval_string
  • eval_quoted
  • eval_quoted_with_env

Code.eval_file はハズレのようです
image.png

Code.eval_string もハズレです
image.png

お、eval_quoted_with_env 付近が何か匂います … 関数も eval ですし
image.png

printfデバッグを仕掛けて、合ってるか確認してみましょう

lib/livebook/runtime/evaluator.ex

  defp eval(:elixir, code, binding, env) do
+IO.puts "=========== eval ==========="
+IO.inspect code
+IO.puts "=========== eval ==========="
    {{result, extra_diagnostics}, diagnostics} =
      Code.with_diagnostics([log: true], fn ->
        try do

Livebookからコード実行してみると … ビンゴッ!!
image.png

Livebookのこの箇所に IO.putsIO.inspect を仕掛けると、Livebook上で表示されるのですね :yum:

Livebookコードブロックの情報を取得する

コードブロックの実行部分が特定できたので、何か改造を施してみましょう

その前に、このコード実行評価でどのような値を返却しているのか見てみます

lib/livebook/runtime/evaluator.ex

  defp eval(:elixir, code, binding, env) do

        |> case do
          {:ok, value, binding, env} ->
+IO.puts "=========== eval ==========="
+IO.inspect value
+IO.inspect binding
+IO.inspect env
+IO.puts "=========== eval ==========="
            {{:ok, value, binding, env}, []}

なるほど、実行結果と、謎の binding、そしてコンパイル時の実行環境情報を保持する Macro.Env が返されているようです
image.png

Macro.Env は、下記の通りです
image.png

env から、下記のようにコードのロケーション情報を拾ってみましょう

lib/livebook/runtime/evaluator.ex

  defp eval(:elixir, code, binding, env) do

        |> case do
          {:ok, value, binding, env} ->
IO.puts "=========== eval ==========="
IO.inspect value
IO.inspect binding
+IO.inspect env |> Macro.Env.location
IO.puts "=========== eval ==========="
            {{:ok, value, binding, env}, []}

セルの情報が拾えそうです
image.png

value がリストのときは、セル情報を載せて、返してみましょう

lib/livebook/runtime/evaluator.ex

  defp eval(:elixir, code, binding, env) do

        |> case do
          {:ok, value, binding, env} ->
-IO.puts "=========== eval ==========="
-IO.inspect value
-IO.inspect binding
-IO.inspect env |> Macro.Env.location
-IO.puts "=========== eval ==========="
-           {{:ok, value, binding, env}, []}
+           case value do
+             value when is_list(value) -> {{:ok, value ++ "location: #{Keyword.get(env |> Macro.Env.location, :file)}", binding, env}, []}
+             _ -> {{:ok, value, binding, env}, []}
+           end

実行結果に、セル情報を入れることが出来ました
image.png

終わりに

Livebookコードブロックのハックをしましたが、簡単でしたよね?

Elixirの知識があれば、OSSをハックしやすいということが伝われば幸いです

次回は、Livebookをノーコードたらしめる重要機能である「SmartCell」付近を攻略していきます

p.s.このコラムが、面白かったり、役に立ったら…

image.png にて、どうぞ応援よろしくお願いします :bow:

10
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
10
2