Skip to content

Commit

Permalink
Merge pull request #92 from mlr-org/feat/dict-prototype
Browse files Browse the repository at this point in the history
feat: allow prototype arguments
  • Loading branch information
sebffischer authored Dec 5, 2023
2 parents 796285b + 9f0a380 commit 8344be9
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 40 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: mlr3misc
Title: Helper Functions for 'mlr3'
Version: 0.12.0-9000
Version: 0.13.0-9000
Authors@R: c(
person("Michel", "Lang", , "[email protected]", role = c("cre", "aut"),
comment = c(ORCID = "0000-0001-9754-0393")),
Expand Down
6 changes: 4 additions & 2 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# mlr3misc 0.13.0
# mlr3misc 0.13.0-9000

* Bugfix: disable leanification when `ROXYGEN_PKG` environment variable is set
* Added the possibility to include prototype arguments when adding elements to a `Dictionary`
* Removed unused argument `required_args` from `Dictionary` class
* Disable leanification when `ROXYGEN_PKG` environment variable is set

# mlr3misc 0.13.0

Expand Down
36 changes: 21 additions & 15 deletions R/Dictionary.R
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,19 @@ Dictionary = R6::R6Class("Dictionary",
#' @param ... (`any`)\cr
#' Passed down to constructor.
#'
#' @param .prototype (`logical(1)`)\cr
#' Whether to construct a prototype object.
#'
#' @return Object with corresponding key.
get = function(key, ...) {
get = function(key, ..., .prototype = FALSE) {
assert_string(key, min.chars = 1L)
dictionary_get(self, key, ...)
assert_flag(.prototype)
args = list(...)
if (.prototype) {
args = insert_named(self$prototype_args(key), args)
}

invoke(dictionary_get, self = self, key = key, .args = args)
},

#' @description
Expand All @@ -115,7 +124,6 @@ Dictionary = R6::R6Class("Dictionary",
#' @description
#' Adds object `value` to the dictionary with key `key`, potentially overwriting a previously stored item.
#' Additional arguments in `...` must be named and are passed as default arguments to `value` during construction.
#' The names of all additional arguments which are mandatory for construction and missing in `...` should be listed in `required_args`.
#'
#' @param key (`character(1)`).
#'
Expand All @@ -124,16 +132,18 @@ Dictionary = R6::R6Class("Dictionary",
#' @param ... (`any`)\cr
#' Passed down to constructor.
#'
#' @param required_args (`character()`).
#' @param .prototype_args (`list()`)\cr
#' List of arguments to construct a prototype object.
#' Can be used when objects have construction arguments without defaults.
#'
#' @return `Dictionary`.
add = function(key, value, ..., required_args = character()) {
add = function(key, value, ..., .prototype_args = list()) {
assert_string(key, min.chars = 1L)
assert(check_class(value, "R6ClassGenerator"), check_r6(value), check_function(value))
assert_character(required_args, any.missing = FALSE)

dots = assert_list(list(...), names = "unique", .var.name = "additional arguments passed to Dictionary")
assign(x = key, value = list(value = value, pars = dots, required_args = required_args), envir = self$items)
assert_list(.prototype_args, names = "unique", .var.name = "prototype arguments")
assign(x = key, value = list(value = value, pars = dots, prototype_args = .prototype_args), envir = self$items) # nolint
invisible(self)
},

Expand All @@ -154,15 +164,15 @@ Dictionary = R6::R6Class("Dictionary",
},

#' @description
#' Returns the names of arguments required to construct the object.
#' Returns the arguments required to construct a simple prototype of the object.
#'
#' @param key (`character(1)`)\cr
#' Key of object to query for required arguments.
#'
#' @return `character()` of names of required arguments.
required_args = function(key) {
#' @return `list()` of prototype arguments
prototype_args = function(key) {
assert_string(key, min.chars = 1L)
self$items[[key]][["required_args"]]
self$items[[key]][["prototype_args"]]
}
)
)
Expand All @@ -184,10 +194,6 @@ dictionary_retrieve_item = function(self, key) {
dictionary_initialize_item = function(key, obj, cargs = list()) {
cargs = c(cargs[is.na(names2(cargs))],
insert_named(obj$pars, cargs[!is.na(names2(cargs))]))
ii = wf(obj$required_args %nin% names(cargs))
if (length(ii)) {
stopf("Need argument '%s' to construct '%s'", obj$required_args[ii], key)
}

constructor = obj$value
if (inherits(constructor, "R6ClassGenerator")) {
Expand Down
26 changes: 15 additions & 11 deletions man/Dictionary.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 11 additions & 11 deletions tests/testthat/test_Dictionary.R
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,6 @@ test_that("Dictionary clones R6", {
expect_false(data.table::address(foo) == data.table::address(d$get("f")))
})

test_that("Dictionary required args", {
foo = R6Class("Foo", public = list(x = 0))
x = Dictionary$new()
x$add("a", foo)
x$add("b", foo, required_args = "c")

expect_equal(x$required_args("a"), character())
expect_equal(x$required_args("b"), "c")
expect_equal(x$required_args("c"), NULL)
})

test_that("Dictionary throws exception on unnamed args", {
foo = R6Class("Foo", public = list(x = 0))
x = Dictionary$new()
Expand Down Expand Up @@ -128,3 +117,14 @@ test_that("avoid unintended partial argument matching", {
expect_r6(a, "A")
expect_equal(a$d, 1)
})


test_that("prototype_args works", {
A = R6Class("A", public = list(x = NULL, initialize = function(x) self$x = x))
d = Dictionary$new()
d$add("a", A, .prototype_args = list(x = 1))
expect_identical(d$prototype_args("a"), list(x = 1))
a = d$get("a", .prototype = TRUE)
expect_identical(a$x, 1)
expect_identical(d$prototype_args("a"), list(x = 1))
})

0 comments on commit 8344be9

Please sign in to comment.