/
CreatePackageReport.R
280 lines (255 loc) · 10.4 KB
/
CreatePackageReport.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
#' R6 Class Representing an R Package Report
#'
#' @description
#' pkgnet compiles one or more package reporters into a package
#' report for a specified package. \code{PackageReport} is an R6 class that
#' holds all of those reporters and has a method \code{render_report()}
#' to generate an HTML report file. You can access each individual reporter
#' and modify it using its methods if you wish.
#'
#' The function \code{\link{CreatePackageReport}()} is a shortcut for both
#' generating a \code{PackageReport} object with instantiated reporters
#' and creating the HTML report in one call.
#'
#' @concept Reporters
#' @importFrom assertthat assert_that is.readable is.string is.writeable
#' @importFrom tools file_ext
#' @importFrom utils browseURL
#' @importFrom rmarkdown render
#' @export
PackageReport <- R6::R6Class(
classname = "PackageReport"
, public = list(
#' @description
#' Initialize an instance of a package report object.
#' @param pkg_name (character string) name of package
#' @param pkg_path (character string) optional directory path to source code of the package.
#' It is used for calculating test coverage. It can be an absolute or relative path.
#' @param report_path (character string) The path and filename of the output report.
#' Default report will be produced in the temporary directory.
#' @return Instantiated package report object.
initialize = function(pkg_name
, pkg_path = NULL
, report_path = tempfile(
pattern = pkg_name
, fileext = ".html"
)
) {
# Input validation for pkg_name, pkg_path
# report_path validated by its active binding
assertthat::assert_that(
assertthat::is.string(pkg_name)
, pkg_name != ""
, is.null(pkg_path) || assertthat::is.readable(pkg_path)
)
.validate_pkg_name(pkg_name)
private$protected$pkg_name <- pkg_name
private$protected$pkg_path <- pkg_path
self$report_path <- report_path
return(invisible(self))
}
#' @description
#' Add a reporter to the package report.
#' @param reporter Instantiated package reporter object
#' @return Self, invisibly
, add_reporter = function(reporter) {
private$set_reporter(reporter, class = class(reporter)[1])
return(invisible(self))
}
#' @description
#' Render html pkgnet package report.
#' @returns Self, invisibly.
, render_report = function() {
log_info("Rendering package report...")
rmarkdown::render(
input = system.file(
file.path("package_report", "package_report.Rmd")
, package = "pkgnet"
)
, output_dir = dirname(self$report_path)
, output_file = basename(self$report_path)
, quiet = TRUE
, params = list(
reporters = private$reporters
, pkg_name = self$pkg_name
)
)
log_info(paste(
"Done creating package report!"
, sprintf("It is available at %s", self$report_path)
))
# If suppress flag is unset, then env variable will be emptry string ""
if (identical(Sys.getenv("PKGNET_SUPPRESS_BROWSER"), "")) {
utils::browseURL(self$report_path)
}
return(invisible(self))
}
) # / public
, active = list(
#' @field pkg_name (character string) name of package. Read-only.
pkg_name = function() {
return(private$protected$pkg_name)
}
#' @field pkg_path (character string) path to source code of the package. Read-only.
, pkg_path = function() {
return(private$protected$pkg_path)
}
#' @field report_path (character string) path and filename of output report.
, report_path = function(report_path) {
if (!missing(report_path)) {
assertthat::assert_that(
assertthat::is.string(report_path)
, report_path != ""
)
if (!identical(tolower(tools::file_ext(report_path)), "html")){
log_fatal(paste(
"report_path must be a .html file path."
, sprintf("You gave '%s'.", report_path)
))
}
assertthat::assert_that(
assertthat::is.writeable(dirname(report_path))
)
private$protected$report_path <- report_path
}
return(private$protected$report_path)
}
#' @field SummaryReporter Instantiated pkgnet \code{\link{SummaryReporter}} object
, SummaryReporter = function(reporter) {
if (!missing(reporter)) {
private$set_reporter(reporter, class = "SummaryReporter")
}
return(private$reporters$SummaryReporter)
}
#' @field DependencyReporter Instantiated pkgnet \code{\link{DependencyReporter}} object
, DependencyReporter = function(reporter) {
if (!missing(reporter)) {
private$set_reporter(reporter, class = "DependencyReporter")
}
return(private$reporters$DependencyReporter)
}
#' @field FunctionReporter Instantiated pkgnet \code{\link{FunctionReporter}} object
, FunctionReporter = function(reporter) {
if (!missing(reporter)) {
private$set_reporter(reporter, class = "FunctionReporter")
}
return(private$reporters$FunctionReporter)
}
#' @field InheritanceReporter Instantiated pkgnet \code{\link{InheritanceReporter}} object
, InheritanceReporter = function(reporter) {
if (!missing(reporter)) {
private$set_reporter(reporter, class = "InheritanceReporter")
}
return(private$reporters$InheritanceReporter)
}
) # /active
, private = list(
protected = list(
pkg_name = NULL
, pkg_path = NULL
, report_path = NULL
)
, reporters = list()
, set_reporter = function(reporter, class) {
# If setting to NULL, it means we want to remove the reporter
if (is.null(reporter)) {
private$reporters[[class]] <- NULL
return(invisible(NULL))
}
# Validate that it's not an R6 generator
if (is.R6Class(reporter)) {
log_fatal(paste(
sprintf(
"You specified an R6 class generator for class %s."
, reporter$classname
)
, sprintf(
"PackageReport is expecting initialized %s object."
, class
)
))
}
assertthat::assert_that(
.is.PackageReporter(reporter)
, inherits(reporter, class)
)
private$reporters[[class]] <- reporter
private$reporters[[class]]$set_package(
pkg_name = self$pkg_name
, pkg_path = self$pkg_path
)
return(invisible(NULL))
}
) # /private
)
#' @title pkgnet Analysis Report for an R package
#' @name CreatePackageReport
#' @concept Main Functions
#' @description Create a standalone HTML report about a package and its networks.
#' @param pkg_name (string) name of a package
#' @param pkg_path (string) The path to the package repository. If given, coverage
#' will be calculated for each function. \code{pkg_path} can be an
#' absolute or relative path.
#' @param pkg_reporters (list) a list of package reporters
#' @param report_path (string) The path and filename of the output report. Default
#' report will be produced in the temporary directory.
#' @return an instantiated \code{\link{PackageReport}} object
#' @export
CreatePackageReport <- function(pkg_name
, pkg_reporters = DefaultReporters()
, pkg_path = NULL
, report_path = tempfile(pattern = pkg_name, fileext = ".html")
) {
# pkg_name, pkg_path, report_path validated by PackageReport
## pkg_reporters input checks ##
assertthat::assert_that(
is.list(pkg_reporters)
)
# Check if generators were passed in by accident
if (any(vapply(pkg_reporters, FUN = R6::is.R6Class, FUN.VALUE = logical(1)))) {
log_fatal(paste(
"At least one of pkg_reporters is an R6 class generator. This"
, "function expects initialized reporter objects."
))
}
# Confirm that all reporters are actually valid initialized reporters
assertthat::assert_that(
all(vapply(pkg_reporters
, FUN = .is.PackageReporter
, FUN.VALUE = logical(1)
))
, msg = "All members of pkg_reporters must be initialized package reporters."
)
# Confirm that all reporters are recognized by PackageReport
lapply(
X = pkg_reporters
, FUN = function(reporter) {
assertthat::assert_that(
class(reporter)[1] %in% names(PackageReport$active)
)
}
)
log_info(paste0("Creating package report for package "
, pkg_name
, " with reporters: "
, paste(unlist(lapply(pkg_reporters, function(x) class(x)[1]))
, collapse = ", ")))
## Create PackageReport object ##
createdReport <- PackageReport$new(
pkg_name = pkg_name,
pkg_path = pkg_path,
report_path = report_path
)
lapply(
X = pkg_reporters
, FUN = function(reporter) {
class <- class(reporter)[1]
createdReport[[class]] <- reporter
}
)
createdReport$render_report()
return(invisible(createdReport))
}
### Imports from package_report.Rmd
#' @importFrom knitr opts_chunk knit_child
NULL