R packages by Hadley Wickham ์ •๋ฆฌ

· โ˜• 32 min read · โœ๏ธ Hoontaek Lee
๐Ÿท๏ธ
  • #2020
  • #Book Review
  • #R
  • Getting started

    Introduction

    ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“œ๋Š” ์ด์œ 

    • ๋‹ค๋ฅธ ์‚ฌ๋žŒ๊ณผ ์ฝ”๋“œ ๊ณต์œ 
    • ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ๋‚ด ์ฝ”๋“œ๋ฅผ ์‰ฝ๊ฒŒ ์ดํ•ดํ•˜๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งค๋‰ด์–ผ ์ž‘์„ฑ
    • ๋‚˜ ์ž์‹ ์ด ๋‚ด ์ฝ”๋“œ๋ฅผ ์‰ฝ๊ฒŒ ์ดํ•ดํ•˜๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งค๋‰ด์–ผ ์ž‘์„ฑ

    Getting started

    ํ•„์š”ํ•œ ํŒจํ‚ค์ง€&ํ•จ์ˆ˜๋ฅผ ์„ค์น˜ํ•œ๋‹ค.

    1
    
    install.packages(c("devtools", "roxygen2", "testthat", "knitr"))
    

    ์˜ฌ๋ฐ”๋ฅธ ๋ฒ„์ „์˜ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ–ˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค(TRUE๊ฐ€ ๋‚˜์™€์•ผ ํ•จ).

    1
    2
    
    install.packages("rstudioapi")
    rstudioapi::isAvailable("0.99.149")
    
    1
    
    devtools::install_github("r-lib/devtools")
    

    ํ•„์š”ํ•œ ๊ฒƒ ๋ชจ๋‘ ์„ค์น˜๋๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
    ์•„๋ž˜ ์ฝ”๋“œ ์ˆ˜ํ–‰ ๊ฒฐ๊ณผ TRUE๊ฐ€ ๋‚˜์˜ค๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

    1
    2
    
    library(devtools)
    has_devel()
    

    Package structure

    • ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“œ๋Š” ๊ณผ์ •
    • ํŒจํ‚ค์ง€์™€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์ฐจ์ด์ 

    Naming your package

    Requirements for a name

    1. ๋ฌธ์ž, ์ˆซ์ž, ๋งˆ์นจํ‘œ๋กœ ๊ตฌ์„ฑ
      • ๋ฌธ์ž๋กœ ์‹œ์ž‘ํ•ด์•ผ ํ•˜๊ณ , ๋งˆ์นจํ‘œ๋Š” ๋งˆ์ง€๋ง‰์— ์˜ฌ ์ˆ˜ ์—†๋‹ค.
      • ๋˜๋„๋ก ๋งˆ์นจํ‘œ๋Š” ์“ฐ์ง€ ๋ง์ž.

    Strategies for creating a name

    • ์œ ๋‹ˆํฌํ•œ ์ด๋ฆ„: ๊ตฌ๊ธ€๋ง ์‰ฝ๊ฒŒ ๋˜๋„๋ก
      • CRAN์—์„œ
        ํ•ด๋‹น ํŒจํ‚ค์ง€๊ฐ€ ์ด๋ฏธ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ
    • ๋Œ€์†Œ๋ฌธ์ž ์„ž์ง€ ๋ง๊ธฐ: ํƒ€์ดํ•‘, ๊ธฐ์–ต ์–ด๋ ต๋‹ค
      • RGtk2
    • ํŒจํ‚ค์ง€์˜ ๊ธฐ๋Šฅ์„ ์‰ฝ๊ฒŒ ์—ฐ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์ด๋ฆ„
      • lubridate: date์™€ times ๋‹ค๋ฃจ๊ธฐ ์‰ฝ๊ฒŒํ•˜๋Š”(lubricate)
    • ์ถ•์•ฝํ˜•(abbreviation) ์‚ฌ์šฉ
    • r ์ถ”๊ฐ€ํ•ด์ฃผ๊ธฐ
      • stringr, readr, gistr, …
    • ์ƒ์šฉ ํŒจํ‚ค์ง€๋ฅผ ๊ฐœ๋ฐœํ•  ๊ฒฝ์šฐ, ํ•ด๋‹น ํšŒ์‚ฌ์˜ ๊ฐ€์ด๋“œ๋ผ์ธ ์ˆ™์ง€ํ•˜๊ธฐ
      • Dropbox๋Š” ๋ธŒ๋žœ๋“œ ์ด๋ฆ„์œผ๋กœ ์–ดํ”Œ๋ฆฌ์บ์ด์…˜์„ ๋งŒ๋“ค์ง€ ๋ชปํ•˜๊ฒŒ ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ rDropbox๊ฐ€ ์•„๋‹Œ rDrop์ด ๋˜์—ˆ๋‹ค.

    Creating a package

    ์ด๋ฆ„์„ ์ง€์—ˆ๋‹ค๋ฉด ์ƒˆ ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž.
    ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”๋ฐ, ๋ชจ๋‘ RStudio์—์„œ ์ง„ํ–‰ ๊ฐ€๋Šฅํ•˜๋‹ค.

    1. RStudio - File - New Project - New Directory - R package - ์ด๋ฆ„ ์ž…๋ ฅ ํ›„ Create Project
    2. ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค:
      devtools::create("path/to/package/pkgname")

    ๋‘ ๋ฐฉ๋ฒ• ๋ชจ๋‘ ์‹คํ–‰ ๊ฒฐ๊ณผ๋Š” ๊ฐ™๋‹ค.
    ์œ„์—์„œ ๋ณด๋“ฏ, ํŒจํ‚ค์ง€ ํ•˜๋‚˜๋ฅผ ํ•˜๋‚˜์˜ ํ”„๋กœ์ ํŠธ๋กœ ๊ฐ„์ฃผํ•œ๋‹ค.
    **๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ๊ตฌ์„ฑ์˜ ํŒจํ‚ค์ง€(the smallest usable package)**๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์„ธ ๊ฐ€์ง€ ์š”์†Œ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.

    1. R/ ํด๋”
    2. DESCRIPTION ํŒŒ์ผ
    3. NAMESPACE ํŒŒ์ผ

    ์ด์™€ ํ•จ๊ป˜, RStudio์—์„œ ์ž‘์—…ํ•˜๊ธฐ ์ˆ˜์›”ํ•˜๋„๋ก pkgname.Rproj๋„ ์ƒ์„ฑ๋œ๋‹ค.

    # ์ฃผ์˜
    package.skeleton() ํ•จ์ˆ˜๋กœ ํŒจํ‚ค์ง€ ์ƒ์„ฑ์ง€ ๋ง ๊ฒƒ!  
    ์œ„ ํ•จ์ˆ˜๋Š” ์ง€๊ธˆ ํ•„์š”ํ•œ ๊ฒƒ๋ณด๋‹ค ๋งŽ์€ ๊ฒƒ์„ ๋งŒ๋“ค๊ธฐ ๋•Œ๋ฌธ์— ์ถ”ํ›„ ์ž‘์—…๋Ÿ‰์ด ๋Š˜์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค.
    

    RStudio projects

    ํŒจํ‚ค์ง€๋ฅผ ํ•˜๋‚˜์˜ ํ”„๋กœ์ ํŠธ๋กœ ๋ถ„๋ฆฌํ•˜๋ฉด ์—ฌ๋Ÿฌ ์žฅ์ ์ด ์žˆ๋‹ค.

    1. ๋‹ค๋ฅธ ํ”„๋กœ์ ํŠธ์™€ ๋…๋ฆฝ์ : ์„œ๋กœ ์ฝ”๋“œ ์˜ํ–ฅ ์—†์Œ
    2. ๋‹ค์–‘ํ•œ ๋‹จ์ถ•ํ‚ค ์‚ฌ์šฉ ๊ฐ€๋Šฅ(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
      1. source
      2. bundled
      3. binary
      4. installed
      5. 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๊ฐ€ ํฌํ•จ๋œ ๋ชจ๋“  ํŒŒ์ผ์ด ์ œ์™ธ๋œ๋‹ค.

    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/
    • 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

    1. Edit an R file.
    2. Press Ctrl/Cmd + Shift + L.
    3. Explore the code in the console.
    4. 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๋‹จ๊ณ„ ์ ˆ์ฐจ๊ฐ€ ์žˆ๋‹ค.

    1. .R ํŒŒ์ผ์— oxygen ์ฝ”๋ฉ˜ํŠธ ์ถ”๊ฐ€ํ•˜๊ธฐ
    2. devtools::document() ์‹คํ–‰(๋˜๋Š” RStudio์—์„œ Ctrl/Cmd + Shift + D)
    * oxygen ์ฝ”๋ฉ˜ํŠธ๋ฅผ `.Rd` ํŒŒ์ผ๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค(`devtools::document()`๊ฐ€ `roxygen2::roxygenise()`๋ฅผ ์‹คํ–‰ํ•จ)
    
    1. ?๋กœ ๋ฏธ๋ฆฌ๋ณด๊ธฐ
    2. ๋‹ค๋“ฌ๊ธฐ

    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์€ ๋น ๋ฅด์ง€๋งŒ, ๋ฌธ์„œ์— ๋งํฌ๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์—†๋‹ค. ๋งŒ์•ฝ ๋งํฌ๋ฅผ ํฌํ•จํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์ด ์ฑ•ํ„ฐ์—์„œ ์†Œ๊ฐœํ•˜๋Š”
    ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ด๋ณด์ž.

    1. .R ํŒŒ์ผ์— roxygen ์ฝ”๋ฉ˜ํŠธ ์ถ”๊ฐ€ํ•˜๊ธฐ
    2. ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๊ฑฐ๋‚˜
      Ctrl/Cmd + Shift + B ๋ˆ„๋ฅด๊ธฐ.
      • ํŒจํ‚ค์ง€๊ฐ€ ๋‹ค์‹œ ๋นŒ๋“œ๋œ๋‹ค(๋ฌธ์„œ ์ˆ˜์ •์‚ฌํ•ญ ๋ฐ˜์˜, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์„ค์น˜, R ์žฌ์‹œ์ž‘, ํŒจํ‚ค์ง€ ๋กœ๋“œ)
      • ๋Š๋ฆฌ์ง€๋งŒ ํ™•์‹คํ•œ ๋ฐฉ๋ฒ•
    3. ?๋กœ ๋ฏธ๋ฆฌ๋ณด๊ธฐ
    4. ๋‹ค๋“ฌ๊ธฐ

    ์œ„ ๋ฐฉ๋ฒ•์„ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— ์•„๋ž˜ ์˜ต์…˜์„ ํ™•์ธํ•ด๋ณผ ๊ฒƒ!

    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

    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")๋ฅผ ์‹คํ–‰ํ•˜๋ฉด

    1. vignettes/ ํด๋”๊ฐ€ ์ƒ์„ฑ๋˜๊ณ 
    2. DESCRIPTION ๋‚ด์šฉ์„ ์ˆ˜์ •ํ•˜๊ณ (i.e. Suggests์™€ VignetteBuilder ํ•„๋“œ์— knitr ์ถ”๊ฐ€)
    3. vignette์˜ ์ดˆ์•ˆ์ด ์ƒ์„ฑ๋œ๋‹ค(vignettes/my-vignette.Rmd).

    ๋‹ค์Œ์œผ๋กœ ํ•  ์ผ์€

    1. ์ดˆ์•ˆ ์ˆ˜์ •
    2. 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()์„ ์‹คํ–‰ํ•˜๋ฉด,

    1. tests/testthat ํด๋”๊ฐ€ ์ƒ์„ฑ๋˜๊ณ 
    2. DESCRIPTION ํŒŒ์ผ์˜ Suggests ํ•„๋“œ์— testthat์ด ์ถ”๊ฐ€๋˜๊ณ 
    3. tests/testthat.R์ด ์ƒ์„ฑ๋œ๋‹ค. ์ด ํŒŒ์ผ์ด R CMD check ๋ช…๋ น์„ ๋‚ด๋ ธ์„ ๋•Œ ๋ชจ๋“  ํ…Œ์ŠคํŠธ๋ฅผ ์ž๋™์œผ๋กœ ์ง„ํ–‰ํ•ด์ค€๋‹ค.

    ๊ทธ ๋‹ค์Œ ์ง„ํ–‰ ๋ฐฉ๋ฒ•์€ ๊ฐ„๋‹จํ•˜๋‹ค.

    1. ์ฝ”๋“œ๋‚˜ ํ…Œ์ŠคํŠธ ์ˆ˜์ •
    2. ํŒจํ‚ค์ง€ ํ…Œ์ŠคํŠธ ์‹คํ–‰: Ctrl/Cmd + Shift + T ๋˜๋Š” devtools::test()
    3. 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 ๋ธ”๋ก๊ณผ ํƒœ๊ทธ(@๋กœ ์‹œ์ž‘)๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ๋ฐฉ์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

    1. .R files์— roxygen ์ฝ”๋ฉ˜ํŠธ ์ถ”๊ฐ€ํ•˜๊ธฐ.
    2. RStudio์—์„œ devtools::document()(๋˜๋Š” Ctrl/Cmd + Shift + D) ์‹คํ–‰ํ•˜๊ธฐ(roxygen ์ฝ”๋ฉ˜ํŠธ -> .Rd files).
    3. NAMESPACE ํ™•์ธํ•˜๊ณ  ํ…Œ์ŠคํŠธํ•˜๊ธฐ.
    4. ์ˆ˜์ • ๋ฐ ๋ฐ˜๋ณตํ•˜๊ธฐ.

    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

    โ€‹

    Share on

    Hoontaek Lee
    WRITTEN BY
    Hoontaek Lee
    Tree-Forest-Climate Researcher

    What's on this Page