Skip to content

Commit

Permalink
Assume less in @sc and @sco (#137)
Browse files Browse the repository at this point in the history
  • Loading branch information
rikhuijzer authored Jun 29, 2021
1 parent f332715 commit e050a1e
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 52 deletions.
2 changes: 1 addition & 1 deletion docs/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"about",
"getting-started",
"demo",
"references"
"references",
]
output_filename = "books"

Expand Down
62 changes: 41 additions & 21 deletions docs/contents/demo.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ In the background, `gen` passes the methods through `convert_output(expr::String
To show that a DataFrame is converted to a Markdown table, we define a method

```jl
@sc(M.my_table)
@sc(M.my_table())
```

and add its output to the Markdown file with
Expand Down Expand Up @@ -116,14 +116,14 @@ Refer to @tbl:my_table with
To show multiple objects, pass a `Vector`:

```jl
@sco(M.multiple_df_vector)
@sco(M.multiple_df_vector())
```

When you want to control where the various objects are saved, use `Options`.
This way, you can pass a informative path with plots for which informative captions, cross-reference labels and image names can be determined.

```jl
@sco(M.multiple_df_example)
@sco(M.multiple_df_example())
```

To define the labels and/or captions manually, see @sec:labels-captions.
Expand Down Expand Up @@ -187,7 +187,7 @@ Possibly, the reasoning is that R Markdown needs to convert the output directly,
To set labels and captions, wrap your object in `Options`:

```jl
@sco(M.options_example)
@sco(M.options_example())
```

which can be referred to with
Expand All @@ -208,48 +208,46 @@ M.options_example_doctests()

So, instead of passing a string which `Books.jl` will evaluate, `Books.jl` can also obtain the code for a method directly.
(Thanks to `CodeTracking.@code_string`.)
For example, we can define the following method:
For example, inside our package, we can define the following method:

<pre>
```jl
M.my_data()
@sc(M.my_data())
```
</pre>

To show code and output (sco), use the `@sco` macro.
To show code and output (sco) for this method, use the `@sco` macro.
This macro is exported by Books, so ensure that you have `using Books` in your package.

<pre>
```jl
@sco(M.my_data)
@sco(M.my_data())
```
</pre>

This gives

```jl
@sco(M.my_data)
@sco(M.my_data())
```

To only show the source code, use `@sc`:

<pre>
```jl
@sc(M.my_data)
@sc(M.my_data())
```
</pre>

resulting in

```jl
@sc(M.my_data)
@sc(M.my_data())
```

Since we're using methods as code blocks, we can use the code shown in one code block in another.
For example, to determine the mean of column A:

```jl
@sco(M.my_data_mean)
@sco(M.my_data_mean())
```

Or, we can show the output inline, namely `jl M.my_data_mean()`, by using
Expand All @@ -258,6 +256,28 @@ Or, we can show the output inline, namely `jl M.my_data_mean()`, by using
`jl M.my_data_mean()`
```

It is also possible to show methods with parameters.

<pre>
```jl
@sc(M.hello(""))
```
</pre>

```jl
@sc(M.hello(""))
```

```jl
sco("""
M.hello("World")
""")
```

Here, the `M` can be a bit confusing.
If this is a problem, you can export the method `hello` to avoid it.
If you are really sure, you can export all symbols in your module with something like [this](https://discourse.julialang.org/t/exportall/4970/16).

## Plots {#sec:plots}

An AlgebraOfGraphics plot is shown below in @fig:example_plot.
Expand All @@ -266,7 +286,7 @@ This is actually a bit tricky, because we want to show vector graphics (SVG) on
Therefore, portable network graphics (PNG) images are also created and passed to LaTeX when building a PDF.

```jl
@sco(M.example_plot)
@sco(M.example_plot())
```

If the output is a string instead of the output you expected, then check whether you load the related packages in time.
Expand All @@ -275,7 +295,7 @@ For example, for this plot, you need to load AlgebraOfGraphics.jl together with
For multiple images, use `Options.(objects, paths)`:

```jl
@sc(M.multiple_example_plots)
@sc(M.multiple_example_plots())
```

Resulting in @fig:example_plot_2 and @fig:example_plot_3:
Expand All @@ -287,13 +307,13 @@ M.multiple_example_plots()
For changing the size, use `axis` from AlgebraOfGraphics:

```jl
@sco(M.image_options_plot)
@sco(M.image_options_plot())
```

And, for adjusting the caption, use `Options`:

```jl
@sco(M.combined_options_plot)
@sco(M.combined_options_plot())
```

or the caption can be specified in the Markdown file:
Expand All @@ -311,13 +331,13 @@ Options(M.image_options_plot(); caption="Label specified in Markdown.")
### Plots {#sec:plotsjl}

```jl
@sco(M.plotsjl)
@sco(M.plotsjl())
```

### Makie {#sec:makie}

```jl
@sco(M.makiejl)
@sco(M.makiejl())
```

## Other notes
Expand All @@ -333,7 +353,7 @@ So, if the package that you're using has defined a new `show` method, this will
For example, for `MCMCChains`,

```jl
@sco(M.chain)
@sco(M.chain())
```

### Note box
Expand Down
2 changes: 2 additions & 0 deletions docs/src/includes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ function my_data_mean()
Statistics.mean(df.A)
end

hello(name) = "Hello, $name"

options_example() = Options(DataFrame(A = [1], B = [2], C = [3]);
caption="My DataFrame.", label="foo")

Expand Down
48 changes: 21 additions & 27 deletions src/showcode.jl
Original file line number Diff line number Diff line change
@@ -1,32 +1,44 @@
"""
remove_hide_comment(expr::AbstractString)
Remove lines which end with `# hide`.
"""
function remove_hide_comment(expr::AbstractString)
expr = string(expr)::String
lines = split(expr, '\n')
lines = rstrip.(lines)
lines = filter(!endswith("# hide"), lines)
expr = join(lines, '\n')
end

"""
@sc(f)
Show code for `f()`; to also show output, use [`@sco`](@ref).
See the documentation or tests for examples.
Show code for function `f`; to also show output, use [`@sco`](@ref).
"""
macro sc(f)
println("Obtaining source code for $f()")
println("Obtaining source code for $f")
esc(quote
s = Books.CodeTracking.@code_string $(f)()
code_block(s)
s = Books.CodeTracking.@code_string $(f)
s = Books.remove_hide_comment(s)
Books.code_block(s)
end)
end

"""
CodeAndFunction(code::AbstractString, f::Function)
CodeAndFunction(code::AbstractString, f)
This struct is used by [`@sco`](@ref).
"""
struct CodeAndFunction
code::AbstractString
f::Function
f::Any
end

"""
@sco(f)
Show code and output for `f()`; to show only code, use [`@sc`](@ref).
See the documentation or tests for examples.
"""
macro sco(f)
esc(quote
Expand All @@ -38,24 +50,14 @@ end
function convert_output(expr, path, cf::CodeAndFunction)
code = cf.code
f = cf.f
out = f()
out = f
out = convert_output(expr, path, out)
"""
$code
$out
"""
end


"""
CodeAndOutput(code::AbstractString)
This struct is used by [`sco`](@ref).
"""
struct CodeAndOutput
code::AbstractString
end

"""
eval_convert(expr::AbstractString)
Expand All @@ -69,14 +71,6 @@ function eval_convert(expr::AbstractString, M)
out = convert_output(expr, nothing, out)
end

function remove_hide_comment(expr::AbstractString)
expr = string(expr)::String
lines = split(expr, '\n')
lines = rstrip.(lines)
lines = filter(!endswith("# hide"), lines)
expr = join(lines, '\n')
end

"""
sco(expr::AbstractString; M=Main)
Expand Down
6 changes: 3 additions & 3 deletions test/showcode.jl
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
sc_test_function() = 1

@testset "showcode" begin
s = @sc sc_test_function
s = @sc(sc_test_function())
code = "sc_test_function() = 1"
@test s == code_block(code)

s = @sco sc_test_function
s = @sco(sc_test_function())
@test s.code == code
@test s.f == sc_test_function
@test s.f == 1

s = sco("x = 3")
@test s == "```\nx = 3\n```\n\n3\n"
Expand Down

0 comments on commit e050a1e

Please sign in to comment.