Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions .github/skills/document/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,21 @@ description: Document package functions. Use when asked to document functions.

*All* R functions in `R/` should be documented in roxygen2 `#'` style, including internal/unexported functions.

- Run `air format .` then `devtools::document()` after changing any roxygen2 docs.
- Run `air format .` then `devtools::document()` after changing any roxygen2 docs. If it says "Could not resolve link to topic" for a function we updated, run `devtools::document()` again to make sure the error was transient.
- Use sentence case for all headings.
- Wrap roxygen comments at 80 characters.
- Files matching `R/import-standalone-*.R` are imported from other packages and have their own conventions. Do not modify their documentation.
- After documenting functions, run `devtools::document(roclets = c('rd', 'collate', 'namespace'))`.
- If `_pkgdown.yml` exists and contains a `reference` section:
- Whenever you add a new (non-internal) documentation topic, also add the topic to `_pkgdown.yml`.
- Use `pkgdown::check_pkgdown()` to check that all topics are included in the reference index.

## Shared parameters

**Parameters used in more than one function** go in `R/aaa-shared_params.R` under `@name .shared-params`. Functions inherit them with `@inheritParams .shared-params`. See `R/aaa-shared_params.R` for current definitions (if it exists).
**Parameters used in more than one function** go in `R/aaa-shared_params.R` under `@name .shared-params`. Functions inherit them with `@inheritParams .shared-params`. See `R/aaa-shared_params.R` for current definitions. Note: definitions of dot-prefixed parameters (e.g. `#' @param .call`) are also imported by roxygen for their dot-less equivalent (e.g. `#' @param call`); if we use both versions, we only need to document the dot-prefixed version in `.shared-params`.

Shared params blocks: alphabetize parameters, use `@name .shared-params` (with leading dot), include `@keywords internal`, end with `NULL`.
Shared params blocks: alphabetize parameters (ignoring dot prefixes), use `@name .shared-params` (with leading dot), include `@keywords internal`, end with `NULL`.

Multiple shared-params groups (e.g. `.shared-params-io`, `.shared-params-parsing`) are appropriate when parameters are only shared within a file and closely related files.
Multiple shared-params groups (e.g. `#' @name .shared-params-io`, `#' @name .shared-params-parsing`) are appropriate when parameters are only shared within a file and closely related files.

## Parameter documentation format

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/copilot-setup-steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ jobs:
any::rcmdcheck
any::rlang
any::roxygen2
any::stbl
any::testthat
any::usethis
any::withr
wranglezone/stbl
local::.

- name: Install air
Expand Down
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ Imports:
glue,
lifecycle,
purrr (>= 1.0.2),
rlang (>= 1.1.0),
stbl,
rlang (>= 1.2.0),
tibble (>= 3.2.1),
tidyselect (>= 1.2.0),
vctrs (>= 0.7.2),
Expand All @@ -38,6 +37,7 @@ Suggests:
memoise (>= 2.0.1),
rmarkdown (>= 2.16),
spelling (>= 2.2),
stbl,
testthat (>= 3.1.4),
tidyr,
yaml (>= 2.3.6)
Expand Down
4 changes: 2 additions & 2 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ export(camel_case_to_snake_case)
export(get_spec)
export(guess_tspec)
export(guess_tspec_df)
export(guess_tspec_list)
export(guess_tspec_object)
export(guess_tspec_object_list)
export(nest_tree)
export(parse_openapi_schema)
export(parse_openapi_spec)
Expand Down Expand Up @@ -94,12 +96,10 @@ importFrom(rlang,as_function)
importFrom(rlang,caller_arg)
importFrom(rlang,caller_env)
importFrom(rlang,check_bool)
importFrom(rlang,check_dots_empty)
importFrom(rlang,check_string)
importFrom(rlang,current_call)
importFrom(rlang,current_env)
importFrom(rlang,is_empty)
importFrom(rlang,is_named)
importFrom(rlang,is_true)
importFrom(rlang,list2)
importFrom(rlang,zap)
Expand Down
7 changes: 6 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
# tibblify (development version)

* All arguments of functions that accept meaningful named `...` are now prefixed with `.` to minimize conflicts with column and object names in `...`. The un-dotted versions of the arguments are still accepted, but calling functions directly with un-dotted arguments will produce a warning once per session (see `?lifecycle::deprecate_soft()`). Un-dotted arguments will be phased out in a future version of this package, so we recommend switching to the dot-prefixed versions. See `?tspec_df` and `?tib_scalar()` for details.
* All code has been refactored for maintainability. While we were careful to ensure that output is unchanged, it is possible that a corner case is no longer handled how it was in version 0.3.0. Please notify us (<https://github.com/wranglezone/tibblify/issues>) if something has changed for the worse in an unexpected way (#243).
* The `guess_tspec()` variants `guess_tspec_list()` and `guess_tspec_object_list()` are now exported (along with `guess_tspec_df()` and `guess_tspec_object()`, which were already exported). `guess_tspec()` should correctly guess the format in most cases, but you can call the variant directly if you think `guess_tspec()` is dispatching incorrectly (#249).
* `untibblify()` now automatically uses the `tib_spec` attribute when present, so tibblified objects can be round-tripped without explicitly passing the spec (#235).
* `parse_openapi_spec()` supports many more fields and works for many more APIs (#190, #200, @jonthegeek and @mgirlich).
* The underlying C implementation has been updated to better comply with R's C API. We also fixed various bugs during this update (#203, #204, #222).
* Documentation of all functions has been updated for clarity (#228, #245, #246).
* All vignettes and the documentation of all functions has been updated for clarity (#243).

(roughly sorted into "Breaking changes", "Potential breaking changes", "New features", "Bug fixes", and "Documentation" as of 2026-04-10, but I left out the headers to make it easier to add more bullets during development)

# tibblify 0.3.1

Expand Down
22 changes: 0 additions & 22 deletions R/aaa-conditions.R

This file was deleted.

13 changes: 13 additions & 0 deletions R/aaa-shared_params.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,40 @@
#' These parameters are used in multiple functions. They are defined here to
#' make them easier to import and to find.
#'
#' @param arg (`character(1)`) An argument name. This name will be mentioned in
#' error messages as the input that is at the origin of a problem.
#' @param .call (`environment`) The environment to use for error messages.
#' @param .children (`character(1)`) The name of the field that contains the
#' children.
#' @param .children_to (`character(1)`) The column name in which to store the
#' children.
#' @param col (`any`) A column from a data frame, which may be a vector, a
#' list, or a nested data frame.
#' @param .elt_transform (`function` or `NULL`) A function to apply to each
#' element before casting to `.ptype_inner`.
#' @param empty_list_unspecified (`logical(1)`) Treat empty lists as
#' unspecified?
#' @param .fill (`vector` or `NULL`) Optionally, a value to use if the field
#' does not exist.
#' @param .format (`character(1)` or `NULL`) Passed to the `format` argument of
#' [as.Date()].
#' @param inform_unspecified (`logical(1)`) Inform about fields whose type could
#' not be determined?
#' @param .key (`character`) The path of names to the field in the object.
#' @param local_env (`environment`) A local environment used to track state
#' across recursive calls, such as whether empty lists were encountered.
#' @param name (`character(1)`) The name of the field.
#' @param .ptype (`vector(0)`) A prototype of the desired output type of the
#' field.
#' @param .ptype_inner (`vector(0)`) A prototype of the input field.
#' @param .required (`logical(1)`) Throw an error if the field does not exist?
#' @param simplify_list (`logical(1)`) Should scalar lists be simplified to
#' vectors?
#' @param spec_list (`list`) A list of specifications.
#' @param tib_list (`list`) A list of tib fields.
#' @param .transform (`function` or `NULL`) A function to apply to the whole
#' vector after casting to `.ptype_inner`.
#' @param value (`list`) An object list whose fields will be guessed.
#' @param .values_to (`character(1)` or `NULL`) For `NULL` (the default), the
#' field is converted to a `.ptype` vector. If a string is provided, the field
#' is converted to a tibble and the values go into the specified column.
Expand Down
67 changes: 67 additions & 0 deletions R/guess_tspec.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#' Guess the `tibblify()` specification
#'
#' @description
#'
#' `guess_tspec()` automatically dispatches to the other `guess_tspec_*()`
#' functions based on the shape of the input. If you are unhappy with its
#' output, calling a specific `guess_tspec_*()` function may yield better
#' results, or at least clearer error messages about why that type isn't
#' supported.
#'
#' - Use `guess_tspec_df()` if the input is a data frame.
#' - Use `guess_tspec_object()` if the input is an object (such as a JSON
#' object that has been read into R as a named list).
#' - Use `guess_tspec_object_list()` if the input is a list of objects (such as
#' a JSON object that has been read into R as a list of named lists).
#' - Use `guess_tspec_list()` if the input object is a list but you aren't sure
#' how it should be processed.
#'
#' See `vignette("supported-structures")` for a discussion of the input types
#' supported by tibblify.
#'
#' @param x (`list` or `data.frame`) A nested list or a data frame.
#' @param ... These dots are for future extensions and must be empty.
#' @inheritParams .shared-params
#'
#' @returns A specification object that can be used in [tibblify()].
#' @export
#'
#' @examples
#' guess_tspec(list(x = 1, y = "a"))
#' guess_tspec(list(list(x = 1), list(x = 2)))
#'
#' guess_tspec(gh_users)
guess_tspec <- function(
x,
...,
empty_list_unspecified = FALSE,
simplify_list = FALSE,
inform_unspecified = should_inform_unspecified(),
call = rlang::caller_env()
) {
rlang::check_dots_empty(call = call)
if (is.data.frame(x)) {
return(guess_tspec_df(
x,
empty_list_unspecified = empty_list_unspecified,
simplify_list = simplify_list,
inform_unspecified = inform_unspecified,
call = call
))
}
if (vctrs::obj_is_list(x)) {
return(guess_tspec_list(
x,
empty_list_unspecified = empty_list_unspecified,
simplify_list = simplify_list,
inform_unspecified = inform_unspecified,
call = call
))
}
Comment thread
jonthegeek marked this conversation as resolved.
stop_input_type(
x,
c("a data frame", "a list"),
arg = caller_arg(x),
call = call
)
}
Loading
Loading