
Propose operation mappings for hand-written wrappers
propose_mappings.RdScreen hand-written wrappers, propose explicit inputs, request, and docs mappings for one service, and keep only the proposals that verify_adoption() confirms are equivalent.
Arguments
- root
Explicit existing client root directory.
- files
Source files to screen, relative to root.
- service
ID of the service whose helper and selected operations the wrappers map to. The service must be defined in its own service file.
- config
Project YAML path relative to root.
- callbacks
Explicit environment containing named development callbacks.
- route
Optional
function(name, call)returning the operation key, such as"GET /items/{item_id}", for a wrapper's helper call. By default, literalmethodandpathhelper arguments must match a selected operation exactly.- bindings
Optional
function(expr)returning a request binding (for examplelist(callback = "batch_limit")) for a helper argument expression, orNULLwhen it does not apply.- prelude
Optional
function(code)receiving the wrapper's body statements. It returnsNULL, or a list withstatements(how many leading statements it accounts for) andarguments(request bindings for the helper arguments those statements build).
Value
A list with operations (per wrapper: file, status "proposed" or "retained", reason, and the matched operation key), proposals (verified mappings keyed by operation), yaml (the proposals as a service operations: map), and contracts and files as returned by verify_adoption().
Details
Nothing in root is written. A wrapper is proposed when its body is a single call to the service helper (optionally result <- helper(...); result or return(result)), after any statements the prelude callback accounts for. Its defaults must be plain data literals, and its roxygen block may use only a title, a lifecycle badge and description, @param, @return, @export, and @examples that call the wrapper with literal inputs. Helper arguments bind a formal to from, a data literal to value, and a list() of those to object or array; the bindings callback handles anything else. Every other wrapper is retained with a reason, as is any proposal that fails verification against the staged service configuration.
Review yaml, copy it into the service file, and adopt as described in verify_adoption().
Examples
# Recognize `query <- list(); if (!is.null(x)) query$key <- x; ...` before the helper call.
# The optional values it collects are exactly a compact_object binding.
query_prelude <- function(code) {
if (!length(code) || !identical(code[[1L]], quote(query <- list()))) {
return(NULL)
}
fields <- list()
for (statement in code[-1L]) {
assignment <- if (is.call(statement) && identical(statement[[1L]], as.name('if'))) statement[[3L]]
target <- if (is.call(assignment) && identical(assignment[[1L]], as.name('<-'))) assignment[[2L]]
value <- if (!is.null(target)) assignment[[3L]]
if (
!is.call(target) || !identical(target[[1L]], as.name('$')) ||
!identical(target[[2L]], as.name('query')) || !is.symbol(value) ||
!identical(statement[[2L]], call('!', call('is.null', value)))
) {
break
}
fields[[as.character(target[[3L]])]] <- list(from = list('params', as.character(value)))
}
list(statements = 1L + length(fields), arguments = list(query = list(compact_object = fields)))
}
if (FALSE) { # \dontrun{
proposal <- specmill::propose_mappings(root, 'R/items.R', 'catalogue', prelude = query_prelude)
proposal$operations
cat(proposal$yaml)
} # }