From de73c3d93dccce932143eaf9e0bfb37857ac7249 Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Tue, 2 Apr 2024 08:44:44 -0400 Subject: [PATCH 1/8] Show descriptions of data sets. (#146) Co-authored-by: jbrea --- src/dataset.jl | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/dataset.jl b/src/dataset.jl index 494fe00..cecd640 100644 --- a/src/dataset.jl +++ b/src/dataset.jl @@ -22,3 +22,19 @@ function dataset(package_name::AbstractString, dataset_name::AbstractString) end error("Unable to locate dataset file $rdaname or $csvname") end + +struct RDatasetsDescription + content::String +end +function description(package_name::AbstractString, dataset_name::AbstractString) + RDatasetsDescription(read(joinpath(@__DIR__, "..", "doc", + package_name, "$dataset_name.html"), String)) +end +function Base.show(io::IO, mime::MIME"text/plain", d::RDatasetsDescription) + nohtml = replace(d.content, Regex("<[^>]*>") => "") + s = replace(nohtml, Regex("\n\n+") => "\n\n") + show(io, mime, Docs.Text(s)) +end +function Base.show(io::IO, mime::MIME"text/html", d::RDatasetsDescription) + show(io, mime, HTML(d.content)) +end From f74c7f2514820bad602e51377b5ec21a819ce2a5 Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Tue, 2 Apr 2024 09:33:52 -0400 Subject: [PATCH 2/8] Add new dataset instructions (#147) * Streamline adding a new dataset * Add instructions to README for adding a new dataset * Add scripts to update the dataset metadata * Add update_doc method to only add a single dataset * Add HTML documentation generation to update_doc * Change update_doc to correctly round trip quotes in the metadata CSV * Sort datasets CSV * Allow datasets with a .RData extension as well as .rda --------- Co-authored-by: Frankie Robertson --- README.md | 17 +++ doc/datasets.csv | 60 +++++------ scripts/update_doc_all.sh | 4 + scripts/update_doc_one.sh | 4 + src/dataset.jl | 5 + src/update_doc.r | 211 +++++++++++++++++++++++--------------- 6 files changed, 189 insertions(+), 112 deletions(-) create mode 100755 scripts/update_doc_all.sh create mode 100755 scripts/update_doc_one.sh diff --git a/README.md b/README.md index ce0927b..2003f5b 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,23 @@ mlmRev|guImmun|Immunization in Guatemala|2159|13 mlmRev|guPrenat|Prenatal care in Guatemala|2449|15 mlmRev|star|Student Teacher Achievement Ratio (STAR) project data|26796|18 +# How to add datasets from a new package + +**Step 1: add the data from the package** + + 1. In your clone of this repo `mkdir -p data/$PKG` + 2. Go to CRAN + 3. Download the *source package* + 4. Extract one or more of the datasets in the `data` directory into the new directory + +**Step 2: add the metadata** + +Run the script: + + $ scripts/update_doc_one.sh $PKG + +Now it's ready for you to submit your pull request. + # Licensing and Intellectual Property Following Vincent's lead, we have assumed that all of the data sets in this repository can be made available under the GPL-3 license. If you know that one of the datasets released here should not be released publicly or if you know that a data set can only be released under a different license, please contact me so that I can remove the data set from this repository. diff --git a/doc/datasets.csv b/doc/datasets.csv index b8081be..8de3ed7 100644 --- a/doc/datasets.csv +++ b/doc/datasets.csv @@ -506,6 +506,36 @@ "datasets","volcano","Topographic Information on Auckland's Maunga Whau Volcano",87,61 "datasets","warpbreaks","The Number of Breaks in Yarn during Weaving",54,3 "datasets","women","Average Heights and Weights for American Women",15,2 +"gamair","aral","aral",488,4 +"gamair","aral.bnd","aral.bnd",107,3 +"gamair","bird","bird",25100,7 +"gamair","blowfly","blowfly",180,3 +"gamair","bone","bone",23,4 +"gamair","brain","brain",1567,6 +"gamair","cairo","cairo",3780,7 +"gamair","chicago","chicago",5114,8 +"gamair","chl","chl",13840,7 +"gamair","co2s","co2s",507,4 +"gamair","coast","coast",2091,3 +"gamair","engine","engine",19,3 +"gamair","gas","gas",60,804 +"gamair","harrier","harrier",37,3 +"gamair","hubble","hubble",24,4 +"gamair","ipo","ipo",156,7 +"gamair","mack","mack",634,17 +"gamair","mackp","mackp",1162,9 +"gamair","med","med",1476,25 +"gamair","meh","meh",1476,24 +"gamair","mpg","mpg",205,27 +"gamair","prostate","prostate",654,530 +"gamair","sitka","sitka",1027,6 +"gamair","sole","sole",1575,8 +"gamair","sperm.comp1","sperm.comp1",15,5 +"gamair","sperm.comp2","sperm.comp2",24,11 +"gamair","stomata","stomata",24,4 +"gamair","swer","swer",2196,10 +"gamair","wesdr","wesdr",669,5 +"gamair","wine","wine",47,8 "gap","PD","A study of Parkinson's disease and APOE, LRRK2, SNCA makers",825,22 "gap","aldh2","ALDH2 markers and Alcoholism",263,18 "gap","apoeapoc","APOE/APOC1 markers and Alzheimer's",353,8 @@ -732,33 +762,3 @@ "vcd","VonBort","Von Bortkiewicz Horse Kicks Data",280,4 "vcd","WeldonDice","Weldon's Dice Data",11,2 "vcd","WomenQueue","Women in Queues",11,2 -"gamair","aral.bnd","aral.bnd",107,3 -"gamair","aral","aral",488,4 -"gamair","bird","bird",25100,7 -"gamair","blowfly","blowfly",180,3 -"gamair","bone","bone",23,4 -"gamair","brain","brain",1567,6 -"gamair","cairo","cairo",3780,7 -"gamair","chicago","chicago",5114,8 -"gamair","chl","chl",13840,7 -"gamair","co2s","co2s",507,4 -"gamair","coast","coast",2091,3 -"gamair","engine","engine",19,3 -"gamair","gas","gas",60,804 -"gamair","harrier","harrier",37,3 -"gamair","hubble","hubble",24,4 -"gamair","ipo","ipo",156,7 -"gamair","mack","mack",634,17 -"gamair","mackp","mackp",1162,9 -"gamair","med","med",1476,25 -"gamair","meh","meh",1476,24 -"gamair","mpg","mpg",205,27 -"gamair","prostate","prostate",654,530 -"gamair","sitka","sitka",1027,6 -"gamair","sole","sole",1575,8 -"gamair","sperm.comp1","sperm.comp1",15,5 -"gamair","sperm.comp2","sperm.comp2",24,11 -"gamair","stomata","stomata",24,4 -"gamair","swer","swer",2196,10 -"gamair","wesdr","wesdr",669,5 -"gamair","wine","wine",47,8 diff --git a/scripts/update_doc_all.sh b/scripts/update_doc_all.sh new file mode 100755 index 0000000..0d8ff1a --- /dev/null +++ b/scripts/update_doc_all.sh @@ -0,0 +1,4 @@ +R --no-save < 0) @@ -114,7 +161,7 @@ update_docs <- function(pkg_dir) { } write <- function(df, fn) { - write.table(df, file = fn, sep = ",", qmethod = "escape", row.names = FALSE) + write.table(df, file = fn, sep = ",", qmethod = "double", row.names = FALSE) } clean <- function(df) { From eb81b482699bbc8ae44bc86ebaa8c1652eb6e1c3 Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Tue, 2 Apr 2024 09:21:36 -0400 Subject: [PATCH 3/8] Add a regex-based HTML to Markdown rewriter for docs This allows them to be displayed in a much better way in the REPL. --- Project.toml | 1 + src/RDatasets.jl | 1 + src/dataset.jl | 72 ++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 66 insertions(+), 8 deletions(-) diff --git a/Project.toml b/Project.toml index bac930b..6cd66d8 100644 --- a/Project.toml +++ b/Project.toml @@ -7,6 +7,7 @@ CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" CodecZlib = "944b1d66-785c-5afd-91f1-9de20f533193" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" +Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" RData = "df47a6cb-8c03-5eed-afd8-b6050d6c41da" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" diff --git a/src/RDatasets.jl b/src/RDatasets.jl index 69d94c2..6b8e133 100644 --- a/src/RDatasets.jl +++ b/src/RDatasets.jl @@ -3,6 +3,7 @@ module RDatasets @eval Base.Experimental.@optlevel 1 end + import Markdown using Reexport, RData, CSV, CodecZlib @reexport using DataFrames diff --git a/src/dataset.jl b/src/dataset.jl index bc86961..ca42a8e 100644 --- a/src/dataset.jl +++ b/src/dataset.jl @@ -28,18 +28,74 @@ function dataset(package_name::AbstractString, dataset_name::AbstractString) error("Unable to locate dataset file $rdaname or $csvname") end -struct RDatasetsDescription +""" + RDatasetDescription(content::String) + +A type to hold the content of a dataset description. + +The main purpose of its existence is to provide a way to display the content +differently in HTML and markdown contexts. +""" +struct RDatasetDescription content::String end + +function description_to_markdown(string) + html_header_regex = r"(?'content'[^<]+)<\/h\g'hnum'>" + function regexmatch2md(matched_string) + m = match(html_header_regex, matched_string) + if isnothing(m.captures[1]) || isnothing(m.captures[2]) + return matched_string + end + + hnum = parse(Int, m[:hnum]) + content = m[:content] + + return join(("\n", "#"^hnum, " ", content, "\n\n")) + end + title_matcher_regex = r"(?'content'[^<]+)<\/title>" + code_matcher_regex = r"<code>(?'content'[^<]+)<\/code>" + pre_matcher_regex = r"<pre>(?'content'[^<]+)<\/pre>" + emph_matcher_regex = r"<(?i)EM(?-i)>(?'content'[^<]+)<\/(?i)EM(?-i)>" + b_matcher_regex = r"<(?i)B(?-i)>(?'content'[^<]+)<\/(?i)B(?-i)>" + new_string = replace( + string, + html_header_regex => regexmatch2md, + title_matcher_regex => titlestr -> "# " * match(title_matcher_regex, titlestr)[:content], + code_matcher_regex => codestr -> "`" * match(code_matcher_regex, codestr)[:content] * "`", + pre_matcher_regex => prestr -> "\n```R\n" * match(pre_matcher_regex, prestr)[:content] * "\n```\n", + emph_matcher_regex => emphstr -> "*" * match(emph_matcher_regex, emphstr)[:content] * "*", + b_matcher_regex => bstr -> "**" * match(b_matcher_regex, bstr)[:content] * "**", + "–" => "-", + ) + nohtml = replace(new_string, Regex("<[^>]*>") => "") + return replace(nohtml, Regex("\n\n+") => "\n\n") +end +""" + description(package_name::AbstractString, dataset_name::AbstractString) + +Return a `RDatasetDescription` object containing the description of the dataset. + +Invoke this function in exactly the same way you would invoke `dataset` to get the dataset itself. +""" function description(package_name::AbstractString, dataset_name::AbstractString) - RDatasetsDescription(read(joinpath(@__DIR__, "..", "doc", + RDatasetDescription(read(joinpath(@__DIR__, "..", "doc", package_name, "$dataset_name.html"), String)) end -function Base.show(io::IO, mime::MIME"text/plain", d::RDatasetsDescription) - nohtml = replace(d.content, Regex("<[^>]*>") => "") - s = replace(nohtml, Regex("\n\n+") => "\n\n") - show(io, mime, Docs.Text(s)) + +function Base.show(io::IO, mime::MIME"text/plain", d::RDatasetDescription) + s = description_to_markdown(d.content) + # Here, we show a Markdown.jl object, which the REPL can render correctly + # as markdown, as it does in help-mode. + show(io, mime, Markdown.parse(s)) +end +function Base.show(io::IO, mime::MIME"text/markdown", d::RDatasetDescription) + s = description_to_markdown(d.content) + # Here, we return a Markdown string directly. This is useful for e.g. documentation, + # where we want to render the markdown as HTML. + show(io, mime, s) end -function Base.show(io::IO, mime::MIME"text/html", d::RDatasetsDescription) - show(io, mime, HTML(d.content)) +# This returns raw HTML documentation. +function Base.show(io::IO, mime::MIME"text/html", d::RDatasetDescription) + show(io, mime, Docs.HTML(d.content)) end From bda35b3a037e6ef973b971dbcd344f50bb948b22 Mon Sep 17 00:00:00 2001 From: Anshul Singhvi <anshulsinghvi@gmail.com> Date: Tue, 2 Apr 2024 09:36:20 -0400 Subject: [PATCH 4/8] More and better docs for `description` --- src/dataset.jl | 89 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 28 deletions(-) diff --git a/src/dataset.jl b/src/dataset.jl index ca42a8e..aede06a 100644 --- a/src/dataset.jl +++ b/src/dataset.jl @@ -28,6 +28,21 @@ function dataset(package_name::AbstractString, dataset_name::AbstractString) error("Unable to locate dataset file $rdaname or $csvname") end + +""" + description(package_name::AbstractString, dataset_name::AbstractString) + +Returns an `RDatasetDescription` object containing the description of the dataset. + +Invoke this function in exactly the same way you would invoke `dataset` to get the dataset itself. + +This object prints well in the REPL, and can also be shown as markdown or HTML. +""" +function description(package_name::AbstractString, dataset_name::AbstractString) + RDatasetDescription(read(joinpath(@__DIR__, "..", "doc", + package_name, "$dataset_name.html"), String)) +end + """ RDatasetDescription(content::String) @@ -35,11 +50,57 @@ A type to hold the content of a dataset description. The main purpose of its existence is to provide a way to display the content differently in HTML and markdown contexts. + +Invoked through [`RDatasets.description`](@ref). """ struct RDatasetDescription content::String end +function Base.show(io::IO, mime::MIME"text/plain", d::RDatasetDescription) + s = description_to_markdown(d.content) + # Here, we show a Markdown.jl object, which the REPL can render correctly + # as markdown, as it does in help-mode. + show(io, mime, Markdown.parse(s)) +end +function Base.show(io::IO, mime::MIME"text/markdown", d::RDatasetDescription) + s = description_to_markdown(d.content) + # Here, we return a Markdown string directly. This is useful for e.g. documentation, + # where we want to render the markdown as HTML. + show(io, mime, s) +end +# This returns raw HTML documentation. +function Base.show(io::IO, mime::MIME"text/html", d::RDatasetDescription) + show(io, mime, Docs.HTML(d.content)) +end + + +""" + description_to_markdown(string::String) + +Converts an HTML string to markdown. This function is written specifically +for HTML descriptions in RDatasets.jl, and so is a bit opinionated on what to +replace, etc. + +It replaces all known HTML tags using regex, and then removes all other HTML tags. + +## Behaviour + +Currently, it handles the following HTML tags: +- `<h1>`, `<h2>`, `<h3>`, `<h4>`, `<h5>`, `<h6>` -> `#`, `##`, `###`, `####`, `#####`, `######` +- `<title>` -> `#` +- `<code>` -> `` `code` `` +- `<pre>` -> "```R\\npre\\n```" +- `<EM>` -> `*EM*` +- `<B>` -> `**B**` +- `–` -> `-` + +## TODOs + +- Tables +- Links +- Images +""" function description_to_markdown(string) html_header_regex = r"<h(?'hnum'\d)>(?'content'[^<]+)<\/h\g'hnum'>" function regexmatch2md(matched_string) @@ -71,31 +132,3 @@ function description_to_markdown(string) nohtml = replace(new_string, Regex("<[^>]*>") => "") return replace(nohtml, Regex("\n\n+") => "\n\n") end -""" - description(package_name::AbstractString, dataset_name::AbstractString) - -Return a `RDatasetDescription` object containing the description of the dataset. - -Invoke this function in exactly the same way you would invoke `dataset` to get the dataset itself. -""" -function description(package_name::AbstractString, dataset_name::AbstractString) - RDatasetDescription(read(joinpath(@__DIR__, "..", "doc", - package_name, "$dataset_name.html"), String)) -end - -function Base.show(io::IO, mime::MIME"text/plain", d::RDatasetDescription) - s = description_to_markdown(d.content) - # Here, we show a Markdown.jl object, which the REPL can render correctly - # as markdown, as it does in help-mode. - show(io, mime, Markdown.parse(s)) -end -function Base.show(io::IO, mime::MIME"text/markdown", d::RDatasetDescription) - s = description_to_markdown(d.content) - # Here, we return a Markdown string directly. This is useful for e.g. documentation, - # where we want to render the markdown as HTML. - show(io, mime, s) -end -# This returns raw HTML documentation. -function Base.show(io::IO, mime::MIME"text/html", d::RDatasetDescription) - show(io, mime, Docs.HTML(d.content)) -end From 9154051b051eae1ae3965daf40930cc9448d2a7b Mon Sep 17 00:00:00 2001 From: Anshul Singhvi <anshulsinghvi@gmail.com> Date: Tue, 2 Apr 2024 09:43:30 -0400 Subject: [PATCH 5/8] Inject metadata into all DataFrames indicating origin from RDatasets --- src/dataset.jl | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/src/dataset.jl b/src/dataset.jl index aede06a..77a737a 100644 --- a/src/dataset.jl +++ b/src/dataset.jl @@ -6,43 +6,61 @@ const Dataset_typedetect_rows = Dict{Tuple{String, String}, Union{Vector,Dict}}( function dataset(package_name::AbstractString, dataset_name::AbstractString) basename = joinpath(@__DIR__, "..", "data", package_name) - + # First, identify possible files rdataname = joinpath(basename, string(dataset_name, ".RData")) - if isfile(rdataname) - return load(rdataname)[dataset_name] - end - rdaname = joinpath(basename, string(dataset_name, ".rda")) - if isfile(rdaname) - return load(rdaname)[dataset_name] - end - csvname = joinpath(basename, string(dataset_name, ".csv.gz")) - if isfile(csvname) - return open(csvname,"r") do io + # Then, check to see which exists. If none exist, error. + dataset = if isfile(rdataname) + load(rdataname)[dataset_name] + elseif isfile(rdaname) + load(rdaname)[dataset_name] + elseif isfile(csvname) + open(csvname,"r") do io uncompressed = IOBuffer(read(GzipDecompressorStream(io))) DataFrame(CSV.File(uncompressed, delim=',', quotechar='\"', missingstring="NA", types=get(Dataset_typedetect_rows, (package_name, dataset_name), nothing)) ) end + else + error("Unable to locate dataset file $rdaname or $csvname") end - error("Unable to locate dataset file $rdaname or $csvname") + # Finally, inject metadata into the dataframe to indicate origin: + DataFrames.metadata!(dataset, "RDatasets.jl", (string(package_name), string(dataset_name))) + return dataset end """ - description(package_name::AbstractString, dataset_name::AbstractString) + RDatasets.description(package_name::AbstractString, dataset_name::AbstractString) + RDatasets.description(df::DataFrame) # only call this on dataframes from RDatasets! Returns an `RDatasetDescription` object containing the description of the dataset. Invoke this function in exactly the same way you would invoke `dataset` to get the dataset itself. This object prints well in the REPL, and can also be shown as markdown or HTML. + +!!! note Unexported + This function is left deliberately unexported, since the name is pretty common. """ function description(package_name::AbstractString, dataset_name::AbstractString) RDatasetDescription(read(joinpath(@__DIR__, "..", "doc", package_name, "$dataset_name.html"), String)) end +# This is a convenience function to get the description of a dataset from a DataFrame. +# Since we set metadata on the DataFrame, we can use this to get the description, +# if it exists. +function description(df::AbstractDataFrame) + if "RDatasets.jl" in DataFrames.metadatakeys(df) + package_name, dataset_name = DataFrames.metadata(df, "RDatasets.jl") + return description(package_name, dataset_name) + else + @warn "No metadata indicating dataset origin found. Returning default description." + return RDatasetDescription("No description available.") + end +end + """ RDatasetDescription(content::String) From 78828923060cac0de376fb107396a3004e602dee Mon Sep 17 00:00:00 2001 From: Anshul Singhvi <anshulsinghvi@gmail.com> Date: Tue, 2 Apr 2024 09:46:01 -0400 Subject: [PATCH 6/8] Document `description` in the README --- README.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 2003f5b..fe345f3 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,21 @@ The RDatasets package provides an easy way for Julia users to experiment with most of the standard data sets that are available in the core of R as well as datasets included with many of R's most popular packages. This package is essentially a simplistic port of the Rdatasets repo created by Vincent Arelbundock, who conveniently gathered data sets from many of the standard R packages in one convenient location on GitHub at https://github.com/vincentarelbundock/Rdatasets In order to load one of the data sets included in the RDatasets package, you will need to have the `DataFrames` package installed. This package is automatically installed as a dependency of the `RDatasets` package if you install `RDatasets` as follows: - - Pkg.add("RDatasets") - +```julia +Pkg.add("RDatasets") +``` After installing the RDatasets package, you can then load data sets using the `dataset()` function, which takes the name of a package and a data set as arguments: - - using RDatasets - iris = dataset("datasets", "iris") - neuro = dataset("boot", "neuro") - +```julia +using RDatasets +iris = dataset("datasets", "iris") +neuro = dataset("boot", "neuro") +``` +You can also get descriptions of the datasets by calling `RDatasets.description`: +```julia +RDatasets.description("datasets", "iris") +# or +RDatasets.description(iris) # only use this on DataFrames returned from `dataset`! +``` # Data Sets The `RDatasets.packages()` function returns a table of represented R packages: From 2b92f04dd2b9e5b035548e6b09ea50bb41429e2b Mon Sep 17 00:00:00 2001 From: Anshul Singhvi <anshulsinghvi@gmail.com> Date: Tue, 2 Apr 2024 09:47:40 -0400 Subject: [PATCH 7/8] Make `description` a bit more robust --- src/dataset.jl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/dataset.jl b/src/dataset.jl index 77a737a..1b87ee3 100644 --- a/src/dataset.jl +++ b/src/dataset.jl @@ -44,8 +44,12 @@ This object prints well in the REPL, and can also be shown as markdown or HTML. This function is left deliberately unexported, since the name is pretty common. """ function description(package_name::AbstractString, dataset_name::AbstractString) - RDatasetDescription(read(joinpath(@__DIR__, "..", "doc", - package_name, "$dataset_name.html"), String)) + doc_html_file = joinpath(@__DIR__, "..", "doc", package_name, "$dataset_name.html") + if isfile(doc_html_file) + return RDatasetDescription(read(doc_html_file, String)) + else + return RDatasetDescription("No description available.") + end end # This is a convenience function to get the description of a dataset from a DataFrame. From 0f6fbce0aa833628f15a34dbf4f34e0c4ad05dda Mon Sep 17 00:00:00 2001 From: Anshul Singhvi <anshulsinghvi@gmail.com> Date: Sat, 13 Dec 2025 08:40:38 -0500 Subject: [PATCH 8/8] Address PR review feedback for v1.0.0 release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix docstring conventions: "Returns" -> "Return", "Invoked" -> "Obtained" - Capitalize "Markdown" consistently in documentation - Move DataFrame constraint info from signature comment into docstring body - Remove unnecessary DataFrames. prefixes (use metadata!, metadatakeys, metadata directly) - Replace unexported note with @public declaration for description and packages - Add SciMLPublic.jl dependency for @public macro - Throw error instead of warning when DataFrame lacks RDatasets metadata - Add `default` keyword argument to description(df) for graceful fallback - Bump version to 1.0.0 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Milan Bouchet-Valat <nalimilan@club.fr> Co-Authored-By: Claude <noreply@anthropic.com> --- Project.toml | 4 +++- src/RDatasets.jl | 2 ++ src/dataset.jl | 31 ++++++++++++++++--------------- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/Project.toml b/Project.toml index 6cd66d8..9f60d9b 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "RDatasets" uuid = "ce6b1742-4840-55fa-b093-852dadbb1d8b" -version = "0.8.0" +version = "1.0.0" [deps] CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" @@ -11,6 +11,7 @@ Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" RData = "df47a6cb-8c03-5eed-afd8-b6050d6c41da" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +SciMLPublic = "431bcebd-1456-4ced-9d72-93c2757fff0b" [compat] CSV = "0.5, 0.6, 0.7, 0.8, 0.9, 0.10" @@ -19,6 +20,7 @@ DataFrames = "0.15, 0.16, 0.17, 0.18, 0.19, 0.20, 0.21, 0.22, 1" FileIO = "1" RData = "0.5, 0.6, 0.7, 0.8, 1" Reexport = "0.2, 1.0" +SciMLPublic = "1" julia = "1.6" [extras] diff --git a/src/RDatasets.jl b/src/RDatasets.jl index 6b8e133..2ed35e5 100644 --- a/src/RDatasets.jl +++ b/src/RDatasets.jl @@ -4,10 +4,12 @@ module RDatasets end import Markdown + import SciMLPublic: @public using Reexport, RData, CSV, CodecZlib @reexport using DataFrames export dataset + @public description, packages global __packages = nothing global __datasets = nothing diff --git a/src/dataset.jl b/src/dataset.jl index 1b87ee3..f9df57d 100644 --- a/src/dataset.jl +++ b/src/dataset.jl @@ -25,23 +25,24 @@ function dataset(package_name::AbstractString, dataset_name::AbstractString) error("Unable to locate dataset file $rdaname or $csvname") end # Finally, inject metadata into the dataframe to indicate origin: - DataFrames.metadata!(dataset, "RDatasets.jl", (string(package_name), string(dataset_name))) + metadata!(dataset, "RDatasets.jl", (string(package_name), string(dataset_name))) return dataset end """ RDatasets.description(package_name::AbstractString, dataset_name::AbstractString) - RDatasets.description(df::DataFrame) # only call this on dataframes from RDatasets! + RDatasets.description(df::AbstractDataFrame; default=nothing) -Returns an `RDatasetDescription` object containing the description of the dataset. +Return an `RDatasetDescription` object containing the description of the dataset. Invoke this function in exactly the same way you would invoke `dataset` to get the dataset itself. -This object prints well in the REPL, and can also be shown as markdown or HTML. +This object prints well in the REPL, and can also be shown as Markdown or HTML. -!!! note Unexported - This function is left deliberately unexported, since the name is pretty common. +When passing a `DataFrame`, it must have been obtained from `RDatasets.dataset`. If the DataFrame +does not have the required metadata, an error is thrown unless a `default` value is provided, +in which case that value is returned instead. """ function description(package_name::AbstractString, dataset_name::AbstractString) doc_html_file = joinpath(@__DIR__, "..", "doc", package_name, "$dataset_name.html") @@ -53,15 +54,15 @@ function description(package_name::AbstractString, dataset_name::AbstractString) end # This is a convenience function to get the description of a dataset from a DataFrame. -# Since we set metadata on the DataFrame, we can use this to get the description, -# if it exists. -function description(df::AbstractDataFrame) - if "RDatasets.jl" in DataFrames.metadatakeys(df) - package_name, dataset_name = DataFrames.metadata(df, "RDatasets.jl") +# Since we set metadata on the DataFrame, we can use this to get the description. +function description(df::AbstractDataFrame; default=nothing) + if "RDatasets.jl" in metadatakeys(df) + package_name, dataset_name = metadata(df, "RDatasets.jl") return description(package_name, dataset_name) + elseif default !== nothing + return default else - @warn "No metadata indicating dataset origin found. Returning default description." - return RDatasetDescription("No description available.") + throw(ArgumentError("DataFrame does not have RDatasets.jl metadata. Use a DataFrame obtained from `RDatasets.dataset`, or provide a `default` value.")) end end @@ -71,9 +72,9 @@ end A type to hold the content of a dataset description. The main purpose of its existence is to provide a way to display the content -differently in HTML and markdown contexts. +differently in HTML and Markdown contexts. -Invoked through [`RDatasets.description`](@ref). +Obtained through [`RDatasets.description`](@ref). """ struct RDatasetDescription content::String