Skip to content

Commit 9700925

Browse files
authored
Merge pull request #65 from johnnychen94/jc/properties
add card properties: author, date, julia
2 parents c5e14dd + 246a2e7 commit 9700925

File tree

18 files changed

+226
-30
lines changed

18 files changed

+226
-30
lines changed

Project.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ authors = ["Johnny Chen <[email protected]>"]
44
version = "0.2.3"
55

66
[deps]
7+
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
78
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
89
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
10+
HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3"
911
ImageCore = "a09fc81d-aa75-5fe9-8630-4744c3626534"
1012
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
1113
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
@@ -16,6 +18,7 @@ YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6"
1618
[compat]
1719
Documenter = "0.22, 0.23, 0.24, 0.25"
1820
FileIO = "1"
21+
HTTP = "0.6, 0.7, 0.8"
1922
ImageCore = "0.7, 0.8"
2023
JSON = "0.20, 0.21"
2124
Literate = "2"
@@ -25,12 +28,11 @@ YAML = "0.3, 0.4"
2528
julia = "1"
2629

2730
[extras]
28-
HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3"
2931
ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1"
3032
ImageShow = "4e3cecfd-b093-5904-9786-8bbb286a6a31"
3133
ReferenceTests = "324d217c-45ce-50fc-942e-d289b448e8cf"
3234
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
3335
TestImages = "5e47fb64-e119-507b-a336-dd2b206d9990"
3436

3537
[targets]
36-
test = ["HTTP", "ImageMagick", "ImageShow", "ReferenceTests", "Test", "TestImages"]
38+
test = ["ImageMagick", "ImageShow", "ReferenceTests", "Test", "TestImages"]

docs/quickstart/usage_example/basics/configure_card.md

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
title: Configure your card
33
cover: assets/logo.svg
44
id: configure_your_card
5+
author: Johnny Chen
6+
date: 2020-09-13
57
description: This demo show you how to pass additional meta info of card to DemoCards.jl
68
---
79

@@ -14,15 +16,26 @@ frontmatter:
1416
title: Configure your card
1517
cover: assets/democards.png
1618
id: configure_your_card
19+
author: Johnny Chen
20+
date: 2020-09-13
1721
description: This demo show you how to pass additional meta info of card to DemoCards.jl
1822

1923
---
2024
```
2125

22-
Of course, you have to make sure the `---` flag shows at the first line of the markdown file,
23-
otherwise DemoCards would just read them as normal contents.
26+
!!! tip
27+
All these YAML configs are optional. If specified, it has higher priority over the meta info
28+
extracted from the demo contents. For example, if you don't like the inferred demo title, then
29+
specify one explicitly in the YAML frontmatter.
2430

25-
There are two valid `cover` options:
31+
Of course, you have to make sure the `---` flag shows at the first line of the markdown file,
32+
otherwise DemoCards would just read them as normal contents.
2633

27-
* a local file specified by relative path to the current file, or,
28-
* an image file specified by http(s) URL (e.g, `https://johnnychen94.github.io/DemoCards.jl/dev/assets/logo.svg`)
34+
The rules are simple:
35+
36+
* `author` and `date` badges will only be added if you configure them.
37+
* If there are multiple authors, they could be splitted by semicolon `;`. For example, `author:
38+
Jane Doe; John Roe` would generate two author badges.
39+
* there are two valid `cover` options:
40+
* a local file specified by relative path to the current file, or,
41+
* an image file specified by http(s) URL.

docs/quickstart/usage_example/julia_demos/1.julia_demo.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
# ---
66
# title: Write your demo in julia
77
# cover: assets/literate.png
8+
# date: 2020-09-13
9+
# author: Johnny Chen
10+
# julia: 1.0.1
811
# description: This demo shows you how to write your demo in julia
912
# ---
1013

@@ -37,10 +40,18 @@ img = testimage("lena")
3740
# # title: <title>
3841
# # cover: <cover>
3942
# # id: <id>
43+
# # date: 2020-09-13
44+
# # author: Johnny Chen
45+
# # julia: 1.3
4046
# # description: <description>
4147
# # ---
4248
# ```
4349

50+
# Julia format demos accept one extra frontmatter config: `julia`. It allows you to specify the
51+
# compat version of your demo. `DemoCards` would 1) throw a warning if your demos are generated
52+
# using a lower version of Julia 2) insert a compat version badge. The warning is something like
53+
# "The running Julia version `1.0.5` is older than the declared compatible version `1.3.0`."
54+
4455
# You should be careful about the leading whitespaces after the first #. Frontmatter as weird as the
4556
# following is not guaranteed to work and it is very likely to hit a YAML parsing error.
4657

src/DemoCards.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
module DemoCards
22

33
import Base: basename
4+
using Dates
45
using Mustache
56
using Literate
67
using ImageCore
78
using FileIO, JSON, YAML
89
using Suppressor # suppress log generated by 3rd party tools, e.g., Literate
10+
import HTTP
911
using Documenter
1012

13+
const JULIA_COMPAT = let regex=r"julia\s*=\s*\"([\d\.]*)\""
14+
lines = filter(readlines(normpath(@__DIR__, "..", "Project.toml"))) do line
15+
occursin(regex, line)
16+
end
17+
VersionNumber(match(regex, lines[1]).captures[1])
18+
end
1119
const config_filename = "config.json"
1220
const template_filename = "index.md"
1321
# directly copy these folders without processing

src/types/card.jl

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ function load_config(card::T, key) where T <: AbstractDemoCard
5151
config = parse(card)
5252

5353
if key == "cover"
54-
root = dirname(card.path)
5554
haskey(config, key) || return nothing
5655

5756
cover_path = config[key]
@@ -68,11 +67,35 @@ function load_config(card::T, key) where T <: AbstractDemoCard
6867
return get(config, key, card.title)
6968
elseif key == "hidden"
7069
return get(config, key, false)
70+
elseif key == "author"
71+
return get(config, key, "")
72+
elseif key == "date"
73+
return DateTime(get(config, key, DateTime(0)))
74+
elseif key == "julia"
75+
version = get(config, key, JULIA_COMPAT)
76+
return version isa VersionNumber ? version : VersionNumber(string(version))
7177
else
7278
throw(ArgumentError("Unrecognized key $(key) for $(T)"))
7379
end
7480
end
7581

82+
function make_badges(card::AbstractDemoCard)
83+
badges = []
84+
if !isempty(card.author)
85+
for author in split(card.author, ';')
86+
# TODO: also split on "and"
87+
isempty(author) && continue
88+
author_str = HTTP.escapeuri(strip(author))
89+
push!(badges, "![Author](https://img.shields.io/badge/Author-$(author_str)-blue)")
90+
end
91+
end
92+
if card.date != DateTime(0)
93+
date_str = string(round(Int, datetime2unix(card.date)))
94+
push!(badges, "![Update time](https://img.shields.io/date/$(date_str))")
95+
end
96+
isempty(badges) ? "" : join(badges, " ")
97+
end
98+
7699

77100
### load concrete implementations
78101

src/types/julia.jl

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ Besides `path`, this struct has some other fields:
2727
* `cover`: path to the cover image
2828
* `id`: cross-reference id
2929
* `title`: one-line description of the demo card
30+
* `author`: author(s) of this demo.
31+
* `date`: the update date of this demo.
3032
* `description`: multi-line description of the demo card
33+
* `julia`: Julia version compatibility
34+
* `hidden`: whether this card is shown in the generated index page
3135
3236
# Configuration
3337
@@ -38,6 +42,9 @@ Supported items are:
3842
* `description`: a multi-line description to this file, will be displayed when the demo card is hovered. By default it uses `title`.
3943
* `id`: specify the `id` tag for cross-references. By default it's infered from the filename, e.g., `simple_demo` from `simple demo.md`.
4044
* `title`: one-line description to this file, will be displayed under the cover image. By default, it's the name of the file (without extension).
45+
* `author`: author name. If there are multiple authors, split them with semicolon `;`.
46+
* `date`: any string contents that can be passed to `Dates.DateTime`. For example, `2020-09-13`.
47+
* `julia`: Julia version compatibility. Any string that can be converted to `VersionNumber`
4148
* `hidden`: whether this card is shown in the layout of index page. The default value is `false`.
4249
4350
An example of the front matter (note the leading `#`):
@@ -47,7 +54,11 @@ An example of the front matter (note the leading `#`):
4754
# title: passing extra information
4855
# cover: cover.png
4956
# id: non_ambiguious_id
50-
# description: this demo shows how you can pass extra demo information to DemoCards package.
57+
# author: Jane Doe; John Roe
58+
# date: 2020-01-31
59+
# description: this demo shows how you can pass extra demo information to DemoCards package. All these are optional.
60+
# julia: 1.0
61+
# hidden: false
5162
# ---
5263
```
5364
@@ -59,15 +70,21 @@ mutable struct JuliaDemoCard <: AbstractDemoCard
5970
id::String
6071
title::String
6172
description::String
73+
author::String
74+
date::DateTime
75+
julia::VersionNumber
6276
hidden::Bool
6377
end
6478

6579
function JuliaDemoCard(path::String)::JuliaDemoCard
6680
# first consturct an incomplete democard, and then load the config
67-
card = JuliaDemoCard(path, "", "", "", "", false)
81+
card = JuliaDemoCard(path, "", "", "", "", "", DateTime(0), JULIA_COMPAT, false)
6882

6983
card.cover = load_config(card, "cover")
7084
card.title = load_config(card, "title")
85+
card.date = load_config(card, "date")
86+
card.author = load_config(card, "author")
87+
card.julia = load_config(card, "julia")
7188
# default id requires a title
7289
card.id = load_config(card, "id")
7390
# default description requires a title
@@ -106,6 +123,11 @@ function save_democards(card_dir::String,
106123
nb_path = joinpath(card_dir, "$(cardname).ipynb")
107124
src_path = joinpath(card_dir, "$(cardname).jl")
108125

126+
if VERSION < card.julia
127+
# It may work, it may not work; I hope it would work.
128+
@warn "The running Julia version `$(VERSION)` is older than the declared compatible version `$(card.julia)`. You might need to upgrade your Julia."
129+
end
130+
109131
# 1. generating assets
110132
cp(card.path, src_path; force=true)
111133
cd(card_dir) do
@@ -141,21 +163,8 @@ function save_democards(card_dir::String,
141163
isempty(strip(src_header)) || (src_header *= "\n\n")
142164

143165
# insert header badge
144-
header = "#md # [![]($download_badge)]($(cardname).jl)"
145-
if !isempty(nbviewer_root_url)
146-
# reach here in CI environment
147-
148-
# remove root/src prefix
149-
nbviewer_folder = relpath(card_dir, "$project_dir/$src")
150-
nbviewer_url = "$(nbviewer_root_url)/$(nbviewer_folder)/$(cardname).ipynb"
151-
else
152-
# local build
153-
nbviewer_url = "$(cardname).ipynb"
154-
end
155-
header *= " [![]($nbviewer_badge)]($nbviewer_url)"
156-
header *= "\n\n"
157-
158-
write(src_path, header, body)
166+
badges = make_badges(card; src=src, card_dir=card_dir, nbviewer_root_url=nbviewer_root_url, project_dir=project_dir) * "\n\n"
167+
write(src_path, badges, body)
159168

160169
# 2. notebook
161170
try
@@ -185,3 +194,28 @@ function save_democards(card_dir::String,
185194
write(src_path, src_header, read(joinpath(tmpdir, basename(src_path)), String))
186195
end
187196
end
197+
198+
function make_badges(card::JuliaDemoCard; src, card_dir, nbviewer_root_url, project_dir)
199+
cardname = splitext(basename(card.path))[1]
200+
badges = ["#md #"]
201+
push!(badges, "[![Source code]($download_badge)]($(cardname).jl)")
202+
203+
if !isempty(nbviewer_root_url)
204+
# Note: this is only reachable in CI environment
205+
nbviewer_folder = normpath(relpath(card_dir, "$project_dir/$src"))
206+
nbviewer_url = replace("$(nbviewer_root_url)/$(nbviewer_folder)/$(cardname).ipynb", Base.Filesystem.path_separator=>'/')
207+
else
208+
nbviewer_url = "$(cardname).ipynb"
209+
end
210+
push!(badges, "[![notebook]($nbviewer_badge)]($nbviewer_url)")
211+
if card.julia != JULIA_COMPAT
212+
# It might be over verbose to insert a compat badge for every julia card, only add one for
213+
# cards that users should care about
214+
# Question: Is this too conservative?
215+
push!(badges, "![compat](https://img.shields.io/badge/julia-$(card.julia)-blue.svg)")
216+
end
217+
218+
push!(badges, invoke(make_badges, Tuple{AbstractDemoCard}, card))
219+
220+
join(badges, " ")
221+
end

src/types/markdown.jl

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ Besides `path`, this struct has some other fields:
2424
* `cover`: path to the cover image
2525
* `id`: cross-reference id
2626
* `title`: one-line description of the demo card
27+
* `author`: author(s) of this demo.
28+
* `date`: the update date of this demo.
2729
* `description`: multi-line description of the demo card
30+
* `hidden`: whether this card is shown in the generated index page
2831
2932
# Configuration
3033
@@ -35,6 +38,8 @@ Supported items are:
3538
* `description`: a multi-line description to this file, will be displayed when the demo card is hovered. By default it uses `title`.
3639
* `id`: specify the `id` tag for cross-references. By default it's infered from the filename, e.g., `simple_demo` from `simple demo.md`.
3740
* `title`: one-line description to this file, will be displayed under the cover image. By default, it's the name of the file (without extension).
41+
* `author`: author name. If there are multiple authors, split them with semicolon `;`.
42+
* `date`: any string contents that can be passed to `Dates.DateTime`. For example, `2020-09-13`.
3843
* `hidden`: whether this card is shown in the layout of index page. The default value is `false`.
3944
4045
An example of the front matter:
@@ -44,7 +49,10 @@ An example of the front matter:
4449
title: passing extra information
4550
cover: cover.png
4651
id: non_ambiguious_id
47-
description: this demo shows how you can pass extra demo information to DemoCards package.
52+
author: Jane Doe; John Roe
53+
date: 2020-01-31
54+
description: this demo shows how you can pass extra demo information to DemoCards package. All these are optional.
55+
hidden: false
4856
---
4957
```
5058
@@ -56,15 +64,25 @@ mutable struct MarkdownDemoCard <: AbstractDemoCard
5664
id::String
5765
title::String
5866
description::String
67+
author::String
68+
date::DateTime
5969
hidden::Bool
6070
end
6171

6272
function MarkdownDemoCard(path::String)::MarkdownDemoCard
6373
# first consturct an incomplete democard, and then load the config
64-
card = MarkdownDemoCard(path, "", "", "", "", false)
74+
card = MarkdownDemoCard(path, "", "", "", "", "", DateTime(0), false)
6575

6676
card.cover = load_config(card, "cover")
6777
card.title = load_config(card, "title")
78+
card.date = load_config(card, "date")
79+
card.author = load_config(card, "author")
80+
81+
# Unlike JuliaDemoCard, Markdown card doesn't accept `julia` compat field. This is because we
82+
# generally don't know the markdown processing backend. It might be Documenter, but who knows.
83+
# More generally, any badges can just be manually added by demo writter, if they want.
84+
# `date` and `author` fields are added just for convinience.
85+
6886
# default id requires a title
6987
card.id = load_config(card, "id")
7088
# default description requires a title
@@ -97,6 +115,7 @@ function save_democards(card_dir::String,
97115
need_header = !haskey(config, "title")
98116
# @ref syntax: https://juliadocs.github.io/Documenter.jl/stable/man/syntax/#@ref-link-1
99117
header = need_header ? "# [$(card.title)](@id $(card.id))\n" : "\n"
118+
100119
footer = credit ? markdown_footer : "\n"
101-
write(markdown_path, header, body, footer)
120+
write(markdown_path, header, make_badges(card)*"\n\n", body, footer)
102121
end

src/utils.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,10 @@ function parse(T::Val, card::AbstractDemoCard)
197197
end
198198

199199
if haskey(config, "cover")
200-
config["cover"] = replace(config["cover"],
201-
r"[/\\]" => Base.Filesystem.path_separator) # windows compatibility
200+
if !is_remote_url(config["cover"])
201+
config["cover"] = replace(config["cover"],
202+
r"[/\\]" => Base.Filesystem.path_separator) # windows compatibility
203+
end
202204
end
203205

204206
return config

test/assets/card/julia/title_7.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
#---
22
#title: Custom Title
33
#id: custom_id
4+
#author: Jane Doe; John Roe
5+
#date: 2020-01-31
6+
#julia: 1.2.3
7+
#cover: https://juliaimages.org/latest/assets/logo.png
48
#---
59

610
# This is the content

test/assets/card/julia/version_1.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#---
2+
#julia: 1.2.3
3+
#---

0 commit comments

Comments
 (0)