Full Code of pharmaR/riskmetric for AI

master fd07e38635dd cached
232 files
318.4 KB
98.4k tokens
1 requests
Download .txt
Showing preview only (369K chars total). Download the full file or copy to clipboard to get everything.
Repository: pharmaR/riskmetric
Branch: master
Commit: fd07e38635dd
Files: 232
Total size: 318.4 KB

Directory structure:
gitextract_cv8kk3_s/

├── .Rbuildignore
├── .github/
│   ├── .gitignore
│   └── workflows/
│       ├── R-CMD-check.yaml
│       ├── pkgdown.yaml
│       └── test-coverage.yaml
├── .gitignore
├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── NAMESPACE
├── NEWS.md
├── R/
│   ├── assess_covr_coverage.R
│   ├── assess_dependencies.R
│   ├── assess_downloads.R
│   ├── assess_export_help.R
│   ├── assess_exported_namespace.R
│   ├── assess_has_bug_reports_url.R
│   ├── assess_has_examples.R
│   ├── assess_has_maintainer.R
│   ├── assess_has_news.R
│   ├── assess_has_source_control.R
│   ├── assess_has_vignettes.R
│   ├── assess_has_website.R
│   ├── assess_last_30_bugs_status.R
│   ├── assess_license.R
│   ├── assess_news_current.R
│   ├── assess_r_cmd_check.R
│   ├── assess_remote_checks.R
│   ├── assess_reverse_dependencies.R
│   ├── assess_size_codebase.R
│   ├── dev_hint.R
│   ├── dev_tips.R
│   ├── metric_score.R
│   ├── options.R
│   ├── pkg_assess.R
│   ├── pkg_cohort.R
│   ├── pkg_metric.R
│   ├── pkg_metric_condition.R
│   ├── pkg_metric_error.R
│   ├── pkg_metric_na.R
│   ├── pkg_metric_todo.R
│   ├── pkg_ref_cache.R
│   ├── pkg_ref_cache_NEWS_urls.R
│   ├── pkg_ref_cache_archive_release_date.R
│   ├── pkg_ref_cache_behaviors.R
│   ├── pkg_ref_cache_bug_reports.R
│   ├── pkg_ref_cache_bug_reports_host.R
│   ├── pkg_ref_cache_bug_reports_url.R
│   ├── pkg_ref_cache_covr_coverage.R
│   ├── pkg_ref_cache_description.R
│   ├── pkg_ref_cache_downloads.R
│   ├── pkg_ref_cache_examples.R
│   ├── pkg_ref_cache_expr_coverage.R
│   ├── pkg_ref_cache_help.R
│   ├── pkg_ref_cache_help_aliases.R
│   ├── pkg_ref_cache_license.R
│   ├── pkg_ref_cache_maintainer.R
│   ├── pkg_ref_cache_news.R
│   ├── pkg_ref_cache_r_cmd_check.R
│   ├── pkg_ref_cache_release_date.R
│   ├── pkg_ref_cache_remote_checks.R
│   ├── pkg_ref_cache_repo_base_url.R
│   ├── pkg_ref_cache_source_control_url.R
│   ├── pkg_ref_cache_tarball_url.R
│   ├── pkg_ref_cache_vignettes.R
│   ├── pkg_ref_cache_web_html.R
│   ├── pkg_ref_cache_web_url.R
│   ├── pkg_ref_cache_website_urls.R
│   ├── pkg_ref_class.R
│   ├── pkg_ref_class_coersion.R
│   ├── pkg_ref_class_extract.R
│   ├── pkg_ref_class_format.R
│   ├── pkg_ref_class_names.R
│   ├── pkg_score.R
│   ├── riskmetric-package.R
│   ├── summarize_scores.R
│   ├── utils.R
│   ├── utils_memoised.R
│   ├── vctrs_list_of_pkg_metric.R
│   ├── vctrs_list_of_pkg_ref.R
│   └── zzz.R
├── README.md
├── _pkgdown.yml
├── cran-comments.md
├── man/
│   ├── all_assessments.Rd
│   ├── allow_mutation.Rd
│   ├── as_pkg_metric.Rd
│   ├── as_pkg_metric_condition.Rd
│   ├── as_pkg_metric_error.Rd
│   ├── as_pkg_metric_na.Rd
│   ├── as_pkg_metric_todo.Rd
│   ├── assess_covr_coverage.Rd
│   ├── assess_dependencies.Rd
│   ├── assess_downloads_1yr.Rd
│   ├── assess_export_help.Rd
│   ├── assess_exported_namespace.Rd
│   ├── assess_has_bug_reports_url.Rd
│   ├── assess_has_examples.Rd
│   ├── assess_has_maintainer.Rd
│   ├── assess_has_news.Rd
│   ├── assess_has_source_control.Rd
│   ├── assess_has_vignettes.Rd
│   ├── assess_has_website.Rd
│   ├── assess_last_30_bugs_status.Rd
│   ├── assess_license.Rd
│   ├── assess_news_current.Rd
│   ├── assess_r_cmd_check.Rd
│   ├── assess_remote_checks.Rd
│   ├── assess_reverse_dependencies.Rd
│   ├── assess_size_codebase.Rd
│   ├── assessment_error_as_warning.Rd
│   ├── assessment_error_empty.Rd
│   ├── assessment_error_throw.Rd
│   ├── available_pkg_ref_fields.Rd
│   ├── bare_env.Rd
│   ├── bug_report_metadata.Rd
│   ├── cache_behaviors.Rd
│   ├── capture_expr_output.Rd
│   ├── dec_mutations_count.Rd
│   ├── determine_pkg_source.Rd
│   ├── dot-tools.Rd
│   ├── examples_from_dir.Rd
│   ├── examples_from_pkg.Rd
│   ├── filter_rd_db.Rd
│   ├── firstS3method.Rd
│   ├── format_assessment_message.Rd
│   ├── get_assessment_columns.Rd
│   ├── get_assessments.Rd
│   ├── get_package_dependencies.Rd
│   ├── get_pkg_ref_classes.Rd
│   ├── if_not_null_else.Rd
│   ├── inc_mutations_count.Rd
│   ├── is_url_subpath_of.Rd
│   ├── memoise_bioc_mirrors.Rd
│   ├── memoise_cran_mirrors.Rd
│   ├── metric_score.Rd
│   ├── metric_score.pkg_metric_covr_coverage.Rd
│   ├── metric_score.pkg_metric_dependencies.Rd
│   ├── metric_score.pkg_metric_downloads_1yr.Rd
│   ├── metric_score.pkg_metric_export_help.Rd
│   ├── metric_score.pkg_metric_exported_namespace.Rd
│   ├── metric_score.pkg_metric_has_bug_reports_url.Rd
│   ├── metric_score.pkg_metric_has_examples.Rd
│   ├── metric_score.pkg_metric_has_maintainer.Rd
│   ├── metric_score.pkg_metric_has_news.Rd
│   ├── metric_score.pkg_metric_has_source_control.Rd
│   ├── metric_score.pkg_metric_has_vignettes.Rd
│   ├── metric_score.pkg_metric_has_website.Rd
│   ├── metric_score.pkg_metric_last_30_bugs_status.Rd
│   ├── metric_score.pkg_metric_license.Rd
│   ├── metric_score.pkg_metric_news_current.Rd
│   ├── metric_score.pkg_metric_r_cmd_check.Rd
│   ├── metric_score.pkg_metric_remote_checks.Rd
│   ├── metric_score.pkg_metric_reverse_dependencies.Rd
│   ├── metric_score.pkg_metric_size_codebase.Rd
│   ├── news_from_dir.Rd
│   ├── parse_dcf_dependencies.Rd
│   ├── pkg_assess.Rd
│   ├── pkg_metric.Rd
│   ├── pkg_metric_eval.Rd
│   ├── pkg_ref.Rd
│   ├── pkg_ref_cache.bug_reports_host.default.Rd
│   ├── pkg_ref_cache.bug_reports_url.pkg_source.Rd
│   ├── pkg_ref_cache.covr_coverage.pkg_source.Rd
│   ├── pkg_ref_cache.expression_coverage.pkg_source.Rd
│   ├── pkg_ref_cache.help.pkg_install.Rd
│   ├── pkg_ref_cache.help.pkg_source.Rd
│   ├── pkg_ref_cache.news.pkg_remote.Rd
│   ├── pkg_ref_class_hierarchy.Rd
│   ├── pkg_ref_mutability_error.Rd
│   ├── pkg_score.Rd
│   ├── print.with_eval_recording.Rd
│   ├── remove_base_packages.Rd
│   ├── require_cache_behaviors.Rd
│   ├── riskmetric.Rd
│   ├── riskmetric_metadata_caching.Rd
│   ├── roxygen_assess_family.Rd
│   ├── roxygen_assess_family_catalog.Rd
│   ├── roxygen_cache_behaviors.Rd
│   ├── roxygen_score_family.Rd
│   ├── score_error_NA.Rd
│   ├── score_error_default.Rd
│   ├── score_error_zero.Rd
│   ├── sub-sub-.pkg_ref.Rd
│   ├── summarize_scores.Rd
│   ├── suppressMatchingConditions.Rd
│   ├── use_assessments_column_names.Rd
│   ├── verify_pkg_source.Rd
│   ├── vignettes_from_dir.Rd
│   ├── vignettes_from_html.Rd
│   ├── with.pkg_ref.Rd
│   └── with_unclassed_to.Rd
└── tests/
    ├── testthat/
    │   ├── setup_mock_web_requests.R
    │   ├── setup_test_packages.R
    │   ├── teardown_mock_web_requests.R
    │   ├── teardown_test_packages.R
    │   ├── test_assess.R
    │   ├── test_assess_dependencies.R
    │   ├── test_assess_export_help.R
    │   ├── test_assess_has_bug_reports_url.R
    │   ├── test_assess_has_examples.R
    │   ├── test_assess_has_news.R
    │   ├── test_assess_last_30_bugs_status.R
    │   ├── test_assess_news_current.R
    │   ├── test_metric_score_labels.R
    │   ├── test_metric_score_range.R
    │   ├── test_packages/
    │   │   ├── pkgsourcebad/
    │   │   │   ├── DESCRIPTION
    │   │   │   ├── NAMESPACE
    │   │   │   ├── R/
    │   │   │   │   └── hello_world_test.R
    │   │   │   └── man/
    │   │   │       └── hello_world_test.Rd
    │   │   ├── pkgsourcebad2/
    │   │   │   └── DESCRIPTION
    │   │   ├── pkgsourcegood/
    │   │   │   ├── DESCRIPTION
    │   │   │   ├── NAMESPACE
    │   │   │   ├── NEWS.md
    │   │   │   ├── R/
    │   │   │   │   └── hello_world_test.R
    │   │   │   └── man/
    │   │   │       └── hello_world_test.Rd
    │   │   └── secondLib/
    │   │       └── secondLibPkg/
    │   │           ├── DESCRIPTION
    │   │           ├── NAMESPACE
    │   │           ├── NEWS.md
    │   │           ├── R/
    │   │           │   └── hello_world_test.R
    │   │           └── man/
    │   │               └── hello_world_test.Rd
    │   ├── test_pkg_ref.R
    │   ├── test_snapshots.R
    │   └── test_webmocks/
    │       ├── data/
    │       │   ├── cran_mirrors.csv
    │       │   ├── cran_news.html
    │       │   ├── cran_package.html
    │       │   ├── cran_package_archive.html
    │       │   ├── cran_package_checks.html
    │       │   ├── cran_packages.csv
    │       │   └── github_repo_issues_api_response.json
    │       └── rebuild_webmocks.R
    └── testthat.R

================================================
FILE CONTENTS
================================================

================================================
FILE: .Rbuildignore
================================================
^codecov\.yml$
^appveyor\.yml$
^\.travis\.yml$
^\.github
^.*\.Rproj$
^\.Rproj\.user$
^LICENSE\.md$
^_pkgdown\.yml$
^docs$
^pkgdown$
^cran-comments\.md$
^\.github$


================================================
FILE: .github/.gitignore
================================================
*.html


================================================
FILE: .github/workflows/R-CMD-check.yaml
================================================
# Workflow derived from https://github.com/r-lib/actions/tree/master/examples
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
#
# NOTE: This workflow is overkill for most R packages and
# check-standard.yaml is likely a better choice.
# usethis::use_github_action("check-standard") will install it.
on:
  push:
    branches: [main, master]
  pull_request:
    branches: [main, master]

name: R-CMD-check

jobs:
  R-CMD-check:
    runs-on: ${{ matrix.config.os }}

    name: ${{ matrix.config.os }} (${{ matrix.config.r }})

    strategy:
      fail-fast: false
      matrix:
        config:
          - {os: macOS-latest,   r: 'release'}

          - {os: windows-latest, r: 'release'}
          # Use 3.6 to trigger usage of RTools35
          - {os: windows-latest, r: '3.6'}

          # Use older ubuntu to maximise backward compatibility
          - {os: ubuntu-22.04,   r: 'devel', http-user-agent: 'release'}
          - {os: ubuntu-22.04,   r: 'release'}
          - {os: ubuntu-22.04,   r: 'oldrel-1'}
          - {os: ubuntu-22.04,   r: 'oldrel-2'}
          - {os: ubuntu-22.04,   r: 'oldrel-3'}

    env:
      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
      R_KEEP_PKG_SOURCE: yes
      _R_CHECK_RD_VALIDATE_RD2HTML_: false

    steps:
      - uses: actions/checkout@v2

      - uses: r-lib/actions/setup-pandoc@v2

      - uses: r-lib/actions/setup-r@v2
        with:
          r-version: ${{ matrix.config.r }}
          http-user-agent: ${{ matrix.config.http-user-agent }}
          use-public-rspm: true

      - uses: r-lib/actions/setup-r-dependencies@v2
        with:
          extra-packages: rcmdcheck

      - uses: r-lib/actions/setup-tinytex@v2

      - uses: r-lib/actions/check-r-package@v2
        with:
          args: 'c("--as-cran", "--no-manual")'

      - name: Show testthat output
        if: always()
        run: find check -name 'testthat.Rout*' -exec cat '{}' \; || true
        shell: bash

      - name: Upload check results
        if: failure()
        uses: actions/upload-artifact@main
        with:
          name: ${{ runner.os }}-r${{ matrix.config.r }}-results
          path: check


================================================
FILE: .github/workflows/pkgdown.yaml
================================================
# Workflow derived from https://github.com/r-lib/actions/tree/master/examples
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
on:
  push:
    branches: [main, master]
    tags: ['*']

name: pkgdown

jobs:
  pkgdown:
    runs-on: ubuntu-latest
    env:
      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - uses: actions/checkout@v2

      - uses: r-lib/actions/setup-pandoc@v2

      - uses: r-lib/actions/setup-r@v2
        with:
          use-public-rspm: true

      - uses: r-lib/actions/setup-r-dependencies@v2
        with:
          extra-packages: any::pkgdown, local::.
          needs: website

      - name: Deploy package
        run: |
          git config --local user.name "$GITHUB_ACTOR"
          git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com"
          Rscript -e 'pkgdown::deploy_to_branch(new_process = FALSE)'


================================================
FILE: .github/workflows/test-coverage.yaml
================================================
# Workflow derived from https://github.com/r-lib/actions/tree/master/examples
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
on:
  push:
    branches: [main, master]
  pull_request:
    branches: [main, master]

name: test-coverage

jobs:
  test-coverage:
    runs-on: ubuntu-latest
    env:
      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}

    steps:
      - uses: actions/checkout@v2

      - uses: r-lib/actions/setup-r@v2
        with:
          use-public-rspm: true

      - uses: r-lib/actions/setup-r-dependencies@v2
        with:
          extra-packages: any::covr

      - name: Test coverage
        run: covr::codecov()
        shell: Rscript {0}


================================================
FILE: .gitignore
================================================
.DS_Store
vignettes
!vignettes/*.Rmd
inst/doc
docs
.Rproj.user
.Rhistory
.RData
.Ruserdata
.html
riskmetric.Rproj


================================================
FILE: DESCRIPTION
================================================
Package: riskmetric
Type: Package
Title: Risk Metrics to Evaluating R Packages
Description: Facilities for assessing R packages against a number of metrics to 
    help quantify their robustness.
Version: 0.2.7
Authors@R: c(
    person("R Validation Hub", role = c("aut"), email = "psi.aims.r.validation@gmail.com"),
    person("Doug", "Kelkhoff", role = c("aut"), email = "doug.kelkhoff@gmail.com"),
    person("Marly", "Gotti", role = c("aut")), 
    person("Eli", "Miller", role = c("cre", "aut"), email = "eli.miller@atorusresearch.com"), 
    person("Kevin", "K", role = c("aut")), 
    person("Yilong", "Zhang", role = c("aut")),
    person("Eric", "Milliman", role = c("aut")),
    person("Juliane", "Manitz", role = c("aut")),
    person("Mark", "Padgham", role = c("ctb")),
    person("PSI special interest group Application and Implementation of Methodologies in Statistics", role = c("cph")))
URL: https://pharmar.github.io/riskmetric/, https://github.com/pharmaR/riskmetric
BugReports: https://github.com/pharmaR/riskmetric/issues
License: MIT + file LICENSE
Encoding: UTF-8
Imports:
    backports,
    utils,
    tools,
    xml2,
    httr,
    curl,
    urltools,
    memoise,
    BiocManager,
    cranlogs,
    covr,
    vctrs,
    pillar,
    tibble,
    pkgload,
    devtools
Suggests:
    dplyr,
    jsonlite,
    knitr,
    magrittr,
    pkgbuild,
    rmarkdown,
    testthat,
    webmockr,
    withr
RoxygenNote: 7.3.3
VignetteBuilder: knitr
Config/testthat/edition: 3


================================================
FILE: LICENSE
================================================
YEAR: 2019
COPYRIGHT HOLDER: PSI special interest group Application and Implementation of Methodologies in Statistics


================================================
FILE: LICENSE.md
================================================
pkg# MIT License

Copyright (c) 2019 PSI special interest group Application and Implementation of Methodologies in Statistics

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: NAMESPACE
================================================
# Generated by roxygen2: do not edit by hand

S3method("$",pkg_ref)
S3method("$<-",pkg_ref)
S3method("[",pkg_ref)
S3method("[<-",pkg_ref)
S3method("[[",pkg_ref)
S3method("[[<-",pkg_ref)
S3method(.DollarNames,pkg_ref)
S3method(as_pkg_metric,default)
S3method(as_pkg_metric,expr_output)
S3method(as_pkg_ref,character)
S3method(as_pkg_ref,default)
S3method(as_pkg_ref,pkg_ref)
S3method(as_tibble,list_of_pkg_ref)
S3method(as_tibble,pkg_ref)
S3method(assess_covr_coverage,default)
S3method(assess_covr_coverage,pkg_source)
S3method(assess_dependencies,default)
S3method(assess_dependencies,pkg_bioc_remote)
S3method(assess_dependencies,pkg_cran_remote)
S3method(assess_dependencies,pkg_install)
S3method(assess_dependencies,pkg_source)
S3method(assess_downloads_1yr,pkg_ref)
S3method(assess_export_help,pkg_install)
S3method(assess_export_help,pkg_remote)
S3method(assess_export_help,pkg_source)
S3method(assess_exported_namespace,default)
S3method(assess_exported_namespace,pkg_install)
S3method(assess_exported_namespace,pkg_source)
S3method(assess_has_bug_reports_url,default)
S3method(assess_has_examples,pkg_ref)
S3method(assess_has_news,pkg_ref)
S3method(assess_has_vignettes,pkg_ref)
S3method(assess_news_current,pkg_ref)
S3method(assess_news_current,pkg_remote)
S3method(assess_r_cmd_check,default)
S3method(assess_r_cmd_check,pkg_bioc_remote)
S3method(assess_r_cmd_check,pkg_cran_remote)
S3method(assess_r_cmd_check,pkg_source)
S3method(assess_remote_checks,default)
S3method(assess_remote_checks,pkg_bioc_remote)
S3method(assess_remote_checks,pkg_cran_remote)
S3method(assess_reverse_dependencies,default)
S3method(assess_size_codebase,default)
S3method(assess_size_codebase,pkg_install)
S3method(assess_size_codebase,pkg_source)
S3method(format,pkg_metric)
S3method(format,pkg_metric_error)
S3method(format,pkg_missing)
S3method(format,pkg_ref)
S3method(metric_score,default)
S3method(metric_score,pkg_metric_covr_coverage)
S3method(metric_score,pkg_metric_dependencies)
S3method(metric_score,pkg_metric_downloads_1yr)
S3method(metric_score,pkg_metric_export_help)
S3method(metric_score,pkg_metric_exported_namespace)
S3method(metric_score,pkg_metric_has_bug_reports_url)
S3method(metric_score,pkg_metric_has_examples)
S3method(metric_score,pkg_metric_has_maintainer)
S3method(metric_score,pkg_metric_has_news)
S3method(metric_score,pkg_metric_has_source_control)
S3method(metric_score,pkg_metric_has_vignettes)
S3method(metric_score,pkg_metric_has_website)
S3method(metric_score,pkg_metric_last_30_bugs_status)
S3method(metric_score,pkg_metric_license)
S3method(metric_score,pkg_metric_news_current)
S3method(metric_score,pkg_metric_r_cmd_check)
S3method(metric_score,pkg_metric_remote_checks)
S3method(metric_score,pkg_metric_reverse_dependencies)
S3method(metric_score,pkg_metric_size_codebase)
S3method(names,pkg_ref)
S3method(pillar_shaft,list_of_pkg_metric)
S3method(pillar_shaft,list_of_pkg_ref)
S3method(pillar_shaft,pkg_metric_error)
S3method(pkg_assess,list_of_pkg_ref)
S3method(pkg_assess,pkg_ref)
S3method(pkg_assess,tbl_df)
S3method(pkg_score,list_of_pkg_metric)
S3method(pkg_score,tbl_df)
S3method(print,pkg_ref)
S3method(print,with_eval_recording)
S3method(summarize_scores,data.frame)
S3method(summarize_scores,list)
S3method(vec_cast.character,list_of_pkg_ref)
S3method(vec_cast.double,list_of_pkg_metric)
S3method(vec_ptype_abbr,pkg_metric)
S3method(vec_ptype_abbr,pkg_ref)
S3method(with,pkg_ref)
export(all_assessments)
export(as_pkg_metric)
export(as_pkg_ref)
export(assess_covr_coverage)
export(assess_dependencies)
export(assess_downloads_1yr)
export(assess_export_help)
export(assess_exported_namespace)
export(assess_has_bug_reports_url)
export(assess_has_examples)
export(assess_has_maintainer)
export(assess_has_news)
export(assess_has_source_control)
export(assess_has_vignettes)
export(assess_has_website)
export(assess_last_30_bugs_status)
export(assess_license)
export(assess_news_current)
export(assess_r_cmd_check)
export(assess_remote_checks)
export(assess_reverse_dependencies)
export(assess_size_codebase)
export(assessment_error_as_warning)
export(assessment_error_empty)
export(assessment_error_throw)
export(get_assessments)
export(metric_score)
export(pkg_assess)
export(pkg_metric)
export(pkg_ref)
export(pkg_score)
export(score_error_NA)
export(score_error_default)
export(score_error_zero)
export(summarize_scores)
import(tools)
importFrom(BiocManager,available)
importFrom(BiocManager,repositories)
importFrom(backports,import)
importFrom(covr,coverage_to_list)
importFrom(covr,package_coverage)
importFrom(covr,tally_coverage)
importFrom(cranlogs,cran_downloads)
importFrom(curl,nslookup)
importFrom(devtools,check)
importFrom(devtools,revdep)
importFrom(httr,GET)
importFrom(httr,content)
importFrom(memoise,memoise)
importFrom(pillar,new_pillar_shaft_simple)
importFrom(pillar,pillar_shaft)
importFrom(pillar,style_na)
importFrom(pkgload,parse_ns_file)
importFrom(tibble,as_tibble)
importFrom(tibble,tibble)
importFrom(tools,Rd_db)
importFrom(tools,file_path_sans_ext)
importFrom(tools,parseLatex)
importFrom(tools,testInstalledPackage)
importFrom(urltools,domain)
importFrom(urltools,url_encode)
importFrom(utils,.DollarNames)
importFrom(utils,.S3methods)
importFrom(utils,available.packages)
importFrom(utils,capture.output)
importFrom(utils,getS3method)
importFrom(utils,head)
importFrom(utils,packageDescription)
importFrom(utils,packageName)
importFrom(utils,packageVersion)
importFrom(utils,tail)
importFrom(vctrs,new_list_of)
importFrom(vctrs,new_vctr)
importFrom(vctrs,vec_cast.character)
importFrom(vctrs,vec_cast.double)
importFrom(vctrs,vec_ptype_abbr)
importFrom(xml2,xml_attr)
importFrom(xml2,xml_attrs)
importFrom(xml2,xml_find_all)
importFrom(xml2,xml_text)


================================================
FILE: NEWS.md
================================================
# riskmetric (development version)

# riskmetric 0.2.6

- Update to address new failing tests responding to `devtools` v2.4.7 changes.

# riskmetric 0.2.5

- Update use of `vctrs` to accommdate changes to acceptable `ptype` parameters
  in `vctrs` v0.7.1 (#394)
- Fix bug with assessing source packages that have non-R files in the R directory ([#362](https://github.com/pharmaR/riskmetric/issues/362))

# riskmetric 0.2.4

- Fix CRAN errors.

# riskmetric 0.2.3

- Fix issue with CRAN package documentation flags. (#311)

# riskmetric 0.2.2

- Fix bug with reporting number of downloads.

# riskmetric 0.2.1

- Updates for S3 Method consistancy for `vec_cast` and `pillar_shift` per CRAN 
comments.

# riskmetric 0.2.0

- We now have a Hex Logo! #233. Thanks to @AARON-CLARK.
- Number of download assessment can now take a specified number of days. #258. Thanks to @parmsam-pfizer.
- A new assessment was added for determining the size of the codebase. #66. Thanks to @shengwei66.
- Fixed an issue of some scores returning negative numbers instead of values between [0,1]. Thanks to @emilliman5.
- A new assessment was added for the presens of a bug report URL for the package. Thanks to @kimjj93.
- A new assessment was added to score the dependency footprint of a package. Thanks to @emilliman5.

# riskmetric 0.1.2

- Hotfix release to correct testing suite such that tests are less continent on
  assumptions of locally installed packages, addressing build issues on CRAN
  builders. (#223, @elimillera)

# riskmetric 0.1.1

- Fixing a bug with subclassing of `pkg_ref` objects using the new concrete
  constructors. (#208, @dgkf)

# riskmetric 0.1.0

- Initial version.
- Added a `NEWS.md` file to track changes to the package.


================================================
FILE: R/assess_covr_coverage.R
================================================
#' Assess a package code coverage using the `covr` package
#'
#' @eval roxygen_assess_family(
#'   "covr_coverage",
#'   paste0("a list containing fields 'filecoverage' and 'totalcoverage' ",
#'     "containing a named numeric vector of file unit test coverage and a ",
#'     "singular numeric value representing overall test coverage ",
#'     "respectively."),
#'   dontrun = TRUE
#' )
#'
#' @export
assess_covr_coverage <- function(x, ...) {
  UseMethod("assess_covr_coverage")
}

attributes(assess_covr_coverage)$column_name <- "covr_coverage"
attributes(assess_covr_coverage)$label <- "Package unit test coverage"



#' @export
assess_covr_coverage.default <- function(x, ...) {
  as_pkg_metric_na(pkg_metric(class = "pkg_metric_covr_coverage"))
}



#' @importFrom covr coverage_to_list
#' @export
assess_covr_coverage.pkg_source <- function(x, ...) {
  pkg_metric_eval(class = "pkg_metric_covr_coverage", {
    covr::coverage_to_list(x$covr_coverage)
  })
}



#' Score a package for unit test coverage
#'
#' Returns the overall test coverage from a covr coverage report
#'
#' @eval roxygen_score_family("covr_coverage", dontrun = TRUE)
#' @return A \code{numeric}
#'
#' @export
metric_score.pkg_metric_covr_coverage <- function(x, ...) {
  x$totalcoverage / 100
}

attributes(metric_score.pkg_metric_covr_coverage)$label <-
  "The fraction of lines of code which are covered by a unit test."


================================================
FILE: R/assess_dependencies.R
================================================
#' Assessment of dependency footprint for a specific package
#'
#' Only Depends, Imports and LinkingTo dependencies are assessed because
#' they are required
#'
#' @details The more packages a package relies on the more chances for errors exist.
#'
#' @eval roxygen_assess_family(
#'   "dependencies",
#'   "a dataframe of package names and they type of dependency the package being assess has to them")
#'
#'
#' @export
assess_dependencies <- function(x, ...){
  UseMethod("assess_dependencies")
}

attributes(assess_dependencies)$column_name <- "dependencies"
attributes(assess_dependencies)$label <- "Package dependency footprint"

#' @export
assess_dependencies.default <- function(x, ...){
  as_pkg_metric_na(pkg_metric(class = "pkg_metric_dependencies"))
}

#' @export
assess_dependencies.pkg_source <- function(x, ...){
  pkg_metric_eval(class = "pkg_metric_dependencies", {
    parse_dcf_dependencies(x$path)
    })
}

#' @export
assess_dependencies.pkg_install <- function(x, ...){
  pkg_metric_eval(class = "pkg_metric_dependencies", {
    parse_dcf_dependencies(x$path)
  })
}

#' @export
assess_dependencies.pkg_cran_remote <- function(x, ...){
  #Attempt to find CRAN URL by matching all urls returned by getOptions("repos") to memoise_cran_mirrors table
  repos <- getOption("repos")[which(getOption("repos") %in% memoise_cran_mirrors()$URL)]

  if(length(repos)==0){
    repos <- grep("[\\.|//]cran\\.", getOption("repos"), ignore.case = T, value = T)
  }
  if(length(repos)==0){
    repos <- getOption("repos")[["CRAN"]]
  }

  if(length(repos)==0){
    as_pkg_metric_error(error = 'Could not determine which CRAN mirror you are using.')
  } else{
    pkg_metric_eval(class = "pkg_metric_dependencies", {
        get_package_dependencies(x$name, repo = repos[1]) ##Will use the first CRAN mirror found in the users environment
    })
  }
}

#' @importFrom BiocManager repositories
#' @export
assess_dependencies.pkg_bioc_remote <- function(x, ...){
  pkg_metric_eval(class = "pkg_metric_dependencies", {
    get_package_dependencies(x$name, BiocManager::repositories()[1])
  })
}

#' Score a package for dependencies
#'
#' Calculates a regularized score based on the number of dependencies a package has.
#' Convert the number of dependencies \code{NROW(x)} into a validation
#' score [0,1] \deqn{ 1 - 1 / (1 + exp(-0.5 * (NROW(x) + 4))) }
#'
#' The scoring function is the classic logistic curve \deqn{ / (1 + exp(-k(x-x[0])) }
#' \eqn{x = NROW(x)}, sigmoid midpoint is 5 reverse dependencies, ie. \eqn{x[0] = 4},
#' and logistic growth rate of \eqn{k = 0.5}.
#'
#' \deqn{ 1 - 1 / (1 + exp(NROW(x)-4)) }
#'
#' @eval roxygen_score_family("dependencies")
#' @return numeric value between \code{0} (high number of  dependencies) and
#'   \code{1} (low number of dependencies)
#'
#' @export
metric_score.pkg_metric_dependencies <- function(x, ...) {
  1 - 1/(1 + exp(-0.5 * (NROW(x) - 4)))
}
attributes(metric_score.pkg_metric_dependencies)$label <-
  "The number of package dependencies"

#Helper functions to get extract dependencies

#' Gets available packages from necessary repository and filters for
#' package of interest
#'
#' @param name package name
#' @param repo package repository (e.g. CRAN or Bioconductor)
#'
#' @return Returns a data frame with two columns 1) Package names, 2) type of dependency (LinkingTo, Imports, Depends)
#' @keywords internal
#'
get_package_dependencies <- function(name, repo){
  ap <- available.packages(repos = repo)
  deps <- ap[rownames(ap)==name, c("LinkingTo","Imports","Depends")]
  deps <- deps[!is.na(deps)]
  deps <- lapply(strsplit(deps, ","), trimws)
  deps <- data.frame(package=unlist(deps),
                     type=rep(names(deps), sapply(deps, length)),
                     stringsAsFactors = FALSE,
                     row.names = NULL)
  deps <- remove_base_packages(deps)
  return(deps)
}

#' Parse DCF of description file
#'
#' @param path pkg_ref path
#' @keywords internal
#'
parse_dcf_dependencies <- function(path){
  dcf <- read.dcf(file.path(path, "DESCRIPTION"), all=TRUE)
  dcf <- dcf[colnames(dcf) %in% c("LinkingTo","Imports", "Depends")]
  dcf <- sapply(dcf, strsplit, split=",")
  dcf <- lapply(dcf, trimws)
  deps <- data.frame(package=unlist(dcf),
                     type=rep(names(dcf), sapply(dcf, length)),
                     stringsAsFactors = FALSE,
                     row.names = NULL)
  deps <- remove_base_packages(deps)
  return(deps)
}

#' Helper function to remove base and recommended packages
#'
#' @param df Data frame of dependencies of a package.
#' @keywords internal
#'
remove_base_packages <- function(df){
  inst <- memoise_available_packages()
  inst_priority <- inst[,"Priority"]
  inst_is_base_rec <- !is.na(inst_priority) & inst_priority %in% c("base", "recommended")
  base_rec_pkgs <- inst[inst_is_base_rec, "Package"]

  deps <- df[!grepl("^R\\s\\(.+\\)", df$package) | df$package %in% base_rec_pkgs, ] ##Remove "R" dependencies as well as base and recomended
  return(deps)
}


================================================
FILE: R/assess_downloads.R
================================================
#' Assess a package for the number of downloads in the past year
#'
#' @details The more times a package has been downloaded the more extensive the user testing and the greater chance there is of someone finding a bug and logging it.
#'
#' @eval roxygen_assess_family(
#'   "downloads_1yr",
#'   "a numeric value between [0,1] indicating the volume of downloads",
#'   dontrun = TRUE
#' )
#'
#' @export
assess_downloads_1yr <- function(x, ...){
  UseMethod("assess_downloads_1yr")
}

# assign a friendly name for assess column
attr(assess_downloads_1yr, "column_name") <- "downloads_1yr"
attr(assess_downloads_1yr, "label") <- "number of downloads in the past year"



#' @export
assess_downloads_1yr.pkg_ref <- function(x, ...) {
  pkg_metric_eval(class = "pkg_metric_downloads_1yr", {
    sum(x$downloads$count)
  })
}



#' Defining an Assessment Scoring Function
#'
#' Score a package for the number of downloads in the past year regularized
#' Convert the number of downloads \code{x} in the past year into a validation
#' score [0,1] \deqn{ 1 - 150,000 / (x + 150,000) }
#'
#' The scoring function is a simplification of the classic logistic curve \deqn{
#' 1 / (1 + exp(-k(x-x[0])) } with a log scale for the number of downloads
#' \eqn{x = log(x)}, sigmoid midpoint is 1000 downloads, ie. \eqn{x[0] =
#' log(1,000)}, and logistic growth rate of \eqn{k = 0.5}.
#'
#' \deqn{ 1 - 1 / (1 + exp(log(x)-log(1.5e5))) = 1 - 150,000 / (x + 150,000) }
#'
#' @eval roxygen_score_family("downloads_1yr")
#' @return numeric value between \code{0} (low) and \code{1} (high download
#'   volume) converting the number of downloads.
#'
#' @export
metric_score.pkg_metric_downloads_1yr <- function(x, ...) {
  # simplification from logistic: 1 - 1 / (1 + exp(log(x)-log(1.5e5)))
  1 - 1.5 / (x / 1e5 + 1.5)
}

attributes(metric_score.pkg_metric_downloads_1yr)$label <- paste0(
  "A logistic rating of the number of package downloads in the past year. ",
  "For more details, see ?riskmetric::metric_score.pkg_metric_downloads_1yr")


================================================
FILE: R/assess_export_help.R
================================================
#' Assess a package for availability of documentation for exported values
#'
#' @eval roxygen_assess_family(
#'   "export_help",
#'   "a logical vector indicating existence of documentation for each namespace export")
#'
#' @export
assess_export_help <- function(x, ...) {
  UseMethod("assess_export_help")
}

attributes(assess_export_help)$column_name <- "export_help"
attributes(assess_export_help)$label <- "exported objects have documentation"



#' @export
assess_export_help.pkg_remote <- function(x, ...) {
  as_pkg_metric_na(
    pkg_metric(class = "pkg_metric_export_help"),
    message = "Cannot scrape exported documentation from a remote package webpage")
}


#' @importFrom pkgload parse_ns_file
#' @export
assess_export_help.pkg_source <- function(x, ...) {
  pkg_metric_eval(class = "pkg_metric_export_help", {
    # Read NAMESPACE
    lines <- readLines(paste0(x$path, "/NAMESPACE"), warn = FALSE)

    # Extract explicit exports
    export_lines <- grep("^export\\(|^exportMethod\\(", lines, value = TRUE)
    exports <- gsub(".*\\(([^)]+)\\).*", "\\1", export_lines)
    exports <- unlist(strsplit(exports, ",\\s*"))
    
    # Extract exportPattern regexes
    pattern_lines <- grep("^exportPattern\\(", lines, value = TRUE)
    patterns <- gsub(".*\\(\"([^\"]+)\"\\).*", "\\1", pattern_lines)
    
    # Match exportPattern regexes against available help aliases
    pattern_exports <- unlist(lapply(patterns, function(pat) {
      grep(pat, names(x$help_aliases), value = TRUE)
    }))
    
    # Combine all exports and remove duplicates
    all_exports <- unique(c(exports, pattern_exports))
    
    # Check which exports have help aliases
    out <- all_exports %in% names(x$help_aliases)
    names(out) <- all_exports
    out
  })
}



#' @export
assess_export_help.pkg_install <- function(x, ...) {
  pkg_metric_eval(class = "pkg_metric_export_help", {
    # ignore S3-dispatched methods
    exports <- getNamespaceExports(x$name)
    out <- exports %in% names(x$help_aliases)
    names(out) <- exports
    out
  })
}

#' Score a package for availability of documentation for exported values
#'
#' Coerce a logical vector indicating availability of export documentation
#'
#' @eval roxygen_score_family("export_help")
#' @return \code{1} if any NEWS files are found, otherwise \code{0}
#'
#' @export
metric_score.pkg_metric_export_help <- function(x, ...) {
  sum(x, na.rm = TRUE) / length(x)
}

attributes(metric_score.pkg_metric_export_help)$label <-
  "The fraction of exported objects that are documented."



#' #' Provide development hints for improving exported value documentation
#' #' @inheritParams dev_tips
#' dev_tips.pkg_metric_export_help <- function(x, ...) {
#'   x_sorted <- x[order(names(x))]
#'   x_sorted <- sort(x_sorted, decreasing = TRUE)
#'
#'   max_nchar <- max(nchar(names(x_sorted)))
#'   row_n <- (getOption("width") / (max_nchar + 2)) %/% 1
#'   max_nchar <- (getOption("width") / row_n) %/% 1
#'
#'   text <- paste0(
#'     ifelse(x_sorted,
#'       dev_hint_crayon_success("\u2713"),  # check mark
#'       dev_hint_crayon_failure("\u2718")), # x mark
#'     names(x_sorted),
#'     strrep(" ", max_nchar - nchar(names(x_sorted))))
#'
#'   dev_hint(
#'     title = "Documenting Exported Objects",
#'     text = list(
#'       dev_hint_section("Not all exported objects have help documentation."),
#'       dev_hint_section(paste0(
#'         "Consider adding [.Rd help files](https://cran.r-project.org/doc/manuals/R-exts.html#Writing-R-documentation-files) ",
#'         "or use [roxygen2](https://cran.r-project.org/web/packages/roxygen2/vignettes/roxygen2.html) ",
#'         "to document your functions alongside the source code.")),
#'       dev_hint_section(paste0(text,
#'         ifelse(seq_along(text) %% row_n == 0, "\n", ""),
#'         collapse = ""),
#'         list(wrap = FALSE))))
#' }


================================================
FILE: R/assess_exported_namespace.R
================================================
#' Assess a package's results from running R CMD check
#'
#' @eval roxygen_assess_family(
#'   "exported_namespace",
#'   "List of functions and objects exported by a package, excluding S3methods",
#' )
#'
#' @importFrom pkgload parse_ns_file
#' @export
assess_exported_namespace <- function(x, ...) {
  UseMethod("assess_exported_namespace")
}

attributes(assess_exported_namespace)$column_name <- "exported_namespace"
attributes(assess_exported_namespace)$label <- "Objects exported by package"

#' @export
assess_exported_namespace.default <- function(x, ...) {
  as_pkg_metric_na(
    pkg_metric(class = "pkg_metric_export_help"),
    message = sprintf("Cannot export namespace from a %s", x$source))
}

#' @export
assess_exported_namespace.pkg_install <- function(x, ...) {
  pkg_metric_eval(class = "pkg_metric_exported_namespace", {
    # ignore S3-dispatched methods
    return(getNamespaceExports(x$name))
  })
}

#' @export
assess_exported_namespace.pkg_source <- function(x, ...) {
  pkg_metric_eval(class = "pkg_metric_exported_namespace", {
    # ignore S3-dispatched methods
    return(pkgload::parse_ns_file(x$path)$exports)
  })
}

#' Score a package for the number of exported objects
#'
#' Score a package for the number of exported objects it has; regularized
#' Convert the number of exported objects \code{length(x)} into a validation
#' score [0,1] \deqn{ 1 / (1 + exp(-0.5 * (sqrt(length(x)) + sqrt(5)))) }
#'
#' The scoring function is the classic logistic curve \deqn{
#' 1 / (1 + exp(-k(x-x[0])) } with a square root scale for the number of exported objects
#' \eqn{x = sqrt(length(x))}, sigmoid midpoint is 25 exported objects, ie. \eqn{x[0] =
#' sqrt(5)}, and logistic growth rate of \eqn{k = 0.25}.
#'
#' \deqn{ 1 / (1 + exp(-0.25 * sqrt(length(x))-sqrt(25))) }
#'
#' @eval roxygen_score_family("exported_namespace")
#' @return numeric value between \code{0} (high number of exported objects) and
#'   \code{1} (low number of exported objects)
#'
#' @export
metric_score.pkg_metric_exported_namespace <- function(x, ...) {
  1 - 1 / (1 + exp(-0.25 * (sqrt(length(x)) - sqrt(25))))
}

attributes(metric_score.pkg_metric_exported_namespace)$label <-
  "The number of exported objects in a package"


================================================
FILE: R/assess_has_bug_reports_url.R
================================================
#' Assess a package for the presence of a url field where bugs can be reported.
#'
#' @eval roxygen_assess_family(
#' "has_bug_reports_url",
#' "a character value containing the BugReports field contents")
#'
#' @export
assess_has_bug_reports_url <- function(x, ...) {
  UseMethod("assess_has_bug_reports_url")
}

# assign a friendly name for assess column
attr(assess_has_bug_reports_url,"column_name") <- "has_bug_reports_url"
attr(assess_has_bug_reports_url,"label") <- "presence of a bug reports url in repository"



#' @export
assess_has_bug_reports_url.default <- function(x, ...) {
  pkg_metric(class = "pkg_metric_has_bug_reports_url", {
    length(x$bug_reports_url)
  })
}



#' Score a package for the presence of a bug report url
#'
#' @eval roxygen_score_family("has_bug_reports_url")
#'
#' @return A logical value indicating whether the package has a BugReports field
#'   filled in
#'
#' @export
metric_score.pkg_metric_has_bug_reports_url <- function(x, ...) {
  as.numeric(x > 0)
}

attributes(metric_score.pkg_metric_has_bug_reports_url)$label <-
  "A binary indicator of whether a package links to a location to file bug reports."


================================================
FILE: R/assess_has_examples.R
================================================
#' Assess a package for the presence of example or usage fields in function documentation
#'
#' @eval roxygen_assess_family(
#'   "has_examples",
#'   "an integer value indicating the proportion of discovered files with examples")
#'
#' @export
assess_has_examples <- function(x, ...) {
  UseMethod("assess_has_examples")
}

# assign a friendly name for examples column
attributes(assess_has_examples)$column_name <- "has_examples"
attributes(assess_has_examples)$label <- "proportion of discovered function files with examples"

#' @export
assess_has_examples.pkg_ref <- function(x, ...) {
  pkg_metric_eval(class = "pkg_metric_has_examples",{
    x$examples
  })
}

#' Score a package for the presence of a example or usage fields
#'
#' Coerce a logical vector indicating availability of example or usage documentation
#'
#' @eval roxygen_score_family("has_examples")
#' @return \code{1} if any example or usage fields are found, otherwise \code{0}
#'
#' @export
metric_score.pkg_metric_has_examples <- function(x, ...) {
  if (length(x) > 0) {
    sum(x, na.rm = TRUE) / length(x)
  } else {
    NA
  }
}

attributes(metric_score.pkg_metric_has_examples)$label <-
  "A proportion of R documentation files with example or usage fields"


================================================
FILE: R/assess_has_maintainer.R
================================================
#' Assess a package for an associated maintainer
#'
#' @eval roxygen_assess_family(
#'   "has_maintainer",
#'   "a character vector of maintainers associated with the package")
#'
#' @export
assess_has_maintainer <- function(x, ...) {
  pkg_metric_eval(class = "pkg_metric_has_maintainer", {
    as.character(x$maintainer)
  })
}

attributes(assess_has_maintainer)$column_name <- "has_maintainer"
attributes(assess_has_maintainer)$label <- "a vector of associated maintainers"



#' Score a package for inclusion of an associated maintainer
#'
#' Coerce a list of maintainers into a numeric value indicating whether the
#' number of listed maintainers is greater than 0.
#'
#' @eval roxygen_score_family("has_maintainer")
#' @return \code{1} if any maintainer is provided, otherwise \code{0}
#'
#' @export
metric_score.pkg_metric_has_maintainer <- function(x, ...) {
  as.numeric(length(x) > 0)
}

attributes(metric_score.pkg_metric_has_maintainer)$label <-
  "A binary indicator of whether a package has a maintainer."


================================================
FILE: R/assess_has_news.R
================================================
#' Assess a package for the presence of a NEWS file
#'
#' @eval roxygen_assess_family(
#'   "has_news",
#'   "an integer value indicating the number of discovered NEWS files")
#'
#' @export
assess_has_news <- function(x, ...) {
  UseMethod("assess_has_news")
}

# assign a friendly name for assess column
attributes(assess_has_news)$column_name <- "has_news"
attributes(assess_has_news)$label <- "number of discovered NEWS files"



#' @export
assess_has_news.pkg_ref <- function(x, ...) {
  pkg_metric(class = "pkg_metric_has_news", {
    length(x$news)
  })
}



#' Score a package for the presence of a NEWS file
#'
#' Coerce the number of news files to binary indication of valid NEWS files
#'
#' @eval roxygen_score_family("has_news")
#' @return \code{1} if any NEWS files are found, otherwise \code{0}
#'
#' @export
metric_score.pkg_metric_has_news <- function(x, ...) {
  as.numeric(x > 0)
}

attributes(metric_score.pkg_metric_has_news)$label <-
  "A binary indicator of whether a package has an associated NEWS file."


================================================
FILE: R/assess_has_source_control.R
================================================
#' Assess a package for an associated source control url
#'
#' @eval roxygen_assess_family(
#'   "has_source_control",
#'   "a character vector of source control urls associated with the package")
#'
#' @export
assess_has_source_control <- function(x, ...) {
  pkg_metric_eval(class = "pkg_metric_has_source_control", {
    x$source_control_url
  })
}

attributes(assess_has_source_control)$column_name <- "has_source_control"
attributes(assess_has_source_control)$label <- "a vector of associated source control urls"



#' Score a package for inclusion of an associated source control url
#'
#' Coerce a list of source control urls into a numeric value indicating whether
#' the number of listed urls is greater than 0.
#'
#' @eval roxygen_score_family("has_source_control")
#' @return \code{1} if any source control url is provided, otherwise \code{0}
#'
#' @export
metric_score.pkg_metric_has_source_control <- function(x, ...) {
  as.numeric(length(x) > 0)
}

attributes(metric_score.pkg_metric_has_source_control)$label <- paste0(
  "A binary indicator of whether the package has an associated ",
  "version-controled repository.")


================================================
FILE: R/assess_has_vignettes.R
================================================
#' Assess a package for the presence of Vignettes files
#'
#' @eval roxygen_assess_family(
#'   "has_vignettes",
#'   "an integer value indicating the number of discovered vignettes files")
#'
#' @export
assess_has_vignettes <- function(x, ...) {
  UseMethod("assess_has_vignettes")
}

# assign a friendly name for assess column
attributes(assess_has_vignettes)$column_name <- "has_vignettes"
attributes(assess_has_vignettes)$label <- "number of discovered vignettes files"



#' @export
assess_has_vignettes.pkg_ref <- function(x, ...) {
  pkg_metric_eval(class = "pkg_metric_has_vignettes", {
    length(x$vignettes)
  })
}



#' Score a package for the presence of a Vignettes file
#'
#' Coerce the number of vignettes files to binary indication of valid Vignettes
#'
#' @eval roxygen_score_family("has_vignettes")
#' @return \code{1} if any Vignettes files are found, otherwise \code{0}
#'
#' @export
metric_score.pkg_metric_has_vignettes <- function(x, ...) {
  as.numeric(x > 0)
}

attributes(metric_score.pkg_metric_has_vignettes)$label <- 
  "A binary indicator of whether the package has any vignettes."


================================================
FILE: R/assess_has_website.R
================================================
#' Assess a package for an associated website url
#'
#' @eval roxygen_assess_family(
#'   "has_website",
#'   "a character vector of website urls associated with the package")
#'
#' @export
assess_has_website <- function(x, ...) {
  pkg_metric_eval(class = "pkg_metric_has_website", {
    x$website_urls
  })
}

attributes(assess_has_website)$column_name <- "has_website"
attributes(assess_has_website)$label <- "a vector of associated website urls"



#' Score a package for inclusion of an associated website url
#'
#' Coerce a list of website urls into a numeric value indicating whether the
#' number of listed urls is greater than 0.
#'
#' @eval roxygen_score_family("has_website")
#' @return \code{1} if any website url is provided, otherwise \code{0}
#'
#' @export
metric_score.pkg_metric_has_website <- function(x, ...) {
  as.numeric(length(x) > 0)
}

attributes(metric_score.pkg_metric_has_website)$label <- 
  "A binary indicator of whether the package has an acompanying website."


================================================
FILE: R/assess_last_30_bugs_status.R
================================================
#' Assess how many recent BugReports have been closed
#'
#' @eval roxygen_assess_family(
#'   "last_30_bugs_status",
#'   "a logical vector indicating whether a recent BugReport was closed",
#'   dontrun = TRUE)
#'
#' @export
assess_last_30_bugs_status <- function(x, ...) {
  pkg_metric_eval(class = "pkg_metric_last_30_bugs_status", {
    bug_reports_status(x)
  })
}

attributes(assess_last_30_bugs_status)$column_name <- "bugs_status"
attributes(assess_last_30_bugs_status)$label <- "vector indicating whether BugReports status is closed"



bug_reports_status <- function(x, ...) {
  UseMethod("bug_reports_status", x$bug_reports)
}



bug_reports_status.github_bug_report <- function(x, ...) {
  vapply(x$bug_reports, "[[", character(1L), "state") == "closed"
}



bug_reports_status.gitlab_bug_report <- function(x, ...) {
  vapply(x$bug_reports, "[[", character(1L), "state") == "closed"
}



#' Score a package for number of recently opened BugReports that are now closed
#'
#' @eval roxygen_score_family("last_30_bugs_status", dontrun = TRUE)
#' @return a fractional value indicating percentage of last 30 bug reports that
#'   are now closed
#'
#' @export
metric_score.pkg_metric_last_30_bugs_status <- function(x, ...) {
  mean(x, na.rm = TRUE)
}

attributes(metric_score.pkg_metric_last_30_bugs_status)$label <- 
  "The fraction of the last 30 bugs which have already been closed."


================================================
FILE: R/assess_license.R
================================================
#' Assess a package for an acceptable license
#'
#' @eval roxygen_assess_family(
#'   "license",
#'   "a string indicating the license under which the package is released")
#'
#' @export
assess_license <- function(x, ...) {
  pkg_metric_eval(class = "pkg_metric_license", {
    x$license
  })
}

attributes(assess_license)$column_name <- "license"
attributes(assess_license)$label <-
  "software is released with an acceptable license"



#' Score a package for acceptable license
#'
#' Maps a license string to a score
#'
#' @eval roxygen_score_family("license")
#'
#' @return score of metric license
#' @export
metric_score.pkg_metric_license <- function(x, ...) {
  # defering scoring of licenses until we have a bit more consensus or guidance
  NA_real_
}

attributes(metric_score.pkg_metric_license)$label <-
  "A binary indicator of whether the package ships with an acceptable license."


================================================
FILE: R/assess_news_current.R
================================================
#' Assess a package for an up-to-date NEWS file
#'
#' @eval roxygen_assess_family(
#'   "news_current",
#'   "a logical vector indicating whether each discovered NEWS file is up-to-date")
#'
#' @export
assess_news_current <- function(x, ...) {
  UseMethod("assess_news_current")
}

attributes(assess_news_current)$column_name <- "news_current"
attributes(assess_news_current)$label <- "NEWS file contains entry for current version number"



#' @export
assess_news_current.pkg_ref <- function(x, ...) {
  pkg_metric(class = "pkg_metric_news_current", {
    grepl(search_version_string(x$version), x$news)
  })
}



#' @export
assess_news_current.pkg_remote <- function(x, ...) {
  pkg_metric_eval(class = "pkg_metric_news_current", {
    html_nodes <- lapply(x$news,
      xml2::xml_find_all,
      sprintf("//text()[contains(., '%s')]", search_version_string(x$version)))
    vapply(html_nodes, function(i) length(i) > 0, logical(1L))
  })
}



#" filter trailing 0 minor versions (e.g. 0.1.0 => "0.1")
search_version_string <- function(ver) {
  gsub("(\\.0)+$", "", as.character(ver))
}



#' Score a package for NEWS files updated to current version
#'
#' Coerce a logical vector of discovered up-to-date NEWS to a metric score
#'
#' @eval roxygen_score_family("news_current")
#' @return \code{1} if any NEWS files are up-to-date, otherwise \code{0}
#'
#' @export
metric_score.pkg_metric_news_current <- function(x, ...) {
  as.numeric(length(x) && all(x))
}

attributes(metric_score.pkg_metric_news_current)$label <- paste0(
  "A binary indicator of whether the associated NEWS file has an entry for ",
  "the current version of the package.")


================================================
FILE: R/assess_r_cmd_check.R
================================================
#' Assess a package's results from running R CMD check
#'
#' @eval roxygen_assess_family(
#'   "r_cmd_check",
#'   "Tally of errors, warnings and notes from running R CMD check locally",
#'   dontrun = TRUE)

#' @export
assess_r_cmd_check <- function(x, ...) {
  UseMethod("assess_r_cmd_check")
}

attributes(assess_r_cmd_check)$column_name <- "r_cmd_check"
attributes(assess_r_cmd_check)$label <- "Package check results"

#' @export
assess_r_cmd_check.default <- function(x, ...) {
  as_pkg_metric_na(pkg_metric(class = "pkg_metric_r_cmd_check",
                              message = "Source code not available to run R CMD check on."))
}

#' @export
assess_r_cmd_check.pkg_source <- function(x, ...) {
  pkg_metric_eval(class = "pkg_metric_r_cmd_check", {
    sapply(x$r_cmd_check[c("notes","errors","warnings")], length)
  })
}

#' @export
assess_r_cmd_check.pkg_cran_remote <- function(x, ...) {
  as_pkg_metric_todo(pkg_metric(class = "pkg_metric_r_cmd_check",
                                message = "Assessment of R CMD check on remote
                                pkg refs is not yet implemented but will be in
                                the future"))
}

#' @export
assess_r_cmd_check.pkg_bioc_remote <- function(x, ...) {
  as_pkg_metric_todo(pkg_metric(class = "pkg_metric_r_cmd_check",
                                "Assessment of R CMD check on remote pkg refs
                                is not yet implemented but will be in the future"))
}

#' Score a package based on R CMD check results run locally
#'
#' The scoring function is the weighted sum of notes (0.1), errors (1) and warnings (0.25), with a maximum score of 1 (no errors, notes or warnings)
#' and a minimum score of 0.
#' Essentially, the metric will allow up to 10 notes, 1 error or 4 warnings before returning the lowest score of 0
#' @eval roxygen_score_family("r_cmd_check", dontrun = TRUE)
#' @return A weighted sum of errors and warnings of all tests preformed
#'
#' @export
metric_score.pkg_metric_r_cmd_check <- function(x, ...) {
  1 - min(c(sum(x*c(0.1, 1, 0.25)), 1))
}
attributes(metric_score.pkg_metric_r_cmd_check)$label <-
  "A weighted sum of errors/warnings/notes from R CMD Check"


================================================
FILE: R/assess_remote_checks.R
================================================
#' Assess package checks from CRAN/Bioc or R CMD check
#'
#' @eval roxygen_assess_family(
#'   "remote_checks",
#'   "Tally of R CMD check results run on differnt OS flavors by BioC or CRAN",
#'   dontrun = TRUE)
#'
#' @export
assess_remote_checks <- function(x, ...) {
  UseMethod("assess_remote_checks")
}
attr(assess_remote_checks, "column_name") <- "remote_checks"
attributes(assess_remote_checks)$label <- "Number of OS flavors that passed/warned/errored on R CMD check"

#' @export
assess_remote_checks.default <- function(x, ...) {
  as_pkg_metric_na(pkg_metric(class="pkg_metric_remote_checks",
                              message="Package is not a CRAN or BioC reference so there
                              are no CRAN/BioC checks to assess"))
}

#' @export
assess_remote_checks.pkg_cran_remote <- function(x, ...) {
  pkg_metric_eval(class = "pkg_metric_remote_checks",{
    table(factor(x$remote_checks[["Status"]],
                 levels = c("OK","WARN","ERROR", "NOTE", "FAIL")))
             })
}

#' @export
assess_remote_checks.pkg_bioc_remote <- function(x, ...) {
  pkg_metric_eval(class = "pkg_metric_remote_checks", {
    table(factor(x$remote_checks[["CHECK"]],
                 levels=c("OK","WARNINGS","ERROR","TIMEOUT")))
             })
}

#' Score a package based on R CMD check results run by BioC or CRAN
#'
#' The scoring function is the number of OS flavors that passed with OK or NOTES + 0.5*the number of OS's that produced WARNINGS divided by the number of OS's checked
#' @eval roxygen_score_family("remote_checks", dontrun = TRUE)
#' @return a fractional value indicating percentage OS flavors that did not produce an error or warning from R CMD check
#'
#' @export
metric_score.pkg_metric_remote_checks <- function(x, ...) {
  unname((x["OK"] + (x[grepl("NOTE", names(x))] *0.75) + (x[grepl("WARN", names(x))] *0.5))/sum(x))
}
attributes(metric_score.pkg_metric_remote_checks)$label <-
  "Weighted sum of OS flavor R CMD check results"


================================================
FILE: R/assess_reverse_dependencies.R
================================================
#' Generate list of Reverse Dependencies for a package
#'
#' @details The more packages that depend on a package the more chance
#' for errors/bugs to be found
#'
#' @eval roxygen_assess_family(
#'   "reverse_dependencies",
#'   "A character vector of reverse dependencies")
#'
#' @export
assess_reverse_dependencies <- function(x, ...){
  UseMethod("assess_reverse_dependencies")
}

#' @importFrom devtools revdep
#' @export
assess_reverse_dependencies.default <- function(x, ...){
  pkg_metric_eval(class = "pkg_metric_reverse_dependencies",
                  devtools::revdep(x$name, bioconductor = TRUE)
  )
}

attr(assess_reverse_dependencies, "column_name") <- "reverse_dependencies"
attr(assess_reverse_dependencies, "label") <- "List of reverse dependencies a package has"

#' Scoring method for number of reverse dependencies a package has
#'
#' Score a package for the number of reverse dependencies it has; regularized
#' Convert the number of reverse dependencies \code{length(x)} into a validation
#' score [0,1] \deqn{ 1 / (1 + exp(-0.5 * (sqrt(length(x)) + sqrt(5)))) }
#'
#' The scoring function is the classic logistic curve \deqn{
#' 1 / (1 + exp(-k(x-x[0])) } with a square root scale for the number of reverse dependencies
#' \eqn{x = sqrt(length(x))}, sigmoid midpoint is 5 reverse dependencies, ie. \eqn{x[0] =
#' sqrt(5)}, and logistic growth rate of \eqn{k = 0.5}.
#'
#' \deqn{ 1 / (1 + -0.5 * exp(sqrt(length(x)) - sqrt(5))) }

#' @eval roxygen_score_family("reverse_dependencies", dontrun = TRUE)
#' @return numeric value between \code{1} (high number of reverse dependencies) and
#'   \code{0} (low number of reverse dependencies)
#'
#' @export
metric_score.pkg_metric_reverse_dependencies <- function(x,...){
  1 / (1 + exp(-0.5 * (sqrt(length(x)) - sqrt(5))))
}

attributes(metric_score.pkg_metric_reverse_dependencies)$label <-
  "The (log10) number of packages that depend on this package."



================================================
FILE: R/assess_size_codebase.R
================================================
#' Assess a package for size of code base
#'
#' @eval roxygen_assess_family(
#'   "size_codebase",
#'   "a numeric value for number of lines of code base for a package")
#'
#' @export
assess_size_codebase <- function(x, ...) {
  UseMethod("assess_size_codebase")
}

attributes(assess_size_codebase)$column_name <- "size_codebase"
attributes(assess_size_codebase)$label <- "number of lines of code base"

#' @export
assess_size_codebase.default <- function(x, ...) {
  as_pkg_metric_na(
    pkg_metric(class = "pkg_metric_size_codebase"),
    message = sprintf("Cannot compute the number of lines of code from a %s", x$source))
}


#' @export
assess_size_codebase.pkg_install <- function(x, ...) {
  pkg_metric_eval(class = "pkg_metric_size_codebase", {
    # create character vector of exported function
    exports <- getNamespaceExports(x$name)

    # add package to the search path
    attachNamespace(x$name)

    # count number of lines for exported function through the mget function
    nloc <- capture.output(mget(exports, envir = as.environment(paste0("package:", x$name))))

    # sum the number of lines and extract the 4 extra lines (function name, bytecode, environment, blank line)
    length(nloc) - 4*length(exports)
  })
}

#' @export
assess_size_codebase.pkg_source <- function(x, ...) {
  pkg_metric_eval(class = "pkg_metric_size_codebase", {
    # create character vector of function files
    files <- list.files(
      path = file.path(x$path, "R"),
      pattern = "\\.R$",
      full.names = TRUE,
      ignore.case = TRUE
    )

    # define the function for counting code base
    count_lines <- function(x){
      # read the lines of code into a character vector
      code_base <- readLines(x)

      # count all the lines
      n_tot <- length(code_base)

      # count lines for roxygen headers starting with #
      n_head <- length(grep("^#+", code_base))

      # count the comment lines with leading spaces
      n_comment <- length(grep("^\\s+#+", code_base))

      # count the line breaks or only white space lines
      n_break <- length(grep("^\\s*$", code_base))

      # compute the line of code base
      n_tot - (n_head + n_comment + n_break)
    }

    # count number of lines for all functions
    nloc <- sapply(files, count_lines)

    # sum the number of lines
    sum(nloc)
  })
}

#' Score a package for number of lines of code
#'
#' Scores packages based on its codebase size, as determined by number of lines of code.
#'
#' @eval roxygen_score_family("size_codebase")
#'
#' @return numeric value between \code{0} (for large codebase) and \code{1} (for small codebase)
#' @export
metric_score.pkg_metric_size_codebase <- function(x, ...) {
  1.5 / (x / 1e2 + 1.5)
}

attributes(metric_score.pkg_metric_size_codebase)$label <-
  "A logistic rating of the number of lines of code in a package."


================================================
FILE: R/dev_hint.R
================================================
#' dev_hint <- function(title, text, format_args = list()) {
#'   if (is.character(text)) text <- list(dev_hint_section(text))
#'   data <- list(
#'     title = title,
#'     text = text,
#'     format_args = format_args)
#'   structure(data, class = c("dev_hint", class(data)))
#' }
#'
#'
#'
#' dev_hint_section <- function(text, format_args = list(wrap = TRUE)) {
#'   structure(text,
#'     format_args = format_args,
#'     class = c("dev_hint_section", class(text)))
#' }
#'
#'
#'
#' dev_hint_crayon_title_style <- crayon::make_style(rgb(0.1, 0.2, 0.6))
#' dev_hint_crayon_title <- function(...)
#'   crayon::bold(dev_hint_crayon_title_style(...))
#'
#' dev_hint_crayon_link <- crayon::make_style(rgb(0.1, 0.6, 0.4))
#' dev_hint_crayon_success <- crayon::make_style(rgb(0.15, 0.7, 0.15))
#' dev_hint_crayon_failure <- crayon::make_style(rgb(0.8, 0.2, 0.2))
#'
#'
#'
#' #' @importFrom utils modifyList
#' #' @export
#' print.dev_hint <- function(x, ...) {
#'   dots <- utils::modifyList(x$format_args, list(...))
#'   cat(do.call(format, c(list(x), dots)))
#' }
#'
#'
#'
#' #' @export
#' format.dev_hint <- function(x, use_crayon = TRUE, wrap = FALSE, ...) {
#'   text_refs <- lapply(x$text, strip_dev_hint_section_links)
#'   text <- lapply(text_refs, "[[", "text")
#'   refs <- unlist(lapply(text_refs, "[[", "refs"))
#'
#'   refs <- paste0(
#'     dev_hint_crayon_link("[", seq_along(refs), "] ", refs, sep = ""),
#'     collapse = "\n")
#'
#'   text <- append(text, list(dev_hint_section(refs, list(wrap = FALSE))))
#'   text <- lapply(text, function(i) {
#'     do.call(format, append(list(i), attr(i, "format_args")))
#'   })
#'
#'   paste0(dev_hint_crayon_title(x$title), "\n", paste(text, collapse = "\n\n"))
#' }
#'
#'
#' strip_dev_hint_section_links <- function(x, use_crayon = TRUE, ref_index_start = 1) {
#'   # find markdown links in text
#'   md_link_re <- "(?<link>\\[(?<text>[^]]+)\\]\\((?<url>[^)]+)\\))"
#'   md_link <- gregexpr(md_link_re, x, perl = TRUE)[[1]]
#'   md_link_start <- attr(md_link, "capture.start")
#'   md_link_end <- md_link_start + attr(md_link, "capture.length") - 1
#'
#'   # match named regex groups
#'   if (all(md_link == -1)) {
#'     refs <- matrix(ncol = ncol(attr(md_link, "capture.start")))[c(),]
#'   } else {
#'     refs <- matrix(substring(x,
#'         first = md_link_start,
#'         last  = md_link_end),
#'       ncol = ncol(attr(md_link, "capture.start")))
#'   }
#'   colnames(refs) <- attr(md_link, "capture.names")
#'
#'   # break text on md links
#'   text <- substring(x,
#'     first = c(0, md_link_start[,"link"]),
#'     last = c(md_link_start[,"link"] - 1, 1e6L))
#'
#'   # remove md links
#'   text[-1] <- substring(text[-1],
#'     first = attr(md_link, "capture.length")[,"link"] + 1,
#'     last = 1e6L)
#'
#'   # add back in link text
#'   text[-1] <- paste0(refs[,"text"],
#'     if (nrow(refs))
#'       dev_hint_crayon_link("[", ref_index_start + seq_along(refs[,"text"]) - 1, "]", sep = ""),
#'     text[-1])
#'   text <- paste(text, collapse = "")
#'
#'   # rejoin with original attributes
#'   attributes(text) <- attributes(x)
#'
#'   # return both modified text, as well as scraped references
#'   list(
#'     text = text,
#'     refs = refs[,"url"])
#' }
#'
#'
#' format.dev_hint_section <- function(x, use_crayon = TRUE, wrap = TRUE) {
#'   if (wrap)
#'     paste0(fansi::strwrap_ctl(x, indent = 2, exdent = 2), collapse = "\n")
#'   else
#'     paste0("  ", strsplit(x, "\n")[[1]], collapse = "\n")
#' }


================================================
FILE: R/dev_tips.R
================================================
#' #' Provide tips for improving a metric
#' #'
#' #' @param x a pkg_metric object
#' #' @param ... additional arguments unused
#' #'
#' #' @export
#' dev_tips <- function(x, ...) {
#'   UseMethod("dev_tips")
#' }


================================================
FILE: R/metric_score.R
================================================
#' Score a package metric
#'
#' Convert a package metric into a numeric value between 0 to 1
#'
#' @param x A \code{pkg_metric_*} class object to score
#' @param ... Additional arguments unused
#'
#' @return score of a package risk metric
#' @export
#'
metric_score <- function(x, ...) {
  if (inherits(x, "pkg_metric_condition"))
    return(metric_score_condition(x, ...))
  UseMethod("metric_score")
}



#' @export
metric_score.default <- function(x, ...) {
  if (!inherits(x, "pkg_metric")) {
    warning(sprintf(paste0(
        "Don't know how to score object of class %s. score is only intended ",
        "to be used with objects inheriting class 'pkg_metric', ",
        "returning default score of 0."),
      paste0('"', class(x), '"', collapse = ", ")))
  } else {
    warning(sprintf(paste0(
        "no available scoring algorithm for metric of class %s, ",
        "returning default score of 0."),
      paste0('"', class(x)[1], '"')))
  }

  0L
}


metric_score_condition <- function(x, ...) {
  UseMethod("metric_score_condition")
}

metric_score_condition.pkg_metric_error <- function(x, ...,
    error_handler = score_error_default) {
  error_handler(x, ...)
}


metric_score_condition.pkg_metric_na <- function(x, ...) {
  structure(NA_real_, class = c("pkg_score_na", "numeric"))
}

metric_score_condition.pkg_metric_error <- function(x, ...) {
  structure(NA_real_, class = c("pkg_score_error", "numeric"))
}

metric_score_condition.pkg_metric_todo <- function(x, ...) {
  structure(NA_real_, class = c("pkg_score_todo", "numeric"))
}



#' Default score error handling, emitting a warning and returning 0
#'
#' @inheritParams metric_score
#' @return a value of package score
#' @export
score_error_default <- metric_score.default



#' Score error handler to silently return 0
#'
#' @inheritParams metric_score
#'
#' @return a value of package score
#' @export
score_error_zero <- function(...) 0



#' Score error handler to silently return NA
#'
#' @inheritParams metric_score
#' @return a value of package score
#' @export
score_error_NA <- function(...) NA_real_



================================================
FILE: R/options.R
================================================
riskmetric.options <- list(
  gitlab_api_host = "https://gitlab.com/api/v4",
  github_api_host = "https://api.github.com"
)


================================================
FILE: R/pkg_assess.R
================================================
#' Helper for creating a roxygen header from template for assess_* functions
#'
#' @param name the name of the assessment, assuming naming conventions are
#'   followed
#' @param return_type an optional added commentary about the return type of the
#'   assessment function
#' @param dontrun logical indicating whether examples should be wrapped in
#'   a dontrun block. This is particularly useful for assessments which may
#'   require an internet connection.
#'
#' @return roxygen section template for assess family functions
#'
#' @examples
#' \dontrun{
#' #' @eval roxygen_assess_family(
#' #'   "has_news",
#' #'   "an integer value indicating the number of discovered NEWS files")
#' }
#'
#' @keywords internal
roxygen_assess_family <- function(name,
    return_type = "an atomic assessment result",
    dontrun = TRUE) {

  assess_func <- sprintf("assess_%s", name)
  score_func <- sprintf("metric_score.pkg_metric_%s", name)
  example_template <- if (dontrun) {
    "@examples \n\\dontrun{\nassess_%s(pkg_ref(\"%s\"))\n}"
  } else {
    "@examples assess_%s(pkg_ref(\"%s\"))"
  }

  c("@param x a \\code{pkg_ref} package reference object",
    "@param ... additional arguments passed on to S3 methods, rarely used",
    sprintf("@return a \\code{pkg_metric} containing %s", return_type),
    sprintf("@seealso \\code{\\link{%s}}", score_func),
    sprintf(example_template, name, packageName()))
}



#' Helper for creating a roxygen itemized list for assess_* functions
#'
#' @return roxygen section template for assess family function catalog
#'
#' @examples
#' \dontrun{
#'   #' @eval assess_family_catalog_roxygen()
#' }
#' @keywords internal
roxygen_assess_family_catalog <- function() {
  assessments <- all_assessments()
  info <- lapply(assessments, attr, "label")
  missing_label <- vapply(info, is.null, logical(1L))
  info[missing_label] <- names(info)[missing_label]

  c("@section Assessment function catalog:",
    "\\describe{",
    sprintf('\\item{\\code{\\link{%s}}}{%s}', names(info), info),
    "}")
}



#' A default list of assessments to perform for each package
#'
#' @return a list of assess_* functions exported from riskmetric
#'
#' @importFrom utils packageName
#' @export
all_assessments <- function() {
  fs <- grep("^assess_[^.]*$",
    getNamespaceExports(utils::packageName()),
    value = TRUE)
  Map(getExportedValue, fs, ns = list(utils::packageName()))
}

#' Get a specific set of assess_* functions for pkg_assess
#'
#' @param fxn_string vector of assess functions
#' @return a list of specific assess_* functions exported from riskmetric
#'
#' @importFrom utils packageName
#' @export
get_assessments <- function(fxn_string=""){
  Map(getExportedValue,
      fxn_string,
      ns = list(utils::packageName()))
}



#' Helper for retrieving a list of columns which contain pkg_metric objects
#'
#' @param tbl a \code{\link[tibble]{tibble}} to select columns among
#'
#' @return a logical vector of \code{pkg_metric} column indices
#' @keywords internal
get_assessment_columns <- function(tbl) {
  vapply(tbl, inherits, logical(1L), "list_of_pkg_metric")
}



#' reassign assignment list names with column_name attribute if available
#'
#' @param x list of columns for which to consider friendly column name
#'   attributes
#'
#' @return a vector of friendly column names if available
#' @keywords internal
use_assessments_column_names <- function(x) {
  column_names <- lapply(x, attr, "column_name")
  colname_null <- vapply(column_names, is.null, logical(1L))
  names(x)[!colname_null] <- column_names[!colname_null]
  names(x)[!nchar(names(x))] <- paste0("unnamed", seq_along(x[!nchar(names(x))]))
  x
}



#' Apply assess_* family of functions to a package reference
#'
#' By default, use all \code{assess_*} funtions in the \code{riskmetric}
#' namespace and produce a \code{\link[tibble]{tibble}} with one column per
#' assessment applied.
#'
#' @param x A single \code{\link{pkg_ref}} object or
#'   \code{\link[tibble]{tibble}} of package references to assess
#' @param assessments A list of assessment functions to apply to each package
#'   reference. By default, a list of all exported assess_* functions from the
#'   riskmetric package.
#' @param ... additional arguments unused
#' @param error_handler A function, which accepts a single parameter expecting
#'   the raised error, which will be called if any errors occur when attempting
#'   to apply an assessment function.
#'
#' @return Either a \code{list_of_pkg_metric} object when a single
#'   \code{pkg_ref} object is passed as \code{x}, or a
#'   \code{\link[tibble]{tibble}} of metrics when a \code{list_of_pkg_ref} or
#'   \code{tibble} is passed as \code{x}. When a \code{\link[tibble]{tibble}}
#'   is returned, it has one row per package reference and a new column per
#'   assessment function, with cells of that column as package metric objects
#'   returned when the assessment was called with the associated pacakge
#'   reference.
#'
#' @eval roxygen_assess_family_catalog()
#'
#'
#' @importFrom tibble as_tibble
#' @importFrom vctrs new_list_of
#' @export
pkg_assess <- function(x, assessments = all_assessments(), ...,
    error_handler = assessment_error_empty) {
  UseMethod("pkg_assess")
}



#' @export
pkg_assess.pkg_ref <- function(x, assessments = all_assessments(), ...,
    error_handler = assessment_error_empty) {

  assessments <- use_assessments_column_names(assessments)
  xout <- list()

  for (i in seq_along(assessments)) {
    assessment_f <- assessments[[i]]
    assessment_name <- names(assessments)[[i]]

    xout[[assessment_name]] <- tryCatch({
      assessment_f(x)
    }, error = function(e) {
      error_handler(e, x$name, assessment_name)
    })

    attributes(xout[[assessment_name]])$label <- attributes(assessment_f)$label
  }

  vctrs::new_list_of(xout,
    structure(logical(), class = "pkg_metric"),
    class = "list_of_pkg_metric")
}



#' @export
pkg_assess.list_of_pkg_ref <- function(x, assessments = all_assessments(), ...,
    error_handler = assessment_error_empty) {

  pkg_assess(tibble::as_tibble(x),
    assessments = assessments,
    error_handler = error_handler)
}



#' @export
pkg_assess.tbl_df <- function(x, assessments = all_assessments(), ...,
    error_handler = assessment_error_empty) {

  assessments <- use_assessments_column_names(assessments)
  for (i in seq_along(assessments)) {
    assessment_f <- assessments[[i]]
    assessment_name <- names(assessments)[[i]]

    x[[assessment_name]] <- lapply(x$pkg_ref, function(pkg_ref) {
      tryCatch({
        assessment_f(pkg_ref)
      }, error = function(e) {
        error_handler(e, pkg_ref$name, assessment_name)
      })
    })

    x[[assessment_name]] <- vctrs::new_list_of(x[[assessment_name]],
      structure(logical(), class = "pkg_metric"),
      class = "list_of_pkg_metric")

    attributes(x[[assessment_name]])$label <- attributes(assessment_f)$label
  }

  x
}


================================================
FILE: R/pkg_cohort.R
================================================
#' @family pkg_ref
pkg_cohort <- function() {
  structure(
    list(),
    class = "pkg_cohort"
  )
}


================================================
FILE: R/pkg_metric.R
================================================
#' A helper for structuring assessment return objects for dispatch with the
#' score function
#'
#' @param x data to store as a \code{pkg_metric}
#' @param ... additional attributes to bind to the \code{pkg_metric} object
#' @param class a subclass to differentiate the \code{pkg_metric} object
#'
#' @return a \code{pkg_metric} object
#'
#' @export
pkg_metric <- function(x = NA, ..., class = c()) {
  if (is.null(x)) x <- list()
  structure(x, ..., class = c(class, "pkg_metric", class(x)))
}



#' Convert an object to a \code{pkg_metric}
#'
#' @inheritParams pkg_metric
#' @return a \code{pkg_metric} object
#' @export
as_pkg_metric <- function(x, class = c()) {
  UseMethod("as_pkg_metric")
}



#' @export
as_pkg_metric.default <- function(x, class = c()) {
  pkg_metric(x, class = class)
}



#' @export
as_pkg_metric.expr_output <- function(x, class = c()) {
  x_metric <- pkg_metric(x, class = class)
  if (is_error(x))
    x_metric <- as_pkg_metric_error(x_metric)
  x_metric
}



#' Evaluate a metric
#'
#' Evalute code relevant to a metric, capturing the evaluated code as well as
#' any messages, warnings or errors that are thrown in the process.
#'
#' @param expr An expression to evaluate in order to calculate a
#'   \code{pkg_metric}
#' @param env An environment in which \code{expr} is to be evaluated
#' @inheritParams pkg_metric
#'
#' @return a \code{pkg_metric} object containing the result of \code{expr}
#' @keywords internal
pkg_metric_eval <- function(expr, ..., class = c(), env = parent.frame()) {
  out <- capture_expr_output(substitute(expr), env = env, quoted = TRUE)
  out_metric <- as_pkg_metric(out, class = class)
  if (inherits(out, "error")) out_metric <- as_pkg_metric_error(out_metric)
  out_metric
}



#' @importFrom vctrs vec_ptype_abbr
#' @method vec_ptype_abbr pkg_metric
#' @export
vec_ptype_abbr.pkg_metric <- function(x, ...) {
  "pkg_metric"
}



#' @export
format.pkg_metric_error <- function(x, ...) {
  class_str <- gsub("^pkg_metric_", "", class(x)[[1]])
  pillar::style_na(paste0("<", class_str, ">"))
}



#' @export
format.pkg_metric <- function(x, ...) {
  class_str <- gsub("^pkg_metric_", "", class(x)[[1]])
  data_str <- with_unclassed_to(x, "pkg_metric", pillar::pillar_shaft(x))
  paste0(capture.output(data_str), collapse = "")
}


================================================
FILE: R/pkg_metric_condition.R
================================================
#' A pkg_metric subclass for general metric evaluation conditions
#'
#' @param x an object to wrap in a \code{pkg_metric_condition} class
#' @param ... additional arguments added as attributes to object \code{x}
#' @param subclass an optional subclass of \code{pkg_metric_condition} to
#'   include
#'
#' @return an object after wrap \code{pkg_metric_condition} class.
#' @keywords internal
as_pkg_metric_condition <- function(x, ..., subclass = c()) {
  dots <- list(...)
  if (length(names(dots)) != length(dots))
    stop("All ellipsis arguments must be named")
  dots <- dots[setdiff(names(dots), "class")]
  attributes(x)[names(dots)] <- dots
  class(x) <- c(subclass, "pkg_metric_condition", class(x))
  x
}


================================================
FILE: R/pkg_metric_error.R
================================================
#' A subclass wrapping an error with an additional parent class
#'
#' @param error an error condition object to capture
#'
#' @return an error condition object after wrap \code{pkg_metric_error} class.
#' @keywords internal
as_pkg_metric_error <- function(error) {
  as_pkg_metric_condition(error, subclass = "pkg_metric_error")
}



#' Error handler for assessments with safe fallback
#'
#' @inheritParams format_assessment_message
#' @param ... additional arguments unused
#'
#' @return a pkg_metric object of pkg_metric_error subclass
#'
#' @family assessment error handlers
#'
#' @export
assessment_error_empty <- function(e, ...) {
  as_pkg_metric_error(pkg_metric(e))
}



#' Error handler for assessments to throw error immediately
#'
#' @inheritParams format_assessment_message
#' @return the error encountered during assessment
#'
#' @family assessment error handlers
#'
#' @export
assessment_error_throw <- function(e, name, assessment) {
  stop(format_assessment_message(e, name, assessment))
}



#' Error handler for assessments to deescalate errors to warnings
#'
#' @inheritParams format_assessment_message
#' @inherit assessment_error_empty return
#'
#' @family assessment error handlers
#'
#' @export
assessment_error_as_warning <- function(e, name, assessment) {
  warning(format_assessment_message(e, name, assessment), call. = FALSE)
  assessment_error_empty(e)
}



#' Assessment console printing formatter
#'
#' make the errors and warnings consistent with meaningful indication of what
#' triggered the error, including the name of the package whose reference
#' triggered the error while running which asesessment.
#'
#' @param e an error raised during a package reference assessment
#' @param name the name of the package whose package reference assessment raised
#'   the error
#' @param assessment the name of the assessment function which raised the error
#' @return a character string of formatted text to communicate the error
#'
#' @importFrom utils capture.output
#' @keywords internal
format_assessment_message <- function(e, name, assessment) {
  out <- "In "

  if (!missing(name))
    out <- paste0(out, "package '", name, "' ")
  if (!missing(assessment))
    out <- paste0(out, "while assessing '", assessment, "' ")

  paste0(out,
    "`", paste(utils::capture.output(e$call), collapse = " "), "` : \n",
    e$message)
}



#' @importFrom pillar pillar_shaft new_pillar_shaft_simple style_na
#' @method pillar_shaft pkg_metric_error
#' @export
pillar_shaft.pkg_metric_error <- function(x, ...) {
  pillar::new_pillar_shaft_simple(pillar::style_na(paste0(
    "<",
    gsub("pkg_metric_", "", class(x)[[1]]),
    ">")))
}


================================================
FILE: R/pkg_metric_na.R
================================================
#' A pkg_metric subclass for when metrics are explicitly not applicable
#'
#' @param x a \code{pkg_metric} object to wrap in a \code{pkg_metric_na}
#'   subclass
#' @param message an optional message explaining why a metric is not applicable.
#' @return a \code{pkg_metric} object after wrap in a \code{pkg_metric_na}
#' @keywords internal
as_pkg_metric_na <- function(x, message = NULL) {
  as_pkg_metric_condition(x, message = message, subclass = "pkg_metric_na")
}


================================================
FILE: R/pkg_metric_todo.R
================================================
#' A pkg_metric subclass for when pkg_metrics have not yet been implemented
#'
#' @param x a \code{pkg_metric} object to wrap in a \code{pkg_metric_todo}
#'   subclass
#' @param message an optional message directing users and potential contributors
#'   toward any ongoing work or first steps toward development.
#' @return a \code{pkg_metric} object after wrap in a \code{pkg_metric_todo}
#' @keywords internal
as_pkg_metric_todo <- function(x, message = NULL) {
  as_pkg_metric_condition(x, message = message, subclass = "pkg_metric_todo")
}


================================================
FILE: R/pkg_ref_cache.R
================================================
#' S3 generic to calculate a `pkg_ref` field
#'
#' Reactively retrieve and cache `pkg_ref` metadata
#'
#' @section Caching Details:
#' \subsection{\code{pkg_ref} class fields}{
#'   The \code{pkg_ref} class structures an environment with special handling
#'   for indexing into the \code{pkg_ref} class using the \code{$} or \code{[[}
#'   operators. For all intents and purposes, the \code{pkg_ref} class is works
#'   conceptually similar to a lazy, immutable \code{list}, and uses the
#'   \code{pkg_ref_cache} function internally to lazily retrieve package
#'   reference fields.
#' }
#' \subsection{Lazy metadata caching}{
#'   Laziness in a \code{pkg_ref} object refers to the delayed evaluation of the
#'   contents of its fields. Since some metadata is time or computationally
#'   intensive to retrieve, and unnessary for some assessments, we want to avoid
#'   that retrieval until it is needed.
#'
#'   The first time that a field is accessed within a \code{pkg_ref} object
#'   \code{x}, a corresponding \code{pkg_ref_cache} S3 generic is called. For
#'   example, when \code{x$description} is first accessed, the \code{pkg_ref}
#'   object uses the function \code{pkg_ref_cache.description} to attempt to
#'   retrieve the contents of the corresponding \code{DESCRIPTION} file.
#'
#'   Often, the way that this data is collected might be different depending on
#'   the subclass of the \code{pkg_ref}. In the case of the \code{description}
#'   metadata, a reference to a local install might be able to read in a local
#'   file directly, whereas a reference to a remote source of metadata might
#'   require first downloading the file. For this reason, many
#'   \code{pkg_ref_cache.*} functions are themselves S3 generics that dispatch
#'   on the class of the \code{pkg_ref} object, allowing for divergent behaviors
#'   for different source of package metadata.
#' }
#' \subsection{\code{pkg_ref} field immutability}{
#'   Once a field has been calculated, its value is immutable. This behavior was
#'   chosen because of the long time frame over which package metadata changes,
#'   rendering it unnecessary to continually reevaluate fields each time they
#'   are accesssed.
#'
#'   This means that within an assessment, a given field for a package will only
#'   ever be calculated once and preserved for downstream use.
#' }
#'
#' @return a \code{pkg_ref} field
#' @examples
#' \dontrun{
#' # implementing a new field called "first_letter" that is consistently derived
#' # across all pkg_ref objects:
#'
#'   pkg_ref_cache.first_letter <- function(x, name, ...) {
#'     substring(x$name, 1, 1)
#'   }
#'
#'   x <- pkg_ref("riskmetric")
#'   x$first_letter
#'
#'
#'
#' # implementing a new field called "subclass_enum" that dispatches on
#' # the subclass of the pkg_ref object:
#'
#'   pkg_ref_cache.subclass_enum <- function(x, name, ...) {
#'     UseMethod("pkg_ref_cache.subclass_enum")
#'   }
#'
#'   pkg_ref_cache.subclass_enum.pkg_ref <- function(x, name, ...) {
#'     0
#'   }
#'
#'   pkg_ref_cache.subclass_enum.pkg_install <- function(x, name, ...) {
#'     1
#'   }
#'
#'   x$subclass_enum
#' }
#'
#' @rdname riskmetric_metadata_caching
#' @name pkg_ref_cache
NULL



#' A helper function for retrieving a list of available fields, identified based
#' on implementation of a pkg_ref_cache method for a given class.
#'
#' @param x a package reference object
#' @return a list of available fields implemented with a pkg_ref_cache method
#'
#' @importFrom utils .S3methods
#' @keywords internal
available_pkg_ref_fields <- function(x) {
  fs <- c(names(getNamespace(packageName())), utils::.S3methods("pkg_ref_cache"))

  # build data.frame by function name and S3 dispatch (to 2 levels of dispatch)
  fs_df <- as.data.frame(t(vapply(strsplit(fs, "\\."), `[`, character(3L), 1:3)))
  names(fs_df) <- c("func", "field", "class")
  fs_df <- fs_df[fs_df$func == "pkg_ref_cache",]

  fs_df <- Filter(function(method) {
    # filter for functions that implement an S3 for a subclass or don't have
    # any dispatched functions (all dispatched classes are NA).
    any(method$class %in% c(class(x), "default")) || all(is.na(method$class))
  }, Filter(nrow, split(fs_df, fs_df$field)))

  fs <- names(fs_df)
  fs <- fs[order(fs)]
  fs
}



#' @param x a package reference object
#' @param name the name of the field that needs to be cached
#' @param ... additional arguments used for computing cached values
#' @param .class a class name to use for S3 dispatch, defaulting to the name as
#'   a character value
#'
#' @return a value to assign to the new field in the package reference object
#'   environment
#'
#' @family package reference cache
#'
#' @rdname riskmetric_metadata_caching
#' @keyworks internal
#' @noRd
pkg_ref_cache <- function(x, name, ..., .class = as.character(name)) {
  UseMethod("pkg_ref_cache", structure(list(), class = .class))
}


================================================
FILE: R/pkg_ref_cache_NEWS_urls.R
================================================
#' Cache appropriate urls for NEWS files
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.news_urls <- function(x, name, ...) {
  UseMethod("pkg_ref_cache.news_urls")
}



#' @importFrom xml2 xml_attrs
pkg_ref_cache.news_urls.pkg_cran_remote <- function(x, name, ...) {
  # scrape CRAN html for NEWS links
  news_links <- xml2::xml_find_all(x$web_html, xpath = '//a[.="NEWS"]')

  # add NEWS link url metadata to package environment
  sprintf("%s/%s",
    x$web_url,
    vapply(xml2::xml_attrs(news_links), "[", character(1L), "href"))
}



#' @importFrom xml2 xml_attrs
pkg_ref_cache.news_urls.pkg_bioc_remote <- function(x, name, ...) {
  # scrape Bioconductor package webpage for NEWS links
  relative_path <- sprintf("../news/%s/NEWS", x$name)
  news_link_xpath <- sprintf('//a[@href="%s"]', relative_path)
  news_links <- xml2::xml_find_all(x$web_html, xpath = news_link_xpath)

  # add NEWS link url metadata to package environment
  xml2::url_absolute(
    vapply(xml2::xml_attrs(news_links), "[", character(1L), "href"),
    x$web_url)
}


================================================
FILE: R/pkg_ref_cache_archive_release_date.R
================================================
#' Cache a List of Archived Package Release Date from a Package Reference
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.archive_release_dates <- function(x, name, ...) {
  UseMethod("pkg_ref_cache.archive_release_dates")
}

pkg_ref_cache.archive_release_dates.pkg_cran_remote <- function(x, name, ...) {

  url <- sprintf("%s/src/contrib/Archive/%s", x$repo_base_url, x$name)

  html <- httr::content(httr::GET(url))
  node <- xml2::xml_find_first(html, "//pre")

  text <- unlist(strsplit(xml2::xml_text(node), "\n"))
  db   <- do.call(rbind, strsplit(text[-1], "\\s+"))
  version <- gsub(paste0(x$name, "_(.*)\\.tar\\.gz"), "\\1", db[,2])
  date  <- db[,3]
  cbind(name = x$name, version, date)

}


================================================
FILE: R/pkg_ref_cache_behaviors.R
================================================
#' List of available caching behaviors with metadata, including default and
#' annotations for building documentation
#'
#' @return a list contain cache behaviros information
#' @keywords internal
cache_behaviors <- list(
  "per_package_request" = list(
    default = function() interactive(),
    annotation = paste0(
      "requires a web request for each package individually, which can be time ",
      "intensive and an irresponsible use of generously hosted public R ",
      "package repositories. It is recommended that this behavior is disabled ",
      "for metric assessments of large numbers of packages or assessments ",
      "triggered via automated scripts. Automatically disabled by default for ",
      "non-interactive use."))
)



#' Document both declare_cache_behavior parameters and options list
#'
#' @param fmt format of cache behavior entries
#' @param name_fmt special formating for name (first) component
#' @param annotation_fmt special formating for annotation (second) component
#' @param wrap_fmt a wrapper for the entirety of the roxygen entries
#' @param collapse passed to paste
#' @return a string
#' @keywords internal
roxygen_cache_behaviors <- function(fmt = "%s: %s", name_fmt = "%s",
    annotation_fmt = "%s", wrap_fmt = "%s", collapse = "\n") {

  cache_behavior_names <- sprintf(name_fmt, names(cache_behaviors))
  cache_behavior_annotations <- sprintf(annotation_fmt,
    vapply(cache_behaviors, "[[", character(1L), "annotation"))

  sprintf(wrap_fmt, paste(
    sprintf(fmt, cache_behavior_names, cache_behavior_annotations),
    collapse = collapse))
}



#' Stop if a function requires disabled behaviors
#'
#' @param behaviors a character vector of behavior flags to assert as
#'   requirements for metadata caching. values must have an entry found in
#'   riskmetric:::cache_behaviors list
#'
#' @return a boolean value
#' @keywords internal
require_cache_behaviors <- function(behaviors) {
  stopifnot(all(behaviors %in% names(cache_behaviors)))

  opt_names <- paste0(packageName(), ".", behaviors)
  names(opt_names) <- opt_names
  behaviors_disabled <- Filter(isFALSE, lapply(opt_names, getOption))

  if (length(behaviors_disabled)) {
    e <- simpleError(message = paste(
      "package metadata caching requires behaviors disabled by option(s)",
      paste0('"', names(behaviors_disabled), '"', collapse = ", ")))
    class(e) <- c("riskmetric_disabled_behavior_error", class(e))
    stop(e)
  }
}


================================================
FILE: R/pkg_ref_cache_bug_reports.R
================================================
#' Retrieve a list of BugReports metadata
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.bug_reports <- function(x, ...) {
  UseMethod("pkg_ref_cache.bug_reports")
}


pkg_ref_cache.bug_reports.default <- function(x, ...) {
  scrape_bug_reports(x, ...)
}



#' Helper for structuring bug reports
#'
#' @param bug_reports_data data to represent a bug report history - generally a
#'   return object from making a request to a repository's issues API
#' @param x a \code{pkg_ref} object where a \code{bug_reports_host} field can be
#'   found
#' @return a \code{bug_reports_host} field
#' @keywords internal
bug_report_metadata <- function(bug_reports_data, x) {
  structure(bug_reports_data,
    class = c(
      paste0(x$bug_reports_host, "_bug_report"),
      "bug_report",
      class(bug_reports_data)))
}



# Helper for scraping bug reports depending on url host name
scrape_bug_reports <- function(x, ...) {
  disp_class <- x$bug_reports_host %||% "NULL"
  UseMethod("scrape_bug_reports", structure(list(), class = disp_class))
}



scrape_bug_reports.default <- function(x, ...) {
  if (is.null(x$bug_reports_host) || length(x$bug_reports_host) == 0L)
    stop("package DESCRIPTION does not have a BugReports field")
  else
    stop(sprintf(
      "scraping bug reports fromm BugReports host '%s' not implemented",
      x$bug_reports_host))
}



#' @importFrom httr GET content
#' @keywords internal
scrape_bug_reports.github <- function(x, ...) {
  owner_repo_issues <- gsub(
    ".*github[^/]*/([^/]+/[^/]+).*",
    "\\1",
    x$bug_reports_url)
  resp <- httr::GET(sprintf(
    "%s/repos/%s/issues?state=all&per_page=%s",
    getOption("riskmetric.github_api_host"),
    owner_repo_issues,
    30))
  out <- httr::content(resp, as = "parsed")
  bug_report_metadata(out, x)
}



#' @importFrom httr GET content
#' @importFrom urltools url_encode
#' @keywords internal
scrape_bug_reports.gitlab <- function(x, ...) {
  owner_repo_issues <- gsub(".*gitlab[^/]*/(.*)", "\\1", x$bug_reports_url)
  owner_repo <- gsub("(.*)/issues", "\\1", owner_repo_issues)
  resp <- httr::GET(sprintf(
    "%s/projects/%s/issues?per_page=%s",
    getOption("riskmetric.gitlab_api_host"),
    url_encode(owner_repo),
    30))
  out <- httr::content(resp, as = "parsed")
  bug_report_metadata(out, x)
}


================================================
FILE: R/pkg_ref_cache_bug_reports_host.R
================================================
#' Get the host name of a BugReports url
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.bug_reports_host <- function(x, ...) {
  UseMethod("pkg_ref_cache.bug_reports_host")
}


#' Get the host name of a BugReports url
#'
#' @importFrom urltools domain
#' @return a \code{pkg_ref} object
#' @keywords internal
pkg_ref_cache.bug_reports_host.default <- function(x, ...) {
  if (is.null(x$bug_reports_url)) return(NULL)
  sapply(strsplit(domain(x$bug_reports_url), "\\."), function(dm) dm[length(dm)-1])
}


================================================
FILE: R/pkg_ref_cache_bug_reports_url.R
================================================
#' Get the BugReports url
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.bug_reports_url <- function(x, ...) {
  UseMethod("pkg_ref_cache.bug_reports_url")
}


#' Get the BugReports url
#'
#' @importFrom utils packageDescription
#' @return a \code{pkg_ref} object
#' @keywords internal
pkg_ref_cache.bug_reports_url.pkg_source <- function(x, ...) {
  # fake a library location given the package source code path where the
  # description can be found, revert on exit when no longer needed

  packageDescription(x$name, dirname(x$path))$BugReports
}



#' @importFrom utils packageDescription
#' @keywords internal
pkg_ref_cache.bug_reports_url.pkg_install <- function(x, ...) {
  packageDescription(x$name)$BugReports
}



#' @importFrom xml2 xml_find_all xml_attr
#' @keywords internal
pkg_ref_cache.bug_reports_url.pkg_cran_remote <- function(x, ...) {
  # scrape CRAN package webpage for BugReports links
  bug_reports_xpath <- "//td[.='BugReports:']/following::td[1]/a"
  bug_reports_link <- xml_find_all(x$web_html, xpath = bug_reports_xpath)
  xml_attr(bug_reports_link, "href")
}



#' @importFrom xml2 xml_find_all xml_attr
#' @keywords internal
pkg_ref_cache.bug_reports_url.pkg_bioc_remote <- function(x, ...) {
  # scrape CRAN package webpage for BugReports links
  bug_reports_xpath <- "//td[.='BugReports']/following::td[1]/a"
  bug_reports_link <- xml_find_all(x$web_html, xpath = bug_reports_xpath)
  xml_attr(bug_reports_link, "href")
}


================================================
FILE: R/pkg_ref_cache_covr_coverage.R
================================================
#' Retrieve output of covr::package_coverage
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.covr_coverage <- function(x, ...) {
  UseMethod("pkg_ref_cache.covr_coverage")
}


#' Retrieve output of covr::package_coverage
#'
#' @importFrom tools testInstalledPackage
#' @importFrom covr package_coverage
#' @return a \code{pkg_ref} object
#' @keywords internal
pkg_ref_cache.covr_coverage.pkg_source <- function(x, ...) {
  # use custom 'code' to avoid triggering errors upon test failure.
  # practically identical to covr::package_coverage with the exclusion of
  # `if (result != 0L) show_failures(out_dir)`
  expr <- bquote(tools::testInstalledPackage(.(x$name), types = 'tests'))
  cnsl <- capture_expr_output({
    res <- covr::package_coverage(
      path = x$path,
      type = "none",
      code = deparse(expr))
  })

  res
}


================================================
FILE: R/pkg_ref_cache_description.R
================================================
#' Cache the DESCRIPTION file contents for a package reference
#'
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.description <- function(x, name, ...) {
  UseMethod("pkg_ref_cache.description")
}



pkg_ref_cache.description.pkg_install <- function(x, name, ...) {
  read.dcf(file.path(x$path, "DESCRIPTION"))
}



pkg_ref_cache.description.pkg_source <- function(x, name, ...) {
  read.dcf(file.path(x$path, "DESCRIPTION"))
}


================================================
FILE: R/pkg_ref_cache_downloads.R
================================================
#' Cache a list of available help files as LaTeX objects
#' @param n Number of days to look back with default value of 365 days
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#'
#' @importFrom cranlogs cran_downloads
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.downloads <- function(x, ..., n=365) {
  cran_downloads(x$name, from=Sys.Date()-n, to=Sys.Date())
}


================================================
FILE: R/pkg_ref_cache_examples.R
================================================
#' Cache the examples available for exported objects for a package reference
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.examples <- function(x, name, ...) {
  UseMethod("pkg_ref_cache.examples")
}

pkg_ref_cache.examples.pkg_install <- function(x, name, ...) {
  examples_from_pkg(x$name)
}

pkg_ref_cache.examples.pkg_source <- function(x, name, ...) {
  examples_from_dir(x$path, x$name)
}

#' Filter a simple database of Rd objects in a package for files with example fields
#'
#' @param rddb a simple database of Rd object obtained via tools::Rd_db
#'
#' @return a vector of Rd file names that have example fields
#' @keywords internal
filter_rd_db <- function(rddb) {
  n <- names(rddb)
  examples <- lapply(n, function(i) {
    rd <- rddb[[i]]
    a <- gsub("\\}", "",
              gsub("\\\\(examples|example|usage)\\{", "",
                   rd[grep("^\\\\(examples|example|usage)", rd)]
              )
    )
    man_name <- i
    man_name <- rep(man_name, length(a))
    names(man_name) <- a
    return(man_name)
  })
  # !duplicated because unique removes names
  e <- unlist(examples)[!duplicated(unlist(examples))]
  e
}

#' Build logical vector for Rd objects with example or usage fields discovered in a given package
#'
#' @param pkg a package name expected to contain exported objects
#'
#' @return a numeric proportion of documentation files with examples
#' @keywords internal
examples_from_pkg <- function(pkg) {
  f <- tools::Rd_db(package = pkg)

  # omit whole package rd
  f <- f[!names(f) %in% c(paste0(pkg, "-package.Rd"), paste0(pkg,".Rd"))]

  rd_all <- names(f)
  e <- filter_rd_db(f)
  rd_all %in% e
}

#' Build logical vector for Rd objects with example or usage fields discovered in a given directory
#'
#' @param path a package directory path expected to contain exported objects
#'
#' @return a numeric proportion of documentation files with examples
#' @keywords internal
examples_from_dir <- function(path, pkg) {
  f <- tools::Rd_db(dir = path)

  # omit whole package rd
  f <- f[!names(f) %in% c(paste0(pkg, "-package.Rd"), paste0(pkg,".Rd"))]

  rd_all <- names(f)
  e <- filter_rd_db(f)
  rd_all %in% e
}


================================================
FILE: R/pkg_ref_cache_expr_coverage.R
================================================
#' Retrieve output of covr::package_coverage, tallied by expression
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.expression_coverage <- function(x, ...) {
  UseMethod("pkg_ref_cache.expr_coverage")
}

#' Retrieve output of covr::package_coverage, tallied by expression
#'
#' @importFrom covr tally_coverage
#' @return a \code{pkg_ref} object
#' @keywords internal
pkg_ref_cache.expression_coverage.pkg_source <- function(x, ...) {
  covr::tally_coverage(x$covr_coverage, by = "expression")
}


================================================
FILE: R/pkg_ref_cache_help.R
================================================
#' Cache a list of available help files as LaTeX objects
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.help <- function(x, name, ...) {
  UseMethod("pkg_ref_cache.help")
}


#' Cache a list of available help files as LaTeX objects
#'
#' @importFrom tools Rd_db parseLatex
#' @return a \code{pkg_ref} object
#' @keywords internal
pkg_ref_cache.help.pkg_install <- function(x, name, ...) {
  tools::Rd_db(package = x$name)
}


#' Cache a list of available help files as LaTeX objects
#'
#' @importFrom tools Rd_db parseLatex
#' @keywords internal
pkg_ref_cache.help.pkg_source <- function(x, name, ...) {
  tools::Rd_db(dir = x$path)
}


================================================
FILE: R/pkg_ref_cache_help_aliases.R
================================================
#' Cache a character vector mapping exported values to documentation filenames
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.help_aliases <- function(x, name, ...) {
  UseMethod("pkg_ref_cache.help_aliases")
}



pkg_ref_cache.help_aliases.pkg_install <- function(x, name, ...) {
  readRDS(file.path(x$path, "help", "aliases.rds"))
}

pkg_ref_cache.help_aliases.pkg_source <- function (x, name, ...) {
  f <- list.files(file.path(x$path, "man"), full.names = TRUE)
  f <- f[grep("\\.Rd$", f)]
  aliases <- lapply(f, function(i) {
                      rd <- readLines(i)
                      a <- gsub("\\}", "", gsub("\\\\alias\\{", "",
                                                rd [grep("^\\\\alias", rd)]))
                      man_name <- strsplit (strsplit (i, "\\/man\\/") [[1]] [2],
                                            "\\.Rd") [[1]]
                      man_name <- rep (man_name, length (a))
                      names (man_name) <- a
                      return (man_name)    })
  # !duplicated because unique removes names
  unlist(aliases)
}


================================================
FILE: R/pkg_ref_cache_license.R
================================================
#' Get the package license
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.license <- function(x, ...) {
  UseMethod("pkg_ref_cache.license")
}



pkg_ref_cache.license.default <- function(x, ...) {
  if ("License" %in% colnames(x$description)) unname(x$description[,"License"])
  else NA_character_
}



#' @importFrom xml2 xml_find_all xml_text
#' @keywords internal
pkg_ref_cache.license.pkg_cran_remote <- function(x, ...) {
  license_xpath <- "//td[.='License:']/following::td[1]"
  license_nodes <- xml_find_all(x$web_html, xpath = license_xpath)
  xml_text(license_nodes)
}



#' @importFrom xml2 xml_find_all xml_text
#' @keywords internal
pkg_ref_cache.license.pkg_bioc_remote <- function(x, ...) {
  license_xpath <- "//td[.='License']/following::td[1]"
  license_nodes <- xml_find_all(x$web_html, xpath = license_xpath)
  xml_text(license_nodes)
}


================================================
FILE: R/pkg_ref_cache_maintainer.R
================================================
#' Cache package's Maintainer
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.maintainer <- function(x, name, ...) {
  UseMethod("pkg_ref_cache.maintainer")
}



pkg_ref_cache.maintainer.pkg_remote <- function(x, name, ...) {
  maintainer_xpath <- "//td[.='Maintainer:']/following::td[1]"
  maintainer <- xml2::xml_text(xml2::xml_find_all(x$web_html, maintainer_xpath))
  maintainer
}



pkg_ref_cache.maintainer.pkg_install <- function(x, name, ...) {
  if ("Maintainer" %in% colnames(x$description))
    return(x$description[,"Maintainer"])

  a   <- if ("Author" %in% colnames(x$description)) x$description[,"Author"] else NA
  a_r <- if ("Authors@R" %in% colnames(x$description)) x$description[,"Authors@R"] else NA

  if (!is.na(a_r)) {
    a_r_exp <- parse(text = a_r)
    if (all(all.names(a_r_exp, unique = TRUE) %in% c("c", "person"))) {
      return(grep("cre", eval(a_r_exp), value = TRUE))
    }
  } else if (!is.na(a)) {
    return(trimws(strsplit(a, ","))[[1]])
  }

  NA
}



pkg_ref_cache.maintainer.pkg_source <- pkg_ref_cache.maintainer.pkg_install


================================================
FILE: R/pkg_ref_cache_news.R
================================================
#' Cache a list of NEWS files from a package reference
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.news <- function(x, name, ...) {
  UseMethod("pkg_ref_cache.news")
}


#' Cache a list of NEWS files from a package reference
#'
#' @importFrom httr content GET
#' @return a \code{pkg_ref} object
#' @keywords internal
pkg_ref_cache.news.pkg_remote <- function(x, name, ...) {
  # default encoding messages suppressed
  suppressMatchingConditions(
    lapply(x$news_urls, function(news_url) {
      response <- httr::GET(news_url)
      httr::content(
        response,
        type = response$headers$`content-type` %||% "text/html")
    }),
    messages = "default")
}



pkg_ref_cache.news.pkg_install <- function(x, name, ...) {
  news_from_dir(system.file(package = x$name))
}



pkg_ref_cache.news.pkg_source <- function(x, name, ...) {
  news_from_dir(x$path)
}



#' Build a list of NEWS files discovered within a given directory
#'
#' @param path a package directory path expected to contain NEWS files
#'
#' @return a list of parsed NEWS files
#' @keywords internal
news_from_dir <- function(path) {
  # accommodate news.Rd, news.md, etc
  files <- list.files(path, pattern = "^NEWS($|\\.)", full.names = TRUE)
  if (!length(files)) return(list())

  content <- rep(list(NULL), length(files))
  names(content) <- files
  valid <- vector(length(files), mode = "logical")

  # attempt to parse all news.* files
  for (i in seq_along(files)) {
    f <- files[[i]]
    ext <- tools::file_ext(f)
    tryCatch({
      if (tolower(tools::file_ext(f)) == "rd") {
        content[[i]] <- .tools()$.news_reader_default(f)
      } else if (tolower(ext) == "md" || nchar(ext) == 0L) {
        # NOTE: should we do validation of markdown format?
        content[[i]] <- readLines(f, warn = FALSE)
      }
      valid[[i]] <- TRUE
    }, error = function(e) {
      valid[[i]] <- FALSE
    })
  }

  # NOTE: should we test whether news file is up-to-date with latest version?
  content[valid]
}


================================================
FILE: R/pkg_ref_cache_r_cmd_check.R
================================================
#' Run R CMD check and capture the results
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.r_cmd_check <- function(x, ...) {
  UseMethod("pkg_ref_cache.r_cmd_check")
}

pkg_ref_cache.r_cmd_check.default <- function (x, ...) {
  return(NA)
}

#' Run R CMD check and capture the results
#'
#' @inheritParams pkg_ref_cache
#' @importFrom devtools check
#' @return a \code{pkg_ref} object
#' @noRd
pkg_ref_cache.r_cmd_check.pkg_source <- function(x, ...){
  check_results <- devtools::check(x$path, quiet=TRUE)
  return(check_results)
}


================================================
FILE: R/pkg_ref_cache_release_date.R
================================================
#' Cache a List of Package Release Date from a Package Reference
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.release_date <- function(x, name, ...) {
  UseMethod("pkg_ref_cache.release_date")
}


pkg_ref_cache.release_date.pkg_remote <- function(x, name, ...) {
  release_xpath <- "//td[.='Published:']/following::td[1]"
  date <- xml2::xml_text(xml2::xml_find_all(x$web_html, release_xpath))
  date
}


pkg_ref_cache.release_date.pkg_install <- function(x, name, ...) {

  if (!"Date" %in% colnames(x$description)) return(NA)
  x$description[, "Date"]
}



pkg_ref_cache.release_date.pkg_source <- pkg_ref_cache.release_date.pkg_install


================================================
FILE: R/pkg_ref_cache_remote_checks.R
================================================
#' Retrieve a CRAN or Bioc checks or run R CMD check
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.remote_checks <- function (x, ...) {
   UseMethod("pkg_ref_cache.remote_checks")
}

pkg_ref_cache.remote_checks.default <- function (x, ...) {
  return(NA)
}

#' @importFrom httr content GET
#' @importFrom xml2 xml_find_all xml_text
pkg_ref_cache.remote_checks.pkg_cran_remote <- function(x, ...) {
  webURL <- sprintf("%s/web/checks/check_results_%s.html", x$repo_base_url, x$name)
  page <- httr::content(httr::GET(webURL))
  tables <- xml2::xml_find_all(page, ".//table")
  table_cran <- xml2::xml_find_all(tables[[1]], "//tr")
  fields <- lapply(table_cran, xml2::xml_find_all, ".//td|.//th")
  fields <- lapply(fields, xml2::xml_text, trim = TRUE)
  rst <- as.data.frame(do.call(rbind, fields[-1]))
  colnames(rst) <- fields[[1]]
  return(rst)
}

#' @importFrom httr content GET
#' @importFrom xml2 xml_find_all xml_text
pkg_ref_cache.remote_checks.pkg_bioc_remote <- function(x, ...) {
  webURL <- sprintf("%s/%s", x$repo_base_url, x$name)

  # TODO:
  # refine x$repo_base_url for BioConductor packages so that we don't need to do
  # nasty substitutions like this
  webURL <- sub("packages/release/bioc[^/]*", "checkResults/release/bioc-LATEST", webURL)

  page <- httr::content(httr::GET(webURL))
  tables <- xml2::xml_find_all(page, ".//table")
  rows <- xml2::xml_find_all(tables[[3]], "//tr")
  rows <- rows[grepl("odd", xml2::xml_attr(rows, "class"))]
  fields <- lapply(rows, xml2::xml_find_all, ".//td|.//th")
  fields <- lapply(fields, function(x) x[grepl("node|status", xml2::xml_attr(x, "class"))])
  text <- lapply(fields, xml2::xml_text, trim = TRUE)
  rst <- as.data.frame(do.call(rbind, text))
  colnames(rst) <- sapply(xml2::xml_find_all(rows[[1]], ".//td"), xml2::xml_text, trim = TRUE)[-1]
  return(rst)
}


================================================
FILE: R/pkg_ref_cache_repo_base_url.R
================================================
#' Cache value of a package's source repo's URL
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.repo_base_url <- function(x, name, ...) {
  UseMethod("pkg_ref_cache.repo_base_url")
}



pkg_ref_cache.repo_base_url.pkg_remote <- function(x, name, ...) {
  gsub("/src/contrib$", "", x$repo)
}


================================================
FILE: R/pkg_ref_cache_source_control_url.R
================================================
#' Cache package's Source Control URL
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.source_control_url <- function(x, name, ...) {
  grep(
    "(github\\.com|bitbucket\\.org|gitlab\\.com)",
    x$website_urls,
    value = TRUE)
}


================================================
FILE: R/pkg_ref_cache_tarball_url.R
================================================
#' Cache value of a package's source tarball URL
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.tarball_url <- function(x, name, ...) {
  UseMethod("pkg_ref_cache.tarball_url")
}



pkg_ref_cache.tarball_url.pkg_remote <- function(x, name, ...) {
  sprintf("%s/%s_%s.tar.gz", x$repo, x$name, x$version)
}


================================================
FILE: R/pkg_ref_cache_vignettes.R
================================================
#' Cache a List of Vignettes Files from a Package Reference
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.vignettes <- function(x, name, ...) {
  UseMethod("pkg_ref_cache.vignettes")
}



pkg_ref_cache.vignettes.pkg_remote <- function(x, name, ...) {
  vignettes_from_html(x)
}


pkg_ref_cache.vignettes.pkg_install <- function(x, name, ...) {
  vignettes_from_dir(system.file(package = x$name))
}



pkg_ref_cache.vignettes.pkg_source <- function(x, name, ...) {
  vignettes_from_dir(x$path)
}



#' Build a List of Vignettes Files Discovered Within a Given Directory
#'
#' @param path a package directory path expected to contain Vignettes files
#'
#' @return a vector of parsed Vignettes files
#' @keywords internal
vignettes_from_dir <- function(path) {
  folder <- c(source = "/vignettes", bundle = "/inst/doc", binary = "/doc")
  files <- unlist(lapply(paste0(path, folder), list.files, full.names = TRUE))

  if (!length(files)) return(data.frame())

  file_path = unique(tools::file_path_sans_ext(files))
  filename = basename(file_path)
  names(file_path) <- filename

  file_path[tolower(filename) != tolower("index")]
}



#' Build a List of Vignettes Files Discovered Within a Package Website
#'
#' @param x a \code{pkg_ref} object
#'
#' @return a vector of Vignettes files
#'
#' @importFrom xml2 xml_attrs
#' @importFrom tools file_path_sans_ext
#' @keywords internal
vignettes_from_html <- function(x) {
  nodes <- xml2::xml_find_all(x$web_html, xpath = '//a[contains(@href,"vignettes")]')

  if (!length(nodes)) return(c())

  file_path <- unlist(xml2::xml_attrs(nodes, "href"))
  filename <- tools::file_path_sans_ext(basename(file_path))
  file_path <- sprintf("%s/%s", x$web_url, file_path)
  names(file_path) <- filename

  file_path
}


================================================
FILE: R/pkg_ref_cache_web_html.R
================================================
#' Cache package's remote display page HTML
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.web_html <- function(x, name, ...) {
  UseMethod("pkg_ref_cache.web_html")
}



#' @importFrom httr content GET
pkg_ref_cache.web_html.pkg_remote <- function(x, name, ...) {
  # suppress messages when httr assumes a default content parameters
  suppressMatchingConditions(
    httr::content(httr::GET(x$web_url)),
    messages = "default")
}


================================================
FILE: R/pkg_ref_cache_web_url.R
================================================
#' Cache package's remote web URL
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.web_url <- function(x, name, ...) {
  UseMethod("pkg_ref_cache.web_url")
}



pkg_ref_cache.web_url.pkg_cran_remote <- function(x, name, ...) {
  sprintf("%s/web/packages/%s", x$repo_base_url, x$name)
}



pkg_ref_cache.web_url.pkg_bioc_remote <- function(x, name, ...) {
  sprintf("%s/html/%s.html", x$repo_base_url, x$name)
}


================================================
FILE: R/pkg_ref_cache_website_urls.R
================================================
#' Cache package's Website URL
#'
#' @inheritParams pkg_ref_cache
#' @family package reference cache
#' @return a \code{pkg_ref} object
#' @keywords internal
#' @noRd
pkg_ref_cache.website_urls <- function(x, name, ...) {
  UseMethod("pkg_ref_cache.website_urls")
}



pkg_ref_cache.website_urls.pkg_remote <- function(x, name, ...) {
  url_xpath <- "//td[.='URL:']/following::td[1]/a"
  url  <- xml2::xml_text(xml2::xml_find_all(x$web_html, url_xpath))
  if(length(url) == 0) return(character(0L))
  url
}



pkg_ref_cache.website_urls.default <- function(x, name, ...) {
  if (!"URL" %in% colnames(x$description)) return(character(0L))
  trimws(strsplit(x$description[,"URL"], ",")[[1]])
}


================================================
FILE: R/pkg_ref_class.R
================================================
#' Create a package reference
#'
#' Create a package reference from package name or filepath, producing an object
#' in which package metadata will be collected as risk assessments are
#' performed. Depending on where the package was found - whether it is found as
#' source code, in a local library or from a remote host - an S3 subclass is
#' given to allow for source-specific collection of metadata. See 'Details' for
#' a breakdown of subclasses. Different sources can be specified by passing a
#' subclass as an arguemnt named 'source', see details.
#'
#' Package reference objects are used to collect metadata pertaining to a given
#' package. As data is needed for assessing a package's risk, this metadata
#' populates fields within the package reference object.
#'
#' The \code{pkg_ref} S3 subclasses are used extensively for divergent metadata
#' collection behaviors dependent on where the package was discovered. Because
#' of this, there is a rich hierarchy of subclasses to articulate the different
#' ways package information can be found.
#'
#' A source argument can be passed using the `source` argument. This will
#' override the logic that riskmetric does when determining a package source.
#' This can be useful when you are scoring the most recent version present on a
#' repository, or testing a specific library.
#'
#' \describe{
#'   \item{\strong{\code{pkg_ref}}}{ A default class for general metadata
#'     collection.}
#'   \item{\strong{\code{pkg_source}}}{ A reference to a source code
#'     directory.}
#'   \item{\strong{\code{pkg_install}}}{ A reference to a package installation
#'     location in a package library. A specific library can be passed by
#'     passing the path to the library as the parameter `lib.loc`}
#'   \item{\strong{\code{pkg_remote}}}{ A reference to package metadata on a
#'     remote server.
#'     \describe{
#'       \item{\strong{\code{pkg_cran_remote}}}{ A reference to package
#'       information pulled from the CRAN repository.}
#'       \item{\strong{\code{pkg_bioc_remote}}}{ A reference to package
#'       information pulled from the Bioconductor repository.}
#'       \item{\strong{\code{pkg_git_remote}}}{ A reference to a package source
#'       code git repository. (not yet implemented)}
#'     }
#'   }
#' }
#'
#' @section Package Cohorts:
#'
#' *Experimental!*
#' Package cohorts are structures to determine the risk of a set of packages.
#' `pkg_library()` can be called to create a object containing the pkg_ref
#' objects of all packages in a system library.
#'
#'
#' @rdname pkg_ref
#' @export
#'
#' @examples
#' \dontrun{
#' # riskmetric will check for installed packages by default
#' ref_1 <- pkg_ref("utils")
#' ref_1$source # returns 'pkg_install'
#'
#' # lib.loc can be used to specify a library for pkg_install
#' ref_3 <- pkg_ref("utils", source = "pkg_install", lib.loc = .libPaths()[1])
#'
#' # You can also override this behavior with a source argument
#' ref_2 <- pkg_ref("utils", source = "pkg_cran_remote")
#' ref_2$source  # returns 'pkg_cran_remote'
#' }
pkg_ref <- function(x, ...) {
  if (missing(x)) {
    return(structure(logical(0L), class = "pkg_ref"))
  }
  as_pkg_ref(x, ...)
}


#' @importFrom vctrs new_vctr
#' @keywords internal
new_pkg_ref <- function(name, version = NA_character_, source, ...) {
  dots <- list(...)
  if (length(dots) && is.null(names(dots)) || any(names(dots) == "")) {
    stop("pkg_ref ellipses arguments must be named")
  }

  source <- match.arg(
    source,
    c(
      "pkg_git_remote",
      "pkg_bioc_remote",
      "pkg_cran_remote",
      "pkg_remote",
      "pkg_install",
      "pkg_source",
      "pkg_missing"
    ),
    several.ok = TRUE
  )

  source <- get_pkg_ref_classes(source)

  pkg_data <- as.environment(append(
    list(
      name = name,
      version = version,
      source = source[[1L]]
    ),
    dots
  ))

  structure(
    pkg_data,
    class = c(source, class(pkg_data))
  )
}


#' The `pkg_ref` subclass hierarchy, used for pkg_ref object creation with a
#' specified subclass
#'
pkg_ref_class_hierarchy <- list(
  "pkg_ref" = list(
    "pkg_missing",
    "pkg_source",
    "pkg_install",
    "pkg_remote" = list(
      "pkg_cran_remote",
      "pkg_bioc_remote",
      "pkg_git_remote"
    )
  )
)


#' Walk the pkg_ref class hierarchy to match a single subclass to a class path
#'
#' @param x (`character(1L)`) A subclass, among those known in pkg_ref subclasses
#' @param classes (`list`) A class hierarchy, described using a named list.
#'   Defaults to `pkg_ref_class_hierarchy`.
#'
#' @return A `character(n)` class path from `pkg_ref` down to the specified
#'   subclass, or `FALSE` if no path is found.
#' @keywords internal
#'
get_pkg_ref_classes <- function(x, classes = pkg_ref_class_hierarchy) {
  if (x %in% names(classes) || x %in% classes) {
    return(x)
  }

  if (!is.list(classes)) {
    return(FALSE)
  }

  for (i in seq_along(classes)) {
    subclasses <- get_pkg_ref_classes(x, classes[[i]])
    if (is.character(subclasses)) return(c(subclasses, names(classes[i])))
  }

  FALSE
}


#' @rdname pkg_ref
#'
#' @param lib.loc The path to the R library directory of the installed package.
pkg_install <- function(x, lib.loc = NULL) {
  if (verify_pkg_source(x, "pkg_install") == "pkg_missing") {
    return(pkg_missing(x))
  }

  path <- find.package(x, lib.loc = lib.loc)
  version <- utils::packageVersion(x, lib.loc = dirname(path))

  new_pkg_ref(x, version = version, path = path, source = "pkg_install")
}

#' @rdname pkg_ref
pkg_source <- function(x) {
  desc <- read.dcf(file.path(x, "DESCRIPTION"))
  name <- unname(desc[, "Package"])

  new_pkg_ref(
    name,
    version = desc[, "Version"][[1]],
    path = normalizePath(x),
    source = "pkg_source"
  )
}

#' @rdname pkg_ref
#'
#' @param repos URL of CRAN repository to pull package metadata.
pkg_cran <- function(
  x,
  repos = getOption("repos", "https://cran.rstudio.com")
) {
  ap <- memoise_available_packages(repos = repos)
  info <- ap[ap[, "Package"] == x, , drop = FALSE]

  new_pkg_ref(
    x,
    version = info[, "Version"],
    repo = info[, "Repository"],
    source = c("pkg_cran_remote")
  )
}

#' @rdname pkg_ref
pkg_bioc <- function(x) {
  bp <- memoise_bioc_available()
  info <- bp[bp[, "Package"] == x, , drop = FALSE]

  new_pkg_ref(
    x,
    version = info[, "Version"],
    repo = "https://bioconductor.org/packages/release/bioc",
    source = c("pkg_bioc_remote")
  )
}

#' @rdname pkg_ref
pkg_missing <- function(x) {
  new_pkg_ref(x, source = c("pkg_missing"))
}

#' @rdname pkg_ref
pkg_library <- function(lib.loc) {
  # Create pkg_cohort object
  cohort <- pkg_cohort()
  for (pkg in list.files(lib.loc, recursive = FALSE, full.names = FALSE)) {
    cohort[[length(cohort) + 1]] <- pkg_install(pkg, lib.loc = lib.loc)
  }
  cohort
}

#' Convert into a package object
#'
#' @param x A singular \code{character} value, \code{character vector} or
#'   \code{list} of \code{character} values of package names or source code
#'   directory paths.
#' @param ... Additional arguments passed to methods.
#'
#' @return When a single value is provided, a single \code{pkg_ref} object is
#'   returned, possibly with a subclass based on where the package was found. If
#'   a \code{vector} or \code{list} is provided, a \code{list_of_pkg_ref} object
#'   constructed with \code{\link[vctrs]{list_of}} is returned, which can be
#'   considered analogous to a \code{list}. See 'Details' for further
#'   information about \code{pkg_ref} subclasses.
#'
#' @rdname pkg_ref
#'
#' @importFrom vctrs new_list_of
#' @export
as_pkg_ref <- function(x, ...) {
  if ((is.list(x) || is.atomic(x)) && length(x) > 1) {
    dots <- list(...)

    # iterate over the list of packages and add sources and versions
    pkg_ref_list <- list()
    for (i in seq_along(x)) {
      if (!is.null(dots$source)) {
        source <- ifelse(length(dots$source) > 1, dots$source[i], dots$source)
      } else {
        source <- NULL
      }

      pkg_ref_list[[i]] <- as_pkg_ref(x[[i]], source = source)
    }

    return(vctrs::new_list_of(
      pkg_ref_list,
      ptype = list(),
      class = "list_of_pkg_ref"
    ))
  } else {
    UseMethod("as_pkg_ref")
  }
}


#' @export
as_pkg_ref.default <- function(x, ...) {
  stop(sprintf(
    "Don't know how to convert object class '%s' to class 'pkg_ref'",
    paste(class(x), collapse = ", ")
  ))
}


#' @export
as_pkg_ref.pkg_ref <- function(x, ...) {
  x
}


#' @importFrom utils available.packages packageVersion
#' @export
as_pkg_ref.character <- function(
  x,
  repos = getOption("repos", "https://cran.rstudio.com"),
  source = NULL,
  lib.loc = NULL,
  ...
) {
  dots <- list(...)

  pkg_source_ <- ifelse(
    is.null(source),
    determine_pkg_source(x, source, repos),
    verify_pkg_source(x, source, repos)
  )

  stopifnot(
    pkg_source_ %in%
      c(
        "pkg_install",
        "pkg_source",
        "pkg_cran_remote",
        "pkg_bioc_remote",
        "pkg_missing"
      )
  )

  switch(
    pkg_source_,
    pkg_install = pkg_install(x, lib.loc = lib.loc),
    pkg_source = pkg_source(x),
    pkg_cran_remote = pkg_cran(x, repos = repos),
    pkg_bioc_remote = pkg_bioc(x),
    pkg_missing = pkg_missing(x)
  )
}

#' Determine the intended source of a new package
#'
#' @param x Package name or path to package
#' @param source type of source passed in `pkg_ref`
#' @return one of c('pkg_source', 'pkg_install', 'pkg_cran_remote',
#'   'pkg_bioc_remote', 'pkg_missing')
#' @keywords internal
determine_pkg_source <- function(x, source, repos) {
  if (dir.exists(x) && file.exists(file.path(x, "DESCRIPTION"))) {
    "pkg_source"

    # non-source package
  } else if (grepl("^[[:alpha:]][[:alnum:].]*[[:alnum:]]$", x)) {
    if (length(find.package(x, quiet = TRUE)) != 0) {
      return("pkg_install")

      # if its not installed, pull the package to check it
    } else {
      ap <- memoise_available_packages(repos = repos)
      info <- ap[ap[, "Package"] == x, , drop = FALSE]

      p <- new_pkg_ref(
        x,
        version = info[, "Version"],
        repo = info[, "Repository"],
        source = c("pkg_remote")
      )
    }

    if (is_available_cran(x, repos, p)) {
      "pkg_cran_remote"
    } else if (is_available_bioc(x, p)) {
      "pkg_bioc_remote"
    } else {
      "pkg_missing"
    }
  } else {
    stop(sprintf("can't interpret character '%s' as a package reference", x))
  }
}

#' Verify a pkg_source when one is manually specified by the user
#' @return a string of package source
#' @keywords internal
verify_pkg_source <- function(x, source, repos) {
  switch(
    source,
    pkg_install = "pkg_install",
    pkg_source = {
      # check source pakcage is present if source is "pkg_source"
      if (source == "pkg_source" && !dir.exists(x)) {
        warning(paste0(c(
          "Package source: `",
          x,
          "` does not exist, source is now 'pkg_missing'"
        )))
        return("pkg_missing")
      }
    },
    pkg_cran_remote = {
      ap <- memoise_available_packages(repos = repos)
      info <- ap[ap[, "Package"] == x, , drop = FALSE]
      p <- new_pkg_ref(
        x,
        version = info[, "Version"],
        repo = info[, "Repository"],
        source = c("pkg_remote")
      )
      if (!is_available_cran(x, repos, p)) {
        warning(paste0(c(
          "Package: `",
          x,
          "` not found on CRAN, source is now 'pkg_missing'"
        )))
        return("pkg_missing")
      }
    },
    pkg_bioc_remote = {
      ap <- memoise_available_packages(repos = repos)
      info <- ap[ap[, "Package"] == x, , drop = FALSE]
      p <- new_pkg_ref(
        x,
        version = info[, "Version"],
        repo = info[, "Repository"],
        source = c("pkg_remote")
      )
      if (!is_available_bioc(x, p)) {
        warning(paste0(c(
          "Package: `",
          x,
          "` not found on bioconductor, source is now 'pkg_missing'"
        )))
        return("pkg_missing")
      }
    },
    source
  )

  source
}


================================================
FILE: R/pkg_ref_class_coersion.R
================================================
#' @importFrom tibble as_tibble
#' @method as_tibble pkg_ref
#' @export
as_tibble.pkg_ref <- function(x, ...) {
  as_tibble(vctrs::new_list_of(list(x),
    ptype = list(),
    class = "list_of_pkg_ref"))
}



#' @importFrom tibble tibble
#' @method as_tibble list_of_pkg_ref
#' @export
as_tibble.list_of_pkg_ref <- function(x, ...) {
  package_names <- vapply(x, "[[", character(1L), "name")
  versions <- vapply(x, function(xi) as.character(xi$version), character(1L))

  tibble::tibble(
    package = package_names,
    version = versions,
    pkg_ref = x)
}


================================================
FILE: R/pkg_ref_class_extract.R
================================================
#' @export
`$.pkg_ref` <- function(x, name) {
  `[[`(x, as.character(name))
}



#' @export
`$<-.pkg_ref` <- function(x, name, value) {
  `[[<-`(x, as.character(name), value = value)
}



#' Lazily instantiated, immutable metadata access
#'
#' If errors are thrown upon instantiation, they are saved and rethrown any time
#' the value is attempted to be accessed. These then propegate through
#' assessment and scoring functions to affect any downstream metrics.
#'
#' @param x pkg_ref object to extract metadata from
#' @param name name of metadata field to extract
#' @param ... additional arguments used to extract from internal environment
#'
#' @return a pkg_ref object
#' @export
#' @keywords internal
`[[.pkg_ref` <- function(x, name, ...) {
  if (!name %in% bare_env(x, names(x))) {
    allow_mutation(x, {
      pkg_ref_cache(x, name)
      ret <- tryCatch(pkg_ref_cache(x, name), error = function(e) e)
      x[[name]] <- ret
      if (inherits(ret, "error")) stop(ret)
      ret
    })
  } else {
    bare_env(x, {
      ret <- x[[name, ...]]
      if (inherits(ret, "error")) stop(ret)
      ret
    })
  }
}



#' @export
`[[<-.pkg_ref` <- function(x, name, value) {
  if (is.null(attr(x, "allowed_mutations")))
    stop(pkg_ref_mutability_error(name))
  bare_env(x, x[[name]] <- value)
}



#' @export
`[.pkg_ref` <- function(x, names, ...) {
  lapply(names, function(n, ...) x[[n, ...]], ...)
}



#' @export
`[<-.pkg_ref` <- function(x, names, value) {
  invisible(Map(function(name, value) {
    `[[<-`(x, name = name, value = value)
  }, names, value))
}



#' evaluate an expression with a  pkg_ref object reclassed as a bare environment
#' object, used to sidestep pkg_ref assignment guardrails
#'
#' @param x a \code{pkg_ref} object
#' @param expr an expression to evaluate, avoiding \code{pkg_ref} extraction
#'   handlers
#' @param envir an environment in which the expression is to be evaluated
#'
#' @return the result of \code{expr}
#' @keywords internal
bare_env <- function(x, expr, envir = parent.frame()) {
  old_class <- class(x)
  class(x) <- "environment"
  on.exit(class(x) <- old_class)
  eval(expr, envir = envir)
}



#' pretty printing for a pkg_ref mutability error caused by trying to do
#' assignment within the pkg_ref without permission
#'
#' @param name name of field for which mutation was attempted
#' @return a \code{simplError} with subclasses \code{pkg_ref_mutability_error},
#'   \code{pkg_ref_error}
#' @keywords internal
pkg_ref_mutability_error <- function(name) {
  message <- list(paste0(
    "Assignment to a pkg_ref environment can only be done in a ",
    "pkg_ref_cache call."))

  if (!missing(name)) message <- append(message, list(paste0(
    "Extend the pkg_ref class by implementing function '",
    "pkg_ref_cache.", name, "'")))

  e <- simpleError(message = paste(message, collapse = " "))
  class(e) <- c("pkg_ref_mutability_error", "pkg_ref_error", class(e))
  e
}



#' a wrapper to assert that a pkg_ref has been permitted to do an additional
#' mutation, used to handle recursive initialization of cached fields
#'
#' @param x a \code{pkg_ref} object
#' @param expr an expression to evaluate, and possible do a mutation within
#' @param envir an environment in which the expression is to be evaluated
#'
#' @return the result of \code{expr}
#' @keywords internal
allow_mutation <- function(x, expr, envir = parent.frame()) {
  inc_mutations_count(x)
  on.exit(dec_mutations_count(x))
  expr <- substitute(expr)
  eval(expr, envir = envir)
}



#' increment the number of allowed mutations
#'
#' @param x pkg_ref object to increment mutation counter for
#' @return a pkg_ref object
#' @keywords internal
inc_mutations_count <- function(x) {
  if (is.null(attr(x, "allowed_mutations"))) attr(x, "allowed_mutations") <- 0
  attr(x, "allowed_mutations") <- attr(x, "allowed_mutations") + 1
}



#' decrement the number of allowed mutations
#'
#' @param x pkg_ref object to decrement mutation counter for
#' @return pkg_ref object
#' @keywords internal
dec_mutations_count <- function(x) {
  attr(x, "allowed_mutations") <- attr(x, "allowed_mutations") - 1
  if (attr(x, "allowed_mutations") <= 0) attr(x, "allowed_mutations") <- NULL
}


================================================
FILE: R/pkg_ref_class_format.R
================================================
#' @importFrom utils head capture.output
#' @export
print.pkg_ref <- function(x, ...) {
  xx <- as.list(x)
  ns <- names(xx)
  ns_unused <- setdiff(available_pkg_ref_fields(x), ns)

  indent <- 2
  width <- 0.95 * getOption("width")

  xs <- vapply(xx, function(xi) {
    truncated <- FALSE
    if (length(xi) > 5) truncated <- TRUE

    if (inherits(xi, "riskmetric_disabled_behavior_error"))
      return(paste0(strrep(" ", indent), "<", xi$message, ">"))

    x_str <- utils::capture.output(head(xi))
    x_str <- gsub("\\s+$", "", x_str)
    x_str <- gsub(sprintf("(.{%0.f})", width - indent), "\\1\n", x_str)
    x_str <- unlist(strsplit(x_str, "\n"))
    if (length(x_str) > 5) truncated <- TRUE

    if (truncated) x_str <- c(head(x_str), "<continued>")
    paste0(strrep(" ", indent), x_str, collapse = "\n")
  }, character(1L))

  cat(
    "<", paste(class(x)[1:which("pkg_ref" == class(x))], collapse = ", "), "> ",
    x$name, " v", as.character(x$version), "\n",
    if (length(ns)) paste0("$", ns, "\n", xs, collapse = "\n"),
    if (length(ns)) "\n",
    if (length(ns_unused)) paste0("$", ns_unused, "...", collapse = "\n"),
    if (length(ns_unused)) "\n",
    sep = "")

  invisible(x)
}



#' @importFrom vctrs vec_ptype_abbr
#' @method vec_ptype_abbr pkg_ref
#' @export
vec_ptype_abbr.pkg_ref <- function(x, ...) {
  "pkg_ref"
}



#' @importFrom vctrs vec_cast.character
#' @method vec_cast.character list_of_pkg_ref
#' @export
vec_cast.character.list_of_pkg_ref <- function(x, to, ...) {
  vapply(x, "[[", character(1L), "name")
}



#' @export
format.pkg_ref <- function(x, ...) {
  class_str <- gsub("^pkg_", "", class(x)[[1]])
  paste0(x$name, pillar::style_subtle(paste0("<", class_str, ">")))
}



#' @export
format.pkg_missing <- function(x, ...) {
  class_str <- gsub("^pkg_", "", class(x)[[1]])
  pillar::style_na(paste0(x$name, "<", class_str, ">"))
}


================================================
FILE: R/pkg_ref_class_names.R
================================================
#' @importFrom utils .DollarNames
#' @export
`.DollarNames.pkg_ref` <- function(x, pattern) {
  names(x)
}



#' @export
names.pkg_ref <- function(x, ...) {
  c(unname(available_pkg_ref_fields(x)), bare_env(x, names(x)))
}


================================================
FILE: R/pkg_score.R
================================================
#' Score a package assessment, collapsing results into a single numeric
#'
#' pkg_score() calculates the risk involved with using a package. Risk ranges
#' from 0 (low-risk) to 1 (high-risk).
#'
#' @param x A \code{pkg_metric} object, whose subclass is used to choose the
#'   appropriate scoring method for the atomic metric metadata. Optionally, a
#'   \code{\link[tibble]{tibble}} can be provided, in which cases all
#'   \code{pkg_metric} values will be scored.
#' @param ... Additional arguments passed to \code{summarize_scores} when an
#'   object of class \code{tbl_df} is provided, unused otherwise.
#' @param error_handler Specify a function to be called if the class can't be
#'   identified. Most commonly this occurs for \code{pkg_metric} objects of
#'   subclass \code{pkg_metric_error}, which is produced when an error is
#'   encountered when calculating an associated assessment.
#'
#' @return A numeric value if a single \code{pkg_metric} is provided, or a
#'   \code{\link[tibble]{tibble}} with \code{pkg_metric} objects scored and
#'   returned as numeric values when a \code{\link[tibble]{tibble}} is provided.
#'
#' @examples
#' \dontrun{
#'
#' # scoring a single assessment
#' metric_score(assess_has_news(pkg_ref("riskmetric")))
#'
#' # scoring many assessments as a tibble
#' library(dplyr)
#' pkg_score(pkg_assess(as_tibble(pkg_ref(c("riskmetric", "riskmetric")))))
#'
#' }
#'
#' @seealso score_error_default score_error_zero score_error_NA
#'
#' @export
pkg_score <- function(x, ..., error_handler = score_error_default) {
  UseMethod("pkg_score")
}



#' @export
pkg_score.tbl_df <- function(x, ..., error_handler = score_error_default) {
  assessment_columns <- get_assessment_columns(x)
  for (coln in which(assessment_columns)) {
    metric_score_s3_fun <- firstS3method("metric_score", class(x[[coln]][[1]]))

    x[[coln]] <- vapply(x[[coln]],
      metric_score,
      numeric(1L),
      error_handler = error_handler)

    attr(x[[coln]], "label") <- attr(metric_score_s3_fun, "label")
    class(x[[coln]]) <- c("pkg_score", class(x[[coln]]))
  }

  ignore_cols <- c("package", "version", "pkg_ref")
  x[["pkg_score"]] <- summarize_scores(x[, !names(x) %in% ignore_cols], ...)

  # reorder columns so that metadata columns come first
  pkg_cols <- intersect(names(x), c("package", "version", "pkg_ref", "pkg_score"))
  x <- x[, c(pkg_cols, setdiff(names(x), pkg_cols))]

  x
}



#' @export
pkg_score.list_of_pkg_metric <- function(x, ...,
    error_handler = score_error_default) {

  lapply(x, function(xi) {
    s <- metric_score(xi, error_handler = error_handler)
    metric_score_s3_fun <- firstS3method("metric_score", class(xi))
    attr(s, "label") <- attr(metric_score_s3_fun, "label")
    class(s) <- c("pkg_score", class(s))
    s
  })
}



#' Helper for creating a roxygen header from template for score.* functions
#'
#' @param name the name of the scoring function, assuming naming conventions are
#'   followed
#' @param dontrun logical indicating whether examples should be wrapped in
#'   a dontrun block. This is particularly useful for assessments which may
#'   require an internet connection.
#'
#' @return roxygen section template for score family functions
#'
#' @examples
#' \dontrun{
#' #' @eval roxygen_score_family("has_news")
#' }
#' @keywords internal
roxygen_score_family <- function(name, dontrun = TRUE) {

  assess_func <- sprintf("assess_%s", name)
  score_func <- sprintf("metric_score.pkg_metric_%s", name)
  example_template <- if (dontrun) {
    "@examples \n\\dontrun{metric_score(%s(pkg_ref(\"%s\")))\n}"
  } else {
    "@examples metric_score(%s(pkg_ref(\"%s\")))"
  }

  if (!assess_func %in% getNamespaceExports(utils::packageName()))
    warning(sprintf(paste0("Error when generating documentation for %s. ",
      "Associated assessment function `%s` was not found in the `riskmetric` ",
      "package. Please provide one to complete documentation."),
      name, assess_func))

  if (!score_func %in% getNamespaceExports(utils::packageName()))
    warning(sprintf(paste0("Error when generating documentation for %s. ",
      "Associated scoring function `%s` was not found in the `riskmetric` ",
      "package. Please provide one to complete documentation."),
      name, score_func))

  c(sprintf("@param x a \\code{pkg_metric_%s} packge metric object", name),
    "@param ... additional arguments unused",
    sprintf(example_template, assess_func, packageName()))
}


================================================
FILE: R/riskmetric-package.R
================================================
#' riskmetric
#'
#' Facilities for assessing R packages against a number of metrics to help
#' quantify their robustness.
#'
#' @import tools
#'
#' @docType package
#' @name riskmetric
#' @keywords internal
"_PACKAGE"



# make check() happy
. <- NULL


================================================
FILE: R/summarize_scores.R
================================================
#' Summarize a default set of assessments into a single risk score
#'
#' This function serves as an example for how a risk score might be derived.
#' Assuming all assessments provided by \code{riskmetric} are available in a
#' dataset, this function can be used to calculate a vector of risks.
#'
#' @param data a \code{\link[tibble]{tibble}} of scored assessments whose column
#'   names match those provided by riskmetric's \code{\link{pkg_assess}} function.
#' @param weights an optional vector of non-negative weights to be assigned to
#'   each assessment.
#'
#' @return a numeric vector of risk scores
#'
#' @examples
#' \dontrun{
#' library(dplyr)
#' summarize_scores(pkg_score(pkg_assess(as_tibble(pkg_ref("riskmetric")))))
#'
#' library(dplyr)
#' pkg_ref("riskmetric") %>%
#'   pkg_assess() %>%
#'   pkg_score() %>%
#'   summarize_scores()
#' }
#'
#' @export
summarize_scores <- function(data, weights = NULL) {
  UseMethod("summarize_scores")
}

#' @export
summarize_scores.data.frame <- function(data, weights = NULL) {
  if (missing(weights))
    weights <- add_default_weights(data)

  # perform checks and standardize weights
  weights <- standardize_weights(data, weights)

  # calculate 'quality' and subtract from 1 to get 'risk'
  qual <- colSums(apply(data[names(weights)], 1L, `*`, weights), na.rm = TRUE)
  risk <- 1 - qual

  risk
}

#' @export
summarize_scores.list <- function(data, weights = NULL) {
  if (missing(weights))
    weights <- add_default_weights(data)

  # perform checks and standardize weights
  weights <- standardize_weights(data, weights)
  1 - sum(as.numeric(data[names(weights)]) * weights, na.rm = TRUE)
}

# Set the default weight of each metric to 1.
add_default_weights <- function(data) {

  # ignore columns that are not of class 'pkg_score'
  ignore_cols <- c("package", "version", "pkg_ref", "pkg_score")
  metrics <- names(data)[!(names(data) %in% ignore_cols)]

  # assign a weight of 1 to each metric
  weights <- rep(1, length(metrics))
  names(weights) <- metrics

  weights
}

# Check that the provided weights are numeric and non-negative.
check_weights <- function(weights) {
  if (!is.numeric(weights))
    stop("The weights must be a numeric vector.")

  if (!all(weights >= 0))
    stop("The weights must contain non-negative values only.")
}

# Check weights values and standardize them.
standardize_weights <- function(data, weights) {

  # check that the weights vector is numeric and non-negative
  check_weights(weights)

  # re-weight for fields that are in the dataset
  weights <- weights[which(names(weights) %in% names(data))]

  # standardize weights from 0 to 1
  weights <- weights / sum(weights, na.rm = TRUE)
}


================================================
FILE: R/utils.R
================================================
#' If not NULL else
#'
#' @param lhs Left-hand side
#' @param rhs Right-hand side
#'
#' A shorthand for a common comparison
#'
#' @name if_not_null_else
#' @return an object same as \code{lhs} or \code{rhs}
#' @keywords internal
`%||%` <- function(lhs, rhs) if (!length(lhs) || is.null(lhs)) rhs else lhs



#' Accessor for tools namespace
#'
#' used internally for
#'   - tools:::.news_reader_default
#' @return tools namespace
#' @keywords internal
.tools <- memoise::memoise(function() {
  getNamespace("tools")
})



#' check if a url originates from a list of repo urls
#'
#' @param url a url which may stem from one of the provided base urls
#' @param urls vector of base urls
#'
#' @return logical vector indicating which base urls have a sub url of
#'   \code{url}
#' @keywords internal
is_url_subpath_of <- function(url, urls) {
  grepl(paste0("(", paste0(gsub("/$", "", urls), collapse = "|"), ")"), url)
}



#' Evaluate an expression after first removing a range of S3 classes
#'
#' @param x a structured S3-classed object
#' @param .class the class to unclass the object to
#' @param expr an expression to evaluate, avoiding parent classs dispatch
#' @param envir an environment in which the expression is to be evaluated
#'
#' @return the result of \code{expr}
#' @keywords internal
with_unclassed_to <- function(x, .class = 1:length(class(x)), expr,
    envir = parent.frame()) {

  x_expr <- substitute(x)
  orig_class <- class(x)
  if (is.character(.class)) .class = 1:which(class(x) == .class)

  eval(bquote(class(.(x_expr)) <- class(.(x_expr))[-.(.class)]), envir = envir)
  out <- eval(expr, envir = envir)
  eval(bquote(class(.(x_expr)) <- .(orig_class)), envir = envir)
  out
}



#' Find the S3 method that will be evaluated when an S3 generic is called by
#' an object of class \code{classes}
#'
#' @inheritParams utils::getS3method
#' @param classes a character vector of classes used to search for the
#' appropriate S3 method
#'
#' @importFrom utils getS3method
#' @return a S3 method
#' @keywords internal
firstS3method <- function(f, classes, envir = parent.frame()) {
  s3methods <- lapply(
    classes,
    utils::getS3method,
    f = f,
    envir = envir,
    optional = TRUE)

  # [1][[1]] hacky way of getting first elem while coercing empty list to NULL
  Filter(Negate(is.null), s3methods)[1][[1]]
}



#' Capture side effects issued by an evaluated expression
#'
#' All messaging condition side effects are captured in the order that they
#' are issued.
#'
#' @param expr an expression to evaluate, capturing output events as they
#'   are issued
#' @param env the environment in which \code{expr} should be evaluated,
#'   defaulting to the calling environment.
#' @param quoted whether \code{expr} is a quoted object and should be evaluated
#'   as is, or whether the expression should be captured from the function call.
#'   Defaults to \code{FALSE}, capturing the passed expression.
#' @inheritParams base::sink
#'
#'
#' @importFrom utils head tail
#' @return an with_eval_recording object
#' @keywords internal
capture_expr_output <- function(expr, split = FALSE, env = parent.frame(),
    quoted = FALSE) {

  expr_quote <- substitute(expr)
  log_file <- tempfile("riskmetric_sink_", fileext = ".txt")
  log_file_con <- file(log_file, "wb")
  on.exit(try(close(log_file_con), silent = TRUE))

  cnds_seek <- numeric()
  cnds_err_traceback <- NULL
  cnds <- list() # messages + warnings + misc conditions

  append_cnd <- function(cnd, envir) {
    cnd_seek <- seek(log_file_con)
    assign("cnds_seek", append(cnds_seek, cnd_seek), envir = envir)
    assign("cnds", append(cnds, list(cnd)), envir = envir)
  }

  n_calls <- length(sys.calls())
  fn_env <- environment()
  sink(log_file_con, split = split)
  res <- withVisible(tryCatch(withCallingHandlers(
    if (!quoted) eval(expr_quote, env) else eval(expr, env),
    condition = function(cnd) {
      if (inherits(cnd, "message") || inherits(cnd, "warning")) {
        calls <- utils::head(utils::tail(sys.calls(), -(8L + n_calls)), -5L)
        cnd$call <- if (length(calls) > 1) calls[[length(calls) - 1]] else NULL
        append_cnd(cnd, fn_env)
        invokeRestart(computeRestarts()[[1]])
      } else if (inherits(cnd, "error")) {
        # trim call stack back to just the scope of the evaluated expression
        calls <- utils::head(utils::tail(sys.calls(), -(8L + n_calls)), -2L)
        cnd$call <- if (length(calls) > 1) calls[[length(calls) - 1]] else NULL
        append_cnd(cnd, fn_env)
        assign("cnds_err_traceback", rev(calls), envir = fn_env)
      } else {
        append_cnd(cnd, fn_env)
      }
    }),
    error = function(e) {
      e
    }))

  # read as raw so that we can keep carriage return and console-overwrites
  sink(NULL)
  close(log_file_con)
  log_text <- rawToChar(readBin(log_file, "raw", file.size(log_file)))
  log_text_line_nchars <- nchar(strsplit(gsub("\r", "\n", log_text), "\n")[[1]])

  # NOTE: Windows might use two newline characters "\r\n"?
  log_newlines <- cumsum(log_text_line_nchars + 1L)

  # rejoin into singular string to split at newlines, as well as any condition
  # emission points
  log_cuts <- sort(unique(c(log_newlines, cnds_seek)))
  log_cuts <- log_cuts[log_cuts < nchar(log_text)]
  log_text <- substring(log_text, c(1, log_cuts + 1L), c(log_cuts, nchar(log_text)))
  log_chars <- cumsum(nchar(log_text))

  # find where to insert emitted conditions among output
  cnd_i <- findInterval(cnds_seek, log_chars)
  cnds_new_index <- cnd_i + seq_along(cnd_i)

  # inject conditions throughout console output as they were emitted
  outputs <- rep(list(NULL), length(log_text) + length(cnds_new_index))
  if (length(cnds_new_index) > 0L) {
    outputs[cnds_new_index] <- cnds
    outputs[-cnds_new_index] <- log_text
  } else {
    outputs <- log_text
  }

  any_output_error <- any(vapply(outputs, inherits, logical(1L), "error"))

  structure(
    res$value,
    .recording = list(
      expr = if (!quoted) expr_quote else expr,
      attributes = attributes(res$value),
      visible = res$visible,
      traceback = cnds_err_traceback,
      output = outputs[nzchar(outputs)]),
    class = c("with_eval_recording", class(res$value)))
}



is_error <- function(expr_output) {
  any(vapply(attr(expr_output, "output"), inherits, logical(1L), "error"))
}



#' Handle pretty printing of expression output
#'
#' @param x expr_output to print
#' @param playback a \code{logical} indicating whether evaluation output
#'   should be played back (\code{FALSE}), or whether the result value should
#'   be printed as is (\code{TRUE}, the default)
#' @param cr a \code{logical} indicating whether carriage returns should be
#'   printed, possibly overwriting characters in the output.
#' @param ... additional arguments unused
#' @param sleep an \code{numeric} indicating a time to sleep between printing
#'   each line to console. This can be helpful if the original output overwrites
#'   valuable information in the log that is eventually overwritten and you
#'   would like to watch it play out as it was formatted.
#'
#' @export
#' @return a print message
#' @keywords internal
print.with_eval_recording <- function(x, playback = FALSE, cr = TRUE, ...,
    sleep = 0) {

  # extract expr execution recording
  rec <- attr(x, ".recording")

  # extract value
  val <- x
  attributes(val) <- rec$attributes
  if (!playback) return(print(val))

  if (rec$expr[[1]] == "{") {
    x_call_str <- vapply(
      rec$expr[-1],
      function(xi) paste0(deparse(xi), collapse = "\n"),
      character(1L))
  } else {
    x_call_str <- capture.output(rec$expr)
  }

  x_call_str[1] <- paste(">", x_call_str[1])
  x_call_str[-1] <- paste("+", x_call_str[-1])
  str_call <- paste(x_call_str, collapse = "\n")

  str_traceback <- paste(
    sprintf(
      "%s %s",
      "#",
      capture.output(traceback(rec$traceback))),
    collapse = "\n")

  cat(str_call, "\n", sep = "")
  for (i in rec$output) {
    if (inherits(i, "message")) {
      message(i$message, appendLF = FALSE)
    } else if (inherits(i, "warning")) {
      message(gsub("^simple", "", .makeMessage(i)), appendLF = FALSE)
    } else if (inherits(i, "error")) {
      message(sprintf("Error%s: %s\n",
        if (!is.null(i$call)) sprintf(" in %s", format(i$call)) else "",
        i$message), appendLF = FALSE)
    } else if (inherits(i, "condition")) {
      message(.makeMessage(i))
    } else if (cr) {
      cat(i)
    } else if (nzchar(gsub("\r", "", i))) {
      cat(gsub("\r", "\n", i))
    }
    if (sleep > 0L) Sys.sleep(sleep)
  }
  if (!is.null(rec$traceback) && length(rec$traceback))
    cat(str_traceback, "\n", sep = "")
  else if (rec$visible)
    val
}




#' Suppress messages and warnings based on one or more regex matches
#'
#' @param expr An expression to evaluate
#' @param ... Named parameters, where the name indicates the class of conditions
#'   to capture and the value is a vector of regular expressions that, when
#'   matched against the respective condition message, should suppress that
#'   condition.
#' @param .opts A named list of arguments to pass to \code{grepl}
#' @param .envir The environment in which \code{expr} is to be evaluated
#' @return a message printed on console
#' @keywords internal
suppressMatchingConditions <- function(expr, ..., .opts = list(),
    .envir = parent.frame()) {

  optioned_grepl <- function(pattern, x)
    do.call(grepl, append(list(pattern = pattern, x = x), .opts))

  generate_cond_handler <- function(cond_regexes) {
    function(cond) {
      if (any(sapply(cond_regexes, optioned_grepl, conditionMessage(cond))))
        invokeRestart(computeRestarts()[[1]])
    }
  }

  do.call(withCallingHandlers,
    append(list(expr), lapply(list(...), generate_cond_handler)))
}



#' Evaluate an expression in the context of a pkg_ref
#'
#' \code{pkg_ref} objects are environments and can be passed to \code{with}
#' in much the same way. This specialized function makes sure that any fields
#' within the \code{pkg_ref} have been appropriately evaluated before trying
#' to execute the expression.
#'
#' @inheritParams base::with
#' @return the value of the evaluated expr.
#' @export
#' @keywords internal
with.pkg_ref <- function(data, expr, ...) {
  expr <- substitute(expr)
  for (n in intersect(names(data), all.names(expr))) data[[n]]
  eval(expr, as.list(data), enclos = parent.frame())
}


is_available_cran <- function(x, repos, p) {
  x %in% memoise_available_packages(repos = repos)[,"Package"] ||
    (!is.null(memoise_cran_mirrors()) &&
       # isTRUE added to catch any issues where the cran mirror isn't available
       isTRUE(is_url_subpath_of(
         p$repo_base_url,
         c(memoise_cran_mirrors()$URL, "https://cran.rstudio.com/"))))
}

is_available_bioc <- function(x, p){
  x %in% memoise_bioc_available()[,"Package"] ||
    (!is.null(memoise_bioc_mirrors()) &&
       isTRUE(is_url_subpath_of(p$repo_base_url, memoise_bioc_mirrors()$URL)))
}


================================================
FILE: R/utils_memoised.R
================================================
#' Fetch CRAN Mirrors Info
#'
#' @param all default \code{TRUE}, passed to \code{\link{utils}[getCRANmirrors]}
#' @param ... additional arguments passed to \code{\link{utils}[getCRANmirrors]}
#' @param .local an optional local directory to source the CRAN package index
#'   from, defaulting to \code{getOption("riskmetric.tests")}, used
#'   for isolating repository requests during testing.
#'
#' @importFrom curl nslookup
#' @importFrom memoise memoise
#' @return a data frame with mirror information
#' @keywords internal
memoise_cran_mirrors <- memoise::memoise({
  # add parameter such that memoised results rerun if internet availability changes
  # NOTE: might need to implement actual caching to avoid inconsistent behavior
  # when run with spotty internet
  function(all = TRUE, ..., .local = getOption("riskmetric.tests")) {
    if (!is.null(.local)) {
      return(read.csv(
        file.path(.local, "test_webmocks", "data", "cran_mirrors.csv"),
        stringsAsFactors = FALSE))
    }

    tryCatch({
      utils::getCRANmirrors(all = all, ...)
    }, error = function(e) {
      NULL
    })
  }
})



#' @importFrom BiocManager available
#' @importFrom memoise memoise
#' @keywords internal
memoise_bioc_available <- memoise::memoise({
  function() {
    con <- url("https://bioconductor.org/packages/release/bioc/src/contrib/PACKAGES")
    on.exit(close(con))
    as.data.frame(read.dcf(con), stringsAsFactors = FALSE)
  }
})



#' Fetch BioC Mirrors Info
#'
#' taken from utils::chooseBioCmirror
#'
#' @importFrom curl nslookup
#' @importFrom memoise memoise
#' @return a data frame with mirror information
#' @keywords internal
memoise_bioc_mirrors <- memoise::memoise({
  # add parameter such that memoised results rerun if internet availability changes
  # NOTE: might need to implement actual caching to avoid inconsistent behavior
  # when run with spotty internet
  function() {
    tryCatch({
      read.csv("https://bioconductor.org/BioC_mirrors.csv")
    }, error = function(e) {
      NULL
    })
  }
})



#' @importFrom memoise memoise
memoise_available_packages <- memoise::memoise({
  function(..., repos = getOption("repos"), .local = getOption("riskmetric.tests")) {
    if (!is.null(.local)) {
      db <- read.csv(
        file.path(.local, "test_webmocks", "data", "cran_packages.csv"),
        stringsAsFactors = FALSE)
      db[, "Repository"] <- contrib.url(repos, getOption("pkgType"))
      return(db)
    } else if (is.null(repos)) {
      return(utils::available.packages(NULL))
    } else if ("@CRAN@" %in% repos) {
      repos[repos == "@CRAN@"] <- "https://cloud.r-project.org"
    }

    utils::available.packages(repos = repos, ...)
  }
})


================================================
FILE: R/vctrs_list_of_pkg_metric.R
================================================
#' @importFrom pillar pillar_shaft
#' @method pillar_shaft list_of_pkg_metric
#' @export
pillar_shaft.list_of_pkg_metric <- function(x, ...) {
  ucx <- lapply(x, unclass)
  p <- pillar::pillar_shaft(ucx)

  is_error <- vapply(x, inherits, logical(1L), "pkg_metric_error")
  p[[1]][is_error] <- vapply(x[is_error], function(xi) {
    pillar::pillar_shaft(xi)[[1]]
  }, character(1L))

  is_atomic_l1 <- vapply(ucx, function(xi) is.atomic(xi) && length(xi) == 1, logical(1L))
  p[[1]][is_atomic_l1] <- ucx[is_atomic_l1]
  attr(p, "width") <- max(attr(p, "width"), nchar(ucx[is_atomic_l1]))

  p
}



#' @importFrom vctrs vec_cast.double
#' @method vec_cast.double list_of_pkg_metric
#' @export
vec_cast.double.list_of_pkg_metric <- function(x, to, ...) {
  out <- vector("numeric", length(x))
  is_error <- vapply(x, inherits, logical(1L), "pkg_metric_error")
  out[is_error] <- NA_real_
  out[!is_error] <- vapply(x, unclass, numeric(1L))
  out
}


================================================
FILE: R/vctrs_list_of_pkg_ref.R
================================================
#' @importFrom pillar pillar_shaft new_pillar_shaft_simple
#' @method pillar_shaft list_of_pkg_ref
#' @export
pillar_shaft.list_of_pkg_ref <- function(x, ...) {
  out <- vapply(x, format, character(1L))
  pillar::new_pillar_shaft_simple(out, align = "left")
}


================================================
FILE: R/zzz.R
================================================
#' @importFrom backports import
#' @keywords internal
.onLoad <- function(libname, pkgname) {
  backports::import(pkgname, "isFALSE")

  # set default cache behaviors
  opts <- Filter(Negate(is.null), Map(function(i) i$default(), cache_behaviors))
  names(opts) <- sprintf("riskmetric.%s", names(opts))
  opts <- opts[!names(opts) %in% names(options())]
  do.call(options, as.list(opts))

  # set default options
  opts <- riskmetric.options
  names(opts) <- sprintf("riskmetric.%s", names(opts))
  opts <- opts[!names(opts) %in% names(options())]
  do.call(options, as.list(opts))

  # if non-interactive, cache package sources on load
  if (!interactive()) {
    memoise_available_packages()
  }
}


================================================
FILE: README.md
================================================
# riskmetric <a href='https://pharmar.github.io/riskmetric/'><img src="man/figures/logo.png" align="right" height="172" style="float:right; height:172px;"/></a>

<!-- badges: start -->
[![Lifecycle](.github/assets/lifecycle-superseded.svg)](https://github.com/pharmaR/val.meter)
[![R build status](https://github.com/pharmaR/riskmetric/workflows/R-CMD-check/badge.svg)](https://github.com/pharmaR/riskmetric/actions?workflow=R-CMD-check)
[![Coverage status](https://codecov.io/gh/pharmaR/riskmetric/branch/master/graph/badge.svg)](https://app.codecov.io/gh/pharmaR/riskmetric?branch=master)
<!-- badges: end -->

`riskmetric` is a collection of risk metrics to evaluate the quality of R
packages.

> [!IMPORTANT]
>
> Lifecycle: **Maintenance Only**
>
> The _R Validation Hub_ is shifting development efforts to our new flagship
> assessment tool, [`{val.meter}`](https://github.com/pharmaR/val.meter). While
> development is not ending for `{riskmetric}`, it has shifted to
> maintenance-only. Please continue to file bug reports for erroneous behaviors,
> but for feature requests and discussion on approach, please head over to
> `{val.meter}`.
> 

## Background

The risk of using an R package is evaluated based on a number of metrics meant
to evaluate development best practices, code documentation, community engagement
and development sustainability. We hope to provide a framework to quantify risk
by assessing these metrics. This package serves as a starting point for
exploring the heterogeneity of code quality, and begin a broader conversation
about the validation of R packages. Primarily, this effort aims to provide some
context for validation within regulated industries.

We separate three steps in the workflow to assess the risk of an R package using `riskmetric`:

1. **Finding a source for package information (installed package or CRAN/git source)** `pkg_ref()`
1. **Assessing the package under validation criteria** `pkg_assess()`
1. **Scoring assessment criteria** `pkg_score()`

The results will be assembled in a dataset of validation criteria containing an
overall risk score for each package as shown in the example below.

## Installation

You can install `riskmetric`  from CRAN with:

```r
install.packages("riskmetric")
```

Or from GitHub using `devtools` with:

```r
devtools::install_github("pharmaR/riskmetric")
```

## Example

Scrape metadata locally or remotely, then assess that metadata and score it to
estimate risk. For each package, derive a composite measure of risk, or a
collection of individual scores which can be easily used to generate validation
reports.

```r
library(dplyr)
library(riskmetric)

pkg_ref(c("riskmetric", "utils", "tools")) %>%
  pkg_assess() %>%
  pkg_score()
```

## The `{riskassessment}` application <a href='https://pharmar.github.io/riskassessment/'><img src="man/figures/hex-riskassessment-aspconfig.png" align="right" height="172" style="float:right; height:172px;"/></a>

`riskassessment` is a full-fledged R package containing a shiny front-end that
augments the utility of `riskmetric`. The application's goal is to provide a 
central hub for an organization to review and assess the risk of R packages,
providing handy tools and guide rails along the way. The app uses a local
database to store & display:

* all `riskmetric` metrics, including package risk scores over time
* organization-wide metric weighting, plus rules to automate org decisions
(whether to endorse/ prohibit the pkg)
* package-level user dialogue on the perceived risk, to facilitate communication
& notes

To learn more about `riskassessment`, please browse the [user guide](https://pharmar.github.io/riskassessment/) or consider
taking the [demo app](https://rinpharma.shinyapps.io/risk_assessment) for a spin.

## Get Involved

We have a bi-weekly sprint meeting for developers to discuss the progress.

* Contact `eric.milliman@biogen.com` to be added to the meeting.
* [Project Planning Meeting Structure](https://github.com/pharmaR/riskmetric/issues/57) 
* [Milestone](https://github.com/pharmaR/riskmetric/milestones)

`riskmetric` is centrally a community project. Comfort with a quantification of
risk comes via consensus, and for that this project is dependent on close
community engagement. There are plenty of ways to help:

- Share the package
- File [issues](https://github.com/pharmaR/riskmetric/issues) when you encounter bugs
- Weigh in on proposed metrics, or [suggest a new one](https://github.com/pharmaR/riskmetric/issues/new?labels=Metric%20Proposal)
- Help us devise the best way to summarize risk into a single score
- Help us keep documentation up to date
- Contribute code to tackle the metric backlog


================================================
FILE: _pkgdown.yml
================================================
template:
  bootstrap: 5

reference:
  - title: "Package Reference"
    desc: "Create Package Reference for Each Package Risk Metric and Cache Metadata"
    contents:
      - starts_with("pkg_ref")
  - title: "Package Assessment"
    desc: "Assess Package Metadata against a risk criterion"
    contents:
      - starts_with("pkg_assess")
      - all_assessments
      - get_assessments
      - starts_with("assess")
  - title: "Package Risk Score"
    desc: "Provide Risk Score based on Risk Metrics"
    contents:
      - pkg_score
      - starts_with("pkg_metric")
      - starts_with("metric_score")
  - title: "Package Risk Summary"
    desc: "Summarizing across metric scores"
    contents:
      - summarize_scores
  - title: "Metric Error Handler"
    desc: "Error handler functions"
    contents:
      - starts_with("assessment_error")
      - starts_with("score_error")
  - title: "Utilities"
    desc: "Utility functions"
    contents:
      - as_pkg_metric
      - as_pkg_ref


================================================
FILE: cran-comments.md
================================================
## riskmetric 0.2.5

Resolved issues with CRAN checks.

Tested on Ubuntu Jammy, GitHub Action, and RHub.

## R CMD check results

0 errors | 0 warnings | 0 notes





================================================
FILE: man/all_assessments.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_assess.R
\name{all_assessments}
\alias{all_assessments}
\title{A default list of assessments to perform for each package}
\usage{
all_assessments()
}
\value{
a list of assess_* functions exported from riskmetric
}
\description{
A default list of assessments to perform for each package
}


================================================
FILE: man/allow_mutation.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_ref_class_extract.R
\name{allow_mutation}
\alias{allow_mutation}
\title{a wrapper to assert that a pkg_ref has been permitted to do an additional
mutation, used to handle recursive initialization of cached fields}
\usage{
allow_mutation(x, expr, envir = parent.frame())
}
\arguments{
\item{x}{a \code{pkg_ref} object}

\item{expr}{an expression to evaluate, and possible do a mutation within}

\item{envir}{an environment in which the expression is to be evaluated}
}
\value{
the result of \code{expr}
}
\description{
a wrapper to assert that a pkg_ref has been permitted to do an additional
mutation, used to handle recursive initialization of cached fields
}
\keyword{internal}


================================================
FILE: man/as_pkg_metric.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_metric.R
\name{as_pkg_metric}
\alias{as_pkg_metric}
\title{Convert an object to a \code{pkg_metric}}
\usage{
as_pkg_metric(x, class = c())
}
\arguments{
\item{x}{data to store as a \code{pkg_metric}}

\item{class}{a subclass to differentiate the \code{pkg_metric} object}
}
\value{
a \code{pkg_metric} object
}
\description{
Convert an object to a \code{pkg_metric}
}


================================================
FILE: man/as_pkg_metric_condition.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_metric_condition.R
\name{as_pkg_metric_condition}
\alias{as_pkg_metric_condition}
\title{A pkg_metric subclass for general metric evaluation conditions}
\usage{
as_pkg_metric_condition(x, ..., subclass = c())
}
\arguments{
\item{x}{an object to wrap in a \code{pkg_metric_condition} class}

\item{...}{additional arguments added as attributes to object \code{x}}

\item{subclass}{an optional subclass of \code{pkg_metric_condition} to
include}
}
\value{
an object after wrap \code{pkg_metric_condition} class.
}
\description{
A pkg_metric subclass for general metric evaluation conditions
}
\keyword{internal}


================================================
FILE: man/as_pkg_metric_error.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_metric_error.R
\name{as_pkg_metric_error}
\alias{as_pkg_metric_error}
\title{A subclass wrapping an error with an additional parent class}
\usage{
as_pkg_metric_error(error)
}
\arguments{
\item{error}{an error condition object to capture}
}
\value{
an error condition object after wrap \code{pkg_metric_error} class.
}
\description{
A subclass wrapping an error with an additional parent class
}
\keyword{internal}


================================================
FILE: man/as_pkg_metric_na.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_metric_na.R
\name{as_pkg_metric_na}
\alias{as_pkg_metric_na}
\title{A pkg_metric subclass for when metrics are explicitly not applicable}
\usage{
as_pkg_metric_na(x, message = NULL)
}
\arguments{
\item{x}{a \code{pkg_metric} object to wrap in a \code{pkg_metric_na}
subclass}

\item{message}{an optional message explaining why a metric is not applicable.}
}
\value{
a \code{pkg_metric} object after wrap in a \code{pkg_metric_na}
}
\description{
A pkg_metric subclass for when metrics are explicitly not applicable
}
\keyword{internal}


================================================
FILE: man/as_pkg_metric_todo.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_metric_todo.R
\name{as_pkg_metric_todo}
\alias{as_pkg_metric_todo}
\title{A pkg_metric subclass for when pkg_metrics have not yet been implemented}
\usage{
as_pkg_metric_todo(x, message = NULL)
}
\arguments{
\item{x}{a \code{pkg_metric} object to wrap in a \code{pkg_metric_todo}
subclass}

\item{message}{an optional message directing users and potential contributors
toward any ongoing work or first steps toward development.}
}
\value{
a \code{pkg_metric} object after wrap in a \code{pkg_metric_todo}
}
\description{
A pkg_metric subclass for when pkg_metrics have not yet been implemented
}
\keyword{internal}


================================================
FILE: man/assess_covr_coverage.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assess_covr_coverage.R
\name{assess_covr_coverage}
\alias{assess_covr_coverage}
\title{Assess a package code coverage using the `covr` package}
\usage{
assess_covr_coverage(x, ...)
}
\arguments{
\item{x}{a \code{pkg_ref} package reference object}

\item{...}{additional arguments passed on to S3 methods, rarely used}
}
\value{
a \code{pkg_metric} containing a list containing fields 'filecoverage' and 'totalcoverage' containing a named numeric vector of file unit test coverage and a singular numeric value representing overall test coverage respectively.
}
\description{
Assess a package code coverage using the `covr` package
}
\examples{
\dontrun{
assess_covr_coverage(pkg_ref("riskmetric"))
}
}
\seealso{
\code{\link{metric_score.pkg_metric_covr_coverage}}
}


================================================
FILE: man/assess_dependencies.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assess_dependencies.R
\name{assess_dependencies}
\alias{assess_dependencies}
\title{Assessment of dependency footprint for a specific package}
\usage{
assess_dependencies(x, ...)
}
\arguments{
\item{x}{a \code{pkg_ref} package reference object}

\item{...}{additional arguments passed on to S3 methods, rarely used}
}
\value{
a \code{pkg_metric} containing a dataframe of package names and they type of dependency the package being assess has to them
}
\description{
Only Depends, Imports and LinkingTo dependencies are assessed because
they are required
}
\details{
The more packages a package relies on the more chances for errors exist.
}
\examples{
\dontrun{
assess_dependencies(pkg_ref("riskmetric"))
}
}
\seealso{
\code{\link{metric_score.pkg_metric_dependencies}}
}


================================================
FILE: man/assess_downloads_1yr.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assess_downloads.R
\name{assess_downloads_1yr}
\alias{assess_downloads_1yr}
\title{Assess a package for the number of downloads in the past year}
\usage{
assess_downloads_1yr(x, ...)
}
\arguments{
\item{x}{a \code{pkg_ref} package reference object}

\item{...}{additional arguments passed on to S3 methods, rarely used}
}
\value{
a \code{pkg_metric} containing a numeric value between [0,1] indicating the volume of downloads
}
\description{
Assess a package for the number of downloads in the past year
}
\details{
The more times a package has been downloaded the more extensive the user testing and the greater chance there is of someone finding a bug and logging it.
}
\examples{
\dontrun{
assess_downloads_1yr(pkg_ref("riskmetric"))
}
}
\seealso{
\code{\link{metric_score.pkg_metric_downloads_1yr}}
}


================================================
FILE: man/assess_export_help.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assess_export_help.R
\name{assess_export_help}
\alias{assess_export_help}
\title{Assess a package for availability of documentation for exported values}
\usage{
assess_export_help(x, ...)
}
\arguments{
\item{x}{a \code{pkg_ref} package reference object}

\item{...}{additional arguments passed on to S3 methods, rarely used}
}
\value{
a \code{pkg_metric} containing a logical vector indicating existence of documentation for each namespace export
}
\description{
Assess a package for availability of documentation for exported values
}
\examples{
\dontrun{
assess_export_help(pkg_ref("riskmetric"))
}
}
\seealso{
\code{\link{metric_score.pkg_metric_export_help}}
}


================================================
FILE: man/assess_exported_namespace.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assess_exported_namespace.R
\name{assess_exported_namespace}
\alias{assess_exported_namespace}
\title{Assess a package's results from running R CMD check}
\usage{
assess_exported_namespace(x, ...)
}
\arguments{
\item{x}{a \code{pkg_ref} package reference object}

\item{...}{additional arguments passed on to S3 methods, rarely used}
}
\value{
a \code{pkg_metric} containing List of functions and objects exported by a package, excluding S3methods
}
\description{
Assess a package's results from running R CMD check
}
\examples{
\dontrun{
assess_exported_namespace(pkg_ref("riskmetric"))
}
}
\seealso{
\code{\link{metric_score.pkg_metric_exported_namespace}}
}


================================================
FILE: man/assess_has_bug_reports_url.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assess_has_bug_reports_url.R
\name{assess_has_bug_reports_url}
\alias{assess_has_bug_reports_url}
\title{Assess a package for the presence of a url field where bugs can be reported.}
\usage{
assess_has_bug_reports_url(x, ...)
}
\arguments{
\item{x}{a \code{pkg_ref} package reference object}

\item{...}{additional arguments passed on to S3 methods, rarely used}
}
\value{
a \code{pkg_metric} containing a character value containing the BugReports field contents
}
\description{
Assess a package for the presence of a url field where bugs can be reported.
}
\examples{
\dontrun{
assess_has_bug_reports_url(pkg_ref("riskmetric"))
}
}
\seealso{
\code{\link{metric_score.pkg_metric_has_bug_reports_url}}
}


================================================
FILE: man/assess_has_examples.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assess_has_examples.R
\name{assess_has_examples}
\alias{assess_has_examples}
\title{Assess a package for the presence of example or usage fields in function documentation}
\usage{
assess_has_examples(x, ...)
}
\arguments{
\item{x}{a \code{pkg_ref} package reference object}

\item{...}{additional arguments passed on to S3 methods, rarely used}
}
\value{
a \code{pkg_metric} containing an integer value indicating the proportion of discovered files with examples
}
\description{
Assess a package for the presence of example or usage fields in function documentation
}
\examples{
\dontrun{
assess_has_examples(pkg_ref("riskmetric"))
}
}
\seealso{
\code{\link{metric_score.pkg_metric_has_examples}}
}


================================================
FILE: man/assess_has_maintainer.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assess_has_maintainer.R
\name{assess_has_maintainer}
\alias{assess_has_maintainer}
\title{Assess a package for an associated maintainer}
\usage{
assess_has_maintainer(x, ...)
}
\arguments{
\item{x}{a \code{pkg_ref} package reference object}

\item{...}{additional arguments passed on to S3 methods, rarely used}
}
\value{
a \code{pkg_metric} containing a character vector of maintainers associated with the package
}
\description{
Assess a package for an associated maintainer
}
\examples{
\dontrun{
assess_has_maintainer(pkg_ref("riskmetric"))
}
}
\seealso{
\code{\link{metric_score.pkg_metric_has_maintainer}}
}


================================================
FILE: man/assess_has_news.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assess_has_news.R
\name{assess_has_news}
\alias{assess_has_news}
\title{Assess a package for the presence of a NEWS file}
\usage{
assess_has_news(x, ...)
}
\arguments{
\item{x}{a \code{pkg_ref} package reference object}

\item{...}{additional arguments passed on to S3 methods, rarely used}
}
\value{
a \code{pkg_metric} containing an integer value indicating the number of discovered NEWS files
}
\description{
Assess a package for the presence of a NEWS file
}
\examples{
\dontrun{
assess_has_news(pkg_ref("riskmetric"))
}
}
\seealso{
\code{\link{metric_score.pkg_metric_has_news}}
}


================================================
FILE: man/assess_has_source_control.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assess_has_source_control.R
\name{assess_has_source_control}
\alias{assess_has_source_control}
\title{Assess a package for an associated source control url}
\usage{
assess_has_source_control(x, ...)
}
\arguments{
\item{x}{a \code{pkg_ref} package reference object}

\item{...}{additional arguments passed on to S3 methods, rarely used}
}
\value{
a \code{pkg_metric} containing a character vector of source control urls associated with the package
}
\description{
Assess a package for an associated source control url
}
\examples{
\dontrun{
assess_has_source_control(pkg_ref("riskmetric"))
}
}
\seealso{
\code{\link{metric_score.pkg_metric_has_source_control}}
}


================================================
FILE: man/assess_has_vignettes.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assess_has_vignettes.R
\name{assess_has_vignettes}
\alias{assess_has_vignettes}
\title{Assess a package for the presence of Vignettes files}
\usage{
assess_has_vignettes(x, ...)
}
\arguments{
\item{x}{a \code{pkg_ref} package reference object}

\item{...}{additional arguments passed on to S3 methods, rarely used}
}
\value{
a \code{pkg_metric} containing an integer value indicating the number of discovered vignettes files
}
\description{
Assess a package for the presence of Vignettes files
}
\examples{
\dontrun{
assess_has_vignettes(pkg_ref("riskmetric"))
}
}
\seealso{
\code{\link{metric_score.pkg_metric_has_vignettes}}
}


================================================
FILE: man/assess_has_website.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assess_has_website.R
\name{assess_has_website}
\alias{assess_has_website}
\title{Assess a package for an associated website url}
\usage{
assess_has_website(x, ...)
}
\arguments{
\item{x}{a \code{pkg_ref} package reference object}

\item{...}{additional arguments passed on to S3 methods, rarely used}
}
\value{
a \code{pkg_metric} containing a character vector of website urls associated with the package
}
\description{
Assess a package for an associated website url
}
\examples{
\dontrun{
assess_has_website(pkg_ref("riskmetric"))
}
}
\seealso{
\code{\link{metric_score.pkg_metric_has_website}}
}


================================================
FILE: man/assess_last_30_bugs_status.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assess_last_30_bugs_status.R
\name{assess_last_30_bugs_status}
\alias{assess_last_30_bugs_status}
\title{Assess how many recent BugReports have been closed}
\usage{
assess_last_30_bugs_status(x, ...)
}
\arguments{
\item{x}{a \code{pkg_ref} package reference object}

\item{...}{additional arguments passed on to S3 methods, rarely used}
}
\value{
a \code{pkg_metric} containing a logical vector indicating whether a recent BugReport was closed
}
\description{
Assess how many recent BugReports have been closed
}
\examples{
\dontrun{
assess_last_30_bugs_status(pkg_ref("riskmetric"))
}
}
\seealso{
\code{\link{metric_score.pkg_metric_last_30_bugs_status}}
}


================================================
FILE: man/assess_license.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assess_license.R
\name{assess_license}
\alias{assess_license}
\title{Assess a package for an acceptable license}
\usage{
assess_license(x, ...)
}
\arguments{
\item{x}{a \code{pkg_ref} package reference object}

\item{...}{additional arguments passed on to S3 methods, rarely used}
}
\value{
a \code{pkg_metric} containing a string indicating the license under which the package is released
}
\description{
Assess a package for an acceptable license
}
\examples{
\dontrun{
assess_license(pkg_ref("riskmetric"))
}
}
\seealso{
\code{\link{metric_score.pkg_metric_license}}
}


================================================
FILE: man/assess_news_current.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assess_news_current.R
\name{assess_news_current}
\alias{assess_news_current}
\title{Assess a package for an up-to-date NEWS file}
\usage{
assess_news_current(x, ...)
}
\arguments{
\item{x}{a \code{pkg_ref} package reference object}

\item{...}{additional arguments passed on to S3 methods, rarely used}
}
\value{
a \code{pkg_metric} containing a logical vector indicating whether each discovered NEWS file is up-to-date
}
\description{
Assess a package for an up-to-date NEWS file
}
\examples{
\dontrun{
assess_news_current(pkg_ref("riskmetric"))
}
}
\seealso{
\code{\link{metric_score.pkg_metric_news_current}}
}


================================================
FILE: man/assess_r_cmd_check.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assess_r_cmd_check.R
\name{assess_r_cmd_check}
\alias{assess_r_cmd_check}
\title{Assess a package's results from running R CMD check}
\usage{
assess_r_cmd_check(x, ...)
}
\arguments{
\item{x}{a \code{pkg_ref} package reference object}

\item{...}{additional arguments passed on to S3 methods, rarely used}
}
\value{
a \code{pkg_metric} containing Tally of errors, warnings and notes from running R CMD check locally
}
\description{
Assess a package's results from running R CMD check
}
\examples{
\dontrun{
assess_r_cmd_check(pkg_ref("riskmetric"))
}
}
\seealso{
\code{\link{metric_score.pkg_metric_r_cmd_check}}
}


================================================
FILE: man/assess_remote_checks.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assess_remote_checks.R
\name{assess_remote_checks}
\alias{assess_remote_checks}
\title{Assess package checks from CRAN/Bioc or R CMD check}
\usage{
assess_remote_checks(x, ...)
}
\arguments{
\item{x}{a \code{pkg_ref} package reference object}

\item{...}{additional arguments passed on to S3 methods, rarely used}
}
\value{
a \code{pkg_metric} containing Tally of R CMD check results run on differnt OS flavors by BioC or CRAN
}
\description{
Assess package checks from CRAN/Bioc or R CMD check
}
\examples{
\dontrun{
assess_remote_checks(pkg_ref("riskmetric"))
}
}
\seealso{
\code{\link{metric_score.pkg_metric_remote_checks}}
}


================================================
FILE: man/assess_reverse_dependencies.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assess_reverse_dependencies.R
\name{assess_reverse_dependencies}
\alias{assess_reverse_dependencies}
\title{Generate list of Reverse Dependencies for a package}
\usage{
assess_reverse_dependencies(x, ...)
}
\arguments{
\item{x}{a \code{pkg_ref} package reference object}

\item{...}{additional arguments passed on to S3 methods, rarely used}
}
\value{
a \code{pkg_metric} containing A character vector of reverse dependencies
}
\description{
Generate list of Reverse Dependencies for a package
}
\details{
The more packages that depend on a package the more chance
for errors/bugs to be found
}
\examples{
\dontrun{
assess_reverse_dependencies(pkg_ref("riskmetric"))
}
}
\seealso{
\code{\link{metric_score.pkg_metric_reverse_dependencies}}
}


================================================
FILE: man/assess_size_codebase.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assess_size_codebase.R
\name{assess_size_codebase}
\alias{assess_size_codebase}
\title{Assess a package for size of code base}
\usage{
assess_size_codebase(x, ...)
}
\arguments{
\item{x}{a \code{pkg_ref} package reference object}

\item{...}{additional arguments passed on to S3 methods, rarely used}
}
\value{
a \code{pkg_metric} containing a numeric value for number of lines of code base for a package
}
\description{
Assess a package for size of code base
}
\examples{
\dontrun{
assess_size_codebase(pkg_ref("riskmetric"))
}
}
\seealso{
\code{\link{metric_score.pkg_metric_size_codebase}}
}


================================================
FILE: man/assessment_error_as_warning.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_metric_error.R
\name{assessment_error_as_warning}
\alias{assessment_error_as_warning}
\title{Error handler for assessments to deescalate errors to warnings}
\usage{
assessment_error_as_warning(e, name, assessment)
}
\arguments{
\item{e}{an error raised during a package reference assessment}

\item{name}{the name of the package whose package reference assessment raised
the error}

\item{assessment}{the name of the assessment function which raised the error}
}
\value{
a pkg_metric object of pkg_metric_error subclass
}
\description{
Error handler for assessments to deescalate errors to warnings
}
\seealso{
Other assessment error handlers: 
\code{\link{assessment_error_empty}()},
\code{\link{assessment_error_throw}()}
}
\concept{assessment error handlers}


================================================
FILE: man/assessment_error_empty.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_metric_error.R
\name{assessment_error_empty}
\alias{assessment_error_empty}
\title{Error handler for assessments with safe fallback}
\usage{
assessment_error_empty(e, ...)
}
\arguments{
\item{e}{an error raised during a package reference assessment}

\item{...}{additional arguments unused}
}
\value{
a pkg_metric object of pkg_metric_error subclass
}
\description{
Error handler for assessments with safe fallback
}
\seealso{
Other assessment error handlers: 
\code{\link{assessment_error_as_warning}()},
\code{\link{assessment_error_throw}()}
}
\concept{assessment error handlers}


================================================
FILE: man/assessment_error_throw.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_metric_error.R
\name{assessment_error_throw}
\alias{assessment_error_throw}
\title{Error handler for assessments to throw error immediately}
\usage{
assessment_error_throw(e, name, assessment)
}
\arguments{
\item{e}{an error raised during a package reference assessment}

\item{name}{the name of the package whose package reference assessment raised
the error}

\item{assessment}{the name of the assessment function which raised the error}
}
\value{
the error encountered during assessment
}
\description{
Error handler for assessments to throw error immediately
}
\seealso{
Other assessment error handlers: 
\code{\link{assessment_error_as_warning}()},
\code{\link{assessment_error_empty}()}
}
\concept{assessment error handlers}


================================================
FILE: man/available_pkg_ref_fields.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_ref_cache.R
\name{available_pkg_ref_fields}
\alias{available_pkg_ref_fields}
\title{A helper function for retrieving a list of available fields, identified based
on implementation of a pkg_ref_cache method for a given class.}
\usage{
available_pkg_ref_fields(x)
}
\arguments{
\item{x}{a package reference object}
}
\value{
a list of available fields implemented with a pkg_ref_cache method
}
\description{
A helper function for retrieving a list of available fields, identified based
on implementation of a pkg_ref_cache method for a given class.
}
\keyword{internal}


================================================
FILE: man/bare_env.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_ref_class_extract.R
\name{bare_env}
\alias{bare_env}
\title{evaluate an expression with a  pkg_ref object reclassed as a bare environment
object, used to sidestep pkg_ref assignment guardrails}
\usage{
bare_env(x, expr, envir = parent.frame())
}
\arguments{
\item{x}{a \code{pkg_ref} object}

\item{expr}{an expression to evaluate, avoiding \code{pkg_ref} extraction
handlers}

\item{envir}{an environment in which the expression is to be evaluated}
}
\value{
the result of \code{expr}
}
\description{
evaluate an expression with a  pkg_ref object reclassed as a bare environment
object, used to sidestep pkg_ref assignment guardrails
}
\keyword{internal}


================================================
FILE: man/bug_report_metadata.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_ref_cache_bug_reports.R
\name{bug_report_metadata}
\alias{bug_report_metadata}
\title{Helper for structuring bug reports}
\usage{
bug_report_metadata(bug_reports_data, x)
}
\arguments{
\item{bug_reports_data}{data to represent a bug report history - generally a
return object from making a request to a repository's issues API}

\item{x}{a \code{pkg_ref} object where a \code{bug_reports_host} field can be
found}
}
\value{
a \code{bug_reports_host} field
}
\description{
Helper for structuring bug reports
}
\keyword{internal}


================================================
FILE: man/cache_behaviors.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_ref_cache_behaviors.R
\docType{data}
\name{cache_behaviors}
\alias{cache_behaviors}
\title{List of available caching behaviors with metadata, including default and
annotations for building documentation}
\format{
An object of class \code{list} of length 1.
}
\usage{
cache_behaviors
}
\value{
a list contain cache behaviros information
}
\description{
List of available caching behaviors with metadata, including default and
annotations for building documentation
}
\keyword{internal}


================================================
FILE: man/capture_expr_output.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/utils.R
\name{capture_expr_output}
\alias{capture_expr_output}
\title{Capture side effects issued by an evaluated expression}
\usage{
capture_expr_output(expr, split = FALSE, env = parent.frame(), quoted = FALSE)
}
\arguments{
\item{expr}{an expression to evaluate, capturing output events as they
are issued}

\item{split}{logical: if \code{TRUE}, output will be sent to the new
    sink and to the current output stream, like the Unix program \code{tee}.}

\item{env}{the environment in which \code{expr} should be evaluated,
defaulting to the calling environment.}

\item{quoted}{whether \code{expr} is a quoted object and should be evaluated
as is, or whether the expression should be captured from the function call.
Defaults to \code{FALSE}, capturing the passed expression.}
}
\value{
an with_eval_recording object
}
\description{
All messaging condition side effects are captured in the order that they
are issued.
}
\keyword{internal}


================================================
FILE: man/dec_mutations_count.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_ref_class_extract.R
\name{dec_mutations_count}
\alias{dec_mutations_count}
\title{decrement the number of allowed mutations}
\usage{
dec_mutations_count(x)
}
\arguments{
\item{x}{pkg_ref object to decrement mutation counter for}
}
\value{
pkg_ref object
}
\description{
decrement the number of allowed mutations
}
\keyword{internal}


================================================
FILE: man/determine_pkg_source.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_ref_class.R
\name{determine_pkg_source}
\alias{determine_pkg_source}
\title{Determine the intended source of a new package}
\usage{
determine_pkg_source(x, source, repos)
}
\arguments{
\item{x}{Package name or path to package}

\item{source}{type of source passed in `pkg_ref`}
}
\value{
one of c('pkg_source', 'pkg_install', 'pkg_cran_remote',
  'pkg_bioc_remote', 'pkg_missing')
}
\description{
Determine the intended source of a new package
}
\keyword{internal}


================================================
FILE: man/dot-tools.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/utils.R
\name{.tools}
\alias{.tools}
\title{Accessor for tools namespace}
\usage{
.tools()
}
\value{
tools namespace
}
\description{
used internally for
  - tools:::.news_reader_default
}
\keyword{internal}


================================================
FILE: man/examples_from_dir.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_ref_cache_examples.R
\name{examples_from_dir}
\alias{examples_from_dir}
\title{Build logical vector for Rd objects with example or usage fields discovered in a given directory}
\usage{
examples_from_dir(path, pkg)
}
\arguments{
\item{path}{a package directory path expected to contain exported objects}
}
\value{
a numeric proportion of documentation files with examples
}
\description{
Build logical vector for Rd objects with example or usage fields discovered in a given directory
}
\keyword{internal}


================================================
FILE: man/examples_from_pkg.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_ref_cache_examples.R
\name{examples_from_pkg}
\alias{examples_from_pkg}
\title{Build logical vector for Rd objects with example or usage fields discovered in a given package}
\usage{
examples_from_pkg(pkg)
}
\arguments{
\item{pkg}{a package name expected to contain exported objects}
}
\value{
a numeric proportion of documentation files with examples
}
\description{
Build logical vector for Rd objects with example or usage fields discovered in a given package
}
\keyword{internal}


================================================
FILE: man/filter_rd_db.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_ref_cache_examples.R
\name{filter_rd_db}
\alias{filter_rd_db}
\title{Filter a simple database of Rd objects in a package for files with example fields}
\usage{
filter_rd_db(rddb)
}
\arguments{
\item{rddb}{a simple database of Rd object obtained via tools::Rd_db}
}
\value{
a vector of Rd file names that have example fields
}
\description{
Filter a simple database of Rd objects in a package for files with example fields
}
\keyword{internal}


================================================
FILE: man/firstS3method.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/utils.R
\name{firstS3method}
\alias{firstS3method}
\title{Find the S3 method that will be evaluated when an S3 generic is called by
an object of class \code{classes}}
\usage{
firstS3method(f, classes, envir = parent.frame())
}
\arguments{
\item{f}{a character string giving the name of the generic.}

\item{classes}{a character vector of classes used to search for the
appropriate S3 method}

\item{envir}{the \code{\link{environment}} in which the method and its
    generic are searched first.}
}
\value{
a S3 method
}
\description{
Find the S3 method that will be evaluated when an S3 generic is called by
an object of class \code{classes}
}
\keyword{internal}


================================================
FILE: man/format_assessment_message.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_metric_error.R
\name{format_assessment_message}
\alias{format_assessment_message}
\title{Assessment console printing formatter}
\usage{
format_assessment_message(e, name, assessment)
}
\arguments{
\item{e}{an error raised during a package reference assessment}

\item{name}{the name of the package whose package reference assessment raised
the error}

\item{assessment}{the name of the assessment function which raised the error}
}
\value{
a character string of formatted text to communicate the error
}
\description{
make the errors and warnings consistent with meaningful indication of what
triggered the error, including the name of the package whose reference
triggered the error while running which asesessment.
}
\keyword{internal}


================================================
FILE: man/get_assessment_columns.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_assess.R
\name{get_assessment_columns}
\alias{get_assessment_columns}
\title{Helper for retrieving a list of columns which contain pkg_metric objects}
\usage{
get_assessment_columns(tbl)
}
\arguments{
\item{tbl}{a \code{\link[tibble]{tibble}} to select columns among}
}
\value{
a logical vector of \code{pkg_metric} column indices
}
\description{
Helper for retrieving a list of columns which contain pkg_metric objects
}
\keyword{internal}


================================================
FILE: man/get_assessments.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_assess.R
\name{get_assessments}
\alias{get_assessments}
\title{Get a specific set of assess_* functions for pkg_assess}
\usage{
get_assessments(fxn_string = "")
}
\arguments{
\item{fxn_string}{vector of assess functions}
}
\value{
a list of specific assess_* functions exported from riskmetric
}
\description{
Get a specific set of assess_* functions for pkg_assess
}


================================================
FILE: man/get_package_dependencies.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assess_dependencies.R
\name{get_package_dependencies}
\alias{get_package_dependencies}
\title{Gets available packages from necessary repository and filters for
package of interest}
\usage{
get_package_dependencies(name, repo)
}
\arguments{
\item{name}{package name}

\item{repo}{package repository (e.g. CRAN or Bioconductor)}
}
\value{
Returns a data frame with two columns 1) Package names, 2) type of dependency (LinkingTo, Imports, Depends)
}
\description{
Gets available packages from necessary repository and filters for
package of interest
}
\keyword{internal}


================================================
FILE: man/get_pkg_ref_classes.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_ref_class.R
\name{get_pkg_ref_classes}
\alias{get_pkg_ref_classes}
\title{Walk the pkg_ref class hierarchy to match a single subclass to a class path}
\usage{
get_pkg_ref_classes(x, classes = pkg_ref_class_hierarchy)
}
\arguments{
\item{x}{(`character(1L)`) A subclass, among those known in pkg_ref subclasses}

\item{classes}{(`list`) A class hierarchy, described using a named list.
Defaults to `pkg_ref_class_hierarchy`.}
}
\value{
A `character(n)` class path from `pkg_ref` down to the specified
  subclass, or `FALSE` if no path is found.
}
\description{
Walk the pkg_ref class hierarchy to match a single subclass to a class path
}
\keyword{internal}


================================================
FILE: man/if_not_null_else.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/utils.R
\name{if_not_null_else}
\alias{if_not_null_else}
\alias{\%||\%}
\title{If not NULL else}
\usage{
lhs \%||\% rhs
}
\arguments{
\item{lhs}{Left-hand side}

\item{rhs}{Right-hand side

A shorthand for a common comparison}
}
\value{
an object same as \code{lhs} or \code{rhs}
}
\description{
If not NULL else
}
\keyword{internal}


================================================
FILE: man/inc_mutations_count.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkg_ref_class_extract.R
\name{inc_mutations_count}
\alias{inc_mutations_count}
\title{increment the number of allowed mutations}
\usage{
inc_mutations_count(x)
}
\arguments{
\item{x}{pkg_ref object to increment mutation counter for}
}
\value{
a pkg_ref object
}
\description{
increment the number of allowed mutations
}
\keyword{internal}


================================================
FILE: man/is_url_subpath_of.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/utils.R
\name{is_url_subpath_of}
\alias{is_url_subpath_of}
\title{check if a url originates from a list of repo urls}
\usage{
is_url_subpath_of(url, urls)
}
\arguments{
\item{url}{a url which may stem from one of the provided base urls}

\item{urls}{vector of base urls}
}
\value{
logical vector indicating which base urls have a sub url of
  \code{url}
}
\description{
check if a url originates from a list of repo urls
}
\keyword{internal}


================================================
FILE: man/memoise_bioc_mirrors.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/utils_memoised.R
\name{memoise_bioc_mirrors}
\alias{memoise_bioc_mirrors}
\title{Fetch BioC Mirrors Info}
\usage{
memoise_bioc_mirrors()
}
\value{
a data frame with mirror information
}
\description{
taken from utils::chooseBioCmirror
}
\keyword{internal}


================================================
FILE: man/memoise_cran_mirrors.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/utils_memoised.R
\name{memoise_cran_mirrors}
\alias{memoise_cran_mirrors}
\title{Fetch CRAN Mirrors Info}
\usage{
memoise_cran_mirrors(all = TRUE, ..., .local = getOption("riskmetric.tests"))
}
\arguments{
Download .txt
gitextract_cv8kk3_s/

├── .Rbuildignore
├── .github/
│   ├── .gitignore
│   └── workflows/
│       ├── R-CMD-check.yaml
│       ├── pkgdown.yaml
│       └── test-coverage.yaml
├── .gitignore
├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── NAMESPACE
├── NEWS.md
├── R/
│   ├── assess_covr_coverage.R
│   ├── assess_dependencies.R
│   ├── assess_downloads.R
│   ├── assess_export_help.R
│   ├── assess_exported_namespace.R
│   ├── assess_has_bug_reports_url.R
│   ├── assess_has_examples.R
│   ├── assess_has_maintainer.R
│   ├── assess_has_news.R
│   ├── assess_has_source_control.R
│   ├── assess_has_vignettes.R
│   ├── assess_has_website.R
│   ├── assess_last_30_bugs_status.R
│   ├── assess_license.R
│   ├── assess_news_current.R
│   ├── assess_r_cmd_check.R
│   ├── assess_remote_checks.R
│   ├── assess_reverse_dependencies.R
│   ├── assess_size_codebase.R
│   ├── dev_hint.R
│   ├── dev_tips.R
│   ├── metric_score.R
│   ├── options.R
│   ├── pkg_assess.R
│   ├── pkg_cohort.R
│   ├── pkg_metric.R
│   ├── pkg_metric_condition.R
│   ├── pkg_metric_error.R
│   ├── pkg_metric_na.R
│   ├── pkg_metric_todo.R
│   ├── pkg_ref_cache.R
│   ├── pkg_ref_cache_NEWS_urls.R
│   ├── pkg_ref_cache_archive_release_date.R
│   ├── pkg_ref_cache_behaviors.R
│   ├── pkg_ref_cache_bug_reports.R
│   ├── pkg_ref_cache_bug_reports_host.R
│   ├── pkg_ref_cache_bug_reports_url.R
│   ├── pkg_ref_cache_covr_coverage.R
│   ├── pkg_ref_cache_description.R
│   ├── pkg_ref_cache_downloads.R
│   ├── pkg_ref_cache_examples.R
│   ├── pkg_ref_cache_expr_coverage.R
│   ├── pkg_ref_cache_help.R
│   ├── pkg_ref_cache_help_aliases.R
│   ├── pkg_ref_cache_license.R
│   ├── pkg_ref_cache_maintainer.R
│   ├── pkg_ref_cache_news.R
│   ├── pkg_ref_cache_r_cmd_check.R
│   ├── pkg_ref_cache_release_date.R
│   ├── pkg_ref_cache_remote_checks.R
│   ├── pkg_ref_cache_repo_base_url.R
│   ├── pkg_ref_cache_source_control_url.R
│   ├── pkg_ref_cache_tarball_url.R
│   ├── pkg_ref_cache_vignettes.R
│   ├── pkg_ref_cache_web_html.R
│   ├── pkg_ref_cache_web_url.R
│   ├── pkg_ref_cache_website_urls.R
│   ├── pkg_ref_class.R
│   ├── pkg_ref_class_coersion.R
│   ├── pkg_ref_class_extract.R
│   ├── pkg_ref_class_format.R
│   ├── pkg_ref_class_names.R
│   ├── pkg_score.R
│   ├── riskmetric-package.R
│   ├── summarize_scores.R
│   ├── utils.R
│   ├── utils_memoised.R
│   ├── vctrs_list_of_pkg_metric.R
│   ├── vctrs_list_of_pkg_ref.R
│   └── zzz.R
├── README.md
├── _pkgdown.yml
├── cran-comments.md
├── man/
│   ├── all_assessments.Rd
│   ├── allow_mutation.Rd
│   ├── as_pkg_metric.Rd
│   ├── as_pkg_metric_condition.Rd
│   ├── as_pkg_metric_error.Rd
│   ├── as_pkg_metric_na.Rd
│   ├── as_pkg_metric_todo.Rd
│   ├── assess_covr_coverage.Rd
│   ├── assess_dependencies.Rd
│   ├── assess_downloads_1yr.Rd
│   ├── assess_export_help.Rd
│   ├── assess_exported_namespace.Rd
│   ├── assess_has_bug_reports_url.Rd
│   ├── assess_has_examples.Rd
│   ├── assess_has_maintainer.Rd
│   ├── assess_has_news.Rd
│   ├── assess_has_source_control.Rd
│   ├── assess_has_vignettes.Rd
│   ├── assess_has_website.Rd
│   ├── assess_last_30_bugs_status.Rd
│   ├── assess_license.Rd
│   ├── assess_news_current.Rd
│   ├── assess_r_cmd_check.Rd
│   ├── assess_remote_checks.Rd
│   ├── assess_reverse_dependencies.Rd
│   ├── assess_size_codebase.Rd
│   ├── assessment_error_as_warning.Rd
│   ├── assessment_error_empty.Rd
│   ├── assessment_error_throw.Rd
│   ├── available_pkg_ref_fields.Rd
│   ├── bare_env.Rd
│   ├── bug_report_metadata.Rd
│   ├── cache_behaviors.Rd
│   ├── capture_expr_output.Rd
│   ├── dec_mutations_count.Rd
│   ├── determine_pkg_source.Rd
│   ├── dot-tools.Rd
│   ├── examples_from_dir.Rd
│   ├── examples_from_pkg.Rd
│   ├── filter_rd_db.Rd
│   ├── firstS3method.Rd
│   ├── format_assessment_message.Rd
│   ├── get_assessment_columns.Rd
│   ├── get_assessments.Rd
│   ├── get_package_dependencies.Rd
│   ├── get_pkg_ref_classes.Rd
│   ├── if_not_null_else.Rd
│   ├── inc_mutations_count.Rd
│   ├── is_url_subpath_of.Rd
│   ├── memoise_bioc_mirrors.Rd
│   ├── memoise_cran_mirrors.Rd
│   ├── metric_score.Rd
│   ├── metric_score.pkg_metric_covr_coverage.Rd
│   ├── metric_score.pkg_metric_dependencies.Rd
│   ├── metric_score.pkg_metric_downloads_1yr.Rd
│   ├── metric_score.pkg_metric_export_help.Rd
│   ├── metric_score.pkg_metric_exported_namespace.Rd
│   ├── metric_score.pkg_metric_has_bug_reports_url.Rd
│   ├── metric_score.pkg_metric_has_examples.Rd
│   ├── metric_score.pkg_metric_has_maintainer.Rd
│   ├── metric_score.pkg_metric_has_news.Rd
│   ├── metric_score.pkg_metric_has_source_control.Rd
│   ├── metric_score.pkg_metric_has_vignettes.Rd
│   ├── metric_score.pkg_metric_has_website.Rd
│   ├── metric_score.pkg_metric_last_30_bugs_status.Rd
│   ├── metric_score.pkg_metric_license.Rd
│   ├── metric_score.pkg_metric_news_current.Rd
│   ├── metric_score.pkg_metric_r_cmd_check.Rd
│   ├── metric_score.pkg_metric_remote_checks.Rd
│   ├── metric_score.pkg_metric_reverse_dependencies.Rd
│   ├── metric_score.pkg_metric_size_codebase.Rd
│   ├── news_from_dir.Rd
│   ├── parse_dcf_dependencies.Rd
│   ├── pkg_assess.Rd
│   ├── pkg_metric.Rd
│   ├── pkg_metric_eval.Rd
│   ├── pkg_ref.Rd
│   ├── pkg_ref_cache.bug_reports_host.default.Rd
│   ├── pkg_ref_cache.bug_reports_url.pkg_source.Rd
│   ├── pkg_ref_cache.covr_coverage.pkg_source.Rd
│   ├── pkg_ref_cache.expression_coverage.pkg_source.Rd
│   ├── pkg_ref_cache.help.pkg_install.Rd
│   ├── pkg_ref_cache.help.pkg_source.Rd
│   ├── pkg_ref_cache.news.pkg_remote.Rd
│   ├── pkg_ref_class_hierarchy.Rd
│   ├── pkg_ref_mutability_error.Rd
│   ├── pkg_score.Rd
│   ├── print.with_eval_recording.Rd
│   ├── remove_base_packages.Rd
│   ├── require_cache_behaviors.Rd
│   ├── riskmetric.Rd
│   ├── riskmetric_metadata_caching.Rd
│   ├── roxygen_assess_family.Rd
│   ├── roxygen_assess_family_catalog.Rd
│   ├── roxygen_cache_behaviors.Rd
│   ├── roxygen_score_family.Rd
│   ├── score_error_NA.Rd
│   ├── score_error_default.Rd
│   ├── score_error_zero.Rd
│   ├── sub-sub-.pkg_ref.Rd
│   ├── summarize_scores.Rd
│   ├── suppressMatchingConditions.Rd
│   ├── use_assessments_column_names.Rd
│   ├── verify_pkg_source.Rd
│   ├── vignettes_from_dir.Rd
│   ├── vignettes_from_html.Rd
│   ├── with.pkg_ref.Rd
│   └── with_unclassed_to.Rd
└── tests/
    ├── testthat/
    │   ├── setup_mock_web_requests.R
    │   ├── setup_test_packages.R
    │   ├── teardown_mock_web_requests.R
    │   ├── teardown_test_packages.R
    │   ├── test_assess.R
    │   ├── test_assess_dependencies.R
    │   ├── test_assess_export_help.R
    │   ├── test_assess_has_bug_reports_url.R
    │   ├── test_assess_has_examples.R
    │   ├── test_assess_has_news.R
    │   ├── test_assess_last_30_bugs_status.R
    │   ├── test_assess_news_current.R
    │   ├── test_metric_score_labels.R
    │   ├── test_metric_score_range.R
    │   ├── test_packages/
    │   │   ├── pkgsourcebad/
    │   │   │   ├── DESCRIPTION
    │   │   │   ├── NAMESPACE
    │   │   │   ├── R/
    │   │   │   │   └── hello_world_test.R
    │   │   │   └── man/
    │   │   │       └── hello_world_test.Rd
    │   │   ├── pkgsourcebad2/
    │   │   │   └── DESCRIPTION
    │   │   ├── pkgsourcegood/
    │   │   │   ├── DESCRIPTION
    │   │   │   ├── NAMESPACE
    │   │   │   ├── NEWS.md
    │   │   │   ├── R/
    │   │   │   │   └── hello_world_test.R
    │   │   │   └── man/
    │   │   │       └── hello_world_test.Rd
    │   │   └── secondLib/
    │   │       └── secondLibPkg/
    │   │           ├── DESCRIPTION
    │   │           ├── NAMESPACE
    │   │           ├── NEWS.md
    │   │           ├── R/
    │   │           │   └── hello_world_test.R
    │   │           └── man/
    │   │               └── hello_world_test.Rd
    │   ├── test_pkg_ref.R
    │   ├── test_snapshots.R
    │   └── test_webmocks/
    │       ├── data/
    │       │   ├── cran_mirrors.csv
    │       │   ├── cran_news.html
    │       │   ├── cran_package.html
    │       │   ├── cran_package_archive.html
    │       │   ├── cran_package_checks.html
    │       │   ├── cran_packages.csv
    │       │   └── github_repo_issues_api_response.json
    │       └── rebuild_webmocks.R
    └── testthat.R
Condensed preview — 232 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (356K chars).
[
  {
    "path": ".Rbuildignore",
    "chars": 163,
    "preview": "^codecov\\.yml$\n^appveyor\\.yml$\n^\\.travis\\.yml$\n^\\.github\n^.*\\.Rproj$\n^\\.Rproj\\.user$\n^LICENSE\\.md$\n^_pkgdown\\.yml$\n^docs"
  },
  {
    "path": ".github/.gitignore",
    "chars": 7,
    "preview": "*.html\n"
  },
  {
    "path": ".github/workflows/R-CMD-check.yaml",
    "chars": 2182,
    "preview": "# Workflow derived from https://github.com/r-lib/actions/tree/master/examples\n# Need help debugging build failures? Star"
  },
  {
    "path": ".github/workflows/pkgdown.yaml",
    "chars": 917,
    "preview": "# Workflow derived from https://github.com/r-lib/actions/tree/master/examples\n# Need help debugging build failures? Star"
  },
  {
    "path": ".github/workflows/test-coverage.yaml",
    "chars": 710,
    "preview": "# Workflow derived from https://github.com/r-lib/actions/tree/master/examples\n# Need help debugging build failures? Star"
  },
  {
    "path": ".gitignore",
    "chars": 114,
    "preview": ".DS_Store\nvignettes\n!vignettes/*.Rmd\ninst/doc\ndocs\n.Rproj.user\n.Rhistory\n.RData\n.Ruserdata\n.html\nriskmetric.Rproj\n"
  },
  {
    "path": "DESCRIPTION",
    "chars": 1488,
    "preview": "Package: riskmetric\nType: Package\nTitle: Risk Metrics to Evaluating R Packages\nDescription: Facilities for assessing R p"
  },
  {
    "path": "LICENSE",
    "chars": 118,
    "preview": "YEAR: 2019\nCOPYRIGHT HOLDER: PSI special interest group Application and Implementation of Methodologies in Statistics\n"
  },
  {
    "path": "LICENSE.md",
    "chars": 1150,
    "preview": "pkg# MIT License\n\nCopyright (c) 2019 PSI special interest group Application and Implementation of Methodologies in Stati"
  },
  {
    "path": "NAMESPACE",
    "chars": 5726,
    "preview": "# Generated by roxygen2: do not edit by hand\n\nS3method(\"$\",pkg_ref)\nS3method(\"$<-\",pkg_ref)\nS3method(\"[\",pkg_ref)\nS3meth"
  },
  {
    "path": "NEWS.md",
    "chars": 1734,
    "preview": "# riskmetric (development version)\n\n# riskmetric 0.2.6\n\n- Update to address new failing tests responding to `devtools` v"
  },
  {
    "path": "R/assess_covr_coverage.R",
    "chars": 1401,
    "preview": "#' Assess a package code coverage using the `covr` package\n#'\n#' @eval roxygen_assess_family(\n#'   \"covr_coverage\",\n#'  "
  },
  {
    "path": "R/assess_dependencies.R",
    "chars": 5002,
    "preview": "#' Assessment of dependency footprint for a specific package\n#'\n#' Only Depends, Imports and LinkingTo dependencies are "
  },
  {
    "path": "R/assess_downloads.R",
    "chars": 2023,
    "preview": "#' Assess a package for the number of downloads in the past year\n#'\n#' @details The more times a package has been downlo"
  },
  {
    "path": "R/assess_export_help.R",
    "chars": 3861,
    "preview": "#' Assess a package for availability of documentation for exported values\n#'\n#' @eval roxygen_assess_family(\n#'   \"expor"
  },
  {
    "path": "R/assess_exported_namespace.R",
    "chars": 2225,
    "preview": "#' Assess a package's results from running R CMD check\n#'\n#' @eval roxygen_assess_family(\n#'   \"exported_namespace\",\n#' "
  },
  {
    "path": "R/assess_has_bug_reports_url.R",
    "chars": 1151,
    "preview": "#' Assess a package for the presence of a url field where bugs can be reported.\n#'\n#' @eval roxygen_assess_family(\n#' \"h"
  },
  {
    "path": "R/assess_has_examples.R",
    "chars": 1238,
    "preview": "#' Assess a package for the presence of example or usage fields in function documentation\n#'\n#' @eval roxygen_assess_fam"
  },
  {
    "path": "R/assess_has_maintainer.R",
    "chars": 1020,
    "preview": "#' Assess a package for an associated maintainer\n#'\n#' @eval roxygen_assess_family(\n#'   \"has_maintainer\",\n#'   \"a chara"
  },
  {
    "path": "R/assess_has_news.R",
    "chars": 1027,
    "preview": "#' Assess a package for the presence of a NEWS file\n#'\n#' @eval roxygen_assess_family(\n#'   \"has_news\",\n#'   \"an integer"
  },
  {
    "path": "R/assess_has_source_control.R",
    "chars": 1138,
    "preview": "#' Assess a package for an associated source control url\n#'\n#' @eval roxygen_assess_family(\n#'   \"has_source_control\",\n#"
  },
  {
    "path": "R/assess_has_vignettes.R",
    "chars": 1113,
    "preview": "#' Assess a package for the presence of Vignettes files\n#'\n#' @eval roxygen_assess_family(\n#'   \"has_vignettes\",\n#'   \"a"
  },
  {
    "path": "R/assess_has_website.R",
    "chars": 993,
    "preview": "#' Assess a package for an associated website url\n#'\n#' @eval roxygen_assess_family(\n#'   \"has_website\",\n#'   \"a charact"
  },
  {
    "path": "R/assess_last_30_bugs_status.R",
    "chars": 1395,
    "preview": "#' Assess how many recent BugReports have been closed\n#'\n#' @eval roxygen_assess_family(\n#'   \"last_30_bugs_status\",\n#' "
  },
  {
    "path": "R/assess_license.R",
    "chars": 894,
    "preview": "#' Assess a package for an acceptable license\n#'\n#' @eval roxygen_assess_family(\n#'   \"license\",\n#'   \"a string indicati"
  },
  {
    "path": "R/assess_news_current.R",
    "chars": 1648,
    "preview": "#' Assess a package for an up-to-date NEWS file\n#'\n#' @eval roxygen_assess_family(\n#'   \"news_current\",\n#'   \"a logical "
  },
  {
    "path": "R/assess_r_cmd_check.R",
    "chars": 2195,
    "preview": "#' Assess a package's results from running R CMD check\n#'\n#' @eval roxygen_assess_family(\n#'   \"r_cmd_check\",\n#'   \"Tall"
  },
  {
    "path": "R/assess_remote_checks.R",
    "chars": 1978,
    "preview": "#' Assess package checks from CRAN/Bioc or R CMD check\n#'\n#' @eval roxygen_assess_family(\n#'   \"remote_checks\",\n#'   \"Ta"
  },
  {
    "path": "R/assess_reverse_dependencies.R",
    "chars": 1923,
    "preview": "#' Generate list of Reverse Dependencies for a package\n#'\n#' @details The more packages that depend on a package the mor"
  },
  {
    "path": "R/assess_size_codebase.R",
    "chars": 2845,
    "preview": "#' Assess a package for size of code base\n#'\n#' @eval roxygen_assess_family(\n#'   \"size_codebase\",\n#'   \"a numeric value"
  },
  {
    "path": "R/dev_hint.R",
    "chars": 3491,
    "preview": "#' dev_hint <- function(title, text, format_args = list()) {\n#'   if (is.character(text)) text <- list(dev_hint_section("
  },
  {
    "path": "R/dev_tips.R",
    "chars": 214,
    "preview": "#' #' Provide tips for improving a metric\n#' #'\n#' #' @param x a pkg_metric object\n#' #' @param ... additional arguments"
  },
  {
    "path": "R/metric_score.R",
    "chars": 2091,
    "preview": "#' Score a package metric\n#'\n#' Convert a package metric into a numeric value between 0 to 1\n#'\n#' @param x A \\code{pkg_"
  },
  {
    "path": "R/options.R",
    "chars": 124,
    "preview": "riskmetric.options <- list(\n  gitlab_api_host = \"https://gitlab.com/api/v4\",\n  github_api_host = \"https://api.github.com"
  },
  {
    "path": "R/pkg_assess.R",
    "chars": 6920,
    "preview": "#' Helper for creating a roxygen header from template for assess_* functions\n#'\n#' @param name the name of the assessmen"
  },
  {
    "path": "R/pkg_cohort.R",
    "chars": 102,
    "preview": "#' @family pkg_ref\npkg_cohort <- function() {\n  structure(\n    list(),\n    class = \"pkg_cohort\"\n  )\n}\n"
  },
  {
    "path": "R/pkg_metric.R",
    "chars": 2292,
    "preview": "#' A helper for structuring assessment return objects for dispatch with the\n#' score function\n#'\n#' @param x data to sto"
  },
  {
    "path": "R/pkg_metric_condition.R",
    "chars": 714,
    "preview": "#' A pkg_metric subclass for general metric evaluation conditions\n#'\n#' @param x an object to wrap in a \\code{pkg_metric"
  },
  {
    "path": "R/pkg_metric_error.R",
    "chars": 2660,
    "preview": "#' A subclass wrapping an error with an additional parent class\n#'\n#' @param error an error condition object to capture\n"
  },
  {
    "path": "R/pkg_metric_na.R",
    "chars": 468,
    "preview": "#' A pkg_metric subclass for when metrics are explicitly not applicable\n#'\n#' @param x a \\code{pkg_metric} object to wra"
  },
  {
    "path": "R/pkg_metric_todo.R",
    "chars": 544,
    "preview": "#' A pkg_metric subclass for when pkg_metrics have not yet been implemented\n#'\n#' @param x a \\code{pkg_metric} object to"
  },
  {
    "path": "R/pkg_ref_cache.R",
    "chars": 4882,
    "preview": "#' S3 generic to calculate a `pkg_ref` field\n#'\n#' Reactively retrieve and cache `pkg_ref` metadata\n#'\n#' @section Cachi"
  },
  {
    "path": "R/pkg_ref_cache_NEWS_urls.R",
    "chars": 1147,
    "preview": "#' Cache appropriate urls for NEWS files\n#'\n#' @inheritParams pkg_ref_cache\n#' @family package reference cache\n#' @retur"
  },
  {
    "path": "R/pkg_ref_cache_archive_release_date.R",
    "chars": 804,
    "preview": "#' Cache a List of Archived Package Release Date from a Package Reference\n#'\n#' @inheritParams pkg_ref_cache\n#' @family "
  },
  {
    "path": "R/pkg_ref_cache_behaviors.R",
    "chars": 2457,
    "preview": "#' List of available caching behaviors with metadata, including default and\n#' annotations for building documentation\n#'"
  },
  {
    "path": "R/pkg_ref_cache_bug_reports.R",
    "chars": 2395,
    "preview": "#' Retrieve a list of BugReports metadata\n#'\n#' @inheritParams pkg_ref_cache\n#' @family package reference cache\n#' @retu"
  },
  {
    "path": "R/pkg_ref_cache_bug_reports_host.R",
    "chars": 606,
    "preview": "#' Get the host name of a BugReports url\n#'\n#' @inheritParams pkg_ref_cache\n#' @family package reference cache\n#' @retur"
  },
  {
    "path": "R/pkg_ref_cache_bug_reports_url.R",
    "chars": 1556,
    "preview": "#' Get the BugReports url\n#'\n#' @inheritParams pkg_ref_cache\n#' @family package reference cache\n#' @return a \\code{pkg_r"
  },
  {
    "path": "R/pkg_ref_cache_covr_coverage.R",
    "chars": 937,
    "preview": "#' Retrieve output of covr::package_coverage\n#'\n#' @inheritParams pkg_ref_cache\n#' @family package reference cache\n#' @r"
  },
  {
    "path": "R/pkg_ref_cache_description.R",
    "chars": 530,
    "preview": "#' Cache the DESCRIPTION file contents for a package reference\n#'\n#'\n#' @inheritParams pkg_ref_cache\n#' @family package "
  },
  {
    "path": "R/pkg_ref_cache_downloads.R",
    "chars": 420,
    "preview": "#' Cache a list of available help files as LaTeX objects\n#' @param n Number of days to look back with default value of 3"
  },
  {
    "path": "R/pkg_ref_cache_examples.R",
    "chars": 2255,
    "preview": "#' Cache the examples available for exported objects for a package reference\n#'\n#' @inheritParams pkg_ref_cache\n#' @fami"
  },
  {
    "path": "R/pkg_ref_cache_expr_coverage.R",
    "chars": 597,
    "preview": "#' Retrieve output of covr::package_coverage, tallied by expression\n#'\n#' @inheritParams pkg_ref_cache\n#' @family packag"
  },
  {
    "path": "R/pkg_ref_cache_help.R",
    "chars": 738,
    "preview": "#' Cache a list of available help files as LaTeX objects\n#'\n#' @inheritParams pkg_ref_cache\n#' @family package reference"
  },
  {
    "path": "R/pkg_ref_cache_help_aliases.R",
    "chars": 1177,
    "preview": "#' Cache a character vector mapping exported values to documentation filenames\n#'\n#' @inheritParams pkg_ref_cache\n#' @fa"
  },
  {
    "path": "R/pkg_ref_cache_license.R",
    "chars": 961,
    "preview": "#' Get the package license\n#'\n#' @inheritParams pkg_ref_cache\n#' @family package reference cache\n#' @return a \\code{pkg_"
  },
  {
    "path": "R/pkg_ref_cache_maintainer.R",
    "chars": 1169,
    "preview": "#' Cache package's Maintainer\n#'\n#' @inheritParams pkg_ref_cache\n#' @family package reference cache\n#' @return a \\code{p"
  },
  {
    "path": "R/pkg_ref_cache_news.R",
    "chars": 2095,
    "preview": "#' Cache a list of NEWS files from a package reference\n#'\n#' @inheritParams pkg_ref_cache\n#' @family package reference c"
  },
  {
    "path": "R/pkg_ref_cache_r_cmd_check.R",
    "chars": 635,
    "preview": "#' Run R CMD check and capture the results\n#'\n#' @inheritParams pkg_ref_cache\n#' @family package reference cache\n#' @ret"
  },
  {
    "path": "R/pkg_ref_cache_release_date.R",
    "chars": 744,
    "preview": "#' Cache a List of Package Release Date from a Package Reference\n#'\n#' @inheritParams pkg_ref_cache\n#' @family package r"
  },
  {
    "path": "R/pkg_ref_cache_remote_checks.R",
    "chars": 1934,
    "preview": "#' Retrieve a CRAN or Bioc checks or run R CMD check\n#'\n#' @inheritParams pkg_ref_cache\n#' @family package reference cac"
  },
  {
    "path": "R/pkg_ref_cache_repo_base_url.R",
    "chars": 393,
    "preview": "#' Cache value of a package's source repo's URL\n#'\n#' @inheritParams pkg_ref_cache\n#' @family package reference cache\n#'"
  },
  {
    "path": "R/pkg_ref_cache_source_control_url.R",
    "chars": 334,
    "preview": "#' Cache package's Source Control URL\n#'\n#' @inheritParams pkg_ref_cache\n#' @family package reference cache\n#' @return a"
  },
  {
    "path": "R/pkg_ref_cache_tarball_url.R",
    "chars": 408,
    "preview": "#' Cache value of a package's source tarball URL\n#'\n#' @inheritParams pkg_ref_cache\n#' @family package reference cache\n#"
  },
  {
    "path": "R/pkg_ref_cache_vignettes.R",
    "chars": 1859,
    "preview": "#' Cache a List of Vignettes Files from a Package Reference\n#'\n#' @inheritParams pkg_ref_cache\n#' @family package refere"
  },
  {
    "path": "R/pkg_ref_cache_web_html.R",
    "chars": 536,
    "preview": "#' Cache package's remote display page HTML\n#'\n#' @inheritParams pkg_ref_cache\n#' @family package reference cache\n#' @re"
  },
  {
    "path": "R/pkg_ref_cache_web_url.R",
    "chars": 512,
    "preview": "#' Cache package's remote web URL\n#'\n#' @inheritParams pkg_ref_cache\n#' @family package reference cache\n#' @return a \\co"
  },
  {
    "path": "R/pkg_ref_cache_website_urls.R",
    "chars": 692,
    "preview": "#' Cache package's Website URL\n#'\n#' @inheritParams pkg_ref_cache\n#' @family package reference cache\n#' @return a \\code{"
  },
  {
    "path": "R/pkg_ref_class.R",
    "chars": 12038,
    "preview": "#' Create a package reference\n#'\n#' Create a package reference from package name or filepath, producing an object\n#' in "
  },
  {
    "path": "R/pkg_ref_class_coersion.R",
    "chars": 561,
    "preview": "#' @importFrom tibble as_tibble\n#' @method as_tibble pkg_ref\n#' @export\nas_tibble.pkg_ref <- function(x, ...) {\n  as_tib"
  },
  {
    "path": "R/pkg_ref_class_extract.R",
    "chars": 4204,
    "preview": "#' @export\n`$.pkg_ref` <- function(x, name) {\n  `[[`(x, as.character(name))\n}\n\n\n\n#' @export\n`$<-.pkg_ref` <- function(x,"
  },
  {
    "path": "R/pkg_ref_class_format.R",
    "chars": 1882,
    "preview": "#' @importFrom utils head capture.output\n#' @export\nprint.pkg_ref <- function(x, ...) {\n  xx <- as.list(x)\n  ns <- names"
  },
  {
    "path": "R/pkg_ref_class_names.R",
    "chars": 223,
    "preview": "#' @importFrom utils .DollarNames\n#' @export\n`.DollarNames.pkg_ref` <- function(x, pattern) {\n  names(x)\n}\n\n\n\n#' @export"
  },
  {
    "path": "R/pkg_score.R",
    "chars": 4452,
    "preview": "#' Score a package assessment, collapsing results into a single numeric\n#'\n#' pkg_score() calculates the risk involved w"
  },
  {
    "path": "R/riskmetric-package.R",
    "chars": 252,
    "preview": "#' riskmetric\n#'\n#' Facilities for assessing R packages against a number of metrics to help\n#' quantify their robustness"
  },
  {
    "path": "R/summarize_scores.R",
    "chars": 2690,
    "preview": "#' Summarize a default set of assessments into a single risk score\n#'\n#' This function serves as an example for how a ri"
  },
  {
    "path": "R/utils.R",
    "chars": 10968,
    "preview": "#' If not NULL else\n#'\n#' @param lhs Left-hand side\n#' @param rhs Right-hand side\n#'\n#' A shorthand for a common compari"
  },
  {
    "path": "R/utils_memoised.R",
    "chars": 2690,
    "preview": "#' Fetch CRAN Mirrors Info\n#'\n#' @param all default \\code{TRUE}, passed to \\code{\\link{utils}[getCRANmirrors]}\n#' @param"
  },
  {
    "path": "R/vctrs_list_of_pkg_metric.R",
    "chars": 946,
    "preview": "#' @importFrom pillar pillar_shaft\n#' @method pillar_shaft list_of_pkg_metric\n#' @export\npillar_shaft.list_of_pkg_metric"
  },
  {
    "path": "R/vctrs_list_of_pkg_ref.R",
    "chars": 260,
    "preview": "#' @importFrom pillar pillar_shaft new_pillar_shaft_simple\n#' @method pillar_shaft list_of_pkg_ref\n#' @export\npillar_sha"
  },
  {
    "path": "R/zzz.R",
    "chars": 700,
    "preview": "#' @importFrom backports import\n#' @keywords internal\n.onLoad <- function(libname, pkgname) {\n  backports::import(pkgnam"
  },
  {
    "path": "README.md",
    "chars": 4680,
    "preview": "# riskmetric <a href='https://pharmar.github.io/riskmetric/'><img src=\"man/figures/logo.png\" align=\"right\" height=\"172\" "
  },
  {
    "path": "_pkgdown.yml",
    "chars": 989,
    "preview": "template:\n  bootstrap: 5\n\nreference:\n  - title: \"Package Reference\"\n    desc: \"Create Package Reference for Each Package"
  },
  {
    "path": "cran-comments.md",
    "chars": 165,
    "preview": "## riskmetric 0.2.5\n\nResolved issues with CRAN checks.\n\nTested on Ubuntu Jammy, GitHub Action, and RHub.\n\n## R CMD check"
  },
  {
    "path": "man/all_assessments.Rd",
    "chars": 370,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_assess.R\n\\name{all_assessments}\n\\alias"
  },
  {
    "path": "man/allow_mutation.Rd",
    "chars": 762,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_class_extract.R\n\\name{allow_mutati"
  },
  {
    "path": "man/as_pkg_metric.Rd",
    "chars": 450,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_metric.R\n\\name{as_pkg_metric}\n\\alias{a"
  },
  {
    "path": "man/as_pkg_metric_condition.Rd",
    "chars": 692,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_metric_condition.R\n\\name{as_pkg_metric"
  },
  {
    "path": "man/as_pkg_metric_error.Rd",
    "chars": 497,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_metric_error.R\n\\name{as_pkg_metric_err"
  },
  {
    "path": "man/as_pkg_metric_na.Rd",
    "chars": 618,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_metric_na.R\n\\name{as_pkg_metric_na}\n\\a"
  },
  {
    "path": "man/as_pkg_metric_todo.Rd",
    "chars": 697,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_metric_todo.R\n\\name{as_pkg_metric_todo"
  },
  {
    "path": "man/assess_covr_coverage.Rd",
    "chars": 843,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_covr_coverage.R\n\\name{assess_covr_c"
  },
  {
    "path": "man/assess_dependencies.Rd",
    "chars": 851,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_dependencies.R\n\\name{assess_depende"
  },
  {
    "path": "man/assess_downloads_1yr.Rd",
    "chars": 883,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_downloads.R\n\\name{assess_downloads_"
  },
  {
    "path": "man/assess_export_help.Rd",
    "chars": 743,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_export_help.R\n\\name{assess_export_h"
  },
  {
    "path": "man/assess_exported_namespace.Rd",
    "chars": 739,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_exported_namespace.R\n\\name{assess_e"
  },
  {
    "path": "man/assess_has_bug_reports_url.Rd",
    "chars": 781,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_has_bug_reports_url.R\n\\name{assess_"
  },
  {
    "path": "man/assess_has_examples.Rd",
    "chars": 777,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_has_examples.R\n\\name{assess_has_exa"
  },
  {
    "path": "man/assess_has_maintainer.Rd",
    "chars": 692,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_has_maintainer.R\n\\name{assess_has_m"
  },
  {
    "path": "man/assess_has_news.Rd",
    "chars": 664,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_has_news.R\n\\name{assess_has_news}\n\\"
  },
  {
    "path": "man/assess_has_source_control.Rd",
    "chars": 740,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_has_source_control.R\n\\name{assess_h"
  },
  {
    "path": "man/assess_has_vignettes.Rd",
    "chars": 707,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_has_vignettes.R\n\\name{assess_has_vi"
  },
  {
    "path": "man/assess_has_website.Rd",
    "chars": 677,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_has_website.R\n\\name{assess_has_webs"
  },
  {
    "path": "man/assess_last_30_bugs_status.Rd",
    "chars": 736,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_last_30_bugs_status.R\n\\name{assess_"
  },
  {
    "path": "man/assess_license.Rd",
    "chars": 650,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_license.R\n\\name{assess_license}\n\\al"
  },
  {
    "path": "man/assess_news_current.Rd",
    "chars": 692,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_news_current.R\n\\name{assess_news_cu"
  },
  {
    "path": "man/assess_r_cmd_check.Rd",
    "chars": 693,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_r_cmd_check.R\n\\name{assess_r_cmd_ch"
  },
  {
    "path": "man/assess_remote_checks.Rd",
    "chars": 708,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_remote_checks.R\n\\name{assess_remote"
  },
  {
    "path": "man/assess_reverse_dependencies.Rd",
    "chars": 820,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_reverse_dependencies.R\n\\name{assess"
  },
  {
    "path": "man/assess_size_codebase.Rd",
    "chars": 673,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_size_codebase.R\n\\name{assess_size_c"
  },
  {
    "path": "man/assessment_error_as_warning.Rd",
    "chars": 844,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_metric_error.R\n\\name{assessment_error_"
  },
  {
    "path": "man/assessment_error_empty.Rd",
    "chars": 665,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_metric_error.R\n\\name{assessment_error_"
  },
  {
    "path": "man/assessment_error_throw.Rd",
    "chars": 813,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_metric_error.R\n\\name{assessment_error_"
  },
  {
    "path": "man/available_pkg_ref_fields.Rd",
    "chars": 650,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_cache.R\n\\name{available_pkg_ref_fi"
  },
  {
    "path": "man/bare_env.Rd",
    "chars": 738,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_class_extract.R\n\\name{bare_env}\n\\a"
  },
  {
    "path": "man/bug_report_metadata.Rd",
    "chars": 610,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_cache_bug_reports.R\n\\name{bug_repo"
  },
  {
    "path": "man/cache_behaviors.Rd",
    "chars": 567,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_cache_behaviors.R\n\\docType{data}\n\\"
  },
  {
    "path": "man/capture_expr_output.Rd",
    "chars": 1022,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/utils.R\n\\name{capture_expr_output}\n\\alias{"
  },
  {
    "path": "man/dec_mutations_count.Rd",
    "chars": 415,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_class_extract.R\n\\name{dec_mutation"
  },
  {
    "path": "man/determine_pkg_source.Rd",
    "chars": 547,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_class.R\n\\name{determine_pkg_source"
  },
  {
    "path": "man/dot-tools.Rd",
    "chars": 285,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/utils.R\n\\name{.tools}\n\\alias{.tools}\n\\titl"
  },
  {
    "path": "man/examples_from_dir.Rd",
    "chars": 587,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_cache_examples.R\n\\name{examples_fr"
  },
  {
    "path": "man/examples_from_pkg.Rd",
    "chars": 566,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_cache_examples.R\n\\name{examples_fr"
  },
  {
    "path": "man/filter_rd_db.Rd",
    "chars": 525,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_cache_examples.R\n\\name{filter_rd_d"
  },
  {
    "path": "man/firstS3method.Rd",
    "chars": 742,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/utils.R\n\\name{firstS3method}\n\\alias{firstS"
  },
  {
    "path": "man/format_assessment_message.Rd",
    "chars": 820,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_metric_error.R\n\\name{format_assessment"
  },
  {
    "path": "man/get_assessment_columns.Rd",
    "chars": 523,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_assess.R\n\\name{get_assessment_columns}"
  },
  {
    "path": "man/get_assessments.Rd",
    "chars": 450,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_assess.R\n\\name{get_assessments}\n\\alias"
  },
  {
    "path": "man/get_package_dependencies.Rd",
    "chars": 646,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_dependencies.R\n\\name{get_package_de"
  },
  {
    "path": "man/get_pkg_ref_classes.Rd",
    "chars": 739,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_class.R\n\\name{get_pkg_ref_classes}"
  },
  {
    "path": "man/if_not_null_else.Rd",
    "chars": 412,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/utils.R\n\\name{if_not_null_else}\n\\alias{if_"
  },
  {
    "path": "man/inc_mutations_count.Rd",
    "chars": 417,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_class_extract.R\n\\name{inc_mutation"
  },
  {
    "path": "man/is_url_subpath_of.Rd",
    "chars": 520,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/utils.R\n\\name{is_url_subpath_of}\n\\alias{is"
  },
  {
    "path": "man/memoise_bioc_mirrors.Rd",
    "chars": 334,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/utils_memoised.R\n\\name{memoise_bioc_mirror"
  },
  {
    "path": "man/memoise_cran_mirrors.Rd",
    "chars": 741,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/utils_memoised.R\n\\name{memoise_cran_mirror"
  },
  {
    "path": "man/metric_score.Rd",
    "chars": 423,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/metric_score.R\n\\name{metric_score}\n\\alias{"
  },
  {
    "path": "man/metric_score.pkg_metric_covr_coverage.Rd",
    "chars": 612,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_covr_coverage.R\n\\name{metric_score."
  },
  {
    "path": "man/metric_score.pkg_metric_dependencies.Rd",
    "chars": 1098,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_dependencies.R\n\\name{metric_score.p"
  },
  {
    "path": "man/metric_score.pkg_metric_downloads_1yr.Rd",
    "chars": 1204,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_downloads.R\n\\name{metric_score.pkg_"
  },
  {
    "path": "man/metric_score.pkg_metric_export_help.Rd",
    "chars": 681,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_export_help.R\n\\name{metric_score.pk"
  },
  {
    "path": "man/metric_score.pkg_metric_exported_namespace.Rd",
    "chars": 1257,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_exported_namespace.R\n\\name{metric_s"
  },
  {
    "path": "man/metric_score.pkg_metric_has_bug_reports_url.Rd",
    "chars": 718,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_has_bug_reports_url.R\n\\name{metric_"
  },
  {
    "path": "man/metric_score.pkg_metric_has_examples.Rd",
    "chars": 702,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_has_examples.R\n\\name{metric_score.p"
  },
  {
    "path": "man/metric_score.pkg_metric_has_maintainer.Rd",
    "chars": 738,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_has_maintainer.R\n\\name{metric_score"
  },
  {
    "path": "man/metric_score.pkg_metric_has_news.Rd",
    "chars": 642,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_has_news.R\n\\name{metric_score.pkg_m"
  },
  {
    "path": "man/metric_score.pkg_metric_has_source_control.Rd",
    "chars": 779,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_has_source_control.R\n\\name{metric_s"
  },
  {
    "path": "man/metric_score.pkg_metric_has_vignettes.Rd",
    "chars": 686,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_has_vignettes.R\n\\name{metric_score."
  },
  {
    "path": "man/metric_score.pkg_metric_has_website.Rd",
    "chars": 716,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_has_website.R\n\\name{metric_score.pk"
  },
  {
    "path": "man/metric_score.pkg_metric_last_30_bugs_status.Rd",
    "chars": 770,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_last_30_bugs_status.R\n\\name{metric_"
  },
  {
    "path": "man/metric_score.pkg_metric_license.Rd",
    "chars": 554,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_license.R\n\\name{metric_score.pkg_me"
  },
  {
    "path": "man/metric_score.pkg_metric_news_current.Rd",
    "chars": 680,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_news_current.R\n\\name{metric_score.p"
  },
  {
    "path": "man/metric_score.pkg_metric_r_cmd_check.Rd",
    "chars": 884,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_r_cmd_check.R\n\\name{metric_score.pk"
  },
  {
    "path": "man/metric_score.pkg_metric_remote_checks.Rd",
    "chars": 833,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_remote_checks.R\n\\name{metric_score."
  },
  {
    "path": "man/metric_score.pkg_metric_reverse_dependencies.Rd",
    "chars": 1304,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_reverse_dependencies.R\n\\name{metric"
  },
  {
    "path": "man/metric_score.pkg_metric_size_codebase.Rd",
    "chars": 710,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_size_codebase.R\n\\name{metric_score."
  },
  {
    "path": "man/news_from_dir.Rd",
    "chars": 462,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_cache_news.R\n\\name{news_from_dir}\n"
  },
  {
    "path": "man/parse_dcf_dependencies.Rd",
    "chars": 343,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_dependencies.R\n\\name{parse_dcf_depe"
  },
  {
    "path": "man/pkg_assess.Rd",
    "chars": 3140,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_assess.R\n\\name{pkg_assess}\n\\alias{pkg_"
  },
  {
    "path": "man/pkg_metric.Rd",
    "chars": 620,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_metric.R\n\\name{pkg_metric}\n\\alias{pkg_"
  },
  {
    "path": "man/pkg_metric_eval.Rd",
    "chars": 795,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_metric.R\n\\name{pkg_metric_eval}\n\\alias"
  },
  {
    "path": "man/pkg_ref.Rd",
    "chars": 4137,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_class.R\n\\name{pkg_ref}\n\\alias{pkg_"
  },
  {
    "path": "man/pkg_ref_cache.bug_reports_host.default.Rd",
    "chars": 424,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_cache_bug_reports_host.R\n\\name{pkg"
  },
  {
    "path": "man/pkg_ref_cache.bug_reports_url.pkg_source.Rd",
    "chars": 399,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_cache_bug_reports_url.R\n\\name{pkg_"
  },
  {
    "path": "man/pkg_ref_cache.covr_coverage.pkg_source.Rd",
    "chars": 429,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_cache_covr_coverage.R\n\\name{pkg_re"
  },
  {
    "path": "man/pkg_ref_cache.expression_coverage.pkg_source.Rd",
    "chars": 493,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_cache_expr_coverage.R\n\\name{pkg_re"
  },
  {
    "path": "man/pkg_ref_cache.help.pkg_install.Rd",
    "chars": 426,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_cache_help.R\n\\name{pkg_ref_cache.h"
  },
  {
    "path": "man/pkg_ref_cache.help.pkg_source.Rd",
    "chars": 389,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_cache_help.R\n\\name{pkg_ref_cache.h"
  },
  {
    "path": "man/pkg_ref_cache.news.pkg_remote.Rd",
    "chars": 419,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_cache_news.R\n\\name{pkg_ref_cache.n"
  },
  {
    "path": "man/pkg_ref_class_hierarchy.Rd",
    "chars": 490,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_class.R\n\\docType{data}\n\\name{pkg_r"
  },
  {
    "path": "man/pkg_ref_mutability_error.Rd",
    "chars": 665,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_class_extract.R\n\\name{pkg_ref_muta"
  },
  {
    "path": "man/pkg_score.Rd",
    "chars": 1599,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_score.R\n\\name{pkg_score}\n\\alias{pkg_sc"
  },
  {
    "path": "man/print.with_eval_recording.Rd",
    "chars": 1087,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/utils.R\n\\name{print.with_eval_recording}\n\\"
  },
  {
    "path": "man/remove_base_packages.Rd",
    "chars": 413,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/assess_dependencies.R\n\\name{remove_base_pa"
  },
  {
    "path": "man/require_cache_behaviors.Rd",
    "chars": 561,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_cache_behaviors.R\n\\name{require_ca"
  },
  {
    "path": "man/riskmetric.Rd",
    "chars": 1060,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/riskmetric-package.R\n\\docType{package}\n\\na"
  },
  {
    "path": "man/riskmetric_metadata_caching.Rd",
    "chars": 3085,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_cache.R\n\\name{pkg_ref_cache}\n\\alia"
  },
  {
    "path": "man/roxygen_assess_family.Rd",
    "chars": 1030,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_assess.R\n\\name{roxygen_assess_family}\n"
  },
  {
    "path": "man/roxygen_assess_family_catalog.Rd",
    "chars": 523,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_assess.R\n\\name{roxygen_assess_family_c"
  },
  {
    "path": "man/roxygen_cache_behaviors.Rd",
    "chars": 801,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_cache_behaviors.R\n\\name{roxygen_ca"
  },
  {
    "path": "man/roxygen_score_family.Rd",
    "chars": 797,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_score.R\n\\name{roxygen_score_family}\n\\a"
  },
  {
    "path": "man/score_error_NA.Rd",
    "chars": 365,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/metric_score.R\n\\name{score_error_NA}\n\\alia"
  },
  {
    "path": "man/score_error_default.Rd",
    "chars": 484,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/metric_score.R\n\\name{score_error_default}\n"
  },
  {
    "path": "man/score_error_zero.Rd",
    "chars": 369,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/metric_score.R\n\\name{score_error_zero}\n\\al"
  },
  {
    "path": "man/sub-sub-.pkg_ref.Rd",
    "chars": 702,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_class_extract.R\n\\name{[[.pkg_ref}\n"
  },
  {
    "path": "man/summarize_scores.Rd",
    "chars": 1027,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/summarize_scores.R\n\\name{summarize_scores}"
  },
  {
    "path": "man/suppressMatchingConditions.Rd",
    "chars": 881,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/utils.R\n\\name{suppressMatchingConditions}\n"
  },
  {
    "path": "man/use_assessments_column_names.Rd",
    "chars": 542,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_assess.R\n\\name{use_assessments_column_"
  },
  {
    "path": "man/verify_pkg_source.Rd",
    "chars": 397,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_class.R\n\\name{verify_pkg_source}\n\\"
  },
  {
    "path": "man/vignettes_from_dir.Rd",
    "chars": 504,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_cache_vignettes.R\n\\name{vignettes_"
  },
  {
    "path": "man/vignettes_from_html.Rd",
    "chars": 457,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pkg_ref_cache_vignettes.R\n\\name{vignettes_"
  },
  {
    "path": "man/with.pkg_ref.Rd",
    "chars": 1111,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/utils.R\n\\name{with.pkg_ref}\n\\alias{with.pk"
  },
  {
    "path": "man/with_unclassed_to.Rd",
    "chars": 690,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/utils.R\n\\name{with_unclassed_to}\n\\alias{wi"
  },
  {
    "path": "tests/testthat/setup_mock_web_requests.R",
    "chars": 3771,
    "preview": "library(webmockr)\nlibrary(httr)\n\noptions(riskmetric.tests = test_path())\nhttr_mock()\n\n# helper function for generating c"
  },
  {
    "path": "tests/testthat/setup_test_packages.R",
    "chars": 3579,
    "preview": "# create a series of reliably evaluated pkg reference objects that can be\n# reused throughout testthat unit tests\n\n# NOT"
  },
  {
    "path": "tests/testthat/teardown_mock_web_requests.R",
    "chars": 94,
    "preview": "options(riskmetric.tests = NULL)\n\nstub_registry_clear()\nhttr_mock(FALSE)\n\nrm(build_downloads)\n"
  },
  {
    "path": "tests/testthat/teardown_test_packages.R",
    "chars": 371,
    "preview": "rm(\n  pkg_ref_source_good,\n  assess_source_good,\n  pkg_ref_source_bad,\n  assess_source_bad,\n  pkg_ref_source_bad2,\n  ass"
  },
  {
    "path": "tests/testthat/test_assess.R",
    "chars": 1519,
    "preview": "test_that(\"pkg_assess on a single pkg_ref returns a vctrs_list_of with one element per assessment\", {\n  expect_s3_class("
  },
  {
    "path": "tests/testthat/test_assess_dependencies.R",
    "chars": 267,
    "preview": "test_that(\"assess_dependencies returns the correct number of dependencies\", {\n  expect_s3_class(\n    assess_source_good$"
  },
  {
    "path": "tests/testthat/test_assess_export_help.R",
    "chars": 725,
    "preview": "# Commenting these out until this is implemented for sourced packages\ntest_that(\"assess_export_help returns expected res"
  },
  {
    "path": "tests/testthat/test_assess_has_bug_reports_url.R",
    "chars": 269,
    "preview": "test_that(\"assess_has_bug_reports_url returns the correct url\", {\n  expect_s3_class(\n    assess_source_good$has_bug_repo"
  }
]

// ... and 32 more files (download for full content)

About this extraction

This page contains the full source code of the pharmaR/riskmetric GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 232 files (318.4 KB), approximately 98.4k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!