usethis

repository·main·Indexed 21 days ago

https://github.com/r-lib/usethis

A workflow package that automates repetitive tasks during project setup and development for both R packages and non-package projects.

Tokens
8.4K
Snippets
25
Records
36
Agent score
75%

What's inside usethis

  1. Understand the difference between a 'work based on the library' and a 'work that uses the library'

    main

    Under the LGPL, distinguishing between these two types of works is critical for determining licensing obligations:

    • Work based on the Library: A work that contains the Library or a portion of it, either verbatim or with modifications (including translations). These are derivative works and are subject to the terms of the LGPL.
    • Work that uses the Library: A program designed to work with the Library by being compiled or linked with it, but which contains no derivative of any portion of the Library. Such a work, in isolation, is not a derivative work and falls outside the scope of the LGPL.

    Note on Linking: Linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library and is therefore covered by the LGPL.

  2. How the active project is managed

    main

    Many usethis functions operate on an active project. The project path is stored internally and functions typically create or modify files within this project context.

    Key behaviors:

    • Activation: A project is activated upon first need (e.g., when proj_get() is called). If no project is active, usethis attempts to activate a project at or above the current working directory.
    • Path Handling: To ensure consistency and avoid manual path manipulation, use the provided project-aware functions.

    Important APIs for project interaction:

    • proj_get(): Gets the current active project path (may trigger activation).
    • proj_get_(): Gets the current active project path without triggering activation.
    • proj_set(): Sets the active project (may trigger activation).
    • proj_set_(): Sets the active project without triggering activation.
    • proj_path(): Forms paths to files within the project.
    • proj_rel_path(): Gets paths relative to the project.
    # Use proj_get() to interact with the active project
    project_path <- proj_get()
    
    # Form a path to a file inside the project
    file_path <- proj_path("src/R/my_function.R")
  3. Apply the GNU General Public License (GPL) v2 to your program

    main

    To distribute your software under the GNU General Public License (GPL) version 2, you should attach specific notices to your program. The most effective way to convey the exclusion of warranty is to attach these notices to the start of each source file. Each file should include at least a copyright line and a pointer to the full license notice.

    For source files, include this template:

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year> <name of author>
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

    Note: You should also include information on how to contact you via electronic and paper mail.

  4. Fix typos in package documentation

    main

    Typos or grammatical errors in documentation can be fixed directly via the GitHub web interface.

    Important: You must edit the source file, not the generated .Rd file. For R packages, this typically means editing the roxygen2 comments within the .R files. To find the correct source file, read the comment on the first line of the .Rd file to identify the corresponding .R file.

  5. Propagate context when wrapping `check_` functions

    main

    When creating a wrapper function that calls existing check_ functions, you must propagate the arg and call arguments. If you don't, error messages will point to your wrapper function instead of the actual entry point where the user called the code.

    Correct Pattern:

    # CORRECT: propagates context from the entry point
    check_positive <- function(x, arg = caller_arg(x), call = caller_env()) {
      check_number_whole(x, min = 1, arg = arg, call = call)
    }
    
    my_function <- function(count) {
      check_positive(count)
    }
    
    my_function(-5)
    #> Error in `my_function()`:  # Correct!
    #> ! `count` must be a whole number larger than or equal to 1.  # Correct!
    check_positive <- function(x, arg = caller_arg(x), call = caller_env()) {
      check_number_whole(x, min = 1, arg = arg, call = call)
    }
  6. Deprecate functions and function arguments

    main

    When deprecating a function or parameter in a package, follow this complete workflow to ensure consistency across code, tests, documentation, and changelogs:

    1. Determine Deprecation Version: Read the current version from DESCRIPTION. The deprecation version should be the next minor release (e.g., if current is 2.5.1.9000, the deprecation version is 2.6.0).
    2. Add Warning: Use lifecycle::deprecate_warn() within the function body.
    3. Update Tests: Silence existing warnings in tests using withr::local_options(lifecycle_verbosity = "quiet") and add a new test using expect_snapshot() to verify the deprecation message.
    4. Update Documentation: Add lifecycle badges to Roxygen tags (@description or @param) and provide migration examples in the @examples section.
    5. Update NEWS.md: Add a concise bullet point to the development version section.
    6. Finalize: Run devtools::document() and air format ..
  7. Update Roxygen documentation for deprecations

    main

    Use lifecycle badges and migration examples to guide users through deprecations.

    Function Deprecation: Add the badge to the @description section and suggest the replacement.

    #' @description
    #' `r lifecycle::badge("deprecated")`
    #'
    #' This function is deprecated. Please use [replacement_function()] instead.

    Argument Deprecation: Add the badge directly to the @param tag.

    #' @param deprecated_param `r lifecycle::badge("deprecated")`

    Migration Examples: In the @examples section, provide both the old and new ways of calling the function using # Old: and # New: comments. Include 2-3 practical examples showing the syntax transition.

    #' @examples
    #' # Old:
    #' old_function(arg1, arg2)
    #' # New:
    #' replacement_function(arg1, arg2)
    #'
    #' # Old:
    #' x <- "value"
    #' old_function("prefix", x, "suffix")
    #' # New:
    #' replacement_function("prefix {x} suffix")
  8. Add `lifecycle::deprecate_warn()` to functions or parameters

    main

    Use lifecycle::deprecate_warn() to trigger warnings when a function or its arguments are used.

    For a deprecated function: Place the call at the beginning of the function body.

    For a deprecated parameter:

    1. Set the default value of the parameter to deprecated().
    2. Use lifecycle::is_present() to check if the user supplied the deprecated argument.
    3. Call lifecycle::deprecate_warn() if it is present.

    Arguments for lifecycle::deprecate_warn():

    • version: The version string when the feature will be removed (e.g., "2.6.0").
    • message: A description of what is deprecated (e.g., "function_name(param)").
    • replacement: (Optional) A string suggesting the replacement function.
    # For a deprecated function:
    function_name <- function(...) {
      lifecycle::deprecate_warn("X.Y.0", "function_name()", "replacement_function()")
      # rest of function
    }
    
    # For a deprecated parameter:
    function_name <- function(param1, deprecated_param = deprecated()) {
      if (lifecycle::is_present(deprecated_param)) {
        lifecycle::deprecate_warn("X.Y.0", "function_name(deprecated_param)")
      }
      # rest of function
    }
  9. Manage Git commits and uncommitted changes

    main

    When performing operations that modify files, usethis provides tools to ensure a clean state and safe committing:

    • Sanity Checks: Functions that make commits use challenge_uncommitted_changes() to encourage working in a clean state (no uncommitted files).
    • Interactive Commits: Use git_commit_ask() to commit changes. It is recommended to specify paths to ensure only intended files are committed.
    • Non-interactive Commits: For automated environments or tests, use gert::git_commit() directly.
    • Handling Untracked Files:
      • Use git_uncommitted(untracked = TRUE) or git_ask_commit(untracked = TRUE) if your work has created new files that need to be tracked.
      • Use untracked = FALSE if your work only modified existing files.
    # Commit specific files interactively
    git_commit_ask(paths = c("DESCRIPTION", "NAMESPACE"))
    
    # In a test/non-interactive context
    gert::git_commit(message = "Automated test commit")
    
    # Check for both modified and newly created files
    git_uncommitted(untracked = TRUE)
  10. Apply the GNU Lesser General Public License (LGPL) to a new library

    main

    To license a new library under the LGPL v2.1, you must attach specific notices to the library. It is recommended to place these at the start of each source file to ensure the exclusion of warranty is effectively conveyed. Each file should include at least a copyright line and a pointer to the full license notice.

    Required Notice Template:

    <one line to give the library's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>
    
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.
    
    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.
    
    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    Additionally, you should include contact information (electronic and paper mail) and, if necessary, obtain a copyright disclaimer from your employer or school.

  11. Apply the Apache License 2.0 to your work

    main

    To apply the Apache License 2.0 to your software, you must attach a specific boilerplate notice to your files. Replace the bracketed placeholders [yyyy] and [name of copyright owner] with your actual copyright year and owner name. Ensure the text is enclosed in the appropriate comment syntax for your specific file format (e.g., # for R or shell scripts, /* ... */ for C/C++).

    Copyright [yyyy] [name of copyright owner]
    
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
    
      http://www.apache.org/licenses/LICENSE-2.0
    
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.