-
Notifications
You must be signed in to change notification settings - Fork 301
Start on use_claude_code()
#2203
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,3 +27,4 @@ | |
| ^\.vscode$ | ||
| ^[.]?air[.]toml$ | ||
| ^scratch\.R$ | ||
| ^\.claude$ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| settings.local.json |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| ## R package development | ||
|
|
||
| ### Key commands | ||
|
|
||
| ``` | ||
| # To run code | ||
| Rscript -e "devtools::load_all(); code" | ||
|
|
||
| # To run all tests | ||
| Rscript -e "devtools::test()" | ||
|
|
||
| # To run tests for R/{name.R} | ||
| Rscript -e "devtools::test(filter = '{name}')" | ||
|
|
||
| # To document the package | ||
| Rscript -e "devtools::document()" | ||
|
|
||
| # To check pkgdown documentation | ||
| Rscript -e "pkgdown::check_pkgdown()" | ||
|
|
||
| # To format code | ||
| air format . | ||
| ``` | ||
|
|
||
| ### Coding | ||
|
|
||
| * Always run `air format .` after generating code | ||
| * Use the base pipe operator (`|>`) not the magrittr pipe (`%>%`) | ||
| * Don't use `_$x` or `_$[["x"]]` since dbplyr must work on R 4.1. | ||
| * Use `\() ...` for single-line anonymous functions. For all other cases, use `function() {...}` | ||
|
|
||
| ### Testing | ||
|
|
||
| - Tests for `R/{name}.R` go in `tests/testthat/test-{name}.R`. | ||
| - All new code should have an accompanying test. | ||
| - If there are existing tests, place new tests next to similar existing tests. | ||
| - Strive to keep your tests minimal with few comments. | ||
|
|
||
| ### Documentation | ||
|
|
||
| - Every user-facing function should be exported and have roxygen2 documentation. | ||
| - Wrap roxygen comments at 80 characters. | ||
| - Internal functions should not have roxygen documentation. | ||
| - Whenever you add a new documentation topic, also add the topic to `_pkgdown.yml`. | ||
| - Use `pkgdown::check_pkgdown()` to check that all topics are included in the reference index. | ||
|
|
||
| ### Writing | ||
|
|
||
| - Use sentence case for headings. | ||
| - Use US English. | ||
|
|
||
| ### Proofreading | ||
|
|
||
| If the user asks you to proofread a file, act as an expert proofreader and editor with a deep understanding of clear, engaging, and well-structured writing. | ||
|
|
||
| Work paragraph by paragraph, always starting by making a TODO list that includes individual items for each top-level heading. | ||
|
|
||
| Fix spelling, grammar, and other minor problems without asking the user. Label any unclear, confusing, or ambiguous sentences with a FIXME comment. | ||
|
|
||
| Only report what you have changed. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| { | ||
|
|
||
| "permissions": { | ||
| "$schema": "https://json.schemastore.org/claude-code-settings.json", | ||
| "defaultMode": "acceptEdits", | ||
| "allow": [ | ||
| "Bash(find:*)", | ||
| "Bash(grep:*)", | ||
| "Bash(ls:*)", | ||
| "Bash(R:*)", | ||
| "Bash(Rscript:*)", | ||
| "Bash(rm:*)", | ||
| "Bash(air:*)", | ||
| "WebFetch(domain:github.com)" | ||
| ], | ||
| "deny": [ | ||
| "Read(.Renviron)", | ||
| "Read(.env)" | ||
| ] | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,156 @@ | ||
| --- | ||
| name: tidy-deprecate-function | ||
| description: Guide for deprecating R functions/arguments. Use when a user asks to deprecate a function or parameter, including adding lifecycle warnings, updating documentation, adding NEWS entries, and updating tests. | ||
| --- | ||
|
|
||
| # Deprecate functions and function arguments | ||
|
|
||
| Use this skill when deprecating functions or function parameters in dbplyr. | ||
|
|
||
| ## Overview | ||
|
|
||
| This skill guides you through the complete process of deprecating a function or parameter, ensuring all necessary changes are made consistently: | ||
|
|
||
| 1. Add deprecation warning using `lifecycle::deprecate_warn()`. | ||
| 2. Silence deprecation warnings in existing tests. | ||
| 3. Add lifecycle badge to documentation. | ||
| 4. Add bullet point to NEWS.md. | ||
| 5. Create test for deprecation warning. | ||
|
|
||
| ## Workflow | ||
|
|
||
| ### Step 1: Determine deprecation version | ||
|
|
||
| Read the current version from DESCRIPTION and calculate the deprecation version: | ||
|
|
||
| - Current version format: `MAJOR.MINOR.PATCH.9000` (development). | ||
| - Deprecation version: Next minor release `MAJOR.(MINOR+1).0`. | ||
| - Example: If current version is `2.5.1.9000`, deprecation version is `2.6.0`. | ||
|
|
||
| ### Step 2: Add `lifecycle::deprecate_warn()` call | ||
|
|
||
| Add the deprecation warning to the function: | ||
|
|
||
| ```r | ||
| # 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 | ||
| } | ||
| ``` | ||
|
|
||
| Key points: | ||
|
|
||
| - First argument is the deprecation version string (e.g., "2.6.0"). | ||
| - Second argument describes what is deprecated (e.g., "function_name(param)"). | ||
| - Optional third argument suggests replacement. | ||
| - Use `lifecycle::is_present()` to check if a deprecated parameter was supplied. | ||
|
|
||
| ### Step 3: Update tests | ||
|
|
||
| Find all existing tests that use the deprecated function or parameter and silence lifecycle warnings. Add at the beginning of test blocks that use the deprecated feature: | ||
|
|
||
| ```r | ||
| test_that("existing test with deprecated feature", { | ||
| withr::local_options(lifecycle_verbosity = "quiet") | ||
|
|
||
| # existing test code | ||
| }) | ||
| ``` | ||
|
|
||
| Then add a new test to verify the deprecation message in the appropriate test file (usually `tests/testthat/test-{name}.R`): | ||
|
|
||
| ```r | ||
| test_that("function_name(deprecated_param) is deprecated", { | ||
| expect_snapshot(. <- function_name(deprecated_param = value)) | ||
| }) | ||
| ``` | ||
|
|
||
| You'll need to supply any additional arguments to create a valid call. | ||
|
|
||
| Then run the tests and verify they pass. | ||
|
|
||
| ### Step 4: Update documentation | ||
|
|
||
| For function deprecation, add to the description section: | ||
|
|
||
| ```r | ||
| #' @description | ||
| #' `r lifecycle::badge("deprecated")` | ||
| #' | ||
| #' This function is deprecated. Please use [replacement_function()] instead. | ||
| ``` | ||
|
|
||
| If the documentation does not already contain `@description`, you will need to add it. | ||
|
|
||
| For argument deprecation, add to the appropriate `@param` tag: | ||
|
|
||
| ```r | ||
| #' @param deprecated_param `r lifecycle::badge("deprecated")` | ||
| ``` | ||
|
|
||
| When deprecating a function or parameter in favor of a replacement, add old/new examples to the `@examples` section to help users migrate. These should relace all existing examples. | ||
|
|
||
| ```r | ||
| #' @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") | ||
| ``` | ||
|
|
||
| Key points: | ||
|
|
||
| - Use "# Old:" and "# New:" comments to clearly show the transition. | ||
| - Include 2-3 practical examples covering common use cases. | ||
| - Make examples runnable and self-contained. | ||
| - Show how the new syntax differs from the old. | ||
|
|
||
| Then re-document the package. | ||
|
|
||
| ### Step 5: Add NEWS entry | ||
|
|
||
| Add a bullet point to the top of the "# dbplyr (development version)" section in NEWS.md: | ||
|
|
||
| ```markdown | ||
| # dbplyr (development version) | ||
|
|
||
| * `function_name(parameter)` is deprecated and will be removed in a future | ||
| version. | ||
| * `function_name()` is deprecated. Use `replacement_function()` instead. | ||
| ``` | ||
|
|
||
| Place the entry: | ||
|
|
||
| - In the lifecycle subsection if it exists, otherwise at the top level under development version. | ||
| - Include the replacement if known. | ||
| - Keep entries concise and actionable. | ||
|
|
||
| ## Implementation checklist | ||
|
|
||
| When deprecating a function or parameter, ensure you: | ||
|
|
||
| - [ ] Read DESCRIPTION to determine deprecation version. | ||
| - [ ] Add `lifecycle::deprecate_warn()` call in the function. | ||
| - [ ] Add `withr::local_options(lifecycle_verbosity = "quiet")` to existing tests. | ||
| - [ ] Create new test for deprecation warning using `expect_snapshot()`. | ||
| - [ ] Run tests to verify everything works. | ||
| - [ ] Add lifecycle badge to roxygen documentation. | ||
| - [ ] Add migration examples to `@examples` section (for function deprecation). | ||
| - [ ] Run `devtools::document()` to update documentation. | ||
| - [ ] Add bullet point to NEWS.md. | ||
| - [ ] Run `air format .` to format code. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| #' Configure a project to use Claude Code | ||
| #' | ||
| #' @description | ||
| #' This function sets up a project to use | ||
| #' [Claude Code](https://docs.anthropic.com/en/docs/claude-code). | ||
| #' Specifically, it: | ||
| #' | ||
| #' - Creates a `.claude/` directory with a `CLAUDE.md` file containing | ||
| #' project-specific instructions for R package development. | ||
| #' | ||
| #' - Creates a `.claude/settings.json` configuration file with recommended | ||
| #' permissions for R package development, including the ability to run R, | ||
| #' format with [Air](https://posit-dev.github.io/air/), and run common | ||
| #' development tools. | ||
| #' | ||
| #' - Creates a `.claude/skills/` directory containing various skills found | ||
| #' useful by the tidyverse team. All skills have a `tidy-` prefix to avoid | ||
| #' clashing with skills that you might provide. | ||
| #' | ||
| #' - Updates `.claude/.gitignore` to ignore `settings.local.json` (for | ||
| #' user-specific settings). | ||
| #' | ||
| #' @export | ||
| #' @examples | ||
| #' \dontrun{ | ||
| #' use_claude_code() | ||
| #' } | ||
| use_claude_code <- function() { | ||
| use_directory(".claude", ignore = TRUE) | ||
| copy_claude_directory() | ||
| use_git_ignore("settings.local.json", directory = ".claude") | ||
|
|
||
| invisible(TRUE) | ||
| } | ||
|
|
||
| copy_claude_directory <- function() { | ||
| source_dir <- path_package("usethis", "claude") | ||
| dest_dir <- proj_path(".claude") | ||
|
|
||
| source_dirs <- dir_ls(source_dir, recurse = TRUE, type = "directory") | ||
| dir_create(path(dest_dir, path_rel(source_dirs, source_dir))) | ||
|
|
||
| source_files <- dir_ls(source_dir, recurse = TRUE, type = "file") | ||
| for (source_file in source_files) { | ||
| rel_path <- path_rel(source_file, source_dir) | ||
| dest_file <- path(dest_dir, rel_path) | ||
|
|
||
| ui_bullets(c("v" = "Creating {.path {pth(dest_file)}}.")) | ||
| file_copy(source_file, dest_file, overwrite = TRUE) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| ## R package development | ||
|
|
||
| ### Key commands | ||
|
|
||
| ``` | ||
| # To run code | ||
| Rscript -e "devtools::load_all(); code" | ||
|
|
||
| # To run all tests | ||
| Rscript -e "devtools::test()" | ||
|
|
||
| # To run tests for R/{name.R} | ||
| Rscript -e "devtools::test(filter = '{name}')" | ||
|
|
||
| # To document the package | ||
| Rscript -e "devtools::document()" | ||
|
|
||
| # To check pkgdown documentation | ||
| Rscript -e "pkgdown::check_pkgdown()" | ||
|
|
||
| # To format code | ||
| air format . | ||
| ``` | ||
|
|
||
| ### Coding | ||
|
|
||
| * Always run `air format .` after generating code | ||
| * Use the base pipe operator (`|>`) not the magrittr pipe (`%>%`) | ||
| * Don't use `_$x` or `_$[["x"]]` since dbplyr must work on R 4.1. | ||
| * Use `\() ...` for single-line anonymous functions. For all other cases, use `function() {...}` | ||
|
|
||
| ### Testing | ||
|
|
||
| - Tests for `R/{name}.R` go in `tests/testthat/test-{name}.R`. | ||
| - All new code should have an accompanying test. | ||
| - If there are existing tests, place new tests next to similar existing tests. | ||
| - Strive to keep your tests minimal with few comments. | ||
|
|
||
| ### Documentation | ||
|
|
||
| - Every user-facing function should be exported and have roxygen2 documentation. | ||
| - Wrap roxygen comments at 80 characters. | ||
| - Internal functions should not have roxygen documentation. | ||
| - Whenever you add a new documentation topic, also add the topic to `_pkgdown.yml`. | ||
| - Use `pkgdown::check_pkgdown()` to check that all topics are included in the reference index. | ||
|
|
||
| ### Writing | ||
|
|
||
| - Use sentence case for headings. | ||
| - Use US English. | ||
|
|
||
| ### Proofreading | ||
|
|
||
| If the user asks you to proofread a file, act as an expert proofreader and editor with a deep understanding of clear, engaging, and well-structured writing. | ||
|
|
||
| Work paragraph by paragraph, always starting by making a TODO list that includes individual items for each top-level heading. | ||
|
|
||
| Fix spelling, grammar, and other minor problems without asking the user. Label any unclear, confusing, or ambiguous sentences with a FIXME comment. | ||
|
|
||
| Only report what you have changed. |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,21 @@ | ||||||||
| { | ||||||||
|
|
||||||||
| "permissions": { | ||||||||
| "$schema": "https://json.schemastore.org/claude-code-settings.json", | ||||||||
| "defaultMode": "acceptEdits", | ||||||||
| "allow": [ | ||||||||
| "Bash(find:*)", | ||||||||
| "Bash(grep:*)", | ||||||||
| "Bash(ls:*)", | ||||||||
| "Bash(R:*)", | ||||||||
| "Bash(Rscript:*)", | ||||||||
| "Bash(rm:*)", | ||||||||
| "Bash(air:*)", | ||||||||
| "WebFetch(domain:github.com)" | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I also end up with this one in most projects. Other candidates I've accrued in local settings recently that might be generally useful (Claude 🫶 the gh cli): We should probably regard |
||||||||
| ], | ||||||||
| "deny": [ | ||||||||
| "Read(.Renviron)", | ||||||||
| "Read(.env)" | ||||||||
| ] | ||||||||
| } | ||||||||
| } | ||||||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Bash(git checkout:*)"might be usefulClaude seems to like to try things and get stuck and need to undo them with git