Skip to content

Commit

Permalink
[R] Enum R6Class Support, closes #3367 (#5728)
Browse files Browse the repository at this point in the history
* wip: fix documentation tags

* update model.mustache

* update template for documentation

* update mustache templates

* update mustache templates

* run ./bin/r-petstore and update R pkg docs

* use loadNamespace instead of package:pkgName string

* update R package code

* wip: enum

* update enum function

* use httr::content to unwrap response

* update enum table and functions

* include simplifyVector and auto_unbox arguments

* remove mapping and return strings

* use triple stash values and update enum class methods

* remove extra comma

* minor: formatting

* update and run ./bin/r-petstore.sh

* move helper for template

- export tag does not coincide with original model function
- move helper down so it does

* update tests based on generator

* Revert "update tests based on generator"

This reverts commit b6314c8.

* Update tests with engine

- preserve test_petstore.R

* restore apiResponse

* restore simplifyVector to TRUE value

* update api.mustache templates

* fix and add tests to package

Co-authored-by: William Cheng <[email protected]>
  • Loading branch information
LiNk-NY and wing328 authored Jul 1, 2020
1 parent fa72c63 commit 8e95298
Show file tree
Hide file tree
Showing 20 changed files with 254 additions and 111 deletions.
4 changes: 3 additions & 1 deletion modules/openapi-generator/src/main/resources/r/api.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,9 @@
if (httr::status_code(resp) >= 200 && httr::status_code(resp) <= 299) {
{{#returnType}}
{{#isPrimitiveType}}
content <- httr::content(resp, "text", encoding = "UTF-8")
content <- httr::content(
resp, "text", encoding = "UTF-8", simplifyVector = FALSE
)
ApiResponse$new(content,resp)
{{/isPrimitiveType}}
{{^isPrimitiveType}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,9 @@ ApiClient <- R6::R6Class(
else if (exists(returnType, pkgEnv) && !(c(returnType) %in% primitiveTypes)) {
returnType <- get(returnType, envir = as.environment(pkgEnv))
returnObj <- returnType$new()
returnObj$fromJSON(jsonlite::toJSON(obj, digits = NA))
returnObj$fromJSON(
jsonlite::toJSON(obj, digits = NA, auto_unbox = TRUE)
)
}
# To handle primitive type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ test_that("{{{operationId}}}", {
# {{notes}}
{{/notes}}
{{#allParams}}
# @param {{{dataType}}} {{{paramName}}} {{{description}}} {{^required}} (optional){{/required}}
# @param {{{paramName}}} {{{dataType}}} {{{description}}}{{^required}} (optional){{/required}}
{{/allParams}}
# @return [{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}]
Expand Down
15 changes: 13 additions & 2 deletions modules/openapi-generator/src/main/resources/r/model.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,31 @@
{{>partial_header}}
#' @docType class
#' @title {{classname}}
#'
#' @description {{classname}} Class
#'
#' @format An \code{R6Class} generator object
#'
{{#vars}}
#' @field {{baseName}} {{title}} {{#isContainer}}{{#isListContainer}}list( {{/isListContainer}}{{#isMapContainer}}named list( {{/isMapContainer}}{{/isContainer}}{{^isPrimitiveType}}\link{{=<% %>=}}{<%/isPrimitiveType%><%={{ }}=%>{{#isContainer}}{{#items}}{{dataType}}{{/items}}{{/isContainer}}{{^isContainer}}{{dataType}}{{/isContainer}}{{=<% %>=}}<%^isPrimitiveType%>}<%={{ }}=%>{{/isPrimitiveType}}{{#isContainer}}{{#isListContainer}} ){{/isListContainer}}{{#isMapContainer}} ){{/isMapContainer}}{{/isContainer}} {{^required}}[optional]{{/required}}
#'
{{/vars}}
#'
#' @importFrom R6 R6Class
#' @importFrom jsonlite fromJSON toJSON
{{#isEnum}}
{{>modelEnum}}
{{/isEnum}}
{{^isEnum}}
#' @export
{{classname}} <- R6::R6Class(
'{{classname}}',
public = list(
{{#vars}}
`{{{baseName}}}` = NULL,
{{/vars}}
initialize = function({{#requiredVars}}`{{baseName}}`{{#hasMore}}, {{/hasMore}}{{/requiredVars}}{{#optionalVars}}{{#-first}}{{#requiredVars.0}}, {{/requiredVars.0}}{{/-first}}`{{baseName}}`={{#defaultValue}}{{{.}}}{{/defaultValue}}{{^defaultValue}}NULL{{/defaultValue}}{{^-last}}, {{/-last}}{{/optionalVars}}, ...){
initialize = function(
{{#requiredVars}}`{{baseName}}`, {{/requiredVars}}{{#optionalVars}}`{{baseName}}`={{#defaultValue}}{{{.}}}{{/defaultValue}}{{^defaultValue}}NULL{{/defaultValue}}, {{/optionalVars}}...
) {
local.optional.var <- list(...)
{{#requiredVars}}
if (!missing(`{{baseName}}`)) {
Expand Down Expand Up @@ -159,6 +167,7 @@
{{/isContainer}}
}
{{/vars}}
self
},
toJSONString = function() {
jsoncontent <- c(
Expand Down Expand Up @@ -241,5 +250,7 @@
}
)
)
{{/isEnum}}
{{/model}}
{{/models}}

48 changes: 48 additions & 0 deletions modules/openapi-generator/src/main/resources/r/modelEnum.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#' @export
{{#allowableValues}}
{{classname}} <- R6::R6Class(
"{{classname}}",
public = list(
initialize = function(...) {
local.optional.var <- list(...)
val <- unlist(local.optional.var)
enumvec <- .parse_{{name}}()
stopifnot(length(val) == 1L)
if (!val %in% enumvec)
stop("Use one of the valid values: ",
paste0(enumvec, collapse = ", "))
private$value <- val
},
toJSON = function() {
jsonlite::toJSON(private$value, auto_unbox = TRUE)
},
fromJSON = function({{classname}}Json) {
private$value <- jsonlite::fromJSON({{classname}}Json,
simplifyVector = FALSE)
self
},
toJSONString = function() {
as.character(jsonlite::toJSON(private$value,
auto_unbox = TRUE))
},
fromJSONString = function({{classname}}Json) {
private$value <- jsonlite::fromJSON({{classname}}Json,
simplifyVector = FALSE)
self
}
),
private = list(
value = NULL
)
)

# add to utils.R
.parse_{{name}} <- function(vals) {
res <- gsub("^\\[|\\]$", "",
"{{{values}}}"
)
unlist(strsplit(res, ", "))
}
{{/allowableValues}}
4 changes: 3 additions & 1 deletion samples/client/petstore/R/R/api_client.R
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,9 @@ ApiClient <- R6::R6Class(
else if (exists(returnType, pkgEnv) && !(c(returnType) %in% primitiveTypes)) {
returnType <- get(returnType, envir = as.environment(pkgEnv))
returnObj <- returnType$new()
returnObj$fromJSON(jsonlite::toJSON(obj, digits = NA))
returnObj$fromJSON(
jsonlite::toJSON(obj, digits = NA, auto_unbox = TRUE)
)
}

# To handle primitive type
Expand Down
10 changes: 8 additions & 2 deletions samples/client/petstore/R/R/category.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@

#' @docType class
#' @title Category
#'
#' @description Category Class
#'
#' @format An \code{R6Class} generator object
#'
#' @field id integer [optional]
#'
#' @field name character [optional]
#'
#'
#' @importFrom R6 R6Class
#' @importFrom jsonlite fromJSON toJSON
#' @export
Expand All @@ -23,7 +25,9 @@ Category <- R6::R6Class(
public = list(
`id` = NULL,
`name` = NULL,
initialize = function(`id`=NULL, `name`=NULL, ...){
initialize = function(
`id`=NULL, `name`=NULL, ...
) {
local.optional.var <- list(...)
if (!is.null(`id`)) {
stopifnot(is.numeric(`id`), length(`id`) == 1)
Expand Down Expand Up @@ -55,6 +59,7 @@ Category <- R6::R6Class(
if (!is.null(CategoryObject$`name`)) {
self$`name` <- CategoryObject$`name`
}
self
},
toJSONString = function() {
jsoncontent <- c(
Expand Down Expand Up @@ -84,3 +89,4 @@ Category <- R6::R6Class(
}
)
)

10 changes: 8 additions & 2 deletions samples/client/petstore/R/R/model_api_response.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@

#' @docType class
#' @title ModelApiResponse
#'
#' @description ModelApiResponse Class
#'
#' @format An \code{R6Class} generator object
#'
#' @field code integer [optional]
#'
#' @field type character [optional]
#'
#' @field message character [optional]
#'
#'
#' @importFrom R6 R6Class
#' @importFrom jsonlite fromJSON toJSON
#' @export
Expand All @@ -26,7 +28,9 @@ ModelApiResponse <- R6::R6Class(
`code` = NULL,
`type` = NULL,
`message` = NULL,
initialize = function(`code`=NULL, `type`=NULL, `message`=NULL, ...){
initialize = function(
`code`=NULL, `type`=NULL, `message`=NULL, ...
) {
local.optional.var <- list(...)
if (!is.null(`code`)) {
stopifnot(is.numeric(`code`), length(`code`) == 1)
Expand Down Expand Up @@ -69,6 +73,7 @@ ModelApiResponse <- R6::R6Class(
if (!is.null(ModelApiResponseObject$`message`)) {
self$`message` <- ModelApiResponseObject$`message`
}
self
},
toJSONString = function() {
jsoncontent <- c(
Expand Down Expand Up @@ -106,3 +111,4 @@ ModelApiResponse <- R6::R6Class(
}
)
)

10 changes: 8 additions & 2 deletions samples/client/petstore/R/R/order.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@

#' @docType class
#' @title Order
#'
#' @description Order Class
#'
#' @format An \code{R6Class} generator object
#'
#' @field id integer [optional]
#'
#' @field petId integer [optional]
Expand All @@ -22,7 +25,6 @@
#'
#' @field complete character [optional]
#'
#'
#' @importFrom R6 R6Class
#' @importFrom jsonlite fromJSON toJSON
#' @export
Expand All @@ -35,7 +37,9 @@ Order <- R6::R6Class(
`shipDate` = NULL,
`status` = NULL,
`complete` = NULL,
initialize = function(`id`=NULL, `petId`=NULL, `quantity`=NULL, `shipDate`=NULL, `status`=NULL, `complete`=FALSE, ...){
initialize = function(
`id`=NULL, `petId`=NULL, `quantity`=NULL, `shipDate`=NULL, `status`=NULL, `complete`=FALSE, ...
) {
local.optional.var <- list(...)
if (!is.null(`id`)) {
stopifnot(is.numeric(`id`), length(`id`) == 1)
Expand Down Expand Up @@ -110,6 +114,7 @@ Order <- R6::R6Class(
if (!is.null(OrderObject$`complete`)) {
self$`complete` <- OrderObject$`complete`
}
self
},
toJSONString = function() {
jsoncontent <- c(
Expand Down Expand Up @@ -171,3 +176,4 @@ Order <- R6::R6Class(
}
)
)

10 changes: 8 additions & 2 deletions samples/client/petstore/R/R/pet.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@

#' @docType class
#' @title Pet
#'
#' @description Pet Class
#'
#' @format An \code{R6Class} generator object
#'
#' @field id integer [optional]
#'
#' @field category \link{Category} [optional]
Expand All @@ -22,7 +25,6 @@
#'
#' @field status character [optional]
#'
#'
#' @importFrom R6 R6Class
#' @importFrom jsonlite fromJSON toJSON
#' @export
Expand All @@ -35,7 +37,9 @@ Pet <- R6::R6Class(
`photoUrls` = NULL,
`tags` = NULL,
`status` = NULL,
initialize = function(`name`, `photoUrls`, `id`=NULL, `category`=NULL, `tags`=NULL, `status`=NULL, ...){
initialize = function(
`name`, `photoUrls`, `id`=NULL, `category`=NULL, `tags`=NULL, `status`=NULL, ...
) {
local.optional.var <- list(...)
if (!missing(`name`)) {
stopifnot(is.character(`name`), length(`name`) == 1)
Expand Down Expand Up @@ -115,6 +119,7 @@ Pet <- R6::R6Class(
if (!is.null(PetObject$`status`)) {
self$`status` <- PetObject$`status`
}
self
},
toJSONString = function() {
jsoncontent <- c(
Expand Down Expand Up @@ -176,3 +181,4 @@ Pet <- R6::R6Class(
}
)
)

10 changes: 8 additions & 2 deletions samples/client/petstore/R/R/tag.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@

#' @docType class
#' @title Tag
#'
#' @description Tag Class
#'
#' @format An \code{R6Class} generator object
#'
#' @field id integer [optional]
#'
#' @field name character [optional]
#'
#'
#' @importFrom R6 R6Class
#' @importFrom jsonlite fromJSON toJSON
#' @export
Expand All @@ -23,7 +25,9 @@ Tag <- R6::R6Class(
public = list(
`id` = NULL,
`name` = NULL,
initialize = function(`id`=NULL, `name`=NULL, ...){
initialize = function(
`id`=NULL, `name`=NULL, ...
) {
local.optional.var <- list(...)
if (!is.null(`id`)) {
stopifnot(is.numeric(`id`), length(`id`) == 1)
Expand Down Expand Up @@ -55,6 +59,7 @@ Tag <- R6::R6Class(
if (!is.null(TagObject$`name`)) {
self$`name` <- TagObject$`name`
}
self
},
toJSONString = function() {
jsoncontent <- c(
Expand Down Expand Up @@ -84,3 +89,4 @@ Tag <- R6::R6Class(
}
)
)

10 changes: 8 additions & 2 deletions samples/client/petstore/R/R/user.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@

#' @docType class
#' @title User
#'
#' @description User Class
#'
#' @format An \code{R6Class} generator object
#'
#' @field id integer [optional]
#'
#' @field username character [optional]
Expand All @@ -26,7 +29,6 @@
#'
#' @field userStatus integer [optional]
#'
#'
#' @importFrom R6 R6Class
#' @importFrom jsonlite fromJSON toJSON
#' @export
Expand All @@ -41,7 +43,9 @@ User <- R6::R6Class(
`password` = NULL,
`phone` = NULL,
`userStatus` = NULL,
initialize = function(`id`=NULL, `username`=NULL, `firstName`=NULL, `lastName`=NULL, `email`=NULL, `password`=NULL, `phone`=NULL, `userStatus`=NULL, ...){
initialize = function(
`id`=NULL, `username`=NULL, `firstName`=NULL, `lastName`=NULL, `email`=NULL, `password`=NULL, `phone`=NULL, `userStatus`=NULL, ...
) {
local.optional.var <- list(...)
if (!is.null(`id`)) {
stopifnot(is.numeric(`id`), length(`id`) == 1)
Expand Down Expand Up @@ -139,6 +143,7 @@ User <- R6::R6Class(
if (!is.null(UserObject$`userStatus`)) {
self$`userStatus` <- UserObject$`userStatus`
}
self
},
toJSONString = function() {
jsoncontent <- c(
Expand Down Expand Up @@ -216,3 +221,4 @@ User <- R6::R6Class(
}
)
)

Loading

0 comments on commit 8e95298

Please sign in to comment.