Skip to contents

Thank you for your interest in contributing to metasurvey.core, the local engine of the metasurvey ecosystem. This document outlines how to propose changes, report bugs, and contribute code.

Bug reports

If you find a bug, please file an issue on GitHub with a minimal reproducible example using the reprex package.

Include:

  • A description of the expected behavior vs. actual behavior.
  • The output of sessionInfo().
  • A minimal dataset, or use make_test_survey() from the test helpers.

If the bug involves the remote registry, the Shiny explorer, ANDA downloads, or the STATA transpiler, it likely belongs in a companion package — see the ecosystem table to find the right repository.

Feature requests and improvements

Use GitHub Discussions to propose new features, improvements, and ideas. Post in the “Ideas” category with a clear description of the problem and your proposed solution. Issues are reserved for confirmed bugs.

Development environment

git clone https://github.com/metasurveyr/metasurvey.core.git
cd metasurvey.core

# Install dependencies
Rscript -e 'pak::local_install_dev_deps()'

# Install pre-commit hooks (requires Python 3)
pip3 install pre-commit
pre-commit install

The usual devtools cycle applies:

devtools::document()   # regenerate man/ and NAMESPACE
devtools::test()       # run the test suite (1500+ tests)
devtools::check()      # full R CMD check

Pre-commit hooks

Pre-commit runs automatically on every commit (see .pre-commit-config.yaml). Among other things, the hooks format R code with styler::tidyverse_style(), lint against .lintr, spell-check documentation against inst/WORDLIST, and block artifacts like .RData or private keys. Roxygen docs are not regenerated by the hooks: run devtools::document() yourself before committing (CI checks that man/ and NAMESPACE are up to date).

Architecture

The main files in R/ (not exhaustive):

R/
├── survey.R            # Survey R6 class
├── PanelSurvey.R       # RotativePanelSurvey + PoolSurvey R6 classes
├── Step.R              # Step R6 class (lazy transformation unit) + bake_steps()
├── steps.R             # step_*() functional API: compute, recode, rename,
│                       # remove, join, filter, validate, quantile, ...
├── Recipes.R           # Recipe R6 class + read_recipe()
├── RecipeWorkflow.R    # RecipeWorkflow R6 class
├── RecipeRegistry.R    # Local (JSON) recipe registry
├── WorkflowRegistry.R  # Local (JSON) workflow registry
├── RecipeAPI.R         # RecipeBackend class ("local" + injectable "api")
├── WorkflowBackend.R   # WorkflowBackend class ("local" + injectable "api")
├── backend-provider.R  # .backend_api_call() hook for remote providers
├── recipe_tidy_api.R   # Tidy search/filter API for recipes
├── workflow_tidy_api.R # Tidy search/filter API for workflows
├── workflow.R          # workflow() — svymean/svytotal/svyratio/svyby
├── workflow_table.R    # Tabular output for workflow results
├── load_survey.R       # Survey loading helpers
├── harmonize.R         # Cross-edition harmonisation
├── provenance.R        # Variable provenance tracking
├── set_engine.R        # Processing engine selection
├── utils.R             # Package options (use_copy, lazy_processing, ...)
└── meta.R              # .onLoad hooks and package messages

Key patterns:

  • Lazy evaluation: step_*() functions record but don’t execute. Call bake_steps() to materialize.
  • data.table everywhere: internal data ops use data.table syntax, never dplyr. Use :=, set(), merge.data.table().
  • No rlang: all metaprogramming uses base R (substitute(), eval(), match.call()). rlang is prohibited.
  • R6 classes: PascalCase names, $initialize(), $print(), $clone(). Step functions are functional wrappers that create Step objects internally.
  • Copy semantics: the use_copy option controls whether steps clone data. Default TRUE for safety. Use set_data() instead of $data <- assignment.
  • Local only: this package must work with no network access. Anything that talks to a remote service belongs in a companion package and reaches core only through the .backend_api_call() provider hook.

Pull requests

  1. Fork the repo and create a branch from main.
  2. Run pre-commit run --all-files to check code quality.
  3. Add or update tests in tests/testthat/.
  4. Run devtools::test() and ensure all tests pass.
  5. Run devtools::check() and fix any warnings or notes.
  6. Submit a PR to main.

Code style

  • Use data.table syntax for internal data operations.
  • Follow existing naming conventions: step_* for step functions, R6 classes use PascalCase.
  • Keep functions focused and avoid over-engineering.
  • No rlang — use base R metaprogramming only.

Testing

  • Use testthat edition 3.
  • Test helpers are in tests/testthat/helper-survey.R (make_test_survey(), make_test_panel()).
  • Integration tests that need external data should use skip_on_cran().
  • print() calls in tests are fine (used to test R6 $print() methods).

Code of Conduct

Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.