diff --git a/NEWS.md b/NEWS.md index bc62bdca..880da6fd 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,53 @@ +# humdrumR 7.0.5 + +Version 7.0.5 includes a small patch to fix a bug related to the `::` function, as well as a new feature/behavior which builds off of that fix. + + +In previous versions, an error would occur if you used `::` inside any of the fundamental humdrumR "with/within" methods (including `base` functions and `dplyr` "verbs"). +We've fixed this bug. + +---- + +We've also added a new feature; specifically, we've made using `::` in humdrumR less necessary. +Now, within a humdrumR call to any of these methods (listed below), if you use any function exported by humdrumR, humdrumR will automatically use the humdrumR version of that function, even if another package you have attached includes a function with same name. +In other words, the humdrumR namespace will always takes priority within a humdrumR method call. + +For example, the `dplyr` package exports a function called `lag()` and so does humdrumR (these functions do the same thing, but humdrumR's version has a few extra features). +Before this update, if you loaded `dplyr` *after* you loaded humdrumR, then `dplyr`'s `lag()` function would generally take priority over humdrumR's `lag()`. +So, code like this + +``` +library(humdrumR) +library(dplyr) + +readHumdrum(humdrumRroot, 'HumdrumData/BachChorales/.*krn') -> chorales + +chorales |> mutate(Lagged = lag(Token)) + + +``` + +would call `dplyr::lag()`. +This sort of behavior can be confusing but wouldn't normally be the end of the world (this is how R is supposed to work, after all). +However, the `lag()` function is particularly problematic because *many* humdrumR methods rely on our special version of `lag()`. +This is why we've implemented a change: +Now, if you use `lag()` within a humdrumR with/within method, it will default to using the humdrumR version, regardless of what other packages are loaded. +So the code above would use `humdrumR::lag()`. +If you *want* to use `dplyr`'s version (or any other package), you still can by specifying (for example) `dplyr::lag()`. +Another function which (in the past) could lead to frequent namespace confusion was `transpose()`---now, you can safely use `transpose()` and know that your system will use `humdrumR::transpose()`. + + +All `.humdrumR` methods for the following functions are affected by this change: + ++ `with()` ++ `within()` ++ `mutate()` ++ `reframe()` ++ `summarize()` ++ `filter()` ++ `subset()` + + # humdrumR 7.0.3 ### count() and table() diff --git a/R/Dispatch.R b/R/Dispatch.R index c9c7e243..7f7d7355 100644 --- a/R/Dispatch.R +++ b/R/Dispatch.R @@ -137,11 +137,11 @@ memoizeParse <- function(args, ..., dispatchArgs = c(), minMemoize = 100L, memoi if (is.struct(result)) { uniqueArgs$i <- seq_len(nrow(uniqueArgs)) - result[merge(memoizeArgs, uniqueArgs, on = colnames(uniqueArgs), sort = FALSE)$i] + result[merge(memoizeArgs, uniqueArgs, sort = FALSE)$i] } else { uniqueArgs[ , Result := result] - merge(memoizeArgs, uniqueArgs, on = head(colnames(uniqueArgs), -1), sort = FALSE)$Result + merge(memoizeArgs, uniqueArgs, by = head(colnames(uniqueArgs), -1), sort = FALSE)$Result } diff --git a/R/Within.R b/R/Within.R index 57244b14..04841e82 100644 --- a/R/Within.R +++ b/R/Within.R @@ -71,6 +71,12 @@ #' If multiple expression arguments are provided, each expression is evaluated in order, from left to right. #' Each expression can refer variables assigned in the previous expression (examples below). #' +#' *Note*: Within any of these expressions, the humdrumR namespace takes priority. +#' This means that, for example, if you use `lag()` within an expression, the humdrumR version of `lag()` +#' will be used, even if you have loaded other packages which have their own `lag()` function. +#' To use another package's function, you'll have to specify `package::function()`---for example, `dplyr::lag()`. +#' This is only an issue when functions have the exact same name as a humdrumR function. +#' #' ### Expression pre-processing #' #' These functions all do some @@ -801,15 +807,21 @@ unformula <- function(quosures) { quoForceHumdrumRcalls <- function(quosures) { - # this changes any function call from a humdrumR function to humdrumR::function - humdrumRpackage <- ls('package:humdrumR') + # this changes any function call from a humdrumR function to humdrumR:::function + # we use ::: because the ls() output includes methods that aren't actually exported (:: won't work). + # we don't include infix functions line %~% + + humdrumRpackage <- ls('package:humdrumR') |> grep(pattern = '%', x = _, value = TRUE, invert = TRUE) + humdrumRpackage <- setdiff(humdrumRpackage, 'count') + # we can't do it to count because the count() generic was originally exported by dplyr + # there might other functions which need to be added to this list? lapply(quosures, \(quo) { withinExpression(quo, predicate = \(Head) Head[1] %in% humdrumRpackage, func = \(exprA) { - exprA$Head <- paste0('humdrumR::', exprA$Head) + exprA$Head <- paste0('humdrumR:::', exprA$Head) exprA }) }) @@ -1036,9 +1048,13 @@ activateQuo <- function(funcQuosure, dotField) { autoArgsQuo <- function(funcQuosure, fields) { - predicate <- \(Head) Head %in% c(autoArgTable$Function, paste0(autoArgTable$Function, '.default')) + + funcRegex <- paste0('^(humdrumR:::?)?', autoArgTable$Function, '(\\.default)?$') + + predicate <- \(Head) any(stringr::str_detect(Head, funcRegex)) + do <- \(exprA) { - tab <- autoArgTable[(Function == exprA$Head | paste0(Function, '.default') == exprA$Head) & + tab <- autoArgTable[stringr::str_detect(exprA$Head, funcRegex) & !Argument %in% names(exprA$Args) & sapply(Expression, \(expr) length(namesInExpr(fields, expr)) > 0L)] args <- setNames(tab$Expression, tab$Argument) diff --git a/R/humdrumR-package.R b/R/humdrumR-package.R index 138b202c..9f36f25d 100644 --- a/R/humdrumR-package.R +++ b/R/humdrumR-package.R @@ -112,7 +112,6 @@ autoArgTable <- rbind(data.table(Argument = 'groupby', Type = 'melodic', Expression = list(quote(Tandem))) ) -autoArgTable[, Function := paste0('humdrumR::', Function)] setOldClass('quosure') setOldClass('quosures') diff --git a/docs/404.html b/docs/404.html index 7adf8057..fbd20f42 100644 --- a/docs/404.html +++ b/docs/404.html @@ -7,10 +7,10 @@ Page not found (404) • humdrumR - - + + - + License • humdrumRLicense • humdrumR Skip to contents -