Thank you for considering contributing to evanverse! This document provides guidelines for contributing to the package.
Table of Contents
- Code of Conduct
- How Can I Contribute?
- Development Setup
- Pull Request Process
- Coding Standards
- Testing Guidelines
- Documentation
- CRAN Compliance
Code of Conduct
This project follows the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to evanzhou.bio@gmail.com.
How Can I Contribute?
Reporting Bugs
Before creating bug reports, please check the issue tracker to avoid duplicates.
When filing a bug report, include:
Clear title and description
Reproducible example using
reprex::reprex()-
Environment details:
sessionInfo() packageVersion("evanverse") Expected vs. actual behavior
Suggesting Enhancements
Enhancement suggestions are tracked as GitHub issues.
When suggesting enhancements, include:
- Use case description
- Proposed API design (if applicable)
- Examples of how it would work
- Alternative solutions you’ve considered
Development Setup
Setup Instructions
# 1. Clone your fork
git clone https://github.com/YOUR-USERNAME/evanverse.git
cd evanverse
# 2. Install development dependencies
install.packages("devtools")
devtools::install_dev_deps()
# 3. Load the package for development
devtools::load_all()
# 4. Run tests
devtools::test()
# 5. Run R CMD check
devtools::check()Development Workflow
# Load package during development
devtools::load_all()
# Run specific tests
devtools::test_active_file()
# Update documentation
devtools::document()
# Check package
devtools::check()Pull Request Process
Branch Strategy
-
main: Stable, CRAN-released code -
dev: Development branch (target for PRs) -
Feature branches:
feature/your-feature-name -
Bug fixes:
fix/issue-description
Commit Messages
We follow the Conventional Commits specification with emojis:
<emoji> <type>: <description>
[optional body]
Types: - feat ✨ - New feature - fix 🐛 - Bug fix - docs 📝 - Documentation changes - style 💄 - Code style/formatting - refactor ♻️ - Code refactoring - test ✅ - Adding/updating tests - chore 🔧 - Maintenance tasks - ci 🚀 - CI/CD changes - perf ⚡ - Performance improvements
Examples:
✨ feat: add new color palette for single-cell data
🐛 fix: handle NA values in plot_venn correctly
📝 docs: update installation instructions for CRAN
Coding Standards
Style Guide
Follow the tidyverse style guide:
# Good
calculate_mean <- function(x, na.rm = TRUE) {
if (!is.numeric(x)) {
stop("`x` must be numeric")
}
mean(x, na.rm = na.rm)
}
# Bad
calculateMean<-function(x,na.rm=TRUE){
if(!is.numeric(x)){stop("`x` must be numeric")}
mean(x,na.rm=na.rm)}Function Design
- Use descriptive names (verbs for functions, nouns for objects)
- Validate inputs at the beginning of functions
- Return consistent types (don’t return different types based on input)
- Provide sensible defaults for optional parameters
-
Use
clipackage for user-facing messages
#' Calculate Summary Statistics
#'
#' @param data A data frame
#' @param col Column name (string or symbol)
#' @param na.rm Logical, remove NA values?
#' @return A named numeric vector
#' @export
#' @examples
#' calc_stats(mtcars, "mpg")
calc_stats <- function(data, col, na.rm = TRUE) {
# Input validation
if (!is.data.frame(data)) {
cli::cli_abort("{.arg data} must be a data frame")
}
# Function logic
x <- data[[col]]
c(
mean = mean(x, na.rm = na.rm),
sd = sd(x, na.rm = na.rm)
)
}Error Handling
Use cli package for consistent error messages:
# Good
cli::cli_abort("{.arg x} must be a single character string")
cli::cli_warn("Missing values detected in {.arg data}")
cli::cli_inform("Processing {nrow(data)} rows...")
# Avoid
stop("x must be a single character string")
warning("Missing values detected")
message("Processing...")Testing Guidelines
Test Structure
Every function should have corresponding tests in tests/testthat/test-<function_name>.R:
#===============================================================================
# Test: my_function()
# File: test-my_function.R
# Description: Unit tests for my_function()
#===============================================================================
#------------------------------------------------------------------------------
# Basic functionality
#------------------------------------------------------------------------------
test_that("my_function() works with valid input", {
result <- my_function(c(1, 2, 3))
expect_type(result, "double")
expect_length(result, 3)
})
#------------------------------------------------------------------------------
# Parameter validation
#------------------------------------------------------------------------------
test_that("my_function() validates input type", {
expect_error(my_function("invalid"), "must be numeric")
expect_error(my_function(NULL), "must be numeric")
})
#------------------------------------------------------------------------------
# Edge cases
#------------------------------------------------------------------------------
test_that("my_function() handles empty input", {
expect_equal(my_function(numeric(0)), numeric(0))
})
test_that("my_function() handles NA values", {
result <- my_function(c(1, NA, 3), na.rm = TRUE)
expect_equal(length(result), 2)
})Test Coverage Requirements
-
Minimum 3 tests per function:
- Expected use case
- Edge case
- Error handling
-
Use appropriate skip conditions:
skip_on_cran() # For slow or network-dependent tests skip_if_offline() # For tests requiring internet skip_if_not_installed("pkg") # For optional dependencies
Running Tests
# All tests
devtools::test()
# Specific file
devtools::test_active_file()
# With coverage report
covr::package_coverage()Documentation
Roxygen2 Comments
All exported functions must have complete roxygen2 documentation:
#' Brief Function Description
#'
#' Detailed description of what the function does. Can span
#' multiple lines and include examples of use cases.
#'
#' @param x A numeric vector. Description of the parameter.
#' @param na.rm Logical; if TRUE, remove NA values before computation.
#' Default is TRUE.
#' @param verbose Logical; print progress messages? Default is FALSE.
#'
#' @return A numeric vector of the same length as \code{x} containing
#' the transformed values.
#'
#' @export
#' @examples
#' # Basic usage
#' transform_data(c(1, 2, 3))
#'
#' # Handle NA values
#' transform_data(c(1, NA, 3), na.rm = TRUE)
#'
#' # With custom options
#' transform_data(1:10, verbose = TRUE)
#'
#' @seealso \code{\link{related_function}}Documentation Standards
- Title: One line, describing what the function does
- Description: More detailed explanation
- Parameters: Document every parameter, including types and defaults
- Return: Describe the return value type and structure
- Examples: At least 2-3 working examples
- Cross-references: Link to related functions
Updating Documentation
# Generate man pages from roxygen2 comments
devtools::document()
# Build and preview pkgdown site locally
pkgdown::build_site()CRAN Compliance
File System Guidelines
Good:
# Use tempdir() for temporary files
temp_file <- file.path(tempdir(), "output.csv")
write.csv(data, temp_file)
# Clean up
unlink(temp_file)Bad:
Network Access
# Always skip network tests on CRAN
test_that("download_url() works", {
skip_on_cran()
skip_if_offline()
result <- download_url("https://example.com/data.csv")
expect_true(file.exists(result))
})Running CRAN Checks
# Local check
devtools::check()
# Check on multiple platforms (requires Docker)
rhub::check_for_cran()
# Windows check
devtools::check_win_release()
devtools::check_win_devel()
# macOS check (requires macOS)
rhub::check_on_macos()Additional Resources
R Package Development
- R Packages (2e) by Hadley Wickham & Jennifer Bryan
- Writing R Extensions
- CRAN Repository Policy
Questions?
If you have questions about contributing, please:
- Check the documentation
- Search existing issues
- Open a new issue with the
questionlabel - Contact the maintainer: evanzhou.bio@gmail.com
License
By contributing to evanverse, you agree that your contributions will be licensed under the MIT License.
Thank you for contributing to evanverse! 🎉
