Stream: helpdesk (published)

Topic: Include pluto file and collect cell results


view this post on Zulip Mason Protter (Oct 06 2021 at 21:34):

Someone had a question on Slack today that I had some fun with, so I figured I'd copy my answer here for posterity. Suppose I have some pluto file like

### A Pluto.jl notebook ###
# v0.16.1

using Markdown
using InteractiveUtils

# ╔═╡ f39d12e8-26eb-11ec-0e1d-5b291ffb6ca5
x = rand(10)

# ╔═╡ bafb4a21-d800-4db5-8d00-3e85a817a635
y = (x .^ 2) .- x'

# ╔═╡ ddccda44-7343-4ec4-98d7-bbd9c398806a
1 .+ x

# ╔═╡ Cell order:
# ╠═f39d12e8-26eb-11ec-0e1d-5b291ffb6ca5
# ╠═bafb4a21-d800-4db5-8d00-3e85a817a635
# ╠═ddccda44-7343-4ec4-98d7-bbd9c398806a

The question is, how can I run this as a script but retain the 'cell strcture' so that one can ask what the output of a given cell was. The idea I came up with was to basically take this file as a string, and then split the string using # ╔═╡ as a delimiter (and throw away the following UUID). That gives me the cell structure, then I just need to assign each cell to a dictionary, put it all in a :block and then eval it.

function collect_cells(s)
    cells = split(s, "# ╔═╡")
    final_expr = Expr(:block, :(Out = Dict{Int, Any}()))
    for (i, cell)  enumerate(cells)
        cell = cell |> IOBuffer |> eachline |> collect |> x -> join(x[2:end], "\n")
        ex = :(Out[$i] = $(Meta.parse("begin\n"*cell*"\nend")))
        push!(final_expr.args, ex)
    end
    final_expr
end

function plutoinclude(f::String#=::filename=#)
    ex = collect_cells(read(f, String))
    eval(ex)
end

e.g. in this case,

s = """
### A Pluto.jl notebook ###
# v0.16.1

using Markdown
using InteractiveUtils

# ╔═╡ f39d12e8-26eb-11ec-0e1d-5b291ffb6ca5
x = rand(10)

# ╔═╡ bafb4a21-d800-4db5-8d00-3e85a817a635
y = (x .^ 2) .- x'

# ╔═╡ ddccda44-7343-4ec4-98d7-bbd9c398806a
1 .+ x

# ╔═╡ Cell order:
# ╠═f39d12e8-26eb-11ec-0e1d-5b291ffb6ca5
# ╠═bafb4a21-d800-4db5-8d00-3e85a817a635
# ╠═ddccda44-7343-4ec4-98d7-bbd9c398806a
""";

collect_cells(s)

#+RESULTS:
quote
    Out = Dict{Int, Any}()
    Out[1] = begin
            #= none:4 =#
            using Markdown
            #= none:5 =#
            using InteractiveUtils
        end
    Out[2] = begin
            #= none:2 =#
            x = rand(10)
        end
    Out[3] = begin
            #= none:2 =#
            y = x .^ 2 .- x'
        end
    Out[4] = begin
            #= none:2 =#
            1 .+ x
        end
    Out[5] = begin
            #= none:5 =#
        end
end

Last updated: Oct 02 2023 at 04:34 UTC