Getting started
Introduction
ํจํค์ง๋ฅผ ๋ง๋๋ ์ด์
- ๋ค๋ฅธ ์ฌ๋๊ณผ ์ฝ๋ ๊ณต์
- ๋ค๋ฅธ ์ฌ๋๋ค์ด ๋ด ์ฝ๋๋ฅผ ์ฝ๊ฒ ์ดํดํ๊ณ ์ฌ์ฉํ ์ ์๊ฒ ๋งค๋ด์ผ ์์ฑ
- ๋ ์์ ์ด ๋ด ์ฝ๋๋ฅผ ์ฝ๊ฒ ์ดํดํ๊ณ ์ฌ์ฉํ ์ ์๊ฒ ๋งค๋ด์ผ ์์ฑ
Getting started
ํ์ํ ํจํค์ง&ํจ์๋ฅผ ์ค์นํ๋ค.
|
|
์ฌ๋ฐ๋ฅธ ๋ฒ์ ์ ํจํค์ง๋ฅผ ์ค์นํ๋์ง ํ์ธํ๋ค(TRUE๊ฐ ๋์์ผ ํจ).
|
|
|
|
ํ์ํ ๊ฒ ๋ชจ๋ ์ค์น๋๋์ง ํ์ธํ๋ค.
์๋ ์ฝ๋ ์ํ ๊ฒฐ๊ณผ TRUE๊ฐ ๋์ค๋์ง ํ์ธํ๋ค.
|
|
Package structure
- ํจํค์ง๋ฅผ ๋ง๋๋ ๊ณผ์
- ํจํค์ง์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ฐจ์ด์
Naming your package
Requirements for a name
- ๋ฌธ์, ์ซ์, ๋ง์นจํ๋ก ๊ตฌ์ฑ
- ๋ฌธ์๋ก ์์ํด์ผ ํ๊ณ , ๋ง์นจํ๋ ๋ง์ง๋ง์ ์ฌ ์ ์๋ค.
- ๋๋๋ก ๋ง์นจํ๋ ์ฐ์ง ๋ง์.
Strategies for creating a name
- ์ ๋ํฌํ ์ด๋ฆ: ๊ตฌ๊ธ๋ง ์ฝ๊ฒ ๋๋๋ก
- CRAN์์
ํด๋น ํจํค์ง๊ฐ ์ด๋ฏธ ์กด์ฌํ๋์ง ํ์ธํ๊ธฐ
- CRAN์์
- ๋์๋ฌธ์ ์์ง ๋ง๊ธฐ: ํ์ดํ, ๊ธฐ์ต ์ด๋ ต๋ค
- RGtk2
- ํจํค์ง์ ๊ธฐ๋ฅ์ ์ฝ๊ฒ ์ฐ์ํ ์ ์๋ ์ด๋ฆ
- lubridate: date์ times ๋ค๋ฃจ๊ธฐ ์ฝ๊ฒํ๋(lubricate)
- ์ถ์ฝํ(abbreviation) ์ฌ์ฉ
- r ์ถ๊ฐํด์ฃผ๊ธฐ
- stringr, readr, gistr, …
- ์์ฉ ํจํค์ง๋ฅผ ๊ฐ๋ฐํ ๊ฒฝ์ฐ, ํด๋น ํ์ฌ์ ๊ฐ์ด๋๋ผ์ธ ์์งํ๊ธฐ
- Dropbox๋ ๋ธ๋๋ ์ด๋ฆ์ผ๋ก ์ดํ๋ฆฌ์บ์ด์ ์ ๋ง๋ค์ง ๋ชปํ๊ฒ ํ๋ค. ๊ทธ๋์ rDropbox๊ฐ ์๋ rDrop์ด ๋์๋ค.
Creating a package
์ด๋ฆ์ ์ง์๋ค๋ฉด ์ ํจํค์ง๋ฅผ ๋ง๋ค์ด๋ณด์.
๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์๋๋ฐ, ๋ชจ๋ RStudio์์ ์งํ ๊ฐ๋ฅํ๋ค.
- RStudio - File - New Project - New Directory - R package - ์ด๋ฆ ์ ๋ ฅ ํ Create Project
- ์๋ ์ฝ๋๋ฅผ ์คํํ๋ค:
devtools::create("path/to/package/pkgname")
๋ ๋ฐฉ๋ฒ ๋ชจ๋ ์คํ ๊ฒฐ๊ณผ๋ ๊ฐ๋ค.
์์์ ๋ณด๋ฏ, ํจํค์ง ํ๋๋ฅผ ํ๋์ ํ๋ก์ ํธ๋ก ๊ฐ์ฃผํ๋ค.
**๊ฐ์ฅ ๋จ์ํ ๊ตฌ์ฑ์ ํจํค์ง(the smallest usable package)**๋ฅผ ์์ฑํ๋ค. ์ธ ๊ฐ์ง ์์๋ก ๊ตฌ์ฑ๋๋ค.
์ด์ ํจ๊ป, RStudio์์ ์์
ํ๊ธฐ ์์ํ๋๋ก pkgname.Rproj
๋ ์์ฑ๋๋ค.
# ์ฃผ์
package.skeleton() ํจ์๋ก ํจํค์ง ์์ฑ์ง ๋ง ๊ฒ!
์ ํจ์๋ ์ง๊ธ ํ์ํ ๊ฒ๋ณด๋ค ๋ง์ ๊ฒ์ ๋ง๋ค๊ธฐ ๋๋ฌธ์ ์ถํ ์์
๋์ด ๋์ด๋ ์ ์๋ค.
RStudio projects
ํจํค์ง๋ฅผ ํ๋์ ํ๋ก์ ํธ๋ก ๋ถ๋ฆฌํ๋ฉด ์ฌ๋ฌ ์ฅ์ ์ด ์๋ค.
- ๋ค๋ฅธ ํ๋ก์ ํธ์ ๋ ๋ฆฝ์ : ์๋ก ์ฝ๋ ์ํฅ ์์
- ๋ค์ํ ๋จ์ถํค ์ฌ์ฉ ๊ฐ๋ฅ(
Alt + Shift + K
)
pkgname.Rproj
ํ์ผ์ devtools::use_rstudio("path/to/package")
๋ช
๋ น์ด๋ก ์์ฑํ ์ ์๋ค.
What is an RStudio project file?
devtools
๊ฐ ๋ง๋ค์ด๋ด๋ ํ
์คํธํ์ผ์ด๋ค.
๊ด๋ จ ์ต์
์ RStudio - Projects Options…์์ ๋ณ๊ฒฝ ๊ฐ๋ฅํ๋ค.
What is a package?
๊ฐ๋จํ ํจํค์ง ์์ฑ์๋ ์์ ๋ด์ฉ์ผ๋ก ์ถฉ๋ถํ์ง๋ง,
ํจํค์ง๋ฅผ ๋ฐฐํฌํ ๋ ํจํค์ง์ ๋ค์ฏ ๊ฐ์ง ์ํ๋ฅผ ์์๋๋ฉด ๋์์ด ๋ ๊ฒ์ด๋ค.
- Lifecycle of a package
- source
- bundled
- binary
- installed
- in-memory
Source packages
์์ง ๊ฐ๋ฐ ์งํ์ค์ธ, ๋ด ์ปดํจํฐ์ ์ ์ฅ๋ผ์๋ ๊ฒ๋ค์ด๋ค.
์์์ ์์ฑํ R/
ํด๋, DESCRIPTION
ํ์ผ ๋ฑ์ด๋ค.
Bundled packages
A bundled package is a package thatโs been compressed into a single file.
ํ๋์ ํ์ผ๋ก ์์ถ๋ ํํ.
๋ฆฌ๋
์ค์์๋ tar.gz
ํ์ฅ์๋ฅผ ์ฌ์ฉํ๋ค. ํ๋์ ํ์ผ๋ก ๋ฌถ์ด์(.tar
) gzip์ผ๋ก ์์ถํ๋ค๋ (.gz
) ๋ป์ด๋ค.
devtools::build()
๋ก ์์ฑํ๋ค.
์์ถ ํด์ ํ Bundled package์ source package์ ์ฐจ์ด๋ ์๋์ ๊ฐ๋ค:
- Bp์๋ Vignettes๊ฐ ์๋ค(๋๋ถ์ html, PDF ์์ฑ ๊ฐ๋ฅ).
- Bp์๋ ๊ฐ๋ฐ ์ค ์์ฑ๋ ์์ํ์ผ(์ปดํ์ผ ๊ด๋ จ ๋ฑ)์ด ์๋ค.
- Bp์๋
.Rbuildignore
์ ์ ํ์๋ ๊ฒ๋ค์ด ์๋ค.
.Rbuildignore
์ด๋…
- source์๋ ์์ด์ผ ํ์ง๋ง bundle์๋ ์์ด์ผ ํ ๋ ๋ช ์ํด์ฃผ๋ฉด ์ข๋ค(๋ฐ์ดํฐ ๋ฑ)
- Perl ์ ํ์ ์ ๊ทํํ์์ ์ฌ์ฉํ๋ค.
- ํ ํ์๋ ํ ๊ฐ์ง ์์ธ ์ฌ๋ก๋ฅผ ์ ๋๋ค.
- ํน์ ํ์ผ์ด๋ ํด๋๋ฅผ ์ ์ธํ๊ณ ์ถ์ ๋, ๊ทธ ์ด๋ฆ์ ๊ทธ๋๋ก ์ฐ๋ฉด ์ ๋๋ค.
- notes๋ฅผ ์ ์ธํ๊ณ ์ถ๋ค๋ฉด
^notes$
ํน์devtools::use_build_ignore("notes")
๋ฅผ ์ฌ์ฉํ๋ค. - notes๋ฅผ ์ฌ์ฉํ๋ฉด ์ด๋ฆ์ notes๊ฐ ํฌํจ๋ ๋ชจ๋ ํ์ผ์ด ์ ์ธ๋๋ค.
- notes๋ฅผ ์ ์ธํ๊ณ ์ถ๋ค๋ฉด
Hadley์ ์์:
^.*\.Rproj$ # Automatically added by RStudio,
^\.Rproj\.user$ # used for temporary files.
^README\.Rmd$ # An Rmarkdown file used to generate README.md
^cran-comments\.md$ # Comments for CRAN submission
^NEWS\.md$ # A news file written in Markdown
^\.travis\.yml$ # Used for continuous integration testing with travis
Binary packages
If you want to distribute your package to an R user who doesnโt have package
development tools, youโll need to make a binary package.
Package development tools๋ฅผ ๊ฐ์ง๊ณ ์์ง ์์ ์ ์ ์๊ฒ ๋ฐฐํฌํ ๋๋ Binary ํํ๋ก ๋ง๋ค์ด์ผ ํ๋ค.
A package bundle๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ํ๋์ ํ์ผ๋ก ์์ถ๋ ํํ์ง๋ง,
(bundle๊ณผ ๋ฌ๋ฆฌ) ์์ถ์ ํด์ ํ์ ๋ source์๋ ๋ด๋ถ ๊ตฌ์กฐ๊ฐ ๋ค๋ฅด๋ค:
R/
ํด๋์.R
ํ์ผ์ด ์๋ค.Meta/
ํด๋์Rds
ํ์ผ์ด ๋ค์ด์๋ค.- ํจํค์ง ์ค๋ช ๋ฑ
readRDS()
๋ก ์ฝ์ ์ ์๋ค.
html/
ํด๋- HTML ํ์์ ๋์๋ง
src/
์ ์๋ ์ฝ๋๋libs/
์ ์ ์ฅ๋๋ค.- 32๋นํธ๋
i386/
, 64๋นํธ๋x64/
- 32๋นํธ๋
inst/
๊ฐ ์ต์์ ๊ฒฝ๋ก์ ์์นํ๋ค.
Binary๋ ํ๋ซํผ ๊ฐ ํธํ์ด ์ ๋๋ค.
Windows์ binary(.zip
)๋ macOS์์ ์ ์ด๋ฆฌ๊ณ , ๋ฐ๋๋ก macOS์ binary(tgz
)๋ Windows์์ ์ด ์
์๋ค.
devtools::build(binary = TRUE)
๋ช
๋ น์ด๋ก ์์ฑํ๋ค.
Installed packages
An installed package is just a binary package thatโs been decompressed into a
package library.
์์ถ ํด์ ํ binary.
์ง๊ธ๊น์ง ๋ฐฐ์ด ๋ฐ๋ก๋ source -> bundle / binary -> installed ์์๋ก ๋ฐฐํฌ๋ฅผ ์งํํ๋ฉด ๋ ๊ฒ ๊ฐ๋ค.
ํ์ง๋ง ์ค์ ๋ก๋ ๋ ๋ค์ํ ๋ฐฉ๋ฒ์ผ๋ก ๋ฐฐํฌํ ์ ์๋ค.
The tool that powers all package installation is the command line tool R CMD
INSTALL - it can install a source, bundle or a binary package.
์ปค๋งจ๋๋ผ์ธ์์ R CMD INSTALL
๋ก source, bundle, binary ์ค์น ๊ฐ๋ฅํ๋ค.
R์์ ์ปค๋งจ๋๋ผ์ธ ๋ช
๋ น์ด ์คํํ ์ ์๋ค:
devtools::install()
:R CMD INSTALL
์คํdevtools::build()
:R CMD build
์คํ(source -> bundle)devtools::install_github()
: GitHub์์ source ๋ค์ด๋ก๋ + vignettes ์์ฑ(build()
)
- install(
R CMD INSTALL
)
install.packages()
,devtools::install_url()
,
devtools::install_gitorious()
,devtools::install_bitbucket()
- ๋ชจ๋
devtools::install_github()
์ ๋น์ทํ ์ญํ ์ ํ๋ค.
- ๋ชจ๋
.Rinstignore
์ ์ฌ์ฉํด ํน์ ํ์ผ ๋ฐ ํด๋๋ฅผ installํ ๋ชฉ๋ก์์ ๋บ ์ ์๋ค(.Rbuildignore
์ ๊ฐ์ ๋ฐฉ์).
In memory packages
ํจํค์ง๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ๋ฉ๋ชจ๋ฆฌ๋ก ๋ถ๋ฌ๋ค์ฌ์ผ ํ๋ค(load).
ํจํค์ง ์ด๋ฆ์ ์๋ตํ๋ ค๋ฉด(e.g. devtools::install()
๋์ install()), "search path"์ ๋ถ์ฌ์ผ
ํ๋ค(attach).
library()` ํจ์๋ก loading + attaching์ ์ํํ ์ ์๋ค.
# Automatically loads devtools
devtools::install()
# Loads and _attaches_ devtools to the search path
library(devtools)
install()
loading๊ณผ attaching์ ํจํค์ง๋ฅผ ๋ง๋ค ๋๋ ์์๋๋ ๊ฒ ์ข๋ค(๋จ์ scriptingํ ๋๋ ๊ตณ์ด ํ์ ์๋ค).
๋ค์ search path ์ฑํฐ์์ ์์ธํ ๋ค๋ฃฐ
์์ ์ด๋ค.
ํจํค์ง ์ ์ ๋ library()
ํจ์๋ฅผ ์ฃผ๋ก ์ฌ์ฉํ์ง๋ง, ํจํค์ง ๊ฐ๋ฐํ ๋๋ ๊ทธ๋ค์ง ์ ์ฉํ์ง ์๋ค. ๊ทธ ํจํค์ง๋ฅผ ๋จผ์ ์ค์นํด์ผ ํ๊ธฐ
๋๋ฌธ์ด๋ค.
๋์ค์ devtools::load_all()
๋ช
๋ น์ด๋, RStudio์ โBuild and reloadโ ๊ธฐ๋ฅ์ ๋ฐฐ์ธ ๊ฒ์ด๋ค. ์ด๋ฅผ ํตํด
์ค์นํ์ง ์๊ณ ๋ ์์ค ์ฝ๋๋ฅผ ๋ฉ๋ชจ๋ฆฌ๋ก ๋ถ๋ฌ๋ค์ผ ์ ์๋ค.
What is a library?
A library is simply a directory containing installed packages.
๋ผ์ด๋ธ๋ฌ๋ฆฌ = ํ ํจํค์ง์ ํด๋. ์์ค๊ฐ ์๋ installed package๋ฅผ ๋ด๊ณ ์๋ ํด๋๋ค.
R์ ์ค์นํ ๋ **์๋์ผ๋ก ์ค์น๋๋ ๊ฒ(e.g. base, stats, …)**๊ณผ ์ฌ์ฉ์๊ฐ ์ค์นํ ๊ฒ์ด ์๋ค. R์ ๋ค์ ์ค์นํ ๋
์ฌ์ฉ์๊ฐ ์ค์นํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์ด๋ฒ๋ฆด ์ ์๋ค(ํ๋๋๋ผ์ด๋ธ์๋ ์์ง๋ง R์ด ์ฐพ์ง ๋ชปํ๋ ๊ฒ).
.libPaths()
๋ช
๋ น์ด๋ก ํ์ฌ ์ฌ์ฉํ๋ R์ ์ค์น๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ชฉ๋ก์ ๋ณผ ์ ์๋ค.
.libPaths()
#> [1] "/Users/hadley/R"
#> [2] "/Library/Frameworks/R.framework/Versions/3.1/Resources/library"
lapply(.libPaths(), dir)
#> [[1]]
#> [1] "AnnotationDbi" "ash" "assertthat"
#> ...
#> [163] "xtable" "yaml" "zoo"
#>
#> [[2]]
#> [1] "base" "boot" "class" "cluster"
#> [5] "codetools" "compiler" "datasets" "foreign"
#> [9] "graphics" "grDevices" "grid" "KernSmooth"
#> [13] "lattice" "MASS" "Matrix" "methods"
#> [17] "mgcv" "nlme" "nnet" "parallel"
#> [21] "rpart" "spatial" "splines" "stats"
#> [25] "stats4" "survival" "tcltk" "tools"
#> [29] "translations" "utils"
.libPaths()
์คํ ๊ฒฐ๊ณผ์์ [1]์ ์ฌ์ฉ์๊ฐ ์ค์นํ, [2]๋ ๊ธฐ๋ณธ์ผ๋ก ์ค์น๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๊ฒฝ๋ก๋ค.
library(pkg)
๋๋ require(pkg)
๋ช
๋ น์ด๋ฅผ ์ฌ์ฉํ๋ฉด R์ .libPaths()
์์ ํด๋น ํจํค์ง๊ฐ ์๋์ง ๊ฒ์ฌํ๋ค.
๋ง์ฝ ์๋ค๋ฉด ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
library(blah)
## Error in library(blah): there is no package called 'blah'
# or:
require(blah)
## Loading required package: blah
## Warning in library(package, lib.loc = lib.loc, character.only = TRUE,
## logical.return = TRUE, : there is no package called 'blah'
library(pkg)
์ require(pkg)
๋ ํจํค์ง๋ฅผ ๋ฐ๊ฒฌํ์ง ๋ชป ํ์ ๋ ๋์ฒ ๋ฐฉ์์ด ๋ค๋ฅด๋ค.
library()
๋ ์๋ฌ๋ฅผ ๋ฐ์์ํค๋ ๋ฐ๋ฉด, require()
๋ ๊ฒฝ๊ณ ๋ฉ์ธ์ง์ ํจ๊ป๊ป FALSE๋ฅผ ๋ฐํํ๋ค. ํจํค์ง ๊ฐ๋ฐ
์ค์๋ ์์ค์ฝ๋์ ์ ๋๋ก library(pkg)
๋ require(pkg)
๋ฅผ ์ฌ์ฉํ๋ฉด ์ ๋๋ค. ๋์ ์ด๋ป๊ฒ ํด์ผ ํ๋์ง๋
package dependencies๋ฅผ
์ฐธ์กฐ.
Package components
R Code (R/
)
R code workflow
- Edit an R file.
- Press Ctrl/Cmd + Shift + L.
- Explore the code in the console.
- Rinse and repeat.
???
Organising your functions
๋๋๋ก ๊ทน๋จ์ ์ธ ๋ฐฉ์์ ํผํ์(ํ ํ์ผ์ ๋ชจ๋ ํจ์ ๋๋ ค๋ฃ๊ธฐ ๋๋ ๋ชจ๋ ํจ์๋ง๋ค ํ์ผ ๋ฐ๋ก ๋ง๋ค๊ธฐ).
์ด๋ฆ์ ์๋ฏธ ์๋ ๊ฒ์ผ๋ก ์ ํ์.
My rule of thumb is that if I canโt remember the name of the file where a
function lives, I need to either separate the functions into more files or give
the file a better name.
ํ ํ์ผ ๋ด์์๋ ํจ์ ์์น๊ฐ ๊ทธ๋ ๊ฒ ์ค์ํ์ง ์๋ค. ๋จ์ถํค๋ก ํจ์ ์ฌ์ด๋ฅผ ๋๋๋ค ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
- ์๋ํฐ ๋ด์์ ํจ์ ์ด๋ฆ ํด๋ฆญํ๊ณ
F2
๋๋ฅด๊ธฐ Ctrl + .
๋๋ฅด๊ณ ํจ์ ์ด๋ฆ ๊ฒ์ํ๊ธฐ
Code style
You donโt have to use my style, but I strongly recommend that you use a
consistent style and you document it.
๊ทธ๋ฅ ์ ๋ช
ํ ๊ฑฐ ์ฐ์([Hadley’s style or Google’s R style
guide).
ํน์ ์คํ์ผ๋ง ํจ์๋ฅผ ์ฌ์ฉํด๋ณด์.
formatR
ํจํค์ง
install.packages("formatR")
formatR::tidy_dir("R")
linter
ํจํค์ง
install.packages("lintr")
lintr::lint_package()
Top-level code
source()
๋ก ๋ถ๋ฅผ ์ ์๋ scripts vs. ํจํค์ง:
- script๋ฅผ ์ฝ์ด๋ค์ด๋ฉด ์๋์ผ๋ก ์คํ๋๋ค. ํจํค์ง๋ ๋น๋๋ง ๋๋ค(์ค๋ธ์ ํธ ์์ฑ =
.RData
๋ฅผ ์ฝ์ด๋ค์ด๋ ์ ). - ํจํค์ง์ ํจ์๋ ๋ด๊ฐ ๋ชจ๋ฅด๋ ์ํฉ์๋ ์ฌ์ฉ๋ ์ ์๋๋ก ๋ง๋ค์ด์ผ ํ๋ค(๋ฐฐํฌํด์ผ ํ๋ฏ๋ก).
Loading code
source()
๋ก ์คํฌ๋ฆฝํธ๋ฅผ ๋ถ๋ฌ๋ค์ด๋ฉด ์ฆ์ ์คํ๋๋ค. ๋ฐ๋ฉด, ํจํค์ง๋ฅผ ๋น๋ํ ๋๋ R/
์ ๋ชจ๋ ์ฝ๋๊ฐ ์คํ๋์ด ๊ทธ ๊ฒฐ๊ณผ๊ฐ ์ ์ฅ๋๋ค.
ํจํค์ง๋ฅผ loadํ๋ฉด ๋น๋ํ ๋ ์ ์ฅํ๋ ๊ฒฐ๊ณผ๋ง ๋ฉ๋ชจ๋ฆฌ์ ์ฝ์ด๋ค์ธ๋ค. ์ด๋ฅผ ์คํฌ๋ฆฝํธ๋ก ํํํ๋ฉด ์๋์ ๊ฐ๋ค:
# Load a script into a new environment and save it
env <- new.env(parent = emptyenv())
source("my-script.R", local = env)
save(envir = env, "my-script.Rdata")
# Later, in another R session
load("my-script.Rdata")
๋ค๋ฅธ ์๋ฅผ ๋ค๋ฉด, ๋ง์ฝ x <- Sys.time()
์ ์คํฌ๋ฆฝํธ์ ์ ์ฅํ๊ณ source()
ํ๋ฉด ์คํฌ๋ฆฝํธ๊ฐ ์คํ๋๊ธฐ ๋๋ฌธ์
source()
ํ ๋์ ์๊ฐ์ด x
์ ์ ์ฅ๋๋ค. ๋ฐ๋ฉด ํจํค์ง์ ๊ฒฝ์ฐ x
์๋ ๋น๋ํ๋ ์๊ฐ์ด ๊ธฐ๋ก๋ผ์๋ค(๋ค์ ์คํํ์ง ์๊ธฐ ๋๋ฌธ).
This means that you should never run code at the top-level of a package.
# foo package
library(ggplot2)
show_mtcars <- function() {
qplot(mpg, wt, data = mtcars)
}
์์ ๊ฐ์ด ์ฝ๋๋ฅผ ์์ฑํ๊ณ ํจํค์ง๋ก ๋ง๋ค์ด์ ์ฌ์ฉํ๋ฉด
library(foo)
show_mtcars()
์๋ฌ๊ฐ ๋ฐ์ํ๋ค. foo
๋ library(ggplot2)
๋ฅผ ์คํํ์ง ์๊ธฐ์ show_mtcars()
์ ์๋ qplot()
์ด ์คํ๋
์ ์๋ค.
์๋์ ๊ฐ์ด ์์ฑํด๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
show_mtcars <- function() {
library(ggplot2)
qplot(mpg, wt, data = mtcars)
}
๋ฐ๋ผ์, DESCRIPTION
ํ์ผ์ ํด๋น ํจํค์ง๋ฅผ ์คํํ๊ธฐ ์ํด ํ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ช
์ํด์ฃผ๋ ๊ฒ ์ข๋ค. package
dependencies์ฐธ๊ณ .
The R landscape
ํจํค์ง๋ ๋ด๊ฐ ๋ชจ๋ฅด๋ ์ฌ๋์ด ๋ด๊ฐ ๋ชจ๋ฅด๋ ์ํฉ, ํ๊ฒฝ์์ ์ฌ์ฉํ ์ ์๋ค. ๊ทธ๋ฌ๋ฏ๋ก ๋ด๊ฐ ์์ฑํ ํจ์๋ ๊ฐ์ฒด๋ฟ๋ง ์๋๋ผ global
setting๋ ํจ๊ป ๊ณ ๋ คํด์ผ ํ๋ค. ์ฆ, global setting์ ํจ๋ถ๋ก ๋ณ๊ฒฝ์ํค๋ ์ฝ๋๋ฅผ ํจํค์ง์ ํฌํจํ๋ฉด ์ ๋๋ค(๋ด ํน์ ์ํฉ์๋ง
์คํ๋๋ ์ฝ๋๊ฐ ๋ง๋ค์ด์ง ์ ์๋ค).
library()
๋require()
๋ฅผ ์ฌ์ฉํ์ง ์๋๋ค. ์ด ๋ ํจ์๋ search path๋ฅผ ๋ฐ๊พธ๊ธฐ ๋๋ฌธ์ ํด๋น global
environment์์ ์ฌ์ฉํ ์ ์๋ ํจ์์ ์ข ๋ฅ์ ์ํฅ์ ๋ฏธ์น๋ค.- ์ ๋๋ก
source()
๋ฅผ ์ฌ์ฉํ์ง ์๋๋ค(current environment๊ฐ ๋ฐ๋๊ฒ ๋๋ค). ๋์ ,
devtools::load_all()
๋ฅผ ์ฌ์ฉํ๋ฉดR/
์ ์๋ ๋ชจ๋ ์คํฌ๋ฆฝํธ๋ฅผ ๋ถ๋ฌ์ฌ ์ ์๋ค. Dataset์ ๋ง๋ค๊ณ ์ถ๋ค๋ฉด
data/
๋ฅผ ํ์ฉํ๋ค(datasets ์ฐธ๊ณ ). - global setting์ ๋ณ๊ฒฝํ ํ์๋
on.exit()
๋ฅผ ์ด์ฉํด ๊ธฐ๋ณธ๊ฐ์ผ๋ก ๋๋๋ ค๋์.
old <- options(stringsAsFactors = FALSE)
on.exit(options(old), add = TRUE)
old <- setwd(tempdir())
on.exit(setwd(old), add = TRUE)
- plotting, printing๋ ๋ชจ๋ global environment์ ์ํฅ์ ๋ฏธ์น๋ค. ๊ฐ๊ฐ ํจ์๋ก ์ฒ๋ฆฌํ๋ฉด ํด๊ฒฐํ ์
์๋ค(e.g. ๋ฐ์ดํฐ ๊ฐ๊ณต ํจ์/๊ทธ๋ฆผ ๊ทธ๋ฆฌ๋ ํจ์ ๋ฐ๋ก ์์ฑ) .
๋ฐ๋๋ก, ๋ค๋ฅธ ์ฌ์ฉ์์ R environment์์๋ง ๊ตฌ๋๋๊ฒ ํด์๋ ์ ๋๋ค. ์๋ฅผ ๋ค์ด, read.csv()
์
stringsAsFactors
๋ฅผ ํจํค์ง์์๋ ๊ธฐ๋ณธ๊ฐ์ธ TRUE
๋ฅผ ์ฌ์ฉํ์ง๋ง, ์ด๋ค ์ฌ๋์ FALSE
๋ก ์ค์ ํ์ ์ ์๋ค.
When you do need side-effects
์์์๋ global environment๋ฅผ ๊ฑด๋๋ฆฌ์ง ๋ง๋ผ๊ณ ์ค๋ช
ํ์ง๋ง,๋ฐ๋๋ก ํจํค์ง๋ฅผ ์ฌ์ฉํ๊ธฐ ์ ์ ํน์ ํ ์ค์ ์ด ํ์ํ ๋๊ฐ ์๋ค.
์ด ๋๋, .onLoad()
๋ .onAttach()
๋ฅผ ์ฌ์ฉํ ์
์๋ค(Namespaces ์ฐธ๊ณ ). ํน์ ์ํฉ์ด
์๋๋ผ๋ฉด .onLoad()
๋ฅผ ์ฌ์ฉํ์.
.onLoad()
์ .onAttach()
ํ์ฉ ์ฌ๋ก
- ํน์ ๋ฉ์ธ์ง๋ฅผ ๋ณด์ฌ์ฃผ๊ณ ์ถ์ ๋(startup messages):
.onAttach()
์ฌ์ฉ
.onAttach <- function(libname, pkgname) {
packageStartupMessage("Welcome to my package")
}
options()
๋ก ํน์ ํ ์ค์ ์ด ํ์ํ ๋: ์ต์ ์ค์ ํ๊ธฐ ์ ์ ๋ด ํจํค์ง ์ด๋ฆ์ prefix๋ก ๋ถ์ฌ์ฃผ๊ธฐ + ๋ค๋ฅธ ์ฌ์ฉ์์ ์ค์
overrideํ์ง ์๊ธฐ.- Hadley๊ฐ ์์ฃผ ์ฐ๋ ์ค์
.onLoad <- function(libname, pkgname) {
op <- options()
op.devtools <- list(
devtools.path = "~/R-dev",
devtools.install.args = "",
devtools.name = "Your name goes here",
devtools.desc.author = "First Last <first.last@example.com> [aut, cre]",
devtools.desc.license = "What license is it under?",
devtools.desc.suggests = NULL,
devtools.desc = list()
)
toset <- !(names(op.devtools) %in% names(op))
if(any(toset)) options(op.devtools[toset])
invisible()
}
- ๋ค๋ฅธ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๋ฅผ ์ฌ์ฉํ ๋(e.g. cpp:
Rcpp::loadRcppModules()
) - vignette engines์ ๋ฑ๋กํ ๋:
tools::vignetteEngine()
.onLoad()
์ฌ์ฉ ํ์๋ .onUnload()
๋ก ํด์ ํด์ฃผ์.
S4 classes, generics and methods
S4 ํด๋์ค๋ฅผ ์ ์ํ ๋๋ environment๋ฅผ ๊ฑด๋๋ ค์ผ ํ๋ฉฐ(generic, class ์ ์ …), DESCRIPTION
ํ์ผ์
Collate
๋ณ์๋ฅผ ํ์ฉํ ์ ์๋ค. ์์ธํ ๋ด์ฉ์ documenting
S4๋ฅผ ์ฐธ๊ณ ํ์.
CRAN notes
(๋งค ์ฑํฐ ๋ง์ง๋ง์ CRAN์ ํจํค์ง๋ฅผ ๋ฑ๋กํ๊ธฐ ์ํ ํ์ ๋ง๋ จํ๋ค. CRAN์ ๋ฑ๋กํ ๊ณํ์ด ์๋ค๋ฉด ๋์ด๊ฐ๋ ์ข๋ค.)
.R
์ ASCII ๋ฌธ์๋ง ์ฌ์ฉํ๊ธฐ!
\u1234
์ ๊ฐ์ ํ์์ผ๋ก ์ ๋์ฝ๋๋ฅผ ์ฌ์ฉํ ์๋ ์๋ค. ํน์ stringi::stri_escape_unicode()๋ฅผ ์ฌ์ฉํด๋ ๋๋ค:
x <- "This is a bullet โข"
y <- "This is a bullet \u2022"
identical(x, y)
## [1] TRUE
cat(stringi::stri_escape_unicode(x))
## This is a bullet \u2022
Package metadata (DESCRIPTION
)
Every package must have a DESCRIPTION. In fact, itโs the defining feature of a
package (RStudio and devtools consider any directory containing DESCRIPTION to
be a package).
devtools::create("mypackage")
๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ๋จํ description ํ์ผ์ด ์์ฑ๋๋ค:
Package: mypackage
Title: What The Package Does (one line, title case required)
Version: 0.1
Authors@R: person("First", "Last", email = "first.last@example.com",
role = c("aut", "cre"))
Description: What the package does (one paragraph)
Depends: R (>= 3.1.0)
License: What license is it under?
LazyData: true
ํจํค์ง๋ฅผ ์ฌ๋ฟ ๋ง๋ค ๋๋ ๊ฐ ํ๋์ ๊ธฐ๋ณธ๊ฐ์ ์ค์ ํ ์๋ ์๋ค(devtools.desc.author
,
devtools.desc.license
, devtools.desc.suggests
, devtools.desc
).
DESCRIPTION
ํ์ผ์ DCF(the Debian control format) ํ์์ ์ฌ์ฉํ๋ค. ๊ฐ ์ค์ ํ๋์ด๋ฆ: ๊ฐ์ผ๋ก
์ด๋ค์ง๊ณ , ๊ฐ์ด ๋ ์ค ์ด์์ด๋ฉด ๋ค์ฌ์ฐ๊ธฐํ๋ค.
Description: The description of a package is usually long,
spanning multiple lines. The second and subsequent lines
should be indented, usually with four spaces.
๋ณธ ์ฑํฐ์์๋ ์ฃผ์ ํ๋ ๋ช ๊ฐ์ง๋ฅผ ์๊ฐํ๋ ค ํ๋ค.
Dependencies: What does your package need?
Title and description: What does your package do?
Author: who are you?
License: Who can use your package?
Version
Other components
Object documentation (man/
)
Documentation is one of the most important aspects of a good package.
๋ฌธ์ํ(documentation)๋ฅผ ์ ํด๋๋ฉด ๋์ ๋ค๋ฅธ ์ฌ๋ ๋ชจ๋์๊ฒ ๋์์ด ๋๋ค. ์ฌ๋ฌ ์์์ ๋ฌธ์ํ ๋ฐฉ๋ฒ์ด ์๋๋ฐ, ๋ณธ ์ฑํฐ์์๋ ?
๋
help()
๋ก ์ด์ด๋ณผ ์ ์๋ orient documentation์ ๋ํด ์ค๋ช
ํ๋ ค ํ๋ค.
Orient documentation์ ์ฌ์ ๊ณผ ๋น์ทํ๋ค. ๋ด๊ฐ ์ฐพ์์ผ ํ๋ ๊ฒ์์ด๊ฐ ๋ฌด์์ธ์ง ์ ๋๋ ์ ์ฉํ์ง๋ง, ๋ฐ๋๋ก ํด๊ฒฐํด์ผ ํ
๋ฌธ์ ๋ง ์๊ณ ์ด๋ฅผ ์ํด ์ด๋ค ๊ฒ์์ด๊ฐ ํ์ํ์ง ๋ชจ๋ฅผ ๋๋ ๋ถํธํ ์ ์๋ค. ์ด๋ฐ ๊ฒฝ์ฐ์๋ vignettes๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ค(๋ค์ ์ฑํฐ).
R์์ object documentationํ๋ ๋ฐฉ๋ฒ์ man/
ํด๋์ .Rd
ํ์ผ์ ์์ฑํ๋ ๊ฒ์ด๋ค. LaTeX ๋ฑ์ผ๋ก ์์ฑํ ํ
HTML, ํ
์คํธ, pdf ๋ฑ์ผ๋ก ๋ณํ๋๋ค. ์ด๋ฅผ ์ง์ ํ๋ ๊ฒ๋ณด๋ค๋, roxygen2 ํจํค์ง๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ํจ์ฌ ์ข๋ค. ๋ฟ๋ง ์๋๋ผ
roxygen2๋ก DESCRIPTION
ํ์ผ์ NAMESPACE
ํ๋์ Collate
ํ๋๋ ๊ด๋ฆฌํ ์ ์๋ค. ๋ณธ ์ฑํฐ์์๋
.Rd
ํ์ผ๊ณผ Collate
ํ๋์ ๋ํด ๋ค๋ฃฐ ๊ฒ์ด๊ณ , ๋๋จธ์ง๋
NAMESPACE ์ฑํฐ์์ ๋ค๋ฃฐ ์์ ์ด๋ค.
The documentation workflow
4๋จ๊ณ ์ ์ฐจ๊ฐ ์๋ค.
.R
ํ์ผ์ oxygen ์ฝ๋ฉํธ ์ถ๊ฐํ๊ธฐdevtools::document()
์คํ(๋๋ RStudio์์Ctrl/Cmd
+Shift
+D
)
* oxygen ์ฝ๋ฉํธ๋ฅผ `.Rd` ํ์ผ๋ก ๋ณํํ๋ค(`devtools::document()`๊ฐ `roxygen2::roxygenise()`๋ฅผ ์คํํจ)
?
๋ก ๋ฏธ๋ฆฌ๋ณด๊ธฐ- ๋ค๋ฌ๊ธฐ
oxygen ์ฝ๋ฉํธ๋ #'
์ผ๋ก ์์ํ๋ค(์์๋ฐ์ดํ๊ฐ ์ถ๊ฐ๋๋ค).
#' Add together two numbers.
#'
#' @param x A number.
#' @param y A number.
#' @return The sum of \code{x} and \code{y}.
#' @examples
#' add(1, 1)
#' add(10, 1)
add <- function(x, y) {
x + y
}
Ctrl/Cmd
+ Shift
+ D
๋ฅผ ๋๋ฅด๊ฑฐ๋ devtools::document()
๋ฅผ ์คํํ๋ฉด ์๋์ ๊ฐ์ man/add.Rd
๊ฐ ์์ฑ๋๋ค:
% Generated by roxygen2 (4.0.0): do not edit by hand
\name{add}
\alias{add}
\title{Add together two numbers}
\usage{
add(x, y)
}
\arguments{
\item{x}{A number}
\item{y}{A number}
}
\value{
The sum of \code{x} and \code{y}
}
\description{
Add together two numbers
}
\examples{
add(1, 1)
add(10, 1)
}
์ฒซ ๋ฒ์งธ ์ค์ “%~~"๋ roxygen2 ์์ฑํ ํ์ผ์ด๊ณ ์์ ํ๋ฉด ์ ๋๋ค. ๋ณดํต add.Rd
ํ์ผ์ ๋ค์ฌ๋ค ๋ณผ ์ผ์ ์์ ๊ฒ์ด๋ค.
R extensions ๋ฉ๋ด์ผ์
๋ ์์ธํ ์ ๋ณด๊ฐ ๋์์๋ค.
?add
๋ help("add")
๋ example("add")
๋ฅผ ์คํํ๋ฉด R์ \alias{"add"}
๊ฐ ๋ค์ด์๋ .Rd
ํ์ผ์
์ฐพ์์ ํ์ฑํ๋ค. ๊ฒฐ๊ณผ๋ ์๋์ ๊ฐ๋ค.
๋ฌธ์๋ฅผ ๋ฏธ๋ฆฌ ๋ณด๋ ๊ฒ ๊ฐ๋ฅํ๋ค. ๋ง์ฝ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๊ฐ ๋์ง ์๋๋ค๋ฉด devtools๋ฅผ ์ฌ์ฉํ๊ณ ์๋์ง, devtools::load_all()
๋ฅผ
์คํํ๋์ง ํ์ธํ์.
Alternative documentation workflow
object documentation์ ๋น ๋ฅด์ง๋ง, ๋ฌธ์์ ๋งํฌ๋ฅผ ํฌํจํ ์ ์๋ค. ๋ง์ฝ ๋งํฌ๋ฅผ ํฌํจํ๊ณ ์ถ๋ค๋ฉด ์ด ์ฑํฐ์์ ์๊ฐํ๋
๋ฐฉ๋ฒ์ ์ฌ์ฉํด๋ณด์.
.R
ํ์ผ์ roxygen ์ฝ๋ฉํธ ์ถ๊ฐํ๊ธฐ- ๋ฒํผ์ ํด๋ฆญํ๊ฑฐ๋
Ctrl/Cmd
+Shift
+B
๋๋ฅด๊ธฐ.- ํจํค์ง๊ฐ ๋ค์ ๋น๋๋๋ค(๋ฌธ์ ์์ ์ฌํญ ๋ฐ์, ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ค์น, R ์ฌ์์, ํจํค์ง ๋ก๋)
- ๋๋ฆฌ์ง๋ง ํ์คํ ๋ฐฉ๋ฒ
?
๋ก ๋ฏธ๋ฆฌ๋ณด๊ธฐ- ๋ค๋ฌ๊ธฐ
์ ๋ฐฉ๋ฒ์ ์คํํ๊ธฐ ์ ์ ์๋ ์ต์ ์ ํ์ธํด๋ณผ ๊ฒ!
Roxygen comments
Roxygen comments start with #’ and come before a function.
ํจ์ ์์ ์์นํ roxygen ๊ตฌ๋ฌธ์ ํ๋์ **๋ธ๋ก(block)**์ด๋ผ ํ๋ค. ๋ธ๋ก์ @tagName details
์ ๊ฐ์ ํ์์
**ํ๊ทธ(tag)**๋ก ์ด๋ค์ง๋ค. ํ๊ทธ์์ @
๋ฅผ ์ฌ์ฉํ๊ณ ์ถ์ผ๋ฉด @@
๋ฅผ ์
๋ ฅํด์ผ ํ๋ค(@
๋ ๋ค๋ฅธ ์๋ฏธ๊ฐ ์์). ๊ฐ ๋ธ๋ก์ ์ฒซ ํ๊ทธ๊ฐ
๋ฑ์ฅํ๊ธฐ ์ ์์ introduction
์ด๋ผ๋ ๋ด์ฉ์ผ๋ก ์์ํ๋ค.
- (ํ์) ์ฒซ ๋ฌธ์ฅ์ ๊ทธ ๋ฌธ์์ ์ ๋ชฉ์ด ๋๋ค.
help(package = mypackage)
๋ฅผ ์คํํ์ ๋ ๊ฐ์ฅ ์์ ์ค๋
๊ทธ๊ฒ์ด๋ค. - (ํ์) ๋ ๋ฒ์งธ ๋ฌธ๋จ์ ์ค๋ช ๋ฌธ์ด๋ค: ๋ฌธ์์์ ์ ๋ชฉ ๋ฐ๋ก ๋ค์์ ๋ฑ์ฅํ๋ฉฐ ๊ทธ ํจ์๊ฐ ๋ฌด์์ ํ๋์ง ์ค๋ช ํ๋ค.
- (์ ํ) ์ธ ๋ฒ์งธ ๋ฌธ๋จ ์ดํ๋ ์ธ๋ถ ๋ด์ฉ์ด๋ค.
์์:
#' Sum of vector elements.
#'
#' \code{sum} returns the sum of all the values present in its arguments.
#'
#' This is a generic function: methods can be defined for it directly or via the
#' \code{\link{Summary}} group generic. For this to work properly, the arguments
#' \code{...} should be unnamed, and dispatch is on the first argument.
sum <- function(..., na.rm = TRUE) {}
\code{}
์ \link{}
๋ ํฌ๋งท๋ช
๋ น์ด๋ค(formatting ์ฐธ๊ณ ).
๋ฌธ์ ํ ์ค์ 80๋จ์ด ์ด๋ด๋ก ํ๊ธฐ๋ฅผ ์ถ์ฒํ๋ค.
RStudio์์ Ctrl/Cmd
+ Shift
+ /
๋๋ code - re-flow comment ํด๋ฆญ.
@section
์ ์ด์ฉํด ์ํ๋ ์ ๋ชฉ์ ์น์
์ ์ถ๊ฐํ ์ ์๋ค. ์ธ๋ถ ๋ด์ฉ์ ๋๋ ๋ ์ ์ฉํ๋ค. ์ฝ๋ก ์ผ๋ก ๋๋์ผ ํ๊ณ , ์ ๋ชฉ์ ํ ์ค๋ก
์์ฑํด์ผ ํ๋ค.
#' @section Warning:
#' Do not operate heavy machinery within 8 hours of using this function.
@seealso
์ @family
๋ ์ ์ฉํ ๋ช
๋ น์ด๋ค.
#' @family aggregate functions
#' @seealso \code{\link{prod}} for products, \code{\link{cumsum}} for cumulative
#' sums, and \code{\link{colSums}}/\code{\link{rowSums}} marginal sums over
#' high-dimensional arrays.
๋ค๋ฅธ ์ ์ฉํ ๋ช
๋ น์ด๋ก @aliases alias1 alias2 ...
์ @keywords keyword1 keyword2 ...
๊ฐ ์๋ค.
Documenting functions
ํจํค์ง๋ ํจ์๋ฅผ ๋ง์ด ๋ค๋ฃฌ๋ค. ํจ์๋ฅผ ๋ค๋ฃฐ ๋ ์ ์ฉํ ์ธ ๊ฐ์ง ๋ช ๋ น์ด๊ฐ ์๋ค.
@param name description
: ํจ์์ ์ ๋ ฅ ์๋ฃ๋ ์ ๋ ฅ ๋ณ์์ ํ์, ํ๋ ์ผ ๋ฑ์ ๊ฐ๊ฒฐํ๊ฒ ๊ธฐ์ ํ๋ค.
description
์ ๋ชจ๋ ๋๋ฌธ์๋ก ์์ํด์ผ ํ๊ณ , ์ฌ๋ฌ ์ค์ด ๋ ์ ์๋ค. ๋ชจ๋ parameter์ ๋ํด@param
์ ์์ฑํด์ผ
ํ๋ค.@param x,y Numeric vectors..
๋ฑ์ผ๋ก ์ฌ๋ฌ ๋ณ์๋ฅผ ํ ๋ฒ์ ์ค๋ช ํ ์ ์๋ค(์ฝค๋ง ๋ค์ ๊ณต๋ฐฑ ์์!).@examples
๋ ์ ์ ์๋ํ๋ ์์ ์ฝ๋๋ฅผ ๋ด์์ผ ํ๋ค(R CMD check
์์ ํ์ธ).\dontrun{}
๋ฅผ ์ฌ์ฉํด ์๋ฌ๊ฐ ๋๋ ์ฝ๋๋ฅผ ์ค๋ช ๋ชฉ์ ์ผ๋ก ํฌํจ์ํฌ ์ ์๋ค.@example path/relative/to/package/root
๋ฅผ ์ด์ฉํด ์ธ๋ถ ๋ฌธ์์ ์์ ์ฝ๋๋ฅผ ์ธ์ฉํ ์ ์๋ค(example์ s๊ฐ ์๋ค!).@return description
๋ก ํจ์๊ฐ ๋ฌด์์ ๋ฐํํ๋์ง ์ค๋ช ํ๋ค.
#' Sum of vector elements.
#'
#' \code{sum} returns the sum of all the values present in its arguments.
#'
#' This is a generic function: methods can be defined for it directly
#' or via the \code{\link{Summary}} group generic. For this to work properly,
#' the arguments \code{...} should be unnamed, and dispatch is on the
#' first argument.
#'
#' @param ... Numeric, complex, or logical vectors.
#' @param na.rm A logical scalar. Should missing values (including NaN)
#' be removed?
#' @return If all inputs are integer and logical, then the output
#' will be an integer. If integer overflow
#' \url{http://en.wikipedia.org/wiki/Integer_overflow} occurs, the output
#' will be NA with a warning. Otherwise it will be a length-one numeric or
#' complex vector.
#'
#' Zero-length vectors have sum 0 by definition. See
#' \url{http://en.wikipedia.org/wiki/Empty_sum} for more details.
#' @examples
#' sum(1:10)
#' sum(1:5, 6:10)
#' sum(F, F, F, T, T)
#'
#' sum(.Machine$integer.max, 1L)
#' sum(.Machine$integer.max, 1)
#'
#' \dontrun{
#' sum("a")
#' }
sum <- function(..., na.rm = TRUE) {}
Documenting datasets
Documenting packages
Documenting classes, generics and methods
Special characters
์๋ ํน์๋ฌธ์๋ ์ฌ์ฉ์ ์ฃผ์ํด์ผ ํ๋ค.
@
: roxygen ํ๊ทธ ์์ํ ๋ ์ฌ์ฉ๋๋ค.@@
์ฌ์ฉํด ์ ๋ ฅ.%
: latex ์ฝ๋ฉํธ ์์ํ ๋ ์ฌ์ฉํ๋ค.\%
์ฌ์ฉํด ์ ๋ ฅ(example์์๋ \ ํ์ ์๋ค).\
: latex escaping์ ์ฌ์ฉ๋๋ค.\\
์ฌ์ฉํด ์ ๋ ฅ.
Do repeat yourself
๋ค๋ฅธ ๋ฌธ์์์ ์ค๋ช ํ ๋ด์ฉ์ ๋ฐ๋ณตํ๊ณ ์ถ์ง ์์ ๋ ์๋ ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
@inheritParams
@describeIn
๋๋@rdname
Text formatting reference sheet
roxygen ํ๊ทธ์์๋ Rd
๋ฌธ๋ฒ์ ์ฌ์ฉํ๋ค. ์๋์์ ๋ช ๊ฐ์ง ์ ์ฉํ ํ์ฉ๋ฒ์ ์๊ฐํ๋ค. ๋ ์์ธํ ๋ด์ฉ์ R
extensions๋ฅผ
์ฐธ๊ณ ํ์.
Character formatting
Links
Lists
Mathematics
Tables
Vignettes (vignettes/
): long-form documentation
A vignette should divide functions into useful categories, and demonstrate how
to coordinate multiple functions to solve problems.
orient documentation์ด ํ์ํ ํค์๋(i.e. ํจ์ ์ด๋ฆ)๋ฅผ ์ ๋ ์ ์ฉํ๋ค๋ฉด, vignette๋ ํด๊ฒฐํ๋ ค๋ ๋ฌธ์ ๋ฅผ ์ ๋
์ ์ฉํ๋ค. ๋ํ, vignette์ ํตํด ํจํค์ง ์ค๋ช
์ ๋์ฑ ์์ธํ ๊ธฐ์ ํ ์ ์๋ค.
browseVignettes()
๋ช
๋ น์ด๋ก ํ์ฌ ์ค์น๋ ๋ชจ๋ vignettes๋ฅผ ๋ณผ ์ ์๋ค.
ํน์ ํจํค์ง์ ๊ฒ๋ง ๋ณด๊ณ ์ถ๋ค๋ฉด browseVignettes("packagename")
๋ช
๋ น์ด๋ฅผ ์ฌ์ฉํ๋ค.
๋ชจ๋ vignettes๋ ์์ค์ฝ๋, HTML(๋๋ PDF), R ์ฝ๋ ์ธ ๊ฐ์ง๋ฅผ ๊ฐ์ง๊ณ ์๋ค. ํน์ vignette์
vignette(x)
๋ช
๋ น์ด๋ก ์ฝ๊ณ , edit(vignette(x))
๋ก ํธ์งํ ์ ์๋ค.
์ค์นํ์ง ์์ vignette์ ์ฝ๋ ๋ฐฉ๋ฒ์ [์ฌ๊ธฐ](CRAN page, e.g., http://cran.r-project.org/web/packages/dplyr)๋ฅผ ์ฐธ๊ณ ํ์.
R 3.0.0 ์ด์ ์๋ vignette๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ด Sweave ๋ฟ์ด์๋ค. Sweave๋ ๋ฌด๊ฒ๊ณ ๋ฐฐ์ฐ๊ธฐ ์ด๋ ค์ ๋ค(LaTeX).
ํ์ง๋ง knitr์ด ๊ฐ๋ฐ๋๊ณ ๋์๋ vignette๋ฅผ ๋ง๋๋ ๊ฒ ์ฌ์์ก๊ณ ๊ฑฐ์ ๋ชจ๋ ํจํค์ง์์ vignette๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ค.
์ด ์ฑํฐ์์๋ knitr์ vignette engine์ ๋ํด ์ค๋ช
ํ๋ ค ํ๋ค. ์ด ์์ง์ ์ฅ์ ์ ์กฐ๊ธ ์๊ฐํ๋ฉด ์๋์ ๊ฐ๋ค.
- ๋งํฌ๋ค์ด ๋ฌธ๋ฒ์ ์ฌ์ฉํ๋ค. LaTeX๋ณด๋ค๋ ๋ฌธ๋ฒ์ด ์์ ๋กญ์ง ๋ชป ํ์ง๋ง, ๋์ ๋ฌธ๋ฒ์ ์งํจ๋ค๋ฉด ๋ด์ฉ์ ์ง์คํ ์ ์๋ค.
- ํ ์คํธ, ์ฝ๋, ๊ฒฐ๊ณผ๋ฅผ ํจ๊ป ๊ธฐ๋กํ ์ ์๋ค.
- rmarkdown ํจํค์ง๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
RStudio๋ฅผ ์ค์นํ ๋ R Markdown ๋ฌธ์๋ฅผ ๋ง๋๋ ๋ฐ ํ์ํ ๋ชจ๋ ๊ฒ์ด ์๋์ผ๋ก ์ค์น๋๋ค.
Vignette workflow
devtools::use_vignette("my-vignette")
๋ฅผ ์คํํ๋ฉด
vignettes/
ํด๋๊ฐ ์์ฑ๋๊ณDESCRIPTION
๋ด์ฉ์ ์์ ํ๊ณ (i.e.Suggests
์VignetteBuilder
ํ๋์ knitr ์ถ๊ฐ)- vignette์ ์ด์์ด ์์ฑ๋๋ค(
vignettes/my-vignette.Rmd
).
๋ค์์ผ๋ก ํ ์ผ์
- ์ด์ ์์
- vignette ์์ฑ:
Ctrl/Cmd
+Shift
+K
(๋๋ ํด๋ฆญ)
์ด๋ค.
Vignette์๋ ์ธ ๊ฐ์ง ์ค์ ๊ตฌ์ฑ ์์๊ฐ ์๋ค.
- The initial metadata block
- Markdown for formatting text
- Knitr for intermingling text, code and results.
๋ค์ ์ธ ์น์ ์์ ๊ฐ๊ฐ์ ์ค๋ช ํ๊ฒ ๋ค.
Metadata
๋ฉํ๋ฐ์ดํ์ ๊ธฐ๋ณธ ํ ํ๋ฆฟ.
---
title: "Vignette Title"
author: "Vignette Author"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{Vignette Title}
%\VignetteEngine{knitr::rmarkdown}
\usepackage[utf8]{inputenc}
---
yaml ๋ฌธ๋ฒ์ด๋ผ์ DESCRIPTION
๊ณผ ์ ์ฌํ๋ค. ํน๋ณํจ ์ ์ >
๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์์ ์ฌ ์ค์ด plain text๋ผ๋ ๊ฒ์ ๋ช
์ํ๋ค๋
๊ฒ์ด๋ค. ์๋๋ ๊ฐ ํ๋์ ๋ํ ์ค๋ช
์ด๋ค.
- Title, author and date
- Output
- Vignette
Markdown
Vignette ์์ฑํ ๋๋ ๋งํฌ๋ค์ด ๋ฌธ๋ฒ์ ์ฌ์ฉํ๋ค.
Knitr
Knitr takes R code, runs it, captures the output, and translates it into
formatted Markdown.
\```{r}
# Add two numbers together
add <- function(a, b) a + b
add(10, 20)
\```
๋ฅผ ์ด์ฉํด
\```r
# Add two numbers together
add <- function(a, b) a + b
add(10, 20)
## [1] 30
\```
์ ๊ฐ์ ๋งํฌ๋ค์ด์ผ๋ก ๋ฐ๊พธ๊ณ ๋ ๋๋งํ์ฌ
# Add two numbers together
add <- function(a, b) a + b
add(10, 20)
## 30
๋ฅผ ์ป๋๋ค.
Development cycle
Cmd
+ Alt
+ C
๋ก ๊ฐ ์ฝ๋ ์ฒญํฌ๋ฅผ ์คํํ๊ณ , Ctrl/Cmd
+ Shift
+ K
๋ก ์ ์ฒด ๋ฌธ์๋ฅผ ์คํํ๋ค.
devtools::build()
๋ฅผ ์ฌ์ฉํด์ ํจํค์ง์ vignette์ ํจ๊ป ๋น๋ํ๋ ๊ฒ ์ข๋ค.
* `devtools::build_vignettes()`๋ ์ฌ์ฉํ์ง ๋ง์
* `build_vignettes = TRUE` ์ต์
์ฌ์ฉ
๋น์ทํ๊ฒ, devtools::install_github(build_vignettes = TRUE)
๋ฑ์ผ๋ก ํ์ฉํ์.
Advice for writing vignettes
์ง์ ์ฌ๋์ ๊ฐ๋ฅด์น๋ฉด์ ์์ฑํด๋ณด์.
vignette๋ฅผ ์์ฑํ ๋๋ ์ด๋ณด์์ ์
์ฅ์์ ์๊ฐํด์ผ ํ๋๋ฐ, ํจํค์ง๋ฅผ ์์ฑํ๋ ์ฌ๋์๊ฒ๋ ์ฝ์ง ์์ ์ผ์ด๋ค.
์ง์ ์ด๋ณด์๋ฅผ ๊ฐ๋ฅด์น๋ค๋ณด๋ฉด ๊ทธ๋ค์ด ๋ฌด์์ ๋ชจ๋ฅด๋์ง, ์ด๋ป๊ฒ ์ค๋ช
ํด์ผ ํ ์ง ๋ฐฐ์ธ ์ ์๋ค.
๊ทธ๋ฌ๋ค๋ณด๋ฉด ๋ด๊ฐ ์ฝ๋ฉํ๋ฉด์ ๋์น ๋ถ๋ถ์ ๋ฐ๊ฒฌํ๊ณ ๊ฐ์ ํ ์๋ ์๋ค.
- Creating passionate users,
Serious Pony ์ถ์ฒ: ํ๋ก๊ทธ๋๋ฐ, ๊ฐ๋ฅด์น๊ธฐ ํ - http://amzn.com/0321898680 ์ถ์ฒ: ๊ธ์ฐ๊ธฐ ํ
- ์ฝ๋ฉํ๋ค๊ฐ ์ง์ณค์ ๋ ๊ธ์ ์จ๋ณด์: ๊ธ์ฐ๊ธฐ์ ์ฝ๋ฉํ๊ธฐ๋ ์๋ก ๋ค๋ฅธ ๋๋ฅผ ์ฌ์ฉํ๋ค(structured
procrastination)
CRAN notes
any packages used by the vignette must be declared in the
DESCRIPTION
- CRAN์ ์ ์ถ๋ ํจํค์ง์ R ์ฝ๋๊ฐ ์ ์ ์๋ํ๋์ง ์ฌ๋ถ๋ฅผ ํ์ธํ๋ค.
- ํจํค์ง ์ค์น ํ์๋ vignette๊ฐ ์ ๋ณด์ผ ์ ์๋ค
- ํด๋ ์ด๋ฆ์
vignettes/
๊ฐ ์๋๋ผvignette/
๋ก ํ๋ฉด ์ ๋์จ๋ค. .Rbuildignore
์ vignette๊ฐ ๋ค์ด์์ ์ ์๋ค.- ๋ฉํ๋ฐ์ดํฐ๊ฐ ๋๋ฝ๋์ ์ ์๋ค.
- ํด๋ ์ด๋ฆ์
error = TRUE
๋ก ์ค์ ํ๋ค๋ฉดpurl = FALSE
๋ ์ค์ ํด์ผ ํ๋ค.- ์ฉ๋์ ๊ดํ ๊ท์น์ ์์ง๋ง ํ์ผ ํฌ๊ธฐ๋ ์ต๋ํ ์ค์ด์(๊ทธ๋ฆผ์ด ๋ง์ ๊ฒฝ์ฐ ๋ฑ)
Where next
- Rmarkdown ๋ฌธ๋ฒ ๊ณต๋ถ
- vignette์ Journal of Statistical Software, The R Journal ๋ฑ์ ํฌ๊ณ
Testing (Tests/
)
The problem with this approach is that when you come back to this code in 3
months time to add a new feature, youโve probably forgotten some of the informal
tests you ran the first time around.
ํจ์๋ฅผ ์ง๊ณ devtools::load_all()
๋ก ๋ถ๋ฌ๋ค์ฌ์ ์ฝ์์์ ์คํํด๋ณด๊ณ ๋ค๋ฌ๊ธฐ๋ฅผ ๋ฐ๋ณต…
์์ ๊ฐ์ด ์๋์ผ๋ก ์ฝ๋ ํ
์คํธ๋ฅผ ์งํํด๋ ๊ทธ ๋น์์๋ ๋ฌธ์ ๊ฐ ์๋ค.
ํ์ง๋ง ์๊ฐ์ด ์ง๋๊ณ ๋ค์ ๊ฐ์ ์ฝ๋๋ฅผ ๋ดค์ ๋๋ ์์ ์ด ์ด๋ค ํ
์คํธ๋ฅผ ์งํํ์๋์ง ๊ธฐ์ตํ๋ ๊ฒ์
์ด๋ ค์ด ์ผ๊ธฐ ๋๋ฌธ์ ๊ณผ๊ฑฐ์ ์งํํด๋ ํ
์คํธ๋ฅผ ๋ฐ๋ณตํ๊ธฐ ์ฝ๋ค.
testthat
ํจํค์ง๋ฅผ ์ฌ์ฉํ๋ฉด ์ฝ๋ ํ
์คํธ๋ฅผ ์๋ํํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ ์ ์๋ค.
๋๋ถ์ ๋์ค์๋ ๊ฐ์ ํ
์คํธ๋ฅผ ์ฝ๊ฒ ๋ฐ๋ณตํ ์ ์๋ค.
Test workflow
devtools::use_testthat()
์ ์คํํ๋ฉด,
tests/testthat
ํด๋๊ฐ ์์ฑ๋๊ณDESCRIPTION
ํ์ผ์Suggests
ํ๋์ testthat์ด ์ถ๊ฐ๋๊ณtests/testthat.R
์ด ์์ฑ๋๋ค. ์ด ํ์ผ์ดR CMD check
๋ช ๋ น์ ๋ด๋ ธ์ ๋ ๋ชจ๋ ํ ์คํธ๋ฅผ ์๋์ผ๋ก ์งํํด์ค๋ค.- automated checking ์ฐธ๊ณ
๊ทธ ๋ค์ ์งํ ๋ฐฉ๋ฒ์ ๊ฐ๋จํ๋ค.
- ์ฝ๋๋ ํ ์คํธ ์์
- ํจํค์ง ํ
์คํธ ์คํ:
Ctrl/Cmd
+Shift
+T
๋๋devtools::test()
- 1-2 ๋ฐ๋ณต
ํ ์คํธ ๊ฒฐ๊ณผ๋ ์๋์ ๊ฐ์ด ๋ํ๋๋ค
Expectation : ...........
rv : ...
Variance : ....123.45.
๊ฐ ์ค์ ํ
์คํธ ํ์ผ ํ๋๋ฅผ, ๊ฐ .
์ ํต๊ณผํ ํ
์คํธ๋ฅผ, ๊ฐ ์ซ์๋ ํต๊ณผํ์ง ๋ชปํ ํ
์คํธ๋ฅผ ๋ํ๋ธ๋ค.
๊ฐ ์ซ์์ ์ธ๋ถ ๋ด์ฉ์ ์ดํด๋ณผ ์ ์๋ค.
1. Failure(@test-variance.R#22): Variance correct for discrete uniform rvs -----
VAR(dunif(0, 10)) not equal to var_dunif(0, 10)
Mean relative difference: 3
2. Failure(@test-variance.R#23): Variance correct for discrete uniform rvs -----
VAR(dunif(0, 100)) not equal to var_dunif(0, 100)
Mean relative difference: 3.882353
ํ
์คํธ ๋ด์ฉ (e.g., โVariance correct for discrete uniform rvsโ), ์์น(e.g.,
โ@test-variance.R#22โ), ์คํจํ ์ด์ (e.g., โVAR(dunif(0, 10)) not equal to
var_dunif(0, 10)โ)๋ฅผ ๋ํ๋ธ๋ค. ๋ชฉํ๋ ๋ชจ๋ ํ
์คํธ๋ฅผ ํต๊ณผํ๋ ๊ฒ์ด๋ค.
Test structure
ํ
์คํธ ํ์ผ์ tests/testthat/
์ ์ ์ฅ๋ผ์๋ค. ๊ฐ ์ด๋ฆ์ ๋ฐ๋์ test
๋ก ์์ํด์ผ ํ๋ค.
๋ค์์ stringr ํจํค์ง์ ํ
์คํธํ์ผ ์์๋ค.
context("String length")
library(stringr)
test_that("str_length is number of characters", {
expect_equal(str_length("a"), 1)
expect_equal(str_length("ab"), 2)
expect_equal(str_length("abc"), 3)
})
test_that("str_length of factor is length of level", {
expect_equal(str_length(factor("a")), 1)
expect_equal(str_length(factor("ab")), 2)
expect_equal(str_length(factor("abc")), 3)
})
test_that("str_length of missing is missing", {
expect_equal(str_length(NA), NA_integer_)
expect_equal(str_length(c(NA, 1)), c(NA, 1))
expect_equal(str_length("NA"), 2)
})
ํ ์คํธ๋ files-tests-expectations๋ก ์ด์ด์ง๋(์์->ํ์) ๊ณ์ธต ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
- expectation: ํ
์คํธ์ ์ต์ ๋จ์. ์ด๋ฆ์ด
expect_
๋ก ์์ํ๋ ํจ์์ด๋ค.
ํด๋น ์ฝ๋๊ฐ ์์ํ๋ ๋๋ก ์๋ํ๋์ง(๊ฒฐ๊ณผ ๊ฐ, ๋ณ์ ์ข ๋ฅ, ์๋ฌ ์ฌ๋ถ ๋ฐ ๋ด์ฉ ๋ฑ) ํ์ธํ๋ค. - test:
test_that()
์ผ๋ก ์ํํ๋ค. ์ฌ๋ฌ expectations๋ก ์ด๋ค์ง๋ฉฐ, ํ๋์ ๊ธฐ๋ฅ(functionality)์
ํ ์คํธํ๋ค(๊ทธ๋์ unit์ด๋ผ๊ณ ๋ ๋ถ๋ฆฐ๋ค). ์ฌ๋ฌ ํจ์๊ฐ ๊ด์ฌํ ์๋ ์๋ค. - file: ์ฌ๋ฌ tests์ ๋ฌถ์์ด๋ค.
context()
์ human-readableํ ์ด๋ฆ์ ํ๊ธฐํ๋ค.
Expectations
ํ
์คํธ์ ์ต์ ๋จ์์ด๋ค. ํ
์คํธ ๊ฒฐ๊ณผ๊ฐ ์์๊ณผ ๊ฐ์์ง ๋ค๋ฅธ์ง ๊ฒฐ๊ณผ๋ฅผ ์๋ ค์ค๋ค.
๋ชจ๋ expectations๋ ๋น์ทํ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
expect_
๋ก ์์- ๋งค๊ฐ๋ณ์ ๋ ๊ฐ: ์ฒซ ๋ฒ์งธ๋ ์ค์ ๊ฒฐ๊ณผ, ๋ ๋ฒ์งธ๋ ์์ ๊ฒฐ๊ณผ
- ๋ ๊ฒฐ๊ณผ๊ฐ ๋ค๋ฅด๋ฉด ์๋ฌ ๋ฐ์
expectations๋ tests์ files ์์ ๋ค์ด์์ง๋ง, ๊ฐ expectation์ ์ง์ ์คํํ ์๋ ์๋ค.
testthat ํจํค์ง์๋ ์ฝ 20 ์ข
๋ฅ์ expectations๊ฐ ์๋ค.
-
test for equality:
expect_equal()
,expect_identical()
.
expect_equal()
๋all.equal()
๋ฅผ ์ด์ฉํด ์ค์ ํ ์ ๋ฐ๋(์ซ์) ๋ด์์ ๋ ๊ฒฐ๊ณผ๊ฐ ๊ฐ์์ง ํ์ธํ๋ค.expect_equal(10, 10) expect_equal(10, 10 + 1e-7) expect_equal(10, 11)
์์ ํ ์ผ์นํ๋์ง๋ฅผ ์๊ณ ์ถ๋ค๋ฉด
expect_identical()
๋ฅผ ์ฌ์ฉํ๋ค(identical()
๊ธฐ๋ฐ).expect_equal(10, 10 + 1e-7) expect_identical(10, 10 + 1e-7)
-
๋ฌธ์:
expect_match()
. ๋ฌธ์ ๋ฒกํฐ์ ์ ๊ทํํ์์ ๋น๊ตํ๋ค.
grepl()
๊ธฐ๋ฐ์ด๋ฉฐ,all
์ ์ด์ฉํด ๋ชจ๋ ๋ฌธ์๊ฐ ์ผ์นํด์ผ ํ๋์ง ํน์ ํ๋์ ๋ฌธ์๋ง ์ผ์นํด๋ ๋๋์ง ์ค์ ํ ์ ์๋ค.string <- "Testing is fun!" expect_match(string, "Testing") # Fails, match is case-sensitive expect_match(string, "testing") # Additional arguments are passed to grepl: expect_match(string, "testing", ignore.case = TRUE)
-
expect_match()
์ 4๊ฐ์ง ๋ณํ:expect_output()
์ ํ๋ฆฐํธํ ๊ฒฐ๊ณผ ๋น๊ต,expect_message()
๋ ๋ฉ์ธ์ง ๋น๊ต,
expect_warning()
๋ ๊ฒฝ๊ณ ๋ฌธ ๋น๊ต,expect_error()
๋ ์๋ฌ ๋น๊ต.a <- list(1:10, letters) expect_output(str(a), "List of 2") expect_output(str(a), "int [1:10]", fixed = TRUE) expect_message(library(mgcv), "This is mgcv")
expect_message()
,expect_warning()
,expect_error()
์์
๋งค๊ฐ๋ณ์๋ฅผ ํ๋๋ง ์ ๋ ฅํ๋ฉด ๋ฉ์ธ์ง(๊ฒฝ๊ณ , ์๋ฌ)๊ฐ ์์ฑ๋๋์ง ์ฌ๋ถ๋ฅผ ํ์ ํ ์ ์๋ค. -
expect_is()
: ๊ฐ์ฒด๊ฐ ํด๋น ํด๋์ค๋ก๋ถํฐ ์ ๋๋์๋์ง(inherit) ๊ฒ์ฌํ๋ค.model <- lm(mpg ~ wt, data = mtcars) expect_is(model, "lm") expect_is(model, "glm")
-
expect_true()
์expect_false()
: ๋ค๋ฅธ expectations๊ฐ ๋ชจ๋ ๋ด ๋ชฉ์ ์ ์ ๋นํ์ง ์์ ๋ ์ ์ฉํ๋ค. -
expect_equal_to_reference()
: ์ฒซ ์ํ ๊ฒฐ๊ณผ์ ๋ค๋ฅธ์ง ๋น๊ต.
Writing tests
test๋ ํ
์คํธ ์ด๋ฆ๊ณผ(Test that์ผ๋ก ์์ํ๋ ๋ฌธ์ฅ) ์ฝ๋ ๋ธ๋ญ(expectations)์ผ๋ก ๊ตฌ์ฑ๋๋ค.
test๋ฅผ ์ด๋ป๊ฒ ๊ตฌ์ฑํ๋์ง๋ ์์ ์ง๋ง, ์์ tests ์ฌ๋ฌ ๊ฐ๊ฐ ํฐ tests ๋ช ๊ฐ๋ณด๋ค ๋์ ๋๊ฐ ๋ง๋ค.
testthat์ R ํ๊ฒฝ์ ๋ค์ ์๋๋๋ก ๋ณต๊ตฌํด์ฃผ์ง ์๋๋ค.
- filesystem: ํด๋ ์์ฑ/์ญ์ /์์ …
- search path:
library()
,attach()
- global options:
options()
,par()
๋ฐ๋ผ์, ์ ๋ด์ฉ์ด ๋ด ํจํค์ง์ ๋ค์ด์๋ค๋ฉด ์ง์ ์์๋ณต๊ตฌ ํด์ค์ผ ํ๋ค(regular R functions ์ด์ฉ).
What to test
- internal๋ณด๋ค external interface(??)์ ์ง์คํ๊ธฐ
- ํ ํ ์คํธ์๋ ํ๋์ ๋์๋ง ํฌํจํ๊ธฐ
- ๊ฒฐ๊ณผ๊ฐ ํ์คํ ์ฝ๋์ ์๊ฐ๋ญ๋น ๋ง๊ธฐ
- ๋ฒ๊ทธ ๋ฐ๊ฒฌํ ๋๋ง๋ค ํ ์คํธํ๊ธฐ
Skipping a test
๊ฐ๋์ ํ
์คํธ ์งํ์ด ๋ถ๊ฐ๋ฅํ ๋๊ฐ ์๋ค(์ธํฐ๋ท ๋ฌธ์ ๋ฑ).
skip()
ํจ์๋ก ํ
์คํธ๋ฅผ ์๋ตํ ์ ์๋ค. ์๋ฌ ๋์ S
๊ฐ ํ์ถ๋๋ค.
check_api <- function() {
if (not_working()) {
skip("API not available")
}
}
test_that("foo api returns bar when given baz", {
check_api()
...
})
Building your own testing tools
์ค๋ณต๋๋ ์ฝ๋๋ฅผ ์๋ก์ด ํจ์๋ก ๋ง๋ค์ด ๊ฐ์ํํ ์ ์๋ค.
library(lubridate)
##
## Attaching package: 'lubridate'
## The following object is masked from 'package:base':
##
## date
test_that("floor_date works for different units", {
base <- as.POSIXct("2009-08-03 12:01:59.23", tz = "UTC")
expect_equal(floor_date(base, "second"),
as.POSIXct("2009-08-03 12:01:59", tz = "UTC"))
expect_equal(floor_date(base, "minute"),
as.POSIXct("2009-08-03 12:01:00", tz = "UTC"))
expect_equal(floor_date(base, "hour"),
as.POSIXct("2009-08-03 12:00:00", tz = "UTC"))
expect_equal(floor_date(base, "day"),
as.POSIXct("2009-08-03 00:00:00", tz = "UTC"))
expect_equal(floor_date(base, "week"),
as.POSIXct("2009-08-02 00:00:00", tz = "UTC"))
expect_equal(floor_date(base, "month"),
as.POSIXct("2009-08-01 00:00:00", tz = "UTC"))
expect_equal(floor_date(base, "year"),
as.POSIXct("2009-01-01 00:00:00", tz = "UTC"))
})
๋ ๊ฐ์ helper functions๋ฅผ ๋ง๋ค์ด์ ๋ ๊ฐ๋จํ๊ฒ ์ค์ผ ์ ์๋ค.
test_that("floor_date works for different units", {
base <- as.POSIXct("2009-08-03 12:01:59.23", tz = "UTC")
floor_base <- function(unit) floor_date(base, unit)
as_time <- function(x) as.POSIXct(x, tz = "UTC")
expect_equal(floor_base("second"), as_time("2009-08-03 12:01:59"))
expect_equal(floor_base("minute"), as_time("2009-08-03 12:01:00"))
expect_equal(floor_base("hour"), as_time("2009-08-03 12:00:00"))
expect_equal(floor_base("day"), as_time("2009-08-03 00:00:00"))
expect_equal(floor_base("week"), as_time("2009-08-02 00:00:00"))
expect_equal(floor_base("month"), as_time("2009-08-01 00:00:00"))
expect_equal(floor_base("year"), as_time("2009-01-01 00:00:00"))
})
expectation ํจ์๋ฅผ ์๋ก ๋ง๋ค์ด์ ๋ ๊ฐ์ํํ ์ ์๋ค.
base <- as.POSIXct("2009-08-03 12:01:59.23", tz = "UTC")
expect_floor_equal <- function(unit, time) {
expect_equal(floor_date(base, unit), as.POSIXct(time, tz = "UTC"))
}
expect_floor_equal("year", "2009-01-01 00:00:00")
์ด๋ ๊ฒ ํ๋ฉด ๋ง์ง๋ง ์ค์ด informative output์ ์ ์ค ์ ์๋ค(????).
์ด๋ด ๋๋ non-standard evaluation๋ฅผ ์ฌ์ฉํด๋ณด์.
bquote()
์ eval()
์ด ํต์ฌ์ธ๋ฐ, ์๋ bquote()
์์ .(x)
๋ x
๋ฅผ ํด๋น ํธ์ถ ์์น์ ๋๋ ์ญํ ์ ํ๋ค.
expect_floor_equal <- function(unit, time) {
as_time <- function(x) as.POSIXct(x, tz = "UTC")
eval(bquote(expect_equal(floor_date(base, .(unit)), as_time(.(time)))))
}
expect_floor_equal("year", "2008-01-01 00:00:00")
์ด๋ฅผ ์ฌ์ฉํด ์ต์ข ์ ์ผ๋ก ์๋์ ๊ฐ์ด ๊ฐ์ํ ํ๋ค.
test_that("floor_date works for different units", {
as_time <- function(x) as.POSIXct(x, tz = "UTC")
expect_floor_equal <- function(unit, time) {
eval(bquote(expect_equal(floor_date(base, .(unit)), as_time(.(time)))))
}
base <- as_time("2009-08-03 12:01:59.23")
expect_floor_equal("second", "2009-08-03 12:01:59")
expect_floor_equal("minute", "2009-08-03 12:01:00")
expect_floor_equal("hour", "2009-08-03 12:00:00")
expect_floor_equal("day", "2009-08-03 00:00:00")
expect_floor_equal("week", "2009-08-02 00:00:00")
expect_floor_equal("month", "2009-08-01 00:00:00")
expect_floor_equal("year", "2009-01-01 00:00:00")
})
Test files
ํ์ผ(file)
์ ํ
์คํธ์ ๊ฐ์ฅ ํฐ ๋จ์์ด๋ค. ๋ชจ๋ ํ์ผ
์ context()
๋ฅผ ๊ฐ์ง๊ณ ์๋ค(๋ด์ฉ ์ค๋ช
).
ํ์ผ
๊ตฌ์ฑํ๋ ๊ฒ ๋ํ ๋ง๋๋ ์ฌ๋ ๋ง์์ด๋ค.
ํ์ง๋ง ๋ชจ๋ ํ
์คํธ๋ฅผ ํ๋์ ํ์ผ์ ๋๋ ๊ฒ, ๋ชจ๋ ํ
์คํธ๋ง๋ค ํ์ผ์ ๋ง๋๋ ๊ฒ์ ํผํ์.
ํ๋์ ๋ณต์กํ ๊ธฐ๋ฅ, ํจ์๋ฅผ ํ๋์ ํ์ผ๋ก ๋ง๋๋ ๊ฒ ์ข์ ๊ฒ์ด๋ค.
CRAN notes
- ๊ตฌ๋ ์๊ฐ์ด ์งง์์ผ ํ๋ค(1๋ถ ์ด๋ด): ์ค๋ ๊ฑธ๋ฆฌ๋ ๋ถ๋ถ์ ๋จธ๋ฆฌ์
skip_on_cran()
๋ฅผ ์จ๋์. - ๋ชจ๋ CRAN ํ
์คํธ๋ ์์ด๋ก(
LANGUAGE=EN
), C sort order(LC_COLLATE=C
)๋ก ์งํ๋๋ค. - OS๋ง๋ค ๋ค๋ฅผ ์ ์๋ ๊ตฌ๋ฌธ์ ์ฃผ์ํ์.
์๋ฅผ ๋ค์ด, ์์์ ๋ฐ์ฌ๋ฆผ ๋ฌธ์ ๋ OS๋ง๋ค ๋ค๋ฅผ ์ ์์ผ๋
expect_identical()
๋ณด๋ค๋expect_equal()
๋ฅผ ์ฌ์ฉํ์.
Namespaces (NAMESPACE
)
๋ค์์คํ์ด์ค(namespace)๋ ๋ค๋ฅธ ์ฌ๋๊ณผ ๋ด ํจํค์ง๋ฅผ ๊ณต์ ํ๋ ค ํ ๋ ์ค์ํ ๊ฐ๋
์ด๋ค(๋๋ง ๋ณด๋ ค๊ณ ํ๋ค๋ฉด ์ค์ํ์ง ์์ ์ ์๋ค).
๋ค์์คํ์ด์ค๋ฅผ ์ ์ ์ํ๋ฉด ๋ด ํจํค์ง๋ ํ๋์ ๋
๋ฆฝ์ ์ธ ๊ฒ์ผ๋ก ์กด์ฌํ ์ ์๊ฒ ๋๋ค.
๋ฐ๋ผ์ ๋ค๋ฅธ ํจํค์ง ์ฝ๋์ ์ํฅ์ ๋ฐ์ง ์๊ณ ํจํค์ง๊ฐ ๊ตฌ๋๋๋ ํ๊ฒฝ์ ๋ ๊ตฌ์ ๋ฐ๊ฒ ๋๋ค.
Motivation
๋ค์์คํ์ด์ค๋ ์ด๋ฆ์ด ์ค๋ณต๋๋ ๊ฒฝ์ฐ ๋ํ๋๋ ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ ์ ์๋ค.
ํน์ ํจํค์ง์ ํจ์๋ฅผ ์ง์ ํ ๋ ์ฌ์ฉํ๋ ::
์ฐ์ฐ์๋ ๋ค์์คํ์ด์ค์ ์ผ์ข
์ด๋ค.
๋ง์ฝ dplyr
๋ฅผ ๋ก๋ํ ํ ์ด์ด์ Hmisc
๋ฅผ ๋ก๋ํ๋ค๊ณ ํ์. ๋ ํจํค์ง ๋ชจ๋ summarize()
ํจ์๋ฅผ ๊ฐ์ง๊ณ ์๋๋ฐ,
๊ทธ๋ฅ ํจ์ ์ด๋ฆ๋ง ํธ์ถํ๋ฉด ๋์ค์ ๋ก๋ํ Hmisc
์ summarize()
๊ฐ ํธ์ถ๋๋ค.
๋ค์์คํ์ด์ค๋ import์ export ๋ ๋ฐฉ๋ฉด์์ ํจํค์ง๋ฅผ ํ๋์ ๋ ๋ฆฝ์ฒด๋ก ๋ง๋ค์ด์ค๋ค.
Import๋ ํจํค์ง ์์ ํจ์ ํ๋๊ฐ ๋ค๋ฅธ ํจ์๋ฅผ ์ด๋ป๊ฒ ์ฐพ๋์ง๋ฅผ ๊ฒฐ์ ํ๋ค. ์๋ฅผ ๋ค์ด๋ณด์.
๋ง์ฝ nrow()
์ ์ ์๋ฅผ ์์๋ก ๋ฐ๊พธ๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
nrow
## function (x)
## dim(x)[1L]
## <bytecode: 0x244d5b0>
## <environment: namespace:base>
nrow()
์ ์์๋ dim()
์ด ์ฌ์ฉ๋๋ค. dim()
์ ์ ์๋ฅผ ์๋์ ๊ฐ์ด ๋ฐ๊พธ๋ฉด nrow()
๋ ์ด๋ป๊ฒ ๋ ๊น?
dim <- function(x) c(1, 1)
dim(mtcars)
## [1] 1 1
nrow(mtcars)
## [1] 32
๋๋๊ฒ๋ nrow()
๋ ๋ณํ์ง ์๋๋ค. dim()
์ ์ฐพ์ ๋ ํจํค์ง ๋ค์์คํ์ด์ค๋ฅผ ์ด์ฉํ๊ธฐ ๋๋ฌธ์ด๋ค.
์ฐ๋ฆฌ๊ฐ ์ ์ํ global environment์ ์๋ dim()
์ด ์๋
base environment์ ์๋ dim()
์ ์ฐธ๊ณ ํ๋ค๋ ๋ป์ด๋ค.
Export๋ ํจํค์ง์ ํจ์ ์ค ์ด๋ค ๊ฒ๋ค์ด ์ธ๋ถ ํจํค์ง๊ฐ ์ฌ์ฉํ ์ ์๋์ง ์ง์ ํด์ค๋ค.
์ด๋ ๊ฒ ํด์ ๋ค๋ฅธ ํจํค์ง์์ ์ถฉ๋์ ๋ง์์ค๋ค.
Search path
๋ค์์คํ์ด์ค๊ฐ ์ ์ค์ํ์ง ์ดํดํ๊ธฐ ์ํด์๋ search path๋ฅผ ์ดํดํ ํ์๊ฐ ์๋ค.
R์ด ํจ์๋ฅผ ํธ์ถํ๋ ค๋ฉด ๊ทธ๊ฒ์ ์ฐพ์๋ด์ผ ํ๋ค.
๊ฐ์ฅ ๋จผ์ ์ฐพ์๋ณด๋ ๊ณณ์ global environment์ด๊ณ ์ฌ๊ธฐ์ ์์ผ๋ฉด search path๋ฅผ ์ฐพ์๋ณธ๋ค.
search path์๋ ๋ด๊ฐ attachํ ํจํค์ง ๋ฆฌ์คํธ๊ฐ ๋ด๊ฒจ์๋ค. search()
๋ช
๋ น์ด๋ก ํ์ธํ ์ ์๋ค.
search()
## [1] ".GlobalEnv" "package:oldbookdown" "package:rmarkdown"
## [4] "package:stats" "package:graphics" "package:grDevices"
## [7] "package:utils" "package:datasets" "package:methods"
## [10] "Autoloads" "package:base"
ํจํค์ง๋ฅผ loadingํ๋ ๊ฒ๊ณผ attachingํ๋ ๊ฒ์ ๋ค๋ฅด๋ค.
๋ณดํต library()
๊ฐ loadingํ๋ ๊ฒ์ด๋ผ ์๊ฐํ๊ธฐ ์ฝ์ง๋ง, ์ฌ์ค ์ด๋ attachingํ๋ ๊ฒ์ด๋ค.
ํจํค์ง๊ฐ ์ค์น๋(installed) ๊ฒฝ์ฐ
- Loading์ 1) ์ฝ๋, ๋ฐ์ดํฐ, DLL ํ์ผ์ ๋ก๋ํ๊ณ 2) S3, S4 ๋ฉ์๋๋ฅผ ๋ฑ๋กํ๊ณ (register) 3) .onLoad() ํจ์๋ฅผ ์คํํ๋ค.
๋ก๋ฉ์ด ๋๋๋ฉด ํจํค์ง๋ฅผ ๋ฉ๋ชจ๋ฆฌ์์ ์ฌ์ฉํ ์ ์๊ฒ ๋๋ค. ํ์ง๋ง ์์ง search path์๋ ์๊ธฐ ๋๋ฌธ์์::
๋ฅผ ์ฌ์ฉํด์ ์ ๊ทผํด์ผ ํ๋ค.
์ฌ์ค::
์ญ์ ํจํค์ง๋ฅผ ๋ก๋ํ๋ค(์ ๋ผ์์ ๊ฒฝ์ฐ).
ํจํค์ง๋ฅผ ์ง์ ๋ก๋ํ๋ ๊ฒฝ์ฐ๋ ๋ณ๋ก ์์ง๋ง, ๊ฐ๋ฅ์ ํ๋ค(requireNamespace()
๋loadNamespace()
) - attaching์ ๋ก๋ฉํ ํจํค์ง๋ฅผ search path์ ๋ฑ๋กํ๋ค.
์ฆ,library()
์require()
์ loading๊ณผ attaching์ ๋ชจ๋ ์ํํ๋ ํจ์์ธ ๊ฒ์ด๋ค.
ํจํค์ง๊ฐ ์ค์น๋์ง ์์๋ค๋ฉด loading(attaching๋)ํ ์ ์๋ค(์๋ฌ ๋ฐ์).
์๋ฅผ ๋ค์ด expect_that()
๋ฅผ ์ฌ์ฉํ๋ค๊ณ ํ์.
library()
๋ฅผ ์ฌ์ฉํ๋ฉด testthat์ด search path์ ๋ฑ๋ก๋๊ฒ ์ง๋ง, ::
์ ๊ฒฝ์ฐ๋ ๊ทธ๋ ์ง ์๋ค.
old <- search()
testthat::expect_equal(1, 1)
setdiff(search(), old)
## character(0)
expect_true(TRUE)
## Error in expect_true(TRUE): could not find function "expect_true"
library(testthat)
expect_equal(1, 1)
setdiff(search(), old)
## [1] "package:testthat"
expect_true(TRUE)
ํจํค์ง๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ค ๊ฐ์ง๊ฐ ์๋ค. loading/attaching ์ฌ๋ถ, ์๋ฌ ๋ฐ์ ์ฌ๋ถ๋ก ๊ตฌ๋ถํ ์ ์๋ค.
Throws error | Returns FALSE |
|
---|---|---|
Load | loadNamespace(“x”) | requireNamespace(“x”, quietly = TRUE) |
Attach | library(x) | require(x, quietly = TRUE) |
์ ๋ค ๊ฐ์ง ์ค ๋ ๊ฐ์ง๋ง ์ฌ์ฉํด์ผ ํ๋ค.
library(x)
: ์ผ๋ฐ R ์คํฌ๋ฆฝํธ์์ ์ฌ์ฉํ๋ค. ํจํค์ง์์๋ ์ ๋ ์ฌ์ฉํ์ง ์๋๋ค.requireNamespace(x, quietly = TRUE)
: ํจํค์ง ์์์ ์ฌ์ฉํ๋ค.
require()
(๋๋ถ๋ถ requireNamespace()๊ฐ ๋ ์ข๋ค)์ด๋ loadNamespace()
๋ ์ฌ์ฉํ ํ์๊ฐ ์๋ค.
require()
๋ library()
๋์ DESCRIPTION
์ Depends
์ Imports
ํ๋๋ฅผ ์ฌ์ฉํ๋ค.
๊ทธ๋ ๋ค๋ฉด DESCRIPTION
์์ Depends
์ Imports
์ ์ฐจ์ด๋ ๋ฌด์์ผ๊น.
๋ ํ๋ ๋ชจ๋ ํ์ํ ํจํค์ง๊ฐ ๋ฏธ๋ฆฌ ์ค์น๋์ด ์๋๋ก ํด์ฃผ๋ ์ ์ ๊ฐ๋ค.
Imports
๋ ํจํค์ง๋ฅผ loadํ๊ณ Depends
๋ attachํ๋ค๋ ์ฐจ์ด๊ฐ ์๋ค.
ํน๋ณํ ์ด์ ๊ฐ ์๋ค๋ฉด Imports
๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ์ข๋ค.
์ต๋ํ global environment๋ฅผ ๊ฑด๋๋ฆฌ์ง ์๋ ๊ฒ ์ข๊ธฐ ๋๋ฌธ์ด๋ค(search path ํฌํจ).
๋ค๋ง, ๋ง์ฝ ๋ค๋ฅธ ํจํค์ง์ ์ฐ๋ํด ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ Depends
๋ฅผ ์ฌ์ฉํ๋ค.
์๋ฅผ ๋ค์ด, analogue ํจํค์ง๋ vegan ํจํค์ง๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋ค.
vegan์ด ์๋ ํ๊ฒฝ์์๋ ๋ฌด์ฉ์ง๋ฌผ์ด๊ธฐ ๋๋ฌธ์ Depends
๋ฅผ ์ฌ์ฉํ๋ค.
์ด์ imports์ exports๋ฅผ ๋ค๋ฃฐ ๊ฑด๋ฐ, ์ด๋ค์ ๋ชจ๋ NAMESPACE
์ ๊ธฐ๋ก๋๋ค.
๋จผ์ NAMESPACE
๊ฐ ์ด๋ป๊ฒ ์๊ฒผ๋์ง ์ดํด๋ณด์.
The NAMESPACE
๋ค์์ testthat ํจํค์ง NAMESPACE
ํ์ผ์ ์ผ๋ถ๋ฅผ ๋ฐ์ทํ ๊ฒ์ด๋ค.
# Generated by roxygen2 (4.0.2): do not edit by hand
S3method(as.character,expectation)
S3method(compare,character)
export(auto_test)
export(auto_test_package)
export(colourise)
export(context)
exportClasses(ListReporter)
exportClasses(MinimalReporter)
importFrom(methods,setRefClass)
useDynLib(testthat,duplicate_)
useDynLib(testthat,reassign_function)
๊ฐ ์ค์ directive(S3method()
, export()
, exportClasses()
๋ฑ)๋ฅผ ํ๋์ฉ ๊ฐ์ง๊ณ ์๋ค.
๊ฐ directive๋ R ๊ฐ์ฒด ํ๋๊ฐ ๋ค๋ฅธ ํจํค์ง์์ ๋ค์ฌ์๋์ง,
ํน์ ๋ค๋ฅธ ํจํค์ง์์ ์ฌ์ฉํ ์ ์๋๋ก export๋์๋์ง๋ฅผ ์๋ ค์ค๋ค.
์ ์ฒด 8๊ฐ์ directive๊ฐ ์๋ค(4๊ฐ๋ exports๊ด๋ จ, 4๊ฐ๋ imports ๊ด๋ จ)
-
export()
: ํจ์๋ฅผ ๋ด๋ณด๋ธ๋ค(S3, S4 generics ํฌํจ). -
exportPattern()
: ํจํด๊ณผ ์ผ์นํ๋ ๋ชจ๋ ํจ์๋ฅผ ๋ด๋ณด๋ธ๋ค. -
exportClasses()
,exportMethods()
: S4 ํด๋์ค ๋ฐ ๋งค์๋๋ฅผ ๋ด๋ณด๋ธ๋ค. -
S3method()
: S3 ๋งค์๋๋ฅผ ๋ด๋ณด๋ธ๋ค. -
import()
: ํ ํจํค์ง์ ๋ชจ๋ ํจ์๋ฅผ ๊ฐ์ ธ์จ๋ค. -
importFrom()
: ์ ํํ ํจ์๋ฅผ ๊ฐ์ ธ์จ๋ค(S4 generics ํฌํจ). -
importClassesFrom()
,importMethodsFrom()
: S4 ํด๋์ค ๋ฐ ๋งค์๋๋ฅผ ๊ฐ์ ธ์จ๋ค -
useDynLib()
: C ์ธ์ด ํจ์ ํ๋๋ฅผ ๊ฐ์ ธ์จ๋ค(compiled code ์ฐธ๊ณ ).
roxygen2๋ฅผ ์ฌ์ฉํ๋ฉด NAMESPACE
ํ์ผ์ ์ฝ๊ฒ ์์ฑํ ์ ์๋ค(์ผ์ผ์ด ์ฐ์ง ์์๋ ๋๋ค).
roxygen2๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ์ฅ์ ์ ํฌ๊ฒ ์ธ ๊ฐ์ง๊ฐ ์๋ค.
- ๋ค์์คํ์ด์ค๊ฐ ๊ด๋ จ ํจ์ ๋ฐ๋ก ์์ ์ ์๋ผ ์์ผ๋ฏ๋ก import/export ๊ตฌ๋ถ์ด ์ฝ๊ฒ ๊ฐ๋ฅํ๋ค.
- @export ํ๊ทธ๋ง ์ฌ์ฉํ๋ฉด ์๋์ผ๋ก ์ ํฉํ directive๋ฅผ ์์ฑํด์ค๋ค.
- ๊ฐ๊ฒฐํด์ง๋ค. ์ผ์ผํ ํจ์ ์์ directive๋ฅผ ์์ฑํด๋ roxygen2๊ฐ ํ๋๋ก ๋ฌถ์ด์ค๋ค(ํจํค์ง ์์ฑํ ๋๋ ํ๋ํ๋ ์ ๋ ๊ฒ ํธํ๋ค).
roxygen2๊ฐ NAMESPACE
, man/*.Rd
๋ ์ค ํ๋๋ง, ํน์ ๋ ๋ค ์์ฑํ ์ ์๊ฒ ๋ง๋ค ์ ์๋ค.
๋ค์์คํ์ด์ค ๊ด๋ จ ํ๊ทธ๊ฐ ์์ผ๋ฉด ์ ์๊ฐ, documentation ๊ด๋ จ ํ๊ทธ๊ฐ ์์ผ๋ฉด ํ์๊ฐ ์๋ต๋๋ค.
Workflow
roxygen2๋ก ๋ค์์คํ์ด์ค ์์ฑํ๋ ๋ฐฉ๋ฒ์ function documentation ์์ฑํ๋ ๊ฒ๊ณผ ๋์ผํ๋ค.
`#‘๋ก ์์ํ๋ roxygen2 ๋ธ๋ก๊ณผ ํ๊ทธ(@๋ก ์์)๋ฅผ ์ฌ์ฉํ๋ค. ๋ฐฉ์์ ๋ค์๊ณผ ๊ฐ๋ค.
.R files
์ roxygen ์ฝ๋ฉํธ ์ถ๊ฐํ๊ธฐ.- RStudio์์
devtools::document()
(๋๋Ctrl/Cmd
+Shift
+D
) ์คํํ๊ธฐ(roxygen ์ฝ๋ฉํธ ->.Rd files
). NAMESPACE
ํ์ธํ๊ณ ํ ์คํธํ๊ธฐ.- ์์ ๋ฐ ๋ฐ๋ณตํ๊ธฐ.
Exports
Exportsํ๊ณ ์ถ์ ๋ ์ฝ์ด๋ณด์.
Imports
Importsํ๊ณ ์ถ์ ๋ ์ฝ์ด๋ณด์.
Data (data/
)
์ธ ๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก ํจํค์ง์ ๋ฐ์ดํฐ๋ฅผ ํฌํจ์ํฌ ์ ์๋ค.
- binary data, ๊ณต๊ฐ:
data/
์ ๋ฃ๊ธฐ. ์์ ๋ฐ์ดํฐ์ ๋ฃ๊ธฐ ์ข๋ค. - parsed data, ๋น๊ณต๊ฐ:
R/sysdata.rda
์ ๋ฃ๊ธฐ. ํจ์๊ฐ ์๋ํ๋ ๋ฐ ํ์ํ ๋ฐ์ดํฐ ๋ฃ๊ธฐ ์ข๋ค. - raw data:
inst/extdata
์ ๋ฃ๊ธฐ. - ํจํค์ง ์์ค์ ํฌํจ์ํค๊ธฐ(์ง์ ์์ฑ ๋๋
dput()
์ด์ฉ).
๋ฐ์ดํฐ ๋ฃ๊ณ ์ถ์ ๋ ๋ ์ฝ์ด๋ณด์
Exported data
Internal data
Raw data
Other data
CRAN notes
Compiled code (src/
)
R์์ c, cpp ๋ฑ ์ปดํ์ผ ์ธ์ด ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ(์๋ ํฅ์)
ํ์ํ ๋ ์ฝ๊ณ ์ ๋ฆฌํ์
Installed files (inst/
)
ํจํค์ง๋ฅผ ์ค์นํ๋ฉด(install) inst/
์ ์๋ ๋ชจ๋ ๋ด์ฉ์ด ๋ณต์ฌ๋์ด ํจํค์ง์ ์ต์์ ๊ฒฝ๋ก๋ก ์ด๋ํ๋ค.
์ด๋ฐ ์ ์์ inst/
์ .Rbuildignore
๋ ์๋ก ๋ฐ๋ ๊ธฐ๋ฅ์ ํ๋ค(๋ณต์ฌํ ๊ฒ/์ ํ ๊ฒ ์ง์ ).
inst/
๋ด์ฉ์ ๊ตฌ์ฑํ ๋๋ ํ ๊ฐ์ง๋ง ์ฃผ์ํ์.
์ต์์ ํด๋์ ๋ณต์ฌ๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ inst/
์ ๋ด์ฉ์ด ๊ธฐ์กด ํ์ ๊ฒฝ๋ก์ ์ด๋ฆ๊ณผ ์ค๋ณต๋์๋ ์ ๋๋ค.
์ฆ, inst/build
, inst/data
, inst/demo
, inst/exec
, inst/help
, inst/html
, inst/inst
,
inst/libs
, inst/Meta
, inst/man
, inst/po
, inst/R
, inst/src
,
inst/tests
, inst/tools
, inst/vignettes
๋ ์ฌ์ฉํ ์ ์๋ค.
์ด๋ฒ ์ฑํฐ์์๋ inst/
์์ ๊ฐ์ฅ ์์ฃผ ๋ฑ์ฅํ๋ ํ์ผ์ ๋ค๋ฃฐ ๊ฒ์ด๋ค.
inst/AUTHOR
,inst/COPYRIGHT
: ์ ์๊ถ ๊ด๋ จ ๋ด์ฉ์ ๊ธฐ์ ํ๋ค.inst/CITATION
: ์ด๋ป๊ฒ ์ธ์ฉํ๋์ง ๊ธฐ์ ํ๋ค
(package citation ์ฐธ๊ณ ).inst/docs
: ์์ฆ์ ์ ์ฐ์ง ์๋๋ค.inst/extdata
: ๋ฐ์ดํฐ์ ์ค๋ช ์ ๊ธฐ์ ํ๋ค
(external data ์ฐธ๊ณ ).inst/java
,inst/python
๋ฑ: ๋ค๋ฅธ ์ธ์ด ๊ด๋ จ ๋ด์ฉ์ ๊ธฐ์ ํ๋ค
(other languages ์ฐธ๊ณ ).
inst/
์ ์๋ ํ์ผ์ system.file()
๋ก ์ฐพ์ ์ ์๋ค.
์๋ฅผ ๋ค์ด inst/extdata/mydata.csv
๋ฅผ ์ฐพ๊ณ ์ถ๋ค๋ฉด,
system.file("extdata", "mydata.csv", package = "mypackage")
๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
ํจ์ ์์ inst/
๋ฅผ ๋ช
์ํ์ง ์์๋๋ฐ,
ํจํค์ง๊ฐ ์ด๋ฏธ ์ค์น๋ผ ์๋ค๋ฉด(ํน์ devtools::load_all()
๋ก ๋ก๋ฉ๋ ์ํ๋ผ๋ฉด) ์ ์๋ํ ๊ฒ์ด๋ค.
Package citation
์ธ์ฉ ํ์ ์์ฑํ๋ ๋ฐฉ๋ฒ
Other languages
๋ค๋ฅธ ์ธ์ด ์ค๋ช ์ถ๊ฐํ๋ ๋ฐฉ๋ฒ
๋ณดํต ๋ค๋ฅธ ์ธ์ด ์ค๋ช
์ ํ์ง ์์ง๋ง,
ํด๋น ํจํค์ง์์ ๋ค๋ฅธ ์ธ์ด ์ ๋ชจ๋์ด ํฐ ๋ถ๋ถ์ ์ฐจ์งํ๋ค๋ฉด ๋ฃ์ด์ผ ํ๋ค.
์ด ๋๋ inst/python
๊ณผ ๊ฐ์ด inst/
ํด๋ ์์ ์ถ๊ฐ ๊ฒฝ๋ก๋ฅผ ๋ง๋ค์ด์ฃผ๊ณ ,
DESCRIPTION
์ SystemRequirements
ํ๋์๋ ๋ช
์ํด์ค์ผ ํ๋ค.
๋จ, Java๋ ์์ธ์ด๋ค(java/
ํด๋๋ฅผ ๋ง๋ค๊ณ .Rinstignore
์ ๋ช
์ํด์ค ๊ฒ, Imports
์ rJava
์ถ๊ฐํ ๊ฒ).
Other components
Best practices
Git and GitHub
Checking
Release
โ