diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4d1f9cb63cc8160ad404a555381346a5fd86acbd..6670955131858c341d8a9fd517ef349f2f4600a1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,17 +3,17 @@ Guia de Colaboração Nos códigos R deve ser usado o padrão de estilo definido em -Advanced R: [Style guide] por Hadley Wickham +> Advanced R: [Style guide] por Hadley Wickham. Para controlar a renderização dos arquivos `Rmd`, edite o `_output.yaml`. Para modificar propriedades do resultado `html`, edite -`\tyle.css`. Para modificar propriedades do resultado `pdf`, edite +`style.css`. Para modificar propriedades do resultado `pdf`, edite `template.tex`. Ao indicar url no meio do texto use ``` -## Para fazer: texto\footnote\url{http://a.url.com} +## Para fazer: texto\footnote{\url{http://a.url.com}} `r renderUrl(text = "texto", url = "http://a.url.com", output = "tex")` ## Para fazer: [texto](http://a.url.com) @@ -21,6 +21,6 @@ Ao indicar url no meio do texto use ``` Essa função, e outras, estão definidas em `config.R`. Esse *script* deve -ser carregado, `source()` no primeiro *chunk* de cada documento. +ser carregado via `source()` no primeiro *chunk* de cada documento. [Style guide]: http://adv-r.had.co.nz/Style.html diff --git a/aux/pitagoras.R b/aux/pitagoras.R new file mode 100644 index 0000000000000000000000000000000000000000..053104ad9198b9f6b705e962ca8cfd576ba0caec --- /dev/null +++ b/aux/pitagoras.R @@ -0,0 +1,26 @@ +##---------------------------------------------------------------------- +#' @title Hipotenusa de Triângulo Retângulo +#' @name pitagoras +#' +#' @description Dados os catetos de um triângulo retângulo, essa função +#' obtém a hipótenusa. +#' +#' @param a,b Vetores numéricos com valores dos catetos do triângulo. +#' +#' @details Essa função é baseada no teorema de Pitágoras +#' \url{https://pt.wikipedia.org/wiki/Teorema_de_Pitágoras}. +#' +#' @return Um vetor com a hipotenusa calculada. +#' +#' @author Walmes Zeviani +#' +#' @examples +#' +#' ## Triangulo pitagórico. +#' pitagoras(a = 3, b = 4) +#' +#' @export +pitagoras <- function(a, b){ + h <- sqrt(a^2 + b^2) + return(h) +} diff --git a/aux/plotTriRet.R b/aux/plotTriRet.R new file mode 100644 index 0000000000000000000000000000000000000000..e16f25dc978434009b0bb036911e56872a2ddc21 --- /dev/null +++ b/aux/plotTriRet.R @@ -0,0 +1,28 @@ +#' @title Desenha um Triângulo Retângulo +#' @name plotTriRet +#' @export +#' +#' @description Exibe um triângulo retângulo a partir dos valores dos +#' catetos. +#' +#' @param a primeiro cateto. +#' @param b segundo cateto. +#' @param ... argumentos passados para a função +#' \code{\link[lattice]{xyplot}} +#' +#' @return Um grafico xyplot do pacote lattice. +#' +#' @seealso \code{\link[lattice]{xyplot}}. +#' +#' @importFrom lattice xyplot +#' +#' @examples +#' +#' plotTriRet(a=3, b=4) +#' +plotTriRet <- function(a, b, ...){ + x <- c(0, a, 0, 0) + y <- c(0, 0, b, 0) + xyplot(y ~ x, type = c("l", "g"), aspect = "iso", + xlab = NULL, ylab = NULL, col = 1, ...) +} diff --git a/cap03.Rmd b/cap03.Rmd new file mode 100644 index 0000000000000000000000000000000000000000..2fdbfa22979e77a2189c160cc874705b99e55dae --- /dev/null +++ b/cap03.Rmd @@ -0,0 +1,838 @@ +--- +title: "Pacote R" +author: "Fernando Mayer & Walmes Zeviani" +--- + +```{r setup, include=FALSE} +library(knitr) + +opts_chunk$set( + dev.args=list(family = "Palatino")) + +options(width = 68) + +## Carrega as definições de sessão. +source("config.R") +rty <- "md" +``` + +**** +# Pacote R # + + * O jeito mais fácil de tornar acessível o código. + * Publicar artigo com material suplementar na forma de pacote. + +**** +# *devtools* & *roxygen2* # + + * Facilitam o desenvolvimento de um pacote R. + * Torna o processo mais simples para um usuário pouco experiente. + * Instalar os pacotes do CRAN e do GitHub. + +**** +# Estrutura de um pacote R # + +Basicamente um pacote do R é uma convenção para organizar e padronizar a +distribuição de funções extras do R. Todo pacote é composto +*obrigatoriamente* por apenas dois diretórios e dois arquivos de meta +dados: + + * `R/`: um diretório contendo as funções em arquivos `*.R` (ex.: + `foo.R`). + * `man/`: um diretório contendo a documentação (páginas de ajuda) de + cada função do diretório acima. Os arquivos de documentação do R + terminam com a extensão `.Rd` (ex.: `foo.Rd`). + * `DESCRIPTION`: um arquivo texto contendo as informações sobre o seu + pacote: título, descrição, autor(es), licença, pacotes do qual + dependende, etc. + * `NAMESPACE`: um arquivo texto que informa quais funções do seu + pacote serão exportadas, ou seja, aquelas que estarão disponíveis + para o usuário, e quais funções são importadas de outros pacotes dos + quais o seu depende. + +Outros componentes que não são obrigatórios, mas podem estar presentes +no pacote são: + + * `tests/`: um diretório contendo *scripts* com testes unitários, + rodados durante a criação do pacote, para testar se existe algum + resultado não esperado sendo retornado por alguma de suas funções. + * `vignettes/`: um diretório que contém uma ou mais *vignettes*, que + traduzidas literalmente são como "vinhetas", pequenos (ou mesmo + grandes) textos que explicam com mais detalhes como os usuários + podem usar as funções de seu pacote. + * `data/`: um diretório contendo arquivos de dados (normalmente em + formato binário e comprimido do R, `.rda` ou `.RData`), que podem + ser usados como exemplos para aplicação das funções do pacote. + +Ainda são comuns diretórios `demo/`, `src/` e +`data-raw/`. TODO-descrever. + +Caso você queira começar a contruir um pacote, as opções são: 1) criar +todos os componentes (diretórios e arquivos) manualmente e ir +alimentando com conteúdo, ou 2) usar a função `create()` do pacote +`devtools` para criar a estrutura inicial, com os arquivos e diretórios +fundamentais, de um pacote. Nesse guia optaremos pela segunda opção pela +já justificada praticidade. Portanto: + +```{r create, comment=NA, include=FALSE, purl=FALSE} +library(devtools) +if (dir.exists(paths="./meupacote")) { + unlink("./meupacote/", recursive = TRUE, force = TRUE) +} +``` +```{r, comment=NA, eval=TRUE} +## Carrega o pacote devtools. +library(devtools) +packageVersion("devtools") + +## Cria o pacote. +create("meupacote", rstudio = FALSE) +``` +```{r, include=FALSE} +## Guarda no NAMESPACE vazio para exibir lá na frente. +namespace <- readLines("./meupacote/NAMESPACE") +``` + +Versões do pacote `devtools` anteriores à 1.9.1 não criam +automaticamente o arquivo `DESCRIPTION`, apenas criam o diretório `R/` e +o arquivo `NAMESPACE`. Em caso de você estar com uma versão defazada do +`devtools`, instale a mais recente do +`r renderUrl("CRAN","https://cran.r-project.org/web/packages/devtools/index.html",rty)` +(estável) ou de desenvolvimento no GitHub do +`r renderUrl("autor","https://github.com/hadley/devtools",rty)`. + +Como pode ser observado na saída acima, esse comando cria um diretório +chamado `meupacote`, contendo os arquivos `DESCRIPTION` e `NAMESPACE` e +o diretório `R/`. + +```{r, echo=FALSE, comment=NA} +cat(system("tree --charset=ascii -F ./meupacote/ | head -n -2", + intern = TRUE), + sep = "\n") +``` + +O diretório `R/` é criado vazio, bem como o arquivo `NAMESPACE`. Já o +arquivo `DESCRIPTION` é criado com algumas informações de sugestão. + +```{r, echo=FALSE, comment=NA} +cat(readLines("./meupacote/DESCRIPTION"), sep = "\n") +``` + +Todo pacote precisa ter o arquivo que o descreve, o `DESCRIPTION`. Uma +forma fácil de criá-lo já com informações do seu pacote, é usando a +função `write.dcf()` (dfc: `Debian control format`) ou o comando +`cat()`, como é ilustrado a seguir. Depois de criado, sinta-se livre +para abrir com seu editor favorito, editar e ampliar. + +```{r, eval=FALSE} +write.dcf( + list(Package = "meupacote", + Title = "Meu Primeiro Pacote R", + Version = "0.0-1", + Author = "Walmes Zeviani <walmes@ufpr.br>", + Maintaner = "Fernando Mayer <fernandomayer@ufpr.br>", + Description = "O que esse pacote faz", + License = "GPL-3", + LazyData = "true", + Depends = sprintf("R (>= %s)", getRversion())), + file = "meupacote/DESCRIPTION"), + indent = 4) +``` +```{r} +cat(file = "meupacote/DESCRIPTION", sep = "\n", + sprintf('Package: meupacote +Title: Meu Primeiro Pacote R +Version: 0.0-1 +Authors@R: as.person(c( + "Fernando de Pol Mayer <fernando.mayer@ufpr.br> [aut,cre]", + "Walmes Marques Zeviani <walmes@ufpr.br> [aut]")) +Description: Esse é o primeiro pacoteque estamos fazendo. Nesse tutorial + o pacote será desenvolvido com funções, dados e vinheta. +License: GPL-3 +URL: http://git.leg.ufpr.br/leg/prr +BugReports: http://git.leg.ufpr.br/leg/prr/issues +LazyData: true +Encoding: UTF-8 +Depends: + R (>= %s)', getRversion())) +``` + +Abaixo serão especificados os detalhes para a criação de cada um dos +componentes exibidos acima. + +## `DESCRIPTION`: Caracterização do pacote ## + +Como você já deve supor, o arquivo `DESCRIPTION` caracteriza o seu +pacote: quem é (são) o(s) autor(es), uma breve descrição do que ele faz, +qual o tipo de licença, quais pacotes são necessários para que o seu +funcione, e mais alguns detalhes. + +No arquivo `DESCRIPITION` uma série de +`r renderUrl("campos","http://r-pkgs.had.co.nz/description.html",rty)` é +permitida. Cada linha representa um campo, alguns obrigatórios (*) e +outros opcionais (#), e após os dois pontos é o valor. Campos que +excedem uma linha devem ser indentados. + + * `Package` (*): é o nome do pacote. Não deve conter espaços, deve + começar com uma letra e o restante deve ser + alfanumérico. Caracteres especiais, como pontuações e acentos, não + são permitidos. + * `Title` (*): é o título do seu pacote. Recomenda-se que, por ser um + título, seja curto e informativo. + * `Version` (*): é a versão do pacote. A versão inicia (ou atual do + pacote). O versionamento de qualquer pedaço de software é uma coisa + muito importante e não há um consenso de que exista um padrão para + todos os casos. No entanto, nos pacotes do R, recomenda-se que as + versões sejam do tipo `x.y-z` ou `x.y.z` onde `x` seria o contador + de versão "maior", `y` de versão "menor", e `z` de "patches" + (alterações menores no código, como correção de bugs por exemplo). + * `Author` ou `Authors@R` (*): lista os criadores, autores e + colaboradores do pacote. Existem várias formas de preencher esse + campo, sendo a mais simples àquele para um único autor e as duas + opções a seguir, equivalentes, para projetos coletivos. + + Authors@R: c( + person("Hadley", "Wickham", + email = "hadley@rstudio.com", + role = "cre"), + person("Winston", "Chang", + email = "winston@rstudio.com", + role = "aut")) + + Authors@R: as.person(c( + "Hadley Wickham <hadley@rstudio.com> [aut, cre]", + "Winston Chang <winston@rstudio.com> [aut]")) + O argumento `role` é importante pois é ele que identifica o papel + de cada autor no desenvolvimento do pacote. Por padrão, é + necessário ter um (e somente um) autor (`"aut"`) e um mantenedor + (`"cre"`), que pode ou não ser a mesma pessoa. Outros papéis, como + por exemplo o de um contribuidor (`"ctb"`), e outros detalhes dessa + função estão em `?person`. O criador ou mantenedor (`"cre"`) é + quase sempre o principal desenvolvedor do projeto, responsável pela + gestão e quem recebe notificações de *bugs*, por exemplo. O autor + (`"aut"`) é quem dá contribuições grandes ao projeto. O colaborador + `"ctb"` é quem dá contribuições menores, ocasionais. Pelo menos um + dos listados no campo autor deve ser o mantenedor (`[cre]`) para + evitar erros durante produção do pacote. + * `Description` (*): Uma descrição um pouco mais detalhada sobre o que + o seu pacote faz. É preciso ter pelo menos duas frases completas + (sim, o R confere isso), mas não muito maior do que um parágrafo, + algo com não mais de 10 linhas. + * `Imports` (#): é um campo para listar os pacotes do qual o seu + obrigatoriamente precisa. A lista de pacotes é separada por + vírgula, em geral um por linha. Aqui entram aqueles pacotes cujas + funções são usadas por você dentro das suas funções. Quando o seu + pacote for instalado, esses pacotes devem estar presentes. Aqueles + que são do CRAN (oficiais) são instados automaticamente. O usuário + deve instalar previamente àqueles que não forem oficiais, como + muitos no github e bioconductor. TODO:verificar Colocar um pacote + nesse campo garante que o pacote estará **instalado**, mas não que + ele será carregado toda que vez que o seu pacote for + carregado. Para utilizar funções de outros pacotes corretamente é + necessário especifições da forma `pacote::funcao()` ou então + utilizar o arquivo `NAMESPACE` conforme veremos abaixo. + * `Depends` (#): esse campo é muito similar ao anterior. A diferença é + que pacotes no `Imports` são carregados (*loaded*) e no `Depends` + são anexados (*attached*). + Dada essa diferença mínima, é muito comum só haver o campo + `Imports`. É comum o `Depends` indicar a versão do R que o seu + pacote depende. É sempre prudente colocar uma versão que seja maior + ou igual a versão que você está desevolvendo o pacote. Em ambos + campos é possível indicar a versão mínima exigida dos pacotes, + conforme abaixo. + + Depends: + R (>= 2.15), + lattice + Imports: + ggplot2, + Matrix (>= 1.2.0), + methods + * `Suggests` (#): é para listar os pacotes do qual o seu tira + proveito, mas que não são exigências. Aqui entram pacotes do qual o + seu chama uma função ou *dataset* na sessão exemplos da + documentação. O usuário precisará instalar aqueles que não + possuir. Diferente daqueles no `Imports` os pacotes listados aqui + não serão instalados junto com o seu. Eles podem ser usados, mas + não são necessários. Por exemplo, você pode usar um pacote apenas + para usar alguma base de dados ou apenas uma função. Use esse campo + apenas se o seu pacote puder funcionar mesmo sem os pacotes + especificados. + * `License` (#): A licença é fundamental se você pretende compartilhar + o seu pacote. Algumas opções comuns são: `CC0` (nenhum tipo de + restrição), `MIT` (prevê atribuição mas é bastante permissiva), e + `GPL-3` (a mais utilizada, requer que qualquer trabalho derivado do + seu seja distribuido com a mesma licença). Para mais opções e + detalhes sobre licenças de software livre, consulte + <http://choosealicense.com>. + * `LazyData` (#): Essa opção somente é importante se você pretende + distribuir algum conjunto de dados com o seu pacote (arquivos + `.rda` no diretório `data/`). Com a opção acima, os dados só serão + carregados se realmente forem chamados (com a função `data()`), e + não carregados na inicialização do pacote. Isso garante mais + agilidade para carregar o pacote e economiza memória caso os dados + não sejam utilizados (especialmente se as bases de dadpos forem + gandes). + * `URL` (#): um site de referencia onde você hospeda o pacote, por + exemplo. + * `BugReports` (#): normalmente endeços para sistemas de controle de + versão, como github e gitlab, onde os usuários podem submeter os + *bugs*. + * `Encoding` (#): É um campo extremamente necessário para nós de + lingua latina pois permite acentos na documentação do pacote, + testos de comentários, etc. Desenvolvedores Linux usam `UTF-8`. + * `VignetteBuilder` (#): Habilitou-se o uso do `knitr` a partir da + versão 3.0.0 do R para produção de + `r renderUrl("vinhetas","http://yihui.name/knitr/demo/vignette/",rty)`. + Estas podem ser escritas em RMarkDown (para html ou pdf), além de + ainda manter RLatex. Antes vinhetas tinham que ser feitas em + Sweave. Esse campo serve para indicar o pacote `knitr`, que também + deve aparecer, pelo menos, no campo `Suggests` também. + +Para podermos utilizar esse arquivo para de fato gerarmos um pacote de +exemplo ao final deste tutorial, vamos modificar alguns campos e +utilizar o seguinte arquivo `DESCRIPTION`: + +## `R/`: Funções + +O diretório `R/` irá conter apenas as funções (arquivos `.R`) do seu +pacote. As funções podem estar em vários arquivos `.R` separados (um +para cada função) ou em arquivos com várias funções cada. A escolha é +mais uma questão de preferência pessoal, mas como veremos mais adiante, +utilizar arquivos separados para as funções torna o processo de +documentação um pouco mais ágil, além de facilitar a manutenção do +pacote com o tempo. + +Para exemplificar, vamos criar uma função simples para resolver um +problema bem conhecido: calcular a hipotenusa de um triângulo retângulo +a partir dos catetos, cuja solução se baseia no Teorema de +Pitágoras. Vamos colocar a função no diretório diretório `R/` com o nome +`pitagoras.R`. + +```{r, eval=FALSE} +pitagoras <- function(a, b){ + h <- sqrt(a^2 + b^2) + return(h) +} +``` +```{r, include=FALSE} +file.copy(from = "./aux/pitagoras.R", to = "./meupacote/R/pitagoras.R") +``` + +Com a função pronta, possivelmente iremos (e devemos) testá-la. Para +carregá-la executamos a função `load_all()` do pacote `devtools` em uma +seção do R com diretório de trabalho apontando para o arquivo +`DESCRIPTION`. + +```{r, echo=TRUE, eval=FALSE} +## Carrega todas as funções do pacote. Assume estar em meupacote/. +load_all() +``` +```{r, echo=FALSE, eval=TRUE} +load_all("meupacote/") +``` +```{r} +## Note que o package:meupacote foi carregado. +search() + +## Os objetos exportados estão disponíveis. +ls("package:meupacote") + +## class(pitagoras); formals(pitagoras); body(pitagoras) +pitagoras +``` + +Essa instrução irá carregar todas as funções que estiverem dentro do +diretório `R/`, tornado-as disponíveis para uso. Além disso carrega os +datasets do diretório `data/` que veremos adiante. + +Se utilizassemos a função `source("R/pitagoras.R")` para carregar a +função teria o mesmo efeito: as funções estariam disponíveis para +uso. No entanto, se tivermos vários arquivos, e/ou estivermos testando +alterações em muitas funções, a função `load_all()` é bem mais +conveniente. Além do mais, as funções carregas com `load_all()` ficam no +*enviroment* do pacote (`package:meupacote`) e não no *workspace* junto +aos objetos de você cria durante a sessão, o `.GlobalEnv`. + +Para melhorar ou corrigir as funções, basta fazer as nos arquivos `.R`, +carregá-las com `load_all()` e testar novamente. Esse processo +geralmente se repete muitas vezes durante o desenvolvimento de um +pacote. + +## `man/`: Documentação + +Você deve ter notado que o diretório `man/` não é criado da mesma forma +que os demais quando utilizamos a função `create()`. Isso porque esse +diretório depende das funções, quatidade e nomes, que serão criadas +dentro do diretório `R/`. No entanto, ele também é obrigatório para +podermos criar um pacote mínimo. + +Como mencionado anteriormente, a documentação de funções do R segue um +formato muito parecido com o LaTeX (mas com alguns comandos +próprios). Cada função criada dentro do diretório `R/`, independente de +estar em um arquivo separado ou único (com várias funções), deve +**obrigatoriamente** ter um arquivo correspondente dentro do diretório +`man/`, com a extensão `.Rd`. Em outras palavras, mesmo que você decida +manter funções no mesmo arquivo em `R/`, as documentações delas estarão +em arquivos separdas em `man/`. Fica um pouco difícil de manter +correspondência e por isso é comum ter uma função por arquivo em +`R/`. Existes excessões. + +Sendo assim, a nossa função de exemplo acima, que está em um arquivo +chamado `pitagoras.R`, precisa de um arquivo `pitagoras.Rd` dentro do `man/` para +documentá-la. + +Existem duas formas de documentar uma função com os arquivos `.Rd`: uma +é da maneira tradicional, escrevendo manualmente a documentação +utilizando a linguagem específica e colocando os campos necessários. Os +detalhes de como fazer isso manualmente estão em +`r renderUrl("Writing R documentation files","http://cran.r-project.org/doc/manuals/r-release/R-exts.html",rty)`. +Outra forma de escrever a documentação de uma função é utilizando o +pacote `roxygen2`, que utiliza algumas etiquetas, ou *tags*, simples e +permite que você escreva a documentação dentro do próprio arquivo +`.R`. Dessa forma fica muito mais simples alterar ou atualizar a +documentação de uma função, pois tudo se concentra dentro de um único +arquivo. + +Neste texto vamos utilizar o pacote `roxygen2` para gerar a documentação +das funções. O primeiro passo é escrever a documentação dentro do +arquivo `.R`. A documentação usando o `roxygen2` segue o seguinte +formato: + + * Toda documentação começa com um comentário especial, do tipo `#'` + (note o `'` depois do `#`). + * Os campos de documentação são criados a parir de etiquetas (*tags*) + que iniciam com `@`, colocados logo após um comentário especial + `#'`. + * Toda a documentação deve ficar diretamente acima do início da + função. + +A documentação com o `roxygen2` da nossa função `pitagoras()` é exibida +a seguir. + +```{r, echo=FALSE, comment=NA} +cat(readLines("meupacote/R/pitagoras.R"), sep = "\n") +``` + +Para gerar a documentação, basta utilizar a função `document()` do +pacote `devtools`. + +```{r, echo=TRUE, eval=FALSE} +## Gera/autualiza do diretório man/ com as documentações. +document() +``` +```{r, echo=FALSE, eval=TRUE} +document("meupacote/") +``` +```{r, echo=FALSE, comment=NA} +cat(system("tree --charset=ascii -F ./meupacote/ | head -n -2", + intern = TRUE), + sep = "\n") +``` + +O resultado da chamada dessa função é: + + * Criar o diretório `man/` se ele ainda não existir, ou se for a + primeira vez que estiver criando a documentação com a função + `document()`. + * Gerar os arquivos `.Rd` dentro de `man/` (se ainda não existirem) + correspondentes às funções no diretório `.R`. + * Se os arquivos `.Rd` já existirem, a chamada da função `document()` + irá apenas atualizar os arquivos que foram modificados. + * Escrever no arquivo `NAMESPACE` as funções a serem exportadas ou + importadas. Veremos mais detalhes abaixo na seção `NAMESPACE`. + +Vale ressaltar que o comando `document()` do pacote `devtools` é de fato +um "wrapper" para a função `roxygenize()` do pacote `roxygen2`. + +No nosso exemplo, a chamada da função `document()` criou o diretório +`man/` e gerou o arquivo `pitagoras.Rd`. Note que é muito mais simples +escrever com o `roxygen2` do que ter que editar esse arquivo todo a +mão. Note também o comentário no início desse arquivo. O `roxygen2` +deixa claro que você não deve (e não precisa) modificar esse arquivo +`pitagoras.Rd` para atualizar a documentação. Sempre que alterar alguma +coisa faça no próprio arquivo `.R`, e a função `document()` irá +atualizar a documentação no arquivo `.Rd`. + +```{r, echo=FALSE, comment=NA} +cat(readLines("./meupacote/man/pitagoras.Rd"), sep = "\n") +``` + +Para conferir se a documentação está de acordo com o que você espera, a +qualquer momento, peça a documentação com `?pitagoras` ou +`help(pitagoras)`. Lembre-se de rodar a função `load_all()` para +carregar a documentação atualizada depois de `document()`. + +Uma outra forma mais automática de conferir se a documentação está +escrita de maneira correta, é utilizando a função `check_doc()` do +pacote `devtools`. Essa função avalia a consistência dos campos, se não +ficaram argumentos sem descrição, campos obrigatórios omissos, chaves +sem fechar, etc. + +```{r, echo=TRUE, eval=FALSE} +check_doc() +``` +```{r, echo=FALSE, eval=TRUE} +check_doc("meupacote/") +``` + +Se nenhuma mensagem de aviso ou erro apareceu acima, então a +documentação está de acordo com o esperado, sintaticamente. + +Alguns detalhes das etiquetas utilizadas nesse exemplo do +`roxygen2` (<http://r-pkgs.had.co.nz/man.html>): + + * `@title`: um título curto da função (deve ser capitalizado). + * `@name`: o nome da função. + * `@description`: descreve o que a função faz e pra que ela serve, de + maneira geral. + * `@param`: descreve o que cada argumento da função faz. Deve ser + sempre no formato: `@param argumento descrição do argumento`. Quando + vários argumentos podem ser descritos juntos, eles devem ser + separados por vírgula mas sem espaços. + + @param title título do gráfico + @param x,y,z vetores de observações + @param ... argumentos passados para a função plot. + * `@details`: espaço para escrever mais detalhes, geralmente mais + técnicos, sobre a sua função, e/ou para detalhar alguma coisa + específica de algum argumento. + * `@return`: especifica o que a sua função retorna (um gráfico, uma + lista, um número, um vetor, um objeto de determinada classe). + * `@author`: autr(es) da função. + * `@seealso`: outras funções que podem ser úteis para quem está usando + a sua função, ou funções similares. No exemplo acima temos duas + marcações que são específicas da documentação do R: `\code{}` para + que o texto dentro das chaves saia com fonte monoespaço e verbatim + (`como esta`), geralmente para especificar nomes de funções, etc.; + `\link[<pacote>]{<função>}` faz o link para a página de ajuda de + alguma `<função>` dentro de algum `<pacote>`. Mais marcações do + formato `.Rd` podem ser encontradas no manual de documentação do R, + e podem ser utilizadas dentro na documentação com `roxygen2`. + * `@example`: exemplos de uso da sua função. + * `@export`: esta tag é a responsável por sua função ficar disponível + para os usuários, e é o que faz a função ser incluida no `NAMESPACE` + (mais detalhes serão vistos na seção `NAMESPACE` abaixo). Se você + não quer que a função seja disponibilizada para os usuários quando + carregarem o seu pacote (em funções internas ou auxiliares por + exemplo), simplesmente não inclua esta tag na documentação. + * `@source` É um campo considerado na documentação de *datasets* para + indicar a fonte dos mesmos. Geralmente contém uma url. + * `@references` É um campo para indicar publicações ou outros tipos de + referências com relação ao objeto documentado. + +Existem ainda campos permitidos que não foram aqui mencionados. A +`r renderUrl("vinheta","https://cran.r-project.org/web/packages/roxygen2/vignettes/rd.html",rty)` +do pacote `roxygen2` +lista todo o conjunto enquanto que uma referência fácil é o +`r renderUrl("*Cheat Sheet*","https://www.rstudio.com/wp-content/uploads/2015/03/devtools-cheatsheet.pdf",rty)` +do pacote `devtools`. + +## `NAMESPACE`: Organização + +<!-- http://r-pkgs.had.co.nz/namespace.html --> + +O `NAMESPACE` é um arquivo que ajuda a organizar as funções exportadas e +importadas pelo seu pacote. Ele ajuda um pacote a ser auto contido, no +sentido de que ele não vai interferir no funcionamento de outros +pacotes, e que também os outros pacotes não irão interferir no +funcionamento do seu. + +Normalmente, a especificação do `NAMESPACE` é a parte mais difícil da +criação de um pacote, mas com o uso do `devtools` como estamos fazendo, +normalmente não será necessário se preocupar com todos os detalhes que +envolvem esse arquivo. O mais importante é saber quais funções serão +exportadas do seu pacote, quais serão importadas, e de que maneira +podemos especificar essas funções. + +### Exportando funções ### + +Exportar funções do seu pacote nada mais é que torná-las disponíveis +para o usuário. No desenvolvimento de um pacote, normalmente são criadas +algumas funções internas ou auxiliares, que são utilizadas apenas por +uma ou mais funções principais e nunca chamadas diretamente. Se em +nenhum momento estas funções precisarem ser utilizadas pelo usuário do +pacote, então elas não precisam (e não devem) ser exportadas, para +minimizar a possibilidade de conflito com outros pacotes. + +Quando um pacote é carregado com `library()` ou `require()`, ele é +"anexado" (*attached*) ao *workspace* do usuário, tornando assim as +funções exportadas disponíveis para serem utilizadas. Você pode conferir +a lista de pacotes anexados em seu *workspace* com `search()`. + +Por padrão, quando iniciamos um pacote com a função `create()` do pacote +`devtools`, é criado um arquivo `NAMESPACE` que exporta automaticamente +**todas** as funções que forem criadas, e que não começem com um ponto +`.`. O arquivo `NAMESPACE` inicial possui a especificação a seguir, que +indica que são exportadas todos os objetos que não começam com ponto. + +```{r echo=FALSE, comment=NA} +cat(namespace, sep = "\n") +``` + +No entanto, se você não quiser exportar todas as funções de dentro do +diretório `R/`, será necessário especificar quais funções deseja +exportar. Para isso, basta usar a tag `@export` na documentação da +função com o `roxygen2` (assim como usamos na documentação da função +`soma.R` acima). A função `document()` é a responsável por verificar as +funções que possuem `@export` e colocá-las adequadamente no arquivo +`NAMESPACE`. Dessa forma, usando o nosso exemplo, após escrever as +funções com `@export` e rodar `document()`, o arquivo `NAMESPACE` passa +a listá-las. + +```{r echo=FALSE, comment=NA} +cat(readLines("./meupacote/NAMESPACE"), sep = "\n") +``` + +Cada objeto exportado, nesse caso todos funções, aparece nesse arquivo, +um em cada linha. Caso existam objetos que você não queira exportar, +basta não colocar a tag `@export` na documentação. (Na verdade, as +funções não exportadas não precisam nem ser documentadas, mas é sempre +uma boa prática escrever a documentação até mesmo para você no futuro). + +### Importando funções ### + +Normalmente as funções que estamos criando para um pacote utilizam +funções de outros pacotes. Todas as funções dos pacotes que são +distribuídos e automaticamente carregados quando você inicia uma sessão +do R, são disponíveis para serem utilizadas em qualquer outra função, +sem a necessidade de qualquer especificação adicional. Estes pacotes +básicos do R são: `base`, `utils`, `datasets`, `grDevices`, `graphics`, +`stats`, e `methods`. Esse conjunto de pacotes já garante uma grande +quantidade de funções, no entanto, algumas vezes podem ser necessárias +funções específicas de outros pacotes. + +Existem três formas básicas de importar, ou seja, utilizar funções de +outros pacotes dentro do seu pacote: + + 1. `pacote::funcao()`: chamar uma função utilizando o operador `::` é + recomendado quando o função for utilizada poucas vezes. Dessa forma + fica claro no seu pacote aonde uma função externa está sendo + utilizada. + 2. `@importFrom pacote funcao`: se uma funcao for utilizada váras + vezes dentro de um pacote, ou se mais de uma função do mesmo pacote + for utilizada, recomenda-se especifica-las com a tag `@importFrom` + na documentação `roxygen2`. Dessa forma não é necessário utilizar o + operador `::` na chamada das funções, o que torna o código um pouco + mais legível se muitas funções externas forem utilizadas. + 3. `@import pacote`: se o seu pacote depende de muitas funções de + outro(s) pacote(s), então o mais razoável é importar todas as + funções do pacote. Isso é feito utilizando a tag `@import` na + documentação do `roxygen2` da função. Dessa forma, todas as funções + do pacote estarão disponíveis para serem utilizadas no seu pacote. + +Já vimos anteriromemte na seção `DESCRIPTION` que exite um campo +`Imports` que serve para especificar de quais pacotes o seu depende. Se +você utilizou qualquer um dos três métodos acima para importar uma ou +várias funções, então **obrigatoriamente** o pacote que contém estas +funções deve ser listado no campo `Imports` (ou `Depends`) do arquivo +`DESCRIPTION`. + +O campo `Imports` do DESCRIPTION e a etiqueta `@imports` da +documentação, embora os nomes sejam iguais, seus papeis são distintos. O +`Imports` apenas verifica se os pacotes listado está presente equanto +que o `@imports` importa as funções para uso e tem ligação com o +`NAMESPACE`. + +Uma distinção importante é que listar os pacotes no campo `Imports` do +arquivo `DESCRIPTION` garante que o usuário terá instalado os pacotes +necessários para que o seu funcione. No entanto, ele não é o responsável +por carregar e tornar as funções desse pacote disponível. Esse papel é +feito por algum dos três métodos citados acima, que por consequência +irão atualizar o arquivo `NAMESPACE`, que é o verdadeiro responsável por +carregar os pacotes e funções necessárias para o uso do seu pacote. + +Por exemplo, vamos criar uma função personalizada para fazer um gráfico +de pontos utilizando a função `xyplot()` do pacote `lattice`. Vamos +supor que esse gráfico personalizado usa um `x` no lugar do ponto (`pch += 4`), e de cor preto (`col = 1`), já que o padrão do `lattice` é azul +claro. Vamos chamar essa função de `meuxy()` e colocá-la no arquivo +`meuxy.R` do diretório `R/`. O conteúdo desse arquivo é exibido a +seguir. + +```{r, echo=FALSE, comment=NA, include=FALSE} +file.copy(from = "aux/plotTriRet.R", + to = "meupacote/R/plotTriRet.R", + overwrite = TRUE) +``` +```{r, echo=FALSE, comment=NA} +cat(readLines("./meupacote/R/plotTriRet.R"), sep = "\n") +``` + +Agora é necessário rodar a função `document()` para gerar o arquivo +`man/plotTriRec.Rd`. Isso também atualiza o arquivo `NAMESPACE`, com a +exportação da função `plotTriRet()`, e a importação da função `xyplot()` +do pacote `lattice`. + +```{r, echo=TRUE, eval=FALSE} +document() +``` +```{r, echo=FALSE, eval=TRUE} +document("meupacote/") +``` + +Note que, na mensagem acima, além de criar o arquivo `meuxy.Rd`, houve +uma atualização do arquivo `NAMESPACE` para importar a função `xyplot()` +da `lattice`. Ou seja, já estamos exportando a função `meuxy()`, e +importando a função `xyplot()` do pacote `lattice`, através da função +`importFrom()`, colocada no `NAMESPACE`. + +```{r, echo=FALSE, comment=NA} +cat(readLines("./meupacote/NAMESPACE"), sep = "\n") +``` + +Note que utilizamos a etiqueta (*tag*) + +```{r, eval=FALSE, highlight=FALSE} +#' @importFrom lattice xyplot +``` + +Mas poderíamos também ter utilizado o operador `::` diretamente na +função, por exemplo + +```{r, eval=FALSE} +plotTriRet <- function(a, b, ...){ + x <- c(0, a, 0, 0) + y <- c(0, 0, b, 0) + lattice::xyplot(y ~ x, type = c("l", "g"), aspect = "iso", + xlab = NULL, ylab = NULL, col = 1, ...) +} +``` + +E, nesse caso, não precisariamos usar a tag `@importFrom`. O resultado +no `NAMESPACE` seria o mesmo. A tag `@import` também poderia ter sido +utilizada, por exemplo, + +```{r, eval=FALSE, highlight=FALSE} +#' @import lattice +``` + +No entanto, nesse caso não há vantagem em importar todo o pacote pois +estamos utilizando apenas uma função. + +Como mencionameos anteriormente, a importação de funções realizadas até +aqui, cria as entradas necessárias no arquivo `NAMESPACE` e torna as +funções disponíveis para o pacote. Sempre que importarmos qualquer +função, será necessário acresentar o nome do pacote à que a função +pertence no arquivo `DESCRIPTION`, mais especificamente no campo +`Imports`. Isso garante que o usuário que instalar o seu pacote também +terá instalado o pacote necessário para que o seu funcione. Esta +inserção deve ser feita manualmente, e dessa forma, +o arquivo `DESCRIPTION` ficaria atualizado com o seguinte conteúdo +(repare a última linha): + +```{r, eval=FALSE} +## Adiciona lattice ao campo Imports no DESCRIPTION. +use_package(package = "lattice", type = "Imports") +``` +```{r echo=FALSE, comment=NA} +use_package(package = "lattice", type = "Imports", pkg = "./meupacote/") +cat(readLines("./meupacote/DESCRIPTION"), sep = "\n") +``` + +Os campos dentro do arquivo `DESCRIPTION` não seguem uma ordem +establecida conforme você já pode perceber. Em geral, por razões óbvias, +os campos iniciais sempre fornecem as informações para humanos e no +final os campos que controlam a construção. + +**** +# Construindo o pacote # + +A última etapa é finalmente construir o pacote, ou seja, gerar um +arquivo fonte (ou binário) que pode ser distribuído para os usuários +instalarem. + +Antes de construir o pacote, podemos rodar uma série de checagens para +conferir se todos os componentes do pacote estão funcionando como seria +o esperado. Essa checagem é feita com o comando `R CMD check` depois de +construir o pacote. No entanto, como estamos usando o `devtools`, +podemos simplificar e utilizar a função `check()` para realizar a mesma +checagem automaticamente, de dentro de uma sessão do R, e deixar para +construir o pacote só no final quando tudo estiver funcionando. + +```{r, echo=TRUE, eval=FALSE} +check() +``` +```{r, echo=FALSE, eval=TRUE, comment=NA} +## Essa chamada so mostra a parte inicial do output. +check("meupacote/") +``` +```{r, echo=FALSE, eval=TRUE, comment=NA} +## Para mostrar o output da chamada da funcao foi necessario chamar o +## Rscript dentro do system. +cat(system("Rscript -e 'library(devtools); check(\"./meupacote/\")'", + intern = TRUE), + sep = "\n") +``` + +Note que esta checagem é bem completa, e se o *status* final for `OK`, +então o pacote está funcionando e pronto para ser instalado. Se nesta +checagem aparecer no final algum `NOTE`, significa que o pacote funciona +mas algumas coisas precisam ser arrumadas. Se houverem `ERROR`s, o +processo de checagem é parado e não é possível instalar o seu pacote até +que no seja arrumado. + +Finalmente para construir o pacote, usaremos a função `build()` do +pacote `devtools`. + +```{r, echo=TRUE, eval=FALSE} +build() +``` +```{r, echo=FALSE, eval=TRUE, results="hide", comment=NA} +## Essa chamada so mostra a parte inicial do output. +build("meupacote/") +``` +```{r, echo=FALSE, eval=FALSE, results="hide", comment=NA} +## Para mostrar o output da chamada da funcao foi necessario chamar o +## Rscript dentro do system. +cat(system("Rscript -e 'library(devtools); build(\"meupacote/\")'", + intern = TRUE), + sep = "\n") +``` + +O resultado da chamada dessa função é o arquivo `r dir(pattern = +".tar.gz")` que contém o código-fonte do seu pacote e está pronto para +ser distribuído e instalado no Linux e Mac. + +No mesmo diretório onde você está desenvolvendo o pacote, você pode ter +outros arquivos e diretórios. Por exemplo, algumas pessoas preferem ter +um diretório que não irá fazer parte do pacote, mas que serve para +guardar *scripts* de teste, bases de dados, material em desenvolvimento, +etc. Nestes casos é necessário especificar que estes arquivos e +diretórios devem ser ignorados no processo de checagem (`check()`) e +construção do pacote (`build()`). Caso algum arquivo ou diretório que +não seja comum ao pacote do R, esses comandos retornarão com um erro, e +não será possível construir o pacote. Para evitar estes erros e ao mesmo +tempo manter esses arquivos e diretórios, liste-os pelo nome no arquivo +`.Rbuildignore` na raíz do pacote. Por exemplo, se você tiver o +diretório `playground/` e um arquivo chamdo `teste.R`, coloque no +arquivo `.Rbuildignore`: + +``` +teste.R +playground/ +``` + +Para gerar um arquivo binário (`.zip`) para instalar no Windows, o +processo é mais complicado (como tudo no Windows). Esse arquivo binário +só é possível ser gerado de dentro do Windows, o que, em muitos casos, +não está disponível para uso. Uma opção então é utilizar o +`r renderUrl("*win-builder*","http://win-builder.r-project.org/",rty)`, +um servidor Windows disponibilizado pelos mantenedores do R para que +pessoas sem acesso ao Windows possam gerar arquivos binários de +pacotes. O processo consiste em entrar na página e enviar o código-fonte +(`.tar.gz`) por upload. Em alguns minutos você recebe um email com o +link para baixar a versão binária do seu pacote para Windows. + +Como estamos usando o `devtools`, podemos apenas utilizar a função +`build_win()`, que irá fazer todo esse processo automaticamente. O link +com a versão binária do arquivo será enviado para o email colocado no +campo `Maintainer` no arquivo `DESCRIPTION`, por isso é importante que +seja um email válido. + +```{r eval=FALSE} +build_win() +``` + +Uma vantagem dessa função é que ela também roda uma checagem para ver se +o pacote funcionará adequadamente no Windows. diff --git a/cap04.Rmd b/cap04.Rmd new file mode 100644 index 0000000000000000000000000000000000000000..9b2c9059eac6f2c589d2357e1145be6306c4b79b --- /dev/null +++ b/cap04.Rmd @@ -0,0 +1,18 @@ +--- +title: "Pacote com dados" +author: "Fernando Mayer & Walmes Zeviani" +--- + +```{r setup, include=FALSE} +library(knitr) + +opts_chunk$set( + dev.args=list(family = "Palatino")) + +options(width = 68) + +## Carrega as definições de sessão. +source("config.R") +rty <- "md" +``` + diff --git a/cap05.Rmd b/cap05.Rmd new file mode 100644 index 0000000000000000000000000000000000000000..8ce2d6264f4dabcc14a297771a1e7cbbe6221ae6 --- /dev/null +++ b/cap05.Rmd @@ -0,0 +1,18 @@ +--- +title: "Métodos e Funções Genéricas" +author: "Fernando Mayer & Walmes Zeviani" +--- + +```{r setup, include=FALSE} +library(knitr) + +opts_chunk$set( + dev.args=list(family = "Palatino")) + +options(width = 68) + +## Carrega as definições de sessão. +source("config.R") +rty <- "md" +``` + diff --git a/cap06.Rmd b/cap06.Rmd new file mode 100644 index 0000000000000000000000000000000000000000..3d21009f82ca66f692272269deb4a1e5065fbbc7 --- /dev/null +++ b/cap06.Rmd @@ -0,0 +1,18 @@ +--- +title: "Vinhetas" +author: "Fernando Mayer & Walmes Zeviani" +--- + +```{r setup, include=FALSE} +library(knitr) + +opts_chunk$set( + dev.args=list(family = "Palatino")) + +options(width = 68) + +## Carrega as definições de sessão. +source("config.R") +rty <- "md" +``` + diff --git a/cap07.Rmd b/cap07.Rmd new file mode 100644 index 0000000000000000000000000000000000000000..33b07363f8be4fa4ba19353f9b845d1f0017f293 --- /dev/null +++ b/cap07.Rmd @@ -0,0 +1,18 @@ +--- +title: "Testes" +author: "Fernando Mayer & Walmes Zeviani" +--- + +```{r setup, include=FALSE} +library(knitr) + +opts_chunk$set( + dev.args=list(family = "Palatino")) + +options(width = 68) + +## Carrega as definições de sessão. +source("config.R") +rty <- "md" +``` + diff --git a/style.css b/style.css index 9510ff098fb70bb18dfb91af0e1f3e2c424e951b..0ab316dcb0e536325becd16f5582a4c3a4eae7b6 100644 --- a/style.css +++ b/style.css @@ -8,10 +8,19 @@ tt, code, pre { font-family: "Inconsolata", "Andale Mono", monospace; } -code { - font-size: 16px; +/* Controla o título. */ +#header { + text-align: center; + border-bottom: 1px solid black; + margin-bottom: 20px; } +/* Controla o sumário. */ +/* #TOC { display: block; } */ +/* h1.title {} */ +/* h4.author {} */ +/* code { font-size: 16px; } */ + pre code { font-size: 14px; } @@ -48,4 +57,4 @@ img { .MathJax { font-size: 80% !important; -} \ No newline at end of file +}