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
2 changes: 2 additions & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@
^README\.Rmd$
^data-raw$
^LICENSE\.md$
^doc$
^Meta$
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
.Ruserdata
docs
rando
inst/doc
/doc/
/Meta/
74 changes: 74 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# ngr - New Graph Reporting

R package with utility functions for dynamic reporting, spatial analysis, hydrology, and data wrangling.

## Build & Test Commands

```r
devtools::document()
devtools::test()
devtools::check()
devtools::install()
```
Build documentation and run checks before committing.

## Commit Style (fledge)

This repo uses [fledge](https://github.com/cynkra/fledge) for changelog management.

**NEWS-worthy commits** start with `- ` (bullet point):
```
- initial commit of [ngr_function_name()] to close [#1](https://github.com/NewGraphEnvironment/ngr/issues/1)
```

**Function references** use square brackets for pkgdown auto-links:
- `[function_name()]` - creates link to function docs in pkgdown site

**Issue references** use full markdown links:
- `[#19](https://github.com/NewGraphEnvironment/ngr/issues/19)`

**Non-NEWS commits** (docs, chores) don't start with `- `:
```
rebuild documentation and update build config
```

## Function Naming Conventions

All exported functions use prefix `ngr_` followed by category:

| Prefix | Category | Example |
|--------|----------|---------|
| `ngr_str_` | String manipulation | `ngr_str_extract_between()` |
| `ngr_spk_` | Spatial/raster (spacehakr) | `ngr_spk_stac_calc()` |
| `ngr_hyd_` | Hydrology | `ngr_hyd_q_daily()` |
| `ngr_dbqs_` | Database/SQL queries | `ngr_dbqs_filter_predicate()` |
| `ngr_tidy_` | Data frame tidying | `ngr_tidy_cols_rm_na()` |
| `ngr_xl_` | Excel operations | `ngr_xl_read_formulas()` |
| `ngr_fs_` | File system | `ngr_fs_copy_if_missing()` |
| `ngr_s3_` | S3/cloud storage | `ngr_s3_dl()` |
| `ngr_git_` | Git/GitHub | `ngr_git_issue()` |
| `ngr_chk_` | Validation/checking | `ngr_chk_dt_complete()` |
| `ngr_pkg_` | Package utilities | `ngr_pkg_detach()` |

## Documentation Style

- Use roxygen2 with markdown enabled
- Add `@family` tags to group related functions (e.g., `@family spacehakr`, `@family string`)
- Use `@importFrom` for all external functions
- Include `@examples` (use `\dontrun{}` for slow/network examples)
- Reference related functions with `@seealso`

## Key Dependencies

- **chk** - Argument validation
- **cli** - User messaging
- **sf/terra** - Spatial operations
- **tidyhydat** - Hydrometric data
- **dplyr/purrr/stringr** - Data wrangling
- **glue** - String interpolation

## DESCRIPTION Management

- Keep Imports alphabetized
- Don't duplicate packages in both Imports and Suggests
- Add vignette-only packages to Suggests (e.g., mapview, rstac)
38 changes: 21 additions & 17 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,41 @@ License: MIT + file LICENSE
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.2.9000
Suggests:
Suggests:
testthat (>= 3.0.0),
mockery,
sf,
purrr
knitr,
rmarkdown,
mapview,
rstac,
stars
Config/testthat/edition: 3
URL: https://github.com/NewGraphEnvironment/ngr, https://newgraphenvironment.github.io/ngr/
BugReports: https://github.com/NewGraphEnvironment/ngr/issues
Imports:
Imports:
chk,
processx,
cli,
stringr,
fs,
curl,
rvest,
lifecycle (>= 1.0.0),
janitor,
tidyxl,
sf,
terra,
purrr,
httr,
dplyr,
fs,
gh,
glue,
httr,
janitor,
lifecycle (>= 1.0.0),
processx,
purrr,
rvest,
sf,
stringr,
terra,
tibble,
tidyhydat,
xml2,
gh
tidyxl,
xml2
Remotes:
nacnudus/tidyxl
Depends:
R (>= 2.10)
LazyData: true
VignetteBuilder: knitr
15 changes: 15 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
# Generated by roxygen2: do not edit by hand

export(ngr_chk_coerce_date)
export(ngr_chk_dt_complete)
export(ngr_dbqs_filter_predicate)
export(ngr_dbqs_ltree)
export(ngr_dbqs_tbl_quote)
export(ngr_fs_copy_if_missing)
export(ngr_fs_id_missing)
export(ngr_git_issue)
export(ngr_git_issue_details)
export(ngr_hyd_q_daily)
export(ngr_hyd_realtime)
export(ngr_pkg_detach)
export(ngr_s3_dl)
Expand All @@ -25,10 +28,13 @@ export(ngr_spk_rast_ext)
export(ngr_spk_rast_not_empty)
export(ngr_spk_rast_rm_empty)
export(ngr_spk_res)
export(ngr_spk_stac_calc)
export(ngr_str_df_col_agg)
export(ngr_str_df_detect_filter)
export(ngr_str_df_extract)
export(ngr_str_dir_from_file)
export(ngr_str_dir_from_path)
export(ngr_str_extract_between)
export(ngr_str_link_url)
export(ngr_str_replace_filenames)
export(ngr_str_replace_in_files)
Expand All @@ -38,6 +44,7 @@ export(ngr_tidy_type)
export(ngr_xl_map_colnames)
export(ngr_xl_map_formulas)
export(ngr_xl_read_formulas)
importFrom(chk,abort_chk)
importFrom(chk,chk_character)
importFrom(chk,chk_data)
importFrom(chk,chk_dir)
Expand Down Expand Up @@ -73,6 +80,7 @@ importFrom(dplyr,across)
importFrom(dplyr,all_of)
importFrom(dplyr,arrange)
importFrom(dplyr,bind_rows)
importFrom(dplyr,distinct)
importFrom(dplyr,filter)
importFrom(dplyr,group_by)
importFrom(dplyr,if_else)
Expand Down Expand Up @@ -121,21 +129,28 @@ importFrom(sf,st_read)
importFrom(sf,st_sample)
importFrom(sf,st_sf)
importFrom(sf,st_transform)
importFrom(stringr,regex)
importFrom(stringr,str_detect)
importFrom(stringr,str_extract)
importFrom(stringr,str_match)
importFrom(stringr,str_replace)
importFrom(stringr,str_replace_all)
importFrom(stringr,str_squish)
importFrom(stringr,str_which)
importFrom(terra,crop)
importFrom(terra,crs)
importFrom(terra,ext)
importFrom(terra,mask)
importFrom(terra,project)
importFrom(terra,rast)
importFrom(terra,res)
importFrom(terra,union)
importFrom(terra,values)
importFrom(terra,vect)
importFrom(tibble,as_tibble)
importFrom(tibble,tibble)
importFrom(tidyhydat,hy_daily_flows)
importFrom(tidyhydat,realtime_stations)
importFrom(tidyhydat,realtime_ws)
importFrom(tidyxl,xlsx_cells)
importFrom(utils,glob2rx)
Expand Down
43 changes: 43 additions & 0 deletions R/ngr_chk_coerce_date.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#' Check and Validate Date-Coercible Input
#'
#' Checks whether an object is a [Date] or can be safely coerced to a [Date]
#' using [base::as.Date()]. If the input is coercible, it is returned
#' invisibly; otherwise, an informative error is thrown.
#'
#' @param x [any] An object expected to be a [Date] or a string coercible to a
#' [Date].
#' @param x_name [character] Optional. A single string giving the name of `x`
#' used in error messages. If `NULL`, the name is inferred from the calling
#' expression.
#'
#' @details
#' This helper is intended for lightweight validation in functions that accept
#' date inputs but do not need to modify them. Coercion is attempted via
#' [base::as.Date()], and failure results in a call to
#' [chk::abort_chk()].
#'
#' @returns
#' `x` invisibly if it is a [Date] or coercible to one. An error is thrown if
#' coercion fails.
#'
#' @seealso
#' [base::as.Date()], [chk::abort_chk()]
#'
#' @family chk
#'
#' @importFrom chk abort_chk
#'
#' @export
ngr_chk_coerce_date <- function(x, x_name = NULL) {
if (!inherits(try(as.Date(x), silent = TRUE), "try-error")) {
return(invisible(x))
}
if (is.null(x_name)) {
x_name <- deparse(substitute(x))
}
chk::abort_chk(
x_name, " must be a Date or a string coercible to Date",
x = x
)
}

66 changes: 66 additions & 0 deletions R/ngr_chk_dt_complete.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#' Check for Complete Date Sequences
#'
#' Checks whether a vector of dates forms a complete, uninterrupted sequence
#' between its minimum and maximum values. If missing dates are detected,
#' they are printed using `dput()` for easy reuse and the function returns
#' `FALSE` invisibly.
#'
#' @param x [Date] A vector of dates to check for completeness.
#' @param units [character] Optional. A single string giving the time unit
#' for the sequence passed to [base::seq.Date()]. Default is `"days"`.
#' @param dates_print [logical] Optional. Whether to print missing dates to the
#' console using `dput()` when gaps are detected. Default is `TRUE`.
#' @param dates_capture [logical] Optional. Whether to capture and return the
#' missing dates as an object when gaps are detected. Default is `FALSE`.
#'
#' @details
#' The function computes a full date sequence using [base::seq.Date()] from
#' `min(x)` to `max(x)` and compares it to the unique values of `x` using
#' [base::setdiff()]. Missing dates, if any, are printed with `dput()` so they
#' can be copied directly into code or tests.
#'
#' @return
#' If `dates_capture = FALSE` (default), returns `TRUE` invisibly if no dates
#' are missing and `FALSE` invisibly if one or more dates are missing.
#'
#' If `dates_capture = TRUE`, returns the missing dates as a [Date] vector
#' (invisibly) when gaps are detected, and `TRUE` invisibly when no dates
#' are missing.
#'
#' @examples
#' dates_ok <- as.Date("2024-01-01") + 0:4
#' ngr_chk_dt_complete(dates_ok)
#'
#' dates_bad <- as.Date(c("2024-01-01", "2024-01-02", "2024-01-04"))
#' ngr_chk_dt_complete(dates_bad)
#'
#' @importFrom cli cli_alert_warning cli_alert_success
#'
#' @export
#' @family chk
ngr_chk_dt_complete <- function(x, units = "days", dates_print = TRUE, dates_capture = FALSE) {
ngr_chk_coerce_date(x)

x <- as.Date(x)

full_seq <- seq.Date(
from = min(x, na.rm = TRUE),
to = max(x, na.rm = TRUE),
by = units
)

dates_missing <- as.Date(setdiff(full_seq, unique(x)), origin = "1970-01-01")

if (length(dates_missing) > 0) {
cli::cli_alert_warning("There are missing dates:")
if (dates_print) {
dput(as.character(dates_missing))
}
if (dates_capture) {
return(invisible(dates_missing))
}
return(invisible(FALSE))
}

invisible(TRUE)
}
Loading