[
  {
    "path": ".gitmodules",
    "content": "[submodule \"notes\"]\n\tpath = notes\n\turl = git@github.com:jbranchaud/til-notes-private.git\n\tbranch = main\n\tignore = all\n"
  },
  {
    "path": ".vimrc",
    "content": "\" vimrc for til\n\n\" In order for this file to be loaded by Vim, the main `.vimrc` file must\n\" contain `set exrc` and optionally `set secure`. Without those lines, Vim\n\" will ignore this file.\n\nfunction! CountTILs()\n    execute '%s/^- \\[//n'\nendfunction\n\nnnoremap <leader>c :call CountTILs()<cr>\n\naugroup DisableMarkdownFormattingForTILReadme\n    autocmd!\n    autocmd BufRead ~/code/til/README.md autocmd! Format\naugroup END\n\n\" local til_readme_group = vim.api.nvim_create_augroup('DisableMarkdownFormattingForTILReadme', { clear = true })\n\" vim.api.nvim_create_autocmd('BufRead', {\n\"   command = 'autocmd! Format',\n\"   group = til_readme_group,\n\"   pattern = vim.fn.expand '~/code/til/README.md',\n\" })\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nThanks for wanting to contribute to my TIL repository!\n\nI welcome submissions that fix typos and correct wrong or misleading\ncontent. All you need to do is fork the repo, make a single commit with a\nconcise, descriptive message, and then submit it as a pull request.\n\nIf you are interested in contributing your own TIL content, I encourage you\nto head on over to\n[til-collective](https://github.com/til-collective/til-collective) and make your\nsubmission there. As for this repo, I'd like to maintain it as my own\npersonal learning journey.\n\nIf you have any questions or suggestions, feel free to open an issue.\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2015 Josh Branchaud\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# TIL\n\n> Today I Learned\n\nA collection of concise write-ups on small things I learn day to day across a\nvariety of languages and technologies. These are things that don't really\nwarrant a full blog post. These are things I've picked up by [Learning In\nPublic™](https://dev.to/jbranchaud/how-i-built-a-learning-machine-45k9) and\nworking across different projects via [VisualMode](https://www.visualmode.dev/).\n\nFor a steady stream of TILs, [sign up for my newsletter](https://visualmode.kit.com/newsletter).\n\n_1761 TILs and counting..._\n\nSee some of the other learning resources I work on:\n\n- [Get Started with Vimium](https://egghead.io/courses/get-started-with-vimium~3t5f7)\n- [Ruby Operator Lookup](https://www.visualmode.dev/ruby-operators)\n- [Vim Un-Alphabet](https://www.youtube.com/playlist?list=PL46-cKSxMYYCMpzXo6p0Cof8hJInYgohU)\n\nIf you've learned something here, support my efforts writing daily TILs by\n[buying me a coffee](https://buymeacoffee.com/jbranchaud) 💜\n\n---\n\n### Categories\n\n* [Ack](#ack)\n* [Ansible](#ansible)\n* [Astro](#astro)\n* [AWS](#aws)\n* [Bash](#bash)\n* [Brew](#brew)\n* [Chrome](#chrome)\n* [Claude Code](#claude-code)\n* [Clojure](#clojure)\n* [CSS](#css)\n* [Deno](#deno)\n* [Devops](#devops)\n* [Docker](#docker)\n* [Drizzle](#drizzle)\n* [Elixir](#elixir)\n* [Gatsby](#gatsby)\n* [Git](#git)\n* [GitHub](#github)\n* [GitHub Actions](#github-actions)\n* [Go](#go)\n* [GROQ](#groq)\n* [Heroku](#heroku)\n* [HTML](#html)\n* [HTTP](#http)\n* [Inngest](#inngest)\n* [Internet](#internet)\n* [Java](#java)\n* [JavaScript](#javascript)\n* [jj](#jj)\n* [jq](#jq)\n* [Kitty](#kitty)\n* [Linux](#linux)\n* [LLM](#llm)\n* [Mac](#mac)\n* [Mise](#mise)\n* [MongoDB](#mongodb)\n* [MySQL](#mysql)\n* [Neovim](#neovim)\n* [Netlify](#netlify)\n* [NextAuth.js](#next-auth)\n* [Next.js](#nextjs)\n* [Phoenix](#phoenix)\n* [Planetscale](#planetscale)\n* [pnpm](#pnpm)\n* [PostgreSQL](#postgresql)\n* [Prisma](#prisma)\n* [Python](#python)\n* [Rails](#rails)\n* [React](#react)\n* [React Native](#react-native)\n* [React Testing Library](#react-testing-library)\n* [ReasonML](#reasonml)\n* [Remix](#remix)\n* [RSpec](#rspec)\n* [Ruby](#ruby)\n* [sed](#sed)\n* [Shell](#shell)\n* [SQLite](#sqlite)\n* [Streaming](#streaming)\n* [Tailwind CSS](#tailwind-css)\n* [Taskfile](#taskfile)\n* [tmux](#tmux)\n* [TypeScript](#typescript)\n* [Unix](#unix)\n* [Vercel](#vercel)\n* [Vim](#vim)\n* [VSCode](#vscode)\n* [Webpack](#webpack)\n* [Workflow](#workflow)\n* [XState](#xstate)\n* [YAML](#yaml)\n* [Zod](#zod)\n* [Zsh](#zsh)\n\n---\n\n### Ack\n\n- [ack --bar](ack/ack-bar.md)\n- [Case-Insensitive Search](ack/case-insensitive-search.md)\n- [List Available File Types](ack/list-available-file-types.md)\n\n### Ansible\n\n- [Loop Over A List Of Dictionaries](ansible/loop-over-a-list-of-dictionaries.md)\n\n### Astro\n\n- [Generate Types For A Content Collection](astro/generate-types-for-a-content-collection.md)\n- [Markdown Files Are Of Type MarkdownInstance](astro/markdown-files-are-of-type-markdown-instance.md)\n\n### AWS\n\n- [AWS CLI Requires Groff Executable](aws/aws-cli-requires-groff-executable.md)\n- [Find And Follow Server Logs](aws/find-and-follow-server-logs.md)\n- [List RDS Snapshots With Matching Identifier Prefix](aws/list-rds-snapshots-with-matching-identifier-prefix.md)\n- [Output CLI Results In Different Formats](aws/output-cli-results-in-different-formats.md)\n- [Sign Up User With Email And Password](aws/sign-up-user-with-email-and-password.md)\n- [SSH Into An ECS Container](aws/ssh-into-an-ecs-container.md)\n- [Turn Off Output Pager For A Command](aws/turn-off-output-pager-for-a-command.md)\n- [Use Specific AWS Profile With CLI](aws/use-specific-aws-profile-with-cli.md)\n\n### Bash\n\n- [Edit The Current Command Prompt](bash/edit-the-current-command-prompt.md)\n\n### Brew\n\n- [Clean Up Your Brew Installations](brew/clean-up-your-brew-installations.md)\n- [Configure Brew Environment Variables](brew/configure-brew-environment-variables.md)\n- [Export List Of Everything Installed By Brew](brew/export-list-of-everything-installed-by-brew.md)\n- [Install From Nonstandard Brewfile](brew/install-from-nonstandard-brewfile.md)\n- [Install Go Packages In Brewfile](brew/install-go-packages-in-brewfile.md)\n- [List All Services Managed By Brew](brew/list-all-services-managed-by-brew.md)\n\n### Chrome\n\n- [Access A Value Logged To The Console](chrome/access-a-value-logged-to-the-console.md)\n- [Chrome Supports Many Unix Keyboard Shortcuts](chrome/chrome-supports-many-unix-keyboard-shortcuts.md)\n- [Copy Some Data From The Console](chrome/copy-some-data-from-the-console.md)\n- [Duplicate The Current Tab](chrome/duplicate-the-current-tab.md)\n- [Easier Access To Network Throttling Controls](chrome/easier-access-to-network-throttling-controls.md)\n- [Keybinding To Focus The Address Bar](chrome/keybinding-to-focus-the-address-bar.md)\n- [Open Current Tab In New Window With Vimium](chrome/open-current-tab-in-new-window-with-vimium.md)\n- [Pause JavaScript From The Source DevTools Panel](chrome/pause-javascript-from-the-source-devtools-panel.md)\n- [Navigate The Browser History With Vimium](chrome/navigate-the-browser-history-with-vimium.md)\n- [Pretty Print Tabular Data](chrome/pretty-print-tabular-data.md)\n- [Reference The Selected Node](chrome/reference-the-selected-node.md)\n- [Search Tabs With The Vimium Vomnibar](chrome/search-tabs-with-the-vimium-vomnibar.md)\n- [Selecting DOM Elements Faster Than Ever](chrome/selecting-dom-elements-faster-than-ever.md)\n- [Simulating Various Connection Speeds](chrome/simulating-various-connection-speeds.md)\n- [Toggle Device Mode](chrome/toggle-device-mode.md)\n- [Toggle Open The Console Drawer](chrome/toggle-open-the-console-drawer.md)\n- [Trigger Commands From The Devtools Command Palette](chrome/trigger-commands-from-the-devtools-command-palette.md)\n- [View Network Traffic For New Tabs](chrome/view-network-traffic-for-new-tabs.md)\n\n### Claude Code\n\n- [Allow Edits From The Start](claude-code/allow-edits-from-the-start.md)\n- [Monitor Usage Limits From CLI](claude-code/monitor-usage-limits-from-cli.md)\n- [Open Current Prompt In Default Editor](claude-code/open-current-prompt-in-default-editor.md)\n- [Resume Specific Session](claude-code/resume-specific-session.md)\n\n### Clojure\n\n- [Aggregation Using merge-with](clojure/aggregation-using-merge-with.md)\n- [Argument Requirements For A Function](clojure/argument-requirements-for-a-function.md)\n- [Combinations Of Items From A Sequence](clojure/combinations-of-items-from-a-sequence.md)\n- [Define Something Only Once](clojure/define-something-only-once.md)\n- [Evaluate One Liners With lein-exec](clojure/evaluate-one-liners-with-lein-exec.md)\n- [Expanding Macros](clojure/expanding-macros.md)\n- [Get The Value Of An Environment Variable](clojure/get-the-value-of-an-environment-variable.md)\n- [List Functions For A Namespace](clojure/list-functions-for-a-namespace.md)\n- [Load A File Into The REPL](clojure/load-a-file-into-the-repl.md)\n- [Mapping With An Index](clojure/mapping-with-an-index.md)\n- [Open JavaDocs](clojure/open-javadocs.md)\n- [Pretty Print The Last Thing](clojure/pretty-print-the-last-thing.md)\n- [Quick Clojure Docs](clojure/quick-clojure-docs.md)\n- [Reductions](clojure/reductions.md)\n- [Set Max Heap Size](clojure/set-max-heap-size.md)\n- [Specify the Directory of a Shell Command](clojure/specify-the-directory-of-a-shell-command.md)\n- [Splitting On Whitespace](clojure/splitting-on-whitespace.md)\n- [Swap Two Items in a Vector](clojure/swap-two-items-in-a-vector.md)\n- [Try A Clojure Project In The REPL](clojure/try-a-clojure-project-in-the-repl.md)\n- [Type of Anything](clojure/type-of-anything.md)\n- [When Overflow Is Desired](clojure/when-overflow-is-desired.md)\n\n### CSS\n\n- [Add Fab Icons To Your Site With FontAwesome 5](css/add-fab-icons-to-your-site-with-fontawesome-5.md)\n- [Add Line Numbers To A Code Block With Counter](css/add-line-numbers-to-a-code-block-with-counter.md)\n- [Animate Smoothly Between Two Background Colors](css/animate-smoothly-between-two-background-colors.md)\n- [Apply Multiple Box Shadows To Single Element](css/apply-multiple-box-shadows-to-single-element.md)\n- [Apply Styles Based On Dark-Mode Preferences](css/apply-styles-based-on-dark-mode-preferences.md)\n- [Apply Styles To The Last Child Of A Specific Type](css/apply-styles-to-the-last-child-of-a-specific-type.md)\n- [Change The Orientation Of An Image](css/change-the-orientation-of-an-image.md)\n- [Circular Icons With A Massive Border Radius](css/circular-icons-with-a-massive-border-radius.md)\n- [Clean Up Repetition With :is() Pseudo-Class](css/clean-up-repetition-with-is-pseudo-class.md)\n- [Conditional Styling For Unsupported CSS Features](css/conditional-styling-for-unsupported-css-features.md)\n- [Create A Pulsing Background With CSS Animation](css/create-a-pulsing-background-with-css-animation.md)\n- [Define CSS Custom Properties With CSS Variables](css/define-css-custom-properties-with-scss-variables.md)\n- [Define HSL Colors With Alpha Values](css/define-hsl-colors-with-alpha-values.md)\n- [Display Responsive iframe Maintaining Aspect Ratio](css/display-responsive-iframe-maintaining-aspect-ratio.md)\n- [Dry Up SCSS With Mixins](css/dry-up-scss-with-mixins.md)\n- [Filter Blur Requires Expensive Calculation](css/filter-blur-requires-expensive-calculation.md)\n- [Give Elements The Same Width With Flexbox](css/give-elements-the-same-width-with-flexbox.md)\n- [Let Pointer Events Pass Through An Element](css/let-pointer-events-pass-through-an-element.md)\n- [Lighten And Darken With CSS Brightness Filter](css/lighten-and-darken-with-css-brightness-filter.md)\n- [Lighten And Darken With SCSS](css/lighten-and-darken-with-scss.md)\n- [Make A Block Of Text Respect New Lines](css/make-a-block-of-text-respect-new-lines.md)\n- [Parameterized SCSS Mixins](css/parameterized-scss-mixins.md)\n- [Prevent Invisible Elements From Being Clicked](css/prevent-invisible-elements-from-being-clicked.md)\n- [:root Has Higher Specificity Than html](css/root-has-higher-specificity-than-html.md)\n- [Style A Background With A Linear Gradient](css/style-a-background-with-a-linear-gradient.md)\n- [Using Maps In SCSS](css/using-maps-in-scss.md)\n\n### Cursor\n\n- [Allow Cursor To Be Launched From CLI](cursor/allow-cursor-to-be-launched-from-cli.md)\n\n### Deno\n\n- [Read In The Contents Of A File](deno/read-in-the-contents-of-a-file.md)\n\n### Devops\n\n- [Aliasing An Ansible Host](devops/aliasing-an-ansible-host.md)\n- [Allow Cross-Origin Requests To Include Cookies](devops/allow-cross-origin-requests-to-include-cookies.md)\n- [Allow HTTPS Through Your UFW Firewall](devops/allow-https-through-your-ufw-firewall.md)\n- [Check For Cached Site Assocation File For iOS](devops/check-for-cached-site-association-file-for-ios.md)\n- [Check The Status of All Services](devops/check-the-status-of-all-services.md)\n- [Check The Syntax Of nginx Files](devops/check-the-syntax-of-nginx-files.md)\n- [Connect To An RDS PostgreSQL Database](devops/connect-to-an-rds-postgresql-database.md)\n- [Default Rails Deploy Script On Hatchbox](devops/default-rails-deploy-script-on-hatchbox.md)\n- [Determine The IP Address Of A Domain](devops/determine-the-ip-address-of-a-domain.md)\n- [Hatchbox Exports Env Vars With asdf](devops/hatchbox-exports-env-vars-with-asdf.md)\n- [Path Of The Packets](devops/path-of-the-packets.md)\n- [Push Non-master Branch To Heroku](devops/push-non-master-branch-to-heroku.md)\n- [Reload The nginx Configuration](devops/reload-the-nginx-configuration.md)\n- [Resolve The Public IP Of A URL](devops/resolve-the-public-ip-of-a-url.md)\n- [Running Out Of inode Space](devops/running-out-of-inode-space.md)\n- [Set, Get, And Unset Env Vars With Dokku](devops/set-get-and-unset-env-vars-with-dokku.md)\n- [Set Up Domain For Hatchbox Rails App](devops/set-up-domain-for-hatchbox-rails-app.md)\n- [SSH Into A Docker Container](devops/ssh-into-a-docker-container.md)\n- [SSL Certificates Can Cover Multiple Domains](devops/ssl-certificates-can-cover-multiple-domains.md)\n- [Wipe A Heroku Postgres Database](devops/wipe-a-heroku-postgres-database.md)\n\n### Docker\n\n- [Check Postgres Version Running In Docker Container](docker/check-postgres-version-running-in-docker-container.md)\n- [Configure Different Host And Container Ports](docker/configure-different-host-and-container-ports.md)\n- [List Running Docker Containers](docker/list-running-docker-containers.md)\n- [Prevent Containers From Running On Startup](docker/prevent-containers-from-running-on-startup.md)\n- [Run A Basic PostgreSQL Server In Docker](docker/run-a-basic-postgresql-server-in-docker.md)\n- [Run SQL Script Against Postgres Container](docker/run-sql-script-against-postgres-container.md)\n\n### Drizzle\n\n- [Create bigint Identity Column For Primary Key](drizzle/create-bigint-identity-column-for-primary-key.md)\n- [Drizzle Tracks Migrations In A Log Table](drizzle/drizzle-tracks-migrations-in-a-log-table.md)\n- [Get Fields For Inserted Row](drizzle/get-fields-for-inserted-row.md)\n\n### Elixir\n\n- [All Values For A Key In A Keyword List](elixir/all-values-for-a-key-in-a-keyword-list.md)\n- [Append To A Keyword List](elixir/append-to-a-keyword-list.md)\n- [Assert An Exception Is Raised](elixir/assert-an-exception-is-raised.md)\n- [Binary Representation Of A String](elixir/binary-representation-of-a-string.md)\n- [Check For A Substring Match](elixir/check-for-a-substring-match.md)\n- [Check List Membership](elixir/check-list-membership.md)\n- [Comparing DateTime Structs](elixir/comparing-datetime-structs.md)\n- [Compute Intermediate Values In A With Construct](elixir/compute-intermediate-values-in-a-with-construct.md)\n- [Compute md5 Digest Of A String](elixir/compute-md5-digest-of-a-string.md)\n- [Counting Records With Ecto](elixir/counting-records-with-ecto.md)\n- [Create A Date With The Date Sigil](elixir/create-a-date-with-the-date-sigil.md)\n- [Create A List Of Atoms](elixir/create-a-list-of-atoms.md)\n- [Creating A PID](elixir/creating-a-pid.md)\n- [Creating Indexes With Ecto](elixir/creating-indexes-with-ecto.md)\n- [Defining Multiple Clauses In An Anonymous Function](elixir/defining-multiple-clauses-in-an-anonymous-function.md)\n- [Determine The Latest Release Of A Hex Package](elixir/determine-the-latest-release-of-a-hex-package.md)\n- [Do You Have The Time?](elixir/do-you-have-the-time.md)\n- [Do You Have The Time? - Part 2](elixir/do-you-have-the-time-part-2.md)\n- [Documentation Lookup With Vim And Alchemist](elixir/documentation-lookup-with-vim-and-alchemist.md)\n- [Dynamically Generating Atoms](elixir/dynamically-generating-atoms.md)\n- [Execute Raw SQL In An Ecto Migration](elixir/execute-raw-sql-in-an-ecto-migration.md)\n- [Expose Internal Representation](elixir/expose-internal-representation.md)\n- [Include Captures With String.split](elixir/include-captures-with-string-split.md)\n- [Inspecting The Process Message Queue](elixir/inspecting-the-process-message-queue.md)\n- [List Functions For A Module](elixir/list-functions-for-a-module.md)\n- [Listing Files In IEx](elixir/listing-files-in-iex.md)\n- [Match On A Map In A With Construct](elixir/match-on-a-map-in-a-with-construct.md)\n- [Passing Around And Using Modules](elixir/passing-around-and-using-modules.md)\n- [Pattern Matching In Anonymous Functions](elixir/pattern-matching-in-anonymous-functions.md)\n- [Pipe Into A Case Statement](elixir/pipe-into-a-case-statement.md)\n- [Quitting IEx](elixir/quitting-iex.md)\n- [Range Into List Using Comprehensions](elixir/range-into-list-using-comprehensions.md)\n- [Refer To A Module Within Itself](elixir/refer-to-a-module-within-itself.md)\n- [Referencing Values In IEx's History](elixir/referencing-values-in-iexs-history.md)\n- [Remove One List From Another](elixir/remove-one-list-from-another.md)\n- [Replace Duplicates In A Keyword List](elixir/replace-duplicates-in-a-keyword-list.md)\n- [Requiring Keys For Structs](elixir/requiring-keys-for-structs.md)\n- [Reversing A List](elixir/reversing-a-list.md)\n- [Reversing A List - Part 2](elixir/reversing-a-list-part-2.md)\n- [Root Directory Of A Project](elixir/root-directory-of-a-project.md)\n- [Round Floats To Integers](elixir/round-floats-to-integers.md)\n- [Run ExUnit Tests In A Deterministic Order](elixir/run-exunit-tests-in-a-deterministic-order.md)\n- [Run The Test At A Specific Line Number](elixir/run-the-test-at-a-specific-line-number.md)\n- [Same Functions Should Be Grouped Together](elixir/same-functions-should-be-grouped-together.md)\n- [Skip A Specific Test](elixir/skip-a-specific-test.md)\n- [String Interpolation With Just About Anything](elixir/string-interpolation-with-just-about-anything.md)\n- [Unique Indexes With Ecto](elixir/unique-indexes-with-ecto.md)\n- [Updating Values In A Map](elixir/updating-values-in-a-map.md)\n- [Using When Clauses In A With Construct](elixir/using-when-clauses-in-a-with-construct.md)\n- [Virtual Fields With Ecto Schemas](elixir/virtual-fields-with-ecto-schemas.md)\n- [When Things Don't Match The With Statements](elixir/when-things-dont-match-the-with-statements.md)\n- [Word Lists For Atoms](elixir/word-lists-for-atoms.md)\n\n### Gatsby\n\n- [Add JavaScript To Body Of The Document](gatsby/add-javascript-to-body-of-the-document.md)\n\n### Git\n\n- [Accessing a Lost Commit](git/accessing-a-lost-commit.md)\n- [Add A Range Of Filename To gitignore](git/add-a-range-of-filenames-to-gitignore.md)\n- [Add Only Tracked Files From A Directory](git/add-only-tracked-files-from-a-directory.md)\n- [Amend Author Of Previous Commit](git/amend-author-of-previous-commit.md)\n- [Auto-Squash Those Fixup Commits](git/auto-squash-those-fixup-commits.md)\n- [Better Diffs With Delta](git/better-diffs-with-delta.md)\n- [Caching Credentials](git/caching-credentials.md)\n- [Change The Start Point Of A Branch](git/change-the-start-point-of-a-branch.md)\n- [Check How A File Is Being Ignored](git/check-how-a-file-is-being-ignored.md)\n- [Check If A File Has Changed In A Script](git/check-if-a-file-has-changed-in-a-script.md)\n- [Check If A File Is Under Version Control](git/check-if-a-file-is-under-version-control.md)\n- [Checking Commit Ancestry](git/checking-commit-ancestry.md)\n- [Checkout Old Version Of A File](git/checkout-old-version-of-a-file.md)\n- [Checkout Previous Branch](git/checkout-previous-branch.md)\n- [Cherry Pick A Range Of Commits](git/cherry-pick-a-range-of-commits.md)\n- [Cherry Pick Multiple Commits At Once](git/cherry-pick-multiple-commits-at-once.md)\n- [Clean Out All Local Branches](git/clean-out-all-local-branches.md)\n- [Clean Out Working Copy With Patched Restore](git/clean-out-working-copy-with-patched-restore.md)\n- [Clean Up Old Remote Tracking References](git/clean-up-old-remote-tracking-references.md)\n- [Clear Entries From Git Stash](git/clear-entries-from-git-stash.md)\n- [Clone A Repo Just For The Files, Without History](git/clone-a-repo-just-for-the-files-without-history.md)\n- [Clone A Repo Locally From .git](git/clone-a-repo-locally-from-git.md)\n- [Configure Global gitignore File](git/configure-global-gitignore-file.md)\n- [Configuring The Pager](git/configuring-the-pager.md)\n- [Copy A File From Another Branch](git/copy-a-file-from-another-branch.md)\n- [Count All Files Of Specific Type Tracked By Git](git/count-all-files-of-specific-type-tracked-by-git.md)\n- [Count Number Of Commits On A Branch](git/count-number-of-commits-on-a-branch.md)\n- [Create A New Branch With Git Switch](git/create-a-new-branch-with-git-switch.md)\n- [Delete All Untracked Files](git/delete-all-untracked-files.md)\n- [Determine Absolute Path Of Top-Level Project Directory](git/determine-absolute-path-of-top-level-project-directory.md)\n- [Determine The Hash Id For A Blob](git/determine-the-hash-id-for-a-blob.md)\n- [Diffing With Patience](git/diffing-with-patience.md)\n- [Dropping Commits With Git Rebase](git/dropping-commits-with-git-rebase.md)\n- [Dry Runs in Git](git/dry-runs-in-git.md)\n- [Exclude A File From A Diff Output](git/exclude-a-file-from-a-diff-output.md)\n- [Exclude A Directory During A Command](git/exclude-a-directory-during-a-command.md)\n- [Excluding Files Locally](git/excluding-files-locally.md)\n- [Extend Git With Custom Commands](git/extend-git-with-custom-commands.md)\n- [Files With Local Changes Cannot Be Removed](git/files-with-local-changes-cannot-be-removed.md)\n- [Find And Remove Files That Match A Name](git/find-and-remove-files-that-match-a-name.md)\n- [Find The Date That A File Was Added To The Repo](git/find-the-date-that-a-file-was-added-to-the-repo.md)\n- [Find The Initial Commit](git/find-the-initial-commit.md)\n- [Fix Whitespace Errors Throughout Branch Commits](git/fix-whitespace-errors-throughout-branch-commits.md)\n- [Get Latest Commit Timestamp For A File](git/get-latest-commit-timestamp-for-a-file.md)\n- [Get The Name Of The Current Branch](git/get-the-name-of-the-current-branch.md)\n- [Get The Short Version Of The Latest Commit](git/get-the-short-version-of-the-latest-commit.md)\n- [Grab A Single File From A Stash](git/grab-a-single-file-from-a-stash.md)\n- [Grep For A Pattern On Another Branch](git/grep-for-a-pattern-on-another-branch.md)\n- [Grep Over Commit Messages](git/grep-over-commit-messages.md)\n- [Highlight Extra Whitespace In Diff Output](git/highlight-extra-whitespace-in-diff-output.md)\n- [Highlight Small Change On Single Line](git/highlight-small-change-on-single-line.md)\n- [Ignore Changes To A Tracked File](git/ignore-changes-to-a-tracked-file.md)\n- [Ignore Files Specific To Your Workflow](git/ignore-files-specific-to-your-workflow.md)\n- [Include A Message With Your Stashed Changes](git/include-a-message-with-your-stashed-changes.md)\n- [Include Or Exclude Remaining Patch Changes](git/include-or-exclude-remaining-patch-changes.md)\n- [Include Some Stats In Your Git Log](git/include-some-stats-in-your-git-log.md)\n- [Intent To Add](git/intent-to-add.md)\n- [Interactively Checkout Specific Files From A Stash](git/interactively-checkout-specific-files-from-a-stash.md)\n- [Interactively Unstage Changes](git/interactively-unstage-changes.md)\n- [Keep File Locally With `git rm`](git/keep-file-locally-with-git-rm.md)\n- [Last Commit A File Appeared In](git/last-commit-a-file-appeared-in.md)\n- [List All Files Added During Span Of Time](git/list-all-files-added-during-span-of-time.md)\n- [List All Files Changed Between Two Branches](git/list-all-files-changed-between-two-branches.md)\n- [List All Git Aliases From gitconfig](git/list-all-git-aliases-from-gitconfig.md)\n- [List Branches That Contain A Commit](git/list-branches-that-contain-a-commit.md)\n- [List Commits On A Branch](git/list-commits-on-a-branch.md)\n- [List Different Commits Between Two Branches](git/list-different-commits-between-two-branches.md)\n- [List Filenames Without The Diffs](git/list-filenames-without-the-diffs.md)\n- [List Just The Files Involved In A Commit](git/list-just-the-files-involved-in-a-commit.md)\n- [List Most Git Commands](git/list-most-git-commands.md)\n- [List Untracked Files](git/list-untracked-files.md)\n- [List Untracked Files For Scripting](git/list-untracked-files-for-scripting.md)\n- [Move The Latest Commit To A New Branch](git/move-the-latest-commit-to-a-new-branch.md)\n- [Override The Global Git Ignore File](git/override-the-global-git-ignore-file.md)\n- [Pick Specific Changes To Stash](git/pick-specific-changes-to-stash.md)\n- [Pulling In Changes During An Interactive Rebase](git/pulling-in-changes-during-an-interactive-rebase.md)\n- [Push To A Branch On Another Remote](git/push-to-a-branch-on-another-remote.md)\n- [Quicker Commit Fixes With The Fixup Flag](git/quicker-commit-fixes-with-the-fixup-flag.md)\n- [Rebase Commits With An Arbitrary Command](git/rebase-commits-with-an-arbitrary-command.md)\n- [Reference A Commit Via Commit Message Pattern Matching](git/reference-a-commit-via-commit-message-pattern-matching.md)\n- [Reference Commits Earlier Than Reflog Remembers](git/reference-commits-earlier-than-reflog-remembers.md)\n- [Remove Untracked Files From A Directory](git/remove-untracked-files-from-a-directory.md)\n- [Rename A Remote](git/rename-a-remote.md)\n- [Renaming A Branch](git/renaming-a-branch.md)\n- [Resetting A Reset](git/resetting-a-reset.md)\n- [Resolve A Merge Conflict From Stash Pop](git/resolve-a-merge-conflict-from-stash-pop.md)\n- [Restore File From One Branch To The Current](git/restore-file-from-one-branch-to-the-current.md)\n- [Review Commits From Before A Certain Date](git/review-commits-from-before-a-certain-date.md)\n- [Run A Git Command From Outside The Repo](git/run-a-git-command-from-outside-the-repo.md)\n- [Set A Custom Pager For A Specific Command](git/set-a-custom-pager-for-a-specific-command.md)\n- [Set Default Branch Name For New Repos](git/set-default-branch-name-for-new-repos.md)\n- [Set Up GPG Signing Key](git/set-up-gpg-signing-key.md)\n- [Shorthand To Force Push A Branch](git/shorthand-to-force-push-a-branch.md)\n- [Show All Commits For A File Beyond Renaming](git/show-all-commits-for-a-file-beyond-renaming.md)\n- [Show Changes For Files That Match A Pattern](git/show-changes-for-files-that-match-a-pattern.md)\n- [Show Changes In The Compose Commit Message View](git/show-changes-in-the-compose-commit-message-view.md)\n- [Show File Diffs When Viewing Git Log](git/show-file-diffs-when-viewing-git-log.md)\n- [Show List Of Most Recently Committed Branches](git/show-list-of-most-recently-committed-branches.md)\n- [Show Only Commits That Touch Specific Lines](git/show-only-commits-that-touch-specific-lines.md)\n- [Show Summary Stats For Current Branch](git/show-summary-stats-for-current-branch.md)\n- [Show The diffstat Summary Of A Commit](git/show-the-diffstat-summary-of-a-commit.md)\n- [Show The Good And The Bad With Git Bisect](git/show-the-good-and-the-bad-with-git-bisect.md)\n- [Show What Is In A Stash](git/show-what-is-in-a-stash.md)\n- [Single Key Presses in Interactive Mode](git/single-key-presses-in-interactive-mode.md)\n- [Skip A Bad Commit When Bisecting](git/skip-a-bad-commit-when-bisecting.md)\n- [Skip Git Hooks As Needed](git/skip-git-hooks-as-needed.md)\n- [Skip Pre-Commit Hooks](git/skip-pre-commit-hooks.md)\n- [Staging Changes Within Vim](git/staging-changes-within-vim.md)\n- [Staging Stashes Interactively](git/staging-stashes-interactively.md)\n- [Stash A Single Untracked File](git/stash-a-single-untracked-file.md)\n- [Stash Everything](git/stash-everything.md)\n- [Stashing Only Unstaged Changes](git/stashing-only-unstaged-changes.md)\n- [Stashing Untracked Files](git/stashing-untracked-files.md)\n- [Switch To A Recent Branch With FZF](git/switch-to-a-recent-branch-with-fzf.md)\n- [Transition A Branch From One Base To Another](git/transition-a-branch-from-one-base-to-another.md)\n- [Turn Off The Output Pager For One Command](git/turn-off-the-output-pager-for-one-command.md)\n- [Two Kinds Of Dotted Range Notation](git/two-kinds-of-dotted-range-notation.md)\n- [Undo Latest Changes Committed To Specific File](git/undo-latest-changes-committed-to-specific-file.md)\n- [Unstage Changes Wih Git Restore](git/unstage-changes-with-git-restore.md)\n- [Untrack A Directory Of Files Without Deleting](git/untrack-a-directory-of-files-without-deleting.md)\n- [Untrack A File Without Deleting It](git/untrack-a-file-without-deleting-it.md)\n- [Update The URL Of A Remote](git/update-the-url-of-a-remote.md)\n- [Use External Diff Tool Like Difftastic](git/use-external-diff-tool-like-difftastic.md)\n- [Using Commands With A Relative Date Format](git/using-commands-with-a-relative-date-format.md)\n- [Verbose Commit Message](git/verbose-commit-message.md)\n- [Viewing A File On Another Branch](git/viewing-a-file-on-another-branch.md)\n- [What Changed?](git/what-changed.md)\n- [What Is The Current Branch?](git/what-is-the-current-branch.md)\n- [Whitespace Warnings](git/whitespace-warnings.md)\n\n### GitHub\n\n- [Access Your GitHub Profile Photo](github/access-your-github-profile-photo.md)\n- [Open A PR To An Unforked Repo](github/open-a-pr-to-an-unforked-repo.md)\n- [Target Another Repo When Creating A PR](github/target-another-repo-when-creating-a-pr.md)\n- [Tell gh What The Default Repo Is](github/tell-gh-what-the-default-repo-is.md)\n\n### GitHub Actions\n\n- [Cache Playwright Dependencies Across Workflows](github-actions/cache-playwright-dependencies-across-workflows.md)\n- [Capture An Output Value For Use In A Later Step](github-actions/capture-an-output-value-for-use-in-a-later-step.md)\n- [Disable A Workflow With The gh CLI](github-actions/disable-a-workflow-with-the-gh-cli.md)\n- [Reference An Encrypted Secret In An Action](github-actions/reference-an-encrypted-secret-in-an-action.md)\n- [Trigger A Workflow Via An API Call](github-actions/trigger-a-workflow-via-an-api-call.md)\n- [Use Labels To Block PR Merge](github-actions/use-labels-to-block-pr-merge.md)\n\n### Go\n\n- [Access Go Docs Offline](go/access-go-docs-offline.md)\n- [Add A Method To A Struct](go/add-a-method-to-a-struct.md)\n- [Basic Delve Debugging Session](go/basic-delve-debugging-session.md)\n- [Build For A Specific OS And Architecture](go/build-for-a-specific-os-and-architecture.md)\n- [Check If Cobra Flag Was Set](go/check-if-cobra-flag-was-set.md)\n- [Combine Two Slices](go/combine-two-slices.md)\n- [Configure Max String Print Length For Delve](go/configure-max-string-print-length-for-delve.md)\n- [Connect To A SQLite Database](go/connect-to-a-sqlite-database.md)\n- [Create A Slice From An Array](go/create-a-slice-from-an-array.md)\n- [Detect If Stdin Comes From A Redirect](go/detect-if-stdin-comes-from-a-redirect.md)\n- [Deterministically Seed A Random Number Generator](go/deterministically-seed-a-random-number-generator.md)\n- [Difference Between Slice And Pointer To Slice](go/difference-between-slice-and-pointer-to-slice.md)\n- [Do Something N Times](go/do-something-n-times.md)\n- [Find Executables Installed By Go](go/find-executables-installed-by-go.md)\n- [Format Date And Time With Time Constants](go/format-date-and-time-with-time-constants.md)\n- [Not So Random](go/not-so-random.md)\n- [Parse A String Into Individual Fields](go/parse-a-string-into-individual-fields.md)\n- [Parse Flags From CLI Arguments](go/parse-flags-from-cli-arguments.md)\n- [Pass A Struct To A Function](go/pass-a-struct-to-a-function.md)\n- [Produce The Zero Value Of A Generic Type](go/produce-the-zero-value-of-a-generic-type.md)\n- [Redirect File To Stdin During Delve Debug](go/redirect-file-to-stdin-during-delve-debug.md)\n- [Replace The Current Process With An External Command](go/replace-the-current-process-with-an-external-command.md)\n- [Sleep For A Duration](go/sleep-for-a-duration.md)\n- [Sort Slice In Ascending Or Descending Order](go/sort-slice-in-ascending-or-descending-order.md)\n- [Upgrading From An Older Version On Mac](go/upgrading-from-an-older-version-on-mac.md)\n- [Write A Custom Scan Function For File IO](go/write-a-custom-scan-function-for-file-io.md)\n\n### GROQ\n\n- [Grab Multiple Values From A Reference](groq/grab-multiple-values-from-a-reference.md)\n- [Grab Values From An Array Of References](groq/grab-values-from-an-array-of-references.md)\n- [Include Attributes When Conditional Check Passes](groq/include-attributes-when-conditional-check-passes.md)\n- [Include Type Of Operation In Webhook Response](groq/include-type-of-operation-in-webhook-response.md)\n\n### Heroku\n\n- [Check Ruby Version For Production App](heroku/check-ruby-version-for-production-app.md)\n- [Connect To A Database By Color](heroku/connect-to-a-database-by-color.md)\n- [Deploy A Review App To A Different Stack](heroku/deploy-a-review-app-to-a-different-stack.md)\n- [Diagnose Problems In A Heroku Postgres Database](heroku/diagnose-problems-in-a-heroku-postgres-database.md)\n- [Open Dashboard For Specific Add-On](heroku/open-dashboard-for-specific-add-on.md)\n- [Run SQL Against Remote Postgres Database](heroku/run-sql-against-remote-postgres-database.md)\n- [Set And Show Heroku Env Variables](heroku/set-and-show-heroku-env-variables.md)\n- [Specify Default Team And App For Project](heroku/specify-default-team-and-app-for-project.md)\n- [SSH Into Heroku Server Hosting App](heroku/ssh-into-heroku-server-hosting-app.md)\n\n### HTML\n\n- [Adding Alt Text To An Image](html/adding-alt-text-to-an-image.md)\n- [Allow Number Input To Accept Decimal Values](html/allow-number-input-to-accept-decimal-values.md)\n- [Determine Which Button Submitted The Form](html/determine-which-button-submitted-the-form.md)\n- [Disable Auto-Completion For A Form Input](html/disable-auto-completion-for-a-form-input.md)\n- [Disclose Additional Details](html/disclose-additional-details.md)\n- [Make Elements Non-Interactive With Inert](html/make-elements-non-interactive-with-inert.md)\n- [Prevent Search Engines From Indexing A Page](html/prevent-search-engines-from-indexing-a-page.md)\n- [Render Text As Superscript](html/render-text-as-superscript.md)\n- [Submit A Form With A Button Outside The Form](html/submit-a-form-with-a-button-outside-the-form.md)\n\n### HTTP\n\n- [What Counts As Cross-Origin With CORS?](http/what-counts-as-cross-origin-with-cors.md)\n\n### Inngest\n\n- [Ensure Lookup Can Be Retried](inngest/ensure-lookup-can-be-retried.md)\n- [Exit Function Early Without Retries](inngest/exit-function-early-without-retries.md)\n\n### Internet\n\n- [Add Emoji To GitHub Repository Description](internet/add-emoji-to-github-repository-description.md)\n- [Add Styled Alerts To GitHub Markdown Documents](internet/add-styled-alerts-to-github-markdown-documents.md)\n- [Analyze Your Website Performance](internet/analyze-your-website-performance.md)\n- [Check Your Public IP Address](internet/check-your-public-ip-address.md)\n- [Digraph Unicode Characters Have A Titlecase](internet/digraph-unicode-characters-have-a-titlecase.md)\n- [Download A Google Doc As Specific Format](internet/download-a-google-doc-as-specific-format.md)\n- [Enable Keyboard Shortcuts In Gmail](internet/enable-keyboard-shortcuts-in-gmail.md)\n- [Exclude AI Overview From Google Search](internet/exclude-ai-overview-from-google-search.md)\n- [Exclude Whitespace Changes From GitHub Diffs](internet/exclude-whitespace-changes-from-github-diffs.md)\n- [Figure Out Your Public IP Address](internet/figure-out-your-public-ip-address.md)\n- [Focus The URL Bar](internet/focus-the-url-bar.md)\n- [Get Random Images From Unsplash](internet/get-random-images-from-unsplash.md)\n- [Grab The RSS Feed For A Substack Blog](internet/grab-the-rss-feed-for-a-substack-blog.md)\n- [Hide Overflowing Text For Google Sheets Column](internet/hide-overflowing-text-for-google-sheets-column.md)\n- [Search Tweets By Author](internet/search-tweets-by-author.md)\n- [Show All Pivotal Stories With Blockers](internet/show-all-pivotal-stories-with-blockers.md)\n- [Verify Site Ownership With DNS Record](internet/verify-site-ownership-with-dns-record.md)\n\n### Java\n\n- [Ensure Resources Always Get Closed](java/ensure-resources-always-get-closed.md)\n- [Install Java On Mac With Brew](java/install-java-on-mac-with-brew.md)\n- [Run A Hello World Program In Eclipse](java/run-a-hello-world-program-in-eclipse.md)\n\n### JavaScript\n\n- [Accessing Arguments To A Function](javascript/accessing-arguments-to-a-function.md)\n- [Add Item To An Array Of References In Sanity](javascript/add-item-to-an-array-of-references-in-sanity.md)\n- [Basic Date Formatting Without A Library](javascript/basic-date-formatting-without-a-library.md)\n- [Character Codes from Keyboard Listeners](javascript/character-codes-from-keyboard-listeners.md)\n- [Check Classes On A DOM Element](javascript/check-classes-on-a-dom-element.md)\n- [Check If A Number Is Positive Or Negative](javascript/check-if-a-number-is-positive-or-negative.md)\n- [Check If File Exists Before Reading It](javascript/check-if-file-exists-before-reading-it.md)\n- [Check If Something Is An Array](javascript/check-if-something-is-an-array.md)\n- [Check Media Queries From JavaScript](javascript/check-media-queries-from-javascript.md)\n- [Check The Password Confirmation With Yup](javascript/check-the-password-confirmation-with-yup.md)\n- [Compare The Equality Of Two Date Objects](javascript/compare-the-equality-of-two-date-objects.md)\n- [Computed Property Names In ES6](javascript/computed-property-names-in-es6.md)\n- [Conditionally Include Pairs In An Object](javascript/conditionally-include-pairs-in-an-object.md)\n- [Configure Jest To Run A Test Setup File](javascript/configure-jest-to-run-a-test-setup-file.md)\n- [Convert Seconds To Date Object](javascript/convert-seconds-to-date-object.md)\n- [Create A Cancelable Promise With PCancelable](javascript/create-a-cancelable-promise-with-pcancelable.md)\n- [Create An Array Containing 1 To N](javascript/create-an-array-containing-1-to-n.md)\n- [Create An Object With No Properties](javascript/create-an-object-with-no-properties.md)\n- [Create Bootstrapped Apps With Yarn](javascript/create-bootstrapped-apps-with-yarn.md)\n- [Create Future And Past Dates From Today](javascript/create-future-and-past-dates-from-today.md)\n- [Custom Type Checking Error Messages With Yup](javascript/custom-type-checking-error-messages-with-yup.md)\n- [Default And Named Exports From The Same Module](javascript/default-and-named-exports-from-the-same-module.md)\n- [Define A Custom Jest Matcher](javascript/define-a-custom-jest-matcher.md)\n- [Destructure With Access To Nested Value And Parent Value](javascript/destructure-with-access-to-nested-value-and-parent-value.md);\n- [Destructuring The Rest Of An Array](javascript/destructuring-the-rest-of-an-array.md)\n- [Enable ES7 Transforms With react-rails](javascript/enable-es7-transforms-with-react-rails.md)\n- [Ensure Shell Can Find Global npm Binaries](javascript/ensure-shell-can-find-global-npm-binaries.md)\n- [Easy Date Comparison With DayJS](javascript/easy-date-comparison-with-dayjs.md)\n- [Expand Emojis With The Spread Operator](javascript/expand-emojis-with-the-spread-operator.md)\n- [Fill An Input With A Ton Of Text](javascript/fill-an-input-with-a-ton-of-text.md)\n- [Find The Version Of An Installed Dependency](javascript/find-the-version-of-an-installed-dependency.md)\n- [Find Where Yarn Is Installing Binaries](javascript/find-where-yarn-is-installing-binaries.md)\n- [for...in Iterates Over Object Properties](javascript/for-in-iterates-over-object-properties.md)\n- [Format A Decimal To A Fixed Number Of Digits](javascript/format-a-decimal-to-a-fixed-number-of-digits.md)\n- [Format A List Of Items By Locale](javascript/format-a-list-of-items-by-locale.md)\n- [Format Time Zone Identifier](javascript/format-time-zone-identifier.md)\n- [Formatting Values With Units For Display](javascript/formatting-values-with-units-for-display.md)\n- [Freeze An Object, Sorta](javascript/freeze-an-object-sorta.md)\n- [Generate A V4 UUID In The Browser](javascript/generate-a-v4-uuid-in-the-browser.md)\n- [Generate Random Integers](javascript/generate-random-integers.md)\n- [Get The Location And Size Of An Element](javascript/get-the-location-and-size-of-an-element.md)\n- [Get The Response Status From An Axios Error](javascript/get-the-response-status-from-an-axios-error.md)\n- [Get The Time Components Of A Date](javascript/get-the-time-components-of-a-date.md)\n- [Get The Time Zone Of The Client Computer](javascript/get-the-time-zone-of-the-client-computer.md)\n- [Globally Install A Package With Yarn](javascript/globally-install-a-package-with-yarn.md)\n- [Globally Install Specific Version Of PNPM](javascript/globally-install-specific-version-of-pnpm.md)\n- [Immutable Remove With The Spread Operator](javascript/immutable-remove-with-the-spread-operator.md)\n- [Initialize A New JavaScript Project With Yarn](javascript/initialize-a-new-javascript-project-with-yarn.md)\n- [Install The Latest Version Of Node With Nvm](javascript/install-the-latest-version-of-node-with-nvm.md)\n- [Interpolate A String Into A Regex](javascript/interpolate-a-string-into-a-regex.md)\n- [ISO-8601 Formatted Dates Are Interpreted As UTC](javascript/iso-8601-formatted-dates-are-interpreted-as-utc.md)\n- [Link A JavaScript Package Locally](javascript/link-a-javascript-package-locally.md)\n- [List Top-Level NPM Dependencies](javascript/list-top-level-npm-dependencies.md)\n- [Load And Use Env Var In Node Script](javascript/load-and-use-env-var-in-node-script.md)\n- [Make The Browser Editable With Design Mode](javascript/make-the-browser-editable-with-design-mode.md)\n- [Make Truly Deep Clone With Structured Clone](javascript/make-truly-deep-clone-with-structured-clone.md)\n- [Matching A Computed Property In Function Args](javascript/matching-a-computed-property-in-function-args.md)\n- [Matching Multiple Values In A Switch Statement](javascript/matching-multiple-values-in-a-switch-statement.md)\n- [Mock A Function With Return Values Using Jest](javascript/mock-a-function-with-return-values-using-jest.md)\n- [New Dates Can Take Out Of Bounds Values](javascript/new-dates-can-take-out-of-bounds-values.md)\n- [Numbers Are Empty](javascript/numbers-are-empty.md)\n- [Object Initialization With Shorthand Property Names](javascript/object-initialization-with-shorthand-property-names.md)\n- [Obtain Undefined Value With The Void Operator](javascript/obtain-undefined-value-with-the-void-operator.md)\n- [Open Global npm Config File](javascript/open-global-npm-config-file.md)\n- [Parse A Date From A Timestamp](javascript/parse-a-date-from-a-timestamp.md)\n- [Pre And Post Hooks For Yarn Scripts](javascript/pre-and-post-hooks-for-yarn-scripts.md)\n- [Prevent Hidden Element From Flickering On Load](javascript/prevent-hidden-element-from-flickering-on-load.md)\n- [Purge Null And Undefined Values From Object](javascript/purge-null-and-undefined-values-from-object.md)\n- [Random Cannot Be Seeded](javascript/random-cannot-be-seeded.md)\n- [Reach Into An Object For Nested Data With Get](javascript/reach-into-an-object-for-nested-data-with-get.md)\n- [Render An Array Of Elements With React 16](javascript/render-an-array-of-elements-with-react-16.md)\n- [Resolve And Pass Multiple Values From A Then](javascript/resolve-and-pass-multiple-values-from-a-then.md)\n- [Run A Bash Script From A Node Script](javascript/run-a-bash-script-from-a-node-script.md)\n- [Run Multiple Node Scripts Concurrently](javascript/run-multiple-node-scripts-concurrently.md)\n- [Running ES6 Specs With Mocha](javascript/running-es6-specs-with-mocha.md)\n- [Scoping Variables With A Block Statement](javascript/scoping-variables-with-a-block-statement.md)\n- [Short Circuit Concurrently When Process Fails](javascript/short-circuit-concurrently-when-process-fails.md)\n- [Show Description Of All npm Config Options](javascript/show-description-of-all-npm-config-options.md)\n- [Sleep For A Bit In Async Code](javascript/sleep-for-a-bit-in-async-code.md)\n- [Sorting Arrays Of Objects With Lodash](javascript/sorting-arrays-of-objects-with-lodash.md)\n- [Splat Arguments To A Function](javascript/splat-arguments-to-a-function.md)\n- [Spread Merging Objects Includes Nil Values](javascript/spread-merging-objects-includes-nil-values.md)\n- [Spread The Rest With ES6](javascript/spread-the-rest-with-es6.md)\n- [Start Node Process In Specific Timezone](javascript/start-node-process-in-specific-timezone.md)\n- [String Interpolation With Template Literals](javascript/string-interpolation-with-template-literals.md)\n- [Support Nested Matching In Custom Jest Matchers](javascript/support-nested-matching-in-custom-jest-matchers.md)\n- [Tell Jest To Focus On Running Only One Test](javascript/tell-jest-to-focus-on-running-only-one-test.md)\n- [Tell Node To Treat JS Files As ESM](javascript/tell-node-to-treat-js-files-as-esm.md)\n- [Tell Prettier To Not Format A Statement](javascript/tell-prettier-to-not-format-a-statement.md)\n- [Test Coverage Stats With Jest](javascript/test-coverage-stats-with-jest.md)\n- [Test Timing-Based Code With Jest Fake Timers](javascript/test-timing-based-code-with-jest-fake-timers.md)\n- [The Comma Operator](javascript/the-comma-operator.md)\n- [Throttling A Function Call](javascript/throttling-a-function-call.md)\n- [Timing Processes](javascript/timing-processes.md)\n- [Transforming ES6 and JSX With Babel 6](javascript/transforming-es6-and-jsx-with-babel-6.md)\n- [Truthiness of Integer Arrays](javascript/truthiness-of-integer-arrays.md)\n- [Turn An HTMLCollection Into An Array](javascript/turn-an-html-collection-into-an-array.md)\n- [Turn Off Console Error Messages In A Test](javascript/turn-off-console-error-messages-in-a-test.md)\n- [Turn Off npm Funding Message](javascript/turn-off-npm-funding-message.md)\n- [Waiting On Multiple Promises](javascript/waiting-on-multiple-promises.md)\n- [Who Am I: NPM Edition](javascript/who-am-i-npm-edition.md)\n- [Write A JavaScript Object To A JSON File](javascript/write-a-javascript-object-to-a-json-file.md)\n- [Yarn Commands Without The Emojis](javascript/yarn-commands-without-the-emojis.md)\n- [Yup Schemas Are Validated Asynchronously](javascript/yup-schemas-are-validated-asynchronously.md)\n\n### jj\n\n- [Colocate jj And git Directories For Project](jj/colocate-jj-and-git-directories-for-project.md)\n- [Describe Current Changes And Create New Change](jj/describe-current-changes-and-create-new-change.md)\n- [Find System-wide Config File For User](jj/find-system-wide-config-file-for-user.md)\n- [Squash Changes Into Parent Commit Interactively](jj/squash-changes-into-parent-commit-interactively.md)\n\n### jq\n\n- [Combine An Array Of Objects Into A Single Object](jq/combine-an-array-of-objects-into-a-single-object.md)\n- [Count Each Collection In A JSON Object](jq/count-each-collection-in-a-json-object.md)\n- [Count The Number Of Things In A JSON File](jq/count-the-number-of-things-in-a-json-file.md)\n- [Extract A List Of Values](jq/extract-a-list-of-values.md)\n- [Filter Out Results Based On List Of Values](jq/filter-out-results-based-on-list-of-values.md)\n- [Find All Objects In An Array Where Key Is Set](jq/find-all-objects-in-an-array-where-key-is-set.md)\n- [Find All Objects With A Matching Key Value Pair](jq/find-all-objects-with-a-matching-key-value-pair.md)\n- [Get A Slice Of The Ends Of An Array](jq/get-a-slice-of-the-ends-of-an-array.md)\n- [Get The First Item For Every Top-Level Key](jq/get-the-first-item-for-every-top-level-key.md)\n- [Get The Last Item From An Array](jq/get-the-last-item-from-an-array.md)\n- [Reduce Object To Just Entries Of A Specific Type](jq/reduce-object-to-just-entries-of-a-specific-type.md)\n- [Turn A List From A Command Into JSON](jq/turn-a-list-from-a-command-into-json.md)\n- [Zip Two JSON Files Together Based On Shared ID](jq/zip-two-json-files-together-based-on-shared-id.md)\n\n### Kitty\n\n- [Set The Title Of A Window](kitty/set-the-title-of-a-window.md)\n- [Use The Built-In Emoji Picker](kitty/use-the-built-in-emoji-picker.md)\n\n### Linux\n\n- [Check Ubuntu Version](linux/check-ubuntu-version.md)\n- [Configure Your Server Timezone](linux/configure-your-server-timezone.md)\n- [List The Statuses Of All Upstart Jobs](linux/list-the-statuses-of-all-upstart-jobs.md)\n- [Show Current System Time And Settings](linux/show-current-system-time-and-settings.md)\n- [Show Used And Available System Memory](linux/show-used-and-available-system-memory.md)\n- [Upgrading Ubuntu](linux/upgrading-ubuntu.md)\n\n### LLM\n\n- [Send cURL To Claude Text Completion API](llm/send-curl-to-claude-text-completion-api.md)\n- [Use The llm CLI With Claude Models](llm/use-the-llm-cli-with-claude-models.md)\n\n### Mac\n\n- [Access All Screen And Video Capture Options](mac/access-all-screen-and-video-capture-options.md)\n- [Access System Information On OS X](mac/access-system-information-on-osx.md)\n- [Access Unsupported Screen Resolutions With RDM](mac/access-unsupported-screen-resolutions-with-rdm.md)\n- [Add A Bunch Of CLI Utilities With coreutils](mac/add-a-bunch-of-cli-utilities-with-coreutils.md)\n- [Capture Screenshot To Clipboard From CLI](mac/capture-screenshot-to-clipboard-from-cli.md)\n- [Check Network Quality Stats From The Command Line](mac/check-network-quality-stats-from-the-command-line.md)\n- [Clean Up Old Homebrew Files](mac/clean-up-old-homebrew-files.md)\n- [Control Which Monitor App Switcher Appears On](mac/control-which-monitor-app-switcher-appears-on.md)\n- [Convert An HEIC Image File To JPG](mac/convert-an-heic-image-file-to-jpg.md)\n- [Default Screenshot Location](mac/default-screenshot-location.md)\n- [Detect How Long A User Has Been Idle](mac/detect-how-long-a-user-has-been-idle.md)\n- [Disable Swipe Navigation For A Specific App](mac/disable-swipe-navigation-for-a-specific-app.md)\n- [Display A Message With Alfred](mac/display-a-message-with-alfred.md)\n- [Find The Process Using A Specific Port](mac/find-the-process-using-a-specific-port.md)\n- [Gesture For Viewing All Windows Of Current App](mac/gesture-for-viewing-all-windows-of-current-app.md)\n- [Insert A Non-Breaking Space Character](mac/insert-a-non-breaking-space-character.md)\n- [Inspect Assertions Preventing Sleep](mac/inspect-assertions-preventing-sleep.md)\n- [Keyboard Shortcuts For Interesting With Text Areas](mac/keyboard-shortcuts-for-interacting-with-text-areas.md)\n- [Launch Some Confetti](mac/launch-some-confetti.md)\n- [List All The Say Voices](mac/list-all-the-say-voices.md)\n- [Open Finder.app To Specific Directory](mac/open-finder-app-to-specific-directory.md)\n- [Prevent Sleep With The Caffeinate Command](mac/prevent-sleep-with-the-caffeinate-command.md)\n- [Quickly Type En Dashes And Em Dashes](mac/quickly-type-en-dashes-and-em-dashes.md)\n- [Require Additional JS Libraries In Postman](mac/require-additional-js-libraries-in-postman.md)\n- [Resize App Windows With AppleScript](mac/resize-app-windows-with-applescript.md)\n- [Resizing Both Corners Of A Window](mac/resizing-both-corners-of-a-window.md)\n- [Reveal Location Of File In Finder.app](mac/reveal-location-of-file-in-finder-app.md)\n- [Run A Hardware Check](mac/run-a-hardware-check.md)\n- [Run AppleScript Commands Inline In The Terminal](mac/run-applescript-commands-inline-in-the-terminal.md)\n- [Set A Window To Its Default Zoom Level](mac/set-a-window-to-its-default-zoom-level.md)\n- [Specify App When Opening From Command Line](mac/specify-app-when-opening-from-command-line.md)\n- [Start Amphetamine Session With AppleScript](mac/start-amphetamine-session-with-applescript.md)\n- [Uninstall LogiTech G Hub From Mac](mac/uninstall-logitech-g-hub-from-mac.md)\n- [Use A Different Font With iTerm2](mac/use-a-different-font-with-iterm2.md)\n- [Use Default Screenshot Shortcuts With CleanShot X](mac/use-default-screenshot-shortcuts-with-cleanshot-x.md)\n- [View All Windows Of The Current App](mac/view-all-windows-of-the-current-app.md)\n- [Write System Clipboard To A File](mac/write-system-clipboard-to-a-file.md)\n\n### Mise\n\n- [Create Umbrella Task For All Test Tasks](mise/create-umbrella-task-for-all-test-tasks.md)\n- [List The Files Being Loaded By Mise](mise/list-the-files-being-loaded-by-mise.md)\n- [Look In Ruby Version Dotfile](mise/look-in-ruby-version-dotfile.md)\n- [Override Your Project Mise File](mise/override-your-project-mise-file.md)\n- [Pick From Tasks Using Interactive Picker](mise/pick-from-tasks-using-interactive-picker.md)\n- [Preserve Color Output For Task Command](mise/preserve-color-output-for-task-command.md)\n- [Read Existing Dot Env File Into Env Vars](mise/read-existing-dot-env-file-into-env-vars.md)\n- [Run A Command With Specific Tool Version](mise/run-a-command-with-specific-tool-version.md)\n- [Search Through Bin Paths For Tool Locations](mise/search-through-bin-paths-for-tool-locations.md)\n\n### MongoDB\n\n- [Determine The Database Version](mongodb/determine-the-database-version.md)\n- [Dump A Remote Database](mongodb/dump-a-remote-database.md)\n- [Dump And Restore With A Single gzip File](mongodb/dump-and-restore-with-a-single-gzip-file.md)\n- [Get Size Stats For A Collection](mongodb/get-size-stats-for-a-collection.md)\n- [List Size Stats For All Collections](mongodb/list-size-stats-for-all-collections.md)\n\n### MySQL\n\n- [Change Existing Column To Not Null](mysql/change-existing-column-to-not-null.md)\n- [Connect To A Database In Safe Update Mode](mysql/connect-to-a-database-in-safe-update-mode.md)\n- [Default Username And Password For New Instance](mysql/default-username-and-password-for-new-instance.md)\n- [Display Output In A Vertical Format](mysql/display-output-in-a-vertical-format.md)\n- [Doing Date Math](mysql/doing-date-math.md)\n- [Dump A Database To A File](mysql/dump-a-database-to-a-file.md)\n- [Echo A Message From A SQL File](mysql/echo-a-message-from-a-sql-file.md)\n- [Get Idea Of What Is In A JSON Column](mysql/get-idea-of-what-is-in-a-json-column.md)\n- [Ignore Duplicates When Inserting Records](mysql/ignore-duplicates-when-inserting-records.md)\n- [List Databases And Tables](mysql/list-databases-and-tables.md)\n- [Run Statements In A Transaction](mysql/run-statements-in-a-transaction.md)\n- [Select Rows After An Offset](mysql/select-rows-after-an-offset.md)\n- [Set Value On Null JSON Column](mysql/set-value-on-null-json-column.md)\n- [Show Create Statement For A Table](mysql/show-create-statement-for-a-table.md)\n- [Show Tables That Match A Pattern](mysql/show-tables-that-match-a-pattern.md)\n- [Show Indexes For A Table](mysql/show-indexes-for-a-table.md)\n\n### Neovim\n\n- [Allow Neovim To Copy/Paste With System Clipboard](neovim/allow-neovim-to-copy-paste-with-system-clipboard.md)\n- [Create User Command To Open Init Config](neovim/create-user-command-to-open-init-config.md)\n- [Jump Between Changes In Current File](neovim/jump-between-changes-in-current-file.md)\n- [Run A Lua Statement From The Command Prompt](neovim/run-a-lua-statement-from-the-command-prompt.md)\n- [Run nvim With Factory Defaults](neovim/run-nvim-with-factory-defaults.md)\n- [Set Up Vim-Plug With Neovim](neovim/set-up-vim-plug-with-neovim.md)\n\n### Netlify\n\n- [Override The Default Yarn Version](netlify/override-the-default-yarn-version.md)\n\n### NextAuth.js\n\n- [Adjust The Shape Of The User Type](next-auth/adjust-the-shape-of-the-user-type.md)\n\n### Next.js\n\n- [Avoid Conflicting Files](nextjs/avoid-conflicting-files.md)\n- [Create Files And Directories For Dynamic Routes](nextjs/create-files-and-directories-for-dynamic-routes.md)\n- [Define URL Redirects In The Next Config](nextjs/define-url-redirects-in-the-next-config.md)\n- [Fetch Does Not Work In API Serverless Function](nextjs/fetch-does-not-work-in-api-serverless-function.md)\n- [Make Environment Variable Publicly Available](nextjs/make-environment-variable-publicly-available.md)\n- [Match Middleware On Groups Of Paths](nextjs/match-middleware-on-groups-of-paths.md)\n- [Organize Pages In Route Groups](nextjs/organize-pages-in-route-groups.md)\n- [Precedence Of Dot Env Files](nextjs/precedence-of-dot-env-files.md)\n- [Push A Route With A URL Object](nextjs/push-a-route-with-a-url-object.md)\n- [Redirect An Unauthorized User](nextjs/redirect-an-unauthorized-user.md)\n- [Remove A Query Param From The URL](nextjs/remove-a-query-param-from-the-url.md)\n- [Ship Public Assets With A Next.js App](nextjs/ship-public-assets-with-a-nextjs-app.md)\n\n### Phoenix\n\n- [Bypass Template Rendering](phoenix/bypass-template-rendering.md)\n- [Check The Installed Version](phoenix/check-the-installed-version.md)\n- [Generate New App Without Brunch](phoenix/generate-new-app-without-brunch.md)\n- [Render A Template To A String](phoenix/render-a-template-to-a-string.md)\n- [Serve Static Assets From Custom Directory](phoenix/serve-static-assets-from-custom-directory.md)\n- [Specifying The Digest Directory](phoenix/specifying-the-digest-directory.md)\n- [Specifying The Server Port](phoenix/specifying-the-server-port.md)\n\n### Planetscale\n\n- [See What Databases You Have Access To](planetscale/see-what-databases-you-have-access-to.md)\n- [Seed Production Data Into Another Branch](planetscale/seed-production-data-into-another-branch.md)\n\n### pnpm\n\n- [Execute A Command From The Workspace Root](pnpm/execute-a-command-from-the-workspace-root.md)\n- [Install Command Runs For Entire Workspace](pnpm/install-command-runs-for-entire-workspace.md)\n- [List The Installed Version Of A Specific Package](pnpm/list-the-installed-version-of-a-specific-package.md)\n\n### PostgreSQL\n\n- [A Better Null Display Character](postgres/a-better-null-display-character.md)\n- [Add Foreign Key Constraint Without A Full Lock](postgres/add-foreign-key-constraint-without-a-full-lock.md)\n- [Add ON DELETE CASCADE To Foreign Key Constraint](postgres/add-on-delete-cascade-to-foreign-key-constraint.md)\n- [Add Unique Constraint Using Existing Index](postgres/add-unique-constraint-using-existing-index.md)\n- [Adding Composite Uniqueness Constraints](postgres/adding-composite-uniqueness-constraints.md)\n- [Aggregate A Column Into An Array](postgres/aggregate-a-column-into-an-array.md)\n- [Assumed Radius Of The Earth](postgres/assumed-radius-of-the-earth.md)\n- [Auto Expanded Display](postgres/auto-expanded-display.md)\n- [Between Symmetric](postgres/between-symmetric.md)\n- [Capitalize All The Words](postgres/capitalize-all-the-words.md)\n- [Change The Current Directory For psql](postgres/change-the-current-directory-for-psql.md)\n- [Change The Owner Of A Sequence](postgres/change-the-owner-of-a-sequence.md)\n- [Check If Clusters Are Upgrade Compatible](postgres/check-if-clusters-are-upgrade-compatible.md)\n- [Check If The Local Server Is Running](postgres/check-if-the-local-server-is-running.md)\n- [Check If User Role Exists For Database](postgres/check-if-user-role-exists-for-database.md)\n- [Check Table For Any Oprhaned Records](postgres/check-table-for-any-orphaned-records.md)\n- [Check The Size Of Databases In A Cluster](postgres/check-the-size-of-databases-in-a-cluster.md)\n- [Checking Inequality](postgres/checking-inequality.md)\n- [Checking The Type Of A Value](postgres/checking-the-type-of-a-value.md)\n- [Clear The Screen In psql](postgres/clear-the-screen-in-psql.md)\n- [Clear The Screen In psql (2)](postgres/clear-the-screen-in-psql-2.md)\n- [Compute Hashes With pgcrypto](postgres/compute-hashes-with-pgcrypto.md)\n- [Compute Median Instead Of Average](postgres/compute-median-instead-of-average.md)\n- [Compute The Levenshtein Distance Of Two Strings](postgres/compute-the-levenshtein-distance-of-two-strings.md)\n- [Compute The md5 Hash Of A String](postgres/compute-the-md5-hash-of-a-string.md)\n- [Concatenate Strings With A Separator](postgres/concatenate-strings-with-a-separator.md)\n- [Configure The Timezone](postgres/configure-the-timezone.md)\n- [Constructing A Range Of Dates](postgres/constructing-a-range-of-dates.md)\n- [Convert A String To A Timestamp](postgres/convert-a-string-to-a-timestamp.md)\n- [Count How Many Records There Are Of Each Type](postgres/count-how-many-records-there-are-of-each-type.md)\n- [Count Records By Type](postgres/count-records-by-type.md)\n- [Count The Number Of Items In An Array](postgres/count-the-number-of-items-in-an-array.md)\n- [Count The Number Of Trues In An Aggregate Query](postgres/count-the-number-of-trues-in-an-aggregate-query.md)\n- [Create A Cluster In A Specific Data Directory](postgres/create-a-cluster-in-a-specific-data-directory.md)\n- [Create A Composite Primary Key](postgres/create-a-composite-primary-key.md)\n- [Create A Table From The Structure Of Another](postgres/create-a-table-from-the-structure-of-another.md)\n- [Create An Index Across Two Columns](postgres/create-an-index-across-two-columns.md)\n- [Create An Index Without Locking The Table](postgres/create-an-index-without-locking-the-table.md)\n- [Create And Execute SQL Statements With \\gexec](postgres/create-and-execute-sql-statements-with-gexec.md)\n- [Create Database Uses Template1](postgres/create-database-uses-template1.md)\n- [Create hstore From Two Arrays](postgres/create-hstore-from-two-arrays.md)\n- [Create Table Adds A Data Type](postgres/create-table-adds-a-data-type.md)\n- [Creating Conditional Constraints](postgres/creating-conditional-constraints.md)\n- [Creating Custom Types](postgres/creating-custom-types.md)\n- [Day Of Week By Name For A Date](postgres/day-of-week-by-name-for-a-date.md)\n- [Day Of Week For A Date](postgres/day-of-week-for-a-date.md)\n- [Default Schema](postgres/default-schema.md)\n- [Defining Arrays](postgres/defining-arrays.md)\n- [Determine Types Of JSONB Records](postgres/determine-types-of-jsonb-records.md)\n- [Determining The Age Of Things](postgres/determining-the-age-of-things.md)\n- [Difference Between Explain And Explain Analyze](postgres/difference-between-explain-and-explain-analyze.md)\n- [Different Ways To Define An Interval](postgres/different-ways-to-define-an-interval.md)\n- [Dump All Databases To A SQL File](postgres/dump-all-databases-to-a-sql-file.md)\n- [Dump And Restore A Database](postgres/dump-and-restore-a-database.md)\n- [Dump The SQL Needed To Recreate A Table](postgres/dump-the-sql-needed-recreate-a-table.md)\n- [Duplicate A Local Database](postgres/duplicate-a-local-database.md)\n- [Edit Existing Functions](postgres/edit-existing-functions.md)\n- [Enable Logging Of Database Activity](postgres/enable-logging-of-database-activity.md)\n- [Enforce Uniqueness On Column Expression](postgres/enforce-uniqueness-on-column-expression.md)\n- [Escaping A Quote In A String](postgres/escaping-a-quote-in-a-string.md)\n- [Escaping String Literals With Dollar Quoting](postgres/escaping-string-literals-with-dollar-quoting.md)\n- [Export Query Results To A CSV](postgres/export-query-results-to-a-csv.md)\n- [Extracting Nested JSON Data](postgres/extracting-nested-json-data.md)\n- [Fetch Data From An Endpoint In SQL](postgres/fetch-data-from-an-endpoint-in-sql.md)\n- [Fetch Specific Number Of Results](postgres/fetch-specific-number-of-results.md)\n- [Find Duplicate Records In Table Without Unique Id](postgres/find-duplicate-records-in-table-without-unique-id.md)\n- [Find Records That Contain Duplicate Values](postgres/find-records-that-contain-duplicate-values.md)\n- [Find Records That Have Multiple Associated Records](postgres/find-records-that-have-multiple-associated-records.md)\n- [Find The Data Directory](postgres/find-the-data-directory.md)\n- [Find The Location Of Postgres Config Files](postgres/find-the-location-of-postgres-config-files.md)\n- [Fizzbuzz With Common Table Expressions](postgres/fizzbuzz-with-common-table-expressions.md)\n- [Force SSL When Making A psql Connection](postgres/force-ssl-when-making-a-psql-connection.md)\n- [Generate A UUID](postgres/generate-a-uuid.md)\n- [Generate Modern Primary Key Columns](postgres/generate-modern-primary-key-columns.md)\n- [Generate Random Alphanumeric Identifier](postgres/generate-random-alphanumeric-identifier.md)\n- [Generate Random UUIDs Without An Extension](postgres/generate-random-uuids-without-an-extension.md)\n- [Generate Series Of Numbers](postgres/generate-series-of-numbers.md)\n- [Generating UUIDs With pgcrypto](postgres/generating-uuids-with-pgcrypto.md)\n- [Get A Quick Approximate Count Of A Table](postgres/get-a-quick-approximate-count-of-a-table.md)\n- [Get Row Count For Most Recent Query](postgres/get-row-count-for-most-recent-query.md)\n- [Get The Size On Disk of An Index](postgres/get-the-size-on-disk-of-an-index.md)\n- [Get The Size Of A Database](postgres/get-the-size-of-a-database.md)\n- [Get The Size Of A Table](postgres/get-the-size-of-a-table.md)\n- [Get The Size Of An Index](postgres/get-the-size-of-an-index.md)\n- [Getting A Slice Of An Array](postgres/getting-a-slice-of-an-array.md)\n- [Group By The Result Of A Function Call](postgres/group-by-the-result-of-a-function-call.md)\n- [Idempotent Inserts](postgres/idempotent-inserts.md)\n- [Include All Queries In The Log File](postgres/include-all-queries-in-the-log-file.md)\n- [Include Columns In A Covering Index](postgres/include-columns-in-a-covering-index.md)\n- [Include Multiple Tables In A pg_dump](postgres/include-multiple-tables-in-a-pg-dump.md)\n- [Insert A Bunch Of Records With Generate Series](postgres/insert-a-bunch-of-records-with-generate-series.md)\n- [Insert Just The Defaults](postgres/insert-just-the-defaults.md)\n- [Inspect Progress Of Long-Running Create Index](postgres/inspect-progress-of-long-running-create-index.md)\n- [Install Postgres With uuid-ossp Using asdf](postgres/install-postgres-with-uuid-ossp-using-asdf.md)\n- [Integers In Postgres](postgres/integers-in-postgres.md)\n- [Intervals Of Time By Week](postgres/intervals-of-time-by-week.md)\n- [Is It Null Or Not Null?](postgres/is-it-null-or-not-null.md)\n- [Label Dollar-Quoted Strings With A Tag](postgres/label-dollar-quoted-strings-with-a-tag.md)\n- [Limit Execution Time Of Statements](postgres/limit-execution-time-of-statements.md)\n- [List All Columns Of A Specific Type](postgres/list-all-columns-of-a-specific-type.md)\n- [List All Rows In A Table](postgres/list-all-rows-in-a-table.md)\n- [List All The Databases](postgres/list-all-the-databases.md)\n- [List All Versions Of A Function](postgres/list-all-versions-of-a-function.md)\n- [List Available Schemas](postgres/list-available-schemas.md)\n- [List Connections To A Database](postgres/list-connections-to-a-database.md)\n- [List Databases Available For Connecting](postgres/list-databases-available-for-connecting.md)\n- [List Database Objects With Disk Usage](postgres/list-database-objects-with-disk-usage.md)\n- [List Database Users](postgres/list-database-users.md)\n- [List Various Kinds Of Objects](postgres/list-various-kinds-of-objects.md)\n- [Lower Is Faster Than ilike](postgres/lower-is-faster-than-ilike.md)\n- [Manage Major Versions With Brew And Direnv](postgres/manage-major-versions-with-brew-and-direnv.md)\n- [Max Identifier Length Is 63 Bytes](postgres/max-identifier-length-is-63-bytes.md)\n- [Open Heroku Database In Postico From Terminal](postgres/open-heroku-database-in-postico-from-terminal.md)\n- [Output Explain Query Plan In Different Formats](postgres/output-explain-query-plan-in-different-formats.md)\n- [pg Prefix Is Reserved For System Schemas](postgres/pg-prefix-is-reserved-for-system-schemas.md)\n- [Postgres Does Not Support Unsigned Integers](postgres/postgres-does-not-support-unsigned-integers.md)\n- [Prepare, Execute, And Deallocate Statements](postgres/prepare-execute-and-deallocate-statements.md)\n- [Pretty Print Data Sizes](postgres/pretty-print-data-sizes.md)\n- [Pretty Printing JSONB Rows](postgres/pretty-printing-jsonb-rows.md)\n- [Prevent A Query From Running Too Long](postgres/prevent-a-query-from-running-too-long.md)\n- [Print The Query Buffer In psql](postgres/print-the-query-buffer-in-psql.md)\n- [Put Unique Constraint On Generated Column](postgres/put-unique-constraint-on-generated-column.md)\n- [References Target Primary Key By Default](postgres/references-target-primary-key-by-default.md)\n- [Remove Not Null Constraint From A Column](postgres/remove-not-null-constraint-from-a-column.md)\n- [Renaming A Sequence](postgres/renaming-a-sequence.md)\n- [Renaming A Table](postgres/renaming-a-table.md)\n- [Restart A Sequence](postgres/restart-a-sequence.md)\n- [Restarting Sequences When Truncating Tables](postgres/restarting-sequences-when-truncating-tables.md)\n- [Salt And Hash A Password With pgcrypto](postgres/salt-and-hash-a-password-with-pgcrypto.md)\n- [Send A Command To psql](postgres/send-a-command-to-psql.md)\n- [Set Inclusion With hstore](postgres/set-inclusion-with-hstore.md)\n- [Set A Seed For The Random Number Generator](postgres/set-a-seed-for-the-random-number-generator.md)\n- [Set A Statement Timeout Threshold For A Session](postgres/set-a-statement-timeout-threshold-for-a-session.md)\n- [Set Up A Project-Local Cluster With Postgres.app](postgres/set-up-a-project-local-cluster-with-postgres-app.md)\n- [Sets With The Values Command](postgres/sets-with-the-values-command.md)\n- [Shorthand Absolute Value Operator](postgres/shorthand-absolute-value-operator.md)\n- [Show All Versions Of An Operator](postgres/show-all-versions-of-an-operator.md)\n- [Show Reconstructed Constraints For A Table](postgres/show-reconstructed-constraints-for-a-table.md)\n- [Show The Hidden Queries Behind Backslash Commands](postgres/show-the-hidden-queries-behind-backslash-commands.md)\n- [Sleeping](postgres/sleeping.md)\n- [Special Math Operators](postgres/special-math-operators.md)\n- [Storing Emails With citext](postgres/storing-emails-with-citext.md)\n- [String Contains Another String](postgres/string-contains-another-string.md)\n- [Survey Of User-Defined Ordering Of Records](postgres/survey-of-user-defined-ordering-of-records.md)\n- [Switch Non-Castable Column Type With Using Clause](postgres/switch-non-castable-column-type-with-using-clause.md)\n- [Switch The Running Postgres Server Version](postgres/switch-the-running-postgres-server-version.md)\n- [Table Names Are Treated As Lower-Case By Default](postgres/table-names-are-treated-as-lower-case-by-default.md)\n- [Temporarily Disable Triggers](postgres/temporarily-disable-triggers.md)\n- [Temporary Tables](postgres/temporary-tables.md)\n- [Terminating A Connection](postgres/terminating-a-connection.md)\n- [The nullif Function](postgres/the-nullif-function.md)\n- [Timestamp Functions](postgres/timestamp-functions.md)\n- [Toggling The Pager In PSQL](postgres/toggling-the-pager-in-psql.md)\n- [Track psql History Separately Per Database](postgres/track-psql-history-separately-per-database.md)\n- [Trim Leading And Trailing Space From String](postgres/trim-leading-and-trailing-space-from-string.md)\n- [Truncate All Rows](postgres/truncate-all-rows.md)\n- [Truncate Tables With Dependents](postgres/truncate-tables-with-dependents.md)\n- [Turning Timing On](postgres/turn-timing-on.md)\n- [Two Ways To Compute Factorial](postgres/two-ways-to-compute-factorial.md)\n- [Two Ways To Escape A Quote In A String](postgres/two-ways-to-escape-a-quote-in-a-string.md)\n- [Types By Category](postgres/types-by-category.md)\n- [Unable To Infer Data Type In Production](postgres/unable-to-infer-data-type-in-production.md)\n- [Union All Rows Including Duplicates](postgres/union-all-rows-including-duplicates.md)\n- [Use A psqlrc File For Common Settings](postgres/use-a-psqlrc-file-for-common-settings.md)\n- [Use A Trigger To Mirror Inserts To Another Table](postgres/use-a-trigger-to-mirror-inserts-to-another-table.md)\n- [Use Argument Indexes](postgres/use-argument-indexes.md)\n- [Use Not Valid To Immediately Enforce A Constraint](postgres/use-not-valid-to-immediately-enforce-a-constraint.md)\n- [Use Rename To Hot Swap Two Tables](postgres/use-rename-to-hot-swap-two-tables.md)\n- [Use Variables In An Anonymous Function](postgres/use-variables-in-an-anonymous-function.md)\n- [Using Expressions In Indexes](postgres/using-expressions-in-indexes.md)\n- [Using Intervals To Offset Time](postgres/using-intervals-to-offset-time.md)\n- [Who Is The Current User](postgres/who-is-the-current-user.md)\n- [Word Count for a Column](postgres/word-count-for-a-column.md)\n- [Write A Query Result To File](postgres/write-a-query-result-to-file.md)\n\n### Prisma\n\n- [Apply Separate Formatting With A Blank Line](prisma/apply-separate-formatting-with-a-blank-line.md)\n- [Batch Insert Records With createMany](prisma/batch-insert-records-with-create-many.md)\n- [Check If Database And Schema Are Not In Sync](prisma/check-if-database-and-schema-are-not-in-sync.md)\n- [Configure Client To Log SQL Queries](prisma/configure-client-to-log-sql-queries.md)\n- [Execute A Raw SQL Query](prisma/execute-a-raw-sql-query.md)\n- [Grab A Limited Set Of Records](prisma/grab-a-limited-set-of-records.md)\n- [Open Connections To Multiple Databases](prisma/open-connections-to-multiple-databases.md)\n- [Override Table Name For Prisma Model](prisma/override-table-name-for-prisma-model.md)\n- [Specify Alternate Location For Prisma Schema](prisma/specify-alternate-location-for-prisma-schema.md)\n\n### Python\n\n- [Access Instance Variables](python/access-instance-variables.md)\n- [Access Most Recent Return Value In REPL](python/access-most-recent-return-value-in-repl.md)\n- [Break Debugger On First Line Of Program](python/break-debugger-on-first-line-of-program.md)\n- [Check If Package Is Installed With Pip](python/check-if-package-is-installed-with-pip.md)\n- [Control Passing Of Time In Tests](python/control-passing-of-time-in-tests.md)\n- [Create A Dummy DataFrame In Pandas](python/create-a-dummy-dataframe-in-pandas.md)\n- [Create A Range Of Descending Values](python/create-a-range-of-descending-values.md)\n- [Dunder Methods](python/dunder-methods.md)\n- [Easy Key-Value Aggregates With defaultdict](python/easy-key-value-aggregates-with-defaultdict.md)\n- [Install With PIP For Specific Interpreter](python/install-with-pip-for-specific-interpreter.md)\n- [Iterate First N Items From Enumerable](python/iterate-first-n-items-from-enumerable.md)\n- [Iterate Over A Dictionary](python/iterate-over-a-dictionary.md)\n- [Keep A Tally With collections.Counter](python/keep-a-tally-with-collections-counter.md)\n- [Load A File Into The Python REPL](python/load-a-file-into-the-python-repl.md)\n- [Look Inside Pytest tmp_path](python/look-inside-pytest-tmp-path.md)\n- [Override The Boolean Context Of A Class](python/override-the-boolean-context-of-a-class.md)\n- [Parse Relative Time To datetime Object](python/parse-relative-time-to-datetime-object.md)\n- [Store And Access Immutable Data In A Tuple](python/store-and-access-immutable-data-in-a-tuple.md)\n- [Test A Function With Pytest](python/test-a-function-with-pytest.md)\n- [Use pipx To Install End User Apps](python/use-pipx-to-install-end-user-apps.md)\n- [Use Verbose Flag To Get More Diff](python/use-verbose-flag-to-get-more-diff.md)\n\n### Rails\n\n- [Access Secrets In A Rails 5.2 App](rails/access-secrets-in-a-rails-5-2-app.md)\n- [ActiveRecord Query For This Or That](rails/active-record-query-for-this-or-that.md)\n- [Add A Check Constraint To A Table](rails/add-a-check-constraint-to-a-table.md)\n- [Add A Database Index If It Does Not Already Exist](rails/add-a-database-index-if-it-does-not-already-exist.md)\n- [Add A Foreign Key Reference To A Table](rails/add-a-foreign-key-reference-to-a-table.md)\n- [Add A Generated Column To A PostgreSQL Table](rails/add-a-generated-column-to-a-postgresql-table.md)\n- [Add A Reference Column With An Index](rails/add-a-reference-column-with-an-index.md)\n- [Add ActiveRecord Error Not Tied To Any Attribute](rails/add-activerecord-error-not-tied-to-any-attribute.md)\n- [Add Color To The IRB Console Prompt](rails/add-color-to-the-irb-console-prompt.md)\n- [Add React With Webpacker To A New Rails App](rails/add-react-with-webpacker-to-a-new-rails-app.md)\n- [Add timestamptz Columns With The Migration DSL](rails/add-timestamptz-columns-with-the-migration-dsl.md)\n- [Adjust The Production Log Level](rails/adjust-the-production-log-level.md)\n- [Advance The Date](rails/advance-the-date.md)\n- [Allow Associations To Be Optional](rails/allow-associations-to-be-optional.md)\n- [Allow List Params Anywhere With Strong Params](rails/allow-list-params-anywhere-with-strong-params.md)\n- [All or Nothing Database Transactions](rails/all-or-nothing-database-transactions.md)\n- [Alphabetize Schema Columns To Keep Them Consistent](rails/alphabetize-schema-columns-to-keep-them-consistent.md)\n- [Alter The Rails Setup Script](rails/alter-the-rails-setup-script.md)\n- [Apply Basic HTML Formatting To Block Of Text](rails/apply-basic-html-formatting-to-block-of-text.md)\n- [Assert Two Arrays Have The Same Items With RSpec](rails/assert-two-arrays-have-the-same-items-with-rspec.md)\n- [Attach A File With Capybara](rails/attach-a-file-with-capybara.md)\n- [Attribute Getter without the Recursion](rails/attribute-getter-without-the-recursion.md)\n- [Attribute Was](rails/attribute-was.md)\n- [Autosave False On ActiveRecord Associations](rails/autosave-false-on-activerecord-associations.md)\n- [Bind Parameters To ActiveRecord SQL Query](rails/bind-parameters-to-activerecord-sql-query.md)\n- [Build A Hash Of Model Attributes](rails/build-a-hash-of-model-attributes.md)\n- [Capture Development Emails With Mailhog](rails/capture-development-emails-with-mailhog.md)\n- [Capybara Page Status Code](rails/capybara-page-status-code.md)\n- [Cast Common Boolean-Like Values To Booleans](rails/cast-common-boolean-like-values-to-booleans.md)\n- [Change The Nullability Of A Column](rails/change-the-nullability-of-a-column.md)\n- [Change The Time Zone Offset Of A DateTime Object](rails/change-the-time-zone-offset-of-a-datetime-object.md)\n- [Check How Database Is Configured](rails/check-how-database-is-configured.md)\n- [Check If ActiveRecord Update Fails](rails/check-if-activerecord-update-fails.md)\n- [Check If Any Records Have A Null Value](rails/check-if-any-records-have-a-null-value.md)\n- [Check Specific Attributes On ActiveRecord Array](rails/check-specific-attributes-on-activerecord-array.md)\n- [Check The Current Named Log Level](rails/check-the-current-named-log-level.md)\n- [Clean Up Memory Hungry Rails Console Processes](rails/clean-up-memory-hungry-rails-console-processes.md)\n- [Code Statistics For An Application](rails/code-statistics-for-an-application.md)\n- [Columns With Default Values Are Nil On Create](rails/columns-with-default-values-are-nil-on-create.md)\n- [Comparing DateTimes Down To Second Precision](rails/comparing-datetimes-down-to-second-precision.md)\n- [Conditional Class Selectors in Haml](rails/conditional-class-selectors-in-haml.md)\n- [Convert A Symbol To A Constant](rails/convert-a-symbol-to-a-constant.md)\n- [Convert JSON Field To Hash With Indifferent Access](rails/convert-json-field-to-hash-with-indifferent-access.md)\n- [Count The Number Of Records By Attribute](rails/count-the-number-of-records-by-attribute.md)\n- [Create A Custom Named References Column](rails/create-a-custom-named-references-column.md)\n- [Create A Join Table With The Migration DSL](rails/create-a-join-table-with-the-migration-dsl.md)\n- [Create Table With bigint Id As Primary Key](rails/create-table-with-bigint-id-as-primary-key.md)\n- [Creating Records of Has_One Associations](rails/creating-records-of-has-one-associations.md)\n- [Custom Validation Message](rails/custom-validation-message.md)\n- [Customize Paths And Helpers For Devise Routes](rails/customize-paths-and-helpers-for-devise-routes.md)\n- [Customize Template For New Schema Migration](rails/customize-template-for-new-schema-migration.md)\n- [Customize The Path Of A Resource Route](rails/customize-the-path-of-a-resource-route.md)\n- [Define The Root Path For The App](rails/define-the-root-path-for-the-app.md)\n- [Delete Paranoid Records](rails/delete-paranoid-records.md)\n- [Demodulize A Class Name](rails/demodulize-a-class-name.md)\n- [Determine The Configured Primary Key Type](rails/determine-the-configured-primary-key-type.md)\n- [Different Ways To Add A Foreign Key Reference](rails/different-ways-to-add-a-foreign-key-reference.md)\n- [Disambiguate Where In A Joined Relation](rails/disambiguate-where-in-a-joined-relation.md)\n- [Empty find_by Returns First Record](rails/empty-find-by-returns-first-record.md)\n- [Enforce Locals Passed To A Partial](rails/enforce-locals-passed-to-a-partial.md)\n- [Ensure A Rake Task Cannot Write Data](rails/ensure-a-rake-task-cannot-write-data.md)\n- [Ensure Migrations Use The Latest Schema](rails/ensure-migrations-use-the-latest-schema.md)\n- [Ensure Record Saved With after_commit Callback](rails/ensure-record-saved-with-after-commit-callback.md)\n- [Filter ActiveModel Validation Errors](rails/filter-active-model-validation-errors.md)\n- [Filter ActiveStorage Blobs To Only Images](rails/filter-active-storage-blobs-to-only-images.md)\n- [Find Or Create A Record With FactoryBot](rails/find-or-create-a-record-with-factory-bot.md)\n- [Find Records With Multiple Associated Records](rails/find-records-with-multiple-associated-records.md)\n- [Force All Users To Sign Out](rails/force-all-users-to-sign-out.md)\n- [Format DateTime With Builtin Formats](rails/format-datetime-with-builtin-formats.md)\n- [Format Specific html.erb Template Files](rails/format-specific-html-erb-template-files.md)\n- [Generate A Model](rails/generate-a-model.md)\n- [Generate A Rails App From The Main Branch](rails/generate-a-rails-app-from-the-main-branch.md)\n- [Generating And Executing SQL](rails/generating-and-executing-sql.md)\n- [Get A Quick Approximate Count Of A Large Table](rails/get-a-quick-approximate-count-of-a-large-table.md)\n- [Get ActiveRecord Attribute Directly From Database](rails/get-active-record-attribute-directly-from-database.md)\n- [Get An Array Of Values From The Database](rails/get-an-array-of-values-from-the-database.md)\n- [Get An Empty ActiveRecord Relation](rails/get-an-empty-activerecord-relation.md)\n- [Get Formatted UTC Offset Value](rails/get-formatted-utc-offset-value.md)\n- [Get Help With A Rails App Update](rails/get-help-with-a-rails-app-update.md)\n- [Get The Column Names For A Model](rails/get-the-column-names-for-a-model.md)\n- [Get The Current Time](rails/get-the-current-time.md)\n- [Grab A Random Record From The Database](rails/grab-a-random-record-from-the-database.md)\n- [Handle Named Arguments In A Rake Task](rails/handle-named-arguments-in-a-rake-task.md)\n- [Hash Slicing](rails/hash-slicing.md)\n- [Ignore Poltergeist JavaScript Errors](rails/ignore-poltergeist-javascript-errors.md)\n- [Include Devise Helpers In Your Controller Tests](rails/include-devise-helpers-in-your-controller-tests.md)\n- [Inspect Configuration Of Database Connection](rails/inspect-configuration-of-database-connection.md)\n- [Inspect Previous Changes To ActiveRecord Object](rails/inspect-previous-changes-to-activerecord-object.md)\n- [Link To The Current Page With Query Params](rails/link-to-the-current-page-with-query-params.md)\n- [List All Installable Rails Versions](rails/list-all-installable-rails-versions.md)\n- [List The Enqueued Jobs](rails/list-the-enqueued-jobs.md)\n- [Load A File When Starting Rails Console](rails/load-a-file-when-starting-rails-console.md)\n- [Load Records In Batches With find_each](rails/load-records-in-batches-with-find-each.md)\n- [Log SQL Queries Executed By ActiveRecord](rails/log-sql-queries-executed-by-activerecord.md)\n- [Look Up Time Zone Info For Identifier](rails/look-up-time-zone-info-for-identifier.md)\n- [Mark A Migration As Irreversible](rails/mark-a-migration-as-irreversible.md)\n- [Make A String Attribute Easy To Inquire About](rails/make-a-string-attribute-easy-to-inquire-about.md)\n- [Make ActionMailer Synchronous In Test](rails/make-action-mailer-synchronous-in-test.md)\n- [Make Remove Column Migration Reversible](rails/make-remove-column-migration-reversible.md)\n- [Manage Timestamps With Upsert](rails/manage-timestamps-with-upsert.md)\n- [Manually Run A Migration From Rails Console](rails/manually-run-a-migration-from-rails-console.md)\n- [Mark For Destruction](rails/mark-for-destruction.md)\n- [Mask An ActiveRecord Attribute](rails/mask-an-activerecord-attribute.md)\n- [Merge A Scope Into An ActiveRecord Query](rails/merge-a-scope-into-an-activerecord-query.md)\n- [Migrating Up Down Up](rails/migrating-up-down-up.md)\n- [Mock Rails Environment With An Inquiry Instance](rails/mock-rails-environment-with-an-inquiry-instance.md)\n- [Order Matters For `rescue_from` Blocks](rails/order-matters-for-rescue-from-blocks.md)\n- [Override Text Displayed By Form Label](rails/override-text-displayed-by-form-label.md)\n- [Parameterize A String With Underscores](rails/parameterize-a-string-with-underscores.md)\n- [Params Includes Submission Button Info](rails/params-includes-submission-button-info.md)\n- [Params Is A Hash With Indifferent Access](rails/params-is-a-hash-with-indifferent-access.md)\n- [Parse Query Params From A URL](rails/parse-query-params-from-a-url.md)\n- [Parse Request Params In Rack::Attack Block](rails/parse-request-params-in-rack-attack-block.md)\n- [Perform SQL Explain With ActiveRecord](rails/perform-sql-explain-with-activerecord.md)\n- [Polymorphic Path Helpers](rails/polymorphic-path-helpers.md)\n- [Prefer select_all Over execute For Read Queries](rails/prefer-select-all-over-execute-for-read-queries.md)\n- [Pretend Generations](rails/pretend-generations.md)\n- [Prevent Mailer Previews From Cluttering Database](rails/prevent-mailer-previews-from-cluttering-database.md)\n- [Prevent Writes With A Sandboxed Rails Console](rails/prevent-writes-with-a-sandboxed-rails-console.md)\n- [Provide Fake Form Helper To Controllers](rails/provide-fake-form-helper-to-controllers.md)\n- [Query A Single Value From The Database](rails/query-a-single-value-from-the-database.md)\n- [Read In Environment-Specific Config Values](rails/read-in-environment-specific-config-values.md)\n- [Read-Only Models](rails/read-only-models.md)\n- [Rebuild Tailwind Bundle For Dev Server](rails/rebuild-tailwind-bundle-for-dev-server.md)\n- [Remove A Database Column From A Table](rails/remove-a-database-column-from-a-table.md)\n- [Remove The Default Value On A Column](rails/remove-the-default-value-on-a-column.md)\n- [Render An Alternative ActionMailer Template](rails/render-an-alternative-action-mailer-template.md)\n- [Render The Response Body In Controller Specs](rails/render-the-response-body-in-controller-specs.md)\n- [Replace An Index With A Unique Index](rails/replace-an-index-with-a-unique-index.md)\n- [Rescue From](rails/rescue-from.md)\n- [Rescue From With A Separate Method](rails/rescue-from-with-a-separate-method.md)\n- [Respond With JSON Regardless of Content Type](rails/respond-with-json-regardless-of-content-type.md)\n- [Restart Puma Server By Touching Restart File](rails/restart-puma-server-by-touching-restart-file.md)\n- [Retrieve An Object If It Exists](rails/retrieve-an-object-if-it-exists.md)\n- [Rollback A Couple Migrations](rails/rollback-a-couple-migrations.md)\n- [Rollback A Specific Migration Out Of Order](rails/rollback-a-specific-migration-out-of-order.md)\n- [Rounding Numbers With Precision](rails/rounding-numbers-with-precision.md)\n- [Run A Rake Task Programmatically](rails/run-a-rake-task-programmatically.md)\n- [Run Commands With Specific Rails Version](rails/run-commands-with-specific-rails-version.md)\n- [Run Dev Processes With Overmind Instead Of Foreman](rails/run-dev-processes-with-overmind-instead-of-foreman.md)\n- [Run Rails Console With Remote Dokku App](rails/run-rails-console-with-remote-dokku-app.md)\n- [Run Some Code Whenever Rails Console Starts](rails/run-some-code-whenever-rails-console-starts.md)\n- [Scaffold Auth Functionality With Rails 8 Generator](rails/scaffold-auth-functionality-with-rails-8-generator.md)\n- [Schedule Sidekiq Jobs Out Into The Future](rails/schedule-sidekiq-jobs-out-into-the-future.md)\n- [Scope Records To A Lower Or Upper Bound](rails/scope-records-to-a-lower-or-upper-bound.md)\n- [Secure Passwords With Rails And Bcrypt](rails/secure-passwords-with-rails-and-bcrypt.md)\n- [Select A Select By Selector](rails/select-a-select-by-selector.md)\n- [Select A Specific Rails Version To Install](rails/select-a-specific-rails-version-to-install.md)\n- [Select Value For SQL Counts](rails/select-value-for-sql-counts.md)\n- [Serialize With fast_jsonapi In A Rails App](rails/serialize-with-fast-jsonapi-in-a-rails-app.md)\n- [Set A Timestamp Field To The Current Time](rails/set-a-timestamp-field-to-the-current-time.md)\n- [Set DateTime To Include Time Zone In Migrations](rails/set-datetime-to-include-time-zone-in-migrations.md)\n- [Set Default As SQL Function In Migration](rails/set-default-as-sql-function-in-migration.md)\n- [Set default_url_options For Entire Application](rails/set-default-url-options-for-entire-application.md)\n- [Set Meta Tags In ERB Views](rails/set-meta-tags-in-erb-views.md)\n- [Set Schema Search Path](rails/set-schema-search-path.md)\n- [Set Statement Timeout For All Postgres Connections](rails/set-statement-timeout-for-all-postgres-connections.md)\n- [Set The Default Development Port](rails/set-the-default-development-port.md)\n- [Show Pending Migrations](rails/show-pending-migrations.md)\n- [Show Rails Models With Pry](rails/show-rails-models-with-pry.md)\n- [Show Rails Routes With Pry](rails/show-rails-routes-with-pry.md)\n- [Skip Validations When Creating A Record](rails/skip-validations-when-creating-a-record.md)\n- [Specify New Attributes For #find_or_create_by](rails/specify-new-attributes-for-find-or-create-by.md)\n- [Temporarily Disable strong_params](rails/temporarily-disable-strong-params.md)\n- [Temporarily Turn Off Pending Migrations Error](rails/temporarily-turn-off-pending-migrations-error.md)\n- [Test For A Subset Of Attributes On A Model](rails/test-for-a-subset-of-attributes-on-a-model.md)\n- [Test If An Instance Variable Was Assigned](rails/test-if-an-instance-variable-was-assigned.md)\n- [Test If deliver_later Is Called For A Mailer](rails/test-if-deliver-later-is-called-for-a-mailer.md)\n- [Test Out URL And Path Helpers In The Console](rails/test-out-url-and-path-helpers-in-the-console.md)\n- [Truncate Almost All Tables](rails/truncate-almost-all-tables.md)\n- [Update Column Versus Update Attribute](rails/update-column-versus-update-attribute.md)\n- [Upgrading Your Manifest For Sprocket's 4](rails/upgrading-your-manifest-for-sprockets-4.md)\n- [Use IRB And Ruby Flags With Rails Console](rails/use-irb-and-ruby-flags-with-rails-console.md)\n- [Use .ruby Extension For Template File](rails/use-ruby-extension-for-template-file.md)\n- [Useful ActiveSupport Constants For Durations](rails/useful-active-support-constants-for-durations.md)\n- [Validate Column Data With Check Constraints](rails/validate-column-data-with-check-constraints.md)\n- [Verify And Read A Signed Cookie Value](rails/verify-and-read-a-signed-cookie-value.md)\n- [Where Am I In The Partial Iteration?](rails/where-am-i-in-the-partial-iteration.md)\n- [Why Redirect And Return In Controllers](rails/why-redirect-and-return-in-controllers.md)\n- [Wipe Out All Precompiled Assets](rails/wipe-out-all-precompiled-assets.md)\n- [Write Reversible Migration To Set Default](rails/write-reversible-migration-to-set-default.md)\n- [Write Safer Where Clauses With Placeholders](rails/write-safer-where-clauses-with-placeholders.md)\n\n### React\n\n- [A Component Is Just A Bag Of Data](react/a-component-is-just-a-bag-of-data.md)\n- [Access The Latest Lifecycle Methods In An Old App](react/access-the-latest-lifecycle-methods-in-an-old-app.md)\n- [Accessing Env Vars In create-react-app](react/accessing-env-vars-in-create-react-app.md)\n- [Accessing Location Within @reach/router](react/accessing-location-within-reach-router.md)\n- [Allow md As An Extension With gatsby-mdx](react/allow-md-as-an-extension-with-gatsby-mdx.md)\n- [Alter The Display Name Of A Component](react/alter-the-display-name-of-a-component.md)\n- [Building A React App In The Browser](react/building-a-react-app-in-the-browser.md)\n- [Check The Type Of A Child Component](react/check-the-type-of-a-child-component.md)\n- [Conditionally Including Event Handler Functions](react/conditionally-including-event-handler-functions.md)\n- [Create A Snowpack-Bundled React App](react/create-a-snowpack-bundled-react-app.md)\n- [Create Dynamically Named Custom React Components](react/create-dynamically-named-custom-react-components.md)\n- [create-react-app Comes With Lodash](react/create-react-app-comes-with-lodash.md)\n- [create-react-app Has A Default Test Setup File](react/create-react-app-has-a-default-test-setup-file.md)\n- [CSS !important Is Not Supported By Inline Styles](react/css-important-is-not-supported-by-inline-styles.md)\n- [Debug Jest Tests In create-react-app](react/debug-jest-tests-in-create-react-app.md)\n- [Defining State In A Simple Class Component](react/defining-state-in-a-simple-class-component.md)\n- [Destructure Variables As Props To A Component](react/destructure-variables-as-props-to-a-component.md)\n- [Details Tags Are A Controllable Component](react/details-tags-are-a-controllable-component.md)\n- [Dispatch Anywhere With Redux](react/dispatch-anywhere-with-redux.md)\n- [Dynamically Add Props To A Child Component](react/dynamically-add-props-to-a-child-component.md)\n- [Dynamically Create HTML Elements](react/dynamically-create-html-elements.md)\n- [Enforce Specific Values With PropTypes](react/enforce-specific-values-with-proptypes.md)\n- [Focus An Input With useRef Hook](react/focus-an-input-with-useref-hook.md)\n- [Force A Component To Only Have One Child](react/force-a-component-to-only-have-one-child.md)\n- [Forcing A Child Remount With The Key Prop](react/forcing-a-child-remount-with-the-key-prop.md)\n- [Formik Connected Components](react/formik-connected-components.md)\n- [Formik's Validation Schema As A Function](react/formiks-validation-schema-as-a-function.md)\n- [Inactive And Active Component Styles With Radium](react/inactive-and-active-component-styles-with-radium.md)\n- [Inline Style Attributes Should Be Camel Cased](react/inline-style-attributes-should-be-camel-cased.md)\n- [Manage State In A Functional Component](react/manage-state-in-a-functional-component.md)\n- [Mapping Over One Or Many Children](react/mapping-over-one-or-many-children.md)\n- [Mock A Function That A Component Imports](react/mock-a-function-that-a-component-imports.md)\n- [Navigate With State Via @reach/router](react/navigate-with-state-via-reach-router.md)\n- [Pairing A Callback With A useState Hook](react/pairing-a-callback-with-a-usestate-hook.md)\n- [Pass A Function To A useState Updater](react/pass-a-function-to-a-usestate-updater.md)\n- [Passing Props Down To React-Router Route](react/passing-props-down-to-react-router-route.md)\n- [Prevent reach/router Redirect Error Screen In Dev](react/prevent-reach-router-redirect-error-screen-in-dev.md)\n- [Proxy To An API Server In Development With CRA](react/proxy-to-an-api-server-in-development-with-cra.md)\n- [Quickly Search For A Component With React DevTools](react/quickly-search-for-a-component-with-react-devtools.md)\n- [@reach/router Renders To A Div](react/reach-router-renders-to-a-div.md)\n- [Read Only Input Elements](react/read-only-input-elements.md)\n- [Rendering Multiple Nodes With Fragments](react/rendering-multiple-nodes-with-fragments.md)\n- [Set The Type For A useState Hook](react/set-the-type-for-a-usestate-hook.md)\n- [Specifying Dependencies Of A useEffect Hook](react/specifying-dependencies-of-a-useeffect-hook.md)\n- [Spelunking Through Components With Enzyme's Dive](react/spelunking-through-components-with-enzymes-dive.md)\n- [Sync Your react-router State With Redux](react/sync-your-react-router-state-with-redux.md)\n- [Test Files In create-react-app](react/test-files-in-create-react-app.md)\n- [Test That Element Does Not Render In The Component](react/test-that-element-does-not-render-in-the-component.md)\n- [Trigger Effect Only When The Component Mounts](react/trigger-effect-only-when-the-component-mounts.md)\n- [Update Formik Initial Values When Props Change](react/update-formik-initial-values-when-props-change.md)\n- [Upgrading To The Latest React In CodeSandbox](react/upgrading-to-the-latest-react-in-codesandbox.md)\n- [Use A Ref To Autofocus An Input](react/use-a-ref-to-autofocus-an-input.md)\n- [Use React 16 With Gatsby](react/use-react-16-with-gatsby.md)\n- [Use withRouter To Pass Down React-Router History](react/use-withrouter-to-pass-down-react-router-history.md)\n- [Visually Select A React Element For Inspection](react/visually-select-a-react-element-for-inspection.md)\n- [Who Is Your Favorite Child?](react/who-is-your-favorite-child.md)\n- [Wrap The Root Of A Gatsby App In A Component](react/wrap-the-root-of-a-gatsby-app-in-a-component.md)\n\n### React Native\n\n- [Avoid The Notch With SafeAreaView](react_native/avoid-the-notch-with-safeareaview.md)\n\n### React Testing Library\n\n- [Check That A Component Renders As Null](react-testing-library/check-that-a-component-renders-as-null.md)\n- [findBy\\* Queries Have Async Built In](react-testing-library/find-by-queries-have-async-built-in.md)\n- [Pretty Print Some DOM To Debug A Test](react-testing-library/pretty-print-some-dom-to-debug-a-test.md)\n- [Test A Component That Uses React Portals](react-testing-library/test-a-component-that-uses-react-portals.md)\n\n### ReasonML\n\n- [Break Out Of A While Loop](reason/break-out-of-a-while-loop.md)\n- [Compile Reason To Native With Dune](reason/compile-reason-to-native-with-dune.md)\n- [Compile Reason With An OCaml Package Using Dune](reason/compile-reason-with-an-ocaml-package-using-dune.md)\n- [Create A Map Of Strings](reason/create-a-map-of-strings.md)\n- [Create A Stream From An Array](reason/create-a-stream-from-an-array.md)\n- [Creating A 2D Array](reason/creating-a-2d-array.md)\n- [Data Structures With Self-Referential Types](reason/data-structures-with-self-referential-types.md)\n- [Defining Variants With Constructor Arguments](reason/defining-variants-with-constructor-arguments.md)\n- [Dynamically Create A Printf String Format](reason/dynamically-create-a-printf-string-format.md)\n- [Exhaustive Pattern Matching Of List Variants](reason/exhaustive-pattern-matching-of-list-variants.md)\n- [Format The Current File Within Vim](reason/format-the-current-file-within-vim.md)\n- [Generate A Native ReasonML Project With Pesy](reason/generate-a-native-reasonml-project-with-pesy.md)\n- [Generate Starter Reason Projects](reason/generate-starter-reason-projects.md)\n- [Helping The Compiler Help Us With Variants](reason/helping-the-compiler-help-us-with-variants.md)\n- [Inline Component Styles With Reason React](reason/inline-component-styles-with-reason-react.md)\n- [Is This A Directory Or A File?](reason/is-this-a-directory-or-a-file.md)\n- [Making Things Mutable](reason/making-things-mutable.md)\n- [Modifying A String With blit_string](reason/modifying-a-string-with-blit-string.md)\n- [Multi-Argument Functions As Syntactic Sugar](reason/multi-argument-functions-as-syntactic-sugar.md)\n- [Pattern Match On Exceptions](reason/pattern-match-on-exceptions.md)\n- [Quickly Bootstrap A React App Using Reason](reason/quickly-bootstrap-a-react-app-using-reason.md)\n- [Seeding And Generating Random Integers](reason/seeding-and-generating-random-integers.md)\n- [Stream A File Line By Line](reason/stream-a-file-line-by-line.md)\n- [String Interpolation With Integers And Sprintf](reason/string-interpolation-with-integers-and-sprintf.md)\n- [String Interpolation With Quoted Strings](reason/string-interpolation-with-quoted-strings.md)\n- [Trying Out ReasonML In CodeSandbox](reason/trying-out-reasonml-in-codesandbox.md)\n- [Two Ways To Find An Item In A List](reason/two-ways-to-find-an-item-in-a-list.md)\n- [Using Optional Labeled Function Arguments](reason/using-optional-labeled-function-arguments.md)\n- [Wrapping A Component For Use In JavaScript](reason/wrapping-a-component-for-use-in-javascript.md)\n\n### Remix\n\n- [Get Query Params From The Request URL](remix/get-query-params-from-the-request-url.md)\n- [Markdown And MDX Files Are Rendered To Routes](remix/markdown-and-mdx-files-are-rendered-to-routes.md)\n- [Relative And Absolute Paths In Links](remix/relative-and-absolute-paths-in-links.md)\n- [Run The Development Server From Another Port](remix/run-the-development-server-from-another-port.md)\n- [Set The Title Of A Page](remix/set-the-title-of-a-page.md)\n\n### RSpec\n\n- [Avoid Accidentally Disabling Pry](rspec/avoid-accidentally-disabling-pry.md)\n- [Check Specific Arguments To Received Method](rspec/check-specific-arguments-to-received-method.md)\n- [Configure Tests To Run In Random Order](rspec/configure-tests-to-run-in-random-order.md)\n- [Find Minimal Set Of Tests Causing A Flicker](rspec/find-minimal-set-of-tests-causing-a-flicker.md)\n- [Format Test Results As A JSON File](rspec/format-test-results-as-a-json-file.md)\n- [Run Tests With Documentation Formatting](rspec/run-tests-with-documentation-formatting.md)\n- [Use Specific Cache Store In A Single Test](rspec/use-specific-cache-store-in-a-single-test.md)\n\n### Ruby\n\n- [A Basic Case Statement](ruby/a-basic-case-statement.md)\n- [A Shorthand For Rerunning Failed Tests With RSpec](ruby/a-shorthand-for-rerunning-failed-tests-with-rspec.md)\n- [Add Comments To Regex With Free-Spacing](ruby/add-comments-to-regex-with-free-spacing.md)\n- [Add Linux As A Bundler Platform](ruby/add-linux-as-a-bundler-platform.md)\n- [Add Progress Reporting To Long-Running Script](ruby/add-progress-reporting-to-long-running-script.md)\n- [Are They All True?](ruby/are-they-all-true.md)\n- [Assert About An Object's Attributes With RSpec](ruby/assert-about-an-objects-attributes-with-rspec.md)\n- [Assoc For Hashes](ruby/assoc-for-hashes.md)\n- [Audit Your Ruby Project For Any CVEs](ruby/audit-your-ruby-project-for-any-cves.md)\n- [Avoid Double Negation With Minitest Refute](ruby/avoid-double-negation-with-minitest-refute.md)\n- [Block Comments](ruby/block-comments.md)\n- [Block Syntaxes Have Different Precedence](ruby/block-syntaxes-have-different-precedence.md)\n- [Build HTTP And HTTPS URLs](ruby/build-http-and-https-urls.md)\n- [Chaining Multiple RSpec Change Matchers](ruby/chaining-multiple-rspec-change-matchers.md)\n- [Check For Any Overlaps In List Of Ranges](ruby/check-for-any-overlaps-in-list-of-ranges.md)\n- [Check If A URL Resolves To 200](ruby/check-if-a-url-resolves-to-200.md)\n- [Check If An Object Includes A Module](ruby/check-if-an-object-includes-a-module.md)\n- [Check Return Status Of Running A Shell Command](ruby/check-return-status-of-running-a-shell-command.md)\n- [Clamp To An Endless Range](ruby/clamp-to-an-endless-range.md)\n- [Click On Text With Capybara](ruby/click-on-text-with-capybara.md)\n- [Colorful Output With MiniTest](ruby/colorful-output-with-minitest.md)\n- [Comparing Class Hierarchy Relationships](ruby/comparing-class-hierarchy-relationships.md)\n- [Comparing Arrays In RSpec](ruby/comparing-arrays-in-rspec.md)\n- [Construct A Constant From A String](ruby/construct-a-constant-from-a-string.md)\n- [Convert A Unix Epoch Timestamp To A Time Object](ruby/convert-a-unix-epoch-timestamp-to-a-time-object.md)\n- [Create an Array of Stringed Numbers](ruby/create-an-array-of-stringed-numbers.md)\n- [Create a CSV::Table Object](ruby/create-a-csv-table-object.md)\n- [Create A Hash From An Array Of Arrays](ruby/create-a-hash-from-an-array-of-arrays.md)\n- [Create Listing Of All Middleman Pages](ruby/create-listing-of-all-middleman-pages.md)\n- [Create Mock Class That Can Be Overridden](ruby/create-mock-class-that-can-be-overridden.md)\n- [Create A Module Of Utility Functions](ruby/create-a-module-of-utility-functions.md)\n- [Create Named Structs With Struct.new](ruby/create-named-structs-with-struct-new.md)\n- [Create Thumbnail Image For A PDF](ruby/create-thumbnail-image-for-a-pdf.md)\n- [Decompose Unicode Character With Diacritic Mark](ruby/decompose-unicode-character-with-diacritic-mark.md)\n- [Defaulting To Frozen String Literals](ruby/defaulting-to-frozen-string-literals.md)\n- [Define A Custom RSpec Matcher](ruby/define-a-custom-rspec-matcher.md)\n- [Define A Method On A Struct](ruby/define-a-method-on-a-struct.md)\n- [Define Multiline Strings With Heredocs](ruby/define-multiline-strings-with-heredocs.md)\n- [Destructure The First Item From An Array](ruby/destructure-the-first-item-from-an-array.md)\n- [Destructuring Arrays In Blocks](ruby/destructuring-arrays-in-blocks.md)\n- [Disable Interpolation For A Heredoc String](ruby/disable-interpolation-for-a-heredoc-string.md)\n- [Disassemble Some Codes](ruby/disassemble-some-codes.md)\n- [Double Splat To Merge Hashes](ruby/double-splat-to-merge-hashes.md)\n- [Edit Previous Parts Of The Pry Buffer History](ruby/edit-previous-parts-of-the-pry-buffer-history.md)\n- [Editing Code In Pry](ruby/editing-code-in-pry.md)\n- [Encode A String As URL-Safe Base64](ruby/encode-a-string-as-url-safe-base64.md)\n- [Enumerate A Pairing Of Every Two Sequential Items](ruby/enumerate-a-pairing-of-every-two-sequential-items.md)\n- [Evaluating One-Off Commands](ruby/evaluating-one-off-commands.md)\n- [Exclude Values From An Array](ruby/exclude-values-from-an-array.md)\n- [Execute Several Commands With Backtick Heredoc](ruby/execute-several-commands-with-backtick-heredoc.md)\n- [Exit A Process With An Error Message](ruby/exit-a-process-with-an-error-message.md)\n- [Expect A Method To Be Called And Actually Call It](ruby/expect-a-method-to-be-called-and-actually-call-it.md)\n- [Extract A Column Of Data From A CSV File](ruby/extract-a-column-of-data-from-a-csv-file.md)\n- [Extract Capture Group Matches With String Slices](ruby/extract-capture-group-matches-with-string-slices.md)\n- [FactoryGirl Sequences](ruby/factory-girl-sequences.md)\n- [Fail](ruby/fail.md)\n- [Fetch Warns About Superseding Block Argument](ruby/fetch-warns-about-superseding-block-argument.md)\n- [Filter By Type](ruby/filter-by-type.md)\n- [Find The Min And Max With A Single Call](ruby/find-the-min-and-max-with-a-single-call.md)\n- [Finding The Source of Ruby Methods](ruby/finding-the-source-of-ruby-methods.md)\n- [Format A Hash Into A String Template](ruby/format-a-hash-into-a-string-template.md)\n- [Forward All Arguments To Another Method](ruby/forward-all-arguments-to-another-method.md)\n- [Gather Positional Arguments In Method Definition](ruby/gather-positional-arguments-in-method-definition.md)\n- [Generate A Signed JWT Token](ruby/generate-a-signed-jwt-token.md)\n- [Generate Ruby Version And Gemset Files With RVM](ruby/generate-ruby-version-and-gemset-files-with-rvm.md)\n- [Get Info About Your RubyGems Environment](ruby/get-info-about-your-ruby-gems-environment.md)\n- [Get Specific Values From Arrays And Hashes](ruby/get-specific-values-from-hashes-and-arrays.md)\n- [Get The Names Of The Month](ruby/get-the-names-of-the-month.md)\n- [Get The Output Of Running A System Program](ruby/get-the-output-of-running-a-system-program.md)\n- [Get UTC Offset For Different Time Zones](ruby/get-utc-offset-for-different-time-zones.md)\n- [Identify Outdated Gems](ruby/identify-outdated-gems.md)\n- [If You Detect None](ruby/if-you-detect-none.md)\n- [Iterate With An Offset Index](ruby/iterate-with-an-offset-index.md)\n- [Include Extra Context In A Honeybadger Notify](ruby/include-extra-context-in-a-honeybadger-notify.md)\n- [Ins And Outs Of Pry](ruby/ins-and-outs-of-pry.md)\n- [Install And Require Gems Inline Without Gemfile](ruby/install-and-require-gems-inline-without-gemfile.md)\n- [Install Latest Version Of Ruby With asdf](ruby/install-latest-version-of-ruby-with-asdf.md)\n- [Invoking Rake Tasks Multiple Times](ruby/invoking-rake-tasks-multiple-times.md)\n- [IRB Has Built-In Benchmarking With Ruby 3](ruby/irb-has-built-in-benchmarking-with-ruby-3.md)\n- [Join URI Path Parts](ruby/join-uri-path-parts.md)\n- [Jump Out Of A Nested Context With Throw/Catch](ruby/jump-out-of-a-nested-context-with-throw-catch.md)\n- [Last Raised Exception In The Call Stack](ruby/last-raised-exception-in-the-call-stack.md)\n- [Limit Split](ruby/limit-split.md)\n- [List The Running Ruby Version](ruby/list-the-running-ruby-version.md)\n- [Listing Local Variables](ruby/listing-local-variables.md)\n- [Load A Module And Execute A Statement](ruby/load-a-module-and-execute-a-statement.md)\n- [Make A Long String Of Text Readable](ruby/make-a-long-string-of-text-readable.md)\n- [Make An Executable Ruby Script](ruby/make-an-executable-ruby-script.md)\n- [Make Structs Easier To Use With Keyword Initialization](ruby/make-structs-easier-to-use-with-keyword-initialization.md)\n- [Map With Index Over An Array](ruby/map-with-index-over-an-array.md)\n- [Mock Method Chain Calls With RSpec](ruby/mock-method-chain-calls-with-rspec.md)\n- [Mocking Requests With Partial URIs Using Regex](ruby/mocking-requests-with-partial-uris-using-regex.md)\n- [Multi-Line Comments](ruby/multi-line-comments.md)\n- [Named Regex Captures Are Assigned To Variables](ruby/named-regex-captures-are-assigned-to-variables.md)\n- [Navigate Back In The Browser With Capybara](ruby/navigate-back-in-the-browser-with-capybara.md)\n- [Next And Previous Floats](ruby/next-and-previous-floats.md)\n- [OpenStruct Has Bad Performance Characteristics](ruby/open-struct-has-bad-performance-characteristics.md)\n- [Or Operator Precedence](ruby/or-operator-precedence.md)\n- [Output Bytecode For A Ruby Program](ruby/output-bytecode-for-a-ruby-program.md)\n- [Override The Initial Sequence Value](ruby/override-the-initial-sequence-value.md)\n- [Parallel Bundle Install](ruby/parallel-bundle-install.md)\n- [Parse JSON Into An OpenStruct](ruby/parse-json-into-an-open-struct.md)\n- [Parsing A CSV With Quotes In The Data](ruby/parsing-a-csv-with-quotes-in-the-data.md)\n- [Pass A Block To Count](ruby/pass-a-block-to-count.md)\n- [Passing Arbitrary Methods As Blocks](ruby/passing-arbitrary-methods-as-blocks.md)\n- [Passing Arguments To A Rake Task](ruby/passing-arguments-to-a-rake-task.md)\n- [Pattern Match Values From A Hash](ruby/pattern-match-values-from-a-hash.md)\n- [Percent Notation](ruby/percent-notation.md)\n- [Precedence Of Logical Operators](ruby/precedence-of-logical-operators.md)\n- [Prevent erb_lint From Removing Opening Tags](ruby/prevent-erb-lint-from-removing-opening-tags.md)\n- [Print Data To Formatted Table](ruby/print-data-to-formatted-table.md)\n- [Question Mark Operator](ruby/question-mark-operator.md)\n- [Rake Only Lists Tasks With Descriptions](ruby/rake-only-lists-tasks-with-descriptions.md)\n- [Read The First Line From A File](ruby/read-the-first-line-from-a-file.md)\n- [Refer To Implicit Block Argument With It](ruby/refer-to-implicit-block-argument-with-it.md)\n- [Reference Hash Key With Safe Navigation](ruby/reference-hash-key-with-safe-navigation.md)\n- [Regenerate Lock File With Newer Bundler](ruby/regenerate-lock-file-with-newer-bundler.md)\n- [Rendering ERB](ruby/rendering-erb.md)\n- [Replace The Current Process With An External Command](ruby/replace-the-current-process-with-an-external-command.md)\n- [Require Entire Gemfile In Pry Session](ruby/require-entire-gemfile-in-pry-session.md)\n- [Rerun Only Failures With RSpec](ruby/rerun-only-failures-with-rspec.md)\n- [Retry A Block After An Exception](ruby/retry-a-block-after-an-exception.md)\n- [Return The Thing Being Printed](ruby/return-the-thing-being-printed.md)\n- [Returning With Sequel](ruby/returning-with-sequel.md)\n- [rexml Is A Bundled Gem As Of Ruby 3.0.0](ruby/rexml-is-a-bundled-gem-as-of-ruby-3-0-0.md)\n- [Run An Older Version Of Bundler](ruby/run-an-older-version-of-bundler.md)\n- [Running A Single MiniTest Example](ruby/running-a-single-minitest-example.md)\n- [Safe Navigation Operator](ruby/safe-navigation-operator.md)\n- [Scripting With RVM](ruby/scripting-with-rvm.md)\n- [Scroll To Top Of Page With Capybara](ruby/scroll-to-top-of-page-with-capybara.md)\n- [Search For Gem Versions Available To Install](ruby/search-for-gem-versions-available-to-install.md)\n- [Set Default Tasks For Rake To Run](ruby/set-default-tasks-for-rake-to-run.md)\n- [Set RVM Default Ruby](ruby/set-rvm-default-ruby.md)\n- [Shift The Month On A Date Object](ruby/shift-the-month-on-a-date-object.md)\n- [Show Public Methods With Pry](ruby/show-public-methods-with-pry.md)\n- [Show The Bundler Location Of An Installed Gem](ruby/show-the-bundler-location-of-an-installed-gem.md)\n- [Silence The Output Of A Ruby Statement In Pry](ruby/silence-the-output-of-a-ruby-statement-in-pry.md)\n- [Single And Double Quoted String Notation](ruby/single-and-double-quoted-string-notation.md)\n- [Skip Specific CVEs When Auditing Your Bundle](ruby/skip-specific-cves-when-auditing-your-bundle.md)\n- [Skip The Front Of An Array With Drop](ruby/skip-the-front-of-an-array-with-drop.md)\n- [Specify Default For Data Definition](ruby/specify-default-for-data-definition.md)\n- [Specify Dependencies For A Rake Task](ruby/specify-dependencies-for-a-rake-task.md)\n- [Specify How Random Array#sample Is](ruby/specify-how-random-array-sample-is.md)\n- [Split A Float Into Its Integer And Decimal](ruby/split-a-float-into-its-integer-and-decimal.md)\n- [Squeeze Out The Extra Space](ruby/squeeze-out-the-extra-space.md)\n- [Stack Heredocs In A Method Call](ruby/stack-heredocs-in-a-method-call.md)\n- [String Interpolation With Instance Variables](ruby/string-interpolation-with-instance-variables.md)\n- [Summing Collections](ruby/summing-collections.md)\n- [Triple Equals: The Case Equality Operator](ruby/triple-equals-the-case-equality-operator.md)\n- [Turn Key And Value Arrays Into A Hash](ruby/turn-key-and-values-arrays-into-a-hash.md)\n- [Turning Any Class Into An Enumerator](ruby/turning-any-class-into-an-enumerator.md)\n- [Turning Things Into Hashes](ruby/turning-things-into-hashes.md)\n- [Uncaught Exceptions In Pry](ruby/uncaught-exceptions-in-pry.md)\n- [`undef_method` And The Inheritance Hierarchy](ruby/undef-method-and-the-inheritance-hierarchy.md)\n- [Uninstall Specific Version Of A Ruby Gem](ruby/uninstall-specific-version-of-a-ruby-gem.md)\n- [Unpacking Strings Into Binary](ruby/unpacking-strings-into-binary.md)\n- [Up And Down With Integers](ruby/up-and-down-with-integers.md)\n- [Update The Gemfile Bundled With Version](ruby/update-the-gemfile-bundled-with-version.md)\n- [Use A Case Statement As A Cond Statement](ruby/use-a-case-statement-as-a-cond-statement.md)\n- [Use dotenv In A Non-Rails Project](ruby/use-dotenv-in-a-non-rails-project.md)\n- [Use Tap For Better Test Data Setup](ruby/use-tap-for-better-test-data-setup.md)\n- [Using BCrypt To Create And Check Hashed Passwords](ruby/using-bcrypt-to-create-and-check-hashed-passwords.md)\n- [What To Do When You Don't Rescue](ruby/what-to-do-when-you-dont-rescue.md)\n- [Who Are My Ancestors?](ruby/who-are-my-ancestors.md)\n- [Wrap Things In An Array, Even Hashes](ruby/wrap-things-in-an-array-even-hashes.md)\n- [Zero Padding](ruby/zero-padding.md)\n\n### sed\n\n- [Apply Multiple Substitutions To The Input](sed/apply-multiple-substitutions-to-the-input.md)\n- [Equivalence Classes Of Repetition MetaChars](sed/equivalence-classes-of-repetition-metachars.md)\n- [Extract Value From Command Output With Sed](sed/extract-value-from-command-output-with-sed.md)\n- [Grab All The Method Names Defined In A Ruby File](sed/grab-all-the-method-names-defined-in-a-ruby-file.md)\n- [Grab The First Line Of A File](sed/grab-the-first-line-of-a-file.md)\n- [OSX sed Does Regex A Bit Different](sed/osx-sed-does-regex-a-bit-different.md)\n- [Output Only Lines Involved In A Substitution](sed/output-only-lines-involved-in-a-substitution.md)\n- [Reference A Capture In The Regex](sed/reference-a-capture-in-the-regex.md)\n- [Reference The Full Match In The Replacement](sed/reference-the-full-match-in-the-replacement.md)\n- [Use An Alternative Delimiter In A Substitution](sed/use-an-alternative-delimiter-in-a-substitution.md)\n\n### Shell\n\n- [Check If The First Argument Is Given](shell/check-if-the-first-argument-is-given.md)\n- [Format And Print The Current Date And Time](shell/format-and-print-the-current-date-and-time.md)\n\n### SQLite\n\n- [Display Results In Readable Column Format](sqlite/display-results-in-readable-column-format.md)\n- [Explore The Database Schema](sqlite/explore-the-database-schema.md)\n\n### Streaming\n\n- [Monitor An Audio Input Device In OBS](streaming/monitor-an-audio-input-device-in-obs.md)\n\n### Tailwind CSS\n\n- [Apply Tailwind Classes To Existing CSS Class](tailwind/apply-tailwind-classes-to-existing-css-class.md)\n- [Base Styles For Text Link](tailwind/base-styles-for-text-link.md)\n- [Disable And Enable A Button](tailwind/disable-and-enable-a-button.md)\n- [Specify Paths For Purging Unused CSS](tailwind/specify-paths-for-purging-unused-css.md)\n- [Use Tailwind Typography Prose In Dark Mode](tailwind/use-tailwind-typography-prose-in-dark-mode.md)\n\n### Taskfile\n\n- [Create Interactive Picker For Set Of Subtasks](taskfile/create-interactive-picker-for-set-of-subtasks.md)\n- [Run A Task If It Meets Criteria](taskfile/run-a-task-if-it-meets-criteria.md)\n\n### tmux\n\n- [Access Past Copy Buffer History](tmux/access-past-copy-buffer-history.md)\n- [Add Bindings To Split Panes To Current Directory](tmux/add-bindings-to-split-panes-to-current-directory.md)\n- [Adjusting Window Pane Size](tmux/adjusting-window-pane-size.md)\n- [Break Current Pane Out To Separate Window](tmux/break-current-pane-out-to-separate-window.md)\n- [Change Base Directory Of Existing Session](tmux/change-base-directory-of-existing-session.md)\n- [Change Base Directory Without Detaching](tmux/change-base-directory-without-detaching.md)\n- [Change The Default Prefix Key](tmux/change-the-default-prefix-key.md)\n- [Create A Named tmux Session](tmux/create-a-named-tmux-session.md)\n- [Create A New Session In A New Server](tmux/create-a-new-session-in-a-new-server.md)\n- [Cycle Through Layouts](tmux/cycle-through-layouts.md)\n- [Display Titles For Each Pane In A Window](tmux/display-titles-for-each-pane-in-a-window.md)\n- [Enabling Vi Mode](tmux/enabling-vi-mode.md)\n- [Get Mouse Copy/Paste Working In Kitty](tmux/get-mouse-copy-paste-working-in-kitty.md)\n- [Hiding The Status Bar](tmux/hiding-the-status-bar.md)\n- [Jumping Between Sessions](tmux/jumping-between-sessions.md)\n- [Kill All Your tmux Sessions](tmux/kill-all-your-tmux-sessions.md)\n- [Kill Other Connections To A Session](tmux/kill-other-connections-to-a-session.md)\n- [Kill The Current Session](tmux/kill-the-current-session.md)\n- [List All Key Bindings](tmux/list-all-key-bindings.md)\n- [List Processes Running Across All Session](tmux/list-processes-running-across-all-sessions.md)\n- [List Sessions](tmux/list-sessions.md)\n- [Open New Splits To The Current Directory](tmux/open-new-splits-to-the-current-directory.md)\n- [Open New Window With A Specific Directory](tmux/open-new-window-with-a-specific-directory.md)\n- [Organizing Windows](tmux/organizing-windows.md)\n- [Paging Up And Down](tmux/paging-up-and-down.md)\n- [Pane Killer](tmux/pane-killer.md)\n- [Reclaiming The Entire Window](tmux/reclaiming-the-entire-window.md)\n- [Remove The Delay On The Escape Key](tmux/remove-the-delay-on-the-escape-key.md)\n- [Rename The Current Session](tmux/rename-the-current-session.md)\n- [Reset An Option Back To Its Default Value](tmux/reset-an-option-back-to-its-default-value.md)\n- [Set Environment Variables When Creating Session](tmux/set-environment-variables-when-creating-session.md)\n- [Set Session Specific Environment Variables](tmux/set-session-specific-environment-variables.md)\n- [Set Up Forwarding Prefix For Nested Session](tmux/set-up-forwarding-prefix-for-nested-session.md)\n- [Show The Current Value For An Option](tmux/show-the-current-value-for-an-option.md)\n- [Swap Split Panes](tmux/swap-split-panes.md)\n- [Switch To A Specific Session And Window](tmux/switch-to-a-specific-session-and-window.md)\n- [tmux in your tmux](tmux/tmux-in-your-tmux.md)\n- [Toggle Between Two Common Sessions](tmux/toggle-between-two-common-sessions.md)\n\n### TypeScript\n\n- [Add Generic Typing To An Anonymous Function](typescript/add-generic-typing-to-an-anonymous-function.md)\n- [Add Types To An Object Destructuring](typescript/add-types-to-an-object-destructuring.md)\n- [Compiler Checks For Unused Params And Variables](typescript/compiler-checks-for-unused-params-and-variables.md)\n- [Create A Non-Empty Array Type](typescript/create-a-non-empty-array-type.md)\n- [Create A Union Type From An Array](typescript/create-a-union-type-from-an-array.md)\n- [Create Union Type From Constants](typescript/create-union-type-from-constants.md)\n- [Extract Object Type Keys Into A Union Type](typescript/extract-object-type-keys-into-a-union-type.md)\n- [Extract Object Type Values Into A Union Type](typescript/extract-object-type-values-into-a-union-type.md)\n- [Generate An Initial tsconfig File](typescript/generate-an-initial-tsconfig-file.md)\n- [Generate Inferred Type From Zod Schema](typescript/generate-inferred-type-from-zod-schema.md)\n- [Get The Return Type Of An Async Function](typescript/get-the-return-type-of-an-async-function.md)\n- [Ignore All Errors In A TypeScript File](typescript/ignore-all-errors-in-a-typescript-file.md)\n- [Interfaces With The Same Name Are Merged](typescript/interfaces-with-the-same-name-are-merged.md)\n- [Narrow The Type Of An Array To Its Values](typescript/narrow-the-type-of-an-array-to-its-values.md)\n- [Re-Export An Imported Type](typescript/re-export-an-imported-type.md)\n- [Set Path Alias For Cleaner Imports](typescript/set-path-alias-for-cleaner-imports.md)\n- [Type Narrowing With Const VS Let Strings](typescript/type-narrowing-with-const-vs-let-strings.md)\n- [Type Narrowing With Similarly Shaped Objects](typescript/type-narrowing-with-similarly-shaped-objects.md)\n- [Type Promise Results With The Awaited Type](typescript/type-promise-results-with-the-awaited-type.md)\n- [Use An Array Check For Type Narrowing](typescript/use-an-array-check-for-type-narrowing.md)\n- [Zero-Config Environments For Trying Out Types](typescript/zero-config-environments-for-trying-out-types.md)\n\n### Unix\n\n- [All The Environment Variables](unix/all-the-environment-variables.md)\n- [Apply Successive Filters To Lines In Less](unix/apply-successive-filters-to-lines-in-less.md)\n- [Authorize A cURL Request](unix/authorize-a-curl-request.md)\n- [Cat A File With Line Numbers](unix/cat-a-file-with-line-numbers.md)\n- [Cat Files With Color Using Bat](unix/cat-files-with-color-using-bat.md)\n- [Change Default Shell For A User](unix/change-default-shell-for-a-user.md)\n- [Change To That New Directory](unix/change-to-that-new-directory.md)\n- [Check Connected Stripe Account Name](unix/check-connected-stripe-account-name.md)\n- [Check If A Port Is In Use](unix/check-if-a-port-is-in-use.md)\n- [Check If Command Is Executable Before Using](unix/check-if-command-is-executable-before-using.md)\n- [Check SSH Key Fingerprints Of Known Hosts](unix/check-ssh-key-fingerprints-of-known-hosts.md)\n- [Check The Current Working Directory](unix/check-the-current-working-directory.md)\n- [Check The Installed OpenSSL Version](unix/check-the-installed-openssl-version.md)\n- [Clear The Screen](unix/clear-the-screen.md)\n- [Combine All My TILs Into A Single File](unix/combine-all-my-tils-into-a-single-file.md)\n- [Command Line Length Limitations](unix/command-line-length-limitations.md)\n- [Compare Two Variables In A Bash Script](unix/compare-two-variables-in-a-bash-script.md)\n- [Configure cd To Behave Like pushd In Zsh](unix/configure-cd-to-behave-like-pushd-in-zsh.md)\n- [Convert JPEG To PNG With ffmpeg](unix/convert-jpeg-to-png-with-ffmpeg.md)\n- [Convert SVG To Favicon](unix/convert-svg-to-favicon.md)\n- [Copying File Contents To System Paste Buffer](unix/copying-file-contents-to-system-paste-buffer.md)\n- [Copying Nested Directories With Ditto](unix/copying-nested-directories-with-ditto.md)\n- [Count The Lines In A CSV Where A Column Is Empty](unix/count-the-lines-in-a-csv-where-a-column-is-empty.md)\n- [Count The Number Of Matches In A Grep](unix/count-the-number-of-matches-in-a-grep.md)\n- [Count The Number Of ripgrep Pattern Matches](unix/count-the-number-of-ripgrep-pattern-matches.md)\n- [Count The Number Of Words On A Webpage](unix/count-the-number-of-words-on-a-webpage.md)\n- [Create A File Descriptor with Process Substitution](unix/create-a-file-descriptor-with-process-substitution.md)\n- [Create A Filename With The Current Date](unix/create-a-filename-with-the-current-date.md)\n- [Create A Sequence Of Values With A Step](unix/create-a-sequence-of-values-with-a-step.md)\n- [Curl With Cookies](unix/curl-with-cookies.md)\n- [Curling For Headers](unix/curling-for-headers.md)\n- [Curling With Basic Auth Credentials](unix/curling-with-basic-auth-credentials.md)\n- [Determine ipv4 And ipv6 Public IP Addresses](unix/determine-ipv4-and-ipv6-public-ip-addresses.md)\n- [Diff Two Files In Unified Format](unix/diff-two-files-in-unified-format.md)\n- [Different Ways To Generate A v4 UUID](unix/different-ways-to-generate-a-v4-uuid.md)\n- [Display All The Terminal Colors](unix/display-all-the-terminal-colors.md)\n- [Display Free Disk Space](unix/display-free-disk-space.md)\n- [Display Line Numbers While Using Less](unix/display-line-numbers-while-using-less.md)\n- [Display The Contents Of A Directory As A Tree](unix/display-the-contents-of-a-directory-as-a-tree.md)\n- [Do A Dry Run Of An rsync](unix/do-a-dry-run-of-an-rsync.md)\n- [Do Not Overwrite Existing Files](unix/do-not-overwrite-existing-files.md)\n- [Download A File With Curl](unix/download-a-file-with-curl.md)\n- [Enable Multi-Select Of Results With fzf](unix/enable-multi-select-of-results-with-fzf.md)\n- [Exclude A Command From The ZSH History File](unix/exclude-a-command-from-the-zsh-history-file.md)\n- [Exclude A Directory With Find](unix/exclude-a-directory-with-find.md)\n- [Exclude A Specific File From fd Results](unix/exclude-a-specific-file-from-fd-results.md)\n- [Exclude Certain Files From An rsync Run](unix/exclude-certain-files-from-an-rsync-run.md)\n- [Figure Out The Week Of The Year From The Terminal](unix/figure-out-the-week-of-the-year-from-the-terminal.md)\n- [File Type Info With File](unix/file-type-info-with-file.md)\n- [Find All Files Matching A Name With fd](unix/find-all-files-matching-a-name-with-fd.md)\n- [Find All Files With A Specific Extension With fd](unix/find-all-files-with-a-specific-extension-with-fd.md)\n- [Find All Tool Version Files Containing Postgres](unix/find-all-tool-version-files-containing-postgres.md)\n- [Find And Copy A Value From Large JSON Output](unix/find-and-copy-a-value-from-large-json-output.md)\n- [Find Any Dotfiles That Modify Path Env Var](unix/find-any-dotfiles-that-modify-path-env-var.md)\n- [Find A File Installed By Brew](unix/find-a-file-installed-by-brew.md)\n- [Find Duplicate Lines In A File](unix/find-duplicate-lines-in-a-file.md)\n- [Find Files With fd](unix/find-files-with-fd.md)\n- [Find Newer Files](unix/find-newer-files.md)\n- [Find Occurrences Of Multiple Values With Ripgrep](unix/find-occurrences-of-multiple-values-with-ripgrep.md)\n- [Find Top-Level Directories Matching A Pattern](unix/find-top-level-directories-matching-a-pattern.md)\n- [Fix Previous Command With fc](unix/fix-previous-command-with-fc.md)\n- [Fix Shim Path After asdf Upgrade](unix/fix-shim-path-after-asdf-upgrade.md)\n- [Fix Unlinked Node Binaries With asdf](unix/fix-unlinked-node-binaries-with-asdf.md)\n- [Format And Display Small Amounts Of Columnar Data](unix/format-and-display-small-amounts-of-columnar-data.md)\n- [Forward Multiple Ports Over SSH](unix/forward-multiple-ports-over-ssh.md)\n- [Generate A SAML Key And Certificate Pair](unix/generate-a-saml-key-and-certificate-pair.md)\n- [Generate A Sequence Of Numbered Items](unix/generate-a-sequence-of-numbered-items.md)\n- [Generate Base64 Encoding Without Newlines](unix/generate-base64-encoding-without-newlines.md)\n- [Generate Random 20-Character Hex String](unix/generate-random-20-character-hex-string.md)\n- [Get A List Of Locales On Your System](unix/get-a-list-of-locales-on-your-system.md)\n- [Get Matching Filenames As Output From Grep](unix/get-matching-filenames-as-output-from-grep.md)\n- [Get The SHA256 Hash For A File](unix/get-the-sha256-hash-for-a-file.md)\n- [Get The Unix Timestamp](unix/get-the-unix-timestamp.md)\n- [Get Word Count For All Files In Git Repo](unix/get-word-count-for-all-files-in-git-repo.md)\n- [Global Substitution On The Previous Command](unix/global-substitution-on-the-previous-command.md)\n- [Globbing For All Directories In Zsh](unix/globbing-for-all-directories-in-zsh.md)\n- [Globbing For Filenames In Zsh](unix/globbing-for-filenames-in-zsh.md)\n- [Gracefully Exit A Script With Trap](unix/gracefully-exit-a-script-with-trap.md)\n- [Grep For Files Without A Match](unix/grep-for-files-without-a-match.md)\n- [Grep For Files With Multiple Matches](unix/grep-for-files-with-multiple-matches.md)\n- [Grep For Multiple Patterns](unix/grep-for-multiple-patterns.md)\n- [Have Script ShellCheck Itself When Executing](unix/have-script-shellcheck-itself-when-executing.md)\n- [Hexdump A Compiled File](unix/hexdump-a-compiled-file.md)\n- [Ignore A Directory During ripgrep Search](unix/ignore-a-directory-during-ripgrep-search.md)\n- [Ignore The Alias When Running A Command](unix/ignore-the-alias-when-running-a-command.md)\n- [Include Ignore Files In Ripgrep Search](unix/include-ignore-files-in-ripgrep-search.md)\n- [Inspect EXIF Data For An Image File](unix/inspect-exif-data-for-an-image-file.md)\n- [Interactively Browse Available Node Versions](unix/interactively-browse-availabile-node-versions.md)\n- [Interactively Switch asdf Package Versions](unix/interactively-switch-asdf-package-versions.md)\n- [Interpret Cron Schedule From The CLI](unix/interpret-cron-schedule-from-the-cli.md)\n- [Jump To The Ends Of Your Shell History](unix/jump-to-the-ends-of-your-shell-history.md)\n- [Kill Everything Running On A Certain Port](unix/kill-everything-running-on-a-certain-port.md)\n- [Killing A Frozen SSH Session](unix/killing-a-frozen-ssh-session.md)\n- [Last Argument Of The Last Command](unix/last-argument-of-the-last-command.md)\n- [Less With Style](unix/less-with-style.md)\n- [Limit Protocols Used In A cURL Command](unix/limit-protocols-used-in-a-curl-command.md)\n- [List All Fonts On Your Machine](unix/list-all-fonts-on-your-machine.md)\n- [List All The Enabled ZSH Options](unix/list-all-the-enabled-zsh-options.md)\n- [List All Users](unix/list-all-users.md)\n- [List Files In A Single Column](unix/list-files-in-a-single-column.md)\n- [List Files Ordered By Modification Date](unix/list-files-ordered-by-modification-date.md)\n- [List Names Of Files With Matches](unix/list-names-of-files-with-matches.md)\n- [List Of Sessions To A Machine](unix/list-of-sessions-to-a-machine.md)\n- [List Parent pid With ps](unix/list-parent-pid-with-ps.md)\n- [List Stats For A File](unix/list-stats-for-a-file.md)\n- [List The Available JDKs](unix/list-the-available-jdks.md)\n- [List The PID And Name Of Current Shell Process](unix/list-the-pid-and-name-of-current-shell-process.md)\n- [List The Stack Of Remembered Directories](unix/list-the-stack-of-remembered-directories.md)\n- [List TXT DNS Records For A Domain](unix/list-txt-dns-records-for-a-domain.md)\n- [Load Env Vars In Bash Script](unix/load-env-vars-in-bash-script.md)\n- [Look Through All Files That Have Been Git Stashed](unix/look-through-all-files-that-have-been-git-stashed.md)\n- [Make Direnv Less Noisy](unix/make-direnv-less-noisy.md)\n- [Make Neovim The Default Way To View Man Pages](unix/make-neovim-the-default-way-to-view-man-pages.md)\n- [Manually Pass Two Git Files To Delta](unix/manually-pass-two-git-files-to-delta.md)\n- [Map A Domain To localhost](unix/map-a-domain-to-localhost.md)\n- [Negative Look-Ahead Search With ripgrep](unix/negative-look-ahead-search-with-ripgrep.md)\n- [Occupy A Local Port With Netcat](unix/occupy-a-local-port-with-netcat.md)\n- [Only Show The Matches](unix/only-show-the-matches.md)\n- [Open The Current Command In An Editor](unix/open-the-current-command-in-an-editor.md)\n- [Output The Last N Bytes Of A Large File](unix/output-the-last-n-bytes-of-a-large-file.md)\n- [Partial String Matching In Bash Scripts](unix/partial-string-matching-in-bash-scripts.md)\n- [PID Of The Current Shell](unix/pid-of-the-current-shell.md)\n- [Print A Range Of Lines For A File With Bat](unix/print-a-range-of-lines-for-a-file-with-bat.md)\n- [Print DateTime Represented By Unix Timestamp](unix/print-datetime-represented-by-unix-timestamp.md)\n- [Print Milliseconds In Human-Readable Format](unix/print-milliseconds-in-human-readable-format.md)\n- [Print Out Files In Reverse](unix/print-out-files-in-reverse.md)\n- [Print The Current Date In Human-Readable Format](unix/print-the-current-date-in-human-readable-format.md)\n- [Produce A Lowercase V4 UUID](unix/produce-a-lowercase-v4-uuid.md)\n- [Provide A Fallback Value For Unset Parameter](unix/provide-a-fallback-value-for-unset-parameter.md)\n- [Remove A Directory Called `-p`](unix/remove-a-directory-called-dash-p.md)\n- [Rename A Bunch Of Files By Constructing mv Commands](unix/rename-a-bunch-of-files-by-constructing-mv-commands.md)\n- [Repeat Yourself](unix/repeat-yourself.md)\n- [Replace Pattern Across Many Files In A Project](unix/replace-pattern-across-many-files-in-a-project.md)\n- [Run A Command Repeatedly Several Times](unix/run-a-command-repeatedly-several-times.md)\n- [Run A cURL Command Without The Progress Meter](unix/run-a-curl-command-without-the-progress-meter.md)\n- [Safely Edit The Sudoers File With Vim](unix/safely-edit-the-sudoers-file-with-vim.md)\n- [Saying Yes](unix/saying-yes.md)\n- [Search Files Specific To A Language](unix/search-files-specific-to-a-language.md)\n- [Search For Homebrew Packages To Install](unix/search-for-homebrew-packages-to-install.md)\n- [Search History](unix/search-history.md)\n- [Search Man Page Descriptions](unix/search-man-page-descriptions.md)\n- [Securely Remove Files](unix/securely-remove-files.md)\n- [See Where asdf Gets Current Tool Version](unix/see-where-asdf-gets-current-tool-version.md)\n- [Set The asdf Package Version For A Single Shell](unix/set-the-asdf-package-version-for-a-single-shell.md)\n- [Shorten SSH Commands With Aliases](unix/shorten-ssh-commands-with-aliases.md)\n- [Show A File Preview When Searching With FZF](unix/show-a-file-preview-when-searching-with-fzf.md)\n- [Show Disk Usage For The Current Directory](unix/show-disk-usage-for-the-current-directory.md)\n- [Show The Size Of Everything In A Directory](unix/show-the-size-of-everything-in-a-directory.md)\n- [Show Tree View Of Processes And Subprocesses](unix/show-tree-view-of-processes-and-subprocesses.md)\n- [Skip Paging If Output Fits On Screen With Less](unix/skip-paging-if-output-fits-on-screen-with-less.md)\n- [SSH Escape Sequences](unix/ssh-escape-sequences.md)\n- [SSH With Port Forwarding](unix/ssh-with-port-forwarding.md)\n- [Specify The Language For A File With Bat](unix/specify-the-language-for-a-file-with-bat.md)\n- [Sort In Numerical Order](unix/sort-in-numerical-order.md)\n- [Switch Versions of a Brew Formula](unix/switch-versions-of-a-brew-formula.md)\n- [Tell direnv To Load The Env File](unix/tell-direnv-to-load-the-env-file.md)\n- [Touch Access And Modify Times Individually](unix/touch-access-and-modify-times-individually.md)\n- [Transform Text To Lowercase](unix/transform-text-to-lowercase.md)\n- [Type Fewer Paths With Brace Expansion](unix/type-fewer-paths-with-brace-expansion.md)\n- [Undo Changes Made To Current Terminal Prompt](unix/undo-changes-made-to-current-terminal-prompt.md)\n- [Undo Some Command Line Editing](unix/undo-some-command-line-editing.md)\n- [Unrestrict Where ripgrep Searches](unix/unrestrict-where-ripgrep-searches.md)\n- [Update Package Versions Known By asdf Plugin](unix/update-package-versions-known-by-asdf-plugin.md)\n- [Use fzf To Change Directories](unix/use-fzf-to-change-directories.md)\n- [Use Negative Lookbehind Matching With ripgrep](unix/use-negative-lookbehind-matching-with-ripgrep.md)\n- [Use Regex Pattern Matching With Grep](unix/use-regex-pattern-matching-with-grep.md)\n- [View A Web Page In The Terminal](unix/view-a-web-page-in-the-terminal.md)\n- [View The Source For A Brew Formula](unix/view-the-source-for-a-brew-formula.md)\n- [Watch The Difference](unix/watch-the-difference.md)\n- [Watch This Run Repeatedly](unix/watch-this-run-repeatedly.md)\n- [Where Are The Binaries?](unix/where-are-the-binaries.md)\n- [xargs Default Command Is echo](unix/xargs-default-command-is-echo.md)\n- [xargs Ignores Alias Substitution By Default](unix/xargs-ignores-alias-substitution-by-default.md)\n\n### Vercel\n\n- [Add Web Server Layer Redirects](vercel/add-web-server-layer-redirects.md)\n- [Deploy An App Without Pushing An Empty Commit](vercel/deploy-an-app-without-pushing-an-empty-commit.md)\n- [Naming Of The Vercel Config File](vercel/naming-of-the-vercel-config-file.md)\n- [Pin Specific pnpm Version For Builds](vercel/pin-specific-pnpm-version-for-builds.md)\n- [Share Development Environment Variables Via CLI](vercel/share-development-environment-variables-via-cli.md)\n\n### Vim\n\n- [Aborting Git Commits And Rebases](vim/aborting-git-commits-and-rebases.md)\n- [Absolute And Relative Line Numbers](vim/absolute-and-relative-line-numbers.md)\n- [Add A File Without Loading It](vim/add-a-file-without-loading-it.md)\n- [Add Custom Dictionary Words](vim/add-custom-dictionary-words.md)\n- [All The Ways To Write And Quit In Vim](vim/all-the-ways-to-write-and-quit-in-vim.md)\n- [Almost The End Of The Line](vim/almost-the-end-of-the-line.md)\n- [Alternate Files With vim-rails](vim/alternate-files-with-vim-rails.md)\n- [Always Keep The Gutter Open](vim/always-keep-the-gutter-open.md)\n- [Amend Commits With Fugitive](vim/amend-commits-with-fugitive.md)\n- [Backspace Options](vim/backspace-options.md)\n- [Beginning And End Of Previous Change](vim/beginning-and-end-of-previous-change.md)\n- [The Black Hole Register](vim/the-black-hole-register.md)\n- [Blank Lines Above And Below](vim/blank-lines-above-and-below.md)\n- [Breaking The Undo Sequence](vim/breaking-the-undo-sequence.md)\n- [Buffer Time Travel](vim/buffer-time-travel.md)\n- [Build And Install A Go Program](vim/build-and-install-a-go-program.md)\n- [Bypass On-Save Tooling When Writing File](vim/bypass-on-save-tooling-when-writing-file.md)\n- [Case-Aware Substitution With vim-abolish](vim/case-aware-substitution-with-vim-abolish.md)\n- [Case-Insensitive Substitution](vim/case-insensitive-substitution.md)\n- [Center The Cursor](vim/center-the-cursor.md)\n- [Check For An Executable](vim/check-for-an-executable.md)\n- [Check Your Current Color Scheme](vim/check-your-current-color-scheme.md)\n- [Clear Out The Jump List](vim/clear-out-the-jump-list.md)\n- [Close All Other Splits](vim/close-all-other-splits.md)\n- [Close All Other Windows](vim/close-all-other-windows.md)\n- [Close the Current Buffer](vim/close-the-current-buffer.md)\n- [Coerce The Current Filetype](vim/coerce-the-current-filetype.md)\n- [Coercing Casing With vim-abolish](vim/coercing-casing-with-vim-abolish.md)\n- [Configure FZF To Use fd For File Finding](vim/configure-fzf-to-use-fd-for-file-finding.md)\n- [Count the Number of Matches](vim/count-the-number-of-matches.md)\n- [Create A New Directory In netrw](vim/create-a-new-directory-in-netrw.md)\n- [Create A New File In A New Directory](vim/create-a-new-file-in-a-new-directory.md)\n- [Creating Non-Existent Directories](vim/creating-non-existent-directories.md)\n- [Default netrw To Tree Liststyle](vim/default-netrw-to-tree-liststyle.md)\n- [Delete Every Other Line](vim/delete-every-other-line.md)\n- [Delete Lines That Match A Pattern](vim/delete-lines-that-match-a-pattern.md)\n- [Delete To The End Of The Line](vim/delete-to-the-end-of-the-line.md)\n- [Deleting Buffers In BufExplorer](vim/deleting-buffers-in-bufexplorer.md)\n- [Deleting Directories Of Files From netrw](vim/deleting-directories-of-files-from-netrw.md)\n- [Detect If You Are On A Mac](vim/detect-if-you-are-on-a-mac.md)\n- [Difference Between :wq and :x](vim/difference-between-wq-and-x.md)\n- [Display Word Count Stats](vim/display-word-count-stats.md)\n- [Edges Of The Selection](vim/edges-of-the-selection.md)\n- [Edit A File At A Specific Line Number](vim/edit-a-file-at-a-specific-line-number.md)\n- [Edit A File Starting On The Last Line](vim/edit-a-file-starting-on-the-last-line.md)\n- [End Of The Word](vim/end-of-the-word.md)\n- [Escaping Terminal-Mode In An Nvim Terminal](vim/escaping-terminal-mode-in-an-nvim-terminal.md)\n- [Filter Lines Through An External Program](vim/filter-lines-through-an-external-program.md)\n- [Find The Nth Character Position In A File](vim/find-the-nth-character-position-in-a-file.md)\n- [Fix The Spelling Of A Word](vim/fix-the-spelling-of-a-word.md)\n- [Fold A Visual Selection And Expand It Back](vim/fold-a-visual-selection-and-expand-it-back.md)\n- [For When That Escape Key Is Hard To Reach](vim/for-when-that-escape-key-is-hard-to-reach.md)\n- [Format Long Lines To Text Width](vim/format-long-lines-to-text-width.md)\n- [From Ruby Variables To JavaScript Variables](vim/from-ruby-variables-to-javascript-variables.md)\n- [Generate and Edit Rails Migration](vim/generate-and-edit-rails-migration.md)\n- [Get The pid Of The Session](vim/get-the-pid-of-the-session.md)\n- [Go Back To The Previous Window](vim/go-back-to-the-previous-window.md)\n- [Go To Beginning And End Of Line](vim/go-to-beginning-and-end-of-line.md)\n- [Go To File With Line Number](vim/go-to-file-with-line-number.md)\n- [Grepping Through The Vim Help Files](vim/grepping-through-the-vim-help-files.md)\n- [Head of File Name](vim/head-of-file-name.md)\n- [Help For Non-Normal Mode Features](vim/help-for-non-normal-mode-features.md)\n- [Highlighting Search Matches](vim/highlighting-search-matches.md)\n- [Horizontal to Vertical and Back Again](vim/horizontal-to-vertical-and-back-again.md)\n- [Increment All The Numbers](vim/increment-all-the-numbers.md)\n- [Incremental Searching](vim/incremental-searching.md)\n- [Interact With The Alternate File](vim/interact-with-the-alternate-file.md)\n- [Interactive Buffer List](vim/interactive-buffer-list.md)\n- [Joining Lines Together](vim/joining-lines-together.md)\n- [Jump Back To The Latest Jump Position](vim/jump-back-to-the-latest-jump-position.md)\n- [Jump Between And Stage Git Hunks With Fugitive](vim/jump-between-and-stage-git-hunks-with-fugitive.md)\n- [Jump To Matching Pair](vim/jump-to-matching-pair.md)\n- [Jump To The Next Misspelling](vim/jump-to-the-next-misspelling.md)\n- [List All Buffers](vim/list-all-buffers.md)\n- [List autocmds Configured For The Current Buffer](vim/list-autocmds-configured-for-the-current-buffer.md)\n- [List Of Plugins](vim/list-of-plugins.md)\n- [Load A Directory Of Files Into The Buffer List](vim/load-a-directory-of-files-into-the-buffer-list.md)\n- [Make Directories For The Current File](vim/make-directories-for-the-current-file.md)\n- [Marks Across Vim Sessions](vim/marks-across-vim-sessions.md)\n- [Match The Beginning And End Of Words](vim/match-the-beginning-and-end-of-words.md)\n- [Moving To A Specific Line](vim/moving-to-a-specific-line.md)\n- [Navigate To The Nth Column On A Line](vim/navigate-to-the-nth-column-on-a-line.md)\n- [Navigating By Blank Lines](vim/navigating-by-blank-lines.md)\n- [NETRW Listing Styles](vim/netrw-listing-styles.md)\n- [Next Modified Buffer](vim/next-modified-buffer.md)\n- [Normal Node Binding To Just Quit](vim/normal-mode-binding-to-just-quit.md)\n- [Open A Tag In A Split Window](vim/open-a-tag-in-a-split-window.md)\n- [Open an Unnamed Buffer](vim/open-an-unnamed-buffer.md)\n- [Open FZF Result In A Split](vim/open-fzf-result-in-a-split.md)\n- [Open Routes File With vim-rails](vim/open-routes-file-with-vim-rails.md)\n- [Open The Directory Of The Current File](vim/open-the-directory-of-the-current-file.md)\n- [Open The Fugitive Git Summary Window](vim/open-the-fugitive-git-summary-window.md)\n- [Open The Gemfile](vim/open-the-gemfile.md)\n- [Open The Latest Rails Migration](vim/open-the-latest-rails-migration.md)\n- [Open The Selected Lines In GitHub With Gbrowse](vim/open-the-selected-lines-in-github-with-gbrowse.md)\n- [Open Vim To A Tag Definition](vim/open-vim-to-a-tag-definition.md)\n- [Opening a URL](vim/opening-a-url.md)\n- [Opening Man Pages In Vim](vim/opening-man-pages-in-vim.md)\n- [Paste A Register From Insert Mode](vim/paste-a-register-from-insert-mode.md)\n- [Preventing Typos with Abbreviations](vim/preventing-typos-with-abbreviations.md)\n- [Previous Buffer](vim/previous-buffer.md)\n- [Previous Visual Selection](vim/previous-visual-selection.md)\n- [Print The Relative Path Of The Current File](vim/print-the-relative-path-of-the-current-file.md)\n- [Print Version Information](vim/print-version-information.md)\n- [Quick File Info](vim/quick-file-info.md)\n- [Quick Man Pages](vim/quick-man-pages.md)\n- [Quick Quickfix List Navigation](vim/quick-quickfix-list-navigation.md)\n- [Quickly Fix A Misspelled Word](vim/quickly-fix-a-misspelled-word.md)\n- [Quickly Switch To A Buffer By Number](vim/quickly-switch-to-a-buffer-by-number.md)\n- [Quit When There Is An Argument List](vim/quit-when-there-is-an-argument-list.md)\n- [Re-indenting Your Code](vim/reindenting-your-code.md)\n- [Read In The Contents Of A Rails File](vim/read-in-the-contents-of-a-rails-file.md)\n- [Rename A File Through netrw](vim/rename-a-file-through-netrw.md)\n- [Rename Current File](vim/rename-current-file.md)\n- [Repeat The Previous Change](vim/repeat-the-previous-change.md)\n- [Repeating Characters](vim/repeating-characters.md)\n- [Replace A Character](vim/replace-a-character.md)\n- [Reset Target tslime Pane](vim/reset-target-tslime-pane.md)\n- [Reverse A Group Of Lines](vim/reverse-a-group-of-lines.md)\n- [Reword A Commit Message With Fugitive](vim/reword-a-commit-message-with-fugitive.md)\n- [Rotate Everything By 13 Letters](vim/rotate-everything-by-13-letters.md)\n- [Rotate The Orientation Of Split Windows](vim/rotate-the-orientation-of-split-windows.md)\n- [Running Bundle With vim-bundler](vim/running-bundle-with-vim-bundler.md)\n- [Scrolling Relative to the Cursor](vim/scrolling-relative-to-the-cursor.md)\n- [Search Backward Through A File](vim/search-backward-through-a-file.md)\n- [Searching For Hex Digits](vim/searching-for-hex-digits.md)\n- [Select Several Results From An FZF Search](vim/select-several-results-from-an-fzf-search.md)\n- [Set End Of Line Markers](vim/set-end-of-line-markers.md)\n- [Set Your Color Scheme](vim/set-your-color-scheme.md)\n- [Setting Filetype With Modelines](vim/setting-filetype-with-modelines.md)\n- [Show All Syntax Highlighting Rules](vim/show-all-syntax-highlighting-rules.md)\n- [Show Matching Entries For Help](vim/show-matching-entries-for-help.md)\n- [Specify The Line Height Of The Quick Fix Window](vim/specify-the-line-height-of-the-quick-fix-window.md)\n- [Split Different](vim/split-different.md)\n- [Split The Current Window](vim/split-the-current-window.md)\n- [Splitting For New Files](vim/splitting-for-new-files.md)\n- [Source Original vimrc When Using Neovim](vim/source-original-vimrc-when-using-neovim.md)\n- [Sum A Bunch Of Numbers In The Current File](vim/sum-a-bunch-of-numbers-in-the-current-file.md)\n- [Swap Occurrences Of Two Words](vim/swap-occurrences-of-two-words.md)\n- [Swapping Split Windows](vim/swapping-split-windows.md)\n- [Swap The Position Of Two Split Windows](vim/swap-the-position-of-two-split-windows.md)\n- [Switch Moving End Of Visual Selection](vim/switch-moving-end-of-visual-selection.md)\n- [Tabs To Spaces](vim/tabs-to-spaces.md)\n- [The Vim Info File](vim/the-vim-info-file.md)\n- [Toggle Absolute And Relative Paths In BufExplorer](vim/toggle-absolute-and-relative-paths-in-bufexplorer.md)\n- [Toggling Syntax Highlighting](vim/toggling-syntax-highlighting.md)\n- [Turning Off Search Highlighting](vim/turning-off-search-highlighting.md)\n- [Unloading A Buffer](vim/unloading-a-buffer.md)\n- [Use Active Window With BufExplorer](vim/use-active-window-with-bufexplorer.md)\n- [Use The Terminal Inside A Vim Session](vim/use-the-terminal-inside-a-vim-session.md)\n- [Using vim-surround With A Visual Selection](vim/using-vim-surround-with-a-visual-selection.md)\n- [Verbose Commits With Fugitive](vim/verbose-commits-with-fugitive.md)\n- [View Commit History of a File](vim/view-commit-history-of-a-file.md)\n- [View The Current File In GitHub](vim/view-the-current-file-in-github.md)\n- [Viewing Man Pages with man.vim](vim/viewing-man-pages-with-man-vim.md)\n- [Vim Without The Extras](vim/vim-without-the-extras.md)\n- [What Is On The Runtime Path?](vim/what-is-on-the-runtime-path.md)\n- [Whole Line Auto-Completion](vim/whole-line-auto-completion.md)\n- [Wrap With Some Room](vim/wrap-with-some-room.md)\n\n### VSCode\n\n- [Add The VSCode CLI To Your Path](vscode/add-the-vscode-cli-to-your-path.md)\n- [Advance Through Search Results](vscode/advance-through-search-results.md)\n- [Enable Breadcrumbs For Version 1.26 Release](vscode/enable-breadcrumbs-for-version-126-release.md)\n- [Find The Location Of User Settings JSON File](vscode/find-the-location-of-user-settings-json-file.md)\n- [Jump To Problems In The Current File](vscode/jump-to-problems-in-the-current-file.md)\n- [Open An Integrated Terminal Window](vscode/open-an-integrated-terminal-window.md)\n- [Open File On Remote Like GitHub](vscode/open-file-on-remote-like-github.md)\n- [Pop Open The Quick Fix Window](vscode/pop-open-the-quick-fix-window.md)\n- [Step Through Project-Wide Search Results](vscode/step-through-project-wide-search-results.md)\n- [Synchronize Vim Clipboard With System Clipboard](vscode/synchronize-vim-clipboard-with-system-clipboard.md)\n- [Toggle Between Terminals](vscode/toggle-between-terminals.md)\n- [Turn Off Display Of Tabs For Files](vscode/turn-off-display-of-tabs-for-files.md)\n\n### Webpack\n\n- [Better Module Imports With Aliases](webpack/better-module-imports-with-aliases.md)\n- [Debugging With Full Source Maps](webpack/debugging-with-full-source-maps.md)\n- [Run ESLint As A Preloader](webpack/run-eslint-as-a-preloader.md)\n- [Specify Port Of CRA's Webpack Dev Server](webpack/specify-port-of-cra-webpack-dev-server.md)\n- [Use A Specific Config File](webpack/use-a-specific-config-file.md)\n\n### Workflow\n\n- [Add Hotkeys For Specific Raycast Extensions](workflow/add-hotkeys-for-specific-raycast-extensions.md)\n- [Add Subscriber To Kit Form Via API](workflow/add-subscriber-to-kit-form-via-api.md)\n- [Add Subtitles To Existing Mux Video Asset](workflow/add-subtitles-to-existing-mux-video-asset.md)\n- [Access 1Password Credential From CLI](workflow/access-1password-credential-from-cli.md)\n- [Allow Key-Repeating With Cursor](workflow/allow-key-repeating-with-cursor.md)\n- [Break Justfile Into Separate Hidden Steps](workflow/break-justfile-into-separate-hidden-steps.md)\n- [Change Window Name In iTerm](workflow/change-window-name-in-iterm.md)\n- [Configure Email Redirect With Cloudflare](workflow/configure-email-redirect-with-cloudflare.md)\n- [Control Media With Drop Keyboard](workflow/control-media-with-drop-keyboard.md)\n- [Convert An ePub Document To PDF On Mac](workflow/convert-an-epub-document-to-pdf-on-mac.md)\n- [Create A Local Sanity Dataset Backup](workflow/create-a-local-sanity-dataset-backup.md)\n- [Create A Public URL For A Local Server](workflow/create-a-public-url-for-a-local-server.md)\n- [Create Todo Items In Logseq](workflow/create-todo-items-in-logseq.md)\n- [Do Project Time Tracking From The CLI](workflow/do-project-time-tracking-from-the-cli.md)\n- [Enable Dev Tools For Safari](workflow/enable-dev-tools-for-safari.md)\n- [Forward Stripe Events To Local Server](workflow/forward-stripe-events-to-local-server.md)\n- [Get URL For GitHub User Profile Photo](workflow/get-url-for-github-user-profile-photo.md)\n- [Get Your Public IP Address](workflow/get-your-public-ip-address.md)\n- [Import A Github Project Into CodeSandbox](workflow/import-a-github-project-into-codesandbox.md)\n- [Interactively Kill A Process With fkill](workflow/interactively-kill-a-process-with-fkill.md)\n- [Open Slack's Keyboard Shortcuts Reference Panel](workflow/open-slacks-keyboard-shortcuts-reference-panel.md)\n- [Pop Videos Out As Picture-in-Picture](workflow/pop-videos-out-as-picture-in-picture.md)\n- [Prune The Excess From node_modules](workflow/prune-the-excess-from-node-modules.md)\n- [Rotate An Image To Be Oriented Upright](workflow/rotate-an-image-to-be-oriented-upright.md)\n- [See Overlaps For A Set Of Time Zones](workflow/see-overlaps-for-a-set-of-time-zones.md)\n- [Send A Message To A Discord Channel](workflow/send-a-message-to-a-discord-channel.md)\n- [Send A PDF To Your Kindle](workflow/send-a-pdf-to-your-kindle.md)\n- [Set Recurring Reminders In Slack](workflow/set-recurring-reminders-in-slack.md)\n- [Show Linting Errors In Zed](workflow/show-linting-errors-in-zed.md)\n- [Temporarily Hide CleanShot X Capture Previews](workflow/temporarily-hide-cleanshot-x-capture-previews.md)\n- [Toggle Between Stories In Storybook](workflow/toggle-between-stories-in-storybook.md)\n- [Update asdf Plugins With Latest Package Versions](workflow/update-asdf-plugins-with-latest-package-versions.md)\n- [View A Nicely-Formatted CSV In Terminal](workflow/view-a-nicely-formatted-csv-in-terminal.md)\n- [View The PR For The Current GitHub Branch](workflow/view-the-pr-for-the-current-github-branch.md)\n\n### XState\n\n- [Always Use Inline Functions With Assign](xstate/always-use-inline-functions-with-assign.md)\n- [Custom Jest Matcher For XState Machine States](xstate/custom-jest-matcher-for-xstate-machine-states.md)\n- [Define Event That Does Internal Self Transition](xstate/define-event-that-does-internal-self-transition.md)\n- [Events Stop Propagating Once Handled](xstate/events-stop-propagating-once-handled.md)\n- [Inline Actions vs Actions In Machine Options](xstate/inline-actions-vs-actions-in-machine-options.md)\n- [Make Immediate And Delayed Transitions](xstate/make-immediate-and-delayed-transitions.md)\n- [Simple States And Composite States](xstate/simple-states-and-composite-states.md)\n- [Start A Machine In A Specific State](xstate/start-a-machine-in-a-specific-state.md)\n- [Use An XState Machine With React](xstate/use-an-xstate-machine-with-react.md)\n\n### YAML\n\n- [Create Multi-Line Strings Without The Line Breaks](yaml/create-multi-line-strings-without-the-line-breaks.md)\n- [YAML Is A Superset Of JSON](yaml/yaml-is-a-superset-of-json.md)\n\n### Zod\n\n- [Check If An Object Is Empty With Zod](zod/check-if-an-object-is-empty-with-zod.md)\n- [Create A Schema That Matches On Any Object](zod/create-a-schema-that-matches-on-any-object.md)\n- [Create Union Type Of Nearly Identical Objects](zod/create-union-type-of-nearly-identical-objects.md)\n- [Get Readable Errors From Schema Parse](zod/get-readable-errors-from-schema-parse.md)\n- [Incorporate Existing Type Into Zod Schema](zod/incorporate-existing-type-into-zod-schema.md)\n- [Set Custom Error Message For Nonempty Array](zod/set-custom-error-message-for-nonempty-array.md)\n\n### Zsh\n\n- [A Better Way To Reload ZSH Configuration](zsh/a-better-way-to-reload-zsh-configuration.md)\n- [Add To The Path Via Path Array](zsh/add-to-the-path-via-path-array.md)\n- [Create And Jump Into A Directory](zsh/create-and-jump-into-a-directory.md)\n- [Link A Scalar To An Array](zsh/link-a-scalar-to-an-array.md)\n- [Use A Space To Exclude Command From History](zsh/use-a-space-to-exclude-command-from-history.md)\n\n## Usage\n\nThe `.vimrc` file for this project contains a function `CountTILs` that can\nbe invoked with `<leader>c`. This will do a substitution count of the\ncurrent number of TILs and display the result in the command tray.\n\n## About\n\nI've written more about how this repo came to be in [How I Built a Learning\nMachine](https://dev.to/jbranchaud/how-i-built-a-learning-machine-45k9) and [A\nDecade of TILs](https://www.visualmode.dev/a-decade-of-tils).\n\nI shamelessly stole this idea from\n[thoughtbot/til](https://github.com/thoughtbot/til).\n\n## Other TIL Collections\n\n* [Today I Learned by Hashrocket](https://til.hashrocket.com)\n* [jwworth/til](https://github.com/jwworth/til)\n* [til.simonwillison.net](https://til.simonwillison.net/)\n\n## License\n\n&copy; 2015-2026 Josh Branchaud\n\nThis repository is licensed under the MIT license. See `LICENSE` for\ndetails.\n"
  },
  {
    "path": "Taskfile.yml",
    "content": "version: '3'\n\nvars:\n  NOTES_DIR: notes\n  NOTES_FILE: '{{.NOTES_DIR}}/NOTES.md'\n  EDITOR: '{{.EDITOR | default \"nvim\"}}'\n\ntasks:\n  default:\n    desc: Show available commands\n    cmds:\n      - task --list\n\n  notes:\n    desc: Interactive picker for notes tasks\n    cmds:\n      - |\n        TASK=$(task --list | grep \"^\\* notes:\" | sed 's/^\\* notes://' | sed 's/\\s\\+/ - /' | fzf --prompt=\"Select notes task: \" --height=40% --reverse) || true\n        if [ -n \"$TASK\" ]; then\n          TASK_NAME=$(echo \"$TASK\" | awk '{print $1}' | sed 's/:$//')\n          task notes:$TASK_NAME\n        fi\n    interactive: true\n    silent: true\n\n  notes:edit:\n    desc: All-in-one edit, commit, and push notes\n    cmds:\n      - task notes:open\n      - task notes:push\n\n  notes:sync:\n    desc: Sync latest changes from the notes submodule\n    cmds:\n      - cd {{.NOTES_DIR}} && git checkout main && git pull\n    silent: false\n\n  notes:open:\n    desc: Opens NOTES.md (syncs latest changes first) in default editor\n    deps: [notes:sync]\n    cmds:\n      - $EDITOR {{.NOTES_FILE}}\n    interactive: true\n\n  notes:push:\n    desc: Commit and push changes to notes submodule\n    dir: '{{.NOTES_DIR}}'\n    cmds:\n      - git add NOTES.md\n      - git commit -m \"Update notes - $(date '+%Y-%m-%d %H:%M')\"\n      - git pull --rebase\n      - git push\n    status:\n      - git diff --exit-code NOTES.md\n    silent: false\n\n  notes:status:\n    desc: Check status of notes submodule\n    dir: '{{.NOTES_DIR}}'\n    cmds:\n      - git status\n\n  notes:diff:\n    desc: Show uncommitted changes in notes\n    dir: '{{.NOTES_DIR}}'\n    cmds:\n      - git diff NOTES.md\n\n  notes:log:\n    desc: Show recent commit history for notes\n    dir: '{{.NOTES_DIR}}'\n    cmds:\n      - git log --oneline -10\n"
  },
  {
    "path": "ack/ack-bar.md",
    "content": "# ack --bar\n\nThe [`ack`](https://beyondgrep.com/) utility has a fun Easter egg that dumps\na Star Wars meme to the command line. Give it a try.\n\n```bash\n$ ack --bar\n```\n\nSee `man ack` for more details.\n"
  },
  {
    "path": "ack/case-insensitive-search.md",
    "content": "# Case-Insensitive Search\n\nUse the `-i` flag to perform a case-insensitive search with `ack`.\n\n```bash\n$ ack -i easter\n\nack/ack-bar.md\n3:The [`ack`](https://beyondgrep.com/) utility has a fun Easter egg that dumps\n\npostgres/configure-the-timezone.md\n18:Eastern time.\n```\n\nIf you are a Vim user, you may be familiar with `smart-case`. The\n`--smart-case` option is a related Ack feature worth checking out.\n\nSee `man ack` for more details.\n"
  },
  {
    "path": "ack/list-available-file-types.md",
    "content": "# List Available File Types\n\nThe `ack` utility allows you to filter the searched files based on file\ntype. If you'd like to know all of the file types available, you can use the\n`--help-types` flag. This will include file types you've specified in your\n`.ackrc` file.\n\nHere is a sample of some of the output.\n\n```\n$ ack --help-types\n    ...\n    --[no]css          .css .less .scss\n    --[no]dart         .dart\n    --[no]delphi       .pas .int .dfm .nfm .dof .dpk .dproj .groupproj .bdsgroup .bdsproj\n    --[no]elisp        .el\n    --[no]elixir       .ex .exs\n    --[no]erlang       .erl .hrl\n    --[no]fortran      .f .f77 .f90 .f95 .f03 .for .ftn .fpp\n    --[no]go           .go\n    --[no]groovy       .groovy .gtmpl .gpp .grunit .gradle\n    --[no]haskell      .hs .lhs\n    --[no]hh           .h\n    --[no]html         .html .mustache .handlebars .tmpl\n    --[no]jade         .jade\n    --[no]java         .java .properties\n    --[no]js           .js\n    ...\n```\n\nSee `man ack` for more details.\n"
  },
  {
    "path": "ansible/loop-over-a-list-of-dictionaries.md",
    "content": "# Loop Over A List Of Dictionaries\n\nAnsible's `loop` can iterate over a list of dictionaries in a task. That task\nwill be evaluated for each `item` in that list. Since each `item` is a\ndictonary, we can access the fields on the `item` directory with dot notation —\n`item.name`.\n\nHere is what this would look like for a task that is setting up authorized SSH\nkeys.\n\n```yaml\n---\n- hosts: all\n  vars:\n    dev_users:\n      - name: alice\n        ssh_key_url: https://github.com/dev1.keys\n      - name: bob\n        ssh_key_url: https://github.com/dev2.keys\n  tasks:\n    - name: Set authorized keys taken from url\n      ansible.posix.authorized_key:\n        user: \"{{ item.name }}\"\n        state: present\n        key: \"{{ item.ssh_key_url }}\"\n      loop: \"{{ dev_users }}\"\n```\n\nNotice the `loop` over the `dev_users` variable gives us access to an `item` in\nthe task. Because each `item` has a `name` and an `ssh_key_url`, we can access\nthose fields in the task.\n\n[source](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_loops.html#standard-loops)\n"
  },
  {
    "path": "astro/generate-types-for-a-content-collection.md",
    "content": "# Generate Types For A Content Collection\n\nLet's say I'm using Astro to publish posts via markdown. One of the best ways\nto do that is as a _Content Collection_. The posts will live in `src/content`\nprobably under a `posts` directory. Plus a config file will define the\ncollection and specify validations for the frontmatter.\n\n```typescript\n// src/content/config.ts\nimport { defineCollection, z } from 'astro:content';\n\nconst postsCollection = defineCollection({\n  schema: z.object({\n    title: z.string(),\n    description: z.string(),\n    tags: z.array(z.string())\n  })\n});\n\nexport const collections = {\n  'posts': postsCollection,\n};\n```\n\nWhen I first add this to my project and get the collection, it won't know what\nthe types are.\n\n```astro\n---\nimport { getCollection } from \"astro:content\";\n\nexport async function getStaticPaths() {\n  const blogEntries = await getCollection(\"posts\");\n  //    ^^^ any\n\n  return blogEntries.map((entry) => ({\n    params: { slug: entry.slug },\n    props: { entry },\n  }));\n}\n---\n```\n\nI can tell Astro to generate a fresh set of types for things like content\ncollections by running the [`astro sync`\ncommand](https://docs.astro.build/en/reference/cli-reference/#astro-sync).\n\n```bash\n$ npm run astro sync\n```\n\nThis updates auto-generated files under the `.astro` directory which get pulled\nin to your project's `env.d.ts` file.\n\nAll of these types will also be synced anytime I run `astro dev`, `astro\nbuild`, or `astro check`.\n"
  },
  {
    "path": "astro/markdown-files-are-of-type-markdown-instance.md",
    "content": "# Markdown Files Are Of Type MarkdownInstance\n\nOne of the things Astro excels at is rendering markdown files as HTML pages in\nyour site. And at some point we'll want to access a listing of those markdown\nfiles in order to do something like display a list of them on an index page.\nFor that, we'll use\n[`Astro.glob()`](https://docs.astro.build/en/reference/api-reference/#astroglob).\n\n```typescript\n---\nconst allPosts = await Astro.glob(\"../posts/*.md\");\n---\n\n<ul>\n  {allPosts.map(post => {\n    return <Post title={post.frontmatter.title} slug={post.frontmatter.slug} />\n  })}\n</ul>\n```\n\nThis looks great, but we'll run into a type error on that first line:\n`'allPosts' implicitly has type 'any'`. We need to declare the type\nof these post instances that are being read-in by Astro.\n\nThese are of [type\n`MarkdownInstance`](https://docs.astro.build/en/reference/api-reference/#markdown-files).\nThat's a generic though, so we need to tell it a bit more about the shape of a\npost.\n\n```typescript\nimport type { MarkdownInstance } from \"astro\";\n\nexport type BarePost = {\n  layout: string;\n  title: string;\n  slug: string;\n  tags: string[];\n};\n\nexport type Post = MarkdownInstance<BarePost>;\n```\n\nWe can then update that first line:\n\n```typescript\nconst allPosts: Post[] = await Astro.glob(\"../posts/*.md\");\n```\n\nAlternatively, you can specify the generic on `glob`:\n\n```typescript\nconst allPosts = await Astro.glob<BarePost>(\"../posts/*.md\");\n```\n"
  },
  {
    "path": "aws/aws-cli-requires-groff-executable.md",
    "content": "# AWS CLI Requires Groff Executable\n\nI have the AWS CLI installed on this machine, but when I went to run certain\ncommands like `aws logs tail my_log_group` or even `aws logs tail help`, I'd\nget the following error:\n\n```\n$ aws logs tail help\n\nCould not find executable named 'groff'\n```\n\nThis may only be an issue on MacOS Ventura for older versions of the CLI, per\n[this PR](https://github.com/aws/aws-cli/pull/7413):\n\n> The CLI's help commands are currently broken on macOS Ventura because Ventura has replaced groff with mandoc. This PR fixes the issue by falling back on mandoc if groff doesn't exist in the path.\n\nThere are two ways of dealing with this. One would be to install the missing\ndependency, [`groff`](https://www.gnu.org/software/groff/):\n\n```bash\n$ brew install groff\n```\n\nThe other is to update the AWS CLI to one that falls back to `mandoc`.\nDepending on how you originally installed the AWS CLI, you can either [follow\ntheir official install/upgrade\ninstructions](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html),\n`pip install --upgrade awscli`, or upgrade view homebrew (`brew upgrade\nawscli`).\n"
  },
  {
    "path": "aws/find-and-follow-server-logs.md",
    "content": "# Find And Follow Server Logs\n\nLet's say you are authenticated with the AWS CLI and have the appropriate\nCloudWatch permissions. You have a few services running in production with\nassociated logs. One of those is a Rails server.\n\nWe want to run `aws logs tail`, but first we check how that command works.\n\n```bash\n$ aws logs tail help\n```\n\nWe see a bunch of options, but the only required one is `group_name` (\"The name\nof the CloudWatch Logs group.\"). We may also notice the `--follow` flag which\nwe'll want to use as well to keep incoming logs flowing.\n\nWe need to determine the log group name for the Rails server. We can do that\nfrom the CLI as well (no need to dig into the web UI).\n\n```bash\n$ aws logs describe-log-groups\n\n{\n    \"logGroups\": [\n        {\n            \"logGroupName\": \"/aws/codebuild/fc-rails-app-abcefg-123456\",\n            \"creationTime\": 1739476650823,\n            \"metricFilterCount\": 0,\n            \"arn\": \"arn:aws:logs:us-east-2:123456789:log-group:/aws/codebuild/fc-rails-app-abcefg-123456:*\",\n            \"storedBytes\": 65617,\n            \"logGroupClass\": \"STANDARD\",\n            \"logGroupArn\": \"arn:aws:logs:us-east-2:123456789:log-group:/aws/codebuild/fc-rails-app-abcefg-123456\"\n        },\n        ...\n    ]\n}\n```\n\nBecause the group name is descriptive enough, we can find the log group we are\ninterested in: `/aws/codebuild/fc-rails-app-abcefg-123456`.\n\nNow we know what we want to `tail`.\n\n```bash\n$ aws logs tail /aws/codebuild/fc-rails-app-abcefg-123456 --follow\n```\n"
  },
  {
    "path": "aws/list-rds-snapshots-with-matching-identifier-prefix.md",
    "content": "# List RDS Snapshots With Matching Identifier Prefix\n\nI'm working on a script that manually creates a snapshot which it will then\nrestore to a temporary database that I can scrub and dump. The snapshots that\nthis script takes are _manual_ and they are named with identifiers that have a\ndefining prefix (`dev-snapshot-`). Besides the few snapshots created by this\nscript, there are tons of automated snapshots that RDS creates for\nbackup/recovery purposes.\n\nI want to list any snapshots that have been created by the script. I can do\nthis with the `describe-db-snapshots` command and some filters.\n\n```bash\n$ aws rds describe-db-snapshots \\\n  --snapshot-type manual \\\n  --query \"DBSnapshots[?starts_with(DBSnapshotIdentifier, 'dev-snapshot-')].DBSnapshotIdentifier\" \\\n  --no-cli-pager\n\n[\n    \"dev-snapshot-20250327-155355\"\n]\n```\n\nThere are two key pieces. The `--snapshot-type manual` filter excludes all\nthose automated snapshots. The `--query` both filters to any snapshots whose\nidentifier `?starts_with` the prefix `dev-snapshot-` and then refines the\noutput to just the `DBSnapshotIdentifier` instead of the entire JSON object.\n\n[source](https://docs.aws.amazon.com/cli/latest/reference/rds/describe-db-snapshots.html)\n"
  },
  {
    "path": "aws/output-cli-results-in-different-formats.md",
    "content": "# Output CLI Results In Different Formats\n\nThe AWS CLI can output the results of commands in three different formats.\n\n- Text\n- JSON\n- Table\n\nThe _default_ output format for my AWS CLI is currently configured to `json`.\n\n```bash\n$ aws configure get output\njson\n```\n\nI can either accept the default or I can override it with the `--output` flag.\n\n```bash\n$ aws rds describe-db-instances \\\n  --query 'DBInstances[*].Endpoint' \\\n  --no-cli-pager\n[\n    {\n        \"Address\": \"fc-database-abcefg-ab1c23de.asdfgh4zxcvb.us-east-2.rds.amazonaws.com\",\n        \"Port\": 5432,\n        \"HostedZoneId\": \"A1BCDE2FG345H6\"\n    }\n]\n\n$ aws rds describe-db-instances \\\n  --query 'DBInstances[*].Endpoint' \\\n  --no-cli-pager \\\n  --output table\n----------------------------------------------------------------------------------------------------\n|                                        DescribeDBInstances                                       |\n+-----------------------------------------------------------------------+-----------------+--------+\n|                                Address                                |  HostedZoneId   | Port   |\n+-----------------------------------------------------------------------+-----------------+--------+\n|  fc-database-abcefg-ab1c23de.asdfgh4zxcvb.us-east-2.rds.amazonaws.com |  A1BCDE2FG345H6 |  5432  |\n+-----------------------------------------------------------------------+-----------------+--------+\n\n$ aws rds describe-db-instances \\\n  --query 'DBInstances[*].Endpoint' \\\n  --no-cli-pager \\\n  --output text\nfc-database-abcefg-ab1c23de.asdfgh4zxcvb.us-east-2.rds.amazonaws.com    A1BCDE2FG345H6  5432\n```\n\n[source](https://docs.aws.amazon.com/cli/v1/userguide/cli-usage-output-format.html)\n"
  },
  {
    "path": "aws/sign-up-user-with-email-and-password.md",
    "content": "# Sign Up User With Email And Password\n\n[AWS Amplify](https://aws.amazon.com/amplify/)\n[Auth](https://docs.amplify.aws/lib/auth/getting-started/q/platform/js) offers\nboth federated and username/password based authentication. Though the docs\naren't clear, the required `username` parameter can be used as the email field\nwith the [`signUp`\nAPI](https://aws-amplify.github.io/amplify-js/api/classes/authclass.html#signup).\n\n```javascript\nimport { Auth } from 'aws-amplify';\n\nasync function signUp({ email, password }) {\n  try {\n    const user = await Auth.signUp({\n      username: email,\n      password,\n      attributes: {},\n    });\n    console.log({ user });\n  } catch (error) {\n    console.log('error signing up:', error);\n  }\n}\n```\n\nOnce the user has entered an email and password into the Sign Up form, those\nvalues can be passed to this `signUp` function. The `email` value is passed as\nthe `username` and the `password` goes in as is.\n\nAmplify Auth will interpret the `username` as an email and register it as the\ncontact email for this user.\n"
  },
  {
    "path": "aws/ssh-into-an-ecs-container.md",
    "content": "# SSH Into An ECS Container\n\nIn [Connect To Production Rails Console on AWS /\nFlightcontrol](https://www.visualmode.dev/connect-to-production-rails-console-aws-flightcontrol),\nI went into full detail about how to access `rails console` for a production\nRails app running in an ECS container.\n\nA big part of that process was establishing an SSH connection to the ECS container.\n\nTo do that, I need to know my region, container ID, and task ID. I can get the\nfirst two by listing my clusters and finding the cluster/container that houses\nthe Rails app.\n\n```bash\n$ aws ecs list-clusters\n{\n    \"clusterArns\": [\n        \"arn:aws:ecs:us-east-2:123:cluster/rails-app-abc123\"\n    ]\n}\n```\n\nThe region then is `us-east-2` and the container ID is `rails-app-abc123`.\n\nI can use that to find the task ID:\n\n```bash\n$ aws ecs list-tasks --region us-east-2 --cluster rails-app-abc123\n{\n    \"taskArns\": [\n        \"arn:aws:ecs:us-east-2:123:task/rails-app-abc123/8526b3191d103bb1ff90c65a655ad004\"\n    ]\n}\n```\n\nThe task ID is the final portion of the URL:\n`8526b3191d103bb1ff90c65a655ad004`.\n\nPutting this all together I can SSH into the ECS container with a bash profile\nlike so:\n\n```bash\n$ aws ecs execute-command \\\n  --region us-east-2 \\\n  --cluster rails-app-abc123 \\\n  --container rails-app-abc123 \\\n  --task 8526b3191d103bb1ff90c65a655ad004 \\\n  --interactive \\\n  --command \"/bin/bash\"\n```\n"
  },
  {
    "path": "aws/turn-off-output-pager-for-a-command.md",
    "content": "# Turn Off Output Pager For A Command\n\nIt is not uncommon for an AWS CLI command to return a ton of output. When that\nhappens, it is nice that the results end up in pager program (like `less`)\nwhere you can search and review them, copy a value of interest, and then exit.\nThe pager prevents that wall of output from cluttering your terminal history.\n\nHowever, sometimes I am running a command that I know is going to return a\nsmall result. I'd rather have the results go to stdout where I can see them in\nthe terminal history rather than to an ephemeral pager.\n\nFor that situation I can tack on the `--no-cli-pager` flag.\n\n```bash\n$ aws rds describe-db-instances \\\n  --query 'DBInstances[*].EngineVersion' \\\n  --output json \\\n  --no-cli-pager\n\n[\n    \"13.15\",\n    \"16.8\"\n]\n```\n\nHere I've asked the AWS CLI to tell me the engine versions of all my RDS\nPostgres databases. Because I know the results are only going to include a\ncouple results for my couple of DBs, I'd like to skip the pager —\n`--no-cli-pager`.\n\nThough I think it is better to do this on a case by case basis, it is also\npossible to turn off the pager via the CLI configuration file.\n\n```bash\n$ aws configure set cli_pager \"\"\n```\n\n[source](https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-pagination.html#cli-usage-pagination-clientside)\n"
  },
  {
    "path": "aws/use-specific-aws-profile-with-cli.md",
    "content": "# Use Specific AWS Profile With CLI\n\nI have multiple AWS profiles authenticated with the AWS CLI. For some projects\nI need to use the `default` one and for others I need to use the other.\n\nFirst, I can list the available profiles like so:\n\n```bash\n$ aws configure list-profiles\ndefault\ndev-my-app\n```\n\nFor one-off commands I can specify the profile for any AWS CLI command using\nthe `--profile` flag.\n\n```bash\n$ aws ecs list-clusters --profile josh-visualmode\n```\n\nHowever, I don't want to have to specify that flag every time when I'm working\non a specific project. Instead I can specify the profile with an environment\nvariable. The [`direnv`](https://direnv.net/) tool is a great way to do this on\na per-project / per-directory basis.\n\nI can create or update the `.envrc` file (assuming I have `direnv` installed)\nadding the following line (and re-allowing the changed file):\n\n```\n# .envrc\nexport AWS_PROFILE=dev-my-app\n```\n\nNow, any AWS command I issue from that directory or its subdirectories will use\nthat profile by default.\n\n[source](https://docs.aws.amazon.com/cli/v1/userguide/cli-configure-files.html#cli-configure-files-using-profiles)\n"
  },
  {
    "path": "bash/edit-the-current-command-prompt.md",
    "content": "# Edit The Current Command Prompt\n\nA neat feature of `bash` is the ability to open whatever the current state of\nthe command prompt is into your default editor.\n\nLet's say we have a really long command that we've just tried to run, but it\nfailed and we need to make a small change somewhere in the middle. Instead of\nholding the left arrow key for 30 seconds, we can instead hit `CTRL-X CTRL-E`.\n\nThis pops us into our `EDITOR` (or maybe `VISUAL`, not sure which). In my case,\nthat is `nvim`. I now have access to all the features I'm used to in `nvim` for\nquickly navigating to and editing, searching and replacing, or whatever.\n\nOnce I've got the command how I like it, I can save and exit (`:wq`) and the\nupdated command will be executed.\n\nThis is similar to [the `fc` builtin](unix/fix-previous-command-with-fc.md),\nwhich also happens to be available for `zsh`.\n"
  },
  {
    "path": "brew/clean-up-your-brew-installations.md",
    "content": "# Clean Up Your Brew Installations\n\nOver time as you upgrade brew-installed programs and make changes to your\n`Brewfile`, your machine will have artifacts left behind that you no longer\nneed.\n\nPeriodically, it is good to clean things up.\n\nFirst, you can get a summary of stale and outdated files that brew has\ninstalled. Use the `--dry-run` flag.\n\n```bash\n$ brew cleanup --dry-run\n```\n\nIf you feel good about what you see in the output, then give things a clean.\n\n```bash\n$ brew cleanup\n```\n\nSecond, if you are using a `Brewfile` to manage what `brew` installs, then you\ncan instruct `brew` to uninstall any dependencies that aren't specified in that\nfile.\n\nBy default it operates as a dry run and the `--force` flag will be needed to\nactually do the cleanup. And specify the filename if it doesn't match the\ndefault of `Brewfile`.\n\n```bash\n$ brew bundle cleanup --file=Brewfile.personal\n```\n\nIf the output looks good, then force the cleanup:\n\n```bash\n$ brew bundle cleanup --force --file=Brewfile.personal\n```\n\nSee `brew cleanup --help` and `brew bundle --help` for more details.\n"
  },
  {
    "path": "brew/configure-brew-environment-variables.md",
    "content": "# Configure Brew Environment Variables\n\nThe `brew` CLI can be configured with a ton of different environment variables.\nA full listing of those can be found in the [Environment section of their\ndocs](https://docs.brew.sh/Manpage#environment).\n\nIf you want to change the defaults of any of those values, you can either set\nthem directly in your environment:\n\n```bash\n$ set HOMEBREW_BAT=1\n```\n\nOr you can set them in a more dedicated place like one of Homebrew's\nenvironment files. There are a couple possible locations for these files. I\nprefer to use `$HOME/.homebrew/brew.env` (i.e. `~/.homebrew/brew.env`).\n\n```\nHOMEBREW_BAT=1\n```\n\nThis file and directly likely don't exist, so you may have to set them up the\nfirst time:\n\n```\n$ mkdir $HOME/.homebrew\n$ touch $HOME/.homebrew/brew.env\n```\n"
  },
  {
    "path": "brew/export-list-of-everything-installed-by-brew.md",
    "content": "# Export List Of Everything Installed By Brew\n\nIf you're on a Mac using Homebrew to install various tools and utilities, there\nmay come a time when you want a listing of what is installed.\n\nRun this command:\n\n```bash\n$ brew bundle dump\n```\n\nIt may take 10 or so seconds. When it is done, you'll have a `Brewfile` in your\ncurrent directory.\n\nOpen it up and you'll see a bunch of lines like the following:\n\n```\ntap \"heroku/brew\"\ntap \"homebrew/bundle\"\ntap \"homebrew/services\"\ntap \"mongodb/brew\"\ntap \"planetscale/tap\"\ntap \"stripe/stripe-cli\"\nbrew \"asdf\"\nbrew \"bat\"\nbrew \"direnv\"\nbrew \"entr\"\nbrew \"exa\"\nbrew \"fd\"\nbrew \"ffmpeg\"\nbrew \"fx\"\nbrew \"fzf\"\nbrew \"gcc\"\nbrew \"gh\"\nbrew \"planetscale/tap/pscale\"\nbrew \"stripe/stripe-cli/stripe\"\ncask \"1password-cli\"\nvscode \"ms-playwright.playwright\"\nvscode \"ms-vsliveshare.vsliveshare\"\nvscode \"prisma.prisma\"\n```\n\nNotice there are `tap`, `brew`, `cask`, and even `vscode` directives.\n\nThis is a file you could export and then run on a 'new' machine to install all\nthe programs you're used to having available on your current machine.\n\n[source](https://danmunoz.com/setting-up-a-new-computer-with-homebrew/)\n"
  },
  {
    "path": "brew/install-from-nonstandard-brewfile.md",
    "content": "# Install From Nonstandard Brewfile\n\nWhen you want to install the packages listed in the `Brewfile` for your current\nproject (or dotfiles), you can run:\n\n```bash\n$ brew bundle\n```\n\nAnd `brew` knows to look for and use the `Brewfile` in the current directory.\n\nIf, however, you are trying to run `brew bundle` for a `Brewfile` located\nsomewhere besides the current directory *OR* you want to target a file with a\nnon-standard name (like\n[`Brewfile.personal`](https://github.com/jbranchaud/dotfiles/blob/main/Brewfile.personal)),\nthen you can use the `--file` flag.\n\n```bash\n$ brew bundle --file Brewfile.personal\n```\n\nThis is what I do [here in my `dotfiles`\nrepo](https://github.com/jbranchaud/dotfiles/blob/b053f6251cae7ed52f698fc2a2c40ba82c5881b0/installer/mac-setup.sh#L42-L48).\n\nSee `man brew` and find the section on `brew bundle` for more details.\n"
  },
  {
    "path": "brew/install-go-packages-in-brewfile.md",
    "content": "# Install Go Packages In Brewfile\n\nTypically my `Brewfile` is only full of `brew` and `cask` directives. That's\nstarting to change now that `brew` supports installing Go packages listed in the\n`Brewfile`.\n\nUse the `go` directive and the URL to the hosted Go package.\n\nHere is an example of a `Brewfile` that includes a `cask`, `brew`, and `go`\ndirective.\n\n```\n# screen resolution tool\ncask \"betterdisplay\"\n\n# Mac keychain management, gpg key\nbrew \"pinentry-mac\"\n\n# Sanitized production Postgres dumps\ngo \"github.com/jackc/pg_partialcopy\"\n```\n\nI've recently added the exact package from above to my [`dotfiles`\nrepo](https://github.com/jbranchaud/dotfiles/commit/e83e9d19504f0e2f95eba33123f907f999bf865e).\n\nHere is the [PR to `brew`](https://github.com/Homebrew/brew/pull/20798) where\nthis functionality was added back in October of 2025.\n"
  },
  {
    "path": "brew/list-all-services-managed-by-brew.md",
    "content": "# List All Services Managed By Brew\n\nDaemonized services, such as PostgreSQL, can be installed and managed with\nHomebrew. Under the hood `brew` uses `launchctl` on Mac to manage these\nservices — i.e. starting, restarting, and stopping them.\n\nAssuming you've already installed some services, you can run `brew services\nlist` to see what services there are and what their current status is.\n\n```bash\n$ brew services list\nName          Status  User       File\nmailhog       none\nmysql         none\npostgresql@11 started jbranchaud ~/Library/LaunchAgents/homebrew.mxcl.postgresql@11.plist\npostgresql@13 none\npostgresql@16 none\nunbound       none\n```\n\nThis is the default behavior if you just run `brew services` without a subcommand.\n\nThis is helpful if you are, for instance, trying to see which PostgreSQL server\nversion you are currently running and which other ones are available to run. I\nmight then issue a `stop` to `postgresql@11` so that I can then `start` the\n`postgresql@16` service.\n\nSee `brew services --help` for more details.\n"
  },
  {
    "path": "chrome/access-a-value-logged-to-the-console.md",
    "content": "# Access A Value Logged To The Console\n\nDid your app just log an object to the dev tools console and you'd like to\ninteract with that object? It's not straightforward, but you can do it.\n\nAssuming you already have dev tools opened to the _console_ tab, right click\non the value that has been logged to the console. Select the _Store as\nGlobal Variable_ option. This will re-log the value assigning it to the\n`temp1` variable.\n\nYou can now reference that object as `temp1` accessing its values and\ncalling functions.\n\nYou can even do this with multiple logged values, each subsequent one will\nbe assigned incrementing variable names: `temp2`, `temp3`, etc.\n\n[source](https://stackoverflow.com/questions/15895579/access-last-logged-value-in-chrome-console)\n"
  },
  {
    "path": "chrome/chrome-supports-many-unix-keyboard-shortcuts.md",
    "content": "# Chrome Supports Many Unix Keyboard Shortcuts\n\nIn a Unix environment, you can use keyboard shortcuts to do a variety of things\nmore efficiently. For instance, hitting `ctrl-a` moves the cursor to the\nbeginning of the line. Conversely, `ctrl-e` moves the cursor to the end of the\nline. Another fun one is `ctrl-u` which erases from the cursor to the beginning\nof the line.\n\nLearning these doesn't only have value when you are logged into some remote\nserver. There are many apps that support a variety of these shortcuts. Chrome\nis one of them.\n\n![examples of unix shortcuts in chrome text area](https://i.imgur.com/7MfNe6c.gif)\n"
  },
  {
    "path": "chrome/copy-some-data-from-the-console.md",
    "content": "# Copy Some Data From The Console\n\nSometimes you have some data that you are playing around with in the\nconsole, something you logged from an API response. You then want to share\nit, so you try to copy the whole thing into your system copy buffer. There\nare a couple hacky ways of doing this, but Chrome supports a really smooth\nway.\n\nUse the `copy` function.\n\n```javascript\ncharacters\n> (8) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]\ncopy(characters[1])\n```\n\nMy system copy buffer now contains the entire object that makes up the\nsecond entry in that list. I can then paste it into Slack or wherever.\n\n[source](https://twitter.com/addyosmani/status/1092686766375616517)\n"
  },
  {
    "path": "chrome/duplicate-the-current-tab.md",
    "content": "# Duplicate The Current Tab\n\nSometimes when viewing a page, you realize you want to keep that page open\nbut also go back to the previous page to view something else. An easy way of\nachieving this is to duplicate the current tab and then go back.\n\nTo duplicate the current tab hit `Cmd+Enter` while the focus is on the URL\nbar.\n\nIf the URL bar is not in focus, then first hit `Cmd+L` to focus followed by\n`Cmd+Enter`.\n"
  },
  {
    "path": "chrome/easier-access-to-network-throttling-controls.md",
    "content": "# Easier Access To Network Throttling Controls\n\nIn [Simulating Various Network Connection\nSpeeds](https://github.com/jbranchaud/til/blob/master/chrome/simulating-various-connection-speeds.md),\nI showed how to change between various simulated connection speeds from the\n_Network_ tab in Chrome devtools. Unfortunately, the Connection Speed\ndropdown is crowded out by a number of other controls in the _Network_ tab.\nAs a result, unless that tab is expanded pretty wide, you won't be able to\nget at it. I've found myself sliding the devtools wider and narrower over\nand over while testing things with throttling.\n\nThere is another, easier place to access throttling.\n\n![](https://i.imgur.com/fHN8F28.gif)\n\nThe console drawer gives us access to a number of additional tabs of\ncontrols. Add the _Network connections_ tab for easier access.\n"
  },
  {
    "path": "chrome/keybinding-to-focus-the-address-bar.md",
    "content": "# Keybinding To Focus The Address Bar\n\nThe address bar (URL bar) in Chrome is versatile. You can enter both URLs and\nsearch terms into it. If I want to enter a new search term, I generally have to\nreach for my mouse, double click in the address bar, and then type in that\nterm.\n\nChrome has a keybinding that sends focus to the address bar, which cuts some of\nthose steps.\n\nHit `Cmd-L`.\n\nYou'll see that the address bar gets focus with the entire address highlighted.\nYou can begin typing your new search term immediately.\n\n[source](https://etc.usf.edu/techease/4all/input-devices/google-chrome-keyboard-shortcuts/)\n"
  },
  {
    "path": "chrome/navigate-the-browser-history-with-vimium.md",
    "content": "# Navigate The Browser History With Vimium\n\nThe [Vimium](https://vimium.github.io/) Chrome extension is great for moving\naround the current page you are on. It can also be used to navigate back and\nforth through your browser history.\n\nYou can go back to the previous page with `H` (`Shift-h`).\n\nYou can go forward to a page you went back from with `L` (`Shift-l`).\n"
  },
  {
    "path": "chrome/open-current-tab-in-new-window-with-vimium.md",
    "content": "# Open Current Tab In New Window With Vimium\n\nSometime I have a busy Chrome window going with a bunch of tabs open for\nvarious lines of work as well as a number of tabs that I've neglected to close.\nI then open a new tab, find something useful, and realize I'm at a \"branching\npoint\". I'm about to start in on a specific chunk of work that will probably\ninvolve opening several more tabs and switch back and forth between some\ndashboards. I want to start all of this from a fresh slate -- or at least from\na fresh Chrome window.\n\nWith [Vimium](https://github.com/philc/vimium), I can hit `W` (`Shift-w`) to\nhave the current tab move from the current window to a new window. The original\nwindow, minus that one tab, will be left as is so that I can go back to it as\nneeded.\n"
  },
  {
    "path": "chrome/pause-javascript-from-the-source-devtools-panel.md",
    "content": "# Pause JavaScript From The Source DevTools Panel\n\nYou know that moment when you accidentally introduce an infinite loop in some\nJavaScript code. You've just refreshed the page in the browser and everything\nseems to both hang and loop. And the browser slows to a crawl.\n\nIf you're trying to get to the bottom of things, you may be `console.log`'ing\nsome data points. However, because of the infinite loop, the logs are flying by\nin the console. It would be great if you could bring things to a halt.\n\nI assume you already have devtools open, since you're looking at the logs. If\nnot, hit `F12`.\n\nThen go to the _Sources_ tab which is where the JavaScript debug tools are\nlocated. From here, you can find and click the pause button. It should be the\nfirst in the panel of debug controls. Alternatively, as long as you have the\n_Source_ tab in focus, you can simply hit `F8`.\n\nOnce you've paused that infinite loop, you can go back to the console and have\na look around.\n"
  },
  {
    "path": "chrome/pretty-print-tabular-data.md",
    "content": "# Pretty Print Tabular Data\n\nLooking at a bunch of data in the Chrome dev tools console isn't great. It\ncan be a bit difficult to read because of the way it is displayed.\nFortunately, the Chrome dev tools come with a handy way of displaying\ntabular data, `console.table()`. If you give `console.table` an array of\nobjects or array of arrays, it will format it in a table like so:\n\n![](http://i.imgur.com/LPgBpRB.png)\n\n```js\nconsole.table([{one: 1, two: 2, three: 3}])\n```\n"
  },
  {
    "path": "chrome/reference-the-selected-node.md",
    "content": "# Reference The Selected Node\n\nIn the Chrome dev tools, if you've selected (highlighted) a node in the DOM,\nyou can reference that node from the console with `$0`. This is handy if you\nare debugging or exploring certain parts of a page and need to run commands\nagainst that node. For instance, if you were to select the `<html>` node in\nthe DOM, you could then programmatically check the `lang` attribute from the\nconsole like so:\n\n```\n> $0.lang\n// \"en-US\"\n```\n\nIf there is `jQuery` on the page and you've selected the node that contains\nall of the page's content, you can do something like the following:\n\n```\n> $($0).html('<h1>Hello, World!</h1>')\n```\n"
  },
  {
    "path": "chrome/search-tabs-with-the-vimium-vomnibar.md",
    "content": "# Search Tabs With The Vimium Vomnibar\n\nIf you use Chrome like I do, then you eventually end up with several windows\nwith dozens if not 100+ tabs open. It can start to get tedius with that many\ntabs to find and navigate to a given tab. Someone might suggest closing a few\ndozen tabs as a solution to this predicament. However, Vimium offers a solution\nthat doesn't require I [_kill my\ndarlings_](https://en.wiktionary.org/wiki/kill_one%27s_darlings).\n\nThe Vomnibar, a Vimium-powered search bar, can be summoned with `T` to only\nsearch through open tabs.\n\nWhen I hit `T`, I see a text area (for refining the search) and then a bunch of\nentries populate below that which I immediately recognize as many of those tabs\nthat I'm going to get back to one of these days.\n\nTo narrow down to the specific thing I'm looking for, I type something into the\ninput. Then I arrow to the result I'm looking for and hit enter. And I'm\ntransported to that tab.\n\nIf I don't like where I ended up, I can also go back to the tab I had been on\nwith `^`.\n"
  },
  {
    "path": "chrome/selecting-dom-elements-faster-than-ever.md",
    "content": "# Selecting DOM Elements Faster Than Ever\n\nSelecting and inspecting DOM elements: you've done it many times before.\nWhether you right click the element and select _Inspect_ (which isn't always\nall that accurate) or you use the DevTools' inspect tool with\nhighlight-assist, it takes a couple clicks to get there.\n\nThere is a faster way.\n\nHit `Cmd-Shift-C`.\n\nChrome DevTools will be expanded open if it isn't already and your mouse\npointer will be put in inspect mode with the highlight-assist. Find your DOM\nelement, give it a click, and start inspecting!\n"
  },
  {
    "path": "chrome/simulating-various-connection-speeds.md",
    "content": "# Simulating Various Connection Speeds\n\nI spend everyday building web apps from a machine that has a wired\nconnection to the internet. Though I spend a lot of time loading various\npages and experiencing the app like a user might, I end up having a pretty\nnarrow perspective. What will this app be like for people on various\nqualities of mobile connections?\n\nChrome has a feature built in to its devtools that makes it easy to throttle\nyour connection to simulate various speeds. Open up devtools with\n`Cmd+Opt+J`, navigate to the _Network_ tab, and then open the throttling\ndrop down.\n\n![](http://i.imgur.com/EI3H9Oe.png)\n\nFrom here we can select the connection speed we want to simulate. If we then\nreload the page, we will not only experience the page load at that speed, we\nwill also see the numbers in that _Network_ tab.\n"
  },
  {
    "path": "chrome/toggle-device-mode.md",
    "content": "# Toggle Device Mode\n\nWorking on some styles? Want to make sure those minor tweaks look good on\nboth desktop and mobile? Your probably moving back and forth between the\ndesktop mode and one of the smaller device modes.\n\nThere is a keybinding for this -- `Cmd-Shift-M`\n\nThe chrome devtools panel will need to be open and in focus for this to\nwork.\n"
  },
  {
    "path": "chrome/toggle-open-the-console-drawer.md",
    "content": "# Toggle Open The Console Drawer\n\nWith Chrome devtools open and in focus, hit `<Esc>`. The console drawer will\nbe toggled open. Hit `<Esc>` again and it will be toggle closed.\n"
  },
  {
    "path": "chrome/trigger-commands-from-the-devtools-command-palette.md",
    "content": "# Trigger Commands From The Devtools Command Palette\n\nThere are a ton of tabs, drop downs, and nested menus in Chrome's devtools. If\nI know what I am looking for, that is great, I can navigate to it without much\ntrouble. But for other features and commands, I'm stumped and can end up\nspending minutes looking around.\n\nFor example, where is the option to 'Disable JavaScript'?\n\nI don't know. And I don't need to know.\n\nInstead of searching around for it, I can pop open the devtools _command\npalette_ with `cmd+shift+p`. This is a modal menu that prompts me to search for\na command to run. I start typing `disab` and already `Disable JavaScript`\nappears as one of the top options. I can select that option and JavaScript will\nbe disabled.\n\nWhen I'm ready to turn it back on. I can hit `cmd+shift+p` again and search for\n`enab`. The `Enable JavaScript` option appears and I can select it to turn it\nback on.\n\nNote: you'll need to have the devtools panel open and your focus will need to\nbe on it for the keybinding to be picked up.\n\n[source](https://developer.chrome.com/docs/devtools/command-menu)\n"
  },
  {
    "path": "chrome/view-network-traffic-for-new-tabs.md",
    "content": "# View Network Traffic For New Tabs\n\nGenerally when you open a new tab and pop open the Network panel in the chrome\ndevtools, you won't immediately see any traffic. This is because the initial\nnetwork requests to load the site happened before you accessed the Network\npanel.\n\nIf you'd like to view the Network traffic immediately without having to refresh\nthe new tab, you'll have to make the devtools panel open automatically with new\ntabs.\n\n1. Click the _triple dot_ icon from the top of the devtools panel\n2. Click 'Settings'\n3. Find the 'DevTools' section\n4. Check the box for 'Auto-open DevTools for popups'\n\nNow, whenever you open a new tab, Chrome devtools will be open and the initial\nnetwork traffic will be recorded.\n\n[source](https://stackoverflow.com/questions/16210468/chrome-dev-tools-how-to-trace-network-for-a-link-that-opens-a-new-tab)\n"
  },
  {
    "path": "claude-code/allow-edits-from-the-start.md",
    "content": "# Allow Edits From The Start\n\nA common pattern for me when using Claude Code is that I start it up in a\nproject, I prompt it with a question or feature spec, it either comes up with a\nplan or just starts working, and as soon as it is ready to make its first edits\nto a file, it prompts me something like:\n\n```\n Do you want to make this edit to Taskfile.yml?\n ❯ 1. Yes\n   2. Yes, allow all edits during this session (shift+tab)\n   3. Type here to tell Claude what to do differently\n```\n\nThat's a nice default so that I don't get surprised by Claude Code editing a\nbunch of files.\n\nHowever, if I'm in a git-backed project and I'm going into a session intending\nto make edits, then I can skip the formalities. I can tell Claude Code when\nstarting up the session that edits are allowed.\n\n```sh\n$ claude --permission-mode acceptEdits\n```\n\nWhen I do this, I'll see the following indicator below the prompt input field:\n\n```\n  ⏵⏵ accept edits on (shift+tab to cycle)\n```\n\nIf I've already started `claude` but I forgot to specify that permission mode, I\ncan also toggle right into _accept edits_ by hitting `Shift+Tab`.\n\n[source](https://www.youtube.com/watch?v=_IK18goX4X8)\n"
  },
  {
    "path": "claude-code/monitor-usage-limits-from-cli.md",
    "content": "# Monitor Usage Limits From CLI\n\nWhen I first started using Claude Code enough to push the usage limits, I would\nperiodically switch over to the browser to check\n`https://claude.ai/settings/usage` to see how close I was getting. That page\nwould tell me what percentage of my allotted usage I had consumed so far for the\ncurrent 5-hour session and then how long until that 5-hour usage window resets.\n\nThis can also be viewed directly in Claude Code for the CLI.\n\nFirst, run the `/status` slash command and then _tab_ over to the _Usage_\nsection. There you will see the same details as in the web view.\n\nI'm also learned, as I write this, that you can go directly to the _Usage_\nsection by typing the `/usage` slash command.\n\nSee [the docs](https://code.claude.com/docs/en/slash-commands) for a listing of\nall slash commands.\n"
  },
  {
    "path": "claude-code/open-current-prompt-in-default-editor.md",
    "content": "# Open Current Prompt In Default Editor\n\n[Claude Code](https://www.claude.com/product/claude-code) gives you a single\nline to write a prompt. You can write and write as much as you want, but it will\nall be on that single line. And avoid accidentally hitting 'Enter' before you're\ndone.\n\nI found myself wanting to space out my thoughts, create a code block as part of\na prompt, and generally have a scratch pad instead of just a text box. By\nhitting `ctrl-g`, I can move the current prompt into my default editor (in my\ncase, `nvim`). From there I can continue to write, edit, and format with all the\naffordances of an editor.\n\nOnce I'm done crafting the prompt, I can save (e.g. `:wq`) and Claude Code will\nbe primed with that text. I can then hit 'Enter' to let `claude` do its thing.\n"
  },
  {
    "path": "claude-code/resume-specific-session.md",
    "content": "# Resume Specific Session\n\nThere are a few different ways to resume a [Claude\nCode](https://code.claude.com/docs/en/overview) session.\n\nFirst, if I have exited a session for the current project and I want to pick\nback up with that most recent one, then I can use `claude --continue`.\n\nIf I have had a few recent sessions for the current project and I want to\nremember what they were and pick up where I left off with one of them, then I\ncan use `claude --resume` (with no argument). That will open a picker where I\ncan browser through a summary of the recent sessions based on their starting\nprompt. The one I pick is the session that will be resumed.\n\nFinally, if I have grabbed a specific session ID (UUID) during the session from\nthe `/status` output, then I can reference that value directly.\n\n```sh\n$ claude --resume 92170532-be31-4a91-b2a9-025b8fa78232\n```\n\nSee `claude --help` for more details.\n"
  },
  {
    "path": "clojure/aggregation-using-merge-with.md",
    "content": "# Aggregation Using merge-with\n\nClojure provides the `merge-with` function as a way of conjoining a series\nof maps. You must provide `merge-with` a function that it can use to merge\ntwo values for matching keys. For instance, imagine you have a bunch of maps\nthat contain counts for entities identified by keywords. You can consolidate\nthe sum of all the counts into a single map using the `merge-with` function\ncombined with the `+` function.\n\n```clojure\n> (merge-with + {:a 1 :b 3} {:b 2 :c 3} {:c 1 :d 4})\n{:a 1, :b 5, :c 4, :d 4}\n```\n\nFor different kinds of data, a different function argument may be more\nappropriate. For instance, aggregating lists instead of integers calls for\nthe `concat` function:\n\n```clojure\n> (merge-with concat {:a '(1 2) :b '(3 4)} {:c '(3 4) :a '(5 4 1)})\n{:a (1 2 5 4 1), :b (3 4), :c (3 4)}\n```\n"
  },
  {
    "path": "clojure/argument-requirements-for-a-function.md",
    "content": "# Argument Requirements For A Function\n\nWhen defining a function, you must declare one or more function definitions,\neach of which will require a different set of arguments. These argument\nlists are stored as metadata for the function. So, if you are trying to\nfigure out what arity a function is or what variations of arguments it\ntakes, you can check the metadata like so:\n\n```clojure\n> (:arglists (meta #'str))\n([] [x] [x & ys])\n```\n\n[source](http://stackoverflow.com/questions/1696693/clojure-how-to-find-out-the-arity-of-function-at-runtime)\n"
  },
  {
    "path": "clojure/combinations-of-items-from-a-sequence.md",
    "content": "# Combinations Of Items From A Sequence\n\nSometimes we want all combinations of items from a list. For instance, we\nmay have 5 people and we want to know all the ways that we can unique pair\nup 2 people from that group of 5. What we want is the number of\ncombinations of 2 people from the 5.\n\nThe\n[clojure/math.combinatorics](https://github.com/clojure/math.combinatorics)\nlibrary provides a `combinations` function that gives us exactly that\nfunctionality.\n\n```clojure\n(use '[clojure.math.combinatorics :as combo])\n\n(combo/combinations [\"Liz\", \"Tracy\", \"Kenneth\", \"Jack\", \"Jenna\"] 2)\n; ((\"Liz\" \"Tracy\") (\"Liz\" \"Kenneth\") (\"Liz\" \"Jack\")\n;  (\"Liz\" \"Jenna\") (\"Tracy\" \"Kenneth\") (\"Tracy\" \"Jack\")\n;  (\"Tracy\" \"Jenna\") (\"Kenneth\" \"Jack\") (\"Kenneth\" \"Jenna\")\n;  (\"Jack\" \"Jenna\"))\n```\n\nThe `combinations` function takes a list of items and then a number for the\nsize of the grouping combinations that it is supposed to produce.\n"
  },
  {
    "path": "clojure/define-something-only-once.md",
    "content": "# Define Something Only Once\n\nClojure provides [`defonce`](https://clojuredocs.org/clojure.core/defonce)\nwhich is a macro that defines something only once. Once a variable has been\nbound to a value, subsequent attempts to do `defounce` for that variable\nwill go unevaluated. This will have no implications for how the `def`\nspecial form works.\n\nHere is an example:\n\n```clojure\n(defonce stuff 5)\n#'user/stuff\nuser=> (defonce stuff \"what\")\nnil\nuser=> stuff\n5\nuser=> (def stuff \"okay\")\n#'user/stuff\nuser=> stuff\n\"okay\"\n```\n"
  },
  {
    "path": "clojure/evaluate-one-liners-with-lein-exec.md",
    "content": "# Evaluate One Liners With lein-exec\n\nYou can install the [`lein-exec`](https://github.com/kumarshantanu/lein-exec)\nplugin and then use it to evaluate one liner bits of code with the `-e`\nflag.\n\n```bash\n$ lein exec -e '(println \"foo\" (+ 20 30))'\nfoo 50\n```\n"
  },
  {
    "path": "clojure/expanding-macros.md",
    "content": "# Expanding Macros\n\nMacros are an important part of Clojure's syntax. They allow you to write\ncleaner, terser, more expressive code.\nThough sometimes you may want to inspect the\nclojure code that is actually produced by a particular macro. The\n`macroexpand` function allows for just this.\n\nFor instance, if you have a snippet of code using the `->>` operator:\n\n```clojure\n(->> 4 (+ 1) (- 2) (* 3))\n```\n\nYou can wrap that form with the `macroexpand` function to see the form that\nis ultimately evaluated:\n\n```clojure\n> (macroexpand (->> 4 (+ 1) (- 2) (* 3)))\n; (* 3 (- 2 (+ 1 4)))\n```\n\nIt doesn't buy us much in a contrived example like this, but can prove\nuseful for better understanding clojure and the more complex code we write.\n"
  },
  {
    "path": "clojure/get-the-value-of-an-environment-variable.md",
    "content": "# Get The Value Of An Environment Variable\n\nYou can get the value of an environment variable on your system using the\n`System/getenv` function. Just pass it the environment variable as a string:\n\n```clojure\n> (System/getenv \"HOME\")\n\"/Users/jbranchaud\"\n```\n\nIt returns `nil` when the environment variable doesn't exist.\n\n```clojure\n> (System/getenv \"HOUSE\")\nnil\n```\n"
  },
  {
    "path": "clojure/list-functions-for-a-namespace.md",
    "content": "# List Functions For A Namespace\n\nYou know that `clojure.string` has a function for uppercasing a string, but\nyou can't quite remember the name of the function. You'd remember if you saw\nthe name though. What you'd like to do is list all the functions in the\n`clojure.string` namespace to see if you can pick it out.\n\nYou can do just that. There are a couple ways to do it, in fact.\n\nYou can use the `dir` function with Clojure 1.6+. Alternatively, you can\ngrab all the keys from the public intern mappings of the namespace.\n\n```clojure\n> (dir clojure.string)\nblank?\ncapitalize\nends-with?\nescape\nincludes?\nindex-of\njoin\nlast-index-of\nlower-case\nre-quote-replacement\nreplace\nreplace-first\nreverse\nsplit\nsplit-lines\nstarts-with?\ntrim\ntrim-newline\ntriml\ntrimr\nupper-case\nnil\n\n> (keys (ns-publics 'clojure.string))\n(ends-with? capitalize reverse join replace-first starts-with? escape last-index-of re-quote-replacement includes? replace split-lines lower-case trim-newline upper-case split trimr index-of trim triml blank?)\n```\n\n[source](http://stackoverflow.com/questions/2747294/how-to-list-the-functions-of-a-namespace)\n"
  },
  {
    "path": "clojure/load-a-file-into-the-repl.md",
    "content": "# Load A File Into The REPL\n\nYou can quickly load a file into a REPL session using the `load-file`\nfunction. You can specify an absolute or relative path and it will\n\n> sequentially read and evaluate the set of forms contained in the file.\n\n```clojure\n(load-file \"path/to/file.clj\")\n```\n\nSee the [`load-file` docs](https://clojuredocs.org/clojure.core/load-file)\nfor more details.\n"
  },
  {
    "path": "clojure/mapping-with-an-index.md",
    "content": "# Mapping With An Index\n\nIf you're mapping over a collection and you need an index for each item, you\ncan reach for `map-indexed`. The `map-indexed` function can be used like so:\n\n```clojure\n> (def foods [\"pizza\" \"hotdog\" \"chicken alfredo\"])\n#'cljs.user/foods\n> (map-indexed (fn [idx item] (str idx \" - \" item)) foods)\n(\"0 - pizza\" \"1 - hotdog\" \"2 - chicken alfredo\")\n```\n\nAlternatively, `map` can take multiple sequences, and each becomes a new argument to the mapping function. By giving an infinite sequential list of numbers starting at 0 as the first sequence, you can pretend they're indices, like so:\n\n```clojure\n> (map (fn [idx item] (str idx \" - \" item)) (range) foods)\n(\"0 - pizza\" \"1 - hotdog\" \"2 - chicken alfredo\")\n```\n"
  },
  {
    "path": "clojure/open-javadocs.md",
    "content": "# Open JavaDocs\n\nClojure has all kinds of Java interop including a fancy function called\n`javadoc`. The `javadoc` function _opens a browser window displaying the\njavadoc for the argument_.\n\nThinking about using Java's `ArrayList` class, but want to read up on it\nfirst? Try\n\n```\n> (javadoc java.util.ArrayList)\ntrue\n```\n\nThe javadoc page for\n[ArrayList](http://docs.oracle.com/javase/6/docs/api/java/util/ArrayList.html)\nwill be opened up in your default browser.\n"
  },
  {
    "path": "clojure/pretty-print-the-last-thing.md",
    "content": "# Pretty Print The Last Thing\n\nClojure provides `pp` as a convenience macro for pretty printing the last\nthing that was output. If you are playing around with a function in the\nrepl, trying to get the output just right, `pp` can come in handy.\n\n```clojure\n> (fancy-func)\n{:one {:a 1, :b 2, :c 3, :d 4}, :two {:b 2, :c 3, :d 4, :e 5}, :three {:c 3,\n:d 4, :e 5, :f 6}, :four {:d 4, :e 5, :f 6, :g 7}}\n> (clojure.pprint/pp)\n{:one {:a 1, :b 2, :c 3, :d 4},\n :two {:b 2, :c 3, :d 4, :e 5},\n :three {:c 3, :d 4, :e 5, :f 6},\n :four {:d 4, :e 5, :f 6, :g 7}}\nnil\n```\n\nSee `(doc pp)` for more details.\n"
  },
  {
    "path": "clojure/quick-clojure-docs.md",
    "content": "# Quick Clojure Docs\n\nAssuming you already have the\n[`fireplace.vim`](https://github.com/tpope/vim-fireplace) plugin installed\nand a repl running, you can quickly pull up the docs for any clojure\nfunction. Navigate the cursor over the keyword in question and hit `K` in\nnormal mode. This will instruct `fireplace.vim` to use the `doc` function on\nthe symbol for that keyword. The docs associated with that keyword will be\ndisplayed at the bottom of the window.\n"
  },
  {
    "path": "clojure/reductions.md",
    "content": "# Reductions\n\nOne of the core functions in Clojure is\n[`reduce`](https://clojuredocs.org/clojure.core/reduce). It allows you to\nbuild up some result based on applying a function to each value in a\ncollection. Clojure provides a similar function that builds up a (lazy)\nsequence of intermediate values as it is performing a reduce.\nThis function is\n[`reductions`](https://clojuredocs.org/clojure.core/reductions).\n\nUsing `reduce` to sum a collection of integers looks like this\n\n```clojure\n> (reduce + 0 [1 2 3 4 5])\n=> 15\n```\n\nwhereas `reductions` performing the same task will look like this\n\n```clojure\n> (reductions + 0 [1 2 3 4 5])\n=> (0 1 3 6 10 15)\n```\n\nh/t Josh Davey\n"
  },
  {
    "path": "clojure/set-max-heap-size.md",
    "content": "# Set Max Heap Size\n\nFor `lein`-based projects, the maximum heap size can be set by including the\n`-Xmx` option in the `jvm-opts` portion of the `project.clj` file. For\ninstance, to set the maximum JVM heap size to 2 gigabytes, include:\n\n```clojure\n  :jvm-opts [\"-Xmx2g\"]\n```\n\nin your `project.clj` file.\n"
  },
  {
    "path": "clojure/specify-the-directory-of-a-shell-command.md",
    "content": "# Specify the Directory of a Shell Command\n\nClojure gives us access to Java's shell capabilities through\n`clojure.java.shell`. For instance, if you want to list the contents of your\nproject's directory, you can issue an `ls` command:\n\n```\n> (clojure.java.shell/sh \"ls\")\n; {:exit 0,\n;  :out \"LICENSE\\nREADME.md\\ndoc\\nproject.clj\\nresources\\nsrc\\ntarget\\ntest\\n\",\n;  :err \"\"}\n```\n\nThe default will always be to execute the command in the directory of the\ncontaining project. It is likely that you'd like to specify a different\ndirectory though. There is a function for that:\n\n```clojure\n(clojure.java.shell/with-sh-dir \"some/dir\" (clojure.java.shell/sh \"ls\"))\n```\n\nOr more concisely, you can specify the directory as part of the `sh`\nfunction:\n\n```clojure\n(clojure.java.shell/sh \"ls\" :dir \"some/dir\")\n```\n"
  },
  {
    "path": "clojure/splitting-on-whitespace.md",
    "content": "# Splitting On Whitespace\n\nIf you have a string with spaces and you want to split the string into a\nvector of strings (delimited by the spaces), then you can do something like\nthis:\n\n```clojure\n(clojure.string/split \"split me up\" #\" \")\n; [\"split\" \"me\" \"up\"]\n```\n\nHowever, if you have extra spaces in your string, the output may not be quite\nwhat you want:\n\n```clojure\n(clojure.string/split \"double  spacing  wtf?\" #\" \")\n; [\"double\" \"\" \"spacing\" \"\" \"wtf?\"]\n```\n\nA quick fix might look like this:\n\n```clojure\n(clojure.string/split \"double  spacing  wtf?\" #\" +\")\n; [\"double\" \"spacing\" \"wtf?\"]\n```\n\nThat's nice, but it is going to fall over as soon as we run into input with\ntabs and new lines. Assuming we want to split on all whitespace, we should\ntell our regular expression to do just that:\n\n```clojure\n(clojure.string/split \"we\\thave new\\nlines and  tabs\\n\" #\"\\s+\")\n; [\"we\" \"have\" \"new\" \"lines\" \"and\" \"tabs\"]\n```\n"
  },
  {
    "path": "clojure/swap-two-items-in-a-vector.md",
    "content": "# Swap Two Items in a Vector\n\nIf you want to replace the value at an index in a vector, you can use the\n`assoc` function supplied by `clojure.core` like so:\n\n```clojure\n> (assoc [5 6 7 8] 1 9)\n; [5 9 7 8]\n```\n\nLikewise, if you want to replace two items in a vector, you can extend the\nabove like so:\n\n```clojure\n> (assoc [5 6 7 8] 1 2 2 4)\n; [5 2 4 8]\n```\n\nWe can take advantage of that second example to construct a function that\nwill swap two values:\n\n```clojure\n(defn swap\n  [items i j]\n  (assoc items i (items j) j (items i)))\n```\n\nThis function will break on values of `i` and `j` that are out of the bounds\nof `items`, but dealing with that is left as an exercise to the reader.\n\n[source](http://stackoverflow.com/questions/5979538/what-is-the-idiomatic-way-to-swap-two-elements-in-a-vector)\n"
  },
  {
    "path": "clojure/try-a-clojure-project-in-the-repl.md",
    "content": "# Try A Clojure Project In The REPL\n\nThe `lein-try` plugin is a tool that makes it easy to quickly try out a\nclojure project in the lein repl. Given the name and version of a clojure\nproject, it will drop you into a repl with that project loaded in. This is a\ngreat way to get the feel for the features of an unfamiliar clojure library\nbefore dropping it in as a dependency to your own project.\n\nFirst, add the plugin to your `~/.lein/profiles.clj` file by including the\nfollowing line in the `:plugins` vector:\n\n```\n[lein-try \"0.4.3\"]\n```\n\nThen simply invoke the plugin with whatever project you want to try:\n\n```\n$ lein try automat\n```\n\nAnd to include a specific version number:\n\n```\n$ lein try automat \"0.1.3\"\n```\n"
  },
  {
    "path": "clojure/type-of-anything.md",
    "content": "# Type of Anything\n\nYou can get the type of anything with the `type` function. Because Clojure\nis built on Java, many of these types may be types you recognize form Java.\n\nBoot up the repl to try some of these out:\n\n```clojure\n> (type 5)\n; java.lang.Long\n> (type 5.2)\n; java.lang.Double\n> (type 5/4)\n; clojure.lang.Ratio\n> (type (int 2))\n; java.lang.Integer\n> (type \"hello, world!\")\n; java.lang.String\n> (type [1 2 3])\n; clojure.lang.PersistentVector\n> (type '(1 2 3))\n; clojure.lang.PersistentList\n```\n\n[source](https://aphyr.com/posts/302-clojure-from-the-ground-up-basic-types)\n"
  },
  {
    "path": "clojure/when-overflow-is-desired.md",
    "content": "# When Overflow Is Desired\n\nIf you try to add two `MAX_VALUE` Longs, Clojure is kind enough to warn you.\n\n```clojure\n> (+ Long/MAX_VALUE Long/MAX_VALUE)\nArithmeticException integer overflow  clojure.lang.Numbers.throwIntOverflow (Numbers.java:1424)\n```\n\nHowever, when overflow is desired, you can use the *unchecked* operators\n(e.g. `unchecked-add`).\n\n```clojure\n> (unchecked-add Long/MAX_VALUE Long/MAX_VALUE)\n-2\n```\n\nSee also `unchecked-subtract` and `unchecked-multiply`.\n"
  },
  {
    "path": "css/add-fab-icons-to-your-site-with-fontawesome-5.md",
    "content": "# Add Fab Icons To Your Site With FontAwesome 5\n\nCheck out the latest version of [FontAwesome](https://fontawesome.com/).\n\n> Version 5 has been re-written and re-designed completely from scratch.\n\nOne part of the rewrite is that _brand_ icons have been organized into their\nown collection. Whether you are using the full suite or just the brands\nbundle, you'll be referencing these icons with the `fab` class name.\n\n```html\n<i class=\"fab fa-react\" />\n```\n\nThis will give you a React icon.\n\nCheck out all the different [_brand_ icons\nhere](https://fontawesome.com/icons?d=gallery&s=brands).\n"
  },
  {
    "path": "css/add-line-numbers-to-a-code-block-with-counter.md",
    "content": "# Add Line Numbers To A Code Block With Counter\n\nThe\n[`counter`](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_counter_styles/Using_CSS_counters)\nfeature in CSS is a stateful feature that allows you to increment and display a\nnumber based on elements' locations in the document. This feature is useful for\nadding numbers to headings and lists, but it can also be used to add line\nnumbers to a code block.\n\nWe need to initialize the counter to start using it. This will give it a name\nand default it to the value 0. We'll tie this to a `pre` tag which wraps our\nlines of code.\n\n```css {{ title: 'globals.css' }}\npre.shiki {\n  counter-reset: line-number;\n}\n```\n\nThen we need to increment the counter for every line of code that appears in\nthe code block\n\n```css {{ title: 'globals.css' }}\npre.shiki .line {\n  counter-increment: line-number;\n}\n```\n\nLast, we need to display these incrementing `line-number` values _before_ each\nline.\n\n```css {{ title: 'globals.css }}\npre.shiki .line:not(:last-of-type)::before {\n  content: counter(line-number);\n  /*\n   * plus any styling and spacing of the numbers\n   */\n}\n```\n\nThis essentially attaches an element to the front (`::before`) of the line\nwhose content is the current value of `line-number`. It is applied to all but\nthe last `.line` because [shiki](https://shiki.matsu.io/) includes an empty\n`.line` at the end.\n\nHere is [the real-world example of\nthis](https://github.com/pingdotgg/uploadthing/blob/4954c9956c141a25a5405991c34cc5ce8d990085/docs/src/styles/tailwind.css#L13-L37)\nthat I referenced for this post.\n\nNote: the counter can be incremented, decremented, or even explicitly set to a\nspecific value.\n"
  },
  {
    "path": "css/animate-smoothly-between-two-background-colors.md",
    "content": "# Animate Smoothly Between Two Background Colors\n\nCSS animations allow you to set up simple rules that the rendering engine\ncan then apply to create smooth transitions between style states.\n\nTo smoothly transition between two background colors, we can create a\nkeyframes at-rule with a fitting name (e.g. `pulse`).\n\n```css\n@keyframes pulse {\n  0% {\n    background-color: red;\n  }\n  50% {\n    background-color: blue;\n  }\n  100% {\n    background-color: red;\n  }\n}\n```\n\nOver the course of a single animation, this set of rules will start the\nbackground color at red, transition to blue 50% of the way through, and then\nback to red again.\n\nWe can then apply this animation within any of our CSS class definitions.\n\n```css\n.square1 {\n  animation: pulse 2s infinite;\n  width: 100px;\n  height: 100px;\n}\n```\n\nAnything with a class of `square1` will have a width and height of `100px`\nas well as a pulsing background color.\n"
  },
  {
    "path": "css/apply-multiple-box-shadows-to-single-element.md",
    "content": "# Apply Multiple Box Shadows To Single Element\n\nMultiple box-shadows can be applied to the same DOM element. The `box-shadow`\nproperty accepts a comma-separated list of `box-shadow` directives.\n\nHere is a pretty nasty looking example from the [MDN\ndocs](https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow#Syntax):\n\n```css\n/* Any number of shadows, separated by commas */\nbox-shadow: 3px 3px red, -1em 0 0.4em olive;\n```\n\nHere is a more practical [example](https://codepen.io/jbranchaud/pen/GRReaxo):\n\n```css\nbox-shadow: 0 0 0 2px #4caf50,\n  0 3px 5px 0 rgba(0,0,0,0.5);\n```\n\nThis gives the effect of a solid border with some shadow for depth.\n\nMultiple shadows has [pretty robust browser\nsupport](https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow#Browser_compatibility).\n\n[source](https://stackoverflow.com/questions/8556604/is-there-a-way-to-use-two-css3-box-shadows-on-one-element/8556627)\n"
  },
  {
    "path": "css/apply-styles-based-on-dark-mode-preferences.md",
    "content": "# Apply Styles Based On Dark-Mode Preferences\n\nThere is a CSS media query for whether a user prefers a Dark-Mode or Light-Mode\ncolor scheme. If you're site is able to provide styling for both modes, then\nyou can hook into those preferences like so:\n\n```css\n@media (prefers-color-scheme: dark) {\n  /* dark-mode styles */\n  /* perhaps changing some custom properties */\n}\n\n@media (prefers-color-scheme: light) {\n  /* light-mode styles */\n  /* perhaps changing some custom properties */\n}\n```\n\nAs of this writing,\n[`prefers-color-scheme`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme)\nis still in a draft state, but it already has decent browser support.\n\n[source](https://24ways.org/2019/interactivity-and-animation-with-variable-fonts/)\n"
  },
  {
    "path": "css/apply-styles-to-the-last-child-of-a-specific-type.md",
    "content": "# Apply Styles To The Last Child Of A Specific Type\n\nThe\n[`:last-child`](https://developer.mozilla.org/en-US/docs/Web/CSS/:last-child)\npseudo-class is a way of specifying styling that will only be applied to an\nelement if it is the last child among its siblings. What if we have elements\nthat are declared amongst elements of another type? This can complicate that\nstyling.\n\nThe styling\n\n```css\nspan:last-child {\n  color: red;\n}\n```\n\nwon't take effect on our last `span` here\n\n```html\n<div>\n  <span>One</span>\n  <span>Two</span>\n  <span>Three</span>\n  <div>Something unrelated</div>\n</div>\n```\n\nbecause amongst its siblings it isn't the last.\n\nOne way of getting around this is with the\n[`:last-of-type`](https://developer.mozilla.org/en-US/docs/Web/CSS/:last-of-type)\npseudo-class.\n\n```css\nspan:last-of-type {\n  color: red;\n}\n```\n\nSee a [live example here](https://codepen.io/jbranchaud/pen/JLEyLP).\n"
  },
  {
    "path": "css/change-the-orientation-of-an-image.md",
    "content": "# Change The Orientation Of An Image\n\nA single-line CSS transform is all it takes to change the orientation of an\nimage (or any DOM element, really).\n\nFor instance, if I have an image that is _on its side_, I can use the following\n[`rotate`\ntransform](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/rotate)\nto orient it correctly.\n\n```css\nimg {\n  transform: rotate(90deg);\n}\n```\n\nIt takes an angle which can be specified in degrees. Here I use `90deg`. If I\nwas going for a different effect, I could do something like `45deg`.\n"
  },
  {
    "path": "css/circular-icons-with-a-massive-border-radius.md",
    "content": "# Circular Icons With A Massive Border Radius\n\nElements by nature are rectangular. By adding some `border-radius`, you can\nsoften the edges a bit. If you add a massive amount of `border-radius`, you\neffectively make the element round.\n\n```css\ndiv.circle {\n  border-radius: 50000px;\n}\n```\n\nHere is a [live example](https://codepen.io/jbranchaud/pen/bGGJKJW).\n"
  },
  {
    "path": "css/clean-up-repetition-with-is-pseudo-class.md",
    "content": "# Clean Up Repetition With :is() Pseudo-Class\n\nYou can use the [`:is()`](https://developer.mozilla.org/en-US/docs/Web/CSS/:is)\npseudo-class to match on a number of different selectors in a concise way. For\ninstance, here is how you can make some CSS shorter and more readable:\n\n```css\n/* before */\nh1.text--bold, h2.text--bold, h3.text--bold, h4.text--bold, h5.text--bold {\n  font-weight: 500;\n}\n\n/* after */\n:is(h1, h2, h3, h4, h5).text--bold {\n  font-weight: 500;\n}\n```\n\nHere is how [CSS-tricks](https://css-tricks.com/almanac/selectors/i/is/)\ndescribes it:\n\n> :is() is the current name for the \"Matches-Any\" pseudo-class in the CSS4\nworking draft. The goal of the \"Matches Any\" selector (with all of it's names)\nis to make complex groupings of selectors easier to write.\n\nIt still has limited browser support, so use it sparingly.\n"
  },
  {
    "path": "css/conditional-styling-for-unsupported-css-features.md",
    "content": "# Conditional Styling For Unsupported CSS Features\n\nAs much as possible, you should aim to use CSS features that have broad browser\nsupport. Sometimes browsers lag behind or you'd like to take advantage of a\ndraft feature in browsers that support it.\n\nFor these situations, you can provide conditional styling using the\n[`@supports`\nat-rule](https://developer.mozilla.org/en-US/docs/Web/CSS/@supports).\n\nHere is an example of conditionally using `display: grid` if it is supported:\n\n```css\n@supports (display: grid) {\n  div {\n    display: grid;\n  }\n}\n```\n\nIn [this\narticle](https://24ways.org/2019/zs-still-not-dead-baby-zs-still-not-dead/)\nthere is an example of using `background-blend-mode` and falling back to\n`background-image` if it isn't supported.\n\n```css\n@supports not (background-blend-mode: normal) {\n  body {\n    background-image: url(fallback.png); \n  }\n}\n```\n"
  },
  {
    "path": "css/create-a-pulsing-background-with-css-animation.md",
    "content": "# Create A Pulsing Background With CSS Animation\n\nYou can create a smoothly pulsing background effect with CSS animations. This\ncan be achieved by defining a set of keyframes that start at one background\ncolor, transitions to another color, and then transitions back to the original\ncolor.\n\n```css\n@keyframes pulse {\n  0%, 100% {\n    background-color: #f56a3f;\n  }\n  50% {\n    background-color: #9e42b0;\n  }\n}\n```\n\nAt the beginning (`0%`) and end (`100%`) we declare the background color to be\n`#f56a3f`. Halfway through (`50%`) it should be `#9e42b0`. The browser will\nanimate everything in between.\n\nThis can then be applied infinitely with a lengthy duration to give it a real\nsmooth feel.\n\n```css\nbody {\n  animation: pulse 20s infinite;\n}\n```\n\nHere is a [live example](https://codepen.io/jbranchaud/pen/vYYqQjO).\n\n[source](https://css-tricks.com/almanac/properties/a/animation/)\n"
  },
  {
    "path": "css/define-css-custom-properties-with-scss-variables.md",
    "content": "# Define CSS Custom Properties With SCSS Variables\n\nIt doesn't work to directly declare a CSS custom property using SCSS variables\nlike this:\n\n```css\n$primary-action: #057A5B;\n\n.btn-primary {\n  --button-color: $primary-action;\n}\n```\n\nAfter SCSS pre-processing, the resulting CSS will look like this:\n\n```css\n.btn-primary {\n  --button-color: $primary-action;\n}\n```\n\nInstead of the variable being translated into its declared value (`#057A5B` in\nthis case), it is left as is.\n\nThis is because CSS custom property syntax is unusual enough that it gets\nprocessed literally. The only way to incorporate a variable is with\n_interpolation_.\n\n```css\n$primary-action: #057A5B;\n\n.btn-primary {\n  --button-color: #{$primary-action};\n}\n```\n\nWrapping the SCSS variable in interpolation syntax (`#{ ... }`) will do the\njob.\n\n[source](https://sass-lang.com/documentation/style-rules/declarations#custom-properties)\n"
  },
  {
    "path": "css/define-hsl-colors-with-alpha-values.md",
    "content": "# Define HSL Colors With Alpha Values\n\nHSL is a more intuitive option for defining colors in CSS.\n\nIt is an acronym which stands for Hue, Saturation, and Lightness which are the\nthree components of an HSL value. It is also possible to include a fourth\nvalue: Alpha for the amount of transparency of the color.\n\nThe modern syntax allows you to use `hsl` with or without an alpha value, and\nno need to use comma separators. If the alpha value is included, it must be\nseparated from the other three values with a forward slash.\n\n```css\n.modern-hsl {\n  background-color: hsl(340deg 100% 50%);\n}\n.modern-hsla {\n  background-color: hsl(340deg 100% 50% / 0.75);\n}\n```\n\nIf you need IE-support, then you'll have to use the older syntax. This version\nof `hsl` requires comma separators, and to apply an alpha value you have to\nswitch to `hsla`.\n\n```css\n.old-hsl {\n  background-color: hsl(340deg, 100%, 50%);\n}\n.old-hsla {\n  background-color: hsla(340deg, 100%, 50%, 0.75);\n}\n```\n\nYou can see it in action and play around with the value in this [live\nexample](https://codepen.io/jbranchaud/pen/gOLVzjx?editors=1100).\n\n\nSee [Can I Use? on HSL](https://caniuse.com/?search=hsl) for more details on\nbrowser support.\n\nh/t to [Josh Comeau](https://twitter.com/JoshWComeau) and his excellent [CSS\nfor JS Developers course](https://css-for-js.dev/)\n"
  },
  {
    "path": "css/display-responsive-iframe-maintaining-aspect-ratio.md",
    "content": "# Display Responsive iframe Maintaining Aspect Ratio\n\nGenerally when rendering an iframe, you'll specify the `width` and `height`\nproperties to give it a fixed display size.\n\nYou can make the iframe responsively expand to the full width of its parent\nwhile maintaining its aspect ratio using a little CSS.\n\nFirst, remove the `width` and `height` properties.\n\nSecond, add a wrapping iframe container:\n\n```html\n<div class=\"iframe-container\">\n  <iframe src=\"https://www.youtube.com/embed/7LDlUMMbv6k\" ...></iframe>\n</div>\n```\n\nThird, sprinkle on a little CSS to make it responsive:\n\n```css\n.iframe-container {\n  position: relative;\n  overflow: hidden;\n  /* 16:9 aspect ratio */\n  padding-top: 56.25%;\n}\n\n.iframe-container iframe {\n  position: absolute;\n  width: 100%;\n  height: 100%;\n  top: 0;\n  left: 0;\n  border: 0;\n}\n```\n\nBen Marshall has a whole [guide to responsive\niframes](https://www.benmarshall.me/responsive-iframes/).\n"
  },
  {
    "path": "css/dry-up-scss-with-mixins.md",
    "content": "# Dry Up SCSS With Mixins\n\nIf you have a similar chunk of styling that is being duplicated across your\nCSS, you'd probably like to dry it up to reduce the pain of maintaining it.\nMixins provide one way of dealing with this problem.\n\nFirst, declare a named mixin of the styles that you are trying to dry up.\n\n```css\n@mixin navigation {\n  nav {\n    display: flex;\n    justify-content: space-around;\n\n    ul {\n      list-style: none;\n\n      li a {\n        text-decoration: none;\n      }\n    }\n  }\n}\n```\n\nThen, this mixin can be _included_ wherever it is needed.\n\n```css\ndiv.base-nav {\n  @include navgation;\n  background-color: #fff;\n  color: #444;\n\n  nav ul {\n    li a:hover {\n      color: #222;\n    }\n  }\n}\n\ndiv.admin-nav {\n  @include navgation;\n  background-color: #000;\n  color: #fff;\n\n  nav ul {\n    li a:hover {\n      color: #ddd;\n    }\n  }\n}\n```\n\nAny subsequent changes to the core navigation styling only need to be made\nin one place, the mixin.\n\n[source](http://sass-lang.com/guide)\n\nh/t Dorian Karter\n"
  },
  {
    "path": "css/filter-blur-requires-expensive-calculation.md",
    "content": "# Filter Blur Requires Expensive Calculation\n\nI had [a\npage](https://www.visualmode.dev/connect-to-production-rails-console-aws-flightcontrol)\non my blog that was experiencing some odd rendering behavior. The issue was\nmanifesting a couple ways.\n\n- Resizing and scrolling were janky and causing entire page layers to re-render\ncausing the page to flash in and out.\n- Sometimes entire layer chunks would fail to paint leaving a white block\nmissing from the page.\n\nThe issue was occurring with and without JavaScript turned on for a\nstatically-built page. I suspected that some aspect of the CSS was at fault.\n\nI was going back and forth with Dillon Hafer about what the issue could be and\nhe wondered, \"could it be the backdrop-blur class from tailwind?\". I tried\nremoving that class and the responsiveness of the page immediately improved.\n\nThe [`filter:\nblur`](https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/blur)\nand [`backdrop-filter:\nblur`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter) both\nuse an expensive [Gaussian blur](https://en.wikipedia.org/wiki/Gaussian_blur)\ncalculation. One of these on a modern machine and browser probably won't have a\nnoticable impact. However, a bunch of them, as in the case of my page with a\nrecurring component, can have quite the performance hit.\n\n[source](https://github.com/tailwindlabs/tailwindcss/issues/15256)\n"
  },
  {
    "path": "css/give-elements-the-same-width-with-flexbox.md",
    "content": "# Give Elements The Same Width With Flexbox\n\nBy default, a row of elements in a basic flex container are going to have\ndynamic widths that accommodate their contents. This may not be desirable if\nyou're going for a uniform look. You could give all child elements a fixed\nwidth (e.g. `width: 100px`), but that loses out on the _flexibility_ of a\nflexbox layout.\n\nYou can instead give all child elements a uniform and flexible width using the\n`flex` property.\n\n```css\n.flex-container {\n  display: flex;\n}\n\n.flex-child {\n  flex: 1;\n}\n```\n\nThis value is a relative ratio. If all children of the flex container have the\nsame `flex` value (i.e. `1`), then they will all be equally sized and that size\nwill adjust as the width of the flex container changes.\n\n[source](https://css-tricks.com/the-thought-process-behind-a-flexbox-layout/)\n"
  },
  {
    "path": "css/let-pointer-events-pass-through-an-element.md",
    "content": "# Let Pointer Events Pass Through An Element\n\nA graphical element can absorb a click event preventing your preferred target\nfrom recieving it. And nothing will happen. If the element is purely for visual\neffect, then there is some CSS you can add so that the underlying element will\nreceive the click event.\n\n```css\n.ignore-clicks {\n  pointer-events: none;\n}\n```\n\nThe [`pointer-events`](https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events) property specifies if and how an element \"can become the target of pointer events.\"\n\n> In addition to indicating that the element is not the target of pointer\n> events, the value none instructs the pointer event to go \"through\" the\n> element and target whatever is \"underneath\" that element instead.\n\n[source](https://bradfrost.com/blog/post/overcomplicatin/)\n"
  },
  {
    "path": "css/lighten-and-darken-with-css-brightness-filter.md",
    "content": "# Lighten And Darken With CSS Brightness Filter\n\nCSS has a `filter` property that can be used with a variety of filter\nfunctions. One of them is the `brightness()` filter. By feeding a percentage\nless than `100%` to `brightness()`, the target element will be made darker.\nInversely, feeding a percentage greater than `100%` to `brightness()` will\nmake the element brighter.\n\n```css\n.brighter-span {\n  filter: brightness(150%);\n}\n\n.darker-span {\n  filter: brightness(50%);\n}\n```\n\n![brighter, regular, and darker spans](https://i.imgur.com/q4oy1d0.png)\n\nSee this [CSS Tricks Article on the `filter`\nproperty](https://css-tricks.com/almanac/properties/f/filter/) for more\ndetails. Check out the browser support story\n[here](http://caniuse.com/#feat=css-filters).\n"
  },
  {
    "path": "css/lighten-and-darken-with-scss.md",
    "content": "# Lighten And Darken With SCSS\n\nWith SCSS, a color can be lightened or darkened by a certain percentage\nusing the\n[`lighten`](http://sass-lang.com/documentation/Sass/Script/Functions.html#lighten-instance_method)\nand\n[`darken`](http://sass-lang.com/documentation/Sass/Script/Functions.html#darken-instance_method)\nfunctions, respectively.\n\nFor instance, given the following HTML\n\n```html\n<div class='one'></div>\n<div class='two'></div>\n<div class='three'></div>\n```\n\nI can style `div.two` with the original color and then style `div.one` with\na lightened version and `div.three` with a darkened version.\n\n```scss\n$box-color: #0074d9;\n\n.two {\n  background: $box-color;\n}\n.one {\n  background: lighten($box-color, 20%);\n}\n.three {\n  background: darken($box-color, 20%);\n}\n```\n\nThe result looks something like this:\n\n![](http://i.imgur.com/SaeTL8H.png)\n"
  },
  {
    "path": "css/make-a-block-of-text-respect-new-lines.md",
    "content": "# Make A Block Of Text Respect New Lines\n\nGenerally when we fill a `div` tag full of text, it will display it one long\nstrand irrespective of any line breaks that are included. This is a great\ndefault, but not necessarily what we want when we are displaying text from\nanother source, such as our users.\n\nWe can convince a block of text to respect new lines by adding a couple CSS\nproperties.\n\n```css\n.multiline-text {\n  word-wrap: break-word;\n  white-space: pre-line;\n}\n```\n\nThe first rule, `word-wrap: break-word`, ensures that long lines of text\nuninterrupted by new lines respect the boundaries of our wrapping element.\nThe second rule, `white-space: pre-line`, handles squashing of extra white\nspace and respecting of new lines.\n\nSee a [working example here](https://codepen.io/anon/pen/bQpKyv).\n"
  },
  {
    "path": "css/parameterized-scss-mixins.md",
    "content": "# Parameterized SCSS Mixins\n\nA mixin can be made to be much more versatile by parameterizing it. If you\nneed variations of a block of CSS, then move the parts that vary out into\nparameters to the mixin.\n\n```css\n@mixin navigation($background-color, $color, $link-color) {\n  nav {\n    display: flex;\n    justify-content: space-around;\n    background-color: $background-color;\n    color: $color;\n\n    ul {\n      list-style: none;\n\n      li a {\n        text-decoration: none;\n        color: $link-color;\n      }\n    }\n  }\n}\n\ndiv.base-nav {\n  @include navgation(#fff, #444, #222);\n}\n\ndiv.admin-nav {\n  @include navgation(#000, #fff, #ddd);\n}\n```\n\nThe mixin can now easily be used to customize different segments of your\napp's styling.\n"
  },
  {
    "path": "css/prevent-invisible-elements-from-being-clicked.md",
    "content": "# Prevent Invisible Elements From Being Clicked\n\nI have a nav element that when clicked reveals a custom drop-down menu. It\nreveals it using CSS transitions and transformations (`opacity` and `scale`).\nWhen the nav element is clicked again, the reverse of these transformations is\napplied to \"hide\" the menu. This gives a nice visual effect.\n\nIt only makes the menu invisible and doesn't actually make it go away. That\nmeans that menu could be invisible, but hovering over the top of a button on\nthe screen. The button cannot be clicked now because the menu is intercepting\nthat [_pointer\nevent_](https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events).\n\nThe fix is to apply CSS (or a class) when the drop-down menu is closed that\ntells it to ignore _pointer events_.\n\n```css\n.pointer-events-none {\n  pointer-events: none;\n}\n```\n\nThis is more of less what [the `pointer-events-none` TailwindCSS\nutility](https://tailwindcss.com/docs/pointer-events) looks like.\n\nThis class is applied by default to the drop-down menu. Then when the nav item\nis clicked, some JavaScript removes that class at the same moment that the menu\nis visually appearing. When a menu item is selected or the menu otherwise\nclosed, it transitions away and the `pointer-events-none` class is reapplied.\n"
  },
  {
    "path": "css/root-has-higher-specificity-than-html.md",
    "content": "# :root Has Higher Specificity Than html\n\nThe `:root` CSS pseudo-selector and `html` will target the same element --\n`<html>`, but `:root` has higher specificity. That means the property rules\ndeclared under `:root` will take precedence over those under `html`.\n\n```css\n:root {\n  background: red;\n}\n\nhtml {\n  background: blue;\n}\n```\n\nIn the case of the above code, the `<html>` element's background color will\nbe `red`.\n\n[source](https://developer.mozilla.org/en-US/docs/Web/CSS/:root)\n"
  },
  {
    "path": "css/style-a-background-with-a-linear-gradient.md",
    "content": "# Style A Background With A Linear Gradient\n\nThe\n[`linear-gradient`](https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient)\nfunction in its simplest form can be used to style the background of an\nelement with a vertical, linear gradient between two colors.\n\n![gradient example](https://i.imgur.com/Jybn4MB.png)\nSee the Pen <a href='https://codepen.io/jbranchaud/pen/pQpypW/'>pQpypW</a> by Josh Branchaud (<a href='https://codepen.io/jbranchaud'>@jbranchaud</a>) on <a href='https://codepen.io'>CodePen</a>.\n\nHere is what the CSS looks like:\n\n```css\n.container {\n  background: linear-gradient(#00449e, #e66465);\n}\n```\n\nThe background of any element with the `container` class will be styled with\na linear gradient that transitions from `#00449e` to `#e66465`.\n"
  },
  {
    "path": "css/using-maps-in-scss.md",
    "content": "# Using Maps In SCSS\n\nYou can collect a set of like values into a\n[map](https://sass-lang.com/documentation/values/maps) with the following SCSS\nsyntax:\n\n```scss\n$backgrounds: (\n  \"gray\": #AAAAAA,\n  \"red\": #FF4136,\n  \"blue\": #0074D9,\n);\n```\n\nYou can then access a value from the map using the [`map-get`\nfunction](https://sass-lang.com/documentation/values/maps#look-up-a-value):\n\n```scss\n.boxA {\n  background-color: map-get($backgrounds, \"gray\");\n}\n\n.boxB {\n  background-color: map-get($backgrounds, \"red\");\n}\n\n.boxC {\n  background-color: map-get($backgrounds, \"blue\");\n}\n```\n\nSee a [live example here](https://codepen.io/jbranchaud/pen/WVJrgp).\n"
  },
  {
    "path": "cursor/allow-cursor-to-be-launched-from-cli.md",
    "content": "# Allow Cursor To Be Launched From CLI\n\nIt is nice to be able to open Cursor for a specific project directly from the\nterminal like so:\n\n```bash\n$ cd ~/dev/my/project\n\n$ cursor .\n```\n\nFor the `cursor` launcher binary to be available like that, we have to find it\nand add it to the path.\n\nIt is probably located in the `/Applications` folder and within that nested down\na couple directories is a `bin` directory that contains the binary we're looking\nfor.\n\n```bash\nls /Applications/Cursor.app/Contents/Resources/app/bin\n bin/\n├──  code*\n├──  cursor*\n└──  cursor-tunnel*\n```\n\nThe `cursor` binary is what we want, so let's add that to our path. In my case,\nI'll add this to my `~/.zshrc` file.\n\n```bash\nexport PATH=\"/Applications/Cursor.app/Contents/Resources/app/bin:$PATH\"\n```\n"
  },
  {
    "path": "deno/read-in-the-contents-of-a-file.md",
    "content": "# Read In The Contents Of A File\n\nDeno offers some nice utilities out of the box like reading in the contents of\na file from the filesystem. The `readTextFile` function is available on the\n`Deno` object.\n\n```typescript\n// Read a file using Deno\nconst text: string = await Deno.readTextFile(\"./first_input.txt\");\n```\n\nYou use a top-level await with the function call and, assuming the file exists,\nit will read the contents in. In this case, I assign them to the `text`\nvariable.\n\nFor the file reading to work when the program is executed, you must use the\n`--allow-read` flag.\n\n```bash\n$ deno run --allow-read program.ts\n```\n\n[source](https://deno.land/manual@v1.14.0/examples/read_write_files)\n"
  },
  {
    "path": "devops/aliasing-an-ansible-host.md",
    "content": "# Aliasing An Ansible Host\n\nWhen specifying the hosts that Ansible can interact with in the\n`/etc/ansible/hosts` file, you can put just the IP address of the host\nserver, like so:\n\n```yml\n192.168.1.50\n```\n\nIP addresses are not particularly meaningful for a person to look at though.\nGiving it a name serves as better documentation and makes it easier to see\nwhat host servers are in play during a task.\n\nAnsible makes it easy to alias host servers. For example, we can name our\nhost `staging` like so:\n\n```yml\nstaging ansible_host=192.168.1.50\n```\n\n[source](https://docs.ansible.com/ansible/latest/inventory_guide/intro_inventory.html#inventory-aliases)\n"
  },
  {
    "path": "devops/allow-cross-origin-requests-to-include-cookies.md",
    "content": "# Allow Cross-Origin Requests To Include Cookies\n\nWhen making a cross-origin fetch request from a client (e.g. browser) to a\nserver, all kinds of CORS protections are enforced by the browser. One of those\nprotections, by default, is to avoid XSS attacks by not sending credentials\n(e.g. cookies, authorization headers or TLS client certificates) in the request\nor expose credentials to the client JavaScript code.\n\nThis is controlled by the\n[Access-Control-Allow-Credentials](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials)\nheader.\n\nIf we want to include things like cookies in the request, then we need to have\nboth the client-originating request and the server to agree to allow\ncredentials.\n\nThe client-side fetch will need to specify that credentials should be included:\n\n```javascript\nfetch(url, {\n  credentials: 'include'\n})\n```\n\nThe server, either in response to a GET or a preflight request, will need to do\ntwo things. First, the response headers need to have\n`Access-Control-Allow-Credentials` set to `true`. Second, the\n[`Access-Control-Allow-Origin`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin)\nwill need to name the specific origin (the client). In other words, the allowed\norigin cannot be set to `*`.\n\n[source](https://stackoverflow.com/a/24689738/535590)\n"
  },
  {
    "path": "devops/allow-https-through-your-ufw-firewall.md",
    "content": "# Allow HTTPS Through Your UFW Firewall\n\nUFW -- Uncomplicated Firewall -- is just what is sounds like. I have it\nrunning on a DigitalOcean box and it is only letting through traffic on\nports 80 (HTTP) and 22 (SSH). I am setting up SSL for a domain hosted on\nthis box which means I need to also let through traffic on 443 (HTTPS).\n\nThe allowed ports can be checked with the `status` command:\n\n```bash\n$ sudo ufw status\n\nStatus: active\n\nTo                         Action      From\n--                         ------      ----\nOpenSSH                    ALLOW       Anywhere\nNginx HTTP                 ALLOW       Anywhere\nOpenSSH (v6)               ALLOW       Anywhere (v6)\nNginx HTTP (v6)            ALLOW       Anywhere (v6)\n```\n\nAs we can see, `HTTPS` has not yet been allowed by `ufw`. We can _allow_\nHTTPS traffic with the `allow` command.\n\n```bash\n$ sudo ufw allow https\n```\n\nCheck the status again and see that `HTTPS` is now included in the list.\n\n[source](https://www.digitalocean.com/community/tutorials/how-to-setup-a-firewall-with-ufw-on-an-ubuntu-and-debian-cloud-server)\n\nh/t Dillon Hafer\n"
  },
  {
    "path": "devops/check-for-cached-site-association-file-for-ios.md",
    "content": "# Check For Cached Site Assocation File For iOS\n\nApple caches your [AASA (Apple App Site\nAssociation)](https://developer.apple.com/documentation/Xcode/supporting-associated-domains)\nfile periodically. This is used for signaling what site URLs should be Univeral\nLinks to your iOS app.\n\nYou can view the contents of the cached site association file by inserting your\ndomain into the end of this URL --\n`https://app-site-association.cdn-apple.com/a/v1/[domain]`.\n\nFor instance, if my app's domain is `www.my-app.com`, then I'd pull up\n`https://app-site-association.cdn-apple.com/a/v1/www.my-app.com` to see what is\ncached.\n\nAdditionally, you can run your site association file through a validator by\nentering your domain into the form at [AASA\nValidator](https://branch.io/resources/aasa-validator/).\n\n[source](https://david.y4ng.fr/implementing-and-testing-universal-links/)\n"
  },
  {
    "path": "devops/check-the-status-of-all-services.md",
    "content": "# Check The Status Of All Services\n\nIn a Linux environment, you can quickly check the status of a number of\ndifferent services. By running `[sudo] service --status-all`, the status\ncommand will be invoked for all services under the `/etc/init.d/` directory.\n\nSo, if you want to check the status of something like `nginx` or `apache`,\njust run `service --status-all` and find it in the list. The `-` symbol\nmeans it isn't running, the `+` symbol means it is up, and the `?` symbol\nmeans that it cannot determine the status.\n"
  },
  {
    "path": "devops/check-the-syntax-of-nginx-files.md",
    "content": "# Check The Syntax Of nginx Files\n\nThe syntax of [`nginx`](https://www.nginx.com/) configuration files can be a\nbit finicky. On top of that, some `nginx` server commands can fail silently.\nGet more confidence by using the following command to check for syntax\nerrors in those files:\n\n```bash\n$ [sudo] nginx -t\n```\n\nIf there is an error, you might see something like this:\n\n```bash\n$ sudo nginx -t\nnginx: [emerg] unexpected \";\" in /etc/nginx/nginx.conf:16\nnginx: configuration file /etc/nginx/nginx.conf test failed\n```\n\nIf all looks good, then you'll see this:\n\n```bash\n$ sudo nginx -t\nnginx: the configuration file /etc/nginx/nginx.conf syntax is ok\nnginx: configuration file /etc/nginx/nginx.conf test is successful\n```\n"
  },
  {
    "path": "devops/connect-to-an-rds-postgresql-database.md",
    "content": "# Connect To An RDS PostgreSQL Database\n\nYou can connect to an RDS PostgreSQL database remotely via `psql`. First,\nyou need to tell AWS that connections from your IP address are allowed. This\nis done by configuring the VPC (Virtual Private Cloud) that is associated\nwith the RDS instance. You'll need to add an inbound rule to the Security\nGroup associated with that VPC. You'll add an inbound rule that allows a\nPostgres connection on port 5432 from your IP address -- which is identified\nby a [CIDR\naddress](https://www.digitalocean.com/community/tutorials/understanding-ip-addresses-subnets-and-cidr-notation-for-networking#cidr-notation).\n\n![create inbound rule](https://i.imgur.com/Ypb9Du7.png)\n\nOnce this rule has been added to the security groups associated with the VPC\nthat is associated with your RDS instance, you'll be able to connect from\nyour machine with `psql`.\n\n```bash\n$ psql my-rds-endpoint.cbazqrhkmyo.us-east-1.rds.amazonaws.com \\\n    --port 5432 \\\n    --user rdsusername \\\n    postgres\n```\n\nAssuming the database username is `rdsusername` and the specific database is\nnamed `postgres`, you'll be prompted for that user's password and then\nconnected.\n"
  },
  {
    "path": "devops/default-rails-deploy-script-on-hatchbox.md",
    "content": "# Default Rails Deploy Script On Hatchbox\n\nI deployed a Rails app to [Hatchbox](https://hatchbox.io) recently. When\nfollowing along in the log during a deploy, I can see most of what is happening\nas part of the deploy. Though it is too verbose to look through every line. I'd\nrather see the contents of the deploy script.\n\nI did quite a bit of digging around while SSH'd into my hatchbox server, but I\ncouldn't find if or where that file might be stored.\n\nInstead, there is a [_Help Center_\narticle](https://hatchbox.relationkit.io/articles/55-what-is-the-default-rails-deploy-script)\nwhere Chris Oliver shares what is in the script.\n\n```bash\nbundle install -j $(nproc)\nyarn install\nbundle exec rails assets:precompile\n[[ -n \"${CRON}\" ]] && bundle exec rails db:migrate\n```\n\nIt does a parallelized `bundle install`, then a `yarn install` (make sure your\nproject is using `yarn.lock`), Rails asset precompilation, and then if `CRON`\nis set (Cron role is available by checking _Cron_ under _Server\nResponsibilities_ for your Hatchbox server), it will run Rails migrations.\n\nFrom app settings, the deploy script can be overridden, or pre- and post-deploy\nsteps can be added.\n"
  },
  {
    "path": "devops/determine-the-ip-address-of-a-domain.md",
    "content": "# Determine The IP Address Of A Domain\n\nThe `dig` (domain information grouper) command can be used to get more\ninformation about a domain name. To discover the IP address for a given\ndomain, invoke `dig` with the domain as an argument.\n\n```bash\n$ dig joshbranchaud.com\n\n; <<>> DiG 9.8.3-P1 <<>> joshbranchaud.com\n;; global options: +cmd\n;; Got answer:\n;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 26589\n;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0\n\n;; QUESTION SECTION:\n;joshbranchaud.com.             IN      A\n\n;; ANSWER SECTION:\njoshbranchaud.com.      86400   IN      A       198.74.60.157\n\n;; Query time: 118 msec\n;; SERVER: 75.75.75.75#53(75.75.75.75)\n;; WHEN: Sun Jan 17 22:32:18 2016\n;; MSG SIZE  rcvd: 51\n```\n\nThe *answer section* tells me that the IP address for `joshbranchaud.com` is\n`198.74.60.157`.\n\nSee `man dig` for more details.\n"
  },
  {
    "path": "devops/hatchbox-exports-env-vars-with-asdf.md",
    "content": "# Hatchbox Exports Env Vars With asdf\n\nWhen you add env vars through the [Hatchbox](https://hatchbox.io/) UI, they get\nexported to the environment of the asdf-shimmed processes. This is handled by\nthe [`asdf-vars` plugin](https://github.com/excid3/asdf-vars). That plugin\nlooks for `.asdf-vars` in the current chain of directories.\n\nI can see there are many `.asdf-vars` files:\n\n```bash\n$ find . -name \".asdf-vars\" -type f\n./.asdf-vars\n./my-app/.asdf-vars\n./my-app/releases/20250120195106/.asdf-vars\n./my-app/releases/20250121041054/.asdf-vars\n```\n\nAnd it is the one in my app's directory that contains the env vars that I set\nin the UI.\n\n```bash\n$ cat my-app/.asdf-vars\nBUNDLE_WITHOUT=development:test\nDATABASE_URL=postgresql://user_123:123456789012345@10.0.1.1/my_app_db\nPORT=9000\nRACK_ENV=production\nRAILS_ENV=production\nRAILS_LOG_TO_STDOUT=true\nRAILS_MASTER_KEY=abc123\nSECRET_KEY_BASE=abc123efg456\n```\n\nWhen I run a shimmed process like `ruby`, those env vars are loaded into the\nprocess's environment.\n\n```bash\n$ cd my-app/current\n$ which ruby\n/home/deploy/.asdf/shims/ruby\n$ ruby -e \"puts ENV['DATABASE_URL']\"\npostgresql://user_123:123456789012345@10.0.1.1/my_app_db\n```\n\n[source](https://www.visualmode.dev/hatchbox-manages-env-vars-with-asdf)\n"
  },
  {
    "path": "devops/path-of-the-packets.md",
    "content": "# Path Of The Packets\n\nYou can use `traceroute` to determine the network path packets follow from\nyour machine to some host server. For instance, if I want to know path\nbetween my laptop (connected to airport wifi) and my website\n[joshbranchaud.com](http://joshbranchaud.com), I can run the following\ncommand:\n\n```\n$ traceroute joshbranchaud.com\ntraceroute to joshbranchaud.com (198.74.60.157), 64 hops max, 52 byte packets\n 1  hotspot.boingohotspot.net (192.168.144.1)  1.209 ms  1.427 ms  1.080 ms\n 2  192.168.13.1 (192.168.13.1)  5.272 ms  3.545 ms  6.231 ms\n 3  10.106.144.1 (10.106.144.1)  13.671 ms  15.311 ms  12.895 ms\n 4  68.13.10.184 (68.13.10.184)  14.789 ms  12.980 ms  13.628 ms\n 5  68.13.8.221 (68.13.8.221)  19.922 ms  12.611 ms  17.853 ms\n 6  nyrkbprj01-ae3.0.rd.ny.cox.net (68.1.5.157)  48.917 ms  56.641 ms  51.771 ms\n 7  eqix.e-2-3.tbr2.ewr.nac.net (198.32.118.157)  62.977 ms  52.970 ms  48.667 ms\n 8  0.e1-2.tbr2.mmu.nac.net (209.123.10.114)  66.253 ms  57.311 ms  52.242 ms\n 9  207.99.53.46 (207.99.53.46)  57.478 ms  53.443 ms  54.510 ms\n10  joshbranchaud.com (198.74.60.157)  59.853 ms  56.375 ms  55.393 ms\n```\n\nSee `man traceroute` for more details.\n"
  },
  {
    "path": "devops/push-non-master-branch-to-heroku.md",
    "content": "# Push Non-master Branch To Heroku\n\nWhen using git to deploy your app to Heroku, it is expected that you push\nto the `master` branch. When you run the following command\n\n```\n$ git push heroku master\n```\n\nHeroku will attempt to build and run your app. However, if you have a\n`staging` branch for your application that you want to push to your\nstaging environment on Heroku, you cannot simply run\n\n```\n$ git push heroku staging\n```\n\nHeroku will only perform a build on pushes to the remote `master` branch.\nYou can get around this, though, by specifying that your `staging` branch\nshould be pushed to the remote `master` branch, like so\n\n```\n$ git push heroku staging:master\n```\n\n[source](https://coderwall.com/p/1xforw/make-heroku-run-a-non-master-branch)\n"
  },
  {
    "path": "devops/reload-the-nginx-configuration.md",
    "content": "# Reload The nginx Configuration\n\nIf you've modified or replaced the configuration file, nginx will not\nimmediately start using the updated nginx configuration.\nOnce a `restart` or `reload` signal is received by nginx, it\nwill apply the changes. The `reload` signal\n\n```\n$ service nginx reload\n```\n\ntells nginx to reload the configuration. It will check the validity of the\nconfiguration file and then spawn new worker processes for the latest\nconfiguration. It then sends requests to shut down the old worker processes.\nThis means that during a *reload* nginx is always up and processing\nrequests.\n\n[source](http://nginx.org/en/docs/beginners_guide.html)\n"
  },
  {
    "path": "devops/resolve-the-public-ip-of-a-url.md",
    "content": "# Resolve The Public IP Of A URL\n\nThe `dig` command is a utility for doing DNS lookups. You can run it with a\nURL argument to lookup the public IP for that domain.\n\n```bash\n$ dig joshbranchaud.com\n\n; <<>> DiG 9.8.3-P1 <<>> joshbranchaud.com\n;; global options: +cmd\n;; Got answer:\n;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62836\n;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0\n\n;; QUESTION SECTION:\n;joshbranchaud.com.             IN      A\n\n;; ANSWER SECTION:\njoshbranchaud.com.      1800    IN      A       159.203.106.229\n\n;; Query time: 50 msec\n;; SERVER: 75.75.75.75#53(75.75.75.75)\n;; WHEN: Sun Apr 14 12:34:52 2019\n;; MSG SIZE  rcvd: 51\n```\n\nThe output is a bit noisy, but if you parse down to the _ANSWER SECTION_,\nyou'll see the IP address that it resolves to.\n\nAlternatively, you can skip the noise and get right to the IP address by\nincluding the `+short` flag.\n\n```bash\n$ dig joshbranchaud.com +short\n159.203.106.229\n```\n\nSee `man dig` for more details.\n"
  },
  {
    "path": "devops/running-out-of-inode-space.md",
    "content": "# Running Out Of inode Space\n\nUnix systems have two types of storage limitations. The first, and more\ncommon, is a limitation on physical storage used for storing the contents of\nfiles. The second is a limitation on `inode` space which represents file\nlocation and other data.\n\nThough it is uncommon, it is possible to run out of `inode` space before\nrunning out of disk space (run `df` and `df -i` to see the levels of each).\nWhen this happens, the system will complain that there is `No space left on\ndevice`. Both `inode` space and disk space are needed to create a new file.\n\nHow can this happen? If lots of directories with lots of empty, small, or\nduplicate files are being created, then the `inode` space can be used up\ndisproportionately to the amount of respective disk space. You'll need to\nclean up some of those files before you can continue.\n\nSources: [this](http://blog.scoutapp.com/articles/2014/10/08/understanding-disk-inodes) and [this](http://www.linux.org/threads/intro-to-inodes.4130/)\n"
  },
  {
    "path": "devops/set-get-and-unset-env-vars-with-dokku.md",
    "content": "# Set, Get, And Unset Env Vars With Dokku\n\nThe `dokku` CLI provides `config` subcommands for managing environment variables\nfor the target container.\n\nAn env var can be set for an active container with `config:set`:\n\n```bash\n$ dokku config:set app-name JEMALLOC_ENABLED=true MALLOC_CONF=\"stats_print:true\"\n```\n\nNotice I'm able to set multiple env vars at once if needed.\n\nIf I ever need to check what an env var is currently set to for one of my app\ncontainers, I can use `config:get`:\n\n```bash\n$ dokku config:get app-name JEMALLOC_ENABLED\ntrue\n```\n\nI can always override any value with another `config:set`. However, if I need to\nentirely remove the env var, I can use `config:unset`:\n\n```bash\n$ dokku config:unset app-name MALLOC_CONF\n```\n\n[source](https://dokku.com/docs/configuration/environment-variables/)\n"
  },
  {
    "path": "devops/set-up-domain-for-hatchbox-rails-app.md",
    "content": "# Set Up Domain For Hatchbox Rails App\n\nWhen we deploy a Rails app with [Hatchbox](https://hatchbox.io), we are given\nan internal URL for publicly accessing our app. It is something like\n`https://123abc.hatchboxapp.com`. That's useful as we are getting things up and\nrunning, but eventually we want to point our own domain at the app.\n\nThe first step is to tell Hatchbox what domain we are going to use.\n\nFrom our app's _Domain & SSL_ page we can enter a domain into the _Add A\nDomain_ input. For instance, I have the\n[visualmode.dev](https://visualmode.dev) domain and I want the\n[still.visualmode.dev](https://still.visualmode.dev) subdomain pointing at my\nRails app. I submit the full name `still.visualmode.dev` and I get an _A\nRecord_ ipv4 address (e.g. `23.12.234.82`).\n\nThe second step is to configure a DNS record with our domain registrar.\n\nFrom the DNS settings of our registrar (e.g. Cloudflare) we can add an _A\nRecord_ where we specify the name (e.g. `still`) and then include the ipv4\naddress provided by Hatchbox. We can save this and wait a minute for it to\npropagate.\n\nAnd soon enough we can visit our Rails app at the custom domain.\n"
  },
  {
    "path": "devops/ssh-into-a-docker-container.md",
    "content": "# SSH Into A Docker Container\n\nBefore you can SSH into a Docker container, you need to know the name of the\ncontainer.\n\nRun\n\n```bash\n$ docker ps\n```\n\nto list the currently running containers and find the name of the one you want\nto connect to. If you don't see the one you are looking for, it may not be\nrunning.\n\nThen, you can connect to it by name with a bash session like so:\n\n```bash\n$ docker exec -it <container name> /bin/bash\n```\n\nThe\n[`-it`](http://docs.docker.oeynet.com/engine/reference/commandline/container_exec/)\nflags open an interactive emulated terminal connection. `/bin/bash` is the\ncommand that gets run in that context.\n\n[source](https://phase2.github.io/devtools/common-tasks/ssh-into-a-container/)\n"
  },
  {
    "path": "devops/ssl-certificates-can-cover-multiple-domains.md",
    "content": "# SSL Certificates Can Cover Multiple Domains\n\nWhen registering an SSL certificate, you can list multiple domains to be\ncovered by it.\n\nOne use case is registering a certificate that covers both the apex domain\n(`example.com`) and all subdomains using a wildcard (`*.example.com`). The\nwildcard alone will not cover `example.com`. If you want `example.com`,\n`www.example.com`, `blog.example.com`, etc. covered under the same certificate,\nthen you'll need to include both the apex and wildcard domains.\n"
  },
  {
    "path": "devops/wipe-a-heroku-postgres-database.md",
    "content": "# Wipe A Heroku Postgres Database\n\nIf you have some sort of non-production version of an application running on\nHeroku, you may encounter a time when you need to wipe your database and\nstart fresh. For a rails project, it may be tempting to do `heroku run rake\ndb:drop db:setup`. Heroku doesn't want you to accidentally do anything\nstupid, so it prevents you from running `rake db:drop`. Instead, you must\nsend a more explicit command\n\n```\n$ heroku pg:reset DATABASE_URL\n```\n\nHeroku will ask you to confirm that you indeed want to wipe out the database\nand will then proceed.\n\nFor the curious reader, running `heroku config` will list the values of a\nnumber of variables including `DATABASE_URL`.\n"
  },
  {
    "path": "docker/check-postgres-version-running-in-docker-container.md",
    "content": "# Check Postgres Version Running In Docker Container\n\nI have a docker container that I'm using to run a PostgreSQL development\ndatabase on my local machine. It was a while ago when I set it up, so I can't\nremember specifically which major version of PostgreSQL I am using.\n\nI use `docker ps` to list the names of each container.\n\n```bash\n$ docker ps --format \"{{.Names}}\"\nstill-postgres-1\nbetter_reads-postgres-1\n```\n\nI grab the one I am interested in. In this case, that is `still-postgres-1`.\n\nThen I can execute a `select version()` statement with `psql` against the\ncontainer with that name like so:\n\n```bash\n$ docker exec still-postgres-1 psql -U postgres -c \"select version()\";\n                                                       version                                                 \n---------------------------------------------------------------------------------------------------------------------\n PostgreSQL 16.2 (Debian 16.2-1.pgdg120+2) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit\n(1 row)\n```\n\nAnd there I have it. I'm running Postgres v16 in this container.\n"
  },
  {
    "path": "docker/configure-different-host-and-container-ports.md",
    "content": "# Configure Different Host And Container Ports\n\nA `docker-compose.yml` file that sets up something like a PostgreSQL service\nwill proxy a port from your host machine to a port on the docker container.\n\nA basic PostgreSQL service will look like this tying `5432` to `5432` under the\n`ports` section.\n\n```yaml\nversion: \"3.7\"\nservices:\n  postgres:\n    image: postgres:latest\n    restart: always\n    environment:\n      - POSTGRES_USER=postgres\n      - POSTGRES_PASSWORD=postgres\n      - POSTGRES_DB=postgres\n    ports:\n      - \"5432:5432\"\n    volumes:\n      - ./postgres-data:/var/lib/postgresql/data\n```\n\nRequests like queries from a `psql` instance that we send to `localhost:5432`\nwill be proxied to `docker-container:5432`.\n\nSince those numbers are the same on both sides, it's not necessarily clear\nwhich is which. The left is the _host_ and the right is the _container_ --\n`[host-port]:[container-port]`. \n\nIf you need to use a port other than 5432 on your host machine (e.g. maybe\nyou're running multiple Postgres servers at once), then you can just change the\nport number on the left side. How about `9876:5432`.\n"
  },
  {
    "path": "docker/list-running-docker-containers.md",
    "content": "# List Running Docker Containers\n\nThe `docker` CLI has a `ps` command that will list all running container by\ndefault.\n\nWhen I run it, I can see that I have a container running a Postgres database\nand another running a MySQL database.\n\n```bash\n$ docker ps\nCONTAINER ID   IMAGE             COMMAND                  CREATED         STATUS         PORTS                               NAMES\nba792e185734   postgres:latest   \"docker-entrypoint.s…\"   12 days ago     Up 12 days     0.0.0.0:9876->5432/tcp              better_reads-postgres-1\n7ca7c1e882e0   mysql:8.0         \"docker-entrypoint.s…\"   19 months ago   Up 8 seconds   33060/tcp, 0.0.0.0:3309->3306/tcp   some-app-db-1\n```\n\nIt lists several pieces of info about the containers: the container id, the\nimage it is based off, when it was created, the running status, the port\nconfiguration, and the name of the container\n\nIf I run `docker ps --help` I can see some additional options. One option is\nthe `--all` flag which will display all known docker container instead of just\nthe running ones.\n"
  },
  {
    "path": "docker/prevent-containers-from-running-on-startup.md",
    "content": "# Prevent Containers From Running On Startup\n\nI have a bunch of docker containers managed by Docker Desktop. Some are related\nto projects I'm actively working on. Whereas many others are inactive projects.\n\nWhen I restart my machine, regardless of which containers I had running or\nturned off, several of them are booted into a running state on startup. This is\nbecaue their restart policy is set to `always`. That's fine for the project I'm\nactively working on, but the others I would like to be _off_ by default.\n\nI need to update each of their restart policies from `always` to `no`.\n\nFirst, I need to figure out their container IDs:\n\n```bash\n$ docker ps --all\nCONTAINER ID   IMAGE                    COMMAND                  CREATED         STATUS                       PORTS                    NAMES\neb7b40aeba2d   postgres:latest          \"docker-entrypoint.s…\"   3 months ago    Up 11 minutes                0.0.0.0:9875->5432/tcp   still-postgres-1\neb9ab2213f2b   postgres:latest          \"docker-entrypoint.s…\"   3 months ago    Exited (0) 11 minutes ago                             next-drizzle-migration-repro-app-postgres-1\nba792e185734   postgres:latest          \"docker-entrypoint.s…\"   4 months ago    Up 11 minutes                0.0.0.0:9876->5432/tcp   better_reads-postgres-1\n3139f9beae76   postgres:latest          \"docker-entrypoint.s…\"   9 months ago    Exited (128) 7 months ago                             basic-next-prisma-postgres-1\n```\n\nReferencing the `CONTAINER ID` and `NAMES` columns, I'm able to then inspect\neach container and see the current `RestartPolicy`:\n\n```bash\n$ docker inspect eb9ab2213f2b | grep -A3 RestartPolicy\n\"RestartPolicy\": {\n    \"Name\": \"always\",\n    \"MaximumRetryCount\": 0\n},\n```\n\nI can then update the `RestartPolicy` to be `no`:\n\n```bash\n$ docker update --restart no eb9ab2213f2b\n```\n\nInpsecting that container again, I can see the updated policy:\n\n```bash\n$ docker inspect eb9ab2213f2b | grep -A3 RestartPolicy\n\"RestartPolicy\": {\n    \"Name\": \"no\",\n    \"MaximumRetryCount\": 0\n},\n```\n\nRinse and repeat for each of the offending containers.\n\n[source](https://stackoverflow.com/questions/45423334/stopping-docker-containers-from-being-there-on-startup)\n"
  },
  {
    "path": "docker/run-a-basic-postgresql-server-in-docker.md",
    "content": "# Run A Basic PostgreSQL Server In Docker\n\nHere is a basic `docker-compose.yml` file for spinning up a Docker container\nthat runs a PostgreSQL server on port 5432. This is what I use to create a\nlocally-running PostgreSQL server that lives inside a docker container.\n\n```yaml\nversion: \"3.7\"\nservices:\n  postgres:\n    image: postgres:latest\n    restart: always\n    environment:\n      - POSTGRES_USER=postgres\n      - POSTGRES_PASSWORD=postgres\n      - POSTGRES_DB=postgres\n    ports:\n      - \"5432:5432\"\n    volumes:\n      - ./postgres-data:/var/lib/postgresql/data\n```\n\nTo create the docker container and start it up, run the following command from\nthe same directory where you put this file:\n\n```bash\n$ docker compose up\n```\n\nThis command knows to look for the `docker-compose.yml` file though you can\nalways be explicit about the file with the `-f` option.\n\nThis configuration points at `postgres:latest` which currently is `16.1`. To\nrun a different major version, you can change the `image` to something like\n`postgres:15`. See [Docker Hub](https://hub.docker.com/_/postgres) for more\noptions.\n"
  },
  {
    "path": "docker/run-sql-script-against-postgres-container.md",
    "content": "# Run SQL Script Against Postgres Container\n\nI've been using dockerized Postgres for local development with several projects\nlately. This is typically with framework tooling (like Rails) where schema\nmigrations and query execution are handled by the tooling using the specified\nconnection parameters.\n\nHowever, I was experimenting with and iterating on some Postgres functions\noutside of any framework tooling. I needed a way to run the SQL script that\n(re)creates the function via `psql` on the docker container.\n\nWith a local, non-containerized Postgres instance, I'd redirect the file to\n`psql` like so:\n\n```bash\n$ psql -U postgres -d postgres < experimental-functions.sql\n```\n\nWhen I tried doing this with `docker exec` though, it was silently failing /\ndoing nothing. As far as I can tell, there was a mismatch with redirection\nhandling across the bounds of the container.\n\nTo get around this, I first copy the file into the `/tmp` directory on the\ncontainer:\n\n```bash\n$ docker cp experimental-functions.sql still-postgres-1:/tmp/experimental-functions.sql\n```\n\nThen the `psql` command that docker executes can be pointed directly at a\nlocal-to-it SQL file.\n\n```bash\n$ docker exec still-postgres-1 psql \\\n  -U postgres \\\n  -d postgres \\\n  -f /tmp/experimental-functions.sql\n```\n\nThere are probably other ways to handle this, but I got into a nice rhythm with\nthis file full of `create or replace function ...` definitions where I could\nmodify, copy over, execute, run some SQL to verify, and repeat.\n"
  },
  {
    "path": "dprint.json",
    "content": "{\n  \"excludes\": [\"README.md\"],\n  \"plugins\": [\"https://plugins.dprint.dev/markdown-0.16.0.wasm\"]\n}\n"
  },
  {
    "path": "drizzle/create-bigint-identity-column-for-primary-key.md",
    "content": "# Create bigint Identity Column For Primary Key\n\nUsing the Drizzle ORM with Postgres, here is how we can create a table that\nuses a [`bigint` data\ntype](https://orm.drizzle.team/docs/column-types/pg#bigint) as a primary key\n[identity\ncolumn](https://www.postgresql.org/docs/current/ddl-identity-columns.html).\n\n```typescript\nimport {\n  pgTable,\n  bigint,\n  text,\n  timestamp,\n} from \"drizzle-orm/pg-core\";\n\n// Users table\nexport const users = pgTable(\"users\", {\n  id: bigint({ mode: 'bigint' }).primaryKey().generatedAlwaysAsIdentity(),\n  email: text(\"email\").unique().notNull(),\n  name: text(\"name\").notNull(),\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n});\n```\n\nThere are a couple key pieces here:\n\n1. We import `bigint` so that we can declare a column of that type.\n2. We specify that it is a primary key with `.primaryKey()`.\n3. We declare its default value as `generated always as identity` via\n   `.generatedAlwaysAsIdentity()`.\n\nNote: you need to specify the `mode` for `bigint` or else you will see a\n`TypeError: Cannot read properties of undefined (reading 'mode')` error.\n\nIf we run `npx drizzle-kit generate` the SQL migration file that gets\ngenerated will contain something like this:\n\n```sql\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS \"users\" (\n  \"id\" bigint PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name \"users_id_seq\" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START WITH 1 CACHE 1),\n  \"email\" text NOT NULL,\n  \"name\" text NOT NULL,\n  \"created_at\" timestamp DEFAULT now() NOT NULL,\n  CONSTRAINT \"users_email_unique\" UNIQUE(\"email\")\n);\n```\n"
  },
  {
    "path": "drizzle/drizzle-tracks-migrations-in-a-log-table.md",
    "content": "# Drizzle Tracks Migrations In A Log Table\n\nWhen I generate (`npx drizzle-kit generate`) and apply (`npx drizzle-kit\nmigrate`) schema migrations against my database with Drizzle, there are SQL\nfiles that get created and run.\n\nHow does Drizzle know which SQL files have been run and which haven't?\n\nLike many SQL schema migration tools, it uses a table in the database to record\nthis metadata. Drizzle defaults to calling this table `__drizzle_migrations`\nand puts it in the `drizzle` schema (which is like a database namespace).\n\nLet's take a look at this table for a project with two migrations:\n\n```sql\npostgres> \\d drizzle.__drizzle_migrations\n                                  Table \"drizzle.__drizzle_migrations\"\n   Column   |  Type   | Collation | Nullable |                         Default\n------------+---------+-----------+----------+----------------------------------------------------------\n id         | integer |           | not null | nextval('drizzle.__drizzle_migrations_id_seq'::regclass)\n hash       | text    |           | not null |\n created_at | bigint  |           |          |\nIndexes:\n    \"__drizzle_migrations_pkey\" PRIMARY KEY, btree (id)\n\npostgres> select * from drizzle.__drizzle_migrations;\n id |                               hash                               |  created_at\n----+------------------------------------------------------------------+---------------\n  1 | 8961353bf66f9b3fe1a715f6ea9d9ef2bc65697bb8a5c2569df939a61e72a318 | 1730219291288\n  2 | b75e61451e2ce37d831608b1bc9231bf3af09e0ab54bf169be117de9d4ff6805 | 1730224013018\n(2 rows)\n```\n\nNotice that Drizzle stores each migration record as [a SHA256 hash of the\nmigration\nfile](https://github.com/drizzle-team/drizzle-orm/blob/526996bd2ea20d5b1a0d65e743b47e23329d441c/drizzle-orm/src/migrator.ts#L52)\nand a timestamp of when the migration was run.\n\n[source](https://orm.drizzle.team/docs/drizzle-kit-migrate#applied-migrations-log-in-the-database)\n"
  },
  {
    "path": "drizzle/get-fields-for-inserted-row.md",
    "content": "# Get Fields For Inserted Row\n\nWith Drizzle, we can insert a row with a set of values like so:\n\n```typescript\nawait db\n  .insert(todoItems)\n  .values({\n    title,\n    userId,\n    description,\n  })\n```\n\nThe result of this is `QueryResult<never>`. In other words, nothing useful is\ncoming back to us from the database.\n\nSometimes an insert is treated as a fire-and-forget (as long as it succeeds) or\nsince we know what data we are inserting, we don't need the database to\nresponse. But what about values that are generated or computed by the database\n-- such as an id from a sequence, timestamp columns that default to `now()`, or\ngenerated columns.\n\nTo get all the fields of a freshly inserted row, we can tack on [the\n`returning()` function](https://orm.drizzle.team/docs/insert#insert-returning)\n(which likely adds something like [`returning\n*`](https://www.postgresql.org/docs/current/dml-returning.html)) to the insert\nquery under the hood).\n\n```typescript\nawait db\n  .insert(todoItems)\n  .values({\n    title,\n    userId,\n    description,\n  })\n  .returning()\n```\n\nThis will have a return type of `Array<type todoItems>` which means that for\neach inserted row we'll have all the fields (columns) for that row.\n\nAlternatively, if we just need the generated ID for the new row(s), we can use\na partial return like so:\n\n```typescript\nawait db\n  .insert(todoItems)\n  .values({\n    title,\n    userId,\n    description,\n  })\n  .returning({ id: todoItems.id })\n```\n"
  },
  {
    "path": "elixir/all-values-for-a-key-in-a-keyword-list.md",
    "content": "# All Values For A Key In A Keyword List\n\nA keyword list in Elixir can contain the same key multiple times.\n\n```elixir\nkwl = [a: 1, b: 2, a: 3, c: 4]\n#=> [a: 1, b: 2, a: 3, c: 4]\n```\n\nThe `get/2` function will only grab the value of the first occurrence.\n\n```elixir\nKeyword.get(kwl, :a)\n#=> 1\n```\n\nYou can use `get_values/2` to retrieve _all_ values associated with the key.\n\n```elixir\nKeyword.get_values(kwl, :a)\n#=> [1, 3]\n```\n"
  },
  {
    "path": "elixir/append-to-a-keyword-list.md",
    "content": "# Append To A Keyword List\n\nIf you have two keyword lists, you can append them like so:\n\n```elixir\n> a = [a: 1]\n[a: 1]\n> b = [b: 2]\n[b: 2]\n> a ++ b\n[a: 1, b: 2]\n```\n\nBut what if something a bit more programmatic is happening and you are\nbuilding up the additions to the keyword list based on variables?\n\n```elixir\n> x = :x\n:x\n> c = a ++ [x 5]\n** (CompileError) iex:5: undefined function x/1\n    (stdlib) lists.erl:1353: :lists.mapfoldl/3\n    (stdlib) lists.erl:1354: :lists.mapfoldl/3\n```\n\nThat makes elixir think `x` is some function when in fact it is just a\nvariable containing the keyword `:x`.\n\nSimply adding a comma doesn't quite do it either.\n\n```elixir\n> c = a ++ [x, 5]\n[{:a, 1}, :x, 5]\n```\n\nWe need to wrap the internal part with curly braces to create the tuple that\ncan then be appended to `a`.\n\n```elixir\n> c = a ++ [{x, 5}]\n[a: 1, x: 5]\n```\n"
  },
  {
    "path": "elixir/assert-an-exception-is-raised.md",
    "content": "# Assert An Exception Is Raised\n\nElixir's [`ExUnit`](http://elixir-lang.org/docs.html) comes with a number of\ndifferent ways to make assertions in your tests. One of those functions is\n[`assert_raise`](http://elixir-lang.org/docs/stable/ex_unit/ExUnit.Assertions.html#assert_raise/2)\nwhich allows you to test that a particular exception is raised when the\ngiven function is invoked.\n\nUsing `assert_raise/2` looks something like this:\n\n```elixir\nassert_raise FunctionClauseError, fn ->\n  Enum.chunk([1,2,3], 0)\nend\n```\n\nThe `assert_raise/3` form is also available which allows you to test both\nthe type of exception and the resulting message.\n\n```elixir\nassert_raise FunctionClauseError, ~r/^no function clause matching/, fn ->\n  Enum.chunk([1,2,3], 0)\nend\n```\n\nUsing the regex sigil for the second argument is generally a good way to go\nto keep tests from getting too brittle.\n"
  },
  {
    "path": "elixir/binary-representation-of-a-string.md",
    "content": "# Binary Representation Of A String\n\n> A common trick in Elixir is to concatenate the null byte <<0>> to a string\n> to see its inner binary representation.\n\nA couple example of this can be seen in the following snippet of code:\n\n```elixir\n> \"hello\" <> <<0>>\n<<104, 101, 108, 108, 111, 0>>\n> \"ƒå®øü†\" <> <<0>>\n<<198, 146, 195, 165, 194, 174, 195, 184, 195, 188, 226, 128, 160, 0>>\n```\n\n[source](http://elixir-lang.org/getting-started/binaries-strings-and-char-lists.html)\n"
  },
  {
    "path": "elixir/check-for-a-substring-match.md",
    "content": "# Check For A Substring Match\n\nUsing Erlang's `:binary.match` function, you can easily check if a string\nhas a matching substring.\n\n```elixir\n> :binary.match(\"all food is good\", \"foo\")\n{4, 3}\n> :binary.match(\"all food is good\", \"bar\")\n:nomatch\n```\n\nAs you can see, the return value on a successful match is a tuple with the\nindex of where the match starts and the length of the match. If there is no\nmatch, the `:nomatch` atom is returned.\n\nSee the [`match/2` and `match/3`\ndocs](http://erlang.org/doc/man/binary.html#match-2) for more details.\n\n[source](http://stackoverflow.com/questions/35551072/how-to-find-index-of-a-substring)\n"
  },
  {
    "path": "elixir/check-list-membership.md",
    "content": "# Check List Membership\n\nYou can use the [`in` operator](https://hexdocs.pm/elixir/operators.html) to\ncheck if something appears in a list. This is a handy way of checking if a\nvariable is one of a few acceptable or expected values.\n\nFor instance, a common DateTime comparison pattern relies on this to check\nif a DateTime is `>=` or `<=` to another DateTime.\n\n```elixir\n{:ok, datetime} = DateTime.from_naive(~N[2016-05-24 13:26:08.003], \"Etc/UTC\")\n\nDateTime.compare(datetime, DateTime.utc_now()) in [:lt, :eq]\n```\n\nAlternatively, you can check that something does not have membership in a\nlist by also including the `not` operator.\n\n```elixir\nDateTime.compare(datetime, DateTime.utc_now()) not in [:lt, :eq]\n```\n"
  },
  {
    "path": "elixir/comparing-datetime-structs.md",
    "content": "# Comparing DateTime Structs\n\n> Remember, comparisons in Elixir using ==/2, >/2, </2 and friends are\n> structural and based on the DateTime struct fields. For proper comparison\n> between datetimes, use the compare/2 function.\n\nAs the [DateTime docs](https://hexdocs.pm/elixir/DateTime.html) say, you'll\nwant to use [`compare/2`](https://hexdocs.pm/elixir/DateTime.html#compare/2)\nin order to accurately compare two `DateTime` structs.\n\n```elixir\n{:ok, older} = DateTime.from_naive(~N[2016-05-24 13:26:08.003], \"Etc/UTC\")\n{:ok, newer} = DateTime.from_naive(~N[2017-11-24 13:26:08.003], \"Etc/UTC\")\n\nDateTime.compare(older, newer)\n#=> :lt\n\nDateTime.compare(newer, older)\n#=> :gt\n\nDateTime.compare(newer, newer)\n#=> :eq\n```\n\nWhen using `compare/2`, you'll get one of `:lt`, `:gt`, or `:eq` as a\nresult, meaning _less than_, _greater than_, or _equal_ respectively.\n"
  },
  {
    "path": "elixir/compute-intermediate-values-in-a-with-construct.md",
    "content": "# Compute Intermediate Values In A With Construct\n\nThe expressions you use in a `with` construct do not have to contain the\n`<-` syntax. You can pattern match and bind values along the way as well.\n\n```elixir\nwith %{id: id} <- get_user(),\n     url = \"/api/#{id}/blogs\",\n     %{status_code: 200, body: body} <- HTTPoison.get(url),\n     {:ok, decoded_body} <- Poison.decode(body) do\n  {:ok, decoded_body}\nend\n```\n\nIn the above (sorta contrived) example we were able to construct a URL in\nthe middle of the series of expressions.\n\nThe values we compute inline will be closed into the `with` construct, so\nthey won't leak.\n\nSee the [`with`\ndocs](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#with/1) for more\ndetails.\n"
  },
  {
    "path": "elixir/compute-md5-digest-of-a-string.md",
    "content": "# Compute md5 Digest Of A String\n\nTo compute the md5 digest of a string, we can use Erlang's top-level `md5`\nfunction.\n\n```elixir\n> :erlang.md5(\"#myelixirstatus\")\n<<145, 148, 139, 99, 194, 176, 105, 18, 242, 246, 37, 69, 142, 69, 226, 199>>\n```\n\nThis, however, gives us the result in the raw binary representation. We\nwould like it in a base 16 encoding, as md5 digests tend to be.\n\nWe can wrap (or pipe) this with `Base.encode16` to get the result we are\nlooking for.\n\n```elixir\n> Base.encode16(:erlang.md5(\"#myelixirstatus\"), case: :lower)\n\"91948b63c2b06912f2f625458e45e2c7\"\n```\n\n[source](https://gist.github.com/10nin/5713366#gistcomment-1445219)\n"
  },
  {
    "path": "elixir/counting-records-with-ecto.md",
    "content": "# Counting Records With Ecto\n\nSometimes you want to know how many records there are in a table. Ecto gives\nus a couple ways to approach this.\n\nWe can use the\n[`count\\1`](https://hexdocs.pm/ecto/Ecto.Query.API.html#count/1) function\nthat the Ecto query API provides.\n\n```elixir\n> Repo.one(from p in \"people\", select: count(p.id))\n\n16:09:52.759 [debug] QUERY OK source=\"people\" db=1.6ms\nSELECT count(p0.\"id\") FROM \"people\" AS p0 []\n168\n```\n\nAlternatively, we can use the\n[`fragment/1`](https://hexdocs.pm/ecto/Ecto.Query.API.html#fragment/1)\nfunction to use PostgreSQL's `count` function.\n\n```elixir\n> Repo.one(from p in \"people\", select: fragment(\"count(*)\"))\n\n16:11:19.818 [debug] QUERY OK source=\"people\" db=1.5ms\nSELECT count(*) FROM \"people\" AS p0 []\n168\n```\n\nLastly, `Ecto.Repo` has the\n[`aggregate/4`](https://hexdocs.pm/ecto/Ecto.Repo.html#c:aggregate/4)\nfunction which provides a `:count` option.\n\n```elixir\n> Repo.aggregate(from(p in \"people\"), :count, :id)\n\n16:11:23.786 [debug] QUERY OK source=\"people\" db=1.7ms\nSELECT count(p0.\"id\") FROM \"people\" AS p0 []\n168\n```\n"
  },
  {
    "path": "elixir/create-a-date-with-the-date-sigil.md",
    "content": "# Create A Date With The Date Sigil\n\nElixir 1.3 introduced a new sigil for creating dates, `~D`. It works in the\nsame way as Date's\n[`new/3`](http://elixir-lang.org/docs/stable/elixir/Date.html#new/3)\nfunction producing the Date struct with each of the date parts.\n\n```elixir\n> ~D[2016-01-01]\n~D[2016-01-01]\n> ~D[2016-01-01].year\n2016\n> ~D[2016-01-01].month\n1\n> ~D[2016-01-01].day\n1\n```\n"
  },
  {
    "path": "elixir/create-a-list-of-atoms.md",
    "content": "# Create A List Of Atoms\n\nThe `~w` sigil makes it easy to create a word list -- a list of strings --\nwhere each word is separated by a space.\n\n```elixir\n> ~w(bulbasaur charmander squirtle)\n[\"bulbasaur\", \"charmander\", \"squirtle\"]\n```\n\nBy appending an `a` onto that sigil construct, you are instructing Elixir\nthat you would instead like a list of atoms.\n\n```elixir\n> ~w(bulbasaur charmander squirtle)a\n[:bulbasaur, :charmander, :squirtle]\n```\n\n[source](http://elixir-lang.org/getting-started/sigils.html#strings)\n"
  },
  {
    "path": "elixir/creating-a-pid.md",
    "content": "# Creating A PID\n\nOften times, when invoking a function that spawns a process, the PID of the\nspawned process is returned and we bind to it. That PID is a reference to\nsome BEAM process in our system.\n\nWe can create our own references using the `pid/3` function.\n\nLet's assume we have the following processes, among others, in our system at\nthe moment.\n\n```elixir\n> Process.list |> Enum.reverse |> Enum.take(3)\n[#PID<0.284.0>, #PID<0.283.0>, #PID<0.282.0>]\n```\n\nWe can create a reference to any of them using the three number parts that\nthey are made up of.\n\n```elixir\n> pid(0, 284, 0)\n#PID<0.284.0>\n```\n\nSee, it's alive.\n\n```elixir\n> pid(0, 284, 0) |> Process.alive?\ntrue\n```\n\nWhat if we make up a PID that doesn't actually reference any process?\n\n```elixir\n> pid(0, 333, 0) |> Process.alive?\nfalse\n```\n\nNote: there is also a `pid/1` version of the function. See `h pid` for more\ndetails.\n"
  },
  {
    "path": "elixir/creating-indexes-with-ecto.md",
    "content": "# Creating Indexes With Ecto\n\nUsing indexes in the right places within relational databases is a great way\nto speed up queries.\n\nTo add a basic index in an Ecto migration, use `Ecto.Migration.index\\2`:\n\n```elixir\ncreate index(:users, [:email])\n```\n\nCreating a composite index doesn't require jumping through any hoops; just\nput the relevant column names in the list:\n\n```elixir\ncreate index(:posts, [:user_id, :title])\n```\n\nSee `h Ecto.Migration.index` for more details.\n"
  },
  {
    "path": "elixir/defining-multiple-clauses-in-an-anonymous-function.md",
    "content": "# Defining Multiple Clauses In An Anonymous Function\n\nAnonymous functions often take the approach of doing a single thing with the\ninputs, regardless of their shape or values. There is no need to limit\nourselves though. The same pattern matching that we use all over our Elixir\nprograms can be utilized to define multiple clauses in an anonymous function\nas well.\n\nConsider the following example:\n\n```elixir\niex> my_function = fn\n  {:ok, x} -> \"Everything is ok: #{x}\"\n  {:error, x} -> \"There was an error: #{x}\"\nend\n#Function<6.52032458/1 in :erl_eval.expr/5>\n```\n\nWe can then invoke our anonymous function using the bound variable to see\nwhat results we get with different kinds of inputs.\n\n```elixir\niex> my_function.({:ok, 123})\n\"Everything is ok: 123\"\niex> my_function.({:error, \"be warned\"})\n\"There was an error: be warned\"\n```\n\n[source](http://stackoverflow.com/a/18023790/535590)\n"
  },
  {
    "path": "elixir/determine-the-latest-release-of-a-hex-package.md",
    "content": "# Determine The Latest Release Of A Hex Package\n\nI will often pop open the browser and do a Google search in order to figure\nout the latest release of a package when adding it to my dependencies.\nHowever, lately I've been getting in the habit of using a quicker approach.\nThe `mix` CLI has a way of looking up info about a package and we don't have\nto leave the terminal to use it.\n\nFor instance, if I need to determine the latest version of the `postgrex`\npackage, I can run the following command.\n\n```bash\n$ mix hex.info postgrex\nPostgreSQL driver for Elixir.\n\nConfig: {:postgrex, \"~> 0.12.0\"}\nReleases: 0.12.0, 0.11.2, 0.11.1, 0.11.0, 0.10.0, 0.9.1, 0.9.0, 0.8.4, 0.8.3, 0.8.2, ...\n\nMaintainers: Eric Meadows-Jönsson, James Fish\nLicenses: Apache 2.0\nLinks:\n  Github: https://github.com/elixir-ecto/postgrex\n```\n\nThe third line gives me the info I need (`{:postgrex, \"~> 0.12.0\"}`) and it\nis already formatted as a tuple that I can paste right into my `mix.exs`\nfile.\n"
  },
  {
    "path": "elixir/do-you-have-the-time-part-2.md",
    "content": "# Do You Have The Time? - Part 2\n\nIn [_Do You Have The\nTime?_](https://github.com/jbranchaud/til/blob/master/elixir/do-you-have-the-time.md),\nI demonstrated a way of using an Erlang function to get at and work with\ntime in Elixir. As of Elixir 1.3, there is now a [`Time`\nmodule](http://elixir-lang.org/docs/stable/elixir/Time.html) that provides a\nsigil and some functions for working with time.\n\nWe can use Elixir's `Time` module to simplify the example from the previous\niteration of this TIL:\n\n```elixir\ndefmodule TickTock do\n  def current_time do\n    Time.from_erl!(:erlang.time)\n    |> Time.to_string\n  end\nend\n\n> TickTock.current_time\n\"19:58:12\"\n```\n"
  },
  {
    "path": "elixir/do-you-have-the-time.md",
    "content": "# Do You Have The Time?\n\nElixir doesn't come with any standard ways of getting at or working with\ntime. There are packages like [Timex](https://github.com/bitwalker/timex)\nout there that we can pull in to our projects. However, if we don't have\nneed for a full-featured date/time library, we can opt for a simpler\nsolution.\n\nErlang can give us the time.\n\n```elixir\ndefmodule TickTock do\n  def current_time do\n    {hh,mm,ss} = :erlang.time\n    \"#{hh}:#{mm}:#{ss}\"\n  end\nend\n\n> TickTock.current_time\n\"11:47:13\"\n```\n"
  },
  {
    "path": "elixir/documentation-lookup-with-vim-and-alchemist.md",
    "content": "# Documentation Lookup With Vim And Alchemist\n\n_Which argument position is the accumulator for `Enum.reduce/3`?_\n\n_How does `group_by` work?_\n\nI find myself fairly frequently jumping from vim to Chrome to do Google\nsearches for Elixir standard lib documentation. It gets the job done, but it\nis kinda slow and I'd prefer to avoid the context switch.\n\nWith [alchemist.vim](https://github.com/slashmili/alchemist.vim), Elixir\ndocumentation lookup is at your finger tips. Just move the cursor over the\nmodule or function you are curious about and hit `K` (from normal mode).\n\nCurious about `Enum.reduce`? Type it out in your current Vim buffer, move\nthe cursor over it, and hit `K`.\n"
  },
  {
    "path": "elixir/dynamically-generating-atoms.md",
    "content": "# Dynamically Generating Atoms\n\n> Atoms are constants where their name is their own value.\n\nThe use of atoms like `:ok` and `:error` show up all over the place in\nElixir. These are atoms that tend to be statically defined. Atoms can also\nbe dynamically defined using string interpolation.\n\nFor example, I can generate a handful of atoms by mapping over a range of\nintegers.\n\n```elixir\n> Enum.map(1..5, &(:\"some_atom_#{&1}\"))\n[:some_atom_1, :some_atom_2, :some_atom_3, :some_atom_4, :some_atom_5]\n```\n"
  },
  {
    "path": "elixir/execute-raw-sql-in-an-ecto-migration.md",
    "content": "# Execute Raw SQL In An Ecto Migration\n\nIf you are performing a database migration with\n[Ecto](https://hexdocs.pm/ecto/Ecto.html), perhaps the most straightforward\napproach is to use Ecto's DSL. However, the DSL may not always be the best\nchoice. Being able to write raw SQL gives you more control. It will also\nenable you to use database features that may not be directly or easily\navailable through the DSL.\n\nRaw SQL can be included in a Ecto migration with a combination of Elixir's\nheredoc syntax and the [`Ecto.Migration#execute/1`\nfunction](https://hexdocs.pm/ecto/Ecto.Migration.html#execute/1). You'll\nalso need to provide both an `up` and `down` function to ensure that your\nmigrations are reversible.\n\n```elixir\ndefmodule MyApp.Repo.Migrations.CreatePostsTable do\n  use Ecto.Migration\n\n  def up do\n    execute \"\"\"\n      create table posts (\n        id serial primary key,\n        title varchar not null,\n        body varchar not null default '',\n        inserted_at timestamptz not null default now(),\n        updated_at timestamptz not null default now()\n      );\n    \"\"\"\n  end\n\n  def down do\n    execute \"drop table posts;\"\n  end\nend\n```\n"
  },
  {
    "path": "elixir/expose-internal-representation.md",
    "content": "# Expose Internal Representation\n\nElixir is a language that has strong support for metaprogramming. It\nprovides easy access to an internal representation of the code in the form\nof an Abstract Syntax Tree (AST) using maps and keyword lists. The `quote`\nmacro is used to expose this internal representation.\n\n```elixir\n> quote do: 2 * 2\n{:*, [context: Elixir, import: Kernel], [2, 2]}\n> quote do: 2 * 2 == 4\n{:==, [context: Elixir, import: Kernel],\n [{:*, [context: Elixir, import: Kernel], [2, 2]}, 4]}\n```\n\n[source](http://elixir-lang.org/getting-started/meta/quote-and-unquote.html)\n"
  },
  {
    "path": "elixir/include-captures-with-string-split.md",
    "content": "# Include Captures With String.split\n\nThe\n[`String.split/3`](http://elixir-lang.org/docs/stable/elixir/String.html#split/3)\nfunction comes with two options: `trim` and `parts`. However, when using it\nwith a regex pattern, you gain access to a couple extra options, including\n`include_captures`. This is because when used with a regex pattern,\n`String.split` just invokes `Regex.split` which comes with extra options\nlike `include_captures`.\n\nHere is `String.split` in action by itself and with the supported `trim`\noption.\n\n```elixir\n> String.split(\"23d\", ~r/\\d+/)\n[\"\", \"d\"]\n> String.split(\"23d\", ~r/\\d+/, trim: true)\n[\"d\"]\n```\n\nAdding in the `include_captures` option, we get a resulting list that\nincludes the value captured by the splitting regex.\n\n```\n> String.split(\"23d\", ~r/\\d+/, trim: true, include_captures: true)\n[\"23\", \"d\"]\n```\n\nThis isn't a documented feature, so it is only supported as long as\n`Regex.split` supports it and as long as `String.split` continues to\ndelegate to `Regex.split`.\n\nh/t Chris Erin\n"
  },
  {
    "path": "elixir/inspecting-the-process-message-queue.md",
    "content": "# Inspecting The Process Message Queue\n\nA core tenant of Elixir is message passing between processes. So, if a\nprocess is sent a message, where does that message go? What happens if it\ngets sent many messages? The `Process.info/2` function allows us to inspect\nthe message queue.\n\nFirst, let's send some messages (to ourself) and then keep an eye on the\nlength of the message queue as we go.\n\n```elixir\n> send self(), {:error, \"this is bad\"}\n{:error, \"this is bad\"}\n> Process.info(self(), :message_queue_len)\n{:message_queue_len, 1}\n> send self(), {:hello, \"world\"}\n{:hello, \"world\"}\n> Process.info(self(), :message_queue_len)\n{:message_queue_len, 2}\n```\n\nNow, I am curious what those specific messages are. Let's ask\n`Process.info/2` for the messages that are in the message queue.\n\n```elixir\n> Process.info(self(), :messages)\n{:messages, [error: \"this is bad\", hello: \"world\"]}\n```\n\nThere are a lot of other things that `Process.info/2` can tell us about a\nprocess. See [the Erlang docs for\n`process_info`](http://erlang.org/doc/man/erlang.html#process_info-2) for\nmore details.\n"
  },
  {
    "path": "elixir/list-functions-for-a-module.md",
    "content": "# List Functions For A Module\n\nDuring an `iex` session, I can do a little introspection on modules using\neither the\n[`__info__/1`](http://elixir-lang.org/docs/stable/elixir/Module.html#__info__/1)\nfunction or Erlang's\n[`module_info/0`](http://erlang.org/doc/man/erlang.html#module_info-0)\nfunction. In particular, I can pass `:functions` to either one to get a list\nof the functions for that module.\n\nThis is what `__info__/1` looks like for the functions of the `List`\nmodule:\n\n```elixir\n> List.__info__(:functions)\n[delete: 2, delete_at: 2, duplicate: 2, first: 1,\n flatten: 1, flatten: 2, foldl: 3, foldr: 3, insert_at: 3,\n keydelete: 3, keyfind: 3, keyfind: 4, keymember?: 3,\n keyreplace: 4, keysort: 2, keystore: 4, keytake: 3,\n last: 1, replace_at: 3, to_atom: 1, to_existing_atom: 1,\n to_float: 1, to_integer: 1, to_integer: 2, to_string: 1,\n to_tuple: 1, update_at: 3, wrap: 1, zip: 1]\n```\n\n[source](http://stackoverflow.com/questions/28664119/in-elixir-is-there-any-way-to-get-a-module-to-list-its-functions)\n"
  },
  {
    "path": "elixir/listing-files-in-iex.md",
    "content": "# Listing Files In IEx\n\nWhen you start an IEx session, you do so in the context of some directory --\nthe current working directory. This context can be important if you need to\ndo something like import a file. In fact, you may want to know what files\nare available in the current working directory.\n\nYou can list them all out within IEx using `ls/0`.\n\n```elixir\niex(1)> ls()\n           .git     .gitignore      README.md         _build         assets         config\n           deps            lib        mix.exs       mix.lock           priv           test\n            tmp\n```\n\nYou can also list the contents of some other specific directory by naming it\nwhen invoking `ls/1`.\n\nSee `h()` within IEx for more details.\n"
  },
  {
    "path": "elixir/match-on-a-map-in-a-with-construct.md",
    "content": "# Match On A Map In A With Construct\n\nMany usage example of the\n[`with`](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#with/1)\nconstruct show a series of matches on a tuple.\n\n```elixir\nwith {:ok, width} <- Map.fetch(opts, :width),\n     {:ok, height} <- Map.fetch(opts, :height) do\n  {:ok, width * height}\nend\n```\n\nYou can match on more than just tuples though. Here is how you might match\non a map.\n\n```elixir\nwith %{status_code: 200, body: body} <- HTTPoison.get!(url),\n     {:ok, decoded_body} <- Poison.decode(body) do\n  {:ok, decoded_body}\nend\n```\n\nIn fact, you have the full power of Elixir's pattern matching available to\nyou in your series of matches for a `with` construct.\n"
  },
  {
    "path": "elixir/passing-around-and-using-modules.md",
    "content": "# Passing Around And Using Modules\n\nA module is a bag of functions. When we define a module, we are tying it to\nan atom. If we pass around the atom that references this module, then we can\nuse it to call its functions.\n\nFor example, consider two types of greetings:\n\n```elixir\ndefmodule Hello do\n  def get_greeting do\n    \"Hello, World!\"\n  end\nend\n\ndefmodule Hola do\n  def get_greeting do\n    \"Hola, Mundo!\"\n  end\nend\n```\n\nAnd a generic greeting module that accepts a language module:\n\n```elixir\ndefmodule Greeting do\n  def say_hello(language_module) do\n    language_module.get_greeting\n    |> IO.puts\n  end\nend\n\nGreeting.say_hello(Hello) # => \"Hello, World!\"\nGreeting.say_hello(Hola) # => \"Hola, Mundo!\"\n```\n\nThe module reference that we pass in to `Greeting.say_hello` can be used to\ninvoke the `get_greeting` function.\n"
  },
  {
    "path": "elixir/pattern-matching-in-anonymous-functions.md",
    "content": "# Pattern Matching In Anonymous Functions\n\nPattern matching shows up everywhere in Elixir, even where you may not be\nexpecting it. When declaring an anonymous function, you can use pattern\nmatching against different sets and shapes of input parameters to invoke\ndifferent behaviors.\n\nHere is an example of how you might use this:\n\n```elixir\n> handle_result = fn\n  {:ok, result} -> IO.puts \"The result is #{result}\"\n  :error -> IO.puts \"Error: couldn't find anything\"\nend\n#Function<6.50752066/1 in :erl_eval.expr/5>\n\n> Map.fetch(%{a: 1}, :a) |> handle_result.()\nThe result is 1\n:ok\n> Map.fetch(%{a: 1}, :b) |> handle_result.()\nError: couldn't find anything\n:ok\n```\n\n[source](https://elixirschool.com/lessons/basics/functions#pattern-matching)\n"
  },
  {
    "path": "elixir/pipe-into-a-case-statement.md",
    "content": "# Pipe Into A Case Statement\n\nThe standard use of a case statement looks something like this:\n\n```elixir\ncase HTTPoison.get(url) do\n  {:ok, %HTTPoison.Response{status_code: 200, body: body}} ->\n    IO.puts body\n  {:ok, %HTTPoison.Response{status_code: 404}} ->\n    IO.puts \"Not found :(\"\n  {:error, %HTTPoison.Error{reason: reason}} ->\n    IO.inspect reason\nend\n```\n\nIf you are a fan of the pipe syntax, then you may enjoying writing the above\nlike this:\n\n```elixir\nurl\n|> HTTPoison.get()\n|> case do\n  {:ok, %HTTPoison.Response{status_code: 200, body: body}} ->\n    IO.puts body\n  {:ok, %HTTPoison.Response{status_code: 404}} ->\n    IO.puts \"Not found :(\"\n  {:error, %HTTPoison.Error{reason: reason}} ->\n    IO.inspect reason\nend\n```\n\nJust like any function, the value from the previous line in the pipe will be\npassed in and used as the value switched over in the case statement.\n"
  },
  {
    "path": "elixir/quitting-iex.md",
    "content": "# Quitting IEx\n\nThere are two ways to quit out of an Interactive Elixir shell. The standard\nway is with `Ctrl-c`. This gives you a list of options, one of which is `a`\nfor _abort_. This will terminate your IEx session and drop you back on the\ncommand line where the process started.\n\nAdditionally, IEx also understands `Ctrl-\\` which is control key that will\nterminate just about any interactive environment. This command will cause\nIEx to immediately exit with no prompt.\n\nNote: IEx does not, however, respond to `Ctrl-d`.\n\n[source](http://blog.plataformatec.com.br/2016/03/how-to-quit-the-elixir-shell-iex/)\n"
  },
  {
    "path": "elixir/range-into-list-using-comprehensions.md",
    "content": "# Range Into List Using Comprehensions\n\nUsing an _identity_ comprehension and the `:into` option, we can easily\nconvert a range into a list.\n\n```elixir\n> for x <- 1..10, into: [], do: x\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n```\n\nCheck out [the docs for the `:into`\noption](http://elixir-lang.org/getting-started/comprehensions.html#the-into-option)\nfor more details.\n"
  },
  {
    "path": "elixir/refer-to-a-module-within-itself.md",
    "content": "# Refer To A Module Within Itself\n\nElixir comes with the `__MODULE__` reserve word for referencing a module\nwithin itself. This is handy for things like structs.\n\n```elixir\ndefmodule SomeNamespace.MyModule do\n  defstruct [:id]\n\n  def do_thing(%__MODULE__{}=thing) do\n    # ...\n  end\nend\n```\n\nYou can use an alias in order to ditch `__MODULE__` and perhaps make your\ncode a bit more human readable.\n\n```elixir\ndefmodule SomeNamespace.MyModule do\n  alias __MODULE__, as: MyModule\n\n  defstruct [:id]\n\n  def do_thing(%MyModule{}=thing) do\n    # ...\n  end\nend\n```\n"
  },
  {
    "path": "elixir/referencing-values-in-iexs-history.md",
    "content": "# Referencing Values In IEx's History\n\nEach time we execute a statement in an `iex` session, the counter is\nincremented. These numbers are references to the history of the session. We\ncan use these references to _refer_ to previously executed values using\n`v/1`. This is particularly handy for multi-line statements or when we\nforget to bind to the result of some function.\n\nConsider the following `iex` session:\n\n```elixir\niex(1)> :one\n:one\niex(2)> 1 + 1\n2\niex(3)> \"three\" |> String.to_atom()\n:three\n```\n\nIf we execute `v()` on its own, it is the same as `v(-1)` in that it will\ngive us the latest value in the history.\n\n```elixir\niex(4)> v()\n:three\n```\n\nProviding any positive number will refer to the references we see next to\neach statement.\n\n```elixir\niex(5)> v(1)\n:one\n```\n\nNegative numbers, as we saw with `v(-1)`, will count backwards in the\nhistory from where we are.\n\n```elixir\niex(6)> v(-4)\n2\n```\n\nSee `h v` for more details.\n"
  },
  {
    "path": "elixir/remove-one-list-from-another.md",
    "content": "# Remove One List From Another\n\nThe `--/2` operator allows you to subtract two lists, that is, remove all\nelements in the _right_ list from the _left_ list. Each occurrence of an\nelement is removed if there is a corresponding element. If there is no\ncorresponding element, it is ignored.\n\nHere are some examples.\n\n```elixir\n> [1, 2, 3] -- [2, 4]\n[1, 3]\n> [:a, :b, :c, :a, :d, :a] -- [:a, :a]\n[:b, :c, :d, :a]\n```\n\nThis kind of list operation is not particularly efficient, so for large\nlists it can be quite slow. The following example took several minutes to\nrun.\n\n```elixir\n> Enum.into(1..1000000, []) -- Enum.into(2..1000000, [])\n[1]\n```\n\nTo achieve a true set difference, you'll note that the docs for this\noperator recommend checking out `MapSet.difference/2`.\n\nSee `h Kernel.--` for more details.\n"
  },
  {
    "path": "elixir/replace-duplicates-in-a-keyword-list.md",
    "content": "# Replace Duplicates In A Keyword List\n\nUse the\n[`Keyword.put`](http://elixir-lang.org/docs/stable/elixir/Keyword.html#put/3)\nfunction to replace duplicate key entries in a keyword list.\n\nIf there are no duplicate entries, the entry will just be added.\n\n```elixir\nKeyword.put([a: 1], :b, 2)\n[b: 2, a: 1]\n```\n\nIf there is a duplicate entry, it will be replaced by the new value.\n\n```elixir\n> Keyword.put([b: 1, a: 1], :b, 2)\n[b: 2, a: 1]\n```\n\nIf there are multiple duplicate entries, they will all be replaced.\n\n```elixir\n> Keyword.put([b: 3, b: 4, a: 1], :b, 2)\n[b: 2, a: 1]\n```\n"
  },
  {
    "path": "elixir/requiring-keys-for-structs.md",
    "content": "# Requiring Keys For Structs\n\nWhen defining a\n[`struct`](http://elixir-lang.org/getting-started/structs.html) in Elixir,\nwe may want to ensure that certain values are provided. We can require that\ncertain keys are used in the creation of a struct with the\n[`@enforce_keys`](https://hexdocs.pm/elixir/Kernel.html#defstruct/1)\nattribute. Here is an example of a `Name` struct.\n\n```elixir\ndefmodule Name do\n  @enforce_keys [:first, :last]\n  defstruct [:first, :middle, :last]\nend\n```\n\nWith this defined, we can create a struct that uses all of the keys.\n\n```elixir\n> jack = %Name{first: \"Jack\", middle: \"Francis\", last: \"Donaghy\"}\n%Name{first: \"Jack\", last: \"Donaghy\", middle: \"Francis\"}\n```\n\nWe can also ignore `:middle` and just provide the required keys.\n\n```elixir\n> liz = %Name{first: \"Liz\", last: \"Lemon\"}\n%Name{first: \"Liz\", last: \"Lemon\", middle: nil}\n```\n\nWe cannot, however, omit any of the keys specified in `@enforce_keys`. If we\ndo omit any of them, Elixir will raise an error.\n\n``` elixir\n> tracy = %Name{first: \"Tracy\"}\n** (ArgumentError) the following keys must also be given when building struct Name: [:last]\n    expanding struct: Name.__struct__/1\n    iex:6: (file)\n```\n"
  },
  {
    "path": "elixir/reversing-a-list-part-2.md",
    "content": "# Reversing A List - Part 2\n\nIn [Reversing A List](reversing-a-list.md), I showed how Erlang's\n`:lists.reverse()` function could be used to reverse a list. Since then,\nElixir now has a built-in function for reversing lists. In fact, it works\nwith anything that implements the `Enumerable` protocol.\n\n```elixir\n> Enum.reverse([1,2,3,4,5])\n[5, 4, 3, 2, 1]\n> Enum.reverse(%{a: 1, b: 2, c: 3})\n[c: 3, b: 2, a: 1]\n```\n"
  },
  {
    "path": "elixir/reversing-a-list.md",
    "content": "# Reversing A List\n\nTo efficiently work with and _transform_ lists in Elixir, you will likely\nneed utilize a list reversing function from time to time. Your best bet is\nto reach for the Erlang implementation which is available as part of the\n`lists` module.\n\nHere are a couple examples of how to use it:\n\n```elixir\n> :lists.reverse([1,2,3])\n[3, 2, 1]\n> :lists.reverse([1, :a, true, \"what\", 5])\n[5, \"what\", true, :a, 1]\n```\n\nNote: though I said \"_transform_ lists\" above, what is actually going on is\nthat a new version of the list representing my transformation is being\ncreated, per Elixir's functional nature.\n"
  },
  {
    "path": "elixir/root-directory-of-a-project.md",
    "content": "# Root Directory Of A Project\n\nDo you need the root directory of an elixir project? The\n[`File.cwd!/0`](http://elixir-lang.org/docs/stable/elixir/File.html#cwd!/0)\nfunction can help.\n\n```elixir\niex> File.cwd!\n\"/home/dev/code/my_app\"\n```\n\nKeep in mind though, this will only work reliably with projects that are\ncompiled using Mix.\n\n[source](https://groups.google.com/forum/#!msg/elixir-lang-talk/Ls0eJDdMMW8/1Lmg5K2MAQAJ)\n"
  },
  {
    "path": "elixir/round-floats-to-integers.md",
    "content": "# Round Floats To Integers\n\nThe\n[`Float.round/2`](http://elixir-lang.org/docs/stable/elixir/Float.html#round/2)\nfunction allows you to round floating point numbers. The result is another\nfloating point number.\n\n```elixir\n> Float.round(1.5)\n2.0\n> Float.round(1.3)\n1.0\n```\n\nIf, instead, you always want an integer as the result of rounding, you can\nuse `Kernel`'s version of a rounding function:\n\n```elixir\n> Kernel.round(1.5)\n2\n> Kernel.round(1.3)\n1\n```\n\nThe\n[`Kernel.round/1`](http://elixir-lang.org/docs/stable/elixir/Kernel.html#round/1)\nfunction accepts both integers and floats, and always returns an integer.\nAdditionally, it can be used in guard tests.\n"
  },
  {
    "path": "elixir/run-exunit-tests-in-a-deterministic-order.md",
    "content": "# Run ExUnit Tests In A Deterministic Order\n\nWhen running a file of\n[`ExUnit`](http://elixir-lang.org/docs/stable/ex_unit/ExUnit.html) tests,\nthey will be executed in a pseudo-random order based on a seed value. In\ngeneral, `ExUnit` will pick a random seed each time you run your tests. If\nyou'd like to add some determinism to the order that your tests run in, you\ncan specify the seed in the `ExUnit` configuration.\n\n```elixir\nExUnit.configure seed: 42\nExUnit.start\n\ndefmodule AssertionTest do\n  use ExUnit.Case, async: true\n\n  test \"the truth\" do\n    assert true\n  end\n\n  test \"more truth\" do\n    assert 2 + 2 = 4\n  end\nend\n```\n\n[source](https://til.hashrocket.com/posts/4a7dc5fd94-run-exunit-tests-in-the-order-they-are-defined)\n\nh/t Chris Erin\n"
  },
  {
    "path": "elixir/run-the-test-at-a-specific-line-number.md",
    "content": "# Run The Test At A Specific Line Number\n\nYou can tell `mix test` to only run tests that appear in a specific file by\nnaming the file:\n\n```bash\n$ mix test test/module/file_test.exs\n```\n\nYou can even point it to a specific line number in that file like so:\n\n```bash\n$ mix test test/module/file_test.exs:45\n```\n\nBehind the scenes, `mix test` is using tags to build a list of exclusions\nand inclusions that result in only the test at line 45 running. Here is an\nequivalent of the above command:\n\n```bash\n$ mix test test/module/file_test.exs --exclude test --include line:45\n```\n\nThis will exclude every test. It will then re-include the test that\ncorresponds to having a tag `line:45`.\n"
  },
  {
    "path": "elixir/same-functions-should-be-grouped-together.md",
    "content": "# Same Functions Should Be Grouped Together\n\nA favorite feature of Elixir is the function clauses that can be defined in\nmultiple ways with pattern matching. I've always grouped same-named function\nclauses together. It seems like good form and it's what I see everyone else\ndoing. It also makes for readable, maintainable code.\n\nThis is more than just personal preference though. It is the correct,\nidiomatic way to organize your Elixir function clauses. The compiler will\nlet you know if anything gets out of place.\n\nConsider the following snippet of code:\n\n```elixir\ndefmodule MeterToLengthConverter do\n  def convert(:feet, m), do: m * 3.28084\n  def convert(:inch, m), do: m * 39.3701\n  def hello(), do: IO.puts \"Hello, World!\"\n  def convert(:yard, m), do: m * 1.09361\nend\n```\n\nIt is syntactically correct, so it will compile. However, the compiler will\nemit a warning like the following:\n\n```\nwarning: clauses for the same def should be grouped together, def convert/2\nwas previously defined (length_converter.ex:2)\n  length_converter.ex:5\n```\n"
  },
  {
    "path": "elixir/skip-a-specific-test.md",
    "content": "# Skip A Specific Test\n\nElixir's `ExUnit` supports all kinds of tags for customizing the behavior of\nyour test suite. The `:skip` tag signals that `ExUnit` should skip over that\nspecific test.\n\n```elixir\n@tag :skip\ntest \"this is a test that should not run\" do\n  assert false\nend\n```\n\nWhen you run `mix test`, it will make sure to not execute any tests with the\n`:skip` tag.\n\nUsing the `:skip` tag can be a great temporary measure in a lot of\nsituations. It is not a good long-term practice to keep these around and\ncheck them in.\n"
  },
  {
    "path": "elixir/string-interpolation-with-just-about-anything.md",
    "content": "# String Interpolation With Just About Anything\n\nComing to Elixir from Ruby, I am used to being able to interpolate literally\n_anything_ into a string. In Elixir, this is not the case.\n\n> By default, it handles strings, atoms (including nil, true, false and\n> module name aliases like String – which are all just atoms behind the\n> scenes), integers, floats, and some lists. That's it.\n\nThere are two approaches you can take to interpolate everything else into a\nstring. The easier approach is to use\n[`Kernel.inspect/2`](http://elixir-lang.org/docs/stable/elixir/Kernel.html#inspect/2).\n\n```elixir\n> IO.puts \"A map #{inspect %{a: 1, b: 2}}\"\nA map %{a: 1, b: 2}\n```\n\nThe other approach is to implement the `String.Chars` protocol for the thing\nthat you are trying to print. You can read more about that in [_Elixir\nString Interpolation for\nRubyists_](http://thepugautomatic.com/2016/01/elixir-string-interpolation-for-the-rubyist/).\n"
  },
  {
    "path": "elixir/unique-indexes-with-ecto.md",
    "content": "# Unique Indexes With Ecto\n\nYou can create a unique index in a migration for one or more columns using\nthe\n[`unique_index/3`](https://hexdocs.pm/ecto/Ecto.Migration.html#unique_index/3)\nfunction.\n\nFor example, if you are creating a join table for `followers` and want to\nensure that duplicate _follower_ entries are prevented, you may want to\ninclude a unique index like so:\n\n```elixir\ncreate table(:followers) do\n  add :followed_user, references(:users), null: false\n  add :following_user, references(:users), null: false\nend\n\ncreate unique_index(:followers, [:followed_user, :following_user])\n```\n\nKeep in mind that `unique_index/3` is a shorthand for\n[`index/3`](https://hexdocs.pm/ecto/Ecto.Migration.html#index/3) when you\nset `unique: true`.\n"
  },
  {
    "path": "elixir/updating-values-in-a-map.md",
    "content": "# Updating Values In A Map\n\nWhen working with maps in any language, you often need a way to update\nkey-value pairs. Furthermore, you will need a way to handle keys that are\nnot already present in the map, generally associating some default value.\n\nIn Elixir, the `Map` module provides the `get_and_update/3` function as a\nway of accomplishing such a task.\n\nYou need to provide the map, the key to be fetched and updated, and a\nfunction for _transforming_ (or updating) the existing value.\n\nLet's use a score counting example to see it in action:\n\n```elixir\n> scores = %{}\n%{}\n# jake scores a point\n> {_, scores} = Map.get_and_update(scores, :jake, fn(x) -> {x, (x || 0) + 1} end)\n{nil, %{jake: 1}}\n# chris scores a point\n> {_, scores} = Map.get_and_update(scores, :chris, fn(x) -> {x, (x || 0) + 1} end)\n{nil, %{chris: 1, jake: 1}}\n# jake scores another point\n> {_, scores} = Map.get_and_update(scores, :jake, fn(x) -> {x, (x || 0) + 1} end)\n{1, %{chris: 1, jake: 2}}\n# final scores\n> scores\n%{chris: 1, jake: 2}\n```\n\nWe use `(x || 0) + 1` as the updated value. This is a simple way of\nproviding a default value for when the key is not already present in the\nmap.\n\nThe update function is expected to return a tuple with the _original_ value\nand the _updated_ value.\n\nSee [the\ndocs](http://elixir-lang.org/docs/stable/elixir/Map.html#get_and_update/3)\nfor more details.\n"
  },
  {
    "path": "elixir/using-when-clauses-in-a-with-construct.md",
    "content": "# Using When Clauses In A With Construct\n\nBecause Elixir's `with` construct supports the full power of the language's\npattern matching, we can use `when` clauses to further narrow down our\nmatches.\n\nFor instance, if we want to match against the response to an API request,\nbut only for response status codes in the 2xx range, we can do something\nlike the following:\n\n```elixir\nwith %{status_code: code, body: body}\n       when code >= 200 && code < 300 <- HTTPoison.get!(url),\n     {:ok, decoded_body} <- Poison.decode(body) do\n  {:ok, decoded_body}\nend\n```\n\nSee the [docs for\n`with`](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#with/1) for more\ndetails.\n"
  },
  {
    "path": "elixir/virtual-fields-with-ecto-schemas.md",
    "content": "# Virtual Fields With Ecto Schemas\n\nIf you'd like to include a particular key-value pair in an Ecto changeset,\nit needs to be included as a field in the schema. In the case of something\nakin to a password field, you want to be able to perform validations against\nit, but the password itself does not have a column in the database. In other\nwords, you want to use the password in memory as part of the validation\nprocess but not save it to the database. To accomplish this, you need to\nspecify that it is a `virtual` field.\n\n```elixir\nschema \"users\" do\n  field :username, :string\n  field :password_digest, :string\n  field :password, :string, virtual: true\nend\n```\n\nWith that schema, you can then validate the `:password` and transform it\ninto the corresponding `:password_digest` field.\n\n```elixir\ndef registration_changeset(model, params) do\n  model\n  |> changeset(params)                  # do other standard validations\n  |> cast(params, [:password])          # include :password in the changeset\n  |> validate_length(:password, min: 8) # validations\n  |> put_pass_hash()                    # transform into :password_digest\nend\n```\n"
  },
  {
    "path": "elixir/when-things-dont-match-the-with-statements.md",
    "content": "# When Things Don't Match The With Statements\n\nYou set up a series of match statements in a `with` construct as a way of\navoiding a bunch of nested if statements. Inevitably you will be passing\ndata through that doesn't meet all of the match criteria. By default, the\n`with` construct will short circuit and your program will continue from\nthere.\n\nYou can, however, take more control over how you handle the _failure_ cases\nby employing an `else` block. The `else` block works a lot like a case\nstatement.\n\n```elixir\nwith %{status_code: 200, body: body} <- HTTPoison.get!(url),\n     {:ok, decoded_body} <- Poison.decode(body) do\n  {:ok, decoded_body}\nelse\n  %{status_code: 401} ->\n    reauthenticate()\n  _ ->\n    log_error()\nend\n```\n\nHere we are able to anticipate a _failure_ case and respond accordingly. For\neverything else, we have a generic action that we take.\n\nSee the [docs for\n`with`](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#with/1) for more\ndetails.\n"
  },
  {
    "path": "elixir/word-lists-for-atoms.md",
    "content": "# Word Lists For Atoms\n\nThe `~w` sigil works similarly to Ruby's `%w` (word array notation). It\nallows you to create a list of words (i.e. strings).\n\n```elixir\n> ~w(one two three)\n[\"one\", \"two\", \"three\"]\n```\n\nIt sets itself apart though with some modifiers. The default behavior\nmatches the `s` modifier (for strings).\n\n```elixir\n> ~w(one two three)s\n[\"one\", \"two\", \"three\"]\n```\n\nWhere it gets more interesting is with the `a` modifier allowing you to\ncreate a list of atoms.\n\n```elixir\n> ~w(one two three)a\n[:one, :two, :three]\n```\n\nNote: there is a third modifier, `c`, for char lists.\n\n```elixir\n> ~w(one two three)c\n['one', 'two', 'three']\n```\n\n[source](http://elixir-lang.org/getting-started/sigils.html)\n"
  },
  {
    "path": "gatsby/add-javascript-to-body-of-the-document.md",
    "content": "# Add JavaScript To Body Of The Document\n\nSometimes your JavaScript script tag needs to be placed in the body of the\ndocument. Like inside the `<body>` tag toward the bottom. With Gatsby you don't\nhave direct access to the outer HTML document without copying it out of the\ncache.\n\nAnd you don't need to copy it out of the cache. Gatsby offers an SSR\n(server-side rendering) API for rendering content into various parts of the\ndocument. Here is how we can use the\n[`onRenderBody`](https://www.gatsbyjs.org/docs/ssr-apis/#onRenderBody) callback\nto add a `<script>` tag to the end of the body.\n\n```javascript\n// gatsby-ssr.js\nimport React from \"react\"\n\nexport const onRenderBody = ({ setPostBodyComponents }) => {\n  return setPostBodyComponents([\n    <script src=\"https://some-3rd-party-script.js\"></script>,\n  ])\n}\n```\n\n`onRenderBody` provides several functions including `setPostBodyComponents`.\nThis takes an array of React fragments that will be injected at the bottom of\nthe document body.\n\n[source](https://github.com/gaearon/overreacted.io/pull/55/files)\n"
  },
  {
    "path": "git/accessing-a-lost-commit.md",
    "content": "# Accessing A Lost Commit\n\nIf you have lost track of a recent commit (perhaps you did a reset), you\ncan generally still get it back. Run `git reflog` and look through the\noutput to see if you can find that commit. Note the sha value associated\nwith that commit. Let's say it is `39e85b2`. You can peruse the\ndetails of that commit with `git show 39e85b2`.\n\nFrom there, the utility belt that is git is at your disposal. For\nexample, you can `cherry-pick` the commit or do a `rebase`.\n"
  },
  {
    "path": "git/add-a-range-of-filenames-to-gitignore.md",
    "content": "# Add A Range Of Filenames To gitignore\n\nThe `.gitignore` file is a file where you can list files that should be ignored\nby git. This will prevent them from showing up in diffs, `git status`, etc.\nMost entries in the `.gitignore` file will plainly correspond to a single file.\n\n```\n# ignore env var files\n.env\n.env.local\n```\n\nSometimes a project has a bunch of similarly named files. Autogenerated files\nare a prime example. For instance, a web app project may contain several\nsitemap files with incrementing suffix values (i.e. `sitemap-1.xml`,\n`sitemap-2.xml`, `sitemap-3.xml`, ...).\n\nI'd like to avoid having to type those all out in my `.gitignore` file. And I\ndon't want to have to add new entries whenever another increment of the file is\ngenerated.\n\nI can handle all the current ones and future ones in a single line using some\nrange pattern matching supported by the `.gitignore` file format.\n\n```\n# ignore sitemap files\npublic/sitemap-[1-99].xml\n```\n\nThis will ignore any sitemap files suffixed with 1 to 99. I don't really expect\nthere to ever be more than handful of those files, so _99_ should definitely do\nthe trick.\n\n[source](https://www.golinuxcloud.com/gitignore-examples/#5_Examples_of_pattern_matching_in_gitignore)\n"
  },
  {
    "path": "git/add-only-tracked-files-from-a-directory.md",
    "content": "# Add Only Tracked Files From A Directory\n\nThe two extremes of staging files in a git repo are to either selectively pick\neach individual chunk of changes with `git add --patch` (my preference!) or to\nrun `git add -A` to add everything.\n\nNow let's say I have large directory full of files that get generated during\ntest runs. Most of these files are tracked (already checked in to the\nrepository). There are also many new files generated as part of the most recent\ntest run.\n\nI want to stage the changes to files that are already tracked, but hold off on\ndoing anything with the new files.\n\nRunning `git add spec/cassettes` won't do the trick because that will pull in\neverything. Running `git add --patch spec/cassettes` will take long and be\ntedious. Instead what I want is the `-u` flag. It's short for _update_ which\nmeans it will only stage already tracked files.\n\n```bash\n$ git add -u spec/cassettes\n```\n\nThat will stage every change to any already known files in `spec/cassettes`.\n\nSee `man git-add` for more details.\n"
  },
  {
    "path": "git/amend-author-of-previous-commit.md",
    "content": "# Amend Author Of Previous Commit\n\nThe author of the previous commit can be amended with the following command\n\n```bash\n$ git commit --amend --author \"Don Draper <ddraper@sterlingcooper.com>\" \n```\n\n[source](http://stackoverflow.com/questions/750172/change-the-author-of-a-commit-in-git)\n"
  },
  {
    "path": "git/auto-squash-those-fixup-commits.md",
    "content": "# Auto-Squash Those Fixup Commits\n\nAs a fan of [atomic commits](https://dev.to/jbranchaud/atomic-commits-4hk2), I\nsometimes find myself with some changes that are ready to stage that belong on\nan earlier commit. If it is the immediately previous, I'll do an `--amend`. For\nanything further back than that, I've come to love the use of `git commit\n--fixup <SHA>`.\n\nOnce one or more _fixup_ commits are on the current branch, they'll need to be\n_squashed_ into the commits for which they've been targeted. This calls for a\n`git rebase`.\n\nGit knows how to squash fixup commits into the correct place, but you have to\ntell it to do so automatically. You can do that one of two ways.\n\nYou can either include the `--autosquash` flag each time you rebase:\n\n```bash\n$ git rebase -i --autosquash\n```\n\nOr you can tell Git to always autosquash in your `~/.gitconfig`:\n\n```\n[rebase]\n\tautoSquash = true\n```\n\nSee the section on `--autosquash` in `man git-rebase` for more details.\n"
  },
  {
    "path": "git/better-diffs-with-delta.md",
    "content": "# Better Diffs With Delta\n\nA `git diff` from the command line is relatively bare bones. It shows you\nremoved lines and added lines that make up a changeset with the former text in\nred and the later text in green. All other contextual text is in white. I've\nfound this to be good enough for most of the life of my git usage. I've been\nmissing out though.\n\nBy using [`delta`](https://github.com/dandavison/delta) as the pager and diff\nfilter for `git`, I get a bunch of nice visual improvements.\n\n- Removals and additions are red and green shaded backgrounds\n- Syntax highlighting for most languages\n- Highlight specific part of a line that has changed\n- Visual spacing and layout is clearer\n\nTo get all of this, all I had to do was install `delta`:\n\n```bash\n$ brew install delta\n```\n\nAnd then add `delta` as both the _core_ pager and `diffFilter` in my global git\nconfig file:\n\n```\n[core]\n\tpager = delta\n[interactive]\n\tsingleKey = true # unrelated, but nice to have\n\tdiffFilter = delta --color-only\n```\n\nIt's also recommended that you use `zdiff3` for your merge conflict style,\nwhich I already had:\n\n```\n[merge]\n\tconflictstyle = zdiff3\n```\n\nOnce you have ths all configred, try a `git diff` or `git add --patch` and see\nhow much more visual info you get.\n"
  },
  {
    "path": "git/caching-credentials.md",
    "content": "# Caching Credentials\n\nWhen public key authentication isn't an option, you may find yourself typing\nyour password over and over when pushing to and pulling from a remote git\nrepository. This can get tedious. You can get around it by configuring git\nto cache your credentials. Add the following lines to the `.git/config` file\nof the particular project.\n\n```\n[credential]\n    helper = cache --timeout=300\n```\n\nThis will tell git to cache your credentials for 5 minutes. Use a much\nlarger number of seconds (e.g. 604800) to cache for longer.\n\nAlternatively, you can execute the command from the command line like so:\n\n```bash\n$ git config credential.helper 'cache --timeout=300'\n```\n\n[source](http://git-scm.com/docs/git-credential-cache)\n"
  },
  {
    "path": "git/change-the-start-point-of-a-branch.md",
    "content": "# Change The Start Point Of A Branch\n\nMore than a few times I have checked out a new branch against, say, `develop`\nwhen I instead meant to base it off `qa`. I've tried what felt like the obvious\nsolution.\n\n```bash\n❯ git checkout qa\n❯ git checkout -b new-branch\nfatal: A branch named 'new-branch' already exists.\n```\n\nGit won't allow this. The fix I tend to go with is to delete the branch, move\nto my intended starting point, and check it out anew.\n\nHere is another approach. The `git checkout` command offers the `-B` flag which\nwill save me a step.\n\n```bash\n❯ git checkout -B new-branch\nSwitched to and reset branch 'new-branch'\n```\n\nUse this with caution. Any commits that have been applied to the subject branch\nwill be reset (read: wiped out) in the process.\n\nSee `man git-checkout` for more details.\n"
  },
  {
    "path": "git/check-how-a-file-is-being-ignored.md",
    "content": "# Check How A File Is Being Ignored\n\nThere are a few places on your machine where you can specify the files that git\nshould ignore. The most common is a repository's `.gitignore` file. The other\nplaces those excludes are specified can be more obscure. Fortunately, `git\ncheck-ignore` is a command that can show you specifically where.\n\nFor instance, let's check why my `notes.md` file is being ignored.\n\n```bash\n$ git check-ignore -v .DS_Store\n.git/info/exclude:7:notes.md   notes.md\n```\n\nAt some point I added it to my repo's `.git/info/exclude` file. The `-v` flag\n(_verbose_) when included with `check-ignore` tells me the file location.\n\nHow about these pesky `.DS_Store` directories? How are those being ignored?\n\n```bash\n$ git check-ignore -v .DS_Store\n/Users/jbranchaud/.gitignore:3:.DS_Store        .DS_Store\n```\n\nAh yes, I had added it to my _global exclude file_ which I've configured in\n`~/.gitconfig` to be the `~/.gitignore` file.\n\nSee `man git-check-ignore` for more details.\n"
  },
  {
    "path": "git/check-if-a-file-has-changed-in-a-script.md",
    "content": "# Check If A File Has Changed In A Script\n\nIf I'm at the command line and I want to check if a file has changed, I can run\n`git diff` and see what has changed. If I want to be more specific, I can run\n`git diff README.md` to see if there are changes to that specific file.\n\nIf I'm trying to do this check in a script though, I want the command to clearly\ntell the script _Yes_ or _No_. Usually a script looks for an exit code to\ndetermine what path to take. But as long as `git diff` runs successfully,\nregardless of whether or not their are changes, it is going to have an\naffirmative exit code of `0`.\n\nThis is why `git diff` offers the `--exit-code` flag.\n\n> Make the program exit with codes similar to diff(1). That is, it exits with 1\n> if there were differences and 0 means no differences.\n\nWith that in mind, we can wire up a script with `git diff` that takes different\npaths depending on whether or not there are changes.\n\n```bash\nif ! git diff --exit-code README.md; then\n  echo \"README.md has changes\"\nelse\n  echo \"README.md is clean\"\nfi\n```\n\nWe can take this a step further and instead use the `--quiet` flag.\n\n> Disable all output of the program. Implies --exit-code. Disables execution of\n> external diff helpers whose exit code is not trusted\n\nThis exhibits the same behavior as `--exit-code` and goes the additional step of\nsilencing diff output and disabling execution of external diff helpers like\n`delta`.\n\nSee `man git-diff` for more details.\n"
  },
  {
    "path": "git/check-if-a-file-is-under-version-control.md",
    "content": "# Check If A File Is Under Version Control\n\nThe `git ls-files` command can be used with the `--error-unmatch` flag to check\nif a file is under version control. It does this by checking if any of the\nlisted files appears on the _index_. If any does not, it is treated as an error.\n\nIn a project, I have a `README.md` that is under version control. And I have\n`node_modules` that shouldn't be under version control (which is why they are\nlisted in my `.gitignore` file). I can check the README and a file somewhere in\n`node_modules`.\n\n```bash\n❯ git ls-files --error-unmatch README.md\nREADME.md\n\n❯ git ls-files --error-unmatch node_modules/@ai-sdk/anthropic/CHANGELOG.md\nerror: pathspec 'node_modules/@ai-sdk/anthropic/CHANGELOG.md' did not match any file(s) known to git\nDid you forget to 'git add'?\n```\n\nNotice the second command results in an error because of the untracked\n`CHANGELOG.md` file in `node_modules`.\n\nHere is another example of this at work while specifying multiple files:\n\n```bash\n❯ git ls-files --error-unmatch README.md node_modules/@ai-sdk/anthropic/CHANGELOG.md package.json\nREADME.md\npackage.json\nerror: pathspec 'node_modules/@ai-sdk/anthropic/CHANGELOG.md' did not match any file(s) known to git\nDid you forget to 'git add'?\n```\n\nEach tracked file gets listed and then the untracked file results in an error.\n\nSee `man git-ls-files` for more details.\n"
  },
  {
    "path": "git/checking-commit-ancestry.md",
    "content": "# Checking Commit Ancestry\n\nI have two commit shas and I want to know if the first is an ancestor of the\nsecond. Put another way, is this first commit somewhere in the history of\nthis other commit.\n\nGit's `merge-base` command combined with the `--is-ancestor` flag makes\nanswering this question easy. Furthermore, because it is a plumbing command,\nit can be used in a script or sequence of commands as a switch based on the\nanswer.\n\nHere is an example of this command in action:\n\n```bash\n$ git merge-base --is-ancestor head~ head && echo 'yes, it is'\nyes, it is\n$ git merge-base --is-ancestor head~ head~~ && echo 'yes, it is'\n```\n\nIn the first command, `head~` is clearly an ancestor of `head`, so the\n`echo` command is triggered. In the second, `head~` is not an ancestor of\n`head~~` so the return status of 1 short-circuits the rest of the command.\nHence, no `echo`.\n\nSee `man git-merge-base` for more details.\n\n[source](http://stackoverflow.com/questions/18345157/how-can-i-tell-if-one-commit-is-an-ancestor-of-another-commit-or-vice-versa)\n"
  },
  {
    "path": "git/checkout-old-version-of-a-file.md",
    "content": "# Checkout Old Version Of A File\n\nWhen you want to return to a past version of a file, you can reset to a past\ncommit. When you don't want to abandon a bunch of other changes, this isn't\ngoing to cut it. Another option is to just checkout the particular file as\nit was at the time of a past commit.\n\nIf the sha of that past commit is `72f2675` and the file's name is\n`some_file.rb`, then just use checkout like so:\n\n```\n$ git checkout 72f2675 some_file.rb\n```\n"
  },
  {
    "path": "git/checkout-previous-branch.md",
    "content": "# Checkout Previous Branch\n\nGit makes it easy to checkout the last branch you were on.\n\n```bash\n$ git checkout -\n```\n\nThis is shorthand for `git checkout @{-1}` which is a way of referring to\nthe previous (or last) branch you were on. You can use this trick to easily\nbounce back and forth between `master` and a feature branch.\n\n[source](http://stackoverflow.com/questions/7206801/is-there-any-way-to-git-checkout-previous-branch)\n"
  },
  {
    "path": "git/cherry-pick-a-range-of-commits.md",
    "content": "# Cherry Pick A Range Of Commits\n\nGit's `cherry-pick` command allows you to specify a range of commits to be\ncherry picked onto the current branch. This can be done with the `A..B`\nstyle syntax -- where `A` is the older end of the range.\n\nConsider a scenario with the following chain of commits: `A - B - C - D`.\n\n```bash\n$ git cherry-pick B..D\n```\n\nThis will cherry pick commits `C` and `D` onto `HEAD`. This is because the\nlower-bound is exclusive. If you'd like to include `B` as well. Try the\nfollowing:\n\n```bash\n$ git cherry-pick B^..D\n```\n\nSee `man git-cherry-pick` for more details.\n"
  },
  {
    "path": "git/cherry-pick-multiple-commits-at-once.md",
    "content": "# Cherry Pick Multiple Commits At Once\n\nI've always thought of `git cherry-pick` as being a command that you can run\nagainst a single commit by specifying the SHA of that commit. That's how I've\nalways used it.\n\nThe man page for `git-cherry-pick` plainly states:\n\n> Given one or more existing commits, apply the change each one introduces,\n> recording a new commit for each.\n\nWe can cherry pick multiple commits at once in a single command. They will be\napplied one at a time in the order listed.\n\nHere we can see an example of applying two commits to the current branch and\nthe accompanying output as they are auto-merged.\n\n```bash\n$ git cherry-pick 5206af5 6362f41\nAuto-merging test/services/event_test.rb\n[jb/my-feature-branch 961f3deb] Use the other testing syntax\n Date: Fri May 2 10:50:14 2025 -0500\n 1 file changed, 7 insertions(+), 7 deletions(-)\nAuto-merging test/services/event_test.rb\n[jb/my-feature-branch b15835d0] Make other changes to the test\n Date: Fri May 2 10:54:48 2025 -0500\n 1 file changed, 7 insertions(+), 7 deletions(-)\n```\n\nIf the commits cannot be cleanly merged, then you may need to do some manual\nresolution as they are applied. Or maybe you want to try including the\n`-Xpatience` merge strategy.\n\nSee `man git-cherry-pick` for more details. Make sure to look at the _Examples_\nsection which contains much more advanced examples beyond what is shown above.\n"
  },
  {
    "path": "git/clean-out-all-local-branches.md",
    "content": "# Clean Out All Local Branches\n\nSometimes a project can get to a point where there are so many local\nbranches that deleting them one by one is too tedious. This one-liner can\nhelp:\n\n```\n$ git branch --merged master | grep -v master | xargs git branch -d\n```\n\nThis won't delete branches that are unmerged which saves you from doing\nsomething stupid, but can be annoying if you know what you are doing. If you\nare sure you want to wipe everything, just use `-D` like so:\n\n```\n$ git branch --merged master | grep -v master | xargs git branch -D\n```\n\n[source](https://twitter.com/steveklabnik/status/583055065868447744)\n"
  },
  {
    "path": "git/clean-out-working-copy-with-patched-restore.md",
    "content": "# Clean Out Working Copy With Patched Restore\n\nI sometimes let the working copy of my projects get a little messy. The working\ncopy is all the changes I've made to tracked files that haven't been staged or\ncommited.\n\nAfter working for a bit, especially on something more exploratory, I end up\nwith comments, log statements, and debugging calls scattered across a bunch of\nfiles.\n\nIf these exploratory changes are mixed in with a bunch of actual changes, it\ncan create a lot noise. I can clean up that noise by restoring the files. I can\nbe surgical about it with the `--patch` flag.\n\n```bash\n$ git restore --patch\n```\n\nThis will prompt me for each changeset.\n\n- `y` -- yes, restore that change\n- `n` -- no, leave it there\n- `q` -- bail out of the restore\n\nThere are other _patch_ options, but these are the ones I use the most. To see\nwhat the rest of the options are, go to `man git-add` and find `patch` in the\n`INTERACTIVE MODE` section.\n"
  },
  {
    "path": "git/clean-up-old-remote-tracking-references.md",
    "content": "# Clean Up Old Remote Tracking References\n\nAfter working on a Git-versioned project for a while, you may find that\nthere are a bunch of references to remote branches in your local repository.\nYou know those branches definitely don't exist on the remote server and\nyou've removed the local branches, but\nyou still have references to them lying around. You can reconcile this\ndiscrepancy with one command:\n\n```bash\n$ git fetch origin --prune\n```\n\nThis will prune all those non-existent remote tracking references which is\nsure to clean up your git log (`git log --graph`).\n\n[source](http://stackoverflow.com/a/3184742/535590)\n"
  },
  {
    "path": "git/clear-entries-from-git-stash.md",
    "content": "# Clear Entries From Git Stash\n\nI often stash changes as I'm moving between branches, rebasing, or pulling in\nchanges from the remote. Usually these are changes that I will want to restore\nwith a `git stash pop` in a few moments.\n\nHowever, sometimes these stashed changes are abandoned to time.\n\nWhen I run `git stash list` on an active project, I see that there are nine\nentries in the list. When I do `git show stash@{0}` and `git show stash@{1}` to\nsee the changes that comprise the latest two entries, I don't see anything I\ncare about.\n\nI can get rid of those individual entries with, say, `git stash drop\nstash@{0}`.\n\nBut I'm pretty confident that I don't care about any of the nine entries in my\nstash list, so I want to _clear_ out all of them. I can do that with:\n\n```bash\n$ git stash clear\n```\n\nNow when I run `git stash list`, I see nothing.\n\nSee `man git-stash` for more details.\n"
  },
  {
    "path": "git/clone-a-repo-just-for-the-files-without-history.md",
    "content": "# Clone A Repo Just For The Files, Without History\n\nThough the history of a Git repository is a huge part of its value, sometimes\nyou just want a copy of the files for the current state of the main branch.\n\nUsing the `--depth` flag with `git-clone` allows you to clone a repo without\nits history. You can do that with a depth of `1` which will clone the top of\nthe tree and exclude all the past history.\n\n```bash\n$ git clone --depth 1 git@github.com:jbranchaud/til.git\n```\n\nIf you do a `git log` after this, you'll see there is only one commit in the\nhistory. Depending on the size and history of the repo, you may notice that the\nclone is quicker than one that includes the full history.\n\nSee `man git-clone` for more details.\n"
  },
  {
    "path": "git/clone-a-repo-locally-from-git.md",
    "content": "# Clone A Repo Locally From .git\n\nIf you want to get a clean copy of a repository that you have locally, there\nis no need to go over the wire cloning it from the remote. You can clone\nfrom a local copy.\n\n```bash\n$ git clone my-repo/.git path/to/fresh-copy\n```\n\nSee `man git-clone` for more details.\n"
  },
  {
    "path": "git/configure-global-gitignore-file.md",
    "content": "# Configure Global gitignore File\n\nThere are some files that you know you'll never want tracked by git. You don't\neven want them showing up as an option. For these files, it can be nice to\nspecify them in a global `.gitignore` file. Then you don't need to specify them\nfor each project.\n\nThis can be configured in `~/.gitconfig` under the `core` settings as\n`excludesFile`.\n\n```\n[core]\n\texcludesFile = ~/.gitignore\n```\n\nThen, create `~/.gitignore` (that's as good a place as any to put it).\n\n```\n# global .gitignore\n.DS_Store\nwip_notes.md\n```\n\nYou'll now notice that for any git project, the files you listed won't be\nshowing up in the untracked list.\n\nYou can also add this to your `~/.gitconfig` with this one-line command.\n\n```bash\n$ git config --global core.excludesfile ~/.gitignore\n```\n\nSee `man git-config` and search `core.excludesFile` for more details.\n"
  },
  {
    "path": "git/configuring-the-pager.md",
    "content": "# Configuring The Pager\n\nWhen you run Git commands that produce a bunch of output, Git will use a\npager to present the content starting at the beginning, rather than spitting\nit all out to the screen at once. This will almost always come in handy for\ncommands like `git-diff` and `git-log`.\n\nBy default, Git uses `less` as its pager.\n\nYou can also choose to configure it to something else by updating your git\nconfig file or by running the following command:\n\n```bash\n$ git config --global core.pager 'more'\n```\n\nIf you'd like to turn the pager off altogether, set it to a blank string.\n\n```bash\n$ git config --global core.pager ''\n```\n\n[source](https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration)\n"
  },
  {
    "path": "git/copy-a-file-from-another-branch.md",
    "content": "# Copy A File From Another Branch\n\nAfter doing some work on a large feature branch, I wanted to split out some of\nthe work into a separate smaller branch to create an initial PR. There were\nseveral files on the feature branch that I knew needed to be part of this\nsmaller branch.\n\nTo bootstrap this smaller branch, I need to check it out from main and then\ncopy over the needed files.\n\nFirst, let's create a fresh branch:\n\n```bash\n$ git branch --show-current\nlarge-feature-branch\n\n$ git checkout main\n$ git checkout -b new-smaller-branch\n```\n\nNow I can start pulling over the files I care about:\n\n```bash\n$ git checkout large-feature-branch some/file/ICareAbout.js\n```\n\nThis form of `git-checkout` looks on the specified branch for the specified\nfile and copies that over to the index.\n\nNote: this will copy over any local, working tree changes that you've made to\nthe named file.\n"
  },
  {
    "path": "git/count-all-files-of-specific-type-tracked-by-git.md",
    "content": "# Count All Files Of Specific Type Tracked By Git\n\nI want to get a count of all the markdown files in my [TIL\nrepo](https://github.com/jbranchaud/til). Since all the files I care about are\ntracked by `git`, I can use `git ls-files` to get a listing of all files. That\ncommand on its own lists all files tracked by your git repository. Though there\nare many other flags we can apply, that will do for my purposes.\n\nBy giving `git ls-files` a pattern to match against, I can turn up just, for\ninstance, markdown files (`*.md`). I can pipe that to `wc -l` to get a count\nrather than exploding my terminal with a list of file names.\n\n```bash\n❯ git ls-files '*.md' | wc -l\n    1503\n```\n\nThat command includes `README.md` and `CONTRIBUTING.md`, but really I only want\nto count the markdown files that constitute a TIL. Those all happen to be\nnested under a single directory. So I can tweak the glob pattern like so:\n\n```bash\n❯ git ls-files '*/*.md' | wc -l\n    1501\n```\n\nSee `man git-ls-files` for more details.\n"
  },
  {
    "path": "git/count-number-of-commits-on-a-branch.md",
    "content": "# Count Number Of Commits On A Branch\n\nThe `git rev-list` command will show all commits that fit the given revision\ncriteria. By adding in the `--count` flag, we get a count of the number of\ncommits that would have been displayed. Knowing this, we can get the count of\ncommits for the current branch like so:\n\n```bash\n$ git rev-list --count HEAD\n4\n```\n\nThis finds and counts commits from `HEAD` (usually the top of the current\nbranch) all the back in reverse chronological order to the beginning of the\nbranch (typically the beginning of the repository). This works exactly as\nexpected for a the `main` branch.\n\nWhat about when we are on a feature branch though?\n\nLet's say we've branched off `main` and made a few commits. And now we want the\ncount.\n\n```bash\n$ git rev-list --count HEAD\n7\n```\n\nUnfortunately, that is counting up the commits on the feature branch but it\nkeeps counting all the way back to the beginning of the repo.\n\nIf we want a count of just the commits on the current branch, then we can\nspecify a range: from whatever `main` was when we branched to the `HEAD` of\nthis branch.\n\n```bash\n$ git rev-list --count HEAD\n3\n```\n\nThis is the same as saying, I want all commits on `HEAD`, but exclude (`^`) the\ncommits on `main`:\n\n```bash\ngit rev-list --count HEAD ^main\n3\n```\n\nSee `man git-rev-list` for more details.\n"
  },
  {
    "path": "git/create-a-new-branch-with-git-switch.md",
    "content": "# Create A New Branch With Git Switch\n\nAs of [Git 2.23](https://www.infoq.com/news/2019/08/git-2-23-switch-restore/),\nthere is a new command in town for change and creating branches --\n`git-switch`.\n\nAs a git user, you may be used to using `git checkout -b my_branch` to create\nand switch to a new branch called `my_branch`. The `git-checkout` command can\ndo that and a lot more. In order to reduce some confusion and create a more\nexplicit command for this kind of action. That's what brought about\n`git-switch`.\n\nCreate and change to a new branch with `git-switch` and the `-c` flag:\n\n```bash\n$ git switch -c my_new_branch\n```\n\nThe `-c` flag is short for `--create` and the docs describe it as \"a convenient\nshortcut for:\"\n\n```bash\n$ git branch <new-branch>\n$ git switch <new-branch>\n```\n\nSee `man git-switch` for more details.\n"
  },
  {
    "path": "git/delete-all-untracked-files.md",
    "content": "# Delete All Untracked Files\n\nGit provides a command explicitly intended for cleaning up (read: removing)\nuntracked files from a local copy of a repository.\n\n> git-clean - Remove untracked files from the working tree\n\nGit does want you to be explicit though and requires you to use the `-f`\nflag to force it (unless otherwise configured).\n\nGit also gives you fine-grained control with this command by defaulting to\nonly deleting untracked files in the current directory. If you want\ndirectories of untracked files to be removed as well, you'll need the `-d`\nflag.\n\nSo if you have a local repository full of untracked files you'd like to get\nrid of, just:\n\n```bash\n$ git clean -f -d\n```\n\nor just:\n\n```bash\n$ git clean -fd\n```\n\n[source](http://stackoverflow.com/questions/61212/remove-local-untracked-files-from-my-current-git-branch)\n"
  },
  {
    "path": "git/determine-absolute-path-of-top-level-project-directory.md",
    "content": "# Determine Absolute Path Of Top-Level Project Directory\n\nThe `git rev-parse` command is a git plumbing command for parsing different\nkinds of things in git into a canonical form that can be used in a deterministic\nway by scripts. I would typically think of using it to work with branch names,\ntags, and other kinds of refs.\n\nThere is a handy, sorta off-label use for it in determining the absolute path of\nthe root directory for the current git repository. Use the `--show-toplevel`\nflag with no other arguments.\n\n```bash\n❯ git rev-parse --show-toplevel\n/Users/lastword/dev/jbranchaud/til\n```\n\nHere, I am in the local copy of [my TIL repo](https://github.com/jbranchaud/til). This command gives me the absolute\npath of the top-level directory where that `.git` directory resides.\n\nThis is useful for scripts that need to orient themselves to the current\nproject's top-level directory regardless of what directory they are being\nexecuted from. This is useful for things like a git hook script or monorepos\nwith scripts located in a specific sub-project directory.\n\nAlso worth mentioning is the `--show-superproject-working-tree` flag. In my TIL\nrepo, I have a private repository included as a submodule. Within that directory\n`--show-toplevel` will produce the absolute path to the submodule. If I instead\nwant the absolute path of the _super project_ (in this case TIL), then I can use\nthis other flag.\n\n```bash\n❯ git rev-parse --show-toplevel\n/Users/lastword/dev/jbranchaud/til/notes\n\n❯ git rev-parse --show-superproject-working-tree\n/Users/lastword/dev/jbranchaud/til\n```\n\nSee `man git-rev-parse` for more details.\n"
  },
  {
    "path": "git/determine-the-hash-id-for-a-blob.md",
    "content": "# Determine The Hash Id For A Blob\n\nGit's `hash-object` command can be used to determine what hash id will be\nused by git when creating a blob in its internal file system.\n\n```bash\n$ echo 'Hello, world!' > hola\n$ git hash-object hola\naf5626b4a114abcb82d63db7c8082c3c4756e51b\n```\n\nWhen a commit happens, git will generate this digest (hash id) based on the\ncontents of the file. The name and location of the file don't matter, just\nthe contents. This is the magic of git. Anytime git needs to store a blob,\nit can quickly match against the hash id in order to avoid storing duplicate\nblobs.\n\nTry it on your own machine, you don't even need to initialize a git\nrepository to use `git hash-object`.\n\n[source](http://ftp.newartisans.com/pub/git.from.bottom.up.pdf)\n"
  },
  {
    "path": "git/diffing-with-patience.md",
    "content": "# Diffing With Patience\n\nThe default diff algorithm used by Git is pretty good, but it can get\nmislead by larger, complex changesets. The result is a noisier, misaligned\ndiff output.\n\nIf you'd like a diff that is generally a bit cleaner and can afford a little\nslow down (you probably can), you can instead use the `patience` algorithm\nwhich is described as such:\n\n> Patience Diff, instead, focuses its energy on the low-frequency\n> high-content lines which serve as markers or signatures of important\n> content in the text. It is still an LCS-based diff at its core, but with\n> an important difference, as it only considers the longest common\n> subsequence of the signature lines:\n\n> Find all lines which occur exactly once on both sides, then do longest\n> common subsequence on those lines, matching them up.\n\nYou can set this as the default algorithm by adding the following lines to\nyour `~/.gitconfig` file:\n\n```\n[diff]\n    algorithm = patience\n```\n\nor it can be set from the command line with:\n\n```bash\n$ git config --global diff.algorithm patience\n```\n\n[source](http://bryanpendleton.blogspot.com/2010/05/patience-diff.html)\n\nh/t Josh Davey\n"
  },
  {
    "path": "git/dropping-commits-with-git-rebase.md",
    "content": "# Dropping Commits With Git Rebase\n\nI've been warned enough times about the potential dangers of `git reset\n--hard ...` that I always second guess myself as I type it out. Is it `git\nreset --hard HEAD` or `git reset --hard HEAD~`?\n\nIf the working directory and index are clean, then there is another way to\nremove commits. A way that gives me more confidence about what exactly is\nbeing removed.\n\nDoing an interactive rebase gives you a number of options. One of those\noptions is `d` (which stands for `drop`).\n\n```\n$ git rebase -i master\n```\n\nThis pulls up an interactive rebase with all commits going back to what is\non master -- great for when working from a feature branch.\n\n```\npick 71ed173 Add Create A Stream From An Array as a reasonml til\npick 80ac8d3 Add some clarity by distinguishing var names\nd 4f06c32 Add Data Structures With Self-Referential Types as a reasonml til\nd 01a0e75 Fix the name of this file\n```\n\nAdding `d` next to the commits you want to get rid of and saving will drop\nthose commits. The great part is that there is zero ambiguity about which\nones are being dropped.\n\nh/t Jake Worth\n"
  },
  {
    "path": "git/dry-runs-in-git.md",
    "content": "# Dry Runs in Git\n\nThere are a few commands in git that allow you to do a *dry run*. That is,\ngit will tell you the effects of executing a command without actually\nexecuting that command.\n\nFor instance, if you are clearing out untracked files, you can double check\nwhat files are going to be deleted with the *dry run* flag, like so:\n\n```\n$ git clean -fd --dry-run\nWould remove tmp.txt\nWould remove stuff/\n```\n\nSimilarly, if you want to check in which files a commit is going to be incorporated,\nyou can:\n\n```\n$ git commit --dry-run --short\nM  README.md\nA  new_file.rb\n```\n\nTry running `git commit --dry-run` (that is, without the `--short` flag).\nLook familiar? That is the same output you are getting from `git status`.\n"
  },
  {
    "path": "git/exclude-a-directory-during-a-command.md",
    "content": "# Exclude A Directory During A Command\n\nMany of the git commands we use, such as `git add`, `git restore`, etc., target\nfiles and paths relative to the current directory. This is typically exactly\nwhat we want, to stage and unstage and so forth the files and directories in\nfront of us.\n\nI recently ran into a situation where I needed to restore a small subset of\nchanges. At the same time, I had a massive number of auto-generated files\nrecording HTTP interactions (hundreds of files, modified on the working tree).\nI wanted to run a `git restore`, but wading through all those HTTP recording\nfiles was not feasible.\n\nI needed to exclude those files. They all belonged to a `spec/cassettes`\ndirectory. I could exclude them with a _pathspec_ magic signature pattern which\nis used to alter and limit the paths in a git command.\n\nA _pathspec_ magic signature is a special pattern made up of a `:` followed by\nsome signature declaring what the pattern means.\n\nThe `(exclude)`, `!`, and `^` magic signatures all mean the same thing —\nexclude. So, we can exclude a directory from a `git restore` command like so:\n\n```bash\n$ git restore --patch -- . ':!spec/cassettes'\n```\n\nWe've employed two pathspec patterns here. The first, `.`, scopes everything to\nthe current directory. The second, `':!spec/cassettes'` excludes everything in\nthe `spec/cassettes` directory.\n\nSee `man gitglossary` for more on _pathspecs_.\n"
  },
  {
    "path": "git/exclude-a-file-from-a-diff-output.md",
    "content": "# Exclude A File From A Diff Output\n\nWhen running `git diff <SHA>`, you'll see output for all files changed at that\ncommit. It's the same if you do a range of commits (e.g. `git diff\n<SHA1>...<SHA2>`).\n\nIf you are looking for changes in a particular part of the tree, then other\nchanges will be a distraction. Some generated files, such as `yarn.lock`, can\ncreate a lot of noise in the diff output.\n\nYou can get a more focused output by excluding certain files and paths. The\nsyntax for doing that, however, is a bit wonky.\n\nTo exclude a file, you have to add an argument formatted like\n`':(exclude)<filename>`.\n\nFor instance, to exclude `yarn.lock`:\n\n```bash\n$ git diff <SHA> -- . ':(exclude)yarn.lock'\n```\n\nor to exclude an entire directory:\n\n```bash\n$ git diff <SHA> -- . ':(exclude)spec/**'\n```\n\n[source](https://stackoverflow.com/questions/39931781/git-diff-stat-exclude-certain-files/39937070#39937070)\n"
  },
  {
    "path": "git/excluding-files-locally.md",
    "content": "# Excluding Files Locally\n\nExcluding (read: ignoring) files that should not be tracked is generally\ndone by listing such files in a tracked `.gitignore` file. Though it doesn't\nmake sense to list all kinds of excluded files here. For files that you'd\nlike to exclude that are temporary or are specific to your local\nenvironment, there is another option. These files can be added to the\n`.git/info/exclude` file as a way of ignoring them locally.\n\nAdd specific files or patterns as needed to that file and then save it.\nRelevant files will no longer show up as untracked files when you `git\nstatus`.\n\nh/t [Dillon Hafer](https://twitter.com/DillonHafer)\n"
  },
  {
    "path": "git/extend-git-with-custom-commands.md",
    "content": "# Extend Git With Custom Commands\n\nI recently learned about the [`git\nabsorb`](https://github.com/tummychow/git-absorb) command. It is interesting in\nits own right, but I bring it up because it isn't a command that is built in to\ngit. When I was looking at the installation instructions for it, it didn't say\nanything about how to _register_ the command with `git`.\n\nHow is git supposed to know about it? How do you extend git with custom\ncommands?\n\nWhat I learned exploring those questions is that `git` will execute any command\non your _path_ with a `git-<command>` naming convention.\n\nSo, if I create a executable binary called `git-taco`, add it to my path, and\nthen run `git taco` (notice, no dash when I run it), `git` will run my custom\nbinary.\n\nIn the same way, if you download `git-absorb` and add it to your path, `git`\nwill run it for you when you enter `git absorb ...`.\n\nYou can even type something like `where git-` and then hit tab to prompt your\nshell to display a list of a varity of other `git` commands, most of which\nprobably ship with `git`.\n\n[source](https://twitter.com/jbrancha/status/1756361704160530555)\n"
  },
  {
    "path": "git/files-with-local-changes-cannot-be-removed.md",
    "content": "# Files With Local Changes Cannot Be Removed\n\nThis is a nice quality-of-life feature in `git` that should help you avoid\naccidentally discarding changes that won't be retrievable.\n\n```bash\n❯ git rm .tool-versions\nerror: the following file has local modifications:\n    .tool-versions\n(use --cached to keep the file, or -f to force removal)\n```\n\nMy `.tool-versions` file has some local changes. I don't realize that and I go\nto issue a `git rm` command on that file. Instead of quietly wiping out my\nchanges, `git` lets me know I'm doing something destructive (these local\nchanges won't be in the diff or the reflog).\n\nI can force the removal if I know what I'm doing with the `-f` flag. Or I can\ntake the two step approach of calling `git restore` on that file and then `git\nrm`.\n\nThe `--cached` flag is also interesting because it doesn't actually delete the\nfile from my file system, but it does stage the file deletion with `git`. That\nmeans the file now shows up as one of my untracked files.\n\nSee `man git-rm` for more details.\n"
  },
  {
    "path": "git/find-and-remove-files-that-match-a-name.md",
    "content": "# Find And Remove Files That Match A Name\n\nLet's say I have a bunch of `robots.txt` file scattered throughout my project.\nI want to find all instances of that file checked into git. I then want to\nremove that file from git.\n\nI can find all the instances of that file checked into git using the\n[`git-ls-files`](https://git-scm.com/docs/git-ls-files) command.\n\n```bash\n$ git ls-files '**/robots.txt'\nproject-a/public/robots.txt\nproject-b/public/robots.txt\napps/project-c/public/robots.txt\n```\n\nThat results in a list of paths of those files regardless of how far down they\nare nested (because of the `**` glob pattern).\n\nAnd because `git-ls-files` is a _git plumbing_ command, it pipes cleanly into\nother unix commands.\n\nI can combine that first command with [`git\nrm`](https://git-scm.com/docs/git-rm) using the\n[`xargs`](https://man7.org/linux/man-pages/man1/xargs.1.html) command.\n\n```bash\n$ git ls-files '**/robots.txt' | xargs git rm\nrm 'project-a/public/robots.txt'\nrm 'project-b/public/robots.txt'\nrm 'apps/project-c/public/robots.txt'\n```\n\nThat takes each path from the first part of the command and passes it to `git\nrm` which stages it as a removed file.\n\nI can finalize my work by creating a commit from these staged changes.\n"
  },
  {
    "path": "git/find-the-date-that-a-file-was-added-to-the-repo.md",
    "content": "# Find The Date That A File Was Added To The Repo\n\nThe `git log` command has a bunch of flags that you can use to filter\ncommits and format their output.\n\nWe can get `git log` to only show the date for a commit in the `short`\nformat with the following flags:\n\n```bash\n$ git log --pretty=format:\"%ad\" --date=short\n```\n\nWe can also get `git log` to filter commits to just those that have files\nbeing added:\n\n```bash\n$ git log --diff-filter=A\n```\n\nLike many `git` commands, we can restrict the output to those that match a\npath or file.\n\n```bash\n$ git log -- README.md\n```\n\nIf we put all of these together, then we have a one-line command for getting\nthe date a specific file was added to the repository:\n\n```bash\n$ git log --pretty=format:\"%ad\" --date=short --diff-filter=A -- README.md\n2015-02-06\n```\n\nSee `man git-log` for more details.\n"
  },
  {
    "path": "git/find-the-initial-commit.md",
    "content": "# Find The Initial Commit\n\nBy definition, the initial commit in a repository has no parents. You can\nexploit that fact and use `rev-list` to find the initial commit; a commit\nwith no parents.\n\n```bash\n$ git rev-list --max-parents=0 HEAD\n```\n\nThe `rev-list` command lists all commits in reverse chronological order. By\nrestricting them to those with at most 0 parents, you are only going to get\nroot commits. Generally, a repository will only have a single root commit,\nbut it is possible for there to be more than one.\n\nSee `man git-rev-list` for more details.\n\n[source](http://stackoverflow.com/questions/5188914/how-to-show-first-commit-by-git-log)\n"
  },
  {
    "path": "git/fix-whitespace-errors-throughout-branch-commits.md",
    "content": "# Fix Whitespace Errors Throughout Branch Commits\n\nLet's say we've been working on some changes to our repository on a branch.\nWe've made several commits. We are close to putting up a PR, but we want to\nmake sure everything is tidied up.\n\nWe run a check and see that there are some whitespace errors that should be\nfixed.\n\n```bash\n$ git diff main --check\nREADME.md:1: trailing whitespace.\n+# git-playground\nscript.sh:9: trailing whitespace.\n+\n```\n\nThis post isn't able to show the highlighted whitespace errors, but we can see\nthe warnings above.\n\nRather than cluttering things with an additional commit that fixes these errors\nor manually cleaning up each commit, we can ask `git` to fix it for us.\n\n```bash\n$ git rebase --whitespace=fix main\n```\n\nThat will do a manual rebase of each commit addressing the whitespace errors.\n\nWe can run the error check again and see no output, which means we are good to\ngo.\n\n```bash\n$ git diff main --check\n```\n\nSee the section on `--whitespace` in `man git-apply` for more details.\n\n[source](https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration)\n"
  },
  {
    "path": "git/get-latest-commit-timestamp-for-a-file.md",
    "content": "# Get Latest Commit Timestamp For A File\n\nThe `git log` command can tell you all the commits that touched a file. That\ncan be narrowed down to the latest commit for that file with the `-1` flag. The\ncommit that it reports can then be further formatted to with the `--format`\nflag.\n\nThe `%ai` format pattern gives the date the commit was authored in an ISO\n8601-like format. The `%aI` (capital `I`) gives the date the commit was\nauthored strictly in the ISO 8601 format.\n\nHere are examples of both side by side:\n\n```bash\n❯ git log -1 --format=%ai -- README.md\n2024-10-15 13:59:09 -0500\n\n❯ git log -1 --format=%aI -- README.md\n2024-10-15T13:59:09-05:00\n```\n\nI made use of this in a script where I needed to get an idea of when various\nfiles were most recently modified.\n\nSee `man git-log` and the `PRETTY FORMATS` section for more details.\n"
  },
  {
    "path": "git/get-the-name-of-the-current-branch.md",
    "content": "# Get The Name Of The Current Branch\n\nThere are a couple ways of doing this. If you are on Git 2.22+, then the\n`git-branch` porcelain command now supports a flag for this.\n\n```bash\n$ git branch --show-current\nmain\n```\n\nIf you are on an older version of Git or looking for a plumbing command that is\nmore appropriate for scripting, then `git-rev-parse` is what you're looking\nfor.\n\n```bash\n$ git rev-parse --abbrev-ref HEAD\nmain\n```\n\n[source](https://stackoverflow.com/questions/6245570/how-to-get-the-current-branch-name-in-git)\n"
  },
  {
    "path": "git/get-the-short-version-of-the-latest-commit.md",
    "content": "# Get The Short Version Of The Latest Commit\n\nAs part of some automated scripting for an app deployment I wanted to be\nable to get the short version of the latest commit to the current git repo.\nGit's `rev-parse` command is the perfect fit for this.\n\n```bash\n$ git rev-parse --short HEAD\n708248b\n```\n\nSee `man git-rev-parse` for more details.\n\n[source](https://stackoverflow.com/questions/5694389/get-the-short-git-version-hash)\n"
  },
  {
    "path": "git/grab-a-single-file-from-a-stash.md",
    "content": "# Grab A Single File From A Stash\n\nIn git, you can reference a commit SHA or branch to checkout differing\nversions of files.\n\n```bash\n$ git checkout d3d2e38 -- README.md\n```\n\nIn the same way, you can snag the version of a file as it existed in a\nstash. Just reference the relevant stash.\n\n```bash\n$ git checkout stash@{1} -- README.md\n```\n\n[source](http://stackoverflow.com/questions/1105253/how-would-i-extract-a-single-file-or-changes-to-a-file-from-a-git-stash)\n"
  },
  {
    "path": "git/grep-for-a-pattern-on-another-branch.md",
    "content": "# Grep For A Pattern On Another Branch\n\nGit has a built-in `grep` command that works essentially the same as the\nstandard `grep` command that unix users are used to. The benefit of\n`git-grep` is that it is tightly integrated with Git.\nYou can search for occurrences of a pattern on another branch. For example,\nif you have a feature branch, `my-feature`,  on which you'd like to search\nfor occurrences of `user.last_name`, then your command would look like this:\n\n```bash\n$ git grep 'user\\.last_name' my-feature\n```\n\nIf there are matching results, they follow this format:\n\n```\nmy-feature:app/views/users/show.html.erb:  <%= user.last_name %>\n...\n```\n\nThis formatting is handy because you can easily copy the branch and file\ndirective for use with [`git-show`](viewing-a-file-on-another-branch.md).\n\nSee `man git-grep` for more details.\n"
  },
  {
    "path": "git/grep-over-commit-messages.md",
    "content": "# Grep Over Commit Messages\n\nThe `git log` command supports a `--grep` flag that allows you to do a text\nsearch (using grep, obviously) over the commit messages for that repository.\nFor the git user that writes descriptive commit messages, this can come in\nquite handy. In particular, this can be put to use in an environment where\nthe standard process involves including ticket and bug numbers in the commit\nmessage. For example, finding bug `#123` can be accomplished with:\n\n```bash\n$ git log --grep=\"#123\"\n```\n\nSee `man git-log` for more details.\n"
  },
  {
    "path": "git/highlight-extra-whitespace-in-diff-output.md",
    "content": "# Highlight Extra Whitespace In Diff Output\n\nWhen running a `git diff` (or `git add --patch`) I'll sometimes come across\nlines that don't have any visible changes. This is usually because some\nwhitespace characters were either added (on accident) or removed (often by a\nautoformatter).\n\nDepending on the `core.whitespace` config, you'll probably see at least some of\nthe whitespace errors that git provides. By default, git only highlights\nwhitespace errors on added (`new`) lines. However if some extra whitespace was\noriginally committed and is now being removed, it won't be highlighted on the\n`old` line in the diff.\n\nWe can have git always highlight whitespace errors by setting\n`wsErrorHighlight` to `all` in the global git config.\n\n```bash\n$ git config --global diff.wsErrorHighlight all\n```\n\nWhich updates the global gitconfig file with the following line:\n\n```\n[diff]\n\twsErrorHighlight = all\n```\n\nThe `all` option is a shorthand for `old,new,context`.\n\nSee `man git-diff` for more details.\n"
  },
  {
    "path": "git/highlight-small-change-on-single-line.md",
    "content": "# Highlight Small Change On Single Line\n\nSometimes a change gets made on a single, long line of text in a Git tracked\nfile. If it is a small, subtle change, then it can be hard to pick out when\nlooking at the diff. A standard diff will show a green line of text stacked on\na red line of text with no more granular information.\n\nThere are two ways we can improve the diff output in these situations.\n\nThe first is built-in to git. It is the `--word-diff` flag which will visually\nisolate the portions of the line that have changed.\n\n```bash\ngit diff --word-diff README.md\n```\n\nWhich will produce something like this:\n\n```diff\nA collection of concise write-ups on small things I learn [-day to day-]{+day-to-day+} across a\n```\n\nThe outgoing part is wrapped in `[-...-]` and the incoming part is wrapped in\n`{+...+}`.\n\nThe second (and my preference) is to use\n[`delta`](https://github.com/dandavison/delta) as an external differ and pager\nfor git.\n\n```bash\ngit -c core.pager=delta diff README.md\n```\n\nI cannot visually demonstrate the difference in a standard code block. So I'll\ndescribe it. We see a red and green line stacked on each other, but with muted\nbackground colors. Then the specific characters that are different stand out\nbecause they are highlighted with brighter red and green. I [posted a visual\nhere](https://bsky.app/profile/jbranchaud.bsky.social/post/3ln245orlxs2j).\n\n`delta` can also be added as a standard part of your config like I demonstrate\nin [Better Diffs With Delta](git/better-diffs-with-delta.md).\n\nh/t to [Dillon Hafer's post on\n`--word-diff`](https://til.hashrocket.com/posts/t994rwt3fg-finds-diffs-in-long-line)\n"
  },
  {
    "path": "git/ignore-changes-to-a-tracked-file.md",
    "content": "# Ignore Changes To A Tracked File\n\nFiles that should never be tracked are listed in your `.gitignore` file. But\nwhat about if you want to ignore some local changes to a tracked file?\n\nYou can tell git to assume the file is unchanged\n\n```bash\n$ git update-index --assume-unchanged <some-file>\n```\n\nReversing the process can be done with the `--no-assume-unchanged` flag.\n\n[source](http://blog.pagebakers.nl/2009/01/29/git-ignoring-changes-in-tracked-files/)\n"
  },
  {
    "path": "git/ignore-files-specific-to-your-workflow.md",
    "content": "# Ignore Files Specific To Your Workflow\n\n_If you want to watch instead of read, I explore this in [Four Ways to Ignore\nFiles with Git](https://www.youtube.com/watch?v=ip06v7Wnfz0)._\n\nThe most common way to tell git to ignore files is to add them to a project's\n`.gitignore` file. This file is kept under version control, so it is shared\nwith anyone who clones the project.\n\nWhat about ignoring files that shouldn't necessarily be recorded in the\nproject's `.gitignore`?\n\nFor instance, let's say I create a `notes.md` file to write some project notes\nto myself or keep track of a few todo items. This file is just for me. I don't\nwant it committed. Because this `notes.md` is an idiosyncrasy of my workflow, I\ndon't want to exclude it in the tracked `.gitignore` file.\n\nInstead, this file is a perfect candidate for the git repository's\n`.git/info/exclude` file. Git treats entries in this file the same as it does\nthe `.gitignore` file. This file only exists on my machine and is not under\nversion control.\n\n```\n# .git/info/exclude\nnotes.md\n```\n\nOnce I've added that line, `notes.md` will no longer show up as an untracked\nfile when I run `git status`.\n\nSee `man gitignore` for more details.\n"
  },
  {
    "path": "git/include-a-message-with-your-stashed-changes.md",
    "content": "# Include A Message With Your Stashed Changes\n\nIf you were to quickly stash some changes, you end up with a stash reference\nthat git would attach a little context to, such as the latest commit SHA and\nthe first line of its commit message.\n\n```bash\n$ git stash list\nstash@{0}: WIP on master: 6766419 Add link to source for latest TIL\n```\n\nOften this won't provide you the needed context to return to your stash and\npick up where you left off even days later.\n\nYou can customize the message of a stash with the `-m` flag.\n\n```bash\n$ git stash push -m 'made some changes'\n```\n\nWhen you view your stash list, you'll see your custom message.\n\n```bash\n$ git stash list\nstash@{0}: On master: made some changes\n```\n\nAnd hopefully that's the context you need to hit the ground running.\n\nSee `man git-stash` for more details.\n"
  },
  {
    "path": "git/include-or-exclude-remaining-patch-changes.md",
    "content": "# Include Or Exclude Remaining Patch Changes\n\nI often use `git add --patch` as a way of interactively staging changes for a\ncommit. Git walks me through each individual chunk of changes—which it calls\n_hunks_—so that I can include it or exclude it.\n\nSometimes, like when I'm working with a `yarn.lock` file, there are a ton of\ncomputer-generated changes to a file that I don't want to individually confirm.\nOne of the options while interactively staging is to hit `a` which will stage the current hunk and all later hunks for the current file.\n\nA complementary scenario arises at times when working with a Rails `schema.rb`\nfile. There are a bunch of Postgres client-specific changes that I don't want\nto commit. Once I get to the `schema.rb` file, I can hit `d` to _not_ stage\nthis or all remaining hunks in the current file.\n\n```\na - stage this hunk and all later hunks in the file\nd - do not stage this hunk or any of the later hunks in the file\n```\n\nThis saves me from hitting `y` a dozen times to accept changes or hitting `n` a\ndozen times to decline changes.\n\nSee `man git-add` and look for the _Interactive mode_ section for more details.\n"
  },
  {
    "path": "git/include-some-stats-in-your-git-log.md",
    "content": "# Include Some Stats In Your Git Log\n\nA simple `git log` command is going to give you a concise set of information\nfor each commit. Usually it is enough info. When it's not, `git log` can\nprovide additional information with the right flags. To include overall and\nper-file stats on the number of insertions and deletions, use the `--stat`\nflag.\n\n```bash\n$ git log --stat\ncommit 66e67741a1cd6857a4467d1453c9f17ef5849f20\nAuthor: jbranchaud <jbranchaud@gmail.com>\nDate:   Mon Nov 13 21:24:41 2017 -0600\n\n    Add Focus The URL Bar as an internet til\n\n README.md                     |  3 ++-\n internet/focus-the-url-bar.md | 10 ++++++++++\n 2 files changed, 12 insertions(+), 1 deletion(-)\n\ncommit 9241e3919ef1e4f68b71a1491d368ae6361084aa\nAuthor: jbranchaud <jbranchaud@gmail.com>\nDate:   Sat Nov 11 11:41:40 2017 -0600\n\n    Add Freeze An Object, Sorta as a javascript til\n\n README.md                            |  3 ++-\n javascript/freeze-an-object-sorta.md | 44 ++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 46 insertions(+), 1 deletion(-)\n\n...\n```\n\nSee `man git-log` for more details.\n"
  },
  {
    "path": "git/intent-to-add.md",
    "content": "# Intent To Add\n\nGit commands like `git diff` and `git add --patch` are awesome, but their\nlittle caveat is that they only work on files that are currently tracked in\nthe repository. That means that after working on that new feature for 30\nminutes, a `git diff` is only going to show you the changes to existing\nfiles and when you go to start making commits with `git add --patch` you\nwill again be provided with only part of the picture.\n\nThe `git add` command has a flag, `-N`, that is described in the git man\npages:\n\n> Record only the fact that the path will be added later. An entry for the\n> path is placed in the index with no content. This is useful for, among other\n> things, showing the unstaged content of such files\n> with git diff and committing them with git commit -a.\n\nBy adding untracked files with the `-N` flag, you are stating your *intent\nto add* these files as tracked files. Once git knows that these files are\nmeant to be tracked, it will know to include them when doing things like\ncomputing the diff, performing an interactive add, etc.\n"
  },
  {
    "path": "git/interactively-checkout-specific-files-from-a-stash.md",
    "content": "# Interactively Checkout Specific Files From A Stash\n\nThis command will prompt you with a list of the stashes in your current git\nrepo. Once you select one of them from the interactive fzf prompt, you will\nthen be prompted with another fzf prompt, this second one allow multi-select.\nFrom there you can tab select the files you want to checkout. Once you've\nmarked the ones you want, hit enter and those files will be checked out to your\nindex.\n\n```bash\ngit stash show --name-only $(\n  git stash list \\\n  | fzf --height=20% --reverse \\\n  | sed 's/:.*//'\n) \\\n| fzf --height=20% --multi --sync \\\n| xargs -I {} sh -c 'git checkout stash@{0} -- {}'\n```\n"
  },
  {
    "path": "git/interactively-unstage-changes.md",
    "content": "# Interactively Unstage Changes\n\nI often use `git add --patch` to interactively stage changes for a commit.\nGit takes me through changes to tracked files piece by piece to check if I\nwant to stage them. This same interactive _staging_ of files can be used in\nreverse when removing changes from the index. Just add the `--patch` flag.\n\nYou can use it for a single file\n\n```bash\n$ git reset --patch README.md\n```\n\nor you can let it operate on the entire repository\n\n```bash\n$ git reset --patch\n```\n\nThis is useful when you've staged part of a file for a commit and then\nrealize that some of those changes shouldn't be committed.\n"
  },
  {
    "path": "git/keep-file-locally-with-git-rm.md",
    "content": "# Keep File Locally With `git rm`\n\nLet's say I've added a new file `data.json` to my repo as part of the most\nrecent commit. I realize this isn't the point at which I want to add that file.\nSo, I do `git rm data.json` and then `git commit --amend` to rework that\ncommit.\n\nHowever, when I look in my working tree, or even just my file system, I'll\nnotice that `data.json` is gone. The `git rm` command completely removed the\nfile since it was previously an untracked file.\n\nTo keep `git rm` from tossing out my file like that, I can include the\n`--cached` flag which will remove the file from the index (stages it to be\n`deleted`), but restore it to the working directory.\n\n```bash\n$ git rm --cached data.json\n```\n\nSee `man git-rm` for more details on the `--cached` flag.\n"
  },
  {
    "path": "git/last-commit-a-file-appeared-in.md",
    "content": "# Last Commit A File Appeared In\n\nIn my project, I have a `README.md` file that I haven't modified in a while.\nI'd like to take a look at the last commit that modified it. The `git log`\ncommand can be used here with few arguments to narrow it down.\n\n```\n$ git log -1 -- README.md\ncommit 6da76838549a43aa578604f8d0eee7f6dbf44168\nAuthor: jbranchaud <jbranchaud@gmail.com>\nDate:   Sun May 17 12:08:02 2015 -0500\n\n    Add some documentation on configuring basic auth.\n```\n\nThis same command will even work for files that have been deleted if you\nknow the path and name of the file in question. For instance, I used to have\nan `ideas.md` file and I'd like to find the commit that removed it.\n\n```\n$ git log -1 -- docs/ideas.md\ncommit 0bb1d80ea8123dd12c305394e61ae27bdb706434\nAuthor: jbranchaud <jbranchaud@gmail.com>\nDate:   Sat May 16 14:53:57 2015 -0500\n\n    Remove the ideas doc, it isn't needed anymore.\n```\n"
  },
  {
    "path": "git/list-all-files-added-during-span-of-time.md",
    "content": "# List All Files Added During Span Of Time\n\nI wanted to get an idea of all the TIL posts I wrote during 2024. Every TIL I\nwrite is under version control in a [git repo on\ngithub](https://github.com/jbranchaud/til). That means git has all the info I\nneed to figure that out.\n\nThe `git diff` command is a good way at this problem. With the\n`--diff-filter=A` flag I can restrict the results to just files that were\n_Added_. And with `--name-only` I can cut all the other diff details out and\nget just filenames.\n\nBut filenames added to which commits? We need to specify a ref range. There is\na ton of flexibility in how you define a ref, including [a date specification\nsuffix](https://git-scm.com/docs/gitrevisions#Documentation/gitrevisions.txt-emltrefnamegtltdategtemegemmasteryesterdayememHEAD5minutesagoem)\nthat points to the value of the ref at an earlier point in time.\n\nSo, how about from the beginning of 2024 to the beginning of 2025:\n\n```\nHEAD@{2024-01-01}..HEAD@{2025-01-01}\n```\n\nPutting that all together, we this command and potentially a big list of files.\n\n```bash\n$ git diff --diff-filter=A --name-only HEAD@{2024-01-01}..HEAD@{2025-01-01}\n```\n\nI wanted to restrict the results to just markdown files, so I added a filename\npattern.\n\n```bash\n$ git diff --diff-filter=A --name-only HEAD@{2024-01-01}..HEAD@{2025-01-01} -- \"*.md\"\n```\n\nI could even go a step further to see only the files added to a specific\ndirectory.\n\n```bash\n$ git diff --diff-filter=A --name-only HEAD@{2024-01-01}..HEAD@{2025-01-01} -- \"postgres/*.md\"\n```\n\nAs a final bonus, I can spit out the github URLs for all those files with a bit of `awk`.\n\n```bash\n$ git diff --diff-filter=A --name-only HEAD@{2024-01-01}..HEAD@{2025-01-01} -- \"postgres/*.md\" |\nawk '{print \"https://github.com/jbranchaud/til/blob/master/\" $0}'\n```\n"
  },
  {
    "path": "git/list-all-files-changed-between-two-branches.md",
    "content": "# List All Files Changed Between Two Branches\n\nThe `git-diff` command can help with finding all files that have changed\nbetween two branches. For instance, if you are at the `HEAD` of your current\nfeature branch and you'd like to see the list of files that have changed\nsince being in sync with the `master` branch, you'd formulate a command like\nthe following:\n\n```bash\n$ git diff --name-only master\n```\n\nThe `--name-only` flag is important because it cuts out the rest of the\nnon-essential output.\n\nYou'll want to list the _older_ branch first and the current branch second\nas a way of showing what has changed from the original branch to get to the\ncurrent branch.\n\nThough the example shows the use of _branches_ any git reference can be used\nto see what has changed between two commits.\n\nSee `man git-diff` for more details.\n"
  },
  {
    "path": "git/list-all-git-aliases-from-gitconfig.md",
    "content": "# List All Git Aliases From gitconfig\n\nRunning the `git config --list` command will show all of the configuration\nsettings you have for `git` relative to your current location. Though most of\nthese setting probably live in `~/.gitconfig`, you may also have some locally\nspecified ones in `.git/config`. This will grab them all including any `alias`\nentries.\n\nWe can narrow things down to just `alias` entries using the `--get-regexp` flag.\n\n```bash\n$ git config --get-regexp '^alias\\.'\n\nalias.ap add --patch\nalias.authors shortlog -s -n -e\nalias.co checkout\nalias.st status\nalias.put push origin HEAD\nalias.fixup commit --fixup\nalias.squash commit --squash\nalias.doff reset HEAD^\nalias.add-untracked !git status --porcelain | awk '/\\?\\?/{ print $2 }' | xargs git add\nalias.reset-authors commit --amend --reset-author -CHEAD\n```\n\nI use `git doff` all the time on feature branches to \"pop\" the latest commmit\nonto the working copy. I was trying to remember exactly what the `git doff`\ncommand is and this was an easy way to check.\n"
  },
  {
    "path": "git/list-branches-that-contain-a-commit.md",
    "content": "# List Branches That Contain A Commit\n\nYou know a certain change made it onto the main branch. You'd like to know if\nthat changes has been integrated back into the development and staging\nbranches. If you have a specific git sha associated with that change, there is\na handy way to check.\n\n```bash\n$ git branch --contains 50e1151\n```\n\nThe `--contains` flag of the\n[`git-branch`](https://git-scm.com/docs/git-branch) command will list all\nbranches locally that contain the given commit sha.\n\nIf you don't see any output, then no branches have that sha. This means either there are remote changes that you need to pull down or you're looking at the wrong repo.\n\nSee `man git-branch` for more details.\n"
  },
  {
    "path": "git/list-commits-on-a-branch.md",
    "content": "# List Commits On A Branch\n\nYou can list all commits that have taken place since a branch split off from\nanother branch using `git log`. You just need to specify a ref range with\nthe originating branch and the branch of interest.\n\n```bash\n$ git log master..my-feature-branch\n```\n\nThat will list all commits on `my-feature-branch` since it branched off from\n`master`.\n\nI like to tighten up the output a bit with a flag:\n\n```bash\n$ git log master..my-feature-branch --oneline\n```\n\nSee `man git-log` for more details.\n"
  },
  {
    "path": "git/list-different-commits-between-two-branches.md",
    "content": "# List Different Commits Between Two Branches\n\nThere are times when I want to get a sense of the difference between two\nbranches. I don't want to look at the actual diff though, I just want to see\nwhat commits are on one and the other.\n\nI can do just this by using the `git-log` command with a couple flags, most\nimportantly the `--cherry-pick` flag.\n\nTo compare the `feature` branch against the `master` branch, I can run a\ncommand like the following:\n\n```bash\n$ git log --left-right --graph --cherry-pick --oneline feature...branch\n```\n\nThis lists commits with the first line of their messages. It also includes\neither a `<` or `>` arrow at the front of each commit indicating whether the\ncommit is on the left (`feature`) or right (`master`) branch, respectively.\n\nNote: you can use more than branches in a command like this. Any two\nreferences will work. You can just use two SHAs for instance.\n\n[source](http://stackoverflow.com/questions/7566416/different-commits-between-two-branches)\n"
  },
  {
    "path": "git/list-filenames-without-the-diffs.md",
    "content": "# List Filenames Without The Diffs\n\nThe `git show` command will list all changes for a given reference\nincluding the diffs. With diffs included, this can get rather verbose at\ntimes. If you just want to see the list of files involved (excluding the\ndiffs), you can use the `--name-only` flag. For instance,\n\n```\n$ git show HEAD --name-only\ncommit c563bafb511bb984c4466763db7e8937e7c3a509\nAuthor: jbranchaud <jbranchaud@gmail.com>\nDate:   Sat May 16 20:56:07 2015 -0500\n\n    This is my sweet commit message\n\napp/models/user.rb\nREADME.md\nspec/factories/user.rb\n```\n"
  },
  {
    "path": "git/list-just-the-files-involved-in-a-commit.md",
    "content": "# List Just The Files Involved In A Commit\n\nAs part of a script I was writing I needed a command that could list out all\nthe files involved in a given commit. The `git-show` command (which is\nconsidered a porcelain command) can do this but isn't ideal for scripting. It\nis recommended to instead use _plumbing_ commands.\n\nThe `git-diff-tree` command is perfect for listing blobs (files) involved in a\ncommit.\n\n```bash\n$ git diff-tree --no-commit-id --name-only -r <SHA>\n```\n\nThe `--no-commit-id` flag suppresses the output of the commit id, because we\nwant just the files. The `--name-only` flag tells the command to suppress other\nfile info and to only show the file names. The `-r` flag tells the command to\nrecurse into subtrees so that you get full pathnames instead of just the\ntop-level directory.\n\nIf you're interested, the `git-show` parallel to this is:\n\n```bash\n$ git show --pretty=\"\" --name-only <SHA>\n```\n\nSee `man git-diff-tree` and `man git-show` for more details on these.\n\n[source](https://stackoverflow.com/questions/424071/how-to-list-all-the-files-in-a-commit)\n"
  },
  {
    "path": "git/list-most-git-commands.md",
    "content": "# List Most Git Commands\n\nYou can list most git commands by using the `-a` flag with `git-help`:\n\n```\n$ git help -a\n```\n\n[Source](http://stackoverflow.com/questions/7866353/git-list-all-available-commands)\n"
  },
  {
    "path": "git/list-untracked-files-for-scripting.md",
    "content": "# List Untracked Files For Scripting\n\nYou'll generally run `git status` to get an overview of the index and working\ntree of a git project. This is a _porcelain_ command meant for a Git end-user.\nIf you want to do some scripting, you'll want a _plumbing_ command like\n`ls_files`.\n\nThe `git ls-files` command will\n\n> Show information about files in the index and the working tree\n\nThis command can be used to list all untracked files in the working tree with\ntwo flags.\n\n1. The `--others` flag will show untracked files in the output\n2. The `--exclude-standard` will use the standard ignore files like\n   `.gitignore` and `.git/info/exclude`.\n\nPut it all together and you've got:\n\n```bash\n$ git ls-files --others --exclude-standard\n```\n\nIn [Make One-Line Commands Interactive with\nfzf](https://www.youtube.com/watch?v=wf5eXdwfVws), I show how to use this with\n`fzf` to interactively remove untracked files that are no longer wanted.\n\n[source](https://stackoverflow.com/a/3801554/535590)\n"
  },
  {
    "path": "git/list-untracked-files.md",
    "content": "# List Untracked Files\n\nGit's `ls-files` command is a plumbing command that allows you to list\ndifferent sets of files based on the state of the working directory. So, if\nyou want to list all untracked files, you can do:\n\n```\n$ git ls-files --others\n```\n\nThis includes files *ignored* by the `.gitignore` file. If you want to\nexclude the ignored files and only see *untracked* and *unignored* files,\nthen you can do:\n\n```\n$ git ls-files --exclude-standard --others\n```\n\nThere are some other flags worth checking at at `git help ls-files`.\n\n[source](http://stackoverflow.com/questions/2657935/checking-for-a-dirty-index-or-untracked-files-with-git)\n"
  },
  {
    "path": "git/move-the-latest-commit-to-a-new-branch.md",
    "content": "# Move The Latest Commit To A New Branch\n\nI sometimes find myself making a commit against the `master` branch that I\nintended to make on a new branch. To get this commit on a new branch, one\npossible approach is to do a reset, checkout a new branch, and then\nre-commit it. There is a better way.\n\n```bash\n$ git checkout -b my-new-branch\n$ git checkout - \n$ git reset --hard HEAD~\n```\n\nThis makes better use of branches and avoids the need to redo a commit that\nhas already been made.\n\nNote: The example was against the `master` branch, but can work for any\nbranch.\n"
  },
  {
    "path": "git/override-the-global-git-ignore-file.md",
    "content": "# Override The Global Git Ignore File\n\nOne of the places that `git` looks when deciding whether to pay attention to or\nignore a file is in your global _ignore_ file. By default, `git` will look for\nthis file at `$XDG_CONFIG_HOME/git/ignore` or `$HOME/.config/git/ignore`.\n\nI don't have `$XDG_CONFIG_HOME` set on my machine, so it will fall back to the\nconfig directory under `$HOME`.\n\nI may have to create the `git` directory and `ignore` file.\n\n```bash\n$ mkdir $HOME/.config/git\n$ touch $HOME/.config/git/ignore\n```\n\nThen I can add file and directories to exclude to that `ignore` file just like\nI would any other `.gitignore` file.\n\nIf I'd prefer for the global _ignore_ file to live somewhere else, I can\nspecify that location and filename in my `$HOME/.gitconfig` file.\n\n```\n[core]\n\texcludesFile = ~/.gitignore\n```\n\nSetting this will override the default, meaning the default file mentioned\nabove will be ignored (\"now you know how it feels, ignore file!\"). In this\ncase, I'll need to create the `.gitignore` file in my home directory and add\nany of my ignore rules.\n\n[source](https://git-scm.com/docs/gitignore)\n"
  },
  {
    "path": "git/pick-specific-changes-to-stash.md",
    "content": "# Pick Specific Changes To Stash\n\nIf you run `git stash`, all of the changes to tracked files on the working tree\nwill be put into a commit-like entity in the stash list.\n\nIf you want to be a bit choosier about what gets saved during a stash, you can\ninclude the `--patch` flag.\n\n> With --patch, you can interactively select hunks from the diff between HEAD\n> and the working tree to be stashed.\n\n```bash\n$ git stash --patch\n```\n\nOnce in the interactive mode initiated by `--patch`, you'll be presented with a\nchange of changes and some options. You hit `y` for \"yes, include this\" and `n`\nfor \"no, don't include that\". And then there are some more advanced options\nwhich you can read about in the _Interactive Mode_ section of `git-add`'s man\npage.\n\nSee `man git-stash` for more details.\n"
  },
  {
    "path": "git/pulling-in-changes-during-an-interactive-rebase.md",
    "content": "# Pulling In Changes During An Interactive Rebase\n\nMy standard workflow when doing feature development is to checkout a feature\nbranch and commit changes as I go. When the feature is finished, I clean up\nthe commit history with an interactive rebase and then integrate those\nchanges with `master`.\n\nI initiate the interactive rebase like this (while on the feature branch):\n\n```\n$ git rebase -i master\n```\n\nThis allows me to squash, fixup, and delete commits that I've made since\nchecking out this branch from `master`.\n\nIt is important to note that an another thing will happen seemingly behind\nthe scenes. Any commits on `master` since the feature branch was checked out\nwill be applied to the feature branch before the effects of the interactive\nrebase are applied.\n\nIf you want to strictly do an interactive rebase of the commits on the\nfeature branch ignoring what is on `master`, then reference the commit you\nchecked out from -- put another way, reference the commit before the first\ncommit on this branch.\n\n```\n$ git rebase -i <sha-of-first-commit-on-this-branch>~\n```\n\nThe tilde (`~`) will go back one commit from the specified commit sha.\n\nSee `man git-rebase` for more details.\n"
  },
  {
    "path": "git/push-to-a-branch-on-another-remote.md",
    "content": "# Push To A Branch On Another Remote\n\nThe kind of `git-push` I do most often is:\n\n```bash\n$ git push origin HEAD\n```\n\nwhich I have aliased to `put` in my `.gitconfig`.\n\n`HEAD` generally refers to whatever branch you currently have checked out. So\nthis command will take the state of your current branch and push it to the\nbranch of the same name on the `origin`, which is a _remote_ (see `git remote\n-v`).\n\nIf you have other remotes set up, such as a `staging`, `heroku`, etc., then you\nmay instead want to push to one of those.\n\n```bash\n$ git push heroku HEAD\n```\n\nThis will push the state of the current branch to that branch on the `heroku`\nremote.\n\nIf I instead want to push the changes from one local branch to a different\nnamed remote branch, then I have to specify both like so:\n\n```bash\n$ git push heroku staging:main\n```\n\nThis will push the state of my local `staging` branch to the `main` branch on\nthe `heroku` remote.\n\n[source](https://devconnected.com/how-to-push-git-branch-to-remote/)\n"
  },
  {
    "path": "git/quicker-commit-fixes-with-the-fixup-flag.md",
    "content": "# Quicker Commit Fixes With The Fixup Flag\n\nImagine you're working a feature branch and realize that the first commit you\nmade had a typo. You could just tack on another commit to fix the typo, but\nthat will add noise to your commit history. You can fix it up by making a\n_fixup_ commit.\n\n1. Make your typo fix\n2. Stage the fix\n3. Find the SHA of the commit that you want to fix (e.g. `2ee53ad`)\n4. Create a _fixup_ commit: `git commit --fixup 2ee53ad`\n\nThis _fixup_ commit is tied to the original commit it is fixing.\n\n```\n❯ git log --pretty=oneline --abbrev-commit\nb4258b6 (HEAD -> feature-branch) fixup! Add header\n9c0d2b0 Different atomic change\n2ee53ad Add header\n8486b91 (master) Initial commit\n```\n\nTo then apply the _fixup_, run `git rebase -i --autosquash master`. This will\npresent you with the following _interactive rebase_ screen:\n\n```\npick 2ee53ad Add header\nfixup b4258b6 fixup! Add header\npick 9c0d2b0 Different atomic change\n\n# Rebase 8486b91..b4258b6 onto 8486b91 (3 commands)\n```\n\nBecause git knows that your _fixup_ commit is tied to `2ee53ad`, it\nautomatically moves it into place below that commit with the `fixup` command.\n\nSaving will apply and autosquash the fixup commit leaving you with a clean\ncommit history.\n"
  },
  {
    "path": "git/rebase-commits-with-an-arbitrary-command.md",
    "content": "# Rebase Commits With An Arbitrary Command\n\nInteractive rebasing is a powerful way to manage and tend to the history of\na git repository. Rewording and squashing commits are fairly common actions.\nBut what if you need to run some arbitrary command against a series of\nrecent commits?\n\nThis is where the `--exec` flag comes in to play.\n\n```bash\n$ git rebase -i HEAD~3 --exec \"git commit --amend --reset-authors -CHEAD\"\n```\n\nThis generates an interactive rebase file that you can review and save when\nready.\n\n```\npick ea4a215 Add Globally Install A Package With Yarn as a javascript til\nexec git commit --amend --reset-author -CHEAD\npick a4f4143 Add Initialize A New JavaScript Project With Yarn as a javascript til\nexec git commit --amend --reset-author -CHEAD\npick 2f00aeb Add Default And Named Exports From The Same Module as a javascript til\nexec git commit --amend --reset-author -CHEAD\n```\n\nAs you can see, the specified command is prepared for execution for each\ncommit involved in the rebase.\n\nh/t [Patricia Arbona](https://github.com/arbonap)\n"
  },
  {
    "path": "git/reference-a-commit-via-commit-message-pattern-matching.md",
    "content": "# Reference A Commit Via Commit Message Pattern Matching\n\nGenerally when referencing a commit, you'll use the SHA or a portion of the\nSHA. For example with `git-show`:\n\n```\n$ git show cd6a63d014\n...\n```\n\nThere are many ways to reference commits though. One way is via regex\npattern matching on the commit message. For instance, if you recently had a\ncommit with a typo and you had included *typo* in the commit message, then\nyou could reference that commit like so:\n\n```\n$ git show :/typo\nAuthor: Josh Branchaud\nDate: Mon Dec 21 15:50:20 2015 -0600\n\n    Fix a typo in the documentation\n...\n```\n\nBy using `:/` followed by some text, git will attempt to find the most\nrecent commit whose commit message matches the text. As I alluded to, regex\ncan be used in the text.\n\nSee `$ man gitrevisions` for more details and other ways to reference\ncommits.\n\n[Source](https://twitter.com/jamesfublo/status/678906346335428608)\n"
  },
  {
    "path": "git/reference-commits-earlier-than-reflog-remembers.md",
    "content": "# Reference Commits Earlier Than Reflog Remembers\n\nWhile preparing some stats for a recent blog post on [A Decade of\nTILs](https://www.visualmode.dev/a-decade-of-tils), I ran into an issue\nreferencing chunks of time further back than 2020.\n\n```bash\n❯ git diff --diff-filter=A --name-only HEAD@{2016-02-06}..HEAD@{2017-02-06} -- \"*.md\"\nwarning: log for 'HEAD' only goes back to Sun, 20 Dec 2020 00:26:27 -0600\nwarning: log for 'HEAD' only goes back to Sun, 20 Dec 2020 00:26:27 -0600\n```\n\nThis is because `HEAD@...` is a reference to the `reflog`. The `reflog` is a\nlocal-only log of objects and activity in the repository. That date looks\nsuspiciously like the time that I got this specific machine and cloned the\nrepo.\n\nIn order to access this information, I need a different approach of finding\nreferences that bound these points in time.\n\nHow about asking `rev-list` for the first commit it can find before the given\ndates in 2017 and 2016 and then using those.\n\n```bash\n❯ git rev-list -1 --before=\"2017-02-07 00:00\" HEAD\n17db6bc4468616786a8f597a10d252c24183d82e\n\n❯ git rev-list -1 --before=\"2016-02-07 00:00\" HEAD\nf1d3d1f796007662ff448d6ba0e3bbf38a2b858d\n\n❯ git diff --diff-filter=A --name-only f1d3d1f796007662ff448d6ba0e3bbf38a2b858d..17db6bc4468616786a8f597a10d252c24183d82e -- \"*.md\"\n\n# git outputs a bunch of files ...\n```\n"
  },
  {
    "path": "git/remove-untracked-files-from-a-directory.md",
    "content": "# Remove Untracked Files From A Directory\n\nLet's say I have a directory (`spec/cassettes`) full of a ton of generated YAML\nfiles. Most of these files are tracked by git. However, I just generated a\nbunch of new ones that are untracked. For whatever reason, I don't want these\nfiles. I need to delete them.\n\nRunning `rm` on each of them is going to be too tedious. And it is tricky to\ntarget them for a bulk delete since there are a ton of other files in that\ndirectory that I want to keep.\n\nOne way to approach this is have `git ls-files` help out with listing all files in the\ndirectory that are untracked. The `--others` flag filters to untracked files.\n\n```bash\ngit ls-files --others --exclude-standard spec/cassettes\n```\n\nFrom there, I can pipe it to `rm` (with `xargs` collapsing all the files into a\nsingle line):\n\n```bash\ngit ls-files --others --exclude-standard spec/cassettes | xargs rm\n```\n\nSee `man git-ls-files` for more details.\n"
  },
  {
    "path": "git/rename-a-remote.md",
    "content": "# Rename A Remote\n\nIf you just added a remote (`git remote add ...`) and messed up the name or\njust need to rename some existing remote, you can do so with the `rename`\ncommand.\n\nFirst, let's see the remotes we have:\n\n```bash\n$ git remote -v\norigin  https://github.com/jbranchaud/til.git (fetch)\norigin  https://github.com/jbranchaud/til.git (push)\n```\n\nTo then rename `origin` to `destination`, for example, we can issue the\nfollowing command:\n\n```bash\n$ git remote rename origin destination\n```\n\nSee `man git-remote` for more details.\n"
  },
  {
    "path": "git/renaming-a-branch.md",
    "content": "# Renaming A Branch\n\nThe `-m` flag can be used with `git branch` to move/rename an existing\nbranch. If you are already on the branch that you want to rename, all you\nneed to do is provide the new branch name.\n\n```bash\n$ git branch -m <new-branch-name>\n```\n\nIf you want to rename a branch other than the one you are currently on, you\nmust specify both the existing (old) branch name and the new branch name.\n\n```bash\n$ git branch -m <old-branch-name> <new-branch-name>\n```\n\nh/t Dillon Hafer\n"
  },
  {
    "path": "git/resetting-a-reset.md",
    "content": "# Resetting A Reset\n\nSometimes we run commands like `git reset --hard HEAD~` when we shouldn't\nhave. We wish we could undo what we've done, but the commit we've *reset* is\ngone forever. Or is it?\n\nWhen bad things happen, `git-reflog` can often lend a hand. Using\n`git-reflog`, we can find our way back to were we've been; to better times.\n\n```bash\n$ git reflog\n00f77eb HEAD@{0}: reset: moving to HEAD~\n9b2fb39 HEAD@{1}: commit: Add this set of important changes\n...\n```\n\nWe can see that `HEAD@{1}` references a time and place before we destroyed\nour last commit. Let's fix things by resetting to that.\n\n```bash\n$ git reset HEAD@{1}\n```\n\nOur lost commit is found.\n\nUnfortunately, we cannot undo all the bad in the world. Any changes to\ntracked files will be irreparably lost.\n\n[source](http://stackoverflow.com/questions/2510276/undoing-git-reset)\n"
  },
  {
    "path": "git/resolve-a-merge-conflict-from-stash-pop.md",
    "content": "# Resolve A Merge Conflict From Stash Pop\n\nOccasionally when I've stashed some changes and then `stash pop` them back onto\nme working tree, I'll end up with a merge conflict. Either some new commits or\nother changes to the working tree are in conflict with what's in the stash. Git\ntells me it's up to me to resolve it.\n\nRunning `git status`, I can see what files have merge conflicts. I can go and\nresolve those now based on what I want the state of my working tree to be.\n\nRunning `git status`, I'll also note that the files from the stash not involved\nin the conflict have been staged. I don' know why git stages those changes when\na merge conflict arises. When I `stash pop` and there is no merge conflict, git\nleaves the changes on the working tree.\n\nThis has confused me more than a couple times. Is there anything I need to do\nto complete or resolve the `stash pop`?\n\nNope. Resolving the conflicts in the affected files is all that needs to be\ndone. And since I'm generally not looking to create a commit at this point, I\n_unstage_ the staged changes with `git reset HEAD`.\n"
  },
  {
    "path": "git/restore-file-from-one-branch-to-the-current.md",
    "content": "# Restore File From One Branch To The Current\n\nOn one feature branch I have created some files and made changes to some\nexisting files as part of spiking a feature. Now I'm on a different branch\ntaking another shot at it. I want changes from one or two of the files. In the\npast I've used `git-checkout` for this task. However, I believe this is one of\nthe use cases they had in mind when they added `git-restore`.\n\nWhat I want to do is _restore_ the state of a file as it appears on some source\nbranch to my current branch. Here is what that looks like:\n\n```bash\n$ git restore --source=some-feature-branch app/models/contact.rb\n```\n\nNow when I check `git status` I'll see the state of that file on the\n`some-feature-branch` branch overlayed on my current working copy. If the file\ndoesn't exist, it will be created.\n\nSee `man git-restore` for more details.\n"
  },
  {
    "path": "git/review-commits-from-before-a-certain-date.md",
    "content": "# Review Commits From Before A Certain Date\n\nI was recently looking at data in a 3rd-party tool and saw that there was a\nvery distinct shift in what was being recorded a couple years prior on a\nspecific date. I wanted to see what changes had been made to the codebase a day\nor two before the shift.\n\nRather than scrolling all the way back in `git log`, I can tell `git log` to\nshow me all commits from before a certain date.\n\nLet's say that date of interest is May 1st, 2021. I can use the `--until` flag\nwith `git log`. However, I should note that `--until` is an exclusive range, so\nI'll need to specify `May 2 2021` if I want to start seeing commits on May 1.\n\n```bash\n$ git log --until='May 2 2021'\n```\n\nBecause `git log` shows commits in reverse chronological order, I'll start\nseeing commits from May 1st and then as I scroll, I'll see older and older\ncommits.\n\nFrom here I can scan commits messages and look for one that I want to dig into.\nI'd then use `git show <sha>` to explore a specific one further.\n\nThis is synonymous with `--before`.\n\nSee `man git-log` for more details.\n"
  },
  {
    "path": "git/run-a-git-command-from-outside-the-repo.md",
    "content": "# Run A Git Command From Outside The Repo\n\nGenerally you run a git command from somewhere within the parent folder where\nthe `.git` directory lives. Git recognizes the `.git` directory in that parent\ndirectory and runs your command against it.\n\nYou can run a command against a given git repository without being within the\nparent directory. This can be handy for scripting as well as for one-off\ncommands when you don't want to `cd` to the directory. To do this, you need to\ntell Git where to find the `.git` directory. You do this with the `-C` flag.\n\nFor instance, from anywhere on my machine, I can view a log of this TIL\nrepository with the following:\n\n```bash\n$ git -C ~/code/til log\n```\n\nNotice that the `-C` flag and its argument are positioned directly after `git`.\nThe command (`log`) should be positioned after that.\n\nSee `man git` for more details.\n\n[source](https://stackoverflow.com/a/35899275/535590)\n"
  },
  {
    "path": "git/set-a-custom-pager-for-a-specific-command.md",
    "content": "# Set A Custom Pager For A Specific Command\n\nThe pager can be [configured globally](configuring-the-pager.md), for [one run\nof a command](turn-off-the-output-pager-for-one-command.md), or as I'll explain\nin this post, for a specific command.\n\n_I explore all of this in [Optimize the way Git displays the output of\ncommands](https://www.youtube.com/watch?v=VpFldePcu_w)._\n\nLet's assume a git configuration that uses `less` for any command that need a\npager. Perhaps you'd like for the `git show` to work a bit differently than\nother commands. You want it to use `less` with the `-F` and `-X` flags.\n\nA custom pager command can be set for any command in the `[pager]` section of\nthe `~/.gitconfig` file.\n\n```\n[pager]\n  show = \"less -FX\"\n```\n\nIf you want to turn off the pager for a specific command, set it to the boolean\nvalue `false` instead.\n\n```\n[pager]\n  show = false\n```\n\nSee `man git-config` for more details in the `core.pager` and `pager.<cmd>`\nsections.\n"
  },
  {
    "path": "git/set-default-branch-name-for-new-repos.md",
    "content": "# Set Default Branch Name For New Repos\n\nWhen you run `git init` in a directory, it will initialize that directory as a\n`git` repository. The default branch name for any new git repository is\n`master`. A better name for the base branch would be something like `main`.\n\nTo set `main` as the new default for all new repos, you can run the following\n`git` command.\n\n```bash\n$ git config --global init.defaultBranch main\n```\n\nThis will update your `.gitconfig` file to contain the following lines.\n\n```\n[init]\n\tdefaultBranch = main\n```\n\nTry running `git init` in a fresh directory and then `git branch\n--show-current` to see that the base branch is now defaulting to `main`.\n"
  },
  {
    "path": "git/set-up-gpg-signing-key.md",
    "content": "# Set Up GPG Signing Key\n\nI wanted to have that \"Verified\" icon start showing up next to my commits in\nGitHub. To do that, I need to generate a GPG key, configure the secret key in\nGitHub, and then configure the public signing key with my git config.\n\n```bash\n# generate a gpg key\n$ gpg --full-generate-key\n\n# Pick the following options when prompted\n# - Choose \"RSA and RSA\" (Options 1)\n# - Max out key size at 4096\n# - Choose expiration date (e.g. 0 for no expiration)\n# - Enter \"Real name\" and \"Email\"\n    (I matched those to what is in my global git config)\n# - Set passphrase (I had 1password generate a 4-word passphrase)\n```\n\nIt may take a few seconds to create.\n\nI can see it was created by listing my GPG keys.\n\n```bash\n$ gpg --list-secret-keys --keyid-format=long\n[keyboxd]\n---------\nsec   rsa4096/1A8656918A8D016B 2025-10-19 [SC]\n...\n```\n\nI'll need the `1A8656918A8D016B` portion of that response for the next command\nand it is what I set as my public signing key in my git config.\n\nFirst, though, I add the full key block to my GitHub profile which I can copy\nlike so:\n\n```bash\n$ gpg --armor --export 1A8656918A8D016B | pbcopy\n```\n\nAnd then I paste that as a new GPG Key on GitHub under _Settings_ -> _SSH and\nGPG Keys_.\n\nLast, I update my global git config with the signing key and the preference to\nsign commits:\n\n```bash\ngit config --global user.signingkey 1A8656918A8D016B\ngit config --global commit.gpgsign true\n```\n\nWithout `commit.gpgsign`, I would have to specify the `-S` flag every time I\nwant to create a signed commit.\n\n[source](https://git-scm.com/book/ms/v2/Git-Tools-Signing-Your-Work)\n"
  },
  {
    "path": "git/shorthand-to-force-push-a-branch.md",
    "content": "# Shorthand To Force Push A Branch\n\nIf your local version of a branch differs in its history from the matching\nremote branch, then git will prevent you from pushing. You can override the\ndifference on the remote by force pushing. One way of doing that is with the\n`--force` flag.\n\n```bash\n$ git push --force origin main\n```\n\nThere is a shorthand for this. [Prefix the branch name with a\n`+`](https://git-scm.com/docs/git-push#Documentation/git-push.txt---force).\n\n```bash\n$ git push origin +main\n```\n\nWhen working in a team context, it is typically a safer bet to use\n`--force-with-lease` instead of force. That way if the remote contains new\nchanges that you haven't pulled down yet, you will prevent yourself from\naccidentally overriding them.\n\nIf you feel you must use `--force`, double check what will happen. Avoid\naccidentally clobbering work that could be hard or impossible to recover.\n\n[source](https://twitter.com/jbrancha/status/1558861987374780416?s=20&t=D7T_aTBaF97AwOvUnz9Muw)\n"
  },
  {
    "path": "git/show-all-commits-for-a-file-beyond-renaming.md",
    "content": "# Show All Commits For A File Beyond Renaming\n\nBy including `-- <filename>` with a `git log` command, we can list all the\ncommits for a file. The following is an example of such a command with some\nformatting and file names.\n\n```bash\n> git log --name-only --pretty=format:%H -- README.md\n4e57c5d46637286731dc7fbb1e16330f1f3b2b7c\nREADME.md\n\n56955ff027f02b57212476e142a97ce2b7e60efe\nREADME.md\n\n5abdc5106529dd246450b381f621fa1b05808830\nREADME.md\n```\n\nWhat we may not realize, though, is that we are missing out on a commit in\nthis file's history. At one point, this file was renamed. The command above\nwasn't able to capture that.\n\nUsing the `--follow` flag with a file name, we can list all commits for a\nfile beyond renaming.\n\n```bash\n> git log --name-only --pretty=format:%H --follow README.md\n4e57c5d46637286731dc7fbb1e16330f1f3b2b7c\nREADME.md\n\n56955ff027f02b57212476e142a97ce2b7e60efe\nREADME.md\n\n5abdc5106529dd246450b381f621fa1b05808830\nREADME.md\n\nea885f458b0d525f673623f2440de9556954c0c9\nREADME.rdoc\n```\n\nThis command roped in a commit from when `README.md` used to be called\n`README.rdoc`. If you want to know about the *full* history of a file, this\nis the way to go.\n\n[source](http://stackoverflow.com/questions/3701404/list-all-commits-for-a-specific-file)\n"
  },
  {
    "path": "git/show-changes-for-files-that-match-a-pattern.md",
    "content": "# Show Changes For Files That Match A Pattern\n\nThe `git show` command allows you to view the changes associated with a\nreference, such as a commit sha (e.g. `git show 86748aacf14e`).\n\nConsider a commit that has changed a bunch of JS files as well as two CSS\nfiles. If we run `git show abcd1234`, we will see all of the changes to each\nfile which can result in quite a bit of noise. What if we only want to view\nthe changes to the CSS files?\n\nWe can instruct the command to only show changes to files that match a\npattern by tacking that pattern on to the end.\n\n```bash\n$ git show abcd1234 *.css\n```\n\nAlternatively, we could scope the output of the command to the files that\nlive in a certain directory.\n\n```bash\n$ git show abcd1235 src/css\n```\n"
  },
  {
    "path": "git/show-changes-in-the-compose-commit-message-view.md",
    "content": "# Show Changes In The Compose Commit Message View\n\nWhen you execute `git commit`, you'll be dropped into your default editor\nand prompted to compose a commit message. By default you'll only see the\nstatus and names of the files involved in the commit.\n\nTo also see the line-by-line-changes in this view, you'll want to commit in\nverbose mode.\n\n```bash\n$ git commit --verbose\n```\n\nYou can also set verbose mode as the default by updating your `~/.gitconfig`\nfile.\n\n```\n[commit]\n    verbose = true\n```\n\n[source](https://stackoverflow.com/questions/5875275/git-commit-v-by-default)\n"
  },
  {
    "path": "git/show-file-diffs-when-viewing-git-log.md",
    "content": "# Show File Diffs When Viewing Git Log\n\nInclude the `-p` flag with the `git log` command to include the diffs along\nwith the rest of the information for each commit. Here is an example of\nrunning this against this repository.\n\n```bash\n$ git log -p\ncommit b9809a329acd8150b2474168f8faaf008f376e35\nAuthor: jbranchaud <jbranchaud@gmail.com>\nDate:   Wed Oct 11 07:27:53 2017 -0500\n\n    Add Inline Style Attributes Should Be Camel Cased as a react til\n\ndiff --git a/README.md b/README.md\nindex c982f8e..6ee7d32 100644\n--- a/README.md\n+++ b/README.md\n@@ -10,7 +10,7 @@ smart people at [Hashrocket](http://hashrocket.com/).\n For a steady stream of TILs from a variety of rocketeers, checkout\n [til.hashrocket.com](https://til.hashrocket.com/).\n\n-_574 TILs and counting..._\n+_575 TILs and counting..._\n\n ---\n```\n\nSee `man git-log` for more details.\n"
  },
  {
    "path": "git/show-list-of-most-recently-committed-branches.md",
    "content": "# Show List Of Most Recently Committed Branches\n\nThe standard way to list your branches is with the `git branch` command. If\nyou use branches extensively for feature work and bug fixes, you may find\nyourself overwhelmed by the list of branches trying to visually parse\nthrough them for the one that you had worked on recently.\n\nWith the `git for-each-ref` command, we can produce a better list of\nbranches.\n\n```bash\n$ git for-each-ref --sort=-committerdate --count=10 --format='%(refname:short)' refs/heads/\n```\n\nThe command itself will iterate over all of the repository's refs and print\nthem out as a list. The `--sort=-committerdate` option will ensure that list\nis sorted by refs mostly recently committed to. The `--count=10` option\nlimits the list output to 10 refs. The `format` flag cleans up the output a\nbit, only showing the shortname of the ref. Lastly, the `refs/heads/`\nargument ensures that only local refs are included in the output, thus\nignoring remote refs.\n\nThe result is a list of local branches ordered by recency which generally\ncorresponds to relevance.\n\nSee `man git-for-each-ref` for more details.\n\n[source](https://twitter.com/djm_/status/961289486721339392)\n"
  },
  {
    "path": "git/show-only-commits-that-touch-specific-lines.md",
    "content": "# Show Only Commits That Touch Specific Lines\n\nWhen you run `git log`, you are listing all commits in reverse-chronological\norder for the current branch. There are ways of filtering the commits that\nget output from `git-log`. As of Git 1.8.4, `git-log` output can be filtered\nby commits that touch a range of line numbers.\n\nThis is done with the `-L` flag.\n\nFor instance, if I want to see all commits that touched the 13th line of my\n`README.md` file, then I can do this:\n\n```bash\n$ git log -L13,13:README.md\n```\n\nI can alter the command to show commits that touched a range of lines like\nso:\n\n```bash\n$ git log -L19,45:README.md\n```\n\nI used the `-L` flag recently to find when a dependency was added to my\n`package.json` file even though the most recent changes to that line were\nversion bumps.\n\n[source](https://stackoverflow.com/questions/8435343/retrieve-the-commit-log-for-a-specific-line-in-a-file)\n"
  },
  {
    "path": "git/show-summary-stats-for-current-branch.md",
    "content": "# Show Summary Stats For Current Branch\n\nWhen I push a branch up to GitHub as a PR, there is a part of the UI that shows\nyou how many lines you've added and removed for this branch. It bases that off\nthe target branch which is typically your `main` branch.\n\nThe `git diff` command can provide those same stats right in the terminal. The\nkey is to specify the `--shortstat` flag which tells `git` to exclude other diff\noutput and only show:\n\n- Number of files changed\n- Number of insertions\n- Number of deletions\n\nHere is the summary stats for a branch I'm working on:\n\n```bash\n❯ git diff --shortstat main\n 8 files changed, 773 insertions(+), 25 deletions(-)\n```\n\nWe have to be on our feature branch and then we point to the branch (or whatever\nref) we want to diff against. Since I want to know how my feature branch\ncompares to `main`, I specify that.\n\nSee `man git-diff` for more details.\n"
  },
  {
    "path": "git/show-the-diffstat-summary-of-a-commit.md",
    "content": "# Show The diffstat Summary Of A Commit\n\nUse the `--stat` flag when running `git show` on a commit to see the\n`diffstat` summary of that commit. For instance, this is what I get for a\nrecent commit to [delve](https://github.com/derekparker/delve):\n\n```bash\n$ git show 8a1f36a1ce --stat\ncommit 8a1f36a1ce71d708d1d82afbc2191de9aefba021\nAuthor: Derek Parker <derek.parker@coreos.com>\nDate:   Wed Jan 27 23:47:04 2016 -0800\n\n    dlv: Flag to print stacktrace on trace subcommand\n\n cmd/dlv/main.go     | 45 ++++++++++-----------------------------------\n terminal/command.go |  7 +++++--\n 2 files changed, 15 insertions(+), 37 deletions(-)\n```\n\nThe following is a description of the `diffstat` program\n\n> This  program  reads the output of diff and displays a histogram of the\n> insertions, deletions, and modifications per-file.\n\nSee `man git-show` and `man diffstat` for more details.\n"
  },
  {
    "path": "git/show-the-good-and-the-bad-with-git-bisect.md",
    "content": "# Show The Good And The Bad With Git Bisect\n\nThe [`git bisect`](https://git-scm.com/docs/git-bisect) command is a\npowerful tool for tracking down a past commit where something verifiable\nabout the code changed -- whether it be visual or functional. After using\n`git bisect` to traverse back and forth through your commit history, you may\nbe wondering where things stand.\n\nThe [`git bisect\nlog`](https://git-scm.com/docs/git-bisect#_bisect_log_and_bisect_replay)\ncommand will show you each commit that has been inspected and whether you've\nmarked it as good or bad.\n\nThese records can be handy for double checking your work if you're worried\nthat you made a mistake along the way.\n"
  },
  {
    "path": "git/show-what-is-in-a-stash.md",
    "content": "# Show What Is In A Stash\n\nUsually when I want to inspect anything in git, I'll use `git show` with a\nspecific ref. This can even be done with stash refs.\n\n```bash\n$ git stash list\nstash@{0}: WIP on ...\nstash@{1}: Some commit on ...\n\n$ git show stash@{0}\n# ...\n```\n\nThe `git-stash` command has a built-in way of showing stashes that will save\nyou from having to type out the somewhat awkward `stash@{n}` ref.\n\n```bash\n$ git stash show 1\n```\n\nThis will show you the `stash@{1}` ref. You can also omit a number which\nwill show you the latest stash (`stash@{0}`).\n\nSee `man git-stash` for more details.\n"
  },
  {
    "path": "git/single-key-presses-in-interactive-mode.md",
    "content": "# Single Key Presses in Interactive Mode\n\nWhen staging changes in interactive mode (`git add -p`), you have a number\nof options associated with single keys. `y` is *yes*, `n` is *no*, `a` is\n*this and all remaining*, and so on.\n\nBy default, you have to press *enter* after making your selection. However,\nit can be configured for single key presses. Add the following to your git\nconfiguration file to enable single key presses for interactive mode:\n\n```\n[interactive]\n    singlekey = true\n```\n\n[source](https://github.com/hashrocket/dotmatrix/blob/master/.gitconfig#L33-L34)\n"
  },
  {
    "path": "git/skip-a-bad-commit-when-bisecting.md",
    "content": "# Skip A Bad Commit When Bisecting\n\nThe `git bisect` command helps you quickly track down the commit where a bug\nwas introduced. It is quick because it picks the optimal (minimal) commits in a\nbinary search fashion.\n\nIt is possible that `git bisect` will pick a commit that you aren't able to\nevaluate as _good_ or _bad_. If that commit is in a WIP state or for some other\nunrelated reason prevents you from evaluating it, then you are kinda stuck.\n\nTo move forward, tell `git bisect` that you want to skip this commit:\n\n```bash\n$ git bisect skip\n```\n\nIt will flag that one as skipped and find you another nearby commit to evaluate\ninstead.\n\nIf your commit history is in such a state that you have to skip many of the\nsuggested commits, it is possible that `git bisect` will not be able to help\nyou identify the problem commit. You may be left with a few commits that you'll\nhave to manually read through and evaluate.\n\nThis is a good reason to keep your commits atomic and in a functional state.\n\n[source](https://git-scm.com/docs/git-bisect#_bisect_skip)\n"
  },
  {
    "path": "git/skip-git-hooks-as-needed.md",
    "content": "# Skip Git Hooks As Needed\n\nProjects have Git hooks configured for all sorts of reasons. Most common are\n`pre-commit` hooks which verify certain aspects of the contents of a commit.\nA `pre-commit` hook could check that the tests all pass, that the changes don't\ninclude any debugging statements, and so forth. There are all kinds of hooks\nthough, like `pre-rebase` and `post-checkout`.\n\nThese hooks can sometimes get in the way and we may need to skip or disable them\non a one-off basis.\n\nSeveral Git commands offer a `--no-verify` flag which can skip running the hook\nassociated with that command.\n\n- `git commit --no-verify` (skips `pre-commit` and `commit-msg` hooks)\n- `git push --no-verify` (skips `pre-push` hook)\n- `git merge --no-verify` (skips `pre-merge-commit` hook)\n- `git am --no-verify` (skips `applypatch-msg` and `pre-applypatch` hooks)\n\nIf you look in the `.git/hooks` directory, there are several other hooks not\ncovered by the above. So, what if I am doing an action like `git checkout` and I\nwant to skip the `post-checkout` hook?\n\nI can override the `hooksPath` config for that one command with the `-c` flag.\n\n```sh\n$ git -c core.hooksPath=/dev/null checkout ...\n```\n\nBy setting it to `/dev/null`, it will find *no* hooks available, so none will be\nexecuted for this command.\n\nSee `man git-config` for more details on `core.hooksPath`.\n"
  },
  {
    "path": "git/skip-pre-commit-hooks.md",
    "content": "# Skip Pre-Commit Hooks\n\nProjects can choose to adopt pre-commit hooks as part of their contribution\nworkflow. These hooks can help enforce project standards like ensuring a set of\nchanges are formatted and linting properly. These can be set up with a tool\nlike [husky](https://github.com/typicode/husky) or with a custom script.\n\nAs you're working on a feature branch, you can and should make frequent\ncheckpoint commits like a climber puts\n[pitons](https://en.wikipedia.org/wiki/Piton) into the rock face. These are\nanchor points that reduce the risk of losing work. They make it easier and\nsafer to return to a point in time when your code was in a \"good\" state.\n\nIf your checkpoint commit isn't conforming to all the pre-commit hook checks,\nyou can choose to skip the checks and commit anyway. To do this, tack on the\n`--no-verify` flag.\n\n```bash\n$ git commit --no-verify\n```\n\nWith this checkpoint in place, you can either plunge forward with the feature\nor you can even go fix the pre-commit violations and combine them into\n(`--amend`) that checkpoint commit.\n\nDon't abuse this. You still want the overall work to conform to project\nguidelines. Use the process that works best for you as you get there.\n\nSee `man git-commit` for more details.\n"
  },
  {
    "path": "git/staging-changes-within-vim.md",
    "content": "# Staging Changes Within Vim\n\nI've always used git from the command line, but only recently have I started\nto leverage [fugitive.vim](https://github.com/tpope/vim-fugitive) to more\nquickly do some common git commands from within vim.\n\nI mostly use *fugitive* to stage changes for committing. To stage entire\nfiles, you can view the repository status, `:Gstatus`, and then navigate up\nand down (`k` and `j`) tapping `-` next to the files to be staged (or\nunstaged).\n\nI've started to use git's interactive mode for staging changes from the\ncommand line (`git add --patch`) more and more and recently wondered if the\nsame thing can be accomplished with *fugitive*.\n\nIt turns out it's pretty simple to do so. Instead of tapping `-` next to a\nfile you want to stage, you can tap `p` next to it and you will be\nimmediately dropped into interactive mode for that file. Prepare the lines\nyou want to stage (or, again, unstage) and save.\n"
  },
  {
    "path": "git/staging-stashes-interactively.md",
    "content": "# Staging Stashes Interactively\n\nThe `-p` flag can be used with `git stash`, just as it is used with `git add`,\nfor interactively staging a stash.\n\nSo, if you have changes in your working tree that you want to stash mixed\nwith ones that you want to keep working with, then you can simply do:\n\n```\ngit stash -p\n```\n\nRead more on [interactive\nstaging](https://git-scm.com/book/en/v2/Git-Tools-Interactive-Staging).\n"
  },
  {
    "path": "git/stash-a-single-untracked-file.md",
    "content": "# Stash A Single Untracked File\n\nIf you want to stash everything in your work tree and untracked files, you can\nrun:\n\n```bash\n$ git stash -u\n```\n\nIf you want a bit more control over what gets stashed from the work tree, you\ncan interactively stash with `--patch` (or `-p`):\n\n```bash\n$ git stash -p\n```\n\nUnfortunately, the two don't work together.\n\n```bash\n$ git stash -u -p\nCan't use --patch and --include-untracked or --all at the same time\n```\n\nSo, if you'd like to stash a specific untracked file, you can instead formulate\na command like the following:\n\n```bash\n$ git stash -u -- <name-of-untracked-file>\n```\n\nThis will stash just the specified untracked file and leave the rest of them as\nthey are.\n\nI found this useful when trying to test the setup of a new library. There was\nan extra new file that I didn't think I needed. Stashing it temporarily gets it\nout of the way without losing it.\n"
  },
  {
    "path": "git/stash-everything.md",
    "content": "# Stash Everything\n\nRunning the `git stash` command will take all the changes to tracked files\nin the working directory and stash them away. You can tack on the\n`--include-untracked` flag to make sure that untracked files are also\nincluded in the stash.\n\nYou can take this a step further with the `--all` flag. This will stash\neverything included files that you've told git to ignore.\n\nYou probably don't want to do this. I ran this command and realized after\nthe command hung for about 10 seconds that I had just stashed the\n`node_modules` directory.\n\nSee `man git-stash` for more details.\n"
  },
  {
    "path": "git/stashing-only-unstaged-changes.md",
    "content": "# Stashing Only Unstaged Changes\n\nIf you have both staged and unstaged changes in your project, you can\nperform a stash on just the unstaged ones by using the `-k` flag. The\nstaged changes will be left intact ready for a commit.\n\n```\n$ git status\nOn branch master\n...\nChanges to be committed:\n\n    modified:   README.md\n\nChanges not staged for commit:\n\n    modified:   app/models/user.rb\n\n$ git stash -k\nSaved working directory and index state ...\n\n$ git status\nOn branch master\n...\nChanges to be committed:\n\n    modified:   README.md\n```\n\nh/t [Chris Erin](https://twitter.com/MCNormalMode)\n"
  },
  {
    "path": "git/stashing-untracked-files.md",
    "content": "# Stashing Untracked Files\n\nNormally when stashing changes, using `git stash`, git is only going to\nstash changes to *tracked* files. If there are any new files in your project\nthat aren't being tracked by git, they will just be left lying around.\n\nYou might not want these *untracked* files left behind, polluting your\nworking copy. Perhaps these files change your projects functionality or\naffect the outcome of tests. You just want them out of the way, for the\nmoment at least.\n\nAnd so along comes the `-u` or `--untracked` flag.\n\n```bash\n$ touch new_file.rb\n$ git stash\nNo local changes to stash\n$ git stash -u\nSaved working directory and index state WIP ...\n```\n"
  },
  {
    "path": "git/switch-to-a-recent-branch-with-fzf.md",
    "content": "# Switch To A Recent Branch With FZF\n\n[Git](https://git-scm.com/) and [FZF](https://github.com/junegunn/fzf) make\na powerful team. Once you've installed FZF on your machine, there are all\nkinds of add-on scripts that you can include in your shell configuration.\n\nThis one, for instance, is a personal favorite.\n\n```bash\nfbr() {\n  local branches branch\n  branches=$(git for-each-ref --count=30 --sort=-committerdate refs/heads/ --format=\"%(refname:short)\") &&\n  branch=$(echo \"$branches\" |\n           fzf-tmux -d $(( 2 + $(wc -l <<< \"$branches\") )) +m) &&\n  git checkout $(echo \"$branch\" | sed \"s/.* //\" | sed \"s#remotes/[^/]*/##\")\n}\n```\n\nWhen you run the `fbr` command from your shell, FZF will compile a list of\nthe most recently committed to branches (including remote branches). That\nlist will then be available in a standard FZF prompt so that you can choose\nthe branch you want to switch to.\n\n[source](https://github.com/junegunn/fzf/wiki/examples)\n"
  },
  {
    "path": "git/transition-a-branch-from-one-base-to-another.md",
    "content": "# Transition A Branch From One Base To Another\n\nLet's say I'm working in a git workflow where we have `main` as our production\nbranch and `dev` as our development branch. I've opened a feature branch off of\n`main` and made a series of commits. It is at that point that I realize I\nshould instead be branched off `dev`. I could open up a new branch off `dev`\nand then `cherry-pick` those commits. That is messier and more steps than\nnecessary.\n\nInstead, I can transition the feature branch I'm already working from to a\ndifferent base.\n\nThe [`git-rebase`](https://git-scm.com/docs/git-rebase) command supports this\nwith the `--onto` flag.\n\n```bash\n$ git rebase --onto dev main my-feature-branch\n```\n\nSpecify the new base branch (`dev`), the current base (`main`), and then the\nname of the branch you are transitioning (`my-feature-branch`).\n\n[source](https://stackoverflow.com/a/10853956/535590)\n"
  },
  {
    "path": "git/turn-off-the-output-pager-for-one-command.md",
    "content": "# Turn Off The Output Pager For One Command\n\nWith `git` a pager, such as `less`, can be configured to display paginated\ncommand output. There are many ways to set up the default pager such as setting\nthe `core.pager` value in your git-config or by setting the `$PAGER` env var.\n\nAssuming it is set to something like `less`, you can view, scroll through, and\nsearch the output of a command like `git log` or `git diff`. When you're\nfinished the pager will close, all the output will vanish, and you'll be back\nat your terminal prompt.\n\nThis is generally a desirable workflow. If, however, you want to be able to\nscroll back in your terminal history to reference a SHA or a commit message,\nyou'll be disappointed.\n\nFor one off commands where you know you'll want the output actually printed to\nthe terminal, you can turn off the pager with the `--no-pager` flag (or `-P` as\na shorthand).\n\n```bash\n$ git --no-pager show\n```\n\nThis will print the details of the HEAD commit to the terminal. I can scroll\nback and reference them as needed.\n\n[source](https://stackoverflow.com/questions/2183900/how-do-i-prevent-git-diff-from-using-a-pager#:~:text=17%20Answers&text=%2D%2Dno%2Dpager%20to%20Git,fits%20in%20a%20single%20screen.&text=As%20a%20previous%20answer%20mentioned,is%20less%20than%20one%20screen.)\n"
  },
  {
    "path": "git/two-kinds-of-dotted-range-notation.md",
    "content": "# Two Kinds Of Dotted Range Notation\n\nThere are two kinds of dotted range notation in git -- `..` and `...`.\n\nIf you'd like to view all changes on your current feature branch since checking\nout from `master`, you can use the two-dot notation:\n\n```bash\n❯ git log master..some-feature-branch --oneline\n9e50bff (some-feature-branch) Add second feature change\nb11bb0b Add first feature change\n```\n\nYou could also switch the refs around to see what has changed on master since\nchecking out:\n\n```bash\n❯ git log some-feature-branch..master --oneline\nc2880f8 (HEAD -> master) Add description to README\n```\n\nThen there is the three-dot notation. This will include all commits from the\nsecond ref that aren't in the first and all commits in the first that aren't in\nthe second.\n\n```bash\n❯ git log master...some-feature-branch --oneline\nc2880f8 (HEAD -> master) Add description to README\n9e50bff (some-feature-branch) Add second feature change\nb11bb0b Add first feature change\n```\n\nSee `man git-rev-parse` for more details.\n\n[source](https://stackoverflow.com/a/24186641/535590)\n"
  },
  {
    "path": "git/undo-latest-changes-committed-to-specific-file.md",
    "content": "# Undo Latest Changes Committed To Specific File\n\nI'm reviewing the changes I've made in a PR before I request a review from my\nteam. There are a scattering of changes in one file that I've changed my mind\non. Everything else looks good though. So, I need to undo the changes in that\nfile before proceeding.\n\nManually undoing them is going to be clunky. There is a way to do it with `git\ncheckout`, but that is one of the ways in which `git-checkout` was overloaded\nleading to the release of `git-restore`.\n\nLet's use `git-restore` instead. By specifying a `--source`, I can tell `git`\nwhat _ref_ in the commit history that file should be restored to. I'm on a\nshort-lived feature branch, so pointing to `main` is good enough.\n\n```bash\n$ git restore --source=main app/models/customer.rb\n```\n\nIf I've changed a file at multiple points on this feature branch and I don't\nwant to undo all of them, then pointing to `main` is no longer going to work.\nInstead, I can point to the commit right before the current one (`HEAD`) that\nI'm trying to undo.\n\n```bash\n$ git restore --source=HEAD~ app/models/customer.rb\n```\n\nThis really isn't much different than the `git-checkout` version, but I still\nfind it to be a little clearer.\n\n```bash\n$ git checkout HEAD~ -- app/models/customer.rb\n```\n\nSee `man git-restore` for more details.\n"
  },
  {
    "path": "git/unstage-changes-with-git-restore.md",
    "content": "# Unstage Changes With Git Restore\n\nGit 2.23 introduced the `restore` command which is a more direct alternative to\n`checkout` and `reset` for restoring the state of the working tree and the\nindex (staging area).\n\nWith the `--staged` flag, we can unstage changes, moving them from the index to\nthe working tree.\n\n> To restore a file in the index to match the version in HEAD (this is the same\n> as using git-reset(1))\n\n```\n$ git restore --staged README.md\n```\n\nStaged changes to `README.md` will be removed from the index and put on the\nworking tree.\n\n```\n$ git restore --staged .\n```\n\nThat will unstage all changes on the index.\n\nThis is now recommended by Git when you run `git status`:\n\n> (use \"git restore --staged <file>...\" to unstage)\n\nSee `man git-restore` for more details.\n"
  },
  {
    "path": "git/untrack-a-directory-of-files-without-deleting.md",
    "content": "# Untrack A Directory Of Files Without Deleting\n\nIn [Untrack A File Without Deleting It](untrack-a-file-without-deleting-it.md),\nI explained how a specific file can be removed from tracking without\nactually deleting the file from the local file system. The same can be done\nfor a directory of files that you don't want tracked. Just use the `-r`\nflag:\n\n```bash\n$ git rm --cached -r <directory>\n```\n\n[source](http://stackoverflow.com/questions/1143796/remove-a-file-from-a-git-repository-without-deleting-it-from-the-local-filesyste)\n"
  },
  {
    "path": "git/untrack-a-file-without-deleting-it.md",
    "content": "# Untrack A File Without Deleting It\n\nGenerally when I invoke `git rm <filename>`, I do so with the intention of\nremoving a file from the project entirely. `git-rm` does exactly that,\nremoving the file both from the index and from the working tree.\n\nIf you want to untrack a file (remove it from the index), but still have it\navailable locally (in the working tree), then you are going to want to use\nthe `--cached` flag.\n\n```bash\n$ git rm --cached <filename>\n```\n\nIf you do this, you may also consider adding that file to the `.gitignore`\nfile.\n\n[source](http://stackoverflow.com/questions/15027873/untrack-and-stop-tracking-files-in-git)\n"
  },
  {
    "path": "git/update-the-url-of-a-remote.md",
    "content": "# Update The URL Of A Remote\n\nI just changed the name of a Github repository. One of the implications of\nthis is that the remote URL that my local git repository has on record is\nnow out of date. I need to update it.\n\nIf I use `git-remote` with the `-v` flag. I can see what remotes I currently\nhave.\n\n```bash\n$ git remote -v\norigin  git@github.com:jbranchaud/pokemon.git (fetch)\norigin  git@github.com:jbranchaud/pokemon.git (push)\n```\n\nNow, to update the URL for that remote, I can use `git remote set-url`\nspecifying the name of the remote and the updated URL.\n\n```bash\n$ git remote set-url origin git@github.com:jbranchaud/pokemon_deluxe.git\n```\n\nIf I check again, I can see it has been updated accordingly.\n\n```bash\n$ git remote -v\norigin  git@github.com:jbranchaud/pokemon_deluxe.git (fetch)\norigin  git@github.com:jbranchaud/pokemon_deluxe.git (push)\n```\n"
  },
  {
    "path": "git/use-external-diff-tool-like-difftastic.md",
    "content": "# Use External Diff Tool Like Difftastic\n\nAssuming we already have a tool like `difft`\n([difftastic](https://difftastic.wilfred.me.uk/introduction.html)) available on\nour machine, we can use it as a diff viewer for the various `git` commands that\ndisplay a diff.\n\nThis requires a manual override which involve two pieces — an inline\nconfiguration of `diff.external` specifying the binary of the external differ\nand the `--ext-diff` flag which tells these commands to use the external diff\nbinary.\n\nHere is what `git show` looks like with `difft`:\n\n```bash\n$ git -c diff.external=difft show --ext-diff\n```\n\nWithout the `--ext-diff` flag, it will fallback to the default differ despite\n`diff.external` being set.\n\nSee `man git-diff` and friends for the `--ext-diff` flag. See `man git-config`\nfor `diff.external`.\n"
  },
  {
    "path": "git/using-commands-with-a-relative-date-format.md",
    "content": "# Using Commands With A Relative Date Format\n\nIf you want to know what changed on a branch _since_ last week, you can more or\nless ask just like that:\n\n```bash\n$ git log --since=\"1 week ago\"\n```\n\nOr, what has happened since yesterday:\n\n```bash\n$ git log --after=\"yesterday\"\n```\n\nThe `--since`/`--after` flags, and their counterparts `--until`/`--before`,\naccept a variety of date formats including _relative dates_.\n\nRelative dates can be used with other commands and even as a ref modifier. For\ninstance, this is a way of comparing `develop` from a week ago with `develop`\nfrom two weeks ago:\n\n```bash\n$ git diff develop@{\"1 week ago\"} develop@{\"2 weeks ago\"}\n```\n\n[source](https://alexpeattie.com/blog/working-with-dates-in-git)\n"
  },
  {
    "path": "git/verbose-commit-message.md",
    "content": "# Verbose Commit Message\n\nGit allows you to display a *diff* of the staged changes in the commit\nmessage buffer. This gives you the opportunity to carefully craft your\ncommit message in a way that accurately describes the changes being\ncommitted. To display the diff when committing:\n\n```bash\n$ git commit -v\n```\n"
  },
  {
    "path": "git/viewing-a-file-on-another-branch.md",
    "content": "# Viewing A File On Another Branch\n\nSometimes you want to view a file on another branch (without switching\nbranches). That is, you want to view the version of that file as it exists\non that branch. `git show` can help. If your branch is named `my_feature` and\nthe file you want to see is `app/models/users.rb`, then your command should\nlook like this:\n\n```\n$ git show my_feature:app/models/users.rb\n```\n\nYou can even tab-complete the filename as you type it out.\n\nSee `man git-show` for more details.\n\n[source](http://stackoverflow.com/questions/7856416/view-a-file-in-a-different-git-branch-without-changing-branches)\n"
  },
  {
    "path": "git/what-changed.md",
    "content": "# What Changed?\n\nIf you want to know what has changed at each commit in your Git history,\nthen just ask `git whatchanged`.\n\n```bash\n$ git whatchanged\n\ncommit ddc929c03f5d629af6e725b690f1a4d2804bc2e5\nAuthor: jbranchaud <jbranchaud@gmail.com>\nDate:   Sun Feb 12 14:04:12 2017 -0600\n\n    Add the source to the latest til\n\n:100644 100644 f6e7638... 2b192e1... M  elixir/compute-md5-digest-of-a-string.md\n\ncommit 65ecb9f01876bb1a7c2530c0df888f45f5a11cbb\nAuthor: jbranchaud <jbranchaud@gmail.com>\nDate:   Sat Feb 11 18:34:25 2017 -0600\n\n    Add Compute md5 Digest Of A String as an Elixir til\n\n:100644 100644 5af3ca2... 7e4794f... M  README.md\n:000000 100644 0000000... f6e7638... A  elixir/compute-md5-digest-of-a-string.md\n\n...\n```\n\nThis is an old command that is mostly equivalent to `git-log`. In fact, the\nman page for `git-whatchanged` says:\n\n> New users are encouraged to use git-log(1) instead.\n\nThe difference is that `git-whatchanged` shows you the changed files in\ntheir raw format which can be useful if you know what you are looking for.\n\nSee `man git-whatchanged` for more details.\n"
  },
  {
    "path": "git/what-is-the-current-branch.md",
    "content": "# What Is The Current Branch?\n\nThis question can be answered with one of git's plumbing commands,\n`rev-parse`.\n\n```\n$ git rev-parse --abbrev-ref HEAD\n```\n\nThe `--abbrev-ref` flag tells `git-rev-parse` to give us the short name for\n`HEAD` instead of the SHA.\n\n[source](http://stackoverflow.com/a/12142066/535590)\n"
  },
  {
    "path": "git/whitespace-warnings.md",
    "content": "# Whitespace Warnings\n\nYou can configure git to warn you about whitespace issues in a file when you\ndiff it. This is handled by the `core.whitespace` configuration. Add the\nfollowing to your `.gitconfig` file:\n\n```\n[core]\n      whitespace = warn\n```\n\nBy default, git will warn you of trailing whitespace at the end of a line as\nwell as blank lines at the end of a file.\n"
  },
  {
    "path": "github/access-your-github-profile-photo.md",
    "content": "# Access Your GitHub Profile Photo\n\nLet's say I have my [GitHub profile](https://github.com/jbranchaud) pulled up in\nthe browser.\n\n```\nhttps://github.com/jbranchaud\n```\n\nIf I then add `.png` to the end of that in the URL bar:\n\n```\nhttps://github.com/jbranchaud.png\n```\n\nI'll be redirected to the URL where the full image file lives. In my case:\n\n```\nhttps://avatars.githubusercontent.com/u/694063?v=4\n```\n\nYou can pull up yours `https://github.com/<username>.png` to access your profile\nimage.\n\n[source](https://dev.to/10xlearner/how-to-get-the-profile-picture-of-a-github-account-1d82)\n"
  },
  {
    "path": "github/open-a-pr-to-an-unforked-repo.md",
    "content": "# Open A PR To An Unforked Repo\n\nSometimes I will clone a repo to explore the source code or to look into a\npotential bug. If my curiosity takes me far enough to make some changes, then I\njump through the hoops of creating a fork, reconfiguring branches, pushing to my\nfork, and then opening the branch as a PR against the original repo.\n\nThe `gh` CLI allows me to avoid all that hoop-jumping. Directly from the cloned\nrepo I can use `gh` to create a new PR. It will prompt me to creat a fork. If I\naccept, it will seamlessly create it and then open a PR from my fork to the\noriginal.\n\n```bash\n$ gh pr create\n```\n\nThis allows me to create the PR with a few prompts from the CLI. If you prefer,\nyou can include the `--web` flag to open the PR creation screen directly in the\nbrowser.\n"
  },
  {
    "path": "github/target-another-repo-when-creating-a-pr.md",
    "content": "# Target Another Repo When Creating A PR\n\nI have a [`dotfiles` repo](https://github.com/jbranchaud/dotfiles) that I forked\nfrom [`dkarter/dotfiles`](https://github.com/dkarter/dotfiles). I'm adding a\nbunch of my own customizations on a `main` branch while continually pulling in\nand merging upstream changes.\n\nThe primary remote according to `gh` is `jbranchaud/dotfiles`. 98% of the time\nthat is what I want. However, I occasionally want to share some changes upstream\nvia a PR. Running `gh pr create` as is will create a PR against my fork. To\noverride this on a one-off basis, I can use the `--repo` flag.\n\n```bash\n$ gh pr create --repo dkarter/dotfiles\n```\n\nThis will create a PR against `dkarter:master` from my branch (e.g.\n[`jbranchaud:jb/fix-hardcoded-paths`](https://github.com/dkarter/dotfiles/pull/373)).\n\nSee `man gh-pr-create` for more details.\n"
  },
  {
    "path": "github/tell-gh-what-the-default-repo-is.md",
    "content": "# Tell gh What The Default Repo Is\n\nI recently forked [dkarter/dotfiles](https://github.com/dkarter/dotfiles) as a\nway of bootstrapping a robust dotfile config for a new machine that I could\nstart making customizations to. I'm maintaining a `my-dotfiles` branch and keep\nthings in sync with the original upstream repo.\n\nWhen trying to go to *my* fork of the repo\n([jbranchaud/dotfiles](https://github.com/jbranchaud/dotfiles)) in the web with\nthe `gh` CLI tool, I ran into a weird issue. It was instead opening up to\n`dkarter/dotfiles`.\n\n`gh` was under the wrong impression which repo should be considered the default.\nTo clarify things for `gh`, there is a command to set the default repo.\n\n```bash\n$ gh repo set-default jbranchaud/dotfiles\n✓ Set jbranchaud/dotfiles as the default repository for the current directory\n```\n\nNow when I run `gh repo view --web`, it opens the browser to my fork of the\ndotfiles.\n\nBut where does this setting live?\n\nOpening this repo's `.git/config` file I can see a section for the `origin`\nremote that includes a new line for `gh-resolved`. This being set to `base`\ntells `gh` that this remote is the one to treat as the default repo.\n\n```\n[remote \"origin\"]\n\turl = git@github.com:jbranchaud/dotfiles.git\n\tfetch = +refs/heads/*:refs/remotes/origin/*\n\tgh-resolved = base\n\n```\n\nSee `gh repo set-default --help` for more details.\n"
  },
  {
    "path": "github-actions/cache-playwright-dependencies-across-workflows.md",
    "content": "# Cache Playwright Dependencies Across Workflows\n\nWith the help of `actions/cache@v3`, I can cache the dependency install and\nsetup involved with using Playwright in GitHub Actions. That setup, in my\nexperience, typically takes ~45s. When it is already cached, it is able to skip\nthat step entirely greatly reducing the overall run time of the script.\n\nFirst, I need to define a cache (`playwright-cache`). Second, I need to only\ninstall the Playwright dependencies when that cache isn't available (`cache-hit\n!= 'true'`).\n\nHere is a striped down workflow demonstrating that.\n\n```yaml\nname: Playwright Script\non:\n  workflow_dispatch:\njobs:\n  Cached-Playwright-Script:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Check out repository code\n        uses: actions/checkout@v3\n      - uses: actions/cache@v3\n        id: playwright-cache\n        with:\n          path: |\n            ~/.cache/ms-playwright\n          key: ${{ runner.os }}-playwright-${{ hashFiles('**/package-lock.json') }}\n      - name: Install dependencies\n        run: npm ci\n      - name: Install playwright deps\n        run: npx playwright install --with-deps chromium\n        if: steps.playwright-cache.outputs.cache-hit != 'true'\n      - run: node playwright-script.js\n```\n\nIf I add the caching step and the cache-conditional `playwright install` steps\nto another workflow in this project, the cache will be available to both of\nthem. That means they both benefit from the savings of that work having already\nbeen cached.\n\n[source](https://justin.poehnelt.com/posts/caching-playwright-in-github-actions/)\n"
  },
  {
    "path": "github-actions/capture-an-output-value-for-use-in-a-later-step.md",
    "content": "# Capture An Output Value For Use In A Later Step\n\nGitHub Actions has a workflow command called `set-output`. This can be used to\ncapture the output from a shell command in step. That output value can then be\nused in a later step.\n\nA useful example of this is reading the version of a tool from a dot-file to\ntell a later step what version of that tool to install.\n\nHere's the `.tool-versions` file included in my repository:\n\n```\npostgres 13.1\nruby 3.0.0\nnodejs 15.4.0\n```\n\nAssuming I've already [checked out my\nrepo](https://github.com/actions/checkout), I can find and read the `nodejs`\nversion from my `.tool-versions` file with a step that uses `set-output`.\n\n```yaml\n  - name: Read Node.js version to install from `.tool-versions`\n    id: nodejs\n    run: >-\n      echo \"::set-output name=NODE_VERSION::$(\n        cat .tool-versions |\n        grep nodejs |\n        sed 's/nodejs \\(.*\\)$/\\1/'\n      )\"\n```\n\n`echo` runs the command in the string which sets `NODE_VERSION` as an output\nvalue to what ends up being `15.4.0`.\n\nThis output value can be referenced in a later step.\n\n```yaml\n  - name: Install required Node.js version\n    uses: actions/setup-node@v1\n    with:\n      node-version: \"${{ steps.nodejs.outputs.NODE_VERSION }}\"\n```\n\n`steps` has a reference to the `nodejs` step (note the `id` above) which then\nhas `outputs` like the `NODE_VERSION`.\n\n[source](https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#using-workflow-commands-to-access-toolkit-functions)\n"
  },
  {
    "path": "github-actions/disable-a-workflow-with-the-gh-cli.md",
    "content": "# Disable A Workflow With The gh CLI\n\nYou may want to temporarily disable a GitHub Actions workflow without deleting\nthe file for the workflow. In my case, this is handy because I want to keep a\nscheduled workflow around as a point of reference, but I don't want it running\nall the time.\n\nThis can be done with [the `workflow` subcommand of the `gh`\nCLI](https://docs.github.com/en/actions/using-workflows/disabling-and-enabling-a-workflow?tool=cli).\n\nFirst, list the workflows for your current repo so that you can figure out the\nworkflow ID that you want to disable.\n\n```bash\n$ gh workflow list\nGitHub Actions Demo          active  60018591\nPlaywright Demo              active  60142509\nScheduled Actions Demo       active  60028624\n```\n\nNow, copy the ID of the workflow you want to disable. In my case, it is\n`60028624`.\n\nThen, run the `disable` command for that workflow ID:\n\n```bash\n$ gh workflow disable 60028624\n✓ Disabled Scheduled Actions Demo\n```\n\nThat workflow is now disabled and it is no longer going to show up in the\ndefault listing of workflows.\n\nIf you want to see it in the list though, you can include the `--all` flag.\n\n```bash\n$ gh workflow list --all\nGitHub Actions Demo          active             60018591\nPlaywright Demo              active             60142509\nScheduled Actions Demo       disabled_manually  60028624\n```\n"
  },
  {
    "path": "github-actions/reference-an-encrypted-secret-in-an-action.md",
    "content": "# Reference An Encrypted Secret In An Action\n\nCI environments like GitHub Actions want to help you keep your secrets secret.\nThey allow you to store an encrypted version of a secret that can be access in\nan action.\n\nFirst, you need to add an encrypted secret to your repository. Navigate to your\nrepository's _Settings_ page and then to the _Secrets_ tab. You can then add\nthe secret with the _New repository secret_ button.\n\nOnce the secret is added, you can reference it in your actions.\n\nLet's say you added your repository secret with the name `MY_API_KEY`. And then\nlet's say that your project needs to be built with that API key available in\nthe environment as `SECRET_API_KEY`. You can reference it from `secrets` in the\n`env` section.\n\n```yaml\n  - name: Build the JS bundle\n    run: yarn build\n    env:\n      SECRET_API_KEY: ${{ secrets.MY_API_KEY }}\n```\n\nThough this API key is stored on GitHub's servers as an encrypted value, it\nwill be decrypted when this workflow step is run.\n\n[source](https://docs.github.com/en/actions/reference/encrypted-secrets#using-encrypted-secrets-in-a-workflow)\n"
  },
  {
    "path": "github-actions/trigger-a-workflow-via-an-api-call.md",
    "content": "# Trigger A Workflow Via An API Call\n\nWe can set up a GitHub Actions workflow to run when triggered by an API call.\nThis is done with the [`workflow_dispatch`\nevent](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch).\n\nFirst, we add `workflow_dispatch` to our workflow as a triggering event:\n\n```yaml\non:\n  workflow_dispatch:\n```\n\nSecond, we create a fine-grained personal GitHub access token that has permissions\nfor dispatching to GitHub Actions. More details on that in the [GitHub\ndocs](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-fine-grained-personal-access-token).\n\nThen, we can use `cURL` or some other tool for issuing an HTTP POST request to\n[the workflow dispatch API\nendpoint](https://docs.github.com/en/rest/actions/workflows?apiVersion=2022-11-28#create-a-workflow-dispatch-event). The `cURL` request will look something like this:\n\n```bash\ncurl -L \\\n  -X POST \\\n  -H \"Accept: application/vnd.github+json\" \\\n  -H \"Authorization: Bearer <YOUR-TOKEN>\"\\\n  -H \"X-GitHub-Api-Version: 2022-11-28\" \\\n  https://api.github.com/repos/OWNER/REPO/actions/workflows/WORKFLOW_ID/dispatches \\\n  -d '{\"ref\":\"topic-branch\",\"inputs\":{\"name\":\"Mona the Octocat\",\"home\":\"San Francisco, CA\"}}'\n```\n\nNote: we need to alter that URL with the `OWNER` and `REPO` that the workflow\nlives in as well as the `WORKFLOW_ID` which can be the name of the workflow\nfile (e.g. `my-dispatchable-workflow.yml`).\n\nThis event also means that we can manually trigger the workflow from the\nGitHub Actions UI for that workflow.\n"
  },
  {
    "path": "github-actions/use-labels-to-block-pr-merge.md",
    "content": "# Use Labels To Block PR Merge\n\nLet's say our GitHub project has custom tags for both `no merge` and `wip`\n(_work in progress_). Whenever either of those labels has been applied to a PR,\nwe want there to be a failed check so as to block the merge. This is useful to\nensure automated tools (as well as someone not looking closely enough) don't\nmerge a PR that isn't _ready to go_.\n\nThis can be achieved with a basic GitHub Actions workflow that requires no\n3rd-party actions. We can add the following as\n`.github/workflows/block-labeled-prs.yml` in our project.\n\n```yaml\nname: Block Labeled PR Merges\n\non:\n  pull_request:\n    types: [labeled, unlabeled, opened, edited, synchronize]\n\njobs:\n  prevent-merge:\n    if: ${{ contains(github.event.*.labels.*.name, 'no merge') || contains(github.event.*.labels.*.name, 'wip') }}\n    name: Prevent Merging\n    runs-on: ubuntu-latest\n    steps:\n      - name: Check for label\n        run: |\n          echo \"Pull request label prevents merging.\"\n          echo \"Labels: ${{ join(github.event.*.labels.*.name, ', ') }}\"\n          echo \"Remove the blocking label(s) to skip this check.\"\n          exit 1\n```\n\nThis workflow is run when a pull request is opened, when it is edited or\nsynchronized, and when a label change is made. The job `prevent-merge` sees if\nany of the label names match `no merge` or `wip`. If so, we echo out some\ndetails in the ubuntu container and then `exit 1` to fail the check.\n\nShoutout to [Jesse Squire's\nimplementation](https://www.jessesquires.com/blog/2021/08/24/useful-label-based-github-actions-workflows/#updated-21-march-2022)\nwhich I've heavily borrowed from here.\n"
  },
  {
    "path": "go/access-go-docs-offline.md",
    "content": "# Access Go Docs Offline\n\nThe Go language has a wonderfully comprehensive standard library. There is\ndocumentation for all of it. You can access that documentation anytime if\nyou have an internet connection via\n[https://golang.org/doc/](golang.org/doc/).\n\nIf you are without an internet connection, you're still in luck. Go has a\nbuilt-in feature for serving the documentation locally _offline_. Just run\nthe following command:\n\n```\n$ godoc -http=:6060\n```\n\nand then visit `localhost:6060`.\n\nNote: if you do not already have `godoc` installed, you can install it with:\n\n```bash\n$ go install golang.org/x/tools/cmd/godoc@latest\n```\n\n[source](http://www.andybritcliffe.com/post/44610795381/offline-go-lang-documentation)\n"
  },
  {
    "path": "go/add-a-method-to-a-struct.md",
    "content": "# Add A Method To A Struct\n\nGiven a `struct` in Go, we can attach a method to that struct. Put another way,\nwe can define a method whose receiver is that struct. Then with an instance of\nthat struct, we can call the method.\n\nLet's say we are modeling a turtle that can move around a 2D grid. A turtle has\na heading (the direction it is headed) and a location (its current X,Y\ncoordinate).\n\n```go\ntype Heading string\n\nconst (\n\tUP    Heading = \"UP\"\n\tRIGHT Heading = \"RIGHT\"\n\tDOWN  Heading = \"DOWN\"\n\tLEFT  Heading = \"LEFT\"\n)\n\ntype Turtle struct {\n\tDirection Heading\n\tX         int\n\tY         int\n}\n```\n\nWe can then add a method like so by specifying the receiver as the first part\nof the declaration:\n\n```go\nfunc (turtle *Turtle) TurnRight() {\n\tswitch turtle.Direction {\n\tcase UP:\n\t\tturtle.Direction = RIGHT\n\tcase RIGHT:\n\t\tturtle.Direction = DOWN\n\tcase DOWN:\n\t\tturtle.Direction = LEFT\n\tcase LEFT:\n\t\tturtle.Direction = UP\n\t}\n}\n```\n\nThe receiver is a pointer to a `Turtle`. The method is called `TurnRight`.\nThere are no parameters or return values.\n\nHere are a sequence of calls to demonstrate how it works:\n\n```go\nfunc main() {\n\tturtle := Turtle{UP, 5, 5}\n\n\tfmt.Println(\"Turtle Direction:\", turtle.Direction)\n\t//=> Turtle Direction: UP\n\n\tturtle.TurnRight()\n\n\tfmt.Println(\"Turtle Direction:\", turtle.Direction)\n\t//=> Turtle Direction: RIGHT\n\n\tturtle.TurnRight()\n\n\tfmt.Println(\"Turtle Direction:\", turtle.Direction)\n\t//=> Turtle Direction: DOWN\n}\n```\n\n[source](https://go.dev/tour/methods/1)\n"
  },
  {
    "path": "go/basic-delve-debugging-session.md",
    "content": "# Basic Delve Debugging Session\n\nWhen using [delve](https://github.com/go-delve/delve) to debug a Go program,\nthese are the series of things I usually find myself doing.\n\nFirst, I start running the program with `dlv` including any arguments after a `--` (in my case, the `solve` subcommand and a filename).\n\n```bash\n$ dlv debug . -- solve samples/001.txt\n```\n\n`dlv` starts up and is ready to run my program from the beginning. I'll need to\nset a couple breakpoints before continuing. I do this with the `break` command,\nspecifying the filename and line number.\n\n```\n(dlv) break main.go:528\nBreakpoint 1 set at 0x10c1a5bea for main.traversePuzzleIterative() ./main.go:528\n(dlv) break main.go:599\nBreakpoint 2 set at 0x10c1a6dcc for main.traversePuzzleIterative() ./main.go:599 \n```\n\nNow I can continue which will run the program until hitting a breakpoint.\n\n```\n(dlv) continue\n> [Breakpoint 2] main.traversePuzzleIterative() ./main.go:599 (hits goroutine(1):1 total:1) (PC: 0x10c1a6dcc)\n   594:                                 }\n   595:                         }\n   596:\n   597:                         topStackFrame := stack[len(stack)-1]\n   598:                         // if the current stack frame has more values, try the next\n=> 599:                         if len(topStackFrame.PossibleValues) > 0 {\n   600:                                 nextValue := topStackFrame.PossibleValues[0]\n   601:                                 topStackFrame.PossibleValues = topStackFrame.PossibleValues[1:]\n   602:                                 topStackFrame.CurrValue = nextValue\n   603:\n   604:                                 // Undo the last placement and make a new one\n```\n\nI can see the context around the line we've stopped on. From here I can dig\ninto the current state of the program by looking at local variables (`locals`)\nor printing out a specific value (`print someVar`). I can continue to step\nthrough the program line by line with `next` or eventually run `continue` to\nproceed to the next breakpoint.\n\n```\n(dlv) locals\ndiagnostics = main.Diagnostics {BacktrackCount: 0, NodeVisitCount: 1, ValidityCheckCount: 2,...+2 more}\nstack = []main.StackData len: 1, cap: 1, [...]\nemptyCellPositions = [][]int len: 3, cap: 4, [...]\nemptyCellIndex = 1\nstatus = \"Invalid\"\ntopStackFrame = main.StackData {RowIndex: 1, ColumnIndex: 7, PossibleValues: []int len: 8, cap: 8, [...],...+1 more}\n(dlv) print topStackFrame\nmain.StackData {\n        RowIndex: 1,\n        ColumnIndex: 7,\n        PossibleValues: []int len: 8, cap: 8, [2,3,4,5,6,7,8,9],\n        CurrValue: 1,}\n(dlv) next\n> main.traversePuzzleIterative() ./main.go:600 (PC: 0x10c1a6dea)\n```\n"
  },
  {
    "path": "go/build-for-a-specific-os-and-architecture.md",
    "content": "# Build For A Specific OS and Architecture\n\nGo programs can run anywhere, but you've got to create builds specific to\neach operating system and architecture. This can be done when building by\nspecifying the `GOOS` and `GOARCH` environment variables.\n\nFor example, if you'd like to build a 32-bit Linux distribution:\n\n```bash\nGOOS=linux GOARCH=386 go build -o linux_386_build\n```\n\nThe `GOOS` value specifies the operating system as Linux and the `GOARCH`\nvalue of `386` specifies a 32-bit architecture.\n\nThe plethora of `GOOS` and `GOARCH` options can be found\n[here](https://golang.org/doc/install/source#environment).\n"
  },
  {
    "path": "go/check-if-cobra-flag-was-set.md",
    "content": "# Check If Cobra Flag Was Set\n\nWhen using [Cobra](https://github.com/spf13/cobra) to define a CLI, we can\nspecify a flag for a command like so:\n\n```go\nvar Seed int64\nmyCmd.PersistentFlags().Int64VarP(&Seed, \"seed\", \"\", -1, \"set a seed\")\n```\n\nThis `--seed` flag has a _default_ of `-1`. If the flag isn't specified, then\nwhen we access that flag's value, we'll get `-1`.\n\nBut how do we differentiate between the _default_ `-1` and someone passing `-1`\nto the `--seed` flag when running the program?\n\nIn the command definition, we can look at the flags and see, by name, if\nspecific ones were changed by user input rather than being the defaults.\n\n```go\nmyCommand := &cobra.Command{\n\t// coommand setup ...\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tif cmd.Flags().Changed(\"seed\") {\n\t\t\tseed, err := cmd.Flags().GetInt64(\"seed\")\n\t\t\tif err != nil {\n\t\t\t\tfmt.Println(\"Seed flag is missing from `cmdFlags()`\")\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\n\t\t\tfmt.Printf(\"Seed was set to %d\\n\", seed)\n\t\t} else {\n\t\t\tfmt.Println(\"Seed was not set\")\n\t\t}\n\t}\n}\n```\n\nIf we don't want to rely on the default and instead want to specify some other\nbehavior when the flag is not manually set by the user, we can detect that\nscenario like this.\n"
  },
  {
    "path": "go/combine-two-slices.md",
    "content": "# Combine Two Slices\n\nThe `append` function can be used to create a new slice with the contents of\nthe given slice and one or more items added to the end.\n\nWe can add one or more items like so:\n\n```go\ns1 := []int{1, 2, 3, 4}\ns2 := append(s1, 5)\ns3 := append(s2, 6, 7, 8)\n\nfmt.Println(s1) //=> [1 2 3 4]\nfmt.Println(s2) //=> [1 2 3 4 5]\nfmt.Println(s3) //=> [1 2 3 4 5 6 7 8]\n```\n\nBut what if we have a second slice instead of individual items? We could import\n`slices` and use its `Concat` function. Or we can stick with `append` and\nunpack that slice as a series of arguments into the second part of `append`\nusing `slice...`.\n\n```go\ns4 := append(s2, s1...)\nfmt.Println(s4) //=> [1 2 3 4 5 1 2 3 4]\n```\n\nHere is the full example:\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\ts1 := []int{1, 2, 3, 4}\n\ts2 := append(s1, 5)\n\ts3 := append(s2, 6, 7, 8)\n\n\tfmt.Println(s1)\n\tfmt.Println(s2)\n\tfmt.Println(s3)\n\n\ts4 := append(s2, s1...)\n\tfmt.Println(s4)\n}\n```\n\n[source](https://pkg.go.dev/builtin#append)\n"
  },
  {
    "path": "go/configure-max-string-print-length-for-delve.md",
    "content": "# Configure Max String Print Length For Delve\n\nDuring a [Delve](https://github.com/go-delve/delve) debugging session, we can\nprint out the value of a given variable with the `print` command. Similarly, we\ncan see the values of all local variables with the `locals` command.\n\nWhenever Delve is printing out strings and slices, it will truncate what it\ndisplays to 64 characters (or items) by default.\n\n```go\n(dlv) print diagnostics.Solutions[0]\n\"295743861\\n431865972\\n876192543\\n387459216\\n612387495\\n549216738\\n7635...+25 more\"\n```\n\nThis can be overridden by [changing the `config` of\n`max-string-len`](https://github.com/derekparker/delve/blob/237c5026f40e38d2dd6f62a7362de7b25b00c1c7/Documentation/cli/expr.md?plain=1#L59)\nto something longer. In my case here, all I need are about 90 characters to\ndisplay my full string, so run `config max-string-len 90` from the `dlv`\nsession.\n\n```go\n(dlv) config max-string-len 90\n(dlv) print diagnostics.Solutions[0]\n\"295743861\\n431865972\\n876192543\\n387459216\\n612387495\\n549216738\\n763524189\\n928671354\\n154938627\"\n```\n\nNow I can see the entire string instead of the truncated version.\n\n[source](https://stackoverflow.com/a/52416264/535590)\n"
  },
  {
    "path": "go/connect-to-a-sqlite-database.md",
    "content": "# Connect To A SQLite Database\n\nUsing the `database/sql` module and the `github.com/mattn/go-sqlite3` package,\nwe can connect to a SQLite database and run some queries. In my case, I have a\nSQLite connection string exported to my environment, so I can access that with\n`os.Getenv`. It's a local SQLite file, `./test.db`.\n\nCalling `sql.Open`, I'm able to connect with a SQLite3 driver to the database\nat that connection string. The `setupDatabase` function returns that database\nconnection pointer. Things like `Exec` and `QueryRow` can be called on `db`. I\nalso need to make sure I close the connection to the database with a `defer`.\n\nHere is a full example of connecting to a local SQLite database and inserting a\nrecord:\n\n```go\npackage main\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"os\"\n\n\t_ \"github.com/mattn/go-sqlite3\"\n)\n\nfunc setupDatabase() *sql.DB {\n\tdatabaseString := os.Getenv(\"GOOSE_DBSTRING\")\n\tif len(databaseString) == 0 {\n\t\tfmt.Println(\"Error retrieving `GOOSE_DBSTRING` from env\")\n\t\tos.Exit(1)\n\t}\n\tdb, err := sql.Open(\"sqlite3\", databaseString)\n\tif err != nil {\n\t\tfmt.Printf(\"Error opening database: %v\\n\", err)\n\t\tos.Exit(1)\n\t}\n\n\treturn db\n}\n\nfunc main() {\n\tdb := setupDatabase()\n\tdefer db.Close()\n\n\tsql := `insert into users (name) values (?);`\n\n\tdb.Exec(sql, \"Josh\")\n}\n```\n"
  },
  {
    "path": "go/create-a-slice-from-an-array.md",
    "content": "# Create A Slice From An Array\n\nSlices in Go are a flexible abstraction over arrays. We can create a slice from\nan array with the `[n:m]` _slicing_ syntax. We specify the left and right\n(exclusive) bounds of the array that we want to create the slice relative to.\n\nWe can exclude the lower bound which translates to the `0` index of the array.\nWe can exclude the left bound which translates to the end of the array. We can\neven exclude both ends of the _slicing_ syntax which means creating a slice of\nthe entire array.\n\nHere is an example of each of those:\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\tarr := [...]string{\n\t\t\"taco\",\n\t\t\"burrito\",\n\t\t\"torta\",\n\t\t\"enchilada\",\n\t\t\"quesadilla\",\n\t\t\"pozole\",\n\t}\n\n\tfirstTwo := arr[:2]\n\tlastTwo := arr[len(arr)-2:]\n\tall := arr[:]\n\n\tfmt.Println(\"First two:\", firstTwo)\n\t// First two: [taco burrito]\n\n\tfmt.Println(\"Last two:\", lastTwo)\n\t// Last two: [quesadilla pozole]\n\n\tfmt.Println(\"All:\", all)\n\t// All: [taco burrito torta enchilada quesadilla pozole\n}\n```\n\n[source](https://go.dev/blog/slices-intro#slices)\n"
  },
  {
    "path": "go/detect-if-stdin-comes-from-a-redirect.md",
    "content": "# Detect If Stdin Comes From A Redirect\n\nReading lines of input from `stdin` is flexible. And we may need our program to\nbehave differently depending on where that input is coming from. For instance,\nif data is redirected or piped to our program, we scan and process it directly.\nOtherwise, we need to prompt the user to enter in specific info and go from\nthere.\n\nWe can detect whether [`os.Stdin`](https://pkg.go.dev/os#pkg-variables) is\nbeing piped to, redirected to, or whether we should prompt the user by looking\nat the file mode descriptor of\n[`os.Stdin.Stat()`](https://pkg.go.dev/os#File.Stat).\n\n```go\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"os\"\n)\n\nfunc main() {\n\tfile, err := os.Stdin.Stat()\n\tif err != nil {\n\t\tfmt.Printf(\"Error checking stdin: %v\\n\", err)\n\t\tos.Exit(1)\n\t}\n\n\tfromTerminal := (file.Mode() & os.ModeCharDevice) != 0\n\tfromAPipe := (file.Mode() & os.ModeNamedPipe) != 0\n\n\tif fromTerminal {\n\t\tfmt.Println(\"This is Char Device mode, let's prompt user for input\")\n\t\ttermScanner := bufio.NewScanner(os.Stdin)\n\t\tfor termScanner.Scan() {\n\t\t\tfmt.Printf(\"- %s\\n\", termScanner.Text())\n\t\t\tbreak;\n\t\t}\n\t} else if fromAPipe {\n\t\tfmt.Println(\"This is Named Pipe mode, contents piped in\")\n\t\tpipeScanner := bufio.NewScanner(os.Stdin)\n\t\tfor pipeScanner.Scan() {\n\t\t\tfmt.Printf(\"- %s\\n\", pipeScanner.Text())\n\t\t}\n\t} else {\n\t\tfmt.Println(\"This means the input was redirected\")\n\t\tredirectScanner := bufio.NewScanner(os.Stdin)\n\t\tfor redirectScanner.Scan() {\n\t\t\tfmt.Printf(\"- %s\\n\", redirectScanner.Text())\n\t\t}\n\t}\n}\n```\n\nIf `os.ModeCharDevice` then we are connected to a character device, like the\nterminal. We can see if input is being piped in by checking against\n`os.ModeNamedPipe`. Otherwise, there are a variety of file modes and I'm\nwilling to assume we're dealing with a regular file redirect at that point.\n"
  },
  {
    "path": "go/deterministically-seed-a-random-number-generator.md",
    "content": "# Deterministically Seed A Random Number Generator\n\nIf you need a random number in Go, you can always reach for the various\nfunctions in the `rand` package.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n)\n\nfunc main() {\n\tfor range 5 {\n\t\troll := rand.Intn(6) + 1\n\t\tfmt.Printf(\"- %d\\n\", roll)\n\t}\n}\n```\n\nEach time I run that, I get a random set of values. Often in programming, we\nwant some control over the randomness. We want to _seed_ the randomness so that\nit is deterministic. We want random, but the kind of random where we know how\nwe got there.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n)\n\nfunc main() {\n\tseed := int64(123)\n\tsrc := rand.NewSource(seed)\n\trng := rand.New(src)\n\n\tfor range 5 {\n\t\troll := rng.Intn(6) + 1\n\t\tfmt.Printf(\"- %d\\n\", roll)\n\t}\n}\n```\n\nIn this second snippet, we create a `Source` with a specific seed value that we\ncan use with a custom `Rand` struct. We can then deterministically get random\nnumbers from it.\n"
  },
  {
    "path": "go/difference-between-slice-and-pointer-to-slice.md",
    "content": "# Difference Between Slice And Pointer To Slice\n\nThough a slice can be thought of and used as a flexible, variable-length\narray-like data structure, it is important to understand that it is also a\nspecial kind of pointer to an underlying array.\n\nThis matters when we a function receives a slice versus a pointer to a slice as\nan argument, depending on what it is doing with that slice.\n\nIf the function is access or updating elements in the slice, there is no\ndifference. There is no meaningful difference between these two functions and\nwe might as well use the former.\n\n```go\nfunc replaceAtIndex(slice []string, index int, value string) {\n\tslice[index] = value\n}\n\nfunc replaceAtIndexPtr(slice *[]string, index int, value string) {\n\t(*slice)[index] = value\n}\n```\n\nOn the other hand, if the receiving function needs to append to or replace the\nslice, then we need to pass a pointer to the slice. A direct slice argument\nwill result in only the function-local copy getting replaced.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\ts1 := []int{8, 6, 7, 9}\n\ts2 := []int{8, 6, 7, 9}\n\n\taddItem(s1, 11)\n\tfmt.Printf(\"s1: %v\\n\", s1) //=> s1: [8 6 7 9]\n\n\taddItemPtr(&s2, 11)\n\tfmt.Printf(\"s2: %v\\n\", s2) //=> s2: [8 6 7 9 11]\n}\n\nfunc addItem(slice []int, value int) {\n\tslice = append(slice, value)\n}\n\nfunc addItemPtr(slice *[]int, value int) {\n\t(*slice) = append(*slice, value)\n}\n```\n\n[source](https://go.dev/tour/moretypes/8)\n"
  },
  {
    "path": "go/do-something-n-times.md",
    "content": "# Do Something N Times\n\nWith Go 1.23 there is a new for-range syntax that makes looping a bit easier\nand more compact.\n\nInstead of needing to set up our 3-part for-loop syntax, we can say we want to\ndo something `N` times with `for range N`.\n\n```go\nfor range n {\n\t// do something\n}\n```\n\nLet's look at an actual, runnable example:\n\n```go\npackage main\n\nimport \"fmt\"\nimport \"math/rand\"\nimport \"time\"\n\nfunc main() {\n\trand.Seed(time.Now().UnixNano()) \n\n\tfood := []string{\"taco\", \"burrito\", \"torta\", \"enchilada\", \"tostada\"}\n\n\tfor range 5 {\n\t\trandomIndex := rand.Intn(len(food))\n\t\tfmt.Println(food[randomIndex])\n\t}\n}\n```\n\nThe output is random and might look something like this:\n\n```bash\n$ go run loop.go\ntaco\nburrito\ntostada\ntaco\nenchilada\n```\n\nI appreciate this syntax addition because it feels very akin to Ruby's `#times`\nmethod:\n\n```ruby\n5.times do\n  # do something\nend\n```\n\n[source](https://eli.thegreenplace.net/2024/ranging-over-functions-in-go-123/)\n"
  },
  {
    "path": "go/find-executables-installed-by-go.md",
    "content": "# Find Executables Installed By Go\n\nWhen you install an executable using `go install`, it puts that executable in\nthe `bin` directory designated by the `GOBIN` environment variable. If that env\nvar isn't set, then it falls back to one of `$GOPATH/bin` or `$HOME/go/bin`.\n\nWhen I run `go help install`, it tells me as much:\n\n```\nExecutables are installed in the directory named by the GOBIN environment\nvariable, which defaults to $GOPATH/bin or $HOME/go/bin if the GOPATH\nenvironment variable is not set.\n```\n\nSo, if I am to install something like [`tern`](https://github.com/jackc/tern),\n\n```bash\n$ go install github.com/jackc/tern/v2@latest\n```\n\nit is going to place that binary in `~/go/bin` for me.\n\n```bash\n$ which tern\n/Users/jbranchaud/go/bin/tern\n```\n"
  },
  {
    "path": "go/format-date-and-time-with-time-constants.md",
    "content": "# Format Date And Time With Time Constants\n\nThe Go [`time` package](https://pkg.go.dev/time) has a [`Format`\nfunction](https://pkg.go.dev/time#Time.Format) for displaying the parts of a\ndate and time in standard and custom ways. It works a bit different than you\nmight be used to from other languages. Rather than using `strftime` identifiers\nlike in this string `\"%B %d, %Y\"`, there is a canonical date that is used as a\nreference point.\n\nThat canonical date is from Janary 2nd, 2006. That was a Monday. It was at 5\nseconds after 3:04PM. The Unix format of it looks like `\"Mon Jan _2 15:04:05\nMST 2006\"`.\n\n```\npackage main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc main() {\n\t// This specific time pulled from `time.Format` docs\n\tt, _ := time.Parse(time.UnixDate, \"Wed Feb 25 11:06:39 PST 2015\")\n\n\t// Reference date and time:\n\t// \"Mon Jan _2 15:04:05 MST 2006\"\n\n\tstrf1 := t.Format(\"|2006|02|01|03:04:05|Day: Mon|\")\n\tfmt.Println(\"strf1:\", strf1)\n\t// strf1: |2015|25|02|11:06:39|Day: Wed|\n\n\tstrf2 := t.Format(time.DateTime)\n\tstrf3 := t.Format(time.RubyDate)\n\tstrf4 := t.Format(time.Kitchen)\n\n\tfmt.Println(\"DateTime:\", strf2) // DateTime: 2015-02-25 11:06:39\n\tfmt.Println(\"RubyDate:\", strf3) // RubyDate: Wed Feb 25 11:06:39 +0000 2015\n\tfmt.Println(\"Kitchen:\", strf4)  // Kitchen: 11:06AM\n}\n```\n\nThough there are a [variety of useful formatting\nconstants](https://pkg.go.dev/time#pkg-constants) already available like\n`DateTime`, `RubyDate`, `Kitchen`, etc., we can also define our own formatting\nstring by using the reference values for each part of a date and time.\n\nIf you want to reference the year, whether as `YYYY` or `YY`, it is always\ngoing to be a form of `2006`, so `2006` or `06` respectively. Even though the\nabove time variable is in February, our format strings will always need to use\none of `Jan`, `January`, `01` or `1`.\n"
  },
  {
    "path": "go/not-so-random.md",
    "content": "# Not So Random\n\nGo's `rand` package makes it easy to generate all sorts of pseudo-random\nnumbers. So if you write a program like so:\n\n```go\npackage main\n\nimport \"fmt\"\nimport \"math/rand\"\n\nfunc main() {\n    stuff := []string{\n        \"one\",\n        \"two\",\n        \"three\",\n        \"four\",\n    }\n    fmt.Println(stuff[rand.Intn(len(stuff))])\n}\n```\n\nand then run it, you will get output like:\n\n```\nthree\n```\n\nand any subsequent runs of the program will continue to produce `three`. This\nis because the default seed for global functions in `math/rand` is \n[specified](https://golang.org/pkg/math/rand/#Seed) as `1`.\n\nIf you want your program to be a little less predictable, you will want to\nseed it yourself, perhaps with the current time, instead of `1`. Try adding\nthe following to the beginning of the `main` function:\n\n```go\nrand.Seed(time.Now().UTC().UnixNano())\n```\n\nYou'll also want to import the `time` package.\n\nThings should *appear* to be a bit more random now.\n\nsource: [Jake Worth](https://twitter.com/jwworth) and\n[Stackoverflow](http://stackoverflow.com/questions/12321133/golang-random-number-generator-how-to-seed-properly)\n"
  },
  {
    "path": "go/parse-a-string-into-individual-fields.md",
    "content": "# Parse A String Into Individual Fields\n\nLet's say you're reading in data from a file or otherwise dealing with an\narbitrary string of data. If that string has a series of values separated by\nwhitespace, you can parse it into individual fields with\n[`strings.Fields`](https://pkg.go.dev/strings#Fields).\n\n```go\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nfunc main() {\n\tdata := \"3 5 2 6 7 1 9\"\n\tfields := strings.Fields(data)\n\n\tfmt.Printf(\"Fields: %v\", fields)\n\t// [3 5 2 6 7 1 9]\n}\n```\n\nHere is another example where we can see that `strings.Fields` deals with\nmultiple whitespace and surrounding whitespace:\n\n```go\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nfunc main() {\n\tdata := \"  go  java c++ rust \"\n\tfields := strings.Fields(data)\n\n\tfmt.Printf(\"%v\", fields)\n\t// [go java c++ rust]\n}\n```\n"
  },
  {
    "path": "go/parse-flags-from-cli-arguments.md",
    "content": "# Parse Flags From CLI Arguments\n\nThough we can grab the arguments to a Go program from `os.Args`, it requires\nsome manual parsing. With the built-in `flag` package, we can declare specific\nflags our program accepts, by type. When we parse them, they will be separated\nout from the rest of the positional arguments.\n\nHere is an example of the program that accepts a boolean `debug` flag. This\nwill work with either `-debug` or `--debug`.\n\n```go\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n)\n\nfunc main() {\n\tvar debug bool\n\tflag.BoolVar(&debug, \"debug\", false, \"turns on debug mode, extra logging\")\n\tflag.Parse()\n\n\tpositionalArgs := flag.Args()\n\n\tif len(positionalArgs) < 1 {\n\t\tfmt.Println(\"Please specify which part to run: 1 or 2\")\n\t\tos.Exit(1)\n\t}\n\n\tif debug {\n\t\tfmt.Println(\"We are in debug mode...\")\n\t\tfmt.Println(\"Received the following argument:\", positionalArgs[0])\n\t}\n\n\t// ...\n}\n```\n\nWe can run the program in debug mode like so:\n\n```bash\n$ go run . --debug 123\nWe are in debug mode...\nReceived the following argument: 123\n```\n\nWe can also take advantage of the `help` flag that we get for free:\n\n```bash\n$ go run . --help\nUsage of /var/folders/62/lx9pcjbs1zbd83zg6twwym2r0000gn/T/go-build3212087168/b001/exe/test:\n  -debug\n        turns on debug mode, extra logging\n```\n\nNote: any recognized flags need to come before any of the position arguments.\nThe `debug` flag won't be picked up if we run the program like this:\n\n```bash\n$ go run . 123 --debug\n```\n\n[source](https://pkg.go.dev/flag)\n"
  },
  {
    "path": "go/pass-a-struct-to-a-function.md",
    "content": "# Pass A Struct To A Function\n\nGo operates as _pass-by-value_ which means that when we pass a struct to a\nfunction, the receiving function gets a copy of the struct. Two things worth\nnoticing about that are 1) an extra memory allocation happens when calling the\nfunction and 2) altering the struct does not affect the original in the calling\ncontext.\n\nOn the other hand, we can have a function that takes a pointer to a struct.\nWhen we call that function, we have a reference to the memory location of the\nstruct instead of a copy of the struct. That means no additional allocation and\nmodifications to the dereferenced struct are modifications to the original in\nthe calling context.\n\nHere is an example that demonstrates both of these. Notice the printed output\nthat is included in comments at the end which shows memory locations and\ncontents of the struct at various points.\n\n```go\npackage main\n\nimport \"fmt\"\n\ntype Order struct {\n\tItem string\n\tQuantity int\n\tDineIn bool\n}\n\nfunc main() {\n\torder := Order{Item: \"taco\", Quantity: 3, DineIn: true}\n\n\tfmt.Println(\"Order:\", order)\n\tfmt.Printf(\"main - Loc: %p\\n\", &order)\n\n\tdoubledOrder := doubleOrder(order)\n\n\tfmt.Println(\"Double Order:\", doubledOrder)\n\tfmt.Println(\"Original Order:\", order)\n\n\tdoubleOrderPtr(&order)\n\n\tfmt.Println(\"Double Order Ptr:\", order)\n}\n\nfunc doubleOrder(order Order) Order {\n\tfmt.Printf(\"doubleOrder - Loc: %p\\n\", &order)\n\torder.Quantity *= 2\n\n\treturn order\n}\n\nfunc doubleOrderPtr(order *Order) {\n\tfmt.Printf(\"doubleOrderPtr - Loc: %p\\n\", order)\n\t(*order).Quantity *= 2\n}\n\n// Order: {taco 3 true}\n// main - Loc: 0xc0000b4000\n// doubleOrder - Loc: 0xc0000b4040\n// Double Order: {taco 6 true}\n// Original Order: {taco 3 true}\n// doubleOrderPtr - Loc: 0xc0000b4000\n// Double Order Ptr: {taco 6 true}\n```\n"
  },
  {
    "path": "go/produce-the-zero-value-of-a-generic-type.md",
    "content": "# Produce The Zero Value For A Generic Type\n\nWhile writing a _pop_ function that would work with slices of a generic type, I\nran into the issue of needing to produce a zero value of type `T` when\nreturning early for an empty slice.\n\nThe way to arbitrarily get the zero value of a generic in Go is with `*new(T)`.\n\nI was able to use this in my `Pop` function like so:\n\n```go\nfunc Pop[T any](slice []T) (T, error) {\n\tif len(slice) == 0 {\n\t\treturn *new(T), fmt.Errorf(\"cannot pop an empty slice\")\n\t}\n\n\tlastItem := slice[len(slice)-1]\n\n\tslice = slice[:len(slice)-1]\n\n\treturn lastItem, nil\n}\n```\n\nIf this is happening in multiple functions and we want a more self-documenting\napproach, we can pull it out into a function `zero`:\n\n```go\nfunc zero[T any]() T {\n\treturn *new(T)\n}\n```\n"
  },
  {
    "path": "go/redirect-file-to-stdin-during-delve-debug.md",
    "content": "# Redirect File To Stdin During Delve Debug\n\nI have a go program that accepts input from stdin. The way I've been running\nthe program as I develop it is to redirect the output of some sample files to\nthe program.\n\n```bash\n$ go run . < sample/001.txt\n```\n\nWhen I then go to debug this program with\n[Delve](https://github.com/go-delve/delve), I'd still like to be able to\nredirect a file into the program to reproduce the exact behavior I'm seeing.\n\nThe following won't work:\n\n```bash\n$ dlv debug . < samples/001.txt\nStdin is not a terminal, use '-r' to specify redirects for the target process or --allow-non-terminal-interactive=true if you really want to specify a redirect for Delve\n```\n\nFortunately, `dlv` sees what I'm trying to do and makes a recommendation. The\n`-r` flag can be used to specify redirects for the target process. The [`dlv`\nredirect\ndocs](https://github.com/go-delve/delve/blob/master/Documentation/usage/dlv_redirect.md)\nexplain that `-r` can be passed a `source:destination`. The `source` is `stdin`\nby default, but can also be `stdout` and `stderr`.\n\nI can redirect my file into the debugging session of my program like so:\n\n```bash\n$ dlv debug . -r stdin:samples/001.txt\n```\n\nOr even more succinctly:\n\n```bash\n$ dlv debug . -r samples/001.txt\n```\n"
  },
  {
    "path": "go/replace-the-current-process-with-an-external-command.md",
    "content": "# Replace The Current Process With An External Command\n\nGo's `syscall.Exec` function can be used to execute an external program.\nInstead of forking a child process though, it runs the external command in\nplace of the current process. You need to give the function three pieces of\ninformation: the location of the binary, the pieces of the command to be\nexecuted, and relevant environment. Here is a simple example.\n\n```go\npackage main\n\nimport \"fmt\"\nimport \"os\"\nimport \"syscall\"\n\nfunc main() {\n    // get the system's environment variables\n    environment := os.Environ()\n\n    // get a slice of the pieces of the command\n    command := []string{\"tmux\", \"new-session\", \"-s\", \"burrito\"}\n\n    err := syscall.Exec(\"/usr/local/bin/tmux\", command, environment)\n    if err != nil {\n        fmt.Printf(\"%v\", err)\n    }\n}\n```\n\nWhen this program is executed, it will replace itself with a new tmux\nsession named *burrito*.\n"
  },
  {
    "path": "go/sleep-for-a-duration.md",
    "content": "# Sleep For A Duration\n\nMany languages allow you to sleep for a certain number of milliseconds. In\nthose languages, you can give `500` or `1000` to the sleep function to\nsleep for half a second and a second respectively. In Go, the duration of a\ncall to [`time.Sleep`](https://golang.org/pkg/time/#Sleep) is in\nnanoseconds. Fortunately, there are constants that make it easy to sleep in\nterms of milliseconds.\n\nFor example, you can sleep for a half a second (500 milliseconds) like so:\n\n```go\npackage main\n\nimport (\n    \"time\"\n)\n\nfunc main() {\n    time.Sleep(500 * time.Millisecond)\n}\n```\n\nOther available time constants are `Nanosecond`, `Microsecond`, `Second`,\n`Minute`, `Hour`.\n"
  },
  {
    "path": "go/sort-slice-in-ascending-or-descending-order.md",
    "content": "# Sort Slice In Ascending Or Descending Order\n\nThe [`slices.Sort`](https://pkg.go.dev/slices#Sort) function defaults to\nsorting a slice in ascending order. If we want to control the sort order, we\nhave to do a little more work. We can reach for the\n[`slices.SortFunc`](https://pkg.go.dev/slices#SortFunc) function. This allows\nus to define a sort function and in that function we can control whether the\nsort order is ascending or descending.\n\nHere I've defined `SortItems` which takes a list of items constrained by the\n[`cmp.Ordered`](https://pkg.go.dev/cmp#Ordered) interface (so things like\n`int`, `string`, `uint64`, etc.). It takes a direction (`ASC` or `DESC`) as a\nsecond argument. It does the directional sort based on that second argument.\n\n```go\nimport (\n\t\"cmp\"\n\t\"fmt\"\n\t\"slices\"\n)\n\ntype Direction int\n\nconst (\n\tASC Direction = iota\n\tDESC\n)\n\nfunc SortItems[T cmp.Ordered](items []T, dir Direction) {\n\tslices.SortFunc(items, func(i, j T) int {\n\t\tif dir == ASC {\n\t\t\treturn cmp.Compare(i, j)\n\t\t} else if dir == DESC {\n\t\t\treturn cmp.Compare(j, i)\n\t\t} else {\n\t\t\tpanic(fmt.Sprintf(\"Unrecognized sort direction: %d\", dir))\n\t\t}\n\t})\n}\n\n// items := []int{3,2,8,1}\n// SortItems(items, ASC)\n// // items => [1,2,3,8]\n// SortItems(items, DESC)\n// // items => [8,3,2,1]\n```\n\nBecause `slices.SortFunc` expects a negative value, zero, or positive value to\ndetermine the sort order, we use\n[`cmp.Compare`](https://pkg.go.dev/cmp#Compare) which returns those kinds of\nvalues. For ascending, we compare `i` to `j`. For descending, we swap them,\ncomparing `j` to `i` to get the reverse sort order.\n"
  },
  {
    "path": "go/upgrading-from-an-older-version-on-mac.md",
    "content": "# Upgrading From An Older Version On Mac\n\nTo upgrade from an older version on Mac, there are a couple manual steps\nthat you need to take. For starters, download the latest installer for Mac\nfrom [Go Lang Downloads](https://golang.org/dl/).\n\nWhile this is downloading, you'll need to delete the older version of Go\nthat is installed on your machine.\n\nFirst, remove the existing Go installation directory:\n\n```bash\n$ sudo rm -rf /usr/local/go\n```\n\nSecond, clean up the Go `bin` directory from your `PATH` environment\nvariable:\n\n```bash\n$ sudo rm /etc/paths.d/go\n```\n\nNow, you can double click on the downloaded installer dmg and follow the\nprompt instructions.\n\nWhen its all said and done, check `go version` from the command line to see\nthat you are now working with the latest.\n"
  },
  {
    "path": "go/write-a-custom-scan-function-for-file-io.md",
    "content": "# Write A Custom Scan Function For File IO\n\nBy default a [`bufio.Scanner`](https://pkg.go.dev/bufio#Scanner) will scan\ninput line-by-line. In other words, splitting on newlines such that each\niteration will emit everything up to the next newline character.\n\nWe can write our own `SplitFunc` and override the default one by calling\n`scanner.Split` with it. Our custom scan function needs to match the type\nsignature of [`SplitFunc`](https://pkg.go.dev/bufio#SplitFunc).\n\nHere is a custom one that emits each individual character but omits the\nnewlines.\n\n```go\nfunc ScanChar(data []byte, atEOF bool) (int, []byte, error) {\n\tif atEOF || len(data) == 0 {\n\t\treturn 0, nil, nil\n\t}\n\n\tstart := 0\n\tfor start < len(data) {\n\t\tif !utf8.FullRune(data[start:]) {\n\t\t\treturn 0, nil, nil\n\t\t}\n\n\t\tr, size := utf8.DecodeRune(data[start:])\n\t\tif r == utf8.RuneError {\n\t\t\treturn 0, nil, fmt.Errorf(\"invalid UTF-8 encoding\")\n\t\t}\n\n\t\tif r != '\\n' {\n\t\t\treturn start + size, data[start:start+size], nil\n\t\t}\n\n\t\t// found a \\n, advance the start position\n\t\tstart += size\n\t}\n\n\treturn start, nil, nil\n}\n```\n\nWe can then use thi `ScanChar` function with a `bufio.Scanner` like so:\n\n```go\nfunc ReadFileByCharacter(file io.Reader) {\n\tscanner := bufio.NewScanner(file)\n\n\t// override default SplitFunc\n\tscanner.Split(scanChar)\n\n\tfor scanner.Scan() {\n\t\tchar := scanner.Text()\n\n\t\tfmt.Printf(\"- %s\\n\", char)\n\t}\n}\n```\n"
  },
  {
    "path": "groq/grab-multiple-values-from-a-reference.md",
    "content": "# Grab Multiple Values From A Reference\n\nLet's say we have an `author` with some attributes including a reference to a\n`person` which contains more data about the person. Here is one way to write a\nquery to access that data.\n\n```groq\n*[_type == 'author' && slug.current == 'donna-tartt']{\n  website,\n  'firstName': person->firstName,\n  'lastName': person->lastName,\n  'age': person->age\n}\n```\n\nHere is another way to write this query that doesn't do three separate accesses\non the `person` reference.\n\n```groq\n*[_type == 'author' && slug.current == 'donna-tartt']{\n  website,\n  person-> {\n    'firstName': firstName,\n    'lastName': lastName,\n    'age': age\n  }\n}\n```\n\nThis isn't quite right though because it leaves the three reference values\nnested under `person`. We can get back to the original shape of our query by\nflattening the `person` object using familiar looking spread syntax (`...`).\n\n```groq\n*[_type == 'author' && slug.current == 'donna-tartt']{\n  website,\n  ...person-> {\n    'firstName': firstName,\n    'lastName': lastName,\n    'age': age\n  }\n}\n```\n"
  },
  {
    "path": "groq/grab-values-from-an-array-of-references.md",
    "content": "# Grab Values From An Array Of References\n\nLet's say we have a `post` object in our schema. A `post` can have an array of\nreferences to `tags` telling you what topics the post covers. Each `tag` has a\nslug and we want to get the `string` value for each slug.\n\nLet's say we are interested in the post with `_id` of `123`.\n\nHere is how we can achieve that with a `groq` query:\n\n```groq\n*[\n  _type == 'post' && _id == 123\n]{\n  'tags': tags[]->slug.current\n}.tags\n\n=> [\"javascript\", \"react-js\"]\n```\n\nIf the schema was such that each `post` just had a single tag reference, then\nyou could write the chain of references as `tag->slug.current`. Because it is\nan array of references, we need the `[]` to declare that we want each value.\n\nThe `->` operator follows the reference. Otherwise we'd just have access to the\n`_ref` and `_type` values.\n\nThe final `.tags` unnests the `tags` value we gathered into an object. Then the\nresult is just the array of slug values.\n"
  },
  {
    "path": "groq/include-attributes-when-conditional-check-passes.md",
    "content": "# Include Attributes When Conditional Check Passes\n\nThe graph-like nature of Sanity means that you'll often be querying for data\nthat spans a variety of document types. For instance, your front-end could be\nrequesting content in the shape of a blog post, video, and podcast. Though\nthere are some similarities, each of these document types will have some unique\nattributes.\n\nWhen using GROQ to query for data that spans different types of documents, you\ncan use [a conditional query\nsyntax](https://www.sanity.io/docs/query-cheat-sheet#64a36d80be73) to include\ntype-specific attributes.\n\n```groq\n*[_type == 'blog' || _type == 'video' || _type == 'podcast'][]{\n  title,\n  'slug': slug.current,\n  _type == 'blog' => {\n    body,\n    read_time\n  },\n  _type == 'video' => {\n    description,\n    mp4_url\n  },\n  _type == 'podcast' => {\n    description,\n    mp3_url\n  }\n}\n```\n\nNotice that there are some attributes that are common across each type (i.e.\n`title` and `slug`). Each type then has attributes unique to its document type\n(i.e. `blog` has `body` and `read_time`).\n\nThis conditional query syntax allows us to both define flexible schemas in\nSanity and then query against that flexible schema.\n\n[source](https://www.youtube.com/watch?v=dCGPNkcTseQ)\n"
  },
  {
    "path": "groq/include-type-of-operation-in-webhook-response.md",
    "content": "# Include Type Of Operation In Webhook Response\n\nWhen setting up a webhook in Sanity Studio, you can specify what types of\noperations you want to trigger the webhook: `create`, `update`, and `delete`.\n\nIf you include all three for a webhook, then you'll probably want to know in\nyour webhook handler which type of operation you're receiving.\n\nWebhooks are run in _Delta Mode_ which means that a collection of GROQ\nfunctions are available in the _filter_ and _projection_ blocks. These\nfunctions include\n[`delta::operation`](https://www.sanity.io/docs/groq-functions#a64594a50318).\n\nHere is what a projection using `delta::operation` might look like:\n\n```groq\n{\n  _id,\n  firstName,\n  lastName,\n  email,\n  'operation': delta::operation()\n}\n```\n\nThis function can resolve to either `create`, `update`, or `delete`.\n"
  },
  {
    "path": "heroku/check-ruby-version-for-production-app.md",
    "content": "# Check Ruby Version For Production App\n\nWhile deploying a fresh Rails app to Heroku recently, I ran into an issue. The\n`it` block argument wasn't working despite being on Ruby 4.0. Or so I thought.\n\nRunning the following command reported the Ruby version of that Heroku server\ninstance:\n\n```bash\n❯ heroku run -- ruby --version\nRunning ruby --version on ⬢ my-app... up, run.3090\nruby 3.3.9 (2025-07-24 revision f5c772fc7c) [x86_64-linux]\n```\n\nI was on `3.3.9` which must have been the fallback default at the time.\n\nThough I had set the Ruby version in my `.ruby-version` file, I had neglected to\nspecify it in the `Gemfile` as well. Once I added it to the `Gemfile` and\nredeployed, my Heroku server instance was running the expected version of Ruby.\n\n```bash\n❯ heroku run -- ruby --version\nRunning ruby --version on ⬢ my-app... up, run.5353\nruby 4.0.0 (2025-12-25 revision 553f1675f3) +PRISM [x86_64-linux]\n```\n\nNote: because [I have set `HEROKU_ORGANIZATION` and\n`HEROKU_APP`](set-default-team-and-app-for-project.md) in my environment\n(`.envrc`) for the local copy of the app, I don't need to specify those when\nrunning the `heroku run` command above.\n\nSee `heroku run --help` for more details.\n"
  },
  {
    "path": "heroku/connect-to-a-database-by-color.md",
    "content": "# Connect To A Database By Color\n\nAll of your PostgreSQL databases in Heroku are given attachment names that use\na random color. This might be _pink_, _brown_, _cobalt_, etc. And the\nattachment names then look like `HEROKU_POSTGRESQL_PINK`,\n`HEROKU_POSTGRESQL_BROWN`, `HEROKU_POSTGRESQL_COBALT`, etc.\n\nWe can connect to a Heroku-managed PostgreSQL instance from the command-line\nlike so:\n\n```bash\n$ heroku pg:psql --app my-app\n```\n\nThis is going to connect to the _default_ database which is the one with the\n`DATABASE_URL` attachment.\n\nThere are lots of instances where we may have other databases besides the\nprimary (e.g. let's say we have a read replica follower). If we want to connect\nto that one, we can do so by _color_.\n\nIf that database's attachment is `HEROKU_POSTGRESQL_IVORY`, then we'd connect\nto it like so:\n\n```bash\n$ heroku pg:psql ivory --app my-app\n```\n\n[source](https://devcenter.heroku.com/articles/managing-heroku-postgres-using-cli#pg-psql)\n"
  },
  {
    "path": "heroku/deploy-a-review-app-to-a-different-stack.md",
    "content": "# Deploy A Review App To A Different Stack\n\nHeroku has different stacks for deploying apps. As newer versions of Linux\ndistros (such as Ubuntu) come out and software packages need patching and\nupdating, Heroku releases new stacks. And deprecates older ones.\n\nBefore upgrading a production app to a new stack, you should test it out first.\nThe recommended way to test this out is with a Review App.\n\nIf you need to bump the Ruby version or make any other changes, do that first.\n\nThen add or update your `app.json` file. This is a Heroku-specific file that\ntells Heroku what stack to use when creating a new app or review app.\n\n```json\n{\n  \"stack\": \"heroku-18\"\n}\n```\n\nLet's say my app is currently on the Heroku-16 stack. I can set the `stack` to\nbe `heroku-18` in `app.json`. Then I can push up a branch with all these\nchanges and turn it into a PR. From the Heroku dashboard, I can click the\nHeroku Button that builds a Review App from the PR.\n\nOnce it it finishes building and deploying, Heroku will give me a custom URL\nfor visiting the app so that I can manually evaluate it.\n\n[source](https://devcenter.heroku.com/articles/upgrading-to-the-latest-stack#testing-an-app-on-a-new-stack)\n"
  },
  {
    "path": "heroku/diagnose-problems-in-a-heroku-postgres-database.md",
    "content": "# Diagnose Problems In A Heroku Postgres Database\n\nHeroku keeps track of all kinds of diagnostics on the performance of your app's\ndatabase. From long running queries and transactions to index cache hit rates\nto unused indexes to tables with bloat.\n\nRunning the `pg:diagnose` command for your Heroku app will surface all of these\ndetails in the terminal.\n\n```bash\n$ heroku pg:diagnose -a APP_NAME\n```\n\nThe report will start with the biggest problem areas which it color codes in\nred. If your app is experiencing degraded performance, the list of red items\nwould be a good place to start investigating.\n\nThe report will then list less urgent problem areas. Those will be color coded\nyellow. Though Heroku has deemed these less serious, you may still want to deal\nwith these.\n\nAll the other areas of diagnose will fall into the _green_ bucket. Meaning\nHeroku doesn't see any issues in those areas.\n"
  },
  {
    "path": "heroku/open-dashboard-for-specific-add-on.md",
    "content": "# Open Dashboard For Specific Add-On\n\nThe number of times I've needed to check the papertrail logs for my\nHeroku-hosted Rails app is a lot. I open a browser tab, go through several\nlayers of navigation to get to my app's dashboard, and then click the\npapertrail link under _Add-ons_.\n\nThere is a much quicker way using the Heroku CLI.\n\n```bash\n$ heroku addons:open papertrail -a my-app-name\nOpening https://addons-sso.heroku.com/apps/abc123/addons/efg456...\n```\n\nIt sends you to an add-ons SSO link in the browser which authenticates you and\ndrops you into the dashboard for that specific add-on. You just need to specify\nthe add-on name and the app name.\n"
  },
  {
    "path": "heroku/run-sql-against-remote-postgres-database.md",
    "content": "# Run SQL Against Remote Postgres Database\n\nYou can access a remote Heroku PostgreSQL database through a `psql` session\nusing the following command:\n\n```bash\nheroku pg:psql --app my-app\n```\n\nThat opens an interactive psql session.\n\nIf instead you'd like to run a single SQL script against that remote database,\nyou can redirect that script to the connection.\n\n```bash\nheroku pg:psql --app my-app < query.sql\n```\n\nThe results of running that SQL will be written to stdout.\n\nYou can take this a step further by redirecting the output into another file so\nthat you can review and search the results at your convenience, rather than\nonly having them appear in your terminal.\n\n```bash\nheroku pg:psql --app my-app < query.sql > results.out\n```\n"
  },
  {
    "path": "heroku/set-and-show-heroku-env-variables.md",
    "content": "# Set And Show Heroku Env Variables\n\nThe `heroku` CLI includes the `config` command which will show all the env\nvariables for the current app.\n\n```bash\n$ heroku config\n=== my-app Config Vars\n\n```\n\nAt this point I have none set.\n\nI can set one with the `config:set` command and a key-value parameter.\n\n```bash\n$ heroku config:set PUBLIC_NEXT_URL=http://localhost:1235\nSetting PUBLIC_NEXT_URL and restarting ⬢ my-app... done, v3\nPUBLIC_NEXT_URL: http://localhost:1235\n```\n\nI can see the value that this specific variable is set to by calling it with\n`config:get`.\n\n```bash\n$ heroku config:get PUBLIC_NEXT_URL\nhttp://localhost:1235\n```\n\n[source](https://devcenter.heroku.com/articles/config-vars#using-the-heroku-cli)\n"
  },
  {
    "path": "heroku/specify-default-team-and-app-for-project.md",
    "content": "# Specify Default Team And App For Project\n\nTypically when you run commands with the Heroku CLI you'll need to specify the\nname of the app on Heroku you're targeting with the `--app` flag. However, to\nfirst see the names of the apps you may want to run `heroku apps` (or `heroku\nlist`). That will list the apps for your default team.\n\nIf you need to see apps for a different team (i.e. organization), you'll need to\nspecify that team either with the `--team` flag or by setting that as an\nenvironment variable.\n\nHere I do the latter in an `.envrc` file:\n\n```\n# Heroku\nexport HEROKU_ORGANIZATION=visualmode\n```\n\nOnce that is set and the environment reloaded, running `heroku apps` will show\nthe apps specific to that team on Heroku.\n\nSimilarly, if you want to set a default app for your project so that you don't\nhave to always specify the `--app` flag, you can update your `.envrc`\naccordingly.\n\n```\n# Heroku\nexport HEROKU_ORGANIZATION=visualmode\nexport HEROKU_APP=my-app\n```\n\nI had a hard time finding official documentation for this which is why I'm\nwriting this up here. I've manually verified this works with my own team and\napp.\n"
  },
  {
    "path": "heroku/ssh-into-heroku-server-hosting-app.md",
    "content": "# SSH Into Heroku Server Hosting App\n\nHeroku hosts and deploys your app on a remote server. One of Heroku's primary\nofferings is that it abstracts away the details of that server. You generally\ndon't need to think about it. Instead you can use the Heroku CLI to interact\nwith it indirectly.\n\nThere will inevitably be a time when you need to access that server directly.\nHeroku gives you a way to do this with their CLI through\n[`ps:exec`](https://devcenter.heroku.com/articles/exec).\n\n```bash\n$ heroku ps:exec --app my-app\n```\n\nThis will connect you to an SSH session with the server that the app is running\non.\n"
  },
  {
    "path": "html/adding-alt-text-to-an-image.md",
    "content": "# Adding Alt Text To An Image\n\nImages on their own are not accessible to anyone using a screen reader. As the\npeople putting content on the web, we can make images more accessible by\nproviding _alternative_ text. This is such a standard that linters not only\nflag `<img />` tags that are missing the `alt` attribute, they also admonish\nyou for unhelpful description text like \"image.\"\n\nYou can appease the linter and make your content accessible with some\ndescriptive text:\n\n```html\n<img src=\"some/image.jpg\" alt=\"a graph with lines trending up\" />\n```\n\nWhen appropriate, you can also choose to include the `alt` attribute with a\nblank value.\n\n> If an image is purely decorative, then we add alt=\"\" to let screen readers\n> know that it’s not important. But if an image is informative, then we need to\n> be supplying a text alternative that describes the picture for anyone who’s\n> using a screen reader or isn’t able to see the image.\n\nPart of accessibility is not putting a bunch of noise in front of your users.\nIf the image isn't part of the content, use `alt=\"\"`.\n\n[source](https://24ways.org/2019/twelve-days-of-front-end-testing/)\n"
  },
  {
    "path": "html/allow-number-input-to-accept-decimal-values.md",
    "content": "# Allow Number Input To Accept Decimal Values\n\nHere is a number input element:\n\n```html\n<input type=\"number\" id=\"amount\" required class=\"border\" />\n```\n\nThis renders an empty number input box with up and down arrows which will, by\ndefault, increment or decrement the value by **1**.\n\nOf course, I can manually edit the input typing in a value like `1.25`.\n\nHowever, when I submit that via an HTML form, the submission will be prevented\nand the browser will display a validation error.\n\n> Please enter a valid value. The two nearest valid values are 1 and 2.\n\nIf I want to be able to input a decimal value like this, I need to change the\n`step` value. It defaults to `1`, but I could change it to `2`, `10`, or in\nthis case to `0.01`.\n\n```html\n<input type=\"number\" step=\"0.01\" id=\"amount\" required class=\"border\" />\n```\n\nNotice now that as you click the up and down arrows, the value is incremented\nand decremented by **0.01** at a time.\n\nIf I want to maintain the step value of `1` while allowing decimal values, I\ncan instead set the `step` value to be `any`.\n\n```html\n<input type=\"number\" step=\"any\" id=\"amount\" required class=\"border\" />\n```\n\nSee the [MDN docs on number\ninputs](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input/number)\nfor more details.\n"
  },
  {
    "path": "html/determine-which-button-submitted-the-form.md",
    "content": "# Determine Which Button Submitted The Form\n\nIt is pretty common for a form to have a singular submit button. If the user\nclicks 'Submit', then the form fires a `POST` off to the server, the server can\nprocess the request, and that's it.\n\nBut what about a form that has two or more buttons? For instance, imagine some\nkind of consent form where the user needs to either _Accept_ or _Reject_ some\nterms.\n\nJust like other inputs, [the `<button>` tag can take both `name` and `value`\nattributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-name).\n\n```html\n<form action=\"/terms\" method=\"post\">\n  <p>Something about the terms ...</p>\n  <div>\n    <label for=\"name\">Email: </label>\n    <input type=\"email\" name=\"email\" id=\"email\" required>\n  </div>\n  <div>\n    <button type=\"submit\" name=\"commit\" value=\"accept\">Accept</button>\n    <button type=\"submit\" name=\"commit\" value=\"reject\">Reject</button>\n  </div>\n</form>\n```\n\nIn addition to the `email` attribute, when the user submits the form, it will\ninclude a `commit` attribute that has a value of either `'accept'` or\n`'reject'`.\n\nNaming it `commit` is [a convention I'm borrowing from Rails's form\nhelpers](https://guides.rubyonrails.org/v5.0/form_helpers.html#a-generic-search-form).\nYou can name it whatever makes sense to you.\n"
  },
  {
    "path": "html/disable-auto-completion-for-a-form-input.md",
    "content": "# Disable Auto-Completion For A Form Input\n\nThe browser wants to be helpful by making informed suggestions about what\nshould be auto-filled into form inputs.\n\nWe may not want this behavior. It could be a source of data entry mistakes, an\nannoyance, or just not something we want our users to experience.\n\nWe can turn this off at an individual field level with the `autocomplete`\nattribute:\n\n```html\n<input type=\"email\" id=\"email\" name=\"email\" autocomplete=\"off\">\n```\n\nNote: It is `off` and not something like `false`.\n\n[source](https://developer.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion)\n"
  },
  {
    "path": "html/disclose-additional-details.md",
    "content": "# Disclose Additional Details\n\nYou can add extra details to an HTML page that are only disclosed if the user\nchooses to disclose them. To do that, we use the `<details>` tag. This tag\nneeds to have a `<summary>` tag nested within it. Anything else nested within\n`<details>` will be what is disclosed when it is toggled open. The `<summary>`\nis what is displayed when it is not open.\n\nHere is a `<detail>` block I recently added to [Ruby Operator\nLookup](https://www.visualmode.dev/ruby-operators).\n\n```html\n<details className=\"pt-2 pb-6\">\n  <summary>What is this thing?</summary>\n  <p className=\"pl-3 pt-2 text-gray-700 text-sm\">\n    Ruby is an expressive, versatile, and flexible dynamic programming language. That means there are all kinds of syntax features, operators, and symbols we can encounter that might look unfamiliar and are hard to look up. Ruby Operator Lookup is a directory of all these language features.\n  </p>\n  <p className=\"pl-3 pt-2 text-gray-700 text-sm\">\n    Use the search bar to narrow down the results. Then click on a button for the operator or symbol you want to explore further.\n  </p>\n</details>\n```\n\nOn page load, the only thing we see is \"What is this thing?\" with a triangle\nsymbol next to it. If we click the summary, then the entire details block\n(those two `<p>` tags) are disclosed.\n\n[source](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details)\n"
  },
  {
    "path": "html/make-elements-non-interactive-with-inert.md",
    "content": "# Make Elements Non-Interactive With Inert\n\nThe [`inert`\nattribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inert)\nglobal attribute is a boolean that can be applied to an element or section of\ncontent in an HTML document. When it is `true`, that elements and anything\nnested within it will not be interactive.\n\n```html\n<div class=\"fancy-animation\" inert>\n  <!-- ... -->\n</div>\n```\n\nThis has a couple different implications:\n\n1. Click events are not fired on these elements.\n\n2. These elements will not be able to gain focus.\n\n3. These elements and content are hidden from assistive technology.\n\nThis is useful for a variety of things. In particular, it is good for\naccessibility when a portion of the document, like a fancy animation, isn't\nmeant to be traversed by assistive technology.\n"
  },
  {
    "path": "html/prevent-search-engines-from-indexing-a-page.md",
    "content": "# Prevent Search Engines From Indexing A Page\n\nThe `robots.txt` file is commonly used to tell (well-behaved) crawlers, such as\nsearch engines, to not visit a page. If another page links to your page, it\nwill still be indexed. To instruct search engines to not index a given page,\nrobot meta tags need to be used.\n\n> If you want to reliably block a page from showing up in the search results,\n> you need to use a meta robots `noindex` tag. That means that, in order to\n> find the `noindex` tag, the search engine has to be able to access that page,\n> so don’t block it with `robots.txt`.\n> [source](https://yoast.com/ultimate-guide-robots-txt/)\n\nTo prevent indexing, add the following meta tag to the `<head>` section of any\nrelevant pages.\n\n```html\n<meta name=\"robots\" content=\"noindex\">\n```\n\n[source](https://developers.google.com/search/docs/advanced/crawling/block-indexing)\n"
  },
  {
    "path": "html/render-text-as-superscript.md",
    "content": "# Render Text As Superscript\n\nThere is an [HTML\ntag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/sup) that\ntells browser engines to render text as superscript -- like when you need an\nexponent.\n\n```\n<p>Render this text as <sup>superscript</sup>!</p>\n```\n\nHere is what the above would look like:\n\n<p>Render this text as <sup>superscript</sup>!</p>\n\nCheck out this [codepen example](https://codepen.io/jbranchaud/pen/GzoyXe)\nto play around with it.\n"
  },
  {
    "path": "html/submit-a-form-with-a-button-outside-the-form.md",
    "content": "# Submit A Form With A Button Outside The Form\n\nYou can tie a submit button to a form that the button doesn't live inside\nof. The trick is to give the form an `id` and then reference that `id` with\nthe button's `form` property.\n\n```html\n<div>\n  <form id=\"my-form\">\n    <label for=\"name\">Name:</label>\n    <input type=\"text\" name=\"name\"></input>\n  </form>\n\n  <!-- ... -->\n\n  <button type=\"submit\" form=\"my-form\">Submit</button>\n</div>\n```\n\nWith this setup, clicking the _Submit_ button will cause the form to be\nsubmitted.\n\nSee the [MDN Button\ndocs](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button) for\nmore details.\n"
  },
  {
    "path": "http/what-counts-as-cross-origin-with-cors.md",
    "content": "# What Counts As Cross-Origin With CORS?\n\nWhen it comes to HTTP, an\n[origin](https://developer.mozilla.org/en-US/docs/Glossary/origin) is defined\nby several different aspects of the URL. This is important for understanding\nwhat qualifies as _same_ and _cross_-origin when dealing with\n[CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) (Cross-Origin\nResource Sharing).\n\nFor something to be _same-origin_, it must have the same scheme (HTTP/HTTPS),\nthe same host, and the same port. If any one of the scheme, host (including\nsubdomains), or port is different, then it is not _same-origin_.\n\nHere are some examples of different origins:\n\n- `https://example.com` vs `http://example.com` (different scheme)\n- `https://example.com` vs `https://sub.example.com` (different host)\n- `https://example.com:3000` vs `https://example.com:5000` (different port)\n\nAs long as the scheme, host, and port match, they are the same origin. The path\n(everything following the origin) doesn't factor into the question of same\norigin.\n"
  },
  {
    "path": "inngest/ensure-lookup-can-be-retried.md",
    "content": "# Ensure Lookup Can Be Retried\n\nA common thing to do in a workflow step is to look up a record. This might be a\nrecord that was created or updated around the time that the workflow was\ntriggered.\n\nYou need to be sure the record was found before proceeding. That might end up\nlooking like this:\n\n```typescript\nexport default inngest.createFunction(\n  { id: \"record-user-purchase\" },\n  { event: \"app/record.purchase\" },\n  async ({ event, step }) => {\n    const checkoutSession =\n      await step.run(\"find checkout session\", async () => {\n        const cs = provider.lookupSession(event.checkoutSessionId)\n\n        return cs;\n      });\n\n    if(!checkoutSession) {\n      throw new Error('Checkout session not found')\n    }\n  }\n);\n```\n\nThis approach has a subtle problem which is that the error for a missing\ncheckout session is raised _outside_ the step that sets `checkoutSession`. As\ninngest does a series of retries, the memorized `checkoutSession` step won't be\nrerun and the error will continue to be thrown.\n\nIt is better to raise the error _within_ the lookup step:\n\n```typescript\nexport default inngest.createFunction(\n  { id: \"record-user-purchase\" },\n  { event: \"app/record.purchase\" },\n  async ({ event, step }) => {\n    const checkoutSession =\n      await step.run(\"find checkout session\", async () => {\n        const cs = provider.lookupSession(event.checkoutSessionId)\n\n        if(!cs) {\n          throw new Error('Checkout session not found')\n        }\n\n        return cs;\n      });\n  }\n);\n```\n\nIf the checkout session is missing on the first couple tries, the step will\nhave a chance to retry the lookup and maybe eventually find what it is looking\nfor.\n"
  },
  {
    "path": "inngest/exit-function-early-without-retries.md",
    "content": "# Exit Function Early Without Retries\n\nWhen an Inngest function fails due to an error, it will be retried up to 3\ntimes with a scheduled back-off. That functionality is built-in. In some cases,\nthere is no sense retrying because the failure case isn't going to change. No\nsense in wasting resources on retries that are going to yield the same result.\n\nIn this case, we can have our code raise a `NonRetriableError`.\n\n```javascript\nimport { NonRetriableError } from \"inngest\"\nimport {inngest} from '@/inngest/inngest.server'\nimport {database} from '@/server/database'\n\nexport default inngest.createFunction(\n  { id: \"reindex-post-for-search\" },\n  { event: \"post.updated\" },\n  async ({ event }) => {\n    const post = await database.findPost({ id: event.data.postId })\n\n    if(!post) {\n      throw new NonRetriableError(`Post not found for id (${event.data.postId})`)\n    }\n\n    // handle reindexing of the post\n  }\n)\n```\n\nWhen inngest catches a `NonRetriableError` it knows to not schedule retries.\n\nIn the context of a try/catch block where some other error has been raised, we\ncan pass that error as a second argument to the `NonRetriableError` for\nadditional info:\n\n```javascript\ncatch(err) {\n  const message = `Post not found for id (${event.data.postId})`\n\n  throw new NonRetriableError(message, { cause: err })\n}\n```\n\n[source](https://www.inngest.com/docs/functions/retries)\n"
  },
  {
    "path": "internet/add-emoji-to-github-repository-description.md",
    "content": "# Add Emoji To GitHub Repository Description\n\nGitHub restricts the set of unicode characters that can appear in the\ndescription field of a repository to anything up to `0xffff`. Most emoji\nhave unicode values above this. This means you will have limited success\nadding emoji via your system's emoji keyboard.\n\nFortunately, GitHub allows you to add any recognized emoji to a repository\ndescription with its specialized emoji syntax (e.g. `:memo:`). You may have\nused this syntax in other parts of GitHub such as the issue tracker.\n\nIf you add an emoji like this:\n\n![](http://i.imgur.com/Tty7Cl2.png)\n\nit will show up like so:\n\n![](http://i.imgur.com/yxRwmkW.png)\n\nCheck out this [Emoji Cheat Sheet](http://www.emoji-cheat-sheet.com/) for\nthe names of all recognized emojis.\n"
  },
  {
    "path": "internet/add-styled-alerts-to-github-markdown-documents.md",
    "content": "# Add Styled Alerts To GitHub Markdown Documents\n\nThe GFM (GitHub Flavored Markdown) variant of markdown adds some nice features\nto our GitHub-rendered markdown documents.\n\nOne such feature that has been around for a couple years, but which I only just\nlearned about, are these styled alerts. There are five of them each with a\ndifferent color and icon to help convey meaning.\n\n```\n> [!NOTE]\n> Useful information that users should know, even when skimming content.\n\n> [!TIP]\n> Helpful advice for doing things better or more easily.\n\n> [!IMPORTANT]\n> Key information users need to know to achieve their goal.\n\n> [!WARNING]\n> Urgent info that needs immediate user attention to avoid problems.\n\n> [!CAUTION]\n> Advises about risks or negative outcomes of certain actions.\n```\n\nI just added the following to the top of one of my project's READMEs to help me\nremember that it is not under active development.\n\n```\n> [!WARNING]\n> This repo is not under active development, you might be looking for\n> [til-visualmode-dev](https://github.com/jbranchaud/til-visualmode-dev).\n```\n\nVisit the GitHub docs for\n[Alerts](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts)\nto see examples of how these render.\n\n[source](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts)\n"
  },
  {
    "path": "internet/analyze-your-website-performance.md",
    "content": "# Analyze Your Website Performance\n\nThe [PageSpeed Insights](https://pagespeed.web.dev/) tool from Google is a\ngreat way to quickly get actionable insights about where to improve your\nwebsite and app's _Performance_, _Accessibility_, and _SEO_.\n\nTo see how your public site or app does, grab its URL and analyze it at\n[PageSpeed Insights](https://pagespeed.web.dev/).\n\nIt will take a minute to run on either Mobile or Desktop (make sure to check\nboth) and then will output four headline numbers (out of 100) for each of the\ncategories.\n\nYou can then dig in to each category to see what recommendations they make for\nimproving your score.\n\nThis can also be run directly from Chrome devtools which is useful if you want\nto see how a locally running site is doing. You can run the analysis from the\n_Lighthouse_ tab of devtools. Note: if the _Performance_ score looks bad, it\nmight be that you are running a non-optimized dev server that isn't reflective\nof how your site would do in production.\n"
  },
  {
    "path": "internet/check-your-public-ip-address.md",
    "content": "# Check Your Public IP Address\n\nIf you visit [https://checkip.amazonaws.com/](https://checkip.amazonaws.com/),\na plain text page will render that displays your current public IP address.\n\nAlternatively, you can `cURL` this endpoint from the command line:\n\n```bash\n$ curl https://checkip.amazonaws.com/\n```\n\nEither way, you'll get your IP address. Do with that what you will.\n"
  },
  {
    "path": "internet/digraph-unicode-characters-have-a-titlecase.md",
    "content": "# Digraph Unicode Characters Have a Titlecase\n\nComing from primarily being exposed to the US American alphabet, I'm familiar\nwith characters that I type into the computer having one of two cases. Either\nit is lowercase by default (`c`) or I can hit the shift key to produce the\nuppercase version (`C`).\n\nUnicode, which has broad support for character encoding across most languages,\nhas a couple characters that are called _digraphs_. These are single code\npoints, but look like they are made up of two characters.\n\nA good example of this is `ǆ`. And if that character were to appear in an all\nuppercase word, then it would display as `Ǆ`.\n\nBut what if it appears at the beginning of a capitalized word?\n\nThat's where _titlecase_ comes into the picture -- `ǅ`.\n\nFrom [wikipedia](https://en.wikipedia.org/wiki/D%C5%BE):\n\n> Note that when the letter is the initial of a capitalised word (like Džungla\n> or Džemper, or personal names like Džemal or Džamonja), the ž is not\n> uppercase. Only when the whole word is written in uppercase, is the Ž\n> capitalised.\n\n(I find it odd that wikipedia's article on this digraph code point is using\nseparate characters instead of the digraph.)\n\n[source](https://devblogs.microsoft.com/oldnewthing/20241031-00/?p=110443)\n"
  },
  {
    "path": "internet/download-a-google-doc-as-specific-format.md",
    "content": "# Download A Google Doc As Specific Format\n\nI was recently given a public Google Doc URL and I was curious if I could\ndownload it from the command line. I didn't want to have to install special CLI\nthough. I was hoping to use something like `curl`.\n\nA brief chat with Claude and I learned that not only can I use `curl`, but I\ncan specify the format in the _export_ URL.\n\n```bash\n$ export GOOGLE_DOC_URL=\"https://docs.google.com/document/d/157rMgHeBf76T9TZnUjtrUyyS2XPwG0tObr-OjYNfMaI\"\n\n$ echo $GOOGLE_DOC_URL\nhttps://docs.google.com/document/d/157rMgHeBf76T9TZnUjtrUyyS2XPwG0tObr-OjYNfMaI\n\n$ curl -L \"$GOOGLE_DOC_URL/export?format=pdf\" -o doc.pdf\n  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current\n                                 Dload  Upload   Total   Spent    Left  Speed\n100   414    0   414    0     0   2763      0 --:--:-- --:--:-- --:--:--  2895\n100 16588    0 16588    0     0  56214      0 --:--:-- --:--:-- --:--:--  167k\n\n$ ls doc.pdf\ndoc.pdf\n```\n\nI append `/export` and then include the `?format=pdf` query param to specify\nthat I want the document to be exported in PDF format. With the `-o` flag I can\nspecify the name and extension of the output file.\n\nThis is a handy on its own, but noticing that Google Docs supports other export\nformats, I thought it would be useful to go back-and-forth with Claude to\nsketch out a script that can do this and prompt me (with `fzf`) for the file\ntype -- [here is the gist for\n`gdoc-download`](https://gist.github.com/jbranchaud/cf3d2028107a1bd8484eed7cca0fcdab).\n"
  },
  {
    "path": "internet/enable-keyboard-shortcuts-in-gmail.md",
    "content": "# Enable Keyboard Shortcuts In Gmail\n\nIn these modern times of asynchronous communication and paperless receipts,\na person's email inbox can get mighty full. Keeping that influx of emails at\nbay is a challenge. If you'd like to start unburying yourself and get on the\npath to inbox zero -- Gmail's keyboard shortcuts can help.\n\nKeyboard shortcuts are not enabled by default, so you'll need to turn them\non in settings. Click the _gear_ icon, select _Settings_ and then scroll\ndown under the _General_ tab until you find the _Keyboard shortcuts_\nsection. Select the _Keyboard shortcuts on_ radio button and then _Save\nchanges_.\n\nYou'll now have access to a variety of shortcuts, such as using the `j` and\n`k` keys to move up and down the list of emails in your inbox. [Find the one\nyou want and hit `o` to open it\nup](https://til.hashrocket.com/posts/41grpsmqzu-gmail-o-).\n\nKeep exploring -- there is a whole world of keyboard shortcuts out there.\n\nh/t Jake Worth\n"
  },
  {
    "path": "internet/exclude-ai-overview-from-google-search.md",
    "content": "# Exclude AI Overview From Google Search\n\nAt the top of most Google searches these days is a section of text that takes a\nmoment to appear, presumably because it is being generated in the moment. This\nis Google's _AI Overview_. These are sometimes useful summaries of the article\nyou are about to click on anyway. Other times the overview is no good, it takes\nup a bunch of screen real estate, and may even [10x the energy consumed by a\nregular\nsearch](https://www.reddit.com/r/technology/comments/1dsvefb/googles_ai_search_summaries_use_10x_more_energy/).\n\nIf you want to exclude the _AI Overview_, tack on a `-ai` when writing out your\nsearch query.\n\n[source](https://www.yahoo.com/tech/turn-off-ai-overview-results-170014202.html)\n"
  },
  {
    "path": "internet/exclude-whitespace-changes-from-github-diffs.md",
    "content": "# Exclude Whitespace Changes From GitHub Diffs\n\nIf you run a tidy ship and use plugins like\n[vim-spacejam](https://github.com/rondale-sc/vim-spacejam), then whitespace\nchanges cluttering up your git diffs probably isn't much of an issue.\n\nHowever, if you are working with other people or messier code bases, then\nyou may not be so lucky. If there are a bunch of whitespace changes in a\ncommit, then that is going to make the diff view of a commit on GitHub\nannoying, and perhaps hard, to read.\n\nYou can cut to the chase by excluding whitespace changes from GitHub's diff\nview by adding `w=1` to the diff URL.\n\nCheck out [this view of the\ndiff](https://github.com/jbranchaud/dotfiles/commit/fad58dfda91e61972b3c28e7e967bb631140e71e)\nand then [this view of the diff that excludes\nwhitespace](https://github.com/jbranchaud/dotfiles/commit/fad58dfda91e61972b3c28e7e967bb631140e71e?w=1).\n\n[source](https://twitter.com/ablwr/status/789141645098938368)\n"
  },
  {
    "path": "internet/figure-out-your-public-ip-address.md",
    "content": "# Figure Out Your Public IP Address\n\nWant to know what your public IP address is?\n\nVisit [ifconfig.io](http://ifconfig.io/) to get a bunch of information about\nyour connection including your public IP address.\n"
  },
  {
    "path": "internet/focus-the-url-bar.md",
    "content": "# Focus The URL Bar\n\nThere are a lot of things you can do in the browser without having to reach\nfor the mouse. Bringing the URL bar into focus is one of those things.\n\nHit `Cmd+L` in any modern browser (I've tried Chrome, Firefox, and Safari)\nand the URL bar will be brought into focus. From there, you can quickly\nchange the URL of the current tab and your fingers never left the keyboard.\n\nh/t Jake Worth\n"
  },
  {
    "path": "internet/get-random-images-from-unsplash.md",
    "content": "# Get Random Images From Unsplash\n\n_The below doesn't work on GitHub. It seems that GitHub caches and serves\nits own version of the image. This will work anywhere where you aren't\ncaching images._\n\nHere is an image from [unsplash.com](https://unsplash.com).\n\n![random images](http://source.unsplash.com/random/1200x600)\n\nI don't know what image I am showing you though. That's because the URL\nbeing sourced for the above image is\n`http://source.unsplash.com/random/1200x600`. This tells unsplash to\nrandomly serve us a `1200x600` image. Try refreshing the page and you'll see\nthat it is different each time. Cool!\n\nThis is a bit of a novelty, but could be useful on occasion. The\n[Gatsby](https://www.gatsbyjs.org/) docs use it to great effect in a\ntutorial so as to not get caught up with the details of serving a specific\nimage.\n"
  },
  {
    "path": "internet/grab-the-rss-feed-for-a-substack-blog.md",
    "content": "# Grab The RSS Feed For A Substack Blog\n\nI've been attempting to put more energy into finding and reading blog posts via\nan RSS feed reader. This as opposed to scrolling and scrolling and hoping that\nthe algorithm turns up an interesting article or two.\n\nA lot of people who have been blogging for a while have a handy RSS feed link\nprominently displayed on their site. We love to see it!\n\nThere are a few people whose writing I really enjoy that distribute their words\nvia Substack. I couldn't find a prominent or not prominent RSS feed link\nanywhere on someone's Substack. What I did learn, after some searching, is that\nyou can tack `/feed` onto the end of someone's Substack URL and that will give\nyou the XML feed.\n\nFor example:\n\n```\nSubstack blog landing page URL:\nhttps://registerspill.thorstenball.com\n\nSubstack blog RSS feed URL:\nhttps://registerspill.thorstenball.com/feed\n```\n\nGrab that feed URL and paste it into your feed reader and you should start\nseeing their stuff show up.\n"
  },
  {
    "path": "internet/hide-overflowing-text-for-google-sheets-column.md",
    "content": "# Hide Overflowing Text For Google Sheets Column\n\nI imported a big CSV into a new Google Sheets document. This included a\n\"Description\" column with many of the descriptions varying between 50 and 80\ncharacters. The bottom line is that the description column was flowing over the\ntop of the columns next to it. Instead of expanding the width of that column as\nfar as the largest description, I wanted to hide the _overflow_.\n\nThe way to do this in Google Sheets is to highlight the entire column by\nclicking on the column grouping. Then under the _Format_ menu item is a\n_Wrapping_ submenu. The _Clip_ option is what I was looking for because it clips\nthe text that gets shown at the edge of the column.\n"
  },
  {
    "path": "internet/search-tweets-by-author.md",
    "content": "# Search Tweets By Author\n\nTwitter has some advanced search features that allow you to do more than\njust search by keyword. The `from:<author>` syntax is the way that you can\nrestrict your search results to a specific twitter user.\n\n![twitter from search](http://i.imgur.com/yWi9JB7.png)\n\nBy using `\"pair programming\" from:hashrocket`, I am able to find all of the\ntweets by `@hashrocket` that use the exact phrase `pair programming`.\n"
  },
  {
    "path": "internet/show-all-pivotal-stories-with-blockers.md",
    "content": "# Show All Pivotal Stories With Blockers\n\nWithin the past year [Pivotal Tracker](https://www.pivotaltracker.com) added\na feature that allows you to mark stories with _blockers_. These are visual\nindicators with a description that are used to show a particular story is\nblocked, that is, it cannot be completed until something else is taken care\nof.\n\nIn order to maintain the health of the project, it is good to triage these\nblocked stories from time to time. The best way to identify all of the\nblocked stories is to filter them into their own column.\n\nEnter `is:blocked` into the search bar to show all of the blocked stories.\n"
  },
  {
    "path": "internet/verify-site-ownership-with-dns-record.md",
    "content": "# Verify Site Ownership With DNS Record\n\nTo run your site through Google Search Console and get detailed reports, you\nneed to verify that you own the site. There are several manual ways of doing\nthis that involve sticking a value unique to your URL in a file or header tag.\nThere is a better way though.\n\nBy adding a TXT DNS record wherever you domain's DNS is managed, you can prove\nto Google that you own the domain. That verification applies to all paths and\nsubdomains of that domain.\n\nSome providers like Cloudflare have a mostly-automated process for this that\nGoogle can hook into as long as you grant permission via OAuth.\n\nYou can also manually create the TXT record if necessary.\n\nEither way, it will look something like:\n\n```bash\n$ dig -t TXT visualmode.dev\n\n;; ANSWER SECTION:\nvisualmode.dev.         377     IN      TXT     \"google-site-verification=MBZ2S2fhnh2gHRxFniRrYW-O6mdyimJDRFj-f\nvblwtk\"\n```\n\nMore details are provided in the [Google Search Console\ndocs](https://support.google.com/webmasters/answer/9008080?hl=en#domain_name_verification).\n"
  },
  {
    "path": "java/ensure-resources-always-get-closed.md",
    "content": "# Ensure Resources Always Get Closed\n\nJava has a construct known as _try-with-resource_ that allows us to always\nensure opened resources get closed. This is safer than similar cleanup in the\n`finally` block which could still leave a memory leak if an error occurs in\nthat block.\n\nTo use the _try-with-resource_ construct, instantiate your opened resource in\nparentheses with the `try`.\n\n```java\ntry (BufferedReader reader = new BufferedReader(new FileReader(filename))) {\n  // ...\n}\n```\n\nThe resource will be automatically closed when the try/catch block completes.\n\nHere is a full example:\n\n```java\nimport java.io.BufferedReader;\nimport java.io.FileReader;\nimport java.io.IOException;\n\npublic class FileReaderExample {\n    public static void main(String[] args) {\n        String fileName = \"example.txt\";\n        \n        try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {\n            String line;\n            int lineCount = 0;\n            \n            while ((line = reader.readLine()) != null && lineCount < 5) {\n                System.out.println(line);\n                lineCount++;\n            }\n        } catch (IOException e) {\n            System.out.println(\"An error occurred while reading the file: \" + e.getMessage());\n        }\n    }\n}\n```\n\nYou can even specify multiple resources in one `try`. The above does that, but\nthis will make it more obvious:\n\n```java\ntry (FileReader fr = new FileReader(filename);\n     BufferedReader br = new BufferedReader(fr)) {\n  // ...\n}\n```\n\n[source](https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html)\n"
  },
  {
    "path": "java/install-java-on-mac-with-brew.md",
    "content": "# Install Java On Mac With Brew\n\nIf you don't already have Java installed on your Mac, you can install it with\nhomebrew.\n\n```bash\n$ brew install java\n```\n\nThis will take a bit to run and when all is complete, you'll go to run\nsomething like a version check and see this:\n\n```bash\n$ java -version\nThe operation couldn’t be completed. Unable to locate a Java Runtime.\nPlease visit http://www.java.com for information on installing Java.\n```\n\nThis is because [OpenJDK](https://openjdk.org/) the open-source implementation\nof the Java Development Kit (Java platform) does not get fully set up by\nhomebrew.\n\nYou'll need to symlink `openjdk` and the exact command with correct paths can\nbe found from running the following:\n\n```bash\n$ brew info openjdk\n\n...\n\nFor the system Java wrappers to find this JDK, symlink it with\n  sudo ln -sfn /usr/local/opt/openjdk/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk.jdk\n\n...\n```\n\nThe paths may look different for you, so copy the exact command and run that.\nOnce the symlink is set, check the version again.\n\n```bash\n$ java -version\nopenjdk version \"23\" 2024-09-17\nOpenJDK Runtime Environment Homebrew (build 23)\nOpenJDK 64-Bit Server VM Homebrew (build 23, mixed mode, sharing)\n```\n\n[source](https://stackoverflow.com/a/65601197/535590)\n"
  },
  {
    "path": "java/run-a-hello-world-program-in-eclipse.md",
    "content": "# Run A Hello World Program In Eclipse\n\nFirst, you'll need to create a new Java Project if you don't already have one\nto work in.\n\nFrom there, you can add a new _Class_ to the `src` folder of that project. I'll\ncall mine `Greeting.java` and the only thing it will contain is a `main`\nmethod.\n\n```java\npublic class Greeting {\n    public static void main(String[] args) {\n    \tString name = args.length > 0 ? args[0] : \"World\";\n\n        System.out.println(\"Hello, \" + name + \"!\");\n    }\n}\n```\n\nThis method tries to read a name from the arguments given to the program at\ntime of execution. If one wasn't provided the ternary falls back to `\"World\"`\nas the default name. It then prints the greeting to stdout.\n\nTo run this program, we can either select _Run_ from the _Run_ menu (which will\nresult in `Hello, World!`) or we can select _Run Configurations..._ from the\nsame menu and add a custom name to _Program Arguments_ under the _Arguments_\ntab.\n"
  },
  {
    "path": "javascript/accessing-arguments-to-a-function.md",
    "content": "# Accessing Arguments To A Function\n\nThe `arguments` object is available within any JavaScript function. It is\nan array-like object with all of the arguments to the function. Even if not\nall of the arguments are referenced in the function signature, they can\nstill be accessed via the `arguments` object.\n\n```javascript\nfunction argTest(one) {\n  console.log(one);\n  console.log(arguments);\n  console.log(arguments[1]);\n}\n\nargTest(1);\n// 1\n// [1]\n// undefined\n\nargTest(1, 'two', true);\n// 1\n// [1,'two',true]\n// 'two'\n```\n\nSee the [Arguments object\ndocs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments)\non MDN for more details.\n\nh/t Dorian Karter\n"
  },
  {
    "path": "javascript/add-item-to-an-array-of-references-in-sanity.md",
    "content": "# Add Item To An Array Of References In Sanity\n\nLet's say we have an existing record in our Sanity dataset. The schema for that\nrecord allows for an array of references to another type of record. As part of\nprogrammatically importing some data, we need to tie some records together by\nadding to that array of references.\n\nWe've already set up our [Sanity client](https://www.sanity.io/docs/js-client)\n(via the JavaScript SDK). We have an `_id` for the record we want to patch. We\nhave a `resourceId` for the resource that we want to _reference_ in the array.\n\nHere is how we perform that `patch`:\n\n```javascript\nawait sanityClient\n  .patch(_id)\n  .setIfMissing({resources: []})\n  .append('resources', [{_type: 'reference', _ref: resourceId}])\n  .commit({autoGenerateArrayKeys: true})\n```\n\n1. We give it the `_id` of the record we want to `patch`.\n2. We set our array of `resources` to an empty array (`[]`) if it hasn't\n   already been set.\n3. We `append` to the `resources` array with an array containing a single item,\n   a reference to our resource.\n4. We `commit` the changes with the directive that Sanity should auto-generate\n   the `_key` value for any new array items.\n"
  },
  {
    "path": "javascript/basic-date-formatting-without-a-library.md",
    "content": "# Basic Date Formatting Without A Library\n\nJavaScript, on modern browsers, has an Internationalization API that, among\nother things, provides some date formatting utilities. You can just start using\nit, no need to import some massive date formatting library.\n\nHere is a `Date` object:\n\n```javascript\n> const now = new Date();\n> now\nTue Nov 19 2019 16:23:43 GMT-0600 (Central Standard Time)\n```\n\nThe default formatting with this API is a good start:\n\n```javascript\n> Intl.DateTimeFormat('en-US').format(now)\n\"11/19/2019\"\n```\n\nThere are also a number of options for more advanced formatting. Here is the\n`dateStyle` option with the four possible option values:\n\n```javascript\n> Intl.DateTimeFormat('en-US', { dateStyle: \"full\" }).format(now)\n\"Tuesday, November 19, 2019\"\n> Intl.DateTimeFormat('en-US', { dateStyle: \"long\" }).format(now)\n\"November 19, 2019\"\n> Intl.DateTimeFormat('en-US', { dateStyle: \"medium\" }).format(now)\n\"Nov 19, 2019\"\n> Intl.DateTimeFormat('en-US', { dateStyle: \"short\" }).format(now)\n\"11/19/19\"\n```\n\nThere is a lot more to this API including localization and custom formatting.\nCheck out the\n[docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat)\nfor those details.\n"
  },
  {
    "path": "javascript/character-codes-from-keyboard-listeners.md",
    "content": "# Character Codes from Keyboard Listeners\n\nIf I create the following keyboard event listeners for `keydown`,\n`keypress`, and `keyup`:\n\n```javascript\nwindow.addEventListener('keydown', function(e) { console.log(\"Keydown: \" + e.charCode + \", \" + e.keyCode); });\nwindow.addEventListener('keypress', function(e) { console.log(\"Keypress: \" + e.charCode + \", \" + e.keyCode); });\nwindow.addEventListener('keyup', function(e) { console.log(\"Keyup: \" + e.charCode + \", \" + e.keyCode); });\n```\n\nand then I press `A`, my browser console will read the following:\n\n```\nKeydown: 0, 65\nKeypress: 65, 65\nKeyup: 0, 65\n```\n\nand if I then press `a`, my browser console will read:\n\n```\nKeydown: 0, 65\nKeypress: 97, 97\nKeyup: 0, 65\n```\n\nThe `keypress` event seems to be the way to go. Regardless, there seems to\nbe quite a bit of [incompatibility and lack of\nsupport](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Browser_compatibility)\nacross browsers for various aspects of the keyboard events.\n"
  },
  {
    "path": "javascript/check-classes-on-a-dom-element.md",
    "content": "# Check Classes On A DOM Element\n\nYou can use the [`classList`\nproperty](https://developer.mozilla.org/en-US/docs/Web/API/Element/classList)\nto check what classes have been assigned to a DOM element.\n\nAssuming the following DOM element:\n\n```html\n<div id=\"auth-modal\" class=\"modal hidden\">...</div>\n```\n\nOnce you get a handle on that element, using your preferred method (e.g.\n[`Document.getElementById`](https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById)),\nyou can start inspecting the class list:\n\n```javascript\n> element.classList.contains(\"modal\")\ntrue\n\n> element.classList.contains(\"hidden\")\ntrue\n\n> element.classList.contains(\"taco\")\nfalse\n\n> element.classList.toString()\n\"modal hidden\"\n```\n"
  },
  {
    "path": "javascript/check-if-a-number-is-positive-or-negative.md",
    "content": "# Check If A Number Is Positive Or Negative\n\nThe\n[`Math`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math)\nmodule has a handy function for checking if a number is _positive_ or\n_negative_. Or _zero_, for that matter.\n\nIt is\n[`Math.sign`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign).\n\n```javascript\n> Math.sign(5)\n1\n\n> Math.sign(-5)\n-1\n\n> Math.sign(0)\n0\n```\n\nAny positive number will result in `1`. Any negative number will result in\n`-1`. If the number happens to be `0`, then `0` will be returned.\n\nThis function goes real well with a switch statement.\n\nNote also that anything that isn't a number will result in `NaN`.\n\n```javascript\n> Math.sign(\"one\")\nNaN\n```\n"
  },
  {
    "path": "javascript/check-if-file-exists-before-reading-it.md",
    "content": "# Check If File Exists Before Reading It\n\nLet's say we are working on a script that tries to read in existing data from a\nJSON data file. It is possible that data file hasn't been created and populated\nyet. In order to account for that scenario, we need to check if the file\nexists. If we try to read from a non-existant file, an error will be thrown.\n\nTo prevent the script from error'ing out, we can use\n[`fs.existsSync`](https://nodejs.org/api/fs.html#fsexistssyncpath) to check if\nthe given file path is an existing file. If we learn that the file does exist,\nwe can proceed with reading it. If not, we can skip the file read and react\naccordingly.\n\n```javascript\nimport fs from 'fs'\n\nconst nonExistantFile = 'non-existant.json'\n\n// set default in case file does not exists\nlet json = {}\n\nif(fs.existsSync(nonExistantFile)) {\n  const fileData = fs.readFileSync(nonExistantFile)\n  json = JSON.parse(fileData.toString())\n}\n\nconsole.log('JSON: ', json)\n```\n\n[source](https://flaviocopes.com/how-to-check-if-file-exists-node/)\n"
  },
  {
    "path": "javascript/check-if-something-is-an-array.md",
    "content": "# Check If Something Is An Array\n\nThe `Array` class has a function on it called\n[`isArray()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray)\nwhich can be used to check if something is an array.\n\n```javascript\n> Array.isArray('Hello, World!');\n// => false\n\n> Array.isArray(['One', 2, [3]]);\n// => true\n\n> Array.isArray({ foo: 'bar' });\n// => false\n\n> Array.isArray([]);\n// => true\n```\n\nThe MDN docs provide an [example\npolyfill](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray#Polyfill)\nif it is not natively available.\n\n```javascript\nif (!Array.isArray) {\n  Array.isArray = function(arg) {\n    return Object.prototype.toString.call(arg) === '[object Array]';\n  };\n}\n```\n"
  },
  {
    "path": "javascript/check-media-queries-from-javascript.md",
    "content": "# Check Media Queries From JavaScript\n\nI'm usually thinking about and [using media\nqueries](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_media_queries/Using_media_queries)\nfrom a CSS context. I use them to control what styles are displayed for a\nvariety of scenarios, such as at different screen widths, when a user prefers\nreduced motion, or when the user prefers a dark color scheme.\n\nThe current value of various media queries can be checked from a JavaScript\ncontext as well.\n\nFor instance, if we want to see if the user prefers a _dark_ color schema, we\ncan look for a _match_ on that media query with\n[`matchMedia`](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia).\n\n```javascript\n> window.matchMedia('(prefers-color-scheme: dark)')\nMediaQueryList {media: '(prefers-color-scheme: dark)', matches: true, onchange: null}\n> window.matchMedia('(prefers-color-scheme: dark)')['matches']\ntrue\n```\n\nThis queries for the [`prefers-color-scheme` media\nfeature](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme).\n\nThe [Astro.build Blog\nTutorial](https://docs.astro.build/en/tutorial/6-islands/2/#add-client-side-interactivity)\nshows an example of using this to wire up a Light/Dark mode toggle.\n"
  },
  {
    "path": "javascript/check-the-password-confirmation-with-yup.md",
    "content": "# Check The Password Confirmation With Yup\n\nThe [Yup](https://github.com/jquense/yup) library makes it easy to validate\nindividual values in a JavaScript object. A common situation when\nimplementing a Sign Up form is asking the user to input their password twice\nand then the app can make sure they match.\n\nTo do this, we need the validation of our `passwordConfirmation` value to\nreach outside of itself to make a comparison with the `password` value. This\ncan be done with Yup's `ref` function.\n\n```javascript\nimport * as Yup from 'yup';\n\nvalidationSchema: Yup.object({\n  password: Yup.string().required('Password is required'),\n  passwordConfirmation: Yup.string()\n     .oneOf([Yup.ref('password'), null], 'Passwords must match')\n});\n```\n\nWe are able to reference the value of `password` with `ref`. We use the\n`oneOf` function to ensure that `passwordConfirmation` either matches\n`password` or if it is left blank and matches `null` then it passes the\nvalidation for the time being. The second argument to `oneOf` is a custom\nvalidation message when this validation fails.\n\n[source](https://github.com/jaredpalmer/formik/issues/90)\n"
  },
  {
    "path": "javascript/compare-the-equality-of-two-date-objects.md",
    "content": "# Compare The Equality Of Two Date Objects\n\nEquality can always feel like a bit of a moving target in JavaScript. Comparing\ntwo objects, even if visually/conceptually identical, will resolve to being not\nequal.\n\nTo compare two `Date` objects, you first need to convert them to something we\ncan check for equality -- numbers. This can be done with `getTime()`.\n\n```javascript\n> now = Date.now()\n> today1 = new Date(now)\n> today2 = new Date(now)\n> today1 === today2\nfalse\n> today1.getTime() === today2.getTime()\ntrue\n```\n\nWith `Date` objects, you can directly use `<`, `>`, `<=`, and `>=`.\n\n[source](https://stackoverflow.com/questions/492994/compare-two-dates-with-javascript)\n"
  },
  {
    "path": "javascript/computed-property-names-in-es6.md",
    "content": "# Computed Property Names In ES6\n\nPerhaps more often than not, property names in an object are based on\nsomething dynamic rather than a static value. In ES5, you may end up with\ncode like the following to build an object with dynamic property names:\n\n```javascript\nvar dynamic1 = 'hello',\n  dynamic2 = 'world';\nvar obj = {};\nvar propName1 = dynamic1 + dynamic2;\nvar propName2 = 5 * 11;\nobj[propName1] = true;\nobj[propName2] = false;\n\n> obj\n// { 55: false, 'helloworld': true }\n```\n\nWith ES6, we get _computed property names_ which allow us to do all of these\ninline when defining the object. We just have to wrap the code that will be\nevaluated to a property name in brackets:\n\n```javascript\nconst dynamic1 = 'hello',\n  dynamic2 = 'world';\nconst obj = {\n  [dynamic1 + dynamic2]: true,\n  [5 * 11]: false\n};\n\n> obj\n// { 55: false, 'helloworld': true }\n```\n\nComputed properties are [already available in many modern\nbrowsers](https://kangax.github.io/compat-table/es6/#test-object_literal_extensions_computed_properties).\n"
  },
  {
    "path": "javascript/conditionally-include-pairs-in-an-object.md",
    "content": "# Conditionally Include Pairs In An Object\n\nYou can add key-value pairs to an object using the ES6 spread operator:\n\n```javascript\n> { one: 1, ...{ hello: \"world\" } }\n{ one: 1, hello: \"world\" }\n```\n\nBy combining the spread operator with some boolean logic, you can conditionally\nadd key-value pairs to an object:\n\n```javascript\n> {\n    one: 1,\n    ...(isArriving && { hello: \"world\" }),\n  }\n```\n\nDepending on the value of `isArriving`:\n\n```javascript\n// isArriving === true\n{ one: 1, hello: \"world\" }\n```\n\nor\n\n```javascript\n// isArriving === false\n{ one: 1 }\n```\n\nThis is useful for dynamically building up some configuration object or data\npayload.\n"
  },
  {
    "path": "javascript/configure-jest-to-run-a-test-setup-file.md",
    "content": "# Configure Jest To Run A Test Setup File\n\nJest can be configured to run a setup file before each test. This is useful\nfor configuring your testing framework in a single place, rather than in\neach test file.\n\nThis setup file can be specified in `package.json` (or `jest.config.js`).\n\n```javascript\n// package.json\n{\n  // ...\n  \"jest\": {\n    \"setupTestFrameworkScriptFile\": \"<rootDir>src/setupTests.js\"\n  }\n}\n```\n\nThe\n[`setupTestFrameworkScriptFile`](https://facebook.github.io/jest/docs/en/configuration.html#setuptestframeworkscriptfile-string)\npoints to a test setup file at the specified location rooted at `<rootDir>`\n(the root of your project).\n\nThis kind of setup is helpful for something like\n[Enzyme](https://github.com/airbnb/enzyme/blob/master/docs/guides/jest.md)\nthat needs to be configured with a specific adapter for use throughout your\ntests.\n"
  },
  {
    "path": "javascript/convert-seconds-to-date-object.md",
    "content": "# Convert Seconds To Date Object\n\nLet's say you have an integer that represents the number of seconds since the\nunix epoch. This is a reasonably common way for systems to represent a date.\n\nFor example, `1713350171` is an _Expiration Date_ I just got from an API.\n\nBut how do we know what date that actually represents and how can we get a\nJavaScript `Date` object from that value?\n\nThe `new Date()` constructor can produce a date object given an integer. That\ninteger is not supposed to be seconds since the unix epoch though. See what we\nget here:\n\n```javascript\n> new Date(1713350171)\n1970-01-20T19:55:50.171Z\n```\n\nSomething is off. The integer that you pass to `new Date()` needs to be the\n_number of milliseconds_ since the unix epoch. We can get there by multiplying\nour _seconds_ value by `1000`.\n\n```javascript\n> new Date(1713350171 * 1000)\n2024-04-17T10:36:11.000Z\n```\n\nNot only can we, as humans, read that date, but we have a `Date` object that we\ncan use within our program.\n\nNote: if you execute `Date.now()`, the value you get is in milliseconds.\n"
  },
  {
    "path": "javascript/create-a-cancelable-promise-with-pcancelable.md",
    "content": "# Create A Cancelable Promise With PCancelable\n\nIf an async task takes a really long time and we find out in the middle of\nits execution that we no longer want the results of that activity, it would\nbe nice to be able to cancel that promise. There was a [proposal for\ncancelable promises](https://github.com/tc39/proposal-cancelable-promises),\nbut it has since been withdrawn. There is an alternative though.\n\nThe [`p-cancelable`](https://github.com/sindresorhus/p-cancelable) package\nprovides a promise wrapper that acts as a cancelable promise.\n\n```javascript\nimport PCancelable from 'p-cancelable';\n\nconst fetchPromise = new PCancelable((resolve, reject, onCancel) => {\n  setTimeout(() => {\n    resolve({ ok: true, data: [1, 2, 3] });\n  }, 10000);\n\n  onCancel(() => {\n    console.log('Promise is being canceled');\n  });\n});\n\nfetchPromise.then(response => {\n  console.log('Promise Resolved: ', response.data);\n}).catch(err => {\n  console.log('Promise Rejected: ', err);\n});\n\nfetchPromise.cancel();\n```\n\nWe can create a promise in a familiar manner. We get an additional argument\n-- the `onCancel` function. This is a function that will be executed if\n`cancel` is called before the promises has resolved or rejected. In the\nabove example, the `fetchPromise.cancel()` line will be invoked before the\n`setTimeout` resolves. The promise will be canceled, causing a rejection\nwhich will push us into the `catch` handler.\n"
  },
  {
    "path": "javascript/create-an-array-containing-1-to-n.md",
    "content": "# Create An Array Containing 1 To N\n\nSome languages, such as Ruby, have a built in range constraint that makes it\neasy to construct an array of values from 1 to N. JavaScript is not one of\nthose languages. Nevertheless, if you don't mind the aesthetics, you can get\naway with something like this:\n\n```javascript\n> Array.apply(null, {length: 10}).map(Number.call, Number);\n=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n```\n\nThat gives us `0` through `9`. To get `1` through `10`, we can tweak it\nslightly:\n\n```javascript\n> Array.apply(null, {length: 10}).map(Number.call, n => Number(n) + 1);\n=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n```\n\nTo generalize this, we can replace `10` with `N` and then just expect that\n`N` will be defined somewhere:\n\n```javascript\n> var N = 10;\n=> undefined\n> Array.apply(null, {length: N}).map(Number.call, n => Number(n) + 1);\n=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n```\n\n[Source](http://stackoverflow.com/a/20066663/535590) \n"
  },
  {
    "path": "javascript/create-an-object-with-no-properties.md",
    "content": "# Create An Object With No Properties\n\nWhen you call `new Object` or even just instantiate an object with `{}`, you\nare creating an object that uses the `Object` prototype. This means it\ninherits from `Object.prototype`.\n\nYou can deliberately create an object with no properties by making sure that\nit does not inherit `Object.prototype`.\n\n```javascript\n> const propertylessObject = Object.create(null);\n{}\n\n> propertylessObject.__proto__\nundefined\n```\n\nUnlike most objects that we encounter as we write JavaScript, this object we\ncreated with `Object.create(null)` has no properties including no\n`__proto__`.\n\nSee\n[Object.create](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create)\nand\n[Object.prototype](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype)\nfor more details.\n"
  },
  {
    "path": "javascript/create-bootstrapped-apps-with-yarn.md",
    "content": "# Create Bootstrapped Apps With Yarn\n\nThe [`yarn` cli](https://yarnpkg.com/lang/en/docs/cli/) comes with a\n[`create`](https://yarnpkg.com/blog/2017/05/12/introducing-yarn/) command\nthat is a convenience command for generating bootstrapped apps that follow\nthe `create-<name>-app` convention.\n\nWant to create a React.js app using\n[`create-react-app`](https://github.com/facebookincubator/create-react-app),\ninvoke the following command:\n\n```\n$ yarn create react-app my-app\n```\n\nDon't already have a particular package globally installed? `yarn create`\nwill install it for you. For instance, the following command with install\nand use [`create-vue-app`](https://github.com/egoist/create-vue-app):\n\n```\n$ yarn create vue-app my-other-app\n```\n\nh/t Gabe Reis\n"
  },
  {
    "path": "javascript/create-future-and-past-dates-from-today.md",
    "content": "# Create Future And Past Dates From Today\n\nJavaScript's built-in\n[`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date)\nobject can be frustrating to work with at times.  It does, however, lend itself\nnicely to some date math. You have to familiarize yourself with some of the API\nand then it is a matter of addition and subtraction.\n\nHere is today:\n\n```javascript\nconst today = new Date();\n// Tue Dec 01 2020 ...\n```\n\nLet's make a copy of today and send it 30 days into the future:\n\n```javascript\nconst future = new Date(today);\nfuture.setDate(future.getDate() + 30);\nfuture\n// Thu Dec 31 2020 ...\n```\n\nOr we could jump back a few years:\n\n```javascript\nconst past = new Date(today);\npast.setFullYear(past.getFullYear() - 4);\npast\n// Thu Dec 01 2016 ...\n```\n\n[source](https://stackoverflow.com/questions/7908098/javascript-set-date-30-days-from-now/7908122#7908122)\n"
  },
  {
    "path": "javascript/custom-type-checking-error-messages-with-yup.md",
    "content": "# Custom Type Checking Error Messages With Yup\n\nIn [Yup Schemas Are Validated\nAsynchronously](https://github.com/jbranchaud/til/blob/master/javascript/yup-schemas-are-validated-asynchronously.md),\nI showed how to create a simple schema that allows you to enforce that a\nvalue is a number.\n\n```javascript\nconst numSchema = yup.number();\n```\n\nIf we use this schema to validate something that isn't a number, Yup will\nprovide a lengthy default message. Here is what we get if we validate against\n`'hey'`:\n\n> this must be a `number` type, but the final value was: `NaN` (cast from\n> the value `\"hey\"`).\n\nThis value isn't necessarily suitable for displaying to a user. We can\ncustomize the type checking error message by redefining our schema with the\n`typeError()` function:\n\n```javascript\nconst numSchema = yup.number().typeError(\"Invalid number\");\n```\n"
  },
  {
    "path": "javascript/default-and-named-exports-from-the-same-module.md",
    "content": "# Default And Named Exports From The Same Module\n\nES6 module syntax allows for a single default export and any number of named\nexports. In fact, you can have both named exports and a default export in\nthe same module.\n\nHere is an example:\n\n```javascript\n// src/animals.js\nexport default function() {\n  console.log('We are all animals!');\n}\n\nexport function cat() {\n  console.log('Meeeow!');\n}\n\nexport function dog() {\n  console.log('Rufff!');\n}\n```\n\nIn this case, you could import the default and named exports like so:\n\n```javascript\n// src/index.js\nimport animals, { cat, dog } from './animals.js';\n\nanimals(); // \"We are all animals!\"\ncat();     // \"Meeeow!\"\ndog();     // \"Rufff!\"\n```\n\n[source](http://2ality.com/2014/09/es6-modules-final.html)\n"
  },
  {
    "path": "javascript/define-a-custom-jest-matcher.md",
    "content": "# Define A Custom Jest Matcher\n\nThough [Jest's built-in\nmatchers](https://jestjs.io/docs/en/expect) will get you pretty\nfar in most testing scenarios, you may find yourself in a testing situation\nbetter served by a custom matcher. Custom matchers can be defined using the\n[`expect.extend()`\nfunction](https://jestjs.io/docs/en/expect#expectextendmatchers).\n\nHere is an example of a matcher that can check equality of two objects based\nsolely on their `id` property.\n\n```javascript\nexpect.extend({\n  toHaveMatchingId(recieved, expected) {\n    const pass = recieved.id === expected.id;\n\n    if (pass) {\n      return {\n        pass: true,\n        message: () =>\n          `expected id:${expected.id} to not match actual id:${recieved.id}`\n      };\n    } else {\n      return {\n        pass: false,\n        message: () =>\n          `expected id:${expected.id} to match actual id:${recieved.id}`\n      };\n    }\n  }\n});\n```\n\nThis defines the name of the matcher (`toHaveMatchingId`), contains some logic\nto figure out whether `received` and `expected` pass the matcher, and then two\nreturn conditions (`pass: true` and `pass: false`) with accompanying\nmessage-returning functions.\n\nIt can then be used like any other Jest matcher:\n\n```javascript\ntest(\"compare objects\", () => {\n  expect({ id: \"001\" }).toHaveMatchingId({ id: \"001\" });\n  // ✅\n  expect({ id: \"001\" }).toHaveMatchingId({ id: \"002\" });\n  // ❌ expected id:002 to match actual id:001\n});\n```\n\nCheck out a [live example](https://codesandbox.io/s/focused-bush-vw2s5).\n"
  },
  {
    "path": "javascript/destructure-with-access-to-nested-value-and-parent-value.md",
    "content": "# Destructure With Access To Nested Value And Parent Value\n\nA destructuring pattern that I often see (especially in React code) is to\npeel off a nested value in the argument declaration of a function.\n\n```javascript\nconst Component = ({ data: { name: displayName }}) => {\n  return (\n    <div>\n      <h1>{displayName}</h1>\n      <SubComponent />\n    </div>\n  );\n};\n```\n\nOn its own this works quite well, but what happens when you need access to\nthe full set of `data` as well as the nested `name` value? I often see this.\n\n```javascript\nconst Component = ({ data }) => {\n  const { name: displayName } = data;\n  return (\n    <div>\n      <h1>{displayName}</h1>\n      <SubComponent data={data} />\n    </div>\n  );\n};\n```\n\nES6 destructuring is flexible. You can skip the `const` line and keep\neverything in the argument declaration.\n\n```javascript\nconst Component = ({ data: { name: displayName }, data }) => {\n  return (\n    <div>\n      <h1>{displayName}</h1>\n      <SubComponent data={data} />\n    </div>\n  );\n};\n```\n\nYou can re-reference the `data` value after the nested destructuring.\n"
  },
  {
    "path": "javascript/destructuring-the-rest-of-an-array.md",
    "content": "# Destructuring The Rest Of An Array\n\nES6 offers some amount of pattern matching on arrays. This means you can do\nfun stuff like grabbing a couple values and then destructuring the rest of\nthe array into a variable.\n\n```javascript\n> const kids = [\"Mike\", \"Will\", \"Dustin\", \"Lucas\", \"Eleven\", \"Max\"];\nundefined\n> const [first, second, ...rest] = kids;\nundefined\n> first\n\"Mike\"\n> second\n\"Will\"\n> rest\n[\"Dustin\", \"Lucas\", \"Eleven\", \"Max\"]\n```\n\nBy using the `...` syntax with a variable name in the left-hand side of the\nassignment, you are able to capture an array of whatever isn't assigned to\npreceding variables.\n"
  },
  {
    "path": "javascript/easy-date-comparison-with-dayjs.md",
    "content": "# Easy Date Comparison With DayJS\n\nLet's say my application fetches dates from the server which come back in\nstring form as `\"YYYY-MM-DD\"` and I'd like to know if those dates already\npassed. This can be done easily by wrapping dates in\n[DayJS](https://github.com/iamkun/dayjs) and using its comparison functions.\n\n```javascript\nimport dayjs from 'dayjs';\n\nconst today = dayjs(new Date());\nconst pastDate = dayjs(\"2018-10-22\");\nconst futureDate = dayjs(\"2022-01-01\");\n\nconsole.log(pastDate.isBefore(today));\n// => true\nconsole.log(futureDate.isBefore(today));\n// => false\n```\n\nThe `dayjs()` function can be used to construct DayJS date objects from Date\nobjects and strings. These can then be compared with functions like\n`isBefore()` and `isAfter()`.\n"
  },
  {
    "path": "javascript/enable-es7-transforms-with-react-rails.md",
    "content": "# Enable ES7 Transforms With react-rails\n\nThe [`react-rails`](https://github.com/reactjs/react-rails) gem adds JSX and\nES6 transforms to the asset pipeline.  By using `.js.jsx` and `.es6.jsx`\nextensions with relevant files, the asset pipeline will know to make the\nappropriate transformation when compiling application assets. ES7 transforms\nare not enabled by default, but can be configured. Add the following to the\n`config/application.js` file to allow ES7's *class properties* syntax:\n\n```ruby\nconfig.react.jsx_transform_options = {\n  optional: [\"es7.classProperties\"]\n}\n```\n\nh/t Mike Chau\n"
  },
  {
    "path": "javascript/ensure-shell-can-find-global-npm-binaries.md",
    "content": "# Ensure Shell Can Find Global npm Binaries\n\nWhen you install a package globablly either with yarn (or npm)\n\n```bash\n$ yarn global add vercel\n```\n\nIt places the binaries for that package in the `bin` directory of your package\nmanager's configured path prefix.\n\nThe absolute path to this `bin` directory can be found with:\n\n```bash\n$ yarn global bin\n/Users/jbranchaud/.asdf/installs/nodejs/15.4.0/.npm/bin\n```\n\nYou can ensure that everything located in that `bin` directory is on your\nshell's path by adding the following line to your shell's config file (e.g.\n`.bashrc` or `.zshrc`).\n\n```bash\nexport PATH=\"$PATH:$(yarn global bin)\"\n```\n\nOnce you've updated your shell config, make sure you _source_ the file or\nrestart your shell.\n\n[source](https://stackoverflow.com/a/40333409/535590)\n"
  },
  {
    "path": "javascript/expand-emojis-with-the-spread-operator.md",
    "content": "# Expand Emojis With The Spread Operator\n\nThere are a number of emojis that are not stand-alone unicode characters,\nbut instead are [a combination of two or more other\nemojis](http://unicode.org/emoji/charts/full-emoji-list.html#1f468_200d_1f469_200d_1f466).\nThe two main places this happens is with family emojis and emojis using\nnon-simpsons skin tones.\n\nYou can use JavaScript's spread operator to expand these emojis to see what\ntheir base components are. Here is a screenshot of a few that I expanded\nfrom Chrome's dev tools.\n\n![](http://i.imgur.com/ObagJJ2.png)\n\n[source](https://twitter.com/wesbos/status/769228067780825088)\n"
  },
  {
    "path": "javascript/fill-an-input-with-a-ton-of-text.md",
    "content": "# Fill An Input With A Ton Of Text\n\nI needed to test out a form validation for an input that should render an\nerror when the length of the context exceeds 10,000 characters. Two small\ntricks make this easy.\n\nFirst, you can target any DOM element via the Chrome dev tools by selecting\nit and then referencing it via the `$0` magic variable. [More details\nhere](https://developers.google.com/web/updates/2015/05/the-currently-selected-dom-node).\n\n```javascript\n> $0\n<input>...</input>\n```\n\nSecond, you can quickly and precisely generate a very long string with the\n`repeat` function.\n\n```javascript\n> \"a\".repeat(10000)\n\"aaaaaaaaaaaaaaaaaaaaaaa...\"\n```\n\nCombine these two tricks in the browser to fill the input with a ton of\ntext:\n\n```javascript\n> $0.value = \"a\".repeat(10000)\n```\n\nh/t Dillon Hafer\n"
  },
  {
    "path": "javascript/find-the-version-of-an-installed-dependency.md",
    "content": "# Find The Version Of An Installed Dependency\n\nI recently ran into a bug related to a specific version of a dependency. As\npart of tracking it down, I needed to figure out what version I had installed.\n\nThe [`yarn list`](https://classic.yarnpkg.com/en/docs/cli/list) command can\nhelp with this. Without any flags, it will show a tree structure listing _every\nsingle_ dependency and sub-dependency that is installed for your project.\n\nHere is an example of what that looks like restricted to a pattern of `jest`.\n\n```bash\n$ yarn list --pattern jest\n\nyarn list v1.22.10\n├─ @testing-library/jest-dom@5.14.1\n├─ @types/jest@27.0.1\n├─ @types/testing-library__jest-dom@5.9.5\n│  ├─ @jest/types@26.6.2\n│  ├─ @types/jest@26.0.23\n│  ├─ jest-diff@26.6.2\n│  └─ jest-get-type@26.3.0\n...\n```\n\nI can look through this list and find the dependency and version of interest.\n\nIt's still a lot of results to comb through, so what I like to do instead is\npipe it to [`fzf`](https://github.com/junegunn/fzf).\n\n```bash\n$ yarn list | fzf\n```\n\nThen I can interactively narrow down the results with the power of FZF's fuzzy\nfinding functionality.\n"
  },
  {
    "path": "javascript/find-where-yarn-is-installing-binaries.md",
    "content": "# Find Where Yarn Is Installing Binaries\n\nWhen you run a command like:\n\n```bash\n$ yarn global add create-react-app\n```\n\n[Yarn](https://yarnpkg.com/lang/en/) is going to install any needed\ndependencies including any binaries. So, where is Yarn putting these binaries?\n\nLet's ask:\n\n```bash\n$ yarn global bin\n/Users/jbranchaud/.asdf/installs/nodejs/10.15.3/.npm/bin\n```\n\nThis is where it is located on my machine. You'll want to run it on your own\nmachine because the exact location will depend on the specifics of your\ninstallation.\n\nSee [the docs](https://yarnpkg.com/lang/en/docs/cli/global/) for more details.\n"
  },
  {
    "path": "javascript/for-in-iterates-over-object-properties.md",
    "content": "# for...in Iterates Over Object Properties\n\nI don't reach for _for loops_ very often, so when I needed one recently I\nthought I'd check out the newer `for...in` construct. It didn't behave quite\nhow I was expecting. I thought it would iterate over the values in the\ntarget list, instead it seemed to be iterating over the indices.\n\nThe [MDN\ndocs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in)\nexplain what is going on:\n\n> The `for...in` statement iterates over all non-Symbol, enumerable properties\n> of an object.\n\nAn array is an object whose properties are the indices of the values stored\nin the array.\n\n```javascript\nconst fruits = [\"apple\", \"banana\", \"orange\"];\nfor (let fruit in fruits) {\n  console.log(fruit, fruits[fruit]);\n}\n// => \"0\" \"apple\"\n// => \"1\" \"banana\"\n// => \"2\" \"orange\"\n```\n\nThe iteration value wasn't what I was looking for, but in this case I can\nuse it to access the value from the list. I'd be better off using a standard\n_for loop_ though.\n"
  },
  {
    "path": "javascript/format-a-decimal-to-a-fixed-number-of-digits.md",
    "content": "# Format A Decimal To A Fixed Number Of Digits\n\nThe `Intl.NumberFormat` object is a reliable way to format numbers in an\ni18n-friendly way. It available with Node and all modern browsers.\n\nIf I want to format number that I expect to contain decimals, I can do so by\nsetting up a formatter using the `decimal` style.\n\n```javascript\nconst locale = \"en-US\";\nconst options = {\n  style: \"decimal\",\n};\n\nconst formatter = new Intl.NumberFormat(locale, options);\n\nconsole.log(formatter.format(1234))\n//=> 1,234\nconsole.log(formatter.format(1234.5678))\n//=> 1,234.568\n```\n\nBecause of my locale (`en-US`), it adds a comma to deliniate the thousandth\nplace. By default, it formats to three decimal places excluding decimals\naltogether if it is a whole number.\n\nIf I want to specify a fixed number of decimal places including for a whole\nnumber, I can use the `minimumFractionDigits` and `maximumFractionDigits`\noptions.\n\n```javascript\nconst locale = \"en-US\";\nconst options = {\n  style: \"decimal\",\n  minimumFractionDigits: 2,\n  maximumFractionDigits: 2,\n};\n\nconst formatter = new Intl.NumberFormat(locale, options);\n\nconsole.log(formatter.format(1234))\n//=> 1,234.00\nconsole.log(formatter.format(1234.5678))\n//=> 1,234.57\n```\n\nHere, it includes the `.00` on the whole number and it truncates the number\nwith more than 2 decimal places rounding as necessary.\n\nSee the [`Intl.NumberFormat`\ndocs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat)\nfor more details.\n"
  },
  {
    "path": "javascript/format-a-list-of-items-by-locale.md",
    "content": "# Format A List Of Items By Locale\n\nThe `Intl` module includes a [`ListFormat`\nobject](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat)\nwhich can be used to format a list of items in a consistent way across locales.\n\nI've reinvented the wheel of writing a helper function numerous times across\nprojects for formatting a list of items that accounts for formatting based on\nhow many items there are. This built-in function handles that with the added\nbenefit of working across locales.\n\nHere are lists of three, two, and one items formatted in the `long` styles for\nUS english.\n\n```javascript\n> const formatter = new Intl.ListFormat('en', { style: 'long', type: 'conjunction' });\nundefined\n\n> formatter.format(['Alice', 'Bob', 'Carla'])\n'Alice, Bob, and Carla'\n\n> formatter.format(['Coffee', 'Tea'])\n'Coffee and Tea'\n\n> formatter.format(['Taco'])\n'Taco'\n```\n\nThe difference between `long` and `short` style for a `conjunction` is _and_\nversus _&_. In addition to the type`conjunction`, you could also use\n`disjunction` which will do an _or_ instead of an _and_. I'm not sure what\nyou'd use the `unit` type for.\n\nYou could use another locale, such as French, as well:\n\n```javascript\n> const formatter = new Intl.ListFormat('fr', { style: 'long', type: 'conjunction' });\nundefined\n\n> formatter.format(['café', 'thé'])\n'café et thé'\n```\n"
  },
  {
    "path": "javascript/format-time-zone-identifier.md",
    "content": "# Format Time Zone Identifier\n\nThough there are surely libraries that can help with this task, we now have\nfull support in the [`Intl.DateTimeFormat`\nAPI](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat)\nfor formatting a date's time zone identifier in various ways.\n\nTo do this, we have to create a formatter specifying the locale, the `timeZone`\noption, and any formatting options. For the formatting, I'll try the\n`timeZoneName` with both `short` and `longGeneric`.\n\nThen we `formatToParts` on any date object and extract the `timeZoneName`\nvalue:\n\n```javascript\nconst options = { timeZone: 'America/Chicago', timeZoneName: \"short\" }\nconst formatter = new Intl.DateTimeFormat(\"en-US\", options)\n\nformatter.formatToParts(new Date()).find((part) => part.type === \"timeZoneName\").value\n//=> 'CDT'\n```\n\nNow, let's try this for `longGeneric`:\n\n```javascript\nconst options = { timeZone: 'America/Chicago', timeZoneName: \"longGeneric\" }\nconst formatter = new Intl.DateTimeFormat(\"en-US\", options)\n\nformatter.formatToParts(new Date()).find((part) => part.type === \"timeZoneName\").value\n//=> 'Central Time'\n```\n\nThere are several more options for the `timeZoneName` as well as a bunch more\nyou can do with the `Intl.DateTimeFormat` API.\n"
  },
  {
    "path": "javascript/formatting-values-with-units-for-display.md",
    "content": "# Formatting Values With Units For Display\n\nThere are all kinds of values and units your app may need to display. The\n[`Intl.NumberFormat`\nAPI](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat)\nthat is available in modern browsers can help with standardizing that display.\n\nHow about formatting distances for display?\n\nHere is a compact formatting of miles:\n\n```javascript\n> const milesFormat =\n    Intl.NumberFormat(\"en-US\", { style: \"unit\", unit: \"mile\" });\n> milesFormat.format(1500)\n\"1,500 mi\"\n```\n\nHere is two different formats for kilometers:\n\n```javascript\n> const kmFormat =\n    Intl.NumberFormat(\"en-US\", { style: \"unit\", unit: \"kilometer\" });\n> kmFormat.format(1500)\n\"1,500 km\"\n> const kilometerFormat =\n    Intl.NumberFormat(\"en-US\", { style: \"unit\", unit: \"kilometer\", unitDisplay: \"long\" })\n> kilometerFormat.format(1500)\n\"1,500 kilometers\"\n```\n\nGive it a try with something else like `miles-per-hour`, `liter`, or `gallon`.\n\n[source](https://twitter.com/jamesreggio/status/1196574375916400640?s=21)\n"
  },
  {
    "path": "javascript/freeze-an-object-sorta.md",
    "content": "# Freeze An Object, Sorta\n\nYou can freeze a JavaScript object using `Object.freeze` which will help\nenforce some immutability practices. Don't be fooled though, you can still\nmodify arrays and objects in the frozen object.\n\nHere is what the docs have to say:\n\n> The Object.freeze() method freezes an object: that is, prevents new\n> properties from being added to it; prevents existing properties from being\n> removed; and prevents existing properties, or their enumerability,\n> configurability, or writability, from being changed, it also prevents the\n> prototype from being changed.\n\nAnd here is `Object.freeze` in action:\n\n```javascript\n> const things = {one: \"two\", hello: \"world\", cats: [\"Von Neumann\", \"Sosa\"]}\nundefined\n> Object.freeze(things)\n{one: \"two\", hello: \"world\", cats: Array(2)}\n\n> things.one = \"three\"\n\"three\"\n> things.dogs = []\n[]\n> delete things.hello\nfalse\n\n> things\n{one: \"two\", hello: \"world\", cats: Array(2)}\n\n> things.cats.push(\"Sneaky\")\n3\n\n> things\n{one: \"two\", hello: \"world\", cats: Array(3)}\n```\n\nSee the [MDN\nDocs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze)\nfor more details.\n\nh/t Jake Worth\n"
  },
  {
    "path": "javascript/generate-a-v4-uuid-in-the-browser.md",
    "content": "# Generate A V4 UUID In The Browser\n\nThe [Web Crypto\nAPI](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) provides\na\n[`randomUUID`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID)\nfunction for generating v4 UUID values which are cryptographically random.\n\nIt works like this:\n\n```javascript\n> crypto.randomUUID()\n'f2050c5e-af52-4ca2-b4d6-23758b3396c9'\n> crypto.randomUUID()\n'079d5186-84d4-41d6-a660-edafb6a74c86'\n```\n\nNo two UUIDs will be the same. This is a great way to generate IDs that are\nguaranteed to be unique. Or if you need a value that is practically impossible\nto guess.\n\nI was surprised to see that as of writing this, this function has great browser\nsupport. Modern versions of all browsers except Internet Explorer have\nimplemented `randomUUID`.\n"
  },
  {
    "path": "javascript/generate-random-integers.md",
    "content": "# Generate Random Integers\n\nJavaScript's `Math` module has a built-in `random` function.\n\n```javascript\n> Math.random();\n0.4663311937101857\n```\n\nIt can be used to generate random floats between 0 and 1.\n\nIf you want integers, though, you're going to have to build your own function.\n\n```javascript\nfunction getRandomInt(max) {\n  return Math.floor(Math.random() * Math.floor(max));\n}\n\n> getRandomInt(10);\n1\n> getRandomInt(10);\n7\n> getRandomInt(10);\n2\n```\n\nThis function allows you to randomly generate numbers between `0` (inclusive)\nand `max`, a number you specify (exclusive).\n\n[source](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random)\n"
  },
  {
    "path": "javascript/get-the-location-and-size-of-an-element.md",
    "content": "# Get The Location And Size Of An Element\n\n[All modern browsers](https://caniuse.com/#feat=getboundingclientrect) ship\nwith the [`getBoundingClientRrect()`\nfunction](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect). It can be invoked for any DOM element. It returns the `x` and `y` coordinates of the element within the browser viewport as well as the `height` and `width` values and the `top` and `bottom` values along the `y-axis` and `left` and `right` values along the `x-axis`.\n\n```javascript\n> $0.getBoundingClientRect()\n{\n  \"x\": 381.421875,\n  \"y\": 70,\n  \"width\": 1030.578125,\n  \"height\": 48,\n  \"top\": 70,\n  \"right\": 1412,\n  \"bottom\": 118,\n  \"left\": 381.421875\n}\n```\n\nFor instance, this is the result of invoking it against a header element on\nthe _MDN page_ linked above.\n"
  },
  {
    "path": "javascript/get-the-response-status-from-an-axios-error.md",
    "content": "# Get The Response Status From An Axios Error\n\nYou can make API requests with [`axios`](https://github.com/axios/axios). If\nthe request fails because of a 4xx or 5xx response, an error will be raised.\nThe response to the request is stored on the error so that you can still access\nthe details of the response in your error handling logic.\n\nHere is a snippet of code that details using async/await with `axios`. It wraps\nthe call in a `try/catch` block.\n\n```javascript\nasync function getCharacter(characterId) {\n  let response;\n\n  try {\n    response = await axios.get(\n      `https://rickandmortyapi.com/api/character/${characterId}`\n    );\n  } catch (e) {\n    response = e.response;\n  }\n\n  console.log(response.status);\n\n  // You can also access the response data\n  // console.log(response.data);\n}\n\ngetCharacter(2);\n//=> 200\n\ngetCharacter(2000);\n//=> 404\n```\n\nIn the case of the second call that results in a 404 response, the `catch`\nblock is executed. This pulls the `response` off the error (`e`).\n\nJust like the standard response, the response from the error contains `status`,\n`data`, `headers`, etc.\n\nThis also works with a promise-based control flow.\n\n[Live Example](https://codesandbox.io/s/ancient-currying-5cmgm?file=/src/index.js)\n"
  },
  {
    "path": "javascript/get-the-time-components-of-a-date.md",
    "content": "# Get The Time Components Of A Date\n\nA `Date` object in JavaScript has several functions available to it for getting\nat the time components of that date.\n\n```javascript\n> const now = new Date()\nundefined\n> now\n2023-06-14T17:44:06.425Z\n> now.getMinutes()\n44\n> now.getSeconds()\n6\n> now.getHours()\n12\n```\n\nFor a given `Date` object, you can access the hours with\n[`getHours()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getHours),\nthe minutes with\n[`getMinutes()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getMinutes),\nand the seconds with\n[`getSeconds()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getSeconds).\n\nTo round things out, there is also\n[`getMilliseconds()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getMilliseconds)\nand\n[`getTimezoneOffset()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset).\n"
  },
  {
    "path": "javascript/get-the-time-zone-of-the-client-computer.md",
    "content": "# Get The Time Zone Of The Client Computer\n\nThe\n[`resolvedOptions`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat/resolvedOptions)\nfunction on `Intl.DateTimeFormat.prototype` provides a number of pieces of\ninformation about the client computer. It includes information such as the\nlocale and the numbering system. It also has the time zone for that machine.\n\nTry running this line of JavaScript in your own browser.\n\n```javascript\n$ Intl.DateTimeFormat().resolvedOptions().timeZone\n```\n\nWhen I run it, I get `America/Chicago`.\n\nYou can use this within your client-side code as a way of determining in\nwhich time zone your users are.\n"
  },
  {
    "path": "javascript/globally-install-a-package-with-yarn.md",
    "content": "# Globally Install A Package With Yarn\n\nI'm used to using the `-g` flag with `npm` to install packages globally.\n\n```bash\n$ npm install -g create-react-app\n```\n\nBut how do I achieve the same thing with [`yarn`](https://yarnpkg.com/en/)?\n\nBy using the `global` command prefix, I can do a number of `yarn` tasks\nglobally, including adding a package.\n\n```bash\n$ yarn global add create-react-app\n```\n\n[source](https://yarnpkg.com/lang/en/docs/cli/global/)\n"
  },
  {
    "path": "javascript/globally-install-specific-version-of-pnpm.md",
    "content": "# Globally Install Specific Version Of PNPM\n\nThere are several ways to install [`pnpm`](https://pnpm.io/). I prefer using\n`npm` because I already have it installed and it fits in with all the other\nglobal packages I have installed.\n\n```bash\nnpm install --location=global pnpm@7.13.4\n```\n\nThe `--location` flag tells `npm` to install it as a `global` package, rather\nthan as part of my current project.\n\nThe `@7.13.4` tacked onto the end of the `pnpm` package name is how I specify\nthe version of the package I am interested in.\n"
  },
  {
    "path": "javascript/immutable-remove-with-the-spread-operator.md",
    "content": "# Immutable Remove With The Spread Operator\n\nES6 introduces the [spread\noperator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator)\nwhich allows you to expand arrays in place for function calls, array\ncomposition, array destructuring, etc. One thing the spread operator allows\nyou to concisely do with array composition is perform immutable operations\non arrays. For instance, to remove an item from an array by index, you can\nthrow together the following function.\n\n```javascript\nconst remove = (items,index) => {\n  return [...items.slice(0,index),\n          ...items.slice(index+1,items.length)];\n};\n\nconst list = [1,2,3,4,5];\nremove(list, 2);\n// [1,2,3,4]\nlist\n// [1,2,3,4,5]\n```\n\nIt only took a couple lines of code and immutability is baked in.\n\nThere may be a couple edge cases that are not handled in this solution (e.g.\n`remove(list, -1)`), but you get the general idea.\n"
  },
  {
    "path": "javascript/initialize-a-new-javascript-project-with-yarn.md",
    "content": "# Initialize A New JavaScript Project With Yarn\n\nYarn, like NPM, has a basic command for initializing a new JavaScript\nproject.\n\n```\n$ yarn init\n```\n\nThis will ask you a number of questions about your project like the name and\nwhat kind of license you want to use. In the end, it just creates a\n`package.json` file which can be used with `yarn` or `npm`.\n"
  },
  {
    "path": "javascript/install-the-latest-version-of-node-with-nvm.md",
    "content": "# Install The Latest Version Of Node With Nvm\n\n[Nvm](https://github.com/creationix/nvm), the Node Version Manager, is a\ngreat way to manage multiple versions of Node.js on a machine. Run the\nfollowing command to get nvm to install the latest version of Node.js for\nyou.\n\n```bash\n$ nvm install node --reinstall-packages-from=node\n```\n\n[source](https://bytearcher.com/articles/ways-to-get-the-latest-node.js-version-on-a-mac/)\n"
  },
  {
    "path": "javascript/interpolate-a-string-into-a-regex.md",
    "content": "# Interpolate A String Into A Regex\n\nYou can build up strings with concatenation or the template literal syntax. If\nyou're incorporating variables as part of this string building, that's called\ninterpolation.\n\nBut what if you need to interpolate variables into a regular expression\n(regex)?\n\nA regex literal looks like this:\n\n```javascript\nconst myRegex = /^Some Customizable Text$/;\n```\n\nThis works great for fixed strings, but won't cut it if you need to work\n_variable_ strings.\n\nWhat's needed to work with variables is the\n[`RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp)\nconstructor:\n\n```javascript\nconst customizableString = \"Some Customizable Text\";\nconst myRegex = new RegExp(`^${customizableString}$`);\n```\n\nYou can build up some string with string variables and regex syntax and `new\nRegExp()` will turn it into a regex.\n\n[source](https://makandracards.com/makandra/15879-javascript-how-to-generate-a-regular-expression-from-a-string)\n"
  },
  {
    "path": "javascript/iso-8601-formatted-dates-are-interpreted-as-utc.md",
    "content": "# ISO-8601 Formatted Dates Are Interpreted As UTC\n\nUsing `new Date()` or `Date.parse()` with a string that represents a date is\na great way to create a `Date` object for a specified date. A variety of\nformats are accepted by these methods.\n\nBut, caution!\n\nThere are subtle differences in how those dates will be interpreted. Given\nany old string that reasonably represents a date, the date will be\ninterpreted using the local time zone, in my case `CST`.\n\n```javascript\n> new Date('2017-12-4')\nMon Dec 04 2017 00:00:00 GMT-0600 (CST)\n```\n\nHowever, as soon as we use an ISO-8601 compliant date format, ECMAScript 5\nspecifies that the date ought to be interpreted using the UTC time zone. As\nyou can see, the results are drastic enough to affect what day it comes out\nto.\n\n```javascript\n> new Date('2017-12-04')\nSun Dec 03 2017 18:00:00 GMT-0600 (CST)\n```\n\n[Source](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse#ECMAScript_5_ISO-8601_format_support)\n"
  },
  {
    "path": "javascript/link-a-javascript-package-locally.md",
    "content": "# Link A JavaScript Package Locally\n\nIf you are putting together a JavaScript package and you'd like to test it\nout locally before putting it on NPM, use `npm link`.\n\nFirst, from the directory of the package you are creating run:\n\n```bash\n$ npm link\n```\n\nThis will symlink the package to the global node modules directory.\n\nThen, from the base project directory that you want to try importing and\nusing the package from, run:\n\n```bash\n$ npm link name-of-package\n```\n\nThis will create an additional symlink from the global node modules\ndirectory to the `node_modules` of this target project.\n\nYou'll now have access to the project, try an `import` to get what you need\nand try it out.\n\nSee `man npm-link` for more details.\n"
  },
  {
    "path": "javascript/list-top-level-npm-dependencies.md",
    "content": "# List Top-Level NPM Dependencies\n\nThe `npm ls` command can be used to list all dependencies for a project.\nThis will, however, produce an exhaustive list of all dependencies including\ndependencies of dependencies. A list this large probably isn't going to be\nof much use.\n\nThe `--depth` flag allows you to restrict the depth of the dependency tree\nthat is generated.\n\n```bash\n$ npm ls --depth=0\n```\n\nThis will produce a list of only the top-level dependencies.\n\nSee `man npm-ls` for more details.\n"
  },
  {
    "path": "javascript/load-and-use-env-var-in-node-script.md",
    "content": "# Load And Use Env Var In Node Script\n\nThe node scripts defined under `scripts` in a `package.json` file can be used\nto do all sorts of handy development tasks for a project.\n\nThere are times where those scripts would be even more useful if they had\naccess to environment variables specified in the project's `.env` files.\n\nWith the help of [`dotenv-cli`](https://github.com/venthur/dotenv-cli) and\n[`cross-var`](https://github.com/elijahmanor/cross-var), we can load in and\nreference the project's env vars.\n\nAs an example, let's say our `.env` file has a `DATABASE_URL`:\n\n```\nDATABASE_URL=\"postgresql://postgres:postgres@localhost:5432/postgres\"\n```\n\nWe can create a node script in `package.json` that accesses that value like so:\n\n```json\n{\n  \"scripts\": {\n    \"db:url\": \"dotenv cross-var -- echo \\\"%DATABASE_URL%\\\"\"\n  }\n}\n```\n\nRunning that command will echo out the value:\n\n```bash\n❯ npm run db:url\n\n> db:url\n> dotenv cross-var -- echo \"%DATABASE_URL%\"\n\npostgresql://postgres:postgres@localhost:9876/postgres\n```\n\nYou could do something more useful with that value like open a `psql`\nconnection to that local database.\n\n[source](https://www.genui.com/resources/env-variables-json)\n"
  },
  {
    "path": "javascript/make-the-browser-editable-with-design-mode.md",
    "content": "# Make The Browser Editable With Design Mode\n\nModern browsers support a Web API called _Design Mode_. When you turn on\n_Design Mode_, you are able to edit the text on the web page like you would do\nin Word or Dreamweaver. This is a great way to experiment with copy.\n\nBy default it is `\"off\"`, but you can turn it on from your browser's devtools\nconsole.\n\n```\n> document.designMode = \"on\"\n\"on\"\n```\n\n[source](https://developer.mozilla.org/en-US/docs/Web/API/Document/designMode)\n"
  },
  {
    "path": "javascript/make-truly-deep-clone-with-structured-clone.md",
    "content": "# Make Truly Deep Clone With Structured Clone\n\nThere are a lot of ways to make a copy of an object. They are all hacks and\nthey all fail in certain circumstances. Using the spread trick only gives you a\nshallow copy where references to nested objects and arrays can still be\nupdated. The `JSON.stringify` trick has to make things like dates into strings,\nso it is lossy.\n\nThere is however now a dedicated method for deep copies with broad support\ncalled\n[`structuredClone`](https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone).\nIt is available on `window`. Let's take a look at it and see how it comparse to\nthe spread operator trick.\n\n```javascript\n> // some data setup\n\n> const data = { one: 1, two: 2, rest: [3,4,5] }\n\n> const obj = { hello: 'world', taco: 'bell', data }\n\n> const shallowObj = { ...obj }\n\n> const deepObj = structuredClone(obj)\n\n> // let's modify the original `data.rest` array\n\n> data.rest.push(6)\n4\n> data\n{ one: 1, two: 2, rest: [ 3, 4, 5, 6 ] }\n\n> // now let's see who was impacted by that mutation\n\n> obj\n{\n  hello: 'world',\n  taco: 'bell',\n  data: { one: 1, two: 2, rest: [ 3, 4, 5, 6 ] }\n}\n\n> shallowObj\n{\n  hello: 'world',\n  taco: 'bell',\n  data: { one: 1, two: 2, rest: [ 3, 4, 5, 6 ] }\n}\n\n> deepObj\n{\n  hello: 'world',\n  taco: 'bell',\n  data: { one: 1, two: 2, rest: [ 3, 4, 5 ] }\n}\n```\n\nThe `shallowObj` from the spread operator copy was mutated even though we\ndidn't intend for that. The `deepObj` from `structuredClone` was a true deep\ncopy and was unaffected.\n\n[source](https://www.builder.io/blog/structured-clone)\n"
  },
  {
    "path": "javascript/matching-a-computed-property-in-function-args.md",
    "content": "# Matching A Computed Property In Function Args\n\nThe [computed property name](http://es6-features.org/#ComputedPropertyNames)\nfeature of ES6 allows you to reference a variable in object assignments and\ndestructurings. This syntax is flexible enough that it can be used in the\narguments portion of a function declaration. In fact, it can even be matched\nagainst another argument -- allowing the creation of some handy, yet terse\nfunctions.\n\n```javascript\nconst get = (key, { [key]: foundValue }) => foundValue;\n```\n\nNotice that the first argument, `key`, will match against the computed\nproperty name in the second argument. The `foundValue` will correspond to\nwhatever `key` maps to in the given object.\n\nThis `get` function can then be used like so.\n\n```javascript\nconst stuff = { a: 1, b: 2, c: 3 };\n\nconsole.log(\"Get a:\", get(\"a\", stuff)); // Get a: 1\nconsole.log(\"Get d:\", get(\"d\", stuff)); // Get d: undefined\n```\n\nh/t\n[@sharifsbeat](https://twitter.com/sharifsbeat/status/1084235020183748610)\n"
  },
  {
    "path": "javascript/matching-multiple-values-in-a-switch-statement.md",
    "content": "# Matching Multiple Values In A Switch Statement\n\nSwitch statements are a handy way to execute different branches of code\nbased on a value match. This is often what is used in Redux reducers when\nupdating the state in response to certain actions.\n\nBut what if you need multiple values to result in the same branch of\nexecution without duplicating the code?\n\nThe execution of a switch statement falls through, so after one match, it\nwill continue to try and do subsequent matches if you don't interrupt the\nexecution with a `break` or `return`. Conveniently, this solves our problem\nof matching multiple values.\n\n```javascript\nswitch (action.type) {\n  case \"UPDATE_NAME\":\n  case \"UPDATE_DURATION\":\n    let newData = anotherReducer(state.data, action);\n    return { ...state, data: newData };\n  default:\n    return state;\n}\n```\n\nSee the [MDN\ndocs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch)\nfor more details.\n"
  },
  {
    "path": "javascript/mock-a-function-with-return-values-using-jest.md",
    "content": "# Mock A Function With Return Values Using Jest\n\n[Jest](https://facebook.github.io/jest/) provides a collection of utilities\nfor working with mocked functions.  To create a mock function, do:\n\n```javascript\njest.fn()\n\n// assign it to a variable\nconst fakeFunc = jest.fn();\n\n// pass it as a prop\n<SpecialInput handleChange={jest.fn()} />\n```\n\nA mocked function can then be attributed with a return value.\n\n```javascript\nconst fakeFunc = jest.fn();\nfakeFunc.mockReturnValue(\"hello\");\nfakeFunc(); // => \"hello\"\n```\n\nThe\n[`mockReturnValue()`](https://facebook.github.io/jest/docs/en/mock-function-api.html#mockfnmockreturnvaluevalue)\nfunction ensures that the value is returned whenever your function is\ncalled.\n\nWe can also limit the return value to occurring just once.\n\n```javascript\nconst fakeFunc = jest.fn();\nfakeFunc.mockReturnValueOnce(\"hello\");\nfakeFunc(); // => \"hello\"\nfakeFunc(); // => null\n```\n\n[`mockReturnValueOnce()`](https://facebook.github.io/jest/docs/en/mock-function-api.html#mockfnmockreturnvalueoncevalue)\nensures the value is returned once and all subsequent calls yield `null`.\n"
  },
  {
    "path": "javascript/new-dates-can-take-out-of-bounds-values.md",
    "content": "# New Dates Can Take Out Of Bounds Values\n\nYou can create a new date by feeding it arguments for _year_, _month_, and\n_day_.\n\n```javascript\n> new Date(2017, 11, 31)\nSun Dec 31 2017 00:00:00 GMT-0600 (CST)\n```\n\nWhat happens if we push the _day_ value out of bounds?\n\n```javascript\n> new Date(2017, 11, 32)\nMon Jan 01 2018 00:00:00 GMT-0600 (CST)\n```\n\nIt rolls over to the next month.\n\nDoes the same happen when we push the _month_ value out of bounds?\n\n```javascript\n> new Date(2017, 12, 31)\nWed Jan 31 2018 00:00:00 GMT-0600 (CST)\n```\n\nYep.\n\nWhat about negative values?\n\n```javascript\n> new Date(2018, -1, 31)\nSun Dec 31 2017 00:00:00 GMT-0600 (CST)\n```\n\nIt rolls the month, and consequently the year, back.\n"
  },
  {
    "path": "javascript/numbers-are-empty.md",
    "content": "# Numbers Are Empty\n\nThe [`lodash`](https://lodash.com/) project comes with a ton of handy\nJavaScript utilities including the\n[`_.isEmpty()`](https://lodash.com/docs#isEmpty) function. This is great for\nchecking if Arrays, Objects, and Strings are _empty_. The following is how\nthis function is defined in the docs:\n\n> Checks if value is an empty collection or object. A value is considered\n> empty if it's an arguments object, array, string, or jQuery-like\n> collection with a length of 0 or has no own enumerable properties.\n\nHaving not examined this definition too closely and because I primarily\nwrite Rails code from day to day, I conflated `_.isEmpty()` with the\n`#blank?` method provided by Rails' `ActiveSupport`. This holds true for the\nmost part, but quickly defies expectations when it comes to numbers.\n\n```javascript\n> _.isEmpty(1)\n// true\n```\n"
  },
  {
    "path": "javascript/object-initialization-with-shorthand-property-names.md",
    "content": "# Object Initialization With Shorthand Property Names\n\nIf I have some variables:\n\n```javascript\nconst one = 1,\n  two = 2,\n  three = 3;\n```\n\nand I'd like to initialize an object with them, I'll generally do something\nlike the following:\n\n```javascript\nconst obj1 = {\n  one: one,\n  two: two,\n  three: three\n};\n// Object { one: 1, two: 2, three: 3 }\n```\n\nThat seems pretty standard, but with ES6 comes a feature called *shorthand\nproperty names* which makes that look verbose and redundant. If you already\nhave properly named variables, they can be used as a short hand for both the\nkey name and variable value:\n\n```javascript\nconst obj2 = {\n  one,\n  two,\n  three\n};\n// Object { one: 1, two: 2, three: 3 }\n```\n\nSee the [MDN Docs for Object\nInitializer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer)\nfor more details.\n"
  },
  {
    "path": "javascript/obtain-undefined-value-with-the-void-operator.md",
    "content": "# Obtain Undefined Value With The Void Operator\n\nThe [`void`\noperator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void)\ntakes any expression, evaluates it, and then results in the `undefined` value.\nA common use of the `void` operator is to get the primitive `undefined` value\nin a consistent way.\n\n```javascript\n> void(0);\nundefined\n```\n\nThis is handy for instances where you need to check if a value is `undefined`:\n\n```javascript\nfunction doSomething({ arg }) {\n  if (arg === void 0) {\n    throw new Error(\"arg is undefined 😱\");\n  }\n\n  // ...\n};\n```\n"
  },
  {
    "path": "javascript/open-global-npm-config-file.md",
    "content": "# Open Global npm Config File\n\nThere are a ton of configuration settings for `npm`. I can open up the global\n`npmrc` file where those configs live with the following command:\n\n```bash\n$ npm config edit --global\n```\n\nThis will open up the file in my default editor (e.g. `vim`).\n\nThere are over 100 settings that are commented out with their default values. I\ncan override these as needed by uncommenting them and setting them to the\ndesired value.\n\nThere is some useful info in the first few lines:\n\n```\n;;;;\n; npm globalconfig file: /Users/me/.asdf/installs/nodejs/20.10.0/etc/npmrc\n; this is a simple ini-formatted file\n; lines that start with semi-colons are comments\n; run `npm help 7 config` for documentation of the various options\n```\n\n1. I can see that the location of the file is specific to the version of node\n   that I current have shimmed. In this case, it's `20.10.0`. If I switch node\n   versions, there will be a different `envrc` to configure.\n\n2. I can get more info about these config values by running `npm help 7 config`.\n"
  },
  {
    "path": "javascript/parse-a-date-from-a-timestamp.md",
    "content": "# Parse A Date From A Timestamp\n\nIf you are given a timestamp ([seconds since the Unix\nepoch](https://stackoverflow.com/a/20823376/535590)) and you try to parse it\nwith [JavaScript's `new\nDate()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date),\nyou are going to get a suprising result.\n\n```javascript\n> new Date(1618499080)\nMon Jan 19 1970 11:34:59 GMT-0600 (Central Standard Time)\n```\n\n1970? I was expected something more in the current millenia.\n\nThis is because JavaScript's `new Date()` expects a timestamp to be in milliseconds. Passing in a seconds representation of a timestamp, when it should be milliseconds, is going to result in a time pretty near the original Unix epoch.\n\nInstead what you need to do is multiple that _seconds_ value by `1000` to get\nit in terms of milliseconds.\n\n```javascript\n> new Date(1618499080 * 1000)\nThu Apr 15 2021 10:04:40 GMT-0500 (Central Daylight Time)\n```\n\nAlso, notice that if I run [`+ new\nDate()`](https://stackoverflow.com/a/221297/535590) without any argument, it\nprovides the current timestamp in milliseconds.\n\n```javascript\n> + new Date()\n1618499080598\n```\n"
  },
  {
    "path": "javascript/pre-and-post-hooks-for-yarn-scripts.md",
    "content": "# Pre And Post Hooks For Yarn Scripts\n\nIn [yarn](https://classic.yarnpkg.com/) v1, there is a special syntax for\nscript names that allows you to define pre and post hooks.\n\nFor instance, if you have a `build` script, you can define a `prebuild` and/or\na `postbuild` script as well. Then, anytime you invoke `yarn build`, the\n`prebuild` script will be automatically run before `build` and the `postbuild`\nscript be automatically run after `build`.\n\nThis `pre{script}` and `post{script}` syntax works for any script.\n\n```json\n{\n  \"scripts\": {\n    \"predeploy\": \"node pre-deploy-steps\"\n    \"deploy\": \"my-framework deploy\",\n    \"postdeploy\": \"node post-deploy-steps\"\n  }\n}\n```\n\nThis syntax may lead to unexpected script invocations. For instance, a\n`preserve` script will run ahead of a `serve` script even though those were\nprobably intended to be unrelated scripts. This is, in part, why this syntax is\nno longer support in yarn v2.\n\n[source](https://classic.yarnpkg.com/lang/en/docs/cli/run/#toc-yarn-run-script)\n"
  },
  {
    "path": "javascript/prevent-hidden-element-from-flickering-on-load.md",
    "content": "# Prevent Hidden Element From Flickering On Load\n\nHere is what it might look like to use [Alpine.js](https://alpinejs.dev/) to\nsprinkle in some JavaScript for controlling a dropdown menu.\n\n```html\n<div x-data=\"{ profileDropdownOpen: false }\">\n  <button\n    type=\"button\"\n    @click=\"profileDropdownOpen = !profileDropdownOpen\"\n  >\n    <!-- some inner html -->\n  </button>\n  <div x-show=\"profileDropdownOpen\" role=\"menu\">\n    <a href=\"/profile\" role=\"menuitem\">Your Profile</a>\n    <a href=\"/sign-out\" role=\"menuitem\">Sign Out</a>\n  </div>\n</div>\n```\n\nFunctionally that will work. You can click the button to toggle the menu open\nand closed.\n\nWhat you might notice, however, when you refresh the page is that the menu\nflickers open as the page first loads and then disappears. This is a quirk of\nthe element being rendered before Alpine.js is loaded and the\n[`x-show`](https://alpinejs.dev/directives/show) directive has a chance to take\neffect.\n\nTo get around this, we can _cloak_ any element with an `x-show` directive that\nshould be hidden by default.\n\n```html\n<div x-data=\"{ profileDropdownOpen: false }\">\n  <button\n    type=\"button\"\n    @click=\"profileDropdownOpen = !profileDropdownOpen\"\n  >\n    <!-- some inner html -->\n  </button>\n  <div x-cloak x-show=\"profileDropdownOpen\" role=\"menu\">\n    <a href=\"/profile\" role=\"menuitem\">Your Profile</a>\n    <a href=\"/sign-out\" role=\"menuitem\">Sign Out</a>\n  </div>\n</div>\n```\n\nThis addition needs to be paired with some custom CSS to hide any _cloaked_\nelements.\n\n```css\n[x-cloak] { display: none !important; }\n```\n\n[source](https://alpinejs.dev/directives/cloak)\n"
  },
  {
    "path": "javascript/purge-null-and-undefined-values-from-object.md",
    "content": "# Purge Null And Undefined Values From Object\n\nThe low-level utilities provided by [`lodash`](https://lodash.com/) offer a\ncouple ways to remove all the `null` and `undefined` values from an object.\n\nFirst, here is an object that I want to _compact_ by removing all `nil` (`null`\nand `undefined`) values.\n\n```javascript\nconst data = {\n  hello: 'world',\n  list: [1,2,3],\n  status: undefined,\n  published_at: null,\n  points: 0\n}\n```\n\nOne method of doing this is with the [`_.pickBy`\nfunction](https://lodash.com/docs/4.17.15#pickBy).\n\n```javascript\n> _.pickBy(data)\n//=> { hello: 'world', list: [1,2,3] }\n```\n\nBecause it defaults to picking _truthy_ values, the `points: 0` is also going\nto be stripped out.\n\nAnother method which allows us to more directly target just `null` and\n`undefined` uses [`_.omitBy`](https://lodash.com/docs/4.17.15#omitBy) and\n[`_.isNil`](https://lodash.com/docs/4.17.15#isNil).\n\n```javascript\n> _.omitBy(data, _.isNil)\n//=> { hello: 'world', list: [1,2,3], points: 0 }\n```\n\nNotice this approach only removes the `null` and `undefined` key-value pairs.\nThe `points: 0` is left in.\n"
  },
  {
    "path": "javascript/random-cannot-be-seeded.md",
    "content": "# Random Cannot Be Seeded\n\nIn JavaScript, you can use `Math.random()` to get a *sorta* random value.\n\n```javascript\n> Math.random()\n0.5130641541909426\n```\n\nMost programming languages give you a method of seeding the random number\ngenerator for determinism. Unfortunately, JavaScript provides no way for\nchoosing or resetting the seed to `Math.random()`.\n\n[source](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random)\n"
  },
  {
    "path": "javascript/reach-into-an-object-for-nested-data-with-get.md",
    "content": "# Reach Into An Object For Nested Data With Get\n\nAmong the many [lodash](https://lodash.com/) utilities is\n[`_.get`](https://lodash.com/docs/4.17.5#get) for getting data from nested\nobjects. You can specify where to reach into the nested data of an object\nusing a _path_.\n\nConsider the following awkwardly nested object:\n\n```javascript\nconst resp = {\n  error: {\n    errors: [\n      { message: \"Something went wrong\" },\n    ],\n  },\n};\n```\n\nHere is how we might reach into this with vanilla JavaScript:\n\n```javascript\nresp.error.errors[0].message;\n```\n\nReaching into this for the `message` value is tricky because as soon as the\n`resp` object contains differently nested data, an error is likely to be\nthrown. We can simultaneously avoid a bunch of exception handling logic and\nprovide a default value with the `_.get` function:\n\n```javascript\n_.get(resp, 'error.errors[0].message', 'Default error message');\n```\n\nIf we decide to not include a default value, then `undefined` will be used.\n"
  },
  {
    "path": "javascript/render-an-array-of-elements-with-react-16.md",
    "content": "# Render An Array Of Elements With React 16\n\n[React 16 was released\ntoday](https://facebook.github.io/react/blog/2017/09/26/react-v16.0.html).\nAmong many exciting features and updates is support for rendering an array\nof elements.\n\nThis can look as simple as this example:\n\n```javascript\nreturn [\n  <li key=\"1\">One</li>,\n  <li key=\"2\">Two</li>,\n  <li key=\"3\">Three</li>\n];\n```\n\nIt really shines in the case of generating elements from an array of data.\n\n```javascript\nlet data = [\n  { value: \"One\", key: \"1\" },\n  { value: \"Two\", key: \"2\" },\n  { value: \"Three\", key: \"3\" }\n];\nreturn data.map(item => {\n  return (\n    <li key={item.key}>\n      {item.value}\n    </li>\n  );\n});\n```\n\nNo need to wrap the result in a `<div>`!\n\n[source](https://facebook.github.io/react/docs/react-component.html#render)\n"
  },
  {
    "path": "javascript/resolve-and-pass-multiple-values-from-a-then.md",
    "content": "# Resolve And Pass Multiple Values From A Then\n\nLet's say you are chaining multiple async function calls together.\n\n```javascript\nfetchTrainer(trainerName)\n  .then(response => {\n    const trainerData = response.body;\n\n    return fetchPokemonFor({ trainerId: trainerData.id });\n  })\n  .then(response => {\n    // I want trainerData, but it is now out of scope...\n  });\n```\n\nBut in the last `then()` you want access to both the `trainerData` and the\n`pokemonData`. So, how do you pass both the `trainerData` and the resolved\nresponse of `fetchPokemonFor()` through to that last `then()`.\n\n```javascript\nfetchTrainer(trainerName)\n  .then(response => {\n    const trainerData = response.body;\n\n    return Promise.all([\n      trainerData,\n      fetchPokemonFor({ trainerId: trainerData.id })\n    ]);\n  })\n  .then(([trainerData, pokemonResponse]) => {\n    const pokemonData = pokemonResponse.body;\n\n    // do something with trainerData and pokemonData\n  });\n```\n\n`Promise.all` allows us to resolve and pass multiple promises. If any of the\nvalues in the array argument is not a promise, it simply passes it through.\n\nh/t Brian Dunn\n"
  },
  {
    "path": "javascript/run-a-bash-script-from-a-node-script.md",
    "content": "# Run A Bash Script From A Node Script\n\nA node script in `package.json` can reference and run any command or executable\nscript available on our system. This is why we're able to have node scripts\nthat do things like run a linter or start a web server.\n\nWe can take this a step further by defining our own scripts to enhance our\ndevelopment and CI environments.\n\nFor instance, let's say we have the following bash script (`check-stripe`) in\nour project's `scripts` directory for checking that we are connected to the\nright Stripe account.\n\n```bash\n#!/bin/bash\n\n# Expected stripe display name\nEXPECTED_STRING=\"My Online Product\"\n\n# Currently connected stripe display name\nCOMMAND_OUTPUT=$(\n\tstripe config --list | grep '^display_name' | awk -F'=' '{print $2}' | xargs\n)\n\n# Compare the expected string with the command output\nif [ \"$EXPECTED_STRING\" = \"$COMMAND_OUTPUT\" ]; then\n    exit 0\nelse\n    echo \"Mismatched Stripe accounts, expected $EXPECTED_STRING, got $COMMAND_OUTPUT.\"\n    exit 1\nfi\n```\n\nThis script exits with either a successful (`0`) or failed (`1`) status. We can\nuse this in our node script to guard another command from getting run.\n\n```json\n{\n  \"scripts\": {\n    \"dev:stripe\": \"./scripts/check-stripe && stripe listen ...\"\n  }\n}\n```\n"
  },
  {
    "path": "javascript/run-multiple-node-scripts-concurrently.md",
    "content": "# Run Multiple Node Scripts Concurrently\n\nThe [`concurrently` npm\npackage](https://github.com/open-cli-tools/concurrently) is a CLI for\nconcurrently running multiple commands or scripts. This is great for working in\nthe context of a web server development where you often need several pieces of\ninfrastructure running locally at once.\n\nAssuming you have the `concurrently` package installed and there are several\ndev scripts in your `package.json`, here is one way this could look:\n\n```json\n{\n  \"scripts\": {\n    \"dev\": \"concurrently \\\"npm run dev:next\\\" \\\"npm run dev:inngest\\\" \\\"npm run dev:mailhog\\\"\",\n    \"dev:next\": \"next dev\",\n    \"dev:inngest\": \"pnpx inngest-cli@latest dev\",\n    \"dev:mailhog\": \"mailhog\",\n  }\n}\n```\n\nRunning `npm run dev` would start a process that runs all three commands and\ncombines their output.\n\nA shorthand way of writing this since these commands all have the same prefix\nis:\n\n```json\n{\n  \"scripts\": {\n    \"dev\": \"concurrently \\\"npm:dev:*\\\"\",\n    \"dev:next\": \"next dev\",\n    \"dev:inngest\": \"pnpx inngest-cli@latest dev\",\n    \"dev:mailhog\": \"mailhog\",\n  }\n}\n```\n"
  },
  {
    "path": "javascript/running-es6-specs-with-mocha.md",
    "content": "# Running ES6 Specs With Mocha\n\nIf your JavaScript specs contain ES6 syntax, [Mocha](https://mochajs.org/),\nby default, will not be able to interpret and run them. In order to run them\nwith Mocha, you will need to tell Mocha to use something like\n[Babel](http://babeljs.io/) to compile them. The `--compile` flag can be\nused to point Mocha to the `babel-core/register` package.\n\n```\n$ mocha --compilers js:babel-core/register path/to/specs/*.spec.js\n```\n\nIf you already have a test command specified in your `package.json` file,\nyou can update it with the `--compile` portion of the above command.\n\nThis all assumes you've already setup your project with Babel and Babel\npresets.\n\n[source](http://jamesknelson.com/testing-in-es6-with-mocha-and-babel-6/)\n"
  },
  {
    "path": "javascript/scoping-variables-with-a-block-statement.md",
    "content": "# Scoping Variables With A Block Statement\n\nA solid way to keep code readable and easy to understand is to ditch the\nterse one-liners in favor of breaking things up across multiple lines and\nusing self-documenting variable names. This isn't all good though. Each new\nvariable that is defined is a handle on some data that can be misused later\nin the syntax scope.\n\nJavaScript has a nice way of being clear about the scope of certain\nvariables:\n\n```javascript\nlet parsedDate;\n{\n  let [month, day, year] = input.split('-');\n  parsedDate = new Date(year, month, day);\n}\n\n// do something with parsedDate\n```\n\nThe `month`, `day`, and `year` variables are scoped to the `{ ... }` which\nis a [block\nstatement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/block).\nThis helps communicate and enforce that those variables are only to be used\nin that very specific context. Other developers and our future selves won't\nbe able to erroneously use those variables.\n\nOf course, breaking out a function is another way of accomplishing this.\nSequestering code in a different part of the file is not always the best\nanswer though. Sometimes you want it locally fenced off. For those times,\nuse a block statement.\n"
  },
  {
    "path": "javascript/short-circuit-concurrently-when-process-fails.md",
    "content": "# Short Circuit Concurrently When Process Fails\n\nIn [Run Multiple Node Scripts\nConcurrently](run-multiple-node-scripts-concurrently.md), I showed how we can\nget all the essential processes of our web app running concurrently in\ndevelopment using the `concurrently` package.\n\nBut what happens when there is an error and one of them exits early instead of\ncontinuing to run?\n\nWell, the rest of the processes under the `concurrently` umbrella continue to\nrun as if nothing has happened. In fact, if there is enough output, you might\neven miss that that one process failed since the error gets quickly pushed off\nthe screen.\n\nIf we need every process running for our app to work, then it would be better\nto have the whole set of concurrent processes short circuit and exit early if\none fails. We can do that by giving `concurrently` the `--kill-others-on-fail`\nflag.\n\n```json\n{\n  \"scripts\": {\n    \"dev\": \"concurrently --kill-others-on-fail \\\"npm:dev:*\\\"\",\n    \"dev:next\": \"next dev\",\n    \"dev:inngest\": \"pnpx inngest-cli@latest dev\",\n    \"dev:mailhog\": \"mailhog\",\n  }\n}\n```\n\nSee the [Usage\nsection](https://github.com/open-cli-tools/concurrently?tab=readme-ov-file#usage)\nof the docs for more details.\n"
  },
  {
    "path": "javascript/show-description-of-all-npm-config-options.md",
    "content": "# Show Description Of All npm Config Options\n\nIn [Open Global npm Config File](open-global-npm-config-file.md), I showed how\nyou can access and modify the current npm config. The thing that stands out in\nthat file is the sheer number of config options.\n\nWhat do they all mean?\n\nTo get \"more than you probably want to know about npm configuration\", open up\nthe npm config help with the following command:\n\n```bash\n$ npm help 7 config\n```\n\nThere are a ton, so browse at your own peril. You'll notice that each option\nlists its default value, the type of that value, and a description about usage.\n"
  },
  {
    "path": "javascript/sleep-for-a-bit-in-async-code.md",
    "content": "# Sleep For A Bit In Async Code\n\nA `sleep` utility function can be useful in a variety of situations. From\ntesting and debugging to simulating a delay in development.\n\nHere is what that function can look like in its simplest form:\n\n```javascript\nfunction sleep(time) {\n  return new Promise((resolve) => {\n    setTimeout(resolve, time)\n  })\n}\n```\n\nThis function returns a promise that will resolve after the given number of\nmilliseconds.\n\nAs an example of how to use it, here is how we can simulate a delay in a fake\nfetch function.\n\n```javascript\nasync function fakeUserFetch(userId) {\n  # add half a second of \"network\" latency\n  await sleep(500)\n\n  const fakeResponse = {\n    id: userId,\n    email: \"fake-email@example.com\"\n  }\n\n  return Promise.resolve(fakeResponse)\n}\n```\n\n[source](https://stackoverflow.com/a/951057/535590)\n"
  },
  {
    "path": "javascript/sorting-arrays-of-objects-with-lodash.md",
    "content": "# Sorting Arrays Of Objects With Lodash\n\nThe [`lodash`](https://lodash.com/) library comes with a couple functions for\nsorting collections of objects --\n[`sortBy`](https://lodash.com/docs/4.17.15#sortBy) and\n[`orderBy`](https://lodash.com/docs/4.17.15#orderBy).\n\nConsider the following collection of pokemon:\n\n```javascript\nconst pokemon = [\n  { name: \"Pikachu\", level: 12 },\n  { name: \"Charmander\", level: 12 },\n  { name: \"Squirtle\", level: 15 },\n  { name: \"Bulbasaur\", level: 11 }\n];\n```\n\nThis collection can be sorted in ascending order by the value of a key in the\nobject using `sortBy`.\n\n```javascript\nimport _sortBy from \"lodash/sortBy\";\n\n_sortBy(pokemon, [\"level\"]);\n```\n\nIf you want to control whether the sorting is in ascending or descending order,\nuse `orderBy`.\n\n```javascript\nimport _orderBy from \"lodash/orderBy\";\n\n_orderBy(pokemon, [\"level\"], [\"desc\"]);\n```\n\nYou can also do sorting with primary and secondary keys by including two values\nin the key sort array.\n\n```javascript\nimport _sortBy from \"lodash/sortBy\";\n\n_sortBy(pokemon, [\"name\", \"level\"]);\n```\n\nAnd if you want to indpendently control ascending/descending for these as well,\nyou can.\n\n```javascript\nimport _orderBy from \"lodash/orderBy\";\n\n_orderBy(pokemon, [\"level\", \"name\"], [\"desc\", \"asc\"]);\n```\n\nCheck out the [live example](https://codesandbox.io/s/jolly-ardinghelli-cem7t)\nto see it in action.\n"
  },
  {
    "path": "javascript/splat-arguments-to-a-function.md",
    "content": "# Splat Arguments To A Function\n\nOften times you have a function that takes a certain set of arguments. Like\nthe following `adder` function:\n\n```javascript\nvar adder = function(a,b,c) {\n  return a + b + c;\n};\n```\n\nBut you are left trying to pass in arguments as an array (e.g. `[1,2,3]`).\nYou want to be able to *splat* the array of arguments so that it matches the\nfunction declaration. This can be done by using `apply`.\n\n```javascript\n> adder.apply(undefined, [1,2,3])\n6\n```\n"
  },
  {
    "path": "javascript/spread-merging-objects-includes-nil-values.md",
    "content": "# Spread Merging Objects Includes Nil Values\n\nA handy way to merge two objects together with ES6 JavaScript syntax is to use\nthe [spread\noperator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax).\n\n```javascript\nconst combinedObj = { ...obj1, ...obj2 };\n```\n\nAll the key-value pairs from each object are combined into a new object. For\nany overlapping keys, the last occurrence's value will take precedence.\n\nThat bit about precedence is true for _nil_ values – `null` and `undefined` –\nas well.\n\n```javascript\nconst obj1 = { taco: 'bell', hello: 'world', list: [1,2,3] }\nconst obj2 = { burrito: 'house', hello: null, list: undefined }\n\nconst combinedObj = { ...obj1, ...obj2 }\n//=> { taco: 'bell', hello: null, list: undefined, burrito: 'house' }\n```\n\nNotice that even though there are \"actual\" values for the `hello` and `list`\nkeys in `obj1`, they are overridden by the `null` and `undefined` values in\n`obj2`.\n"
  },
  {
    "path": "javascript/spread-the-rest-with-es6.md",
    "content": "# Spread The Rest With ES6\n\nThe spread operator provided by ES6 is a powerful syntactic feature. One way\nit can be used is to capture the _rest_ of an object or array in a variable.\n\n```javascript\nconst pokemon = [\"Charmander\", \"Squirtle\", \"Bulbasaur\"];\nconst [first, ...rest] = pokemon;\n\nconsole.log(\"Remaining: \", rest); // Remaining: [\"Squirtle\", \"Bulbasaur\"]\n\nconst gymLeaders = {\n  brock: \"rock\",\n  misty: \"water\",\n  surge: \"electric\",\n  erika: \"grass\"\n};\nlet { brock, erika, ...otherLeaders } = gymLeaders;\n\nconsole.log(otherLeaders); // Object {misty: \"water\", surge: \"electric\"}\n```\n\nUsing this spread destructuring we can capture the remaining parts of an\narray or object in a variable. We can also use this syntax in a function\nsignature to grab specific items from an incoming object argument without\nlosing track of the rest -- this is especially useful in React.js\ndevelopment when dealing with incoming props.\n\nThis is a [stage 4\nfeature](https://github.com/tc39/proposal-object-rest-spread) and may not be\navailable in your particular environment.\n\nSee a [live example here](https://codesandbox.io/s/ov2xr1o12y).\n"
  },
  {
    "path": "javascript/start-node-process-in-specific-timezone.md",
    "content": "# Start Node Process In Specific Timezone\n\nWhen running a node process on your machine locally, it will adopt your\nmachine's local timezone.\n\nI can observe this by starting a `node` process and outputting a date with\n`toLocaleString()`.\n\n```javascript\n> new Date().toLocaleString()\n'11/30/2020, 8:48:17 PM'\n```\n\nThis is the time that I'm writing this post, in Chicago (CST).\n\nI can then start the process in another timezone, such as UTC.\n\n```bash\n$ TZ=utc node\n```\n\nWith that `node` process, I can now do the same experiment.\n\n```javascript\n> new Date().toLocaleString()\n'12/1/2020, 2:52:40 AM'\n```\n\nThe time jumps ahead about 6 hours because it is going from CST (UTC-6) to UTC.\n\nSimilarly, I could start the Node process for the west coast like so,\n\n```bash\n$ TZ='America/Los_Angeles' node\n```\n"
  },
  {
    "path": "javascript/string-interpolation-with-template-literals.md",
    "content": "# String Interpolation With Template Literals\n\nES6 adds support for [template\nliterals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals).\nTemplate literals make it much easier to compose strings of content --\nstring interpolation. They allow for single and double quotes without having\nto fuss with escaping.  Embedded expressions are also supported which means\nyou can avoid awkward-to-type string concatenation with the `+` operator.\n\nHere is an example:\n\n```javascript\n> let movie = 'it'\nundefined\n> `What's up, I just saw \"${movie.toUpperCase()}\".`\n\"What's up, I just saw \"IT\".\"\n```\n"
  },
  {
    "path": "javascript/support-nested-matching-in-custom-jest-matchers.md",
    "content": "# Support Nested Matching In Custom Jest Matchers\n\nA [custom Jest matcher](define-a-custom-jest-matcher) can use standard\nJavaScript operations to evaluate if the given value(s) should pass or not.\n\n```javascript\nexpect.extend({\n  toContainValue(receivedArray, containedValue) {\n    const pass =\n      receivedArray.some(value => value === containedValue);\n\n    // return formatted pass/not-pass objects with messages\n    return { ... }\n  }\n});\n```\n\nThis approach alone doesn't support the power of Jest's nested matchers.\nConsider trying to use this like so:\n\n```javascript\nexpect(['a', 2, true]).toContainValue(expect.any(Number));\n```\n\nThis would fail, even though there is a value in there that matches\n`any(Number)`.\n\nJest ships with some [Jasmine](https://jasmine.github.io/) utilities that you\ncan use, just as Jest does internally, to perform nested matching:\n\n```javascript\nconst { equals } = require(\"expect/build/jasmineUtils\");\n\nexpect.extend({\n  toContainValue(receivedArray, containedValue) {\n    const pass =\n      receivedArray.some(value => equals(value, containedValue));\n\n    // return formatted pass/not-pass objects with messages\n    return { ... }\n  }\n});\n```\n\nThat `equals` utility knows how to compare raw values like integers, booleans,\nand even whole objects against nested `expect` matchers.\n\n[source](https://github.com/facebook/jest/issues/8295#issuecomment-482545274)\n"
  },
  {
    "path": "javascript/tell-jest-to-focus-on-running-only-one-test.md",
    "content": "# Tell Jest To Focus On Running Only One Test\n\nTest output can be noisy. Sometimes one test is inadvertently dependent on\nanother. These are some of the reasons you may want to tell\n[Jest](https://jestjs.io/) to focus in and only run one particular `test`\nblock.\n\nYou can do this by calling\n[`test.only()`](https://jestjs.io/docs/setup-teardown#general-advice) instead\nof `test()`.\n\nFind the test block you are interested in focusing on and update it to look\nlike this:\n\n```javascript\n// tests above ...\n\ntest.only('ensure the function returns the value', () => {\n  // ...\n  // test implementation\n  // ...\n})\n\n// tests below ...\n```\n\nWith that 5-character addition (`.only`) we instruct Jest to run that one test\nwhile skipping all others.\n\nThis is particularly useful when you are doing some `console.log` debugging of\na test. You can eliminate any confusion about which test is logging out by only\nrunning one test.\n\n[source](https://stackoverflow.com/a/42828586/535590)\n"
  },
  {
    "path": "javascript/tell-node-to-treat-js-files-as-esm.md",
    "content": "# Tell Node To Treat JS Files As ESM\n\nBy default, Node will treat all `.js` files as CommonJS. That means you'll need\nto use the CommonJS export and require syntax to share code between files. If\nyou'd instead like to opt-in to ESM (ECMAScript Modules), you'll need to update\nyour `package.json`.\n\nAdd the following line:\n\n```json\n\"type\": \"module\",\n```\n\nThis will tell node that instead of CJS, it should treat all `.js` files as\nESM. This means that ESM-based `export` and `import` syntax will work.\n\nThis also means you don't need to be defining your files with the `.mjs`\nextension.\n\nFor more extensive reading on this, see:\n\n- [ECMAScript Modules in Node.js](https://www.typescriptlang.org/docs/handbook/esm-node.html)\n- [Getting Started with (and Surviving) Node.js ESM](https://formidable.com/blog/2021/node-esm-and-exports/)\n- [`.mts` is a cool file extension (TypeScript ES modules)](https://mtsknn.fi/blog/mts-file-extension/)\n"
  },
  {
    "path": "javascript/tell-prettier-to-not-format-a-statement.md",
    "content": "# Tell Prettier To Not Format A Statement\n\n[Prettier](https://prettier.io/) is a boon to productivity because individuals\nand teams don't have to make any decisions about the fine details of how their\ncode is formatted. Generally, let `prettier` do its thing.\n\nThere are some situations where you want to preserve your own formatting,\nespecially if it improves readability.\n\nHere is some `prettier` formatted code:\n\n```javascript\nconst relativeCoords = {\n  A: [xPos - 1, yPos - 1],\n  B: [xPos, yPos - 1],\n  C: [xPos + 1, yPos - 1],\n  D: [xPos - 1, yPos],\n  E: [xPos + 1, yPos],\n  F: [xPos - 1, yPos + 1],\n  G: [xPos, yPos + 1],\n  H: [xPos + 1, yPos + 1],\n};\n```\n\nOriginally, I included some whitespace to keep things visually aligned. If I\ninclude a `prettier-ignore` comment, the statement immediately following it\nwill not be touched by prettier.\n\n```javascript\n// prettier-ignore\nconst relativeCoords = {\n  A: [xPos - 1, yPos - 1],\n  B: [xPos    , yPos - 1],\n  C: [xPos + 1, yPos - 1],\n  D: [xPos - 1, yPos    ],\n  E: [xPos + 1, yPos    ],\n  F: [xPos - 1, yPos + 1],\n  G: [xPos    , yPos + 1],\n  H: [xPos + 1, yPos + 1],\n};\n```\n\n[source](https://prettier.io/docs/en/ignore.html#javascript)\n"
  },
  {
    "path": "javascript/test-coverage-stats-with-jest.md",
    "content": "# Test Coverage Stats With Jest\n\n[Jest](https://facebook.github.io/jest/) is a delightful tool for JavaScript\ntesting from Facebook. As your project evolves and you add tests (or perhaps\nchoose to not add tests) you may wonder what kind of test coverage you have.\nWhat is the overall coverage? Which files are well covered and which are\nseriously lacking?\n\nUse the `--coverage` flag to get this information.\n\n```bash\n$ jest --coverage\n```\n\nAfter running all of your tests a table will be output to the terminal with\na list of files and their respective coverage percentages in terms of\nstatement, branch, function, and line coverage.\n\n```\n---------------------------|----------|----------|----------|----------|----------------|\nFile                       |  % Stmts | % Branch |  % Funcs |  % Lines |Uncovered Lines |\n---------------------------|----------|----------|----------|----------|----------------|\n```\n\nThis can help guide you to what parts of your app may need more testing.\n"
  },
  {
    "path": "javascript/test-timing-based-code-with-jest-fake-timers.md",
    "content": "# Test Timing-Based Code With Jest Fake Timers\n\nIn real-world code we use timeouts to do things like debouncing and throttling\nof functions. This is really hard to test efficently and accurately with basic\ntest runner tooling.\n\nJest, however, offers some [Timer Mock\ntooling](https://jestjs.io/docs/en/timer-mocks) that removes most of the\ncomplexity of getting this right.\n\nHere is a method to test:\n\n```javascript\nconst doSomethingAfter200ms = doSomething => {\n  setTimeout(() => {\n    doSomething();\n  }, 200);\n};\n```\n\nA test that shows this to work would have to observe `doSomething` getting\ncalled after 200ms.\n\nThe following test won't work because the expectation is evaluated before the\ntimeout function is triggered.\n\n```javascript\ndescribe(\"doSomethingAfter200ms\", () => {\n  test(\"does something after 200ms (fail)\", () => {\n    const doSomething = jest.fn();\n\n    doSomethingAfter200ms(doSomething);\n\n    expect(doSomething).toHaveBeenCalled();\n  });\n});\n```\n\nBy activating `jest.useFakeTimers()`, we can simulate the passing of 200ms and\nthen check that our mocked function was called.\n\n```javascript\njest.useFakeTimers();\n\ndescribe(\"doSomethingAfter200ms\", () => {\n  test(\"does something after 200ms (pass)\", () => {\n    const doSomething = jest.fn();\n\n    doSomethingAfter200ms(doSomething);\n\n    jest.advanceTimersByTime(201);\n\n    expect(doSomething).toHaveBeenCalled();\n  });\n});\n```\n\nJest's function mocks and timer mocks make this possible.\n"
  },
  {
    "path": "javascript/the-comma-operator.md",
    "content": "# The Comma Operator\n\nI was surprised to see the result of this line of code:\n\n```javascript\nconst what = (1,2,3,4);\nconsole.log(what); //=> 4\n```\n\nI asked around on\n[twitter](https://twitter.com/jbrancha/status/1084936559323951105) and\nlearned that the syntax construct at play here is the [comma\noperator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator).\n\n> The comma operator evaluates each of its operands (from left to right) and\n> returns the value of the last operand.\n\nAnd that is why `what` gets bound to `4`.\n"
  },
  {
    "path": "javascript/throttling-a-function-call.md",
    "content": "# Throttling A Function Call\n\nImagine you have a JavaScript function that makes a request to your server.\nPerhaps it is sending user input from a `textarea` to be processed by the\nserver. You may want to wrap this function in a keyboard event listener so\nthat you are sure to react immediately to any user input. However, as the\nuser starts typing away into this text area you may find that way to many\nrequests are being fired off to the server. The request needs to be\n*throttled*.\n\nYou can roll your own approach to sufficiently intermittent server calls.\nThough, it turns out that [underscore.js](http://underscorejs.org/) comes\nwith two functions out of the box for this kind of behavior.\n\n- [`throttle`](http://underscorejs.org/#throttle) will give you a function\n  that wraps your function in a way that essentially rate-limits it to being\n  called at most once every `N` milliseconds.\n\n- [`debounce`](http://underscorejs.org/#debounce), on the other hand, will\n  give you a function that only calls your function once `N` milliseconds\n  has passed since it was last called.\n\nThese are two subtly different approaches to making sure a function gets\ncalled, just not too often.\n\nh/t [Jake Worth](https://twitter.com/jwworth)\n"
  },
  {
    "path": "javascript/timing-processes.md",
    "content": "# Timing Processes\n\nIf you want to time a process, you can use the `console.time()` and\n`console.timeEnd()` utilities specified by the `console` Web API. Invoking\n`console.time()` with a label starts a named timer. You can then run the\nprocess you want to time. Then invoke `console.timeEnd()` with the same\nlabel to terminate the timer and see how long the process took.\n\n```javascript\nconsole.time('sorting');\n[11,10,9,8,7,6,5,4,3,2,1].sort();\nconsole.timeEnd('sorting');\n> sorting: 0.278ms\n\nconsole.time('console logging');\nconsole.log('logging to the console');\nconsole.timeEnd('console logging');\n> logging to the console\n> console logging: 0.311ms\n\nconsole.time('adding'); 1 + 1; console.timeEnd('adding');\n> adding: 0.006ms\n```\n\nThese functions are implemented in most modern browsers.\n\nSee [the\ndocs](https://developer.mozilla.org/en-US/docs/Web/API/Console/time) for\nmore details.\n"
  },
  {
    "path": "javascript/transforming-es6-and-jsx-with-babel-6.md",
    "content": "# Transforming ES6 and JSX With Babel 6\n\nWith Babel 5, transforming ES6 and JSX into ES5 code was accomplished by\nincluding the `babel-loader`. This would be configured in\n`webpack.config.js` with something like the following:\n\n```javascript\nmodule: {\n  loaders: [\n    {\n      test: /\\.jsx?$/,\n      exclude: /node_modules/,\n      loader: 'babel-loader',\n    }\n  ],\n},\n```\n\nNow, with Babel 6, the different parts of the loader have been broken out\ninto separate plugins. These plugins need to be installed\n\n```\n$ npm install babel-preset-es2015 babel-preset-react --save-dev\n```\n\nand then included as presets\n\n```javascript\nmodule: {\n  loaders: [\n    {\n      test: /\\.jsx?$/,\n      exclude: /node_modules/,\n      loader: 'babel-loader',\n      query: {\n        presets: ['es2015', 'react']\n      },\n    }\n  ],\n},\n```\n\nAlternatively, the presets can be specified in the project's `.babelrc` file.\n\n[Source](http://jamesknelson.com/the-six-things-you-need-to-know-about-babel-6/)\n"
  },
  {
    "path": "javascript/truthiness-of-integer-arrays.md",
    "content": "# Truthiness of Integer Arrays\n\nWe can consider the truthiness of `[1]` as follows:\n\n```javascript\n> [1] == true\n=> true\n> Boolean(true)\n=> true\n> Boolean([1])\n=> true\n```\n\nWe can consider the truthiness of `[0]` as follows:\n\n```javascript\n> [0] == false\n=> true\n> Boolean(false)\n=> false\n> Boolean([0])\n=> true\n```\n\nThe truthiness of `[0]` does not seem to be consistent.\n\nSee this [JavaScript Equality Table](https://dorey.github.io/JavaScript-Equality-Table/)\nfor more details.\n"
  },
  {
    "path": "javascript/turn-an-html-collection-into-an-array.md",
    "content": "# Turn An HTMLCollection Into An Array\n\nIf you are using any of the built-in document query utilities, such as\n[`getElementsByClassName()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName):\n\n```javascript\n> document.getElementsByClassName(\"some-class\")\nHTMLCollection(5) [ ... ]\n```\n\nThen you are going to get an\n[`HTMLCollection`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection)\nin response. An instance of this cannot be iterated over, so you cannot call\nthings like `map` and `filter` against it.\n\nTo use Array collection methods, you are first going to need to turn the\n`HTMLCollection` into an array. You can do this with\n[`Array.from`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from):\n\n```javascript\n> Array.from(document.getElementsByClassName(\"some-class\"))\n[ ... ]\n```\n\n[source](https://medium.com/@chuckdries/traversing-the-dom-with-filter-map-and-arrow-functions-1417d326d2bc)\n"
  },
  {
    "path": "javascript/turn-off-console-error-messages-in-a-test.md",
    "content": "# Turn Off Console Error Messages In A Test\n\nI'm using [Jest](https://facebook.github.io/jest/) to test a React component\nthat requires a prop via\n[PropTypes](https://reactjs.org/docs/typechecking-with-proptypes.html). In\none of my tests, I want to test that component when the required prop is\nexcluded. The side effect of doing this is that my test output gets\ncluttered with the PropType warning.\n\nThe thing to do is silence the error message during that test.\n\n```javascript\nit('renders a component without a required prop', () => {\n  const originalError = console.error;\n  console.error = jest.fn();\n\n  // test code here\n  expect(shallow(<My Component />)).toDoSomething;\n\n  console.error = originalError;\n});\n```\n\nWe can silence `console.error` by temporarily replacing it with a\nJest-mocked function and then putting it back at the end of the test.\n"
  },
  {
    "path": "javascript/turn-off-npm-funding-message.md",
    "content": "# Turn Off npm Funding Message\n\nWhen you run `npm install`, you'll see a few different details output to your\nterminal. One you are probably used to seeing is the one about packages looking\nfor funding.\n\n```bash\n❯ npm install\n\nup to date, audited 253 packages in 2s\n\n88 packages are looking for funding\n  run `npm fund` for details\n\n6 vulnerabilities (1 low, 4 moderate, 1 high)\n```\n\nIf for whatever reason you need to turn off this (e.g. for scripting and CI\npurposes), you can globally configure it with the `npm config` command.\n\n```bash\n❯ npm config set fund false --location=global\n```\n\nRun an `npm install` again and the funding message will no longer show.\n\nThis edits the `npmrc` located in the `/etc` directory of wherever your current\nversion of Node is installed. Running `npm config edit --global` will open you\nup to this file as well.\n\nh/t Dillon Hafer\n"
  },
  {
    "path": "javascript/waiting-on-multiple-promises.md",
    "content": "# Waiting On Multiple Promises\n\nYou may find yourself in a situation where you have to request multiple\nresources from multiple API endpoints and then combine that data in some\nway.\n\nOne way to achieve this would be with nested promises.\n\n```javascript\nfetch('/blogs').then((response) => {\n  let blogs = response.body;\n\n  fetch('/tags').then((response) => {\n    let tags = response.body;\n\n    // combine blogs and tags ...\n  })\n})\n```\n\nThis nesting isn't ideal and it can get hard to read as the full\nimplementation is put into place.\n\nThe `Promise` API provides an alternative.\n\n```javascript\nlet blogsPromise = fetch('/blogs')\nlet tagsPromise = fetch('/tags')\n\nPromise.all([blogsPromise, tagsPromise]).then(([blogsResp, tagsResp]) => {\n  // combine blogs and tags ...\n})\n```\n\nWith\n[`Promise.all()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all)\nwe are able to wrap any number of promises and wait for all of them to\nresolve until we do something with the results. This allows us to create a\ncontext in which we have all the data we need without a bunch of nesting.\n"
  },
  {
    "path": "javascript/who-am-i-npm-edition.md",
    "content": "# Who Am I: NPM Edition\n\nWant to know who has been configured as the current user via the NPM CLI?\n\n```bash\n$ npm whoami\n```\n\nSee `man npm-whoami` for more details.\n"
  },
  {
    "path": "javascript/write-a-javascript-object-to-a-json-file.md",
    "content": "# Write A JavaScript Object To A JSON File\n\nTo write a JavaScript object to a file as JSON, I need to use two concepts.\n\nFirst, I need to use\n[`JSON.stringify`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify)\nto conver the object to a string of valid JSON. Plus, by specifying the third\nargument as `2`, I get an indentation of two spaces as it formats the JSON.\n\n```javascript\nJSON.stringify(data, null, 2)\n```\n\nSecond, I need to import the `fs` (filesystem) package so that I can write the\nJSON string to a file. In this example, I've chosen to use the synchronous\nversion\n([`writeFileSync`](https://nodejs.org/api/fs.html#fswritefilesyncfile-data-options))\nto keep my function simple. There is also an async version.\n\n```javascript\nimport fs from 'fs'\n\nfs.writeFileSync('my-data.json', json_string, 'utf8')\n```\n\nHere is a full example of what this could look like:\n\n```javascript\nimport fs from 'fs'\n\nconst writeJsonToFile = (path, data) => {\n  try {\n    fs.writeFileSync(path, JSON.stringify(data, null, 2), 'utf8')\n    console.log('Data successfully saved to disk')\n  } catch (error) {\n    console.log('An error has occurred ', error)\n  }\n}\n\nconst data = {\n  name: 'Super Software LLC',\n  orgIds: [1,3,7,11]\n}\n\nwriteJsonToFile('my-data.json', data)\n```\n"
  },
  {
    "path": "javascript/yarn-commands-without-the-emojis.md",
    "content": "# Yarn Commands Without The Emojis\n\nIf you are a hater and you'd like to run [`yarn`](https://yarnpkg.com/en/)\ncommands without emojis being playfully included in the output, just include\nthe `--no-emoji` flag.  The output of a command like `add` will look like\nthis:\n\n```bash\n$ yarn add chalk --no-emoji\nyarn add v0.17.10\n[1/4] Resolving packages...\n[2/4] Fetching packages...\n[3/4] Linking dependencies...\n[4/4] Building fresh packages...\nsuccess Saved lockfile.\nsuccess Saved 7 new dependencies.\n├─ ansi-styles@3.1.0\n├─ chalk@2.0.1\n├─ color-convert@1.9.0\n├─ color-name@1.1.3\n├─ escape-string-regexp@1.0.5\n├─ has-flag@2.0.0\n└─ supports-color@4.2.0\nDone in 0.54s.\n```\n\nSee `yarn help` for details.\n"
  },
  {
    "path": "javascript/yup-schemas-are-validated-asynchronously.md",
    "content": "# Yup Schemas Are Validated Asynchronously \n\n[Yup](https://github.com/jquense/yup) provides a flexible object schema\nvalidation DSL. For instance, if you want to enforce that a certain value is\na number, you can define something like this:\n\n```javascript\nconst numSchema = yup.number();\n```\n\nYou can then validate anything against that schema.\n\n```javascript\nconst validator = (val) => {\n  numSchema.validate(val)\n    .then(result => {\n      console.log(result); // it is the value of `val`\n      return true;\n    })\n    .catch(error => {\n      console.log(error.errors); // array of validation error messages\n      return false;\n    });\n};\n```\n\nThe validation is async, so if it succeeds the `then` block is hit. If the\nvalidation fails, it will fall through to the `catch`.\n\n```javascript\nvalidator(5) // => true\nvalidator('what') // => false\n```\n"
  },
  {
    "path": "jj/colocate-jj-and-git-directories-for-project.md",
    "content": "# Colocate jj And git Directories For Project\n\nWhen doing a standard clone of a git repository with `jj`, you'll get a copy of\nthe project with a `.jj` directory containing the version control information.\n\n```bash\n$ jj git clone git@github.com:jbranchaud/my-repo\nFetching into new repo in \"/path/of/local/repo\"\n...\n\n$ exa --tree --all -L 1\n.\n├── .gitignore\n├── .jj\n├── Cargo.lock\n├── Cargo.toml\n└── src\n```\n\nThis is fine if I'm completely familiar with using\n[jujutsu](https://martinvonz.github.io/jj/latest/). However, if I'm coming from\n`git` and still learning, then it would be nice to be able to fallback to\nfamiliar `git` commands when needed.\n\nBut without a `.git` directory, I get this:\n\n```bash\n$ git log\nfatal: not a git repository (or any of the parent directories): .git\n```\n\nWhen cloning a git repo with `jj`, I can instruct it to _colocate_ which means\nthat it will create both the `.jj` and the `.git` data directories in the\nproject.\n\n```bash\n$ jj git clone --colocate git@github.com:jbranchaud/my-repo\nFetching into new repo in \"/path/of/local/repo\"\n...\n\n$ exa --tree --all -L 1\n.\n├── .git\n├── .gitignore\n├── .jj\n├── Cargo.lock\n├── Cargo.toml\n└── src\n```\n\nNow I can run `jj` commands or `git` commands:\n\n```bash\n$ git log\ncommit 0c72abbb83657096677f9a3d5ddc7bce20839165 (HEAD, origin/trunk, trunk)\n...\n```\n\n[source](https://martinvonz.github.io/jj/latest/git-compatibility/#co-located-jujutsugit-repos)\n"
  },
  {
    "path": "jj/describe-current-changes-and-create-new-change.md",
    "content": "# Describe Current Changes And Create New Change\n\nOne of the first patterns I learned with `jj` was a pair of commands to\nessentially \"commit\" the working copy and start a fresh, new change. So if I am\ndone making some changes, I can add a description to the `(no description)`\nworking copy and then start a new working copy _change_.\n\n```bash\n$ jj describe -m \"Add status subcommand to show current status\"\n$ jj new\n```\n\nI learned from [Steve](https://steveklabnik.com/) in the [jj\ndiscord](https://discord.gg/dkmfj3aGQN) that a shorthand for this pattern is to\nuse the `jj commit` command directly.\n\n> When called without path arguments or `--interactive`, `jj commit` is\n> equivalent to `jj describe` followed by `jj new`.\n\nThat means, instead of the above pair of commands, I could have done:\n\n```bash\n$ jj commit -m \"Add status subcommand to show current status\"\n```\n\nThat would have had the same result in my case. However, notice the caveats\nmentioned in the quote above and check out `man jj-commit` for more details on\nthat.\n"
  },
  {
    "path": "jj/find-system-wide-config-file-for-user.md",
    "content": "# Find System-wide Config File For User\n\nThe `jj` CLI can be configured in a couple different places. When I recently\nran a `jj config` command, I was curious where specifically it was getting set.\nThose changes didn't appear in the repo's config (`./.jj/repo/config.toml`).\nThat makes sense since it would only apply to that repo. So, where is the\nsystem-wide config file?\n\nThe following commond shows where on your machine it is located.\n\n```bash\n$ jj config path --user\n/Users/jbranchaud/Library/Application Support/jj/config.toml\n```\n\nNow, the next time I set a config like this:\n\n```bash\n$ jj config set --user ui.paginate never\n```\n\nor want to check what other config options are set to, I can visit that path\nand take a look.\n\n[source](https://github.com/martinvonz/jj/blob/main/docs/config.md)\n"
  },
  {
    "path": "jj/squash-changes-into-parent-commit-interactively.md",
    "content": "# Squash Changes Into Parent Commit Interactively\n\nWhile I have some changes in progress as part of the working copy, I can squash\nthem into the previous / parent commit with the `jj squash` command. Running\nthat command as is will apply all the working copy changes to the parent leaving\nthe current revision empty.\n\nI can also interactively squash those changes similar in spirit to how I might\nuse `git add --patch` to stage and then amend specific changes into the previous\ncommit with `git`. This can be done with [`jj`](https://github.com/jj-vcs/jj)\nusing `squash` with the `-i` flag.\n\n```bash\njj squash -i # or --interactive\n```\n\nThis will open up a TUI where I can click around or use keys. Each file in the\nsource revision (in my case, the working copy) will be listed. I can move the\ncursor between them hitting _space_ to toggle them in or out of the squash\nselection.\n\nI can also hit `f` over a given file to toggle _folding_. When folding is on, a\ndiff of the file will be disclosed with checkboxes for toggling individual\nhunks and lines.\n\nOnce I'm satisfied with my interactive selection, I can hit `c` to confirm and\nonly the selected files and changes will be squashed into the parent.\n\nSee `man jj-squash` for more details.\n\n[source](https://steveklabnik.github.io/jujutsu-tutorial/real-world-workflows/the-squash-workflow.html)\n"
  },
  {
    "path": "jq/combine-an-array-of-objects-into-a-single-object.md",
    "content": "# Combine An Array Of Objects Into A Single Object\n\nIf you've spent any amount of time pulling data out of a JSON file with `jq`,\nyou may have run into a result set that looks a little too spacious. It's this\narray of single key-value pair objects.\n\n```bash\n$ jq '.items | map({(.slug)}: .amount})' my-data.json\n\n[\n  {\n    \"key-1\": 123\n  },\n  {\n    \"key-2\": 345\n  },\n  {\n    \"key-3\": 456\n  },\n  ...\n]\n```\n\nWhen what you really wanted was a single object full of those unique key-value\npairs.\n\nThat query has you 90% of the way there. The trick is to pipe that array\nthrough the [`add` function](https://jqlang.github.io/jq/manual/#add) which\nwill combine each of those individual objects into a single object.\n\n```bash\n$ jq '.items | map({(.slug)}: .amount}) | add' my-data.json\n\n{\n  \"key-1\": 123,\n  \"key-2\": 345,\n  \"key-3\": 456,\n  ...\n}\n```\n"
  },
  {
    "path": "jq/count-each-collection-in-a-json-object.md",
    "content": "# Count Each Collection In A JSON Object\n\nLet's say your JSON file is an object that represents several different\ncollections (arrays) of data.\n\n```json\n{\n  \"users\": [ ... ],\n  \"orders\": [ ... ],\n  \"carts\": [ ... ]\n}\n```\n\nWe can get a nice summary of the counts of those collections using\n[`jq`](https://stedolan.github.io/jq/). We can do that with the [`with_entries`\nfunction](https://stedolan.github.io/jq/manual/#to_entries,from_entries,with_entries).\nWe preserve the key (name) of each collection and then process each list with\nthe `length` function.\n\n```bash\njq '. | with_entries({ \"key\": .key, \"value\": (.value | length)})' data.json\n{\n  \"users\": 1234,\n  \"orders\": 5432,\n  \"carts\": 89\n}\n```\n\nThe `with_entries` function essentially maps over each key-value pair\nprocessing it with the given expression. It will then convert that `{\"key\":\nsome_key, \"value\": 123}` mapping back into a key-value pair that gets combined\nwith all the others.\n\n[source](https://til.simonwillison.net/jq/flatten-nested-json-objects-jq)\n"
  },
  {
    "path": "jq/count-the-number-of-things-in-a-json-file.md",
    "content": "# Count The Number Of Things In A JSON File\n\nJQ is a great tool for finding out the number of things in a JSON file.\n\nIf the top-level contents of the JSON is a list, then you can pipe it directly\nto the [`length` function](https://stedolan.github.io/jq/manual/#length).\n\n```bash\n// [1, 2, {\"three\": 4}]\n$ jq '. | length' data.json\n3\n```\n\nIt works the same for counting the number of entries (key-value pairs) in a\ntop-level JSON object.\n\n```bash\n// { \"hello\": \"world\", \"list\": [1,2,3] }\n$ jq '. | length' data.json\n2\n```\n\nIf you are trying to get the count of a nested value, navigate to it and then\npipe that to `length`.\n\n```bash\n// { \"hello\": \"world\", \"list\": [1,2,3] }\n$ jq '.list | length' data.json\n3\n```\n\nYou can even count each value in a JSON object by transforming it into an array\nof the values with `[]`.\n\n```bash\n// { \"hello\": \"world\", \"list\": [1,2,3] }\n$ jq '.[] | length' data.json\n5\n3\n```\n\nNotice, the length of `\"world\"` is `5` characters and the length of `[1,2,3]`\nis `3` elements.\n"
  },
  {
    "path": "jq/extract-a-list-of-values.md",
    "content": "# Extract A List Of Values\n\n[`jq`](https://stedolan.github.io/jq/) can be used to extract a list of values\nfrom an array in a JSON file.\n\nConsider the following JSON:\n\n```json\n{\n  \"items\": [\n    { \"id\": 1, \"name\": \"Liz Lemon\" },\n    { \"id\": 2, \"name\": \"Pete Hornberger\" },\n    { \"id\": 3, \"name\": \"Tracy Jordan\" },\n    { \"id\": 4, \"name\": \"Jenna Maroney\" }\n  ]\n}\n```\n\nFirst, you need to specify the selector path to the list. One it's own that\nwill grab the list.\n\n```bash\n$ jq '.items' data.json\n[\n  {\n    \"id\": 1,\n    \"name\": \"Liz Lemon\"\n  },\n  ...\n]\n```\n\nThen you need to use brackets to interact with the list. `.items[0]` and\n`.items[1]` would grab the first and second item in the list, respectively.\nLeaving the brackets empty (`.items[]`) tells `jq` that you want to interact\nwith each item in the list.\n\nThen tack on a selector for what you want out of each item.\n\n```bash\n$ jq '.items[].name' data.json\n\"Liz Lemon\"\n\"Pete Hornberger\"\n\"Tracy Jordan\"\n\"Jenna Maroney\"\n```\n\nThis grabs the name from each of the objects within the _items_ array. The\nresults are printed to stdout.\n"
  },
  {
    "path": "jq/filter-out-results-based-on-list-of-values.md",
    "content": "# Filter Out Results Based On List Of Values\n\nLet's say we have an array of objects in a JSON file. We want to extract some\ndata about each of those objects, but first we want to filter out some of the\nobjects that we don't need. This will be based on a list of IDs.\n\nThe JSON might look something like this:\n\n```json\n[\n  {'id': '123', ...},\n  {'id': '456', ...},\n  {'id': '789', ...},\n  {'id': '963', ...},\n  ...\n]\n```\n\nWith the [`select`](https://jqlang.github.io/jq/manual/#select) function, we\ncan filter the array down to those objects whose IDs are\n[`not`](https://jqlang.github.io/jq/manual/#and-or-not)\n[`inside`](https://jqlang.github.io/jq/manual/#inside) the list of IDs to\nexclude.\n\n```\njq '.[] | select([.id] | inside[\"456\", \"963\"] | not)' data.json\n```\n\nInside that `select`, we grab the `id` as a single value array, check if that\nvalue is inside our _exclude_ array, and then invert that result. If there is a\nmatch, that object will be filtered out.\n\nWe can then chain additional filtering and extraction on to the end of the\nquery to produce the result we want.\n"
  },
  {
    "path": "jq/find-all-objects-in-an-array-where-key-is-set.md",
    "content": "# Find All Objects In An Array Where Key Is Set\n\nLet's say we have a large array of objects. And the data in those objects,\nwhile generally having the same shape, does not always have certain values set.\n\nFor instance, here is some data where the `token` is sometimes set, sometimes\n`null`, and sometimes missing altogether.\n\n```json\n[\n  {\n    \"id\": 1,\n    \"token\": \"abc\"\n  },\n  {\n    \"id\": 3,\n    \"token\": null\n  },\n  {\n    \"id\": 5\n  },\n  ...\n]\n```\n\nWe can find out how many objects in this collection have the `token` key set to\nan actual value with [a `jq` query](https://stedolan.github.io/jq/manual) like\nthe following.\n\n```bash\njq '. | map(select(has(\"token\") and .token != null)) | length' data.json\n```\n\nThis maps over each object selecting those where it has `token` and `token` is\nnot `null`.\n\nWe can instead produce the inverse count—those objects where `token` is not set\nto a value—with the `not` operator.\n\n```bash\njq '. | map(select(has(\"token\") and .token != null | not)) | length' data.json\n```\n\nIf you want to inspect the array of objects that either of these queries filters down to, you can drop the `| length` part.\n\n```bash\njq '. | map(select(has(\"token\") and .token != null))' data.json\n```\n\nHere is [a live example](https://jqterm.com/?query=.%20%7C%20map%28select%28has%28%22token%22%29%20and%20.token%20!%3D%20null%20%7C%20not%29%29).\n"
  },
  {
    "path": "jq/find-all-objects-with-a-matching-key-value-pair.md",
    "content": "# Find All Objects With A Matching Key Value Pair\n\nLet's say I have a JSON file representing a bunch of people's reading lists.\nThat means it is an array of objects where each object is a person's reading\nprofile and contains a _list_ of books. Some of those books have a _status_ of\n`reading` meaning the person is currently reading that book.\n\nHow can we find all books that are currently being read?\n\n```\njq '. | map(\n      {\n        name: .username,\n        in_progress_books: (.books | map(select(.status == \"reading\")))\n      }\n    )'\n```\n\n```\n[\n  { name: 'bobr', in_progress_books: [...] },\n  { name: 'sallyf', in_progress_books: [...] },\n  ...\n]\n```\n\nThat will show us for each reader what books they are currently reading.\n\nAlternatively, we could roll that all up into a single list of books.\n\n```\njq '. |\n      map(.books | map(select(.status == \"reading\"))) |\n      flatten'\n```\n\n```\n[\n  { title: 'Moby Dick', status: 'reading', ... }\n  { title: 'The Great Gatsby', status: 'reading', ... }\n  ...\n]\n```\n\n[source](https://stackoverflow.com/a/18608100/535590)\n"
  },
  {
    "path": "jq/get-a-slice-of-the-ends-of-an-array.md",
    "content": "# Get A Slice Of The Ends Of An Array\n\n[`jq`](https://jqlang.github.io/jq/) has an array slice syntax that allows us\nto grab a subset of values from an array. The general form of this syntax is\n`[n:m]` where `n` is the index of the start of our slice (inclusive) and `m` is\nthe index of the end of our slice (non-inclusive).\n\nIf we omit the `n`, it defaults to `0`, or the start of the array. Similarly,\nif we omit the `m`, it defaults to the end of the list.\n\nKnowing that, we can grab the first few elements of the list like so:\n\n```bash\n❯ echo '[\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\"]' | jq '.[:3]'\n[\n  \"a\",\n  \"b\",\n  \"c\"\n]\n```\n\nWe can also use a negative index value to count back from the end of the array.\nThis allows us to grab a slice from some point relative to the end of the list.\nInstead of having to compute it based on knowing the length of the array.\n\nKnowing that, we can grab the last few elements of the list like so:\n\n```bash\n❯ echo '[\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\"]' | jq '.[-3:]'\n[\n  \"e\",\n  \"f\",\n  \"g\"\n]\n```\n\n[source](https://jqlang.github.io/jq/manual/#array-string-slice)\n"
  },
  {
    "path": "jq/get-the-first-item-for-every-top-level-key.md",
    "content": "# Get The First Item For Every Top-Level Key\n\nLet's say we have a JSON object where each key in that object is tied to a\nlarge array of values. To get a better idea of what the data looks like, we\nwant to trim down the JSON a bit. Essentially, we want to tie each key to the\nfirst value in each of their respective arrays.\n\nWe can do this by reducing the object into a new object where each top-level\nkey is tied to the first item in its array.\n\n```bash\n$ jq '. as $object | reduce keys[] as $k ({}; .[$k] = $object[$k][0])' data.json\n```\n\nThis uses variables (`$object` and `$k`) and the [`reduce`\nfunction](https://stedolan.github.io/jq/manual/#Reduce) to iterate over the\nincoming JSON object and produce a new object with the trimmed down data.\n\nJSON like this:\n\n```json\n{\n  \"key1\": [\"a\", \"b\", \"c\"],\n  \"key2\": [1, 2, 3],\n  \"key3\": [\"x\", \"y\", \"z\"]\n}\n```\n\nwill be turned into this:\n\n```json\n{\n  \"key1\": \"a\",\n  \"key2\": 1,\n  \"key3\": \"x\"\n}\n```\n"
  },
  {
    "path": "jq/get-the-last-item-from-an-array.md",
    "content": "# Get The Last Item From An Array\n\nThere are two ways to get the last item from an array using\n[`jq`](https://jqlang.github.io/jq/).\n\nThe one that is perhaps a bit more intuitive is to pipe the array to the\n[`last`](https://jqlang.github.io/jq/manual/#first-last-nth-2) function.\n\n```bash\n$ echo '[1,2,3]' | jq '. | last'\n3\n```\n\nAnother approach is to use an [array index\nexpression](https://jqlang.github.io/jq/manual/#array-index) to positionally\ngrab the last element of the array. As is the case with some languages and\nlibraries, `-1` positionally refers to the last item in the array.\n\n```bash\n$ echo '[1,2,3]' | jq '.[-1]'\n3\n```\n"
  },
  {
    "path": "jq/reduce-object-to-just-entries-of-a-specific-type.md",
    "content": "# Reduce Object To Just Entries Of A Specific Type\n\nLet's say I have a large JSON data file with a ton of top-level fields of\nvarying types. It can be hard to wade through it as is. [The `jq`\nutility](https://stedolan.github.io/jq/manual/) can help. I can filter a JSON\nobject down to just the fields of a certain type.\n\nFor instance, I may want to start with a view of the JSON that is restricted to\njust the values of type `array`.\n\nTo do this, I need to use a couple different `jq` helper functions.\n\n```bash\njq '. | to_entries | map(select(.value | type | match(\"array\"))) | from_entries' data.json\n```\n\nThis starts with `to_entries` to convert an object into an array of key-value\npairs. I then `map` over those pairs selecting just the pairs whose value\nmatches the `\"array\"` type. I then use `from_entries` to turn the reduced array\nback into an object.\n\nThere is a less verbose way to do the above. The `to_entries` and\n`from_entries` can be collapsed into a `with_entries` that wraps the `map`\ncall.\n\n```bash\njq '. | with_entries(map(select(.value | type | match(\"array\")))' data.json\n```\n"
  },
  {
    "path": "jq/turn-a-list-from-a-command-into-json.md",
    "content": "# Turn A List From A Command Into JSON\n\nThere are a lot of command-line utilities that produce a list of things. Since\nJSON is a universal data format, it would be useful to be able to quickly turn\nsome items from `stdout` into a JSON list.\n\nThe [`jq`](https://jqlang.github.io/jq/) utility can help with this.\n\nLet's say I'm working with the following `git` command that lists changed files\nin a specific directory.\n\n```bash\n$ git diff --name-only | grep some/dir\n```\n\nI can then pipe that list of files to `jq` with a few flags.\n\n```bash\n$ git diff --name-only \\\n  | grep some/dir \\\n  | jq -R -s 'split(\"\\n\")[:-1]'\n```\n\nHere's what is going on:\n\n- The `-R` flag tells `jq` to accept raw input, rather than looking for JSON.\n- The `-s` flag is short for `--slurp` and tells `jq` to read in the entire\n  input before applying the filter.\n- The string argument is the filter to be applied to the output. It splits on\n  newlines and then takes the entire array except for the last item (`[:-1]`)\n  which would be an empty string for the trailing newline.\n- `jq` automatically turns the whole thing into a formatted JSON list.\n"
  },
  {
    "path": "jq/zip-two-json-files-together-based-on-shared-id.md",
    "content": "# Zip Two JSON Files Together Based On Shared ID\n\nLet's say we have JSON file (`list1.json`) that contains an array of objects.\nMaybe they represent metadata about some books. Something like this:\n\n```json\n[\n  { 'slug': 'the-subtle-knife', 'title': 'The Subtle Knife', ... },\n  { 'slug': 'all-systems-red', 'title': 'All Systems Red', ... },\n  { 'slug': 'piranesi-abc123', 'title': 'Piranesi', ... },\n  ...\n]\n```\n\nAnd then we have another JSON file (`list2.json`) in a similar format that\ncontains an additional piece of metadata tied to each slug:\n\n```json\n[\n  { 'slug': 'the-subtle-knife', 'author': 'Philip Pullman' },\n  { 'slug': 'all-systems-red', 'author': 'Martha Wells' },\n  { 'slug': 'piranesi-abc123', 'author': 'Susanna Clarke' },\n  ...\n]\n```\n\nAnd we want to pull the details from the second file and combine them into the\nfirst file based on that shared identifier, in this case, the `slug`.\n\nInstead of copying over a ton of values manually or writing a full-fledged\nscript to do this, we can use a `jq` one-liner with the `--slurpfile` flag.\n\n```\njq --slurpfile list1 list1.json --slurpfile list2 list2.json -n '\n  $list1[] as $item1\n  | $list2[] as $item2\n  | select($item1.slug == $item2.slug)\n  | $item1 + $item2\n'\n\n[\n  { 'slug': 'the-subtle-knife', 'title': 'The Subtle Knife', 'author': 'Philip Pullman', ... },\n  { 'slug': 'all-systems-red', 'title': 'All Systems Red', 'author': 'Martha Wells', ... },\n  { 'slug': 'piranesi-abc123', 'title': 'Piranesi', 'author': 'Susanna Clarke', ... },\n  ...\n]\n```\n\nThis reads in both files as lists into named variables, selects for the items\nthat have matching `slug` values, and then unions those objects together. The\nresult will go to standard out, but it could also be redirected into a new JSON\nfile.\n"
  },
  {
    "path": "kitty/set-the-title-of-a-window.md",
    "content": "# Set The Title Of A Window\n\nKitty, I believe by default, will set the title of the current window to a\nprevious run command.\n\nFor instance, I often start out my terminal session by running a `tmux` command\nto create or join a tmux session. After this, the title of the window ends up\nsticking as something like `tmux new -s my-project`.\n\nBecause I switch between various projects, I'd prefer the window title be\nsomething more generic. The window title can be manually set. To do this, open\na 'New OS Window'—either from the menu or by hitting `Cmd-N`.\n\nThen run a `set-window-title` command with `kitty`.\n\n```bash\n$ kitty @ set-window-title --match id:1 code\n```\n\nThe `--match id:1` tells `kitty` what window to target with this command.\nBecause I only ever keep one window open, the `id` of that window is always\n`1`. If you're not sure which window `id` to target, you can list the windows\nand find the one you are looking for.\n\n```bash\n$ kitty ls\n```\n\n[source](https://sw.kovidgoyal.net/kitty/remote-control.html#kitty-set-window-title)\n"
  },
  {
    "path": "kitty/use-the-built-in-emoji-picker.md",
    "content": "# Use The Built-In Emoji Picker\n\nKitty has a built-in emoji picker which you can use to search for and select an\nemoji character to be placed in your current terminal context. This is handy\nbecause Mac OSX's built-in emoji picker (Ctrl-Cmd-Space) doesn't work in Kitty.\n\nTo open up Kitty's emoji picker, hit `Ctrl-Shift-u` (or prefix `u` with\nwhatever your Kitty metakey is). You'll see a full screen menu with 4 different\ntabs. If you move to the _Emoji (F2)_ tab (`Ctrl-]` and `Ctrl-[` to navigate),\nyou'll be able to search for an emoji based on its metadata name.\n\nFor instance, if I type `check`, I'll see a bunch of unicode characters that\nmatch that term including `3  ✅ White heavy check mark`. By hitting tab until\nI reach that result, I can hit `Enter` to send that emoji to the terminal\ncontext.\n\n[source](https://sw.kovidgoyal.net/kitty/kittens/unicode-input.html)\n"
  },
  {
    "path": "linux/check-ubuntu-version.md",
    "content": "# Check Ubuntu Version\n\nAre you on Ubuntu? Want to know what version (release) of Ubuntu you are\nusing?\n\nRun the following to find out:\n\n```bash\n$ lsb_release -r\n```\n"
  },
  {
    "path": "linux/configure-your-server-timezone.md",
    "content": "# Configure Your Server Timezone\n\nOn Ubuntu and Debian, you can open an interactive prompt for configuring\nyour timezone with the following command:\n\n```bash\n$ dpkg-reconfigure tzdata\n```\n"
  },
  {
    "path": "linux/list-the-statuses-of-all-upstart-jobs.md",
    "content": "# List The Statuses Of All Upstart Jobs\n\nTo see a list of all known upstart jobs and their statuses, use the\nfollowing command:\n\n```bash\n$ initctl list\n...\nconsole stop/waiting\nmounted-run stop/waiting\nacpid start/running, process 2927\ncheckfs.sh start/running\ncheckroot-bootclean.sh start/running\nkmod stop/waiting\nmountnfs.sh start/running\nnginx stop/waiting\nplymouth-stop stop/waiting\nrcS stop/waiting\nufw start/running\n...\n```\n\nIt will tell you for each job if it is stopped or started.\n\nSee `man initctl` for more details.\n\nh/t Josh Davey\n"
  },
  {
    "path": "linux/show-current-system-time-and-settings.md",
    "content": "# Show Current System Time And Settings\n\nIf you are accessing a remote server and viewing logs, you may want to know\nwhat the current system time is. The `timedatectl` command can show the\ncurrent system date, time, and related settings.\n\n```bash\n$ timedatectl\n       Local time: Di 2015-04-07 16:26:56 CEST\n   Universal time: Di 2015-04-07 14:26:56 UTC\n         RTC time: Di 2015-04-07 14:26:56\n        Time zone: Europe/Berlin (CEST, +0200)\n  Network time on: yes\n NTP synchronized: yes\n  RTC in local TZ: no\n```\n\nThis command can also be used to modify these settings.\n\n[source](http://man7.org/linux/man-pages/man1/timedatectl.1.html)\n"
  },
  {
    "path": "linux/show-used-and-available-system-memory.md",
    "content": "# Show Used And Available System Memory\n\nThe `free` command will display the total RAM on your system as well as how\nmuch of it is used and how much is still freely available.\n\n```bash\n$ free\n              total        used        free      shared  buff/cache   available\nMem:        1000260      166004      552808       14440      281448      664724\nSwap:             0           0           0\n```\n\nThe default output format of `free` is not very readable though. To make it\nmore human readable, you can add the `-h` (_human_) and `--si` (_International\nSystem of Units_) flags.\n\n```bash\n$ free -h --si\n              total        used        free      shared  buff/cache   available\nMem:           976M        162M        547M         14M        266M        649M\nSwap:            0B          0B          0B\n```\n\nSee `man free` for more details.\n"
  },
  {
    "path": "linux/upgrading-ubuntu.md",
    "content": "# Upgrading Ubuntu\n\nI recently discovered that my Linode box was running a fairly old version of\nUbuntu. Because it is a remote box that I SSH into, there is no graphical\nuser interface. Upgrading to a newer release can be accomplished with the\nfollowing command line utility:\n\n```\n$ do-release-upgrade\n```\n\nIt includes a series of prompts regarding choices about the upgrade and a\nlot of waiting.\n\nAdding the `-d` flag will upgrade to the latest development release.\n"
  },
  {
    "path": "llm/send-curl-to-claude-text-completion-api.md",
    "content": "# Send cURL To Claude Text Completion API\n\nHere is how we can make a `cURL` (`POST`) request to the Claude text completion\nAPI. It requires already having a Claude API account with (paid) credits. At\nthis time, you can get $5 in free credits to try it out.\n\nAssuming all that, we can grab an API key, store it somewhere safe and\naccessible like 1Password, and then start formatting a request.\n\nWe need to specify a couple headers as well as `POST` body parameters.\n\n```bash\ncurl -X POST \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-api-key: $(op item get \"Anthropic Claude API Key\" --field credential)\" \\\n  -H \"anthropic-version: 2023-06-01\" \\\n  -d \\\n'{\n  \"model\": \"claude-2.1\",\n  \"max_tokens_to_sample\": 1024,\n  \"prompt\": \"Human: Show me an example of a simple Ruby program.\\n\\nAssistant:\"\n}' \\\n  https://api.anthropic.com/v1/complete\n```\n\nThe required headers are:\n- `\"Content-Type: application/json\"`\n- `x-api-key` with our API key\n- `\"anthropic-version: 2023-06-01\"` (the latest Anthropic API version)\n\nThen, in the body, we specify:\n- the `model` (e.g. `claude-2.1`)\n- the max number of tokens you want the model to use\n- a prompt that starts with `Human:` and then prompts the `Assistant:`\n\nNote: this is a legacy API and the [Messages\nAPI](https://docs.anthropic.com/claude/reference/messages_post) should be\npreferred.\n\n[source](https://docs.anthropic.com/claude/reference/complete_post)\n"
  },
  {
    "path": "llm/use-the-llm-cli-with-claude-models.md",
    "content": "# Use The llm CLI With Claude Models\n\n[Simon Willison's `llm`](https://llm.datasette.io/en/stable/index.html) can be\nused with a bunch of different models (local and API). The whole thing is\nplugin driven. To use a specific model, you'll need to install the plugin for\nit. For instance, to use the [Claude 3 family of\nmodels](https://www.anthropic.com/news/claude-3-family) you need to install\n`llm-claude-3`.\n\n```bash\n$ llm install llm-claude-3\n```\n\nThen when prompting `llm`, specify which of the Claude models you want to use —\n`claude-3-haiku`, `claude-3-sonnet`, or `claude-3-opus` — with the `-m` flag:\n\n```bash\n$ llm \\\n  -m claude-3-haiku \\\n   --key $CLAUDE_API_KEY \\\n  'Show me the SQL query to create a cocktails table.'\n```\n\nNote: instead of adding my Claude API key to the key store, I've opted to\ninclude it with the `--key` flag via an environment variable that I've set\nahead of time.\n"
  },
  {
    "path": "mac/access-all-screen-and-video-capture-options.md",
    "content": "# Access All Screen And Video Capture Options\n\nThere are a number of hotkeys to help you quickly capture a screenshot on the\nMac. If you aren't sure which is which or what options are available, you can\nhit `Cmd+Shift+5`. This will open up a panel with the five main options. These\ninclude Capture Entire Screen, Capture Selected Window, and Capture Selected\nPortion for screenshots as well as Record Entire Screen and Record Selected\nPortion for videos.\n"
  },
  {
    "path": "mac/access-system-information-on-osx.md",
    "content": "# Access System Information OS X\n\nOn machines running OS X, there is an Apple icon in the upper left corner as\npart of the menu bar. Clicking on this icon reveals a number of options. The\nfirst reads _About This Mac_.\n\nIf you hold down the `option` key, however, that first option will instead\nread _System information..._\n\nSelect that option to access the System Information panel which can tell you\ndetails about your hardware, software, and network.\n\nh/t Dillon Hafer\n"
  },
  {
    "path": "mac/access-unsupported-screen-resolutions-with-rdm.md",
    "content": "# Access Unsupported Screen Resolutions With RDM\n\nIf you visit the _Display Settings_ for your Mac, you'll find that you only\nhave a handful of screen resolution options. For standard use, you'll get by\nwith these. If you need a specific, unsupported resolution you'll need help\nfrom a 3rd party tool. There are many options out there.\n[RDM](https://github.com/avibrazil/RDM) is a free and open-source option.\n\nOnce you have it installed and have given it _Accessibility_ permissions,\nopen the menu from your top toolbar and select the resolution you are\nlooking for.\n\nI use RDM to adjust my screen resolution to 1280x720 for optimal\nscreencasting.\n"
  },
  {
    "path": "mac/add-a-bunch-of-cli-utilities-with-coreutils.md",
    "content": "# Add A Bunch Of CLI Utilities With coreutils\n\nThe [`coreutils`](https://www.gnu.org/software/coreutils/) project is a\ncollection of useful utilities that every operating system ought to have.\n\n> The GNU Core Utilities are the basic file, shell and text manipulation\n> utilities of the GNU operating system. These are the core utilities which are\n> expected to exist on every operating system.\n\nWhile many of these utilities are redundant with BSD utilities that MacOS\nchooses to ship with, there are some differences in the overlapping ons and then\nmany additions from `coreutils`.\n\nThey can be installed with Homebrew:\n\n```bash\n$ brew install coreutils\n```\n\nAnd then you should have some new things available on your path. Take `shuf`, for\ninstance. This utility can shuffle and select items from a file or incoming\nlines from another command. Here I use it to randomly grab a number between 1\nand 5 (with the help of `seq`):\n\n```bash\n❯ seq 1 5 | shuf -n 1\n3\n\n❯ seq 1 5 | shuf -n 1\n2\n\n❯ seq 1 5 | shuf -n 1\n5\n```\n\nOr how about some utilities for manipulating file names? Among others there is\n`realpath`, `basename`, and `dirname`.\n\n```bash\n❯ realpath README.md\n/Users/lastword/dev/jbranchaud/til/README.md\n\n❯ realpath README.md | xargs basename\nREADME.md\n\n❯ realpath README.md | xargs dirname\n/Users/lastword/dev/jbranchaud/til\n```\n\nSee the [manual](https://www.gnu.org/software/coreutils/manual/coreutils.html)\nfor many more details.\n"
  },
  {
    "path": "mac/capture-screenshot-to-clipboard-from-cli.md",
    "content": "# Capture Screenshoot To Clipboard From CLI\n\nMacOS comes with a `screencapture` utility that you can run from the terminal\nto activate the built-in screenshot functionality on Mac.\n\nUsually when I am taking a screenshot, I want to do something with it right\naway. Such as paste it into an application or group chat. The `-c` flag forces\nthe screen capture to go the clipboard.\n\nI also generally want to capture a specific area of the screen so that the\ncaptured image includes the right amount of context and nothing more. The `-i`\nflag puts you in interactive screen capture mode. That means your cursor will\nturn into a crosshair that you can use to make a drag selection of the capture\narea.\n\n```bash\n$ screencapture -ic\n```\n\nSelect an area to capture, it's now on your clipboard, paste it where you need\nit.\n\nNote: The first time you run this command, your terminal program (e.g. iTerm2)\nmay prompt you for the necessary OS permissions in order to capture images of\nyour screen. You'll need to grant those permissions and then rerun the command.\n\nSee `man screencapture` for more details.\n"
  },
  {
    "path": "mac/check-network-quality-stats-from-the-command-line.md",
    "content": "# Check Network Quality Stats From The Command Line\n\nMacOS comes with a little known CLI utility for checking your current network\nquality statistics. It is aptly named `networkQuality`.\n\nHere is what a basic run of the tool might output:\n\n```bash\n$ networkQuality\n\n...\nDownlink: capacity 281.430 Mbps, responsiveness 101 RPM - Uplink: capacity 16.629 Mbps, responsiveness 101 R\nDownlink: capacity 285.534 Mbps, responsiveness 101 RPM - Uplink: capacity 16.028 Mbps, responsiveness 101 R\n==== SUMMARY ====\nUplink capacity: 22.982 Mbps\nDownlink capacity: 288.152 Mbps\nResponsiveness: Low (93 RPM)\nIdle Latency: 26.375 milliseconds\n```\n\nYou can get an even more detailed summary with the `-v` option:\n\n```bash\n$ networkQuality -v\n\n...\n==== SUMMARY ====\nUplink capacity: 18.257 Mbps (Accuracy: High)\nDownlink capacity: 469.355 Mbps (Accuracy: High)\nResponsiveness: Medium (252 RPM) (Accuracy: High)\nIdle Latency: 25.583 milliseconds (Accuracy: High)\nInterface: en0\nUplink bytes transferred: 19.750 MB\nDownlink bytes transferred: 488.265 MB\nUplink Flow count: 8\nDownlink Flow count: 12\nStart: 9/24/24, 11:06:20 AM\nEnd: 9/24/24, 11:06:30 AM\nOS Version: Version 13.5.2 (Build 22G91)\n```\n\nSee `man networkQuality` for more details.\n\n[source](https://cyberhost.uk/the-hidden-macos-speedtest-tool-networkquality/)\n"
  },
  {
    "path": "mac/clean-up-old-homebrew-files.md",
    "content": "# Clean Up Old Homebrew Files\n\nIf you've been using [Homebrew](https://github.com/Homebrew/homebrew) for a\nwhile, you may have built up some cruft in the form old and outdated files.\nThese will not be cleaned up automatically. You have do tell Homebrew to do\nso. This can be done with the following command.\n\n```bash\n$ brew cleanup\n```\n\nThis command will report what files it cleans up as well as how much disk\nspace it was able to clear.\n\nSee `man brew` for more details.\n\nh/t Dorian Karter\n"
  },
  {
    "path": "mac/control-which-monitor-app-switcher-appears-on.md",
    "content": "# Control Which Monitor App Switcher Appears On\n\nFor the most part when I hit `cmd+tab` (and `cmd+shift+tab`) to switch between\napps, the visual switcher UI (which shows a row of the open apps) appears on my\nmain monitor. However, sometimes I will be hitting `cmd+tab` and nothing shows\nup on my main monitor. I look to the right at my side monitor and there is the\napp switcher UI.\n\nWhy is it appearing over there all of a sudden?\n\nThe reason is that the app switcher UI is anchored to the same screen where the\ndoc is located. Though the doc defaults to my main monitor, if I access the doc\nfrom the side monitor, now it is anchored there.\n\nTo switch it back, I just have to make the doc slide up on my main monitor by\nrunning my mouse down to the bottom of that screen.\n\nThe switch up was because I accidentally accessed the doc on my side monitor\nwithout realizing.\n\n[source](https://superuser.com/a/744680)\n"
  },
  {
    "path": "mac/convert-an-heic-image-file-to-jpg.md",
    "content": "# Convert An HEIC Image File To JPG\n\nI took a photo with my iPhone and then airdropped it to my Mac. This opened it\nup in Preview. From there I could see that the extension on the file was HEIC.\nI'm not familiar with that filetype and what I want is a JPG.\n\nThe Preview app (which is already open in this scenario) can handle this\nconversion.\n\nGo to _File_ > _Export..._\n\nChange the _format_ from `HEIC` to `JPEG`.\n\nFeel free to update the name and save location at this point as well.\n\nThen hit _Save_ and Preview will perform the conversion.\n\n[source](https://osxdaily.com/2019/11/22/convert-heic-to-jpg-mac-preview/)\n"
  },
  {
    "path": "mac/default-screenshot-location.md",
    "content": "# Default Screenshot Location\n\nBy default, Mac saves all screenshots to the desktop. If you'd like\nscreenshots to be dumped somewhere else, you have to configure it manually\nfrom the command line. For instance, if you'd like your screenshots to be\nsaved in the `~/screenshots` directory, then enter the following commands:\n\n```bash\n$ mkdir ~/screenshots\n$ defaults write com.apple.screencapture location ~/screenshots\n$ killall SystemUIServer\n```\n\n[source](http://osxdaily.com/2011/01/26/change-the-screenshot-save-file-location-in-mac-os-x/)\n"
  },
  {
    "path": "mac/detect-how-long-a-user-has-been-idle.md",
    "content": "# Detect How Long A User Has Been Idle\n\nThe `ioreg` utility on MacOS dumps the I/O Kit registry tree. This lets us look\nat the state of all hardware devices and drivers registered with I/O Kit.\nLooking specifically at the Human Interface Device subsystem (`IOHIDSystem`), we\ncan find a handful of properties including the `HIDIdleTime`.\n\n```bash\n$ ioreg -c IOHIDSystem | awk '/HIDIdleTime/'\n    | | |   \"HIDIdleTime\" = 91831000\n```\n\nThat value is the number of nanoseconds since a human input device was last\ninteracted with. That is the amount of time the user (me) has been idle.\n\nI can convert this to seconds, which is the small amount of time between me\nhitting enter in the terminal and the command finding the idle time.\n\n```bash\n$ ioreg -c IOHIDSystem | awk '/HIDIdleTime/ {printf \"%.2f seconds\\n\", $NF/1000000000}'\n0.13 seconds\n```\n\nI can run this in `watch` to see the elapsed idle time increment.\n\n```bash\nwatch -n 1 \"echo -n 'Idle time: '; ioreg -c IOHIDSystem | awk '/HIDIdleTime/ {printf \\\"%.1f seconds\\\\n\\\", \\$NF/1000000000}'\"\n```\n\nAfter watching the _idle time_ increment for a bit, I can move the mouse and\nwatch it reset on the next `watch` loop.\n\nThis could be used as part of a script that takes certain actions after the user\nhas been idle for a while, like putting the display to sleep or stopping a time\ntracker app.\n\nThere is a _lot_ going on in the `ioreg` output and it's hard to make sense of\nhardly any of it. I found running `ioreg -c IOHIDSystem | less`, searching for\n`IdleTime`, and browsing from there to be a good starting point.\n"
  },
  {
    "path": "mac/disable-swipe-navigation-for-a-specific-app.md",
    "content": "# Disable Swipe Navigation For A Specific App\n\nMac's touch pad has a bunch of handy swipe gestures, including swiping two\nfingers to the left or the right to navigate backward or forward. This\nparticular gesture can be globally enabled and disabled. I find it useful\nfor most apps and a pain in a few apps, such as Google Chrome.\n\nFrom the terminal we can disable it for a specific app (like Google Chrome):\n\n```bash\n$ defaults write com.google.Chrome AppleEnableSwipeNavigateWithScrolls -bool FALSE\n```\n\nRestart the target application, in my case Chrome. The left and right swipe\nnavigation will no longer be triggered.\n\n[source](https://apple.stackexchange.com/questions/21236/how-do-i-disable-chromes-two-finger-back-forward-navigation)\n"
  },
  {
    "path": "mac/display-a-message-with-alfred.md",
    "content": "# Display A Message With Alfred\n\nWant to display some text in a large format on your screen for someone else\nto read? The [Alfred app](https://www.alfredapp.com/) can help.\n\nActivate Alfred and type in some text. Then hit `Cmd+L`.\n\nThe shorter the snippet of the text, the larger it will appear.\n"
  },
  {
    "path": "mac/find-the-process-using-a-specific-port.md",
    "content": "# Find The Process Using A Specific Port\n\nThe `netstat` utility is often recommended for finding the PID (process ID)\nbound to a specific port. Unfortunately, Mac's version of netstat does not\nsupport the `-p` (process) flag. Instead, you'll want to use the `lsof`\nutility.\n\n```bash\n$ sudo lsof -i tcp:4567\n```\n\nRunning this will produce a nicely formatted response that tells you several\npieces of information about the process bound to `:4567` including the PID.\n\n[source](https://stackoverflow.com/questions/3855127/find-and-kill-process-locking-port-3000-on-mac)\n"
  },
  {
    "path": "mac/gesture-for-viewing-all-windows-of-current-app.md",
    "content": "# Gesture For Viewing All Windows Of Current App\n\nWhen working on a web application, I often end up with a couple Chrome\nwindows open and sometimes even a couple terminal windows open. I generally\nuse the `Cmd+~` key binding to toggle through them. This can occasionally\nget confusing though. To get the fuller picture, I can get a birds-eye view of all windows for\nthe current app using a track pad gesture.\n\nSwiping down with three fingers on the track pad will provide a zoomed out\nview of all windows. Click on the window you care about to view that or\nswipe back up with three fingers to dismiss it.\n\n[source](https://twitter.com/HipsterSmoothie/status/1084565618009862145)\n"
  },
  {
    "path": "mac/insert-a-non-breaking-space-character.md",
    "content": "# Insert A Non-Breaking Space Character\n\nOn Mac, you can insert a non-breaking space character by hitting\n`option-space`.\n\nI'm not sure when people use non-breaking spaces, but this is a handy\nshortcut for those situations.\n\n[source](https://twitter.com/jnadeau/status/725436138601615360)\n"
  },
  {
    "path": "mac/inspect-assertions-preventing-sleep.md",
    "content": "# Inspect Assertions Preventing Sleep\n\nThe `pmset` command is for inspecting and manipulating _Power Management\nSettings_ on MacOS. The `-g` flag is for _getting_ details. We can get a summary\nof power assertions with `-g assertions`. These assertions are ways that the\nsystem and display are prevented from sleeping.\n\nA common assertion preventing sleep is the user being active. Another example of\nan assertion is a program like `caffeinate` that sets a timeout preventing sleep\nfor a fixed period of time.\n\nHere I activate a 30 minute (1600 second) `caffeinate` session and then I\ninspect the power management assertions which shows the details of that\nassertion as well as two others.\n\n```bash\n❯ caffeinate -t 1600 &\n[1] 98217\n\n❯ pmset -g assertions\n2025-11-02 13:20:57 -0600\nAssertion status system-wide:\n   BackgroundTask                 0\n   ApplePushServiceTask           0\n   UserIsActive                   1\n   PreventUserIdleDisplaySleep    0\n   PreventSystemSleep             0\n   ExternalMedia                  0\n   PreventUserIdleSystemSleep     1\n   NetworkClientActive            0\nListed by owning process:\n   pid 98217(caffeinate): [0x00045477000194b3] 00:00:03 PreventUserIdleSystemSleep named: \"caffeinate command-line tool\"\n        Details: caffeinate asserting for 1600 secs\n        Localized=THE CAFFEINATE TOOL IS PREVENTING SLEEP.\n        Timeout will fire in 1597 secs Action=TimeoutActionRelease\n   pid 145(WindowServer): [0x00044f2f00099212] 00:00:00 UserIsActive named: \"com.apple.iohideventsystem.queue.tickle serviceID:10009be9e service:AppleUserHIDEventService product:CTRL Keyboard eventType:3\"\n        Timeout will fire in 600 secs Action=TimeoutActionRelease\n   pid 80(powerd): [0x00044f2f00019216] 00:22:34 PreventUserIdleSystemSleep named: \"Powerd - Prevent sleep while display is on\"\n```\n\nSee `man pmset` and `man caffeinate` for more details.\n"
  },
  {
    "path": "mac/keyboard-shortcuts-for-interacting-with-text-areas.md",
    "content": "# Keyboard Shortcuts For Interacting With Text Areas\n\nWhen interacting with a document text area on MacOS (such as in the Notes app),\nthere are a bunch of keyboard shortcuts made available to you via the operating\nsystem.\n\nA couple common ones that I'm used to from Unix environments are:\n\n- `ctrl-a` to move the cursor to the beginning of the line\n- `ctrl-e` to move the cursor to the end of the line\n- `ctrl-p` to move the cursor up a line (this is a common _previous_ keybinding)\n- `ctrl-n` to move the cursor down a line (this is a common _next_ keybinding)\n\nA handy one that I wasn't aware of is `ctrl-l` which will scroll the text area\nso that the cursor gets centered in the view area.\n\nA much more niche one I wasn't aware of is `ctrl-t` which swaps the character\nbefore the cursor with the character after the cursor. I can only imagine this\nbeing useful for quickly fixing transposed characters in a misspelled word,\ne.g. `baer`.\n\nThere are many more *Document Shortcuts* as well as well as keyboard shorcuts\nfor other apps and situations. The full listing is at [Mac Keyboard\nShortcuts](https://support.apple.com/en-us/102650).\n"
  },
  {
    "path": "mac/launch-some-confetti.md",
    "content": "# Launch Some Confetti\n\nIf you have [Raycast](https://www.raycast.com/) installed on your machine, then\nyou have quick access to some confetti via their quick command palette. Trigger\nthe command palette to open, start typing `confetti` until it appears as the\nfocused option, and then hit enter.\n\n🎉\n\nWe can launch confetti other ways, including programmatically from scripts.\n\nTo do this, we need to first find the _deeplink_ for the Raycast _confetti_\nprogram. Trigger the command palette and type out `confetti` again. However,\nthis time instead of hitting enter, hit `Cmd+k` to open other actions. Find the\n_Copy Deeplink_ option.\n\nYou should now have this on your clipboard:\n\n```\nraycast://extensions/raycast/raycast/confetti\n```\n\nWith this deeplink in hand, we can now trigger confetti other places. The\neasiest way to do this is to open a terminal and pass that deep link as an\nargument to `open`.\n\n```bash\n$ open raycast://extensions/raycast/raycast/confetti\n```\n\nNow you can wrap that up in any old bash script or even just tack it on to the\nend of a run of your test suite:\n\n```bash\n$ rails test && open raycast://extensions/raycast/raycast/confetti\n```\n"
  },
  {
    "path": "mac/list-all-the-say-voices.md",
    "content": "# List All The Say Voices\n\nThe `say` command can be a fun party trick.\n\n```bash\n$ say Get ready for the bass to drop\n```\n\nYour friends will be even more impressed when you use some of the alternate\nvoices.\n\n```bash\n$ say -v Daniel \"Would you like a cup of tea?\"\n```\n\nTo see all the alternate voices available, type the following\n\n```bash\n$ say -v '?'\n```\n\n[source](http://stackoverflow.com/questions/1489800/getting-list-of-mac-text-to-speech-voices-programmatically)\n"
  },
  {
    "path": "mac/open-finder-app-to-specific-directory.md",
    "content": "# Open Finder.app To Specific Directory\n\nThe Mac OSX built-in GUI for navigating directories and files is _Finder.app_.\nI use it just about anytime I need to drag a file on my machine into Slack,\nDiscord, Google Drive, or wherever else has a file drop zone.\n\nSometimes certain directories can be hard to navigate to because they are\ndeeply nested or because Mac hides them by default. The `~/Library` directory\nis a great example of the latter.\n\nI can use the `open` command from the terminal to open a Finder window right in\nthat directory.\n\n```bash\n$ cd ~/Library\n$ open .\n```\n\nI first navigated there and then I ran `open .` which means open the current\ndirectory. For directories, `open` defaults to using Finder.app.\n\nI could have also run `open` with the target directory name instead of\nnavigating there first.\n\n```bash\n$ open ~/Library\n```\n\nSee `man open` for more details.\n"
  },
  {
    "path": "mac/prevent-sleep-with-the-caffeinate-command.md",
    "content": "# Prevent Sleep With The Caffeinate Command\n\nMacOS has a built-in utility `caffeinate` that can programatically prevent your\nmachine from sleeping. There are two kinds of sleep that it can prevent via\n_assertions_.\n\n> caffeinate creates assertions to alter system sleep behavior.\n\nThe two kinds of sleep behavior are _display sleep_ and _system idle sleep_. An\nassertion to prevent display sleep can be created with `-d` and system idle\nsleep with `-i`.\n\nWe can combine those to prevent both and then specify a duration (_timeout_)\nwith `-t` (with a value in seconds).\n\n```bash\ncaffeinate -d -i -t 600\n```\n\nThis creates assertions with 10 minute timeouts for both display and system idle\nsleep.\n\nThe `caffeinate` command is blocking, so if you want to start it in the\nbackground, you can do that like so:\n\n```bash\ncaffeinate -d -i -t 600 &\n```\n\nSee `man caffeinate` for more details.\n"
  },
  {
    "path": "mac/quickly-type-en-dashes-and-em-dashes.md",
    "content": "# Quickly Type En Dashes And Em Dashes\n\nTo type a hyphen, you hit the key right next to the zero: `-`. But what about\nif you need the similar looking en dash and em dash?\n\nSome programs have text areas that will automatically convert two consecutive\ndashes into an em dash.\n\nThere is a more reliable method that can get you both: these two keybindings\nwhich are a variation of the `-` key itself.\n\n* `Option -` will produce an en dash (–), named that because it is typically\n  the width of the n character.\n\n* `Option Shift -` will produce an em dash (—), named that because it is\n  typically the width of the m character.\n\nThe en dash seems to be the less familiar of the two. For more details on when\nto use that, [check out this excerpt from Dreyer's\nEnglish](https://twitter.com/jbrancha/status/1344345683294380035).\n\nh/t [Shawn Wang (@swyx)](https://twitter.com/swyx/status/1344127570753646593?s=20)\n"
  },
  {
    "path": "mac/require-additional-js-libraries-in-postman.md",
    "content": "# Require Additional JS Libraries In Postman\n\nWhen writing pre-request scripts and test scripts as part of a\n[Postman](https://www.getpostman.com/) request, you aren't limited to\nvanilla JavaScript. There are a handful of libraries that can be required\nwhere needed.\n\nThis short list of available libraries includes `cherrio`, `lodash`, and\n`moment`.\n\nTo pull one of these into a particular script, use the standard `require`\nfeature:\n\n```javascript\nvar moment = require('moment');\n\nvar now = moment();\n```\n\nFor a full list of what is available, check out [Postman's Sandbox API\nReference](https://www.getpostman.com/docs/postman/scripts/postman_sandbox_api_reference).\n"
  },
  {
    "path": "mac/resize-app-windows-with-applescript.md",
    "content": "# Resize App Windows With AppleScript\n\nI showed in a [previous\nTIL](run-applescript-commands-inline-in-the-terminal.md) how we can run\nAppleScript commands inline from the terminal. Here is an inline command\nfor positioning and resizing your iTerm2 window.\n\n```bash\nosascript -e 'tell application \"iTerm2\"\n  set the bounds of the first window to {50, 50, 1280, 720}\nend tell'\n```\n\nThe first two values tell the command the `x` and `y` coordinates of where\nto position the upper left corner of the window relative to the upper left\ncorner of your screen. The next two values are the `width` and `height` that\nthe window should be resized to.\n\n[source](https://apple.stackexchange.com/questions/98064/set-size-of-window-to-exact-pixels-and-place-via-x-y-coordinates)\n"
  },
  {
    "path": "mac/resizing-both-corners-of-a-window.md",
    "content": "# Resizing Both Corners Of A Window\n\nHold the `option` key while resizing a corner of a window and it will\nsimultaneously and equivalently resize the opposite corner.\n"
  },
  {
    "path": "mac/reveal-location-of-file-in-finder-app.md",
    "content": "# Reveal Location Of File In Finder.app\n\nIn the terminal I have the path to an image file. I want to open Finder.app to\nthe location of that image file so that I can drag and drop it into a file\nupload area in the browser.\n\nInstead of opening a Finder.app window and navigating directory by directory to\nthe location, I can use the `open` command. Using `open` directly with the image\nfile will open the image in Preview.app. I want to reveal the directory that the\nimage file is in within Finder.app. _Reveal_ is the keyword and the `-R` flag\ndoes just that.\n\nHere is an example of this that I actually ran when uploading a screenshot that\nwent into [this blogmark post](https://still.visualmode.dev/blogmarks/255):\n\n```bash\n$ open -R /Users/lastword/images/tiobe-index-graph-march-2026.png\n```\n\nSee `man open` for more details.\n"
  },
  {
    "path": "mac/run-a-hardware-check.md",
    "content": "# Run A Hardware Check\n\nIf your Mac is behaving in an odd way, there may be an issue with some piece\nof the hardware -- such as the RAM.\n\nYou can perform a hardware check in order to chase down a diagnosis.\n\n- Shutdown your machine\n- Boot your machine\n- While it is booting, hold down the `d` key\n\nAt this point, the machine should have booted into a special hardware check\nmode. Select your preferred language, the hardware check will be performed,\nand any issues will be reported.\n\nh/t Dillon Hafer\n"
  },
  {
    "path": "mac/run-applescript-commands-inline-in-the-terminal.md",
    "content": "# Run AppleScript Commands Inline In The Terminal\n\n[AppleScript](https://developer.apple.com/library/archive/documentation/AppleScript/Conceptual/AppleScriptLangGuide/introduction/ASLR_intro.html)\nis often invoked as a series of commands from a file. It is also possible to\nexecute individual commands inline in the terminal. Use the `-e` flag to\nspecify the command.\n\nFor example, if you'd like to mute your Mac:\n\n```bash\n$ osascript -e 'set volume 0'\n```\n\nRun that and your Mac's volume will now be at zero.\n\n[source](http://osxdaily.com/2016/08/19/run-applescript-command-line-macos-osascript/)\n"
  },
  {
    "path": "mac/set-a-window-to-its-default-zoom-level.md",
    "content": "# Set A Window To Its Default Zoom Level\n\nOften when showing my screen to someone else or connecting to a project, I\nhave to adjust the zoom level of my current window by hitting `Cmd +` a\nbunch of times. Once I am done I usually do some guess work to get the\nscreen size back to what I am used to, hitting `Cmd -` a couple times.\n\nThere is an easier way.\n\nHitting `Cmd 0` will return the window back to its default zoom level.\n\nh/t Jake Worth\n"
  },
  {
    "path": "mac/specify-app-when-opening-from-command-line.md",
    "content": "# Specify App When Opening From Command Line\n\nWhen you `open` files from the command line\n\n```bash\n$ open README.md\n```\n\nthe default app for that filetype will be used. For me, `README.md` will be\nopened in VS Code.\n\nIf you have a different app in mind, you can specify it using the `-a` flag:\n\n```bash\n$ open README.md -a Notes\n```\n\nThis will open `README.md` in Mac's Notes app.\n\nSee `man open` for more details.\n"
  },
  {
    "path": "mac/start-amphetamine-session-with-applescript.md",
    "content": "# Start Amphetamine Session With AppleScript\n\nI use the _Amphetamine_ app on Mac to keep my computer from going to sleep\nduring the day. It is a menu bar app that can be used to start a _Session_ of\ntime where it will keep your computer from going to sleep. At the start of my\nday, I'll typically start an 8 hour _Session_. This is useful if I have to step\naway fo 10 minutes or if I'm doing some writing in my notebook, my computer\nwon't go to sleep on me.\n\nThough these sessions can be controlled from the menu bar app, I was excited to\nlearn that I can also programatically start a session with AppleScript.\n\nHere is how to start a _Session_ (overriding an existing session) with options\nthat specify it is 8 hours long and the display should not be allowed to sleep.\n\n```bash\n$ osascript -e 'tell application \"Amphetamine\" to start new session with options {duration:8, interval:hours, displaySleepAllowed:false}'\n```\n\nThe `interval` could also be `minutes` and then I could change the duration to\nan amount of time that makes sense in minutes, e.g. `90` for 1.5 hours.\n\nNote: the `with options {...}` segement is all or nothing. All three need to be included or don't include the clause at all.\n\nAdditionally, a session of indefinite duration can be started by including no options:\n\n```bash\n$ osascript -e 'tell application \"Amphetamine\" to start new session'\n```\n\nAnd any existing session can be ended with:\n\n```bash\n$ osascript -e 'tell application \"Amphetamine\" to end session'\n```\n\n[source](https://iffy.freshdesk.com/support/solutions/articles/48000078223-applescript-documentation)\n"
  },
  {
    "path": "mac/uninstall-logitech-g-hub-from-mac.md",
    "content": "# Uninstall LogiTech G Hub From Mac\n\nI rarely uninstall software from my Mac. And unless the software is nice enough\nto provide a clear 'Uninstall' flow, it is not straightforward how to do it. In\nfact, it probably varies quite a bit from app to app.\n\nIn the case of LogiTech's G Hub, I was able to find the following instructions\nfor uninstalling it. The thing of note is that the updater app can take an\n`--uninstall` flag.\n\n```bash\nsudo /Applications/lghub.app/Contents/MacOS/lghub_updater.app/Contents/MacOS/lghub_updater --uninstall\n```\n\nI still had to remove the app launcher from my `Applications` directory.\n\n[source](https://www.reddit.com/r/LogitechG/comments/bluth5/comment/lbhctx1/)\n"
  },
  {
    "path": "mac/use-a-different-font-with-iterm2.md",
    "content": "# Use A Different Font With iTerm2\n\nI wanted to give [`gh-dash`](https://github.com/dlvhdr/gh-dash) a try, but\nafter installing and opening it up, I was seeing a bunch of `?` characters\nwhere specialized font icons were missing. Their README recommended installing\na [`Nerd Font`](https://github.com/ryanoasis/nerd-fonts) that includes those\nicons, such as [`Fira Code`](https://github.com/tonsky/FiraCode).\n\nI was able to install `font-fira-code-nerd-font` with homebrew:\n\n```bash\n$ brew install font-fira-code-nerd-font\n```\n\nThen to get iTerm2 to start using that font, I had to change the font setting\nfor my current profile.\n\nUnder the _iTerm2_ menu is _Settings..._. From there, I clicked the _Profiles_\nsection. For the _Default_ profile, I went to the _Text_ tab and under _Font_ I\nselected _FireCode Nerd Font Mono_ from the dropdown.\n\nThat won't take effect on any current iTerm2 windows. Since I have everything\nrunning through `tmux`, I could close my current window, open a new one\n(`Cmd+N`), and reconnect to my existing `tmux` session. Now when I run `gh\ndash`, I see all the font icons that were missing before.\n"
  },
  {
    "path": "mac/use-default-screenshot-shortcuts-with-cleanshot-x.md",
    "content": "# Use Default Screenshot Shortcuts With CleanShot X\n\n_[Watch the screencast](https://www.youtube.com/watch?v=yoMWfe1F9h4) that\naccompanies this TIL to see how to do this visually._\n\nOn macOS there are a set of keyboard shortcuts for taking screenshots. The one\nthat I use most often is `Cmd-Shift-4`. It turns the cursor into cross hairs so\nthat I can make a drag selection of part of the screen to be captured as a\nscreenshot.\n\nI've recently transitioned to using CleanShot X for taking screenshots. It\noffers some improvements over the built-in screenshot tool, like annotations\nand sticking recently screenshots in the corner of the window. As part of this\ntransition, I wanted `Cmd-Shift-4` to activate CleanShot X's _Capture Area_\nfeature instead of the built-in one.\n\nTo do this, first open up _System Preferences > Keyboard > Shortcuts_. Then go\nto the _Screenshots_ section and de-select any shortcuts that you want to\nremap. For `Cmd-Shift-4`, that is \"Save picture of selected area as a file\".\n\nThen I open _Preferences > Shortcuts_ for CleanShot X and map _Capture Area_ to\n`Cmd-Shift-4`.\n\nHitting `Cmd-Shift-4` will now activate CleanShot X's Capture Area instead of\nthe one for the built-in screenshot app.\n"
  },
  {
    "path": "mac/view-all-windows-of-the-current-app.md",
    "content": "# View All Windows Of The Current App\n\nIn [Gesture For Viewing All Windows Of Current\nApp](gesture-for-viewing-all-windows-of-current-app.md), I showed off a\ntrack pad gesture that allows you to view all window instances of the app\nyou are currently focused on.\n\nThere is an analog keyboard shortcut that allows you to do the same thing --\nwithout dragging your hands away from the keys.\n\nTap `Ctrl+↓` to do the same.\n"
  },
  {
    "path": "mac/write-system-clipboard-to-a-file.md",
    "content": "# Write System Clipboard To A File\n\nMacOS has two CLI utilities `pbcopy` and `pbpaste` which, respectively, copy\n_to_ and paste _from_ the system clipboard via the CLI.\n\nLet's say I've just copied a large block of text from somewhere onto my system\nclipboard. I now want to paste that into a new file. Instead of creating a new\nfile, opening it up in my preferred editor, pasting all that text, and saving\nthe file, I can run one small command from the CLI.\n\n```bash\n$ pbpaste > data.txt\n```\n\nThis redirects the contents of `pbpaste` (which is the system clipboard) into\nthe file `data.txt`. If that file doesn't already exist, then it will be\ncreated before the data is written to it.\n\nSee `man pbpaste` for more details.\n"
  },
  {
    "path": "mise/create-umbrella-task-for-all-test-tasks.md",
    "content": "# Create Umbrella Task For All Test Tasks\n\nWhen I was first sketching out the [`mise` tasks](https://mise.jdx.dev/tasks/running-tasks.html) for a Rails app, I added\nthe following two tasks. One is for running all the `rspec` tests. The other is\nfor running all the `vitest` (JavaScript) tests.\n\n```toml\n[tasks.\"test:rspec\"]\nrun = \"unbuffer bundle exec rspec\"\ndescription = \"Run RSpec tests\"\ndepends = [\"bundle-install\"]\n\n[tasks.\"test:vitest\"]\nrun = \"unbuffer yarn test run\"\ndescription = \"Run Vitest tests\"\ndepends = [\"node-install\"]\n```\n\nI didn't want to have to invoked both of this individually every time I wanted\nto run the full suite. So I added a `test:all` task to do it all.\n\n```toml\n[tasks.\"test:all\"]\ndescription = \"Run all tests (RSpec and Vitest)\"\nrun = [\n  \"unbuffer bundle exec rspec\",\n  \"unbuffer yarn test run\",\n]\ndescription = \"Run RSpec tests\"\ndepends = [\"bundle-install\", \"node-install\"]\n```\n\nThis worked (for now). But it ate at me, for a couple reasons. I had to\nduplicate everything about the existing `test:rspec` and `test:vitest` tasks.\nAnd this didn't account for a new kind of test task being added (e.g.\n`test:e2e`).\n\nInstead, I can rely on `depends` and wildcards to achieve this without the\nduplication which makes it more future-proof.\n\n```toml\n[tasks.\"test:all\"]\ndescription = \"Run all tests (RSpec and Vitest)\"\ndepends = [\"test:*\"]\n```\n\nRunning `mise run test:all` won't execute its own command, but because it\ndepends on all other `test:*` tasks, the tests will get run through those\ndependencies.\n\nThis task naming pattern also allows for calling all tests with `mise run \"test:**\"`.\n"
  },
  {
    "path": "mise/list-the-files-being-loaded-by-mise.md",
    "content": "# List The Files Being Loaded By Mise\n\nWhile running `mise` for the first time, after adding a `mise.toml` file to a\nproject, I noticed something strange. Instead of invoking the command I had\nspecified (`mise run dev`), several parellel tool downloads were kicked off. In\naddition to Ruby, it was installing an older version of Postgres, and lua. What\ngives?\n\nBy running `mise cfg`, I can list all the files being loaded by `mise` and get\nto the bottom of this.\n\n```bash\nmise cfg\n\nPath                         Tools\n~/.tool-versions             node, ruby, postgres, lua\n~/code/still/.ruby-version   ruby\n~/code/still/Gemfile         (none)\n~/code/still/.tool-versions  ruby\n~/code/still/mise.toml       (none)\n```\n\nI was only thinking about the files local to my project and I forgot that I\nhave a system-wide `.tool-versions` file. As we can see from the output, that\nfile specifies `postgres` and `lua` as well. Mise wanted to ensure that it had\ndownloaded the specified versions of each of those tools before running my\ntask.\n\n[source](https://mise.jdx.dev/configuration.html)\n"
  },
  {
    "path": "mise/look-in-ruby-version-dotfile.md",
    "content": "# Look In Ruby Version Dotfile\n\nNewer versions of [`mise`](https://mise.jdx.dev/dev-tools/) specifically only\nlook for tool versions in `mise.toml` as well as the asdf `.tool-versions` file.\nA lot of Ruby projects use the `.ruby-version` file to indicate the Ruby version\nof a project. To continue to use the `.ruby-version` file instead of migrating\nto `mise.toml`, you need to tell `mise` that you prefer to use the idiomatic\nversion file.\n\nI added the following line to my\n[`~/.config/mise/config.toml`](https://github.com/jbranchaud/dotfiles/commit/8edeb7a9c53500e89e88b4079cbd1859ebebcbda)\nfile:\n\n```toml\nidiomatic_version_file_enable_tools = [\"ruby\"]\n```\n\nNow, whenever `mise` is looking for the specified Ruby version of a project, it\nwill also look for `.ruby-version`.\n\nHere is a [full list of idomatic version files supported by\n`mise`](https://mise.jdx.dev/configuration.html#idiomatic-version-files).\n\nSee\n[`idiomatic_version_file_enable_tools`](https://mise.jdx.dev/configuration/settings.html#idiomatic_version_file_enable_tools)\nas well as the [Ruby-specific documentation](https://mise.jdx.dev/lang/ruby.html#ruby-version-and-gemfile-support)\nfor more details.\n"
  },
  {
    "path": "mise/override-your-project-mise-file.md",
    "content": "# Override Your Project Mise File\n\nA project I'm working on has a version-controlled `.mise.toml` file in it. Some\nchanges were made to that recently that introduce some env vars that conflict\nwith my setup. If I make edits to that file, then I have a modified version of\n`.mise.toml` sitting in my Git working copy.\n\n```\n# .mise.toml\n[env]\nCONFIG_SETTING = \"project\"\n```\n\nInstead, I can rely on the loading precedence rules of `mise` to override those\nproject settings with my individual settings. I can do that with the\n`.mise.local.toml` file which is played on top of any `mise` configuration from\nfiles further down the precedence chain.\n\n```\n# .mise.local.toml\n[env]\nCONFIG_SETTING = \"override\"\n```\n\nAssuming I have `mise` setup with my shell environment to automatically load in\nthese files, I can now check what takes precedence:\n\n```bash\n$ echo $CONFIG_SETTING\noverride\n```\n\nMake sure `.mise.local.toml` is included in the `.gitignore` file to avoid\nchecking in your personal environment overrides.\n\nTo be sure about what files are loaded and in what order, give `mise cfg` a try.\nI discuss that in more detail in [List The Files Being Loaded By Mise](list-the-files-being-loaded-by-mise.md).\n"
  },
  {
    "path": "mise/pick-from-tasks-using-interactive-picker.md",
    "content": "# Pick From Tasks Using Interactive Picker\n\nIn [Add Mise Tasks For Common Workflow\nCommands](https://www.visualmode.dev/add-mise-tasks-for-common-workflow-commands),\nI wrote about a set of tasks I added as shortcuts for connecting to the `rails console` in various environments.\n\n```toml\n# mise.toml\n[tasks.\"console:staging\"]\ndescription = \"Open a Rails console on staging\"\nrun = \"ssh -t my-app-staging dokku run my-app rails console\"\n\n[tasks.\"console:prod\"]\ndescription = \"Open a Rails console on production\"\nrun = \"ssh -t my-app-prod dokku run my-app rails console\"\n```\n\nWhen a project is configured with multiple `mise` tasks like this, we can invoke\n`mise run` without any specific arguments and it will prompt you with an\ninteractive picker. The picker will populate with all the tasks like so:\n\n```bash\n❯ mise run\nTasks\nSelect a task to run\n❯ console:prod     Open a Rails console on production\n  console:staging  Open a Rails console on staging\n/\nesc clear filter • enter confirm\n```\n\nWe can navigate between the options with the arrow keys (and if we exit _filter_\nmode by hitting `esc`, then `j/k` also work to move down and up). While in\n_filter_ mode, we can type into the prompt which will filter the list of\ncommands down to just the partial matches.\n\nOnce we're targeting the task we want to run, we hit `enter` and the task is\nexecuted.\n"
  },
  {
    "path": "mise/preserve-color-output-for-task-command.md",
    "content": "# Preserve Color Output For Task Command\n\nI decided to wrap a couple test running commands for a project into a single\n`test:all` mise task. It looked something like this:\n\n```toml\n[tasks.\"test:all\"]\nrun = \"\"\"\nbundle exec rspec\nyarn test run\n\"\"\"\ndescription = \"Run all tests (RSpec and Vitest)\"\ndepends = [\"bundle-install\", \"node-install\"]\n```\n\nI can run this with `mise run test:all` and it works. However, there is a\nglaring issue that immediately juts out. All of the test runner output is\nuncolored text. I'm used to and strongly prefer greens (passes), reds (fails),\nand yellows (skips) of test runner output.\n\nThe test runners lose the text coloring when run through `mise` because they\nbelieve they are not running in _interactive_ mode.\n\nThe [`expect`](https://linux.die.net/man/1/expect) tools (`brew install\nexpect`) install with another binary called\n[`unbuffer`](https://linux.die.net/man/1/unbuffer). `unbuffer` can coerce a\ncommand to run in interactive mode. Prepending these test runner commands with\n`unbuffer` will preserve the colors as the results are output to the terminal.\n\nHere is the update `test:all` task:\n\n```toml\n[tasks.\"test:all\"]\nrun = \"\"\"\nunbuffer bundle exec rspec\nunbuffer yarn test run\n\"\"\"\ndescription = \"Run all tests (RSpec and Vitest)\"\ndepends = [\"bundle-install\", \"node-install\"]\n```\n\nFor some commands, it seems able to stream out (rather than _buffer_) the\nresults (e.g. with `vitest`). Whereas with `rspec`, the test suite runs to\ncompletion and is then output to the terminal. I'm still investigating\nstreaming the `rspec` results.\n"
  },
  {
    "path": "mise/read-existing-dot-env-file-into-env-vars.md",
    "content": "# Read Existing Dot Env File Into Env Vars\n\nJust about any web app that I've worked on has had a `.env` file as a way of\nconfiguring aspects of the app specific to that environment. These typically\nare read into the environment with a language-specific\n[dotenv](https://github.com/bkeepers/dotenv) tool.\n\nMise supports this convention. In addition to specifying individual non-secret\nenv vars, you can also instruct `mise` to read-in a `.env` file like so:\n\n```toml\n[env]\nPORT=3344\n_.file = \".env\"\n```\n\nThe `_.file` line tells `mise` that there is a file `.env` with key-value pairs\nthat it should read in. It can even handle `.env.json` and `.env.toml` file\nformats.\n\nTo ensure that `mise` is picking up the values from the `.env` file, you can\nrun the following command and make sure they show up in the output:\n\n```bash\n$ mise env\n```\n\n[source](https://mise.jdx.dev/environments/secrets.html)\n"
  },
  {
    "path": "mise/run-a-command-with-specific-tool-version.md",
    "content": "# Run A Command With Specific Tool Version\n\nBecause I'm using `mise` to manage the versions of tools like Node, I can\nexecute commands in the context of specific versions. Behind the scenes `mise`\nmakes sure I have the necessary tool(s) installed at the desired version(s).\n\nSo, [`mise exec` command](https://mise.jdx.dev/cli/exec.html) will default to\nusing the latest version of a tool if I haven't been more specific. At the time\nof this writing, for Node, that is v23.\n\n```bash\n$ mise exec node -- node --version\nv23.9.0\n```\n\nTo be specific I could specify the major version with `node@23` like so:\n\n```bash\nmise exec node@23 -- npx repomix\nNeed to install the following packages:\nrepomix@0.2.39\nOk to proceed? (y) y\n\n...\n```\n\nOr if I wanted to use a different, older version of Node, I could specify that\nas well. We can see it will first install that and then execute the command:\n\n```bash\n$ mise exec node@22 -- npx repomix\ngpg: Signature made Tue Feb 11 04:44:53 2025 CST\ngpg:                using RSA key C0D6248439F1D5604AAFFB4021D900FFDB233756\ngpg: Good signature from \"Antoine du Hamel <duhamelantoine1995@gmail.com>\" [unknown]\n\n📦 Repomix v0.2.39\n\n...\n```\n"
  },
  {
    "path": "mise/search-through-bin-paths-for-tool-locations.md",
    "content": "# Search Through Bin Paths For Tool Locations\n\nThe `mise bin-paths` command will list all the bin paths that are managed by\n`mise`. When you tell `mise` to install a tool, it installs a specific version\nat a location where its binaries can be made accessible on the system path.\n\nWhile `mise ls` is useful for seeing what is installed by `mise` and at what\nversion, the `bin-paths` command can tell you where those tool installations\nwith their binaries are located.\n\nCombine this with `grep` or `rg` to narrow down the results to tools by a\nspecific name:\n\n```bash\n❯ mise bin-paths | rg 'neovim'\n/Users/lastword/.local/share/mise/installs/npm-neovim/5.4.0/bin\n/Users/lastword/.local/share/mise/installs/pipx-neovim-remote/2.5.1/bin\n/Users/lastword/.local/share/mise/installs/neovim/0.11.6/bin\n```\n\nI can then look in one of these directories to see the one or more binaries that\nthey include. For instance, here is what is in the `node` bin path:\n\n```bash\n❯ ls /Users/lastword/.local/share/mise/installs/node/22.22.0/bin\n ./   ../   claude@   corepack@   node*   npm*   npx@\n```\n\nSee `mise bin-paths --help` for more details.\n"
  },
  {
    "path": "mongodb/determine-the-database-version.md",
    "content": "# Determine The Database Version\n\nWhether your Mongo database is local or remote, you should connect to it using\nthe [`mongo` CLI](https://docs.mongodb.com/manual/mongo/).\n\nOnce connected, you can issue the following query:\n\n```\ndb.version()\n```\n\nThis will output the version of your Mongo database.\n\n[source](https://docs.mongodb.com/manual/reference/method/db.version/)\n"
  },
  {
    "path": "mongodb/dump-a-remote-database.md",
    "content": "# Dump A Remote Database\n\nHere is a single-line script for dumping a remote mongo database. This will\ndump it to your local filesystem in a binary format (`.bson`) that you can then\nrestore to another mongo instance.\n\nCreate a file like this called `mongdump-cmd` and replace the various\nplaceholder values (e.g. `<HOST>`) with valid values for your remote mongo\ninstance.\n\n```bash\nmongodump --host '<HOST>:<PORT>' \\\n          --ssl \\\n          --username '<USER>' \\\n          --password '<PASSWORD>' \\\n          --authenticationDatabase 'admin' \\\n          --out ./mongo-backups/<DATE>-dump\n```\n\nCreate the backup directory:\n\n```bash\n$ mkdir mongo-backups\n```\n\nThen execute the bash script:\n\n```bash\n$ bash mongodump-cmd\n```\n\nThis will dump everything on the remote instance into the\n`mongo-backups/2020-06-20-dump/` directory. You can also include the `--db`\nflag to dump a specific database.\n\nThis can later be used with `mongoresetore` to restore the data to the mongo\ninstance you specify.\n"
  },
  {
    "path": "mongodb/dump-and-restore-with-a-single-gzip-file.md",
    "content": "# Dump And Restore With A Single gzip File\n\nThe `mongodump` and `mongorestore` utilities provide a way for grabbing all the\ndata from one database and putting it into another database. These commands are\nuseful for transitioning production data to a database instance with more\ncomputing resources.\n\nThe `--archive` and `--gzip` flags, supported by both commands, are what allow\nus to do the whole process with a single file. Without flags, `mongodump` will\noutput multiple `.bson` files.\n\nHere is what the `mongodump` command might look like pointed at a remote URI:\n\n```bash\nmongodump \\\n  --uri=\"mongodb+srv://<USER>:<PASSWORD>@<CLUSTER-HOST-URL>\" \\\n  --archive=\"myapp-dump.20221105.gz\" \\\n  --gzip\n```\n\nThis will take a little while to run based on the size of the database. The\nresult will be a file in your current directory with the name\n`myapp-dump.20221105.gz`. Because it is gzip'd, it will be a few times smaller\nthan the standing database.\n\nTo then load all the data into your new Mongo database cluster, you'll use\n`mongorestore` with all the same flags, making sure to swap out the destination\nURI details with those of the new instance.\n\n```bash\nmongorestore \\\n  --uri=\"mongodb+srv://<USER>:<PASSWORD>@<NEW-CLUSTER-HOST-URL>\" \\\n  --archive=\"myapp-dump.20221105.gz\" \\\n  --gzip\n```\n\nFor more details, see [Output an Archive\nFile](https://www.mongodb.com/docs/database-tools/mongodump/#output-to-an-archive-file)\nand [Compress the\nOutput](https://www.mongodb.com/docs/database-tools/mongodump/#compress-the-output).\n"
  },
  {
    "path": "mongodb/get-size-stats-for-a-collection.md",
    "content": "# Get Size Stats For A Collection\n\nFor any collection in your MongoDB instance.\n\n```javascript\n> db.getCollectionNames()\n[\"books\", \"authors\", \"genres\"]\n```\n\nYou can list a collection of stats, which include the amount of disk space that\ncollection is utilizing.\n\n```javascript\n> db.books.stats().size\n11057056\n```\n\nBy default this size is in bytes, which isn't all that human-readable of a\nvalue.\n\nBy passing in a `scale` value to `stats()`, you can get a value that is a bit\nmore understandable. A scale of `1024` would give you kilobytes, so a scale of\n`1024 * 1024` would give you megabytes.\n\n```javascript\n> db.books.stats({ scale: 1024 * 1024 }).size\n10\n```\n\n[source](https://docs.mongodb.com/manual/reference/method/db.collection.stats/)\n"
  },
  {
    "path": "mongodb/list-size-stats-for-all-collections.md",
    "content": "# List Size Stats For All Collections\n\nIn [Get Size Stats for a Collection](get-size-stats-for-a-collection.md), we\nsaw how to use `db.collection.stats()` and its `scale` parameter to get a\nuseful size metric for a given collection.\n\nWe can combine some of this concepts with some scripting to list human-readable\nsize metrics for all of our database's collections:\n\n```javascript\n> db.getCollectionNames().forEach(function (collectionName) {\n    sizeInMb = db[collectionName].stats({ scale: 1024 * 1024 }).size;\n    print(collectionName + \": \" + sizeInMb + \"MB\");\n  })\nbooks: 10MB\nauthors: 2MB\ngenres: 1MB\n```\n\nThis snippet gets all the collections for the current database and iterates\nover them. For each collection name, it looks up the `size` stat for that\ncollection scaled to megabytes and then prints it all out with some contextual\ninformation.\n\n[source](https://docs.mongodb.com/manual/faq/storage/#data-storage-diagnostics)\n"
  },
  {
    "path": "mysql/change-existing-column-to-not-null.md",
    "content": "# Change Existing Column To Not Null\n\nLet's say you have an existing nullable column. You want to update the schema\nto enforce a `not null` constraint on that column. You can do that with an\n[`alter table`](https://dev.mysql.com/doc/refman/8.0/en/alter-table.html) DDL\nstatement. You can do this with the `modify` or `change` option.\n\nWith `modify` you redeclare the column definition with the options that you\nwant. You'll need to know and specify the existing data type of that column.\n\n```sql\nalter table books modify publication_year int not null;\n```\n\nIt is possible, but clumsy to do this with the `change` option because you\ndeclare the column name twice. That's because `change` is typically used to\nrename a column.\n\n```sql\nalter table books change publication_year publication_year int not null;\n```\n\nIf you're updating a column for a table that already contains data, make a plan\nto backfill any existing records that have `null` for that column. Every record\nwill need a value in that column before the `modify` can be applied.\n\n[source](https://stackoverflow.com/a/6305252/535590)\n"
  },
  {
    "path": "mysql/connect-to-a-database-in-safe-update-mode.md",
    "content": "# Connect To A Database In Safe Update Mode\n\nThe MySQL client has a _Safe-Updates Mode_ that you can use when connecting to\na database. When this mode is active, the client will interrupt `update` and\n`delete` commands that don't specify a `where` clause that filters by a _key_\nvalue. That, or you need to explicitly `limit` the number of rows impacted by\nthe query.\n\nTo start a connection in this mode, you can use either the `--safe-updates`\nflag or the cheekier `--i-am-a-dummy` flag.\n\n```bash\n$ mysql --i-am-a-dummy -h ::1 -P 3309 -u root -D my-database\n```\n\nThen if you try to do an unrestricted `update` or `delete`, you'll see the\nfollowing message:\n\n```sql\nmysql> update users set email = 'oops@email.com';\nERROR 1175 (HY000): You are using safe update mode and you tried to update\na table without a WHERE that uses a KEY column.\n```\n\nThis can also be set within the connection like so:\n\n```sql\nmysql> set sql_safe_updates=1;\n```\n\n[source](https://dev.mysql.com/doc/refman/8.0/en/mysql-tips.html#safe-updates)\n"
  },
  {
    "path": "mysql/default-username-and-password-for-new-instance.md",
    "content": "# Default Username And Password For New Instance\n\nLet's say you've set up a fresh new instance of MySQL. Perhaps in a docker\ncontainer with a MySQL image. When you first connect to the instance, you'll be\nprompted for a username and password.\n\nWhat is the username and password for a MySQL instance you've just created?\n\nThere are defaults. The default username is `root` and the default password is\nleft blank.\n\nSo, your connection URL will look something like this:\n\n```\nmysql://root@localhost:3306\n```\n\nYou can use that on the CLI or plug it in to the connection details panel of\nyour favorite SQL client.\n\n[source](https://dev.mysql.com/doc/refman/8.0/en/default-privileges.html)\n"
  },
  {
    "path": "mysql/display-output-in-a-vertical-format.md",
    "content": "# Display Output In A Vertical Format\n\nOutput for tables with lots of columns can be hard to read and sometimes\noverflow the terminal window. Consider the output from [Show Indexes For A\nTable](show-indexes-for-a-table.md):\n\n```sql\n> show indexes in users;\n+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+\n| Table | Non_unique | Key_name     | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |\n+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+\n| users |          0 | PRIMARY      |            1 | id          | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |\n| users |          0 | unique_email |            1 | email       | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |\n+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+\n```\n\nWe can vertically orient the output of a statement by terminating it with\n`\\G` instead of `;` (or `\\g`).\n\n```sql\n> show indexes in users\\G\n*************************** 1. row ***************************\n        Table: users\n   Non_unique: 0\n     Key_name: PRIMARY\n Seq_in_index: 1\n  Column_name: id\n    Collation: A\n  Cardinality: 0\n     Sub_part: NULL\n       Packed: NULL\n         Null:\n   Index_type: BTREE\n      Comment:\nIndex_comment:\n*************************** 2. row ***************************\n        Table: users\n   Non_unique: 0\n     Key_name: unique_email\n Seq_in_index: 1\n  Column_name: email\n    Collation: A\n  Cardinality: 0\n     Sub_part: NULL\n       Packed: NULL\n         Null:\n   Index_type: BTREE\n      Comment:\nIndex_comment:\n```\n"
  },
  {
    "path": "mysql/doing-date-math.md",
    "content": "# Doing Date Math\n\nMySQL has an array of functions for interacting with `date` and `datetime`\nvalues. If you'd like to do math with a date to compute a date in the future\nor the past, you can use the\n[`DATE_ADD()`](https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-add)\nand\n[`DATE_SUB()`](https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-sub)\nfunctions.\n\n```mysql\nmysql> select now() Now, date_add(now(), interval 10 minute) '10 Minutes Later';\n+---------------------+---------------------+\n| Now                 | 10 Minutes Later    |\n+---------------------+---------------------+\n| 2018-10-18 15:53:29 | 2018-10-18 16:03:29 |\n+---------------------+---------------------+\n\nmysql> select now() Now, date_sub(now(), interval 9 day) '9 Days Earlier';\n+---------------------+---------------------+\n| Now                 | 9 Days Earlier      |\n+---------------------+---------------------+\n| 2018-10-18 15:54:01 | 2018-10-09 15:54:01 |\n+---------------------+---------------------+\n```\n\nThere are equivalent `ADDDATE()` and `SUBDATE()` functions if you prefer.\n\nCheck out [the\ndocs](https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html)\nfor more details.\n"
  },
  {
    "path": "mysql/dump-a-database-to-a-file.md",
    "content": "# Dump A Database To A File\n\nThe `mysqldump` client is a handy tool for creating a backup or snapshot of\na MySQL database. The standard use of this command produces an alphabetical\nseries of statements that comprise the structure and data of the specified\ndatabase. It directs all of this to `stdout`. You'll likely want to redirect\nit to a file.\n\n```bash\n$ mysqldump my_database > my_database_backup.sql\n```\n\nThe output will include special comments with MySQL directives that disable\nthings like constraint checking. This is what allows the output to be in\nalphabetical order without necessarily violating any foreign key\nconstraints.\n\nIf you need to dump multiple databases, include the `--databases` flag with\na space-separated list of database names. Or dump all of them with\n`--all-databases`.\n\nSee `man mysqldump` for more details.\n"
  },
  {
    "path": "mysql/echo-a-message-from-a-sql-file.md",
    "content": "# Echo A Message From A SQL File\n\nLet's say we have a SQL file that we run to seed our database. We want to echo\na message to stdout at the beginning of that file's execution. We can do this\nwith [a MySQL client _shell\ncommand_](https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-shell-commands.html).\nSpecifically, we need to use the `\\system` or `\\!` command to run our system's\n`echo` command.\n\nHere is what that could look like:\n\n```sql\n\\! echo '*****************************************'\n\\! echo '*                                       *'\n\\! echo '*  Loading seed data into the database  *'\n\\! echo '*                                       *'\n\\! echo '*****************************************'\n\ninsert into products ...\n```\n\nThat message banner will be output when you run the script.\n\n```bash\n$ mysql -h ::1 -P 3306 -u root -D local_database < seed_data.sql\n\n*****************************************\n*                                       *\n*  Loading seed data into the database  *\n*                                       *\n*****************************************\n```\n"
  },
  {
    "path": "mysql/get-idea-of-what-is-in-a-json-column.md",
    "content": "# Get Idea Of What Is In A JSON Column\n\nWhile digging through some data trying to reacquaint myself with the overall\nschema and data model, I ran into an issue selecting rows from this\n`content_resource` table. There was so much text packed in to the `\"body\"`,\n`\"summary\"`, and `\"description\"` key-value pairs of `fields` JSON column that a\nsimple `select * ... limit 3;` was overwhelming the screen with text and table\nformatting characters (i.e. `+------+-------`).\n\nI figured the `fields` JSON followed a reliable structure, at least for records\nof the same `type`. So, let's start by only grabbing the\n[`json_keys`](https://dev.mysql.com/doc/refman/8.4/en/json-search-functions.html#function_json-keys)\nso that I can get a sense of the shape of the JSON.\n\n```sql\nselect id, json_keys(fields)\nfrom content_resource\nwhere type = 'post'\nlimit 3;\n\n+-----+-----------------------------------------------------------------------------------------------------------+\n| id  | json_keys(`fields`)                                                                                       |\n+-----+-----------------------------------------------------------------------------------------------------------+\n|  1  | [\"body\", \"slug\", \"state\", \"title\", \"summary\", \"postType\", \"visibility\", \"description\", \"originalLessonId\"] |\n|  2  | [\"body\", \"slug\", \"state\", \"title\", \"summary\", \"postType\", \"visibility\", \"description\", \"originalLessonId\"] |\n|  3  | [\"body\", \"slug\", \"state\", \"title\", \"summary\", \"postType\", \"visibility\", \"description\", \"originalLessonId\"] |\n+-----+-----------------------------------------------------------------------------------------------------------+\n```\n\nFor the `post` type, I see the same keys for this sampling of rows. Now I have\nan idea what keys are present and can start digging in further.\n\nMy next query might look something like this:\n\n```sql\nselect id, fields->'$.slug', fields->'$.title', fields->'$.state'\nfrom content_resource\nwhere type = 'post'\nlimit 3;\n```\n"
  },
  {
    "path": "mysql/ignore-duplicates-when-inserting-records.md",
    "content": "# Ignore Duplicates When Inserting Records\n\nWhile trying to run a seed script to set up some application data in a MySQL\ndatabase, I ran into several duplicate-key errors. Some of this data had\nalready been added in another context, but I still need some of the seeds.\n\n```sql\ninsert into MerchantAccount (col1, col2, col3)\n  values ('data1', 'data2', 'data3'),\n         ('data4', 'data5', 'data6'),\n         (...);\n```\n\nThe solution was to allow MySQL to `ignore` the duplicate records and insert\nthe rest.\n\n```sql\ninsert ignore into MerchantAccount (col1, col2, col3)\n  values ('data1', 'data2', 'data3'),\n         ('data4', 'data5', 'data6'),\n         (...);\n```\n\nNotice all I had to do was update the statment by adding `ignore` right after\n[`insert`](https://dev.mysql.com/doc/refman/8.0/en/insert.html).\n\n> If you use the `IGNORE` modifier, ignorable errors that occur while executing\n> the `INSERT` statement are ignored. For example, without `IGNORE`, a row that\n> duplicates an existing `UNIQUE` index or `PRIMARY KEY` value in the table\n> causes a duplicate-key error and the statement is aborted. With `IGNORE`, the\n> row is discarded and no error occurs. Ignored errors generate warnings\n> instead.\n\n[source](https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#ignore-effect-on-execution)\n"
  },
  {
    "path": "mysql/list-databases-and-tables.md",
    "content": "# List Databases And Tables\n\nIf you've started a [mysql](https://dev.mysql.com/) session, but haven't\nconnected to a particular database yet, you can list the available databases\nlike so:\n\n```sql\n> show databases;\n+-----------------------------+\n| Database                    |\n+-----------------------------+\n| information_schema          |\n| my_app_dev                  |\n+-----------------------------+\n```\n\nIf you are curious about the tables in a particular database, you can list\nthem by specifying the database's name:\n\n```sql\n> show tables in my_app_dev;\n+------------------------------+\n| Tables_in_my_app_dev         |\n+------------------------------+\n| pokemons                     |\n| trainers                     |\n+------------------------------+\n```\n\nAlternatively, you can connect to the database of interest and then there is\nno need to specify the name of the database going forward.\n\n```sql\n> use my_app_dev;\n> show tables;\n+------------------------------+\n| Tables_in_my_app_dev         |\n+------------------------------+\n| pokemons                     |\n| trainers                     |\n+------------------------------+\n```\n"
  },
  {
    "path": "mysql/run-statements-in-a-transaction.md",
    "content": "# Run Statements In A Transaction\n\nI'm connecting to a production MySQL database to make some changes to a\nspecific user account. That means I am going to run an `update` statement and I\nexpect that statement to affect exactly *one* row in the `users` table.\n\nIf I run the `update` statement in a transaction, then I can verify all looks\ngood before committing those changes. And importantly, I can rollback the\nchanges if anything looks off.\n\n```sql\n> start transaction;\n\n> update users set roles = 'admin' where id = '1234';\nQuery ok, 1 row affected\n\n> select * from users where id = '1234';\n-- check that all looks good\n\n> commit;\n```\n\nIn the above case, all looked good, so I ran `commit`. If more rows than I\nexpected were affected or the changed record didn't look right, I could instead\n`rollback`. None of those changes would make it into live production data.\n\n[source](https://dev.mysql.com/doc/refman/8.0/en/commit.html)\n"
  },
  {
    "path": "mysql/select-rows-after-an-offset.md",
    "content": "# Select Rows After An Offset\n\nWhen doing pagination and other queries for special-case scenarios, we may need\nto grab rows after a certain offset.\n\nThere are two variations of the MySQL syntax for selecting rows after a certain\noffset.\n\n```sql\nselect * from events limit 100, 10;\n```\n\nThis first query will grab up to 10 rows after applying an offset of 100.\nTypically we'll see a `limit` clause with just one value which represents how\nmany rows to limit the result set to. However, if we optionally include `N, `\nin the middle of that clause. Whatever number `N` is will be the offset.\n\nAnother way to write this is:\n\n```sql\nselect * from events limit 10 offset 100;\n```\n\nThis gets the same result: 10 rows after an offset of 100. This is perhaps a\nbit more straightforward and reduces the chance that we forget which value is\nwhich like we might in the first syntax variation.\n\nNote: row ordering is only deterministic if you specify an order. To get\nconsistent results with `offset`, you'll most likely want to be specifying an\n`order by` clause as well.\n\n[source](https://dev.mysql.com/doc/refman/8.0/en/select.html)\n"
  },
  {
    "path": "mysql/set-value-on-null-json-column.md",
    "content": "# Set Value On Null JSON Column\n\nTo set a key-value pair on a JSON field, you can reach for\n[MySQL's `json_set`](https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html#function_json-set)\nor one of [the other JSON setter\nfunctions](https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html).\n\nHowever, if the JSON field you are updating is `null`, you might get an\nunexpected result.\n\n```sql\n> update User\n    set metadata = json_set(metadata, '$.discord_id', 'discord_123')\n    where id = 123;\n\nQuery OK, 0 rows affected (0.00 sec)\nRows matched: 1  Changed: 0  Warnings: 0\n```\n\nWe can see that the `where` clause matched on a single row as expected, but\nright above that it says _0 rows affected_.\n\nWhat happened?\n\nThe `json_set` function is not able to set a key-value pair on `null`. It needs\na JSON object to work on.\n\nThere are a number of ways to get around this. I find that\n[`coalesce`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#function_coalesce)\nis a natural way to handle this. If `metadata` happens to be `null`, then we\n_coalesce_ it to `'{}'` (an empty object).\n\n```sql\n> update User\n    set metadata = json_set(coalesce(metadata, '{}'), '$.discord_id', 'discord_123')\n    where id = 123;\n\nQuery OK, 1 row affected (0.02 sec)\nRows matched: 1  Changed: 1  Warnings: 0\n```\n\nIt updates as expected. That same statement will work on a row where `metadata`\nalready contains a JSON object since the `coalesce` will resolve to that\ninstead of the empty object.\n"
  },
  {
    "path": "mysql/show-create-statement-for-a-table.md",
    "content": "# Show Create Statement For A Table\n\nIn MySQL, you can get a quick rundown of a table using `describe users`. An\nalternative to this approach is to have MySQL show the `create` statement\nfor a table.\n\n```sql\n> show create table users\\G\n*************************** 1. row ***************************\n       Table: users\nCreate Table: CREATE TABLE `users` (\n  `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,\n  `first_name` varchar(80) NOT NULL,\n  `last_name` varchar(80) NOT NULL,\n  `email` varchar(80) NOT NULL,\n  `middle_initial` varchar(80) NOT NULL,\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `unique_email` (`email`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1\n```\n\nThis includes some additional information like primary key and index\ninformation. It is also a great way to study the SQL that it takes to create\nall the facets of a table.\n\nSee the [`show create table`\ndocs](https://dev.mysql.com/doc/refman/5.7/en/show-create-table.html) for\nmore details.\n\nh/t Jake Worth\n"
  },
  {
    "path": "mysql/show-indexes-for-a-table.md",
    "content": "# Show Indexes For A Table\n\nWhen describing a table, such as the table `users`:\n\n```sql\n> describe users;\n+------------+-----------------------+------+-----+---------+----------------+\n| Field      | Type                  | Null | Key | Default | Extra          |\n+------------+-----------------------+------+-----+---------+----------------+\n| id         | mediumint(8) unsigned | NO   | PRI | NULL    | auto_increment |\n| first_name | varchar(80)           | NO   |     | NULL    |                |\n| last_name  | varchar(80)           | NO   |     | NULL    |                |\n| email      | varchar(80)           | NO   | UNI | NULL    |                |\n+------------+-----------------------+------+-----+---------+----------------+\n```\n\nI can see in the `Key` column that there is a primary key and a unique key\nfor this table on `id` and `email`, respectively.\n\nThese keys are indexes. To get more details about each of the indexes on\nthis table, we can use the\n[`show indexes`](https://dev.mysql.com/doc/refman/5.7/en/show-index.html)\ncommand.\n\n```sql\n> show indexes in users;\n+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+\n| Table | Non_unique | Key_name     | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |\n+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+\n| users |          0 | PRIMARY      |            1 | id          | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |\n| users |          0 | unique_email |            1 | email       | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |\n+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+\n```\n"
  },
  {
    "path": "mysql/show-tables-that-match-a-pattern.md",
    "content": "# Show Tables That Match A Pattern\n\nAn unfamiliar database with tons of tables can be a difficult thing to\nnavigate. You may have an idea of the kind of table you are looking for\nbased on a domain concept you've seen elsewhere.\n\nYou can pare down the results returned by `show tables` by including a\n`like` clause with a pattern. For example, this statement will show me only\ntables that have the word `user` in them:\n\n```sql\n> show tables like '%user%';\n+-------------------------------+\n| Tables_in_jbranchaud (%user%) |\n+-------------------------------+\n| admin_users                   |\n| users                         |\n+-------------------------------+\n```\n"
  },
  {
    "path": "neovim/allow-neovim-to-copy-paste-with-system-clipboard.md",
    "content": "# Allow Neovim To Copy/Paste With System Clipboard\n\nBy default, Neovim uses some internal registers for managing the values that\nhave been copied (`y`) and what should be pasted (`p`). These registers are\nindependent from the system clipboard, so a value copied from the browser will\nnot show up when you hit `p` in Neovim (or Vim).\n\nIf you'd like to create a more seamless and cohesive copy/paste experience for\nyourself, you can instruct Neovim to read from and write to the system\nclipboard when copy/paste actions happen.\n\nThis is accomplished with a `provider` that instructs Neovim to use the system\nclipboard directly for all copy/paste operations.\n\n```vimscript\n\" ~/.vimrc\nset clipboard+=unnamedplus\n```\n\nSetting the `clipboard` option to include `unnamedplus` enables that provider\n\"which transparently uses shell commands to communicate with the system\nclipboard or any other clipboard 'backend'.\" So, for Mac, `pbcopy` and\n`pbpaste`.\n\nSee `:h provider-clipboard` for more details.\n"
  },
  {
    "path": "neovim/create-user-command-to-open-init-config.md",
    "content": "# Create User Command To Open Init Config\n\nI'm experimenting with a fresh Neovim configuration using\n[kickstart](https://github.com/nvim-lua/kickstart.nvim). That means I'm\nfrequently navigating to my `init.lua` file to add and adjust things that I\nfind are missing from my workflow.\n\nI got tired of typing out the path—in my case `~/.config/nvim/init.lua`—every\nsingle time I wanted to edit it. So, I typed out that path one last time so\nthat I could add a custom user command.\n\n```\n-- Open this config file\nvim.api.nvim_create_user_command(\n  'Config',\n  \"e ~/.config/nvim/init.lua\",\n  {bang = true, desc = \"Open init.lua Neovim config\"}\n)\n```\n\nThis uses [the lua command\nAPI](https://neovim.io/doc/user/api.html#api-command) to create a user-defined\ncommand.\n\nWhen I invoke `:Config` from the Neovim command prompt and hit enter, Neovim\nwill effectively replace that command with the second argument to that command\n— `:e ~/.config/nvim/init.lua`. Which opens me up to the config file.\n"
  },
  {
    "path": "neovim/jump-between-changes-in-current-file.md",
    "content": "# Jump Between Changes In Current File\n\nWith the [gitsigns.nvim plugin](https://github.com/lewis6991/gitsigns.nvim) for\nNeovim, I get some handy Git-related capabilities like gutter highlighting of\nadditions, deletions, and changes to lines in the current file. These contiguous\nsections of modification to the versioned state of a file are called hunks.\n\nHere are two mappings (in Lua) for gitsigns that allow me to jump to the next\n(`]h`) or previous (`[h`) hunk in the current file.\n\n```lua\n---@type LazyKeysSpec[]\nM.gitsigns_mappings = {\n\n  -- Navigation\n  {\n    ']h',\n    function()\n      if vim.wo.diff then\n        vim.cmd.normal { ']c', bang = true }\n      else\n        require('gitsigns').nav_hunk 'next'\n      end\n    end,\n    desc = 'Next Hunk',\n  },\n\n  {\n    '[h',\n    function()\n      if vim.wo.diff then\n        vim.cmd.normal { '[c', bang = true }\n      else\n        require('gitsigns').nav_hunk 'prev'\n      end\n    end,\n    desc = 'Prev Hunk',\n  },\n}\n```\n\nThis is particularly useful when I've just opened a big file and I want to jump\ndirectly to active changes in that file.\n\nI got this mapping directly from [Dorian's\ndotfiles](https://github.com/dkarter/dotfiles).\n"
  },
  {
    "path": "neovim/run-a-lua-statement-from-the-command-prompt.md",
    "content": "# Run A Lua Statement From The Command Prompt\n\nThe `:lua` command is provided by Neovim as a way to execute a Lua _chunk_.\n\nI can use it to, for instance, execute a print statement.\n\n```\n:lua print('Hello, World!')\n```\n\nI could print out something more interesting like the full path of the current\nfile using `vim.fn.expand` with `%`.\n\n```\n:lua print(vim.fn.expand('%'))\n```\n\nOr as the helpfiles point out, I can see the value of some expression by\nincluding a preceeding `=`.\n\n```\n:lua =jit.version\n```\n\nSee `:h :lua` for more details.\n"
  },
  {
    "path": "neovim/run-nvim-with-factory-defaults.md",
    "content": "# Run nvim With Factory Defaults\n\nMost of the fun of using Neovim is tailoring it to your exact needs with custom\nconfigurations. Your configuration can be made up of environment variables,\n`init.lua`/`init.vim`, and user directories on the `runtimepath`.\n\nPerhaps though, you want to load neovim with its \"factory defaults\". You want\nto ignore all your custom config and your _shada_ (shared data) file. I wanted\nto do just that recently to verify that neovim has the `ft-manpage` plugin\nenabled by default (as opposed to enabled somewhere in the labryinth of my\nconfig files).\n\nThe `--clean` flag does just this. It loads built-in plugins, but none of the\nuser defined config.\n\n```bash\n$ nvim --clean\n```\n\nThis is different than `nvim -u NONE` which excludes all plugins, including\nbuilt-in ones.\n\nSee `man nvim` and `:help --clean` for more details.\n"
  },
  {
    "path": "neovim/set-up-vim-plug-with-neovim.md",
    "content": "# Set Up Vim-Plug With Neovim\n\nTo get [vim-plug](https://github.com/junegunn/vim-plug) working with Neovim, it\nneeds to be installed in a known autoload directory.\n\nThe help files say that \"plugins installed by user\" should be located in the\ndata home directory at `stdpath(\"data\")` under `site`. For me (on OSX) the data\nhome directory is `~/.local/share/nvim`, so `~/.local/share/nvim/site`.\n\nUnder this site directory, along with any directories on the `runtimepath`,\nNeovim looks for various runtime files and subdirectories. This includes the\n`/autoload` directory. That's where you want to install `vim-plug`.\n\n```bash\nsh -c 'curl -fLo \"${XDG_DATA_HOME:-$HOME/.local/share}\"/nvim/site/autoload/plug.vim --create-dirs \\\n       https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim'\n```\n\nThis shell statement uses [the `:-` parameter\nexpansion](../unix/provide-a-fallback-value-for-unset-parameter.md) to specify a\npath using either the `XDG_DATA_HOME` or `$HOME` as a fallback. This ends up\nresolving to `~/.local/share`, so the `plug.vim` file is placed in\n`~/.local/share/nvim/site/autload/`.\n\nSee `:h runtimepath` for more details.\n"
  },
  {
    "path": "netlify/override-the-default-yarn-version.md",
    "content": "# Override The Default Yarn Version\n\nWhen you first deploy an app to [Netlify](https://www.netlify.com/), the\ncurrent default [Yarn](https://yarnpkg.com/) version will be locked in. This\nYarn version will be used for future builds and deployments.\n\nYou can override the default Yarn version by including the `YARN_VERSION`\nenvironment variable. Set it to the desired major and minor version in the app\nsettings panel. The next deployment will use that new version.\n\n[source](https://community.netlify.com/t/default-yarn-version-is-now-1-17/2297)\n"
  },
  {
    "path": "next-auth/adjust-the-shape-of-the-user-type.md",
    "content": "# Adjust The Shape Of The User Type\n\nLet's say we want extra attributes on our `user` object that gets passed around\nas part of authentication with [NextAuth.js](https://next-auth.js.org/). If\nwe're using a database adapter, it's because we have added columns to the\n`User` table. Or it may be that we are adding extra attributes to the body of\nthe JWT token.\n\nEither way, we need the underlying `User` type (rather, interface) to reflect\nthat.\n\nWithin a `declare module` block for NextAuth, we can define a `User` interface\nwith any additional properties that we want.\n\nThis adds `roles` as a required `string` type.\n\n```typescript\ndeclare module \"next-auth\" {\n  interface User {\n    // ...other properties\n    roles: string;\n  }\n}\n```\n\nSome natural places to add this declaration are in the auth file itself (e.g.\n`src/server/auth.ts`). Or we can put it in a dedicated top-level\n`next-auth.d.ts` file as long as we tell our `tsconfig.json` to include it:\n\n```json\n{\n  ...\n  \"include\": [\n    \"src/**/*\",\n    \"process.d.ts\",\n    \"next-auth.d.ts\"\n  ],\n  ...\n}\n```\n"
  },
  {
    "path": "nextjs/avoid-conflicting-files.md",
    "content": "# Avoid Conflicting Files\n\nWhen Next.js is bundling and building your project, it will get completely\ntripped up by any instance of conflicting project files. What I mean by\nconflicting project files are two JavaScript or TypeScript (or flavors of JSX\nfiles) that would resolve to the same thing.\n\nHere is one example where the extensions differ:\n\n```\nsrc/pages/welcome.tsx\nsrc/pages/welcome.jsx\n```\n\nHere is another example where the paths differ but the bundled result would\nconflict:\n\n```\nsrc/pages/welcome.tsx\nsrc/pages/welcome/index.tsx\n```\n\nIf you have any instances of these conflicting files, you'll be presented with\na beguiling and cryptic error message when trying to run the dev server.\n\n```\nTypeError [ERR_INVALID_ARG_TYPE]: The \"to\" argument must be of type string. Received undefined\n    at new NodeError (node:internal/errors:405:5)\n    at validateString (node:internal/validators:162:11)\n    at Object.relative (node:path:1191:5)\n    at Watchpack.<anonymous> (/my_app/node_modules/.pnpm/next@14.2.5_@babel+core@7.24.9_react-dom@18.3.1_react@18.3.1/node_modules/next/dist/server/lib/router-utils/setup-dev-bundler.js:381:55) {\n  code: 'ERR_INVALID_ARG_TYPE'\n}\n```\n\nOne of those files needs to go. Remove one of them and you'll be good to go.\n"
  },
  {
    "path": "nextjs/create-files-and-directories-for-dynamic-routes.md",
    "content": "# Create Files And Directories For Dynamic Routes\n\n[Next.js](https://nextjs.org/) allows you to go beyond static, predefined pages\nand routes with [dynamic\nrouting](https://nextjs.org/docs/routing/dynamic-routes).\n\nThe common example is a `posts` route that includes a _slug_ to dynmically\nreference a particular post. The template for that page can be defined at\n`pages/posts/[slug].js`. Notice the square brackets around the slug, that tells\nNext that it is a dynamic route and whatever matches against the slug should be\nincluded in `router.query` as `slug`.\n\nLet's try to create that file:\n\n```bash\n$ touch pages/posts/[slug].js\nzsh: no matches found: pages/posts/[slug].js\n```\n\nThat failed. To create this kind of file from the command-line, you are going\nto need to escape the square brackets:\n\n```bash\n$ touch pages/posts/\\[slug\\].js\n```\n\nYou can do the same if you use dynamic routing in your directory structure:\n\n```bash\n$ mkdir -p pages/posts/\\[year\\]/\\[month\\]/\\[day\\]\n```\n\nAnd now we have the following structure:\n\n```bash\n$ exa --tree pages/posts\npages/posts\n├── [slug].js\n└── [year]\n   └── [month]\n      └── [day]\n```\n"
  },
  {
    "path": "nextjs/define-url-redirects-in-the-next-config.md",
    "content": "# Define URL Redirects In The Next Config\n\nIn [Add Web Server Layer Redirects](vercel/add-web-server-layer-redirects.md),\nI explained how to define URL redirects to your [Vercel](https://vercel.com/)\nconfiguration for a [Next.js](https://nextjs.org/) app. Because these redirect\nrules are defined in `vercel.json` which is processed at the time of deployment\non the Vercel platform, you are unable to experience these redirects with your\nlocal dev instance of the app. That could be misleading and cause confusion\nduring development.\n\nInstead, you can define your redirects in `next.config.js` as part of the\nNext.js app's configuration. When locally running the Next dev server, these\nredirects will be processed and active.\n\nHere is an example of these redirects in `next.config.js`:\n\n```javascript\nconst nextConfig = {\n  async redirects() {\n    return [\n      {\n        source: \"blog/old-blog-post-name\",\n        destination: \"blog/new-blog-post-name\",\n        permanent: true,\n      },\n      {\n        source: \"/store\",\n        destination: \"store.example.com\"\n        permanent: true,\n      },\n    ]\n  },\n}\n```\n\nThese will be 308 Permanent Redirects because of `permanent: true`. You can\nchange that to `false` to make them into 307s.\n"
  },
  {
    "path": "nextjs/fetch-does-not-work-in-api-serverless-function.md",
    "content": "# Fetch Does Not Work In API Serverless Function\n\nNext.js ships with [its own implementation of\n`fetch`](https://nextjs.org/docs/app/api-reference/functions/fetch) that\nextends the [native `fetch`\nAPI](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).\n\nI ran into a bug recently that was only reproducible in production. I had a\nNext.js API function that was `POST`ing to another API endpoint using `fetch`.\nI tested it several ways in development. It worked great. However, once the\nfeature was in production, it was silently failing. After some `console.log`\ndebugging, I discovered that the target API was getting an empty `body` in the\n`POST` request.\n\nI don't know the specifics of why, but somehow the `fetch` implementation\nrunning in the Vercel serverless function environment apparently strips out the\n`body` of a POST request.\n\nThe solution, for me, was to add the\n[`node-fetch`](https://github.com/node-fetch/node-fetch) package and import\nthat version of fetch in my API function. Once I made that change, my feature\nwas working again.\n\n[source](https://github.com/vercel/vercel/discussions/4971)\n"
  },
  {
    "path": "nextjs/make-environment-variable-publicly-available.md",
    "content": "# Make Environment Variable Publicly Available\n\nYou can define environment variables in `.env.development` and\n`.env.production` files for use in your app. This is a great way to seamlessly\nswap out values that are specific to each environment.\n\nFor instance, you might have a base URL for API requests that points to a local\nserver in development and then to the live server in production.\n\nYou could define that value like so:\n\n```\nAPI_BASE_URL=localhost:3000/api/v1\n```\n\nThe problem you'll quickly run into is in trying to access that value from any\nclient-side pages or components.\n\n```\nprocess.env.API_BASE_URL //=> undefined\n```\n\nNext.js is trying to help us out here. Environment variables are often times\nprivate keys and other secrets that shouldn't be bundled into our public client\ncode. So Next.js excludes all env vars from the build by default.\n\nOur API's base URL is not a secret though. The way to make env vars like that\npublicly avilable is to prepend them with `NEXT_PUBLIC_`.\n\n```\nNEXT_PUBLIC_API_BASE_URL=localhost:3000/api/v1\n```\n\nNow, it is available anywhere in your client and server code:\n\n```\nprocess.env.NEXT_PUBLIC_API_BASE_URL //=> 'localhost:3000/api/v1'\n```\n\n[source](https://nextjs.org/docs/basic-features/environment-variables#exposing-environment-variables-to-the-browser)\n"
  },
  {
    "path": "nextjs/match-middleware-on-groups-of-paths.md",
    "content": "# Match Middleware On Groups Of Paths\n\nThe Next.js middleware takes an array of path matchers in its config to decide\nwhat pages to apply middleware to. These paths can use regex via\n[`path-to-regexp`](https://github.com/pillarjs/path-to-regexp#path-to-regexp-1).\n\nLet's say I'm using middleware to do authentication checks for certain pages.\n\nIf I want to visits to my `/dashboard` page to run through middleware, I can\nconfigure my matcher like so:\n\n```javascript\nexport const config = { matcher: [\"/dashboard\"] };\n```\n\nIf we want to match against `/dashboard` and any possible sub-structure to that\npath, we can apply some regex:\n\n```javascript\nexport const config = { matcher: [\"/dashboard/:all*\"] };\n```\n\nThat will match `/dashboard`, `/dashboard/hello`, `dashboard/hello/world`, etc.\n\nLastly, let's say I only want to match routes under the `/dashboard` route. I\ncan replace the `*` (zero-or-more matches) with a `+` (one-or-more matches):\n\n```javascript\nexport const config = { matcher: [\"/dashboard/:all+\"] };\n```\n\nThat will match `/dashboard/hello`, `/dashboard/hello/world`, etc., but not\n`/dashboard`.\n\n[source](https://nextjs.org/docs/app/building-your-application/routing/middleware)\n"
  },
  {
    "path": "nextjs/organize-pages-in-route-groups.md",
    "content": "# Organize Pages In Route Groups\n\nWith the Next.js App Router we can organize pages without affecting the URL\npath structure by nesting those directories and pages within a _Route Group_. A\nRoute Group is directory where the name is surrounded by parentheses, e.g.\n`/(symbols)`.\n\nFor instance, in my [Ruby Operator\nLookup](https://www.visualmode.dev/ruby-operators) project, I have the\nfollowing structure:\n\n```bash\n$ exa --true src/app/ruby-operators\n\nsrc/app/ruby-operators\n├── (symbols)\n│  ├── ampersand\n│  │  └── page.mdx\n│  ├── arbitrary-keyword-arguments\n│  │  └── page.mdx\n│  ├── asterisk\n│  │  └── page.mdx\n│  ├── at-symbol\n│  │  └── page.mdx\n│  ├── backtick\n│  │  └── page.mdx\n│  ├── ...\n│  └── underscore\n│     └── page.mdx\n├── client-layout.tsx\n├── layout.tsx\n├── page.tsx\n└── wrapper.ts\n```\n\nI'm able to organize all the different symbols and operators under a separate\ndirectory `/(symbol)/`. That makes development easier. However, the end result\nrouting still has each symbol located directly under `/ruby-operators/`, e.g.\n`/ruby-operators/ampersand`.\n\n[source](https://nextjs.org/docs/app/getting-started/project-structure#route-groups)\n"
  },
  {
    "path": "nextjs/precedence-of-dot-env-files.md",
    "content": "# Precedence Of Dot Env Files\n\n_Dot Env_ files like `.env`, `.env.development`, `.env.local`, etc. are one of\nthe main ways to configure your Next.js app across various environments.\n\nIt's not uncommon to see several different `.env*` files in production app that\nis under active development.\n\nHere is an example of almost every variant in play:\n\n```bash\n$ ls -a -1 .env*\n.env\n.env.development\n.env.development.local\n.env.development.local.example\n.env.local\n.env.production\n.env.test\n```\n\nSo, how does Next.js decide which files to load and in what order?\n\nIt will always attempt to load `.env` and `.env.local` (except in `test`) if\nthose exist. It will also look for environment-specific files based on the\n`NODE_ENV` (which can be one of `development`, `test`, or `production`). So, in\n`development`, the `.env.development` and `.env.development.local` will be\nloaded. Something like `.env.development.local.example` isn't on the list, but\nrather is a convention for a dotenv file's template.\n\nAs for the order, the environment itself (your system's environment variables)\nwhich are present in `process.env` take the highest precedence. After that, it\nlooks in any of the follow present files in this order, stopping once it finds\nwhat it is looking for:\n\n- `.env.$(NODE_ENV).local`\n- `.env.local`\n- `.env.$(NODE_ENV)`\n- `.env`\n\n[source](https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables#environment-variable-load-order)\n"
  },
  {
    "path": "nextjs/push-a-route-with-a-url-object.md",
    "content": "# Push A Route With A URL Object\n\nThere are two ways of using the Next.js router to transition to another route\nusing\n[`push`](https://nextjs.org/docs/api-reference/next/router#with-url-object).\n\nThe first, and perhaps more common, is by passing it a string.\n\n```javascript\nrouter.push('/search?tag=react')\n```\n\nThis is great for simple routes. When routes require query params, this can\nlead to error-prone string interpolation. That's where the second way comes in.\n\nThe second is to use a [URL\nObject](https://nextjs.org/docs/api-reference/next/router#with-url-object)\ninstead of a string.\n\n```javascript\nrouter.push({\n  pathname: '/search',\n  query: { tag: 'react' }\n})\n```\n\nHere we are working with an object. I find objects a bit easier to work with,\nthan strings, when doing programmatic things. Especially when it comes to\nadding and removing query params.\n"
  },
  {
    "path": "nextjs/redirect-an-unauthorized-user.md",
    "content": "# Redirect An Unauthorized User\n\nWith the Page Router in earlier next version, we could do a server-side\nauthorization check in `getServerSideProps` and then return a\n[`redirect`](https://nextjs.org/docs/pages/api-reference/functions/get-server-side-props#redirect)\nresponse in order to redirect the user to a page they are authorized for.\n\nThat might look something like this:\n\n```javascript\nexport async function getServerSideProps(context) {\n  const session = await getServerAuthSession()\n  const ability = getAbility({user: session?.user})\n\n  if (!ability.can('create', 'Post')) {\n    return {\n      redirect: {\n        destination: '/posts',\n        permanent: false,\n      },\n    }\n  }\n \n  return {\n    props: {},\n  }\n}\n```\n\nWe can achieve the same thing with the App Router, but with a bit less code.\nThe `next/navigation` package has a [`redirect`\nfunction](https://nextjs.org/docs/app/api-reference/functions/redirect) that we\ncan invoke directly in a component. This will redirect the user instead of\nrendering the component to HTML.\n\n```javascript\nimport { redirect } from 'next/navigation'\n\nexport default async function CreatePost() {\n  const session = await getServerAuthSession()\n  const ability = getAbility({user: session?.user})\n\n  if (!ability.can('create', 'Post')) {\n    redirect('/posts')\n  }\n\n  // JSX follows\n  return (...)\n}\n```\n"
  },
  {
    "path": "nextjs/remove-a-query-param-from-the-url.md",
    "content": "# Remove A Query Param From The URL\n\nLet's say you have a Next.js app. Sometimes users visit the app with special\nquery params. You want to extract the value of those query params, do something\nwith them, and then remove them from the URL.\n\nThis can be done with\n[`next/router`](https://nextjs.org/docs/api-reference/next/router).\n\nLet's say this component loads while the app URL is `/home?code=123`.\n\n```javascript\nimport React, { useEffect } from \"react\";\nimport {useRouter} from \"next/router\";\n\nfunction SomeComponent() {\n  const router = useRouter();\n\n  useEffect(() => {\n    // extract the value from the query params\n    const { code, ...updatedQuery } = router.query;\n\n    if (!!code) {\n      // do something with the extract query param\n      doSomethingWithCode(code);\n\n      // create an updated router path object\n      const newPathObject = {\n        pathname: router.pathname,\n        query: updatedQuery\n      }\n\n      // update the URL, without re-triggering data fetching\n      router.push(newPathObject, undefined, { shallow: true });\n    }\n  }, [])\n\n  return (\n   ...\n  );\n}\n```\n\nAfter the mount, the URL will read `/home` and the code will have done\nsomething with the code value.\n\nThis is accomplished by destructuring the target query param apart from the\nrest, constructing a new router path object with the rest of the query params,\nand then [pushing that route update\n_shallowly_](https://nextjs.org/docs/routing/shallow-routing) so that data\ndoesn't get refetched.\n"
  },
  {
    "path": "nextjs/ship-public-assets-with-a-nextjs-app.md",
    "content": "# Ship Public Assets With A Next.js App\n\nA Next.js project includes a top-level `public` directory. Anything in this\ndirectory at build time will be publicly available.\n\nThis is handy for things like a logo, cover image, or favicon.\n\nIf I create an `images` directory in `public` and then place an SVG in it:\n\n```bash\n$ ls public/images\nlogo.svg\n```\n\nThen I can reference that image in the HTML or JSX of my app pages, such as in\na `header.jsx` component.\n\n```jsx\nconst Header = () => {\n  <div>\n    {/* a bunch of header and nav content */}\n    <img className=\"logo\" src=\"/images/logo.svg\" />\n  </div>\n}\n```\n\nNotice it is publicly available at `/images/logo.svg`.\n\nYou can do this with other files as well. For instance, some kind of company\nbrochure PDF could be placed in `public` and you could link to it as a\ndownload.\n\n[source](https://nextjs.org/docs/basic-features/static-file-serving)\n"
  },
  {
    "path": "phoenix/bypass-template-rendering.md",
    "content": "# Bypass Template Rendering\n\nGenerally when rendering a response to a request in a Phoenix app, the\ncontroller will make a render call that targets a specific template. If it\nsuits our needs, we can skip writing a template and bypass the template\nportion of the response pipeline by implementing our own `render` function\ndirectly in the view module.\n\nConsider the following route and controller action:\n\n```elixir\n# web/router.ex\nget \"/hello\", UserController, :hello\n\n# web/controllers/user_controller.ex\ndef hello(conn, _params) do\n  render(conn, \"hello.html\")\nend\n```\n\nThe render call would normally trigger a corresponding template function,\nbut we bypass it by adding the following function to our view module:\n\n```elixir\n# web/views/user_view.ex\ndef render(\"hello.html\", _assigns) do\n  \"Hello, World!\"\nend\n```\n\nVisiting `/hello` will render a page with the view's layout and the words\n\"Hello, World!\".\n"
  },
  {
    "path": "phoenix/check-the-installed-version.md",
    "content": "# Check The Installed Version\n\nCheck what the installed version of Phoenix is with the `-v` flag.\n\n```bash\n$ mix phoenix.new -v\nPhoenix v1.2.0\n```\n\n[source](http://shorts.jeffkreeftmeijer.com/2015/find-the-currently-installed-phoenix-version-number/)\n"
  },
  {
    "path": "phoenix/generate-new-app-without-brunch.md",
    "content": "# Generate New App Without Brunch\n\nBy default when you create a new Phoenix app using `phx.new`, a set of files\nand configurations will be generated for [Brunch](http://brunch.io/). Though\nthe Phoenix team decided to use Brunch, you don't have to. You may not want\nPhoenix to handle asset building or you may just prefer another tool. Either\nway, if you'd like to opt out, you can include the `--no-brunch` flag when\ngenerating the project.\n\n```bash\n$ mix phx.new --no-brunch my_app\n```\n\nIf you have an existing project that you'd like to remove Brunch from, there\nis some information in [Phoenix's Static Assets\ndocumentation](http://phoenixframework.org/blog/static-assets).\n"
  },
  {
    "path": "phoenix/render-a-template-to-a-string.md",
    "content": "# Render A Template To A String\n\nTemplates in a [Phoenix](http://www.phoenixframework.org/) application\nultimately get compiled to functions that can be quickly rendered with the\nnecessary data. We can take a look at how a template will be rendered using\n[`Phoenix.View.render_to_string/3`](https://hexdocs.pm/phoenix/Phoenix.View.html#render_to_string/3).\n\nFirst, we need a template:\n\n```elixir\n# user.html.eex\n<h1><%= @user.first_name %></h1>\n<h5><%= @user.username %> (<%= @user.email %>)</h5>\n```\n\nWe can then render that template for the view with some user:\n\n```elixir\n> user = %User{first_name: \"Liz\", last_name: \"Lemon\", username: \"llemon\", email: \"lizlemon@nbc.com\"}\n%MyApp.User{...}\n\n> Phoenix.View.Render_to_string(MyApp.UserView, \"user.html\", user: user)\n\"<h1>Liz</h1>\\n<h5>llemon (lizlemon@nbc.com)</h5>\\n\"\n```\n"
  },
  {
    "path": "phoenix/serve-static-assets-from-custom-directory.md",
    "content": "# Serve Static Assets From Custom Directory\n\nWhen you new up a Phoenix project, an `endpoint.ex` file will be generated.\nThis file is full of different plugs for handling incoming traffic. The\n`Plug.Static` declaration specifies how your application will handle and\nserve requests for static files.\n\n```elixir\n  plug Plug.Static,\n    at: \"/\", from: :my_app, gzip: false,\n    only: ~w(css fonts images js favicon.ico robots.txt)\n```\n\nThe `from` options declares where these static files are located. In this\ncase it references our application (`:my_app`) as the target which will\ntranslate to its `priv/static` directory.\n\nIf you instead want to serve your files from a different, custom directory,\nyou can replace it with the path to that directory.\n\n```elixir\n  plug Plug.Static,\n    at: \"/\", from: \"priv/my_frontend/static\", gzip: false,\n    only: ~w(css fonts images js favicon.ico robots.txt)\n```\n\n[source](https://hexdocs.pm/plug/Plug.Static.html)\n"
  },
  {
    "path": "phoenix/specifying-the-digest-directory.md",
    "content": "# Specifying The Digest Directory\n\nBy default, Phoenix targets `priv/static` when preparing digested assets for\nproduction. This process happens when running `mix phx.digest`.\n\nIf you are doing some custom work with your assets such that they are in a\ndifferent location, you'll need to tell Phoenix where to look. To do this,\njust include an optional path argument.\n\n```bash\n$ mix phx.digest path/to/my/assets\n```\n\nThe digests will be put in that target directory. If you'd like to specify a\ndifferent output directory, such as `priv/static`, include the `-o` flag.\n\n```bash\n$ mix phx.digest path/to/my/assets -o priv/static\n```\n"
  },
  {
    "path": "phoenix/specifying-the-server-port.md",
    "content": "# Specifying The Server Port\n\nRunning `mix phx.server` for a Phoenix project with the default settings\nwill attach the server to port `4000`.\n\nIf you'd like to use a different port in development, you can change it in\n`config/dev.exs`.\n\n```elixir\nconfig :my_app, MyApp.Web.Endpoint,\n  http: [port: 4444],\n  ...\n```\n\nAlternatively, you can allow it to be configurable from the command line\nwith an environment variable and a fallback port.\n\n```elixir\nconfig :my_app, MyApp.Web.Endpoint,\n  http: [port: System.get_env(\"PORT\") || 4000],\n  ...\n```\n\nRunning\n\n```bash\n$ PORT=4444 mix phx.server\n```\n\nwill launch the server on port `4444`.\n"
  },
  {
    "path": "planetscale/see-what-databases-you-have-access-to.md",
    "content": "# See What Databases You Have Access To\n\nAssuming you have the `pscale` CLI installed and you've authenticated with it,\nyou can run the following to view available databases.\n\n```bash\n$ pscale database list\n  NAME        KIND    CREATED AT    UPDATED AT\n ----------- ------- ------------- -------------\n  bookshelf   mysql   3 years ago   3 years ago\n```\n\nI'm not very active on my personal account. Planetscale is a multi-tenant SaaS\nthough. I can switch from my personal `org` to another team I have access to.\n\n```bash\n$ pscale org switch another-team\n```\n\nAnd then from there I can run `pscale database list` again to see what databases\nI have access to from this other organization.\n\nSee `pscale database help` and `pscale org help` for more details.\n"
  },
  {
    "path": "planetscale/seed-production-data-into-another-branch.md",
    "content": "# Seed Production Data Into Another Branch\n\nWhen you [create a Planetscale\nbranch](https://planetscale.com/docs/reference/branch) off `main`, it will only\ncopy over the schema. No data will be copied over to that new branch.\n\nYou can copy data over from the initial branch (`main`) in two steps from the\nCLI. First, create a dump of the branch. Then restore the dump into your new\nbranch.\n\n```bash\n$ pscale database dump database-name main --output ./dump\n```\n\nThat creates SQL files locally in the `dump` folder with both schema and data\nstatements.\n\nThat folder of SQL files can then be restored into one of your branches.\n\n```bash\n$ pscale database restore-dump database-name branch-name --dir ./dump --overwrite-tables\n```\n\nThe `--overwrite-tables` flag is needed because your branch's existing schema\nwill conflict with the `create` schema statements in the SQL files.\n\nYou can `pscale shell` into that branch and run a `select ...` statement to\ncheck out the data.\n"
  },
  {
    "path": "pnpm/execute-a-command-from-the-workspace-root.md",
    "content": "# Execute A Command From The Workspace Root\n\n[`pnpm`](https://pnpm.io/) is designed to work with monorepos. In a monorepo\nproject you'll have a root `package.json` (in the top-level directory of the\nrepository) as well as individual `package.json` files per app and package. If\nyou're working from within the directory of one of your apps and you invoke a\ncommand, `pnpm` should execute that command for this app. The `pnpm` CLI does\ngive you control to execute the command from the workspace root instead if\nyou'd like.\n\nA likely setup is that both your root `package.json` and your individual app\n`package.json` files have a `build` command.\n\nInvoking the build command from `apps/my-app`:\n\n```bash\npnpm build\n```\n\nwill run the `my-app` build command, as specified in its `package.json`.\n\nYou could instead throw in [the `--workspace-root`\nflag](https://pnpm.io/pnpm-cli#-w---workspace-root).\n\n```bash\npnpm --workspace-root build\n```\n\nThis will ignore whatever subdirectory you are in and invoke the `build`\ncommand defined in your top-level `package.json` file.\n"
  },
  {
    "path": "pnpm/install-command-runs-for-entire-workspace.md",
    "content": "# Install Command Runs For Entire Workspace\n\nWhen you run [`pnpm install`](https://pnpm.io/cli/install) in a monorepo, it\nwill run from the context of the workspace root. That means it will install\ndependencies for your entire monorepo across apps and packages.\n\nEven if you are in a subdirectory for a specific project with its own\n`package.json`, running `pnpm install` will install dependencies for the entire\nworkspace.\n\nIf you want to install dependencies only for a specific project or a subset of\nprojects, you can use [the `--filter`\nflag](https://pnpm.io/cli/install#--filter-package_selector).\n"
  },
  {
    "path": "pnpm/list-the-installed-version-of-a-specific-package.md",
    "content": "# List The Installed Version Of A Specific Package\n\n`pnpm` is a Node-ecosystem package manager with first-class support for\nmonorepos. In a monorepo with many apps and packages that each have their own\n`package.json` file, it can be tricky to know what version of a package is\ninstalled for a specific app or package.\n\nThe `pnpm list` command can help with that. First navigate to a specific app or\npackage whose dependencies you want to know about. Then run a command like the\nfollowing, replacing `@trpc/next` with your package of interest.\n\n```bash\n$ pnpm list '@trpc/next'\nLegend: production dependency, optional only, dev only\n\nepic-react /Users/jbranchaud/code/clients/egghead/products/apps/epic-react\n\ndependencies:\n@trpc/next 10.7.0\n```\n\nIt tells you the exact version of that dependency that is isntalled for the\ncurrent app/package.\n\nThis command can also be used with regex. Let's say you want to know about all\n`next`-related dependencies. You could do the following:\n\n```bash\n$ pnpm list '*next*'\n```\n\n[source](https://pnpm.io/cli/list)\n"
  },
  {
    "path": "postgres/a-better-null-display-character.md",
    "content": "# A Better Null Display Character\n\nBy default, `psql` will display null values with whitespace. This makes it\ndifficult to quickly identify null values when they appear amongst a bunch\nof other data. You can pick a better display value for null characters with\n`\\pset null`. My preference is the following:\n\n```\n\\pset null 'Ø'\n```\n\nI have this in my `.psqlrc` file so that it is used by default every time.\n"
  },
  {
    "path": "postgres/add-foreign-key-constraint-without-a-full-lock.md",
    "content": "# Add Foreign Key Constraint Without A Full Lock\n\nAdding a foreign key constraint to a large production table can cause a full\ntable lock resulting in downtime. This is because the entire table needs to be\nscanned to check that the constraint is valid.\n\nThe amount of locking, and ultimately the impact on your app, can be reduced by\nspreading this action across two commands. First is to add the constraint\nwithout checking that all the existing records are valid.\n\n```sql\nalter table books\n  add constraint fk_books_authors\n  foreign key (author_id)\n  references authors(id)\n  not valid;\n```\n\nThe constraint will be added immediately and any subsequent inserts or updates\nwill be subject to the new foreign key constraint.\n\nThe second step is to make this constraint valid for all the existing rows.\n\n```sql\nalter table books validate constraint fk_books_authors;\n```\n\nThis \"validation acquires only a SHARE UPDATE EXCLUSIVE lock on the table being\naltered.\" This is lower impact than a full table lock.\n\n[Source](https://www.postgresql.org/docs/current/sql-altertable.html#SQL-ALTERTABLE-NOTES)\n"
  },
  {
    "path": "postgres/add-on-delete-cascade-to-foreign-key-constraint.md",
    "content": "# Add ON DELETE CASCADE To Foreign Key Constraint\n\nThe `alter table` command lets you do quite a bit. But when it comes to\naltering existing constraints, there is not much you can do. If you want to\nadd an `on delete cascade` to an existing foreign key constraint, you are\ngoing to need two statements.\n\nThe first statement will drop the constraint and the second statement will\nrecreate it with the addition of the `on delete` clause. Furthermore, you'll\nwant to do this in a transaction to ensure the integrity of your data during\nthe transition between indexes.\n\nHere is an example:\n\n```sql\nbegin;\n\nalter table orders\ndrop constraint orders_customer_id_fkey;\n\nalter table orders\nadd constraint orders_customer_id_fkey\nforeign key (customer_id)\nreferences customers (id)\non delete cascade;\n\ncommit;\n```\n\n[source](http://stackoverflow.com/questions/10356484/how-to-add-on-delete-cascade-constraints)\n"
  },
  {
    "path": "postgres/add-unique-constraint-using-existing-index.md",
    "content": "# Add Unique Constraint Using Existing Index\n\nAdding a unique constraint to an existing column on a production table can\nblock updates. If we need to avoid this kind of locking for the duration of\nindex creation, then we can first create the index concurrently and then use\nthat existing index to back the unique constraint.\n\n```sql\ncreate index concurrently users_email_idx on users (email);\n\n-- wait for that to complete\n\nalter table users\n  add constraint unique_users_email unique using index users_email_idx;\n```\n\nFirst, we concurrently create the index. The time this takes will depend on how\nlarge the table is. That's the blocking time we are avoiding with this\napproach. Then once that completes we can apply a unique constraint using that\npreexisting index.\n\nNote: if a non-unique value exists in the table for that column, adding the\nconstraint will fail. You'll need to deal with that _duplicate_ value first.\n\n[source](https://dba.stackexchange.com/questions/81627/postgresql-9-3-add-unique-constraint-using-an-existing-unique-index)\n"
  },
  {
    "path": "postgres/adding-composite-uniqueness-constraints.md",
    "content": "# Adding Composite Uniqueness Constraints\n\nThere are two ways in Postgres to create a composite uniqueness constraint;\nthat is, a constraint that ensures that the combination of two or more\nvalues on a table only appear once. For the following two code snippets,\nassume that we have a table relating Pokemon and Trainers and that our\ndomain restricts each Trainer to only having at most one of each Pokemon.\n\nThe first approach is to create a `constraint` directly on the table:\n\n```sql\nalter table pokemons_trainers\n  add constraint pokemons_trainers_pokemon_id_trainer_id_key\n  unique (pokemon_id, trainer_id);\n```\n\nThe second approach is to create a unique index:\n\n```sql\ncreate unique index pokemons_trainers_pokemon_id_trainer_id_idx\n  on pokemons_trainers (pokemon_id, trainer_id);\n```\n"
  },
  {
    "path": "postgres/aggregate-a-column-into-an-array.md",
    "content": "# Aggregate A Column Into An Array\n\nPostgreSQL's `array_agg` function can be used to aggregate a column into an\narray. Consider the following column:\n\n```sql\n> select num from generate_series(1,5) as num;\n num\n-----\n   1\n   2\n   3\n   4\n   5\n```\n\nBy wrapping the `array_agg` aggregate function around `num` we are able to\n*aggregate* the values in that column into an array, like so:\n\n```sql\n> select array_agg(num) from generate_series(1,5) as num;\n  array_agg\n-------------\n {1,2,3,4,5}\n```\n\nSee the docs on [aggregate\nfunctions](http://www.postgresql.org/docs/current/static/functions-aggregate.html)\nfor more details.\n"
  },
  {
    "path": "postgres/assumed-radius-of-the-earth.md",
    "content": "# Assumed Radius Of The Earth\n\nUsing the\n[`earthdistance`](https://www.postgresql.org/docs/8.3/static/earthdistance.html)\nmodule, we can get the assumed radius of the earth (in meters).\n\n```sql\n> create extension cube;\nCREATE EXTENSION\n\n> create extension earthdistance;\nCREATE EXTENSION\n\n> select earth();\n  earth\n---------\n 6378168\n```\n"
  },
  {
    "path": "postgres/auto-expanded-display.md",
    "content": "# Auto Expanded Display\n\nBy default, postgres has expanded display turned off. This means that\nresults of a query are displayed *horizontally*.\nAt times, the results of a query can be so wide that line wrapping occurs.\nThis can make the results and their corresponding column names rather\ndifficult to read. In these situations, it is preferable to turn on expanded\ndisplay so that results are displayed *vertically*.\nThe `\\x` command can be used to toggle expanded display on and off.\n\nHaving to toggle expanded display on and off depending on the way a\nparticular set of results is going to display can be a bit tedious.\nFortunately, running `\\x auto` will turn on auto expanded display. This\nmeans postgres will display the results normally when they fit and only\nswitch to expanded display when it is necessary.\n\nh/t Jack Christensen\n"
  },
  {
    "path": "postgres/between-symmetric.md",
    "content": "# Between Symmetric\n\nPostgreSQL's `between` construct allows you to make a comparison _between_\ntwo values (numbers, timestamps, etc.).\n\n```sql\n> select *\n  from generate_series(1,10) as numbers(a)\n  where numbers.a between 3 and 6;\n a\n---\n 3\n 4\n 5\n 6\n```\n\nIf you supply an empty range by using the larger of the two values first, an\nempty set will result.\n\n```sql\n> select *\n  from generate_series(1,10) as numbers(a)\n  where numbers.a between 6 and 3;\n a\n---\n```\n\nTacking `symmetric` onto the `between` construct is one way to avoid this\nissue.\n\n```sql\n> select *\n  from generate_series(1,10) as numbers(a)\n  where numbers.a between symmetric 6 and 3;\n a\n---\n 3\n 4\n 5\n 6\n```\n\n> BETWEEN SYMMETRIC is the same as BETWEEN except there is no requirement\n> that the argument to the left of AND be less than or equal to the argument\n> on the right. If it is not, those two arguments are automatically swapped,\n> so that a nonempty range is always implied.\n\n[source](https://www.postgresql.org/docs/current/functions-comparison.html#:~:text=BETWEEN%20SYMMETRIC%20is%20like%20BETWEEN,nonempty%20range%20is%20always%20implied.)\n"
  },
  {
    "path": "postgres/capitalize-all-the-words.md",
    "content": "# Capitalize All The Words\n\nPostgreSQL provides the string function `initcap()` as a way of capitalizing\nall words. In the process, it cleans up the casing of the remaining parts of\nthe words.\n\nHere are some examples of how it works.\n\n```sql\n> select initcap('hello, world');\n   initcap\n--------------\n Hello, World\n\n> select initcap('HELLO, WORLD');\n   initcap\n--------------\n Hello, World\n```\n\nSee the [String Functions and Operators\ndocs](https://www.postgresql.org/docs/current/static/functions-string.html)\nfor more details.\n"
  },
  {
    "path": "postgres/change-the-current-directory-for-psql.md",
    "content": "# Change The Current Directory For psql\n\nWhen you start a `psql` session, your current directory is what `psql` will\nuse as its current directory. This is important for meta-commands that use\nrelative paths based on the current directory -- for instance, the `\\i`\nmeta-command for importing files.\n\nYou can change the current directory within a `psql` session using the `\\cd`\nmeta-command.\n\nIf my current directory is `home` and there is a `sql` directory in `home,\nthese commands will do the following:\n\n```sql\n\\! pwd\n-- /home\n\\cd sql\n\\! pwd\n-- /home/sql\n```\n\nThe `\\cd` meta-command even supports tab completion relative to the current\ndirectory.\n\nYou can also change to your home directory using just `\\cd`.\n"
  },
  {
    "path": "postgres/change-the-owner-of-a-sequence.md",
    "content": "# Change The Owner Of A Sequence\n\nSequence ownership is one of those things in PostgreSQL that is just under the\nsurface and so it is easy to not know about it. If, however, you are doing a\nlive migration where you are swapping out a column or entire table, you'll need\nto know about it.\n\nFor instance, consider migrating a primary key column from `int` to `bigint`.\nLet's say you construct and backfill the new `bigint` column and then swap it\nout with the `int` column.\n\nRun a sequence ownership query like [the ones discussed in this\narticle](https://sadique.io/blog/2019/05/07/viewing-sequence-ownership-information-in-postgres/)\nand you'll see that the original `int` column still owns the sequence.\n\nIf you try to drop `old_id`, you'll fortunately get a warning from Postgres:\n\n```sql\nalter table cats drop column old_id;\nERROR:  cannot drop column old_id of table cats because other objects depend on it\nDETAIL:  default value for column id of table cats depends on sequence cats_id_seq\nHINT:  Use DROP ... CASCADE to drop the dependent objects too.\n```\n\nThe `DROP ... CASCADE` suggestion is not the thing to do here. Instead, you'll\nwant to update the ownership of the sequence to the _new_ `id` column:\n\n```sql\nalter sequence cats_id_seq owned by cats.id;\n```\n\n[source](https://www.postgresql.org/docs/current/sql-altersequence.html)\n"
  },
  {
    "path": "postgres/check-if-clusters-are-upgrade-compatible.md",
    "content": "# Check If Clusters Are Upgrade Compatible\n\nOne of the ways to upgrade a PostgreSQL database from one server version to\nanother is to use the built-in `pg_upgrade` command. This can be faster and\nrequire fewer manual steps than something like a `pg_dump` and `pg_restore`.\n\nHowever, before you run the `pg_upgrade` command for real, you should check\nthat the target database is compatible with the current database. To do this,\nwrite your `pg_update` command with all the flags you need and then tack on\n`--check` at the end. This does a dry-run reporting the results of a series of\nconsistency checks.\n\nHere is what a successful _check_ looks like:\n\n```bash\n$ /usr/local/opt/postgresql@13/bin/pg_upgrade \\\n  --old-bindir $HOME/.asdf/installs/postgres/12.3/bin \\\n  --new-bindir /usr/local/opt/postgresql@13/bin \\\n  --old-datadir $HOME/.asdf/installs/postgres/12.3/data \\\n  --new-datadir ./postgres/data \\\n  --check\n\nPerforming Consistency Checks\n-----------------------------\nChecking cluster versions                                   ok\nChecking database user is the install user                  ok\nChecking database connection settings                       ok\nChecking for prepared transactions                          ok\nChecking for system-defined composite types in user tables  ok\nChecking for reg* data types in user tables                 ok\nChecking for contrib/isn with bigint-passing mismatch       ok\nChecking for presence of required libraries                 ok\nChecking database user is the install user                  ok\nChecking for prepared transactions                          ok\nChecking for new cluster tablespace directories             ok\n\n*Clusters are compatible*\n```\n\nIf there is an issue, such as mismatched collation settings, the output will\nreport the issue. You'll have to decide how to resolve those on a case-by-case\nbasis.\n"
  },
  {
    "path": "postgres/check-if-the-local-server-is-running.md",
    "content": "# Check If The Local Server Is Running\n\nAn install of PostgreSQL comes with a number of utilities including the\n`pg_isready` command. This command can be used to check if the local PostgreSQL\nserver is up, running, and ready to receive connections.\n\nIf the server has not yet been started, running the command will result in a\n`no response` response.\n\n```bash\n$ pg_isready\nlocalhost:5432 - no response\n```\n\nIn this case, the `pg_ctl` command can be used to start the server.\n\n```bash\n$ pg_ctl -D $HOME/.asdf/installs/postgres/12.3/data start\nwaiting for server to start....\n\n...\n\n done\nserver started\n```\n\nIt tells us that the server is started and we can confirm that by again running\n`pg_isready`.\n\n```bash\n$ pg_isready\nlocalhost:5432 - accepting connections\n```\n\nThis command is most useful as part of a script, such as in a CI environment.\nIn that case, you may not want it writing to `stdout`, you just want to use the\ncommand's exit code. For that, you can tack on the `--quiet` flag.\n\n```\n$ pg_isready --quiet\n```\n\n[source](https://www.postgresql.org/docs/current/app-pg-isready.html)\n"
  },
  {
    "path": "postgres/check-if-user-role-exists-for-database.md",
    "content": "# Check If User Role Exists For Database\n\nUser roles define who can access a database cluster and broadly what level of\ncontrol they have over that cluster.\n\nThe most straightforward way to check if a user role exists is to connect to\none of the databases in the cluster and run a query against the `pg_roles`\ntable.\n\n```sql\nselect * from pg_roles where rolename='dev';\n\n  rolname\n------------\n    dev\n(1 row)\n```\n\nThis same concept can be used in a script when automating some database setup.\nTo do that, we'll use `-c` (and some other flags) to dispatch a query to `psql`\nfrom a shell context.\n\n```bash\npsql postgres -tXAc \"SELECT 1 FROM pg_roles WHERE rolname='dev'\" \\\n  | grep -q 1 \\\n  || createuser --interactive dev\n```\n\nThis queries for the value `1` if the user role named `dev` exists. The output\nof that is piped to `grep` (in quiet mode, `-q`) to check if `1` is in the\noutput. If user roles doesn't exist and grep doesn't match on `1`, then the\nright side of the _or_ (`||`) gets called. That command could be whatever. I've\nchosen to call PostgreSQL's `createuser` to create the `dev` user role.\n"
  },
  {
    "path": "postgres/check-table-for-any-orphaned-records.md",
    "content": "# Check Table For Any Orphaned Records\n\nIf you don't have a foreign key constraint in place to enforce the relationship\nbetween records in two different tables, then there are a number of ways you\ncould end up with orphaned records. Orphaned records are records that have a\nvalue in an `*_id` column when that value doesn't correspond to any record in\nthe related table.\n\nFor example, let's say we have an `authors` table with an `id` column and a\n`books` table with an `author_id` column. If there is a book record with an\n`author_id` value that doesn't resolve to any record in the `authors` table,\nthen that book is an orphaned record.\n\nYou can find out if a table has orphaned records like so:\n\n```sql\nselect count(*)\n  from books\n  left join authors\n    on books.author_id = authors.id\n  where authors.id is null\n    and books.author_id is not null;\n```\n\nWe select from our table with the foreign key (`books`) and _left join_ it\nagainst the related table (`authors`). If there are any book records where the\njoined author row is `null`, then that book is orphaned.\n"
  },
  {
    "path": "postgres/check-the-size-of-databases-in-a-cluster.md",
    "content": "# Check The Size Of Databases In A Cluster\n\nThe `\\l` command in `psql` will list all the databases for the server. The\nfield surfaced by this meta-command are:\n\n- Name\n- Owner\n- Encoding\n- Locale Provider\n- Collate\n- Ctype\n- ICU Locale\n- ICU Rules\n- Access privileges\n\nIf we add a `+`, issuing instead `\\l+`, we get three additional fields:\n\n- Size\n- Tablespace\n- Description\n\nThe _Size_ column is the human-formatted size of each database.\n\nAnother way to do this is with some SQL querying the underlying record keeping\nof the server's database.\n\n```sql\nselect\n  db.datname as db_name,\n  pg_size_pretty(pg_database_size(db.datname)) as db_size\nfrom pg_database db\norder by pg_database_size(db.datname) desc;\n```\n\nCredit to [this StackOverflow\nanswer](https://stackoverflow.com/a/18907188/535590) for how to do this with a\nSQL query.\n\n[source](https://www.postgresql.org/docs/current/app-psql.html#APP-PSQL-META-COMMAND-LIST)\n"
  },
  {
    "path": "postgres/checking-inequality.md",
    "content": "# Checking Inequality\n\nIn most languages there is a `!=` operator for checking inequality of two\nthings.\n\nPostgres also supports the synonymous `<>` operator for checking inequality.\n\n```sql\n> select 1 <> 1;\n ?column?\n----------\n f\n\n> select true <> false;\n ?column?\n----------\n t\n\n> select 'taco' <> 'burrito';\n ?column?\n----------\n t\n```\n\nh/t Brian Dunn\n\n[source](https://www.postgresql.org/docs/9.5/static/functions-comparison.html)\n"
  },
  {
    "path": "postgres/checking-the-type-of-a-value.md",
    "content": "# Checking The Type Of A Value\n\nThe `pg_typeof()` function allows you to determine the data type of anything\nin Postgres.\n\n```sql\n> select pg_typeof(1);\n pg_typeof\n-----------\n integer\n(1 row)\n\n> select pg_typeof(true);\n pg_typeof\n-----------\n boolean\n(1 row)\n```\n\nIf you try it on an arbitrary string, it is unable to disambiguate which\nstring type (e.g. `text` vs `varchar`).\n\n```sql\n> select pg_typeof('hello');\n pg_typeof\n-----------\n unknown\n(1 row)\n```\n\nYou just have to be a bit more specific.\n\n```sql\n> select pg_typeof('hello'::varchar);\n     pg_typeof\n-------------------\n character varying\n(1 row)\n```\n\n[source](http://www.postgresql.org/docs/9.3/static/functions-info.html#FUNCTIONS-INFO-CATALOG-TABLE)\n"
  },
  {
    "path": "postgres/clear-the-screen-in-psql-2.md",
    "content": "# Clear The Screen In psql (2)\n\nIn [Clear The Screen In psql](clear-the-screen-in-psql.md), I showed how you\ncan shell out to the `clear` command as a way of clearing the screen in\n`psql`.\n\nIt turns out there is an even simpler way. Just hit `CTRL-l`.\n"
  },
  {
    "path": "postgres/clear-the-screen-in-psql.md",
    "content": "# Clear The Screen In psql\n\nThe `psql` interactive terminal does not have a built-in way of clearing the\nscreen. What I usually do if I really need the screen cleared is quit, run\n`clear` from the shell, and then open a new `psql` session. This is\nunnecessary though. Instead, we can use the `\\!` command to execute a shell\ncommand, in this case, the `clear` command.\n\n```\n> \\! clear\n```\n\nThis clears the screen in one step and keeps our current session running.\n\nSee the [psql\ndocs](http://www.postgresql.org/docs/current/static/app-psql.html) for more\ndetails.\n"
  },
  {
    "path": "postgres/compute-hashes-with-pgcrypto.md",
    "content": "# Compute Hashes With pgcrypto\n\nThe `pgcrypto` extension that comes with PostgreSQL adds access to some\ngeneral hashing functions. Included are `md5`, `sha1`, `sha224`, `sha256`,\n`sha384` and `sha512`. Any of these hashing functions can be applied to an\narbitrary string using the `digest` function. Here are example of the `md5`\nand `sha1` algorithms:\n\n```sql\n> create extension pgcrypto;\nCREATE EXTENSION\n\n> select digest('Hello, World!', 'md5');\n               digest\n------------------------------------\n \\x65a8e27d8879283831b664bd8b7f0ad4\n\n> select digest('Hello, World!', 'sha1');\n                   digest\n--------------------------------------------\n \\x0a0a9f2a6772942557ab5355d76af442f8f65e01\n```\n\nSee the [`pgcrypto` docs](\nhttp://www.postgresql.org/docs/current/static/pgcrypto.html) for more\ndetails.\n"
  },
  {
    "path": "postgres/compute-median-instead-of-average.md",
    "content": "# Compute Median Instead Of Average\n\nOne of the first aggregate functions we might use in PostgreSQL, besides `sum`,\nis `avg`.\n\n```sql\nselect avg(book_count) as average_books_read\nfrom (\n  select users.id, count(books.id) as book_count\n  from users\n  left join books\n    on books.user_id = users.id\n  where books.read_in_year = 2025\n  group by users.id\n) as user_book_counts;\n```\n\nThis computes the average of the set of values which sums them all up\nand divides by the count. The average (maybe you've heard this also called the\n_mean_) is not always the best way to understand data, especially when there are\noutliers.\n\nInstead, we might want to compute the _median_ value of our set of data. There\nis no easily identifiable `median` aggregate function. Instead, we can use\n`percentile_cont` with a value of `0.5`. This gets us the 50th percentile of our\nset of data which is the definition of the _median_.\n\n```sql\nselect percentile_cont(0.5) within group (\n  order by book_count\n) as median_books_read\nfrom (\n  select users.id, count(books.id) as book_count\n  from users\n  left join books on books.user_id = users.id and books.read_in_year = 2025\n  group by users.id\n) as user_book_counts;\n```\n\nThe full syntax for `percentile_cont` is `percentile_cong(precision) within\ngroup (order by ...)` because this is an aggregiate that has to work with an\nordered-set of data.\n\n[source](https://www.postgresql.org/docs/current/functions-aggregate.html)\n"
  },
  {
    "path": "postgres/compute-the-levenshtein-distance-of-two-strings.md",
    "content": "# Compute The Levenshtein Distance Of Two Strings\n\nPostgreSQL has a built-in function for computing the [Levenshtein\ndistance](https://en.wikipedia.org/wiki/Levenshtein_distance) between two\nstrings.\n\n```sql\n> select levenshtein('hello', 'world');\n levenshtein\n-------------\n           4\n\n> select levenshtein('function', 'funtcion');\n levenshtein\n-------------\n           2\n```\n\nCheck out the [`fuzzystrmatch`\nmodule](https://www.postgresql.org/docs/current/fuzzystrmatch.html#id-1.11.7.24.6)\nfor more details.\n"
  },
  {
    "path": "postgres/compute-the-md5-hash-of-a-string.md",
    "content": "# Compute The md5 Hash Of A String\n\nOne of the functions provided by PostgreSQL for working with string data is\nthe `md5()` function. This function calculates the md5 hash of a given string.\n\nIt works like this:\n\n```sql\n> select md5('Hello, World!');\n               md5\n----------------------------------\n 65a8e27d8879283831b664bd8b7f0ad4\n\n> select md5('$3cr3tp4$$w0rd');\n               md5\n----------------------------------\n bbabecfd4031211077473734bae7249f\n```\n\nThere are more hashing algorithms provided by the `pgcrypto` extension. See\n[Compute Hashes With pgcrypto](postgres/compute-hashes-with-pgcrypto.md) for\nmore details on that.\n"
  },
  {
    "path": "postgres/concatenate-strings-with-a-separator.md",
    "content": "# Concatenate Strings With A Separator\n\nI was putting together an example of using a generated column that concatenates\nstring values from a few other columns. I used manual concatenation with the\n`||` operator like so:\n\n```sql\ncreate table folders (\n  id integer generated always as identity primary key,\n  user_id integer not null,\n  name text not null,\n  parent_folder_id integer references folders(id),\n  path text generated always as (\n    user_id::text || ':' || lower(name) || ':' || coalesce(parent_folder_id::text, '0')\n  ) stored\n);\n```\n\nInstead of doing that manual concatenation for the `path` generated column, I\ncan use\n[`concat_ws`](https://www.postgresql.org/docs/current/functions-string.html).\n\n```sql\ncreate table folders (\n  id integer generated always as identity primary key,\n  user_id integer not null,\n  name text not null,\n  parent_folder_id integer references folders(id),\n  path text generated always as (\n    concat_ws(\n      ':',\n      user_id::text,\n      lower(name),\n      coalesce(parent_folder_id::text, '0')\n    )\n  ) stored\n);\n```\n\nThe first argument to `concat_ws` is the separator I want to use. The remaining\narguments are the strings that should be concatenated with that separator.\n\nOne other things that is nice about `concat_ws` is that it will ignore `null`\nvalues that it receives.\n\n```sql\n> select concat_ws(':', 'one', 'two', null, 'three');\n+---------------+\n| concat_ws     |\n|---------------|\n| one:two:three |\n+---------------+\n```\n"
  },
  {
    "path": "postgres/configure-the-timezone.md",
    "content": "# Configure The Timezone\n\nRunning `show timezone;` will reveal the timezone for your postgres\nconnection. If you want to change the timezone for the duration of the\nconnection, you can run something like\n\n```\n> set timezone='America/New_York';\nSET\n> show timezone;\n TimeZone\n------------------\n America/New_York\n(1 row)\n```\n\nNow, if you run a command such as `select now();`, the time will be in\nEastern time.\n\nh/t Jack Christensen\n"
  },
  {
    "path": "postgres/constructing-a-range-of-dates.md",
    "content": "# Constructing A Range Of Dates\n\nPostgreSQL offers a number of range types including the `daterange` type.\nThis can be constructed using the `daterange()` function with two strings\nrepresenting the lower and upper bounds of the date range respectively.\n\n```sql\n> select daterange('2015-1-1','2015-1-5');\n        daterange\n-------------------------\n [2015-01-01,2015-01-05)\n```\n\nThe lower bound is inclusive -- indicated by the `[` character -- and the\nupper bound is exclusive -- indicated by the `)` character.\n\n[source](http://www.postgresql.org/docs/current/static/rangetypes.html)\n"
  },
  {
    "path": "postgres/convert-a-string-to-a-timestamp.md",
    "content": "# Convert A String To A Timestamp\n\nIf you have a string that represents a point in time, there are a couple\nways that you can convert it to a PostgreSQL `timestamptz` value.\n\nIf the string is in [ISO 8601\nformat](https://en.wikipedia.org/wiki/ISO_8601), then it can be simply cast\nto `timestamptz`.\n\n```sql\n> select '2018-10-24'::timestamptz;\n      timestamptz\n------------------------\n 2018-10-24 00:00:00-05\n```\n\nA more general purpose approach is to use the\n[`to_timestamp`](https://www.postgresql.org/docs/11/static/functions-formatting.html)\nfunction.\n\n```sql\n> select to_timestamp('2018-10-24', 'YYYY-MM-DD');\n      to_timestamp\n------------------------\n 2018-10-24 00:00:00-05\n```\n\nThe first argument is our string-to-be-converted in whatever format. The\nsecond argument is another string describing in what format that string is.\n\nNote: Both of these approaches produce a `timestamptz` value.\n"
  },
  {
    "path": "postgres/count-how-many-records-there-are-of-each-type.md",
    "content": "# Count How Many Records There Are Of Each Type\n\nLet's say I have a `books` table full of data. One of the columns on this table\nis `status` which represents whether the book is published, in review, or still\na draft.\n\nWe can find out how many records (books) there are for each `status` using a\n`group by` clause and the `count` aggregate function.\n\n```sql\n> select status, count(*)\n    from books\n    group by status;\n\n  status   | count\n-----------+-------\n ø         |   123\n published |   611\n draft     |   364\n review    |   239\n(4 rows)\n```\n\nBecause we don't have a `not null` constraint on the `status` column, there are\nalso some records that have a null value.\n\nWe can take this a step further by ordering the output in a consistent\nway—descending order of the count column.\n\n```sql\n> select status, count(*)\n    from books\n    group by status\n    order by 2 desc;\n\n  status   | count\n-----------+-------\n published |   611\n draft     |   364\n review    |   239\n ø         |   123\n(4 rows)\n```\n\nThis `order by` clauses uses [a positional index from the select\narguments](use-argument-indexes.md), so the `2` references the `count(*)`\nargument.\n"
  },
  {
    "path": "postgres/count-records-by-type.md",
    "content": "# Count Records By Type\n\nIf you have a table with some sort of type column on it, you can come up\nwith a count of the records in that table by type. You just need to take\nadvantage of `group by`:\n\n```sql\n> select type, count(*) from pokemon group by type;\n\n  type   | count \n-----------------\n fire    |    10\n water   |     4\n plant   |     7\n psychic |     3\n rock    |    12\n```\n"
  },
  {
    "path": "postgres/count-the-number-of-items-in-an-array.md",
    "content": "# Count The Number Of Items In An Array\n\nThere are two ways to count the number of items in an array with PostgreSQL.\nThe one that might jump out at you or show up at the top of search results is\n[`array_length`](https://www.postgresql.org/docs/current/functions-array.html).\n\n```sql\n> select array_length(array[1,2,3], 1);\n+--------------+\n| array_length |\n|--------------|\n| 3            |\n+--------------+\n\n> select array_length(array[[1,2], [3,4]], 2);\n+--------------+\n| array_length |\n|--------------|\n| 2            |\n+--------------+\n```\n\nThis requires specifying the dimension at which you want to check the length.\nThe first example, checking the 1st dimension of a one-dimensional array, seems\nlike the more common and useful scenario. In the second example, we are\nchecking the 2nd dimension.\n\nThe other way we can determine the number of items in an array is with the\n[`cardinality`](https://www.postgresql.org/docs/current/functions-array.html)\nfunction.\n\n> Returns the total number of elements in the array, or 0 if the array is\n> empty.\n\n```sql\n> select cardinality(array[1,2,3]);\n+-------------+\n| cardinality |\n|-------------|\n| 3           |\n+-------------+\n\n> select cardinality(array[[1,2], [3,4]]);\n+-------------+\n| cardinality |\n|-------------|\n| 4           |\n+-------------+\n```\n\nThis behaves the same as `array_length` for a one-dimensional array and doesn't\nrequire a second argument. Where it gets more interesting is with\nmulti-dimensional arrays. It returns the total number of elements in the\narrayregardless of the nesting.\n\n[source](https://mattrighetti.com/2025/01/20/you-dont-need-sql-builders)\n"
  },
  {
    "path": "postgres/count-the-number-of-trues-in-an-aggregate-query.md",
    "content": "# Count The Number Of Trues In An Aggregate Query\n\nThe `sum` function is an aggregate function that allows you to sum up a bunch\nof integers. What if you want to sum up a boolean column? You may want to know\nhow many times `true` appears in a collection of grouped records.\n\nThis can be done by mixing in a `case` statement.\n\n```sql\nselect\n  author_id,\n  sum(case when available then 1 else 0 end)\nfrom books\ngroup by author_id;\n```\n\nHere, we are able to find out for each author how many books they have\navailable.\n\nIf we want to count `false` values, we can just invert the `sum` statement:\n\n```sql\nsum(case when available then 0 else 1 end)\n```\n\n[source](https://stackoverflow.com/a/5396728/535590)\n"
  },
  {
    "path": "postgres/create-a-cluster-in-a-specific-data-directory.md",
    "content": "# Create A Cluster In A Specific Data Directory\n\nLet's say I want to create a PostgreSQL cluster near my app. So, I create a\n`postgres/data` directory next to my app. Then I run the `initdb` command\npointing at that directory and specifying the UTF-8 locale.\n\nHere is what that looks like:\n\n```bash\n$ /usr/local/opt/postgresql@13/bin/initdb -D postgres/data --locale=en_US.UTF-8\n\nThe files belonging to this database system will be owned by user \"jbranchaud\".\nThis user must also own the server process.\n\nThe database cluster will be initialized with locale \"en_US.UTF-8\".\nThe default database encoding has accordingly been set to \"UTF8\".\nThe default text search configuration will be set to \"english\".\n\nData page checksums are disabled.\n\nfixing permissions on existing directory postgres/data ... ok\ncreating subdirectories ... ok\nselecting dynamic shared memory implementation ... posix\nselecting default max_connections ... 100\nselecting default shared_buffers ... 128MB\nselecting default time zone ... America/Chicago\ncreating configuration files ... ok\nrunning bootstrap script ... ok\nperforming post-bootstrap initialization ... ok\nsyncing data to disk ... ok\n\ninitdb: warning: enabling \"trust\" authentication for local connections\nYou can change this by editing pg_hba.conf or using the option -A, or\n--auth-local and --auth-host, the next time you run initdb.\n\nSuccess. You can now start the database server using:\n\n    '/usr/local/opt/postgresql@13/bin/pg_ctl' -D postgres/data -l logfile start\n```\n\nAs stated at the end of the command's output, I can run the `postgres` server\nwith that data directory with:\n\n```bash\n$ '/usr/local/opt/postgresql@13/bin/pg_ctl' -D postgres/data -l logfile start\n```\n"
  },
  {
    "path": "postgres/create-a-composite-primary-key.md",
    "content": "# Create A Composite Primary Key\n\nThe unique identifier for a given row in a table is the *primary key*.\nGenerally, a row can be uniquely identified by a single data point (such as\nan id), so the primary key is simply that single data point. In some cases,\nyour data can be more appropriately uniquely identified by multiple values.\nThis is where composite primary keys can lend a hand. Consider an example\n`plane_tickets` table where each ticket can be uniquely identified by the\npassenger and flight it is associated with:\n\n```sql\ncreate table plane_tickets (\n  passenger_id integer references passengers not null,\n  flight_id integer references flights not null,\n  confirmation_number varchar(6) not null,\n  seat_assignment varchar not null,\n  primary key (passenger_id, flight_id)\n);\n```\n"
  },
  {
    "path": "postgres/create-a-table-from-the-structure-of-another.md",
    "content": "# Create A Table From The Structure Of Another\n\nThere are a couple ways to create a new table from the structure of another table.\n\nOne of those ways is with the [`create table as`\nsyntax](https://www.postgresql.org/docs/current/sql-createtableas.html).\n\n```sql\ncreate table dupe_table as table existing_table with no data;\n```\n\nI wouldn't recommend this approach though because it only reproduces the\ncolumns and datatypes. The modifiers, indexes, and constraints are not\nincluded.\n\nThe [`create table`\nsyntax](https://www.postgresql.org/docs/current/sql-createtable.html), on the\nother hand, gives you more options and flexibility for this kind of task.\n\n```sql\ncreate table dupe_table (like existing_table);\n```\n\nThis works just like the first statement, reproducing just the columns and\ndatatypes.\n\nThere are options for enhancing this statement. We can tell it to additionally\n_include_ things like `defaults`, `indexes`, `constraints`, or even just\n_everything_ (`including all`).\n\nHere is what it looks like to copy the `existing_table` so that things like\n`not null`, B-Tree indexes, and primary key `default` values are reproduced\nalong with the columns and datatypes.\n\n```sql\ncreate table dupe_table (\n  like existing_table\n    including defaults\n    including indexes\n    including constraints\n)\n```\n\n[source](https://www.reddit.com/r/PostgreSQL/comments/uu8xcs/comment/i9e36m2/)\n"
  },
  {
    "path": "postgres/create-an-index-across-two-columns.md",
    "content": "# Create An Index Across Two Columns\n\nMost commonly when we create an index, it is targeted at a single column of a\ntable. Sometimes an expensive query that works with two different columns would\nbe better off with an index that combines those two columns. This is called a\n_composite index_.\n\nLet's consider this query:\n\n```sql\nselect * from events\n  where user_id = 123\n  order by created_at desc\n  limit 1;\n```\n\nThough this query will use the index on `created_at` to do an Index Scan, it\nwill still have to do a bunch of expensive filtering of `user_id` values after\nthe fact.\n\nWhat this query needs to be efficient is a _composite index_ on `user_id` and\n`created_at`. We can create one like so:\n\n```sql\ncreate index events_user_id_created_at_idx\n  on events (user_id, created_at);\n```\n\nInstead of doing a bunch of post-index filtering on `user_id` values, that\nexpensive query will factor `user_id` into its Index Scan and complete much\nquicker.\n\nSee [the Postgres docs on multicolumn\nindexes](https://www.postgresql.org/docs/current/indexes-multicolumn.html) for\nmore details.\n"
  },
  {
    "path": "postgres/create-an-index-without-locking-the-table.md",
    "content": "# Create An Index Without Locking The Table\n\nWhen creating an index for a column, the process of building the index will\nlock the column's table. For small datasets this isn't a concern because the\nindex will take no time at all to create. For larger datasets, the lock could\nlast long enough to create meaningful downtime. This can all be avoided by\ntelling Postgres to build the index concurrently.\n\n```sql\ncreate index concurrently idx_book_isbns on books(isbn);\n```\n\nCreating the index this way will take a bit longer and put more strain on\nmachine resources, but it allows concurrent inserts, updates, or deletes on the\ntable. In other words, you can add an index to a large table in a production\nenvironment without bringing down your app.\n\nRead more about the [details and potential\ncaveats](https://www.postgresql.org/docs/current/sql-createindex.html#SQL-CREATEINDEX-CONCURRENTLY)\nin the docs.\n"
  },
  {
    "path": "postgres/create-and-execute-sql-statements-with-gexec.md",
    "content": "# Create And Execute SQL Statements With \\gexec\n\nThe [`\\gexec`\nmeta-command](https://www.postgresql.org/docs/current/app-psql.html#APP-PSQL-META-COMMAND-GEXEC)\nis a variation of the [`\\g`\nmeta-command](https://www.postgresql.org/docs/current/app-psql.html#APP-PSQL-META-COMMAND-G),\nboth of which can be used in a `psql` session. Whereas the `\\g` command sends\nthe current query in the buffer to the PostgreSQL server for execution, the\n`\\gexec` command first sends the query to the server for execution and then\nexecutes each row of the result as its own SQL statement.\n\nThis is both a bit absurd and powerful. And a bit unnecessary considering all\nof the scripting capabilities with anything from bash to any language with a\nSQL client library.\n\nNevertheless, let's take a look at a contrived example of how it works. Here,\nwe have a SQL statement that does some string concatenation based off values in\nan array. This results in three separate `create schema` statements.\n\n```sql\n> select\n    'create schema if not exists schema_' || letter || ';'\n  from unnest(array['a', 'b', 'c']) as letter\n  \\gexec\n\nCREATE SCHEMA\nCREATE SCHEMA\nCREATE SCHEMA\n\n> \\dn\n       List of schemas\n   Name   |       Owner\n----------+-------------------\n public   | pg_database_owner\n schema_a | postgres\n schema_b | postgres\n schema_c | postgres\n(4 rows)\n```\n\nThree new schemas get created which we can inspect with `\\dn`.\n\nNotice, if we simply execute the primary statement, we can see the intermediate\nresult that `\\gexec` will subsequently execute.\n\n```sql\n> select\n    'create schema if not exists schema_' || letter || ';'\n  from unnest(array['a', 'b', 'c']) as letter\n  \\g\n\n               ?column?\n---------------------------------------\n create schema if not exists schema_a;\n create schema if not exists schema_b;\n create schema if not exists schema_c;\n(3 rows)\n```\n"
  },
  {
    "path": "postgres/create-database-uses-template1.md",
    "content": "# Create Database Uses Template1\n\nWhenever you use the [`create\ndatabase`](https://www.postgresql.org/docs/current/sql-createdatabase.html)\nquery, unless otherwise specified, it will create it by cloning `template1` by\ndefault.\n\nYou can view, inspect, and even modify this database template by connecting to\nit.\n\n```sql\n\\c template1\n```\n\nEvery Postgres cluster starts with two templates.\n\n```sql\nselect datname from pg_database where datistemplate = true;\n  datname\n-----------\n template1\n template0\n(2 rows)\n```\n\nYou cannot however connect to and modify `template0`. It is a fallback clone of\n`template1` that you can utilize if you ever modify `template1` and need to\nrestore it.\n\n[source](https://supabase.io/blog/2020/07/09/postgresql-templates/)\n"
  },
  {
    "path": "postgres/create-hstore-from-two-arrays.md",
    "content": "# Create hstore From Two Arrays\n\nPostgreSQL allows the use of the `hstore` type by enabling the `hstore`\nextension. One way to create an instance of `hstore` data is by passing two\narrays to the `hstore()` function. The first array is a set of keys and the\nsecond array is the set of values.\n\n```sql\n> select hstore(array['one','two','three'], array['1','2','3']);\n                hstore\n--------------------------------------\n \"one\"=>\"1\", \"two\"=>\"2\", \"three\"=>\"3\"\n```\n\nThe two arrays must be the same length or an error will occur.\n\n```sql\n> select hstore(array['one','two','three'], array['1','2']);\nERROR:  arrays must have same bounds\n```\n"
  },
  {
    "path": "postgres/create-table-adds-a-data-type.md",
    "content": "# Create Table Adds A Data Type\n\nEach time you create a table in PostgreSQL, a new data type represented by\nthat table is created and added to the `pg_type` table. According to the\nPostgres docs:\n\n> CREATE TABLE also automatically creates a data type that represents the\n> composite type corresponding to one row of the table. Therefore, tables\n> cannot have the same name as any existing data type in the same schema.\n\nFor instance, if you create a `users` table like so:\n\n```sql\ncreate table users (\n  id serial primary key,\n  first_name varchar not null,\n  last_name varchar not null\n);\n```\n\nthen the `pg_type` will now contain an entry with a `typname` of `users`.\n\n```sql\nselect * from pg_type where typname = 'users';\n-[ RECORD 1 ]--+------------\ntypname        | users\ntypnamespace   | 2200\ntypowner       | 16384\n...\n```\n\nh/t Bruce Momjian\n"
  },
  {
    "path": "postgres/creating-conditional-constraints.md",
    "content": "# Creating Conditional Constraints\n\nThere are times when it doesn't make sense for a constraint to apply to all\nrecords in a table. For instance, if we have a table of pokemon, we may only\nwant to apply a unique index constraint to the names of non-wild pokemon.\nThis can be achieved with the following conditional constraint:\n\n```sql\ncreate unique index pokemons_names on pokemons (names)\nwhere wild = false;\n```\n\nIf we try to insert a non-wild pokemon with a duplicate name, we will get an\nerror. Likewise, if we try to update a pokemon with a duplicate name from\nwild to non-wild, we will get an error.\n\n[source](http://www.postgresguide.com/performance/conditional.html)\n"
  },
  {
    "path": "postgres/creating-custom-types.md",
    "content": "# Creating Custom Types\n\nPostgreSQL has support for creating custom types. When you need something\nmore expressive than the built-in types and you don't want your data spread\nacross multiple columns, you can instead create a custom type.\n\n```sql\ncreate type dimensions as (\n  width integer,\n  height integer,\n  depth integer\n);\n```\n\nThis new type can then be used in the definition of a new table\n\n```sql\ncreate table moving_boxes (\n  id serial primary key,\n  dims dimensions not null\n);\n```\n\nand when inserting data\n\n```sql\ninsert into moving_boxes (dims) values (row(3,4,5)::dimensions);\n```\n\nSee the [`create type`\ndocs](http://www.postgresql.org/docs/current/static/sql-createtype.html) for\nmore details.\n"
  },
  {
    "path": "postgres/day-of-week-by-name-for-a-date.md",
    "content": "# Day Of Week By Name For A Date\n\nIn [Day Of Week For A Date](day-of-week-for-a-date.md), I explained how to\ndetermine what day of the week a date is as an integer with PostgreSQL. This\nused the `date_part()` function. By using the `to_char()` function with a\ndate or timestamp, we can determine the day of the week by name (e.g.\nMonday). For instance, to determine what day today is, try a statement like\nthe following:\n\n```sql\n> select to_char(now(), 'Day');\n  to_char\n-----------\n Sunday\n```\n\nThe `Day` part of the second argument is just one of many template patterns\nthat can be used for formatting dates and times.\n\nSee [Data Type Formatting\nFunctions](http://www.postgresql.org/docs/current/static/functions-formatting.html)\nin the Postgres docs for more details.\n"
  },
  {
    "path": "postgres/day-of-week-for-a-date.md",
    "content": "# Day Of Week For A Date\n\nGiven a `date` in PostgreSQL\n\n```sql\n> select '2050-1-1'::date;\n    date\n------------\n 2050-01-01\n```\n\nyou can determine the day of the week for that date with the `date_part()`\nfunction\n\n```sql\n> select date_part('dow', '2050-1-1'::date);\n date_part\n-----------\n         6\n```\n\nThe days of week are `0` through `6`, `0` being Sunday and `6` being\nSaturday.\n\n[source](http://www.postgresql.org/docs/current/static/functions-datetime.html)\n"
  },
  {
    "path": "postgres/default-schema.md",
    "content": "# Default Schema\n\nSchemas can be used to organize tables within a database. You can see all\nthe schemas your database has like so\n\n```sql\n> select schema_name from information_schema.schemata;\n    schema_name\n--------------------\n pg_toast\n pg_temp_1\n pg_toast_temp_1\n pg_catalog\n public\n information_schema\n(6 rows)\n```\n\nWhen you create a new table, it will need to be placed under one of these\nschemas. So if you have a `create table posts (...)`, how does postgres know\nwhat schema to put it under?\n\nPostgres checks your `search_path` for a default.\n\n```sql\n> show search_path;\n   search_path\n-----------------\n \"$user\", public\n(1 row)\n```\n\nFrom our first select statement, we see that there is no schema with my user\nname, so postgres uses public as the default schema.\n\nIf we set the search path to something that won't resolve to a schema name,\npostgres will complain\n\n```sql\n> set search_path = '$user';\nSET\n> create table posts (...);\nERROR:  no schema has been selected to create in\n```\n"
  },
  {
    "path": "postgres/defining-arrays.md",
    "content": "# Defining Arrays\n\nIn postgres, an array can be defined using the `array` syntax like so:\n\n```sql\n> select array['a','b','c'];\n  array\n---------\n {a,b,c}\n```\n\nIf you are inserting into an existing array column, you can use the array\nliteral syntax.\n\n```sql\n> create temp table favorite_numbers(numbers integer[]);\nCREATE TABLE\n> insert into favorite_numbers values( '{7,3,9}' );\nINSERT 0 1\n> select numbers[2] from favorite_numbers;\n numbers\n---------\n       3\n```\n\nPostgres also supports two-dimensional arrays.\n\n```sql\nselect array[[1,2,3],[4,5,6],[7,8,9]] telephone;\n         telephone\n---------------------------\n {{1,2,3},{4,5,6},{7,8,9}}\n```\n"
  },
  {
    "path": "postgres/determine-types-of-jsonb-records.md",
    "content": "# Determine Types Of JSONB Records\n\nYou can stick several different things into a [JSONB postgres\ncolumn](https://www.postgresql.org/docs/9.4/datatype-json.html).\n\n> Possible types are object, array, string, number, boolean, and null.\n\nIf you are trying to audit what is in them, you might reach for:\n\n```sql\n> select pg_typeof(my_jsonb_column) from my_table;\n```\n\nThat is just gonna spit out `jsonb` over and over, like, I already know that.\n\nWhat you really want to know is, is the top-level thing an _object_, an\n_array_, or maybe just a _string_ or _number_. There are specific JSON\nprocessing functions for this, `json_typeof` and `jsonb_typeof` which you can\ncall like so:\n\n```sql\n> select jsonb_typeof(my_jsonb_column) from my_table;\n jsonb_typeof\n--------------\n object\n array\n ...\n```\n\n[source](https://www.postgresql.org/docs/9.5/functions-json.html)\n"
  },
  {
    "path": "postgres/determining-the-age-of-things.md",
    "content": "# Determining The Age Of Things\n\nIn PostgreSQL, we can determine the age of something (or someone) by passing\na timestamp to the `age` function.\n\nFor instance, if we want to know how long it has been since y2k, we can run\nthe following query:\n\n```sql\n> select age(timestamp '2000-01-01');\n           age\n-------------------------\n 16 years 4 mons 12 days\n```\n\nAdditionally, if we want to know the amount of time between two dates, we\ncan pass two timestamps to the `age` function.\n\nFor example, we can find out how old Prince lived to be by passing in the\ndate of death and then date of birth:\n\n```sql\n> select age(timestamp 'April 21, 2016', timestamp 'June 7, 1958');\n           age\n--------------------------\n 57 years 10 mons 14 days\n```\n\nh/t Josh Davey\n"
  },
  {
    "path": "postgres/difference-between-explain-and-explain-analyze.md",
    "content": "# Difference Between Explain And Explain Analyze\n\nThe `explain` statement allows you to gain some insight into the performance of\na query. You may hear `explain` and `explain analyze` referred to\ninterchangeably in conversation. Though they can both be used to explore how a\nquery will perform, it's important to know a key difference. `explain analyze`\nexecutes the query, `explain` does not.\n\nFor `select` queries, the distinction may not feel that important. For\n`insert`s, `update`s, and `delete`s, you'll want to be clear about which one\nyou are using.\n\n```sql\n> explain insert into books (title, author) values ('Fledgling', 'Octavia Butler');\n                     QUERY PLAN\n----------------------------------------------------\n Insert on books  (cost=0.00..0.01 rows=1 width=76)\n   ->  Result  (cost=0.00..0.01 rows=1 width=76)\n\n> select count(*) from books;\n count\n-------\n     0\n```\n\nWith `explain`, you get cost estimates of the `insert` statement.\n\n```sql\n> explain analyze insert into books (title, author) values ('Fledgling', 'Octavia Butler');\n                                          QUERY PLAN\n----------------------------------------------------------------------------------------------\n Insert on books  (cost=0.00..0.01 rows=1 width=76) (actual time=0.285..0.285 rows=0 loops=1)\n   ->  Result  (cost=0.00..0.01 rows=1 width=76) (actual time=0.012..0.012 rows=1 loops=1)\n Planning time: 0.021 ms\n Execution time: 0.309 ms\n\n> select count(*) from books;\n count\n-------\n     1\n```\n\nWith `explain analyze`, you get estimates and actual numbers. You also get a\nrow inserted in the `books` table.\n"
  },
  {
    "path": "postgres/different-ways-to-define-an-interval.md",
    "content": "# Different Ways To Define An Interval\n\nThere are several different ways in PostgreSQL to define an `interval` data\ntype. An `interval` is useful because it can represent a discrete chunk of\ntime. This is handy for doing date math.\n\nHere are four different ways to define an `interval`:\n\n1. Use the `interval` keyword with a string\n\n```sql\n> select interval '3 days';\n interval\n----------\n 3 days\n(1 row)\n```\n\n2. Cast a string to the `interval` type\n\n```sql\n> select '3 days'::interval;\n interval\n----------\n 3 days\n(1 row)\n```\n\n3. The `@` operator is a finicky syntax for declaring an interval\n\n```sql\n> select @ 3 days;\n days\n------\n    3\n(1 row)\n```\n\n4. The [`make_interval`\n   function](https://www.postgresql.org/docs/current/functions-datetime.html)\n   can take various forms of arguments to construct an interval\n\n```sql\n> select make_interval(days => 3);\n make_interval\n---------------\n 3 days\n(1 row)\n```\n\n[source](https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-INTERVAL-INPUT)\n"
  },
  {
    "path": "postgres/dump-all-databases-to-a-sql-file.md",
    "content": "# Dump All Databases To A SQL File\n\nI recently needed to reinstall my local Postgres installation. I had several\ndatabases with data in that cluster that I wanted to preserve. Before I could\ngo uninstalling and re-installing Postgres, I needed to dump the entire cluster\nof databases.\n\nThe `pg_dumpall` command that installs with Postgres can be used for this.\n\n```bash\n$ pg_dumpall > postgres_13_1_cluster_dump.sql\n```\n\nThe command outputs to stdout a SQL dump of all the databases stored in the\ndata directory of this Postgres instance.\n\nI took this a step further and ignored the `template0` and `template1`\ndirectories because I knew those would come with the new install. I did that by\nadding the `--exclude-database` flag with a pattern.\n\n```bash\n$ pg_dumpall \\\n  --exclude-database=\"template*\" \\\n  > postgres_13_1_cluster_dump.sql\n```\n\nThis data dump can be restored with the new install using:\n\n```bash\n$ psql -f postgres_13_1_cluster_dump.sql postgres\n```\n\nI wrote more about this process in [Reinstall Postgres with OpenSSL Using\nasdf](https://dev.to/jbranchaud/reinstall-postgresql-with-openssl-using-asdf-cmj).\n\nAlso, see `pg_dumpall --help` or the [Postgres\ndocs](https://www.postgresql.org/docs/current/app-pg-dumpall.html) for more\ndetails.\n"
  },
  {
    "path": "postgres/dump-and-restore-a-database.md",
    "content": "# Dump And Restore A Database\n\nPostgreSQL comes with two command-line utilities for dumping and then\nrestoring a database -- `pg_dump` and `pg_restore`, respectively.\n\nUsing the `pg_dump` with the `-Fc` flag will create a dump of the given\ndatabase in a custom format. The output of this command can be redirected\ninto a file (the `.dump` extension is a standard convention):\n\n```bash\n$ pg_dump -Fc my_database > my_database.dump\n```\n\nUsing the custom format option provides a couple benefits. The output is\nsignificantly compressed in comparison to a generic SQL dump. The dump and\nrestoration is more flexible. Lastly, the dump can be performed in parallel\nif your machine has multiple cores to work with. Likewise, the restoration\ncan be done in parallel with multiple jobs.\n\nTo restore the dump, create a fresh database and then use `pg_restore`:\n\n```bash\n$ createdb my_new_database\n$ pg_restore -d my_new_database my_database.dump\n```\n\nNote: the dumped tables will depend on some user role. You will need to\nensure that this role exists on the database cluster where the restore is\nhappening. You can use the `createuser` command if necessary.\n\nSee the\n[`pg_dump` docs](http://www.postgresql.org/docs/current/static/app-pgdump.html)\nand [`pg_restore`\ndocs](http://www.postgresql.org/docs/current/static/app-pgrestore.html)\nfor more details.\n"
  },
  {
    "path": "postgres/dump-the-sql-needed-recreate-a-table.md",
    "content": "# Dump The SQL Needed To Recreate A Table\n\nThe [`pg_dump`](https://www.postgresql.org/docs/current/app-pgdump.html)\ncommand and its arsenal of flags can do a lot of things. This includes\nproducing the set of [DDL](https://www.postgresql.org/docs/current/ddl.html)\nSQL commands needed to recreate a table and all of it sequences, constraints,\nand indexes.\n\nThe primary flags to know about for this scenario are `-t` (which lets you\nspecify a table) and `--schema-only` (which indicates that we want to exclude\ndata from the data).\n\n```bash\n$ pg_dump -t 'users' --schema-only my_database > users.schema.sql\n```\n\nRun a command like to create a file `users.schema.sql` that will contain a\nseries of SQL commands that will:\n\n- create the table with its columns (including defaults, `not null` constraints, etc.)\n- create and set the sequence on a serial ID column\n- add any foreign key constraints\n- create any indexes\n\nThen if you're ever wanting to recreate this table, you can hand that file\ndirectly to `pg_restore`. Or, since it is in SQL, you can run those commands\nmanually.\n\nThere are a ton of flags beyond the two covered here. Read about them in the\n[`pg_dump` docs\npages](https://www.postgresql.org/docs/current/app-pgdump.html).\n"
  },
  {
    "path": "postgres/duplicate-a-local-database.md",
    "content": "# Duplicate A Local Database\n\nYou can quickly create a new database instance that is a duplicate of another\ndatabase. If the existing database is local, you don't need to dump and\nrestore. Instead you can use the `createdb` command that comes with Postgres:\n\n```bash\n$ createdb -O ownername -T originaldb newdb\n```\n\nThis creates a new database called `newdb` using `originaldb` as a template\n(`-T`). This will include the entire schema and data of the original database.\nThe `-O` flag allows you to specify the owner of the database. Since this is\nlocal, you probably want your primary unix user as the owner.\n\n[source](https://stackoverflow.com/a/6739995/535590)\n"
  },
  {
    "path": "postgres/edit-existing-functions.md",
    "content": "# Edit Existing Functions\n\nIn the `psql` console, use `\\ef` with the name of a function to fetch and\nopen the definition of the function. The function will be opened in your\nsystem `$EDITOR` in the form of a `create or replace function` query.\n\nExecuting\n\n```sql\n> \\ef now\n```\n\nwill open the following in your default editor\n\n```sql\nCREATE OR REPLACE FUNCTION pg_catalog.now()\n RETURNS timestamp with time zone\n LANGUAGE internal\n STABLE STRICT\nAS $function$now$function$\n```\n"
  },
  {
    "path": "postgres/enable-logging-of-database-activity.md",
    "content": "# Enable Logging Of Database Activity\n\nFor logging to be enabled for a PostgreSQL server, it needs to be properly\nconfigured. This means ensuring the `logging_collector` option is on. By\ndefault I believe it is `off`.\n\nThis is configured in the `postgresql.conf` file and requires a server restart.\n\nFirst, to find where the conf file is. I can answer that question in a `psql`\nsession.\n\n```sql\n> show config_file;\n                             config_file\n---------------------------------------------------------------------\n /Users/jbranchaud/.asdf/installs/postgres/12.3/data/postgresql.conf\n(1 row)\n```\n\nNow, I can open up that file and search for the line that has\n`logging_collector`. I uncomment that line and change `off` to `on`.\n\n```\n# This is used when logging to stderr:\nlogging_collector = on \t\t# Enable capturing of stderr and csvlog\n\t\t\t\t\t# into log files. Required to be on for\n\t\t\t\t\t# csvlogs.\n\t\t\t\t\t# (change requires restart)\n```\n\nThis requires a restart of the Postgres server.\n\n```bash\n$ ~/.asdf/installs/postgres/12.3/bin/pg_ctl -D ~/.asdf/installs/postgres/12.3/data restart\nwaiting for server to shut down.... done\nserver stopped\nwaiting for server to start...\n done\nserver started\n```\n\nI can now adjust any further logging-related configurations on a server or\nsession basis. And then view those logs.\n"
  },
  {
    "path": "postgres/enforce-uniqueness-on-column-expression.md",
    "content": "# Enforce Uniqueness On Column Expression\n\nWhen creating a table for, say `users`, where you will store `email` addresses,\nyou'll likely want to enforce uniqueness on the that `email` field. And because\npeople have all sorts of ways of entering their emails, in terms of casing, you\nmay be tempted to try to enforce uniqueness on a lowercased version of `email`.\n\n```sql\ncreate table users (\n  id integer generated always as identity primary key,\n  email text not null,\n  unique ( lower(email) ) -- !! this won't work\n);\n```\n\nA unique _constraint_ must be on one or more columns. You cannot include an\n_expression_ when defining the unique constraint.\n\nYou can however accomplish similar aims with [a _unique index_ on the\nexpression](https://www.postgresql.org/docs/current/indexes-expressional.html).\nThat is because the index is able to store the result of the expression in\nitself.\n\n```sql\ncreate table users (\n  id integer generated always as identity primary key,\n  email text not null\n);\n\ncreate unique index unq_lower_email on users ( lower(email) );\n```\n\nThis is likely what you want for this example anyway because it will probably\nbe a common query to look up the user by `lower(email)` and the index will\nspeed up those queries.\n"
  },
  {
    "path": "postgres/escaping-a-quote-in-a-string.md",
    "content": "# Escaping A Quote In A String\n\nIn PostgreSQL, string (`varchar` and `text`) literals are declared with\nsingle quotes (`'`). That means that any string containing a single quote\nwill need some escaping. The way to escape a single quote is with another\nsingle quote.\n\n```sql\n> select 'what''s up!';\n  ?column?\n------------\n what's up!\n```\n\n[source](http://jonathansacramento.com/posts/20160122-improve-postgresql-workflow-vim-dbext.html)\n"
  },
  {
    "path": "postgres/escaping-string-literals-with-dollar-quoting.md",
    "content": "# Escaping String Literals With Dollar Quoting\n\nString literals in PostgreSQL are defined by surrounding the content with\nthe `'` character. For string literals that contain the `'` character, you\nmay have seen it escaped with a preceding `'`.\n\n```sql\n> select 'Isn''t this nice?';\n     ?column?\n------------------\n Isn't this nice?\n```\n\nThis is easy enough to do, but can be error prone and doesn't work well if\nSQL is being programmatically generated. A great workaround is to escape\nstring literals using what is called dollar quoting.\n\n```sql\n> select $$Isn't this even nicer?$$;\n        ?column?\n------------------------\n Isn't this even nicer?\n```\n\nJust wrap both ends in `$$` instead of `'`.\n\n[source](https://www.postgresql.org/docs/current/static/sql-syntax-lexical.html)\n"
  },
  {
    "path": "postgres/export-query-results-to-a-csv.md",
    "content": "# Export Query Results To A CSV\n\nDigging through the results of queries in Postgres's `psql` is great if you\nare a programmer, but eventually someone without the skills or access may\nneed to check out that data. Exporting the results of a query to CSV is a\nfriendly way to share said results because most people will have a program\non their computer that can read a CSV file.\n\nFor example, exporting all your pokemon to `/tmp/pokemon_dump.csv` can be\naccomplished with:\n\n```sql\ncopy (select * from pokemons) to '/tmp/pokemon_dump.csv' csv;\n```\n\nBecause we are grabbing the entire table, we can just specify the table name\ninstead of using a subquery:\n\n\n```sql\ncopy pokemons to '/tmp/pokemon_dump.csv' csv;\n```\n\nInclude the column names as headers to the CSV file with the `header`\nkeyword:\n\n```sql\ncopy (select * from pokemons) to '/tmp/pokemon_dump.csv' csv header;\n```\n\nIf your user has limited access, you can use the \\copy command like so:\n\n```sql\n\\copy (select * from pokemons) to '/tmp/pokemon_dump.csv' with csv header;\n```\n\n[source](http://stackoverflow.com/questions/1120109/export-postgres-table-to-csv-file-with-headings)\n"
  },
  {
    "path": "postgres/extracting-nested-json-data.md",
    "content": "# Extracting Nested JSON Data\n\nIf you are storing nested JSON data in a postgres JSON column, you are\nlikely going to find yourself in a situation where you need to access some\nof those nested values in your database code. For instance, you may need to\nget at the license number in this JSON column\n\n```sql\n  owner\n--------------------------------------------------------------------------------\n'{ \"name\": \"Jason Borne\", \"license\": { \"number\": \"T1234F5G6\", \"state\": \"MA\" } }'\n```\n\nUnfortunately, the `->` operator isn't going to do the trick. You need the\n`json_extract_path` function\n\n```sql\n> select json_extract_path(owner, 'license', 'number') from some_table;\n\n json_extract_path\n-------------------\n   'T1234F5G6'\n```\n\nRead more about [JSON Functions and\nOperators](http://www.postgresql.org/docs/9.4/static/functions-json.html).\n"
  },
  {
    "path": "postgres/fetch-data-from-an-endpoint-in-sql.md",
    "content": "# Fetch Data From An Endpoint In SQL\n\nThe [`pgsql-http` extension](https://github.com/pramsey/pgsql-http) provides a\nvariety of functions for allowing PostgreSQL to act as an HTTP client. This is\na bit unorthodox and may not be a good idea in production systems. That said,\nit is cool that it is possible. Let's look at an example of it.\n\nFirst, I've installed the extension on the Docker container running my local\nPostgres server.\n\n```bash\n$ docker exec -it still-postgres-1 bash\n\n$ apt-get update\n\n$ apt-get install postgres-16-http # I'm running Postgres v16\n\n$ exit\n```\n\nThen I'll connect to a `psql` session in that container for the `postgres` database.\n\n```bash\n$ docker exec still-postgres-1 psql -U postgres -d postgres\n```\n\nThen I enable the extension.\n\n```sql\n> create extension if not exists http;\nCREATE EXTENSION\n```\n\nNow I can point a PostgreSQL statement at a live endpoint like\n[https://httpbun.com/ip](https://httpbun.com/ip) which will respond with a\nchunk of JSON including the IP address for that project's server. I do this\nusing `http_get` which makes a `GET` request to the given endpoint. The body is\nincluded in the result set.\n\n```bash\n> select content from http_get('http://httpbun.com/ip');\n           content\n-----------------------------\n {                          +\n   \"origin\": \"73.75.236.101\"+\n }                          +\n\n(1 row)\n```\n"
  },
  {
    "path": "postgres/fetch-specific-number-of-results.md",
    "content": "# Fetch Specific Number Of Results\n\nIf you pull up just about any intro to PostgreSQL (or even SQL), one of the\nfirst things they are going to teach you is the `limit` clause. This is taught\nas _the_ way for limiting the result set to a specific number of rows.\n\n```sql\n> select title from books limit 4;\n+-----------------------+\n| title                 |\n|-----------------------|\n| The Secret History    |\n| A Gentleman in Moscow |\n| Exhalation: Stores    |\n| Annihilation          |\n+-----------------------+\nSELECT 4\n```\n\nYou might be as surprised as I was to learn that `limit` is not part of the SQL\nstandard. It is extremely common for this use case, but the SQL standard\ndefines `fetch first N rows only` as the way to fetch a specific number of\nrows. As we can see, [it works identically to `limit\nN`](https://www.postgresql.org/docs/current/sql-select.html#SQL-LIMIT).\n\n```sql\n> select title from books fetch first 4 rows only;\n+-----------------------+\n| title                 |\n|-----------------------|\n| The Secret History    |\n| A Gentleman in Moscow |\n| Exhalation: Stores    |\n| Annihilation          |\n+-----------------------+\nSELECT 4\n```\n\nThe `rows` and `row` keywords are interchangeable which makes statements more\nreadable if, for instance, you're doing `... fetch first 1 row only`.\n\n[source](https://www.cybertec-postgresql.com/en/postgresql-limit-vs-fetch-first-rows-with-ties/)\n"
  },
  {
    "path": "postgres/find-duplicate-records-in-table-without-unique-id.md",
    "content": "# Find Duplicate Records In Table Without Unique Id\n\nI recently came across a couple methods for listing out instances of duplicate\nrecords in a table where the table doesn't have an explicit unique identifier.\nHere is [a post](find-records-that-contain-duplicate-values.md) that explains\nhow to do this when a unique identifier is present.\n\nIf the table doesn't have an explicit primary key or other uniquely identifying\nvalue, then we'll have to get some help from [PostgreSQL's internal system\ncolumns](https://www.postgresql.org/docs/current/ddl-system-columns.html) —\nnamely the `ctid`.\n\nThe `ctid` is:\n\n> The physical location of the row version within its table.\n\nLet's use the example of the `mailing_list` table with potential duplicate\n`email` values.\n\nHere is the [first approach](https://stackoverflow.com/a/26773018/535590):\n\n```sql\ndelete from mailing_list\nwhere ctid not in (\n  select min(ctid)\n  from mailing_list\n  group by email\n);\n```\n\nThis uses a subquery to find the first occurrence of every unique email and\nthen deletes the rest. The `ctid` is the unique value that we can call the\n`min` aggregate on.\n\nA [second approach](https://stackoverflow.com/a/46775289/535590):\n\n```sql\ndelete from mailing_list ml1\n  using mailing_list ml2\nwhere ml1.ctid < ml2.ctid\n  and ml1.email = ml2.email;\n```\n\nThis uses `delete using` to join the table against itself as a cartesian\nproduct to compare every entry to every other entry.\n"
  },
  {
    "path": "postgres/find-records-that-contain-duplicate-values.md",
    "content": "# Find Records That Contain Duplicate Values\n\nLet's say I have a `mailing_list` table that contains all the email addresses\nthat I want to send a mailing out to. Without a uniqueness constraint on the\n`email` column, I can end up with multiple records containing the same email\naddress — duplicates.\n\nHere are a couple queries for checking to see if any duplicate records exist\nand which ones they are.\n\n```sql\nselect email\nfrom (\n  select\n    email,\n    row_number() over (\n      partition by email\n      order by email\n    ) as row_num\n  from mailing_list\n) t\nwhere t.row_num > 1;\n```\n\nThis is cool because it uses a [window\nfunction](https://www.postgresql.org/docs/current/tutorial-window.html),\nspecifically the\n[`row_number()`](https://www.postgresql.org/docs/current/functions-window.html)\nwindow function, to assign an incrementing number to each row in the partition.\n\nHere is another, conceptually simpler approach.\n\n```sql\nselect\n  email\n  count(*)\nfrom mailing_list\ngroup by email\nhaving count(*) > 1\norder by email;\n```\n\nThough we cannot use a `where` clause with an aggregate (`count`), we can reach\nfor a `having` clause to grab only those results where we've found more than\n`1` — duplicates.\n\n[source](https://www.postgresqltutorial.com/how-to-delete-duplicate-rows-in-postgresql/)\n"
  },
  {
    "path": "postgres/find-records-that-have-multiple-associated-records.md",
    "content": "# Find Records That Have Multiple Associated Records\n\nA common type of table association in a relational database is a one-to-many\nrelationship. For instance, a database representing a bookshelf may have an\n`authors` table where each record can be associated with multiple records in\nthe `books` table. That relationship is represented by a `author_id` foreign\nkey column on `books` that points to `authors.id`.\n\nWe can write a query to find all authors that have not zero or one, but\nmultiple books by doing a join and then tacking on a `having` clause.\n\n```sql\nselect authors.id, authors.name, count(books.id)\n  from authors\n  join books\n    on authors.id = books.author_id\n  group by authors.id\n  having count(books.id) >= 2;\n```\n\nThis will result in a listing of author ids, author names, and their number of\nbooks.\n\nIt does this by joining books to authors, grouping by the `authors.id` to\nproduce a set of records unique to each author, and then combining multiple\nbooks by aggregating them with a `count`. The `having` clause is necessary\nbecause it is our way of _filtering_ on an aggregate value, in this case the\n`count`.\n"
  },
  {
    "path": "postgres/find-the-data-directory.md",
    "content": "# Find The Data Directory\n\nWhere does postgres store all of the data for a database cluster? Well, in\nits data directory. Where exactly that data directory is can depend on how\nthe database cluster was setup. Postgres can tell you right where to look,\nthough. Within `psql`, run\n\n```sql\n> show data_directory\n```\n\nPostgres will output the absolute path of the data directory.\n\n[source](http://dba.stackexchange.com/questions/1350/how-do-i-find-postgresqls-data-directory)\n"
  },
  {
    "path": "postgres/find-the-location-of-postgres-config-files.md",
    "content": "# Find The Location Of Postgres Config Files\n\nIf you can connect to your database with `psql`, then you can easily find\nthe location of your Postgres config files. After connecting, I can ask\nPostgres to show me where the main config file is:\n\n```sql\n> show config_file;\n                                  config_file\n--------------------------------------------------------------------------------\n /Users/jbranchaud/Library/Application Support/Postgres/var-9.5/postgresql.conf\n```\n\nIn the same directory as that `postgresql.conf` file are a number of other\nconfiguration files such as the `pg_hba.conf` file.\n\nh/t Dillon Hafer\n"
  },
  {
    "path": "postgres/fizzbuzz-with-common-table-expressions.md",
    "content": "# Fizzbuzz With Common Table Expressions\n\nIn learning about CTEs (common table expressions) in postgres, I discovered\nthat you can do some interesting and powerful things using the `with\nrecursive` construct. The following solves the fizzbuzz problem for integers\nup to 100\n\n```sql\nwith recursive fizzbuzz (num,val) as (\n    select 0, ''\n    union\n    select (num + 1),\n      case\n      when (num + 1) % 15 = 0 then 'fizzbuzz'\n      when (num + 1) % 5  = 0 then 'buzz'\n      when (num + 1) % 3  = 0 then 'fizz'\n      else (num + 1)::text\n      end\n    from fizzbuzz\n    where num < 100\n)\nselect val from fizzbuzz where num > 0;\n```\n\nCheck out [With Queries (Common Table Expressions)](http://www.postgresql.org/docs/9.4/static/queries-with.html)\nfor more details on CTEs.\n"
  },
  {
    "path": "postgres/force-ssl-when-making-a-psql-connection.md",
    "content": "# Force SSL When Making A psql Connection\n\nIf you try connecting `psql` to a Postgres server that requires SSL\nconnections, you'll see an error message like this:\n\n```\npsql: error: FATAL:  SSL/TLS required\n```\n\nYou can tell `psql` to make an SSL connection by adding the `sslmode=require`\nkey-value pair to the connection.\n\nIf you're using a connection string, that might look like this:\n\n```bash\n$ psql postgres://username:password@host.com/dbname?sslmode=require\n```\n\nOr if you're using the connection parameter flags, it may look like this, using\nthe `--set` flag:\n\n```bash\n$ PGPASSWORD=password psql \\\n    --set=sslmode=require \\\n    -h host.com \\\n    -U username \\\n    dbname\n```\n\nIf after adding `sslmode=require`, you find that SSL support is not compiled\nin, [follow the instructions in this post to reinstall Postgres with SSL\nsupport](https://dev.to/jbranchaud/reinstall-postgresql-with-openssl-using-asdf-cmj).\n"
  },
  {
    "path": "postgres/generate-a-uuid.md",
    "content": "# Generate A UUID\n\nPostgres has support for universally unique identifiers (UUIDs) as a column\ndata type via `uuid`. If you have a UUID column, you may need to generate a\nUUID.  This requires the `uuid-ossp` module. This module provides a number\nof functions for generating UUIDs including the `uuid_generate_v4()`\nfunction which bases the UUID entirely off random numbers.\n\n```sql\n> create extension \"uuid-ossp\";\nCREATE EXTENSION\n> select uuid_generate_v4();\n           uuid_generate_v4\n--------------------------------------\n a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11\n```\n\nSee the [postgres docs](http://www.postgresql.org/docs/9.4/static/uuid-ossp.html) for more\ndetails on UUID generation functions.\n"
  },
  {
    "path": "postgres/generate-modern-primary-key-columns.md",
    "content": "# Generate Modern Primary Key Columns\n\nChances are if you have looked at some examples, blog posts, or real-world\ninstances of a `create table` statement, it defined the primary key with\n`serial` (or `bigserial`).\n\n```sql\ncreate table books (\n  id serial primary key,\n  title text not null,\n  author text not null,\n  created_at timestamptz not null default now(),\n  updated_at timestamptz not null default now()\n);\n```\n\nThe `serial` syntax is everywhere, but for quite a while now it has not been\nthe recommended way to define a primary key column for the `int` or `bigint`\ndata types.\n\nThe [\"Don't Do This\" page of the PostgreSQL\nwiki](https://wiki.postgresql.org/wiki/Don%27t_Do_This#Don.27t_use_serial) says\n\"Don't use serial\".\n\n> For new applications, identity columns should be used instead. The serial\n> types have some weird behaviors that make schema, dependency, and permission\n> management unnecessarily cumbersome.\n\nThe modern way to define a primary key column for `int` or `bigint` is with a\ngenerated identity column.\n\n```sql\ncreate table books (\n  id int primary key generated always as identity,\n  title text not null,\n  author text not null,\n  created_at timestamptz not null default now(),\n  updated_at timestamptz not null default now()\n);\n```\n\nCheck out the PostgreSQL docs for more about [identity\ncolumns](https://www.postgresql.org/docs/17/ddl-identity-columns.html).\n"
  },
  {
    "path": "postgres/generate-random-alphanumeric-identifier.md",
    "content": "# Generate Random Alphanumeric Identifier\n\nHere is a PostgreSQL query that uses\n[`pgcrypto`](https://www.postgresql.org/docs/current/pgcrypto.html) (for\n[`get_random_bytes`](https://www.postgresql.org/docs/current/pgcrypto.html#PGCRYPTO-RANDOM-DATA-FUNCS))\nand a CTE to generate a cryptographically-random 8-character alphanumeric\nidentifier.\n\n```sql\n-- First ensure pgcrypto is installed\ncreate extension if not exists pgcrypto;\n\n-- Generates a single 8-character identifier\nwith chars as (\n  -- excludes some look-alike characters\n  select '23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz' as charset\n),\nrandom_bytes as (\n  select gen_random_bytes(8) as bytes\n),\npositions as (\n  select generate_series(0, 7) as pos\n)\nselect string_agg(\n  substr(\n    charset,\n    (get_byte(bytes, pos) % length(charset)) + 1,\n    1\n  ),\n  '' order by pos\n) as short_id\nfrom positions, random_bytes, chars;\n```\n\nHere is an example of the output:\n\n```sql\n+----------+\n| short_id |\n|----------|\n| NXdu9AnV |\n+----------+\n```\n\nThe\n[`generate_series`](https://www.postgresql.org/docs/current/functions-srf.html)\ngives us an 8-row table from 0 to 7 that we can use as indexes into the byte\npositions of the value we get from `gen_random_bytes`. Those random bytes get\nmapped to individual alphanumeric characters from `chars`. That then gets\nsqueezed together with `string_agg`.\n\nNote: the character set excludes some characters that can be mistaken for one\nanother like `0` and `O` or `1` and `l`.\n\nNote: you could change the right-bound of the `generate_series` to generate a\ndifferent length identifier.\n"
  },
  {
    "path": "postgres/generate-random-uuids-without-an-extension.md",
    "content": "# Generate Random UUIDs Without An Extension\n\nIn other posts I've covered how to generate v4 random UUIDs in PostgreSQL\n[using the `uuid-ossp` extension](generate-a-uuid.md) as well as the more\nup-to-date method of [using the `pgcrypto`\nextension](generating-uuids-with-pgcrypto.md).\n\nAs of PostgreSQL v13, you no longer need to add an extension for v4 UUID\ngeneration. It comes built-in as the `gen_random_uuid()` function.\n\n```sql\n> select gen_random_uuid();\n           gen_random_uuid\n--------------------------------------\n 0aa72fe6-ede7-4ccf-b328-348becc58066\n(1 row)\n```\n\nIf you need other non-v4 UUID functions, you'll have to stick with\n[uuid-ossp](https://www.postgresql.org/docs/current/uuid-ossp.html).\n"
  },
  {
    "path": "postgres/generate-series-of-numbers.md",
    "content": "# Generate Series Of Numbers\n\nPostgres has a `generate_series` function that can be used to, well,\ngenerate a series of something. The simplest way to use it is by giving it\n`start` and `stop` arguments\n\n```sql\n> select generate_series(1,5);\n generate_series \n-----------------\n               1\n               2\n               3\n               4\n               5\n```\n\nThe default step is 1, so if you want to count backwards, you need to\nspecify a negative step\n\n\n```sql\n> select generate_series(5,1,-1);\n generate_series \n-----------------\n               5\n               4\n               3\n               2\n               1\n```\n\nYou can use a larger step value to, for instance, get only multiples of 3\n\n```sql\n> select generate_series(3,17,3);\n generate_series \n-----------------\n               3\n               6\n               9\n              12\n              15\n```\n\nTrying this out with timestamps is left as an exercise for the reader.\n"
  },
  {
    "path": "postgres/generating-uuids-with-pgcrypto.md",
    "content": "# Generating UUIDs With pgcrypto\n\nIf you check out the docs for the [`uuid-ossp`\nextension](https://www.postgresql.org/docs/current/static/uuid-ossp.html),\nyou'll come across the following message.\n\n> The OSSP UUID library... is not well maintained, and is becoming\n> increasingly difficult to port to newer platforms. \n\nA little bit later, it says:\n\n> If you only need randomly-generated (version 4) UUIDs, consider using the\n> gen_random_uuid() function from the pgcrypto module instead.\n\nSo, if we are using the UUID data type and only need to generate random\nUUIDs, we can rely on the [`pgcrypto`\nextension](https://www.postgresql.org/docs/current/static/pgcrypto.html). It\ncomes with the `gen_random_uuid()` function which generates random v4 UUIDs.\n\n```sql\n> create extension \"pgcrypto\";\nCREATE EXTENSION\n\n> select gen_random_uuid();\n           gen_random_uuid\n--------------------------------------\n 0a557c31-0632-4d3e-a349-e0adefb66a69\n\n> select gen_random_uuid();\n           gen_random_uuid\n--------------------------------------\n 83cdd678-8198-4d56-935d-d052f2e9db37\n```\n"
  },
  {
    "path": "postgres/get-a-quick-approximate-count-of-a-table.md",
    "content": "# Get A Quick Approximate Count Of A Table\n\nReally large PostgreSQL tables can be slow to work with. Even a count of the\nrows in a really large table can take a while to tabulate. I'm talking about\ntables on the order of hundreds of millions of rows.\n\nFor instance, here is a query grabbing the count of a ~400 million row table.\n\n```sql\n> select count(*) from events;\n\n   count\n-----------\n 427462316\n(1 row)\n\nTime: 55113.794 ms\n```\n\nIf I'm willing to wait nearly a minute (55 seconds), I can get an accurate\ncount of the rows in this `events` table.\n\nIf I don't want to wait and an approximate count will do, there are faster\nways. One way is to query the `pg_class` table.\n\n```\n> select reltuples::numeric as count\n  from pg_class\n  where relname='events';\n\n   count\n-----------\n 427462000\n(1 row)\n\nTime: 0.413 ms\n```\n\nThe resulting count is within hundreds of the actual value and tells me what I\nneed to know. And instead of 55 seconds, it takes less than half a millisecond.\n\n[source](https://andyatkinson.com/postgresql-tips)\n"
  },
  {
    "path": "postgres/get-row-count-for-most-recent-query.md",
    "content": "# Get Row Count For Most Recent Query\n\nAnytime you execute a query in `psql`, there is a _row count_ associated with\nthat query. This is most naturally understood with a `select` query where a\ndiscreet number of rows are returned. We typically see the row count (e.g. `(19\nrows)`) right below the result set.\n\nYou can always reference the row count of the most recent query with [the\n`:ROW_COUNT`\nvariable](https://www.postgresql.org/docs/current/app-psql.html#APP-PSQL-VARIABLES-ROW-COUNT).\nHere we use `\\echo` to print it out.\n\n```sql\n> select generate_series(2,20);\n generate_series\n-----------------\n               2\n               3\n               4\n               5\n               6\n               7\n               8\n               9\n              10\n              11\n              12\n              13\n              14\n              15\n              16\n              17\n              18\n              19\n              20\n(19 rows)\n\nTime: 12.338 ms\n> \\echo :ROW_COUNT\n19\n```\n\nFor some queries, like one that induces a pager (e.g. `less`) to be used,\nyou'll lose track of the row count once the pager closes. This is where being\nable to reference the row count without rerunning the query is most useful.\n\n```sql\n> select generate_series(2,2000);\nTime: 9.815 ms\n> \\echo :ROW_COUNT\n1999\n```\n\nNotice, we can also get a row count from other kinds of queries like this\n`insert` statement.\n\n```sql\n> insert into users (id) values (50001), (50002), (50003);\nINSERT 0 3\nTime: 2.804 ms\n> \\echo :ROW_COUNT\n3\n```\n\n[source](https://postgresql.verite.pro/blog/2024/05/13/advanced-psql-coproc.html)\n"
  },
  {
    "path": "postgres/get-the-size-of-a-database.md",
    "content": "# Get The Size Of A Database\n\nIf you have connect access to a PostgreSQL database, you can use the\n`pg_database_size()` function to get the size of a database in bytes.\n\n```sql\n> select pg_database_size('hr_hotels');\n pg_database_size\n------------------\n          8249516\n```\n\nJust give it the name of the database and it will tell you how much disk\nspace that database is taking up.\n\nCheckout [the Postgres docs](http://www.postgresql.org/docs/current/static/functions-admin.html) for more details.\n"
  },
  {
    "path": "postgres/get-the-size-of-a-table.md",
    "content": "# Get The Size Of A Table\n\nIn [Get The Size Of A Database](get-the-size-of-a-database.md), I showed a\nPostgreSQL administrative function, `pg_database_size()`, that gets the size\nof a given database. With the `pg_relation_size()` function, we can get the\nsize of a given table. For instance, if we'd like to see the size of the\n`reservations` table, we can executing the following query:\n\n```sql\n> select pg_relation_size('reservations');\n pg_relation_size\n------------------\n          1531904\n```\n\nThis gives us the size of the `reservations` table in bytes. As you might\nexpect, the referenced table needs to be part of the connected database and\non the search path.\n\nSee [the Postgres docs](http://www.postgresql.org/docs/current/static/functions-admin.html) for more details.\n"
  },
  {
    "path": "postgres/get-the-size-of-an-index.md",
    "content": "# Get The Size Of An Index\n\nWant to get an idea of how much disk space that additional index is taking\nup? You can query for it with the same methods discussed in [Get The Size Of\nA Table](get-the-size-of-a-table.md) and [Pretty Print Data\nSizes](pretty-print-data-sizes.md).\n\nFor instance, if I have a table with a `users_pkey` index and a\n`users_unique_lower_email_idx` index, I can check the sizes like so:\n\n```sql\n> select pg_size_pretty(pg_relation_size('users_pkey'));\n pg_size_pretty\n----------------\n 240 kB\n\n> select pg_size_pretty(pg_relation_size('users_unique_lower_email_idx'));\n pg_size_pretty\n----------------\n 704 kB\n```\n\n[source](https://www.niwi.nz/2013/02/17/postgresql-database-table-indexes-size/)\n"
  },
  {
    "path": "postgres/get-the-size-on-disk-of-an-index.md",
    "content": "# Get The Size On Disk Of An Index\n\nIndexes, when added to the right columns, can provide massive performance gains\nfor certain queries. Indexes aren't free though. It is worth noting that they\ntake up disk space. The amount of disk space they take is generally irrelevant,\nbut it is at least worth being aware of. Especially if you're deal with a\nmassive table.\n\nYou can check the current size of an index on disk with [PostgreSQL's\n`pg_relation_size`\nfunction](https://www.postgresql.org/docs/current/functions-admin.html).\n\nFirst, you'll want to look up the name of the index you're curious about.\nRunning `\\d table_name` (replacing `table_name` with the name of the table the\nindex is on) will show you everything about the table including its indexes and\ntheir names.\n\nThen run the following query:\n\n```sql\nselect pg_size_pretty(pg_relation_size('index_users_on_email'));\n pg_size_pretty\n----------------\n 41 MB\n(1 row)\n```\n\nThis one is pretty small. They can get pretty big though. I've seen some that\ntake up over 1GB on disk.\n"
  },
  {
    "path": "postgres/getting-a-slice-of-an-array.md",
    "content": "# Getting A Slice Of An Array\n\nPostgres has a very natural syntax for grabbing a slice of an array. You\nsimply add brackets after the array declaring the lower and upper bounds\nof the slice separated by a colon.\n\n```sql\n> select (array[4,5,6,7,8,9])[2:4];\n  array\n---------\n {5,6,7}\n```\n\nNotice that the bounds are inclusive, the array index is `1`-based, and the\narray declaration above needs to be wrapped in parentheses in order to not\ntrip up the array slice syntax.\n\nYou can also select rectangular slices from two dimensional arrays like so:\n\n```sql\n> select (array[[1,2,3],[4,5,6],[7,8,9]])[2:3][1:2];\n     array\n---------------\n {{4,5},{7,8}}\n```\n"
  },
  {
    "path": "postgres/group-by-the-result-of-a-function-call.md",
    "content": "# Group By The Result Of A Function Call\n\nTypically, a query that I write involving a `group by` will look more or less\nlike this:\n\n```sql\nselect category, count(*)\n  from products\n  group by category;\n```\n\nThe `category` column is the thing I'm grouping by. In this case, I'm doing a\nlittle data exploration.\n\nWe are not strictly limited to grouping by a column. We can use all sorts of\nfunctions offered by Postgres to get at more interesting results. [String\nfunctions](https://www.postgresql.org/docs/current/functions-string.html) are a\ngreat place to start.\n\nLet's say our `products` table also has an `identifier` column with a naming\nscheme where the first three letters of the identifier correspond to the\nproduct's classification. We can group by that part of the `identifier`:\n\n```sql\nselect substring(identifier from 1 for 3), count(*)\n  from products\n  group by substring(identifier from 1 for 3);\n```\n\nThe funkiness of the `substring` syntax aside, we were able to group our\nproducts in a new way and learn something about our data.\n"
  },
  {
    "path": "postgres/idempotent-inserts.md",
    "content": "# Idempotent Inserts\n\nI'm writing a bunch of records from one table to another using\n[`insert`](https://www.postgresql.org/docs/current/sql-insert.html). This is\npart of a process to swap out a massive table with an identical version that\nhas a fraction of the records.\n\nI want to copy a subset of rows from the primary table to the replacement table\nthat meet certain criteria. This query should be re-runnable and idempotent.\nThat way I can run it, investage the replacement table, and then run it again\nbefore swapping out the tables. This helps ensure I don't miss anything.\n\nSuch an idempotent query can be written with the help of the `on conflict`\nclause.\n\n```sql\ninsert into replacement_table\nselect * from original_table\nwhere created_at > (now() - '3 months'::interval)\non conflict do nothing;\n```\n\nIf I run that multiple times, it skips over any records that would otherwise\ncause a conflict. The unique primary key column is usually what determines a\nconflicting record.\n\nWithout the `on conflict do nothing`, trying to run this `insert` multiple\ntimes will fail on subsequent runs when it tries to re-insert rows with primary\nkeys it has already inserted.\n"
  },
  {
    "path": "postgres/include-all-queries-in-the-log-file.md",
    "content": "# Include All Queries In The Log File\n\nThe default log-level (`log_statement` setting) for a PostgreSQL server is\n`none`. Other valid log-levels for [that setting are `ddl`, `mod`, and\n`all`](https://www.postgresql.org/docs/13/runtime-config-logging.html).\n\nIf you want to see all the queries hitting a database, you'll want to set it to\n`all`. This can be set as a server-wide setting or it can be set on a\nper-session basis.\n\nBecause `all` is so noisy, I like to use it on a per-session basis when I'm in\na situation where I know I'd like to see all queries.\n\n```sql\n> set log_statement = 'all';\n```\n\nAfter running that statement in my `psql` session, I can tail the log file to\nkeep an eye on queries hitting the database.\n\nBe sure that [logging is enabled via the\n`logging_collector`](enable-logging-of-database-activity.md) as well.\n"
  },
  {
    "path": "postgres/include-columns-in-a-covering-index.md",
    "content": "# Include Columns In A Covering Index\n\nA _covering index_ is a special type of B-Tree index that, in addition to\nindexing on a certain field, also _includes_ one or more columns as extra data\nin the leaves of the tree. When created correctly, this can speed up the\nqueries it targets by achieving an _index-only scan_.\n\nLet's say we have a frequently run query on a large `events` table that looks\nlike this:\n\n```sql\nselect user_id, identifier, type\n  from events\n  where user_id = $1;\n```\n\nHere is what it looks like to create an index for this query with the `include`\nkeyword:\n\n```sql\ncreate index user_id_on_events_idx\n  on (user_id)\n  include (identifier, type);\n```\n\nAn index on its own can already cause a significant speed up to the queries it\ntargets, but may still need to retrieve some `select` attributes from the\ntable. For hot-path queries with a set of specific columns always included in\nthe select, there can be significant additional speed ups by having the index\n_cover_ those columns.\n\nFor more details, check out [A Close Look At The Index Include\nClause](https://use-the-index-luke.com/blog/2019-04/include-columns-in-btree-indexes).\n"
  },
  {
    "path": "postgres/include-multiple-tables-in-a-pg-dump.md",
    "content": "# Include Multiple Tables In A pg_dump\n\nWhen the `pg_dump` command is given the `-t` flag, it will dump just the table\nnamed with that flag. If you want to include multiple tables in the dump, you\njust need to use the flag multiple times.\n\n```bash\n$ pg_dump -t users -t users_roles -t roles my_database > roles.dump.sql\n```\n\nAlternatively, you can specify a\n[pattern](https://www.postgresql.org/docs/current/app-psql.html#APP-PSQL-PATTERNS)\nwhen using the `-t` flag.\n\n```bash\n$ pg_dump -t 'users*|roles' my_database > roles.dump.sql\n```\n\nYou have to be a little more mindful of what will and won't be included when\ncrafting a pattern. It is a nice shortcut for a well-known or well-constrained\ndata model.\n\nSee the [`pg_dump`\ndocs](https://www.postgresql.org/docs/current/app-pgdump.html) for more\ndetails, as well as [some\nexamples](https://www.postgresql.org/docs/current/app-pgdump.html#PG-DUMP-EXAMPLES).\n"
  },
  {
    "path": "postgres/insert-a-bunch-of-records-with-generate-series.md",
    "content": "# Insert A Bunch Of Records With Generate Series\n\nSometimes you want to quickly insert a bunch of fake (or real) data into a\nPostgres table. This is a great way to populate seed data or set up data\nscenarios for testing things out.\n\nFor instance, I recently used the following query to generate a bunch of data\nin a `roles` table to test out a query performance issue.\n\n```sql\n> insert into roles (\n    name,\n    resource_id,\n    resource_type,\n    created_at,\n    updated_at\n  )\n  select\n    'organization_user',\n    g.id,\n    'Organization',\n    now(),\n    now()\n  from generate_series(1,54000) as g(id);\n```\n\nThe key part is the [`generate_series()`\nfunction](https://www.postgresql.org/docs/current/functions-srf.html) which\nwill produce a row for every value between the two arguments. In this case, it\nwill generate `1`, `2`, `3`, etc. all the way up to `54000` -- so 54k rows in\ntotal.\n\nThe query selects off that generated series with some static values and some\ntimestamps to create sufficiently fake data that can be inserted into the\nspecified columns of the `roles` table.\n\nThis quickly inserts tens of thousands of records that I can now use to test\nout the performance of a SQL query.\n"
  },
  {
    "path": "postgres/insert-just-the-defaults.md",
    "content": "# Insert Just The Defaults\n\nIf you are constructing an `INSERT` statement for a table whose required\ncolumns all have default values, you may just want to use the defaults. In\nthis situation, you can break away from the standard:\n\n```\n> insert into table_name (column1, column2) values (value1, value2);\n```\n\nInstead, simply tell Postgres that you want it to use the default values:\n\n```\n> insert into table_name default values;\n```\n"
  },
  {
    "path": "postgres/inspect-progress-of-long-running-create-index.md",
    "content": "# Inspect Progress Of Long-Running Create Index\n\nStrategically applied indexes are an important part of keeping queries against\na database fast. Initially applying those indexes—especially for large tables\nin production—can take a bit of time.\n\nThe `create index` call doesn't provide any indication of progress. So if\napplying an index takes minutes or even hours, it can be disconcerting.\n\nIs it still working or is it locked up? How far along is it?\n\nPostgres tracks the index creation process in `pg_stat_progress_create_index`\nand we can query that table.\n\n```sql\nselect\n  now()::time(0), \n  a.query, \n  p.phase, \n  p.blocks_total, \n  p.blocks_done, \n  p.tuples_total, \n  p.tuples_done,\n  ai.schemaname,\n  ai.relname,\n  ai.indexrelname\nfrom pg_stat_progress_create_index p \njoin pg_stat_activity a on p.pid = a.pid\nleft join pg_stat_all_indexes ai on ai.relid = p.relid and ai.indexrelid = p.index_relid;\n```\n\nThere are a bunch of phases that Postgres goes through to create the index,\nespecially if it is being created `concurrently`. The `blocks_done` and\n`tuples_done` numbers will keep ticking along, giving you an indication that\nthe process is proceeding.\n\n[source one](https://dba.stackexchange.com/a/249784) and [source two](https://www.depesz.com/2019/04/18/waiting-for-postgresql-12-report-progress-of-create-index-operations/)\n"
  },
  {
    "path": "postgres/install-postgres-with-uuid-ossp-using-asdf.md",
    "content": "# Install Postgres With uuid-ossp Using asdf\n\nThe `uuid-ossp` extension is part of `postgres-contrib` and is often included\nwith installs of PostgreSQL. By default, when installing PostgreSQL with\n[`asdf`](https://asdf-vm.com/#/) using the\n[`asdf-postgres`](https://github.com/smashedtoatoms/asdf-postgres) plugin, the\n`uuid-ossp` extension is not included.\n\nWithout it I had trouble running schema migrations against a database that was\ntrying to create the `uuid-ossp` extension:\n\n> postgresql uuid-ossp.control file missing in extention folder\n\nTo include `uuid-ossp` when installing Postgres with `asdf`, you'll need to\ninclude _extra config options_.\n\nFor instance, to install Postgres 9.6.21 with `uuid-ossp` included:\n\n```bash\n$ POSTGRES_EXTRA_CONFIGURE_OPTIONS=\"--with-uuid=e2fs\" asdf install postgres 9.6.21\n```\n\nThere are some resources that recommend using `--with-uuid=ossp`, but that\nappears to require a prerequisite install of a separate package, so I prefer\nthe `e2fs` option.\n\n[source](https://github.com/smashedtoatoms/asdf-postgres/issues/4#issuecomment-350592132)\n"
  },
  {
    "path": "postgres/integers-in-postgres.md",
    "content": "# Integers In Postgres\n\nPostgres has three kinds of integers. Or rather three sizes of integers.\nThere are `smallint` (`int2`), `integer` (`int4`), and `bigint` (`int8`)\nintegers. As you might expect, they are 2 byte, 4 byte, and 8 byte integers\nrespectively. They are also signed integers. All of this has implications\nfor what ranges of integers can be represented by each type.\n\nThe `smallint` integers have 2 bytes to use, so they can be used to\nrepresent integers from -32768 to +32767.\n\nThe `integer` integers have 4 bytes to use, so they can be used to represent\nintegers from -2147483648 to +2147483647.\n\nThe `bigint` integers have 8 bytes to use, so they can be used to represent\nintegers from -9223372036854775808 to +9223372036854775807.\n\nThough columns can be restricted to use a particular-sized integer, postgres\nis smart enough to default to `integer` and only use `bigint` as necessary\nwhen working with integers on the fly.\n\n```sql\n> select pg_typeof(55);\n pg_typeof\n-----------\n integer\n\n> select pg_typeof(99999999999999999);\n pg_typeof\n-----------\n bigint\n```\n"
  },
  {
    "path": "postgres/intervals-of-time-by-week.md",
    "content": "# Intervals Of Time By Week\n\nIt is pretty common to use hours or days when creating a Postgres\ninterval. However, intervals can also be created in week-sized chunks\n\n```sql\n> select '2 weeks'::interval;\n interval\n----------\n 14 days\n(1 row)\n\n> select make_interval(0,0,7,0,0,0,0);\n make_interval\n---------------\n 49 days\n(1 row)\n```\n"
  },
  {
    "path": "postgres/is-it-null-or-not-null.md",
    "content": "# Is It Null Or Not Null?\n\nIn PostgreSQL, the standard way to check if something is `NULL` is like so:\n\n```sql\nselect * as wild_pokemons from pokemons where trainer_id is null;\n```\n\nTo check if something is not null, you just add `not`:\n\n```sql\nselect * as captured_pokemons from pokemons where trainer_id is not null;\n```\n\nPostgreSQL also comes with `ISNULL` and `NOTNULL` which are non-standard\nways of doing the same as above:\n\n\n```sql\nselect * as wild_pokemons from pokemons where trainer_id isnull;\n```\n\n```sql\nselect * as captured_pokemons from pokemons where trainer_id notnull;\n```\n"
  },
  {
    "path": "postgres/label-dollar-quoted-strings-with-a-tag.md",
    "content": "# Label Dollar-Quoted Strings With A Tag\n\nIn [Escaping String Literals with Dollar\nQuoting](escaping-string-literals-with-dollar-quoting.md), I showed how\nPostgreSQL supports escaped string literals so that you don't have to put\nbackslashes everywhere. This is done by opening and closing the string with\n`$$`.\n\nWhat if your string literal is going to contain a sequence of two `$` symbols?\nOr a better hypothetical, what if you want to convey some information about\nwhat the string represents?\n\nFor either of these, the _tagged_ dollar-quoting is a great fit.\n\n```sql\n> select $JSON${\"name\": \"Sally's Bistro\", \"price\": \"$$$\"}$JSON$::jsonb;\n                   jsonb\n--------------------------------------------\n {\"name\": \"Sally's Bistro\", \"price\": \"$$$\"}\n(1 row)\n\n> select $JSON${\"name\": \"Sally's Bistro\", \"price\": \"$$$\"}$JSON$::jsonb->'name' as name;\n       name\n------------------\n \"Sally's Bistro\"\n(1 row)\n```\n\nThe tagged dollar-quoting allows me to write a string that can be cast to\n`jsonb` without having to think about which characters need to be escaped. In\nthe second example, I'm able to interact with it like any `jsonb` entity.\n\nHere, our tag is `JSON`. It helps convey that the string literal represents\nJSON. A tag \"follows the same rules as an unquoted identifier, except that it\ncannot contain a dollar sign.\" The tag goes between the dollar signs and is\ncase-sensitive.\n\n[source](https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-DOLLAR-QUOTING)\n"
  },
  {
    "path": "postgres/limit-execution-time-of-statements.md",
    "content": "# Limit Execution Time Of Statements\n\nYou can limit the amount of time that postgres will execute a statement\nby setting a hard timeout. By default the timeout is 0 (see `show\nstatement_timeout;`) which means statements will be given as much time as\nthey need.\n\nIf you do want to limit your statements, to say, 1 second, you can set the\nexecution time like so\n\n```sql\n> set statement_timeout = '1s';\nSET\n> show statement_timeout;\n statement_timeout\n-------------------\n 1s\n(1 row)\n```\n\nAny queries taking longer than 1 second will be aborted with the following\nmessage output\n\n```\nERROR:  canceling statement due to statement timeout\n```\n"
  },
  {
    "path": "postgres/list-all-columns-of-a-specific-type.md",
    "content": "# List All Columns Of A Specific Type\n\nWe can access information about all the columns in our database through the\n`information_schema` tables; in particular, the `columns` table. After\nconnecting to a particular database, we can list all columns (across all our\ntables) of a specific type. We just need to know the schema of the tables we\nare interested in and the type that we want to track down.\n\nMy application's tables are under the `public` schema and I want to track\ndown all `timestamp` columns. My query can look something like this\n\n```sql\n> select table_name, column_name, data_type from information_schema.columns where table_schema = 'public' and data_type = 'timestamp without time zone';\n   table_name    | column_name |          data_type\n-----------------+-------------+-----------------------------\n articles        | created_at  | timestamp without time zone\n articles        | updated_at  | timestamp without time zone\n users           | created_at  | timestamp without time zone\n users           | updated_at  | timestamp without time zone\n(4 rows)\n```\n\nAlternatively, I could look for both `timestamp` and `timestamptz` with a\nquery like this\n\n```sql\n> select table_name, column_name, data_type from information_schema.columns where table_schema = 'public' and data_type like '%timestamp%';\n```\n"
  },
  {
    "path": "postgres/list-all-rows-in-a-table.md",
    "content": "# List All Rows In A Table\n\nPerhaps the more common way to list all rows in a table is with the\nfollowing `select` command:\n\n```sql\nselect * from bedding_types;\n```\n\nThere is an alternative approach that also selects all rows from a table.\nIt's essentially a shorthand -- the `table` command.\n\n```sql\n> table bedding_types;\n   name\n----------\n No Bed\n 1 Full\n 1 Double\n 2 Double\n 1 Twin\n 2 Twins\n 1 Queen\n 2 Queen\n 1 King\n 2 Kings\n 3 Kings\n Murphy\n Sofa Bed\n```\n\nh/t Jack Christensen\n"
  },
  {
    "path": "postgres/list-all-the-databases.md",
    "content": "# List All The Databases\n\nThere are two ways to list all the available databases. The first is a\n`psql` only command:\n\n```\n\\list\n```\n\nThe second approach is to query the `pg_database` table. Something like the\nfollowing will suffice:\n\n```sql\nselect datname from pg_database;\n```\n"
  },
  {
    "path": "postgres/list-all-versions-of-a-function.md",
    "content": "# List All Versions Of A Function\n\nWithin `psql` you can use `\\df` to list a postgres function with a given\nname\n\n```sql\n> \\df now\n                              List of functions\n   Schema   | Name |     Result data type     | Argument data types |  Type\n------------+------+--------------------------+---------------------+--------\n pg_catalog | now  | timestamp with time zone |                     | normal\n(1 row)\n```\n\nWhen a function has multiple definitions across a number of types, `\\df`\nwill list all versions of that function\n\n```sql\n> \\df generate_series\nList of functions\n-[ RECORD 1 ]-------+-------------------------------------------------------------------\nSchema              | pg_catalog\nName                | generate_series\nResult data type    | SETOF bigint\nArgument data types | bigint, bigint\nType                | normal\n-[ RECORD 2 ]-------+-------------------------------------------------------------------\nSchema              | pg_catalog\nName                | generate_series\nResult data type    | SETOF bigint\nArgument data types | bigint, bigint, bigint\nType                | normal\n-[ RECORD 3 ]-------+-------------------------------------------------------------------\nSchema              | pg_catalog\nName                | generate_series\nResult data type    | SETOF integer\nArgument data types | integer, integer\nType                | normal\n-[ RECORD 4 ]-------+-------------------------------------------------------------------\nSchema              | pg_catalog\nName                | generate_series\nResult data type    | SETOF integer\nArgument data types | integer, integer, integer\nType                | normal\n-[ RECORD 5 ]-------+-------------------------------------------------------------------\nSchema              | pg_catalog\nName                | generate_series\nResult data type    | SETOF timestamp with time zone\nArgument data types | timestamp with time zone, timestamp with time zone, interval\nType                | normal\n-[ RECORD 6 ]-------+-------------------------------------------------------------------\nSchema              | pg_catalog\nName                | generate_series\nResult data type    | SETOF timestamp without time zone\nArgument data types | timestamp without time zone, timestamp without time zone, interval\nType                | normal\n```\n"
  },
  {
    "path": "postgres/list-available-schemas.md",
    "content": "# List Available Schemas\n\nUse the `\\dn` command within a `psql` session to list the available schemas.\nThis will only included user created schemas. This means that schemas like\n`public` will be listed whereas schemas like `information_schema` and\n`pg_catalog` will not.\n\nYou can use `\\dnS` to also list system schemas.\n\n[source](http://www.postgresql.org/docs/current/static/app-psql.html)\n"
  },
  {
    "path": "postgres/list-connections-to-a-database.md",
    "content": "# List Connections To A Database\n\nThe `pg_stat_activity` table can be used to determine what connections there\ncurrently are to the PostgreSQL server and to a particular database. To see\nthe process ids and usernames of all connection to your PostgreSQL server,\nrun the following query:\n\n```sql\n> select pid, usename from pg_stat_activity;\n  pid  |  usename\n-------+------------\n 57174 | jbranchaud\n 83420 | jbranchaud\n```\n\nInclude `datname` in the requested columns to figure out the database of\neach connection.\n\n```sql\n> select pid, usename, datname from pg_stat_activity;\n  pid  |  usename   |  datname\n-------+------------+-----------\n 57174 | jbranchaud | hr_hotels\n 83420 | jbranchaud | pgbyex\n```\n\nThe results can be restricted to a particular database as necessary.\n\n```sql\n> select pid, usename from pg_stat_activity where datname = 'hr_hotels';\n  pid  |  usename\n-------+------------\n 57174 | jbranchaud\n```\n"
  },
  {
    "path": "postgres/list-database-objects-with-disk-usage.md",
    "content": "# List Database Objects With Disk Usage\n\nI'll often times use `\\d` or `\\dt` to check out the tables in my database.\nThis shows the schema, object name, object type (e.g. `table`), and owner\nfor each.\n\nBy adding the `+` to that meta-command, I can also see the disk usage for\neach database object.\n\nHere is an example of look at all tables in a database with the additional\n`Size` (or disk usage) information:\n\n```sql\n> \\dt+\n                              List of relations\n Schema |        Name        | Type  |   Owner    |    Size    | Description\n--------+--------------------+-------+------------+------------+-------------\n public | amount_types       | table | jbranchaud | 16 kB      |\n public | ingredient_amounts | table | jbranchaud | 8192 bytes |\n public | ingredient_types   | table | jbranchaud | 16 kB      |\n public | ingredients        | table | jbranchaud | 48 kB      |\n public | recipes            | table | jbranchaud | 16 kB      |\n public | schema_migrations  | table | jbranchaud | 16 kB      |\n public | users              | table | jbranchaud | 16 kB      |\n```\n"
  },
  {
    "path": "postgres/list-database-users.md",
    "content": "# List Database Users\n\nWithin `psql`, type `\\du` to list all the users for a database and their\nrespective permissions.\n\n```bash\n> \\du\n                              List of roles\n Role name  |                   Attributes                   | Member of\n------------+------------------------------------------------+-----------\n jbranchaud | Superuser, Create role, Create DB, Replication | {}\n sampleuser | Create DB                                      | {}\n ```\n"
  },
  {
    "path": "postgres/list-databases-available-for-connecting.md",
    "content": "# List Databases Available For Connecting\n\nI tend to have a couple different versions of Postgres installed on my\ndevelopment machine. Each server version tends to have a different set of\ndatabases. As I switch between projects and Postgres versions, it can be hard\nto remember the name of the database to which I want to connect when using\n`psql`.\n\nI usually connect to one of the defaults, which is either named `postgres` or\nnamed after the machine user.\n\nThere is a better way. I can first ask `psql` to list all the available\ndatabases.\n\n```\n❯ psql --list\nTiming is on.\n                                               List of databases\n              Name              |   Owner    | Encoding |   Collate   |    Ctype    |     Access privileges\n--------------------------------+------------+----------+-------------+-------------+---------------------------\n jbranchaud                     | jbranchaud | UTF8     | en_US.UTF-8 | en_US.UTF-8 |\n postgres                       | jbranchaud | UTF8     | en_US.UTF-8 | en_US.UTF-8 |\n thirty_days_server_development | jbranchaud | UTF8     | en_US.UTF-8 | en_US.UTF-8 |\n thirty_days_server_test        | jbranchaud | UTF8     | en_US.UTF-8 | en_US.UTF-8 |\n(4 rows)\n```\n\nThen I know before connecting which one I'm looking for or if it must be in the\ndata directory of another Postgres server version.\n"
  },
  {
    "path": "postgres/list-various-kinds-of-objects.md",
    "content": "# List Various Kinds Of Objects\n\nOur PostgreSQL database can end up with all kinds of objects: tables,\nsequences, views, etc. We can use a variety of `psql` meta-commands to list\nthe different types of (user-created) objects in our database.\n\n- `\\dt` will list all the tables\n- `\\dE` will list all the foreign tables\n- `\\di` will list all the indexes\n- `\\ds` will list all the sequences\n- `\\dv` will list all the views\n- `\\dm` will list all the materialized views\n\nThese can also be combined. For instance, to see all the tables and\nsequences, we can run `\\dts`.\n"
  },
  {
    "path": "postgres/lower-is-faster-than-ilike.md",
    "content": "# Lower Is Faster Than ilike\n\nThere are a couple ways to do a case-insensitive comparison of data in\nPostgreSQL. One way is to use the `ilike` operator for comparison. Another\nway is to use the `lower()` function on both sides of the `=` operator for\ncomparison. Using `lower()` is a bit faster than using `ilike`.\n\nWhen comparing\n\n```sql\nselect * from users where email ilike 'some-email@example.com';\n```\n\nto\n\n```sql\nselect * from users where lower(email) = lower('some-email@example.com');\n```\n\nwe find (via `explain analyze`) that using `lower()` was taking around 12ms\nwhere as the `ilike` example was taking around 17ms.\n\nWe earn orders of magnitude in performance when adding a functional index\nthat uses the `lower()` function like so:\n\n```sql\ncreate unique index users_unique_lower_email_idx on users (lower(email));\n```\n\nAfter adding this index, the example using `lower()` drops to around 0.08ms.\n\nFor the full example and `explain analyze` outputs, [see this\ndocument](https://github.com/jbranchaud/postgresing/blob/master/ilike_vs_lower.sql).\n"
  },
  {
    "path": "postgres/manage-major-versions-with-brew-and-direnv.md",
    "content": "# Manage Major Versions With Brew and Direnv\n\nI can install multiple major versions of PostgreSQL to my machine with `brew`\nwith commands like the following:\n\n```bash\n$ brew install postgresql@14\n$ brew install postgresql@16\n$ # ...\n```\n\nI can then start and stop specific Postgres server versions using the `brew\nservices start/stop` commands. Let's say 14 is running, but I want to switch to 16.\n\n```bash\n$ brew services stop postgresql@14\n$ brew services start postgresql@16\n```\n\nThen I can use [`direnv`](https://direnv.net/) to manage the Postgres client\n(bin directory) that gets used for certain projects. This way when I run a\ncommand like `pg_dump` or `psql` it will use the one associated with a specific\nmajor version of Postgres.\n\nAssuming I already have `direnv` installed, I can add a `.envrc` to my project\nwith the following line:\n\n```\nPATH_add /usr/local/opt/postgresql@16/bin\n```\n\nAnd then tell my system that the changes to this file are allowed to be sourced\nby `direnv`:\n\n```bash\n$ direnv allow .\n```\n\nThat's it. Now I have PostgreSQL 16 (client and server) ready to use for my\ncurrent project.\n"
  },
  {
    "path": "postgres/max-identifier-length-is-63-bytes.md",
    "content": "# Max Identifier Length Is 63 Bytes\n\nIn PostgreSQL, identifiers -- table names, column names, constraint names,\netc. -- are limited to a maximum length of 63 bytes. Identifiers longer than\n63 characters can be used, but they will be truncated to the allowed length\nof 63.\n\n```sql\n> alter table articles\n    add constraint this_constraint_is_going_to_be_longer_than_sixty_three_characters_id_idx\n    check (char_length(title) > 0);\nNOTICE:  identifier \"this_constraint_is_going_to_be_longer_than_sixty_three_characters_id_idx\" will be truncated to \"this_constraint_is_going_to_be_longer_than_sixty_three_characte\"\nALTER TABLE\n```\n\nPostgres warns us of identifiers longer than 63 characters, informing us of\nwhat they will be truncated to. It then proceeds to create the identifier.\n\nIf postgres is trying to generate an identifier for us - say, for a foreign\nkey constraint - and that identifier is longer than 63 characters, postgres\nwill truncate the identifier somewhere in the middle so as to maintain the\nconvention of terminating with, for example, `_fkey`.\n\nThe 63 byte limit is not arbitrary. It comes from `NAMEDATALEN - 1`. By default\n`NAMEDATALEN` is 64. If need be, this value can be modified in the Postgres\nsource. Yay, open-source database implementations.\n\nSee [the postgres docs](http://www.postgresql.org/docs/current/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS) for more details.\n"
  },
  {
    "path": "postgres/open-heroku-database-in-postico-from-terminal.md",
    "content": "# Open Heroku Database In Postico From Terminal\n\nI recently downloaded [Postico](https://eggerapps.at/postico/) at the\nrecommendation of [Dillon Hafer](https://dillonhafer.com/). I tend to use\n`psql` as a PostgreSQL client for all my database querying needs. However,\nDillon highly recommended Postico for doing system admin querying.\n\nI needed to connect directly to a production Postgres server on Heroku to\ninvestigate slow queries. Postico presented me with a form of individual fields\nfor host, port, username, password, database, etc.\n\nThis would have been a little annoying to fill in manually. Dillon had a\nshortcut to recommend. From the command line you can open Postico with a\nconnection string. It knows how to split that connection string into the\nrespective fields.\n\n```bash\nheroku config:get DATABASE_URL --app APP_NAME | xargs open -a Postico\n```\n\nThis requests the `DATABASE_URL` from Heroku. It is a Postgres connection\nstring with all the fields needed to connect to a remove server. This is then\npassed via `xargs` to `Postico` as it is being `open`ed.\n"
  },
  {
    "path": "postgres/output-explain-query-plan-in-different-formats.md",
    "content": "# Output Explain Query Plan In Different Formats\n\nThe output of an [`explain` (or `explain analyze`) query\nplan](https://www.postgresql.org/docs/current/sql-explain.html) for a given\nquery defaults to a `TEXT` format that is meant to be read by a person.\n\n```sql\n> explain (analyze) select title from books where created_at > now() - '1 year'::interval;\n                                           QUERY PLAN\n-------------------------------------------------------------------------------------------------\n Seq Scan on books  (cost=0.00..1.28 rows=5 width=32) (actual time=0.011..0.017 rows=22 loops=1)\n   Filter: (created_at > (now() - '1 year'::interval))\n Planning Time: 0.052 ms\n Execution Time: 0.027 ms\n(4 rows)\n```\n\nIf we instead want the query plan in a standardized format that is parseable\nand readable by a program, we can specify an alternate format like `JSON`,\n`YAML`, or `XML`.\n\nHere is the same plan with `format json`:\n\n```sql\n> explain (analyze, format json) select title from books where created_at > now() - '1 year'::interval;\n                           QUERY PLAN\n----------------------------------------------------------------\n [                                                             +\n   {                                                           +\n     \"Plan\": {                                                 +\n       \"Node Type\": \"Seq Scan\",                                +\n       \"Parallel Aware\": false,                                +\n       \"Async Capable\": false,                                 +\n       \"Relation Name\": \"books\",                               +\n       \"Alias\": \"books\",                                       +\n       \"Startup Cost\": 0.00,                                   +\n       \"Total Cost\": 1.28,                                     +\n       \"Plan Rows\": 5,                                         +\n       \"Plan Width\": 32,                                       +\n       \"Actual Startup Time\": 0.008,                           +\n       \"Actual Total Time\": 0.014,                             +\n       \"Actual Rows\": 22,                                      +\n       \"Actual Loops\": 1,                                      +\n       \"Filter\": \"(created_at > (now() - '1 year'::interval))\",+\n       \"Rows Removed by Filter\": 0                             +\n     },                                                        +\n     \"Planning Time\": 0.050,                                   +\n     \"Triggers\": [                                             +\n     ],                                                        +\n     \"Execution Time\": 0.023                                   +\n   }                                                           +\n ]\n(1 row)\n```\n\nI present all four formats for a complex query plan [in this\nGist](https://gist.github.com/jbranchaud/731b1a68f5cc70c4f7a9e1f5ef570836).\n"
  },
  {
    "path": "postgres/pg-prefix-is-reserved-for-system-schemas.md",
    "content": "# pg Prefix Is Reserved For System Schemas\n\nHave you ever tried to create a schema with `pg_` as the first part of the\nname of the schema? If so, you probably didn't get very far. Postgres won't\nlet you do that. It reserves the `pg_` prefix for system schemas. If you try\nto create a schema in this way, you'll get an *unacceptable schema name*\nerror.\n\n```sql\n> create schema pg_cannot_do_this;\nERROR:  unacceptable schema name \"pg_cannot_do_this\"\nDETAIL:  The prefix \"pg_\" is reserved for system schemas.\n```\n"
  },
  {
    "path": "postgres/postgres-does-not-support-unsigned-integers.md",
    "content": "# Postgres Does Not Support Unsigned Integers\n\nPostgreSQL has a variety of sizes of integer types, from `smallint` (2 bytes)\nto `integer` (4 bytes) to `bigint` (8 bytes), as well as [other numeric\ntypes](https://www.postgresql.org/docs/current/datatype-numeric.html).\n\nIt does _not_ however support unsigned versions of these numeric types.\n\nThat means, with an `integer` for instance, we can store numbers between\n`-2147483648` and `+2147483647`. That's everything that can fit into 4 bytes.\nIn a system that supported 4 byte unsigned integers we'd be able to represent\nfrom `0` all the way up to `4294967295`.\n\nIn PostgreSQL, we're limited to these _signed_ numeric types.\n\nThat means if we were hoping that the data type could essentially enforce a\nnon-negative restriction on the data in one of our columns, we're going to have\nto be more creative. The obvious choice to me is to consider adding a [check\nconstraint](https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-CHECK-CONSTRAINTS)\n(e.g. `quantity integer check (quantity > 0)`).\n\nAnother option, as pointed out by [this StackOverflow\nanswer](https://stackoverflow.com/a/31833279/535590), is to create [a\nuser-defined _domain\ntype_](https://www.postgresql.org/docs/current/domains.html) that restricts\nvalid values. To me, the ergonomics of using a domain type are a bit awkward\nand not worth the effort.\n\nWith either of these solutions, we are only approximating an unsigned integer\nand do not actually have the same range of values available.\n"
  },
  {
    "path": "postgres/prepare-execute-and-deallocate-statements.md",
    "content": "# Prepare, Execute, and Deallocate Statements\n\nIn PostgreSQL, you can prepare a named statement to be executed later using\n[`prepare`](https://www.postgresql.org/docs/current/static/sql-prepare.html).\n\n```sql\n> prepare column_names (text) as\n    select column_name from information_schema.columns where table_name = $1;\nPREPARE\n```\n\nThese statements are kept around for the duration of the session. To see the\navailable statements, check out the `pg_prepared_statements` view.\n\n```sql\n> select * from pg_prepared_statements;\n     name     |                                  statement                                  |         prepare_time          | parameter_types | from_sql\n--------------+-----------------------------------------------------------------------------+-------------------------------+-----------------+----------\n column_names | prepare column_names (text) as                                             +| 2017-03-10 15:01:09.154528-06 | {text}          | t\n              |   select column_name from information_schema.columns where table_name = $1; |                               |                 |\n```\n\nTo run a prepared statement, use `execute` with the name of the statement\nand any arguments.\n\n```sql\n> execute column_names('users');\n   column_name\n-----------------\n id\n email\n password_digest\n created_at\n updated_at\n first_name\n last_name\n```\n\nYou can also delete a statement with\n[`deallocate`](https://www.postgresql.org/docs/current/static/sql-deallocate.html)\nif you'd like.\n\n```sql\n> deallocate column_names;\nDEALLOCATE\n```\n"
  },
  {
    "path": "postgres/pretty-print-data-sizes.md",
    "content": "# Pretty Print Data Sizes\n\nUse the `pg_size_pretty()` function to pretty print the sizes of data in\nPostgreSQL. Given a `bigint`, it will determine the most human-readable\nformat with which to print the value:\n\n```sql\n> select pg_size_pretty(1234::bigint);\n pg_size_pretty\n----------------\n 1234 bytes\n\n> select pg_size_pretty(123456::bigint);\n pg_size_pretty\n----------------\n 121 kB\n\n> select pg_size_pretty(1234567899::bigint);\n pg_size_pretty\n----------------\n 1177 MB\n\n> select pg_size_pretty(12345678999::bigint);\n pg_size_pretty\n----------------\n 11 GB\n```\n\nThis function is particularly useful when used with the\n[`pg_database_size()`](get-the-size-of-a-database.md) and\n[`pg_relation_size()`](get-the-size-of-a-table.md) functions.\n\n```sql\n> select pg_size_pretty(pg_database_size('hr_hotels'));\n pg_size_pretty\n----------------\n 12 MB\n```\n"
  },
  {
    "path": "postgres/pretty-printing-jsonb-rows.md",
    "content": "# Pretty Printing JSONB Rows\n\nWho needs a document store when you can just use PostgreSQL's `JSONB` data\ntype? Viewing rows of `JSONB` output can be challenging though because it\ndefaults to printing them as a single line of text.\n\n```sql\n> select '{\"what\": \"is this\", \"nested\": {\"items 1\": \"are the best\", \"items 2\": [1, 2, 3]}}'::jsonb;\n                                      jsonb\n----------------------------------------------------------------------------------\n {\"what\": \"is this\", \"nested\": {\"items 1\": \"are the best\", \"items 2\": [1, 2, 3]}}\n(1 row)\n```\n\nFortunately, Postgres comes with a function for prettying up the format of\nthe output of these rows --\n[`jsonb_pretty`](https://www.postgresql.org/docs/current/static/functions-json.html)\n\n```sql\n> select jsonb_pretty('{\"what\": \"is this\", \"nested\": {\"items 1\": \"are the best\", \"items 2\": [1, 2, 3]}}'::jsonb);\n            jsonb_pretty\n------------------------------------\n {                                 +\n     \"what\": \"is this\",            +\n     \"nested\": {                   +\n         \"items 1\": \"are the best\",+\n         \"items 2\": [              +\n             1,                    +\n             2,                    +\n             3                     +\n         ]                         +\n     }                             +\n }\n(1 row)\n```\n\nh/t Jack Christensen\n"
  },
  {
    "path": "postgres/prevent-a-query-from-running-too-long.md",
    "content": "# Prevent A Query From Running Too Long\n\nA number of different factors can effect how long a query takes to run.\nCertainly the size of a table and the complexity of the query play a big role.\nLocking can really slow a query down by making it wait to get started. A series\nof competing queries that induce table locking can grind things to a halt.\n\nIf you don't want queries in a particular connection being allowed to wait or\nrun too long, you can set a timeout.\n\n```sql\nset statement_timeout to '500';\n```\n\nThat will ensure that any statement run in that connection will be terminated\nif it takes longer than 500ms.\n\nYou can also specify a unit:\n\n```sql\nset statement_timeout to '15s';\n```\n\nThat will enforce statement timeout of 15 seconds.\n\nSee the\n[docs](https://www.postgresql.org/docs/current/runtime-config-client.html) for\nmore details.\n"
  },
  {
    "path": "postgres/print-the-query-buffer-in-psql.md",
    "content": "# Print The Query Buffer In psql\n\nI'll often be composing a PostgreSQL query in Vim and decide I want to give\nit a try in `psql`. I copy the relevant snippet of SQL to my system buffer\nand then paste into `psql`. I'm usually hit with a mess of text like this\nthough:\n\n```sql\njbranchaud=# create table nullable_fields (\njbranchaud(#   id serial primary key,\n  first varchar,\n  last varchar\n)\n  id serial primary key,\njbranchaud(#   first varchar,\n  last varchar\n)\n  first varchar,\njbranchaud(#   last varchar\n)\n  last varchar\njbranchaud(# )\n)\njbranchaud-#\n```\n\nYikes. That's not readable. Fortunately, `psql` provides a command for\nprinting the current contents of the query buffer. By typing `\\p` I'll see a\nmore readable version of what I just pasted in.\n\n```sql\njbranchaud-# \\p\ncreate table nullable_fields (\n  id serial primary key,\n  first varchar,\n  last varchar\n)\njbranchaud-#\n```\n\nAfter taking another glance at the snippet of SQL, I decide to complete the\nquery to create my new table.\n\n```sql\njbranchaud-# ;\nCREATE TABLE\n```\n"
  },
  {
    "path": "postgres/put-unique-constraint-on-generated-column.md",
    "content": "# Put Unique Constraint On Generated Column\n\nYou cannot apply a _unique constraint_ to an expression over a column, e.g.\n`lower(email)`. You can, however, create a [generated\ncolumn](https://www.postgresql.org/docs/current/ddl-generated-columns.html) for\nthat expression and then apply the unique constraint to that generated column.\n\nHere is what that could look like:\n\n```sql\n> create table users (\n    id integer generated always as identity primary key,\n    name text not null,\n    email text not null,\n    email_lower text generated always as (lower(email)) stored,\n    unique ( email_lower )\n);\n\n> \\d users\n+-------------+---------+-----------------------------------------------------------------+\n| Column      | Type    | Modifiers                                                       |\n|-------------+---------+-----------------------------------------------------------------|\n| id          | integer |  not null generated always as identity                          |\n| name        | text    |  not null                                                       |\n| email       | text    |  not null                                                       |\n| email_lower | text    |  default lower(email) generated always as (lower(email)) stored |\n+-------------+---------+-----------------------------------------------------------------+\nIndexes:\n    \"users_pkey\" PRIMARY KEY, btree (id)\n    \"users_email_lower_key\" UNIQUE CONSTRAINT, btree (email_lower)\n```\n\nAnd then an demonstration of violating that constraint:\n\n```sql\n\n> insert into users (name, email) values ('Bob', 'bob@email.com');\nINSERT 0 1\n\n> insert into users (name, email) values ('Bobby', 'BOB@email.com');\nduplicate key value violates unique constraint \"users_email_lower_key\"\nDETAIL:  Key (email_lower)=(bob@email.com) already exists.\n```\n\nThe main tradeoff here is that you are doubling the amount of storage you need\nfor that column. Unless it is a massive table, that is likely not an issue.\n"
  },
  {
    "path": "postgres/references-target-primary-key-by-default.md",
    "content": "# References Target Primary Key By Default\n\nTypically when I am creating a table or adding a column that involves a foreign\nkey constraint, I explicitly name the reference column.\n\n```sql\ncreate table contacts (\n  id int generated always as identity primary key,\n  user_id int references users(id);\n);\n```\n\nThe [Create Table PostgreSQL\nDocs](https://www.postgresql.org/docs/17/sql-createtable.html) point out that\nspecifying the reference column isn't strictly necessary.\n\n> These clauses specify a foreign key constraint, which requires that a group\n> of one or more columns of the new table must only contain values that match\n> values in the referenced column(s) of some row of the referenced table. If\n> the refcolumn list is omitted, the primary key of the reftable is used.\n\nIf we're using the primary key as the reference column, then we can choose to\nomit the reference column.\n\n```sql\ncreate table contacts (\n  id int generated always as identity primary key,\n  user_id int references users;\n);\n```\n\nIn the same way we can do this when adding a column.\n\n```sql\nalter table contacts\n  add column account_id int references account;\n```\n"
  },
  {
    "path": "postgres/remove-not-null-constraint-from-a-column.md",
    "content": "# Remove Not Null Constraint From A Column\n\nWhen you want to add a [`not\nnull`](https://www.postgresql.org/docs/current/ddl-constraints.html#id-1.5.4.6.6)\nconstraint to a column, you do so by _setting_ it.\n\n```sql\nalter table books\n  alter column publication_date\n  set not null;\n```\n\nYou can remove a `not null` constraint from a column, by _dropping_ it.\n\n```sql\nalter table books\n  alter column publication_date\n  drop not null;\n```\n\nNotice this excerpt of syntax from the official Postgres docs:\n\n```\n... ALTER [ COLUMN ] column_name { SET | DROP } NOT NULL\n```\n\n[source](https://www.postgresql.org/docs/current/sql-altertable.html)\n"
  },
  {
    "path": "postgres/renaming-a-sequence.md",
    "content": "# Renaming A Sequence\n\nIf a table is created with a `serial` type column, then a sequence is also\ncreated with a name based on the name of the table.\n\n```sql\n> \\d\n            List of relations\n Schema |       Name      |   Type   |   Owner\n--------+-----------------+----------+------------\n public | accounts        | table    | jbranchaud\n public | accounts_id_seq | sequence | jbranchaud\n```\n\nIn [Renaming A Table](renaming-a-table.md), I showed how a table can be\nrenamed in PostgreSQL. This will not, however, rename associated sequences.\nTo maintain naming consistency, you may want to also rename sequences when\nrenaming tables. This can be done with a query like the following:\n\n```sql\n> alter sequence accounts_id_seq rename to users_id_seq;\n```\n\nSee the [`alter\nsequence`](http://www.postgresql.org/docs/current/static/sql-altersequence.html)\ndocs for more details.\n"
  },
  {
    "path": "postgres/renaming-a-table.md",
    "content": "# Renaming A Table\n\nUsing the `alter table` command in PostgreSQL, you can rename an existing\ntable. This command will also update any references to the table such as via\nforeign key constraints. Just run a command like the following:\n\n```sql\nalter table ingredient_types rename to item_types;\n```\n\nNote that this may result in breaking a number of conventions. Foreign keys,\nsequences, and constraints with names eponymous to the original table will\nno longer follow convention despite the references being updated. These can\nbe renamed as well if desired.\n\nSee\n[`renaming_table.sql`](https://github.com/jbranchaud/postgresing/blob/master/renaming/rename_table.sql)\nfor a full example.\n\nSee the [`alter table`\ndocs](http://www.postgresql.org/docs/current/static/sql-altertable.html) for\nmore details.\n"
  },
  {
    "path": "postgres/restart-a-sequence.md",
    "content": "# Restart A Sequence\n\nIn postgres, if you are truncating a table or doing some other sort of\ndestructive action on a table in a development or testing environment, you\nmay notice that the id sequence for the primary key just keeps plugging\nalong from where it last left off. The sequence can be reset to any value\nlike so:\n\n```sql\n> alter sequence my_table_id_seq restart with 1;\nALTER SEQUENCE\n```\n\n[source](http://www.postgresql.org/docs/current/static/sql-altersequence.html)\n"
  },
  {
    "path": "postgres/restarting-sequences-when-truncating-tables.md",
    "content": "# Restarting Sequences When Truncating Tables\n\nPostgreSQL's\n[`truncate`](http://www.postgresql.org/docs/current/static/sql-truncate.html)\nfeature is a handy way to clear out all the data from a table. If you use\n`truncate` on a table that has a `serial` primary key, you may notice that\nsubsequent insertions keep counting up from where you left off. This is\nbecause the sequence the table is using hasn't been restarted. Sure, you can\nrestart it manually or you can tell `truncate` to do it for you. By\nappending `restart identity` to the end of a `truncate` statement, Postgres\nwill make sure to restart any associated sequences at `1`.\n\n```sql\ntruncate pokemons, trainers, pokemons_trainers restart identity;\n```\n"
  },
  {
    "path": "postgres/salt-and-hash-a-password-with-pgcrypto.md",
    "content": "# Salt And Hash A Password With pgcrypto\n\nThe\n[`pgcrypto`](http://www.postgresql.org/docs/current/static/pgcrypto.html)\nextension that ships with PostgreSQL can be used to do a number of\ninteresting things. This includes functions for doing salted password\nhashing. Using the `crypt` and `gen_salt` functions, we can securely store a\nuser password and later compare it to plain-text passwords for\nauthentication purposes.\n\n```sql\ncreate extension pgcrypto;\n\nselect crypt('pa$$w0rd', gen_salt('bf'));\n                            crypt\n--------------------------------------------------------------\n $2a$06$Z7wmrkYMOyLboLcULUYzNe6nHUcWywSZTt6nSrT5Xdv/VLdJ4g99K\n\n> select (\n    '$2a$06$Z7wmrkYMOyLboLcULUYzNe6nHUcWywSZTt6nSrT5Xdv/VLdJ4g99K' =\n    crypt(\n      'pa$$w0rd',\n      '$2a$06$Z7wmrkYMOyLboLcULUYzNe6nHUcWywSZTt6nSrT5Xdv/VLdJ4g99K'\n    )\n  ) as matched;\n matched\n---------\n t\n\n> select (\n    '$2a$06$Z7wmrkYMOyLboLcULUYzNe6nHUcWywSZTt6nSrT5Xdv/VLdJ4g99K' =\n    crypt(\n      'password',\n      '$2a$06$Z7wmrkYMOyLboLcULUYzNe6nHUcWywSZTt6nSrT5Xdv/VLdJ4g99K'\n    )\n  ) as matched;\n matched\n---------\n f\n```\n\nThe salt value is generated using the blowfish encryption algorithm (hence,\nthe `'bf'`). There is support for other algorithms such as `md5`.\n\nSee the\n[`pgcrypt` documentation](http://www.postgresql.org/docs/current/static/pgcrypto.html) for\nmore details.\n"
  },
  {
    "path": "postgres/send-a-command-to-psql.md",
    "content": "# Send A Command To psql\n\nYou can send a command to `psql` to be executed by using the `-c` flag\n\n```bash\n$ psql -c \"select 'Hello, World!';\"\n   ?column?\n---------------\n Hello, World!\n(1 row)\n```\n\nSpecify a particular database as needed\n\n```bash\n$ psql blog_prod -c 'select count(*) from posts;'\n count \n-------\n     8 \n(1 row)\n```\n\nh/t Jack Christensen\n"
  },
  {
    "path": "postgres/set-a-seed-for-the-random-number-generator.md",
    "content": "# Set A Seed For The Random Number Generator\n\nIn PostgreSQL, the internal seed for the random number generator is a\nrun-time configuration parameter. This `seed` parameter can be set to a\nparticular seed in order to get some determinism from functions that utilize\nthe random number generator. The seed needs to be something between `0` and\n`1`.\n\nWe can see this in action by setting the seed and then invoking `random()` a\ncouple times. Doing this twice, we will see the reproducibility we can\nachieve with a seed.\n\n```sql\n> set seed to 0.1234;\nSET\n\n> select random();\n      random\n-------------------\n 0.397731185890734\n\n> select random();\n      random\n------------------\n 0.39575699577108\n(1 row)\n\n> set seed to 0.1234;\nSET\n\n> select random();\n      random\n-------------------\n 0.397731185890734\n\n> select random();\n      random\n------------------\n 0.39575699577108\n```\n\nThe seed can also be configured with the `setseed()` function.\n\nSee [the PostgreSQL\ndocs](http://www.postgresql.org/docs/8.3/static/sql-set.html) for more\ndetails.\n"
  },
  {
    "path": "postgres/set-a-statement-timeout-threshold-for-a-session.md",
    "content": "# Set A Statement Timeout Threshold For A Session\n\nThe `statement_timeout` variable is used to tell the PostgreSQL server that you\nwant it to terminate statements (queries and transactions) that run past the\nspecified threshold. This is a great way to [prevent runaway\nqueries](https://blog.crunchydata.com/blog/control-runaway-postgres-queries-with-statement-timeout)\nin a production environment.\n\nYou can set this threshold with a `set` statement. It can take an integer\nargument of milliseconds. Here I set it to a timeout of 1 minute.\n\n```sql\n> set statement_timeout = 60000;\nSET\n> show statement_timeout;\n statement_timeout\n-------------------\n 1min\n(1 row)\n```\n\nThis will set the `statement_timeout` for the duration of the session. It won't\neffect other sessions.\n\nYou can also set the threshold with a string argument which allows you to\ninclude a unit of time. Here I set it to 30 seconds.\n\n```sql\n> set statement_timeout = '30s';\nSET\n> show statement_timeout;\n statement_timeout\n-------------------\n 30s\n(1 row)\n```\n\nNow that the `statement_timeout` is set to `30s`, I can run a query that I know\nwill exceed that threshold\n([`pg_sleep`](https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-DELAY)).\n\n```sql\n> select pg_sleep(31);\nERROR:  canceling statement due to statement timeout\nTime: 30001.997 ms (00:30.002)\n```\n\nAfter 30 seconds have passed, the Postgres server will interrupt the query.\n"
  },
  {
    "path": "postgres/set-inclusion-with-hstore.md",
    "content": "# Set Inclusion With hstore\n\nIn PostgreSQL, `hstore` records can be compared via set inclusion. The `@>`\nand `<@` operators can be used for this. The `@>` operator checks if the\nright operand is a subset of the left operand. The `<@` operator checks if\nthe left operand is a subset of the right operand.\n\n```sql\n> select '\"one\"=>\"1\", \"two\"=>\"2\", \"three\"=>\"3\"'::hstore @> '\"two\"=>\"2\"'::hstore;\n ?column?\n ----------\n  t\n\n> select '\"one\"=>\"1\", \"two\"=>\"2\", \"three\"=>\"3\"'::hstore <@ '\"two\"=>\"2\"'::hstore;\n ?column?\n----------\n f\n```\n\nSee the [`hstore` PostgreSQL\ndocs](http://www.postgresql.org/docs/current/static/hstore.html) for more\ndetails.\n"
  },
  {
    "path": "postgres/set-up-a-project-local-cluster-with-postgres-app.md",
    "content": "# Set Up A Project-Local Cluster With Postgres.app\n\nI want to set up a PostgreSQL cluster in my project directory. This helps\nprovide some separation and clarity that this cluster and its databases are just\nfor this project.\n\nThis can be done with `Postgres.app` (on Mac) hitting the `+` button in the\nbottom left corner of the app. This will pop open a \"Create new server\" modal.\n\nFrom there, you'll want to give the server a name that you can identify within\n`Postgres.app`. E.g. \"<App Name> Cluster\"\n\nThen select the Postgres version. My existing project is still on 17, so I'll\nselect that.\n\nThe not so intuitive part is the _Data Directory_. Use the \"Choose...\" file\npicker to find the root directory of your project. Select that. Then click into\nthe text input for the data directory and append the name of the data directory\n_to be created_ to that path. If I want it to all go in `postgres-data`, then my\npath will look like:\n\n```\n/Users/me/dev/my-app/postgres-data\n```\n\nThe `postgres-data` directory doesn't exist yet. But it will in a moment.\n\nYou probably want the default port, so leave that at `5432` unless you know\notherwise.\n\nClick `Create server`, though that won't actually create the server yet. Now\nwith that server selected in `Postgres.app` click the `Initialize` button. That\nwill create the `postgres-data` directory and then run `initdb` under the hood\nwhich will add everything your server needs. It will now be running at that\nport, ready to connect.\n"
  },
  {
    "path": "postgres/sets-with-the-values-command.md",
    "content": "# Sets With The Values Command\n\nYou can concisely create sets of values in PostgreSQL using the `values`\ncommand.\n\n```sql\n> values (1), (2), (3);\n column1\n---------\n       1\n       2\n       3\n```\n\nYou can even create multiple columns of values.\n\n```sql\n> values (1, 'a', true), (2, 'b', false);\n column1 | column2 | column3\n---------+---------+---------\n       1 | a       | t\n       2 | b       | f\n```\n\nThis is most often used with an insert command, but can be used on its own,\nas a subquery, within a CTE, etc.\n\n[source](http://www.postgresql.org/docs/current/static/sql-values.html)\n"
  },
  {
    "path": "postgres/shorthand-absolute-value-operator.md",
    "content": "# Shorthand Absolute Value Operator\n\nPostgres offers many [math\nfunctions](https://www.postgresql.org/docs/8.0/functions-math.html) including\n`abs` for computing the absolute value of a number.\n\n```sql\n> select abs(-1);\n abs\n-----\n   1\n(1 row)\n```\n\nThere is also an absolute value _operator_ -- the `@` symbol. This can be used\nto do the same thing.\n\n```sql\n> select @ -1;\n ?column?\n----------\n        1\n(1 row)\n```\n\n[source](https://kb.objectrocket.com/postgresql/why-use-postgres-abs-function-in-sql-729)\n"
  },
  {
    "path": "postgres/show-all-versions-of-an-operator.md",
    "content": "# Show All Versions Of An Operator\n\nWe may be familiar with PostgreSQL's containment operator (`@>`). Maybe\nwe've used it with an array before, so we understand the general idea. But\nnow we are curious about what are the other types with which this\ncontainment operator can be used.\n\nWe can quickly find out the answer with the `\\do` command in `psql`:\n\n```sql\n> \\do @>\n                               List of operators\n   Schema   | Name | Left arg type | Right arg type | Result type | Description\n------------+------+---------------+----------------+-------------+-------------\n pg_catalog | @>   | aclitem[]     | aclitem        | boolean     | contains\n pg_catalog | @>   | anyarray      | anyarray       | boolean     | contains\n pg_catalog | @>   | anyrange      | anyelement     | boolean     | contains\n pg_catalog | @>   | anyrange      | anyrange       | boolean     | contains\n pg_catalog | @>   | box           | box            | boolean     | contains\n pg_catalog | @>   | box           | point          | boolean     | contains\n pg_catalog | @>   | circle        | circle         | boolean     | contains\n pg_catalog | @>   | circle        | point          | boolean     | contains\n pg_catalog | @>   | jsonb         | jsonb          | boolean     | contains\n pg_catalog | @>   | path          | point          | boolean     | contains\n pg_catalog | @>   | polygon       | point          | boolean     | contains\n pg_catalog | @>   | polygon       | polygon        | boolean     | contains\n pg_catalog | @>   | tsquery       | tsquery        | boolean     | contains\n```\n\nThe `Left arg type` and `Right arg type` columns tell us what we need to\nknow.\n\nThis `\\do` command can be used with any operator for a similar set of\ninformation.\n\nh/t Bruce Momjian\n"
  },
  {
    "path": "postgres/show-reconstructed-constraints-for-a-table.md",
    "content": "# Show Reconstructed Constraints For A Table\n\nThe [`pg_get_constraintdef`\nfunction](https://pgpedia.info/p/pg_get_constraintdef.html) can be used to\nreconstruct the command for creating a given constraint. This isn't necessarily\nthe command (or commands) that originally created the constraint, but rather a\nreconstruction.\n\nWe have to pass it an `oid` that corresponds to the constraint which we can get\nfrom the `pg_constraint` table. These results can be further narrowed down by\nthe `conname` (constraint name) and `conrelid` (table name).\n\nHere is an example of listing the constraints on a `reading_statuses` table.\n\n```sql\n> select\n    conname,\n    pg_get_constraintdef(oid)\n  from pg_constraint\n  where conrelid = 'reading_statuses'::regclass;\n\n               conname               |                                                                               pg_get_constraintdef\n-------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n reading_statuses_pkey               | PRIMARY KEY (id)\n fk_rails_17ee7cb2c4                 | FOREIGN KEY (user_id) REFERENCES users(id)\n fk_rails_0d3729339f                 | FOREIGN KEY (book_id) REFERENCES books(id)\n reading_statuses_valid_status_check | CHECK (((status)::text = ANY ((ARRAY['started'::character varying, 'completed'::character varying, 'abandoned'::character varying, 'already_read'::character varying])::text[])))\n(4 rows)\n```\n\nI came across this while experimenting with [an idea for a fail-fast Rails\ninitializer\ncheck](https://gist.github.com/jbranchaud/12813a0558f9cd06bcc24b7d8706550c)\nthat verifies the values of the `reading_statuses_valid_status_check` stay in\nsync with the Rails version of those values that live in a constant.\n"
  },
  {
    "path": "postgres/show-the-hidden-queries-behind-backslash-commands.md",
    "content": "# Show The Hidden Queries Behind Backslash Commands\n\nThe `ECHO_HIDDEN` variable in PostgreSQL's `psql` determines whether the\nqueries behind backslash commands are displayed. It defaults to `false`. So,\ngenerally, when you run something like `\\d` or `\\l+`, you'll just see the\nresult and not the query that helped produce it.\n\nIf you're curious what's behind any of these backslash commands, then set\n`ECHO_HIDDEN` to `true` to get a look.\n\n```sql\n> \\set ECHO_HIDDEN true\n> \\d\n********* QUERY **********\nSELECT n.nspname as \"Schema\",\n  c.relname as \"Name\",\n  CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 'i' THEN 'index' WHEN 'S' THEN 'sequence' WHEN 's' THEN 'special' WHEN 'f' THEN 'foreign table' WHEN 'p' THEN 'partitioned table' WHEN 'I' THEN 'partitioned index' END as \"Type\",\n  pg_catalog.pg_get_userbyid(c.relowner) as \"Owner\"\nFROM pg_catalog.pg_class c\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\nWHERE c.relkind IN ('r','p','v','m','S','f','')\n      AND n.nspname <> 'pg_catalog'\n      AND n.nspname <> 'information_schema'\n      AND n.nspname !~ '^pg_toast'\n  AND pg_catalog.pg_table_is_visible(c.oid)\nORDER BY 1,2;\n**************************\n\n               List of relations\n Schema |     Name     |   Type   |   Owner\n--------+--------------+----------+------------\n public | users        | table    | jbranchaud\n public | users_id_seq | sequence | jbranchaud\n```\n\nThat query is what `psql` uses to list the relations for your current database.\n"
  },
  {
    "path": "postgres/sleeping.md",
    "content": "# Sleeping\n\nGenerally you want your SQL statements to run against your database as\nquickly as possible. For those times when you are doing some sort of\ndebugging or just want your queries to look very computationally expensive,\nPostgreSQL offers the `pg_sleep` function.\n\nTo sleep for 5 seconds, try the following:\n\n```sql\n> select now(); select pg_sleep(5); select now();\n              now\n-------------------------------\n 2016-01-08 16:30:21.251081-06\n(1 row)\n\nTime: 0.274 ms\n pg_sleep\n----------\n\n(1 row)\n\nTime: 5001.459 ms\n              now\n-------------------------------\n 2016-01-08 16:30:26.252953-06\n(1 row)\n\nTime: 0.260 ms\n```\n\nAs you'll notice, the `pg_sleep` statement took about 5 seconds.\n\n[source](http://www.if-not-true-then-false.com/2010/postgresql-sleep-function-pg_sleep-postgres-delay-execution/)\n"
  },
  {
    "path": "postgres/special-math-operators.md",
    "content": "# Special Math Operators\n\nPostgres has all the mathematical operators you might expect in any\nprogramming language (e.g. `+`,`-`,`*`,`/`,`%`). It also has a few extras\nthat you might not be expecting.\n\nFactorial Operator:\n\n```sql\n> select 5!;\n ?column?\n----------\n      120\n(1 row)\n```\n\nSquare Root Operator:\n\n```sql\n> select |/81;\n ?column?\n----------\n        9\n(1 row)\n```\n\nAbsolute Value Operator:\n\n```sql\n> select @ -23.4;\n ?column?\n----------\n     23.4\n(1 row)\n```\n"
  },
  {
    "path": "postgres/storing-emails-with-citext.md",
    "content": "# Storing Emails With citext\n\nEmail addresses should be treated as case-insensitive because they are. If a\nuser is trying to sign in with their email address, we shouldn't care if\nthey type `user@example.com` or `User@example.com`. Both of those email\naddresses should be treated as equal and ultimately lead us to the same\n`User` record.\n\nWith the\n[`citext`](http://www.postgresql.org/docs/current/static/citext.html)\nextension, we can create a column that acts as a case-insensitive text type.\nAny comparisons on a column of that type will internally have the `lower`\nfunction executed on the arguments.\n\nThe following example shows this in action:\n\n```sql\ncreate extension if not exists citext;\n\ncreate table citext_emails (\n  id serial primary key,\n  email citext not null unique\n);\n\ninsert into citext_emails (email) values ('LizLemon@nbc.com');\n\nselect * from citext_emails where email = 'lizlemon@nbc.com';\n--  id |      email\n-- ----+------------------\n--   1 | LizLemon@nbc.com\n```\n\nSee\n[`citext-emails.sql`](https://github.com/jbranchaud/postgresing/blob/master/citext-emails.sql)\nfor a full example.\n"
  },
  {
    "path": "postgres/string-contains-another-string.md",
    "content": "# String Contains Another String\n\nYou can check if a string *contains* another string using the `position`\nfunction.\n\n```sql\n> select position('One' in 'One Two Three');\n position\n----------\n        1\n```\n\nIt returns the 1-based index of the first character of the first match of\nthat substring.\n\n```sql\n> select position('Four' in 'One Two Three');\n position\n----------\n        0\n```\n\nIf the substring doesn't appear within the string, then the result is 0.\n\nThus, you can determine if a string *contains* another string by checking if\nthe value resulting from `position` is greater than 0.\n"
  },
  {
    "path": "postgres/survey-of-user-defined-ordering-of-records.md",
    "content": "# Survey Of User-Defined Ordering Of Records\n\n### Approaches\n\n#### Positional Indexes\n\nAssign an integer position to everything in the list. To insert something in\nthe middle of the list, you assign it that position and then increment the\nposition each item in the list after it by one. Can require a lot more writes\nthan other approaches.\n\n#### Positional Averaging\n\nYou can insert an item between two others with a single operation by taking the\naverage of the positional values (indexes) of the two surrounding items and\nmaking that the position of the item being inserted.\n\n- Decimal / Floating-Point - runs out of precision fairly quickly\n- Fractional / True Fractions - much more precision, trickier to implement\n- Large Int Boundaries - add first item at `0`, add second item at average of\n  `0` and `MAX_INT`. Need to insert at the front of the list, average lowest\n  index item with `MIN_INT`. [source](https://github.com/brendon/ranked-model/blob/master/lib/ranked-model.rb#L8-L11)\n\n#### LexoRank\n\nSimilar to the (numeric) positional averaging approaches, but uses strings\ninstead to get much more precision. Lexicographical ordering is used. To insert\nbetween two items, add a character to the end of the string that will position\nit between the two items.\n\n#### Stored Array\n\nStore an ordered array of element IDs either as a `jsonb` column or stringified\nJSON in a `text` column on the _collection_ table. If you have `list_items`\nthat are ordered, then the `lists` table will have an `ordering` column of\n`list_items` IDs. You lose referential integrity with this approach.\n\nHere is an [example\nimplementation](https://gist.github.com/jbranchaud/a00e0d6d17d562bec3007e3a4bcace94).\n\n#### Linked List\n\nA singly or doubly linked list where each item points to the next item in the list (and in the case of the doubly, points back to its previous item).\n\n[source](https://news.ycombinator.com/item?id=25802129)\n\n### References\n\n- [User-defined Order in SQL](https://begriffs.com/posts/2018-03-20-user-defined-order.html)\n- [Building Sortable Relations with PostgreSQL](https://brunoscheufler.com/blog/2022-09-26-building-sortable-relations-with-postgresql)\n- [User Defined Ordering Made Easy](https://steve.dignam.xyz/2020/03/31/practical-ordering/)\n- [Realtime Editing of Ordered Sequences](https://www.figma.com/blog/realtime-editing-of-ordered-sequences/#fractional-indexing/) (fractional indexing)\n- [Numeric and String Indexing](https://stackoverflow.com/questions/9536262/best-representation-of-an-ordered-list-in-a-database/49956113#49956113)\n- [Keeping an ordered collection in PostgreSQL](https://medium.com/the-missing-bit/keeping-an-ordered-collection-in-postgresql-9da0348c4bbe)\n- [Jira’s ranking system explained](https://tmcalm.nl/blog/lexorank-jira-ranking-system-explained/)\n- [JIRA LexoRank Explained](https://www.youtube.com/watch?v=OjQv9xMoFbg)\n- [User-defined Order in SQL | Hacker News](https://news.ycombinator.com/item?id=16635440)\n\n### Examples / Implementations\n\n- [Ranked Model - big integer positional averaging](https://github.com/brendon/ranked-model/blob/master/lib/ranked-model/ranker.rb#L174-L181)\n- [LexoRank Ruby Gem](https://github.com/richardboehme/lexorank)\n"
  },
  {
    "path": "postgres/switch-non-castable-column-type-with-using-clause.md",
    "content": "# Switch Non-Castable Column Type With Using Clause\n\nWith certain data types, such as from `int` to `bigint` or `timestamptz` to\n`timestamp`, there is an automatic type casting that can take place with\nexisting data. This means Postgres knows how to handle a data type change\nlike:\n\n```sql\nalter table users\n  alter column id\n  set data type bigint;\n```\n\nWith other data types, such as `int` to `uuid`, there is no way for Postgres to\nknow how to automatically cast it. To change the data type of a column in a\nscenario like this, you have to tell Postgres how to handle the conversion with\na `using` clause.\n\n```sql\nalter table users\n  alter column id\n  set data type uuid using (gen_random_uuid());\n```\n\nIn this instance, the `using` clause tells Postgres to ignore the existing\ninteger `id` value and use the `gen_random_uuid()` function to generate a UUID\nvalue to take its place.\n\nThe `using` clause can also reference the existing column value as part of its\ntype cast.\n\nSee the [alter table\ndocumentation](https://www.postgresql.org/docs/current/sql-altertable.html) for\nmore details on this.\n"
  },
  {
    "path": "postgres/switch-the-running-postgres-server-version.md",
    "content": "# Switch The Running Postgres Server Version\n\nI use [asdf](https://github.com/asdf-vm/asdf) install and manage multiple\nversions of Postgres on my Mac OSX machine. With `asdf` and project-based\n`.tools-versions` files, I can control what version of Postgres (`psql`) I use\nat a project-level.\n\nThe one snag with this workflow is managing the currently running server\nversion.  Lets say I need to switch from a project using `12.3` to a project\nusing `13.1`. If the Postgres server running on my machine is using the\nPostgres server 12.3, then I'll need to manually stop that server and start up\nthe Postgres server 13.1.\n\nThis can be done like so:\n\n```bash\n# stop the 12.3 server\n$ $HOME/.asdf/installs/postgres/12.3/bin/pg_ctl \\\n    -D $HOME/.asdf/installs/postgres/12.3/data \\\n    stop\n\n# start the 13.1 server\n$ $HOME/.asdf/installs/postgres/13.1/bin/pg_ctl \\\n    -D $HOME/.asdf/installs/postgres/13.1/data \\\n    start\n```\n\nThis uses the specific asdf-versioned `pg_ctl` command to stop and start the\nservers.\n\nI've found it tedious to dig up these commands each time I need to switch, so I\nadded a [`switch_pg` function to my `~/.zshrc`\nconfig](https://gist.github.com/jbranchaud/3cda6be6e1dc69c6f55435a387018dac).\n"
  },
  {
    "path": "postgres/table-names-are-treated-as-lower-case-by-default.md",
    "content": "# Table Names Are Treated As Lower-Case By Default\n\nThis one is a bit unintuitive and can cause some real confusion -- when you\ncreate a table in PostgreSQL, any casing is ignored, it is treated as\nlower-case. Let's see it to believe it:\n\n```sql\n> create table BookMarks (\n    id integer generated always as identity primary key,\n    location text not null\n  );\n\n> \\d\n+--------+--------------------+----------+----------+\n| Schema | Name               | Type     | Owner    |\n|--------+--------------------+----------+----------|\n| public | bookmarks          | table    | postgres |\n| public | bookmarks_id_seq   | sequence | postgres |\n+--------+--------------------+----------+----------+\n```\n\nNotice that when we list our tables, the uppercase `M` and `B` are gone. That's\nbecause Postgres folds away the casing when processing the table name\nidentifier.\n\nIt doesn't matter how we refer to it for queries:\n\n```sql\n> select * from BookMarks;\n+----+----------+\n| id | location |\n|----+----------|\n+----+----------+\n\n> select * from bookmarks;\n+----+----------+\n| id | location |\n|----+----------|\n+----+----------+\n```\n\nYou can force Postgres to respect the casing by wrapping the table name in\nquotes.\n\n```sql\n> create table \"BookMarks\" (\n    id integer generated always as identity primary key,\n    location text not null\n  );\n\n> \\d\n+--------+--------------------+----------+----------+\n| Schema | Name               | Type     | Owner    |\n|--------+--------------------+----------+----------|\n| public | BookMarks          | table    | postgres |\n| public | BookMarks_id_seq   | sequence | postgres |\n+--------+--------------------+----------+----------+\n\n> select * from \"BookMarks\";\n+----+----------+\n| id | location |\n|----+----------|\n+----+----------+\n\n> select * from \"bookmarks\";\nrelation \"bookmarks\" does not exist\nLINE 1: select * from \"bookmarks\"\n                      ^\n\n> select * from BookMarks;\nrelation \"bookmarks\" does not exist\nLINE 1: select * from BookMarks\n                      ^\n```\n\nThat then means you have to quote your table name anytime you want to refer to\nit in a query. It's not worth it. It is better to always keep your table names\nlower-case using snake case.\n\n[source](https://weiyen.net/articles/avoid-capital-letters-in-postgres-names)\n"
  },
  {
    "path": "postgres/temporarily-disable-triggers.md",
    "content": "# Temporarily Disable Triggers\n\nIn general, you are always going to want your triggers to fire. That's why\nthey are there. Though special circumstances may arise where you need to\ntemporarily disable them. Use\n\n```sql\n> set session_replication_role = 'replica';\nSET\n```\n\nBy changing the\n[replication role](http://www.postgresql.org/docs/9.4/static/runtime-config-client.html#GUC-SESSION-REPLICATION-ROLE)\nfrom `origin` to\n`replica` you are essentially disabling all non-replica triggers across the\ndatabase (for that session). When you are done, you can simply set the\nreplication role back so that normal trigger behavior can resume\n\n```sql\n> set session_replication_role = 'origin';\nSET\n```\n\nA more direct and fine-grained approach to disabling triggers is to use an\n`alter table` command that targets a specific trigger.\n\nh/t Jack Christensen\n"
  },
  {
    "path": "postgres/temporary-tables.md",
    "content": "# Temporary Tables\n\nCreate a temporary table in Postgres like so\n\n```sql\ncreate temp table posts (\n    ...\n);\n```\n\nThis table (and its data) will only last for the duration of the session.\nIt is created on a schema specific to temporary tables. It is also worth\nnoting that it won't be autovacuumed, so this must be done manually as\nnecessary.\n"
  },
  {
    "path": "postgres/terminating-a-connection.md",
    "content": "# Terminating A Connection\n\nConsider the scenario where you are trying to drop a database, but there are\nexisting connections.\n\n```bash\n$ dropdb sample_db\ndropdb: database removal failed: ERROR:  database \"sample_db\" is being accessed by other users\nDETAIL:  There is 1 other session using the database.\n```\n\nIf you don't know where these connections are, you can terminate them within\na `psql` session. You just have to figure out the `pid` of those\nconnections. In [List Connections To A\nDatabase](list-connections-to-a-database.md), I explained how to\nget at the `pid` values of connections. Using the `pid` value and\n`pg_terminate_backend()`, you can terminate a connection.\n\n```sql\n> select pg_terminate_backend(12345);\n pg_terminate_backend\n----------------------\n t\n```\n\nTo terminate all connections to a particular database, use a query like the\nfollowing:\n\n```sql\nselect pg_terminate_backend(pg_stat_activity.pid)\nfrom pg_stat_activity\nwhere pg_stat_activity.datname = 'sample_db'\n  and pid <> pg_backend_pid();\n pg_terminate_backend\n----------------------\n t\n```\n\nThis excludes the current session, so you'll need to exit `psql` as well\nbefore dropping the database.\n\n[source](http://stackoverflow.com/questions/5408156/how-to-drop-a-postgresql-database-if-there-are-active-connections-to-it)\n"
  },
  {
    "path": "postgres/the-nullif-function.md",
    "content": "# The nullif Function\n\nPostgreSQL, in addition to generalized case statements, includes the\n[`nullif`](https://www.postgresql.org/docs/current/functions-conditional.html)\nfunction. The docs describe it as a way \"to perform the inversation operation\nof a `coalesce`\".\n\nRather than resolving to some fallback value if the primary value is `null`\n(like `coalesce` does), it will resolve to `null` if the given values are the\nsame.\n\n```sql\n> select nullif(0, 0);\n nullif\n--------\n      ø\n(1 row)\n```\n\nIf the values are not equal, then the first value is the result of the\nfunction.\n\n```sql\n> select nullif(1, 0);\n nullif\n--------\n      1\n(1 row)\n```\n\nOne way this can be used is in conjunction with the `coalesce` function. For\ninstance, if I have a table of values that are either 0 or a positive number, I\ncan coerce all the zeros to be `1` like so.\n\n```sql\n> select coalesce(nullif(0, 0), 1);\n coalesce\n----------\n        1\n(1 row)\n```\n\nh/t [Ian Jones](https://twitter.com/_jonesian)\n"
  },
  {
    "path": "postgres/timestamp-functions.md",
    "content": "# Timestamp Functions\n\nThere are a handful of timestamp functions available in postgres. The most\ncommon one is probably `now()`. This is an alias of\n`transaction_timestamp()` which the postgres docs describe as:\n\n> Current date and time (start of current transaction)\n\nTwo other interesting timestamp functions are `statement_timestamp()` and\n`clock_timestamp()`. The postgres docs describe `statement_timestamp()` as:\n\n> Current date and time (start of current statement)\n\nUsing `statement_timestamp()` throughout a transaction will yield different\nresults from statement to statement.\n\nThe postgres docs describe `clock_timestamp()` as:\n\n> Current date and time (changes during statement execution)\n\nUsing `clock_timestamp()` may even yield different results depending on\nwhere it appears in a given statement.\n\nTry running something like this to see:\n\n```postgresql\n> select clock_timestamp(), clock_timestamp(), clock_timestamp(), clock_timestamp();\n        clock_timestamp        |        clock_timestamp        |        clock_timestamp        |        clock_timestamp        \n-------------------------------+-------------------------------+-------------------------------+------------------------------\n 2015-03-20 14:58:49.832592-05 | 2015-03-20 14:58:49.832592-05 | 2015-03-20 14:58:49.832593-05 | 2015-03-20 14:58:49.832593-05\n```\n\nYou'll notice that we see a change in the clock time at the microsecond\nlevel mid-way through the statement.\n\nsources: [postgres docs](http://www.postgresql.org/docs/9.1/static/functions-datetime.html) and\n[Jack C.](http://hashrocket.com/team/jack-christensen)\n"
  },
  {
    "path": "postgres/toggling-the-pager-in-psql.md",
    "content": "# Toggling The Pager In PSQL\n\nWhen the pager is enabled in `psql`, commands that produce larger output\nwill be opened in a pager. The pager can be enabled within `psql` by running\n`\\pset pager on`.\n\nIf you'd like to retain the output of commands, perhaps as reference for\nsubsequent commands, you can turn the pager off. As you might expect, the\npager can be disabled with `\\pset pager off`.\n\n[source](http://stackoverflow.com/questions/11180179/postgresql-disable-more-output)\n"
  },
  {
    "path": "postgres/track-psql-history-separately-per-database.md",
    "content": "# Track psql History Separately Per Database\n\nBy default, `psql` will keep track of all recent queries and commands in the\n`.psql_history` file in your home directory.\n\nWhen in a `psql` session, you can hit the `Up` key to go back through the\nhistory to find a previously entered query. That means you can quickly retrieve\nand rerun past queries.\n\nHowever the default `psql` configuration means that your history can contain\nqueries from a `psql` session with another database that don't make sense in\nthe context of the current database.\n\nYou can keep these query histories separate by configuring `psql` to use\nseparate history files per database. This can be done by adding the following\nline to your `~/.psqlrc` file.\n\n```\n\\set HISTFILE ~/.psql_history-:DBNAME\n```\n\n[source](https://github.com/hashrocket/dotmatrix/commit/1bd581db3a7192eb7aaa766a97e4b4b82d544067)\n"
  },
  {
    "path": "postgres/trim-leading-and-trailing-space-from-string.md",
    "content": "# Trim Leading And Trailing Space From String\n\nPostgreSQL has a bunch of [string\nfunctions](https://www.postgresql.org/docs/current/functions-string.html),\nincluding several for doing various string trimming.\n\nWe can use the simplest form of `trim` to remove leading and trailing space\ncharacters from a string.\n\n```sql\n> select trim('  Taco Cat ');\n+----------+\n| btrim    |\n|----------|\n| Taco Cat |\n+----------+\n```\n\nThe syntax for calling `trim` is a bit odd relative to other PostgreSQL\nfunctions and functions in other languages. Here is the \"grammar\" as described\nin the docs:\n\n```\ntrim ( [ LEADING | TRAILING | BOTH ] [ characters text ] FROM string text ) → text\n```\n\nWe pick `leading`, `trailing`, or `both`, with `both` being the default. Then\nwe specify the character(s) we want to remove. This is also optional, the\ndefault being the space character. Then we say `from` what string we want to\ntrim those characters.\n\nHere we remove all sequential spaces from `both` ends of the given string:\n\n```sql\n> select trim(both from '  Taco Cat ');\n+----------+\n| btrim    |\n|----------|\n| Taco Cat |\n+----------+\n```\n\nTo further demonstrate how `trim` works, here we remove all sequences made up\nof any of spaces, uppercase `T`, and lowercase `t` from `both` ends of the\nstring:\n\n```sql\n> select trim(both ' Tt' from '  Taco Cat ');\n+--------+\n| btrim  |\n|--------|\n| aco Ca |\n+--------+\n```\n\nNotice that in all the above examples the column name of the result is `btrim`.\nThat's probably because `btrim` (_trim both ends_) is being called under the\nhood for the `both` option.\n"
  },
  {
    "path": "postgres/truncate-all-rows.md",
    "content": "# Truncate All Rows\n\nGiven a postgres database, if you want to delete all rows in a table, you\ncan use the `DELETE` query without any conditions.\n\n```sql\n> delete from pokemons;\nDELETE 151\n```\n\nThough `DELETE` can do the job, if you really are deleting all rows to clear\nout a table, you are better off using `TRUNCATE`. A `TRUNCATE` query will be\nfaster than a `DELETE` query because it will just delete the rows without\nscanning them as it goes.\n\n```sql\n> truncate pokemons;\nTRUNCATE TABLE\n```\n\n[source](http://www.postgresql.org/docs/8.2/static/sql-truncate.html)\n"
  },
  {
    "path": "postgres/truncate-tables-with-dependents.md",
    "content": "# Truncate Tables With Dependents\n\nIn [Truncate All Rows](truncate-all-rows.md), I talked about how\npostgres's `truncate` can be used to quickly delete all rows in a table. In\npractice this alone won't be very useful though, because tables usually have\nother tables that depend on them via foreign keys. If you have tables `A`\nand `B` where `B` has a foreign key referencing `A`, then trying to truncate\n`A` will result in something like this:\n\n```sql\n> truncate A;\nERROR:  cannot truncate a table referenced in a foreign key constraint\n```\n\nFortunately, `truncate` has some tricks up its sleeve.\n\nIf you know two tables are tied together via a foreign key constraint, you\ncan just truncate both of them at once:\n\n```sql\n> truncate A, B;\nTRUNCATE TABLE;\n```\n\nIf many tables are tied together in this way and you are looking to throw\nall of it out, then a simpler approach is to cascade the truncation:\n\n```sql\n> truncate A cascade;\nNOTICE:  truncate cascades to table \"B\"\nTRUNCATE TABLE\n```\n\nUse these with care and potentially within transactions because your data\nwill go bye bye.\n\nh/t Dillon Hafer and Jack Christensen\n"
  },
  {
    "path": "postgres/turn-timing-on.md",
    "content": "# Turn Timing On\n\nWhen digging around your database and running queries, it is helpful to\nhave an eye on the speed of those queries. This can give insight into\nwhere there are needs for optimizations.\n\nTurn timing on (and off) within `psql` by running `\\timing`. With timing\non, the duration of each query will be displayed in milliseconds after the\noutput of the query.\n"
  },
  {
    "path": "postgres/two-ways-to-compute-factorial.md",
    "content": "# Two Ways To Compute Factorial\n\nIn PostgreSQL, there are two ways to compute the factorial of a number.\nThere is a prefix operator and a postfix operator. The prefix operator is\n`!!` and can be used like so:\n\n```sql\n> select !!5;\n ?column?\n----------\n      120\n```\n\nThe postfix operator is `!` and can be used like so:\n\n```sql\n> select 5!;\n ?column?\n----------\n      120\n```\n\nSee the [mathematical functions and operators\ndocs](http://www.postgresql.org/docs/8.1/static/functions-math.html)\nfor more details.\n"
  },
  {
    "path": "postgres/two-ways-to-escape-a-quote-in-a-string.md",
    "content": "# Two Ways To Escape A Quote In A String\n\nString literals in PostgreSQL have to be wrapped in single quotes. This can be\ntricky if you are faced with writing out a query using a string that contains a\nsingle quote.\n\n```sql\n> select 'who's on first?';\n...\n```\n\nThe query won't execute because it is waiting for you to close the second set\nof quotes.\n\nI know of two ways to handle this situation.\n\nThe first is to put two single quotes back to back. The first will cause the\nsecond to be escaped so that the quote shows up in the string.\n\n```sql\n> select 'who''s on first?';\n    ?column?\n-----------------\n who's on first?\n(1 row)\n```\n\nThe second is to prepend the string with [the `E`\ncharacter](https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS)\nto allow escape sequences in strings.\n\n```sql\n> select E'who\\'s on first?';\n    ?column?\n-----------------\n who's on first?\n(1 row)\n```\n\n[source](https://stackoverflow.com/a/12320729)\n"
  },
  {
    "path": "postgres/types-by-category.md",
    "content": "# Types By Category\n\nPostgres has many types, each of which fall into a particular category.\nThese categories include Array, Boolean, String, Numeric, Composite, etc.\nEach of these categories has a corresponding code. For instance, numeric\ntypes have a code of `N`. Using `N` I can get a list of all the numeric\ntypes:\n\n```sql\n> select typname from pg_type where typcategory = 'N';\n     typname\n-----------------\n int8\n int2\n int4\n regproc\n oid\n float4\n float8\n money\n numeric\n regprocedure\n regoper\n regoperator\n regclass\n regtype\n regconfig\n regdictionary\n cardinal_number\n(17 rows)\n```\n\nCheck out\n[`pg_type`](http://www.postgresql.org/docs/current/interactive/catalog-pg-type.html)\nin the Postgres docs for a list of all categories and codes.\n"
  },
  {
    "path": "postgres/unable-to-infer-data-type-in-production.md",
    "content": "# Unable To Infer Data Type In Production\n\nInspired by [You Probably Don't Need Query\nBuilders](https://mattrighetti.com/2025/01/20/you-dont-need-sql-builders), I\nwrote a query in one of my applications that has filter clauses that get\nshort-circuited if the filter value hasn't been included.\n\nThat query looked something like this:\n\n```ruby\n@tags =\n  Tag.where(\"? is null or normalized_value ilike ?\", normalized_query, \"%#{normalized_query}%\")\n     .order(:normalized_value)\n     .limit(10)\n```\n\nThe `normalized_value ilike ?` filtering won't be applied if the\n`normalized_query` value isn't present (`nil`). This helps me avoid writing\nmessy ternaries or if-else conditional query building madness.\n\nUnfortunately, when I shipped this query to production, the page started\nfailing and Postgres was reporting this error in the logs.\n\n```\nCaused by: PG::IndeterminateDatatype (ERROR:  could not determine data type of parameter $1)\n```\n\nThe query is prepared as a parameterized statement and Postgres appears to be\nunable to determine the datatype of the first parameter (`$1`) —\n`normalized_query`.\n\nI was unable to reproduce the issue in development. It was only occuring in\nproduction. Until I can come up with a root cause analysis, I have the\nfollowing fix that does a casting to `text`. This helps out with the type\ninference and makes the issue go away.\n\n```ruby\n@tags =\n  Tag.where(\"cast(? as text) is null or normalized_value ilike ?\", normalized_query, \"%#{normalized_query}%\")\n     .order(:normalized_value)\n     .limit(10)\n```\n\nInterestingly, this person using `pgtyped` [ran into the exact same issue with\nthe same type of query](https://github.com/adelsz/pgtyped/issues/354).\n"
  },
  {
    "path": "postgres/union-all-rows-including-duplicates.md",
    "content": "# Union All Rows Including Duplicates\n\nTwo tables or sets of results can be joined together into a single result set\nusing [the `union`\noperator](https://www.postgresql.org/docs/current/queries-union.html). When\ncombining results with `union`, all duplicate rows will be removed from its\nresult.\n\n```sql\n> select generate_series(1,4)\n  union\n  select generate_series(3,6)\n  order by 1 asc;\n\n generate_series\n-----------------\n               1\n               2\n               3\n               4\n               5\n               6\n(6 rows)\n```\n\nNotice that despite both sides of the `union` having their own 3 and 4, those\nvalues each only show up once in the result.\n\nIf we don't want duplicates to be excluded, we can use `union all`.\n\n```sql\n> select generate_series(1,4)\n  union all\n  select generate_series(3,6)\n  order by 1 asc;\n\n generate_series\n-----------------\n               1\n               2\n               3\n               3\n               4\n               4\n               5\n               6\n(8 rows)\n```\n\nIn this case we have 8 rows instead of 6 with the values 3 and 4 each appearing\ntwice.\n\n[source](https://www.postgresqltutorial.com/postgresql-union/)\n"
  },
  {
    "path": "postgres/use-a-psqlrc-file-for-common-settings.md",
    "content": "# Use A psqlrc File For Common Settings\n\nThere are a handful of settings that I inevitably turn on or configure each\ntime I open up a `psql` session. I can save myself a little time and sanity\nby configuring these things in a `.psqlrc` dotfile that is located in my\nhome directory. This will ensure my `psql` session is configured just how I\nlike it each time I launch it. Here is what my `~/.psqlrc` file currently\nlooks like:\n\n```\n\\x auto\n\\timing\n\\pset null 'Ø'\n```\n"
  },
  {
    "path": "postgres/use-a-trigger-to-mirror-inserts-to-another-table.md",
    "content": "# Use A Trigger To Mirror Inserts To Another Table\n\nOn a PostgreSQL server, a trigger can be set up to execute a function whenever\na certain action happens. In this case, I want set up a trigger to call a\ncustom function whenever an `insert` happens on a specific table\n(`original_table`). That custom function will then mirror the inserted values\ninto a secondary table (`another_table`).\n\nFirst, I have to create a function that will respond to `insert` operations by\ninserting the newly inserted rows into `another_table`.\n\n```sql\ncreate or replace function mirror_table_to_another_table()\n  returns trigger as $mirrored_table$\n    begin\n      if (TG_OP = 'INSERT') then\n        insert into another_table\n          select * from new_table;\n      end if;\n      return null; -- result is ignored since this is an after trigger\n    end;\n$mirrored_table$ language plpgsql;\n```\n\nThis function can then be referenced by the trigger I set up. After any insert\non the `original_table`, the function defined above will be executed.\n\n```sql\ncreate trigger mirror_table_to_another_table_trigger\n  after insert on original_table\n  referencing new table as new_table\n  for each statement\n    execute function mirror_table_to_another_table();\n```\n\nNote that I am handling inserts at a statement level and that multiple rows can\nbe inserted in a single statement. That is why the function mirrors to the\nother table with `select * from new_table`.\n"
  },
  {
    "path": "postgres/use-argument-indexes.md",
    "content": "# Use Argument Indexes\n\nIn Postgres, each of the arguments you specify in a `select` statement has a\n1-based index tied to it. You can use these indexes in the `order by` and\n`group by` parts of the statement.\n\nInstead of writing\n\n```sql\nselect id, updated_at from posts order by updated_at;\n```\n\nyou can write\n\n```sql\nselect id, updated_at from posts order by 2;\n```\n\nIf you want to group by a table's `type` and then order by the counts from\nhighest to lowest, you can do the following\n\n```sql\nselect type, count(*) from transaction group by 1 order by 2 desc;\n```\n"
  },
  {
    "path": "postgres/use-not-valid-to-immediately-enforce-a-constraint.md",
    "content": "# Use Not Valid To Immediately Enforce A Constraint\n\nWhen adding a constraint to a table, you can optionally include `not valid`.\nThis tells Postgres that it doesn't need to enforce the constraint on\nexisting records in the table. At least not immediately. This constraint\nwill be enforced for any updates and subsequent insertions. Thus, you can\nimmediately enforce the constraint while giving yourself time to clean up\nor massage any existing records that conflict with the constraint.\n\nHere is an example of how you would add a constraint this way:\n\n```sql\nalter table boxes\nadd constraint check_valid_length\ncheck (length > 0) not valid;\n```\n\nEventually, you will want to ensure that all data in the table conforms to the\nconstraint. Once you get to that point, you can mark the constraint as valid\nwith a `validate constraint` command:\n\n```sql\nalter table boxes\nvalidate constraint check_valid_length;\n```\n\nAs long as all records are valid with respect to this constraint, it will be\nmarked as valid.\n\nh/t Chris Erin\n"
  },
  {
    "path": "postgres/use-rename-to-hot-swap-two-tables.md",
    "content": "# Use Rename To Hot Swap Two Tables\n\nThe [`alter\ntable`](https://www.postgresql.org/docs/current/sql-altertable.html) command\ncan be used to [rename a\ntable](https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-rename-table/).\nBecause it is changing the name of a reference rather than actually moving any\ndata around, it is very fast.\n\nWe can exploit the speed of a _rename_ to hot swap two tables. This is useful\nfor a situation where we've created an identical table with a small fraction of\nthe data of the original table. By hot swapping them, we've exchanged the large\ntable for a smaller one without our application code noticing anything\nhappened.\n\nLet's assume we have a massive `events` table and then a much smaller\n`new_events` table with the same structure.\n\nThe following transaction will swap those two tables in the blink of an eye.\n\n```sql\nbegin;\n\nalter table events rename to old_events;\nalter table new_events rename to events;\n\ncommit;\n```\n\nThe resulting `old_events` table can then be deleted at our convenience.\n\nThe other nice thing about this approach is that, before deleting `old_events`,\nyou can easily and quickly swap them back using the same approach. It is always\na comfort when huge changes like this are easy to reverse if necessary.\n"
  },
  {
    "path": "postgres/use-variables-in-an-anonymous-function.md",
    "content": "# Use Variables In An Anonymous Function\n\nI was curious how variables could be declared and used in PostgreSQL, so I did\na little experiment with a `books` and `authors` schema.\n\nVariables need to be declared and used within the context of a function. Using\nthe [`do` syntax](https://www.postgresql.org/docs/9.1/sql-do.html) I am able to\ndeclare and execute an anoymous code block.\n\nWithin that code block I can declare one or more variables by giving them a\ntype and optionally a default value. Below I declare `author_id` with a default\nand `result` as a `record` type.\n\n```sql\ndo $$\ndeclare\n  author_id varchar := 'e2b42ebf-7ea9-4d9e-8edf-310fc1894bcd';\n  result record;\nbegin\n  for result in select title from books where \"authorId\" = author_id\n  loop\n    raise notice '| % |', result.title;\n  end loop;\nend $$;\n```\n\nI'm able to use the `author_id` variable directly in a `select` statement.\n\n```sql\nselect title from books where \"authorId\" = author_id\n```\n\nand then using a [for\nloop](https://www.postgresql.org/docs/current/plpgsql-control-structures.html#PLPGSQL-RECORDS-ITERATING)\nwith my `result` of `record` type, I can iterate over each of the results from\nthe `select`.\n\nBecause this anonymous `do` block implicitly has a `void` return type, I need\nto do something with the result within the block. For demonstration purposes, I\nuse [`raise\nnotice`](https://www.postgresql.org/docs/current/plpgsql-errors-and-messages.html)\nto log out each book title.\n"
  },
  {
    "path": "postgres/using-expressions-in-indexes.md",
    "content": "# Using Expressions In Indexes\n\nThough we usually see column names by themselves when defining an index, it\nis also possible to create an index with an expression.\n\nLet's say I have a `users` table with an `email` column. Then I may end up\ncreating an index like this\n\n```sql\ncreate index email_idx on users (email);\n```\n\nIf I always perform queries on the `email` column with the `lower()`\nfunction, like this\n\n```sql\nselect * from users where lower(email) = lower('some@email.com');\n```\n\nthen I will want to also create an index with that full expression --\n`lower(email)`\n\nI can do this with a statement like the following\n\n```sql\ncreate index lower_email_idx on users (lower(email));\n```\n\nWithout an index that uses the full `lower(email)` expression, `select`\nstatements like the one above will be forced to do full sequential scans\ninstead of indexed scans.\n"
  },
  {
    "path": "postgres/using-intervals-to-offset-time.md",
    "content": "# Using Intervals To Offset Time\n\nPostgres Intervals can be used with time as a way of determining a\nstandard offset. For instance, I can concisely determine what the time was 2\nhours earlier with\n\n```sql\n> select now() - '2 hours'::interval as earlier;\n            earlier\n-------------------------------\n 2015-06-12 21:17:43.678822-05\n```\n\nor similarly\n\n```sql\n> select now() - interval '2 hours' as earlier;\n            earlier\n-------------------------------\n 2015-06-12 21:17:43.678822-05\n```\n"
  },
  {
    "path": "postgres/who-is-the-current-user.md",
    "content": "# Who Is The Current User\n\nYou can determine the current user of a psql session by selecting on the `current_user`\n\n```sql\n> select current_user;\n\n  current_user\n----------------\n   test_user\n```\n\nYou can also select on the `user` which is an alias of `current_user`\n\n```sql\n> select user;\n\n     user\n----------------\n   test_user\n```\n"
  },
  {
    "path": "postgres/word-count-for-a-column.md",
    "content": "# Word Count for a Column\n\nAssuming I have a database with a posts table:\n\n```sql\n> select * from posts where id = 1;\n id |  title   |              content               \n----+----------+------------------------------------\n  1 | My Title | This is the content of my article. \n```\n\nI can compute the word count of the content of a given post like so:\n\n```sql\n> select sum(array_length(regexp_split_to_array(content, '\\s+'), 1)) from posts where id = 1;\n sum \n-----\n   7 \n```\n\n[source](http://blog.lingohub.com/2013/07/sql-word-count-character-count-postgres/)\n"
  },
  {
    "path": "postgres/write-a-query-result-to-file.md",
    "content": "# Write A Query Result To File\n\nGenerally when writing a query in `psql` a statement will be terminated with\na semicolon. An alternative approach is to end it with a `\\g` instead. This\nwill also send the query to the Postgres server for execution.\n\n```sql\nselect 1 \\g\n```\n\nIf a filename is included after the `\\g`, then the result of the query will\nbe written to that file instead of output to the `psql` session.\n\n```sql\n> select 1, 2, 3 \\g query_result.txt\n```\n\nIf we `cat` that file, we can see the query result.\n\n```sql\nTime: 4.293 ms\n> \\! cat query_result.txt\n ?column? | ?column? | ?column?\n----------+----------+----------\n        1 |        2 |        3\n(1 row)\n```\n\nSee `man psql` for more details.\n"
  },
  {
    "path": "prisma/apply-separate-formatting-with-a-blank-line.md",
    "content": "# Apply Separate Formatting With A Blank Line\n\nPrisma's CLI includes a `format` command. When run, this will standardize the\nlayout of the `schema.prisma` file. This is variable based on the length of\ncolumn and attribute names.\n\nYou can exercise some control over the formatting and visually organize the\nparts of a model by injecting blank lines between sets of statements.\n\nHere is what a formatted model might look like with no blank lines:\n\n```prisma\nmodel Book {\n  id              String   @id @default(uuid())\n  title           String\n  publicationDate DateTime\n  author          Author   @relation(fields: [authorId], references: [id])\n  authorId        String\n  createdAt       DateTime @default(now()) @map(name: \"created_at\")\n  updatedAt       DateTime @updatedAt @map(name: \"updated_at\")\n}\n```\n\nAll the types get aligned based on the longest column name.\n\nNow, here is what it looks like if I use a blank line to separate all the\nprimary fields from the `createdAt` and `updatedAt`.\n\n```prisma\nmodel Book {\n  id              String   @id @default(uuid())\n  title           String\n  publicationDate DateTime\n  author          Author   @relation(fields: [authorId], references: [id])\n  authorId        String\n\n  createdAt DateTime @default(now()) @map(name: \"created_at\")\n  updatedAt DateTime @updatedAt @map(name: \"updated_at\")\n}\n```\n\nNotice how the second block of lines is aligned independent of the first.\n"
  },
  {
    "path": "prisma/batch-insert-records-with-create-many.md",
    "content": "# Batch Insert Records With createMany\n\nAs part of its suite of CRUD functionality, [Prisma has a `createMany`\nfunction](https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#createmany)\nthat allows you to `insert` many records at once with your target database.\nThis will perform one large insert statement which will generally be faster\nthan an equivalent series of individual insert statements.\n\n```javascript\nconst createResult = await prisma.books.createMany({\n  data: [\n    { isbn: '123', title: 'The Goldfinch' },\n    { isbn: '345', title: 'Piranesi' },\n    { isbn: '987', title: 'The Fifth Season' },\n  ],\n  skipDuplicates: true\n})\n```\n\nWith the `skipDuplicates` option, any inserts that would result in a duplicate\nrecord (`isbn` is my unique key in this example) will be skipped.\n\nThe result of the query will include a `count` key to let you know how many\nrecords were actually inserted.\n\nIf I'm bulk inserting a _ton_ of data, I like to chunk it up so that I'm not\ncreating queries that are too big. For a recent script, I found that `1000` was\na good chunking number.\n\n```javascript\nimport 'chunk' from 'lodash/chunk'\n\nconst chunkedBatchInsert = async (records) => {\n  for(const batch of chunk(records, 1000)) {\n    await prisma.books.createMany({\n      data: batch,\n      skipDuplicates: true\n    })\n  }\n}\n```\n"
  },
  {
    "path": "prisma/check-if-database-and-schema-are-not-in-sync.md",
    "content": "# Check If Database And Schema Are Not In Sync\n\nThe [`prisma migrate\ndiff`](https://www.prisma.io/docs/orm/reference/prisma-cli-reference#migrate-diff)\ncommand is a versatile tool that can be used to check if there is a difference\nbetween two sources. In this case, we want to check if our database is in sync\nwith the `schema.prisma` file for our project.\n\nIf we have made changes to the schema file, but haven't yet migrated or pushed\nthose changes to our local database, then we want to be notified of that\nmismatch.\n\nWe'll point at the schema file with `--to-schema-datamodel` and at our local\ndatabase with `--from-url`.\n\n```bash\n❯ npx prisma migrate diff \\\n    --to-schema-datamodel ./prisma/schema.prisma \\\n    --from-url mysql://root@localhost:3309/kcd-products\n\n[*] Changed the `User` table\n  [+] Added column `metadata`\n```\n\nIn the case where there is a different, we see an output summary of the diff.\n\nLet's say we've applied our changes (`prisma db push`) to our local database.\nIf we now run that same command again, we can see that no difference is\ndetected and our database is in sync with our schema.\n\n```bash\n❯ npx prisma migrate diff \\\n    --to-schema-datamodel ./prisma/schema.prisma \\\n    --from-url mysql://root@localhost:3309/kcd-products\n\nNo difference detected.\n```\n"
  },
  {
    "path": "prisma/configure-client-to-log-sql-queries.md",
    "content": "# Configure Client To Log SQL Queries\n\nDuring development, especially while debugging, it can be helpful to see the\nactual SQL queries generated by Prisma queries we are formulating. Because an\nORM is an abstraction over SQL, it isn't always obvious what the resulting SQL\nwill turn out to be.\n\nBy adding the `log` configuration to where we initialize our Prisma client, we\ncan tell it to log things like errors and the SQL of the queries it executes.\n\n```javascript\nexport const prisma =\n  new PrismaClient({\n    log: ['error', 'query']\n  })\n```\n\nIf we only want the SQL logged in development, we could do something like this:\n\n```javascript\nexport const prisma =\n  new PrismaClient({\n    log:\n      process.env.NODE_ENV === 'development'\n        ? ['query', 'error']\n        : ['error'],\n  })\n```\n\nIf we look in our app server logs when a code path that contains a Prisma query\nexecutes, we'll see a line for each SQL statement.\n\n[source](https://github.com/prisma/prisma/discussions/3967)\n"
  },
  {
    "path": "prisma/execute-a-raw-sql-query.md",
    "content": "# Execute A Raw SQL Query\n\n[Prisma](https://www.prisma.io/) with TypeScript acts as a powerful\n[ORM](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping) for\ninteracting with your database. However, not every kind of query that you may\nneed can be represented with the API generated from your schema. For instance,\ncertain tables might be ignored in your `prisma.schema` file. Or you may want\nto hand-craft a query for performance or ergonomics reasons.\n\nLike any good ORM, Prisma provides an escape hatch for this kind of situation\nwith the\n[`$queryRaw`](https://www.prisma.io/docs/concepts/components/prisma-client/raw-database-access#queryraw)\ntag function.\n\n```typescript\nfunction getExpiresIn({ email }) {\n  const prisma = new PrismaClient()\n\n  const result: Array<object> = await prisma.$queryRaw`\n    select\n      id,\n      code,\n      date_trunc('days', expires_at - now())::varchar as expires_in\n    from tickets\n    where email = ${email}\n  `\n\n  // result\n  // => [{ id: 123, code: 'abc123', expires_in: '3 days' }]\n\n  return result\n}\n```\n\nThis runs the raw SQL in the template literal against the database. The result\nis returned as an array of objects with key-value pairs for each selected\nvalue.\n\nWriting the SQL query myself, in this case, means I can take advantage of\ndatabase (Postgres) specific features (e.g.\n[`date_trunc`](https://www.postgresqltutorial.com/postgresql-date-functions/postgresql-date_trunc/)\nand [interval\nmath](https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-interval/)).\n\n[source](https://www.prisma.io/docs/concepts/components/prisma-client/raw-database-access)\n"
  },
  {
    "path": "prisma/grab-a-limited-set-of-records.md",
    "content": "# Grab A Limited Set Of Records\n\nLet's say you want to grab some records from a table, but you want to limit the\nresult set to 10 records.\n\nYou can do that with the `take` option.\n\n```javascript\nconst posts = await prisma.post.findMany({\n  take: 10\n});\n```\n\nIt is generally good to not assume anything about the ordering. Instead, you\nshould be explicit about the order you want, so let's include an `orderBy` as\nwell.\n\n```javascript\nconst posts = await prisma.post.findMany({\n  take: 10,\n  orderBy: { createdAt: \"asc\" },\n});\n```\n\nThis will return the 10 most recently created posts.\n\n[source](https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#findmany)\n"
  },
  {
    "path": "prisma/open-connections-to-multiple-databases.md",
    "content": "# Open Connections To Multiple Databases\n\nA standard database connection with Prisma is determined by a `DATABASE_URL`\nenv var set in the `.env` file of your project. Typically, the Prisma client\nconnecting to that URL will be configured in a separate file and imported\nwherever it is used.\n\n```javascript\nimport {prisma} from './utils/prisma'\n```\n\nWhat if you want to connect to a second, alternate database?\n\nYou can create a new Prisma client with the data source configured to be a\ndifferent connection URL.\n\n```javascript\nimport {prisma as primaryPrismaClient} from '@skillrecordings/database'\nimport {PrismaClient} from '@prisma/client'\n\nconst secondaryDatabaseUrl = 'mysql://root@localhost:3399/my-database'\n\nconst secondaryPrismaClient = new PrismaClient({\n  datasources: {\n    db: {\n      url: secondaryDatabaseUrl\n    }\n  },\n})\n```\n\nAnd with that, you can execute queries against both databases.\n\n```javascript\nconst primaryUserCount = await primaryPrismaClient.user.count()\nconst secondaryUserCount = await secondaryPrismaClient.user.count()\n```\n\n[source](https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#programmatically-override-a-datasource-url)\n"
  },
  {
    "path": "prisma/override-table-name-for-prisma-model.md",
    "content": "# Override Table Name For Prisma Model\n\nWhen defining your Prisma schema, you'll add models to your\n`prisma/schema.prisma` file that look something like this:\n\n```\nmodel Book {\n  id               BigInt   @id @default(autoincrement()) @db.BigInt\n  title            String\n  author           String\n  publication_year Int\n  created_at       DateTime @default(now())\n  updated_at       DateTime @updatedAt\n}\n```\n\nThe prisma client (ORM-layer) that gets generated will have a `Book` type and\nyou'll be able to reference the model to, for instance, create a record with\n`prisma.book.create(...)`. Both of these things are derived from the model\nname: `Book`.\n\nThe other thing that is derived from the model name is the name given to the\nunderlying database table. So you end up with a table called `Book`. You may,\nhowever, prefer a table naming convention where this one would be named `books`\n(snake_case and pluralized).\n\nTo achieve that, you have to manually override the table name with [the `@@map`\ndirective](https://www.prisma.io/docs/orm/reference/prisma-schema-reference#map-1).\nAdd it toward the bottom of the model like so:\n\n```\nmodel Book {\n  id               BigInt   @id @default(autoincrement()) @db.BigInt\n  title            String\n  author           String\n  publication_year Int\n  created_at       DateTime @default(now())\n  updated_at       DateTime @updatedAt\n\n  @@map(\"books\")\n}\n```\n"
  },
  {
    "path": "prisma/specify-alternate-location-for-prisma-schema.md",
    "content": "# Specify Alternate Location For Prisma Schema\n\nBy default, Prisma looks for a schema in one of two locations:\n\n- `./prisma/schema.prisma`\n- `./schema.prisma`\n\nIf it isn't in one of those two spots, then you'll get an error.\n\nYou can manually specify an alternate location. One way is to use the\n`--schema` flag with all `prisma` commands. A less tedious approach\n([introduced in this PR](https://github.com/prisma/prisma/pull/3566)) is to\nspecify the location in your `package.json`.\n\n```json\n{\n  \"prisma\": {\n    \"schema\": \"../../packages/database/prisma/schema.prisma\"\n  }\n}\n```\n\nThis is handy in situations where your database schema and utils are packaged\nup separately, like in a monorepo. Here is an example of [a monorepo\nreferencing a prisma schema in a separate\npackage](https://github.com/skillrecordings/products/blob/b10dece7170abcb9076221c0863549e2291541ae/apps/testingaccessibility/package.json#L201-L203).\n\n[source](https://www.prisma.io/docs/concepts/components/prisma-schema#prisma-schema-file-location)\n"
  },
  {
    "path": "python/access-instance-variables.md",
    "content": "# Access Instance Variables\n\nYou can define instance variables when instantiating a class.\n\n```python\nclass Person:\n    def __init__(self, first_name, last_name):\n        self.first_name = first_name\n        self.last_name = last_name\n\n    def full_name(self):\n        return self.first_name + \" \" + self.last_name\n```\n\nThen those instance variables can be accessed as properties of that class\ninstances.\n\n```python\nme = Person(\"Josh\", \"Branchaud\")\n\nprint(me.first_name) #=> \"Josh\"\nprint(me.full_name()) #=> \"Josh Branchaud\"\n```\n"
  },
  {
    "path": "python/access-most-recent-return-value-in-repl.md",
    "content": "# Access Most Recent Return Value In REPL\n\nOne of my favorite features of Ruby's `irb` and `pry` are that you can use `_`\nto reference the most recent return value. Often as we use an interpreter or\nREPL, we end up with _intermediate_ values. That is, we've execute some kind of\nstatement which returned a value and we now want to use that resulting value in\nour next statement. Python also supports `_`.\n\nLet's say I've run a statement that took a while to process, but I forgot to\nassign it to a variable. Instead of re-running the whole thing, I can create a\nvariable that references the previous return value using `_`.\n\n```python\n>>> BytePairEncoding.train_bpe(long_text)\n{'merge_rules': [...], 'vocab': {...}}\n>>> result = _\n>>> list(result.keys())\n['merge_rules', 'vocab']\n```\n\nEven if I don't necessarily want to assign it a variable, it can be nice to\nreference the previous value as I continue with what I'm doing:\n\n```python\n>>> result['merge_rules'][0][1]\n256\n>>> result['vocab'][_]\nb'e '\n```\n\nNotice how the value from the first statement gets used as part of a `dict`\naccess.\n\n[source](https://docs.python.org/3/tutorial/introduction.html#numbers)\n"
  },
  {
    "path": "python/break-debugger-on-first-line-of-program.md",
    "content": "# Break Debugger On First Line Of Program\n\nOne of the things I appreciate about how\n[Delve](https://github.com/go-delve/delve) (the debugger for Go) works by\ndefault is that when you start it up, it immediately breaks on the first line\nof the program. This is as good a starting point as any regardless of whether\nyou have other breakpoints set.\n\nAs I was reading through the VS Code Python Debugger configuration docs, I\nnoticed [an option called\n`stopOnEntry`](https://code.visualstudio.com/docs/python/debugging#_stoponentry).\nIt is turned off by default, but if you turn it on, then you get the same\nbehavior as I described for Delve. Nice!\n\nThis can be configured in a `.vscode/launch.json` file:\n\n```json\n{\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Python Debugger: Current File\",\n      \"type\": \"debugpy\",\n      \"request\": \"launch\",\n      \"program\": \"${file}\",\n      \"console\": \"integratedTerminal\",\n      \"stopOnEntry\": true\n    }\n  ]\n}\n```\n\nNow, when running this debugger configuration profile, you'll break the\ndebugger on the first line of the program. From there add more breakpoints,\nstart stepping through, etc.\n"
  },
  {
    "path": "python/check-if-package-is-installed-with-pip.md",
    "content": "# Check If Package Is Installed With Pip\n\nI recently installed PyTorch, but when I tried using it, I was getting an error\nabout `numpy` not being installed. I was kind of surprised by that because I\nthought I would have already had that.\n\nI wanted to check, so I asked with `pip show`:\n\n```bash\n❯ python3 -m pip show numpy\nWARNING: Package(s) not found: numpy\n```\n\nI can even list everything that is installed with `pip` using `pip list` like\nso:\n\n```bash\n❯ python3 -m pip list\nPackage            Version   Build\n------------------ --------- -----\ncertifi            2026.1.4\ncffi               2.0.0\ncharset-normalizer 3.4.4\nclick              8.3.1\ncommonmark         0.9.1\ncryptography       46.0.3\ndocutils           0.22.4\nfilelock           3.24.2\nfsspec             2026.2.0\nidna               3.11\nJinja2             3.1.6\n...\n```\n\nI then installed `numpy` (`python3 -m pip install numpy`) and how I can use `pip\nshow` again to confirm that.\n\n```bash\n❯ python3 -m pip show numpy\nName: numpy\nVersion: 2.4.2\nSummary: Fundamental package for array computing in Python\nHome-page: https://numpy.org\nAuthor: Travis E. Oliphant et al.\nAuthor-email:\nLicense-Expression: BSD-3-Clause AND 0BSD AND MIT AND Zlib AND CC0-1.0\nLocation: /Users/lastword/.local/share/mise/installs/python/3.12.12/lib/python3.12/site-packages\nRequires:\nRequired-by:\n```\n"
  },
  {
    "path": "python/control-passing-of-time-in-tests.md",
    "content": "# Control Passing Of Time In Tests\n\nWhile it is nice to be able to write pure functional code, our software still\nlives in the real world and may have to relate to or depend on the passing of\ntime. In order to test this kind of code, we need time to behave in a reliable,\ndeterministic way. One of the best ways to create a testing environment where\nthat is true is to bring in tooling that hijacks time.\n\nThe [`freezegun` module](https://github.com/spulec/freezegun) is a great tool\nfor that job. We can use it to freeze time at a specific testable point, advance\ntime a specific amount, and much more.\n\nHere is an example from the tests for [my CLI-based time tracking\napp](https://github.com/jbranchaud/py-vmt/blob/acb26e4840279d936a12f16c505ca7e75e9a6d20/tests/src/py_vmt/test_cli.py#L21)\nwhere I freeze time before starting a session. That gives me a chance to assert\nabout the exact start time that is output by the command. Then I can advance\ntime a little and assert that the `status` command outputs the correct thing.\n\n```python\nimport datetime\nfrom freezegun import freeze_time\n\n# some other test setup omitted ...\n\ninitial_datetime = datetime.datetime(\n    2026, 3, 14, 15, 5, 11, 0, datetime.timezone.utc\n)\nwith freeze_time(initial_datetime) as frozen_datetime:\n    # start a session\n    start_result = runner.invoke(cli, [\"start\", \"my-project\"])\n    output = \"Started tracking 'my-project' at 10:05AM\"\n    assert output in start_result.output\n\n    frozen_datetime.tick(delta=datetime.timedelta(minutes=30))\n\n    # check status\n    status_result = runner.invoke(cli, [\"status\"])\n    output = \"Tracking 'my-project' for 30m (since 10:05AM)\"\n    assert output in status_result.output\n```\n"
  },
  {
    "path": "python/create-a-dummy-dataframe-in-pandas.md",
    "content": "# Create A Dummy DataFrame In Pandas\n\n[Pandas](https://pandas.pydata.org/pandas-docs/stable/index.html) has all kinds\nof utilities for pulling in and processing tabular data. You can pull in a\nbunch of data from a SQL database into a `DataFrame`. This `DataFrame` object\nis then something you could pass around, process, and read from.\n\nWhen you are sketching out an implementation or writing some tests, it may not\nbe feasible to read data from a DB. Instead, you can create a little dummy\n`DataFrame` using the\n[`from_dict`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.from_dict.html#pandas.DataFrame.from_dict)\nfunction.\n\n\n```python\nimport pd\n\ndata = {'pokemon': ['Charmander', 'Squirtle', 'Bulbasaur'], 'type': ['Fire', 'Water', 'Grass']}\npd.DataFrame.from_dict(data)\n```\n\nThis creates a two column `DataFrame` with a `pokemon` header and a `type`\nheader. The two lists of value will be matched up positionally, so `squirtle`\nwill be paired with `water`.\n"
  },
  {
    "path": "python/create-a-range-of-descending-values.md",
    "content": "# Create A Range Of Descending Values\n\nA typical use of `range` looks something like this:\n\n```python\n>>> list(range(1, 5))\n[1, 2, 3, 4]\n```\n\nWhich is equivalent to this one where we give a `step` value of `1`.\n\n```python\n>>> list(range(1, 5, 1))\n[1, 2, 3, 4]\n```\n\nIf we try to create a _negative range_, that is, a range of values in decreasing\norder, we get an empty list.\n\n```python\n>>> list(range(0, -7))\n[]\n```\n\nThat's because the `step` value still defaults to `1`. And there are no positive\nsteps between `0` and `-7`. So, let's give `range` a `step` value of `-1`.\n\n```python\n>>> list(range(0,-7, -1))\n[0, -1, -2, -3, -4, -5, -6]\n```\n\nOne practical use case of a negative range like this is using a list\ncomprehension to transform it into a list of the _last seven days_.\n\n```python\n>>> from datetime import datetime, timedelta\n>>> [datetime.now().date() + timedelta(days=days) for days in range(0,-7, -1)]\n[datetime.date(2026, 3, 19), datetime.date(2026, 3, 18), datetime.date(2026, 3, 17), datetime.date(2026, 3, 16), datetime.date(2026, 3, 15), datetime.date(2026, 3, 14), datetime.date(2026, 3, 13)]\n```\n\nOf course this could have been written with a positive range and then\nsubtracting the `timedelta`. I like that I have the option of doing this in\nwhatever way makes the code most readable.\n"
  },
  {
    "path": "python/dunder-methods.md",
    "content": "# Dunder Methods\n\nPython has all kinds of special, or rather, _magic_ methods that allow for\ncustomizing all kinds of class behavior. There is `__init__()`, `__bool__()`,\nand so many others.\n\nThe thing they all have in common is that their names are wrapped in _double\nunderscores_. This is why they are called _dunder methods_.\n\nSome of these are used every single day, like the `__init__()` method for\ndefining how a class should create an object. Others, used from time to time,\nare for overriding how comparisons or conversions happen. E.g. you may want to\noverride `__bool__()` or `__len__()` to customize the truthiness of a custom\nclass.\n\nThere are so many others, ones you probably haven't even heard of. To see a\nfull listing, check out this [cheat sheet of every dunder\nmethod](https://www.pythonmorsels.com/every-dunder-method/#cheat-sheet).\n\nNote: these are not to be confused with _dunder attributes_ which are things\nlike `__name__`, `__file__`, and `__version__` which correspond to a value that\nyou can access in a specific context rather than behavior to override.\n"
  },
  {
    "path": "python/easy-key-value-aggregates-with-defaultdict.md",
    "content": "# Easy Key-Value Aggregates With defaultdict\n\nThe `collections` module has the `defaultdict` object that can be used to\naggregate values tied to a key. What sets this apart from simply using a `dict`\nis that we get the base value for free. So if our aggregate value is a list,\nthen we get `[]` by default for each new key. In the same way, we'd get `0` if\nit was constructed with `int`.\n\nHere is the counter example from [Keep A Tally With\ncollections.Counter](keep-a-tally-with-collections-counter.md)\n\n```python\nfrom collections import defaultdict\n\ndef get_pair_counts(token_ids: list[int]) -> Counter:\n    \"\"\"Count how often each adjacent pair appears\"\"\"\n    counts = defaultdict(int)\n    for i in range(len(token_ids) - 1):\n        pair = (token_ids[i], token_ids[i + 1])\n        counts[pair] += 1\n    return counts\n```\n\nWe never have to initially set a key to `0`. If the key is not yet present, then\n`int()` (the zero-value constructor) is used as the `__missing__` value.\n\nWe can do the same with `list`:\n\n```python\n>>> import collections\n>>> stuff = collections.defaultdict(list)\n>>> stuff['alpha'].append(1)\n>>> stuff['alpha']\n[1]\n>>> stuff['beta']\n[]\n```\n\nIn the same way, this uses `list()` as the `__missing__` value to start of each\nkey with an `[]`.\n\nI find this so handy because in other languages I've typically had to do\nsomething more like this:\n\n```python\nwords_by_length = {}\nfor item in items:\n    if len(item) not in words_by_length:\n        words_by_length[len(item)] = []\n    words_by_length[len(item)].append(item)\n```\n\nThis is much clunkier.\n"
  },
  {
    "path": "python/install-with-pip-for-specific-interpreter.md",
    "content": "# Install With PIP For Specific Interpreter\n\nThe `pip` module can be invoked for any of its commands, such as install, using\na specific Python interpreter like so:\n\n```bash\n$ python3 -m pip install black\n```\n\nThis avoid ambiguity between the version of Python I am using and version of the\npackage manager I'm using.\n\nSimilarly if I need to upgrade `pip`, I can do the following:\n\n```bash\n$ python3 -m pip install --upgrade pip\n```\n"
  },
  {
    "path": "python/iterate-first-n-items-from-enumerable.md",
    "content": "# Iterate First N Items From Enumerable\n\nAs I'm working through the 2nd chapter of [Build a Large Language Model (from\nscratch)](https://still.visualmode.dev/blogmarks/227), I came across a code\nexample processing a dictionary of words. This example used a for loop to print\nout each dictionary entry until an index of 50 was reached on then it did a\n`break`.\n\nThis struck me as an odd way to grab and process N items from a list. I did some\nsearching and found `itertools` which provides\n[`islice`](https://docs.python.org/3/library/itertools.html#itertools.islice).\n\n```python\nfrom itertools import islice\n\n# preprocess words from a file into a word list\nall_words = ... # not shown here\n\nvocab = {token: integer for integer, token in enumerate(all_words)}\nfor item in islice(enumerate(vocab.items()), 50):\n    print(item)\n```\n\nThe `islice` function is a better approach because the intention (to grab the\nfirst 50 things) is encoded in the function call rather than buried in a loop\nbody. It also has equivalent memory efficiency to the original example because\nit lazily processes the list of `vocab` items.\n"
  },
  {
    "path": "python/iterate-over-a-dictionary.md",
    "content": "# Iterate Over A Dictionary\n\nLet's say we have a `dict` that contains counts of occurrences for each word in\nsome sample text:\n\n```python\nwords_frequency = {\n    \"the\": 4,\n    \"a\": 3,\n    \"dog\": 1,\n    \"bone\": 1,\n    \"wants\": 1,\n    ...\n}\n```\n\nHere is how we can iterate over the `dict`, accessing both the keys and values:\n\n```python\nfor word, count in word_frequency.items():\n    print(f\"- {word} appears {count} time{'' if count == 1 else 's'}\")\n```\n\nUsing the\n[`items()`](https://docs.python.org/3/library/stdtypes.html#dict.items) method,\nwe're able to access both _key_ and _value_ with the for loop as it iterates.\n\nAnother approach is to loop directly on the `dict` which implicitly surfaces the\n_key_ for iteration. This can then be used to get the value from the `dict`:\n\n```python\nfor word in word_frequency:\n    print(f\"- {word}: {word_frequency[word]}\n```\n"
  },
  {
    "path": "python/keep-a-tally-with-collections-counter.md",
    "content": "# Keep A Tally With collections.Counter\n\nPython's `collections` module comes with a\n[`Counter`](https://docs.python.org/3/library/collections.html#collections.Counter)\nobject which is a specialized dict subclass focussed on tallying counts of keys.\n\n> It is a collection where elements are stored as dictionary keys and their\n> counts are stored as dictionary values. Counts are allowed to be any integer\n> value including zero or negative counts.\n\nI used it recently while doing an exploratory implementation of a Byte-Pair\nEncoding (BPE):\n\n```python\nfrom collections import Counter\n\ndef get_pair_counts(token_ids: list[int]) -> Counter:\n    \"\"\"Count how often each adjacent pair appears\"\"\"\n    counts = Counter()\n    for i in range(len(token_ids) - 1):\n        pair = (token_ids[i], token_ids[i + 1])\n        counts[pair] += 1\n    return counts\n```\n\nHere I'm able to count the number of occurrences of each pair of bytes from the\ninput text. A tuple of `int` values is hashable, so they work great as keys for\na `Counter`.\n\nThe count value of any key will default to `0`. That makes it straightforward to\nincrement from there as you iterating over occurrences.\n\n```python\n>>> counts = Counter()\n>>> counts['hello']\n0\n>>> count['hello'] += 1\n>>> count['hello']\n1\n```\n"
  },
  {
    "path": "python/load-a-file-into-the-python-repl.md",
    "content": "# Load A File Into The Python REPL\n\nI opened up a Python REPL to try some things out.\n\n```\n$ python3\n>>> import math\n>>> math.floor(5/2)\n2\n```\n\nNow, I want to reference a Python file I've been working on so that I can\nmanually test the behavior of what I'm building. To do this, I can import a file\nby its name in the same way that I would import any module. Then I can use that\nnamespace for class and method references. Crucially, the file should exist in\nthe same directory the REPL was started from.\n\nFirst, here is the file:\n\n```python\n# bpe.py\nclass BytePairEncoding:\n    def text_to_bytes(text: str) -> list[int]:\n        \"\"\"Convert a string to a list of byte values (0-255)\"\"\"\n        return list(text.encode(\"utf-8\"))\n```\n\nNow to use it from the REPL:\n\n```\n$ python\n>>> import bpe\n>>> bpe.BytePairEncoding.text_to_bytes(\"Gimme some bytes!\")\n[71, 105, 109, 109, 101, 32, 115, 111, 109, 101, 32, 98, 121, 116, 101, 115, 33]\n```\n"
  },
  {
    "path": "python/look-inside-pytest-tmp-path.md",
    "content": "# Look Inside Pytest tmp_path\n\nIn [Isolate and Debug File Side-Effects with Pytest\n`tmp_path`](https://www.visualmode.dev/isolate-and-debug-file-side-effects-with-pytest-tmp-path),\nI wrote about how I use\n[`tmp_path`](https://docs.pytest.org/en/stable/reference/reference.html#std-fixture-tmp_path)\nin a Pytest fixture to test [my `py-vmt` CLI](https://github.com/jbranchaud/py-vmt). During testing of the CLI interface\nvia [`click`'s testing utilities](https://click.palletsprojects.com/en/stable/testing/), `vmt` creates,\nmodifies, and reads from files. Isolating that behavior with the `tmp_path`\nfixture is useful because it prevents individual test cases from conflicting\nwith one another.\n\nHere is what the fixture looks like at the top of my test file:\n\n```python\n# auto fixture for all test cases that monkeypatches the platform dirs to a tmp\n# path so that test side-effects don't persist between runs\n@pytest.fixture(autouse=True)\ndef use_tmp_platform_dirs(tmp_path, monkeypatch):\n    data_dir = tmp_path / \"data\"\n    config_dir = tmp_path / \"config\"\n    data_dir.mkdir()\n    config_dir.mkdir()\n    monkeypatch.setattr(CliContext, \"get_data_dir\", staticmethod(lambda: data_dir))\n    monkeypatch.setattr(CliContext, \"get_config_dir\", staticmethod(lambda: config_dir))\n```\n\nThe root of the temp directory is located at `tempfile.gettempdir()` and the\ndirectories from there are organized with this structure:\n\n```\n{temproot}/pytest-of-{user}/pytest-{num}/{testname}/\n```\n\nSo, in the case of `vmt`, I can find the `config` and `data` dirs for a specific\ntest run here:\n\n```bash\n❯ ls /var/folders/zc/q6gnvbgx6kq77828jn38716r0000gn/T/pytest-of-lastword/pytest-2/test_start_status_stop_flow0\nconfig data\n```\n"
  },
  {
    "path": "python/override-the-boolean-context-of-a-class.md",
    "content": "# Override The Boolean Context Of A Class\n\nEverything in Python has a truthiness that can be checked with `bool()`. An\nempty list (`[]`) is falsy. A non-empty list (`[1,2,3]`) is truthy. Similar\nwith numbers:\n\n```python\n>>> bool(0)\nFalse\n>>> bool(1)\nTrue\n```\n\nAny instance of an object is going to be truthy by default. If you want to\ncontrol in what context an instance is considered truthy or falsy, you can\noverride\n[`__bool__()`](https://docs.python.org/3/reference/datamodel.html#object.__bool__).\nIf that's not implemented, but\n[`__len__()`](https://docs.python.org/3/reference/datamodel.html#object.__len__)\nis, then it will fallback to that.\n\nLet's look at a few example classes:\n\n```python\nclass CartZero:\n    def __init__(self, items=[]):\n        self.items = items or []\n\nclass CartBool:\n    def __init__(self, items=[]):\n        self.items = items or []\n\n    def __bool__(self):\n        print(\"__bool__() override\")\n        return bool(self.items)\n\nclass CartLen:\n    def __init__(self, items=[]):\n        self.items = items or []\n\n    def __len__(self):\n        print(\"__len__() override\")\n        return len(self.items)\n\nclass CartBoolAndLen:\n    def __init__(self, items=[]):\n        self.items = items or []\n\n    def __len__(self):\n        print(\"__len__() override\")\n        return len(self.items)\n\n    def __bool__(self):\n        print(\"__bool__() override\")\n        return bool(self.items)\n\ncart1 = CartZero()\ncart2 = CartBool()\ncart3 = CartLen()\ncart4 = CartBoolAndLen()\n\nprint(\"CartZero() -> %s\" %(bool(cart1)))\nprint('')\nprint(\"CartBool() -> %s\" %(bool(cart2)))\nprint('')\nprint(\"CartLen() -> %s\" %(bool(cart3)))\nprint('')\nprint(\"CartBoolAndLen() -> %s\" %(bool(cart4)))\n```\n\nAn 'empty' `Cart` be default is truthy. However, we can override some\ncombination of `__bool__()` or `__len__()` to give it a boolean context that\ngoes `false` when \"empty\".\n\n```\nCartZero() -> True\n\n__bool__() override\nCartBool() -> False\n\n__len__() override\nCartLen() -> False\n\n__bool__() override\nCartBoolAndLen() -> False\n```\n"
  },
  {
    "path": "python/parse-relative-time-to-datetime-object.md",
    "content": "# Parse Relative Time To datetime Object\n\nI was looking for an out-of-the-box solution for parsing natural language,\nrelative time strings (e.g. `'33 minutes ago'`) into valid `datetime` objects.\nThe best library for this is\n[`dateparser`](https://dateparser.readthedocs.io/en/latest/).\n\nWhile it is as easy to use this as _import_ then _parse_:\n\n```python\n>>> import dateparser\n>>> dateparser.parse('33 minutes ago')\ndatetime.datetime(2026, 3, 7, 23, 19, 9, 17855)\n```\n\nThere is more to it if we need to deal with timezones.\n\nIn my use case, I wanted to my `datetime` object to be timezone-aware and I\nwanted to store it in `UTC`.\n\nAs is, the above simple `datetime` object is not `tzaware`, meaning it doesn't\nhave any `tzinfo` attached to it.\n\n```python\n>>> dateparser.parse('33 minutes ago').tzinfo is not None\nFalse\n```\n\nWe need to pass some additional settings during `parse`.\n\n```python\n>>> settings = {'RETURN_AS_TIMEZONE_AWARE': True}\n>>> dateparser.parse('33 minutes ago', settings=settings)\n>>> _\ndatetime.datetime(2026, 3, 8, 9, 53, 36, 225099, tzinfo=zoneinfo.ZoneInfo(key='America/Chicago'))\n>>> settings['TO_TIMEZONE'] = 'UTC'\n>>> dateparser.parse('33 minutes ago', settings=settings)\n>>> _\ndatetime.datetime(2026, 3, 8, 14, 54, 47, 34041, tzinfo=<StaticTzInfo 'UTC'>)\n```\n\nThe first step to getting a `datetime` object that is `tzaware` is to set\n`RETURN_AS_TIMEZONE_AWARE` to `True`. That picks up the locale setting of the\nsystem it is running on -- in my case, I'm in Chicago.\n\nI said I wanted to store this as UTC though. That means I need to pass an\nadditional setting `TO_TIMEZONE` with a value of `'UTC'` which will translate\nthe `datetime` from my local time to UTC -- notice the 5 hour difference from\n`9` to `14`.\n\nStoring `datetime` details like this with timezone info _as_ UTC is nice because\nit keeps everything consistent at the storage layer and then at the presentation\nlayer I can always convert it right back to the local timezone with\n`astimezone`.\n\n```python\n>>> _.astimezone()\ndatetime.datetime(2026, 3, 8, 9, 54, 47, 34041, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=68400), 'CDT'))\n```\n\nSee the [`datetime` docs](https://docs.python.org/3/library/datetime.html) for\nmore details.\n"
  },
  {
    "path": "python/store-and-access-immutable-data-in-a-tuple.md",
    "content": "# Store And Access Immutable Data In A Tuple\n\nYou can store heterogeneous data (of varying types) as a _tuple_ which is a\nlight-weight immutable data structure.\n\nYou can be explicit about the tuple by wrapping the items in parentheses:\n\n```python\n>>> book = ('An Immense World', 'Ed Yong', 2022)\n```\n\nThough it is also possible to comma-separate the items and forego the\nparentheses.\n\n```python\n>>> book2 = 'The Shining', 'Stephen King', 1977\n>>> book2\n('The Shining', 'Stephen King', 1977)\n```\n\nOnce we have our tuple, we can access any item from it positionally. We can\nalso use _sequence unpacking_ to assign the values to a series of variables:\n\n```python\n>>> book[0]\n'An Immense World'\n>>> book[1]\n'Ed Yong'\n>>> book[2]\n2022\n>>> title, author, publication_year = book\n>>> title\n'An Immense World'\n>>> author\n'Ed Yong'\n>>> publication_year\n2022\n```\n\nAnd, as promised, it is immutable (unlike lists):\n\n```python\n>>> book[1] = 'Agatha Christie'\nTraceback (most recent call last):\n  File \"<stdin>\", line 1, in <module>\nTypeError: 'tuple' object does not support item assignment\n```\n\n[source](https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences)\n"
  },
  {
    "path": "python/test-a-function-with-pytest.md",
    "content": "# Test A Function With Pytest\n\nThe [`pytest` framework](https://docs.pytest.org/en/latest/index.html) is a\nsolid choice for unit testing your python project.\n\nAny file whose name is preceeded with `test_` that contains functions whose\nnames are preceeded with `test_` will be processed and executed by the pytest\ntest runner.\n\n```python\n# test_taco.py\n\ndef taco(day):\n  return \"Taco \" + day\n\ndef test_taco_tuesday():\n  assert taco(\"Tuesday\") == \"Taco Tuesday\" # passes\n\ndef test_taco_blank():\n  assert taco(\"\") == \"Taco\" # fails, missing trailing space\n```\n\nUse `assert` statements to check that a comparison is `true`. If it isn't the\n`assert` statement will result in a test failure with some output about what\nwent wrong.\n\nEnsure you have `pytest` installed and then run the following from your project\ndirectory:\n\n```bash\n$ pytest\n#=> ... you'll see the test output below\n```\n"
  },
  {
    "path": "python/use-pipx-to-install-end-user-apps.md",
    "content": "# Use pipx To Install End User Apps\n\nThe [`pipx`](https://pipx.pypa.io/stable/) tool is an installer for the python\necosystem. It differs from `pip` in that it is for installing end-user\napplications and it does so in isolated environments.\n\nYou can install `pipx` with an OS-specific installer like Homebrew:\n\n```bash\n$ brew install pipx\n```\n\nEnsure `pipx`-installed apps are on your path:\n\n```bash\n$ pipx ensurepath\n```\n\nThen use `pipx` to install programs like\n[`cowsay`](https://pypi.org/project/cowsay/) or\n[`llm`](https://llm.datasette.io/en/stable/setup.html):\n\n```bash\n$ pipx install llm\n\n$ which llm\n/Users/jbranchaud/.local/bin/llm\n\n$ llm --version\nllm, version 0.13.1\n```\n"
  },
  {
    "path": "python/use-verbose-flag-to-get-more-diff.md",
    "content": "# Use Verbose Flag To Get More Diff\n\nHere is the output of running some `pytest` unit tests. A couple of the tests\npass, which produces little output. But I get a big block of details for the one\nfailing test. In this case the failure is an assertion between two lists that\ndon't match.\n\n```bash\n❯ uv run pytest\n========================================== test session starts ==========================================\nplatform darwin -- Python 3.12.12, pytest-9.0.2, pluggy-1.6.0\nrootdir: /Users/lastword/dev/misc/build-an-llm\nconfigfile: pyproject.toml\ncollected 3 items\n\ntests/chapter_02/test_bpe_tokenizer.py .F.                                                        [100%]\n\n=============================================== FAILURES ================================================\n_____________________________________ test_merge_with_byte_sequence _____________________________________\n\n    def test_merge_with_byte_sequence():\n        token_ids = [1, 2, 3, 4, 5, 2, 3, 1, 2, 3, 4, 1]\n        merged_tokens = BPETokenizer._merge(token_ids, [2, 3, 4], 256)\n        # assert merged_tokens == [1, 256, 5, 2, 3, 1, 256, 1]\n>       assert merged_tokens == [1, 256, 5, 4, 5, 1, 256, 1]\nE       assert [1, 256, 5, 2, 3, 1, ...] == [1, 256, 5, 4, 5, 1, ...]\nE\nE         At index 3 diff: 2 != 4\nE         Use -v to get more diff\n\ntests/chapter_02/test_bpe_tokenizer.py:13: AssertionError\n======================================== short test summary info ========================================\nFAILED tests/chapter_02/test_bpe_tokenizer.py::test_merge_with_byte_sequence - assert [1, 256, 5, 2, 3, 1, ...] == [1, 256, 5, 4, 5, 1, ...]\n====================================== 1 failed, 2 passed in 0.02s ======================================\n```\n\nThe lists are too long to fully display in the failure output. `pytest` is able\nto tell us two useful things though. First, it mentions that the first\ndiscrepancy in the lists is at index `3` where `2 != 4`. Second, it says `Use -v\nto get more diff`.\n\nLet's try rerunning the tests with `-v`.\n\n```bash\n❯ uv run pytest -v\n========================================== test session starts ==========================================\nplatform darwin -- Python 3.12.12, pytest-9.0.2, pluggy-1.6.0 -- /Users/lastword/dev/misc/build-an-llm/.venv/bin/python3\ncachedir: .pytest_cache\nrootdir: /Users/lastword/dev/misc/build-an-llm\nconfigfile: pyproject.toml\ncollected 3 items\n\ntests/chapter_02/test_bpe_tokenizer.py::test_merge_with_byte_pair PASSED                          [ 33%]\ntests/chapter_02/test_bpe_tokenizer.py::test_merge_with_byte_sequence FAILED                      [ 66%]\ntests/chapter_02/test_bpe_tokenizer.py::test_subsequence_at_index PASSED                          [100%]\n\n=============================================== FAILURES ================================================\n_____________________________________ test_merge_with_byte_sequence _____________________________________\n\n    def test_merge_with_byte_sequence():\n        token_ids = [1, 2, 3, 4, 5, 2, 3, 1, 2, 3, 4, 1]\n        merged_tokens = BPETokenizer._merge(token_ids, [2, 3, 4], 256)\n        # assert merged_tokens == [1, 256, 5, 2, 3, 1, 256, 1]\n>       assert merged_tokens == [1, 256, 5, 4, 5, 1, 256, 1]\nE       AssertionError: assert [1, 256, 5, 2, 3, 1, ...] == [1, 256, 5, 4, 5, 1, ...]\nE\nE         At index 3 diff: 2 != 4\nE\nE         Full diff:\nE           [\nE               1,\nE               256,...\nE\nE         ...Full output truncated (13 lines hidden), use '-vv' to show\n\ntests/chapter_02/test_bpe_tokenizer.py:13: AssertionError\n======================================== short test summary info ========================================\nFAILED tests/chapter_02/test_bpe_tokenizer.py::test_merge_with_byte_sequence - AssertionError: assert [1, 256, 5, 2, 3, 1, ...] == [1, 256, 5, 4, 5, 1, ...]\n====================================== 1 failed, 2 passed in 0.02s ======================================\n```\n\nThat was sort of a tease because it starts to display a \"Full diff\", but that\ngets quickly truncated. `pytest` then tells us that we can `use '-vv' to show`\nthe full diff.\n\n```bash\n❯ uv run pytest -vv\n========================================== test session starts ==========================================\nplatform darwin -- Python 3.12.12, pytest-9.0.2, pluggy-1.6.0 -- /Users/lastword/dev/misc/build-an-llm/.venv/bin/python3\ncachedir: .pytest_cache\nrootdir: /Users/lastword/dev/misc/build-an-llm\nconfigfile: pyproject.toml\ncollected 3 items\n\ntests/chapter_02/test_bpe_tokenizer.py::test_merge_with_byte_pair PASSED                          [ 33%]\ntests/chapter_02/test_bpe_tokenizer.py::test_merge_with_byte_sequence FAILED                      [ 66%]\ntests/chapter_02/test_bpe_tokenizer.py::test_subsequence_at_index PASSED                          [100%]\n\n=============================================== FAILURES ================================================\n_____________________________________ test_merge_with_byte_sequence _____________________________________\n\n    def test_merge_with_byte_sequence():\n        token_ids = [1, 2, 3, 4, 5, 2, 3, 1, 2, 3, 4, 1]\n        merged_tokens = BPETokenizer._merge(token_ids, [2, 3, 4], 256)\n        # assert merged_tokens == [1, 256, 5, 2, 3, 1, 256, 1]\n>       assert merged_tokens == [1, 256, 5, 4, 5, 1, 256, 1]\nE       assert [1, 256, 5, 2, 3, 1, 256, 1] == [1, 256, 5, 4, 5, 1, 256, 1]\nE\nE         At index 3 diff: 2 != 4\nE\nE         Full diff:\nE           [\nE               1,\nE               256,\nE               5,\nE         -     4,\nE         ?     ^\nE         +     2,\nE         ?     ^\nE         -     5,\nE         ?     ^\nE         +     3,\nE         ?     ^\nE               1,\nE               256,\nE               1,\nE           ]\n\ntests/chapter_02/test_bpe_tokenizer.py:13: AssertionError\n======================================== short test summary info ========================================\nFAILED tests/chapter_02/test_bpe_tokenizer.py::test_merge_with_byte_sequence - assert [1, 256, 5, 2, 3, 1, 256, 1] == [1, 256, 5, 4, 5, 1, 256, 1]\n\n  At index 3 diff: 2 != 4\n\n  Full diff:\n    [\n        1,\n        256,\n        5,\n  -     4,\n  ?     ^\n  +     2,\n  ?     ^\n  -     5,\n  ?     ^\n  +     3,\n  ?     ^\n        1,\n        256,\n        1,\n    ]\n====================================== 1 failed, 2 passed in 0.02s ======================================\n```\n\nThis is a lot more output to look at. What we can perhaps see more clearly now\nis that the lists match up until there is a mismatch between `2` and `4` at the\nthird index. And then right after that is another mismatch between `3` and `5`.\n\nThis kind of output can only scale so much, so use it when it works and when the\ndiff view starts to fall short, rework the assertions to get more readable and\nactionable test output.\n"
  },
  {
    "path": "rails/access-secrets-in-a-rails-5-2-app.md",
    "content": "# Access Secrets In A Rails 5.2 App\n\nFor a long time the access chain for getting at secrets in your Rails app\nstayed the same. For instance, getting at the `secret_key_base` value looked\nsomething like this:\n\n```ruby\nRails.application.secrets.secret_key_base\n```\n\nIn the world of Rails 5.2, secrets are no longer secrets. They are now\ncredentials. This means they are under the `credentials` key instead of the\n`secrets` key. Here is how you can access `secret_key_base` now:\n\n```ruby\nRails.application.credentials.secret_key_base\n```\n\n[source](https://www.engineyard.com/blog/rails-encrypted-credentials-on-rails-5.2)\n"
  },
  {
    "path": "rails/active-record-query-for-this-or-that.md",
    "content": "# ActiveRecord Query For This Or That\n\nWhen including multiple `where` clauses on a query, we are adding more\nspecificity to the resulting `ActiveRecord` relation -- it's like saying we\nwant records that match this _and_ that. But what about when we want to find\nrecords that match this _or_ that?\n\nThis is supported by `ActiveRecord` through the `or` query method.\n\nLet's say we want all books that are either unpublished _or_ are published in\n2019.\n\n```ruby\n> Book.where(status: 'unpublished').or(Book.where(publication_year: 2019))\n=> #<ActiveRecord::Relation [...]>\n```\n\nThis will generate SQL that includes a `where` clause like the following:\n\n```sql\nwhere (books.status = 'unpublished' or books.publication_year = 2019)\n```\n\nSee the\n[docs](https://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-or)\nfor more details.\n"
  },
  {
    "path": "rails/add-a-check-constraint-to-a-table.md",
    "content": "# Add A Check Constraint To A Table\n\nPostgreSQL allows you to enforce all kinds of rules about the value of a column\nor the relationship between two columns. These rules are defined with [_check\nconstraints_](https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-CHECK-CONSTRAINTS).\nActiveRecord's migration DSL does not provide a way for adding check\nconstraints directly. They can be added by executing a SQL statement in a\nmigration.\n\n```ruby\nclass EnsurePageCountIsPositive < ActiveRecord::Migration[5.2]\n  def up\n    execute <<-SQL\n      alter table books\n        add constraint ensure_page_count_is_positive\n        check (page_count > 0);\n    SQL\n  end\n\n  def down\n    execute <<-SQL\n      alter table books\n        drop constraint ensure_page_count_is_positive;\n    SQL\n  end\n```\n\nThis check constraint ensures that, anytime you add or update a row in the book\ncolumn, the value of `page_count` column is always greater than `0`. This is a\nnice thing to enforce because it wouldn't make much sense for a book to have,\nsay, `-10` pages.\n\nNote: these constraints will not appear in your `db/schema.rb` file. If you\nwant to see what check constraints have been defined across your tables, you\ncan crack open `psql` to investigate.\n"
  },
  {
    "path": "rails/add-a-database-index-if-it-does-not-already-exist.md",
    "content": "# Add A Database Index If It Does Not Already Exist\n\nSometimes you aren't sure if an index might already exist in one of the\nenvironments where a migration is going to run. But you still need to add the\nindex elsewhere. One way of handling that is to add an index with the\n`if_not_exists` directive.\n\n```ruby\nclass AddIndexToEventsCreatedAt < ActiveRecord::Migration[6.1]\n  def change\n    add_index :events, :created_at, if_not_exists: true\n  end\nend\n```\n\n`ActiveRecord` will translate this directive into the resulting SQL statement\nlike so:\n\n```sql\ncreate index if not exists index_events_on_created_at on events ... ;\n```\n\nThis way the index will be created in a database where it doesn't already exist\nand otherwise the statement will short-circuit rather than erroring when one\ndoes exist.\n\nA couple notes:\n\n1) From the PostgreSQL manual:\n\n> there is no guarantee that the existing index is anything like the one that\n> would have been created.\n\n2) The `if_not_exists` option also works with `create_table`.\n\n[source](https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html)\n"
  },
  {
    "path": "rails/add-a-foreign-key-reference-to-a-table.md",
    "content": "# Add A Foreign Key Reference To A Table\n\nForeign keys are a great way to maintain referential integrity within our data.\nWe can add reference columns with foreign key constraints using the Rails\nmigration DSL.\n\nHere is how we include one as part of creating a table:\n\n```ruby\ndef up\n  create_table :books do |t|\n    # ... other columns\n\n    t.references :author, index: true, foreign_key: true\n  end\nend\n```\n\nThis will add a column, `author_id`, to the `books` table that references the\n`authors` table. It will have both a foreign key constraint and an index\napplied to it.\n\nHere is how we do the same for an existing table:\n\n```ruby\ndef up\n  add_reference :books, :author, index: true, foreign_key: true\nend\n```\n\nAs of Rails 5, this is a bit verbose as `index: true` happens by default.\nThough I'm always in favor of explicitness. If for whatever reason you don't\nwant an index, you will have to specify `index: false`.\n"
  },
  {
    "path": "rails/add-a-generated-column-to-a-postgresql-table.md",
    "content": "# Add A Generated Column To A PostgreSQL Table\n\nAs of Rails 7, ActiveRecord supports generated columns for app's backed by a\nPostgreSQL database. This is achieved with a `virtual` column.\n\n```ruby\nclass CreateTags < ActiveRecord::Migration[8.0]\n  def change\n    create_table :tags, id: :bigint do |t|\n      t.string :value\n      t.virtual :normalized_value, type: :text, as: \"lower(value)\", stored: true\n\n      t.timestamps\n    end\n  end\nend\n```\n\nWith a table like this, any time we add a record with a `value`, PostgreSQL\ncomputes and stores the `normalized_value` column based on that.\n\n[source](https://blog.saeloun.com/2022/01/25/rails-7-postgres-support-for-generated-columns/)\n"
  },
  {
    "path": "rails/add-a-reference-column-with-an-index.md",
    "content": "# Add A Reference Column With An Index\n\nThough I prefer to always back my reference columns with a [foreign\nkey](add-a-foreign-key-reference-to-a-table.md), sometimes you may just want to\nadd the reference column on its own. Though this could be done manually with\nthe `add_column` directive, you can be more explicit with `add_reference` --\nwhich allows you to specify whether or not an index is to be added.\n\n```ruby\ndef up\n  add_reference :books, :author, index: true\nend\n```\n\nThis will add `authors_id` and an index to the `books` table.\n\nYou can additionally specify the type of the column. This is handy if you are\nusing `uuid`s for all your primary keys.\n\n```ruby\ndef up\n  add_reference :books, :author, type: :uuid, index: true\nend\n```\n\n[source](https://nandovieira.com/using-uuid-with-postgresql-and-activerecord)\n"
  },
  {
    "path": "rails/add-activerecord-error-not-tied-to-any-attribute.md",
    "content": "# Add ActiveRecord Error Not Tied To Any Attribute\n\nOften the [errors on an ActiveRecord\nobject](https://api.rubyonrails.org/v6.1.3.2/classes/ActiveModel/Errors.html)\nare tied to a specific attribute of that object. For instance, when this\nvalidation is violated\n\n```ruby\nvalidates :name, presence: true\n```\n\nThen the error will be tied to `:name`.\n\nWith the\n[`ActiveModel::Errors#add`](https://api.rubyonrails.org/v6.1.3.2/classes/ActiveModel/Errors.html#method-i-add)\nmethod, we can write custom validation logic that ties an error to a specific\nattribute.\n\n```ruby\nvalidate :quantity_for_bulk_purchase\n\ndef quantity_for_bulk_purchase\n  return if purchase_type != :bulk\n\n  if quantity < 12\n    errors.add(:quantity, \"must be greater than 12 for bulk purchases\")\n  end\nend\n```\n\nErrors don't have to be tied to specific attribute. They can be tied to the\nobject as a whole. This can be better for validations, like the one above, that\ninvolve multiple attributes.\n\n```ruby\nvalidate :quantity_for_bulk_purchase\n\ndef quantity_for_bulk_purchase\n  return if purchase_type != :bulk\n\n  if quantity < 12\n    errors.add(:base, \"Quantity must be greater than 12 for bulk purchases\")\n  end\nend\n```\n\nBy using the `:base` symbol, we are ascribing this error to the object as a\nwhole.\n\n```\n> my_object.errors\n#=> #<ActiveModel::Errors:0x00007fccaa5a8740\n @base=\n  #<MyObject:0x00007fcc8a5e9238\n    ...\n    @details={:base=>[{:error=>\"Quantity must be greater than 12 for bulk purchases\"}]},\n    @messages={:base=>[\"Quantity must be greater than 12 for bulk purchases\"]}>\n\n> my_object.errors.full_messages\n#=> [\"Quantity must be greater than 12 for bulk purchases\"]\n```\n"
  },
  {
    "path": "rails/add-color-to-the-irb-console-prompt.md",
    "content": "# Add Color To The IRB Console Prompt\n\nIRB has a little-known [`Color`\nmodule](https://docs.ruby-lang.org/en/3.2/IRB/Color.html) with some helpers for\nadding a splash of color to the IRB prompt. I like to clearly differentiate the\nenvironment I'm in when connecting to the `rails console`, so I have a\ncustomize the prompt to display and colorize the current environment.\n\nI can wrap any string in ANSI escape codes that instruct the terminal to style\nthe text with color. For instance, here is how I can style the word `DEV` to be\ninverted against a blue background.\n\n```ruby\nIRB::Color.colorize(\"DEV\", [:BLUE, :BOLD, :REVERSE])\n```\n\nwhich will clearly stand out from `PROD` against a red background:\n\n```ruby\nIRB::Color.colorize(\"PROD\", [:RED, :BOLD, :REVERSE])\n```\n\nHere is a full example of customizing the prompt from the\n`config/application.rb` file.\n\n```ruby\nmodule MyApp \n  class Application < Rails::Application\n    # ...\n\n    console do\n      # Get the application module name and convert to kebab-case\n      app_name = Rails.application.class.module_parent.name\n      kebab_name = app_name.underscore.dasherize\n\n      # Environment color coding\n      env_colors = {\n        \"development\" => IRB::Color.colorize(\"DEV\", [:BLUE, :BOLD, :REVERSE]),\n        \"production\" => IRB::Color.colorize(\"PROD\", [:RED, :BOLD, :REVERSE]),\n        \"test\" => IRB::Color.colorize(\"TEST\", [:YELLOW, :BOLD, :REVERSE]),\n      }\n\n      colored_env = \"(#{env_colors[Rails.env]})\"\n\n      # Docs: https://docs.ruby-lang.org/en/3.2/IRB.html#module-IRB-label-Customizing+the+IRB+Prompt\n      IRB.conf[:PROMPT][:RAILS_APP] = {\n        PROMPT_I: \"#{kebab_name}#{colored_env}> \",\n        PROMPT_N: \"#{kebab_name}#{colored_env}* \",\n        PROMPT_S: \"#{kebab_name}#{colored_env}% \",\n        PROMPT_C: \"#{kebab_name}#{colored_env}? \",\n        RETURN: \"=> %s\\n\"\n      }\n\n      # Set it as the current prompt\n      IRB.conf[:PROMPT_MODE] = :RAILS_APP\n    end\n  end\nend\n```\n\nThe Ruby docs have more about [IRB Prompt\nCustomization](https://docs.ruby-lang.org/en/3.2/IRB.html#module-IRB-label-Customizing+the+IRB+Prompt).\n"
  },
  {
    "path": "rails/add-react-with-webpacker-to-a-new-rails-app.md",
    "content": "# Add React With Webpacker To A New Rails App\n\n[Webpacker](https://github.com/rails/webpacker) makes it easy to manage\napp-like JavaScript in the context of a Rails app. React is a great\ncandidate for this kind of webpack-powered JavaScript processing pipeline.\n\nTo set up a new Rails project with Webpack and React wired up, add the\n`--webpack=react` flag:\n\n```bash\n$ rails new rails-react-app --webpack=react\n```\n\nAs part of the generated app, you will get a `app/javascript/packs`\ndirectory with a `hello_react.jsx` file that has a really basic React\ncomponent.\n\n[source](https://github.com/rails/webpacker#react)\n"
  },
  {
    "path": "rails/add-timestamptz-columns-with-the-migration-dsl.md",
    "content": "# Add timestamptz Columns With The Migration DSL\n\nThe Rails migration DSL comes with the\n[`t.timestamps`](https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html#method-i-timestamps)\nmethod. This allows you to add the `created_at` and `updated_at` timestamp\ncolumns that are standard for most models in Rails apps.\n\n```ruby\ncreate_table :posts do |t|\n  t.string :title, null: false\n  # ...\n\n  t.timestamps\nend\n```\n\nWith a PostgreSQL database, this will result in a `posts` table that has\n`created_at` and `updated_at` columns that are of type `timestamp(6) without\ntime zone`.\n\nI'd prefer to use timestamp columns that include a time zone offset. PostgreSQL\nsupports this with its [`timestamptz` (`timestamp with time\nzone`)](https://www.postgresql.org/docs/current/datatype-datetime.html) data\ntype.\n\nWe can tell the Rails DSL to generate this type of column by abondoning the\n`t.timestamps` method and instead creating custom columns with\n[`t.column`](https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html#method-i-column).\n\n```ruby\ncreate_table :posts do |t|\n  t.string :title, null: false\n  # ...\n\n  t.column :created_at, :timestamptz, null: false\n  t.column :updated_at, :timestamptz, null: false\nend\n```\n\nIt is a little less convenient than the `t.timestamps` helper, but it is nice\nto know we can have a little more control over the data type.\n"
  },
  {
    "path": "rails/adjust-the-production-log-level.md",
    "content": "# Adjust The Production Log Level\n\nA Rails app by default takes on the `debug` log level. This is great for\ndevelopment because it spits out a lot of information as you build and debug.\n\nThat's going to typically be a bit too noisy for a production environment\nthough. That is why Rails ships with the `config/environments/production.rb`\nfile configured to the `info` log level.\n\n```ruby\n# config/environments/production.rb\nRails.application.configure do\n\n  # ...\n\n  # \"info\" includes generic and useful information about system operation, but avoids logging too much\n  # information to avoid inadvertent exposure of personally identifiable information (PII). If you\n  # want to log everything, set the level to \"debug\".\n  config.log_level = ENV.fetch(\"RAILS_LOG_LEVEL\", \"info\")\n\n  # ...\nend\n```\n\nSometimes, like when we're trying to track down some buggy behavior, we may\nwant to switch Rails from one log level to another. That's why it is configured\nby the `RAILS_LOG_LEVEL` env var and otherwise falls back to `info`.\n\nTo, for example, switch production over to the `debug` log level, we'd first\nchange the `RAILS_LOG_LEVEL` env var to `debug`. Then we'd need to make sure\nour Rails app is restarted so that the config change is picked up. Heroku's\n`heroku config:set` will do that automatically. Depending on your setup, you\nmay need to manually restart your web server (e.g. Puma).\n"
  },
  {
    "path": "rails/advance-the-date.md",
    "content": "# Advance The Date\n\nIn Rails land, you can advance a date forward and backward with the\n`#advance` method:\n\n```ruby\n> Date.today\n=> Wed, 31 Aug 2016\n> Date.today.advance(days: 1)\n=> Thu, 01 Sep 2016\n> Date.today.advance(months: 1)\n=> Fri, 30 Sep 2016\n> Date.today.advance(months: -2)\n=> Thu, 30 Jun 2016\n```\n\nh/t Dillon Hafer\n"
  },
  {
    "path": "rails/all-or-nothing-database-transactions.md",
    "content": "# All or Nothing Database Transactions\n\nWhen you are updating multiple records in an *all or nothing* scenario, you\ncan use [Active Record\nTransactions](http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html)\nto ensure that either everything is updated or none of it is updated.\n\nFor instance, if you are transferring *internet points* from one user's\naccount to another user's account, you need to be sure that the transfer\nbalances out. If updating one user is successful, but updating the other\nfails, then there will be a discrepancy in the data. A transaction will\nensure that when any part of the update fails the entire transaction is\nrolled back (at the database level).\n\n```ruby\nUser.transaction do\n  user1.internet_points += 20\n  user2.internet_points -= 20\n  user1.save!\n  user2.save!\nend\n```\n"
  },
  {
    "path": "rails/allow-associations-to-be-optional.md",
    "content": "# Allow Associations To Be Optional\n\nAs of Rails 5, whenever a `belongs_to` association is declared in an\n`ActiveRecord` model, it is assumed to be a required association.\n\n```ruby\nclass Book < ApplicationRecord\n  belongs_to :author\nend\n```\n\nIf we were to create a `Book` instance without an `Author`, then we would get\nan error – `Validation Failed: Author is missing`.\n\nWe could either make sure to always create books with authors or, if it makes\nsense for our data model, we could treat the author as optional.\n\nThe most explicit and precise way to make a relation optional is to declare it\nas such in the `belongs_to` directive.\n\n```ruby\nclass Book < ApplicationRecord\n  belongs_to :author, optional: true\nend\n```\n\nAnother approach, though I don't recommend it unless you have a strong reason,\nis to globally make associations optional. You can do this by adding the\nfollowing line to your `config/application.rb` file.\n\n```ruby\nconfig.active_record.belongs_to_required_by_default = false\n```\n\n[source](https://www.bigbinary.com/blog/rails-5-makes-belong-to-association-required-by-default)\n"
  },
  {
    "path": "rails/allow-list-params-anywhere-with-strong-params.md",
    "content": "# Allow List Params Anywhere With Strong Params\n\nThe intended use of\n[`StrongParams`](https://api.rubyonrails.org/classes/ActionController/StrongParameters.html)\nis to prevent unintended params from getting through a controller action during\nmass assignment.\n\nThis can be put to use other places in your Rails app, such as a service\nobject, where mass assignment is used to update records.\n\n```ruby\nclass BookTitleUpdater\n  ALLOW_LIST = [:title].freeze\n\n  def self.run(data)\n    params = ActionController::Parameters.new(data).permit(*ALLOW_LIST)\n\n    Book.find(data[:id]).update!(params)\n  end\nend\n```\n\nThis helps prevent other values from getting inadvertently updated on the `book` record.\n\n```ruby\n> ALLOW_LIST = [:title]\n> data = { title: \"Legacy Code\", author_id: 22 }\n> params = ActionController::Parameters.new(data).permit(*ALLOW_LIST)\n> params.to_h\n#=> { title: \"Legacy Code\" }\n```\n\nThe `author_id` value is ignored and won't be passed to the `#update` call.\n"
  },
  {
    "path": "rails/alphabetize-schema-columns-to-keep-them-consistent.md",
    "content": "# Alphabetize Schema Columns To Keep Them Consistent\n\nWhen working on a Rails project with a team, there can be lots of unnecessary\nchurn in the `db/schema.rb` file. While there are a couple things that can\ncause this churn, the main one is reordering of columns during local migration.\n\nThe [`strong_migrations` gem](https://github.com/ankane/strong_migrations)\nprovides [a handy rake task to apply alphabetical ordering to columns\nnames](https://github.com/ankane/strong_migrations#schema-sanity). This keeps\nthem in a consistent order which reduces churn.\n\nAssuming you have the `strong_migrations` gem included in your app, add the\nfollowing line to the end of your `Rakefile`.\n\n```ruby\ntask \"db:schema:dump\": \"strong_migrations:alphabetize_columns\"\n```\n\nThis sets `strong_migrations:alphabetize_columns` as a prerequisite task to\n`db:schema:dump`. Whenever `db:schema:dump` gets run, the alphabetization task\nwill get run first. This ensures the resulting `db/schema.rb` file always has\ncolumn names in a consistent order.\n\nThe origin of this idea is Paul Gross's blog post [Alphabetize schema.rb\nColumns](https://www.pgrs.net/2008/03/12/alphabetize-schema-rb-columns/).\n"
  },
  {
    "path": "rails/alter-the-rails-setup-script.md",
    "content": "# Alter The Rails Setup Script\n\nWhen you generate a new Rails app, a set of scripts are put in the `bin/`\nfolder of your new app. These _bin scripts_ are ruby scripts that you can use\nto run `rails` commands, `rake` commands, as well as `setup` your rails\nproject.\n\nThese scripts can be modified like you'd modify any other ruby code.\n\nIn fact, the `setup` scripts encourages you to modify it by providing an\nexample of an additional setup step you can add.\n\n```bash\n#!/usr/bin/env ruby\nrequire \"fileutils\"\n\n# ...\n\nFileUtils.chdir APP_ROOT do\n  # This script is a way to set up or update your development environment automatically.\n  # This script is idempotent, so that you can run it at any time and get an expectable outcome.\n  # Add necessary setup steps to this file.\n\n  puts \"\\n== Installing dependencies ==\"\n  system! \"gem install bundler --conservative\"\n  system(\"bundle check\") || system!(\"bundle install\")\n\n  # puts \"\\n== Copying sample files ==\"\n  # unless File.exist?(\"config/database.yml\")\n  #   FileUtils.cp \"config/database.yml.sample\", \"config/database.yml\"\n  # end\n\n  # ...\nend\n```\n\nThere are several steps built in, but it provides an example of how you can\ncopy a sample YAML file to be the actual version of that YAML file.\n"
  },
  {
    "path": "rails/apply-basic-html-formatting-to-block-of-text.md",
    "content": "# Apply Basic HTML Formatting To Block Of Text\n\nMy Rails app has a form that allows a user to enter in free-form text. I enter\nin a couple paragraphs and save the record. It is rendered on a show page with\na couple lines of ERB like so:\n\n```ruby\n<div class=\"max-w-3xl mx-auto\">\n  <div class=\"space-y-4\">\n    <div class=\"prose mt-8 text-gray-700\">\n      <%= @record.notes %>\n    </div>\n  </div>\n</div>\n```\n\nWhen I view the erb-displayed version of that record's text, all those\ncarefully spaced paragraphs are clumped together. That is because those newline\n(`\\n` and `\\n\\n`) characters while understood to be whitespace do not have\nformatting implications in the browser like a combination of HTML tags and CSS\ndo.\n\nI can apply some basic formatting with [the aptly named `simple_format` method\navailable as an `ActionView`\nhelper](https://api.rubyonrails.org/classes/ActionView/Helpers/TextHelper.html#method-i-simple_format).\n\n```ruby\n<div class=\"max-w-3xl mx-auto\">\n  <div class=\"space-y-4\">\n    <div class=\"prose mt-8 text-gray-700\">\n      <%= simple_format(@record.notes) %>\n    </div>\n  </div>\n</div>\n```\n\nThis turns single `\\n` characters into a `<br />` tag and double `\\n\\n` cause\nthe surrounding paragraphs to be wrapped in `<p>` tags. That simple formatting\ncombined with my existing TailwindCSS styles makes the formatting of my text\nimmediately look much better.\n"
  },
  {
    "path": "rails/assert-two-arrays-have-the-same-items-with-rspec.md",
    "content": "# Assert Two Arrays Have The Same Items With RSpec\n\nMethods that return arrays of values with inconsistent orderings can be\nannoying to test with the `#eq` matcher. To keep your test from fickering,\nyou'd have to ensure the comparison is the same every time.\n\n```ruby\nit \"has the correct values\" do\n  expect(fetch_colors(params).sort).to eq([\"blue\", \"green\", \"yellow\"])\nend\n```\n\nIt'd be better if we could keep our test focused and simple. If sort order\nisn't something we care about, then it shouldn't be part of our test. RSpec has\na matcher for this kind of scenario --\n[`#match_array`](https://www.rubydoc.info/github/rspec/rspec-expectations/RSpec%2FMatchers:match_array).\n\n```ruby\nit \"has the correct values\" do\n  expect(fetch_colors(params)).to match_array([\"blue\", \"green\", \"yellow\"])\nend\n```\n\nThis allows us to ensure that each side of the comparison has the same set\nvalues, irrespective of ordering.\n"
  },
  {
    "path": "rails/attach-a-file-with-capybara.md",
    "content": "# Attach A File With Capybara\n\nThere are two ways to attach a file with\n[Capybara](https://github.com/jnicklas/capybara). The more conventional way\nis with the\n[`attach_file`](http://www.rubydoc.info/github/jnicklas/capybara/Capybara%2FNode%2FActions%3Aattach_file)\nmethod.\n\nAssuming there is a form with a file input similar to the following:\n\n```html\n<label for='data-file'>Data File</label>\n<input type='file' name='data-file' />\n```\n\n```ruby\nattach_file('data-file', 'path/to/file.csv')\n```\n\nThe first argument to `attach_file` is a locator which refers to the `name`\nattribute on the `input` tag.\n\nIf for some reason there is no `name` attribute on the `input` tag, the file\ncan be attached with a standard `find` and `set`.\n\n```ruby\nfind('form input[type=\"file\"]').set('path/to/file.csv')\n```\n"
  },
  {
    "path": "rails/attribute-getter-without-the-recursion.md",
    "content": "# Attribute Getter without the Recursion\n\nYou may find yourself adding a custom *getter* method for one of the\nattributes in a Rails model. It might look something like this:\n\n```ruby\ndef name\n  name || account.name\nend\n```\n\nThis method will fall on its face as it quickly expands the stack\nrecursively calling itself. Instead, you can tell `ActiveRecord` that you\nwant the value of that attribute without invoking the getter\nInstead, we want to get the value of the attribute without invoking the\nmodel's getter. `ActiveRecord` allows us to do this with the\n[`read_attribute`](http://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Read.html#method-i-read_attribute)\nmethod. Check it out:\n\n```ruby\ndef name\n  read_attribute(:name) || account.name\nend\n```\n\n[source](http://stackoverflow.com/questions/21835116/overwrite-getter-activerecord-model-rails)\n"
  },
  {
    "path": "rails/attribute-was.md",
    "content": "# Attribute Was\n\nWhen modifying the attributes of an `ActiveRecord` object, you may want to\nknow what values the modified attributes used to have. `ActiveRecord` gets\nsome handy methods from the\n[`ActiveModel::Dirty`](http://api.rubyonrails.org/classes/ActiveModel/Dirty.html)\nmodule that allow you to check these values out even if the object's\nattributes were changed before you received it (though you are out of luck\nonce it has been saved). Just add `_was` onto the end of the attribute in\nquestion.\n\n```ruby\n>> pokemon.name\n=> \"Charizard\"\n>> pokemon.name = \"Squirtle\"\n=> \"Squirtle\"\n>> pokemon.name\n=> \"Squirtle\"\n>> pokemon.name_was\n=> \"Charizard\"\n>> pokemon.save\n   ...\n=> true\n>> pokemon.name_was == pokemon.name\n=> true\n```\n\n[source](http://api.rubyonrails.org/classes/ActiveModel/Dirty.html)\n"
  },
  {
    "path": "rails/autosave-false-on-activerecord-associations.md",
    "content": "# Autosave False On ActiveRecord Associations\n\nA relationship between two ActiveRecord models can be established with a\n`has_one` or `has_many` association. This relationship has some\nimplications. By default, saving a record will also save the associated\nrecords that have since been built. Consider this example of users that have\nmany posts (`has_many posts`).\n\n```ruby\n> u = User.first\n#=> #<User ...>\n> u.posts\n#=> []\n> u.posts.build(title: \"Some Title\", content: \"This is a post\")\n#=> #<Post ...>\n> u.save\n#=> true\n> u.posts(reload: true)\n#=> [#<Post ...>]\n```\n\nWhen the user is saved, the associated post that was built for that user\nalso gets saved to the database.\n\nIf the association is instead defined with the `autosave` option set to\nfalse, then saving a record will not cause associated records to also be\nsaved. The associated records will need to be saved explicitly. Consider the\nsame example from above, but with `has_many posts, autosave: false`.\n\n```ruby\n> u = User.first\n#=> #<User ...>\n> u.posts\n#=> []\n> u.posts.build(title: \"Some Title\", content: \"This is a post\")\n#=> #<Post ...>\n> u.save\n#=> true\n> u.posts(reload: true)\n#=> []\n```\n\nThe post wasn't saved with the user and it wasn't saved explicitly, so it\nisn't persisted to the database.\n"
  },
  {
    "path": "rails/bind-parameters-to-activerecord-sql-query.md",
    "content": "# Bind Parameters To ActiveRecord SQL Query\n\nMany of the connection query methods that come with `ActiveRecord` accept an\noptional `binds` parameter. This can be used to safely inject parameters into\nthe query.\n\nHere's a SQL query we could use with one of these methods:\n\n```ruby\nsql = <<-SQL\n  select\n    coalesce(places.latitude, 41.8781) latitude,\n    coalesce(places.longitude, -87.6298) longitude\n  from places\n  join appointments\n    on places.id = apointments.places_id\n  where appointments.id = $1\n    and status = $2\nSQL\n```\n\nNotice the `$1` and `$2`, those are what will be bound to the two parameters\nincluded as `binds`.\n\n```ruby\nconnection = ActiveRecord::Base.connection\n\nbinds = [[nil, appt_id], [nil, input_status]]\ncoords = connection.select_one(sql, nil, binds)\n\ncoords\n#=> { \"latitude\": 41.8781, \"longitude\": -87.6298 }\n```\n\nNotice the `binds` is an array of tuples. It's the second value in each tuple\nthat gets bound the corresponding binding indicator in the sql. The syntax is a\nbit awkward since it is a lower-level API, however once you know it, you can\nmanage.\n"
  },
  {
    "path": "rails/build-a-hash-of-model-attributes.md",
    "content": "# Build A Hash Of Model Attributes\n\nHave you ever found yourself creating an `ActiveRecord` object with\n[FactoryBot](https://github.com/thoughtbot/factory_bot) with the sole purpose\nof turning it into a hash of attributes?\n\n```ruby\n> FactoryBot.build(:book).attributes\n{ \"id\"=>nil, \"title\"=>\"Fledgling\", \"genre\"=>\"fiction\" }\n```\n\nFactoryBot has a built-in method for doing this:\n\n```ruby\n> FactoryBot.attributes_for(:book)\n{ title: \"Fledgling\", genre: \"fiction\" }\n```\n\nIt also accepts any traits for that factory:\n\n```ruby\n> FactoryBot.attributes_for(:book, :published)\n{\n  title: \"Fledgling\",\n  genre: \"fiction\",\n  publication_year: 2005,\n  page_count: 362\n}\n```\n\nThis is a handy way of build a base set of attributes when testing an API\nendpoint.\n\n[source](https://devhints.io/factory_bot)\n"
  },
  {
    "path": "rails/capture-development-emails-with-mailhog.md",
    "content": "# Capture Development Emails With Mailhog\n\nMy preferred way to capture and view emails being sent by a Rails app in\ndevelopment is to use [MailHog](https://github.com/mailhog/MailHog). It runs a\nlocal SMTP server at port `1025` and a barebones email client at port `8025`.\n\nThe `mailhog` utility can be installed with `brew`:\n\n```bash\n$ brew install mailhog\n```\n\nThe development `smtp` settings are configured in\n`config/environments/development.rb`:\n\n```ruby\n  config.action_mailer.delivery_method = :smtp\n  config.action_mailer.smtp_settings = {\n    address: 'localhost',\n    port: 1025,\n  }\n```\n\nThen start running `mailhog` with its default settings:\n\n```bash\n$ mailhog\n```\n\nAll outgoing email from the development server will be captured and viewable in\nboth `html` and `text` form at `localhost:8025`.\n"
  },
  {
    "path": "rails/capybara-page-status-code.md",
    "content": "# Capybara Page Status Code\n\nTo quickly determine if a page is rendering as expected or not, you can\ncheck the status code of the page. If your page is rendering successfully,\nyou'll see something like this:\n\n```ruby\n> page.status_code\n# => 200\n```\n\nIf some sort of application authorization logic is causing the page to not\nrender as normal, you may see something like this:\n\n```ruby\n> page.status_code\n# => 403\n```\n"
  },
  {
    "path": "rails/cast-common-boolean-like-values-to-booleans.md",
    "content": "# Cast Common Boolean-Like Values To Booleans\n\nSometimes you have to deal with values that are supposed to represent booleans,\nbut they aren't actually boolean values (i.e. `\"t\"` instead of `true`). Rail's\n`ActiveModel` has a helper for casting these common boolean-like values to\nactual booleans.\n\n```ruby\n> ActiveModel::Type::Boolean.new.cast('f')\n=> false\n> ActiveModel::Type::Boolean.new.cast('t')\n=> true\n> ActiveModel::Type::Boolean.new.cast('true')\n=> true\n> ActiveModel::Type::Boolean.new.cast('FALSE')\n=> false\n> ActiveModel::Type::Boolean.new.cast(0)\n=> false\n> ActiveModel::Type::Boolean.new.cast(1)\n=> true\n> ActiveModel::Type::Boolean.new.cast(true)\n=> true\n> ActiveModel::Type::Boolean.new.cast(false)\n=> false\n```\n\nThis cast method gives you a handy way to handle all thsoe different cases.\nThis is available as of Rails 5+.\n"
  },
  {
    "path": "rails/change-the-nullability-of-a-column.md",
    "content": "# Change The Nullability Of A Column\n\nDo you have an existing table with a column that is exactly as you want it\nexcept that it needs to be changed to either `null: false` or `null: true`?\n\nOne option is to use ActiveRecord's `change_column_null` method in your\nmigration.\n\nFor example to change a nullable column to `null: false`, you'll want a\nmigration like the following:\n\n```ruby\ndef change\n  change_column_null :posts, :title, false\nend\n```\n\nNote, if you have existing records with `null` values in the `title` column,\nthen you'll need to deal with those before migrating.\n\nIf you want to make an existing column nullable, change that `false` to\n`true`:\n\n```ruby\ndef change\n  change_column_null :posts, :title, true\nend\n```\n"
  },
  {
    "path": "rails/change-the-time-zone-offset-of-a-datetime-object.md",
    "content": "# Change The Time Zone Offset Of A DateTime Object\n\nLet's say you have a timestamp string that you parse with\n[`DateTime.parse`](https://ruby-doc.org/stdlib-2.6.1/libdoc/date/rdoc/DateTime.html#method-c-parse).\n\n```ruby\n> DateTime.parse('2021-02-23T11:59:11')\n#=> Tue, 23 Feb 2021 11:59:11 +0000\n```\n\nWithout the specification of a time zone offset in the timestamp string, it\nwill be parsed as UTC.\n\nIf you want to change it to another time zone, you can alter the `offset`\noption of the `DateTime` object. Rails provides the\n[`#change`](https://api.rubyonrails.org/classes/DateTime.html#method-i-change)\nmethod for doing this.\n\n```ruby\n> DateTime.parse('2021-02-23T11:59:11').change(offset: '-600')\n#=> Tue, 23 Feb 2021 11:59:11 -0600\n```\n\nBy changing the `offset` to `-600`, the `DateTime` now represents a time in\nCentral Time.\n\n[source](https://stackoverflow.com/a/47861810/535590)\n"
  },
  {
    "path": "rails/check-how-database-is-configured.md",
    "content": "# Check How Database Is Configured\n\nWhile making some adjustments to the database connection string (`DATABASE_URL`)\nfor a pre-production Rails environment, we wanted to check that configuration\noptions like `sslmode` were picked up.\n\nFrom a `rails console` session I can check the live database configuration like\nso:\n\n```ruby\n> ActiveRecord::Base.connection_db_config.configuration_hash\n=> {\n  adapter: \"postgresql\",\n  encoding: \"unicode\",\n  pool: 5,\n  database: \"my_app_development\"\n}\n```\n\nI can look at the\n[`configuration_hash`](https://api.rubyonrails.org/classes/ActiveRecord/DatabaseConfigurations/HashConfig.html#attribute-i-configuration_hash)\nfrom `rails console` of my pre-prod environment to see more configuration\nsettings:\n\n```ruby\n> ActiveRecord::Base.connection_db_config.configuration_hash\n=> {\n  adapter: \"postgresql\",\n  encoding: \"unicode\",\n  pool: 5,\n  username: \"app_user\",\n  password: \"super_s3cr3t\",\n  port: 15432,\n  database: \"pre_prod_database\",\n  host: \"some-host-123.ondigitalocean.com\",\n  sslmode: \"verify-full\"\n}\n```\n\nSince I was specifically looking for the `sslmode` value, I can access that\ndirectly:\n\n```ruby\n> ActiveRecord::Base.connection_db_config.configuration_hash[:sslmode]\n=> \"verify-full\"\n```\n"
  },
  {
    "path": "rails/check-if-activerecord-update-fails.md",
    "content": "# Check If ActiveRecord Update Fails\n\nThere are two ways to update an `ActiveRecord` instance (not to mention\n[`assign_attributes`](https://api.rubyonrails.org/classes/ActiveModel/AttributeAssignment.html),\n[`update_attribute`](https://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update_attribute),\netc.).\n\nYou can call\n[`update`](https://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update)\nand\n[`update!`](https://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update-21).\nIf the updates would make the record invalid based on the model's validations,\nthen the update will fail.\n\nYou can tell if `update` failed because it will return `false` (instead of\n`true`).\n\n```ruby\nunless book.update(book_params)\n  log_book_update_failed(id: book.id)\nend\n```\n\nThe `update!` version will raise an `ActiveRecord::ActiveRecordError`\nexception if the update fails.\n\n```ruby\nbegin\n  book.update!(book_params)\nrescue ActiveRecord::ActiveRecordError\n  log_book_update_failed(id: book.id)\nend\n```\n"
  },
  {
    "path": "rails/check-if-any-records-have-a-null-value.md",
    "content": "# Check If Any Records Have A Null Value\n\nI like to add missing `not null` constraints where appropriate when they are\nmissing. The [`change_column_null`\nmethod](change-the-nullability-of-a-column.md) is the Rails DSL way of doing\nthis.\n\nBut first, you need to be sure that all databases this will be running against\ndon't have any `null` values already present for any records. If there are\n`null` values present, then the migration will fail.\n\nOne way of doing that check is with some SQL and the\n[`select_values`](https://api.rubyonrails.org/v6.1.0/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html#method-i-select_values)\nmethod.\n\n```ruby\nActiveRecord::Base\n  .connection\n  .select_values(\"select id from projects where user_id is null\")\n  .any?\n```\n\nThis bit of SQL asks for the `id`s of any records in the `projects` table where\na specific column (`user_id`) is explicitly `null`.\n\nIf this returns `false`, then you are good to migrate. If this returns `true`,\nthen you'll have to do some data massaging first.\n"
  },
  {
    "path": "rails/check-specific-attributes-on-activerecord-array.md",
    "content": "# Check Specific Attributes On ActiveRecord Array\n\nIf you're writing a test against a method that returns a collection of\nActiveRecord results, it can be tedious to check specific values for each.\nThere are certainly an endless number of ways to approach those assertions.\n\nYou can keep your assertion fairly concise by using nested RSpec matchers.\nThere are two in particular that can help with this kind of check:\n\n```ruby\nbooks = get_books_by(\"David Sedaris\")\n\nexpect(books).to match_array(\n  [\n    have_attributes(\n      \"title\" => \"Calypso\",\n      \"publication_year\" => \"2018\",\n    ),\n    have_attributes(\n      \"title\" => \"Theft By Finding\",\n      \"publication_year\" => \"2017\",\n    ),\n  ],\n)\n```\n\nThe outer part of the assertion is `match_array` which checks that the result\nis an array of a certain size with specific elements. On its own we'd have to\nspell out all the attributes of each book, including things like `created_at`\nand `updated_at`. However, by combining it with `have_attributes` matchers, we\nare able to make the assertion over a subset of each record's attributes.\n"
  },
  {
    "path": "rails/check-the-current-named-log-level.md",
    "content": "# Check The Current Named Log Level\n\nI'm connected to a `rails console` session for an active Rails app. I want to\ncheck the current log level.\n\n```ruby\n> Rails.logger.level\n=> 1\n```\n\nThe `1` doesn't mean much to me at a glance. I can translate that to the\nseverity level using the `Logger::SEV_LABLE` constant.\n\n```ruby\n[44] pry(main)> Logger::SEV_LABEL[Rails.logger.level]\n=> \"INFO\"\n```\n\nAh yes, `INFO`, that makes sense as the default.\n\nI can see all the severity levels by inspecting the constant itself.\n\n```ruby\n[45] pry(main)> Logger::SEV_LABEL\n=> [\"DEBUG\", \"INFO\", \"WARN\", \"ERROR\", \"FATAL\", \"ANY\"]\n```\n\nAs I convenience, I can set the label using the index, the string, or even a\nsymbol.\n\n```ruby\n> Rails.logger.level\n=> 1\n> Rails.logger.level = \"WARN\"\n=> \"WARN\"\n> Rails.logger.level\n=> 2\n> Rails.logger.level = :debug\n=> :debug\n> Rails.logger.level\n=> 0\n```\n\nSee the [Debugging Rails Applications\nguide](https://guides.rubyonrails.org/debugging_rails_applications.html#log-levels)\nfor more details.\n"
  },
  {
    "path": "rails/clean-up-memory-hungry-rails-console-processes.md",
    "content": "# Clean Up Memory Hungry Rails Console Processes\n\nI noticed (using `htop`) that a remote server hosting a Rails app had most of\nits RAM being actively consumed. This was hindering my ability to run a fresh\ndeploy because the deploy processes had to do a ton of memory swapping which\ndrastically slowed the whole thing down.\n\nWith some investigation, I discovered that most of the memory was being consumed\nby a handful of `rails console` processes. I didn't have any known active `rails console` processes that I was using. That combined with the dates of these\nprocesses starting way in the past suggested to me that these were abandoned\nprocesses that hadn't been properly cleaned up.\n\n```bash\nserver:~# ps aux | grep rails\n32767     878915  0.0  0.0 1227160  936 pts/0    Ssl+  2025   0:03 /exec rails console\n32767     878942  0.9  6.5 830996 261748 pts/0   Rl+   2025 249:51 ruby /app/bin/rails console\n32767    3004097  0.0  0.0 1227160  692 pts/0    Ssl+  2025   0:04 /exec rails console\n32767    3004129  0.9  6.4 834672 257228 pts/0   Dl+   2025 406:31 ruby /app/bin/rails console\n32767    3048582  0.0  0.0 1227160  940 pts/0    Ssl+ Jan09   0:00 /exec rails console\n32767    3048611  1.1  6.3 829936 253484 pts/0   Dl+  Jan09  60:50 ruby /app/bin/rails console\n32767    3060033  0.0  0.0 1227160  944 pts/0    Ssl+  2025   0:04 /exec rails console\n32767    3060063  0.9  6.5 838084 260812 pts/0   Rl+   2025 405:37 ruby /app/bin/rails console\nroot     3699372  0.0  0.0   7008  1300 pts/0    S+   15:51   0:00 grep --color=auto rails\nserver:~# ps aux | grep 'rails console' | awk '{sum+=$6} END {print sum/1024 \" MB\"}'\n1014.64 MB\n```\n\nAs we can see by tacking on this `awk` command, these processes are consuming\n1GB of memory.\n\nEach of these is a pair of processes. A parent process (`/exec rails console`)\nthat kicks off and supervises the memory-hungry child process (`ruby /app/bin/rails console`).\n\nTo free up this memory, I targeted each of the parent processes with a `kill`\ncommand one by one. For example:\n\n```bash\nserver:~# kill 878915\n```\n\nI suspect that I may have left the occasional terminal tab open with one of\nthese `rails console` processes running and the SSH connection was getting\nkilled without the `rails console` getting killed with it.\n"
  },
  {
    "path": "rails/code-statistics-for-an-application.md",
    "content": "# Code Statistics For An Application\n\nRails applications and engines provide `stats`, a rake task for reporting\nhigh level code statistics. Running it on a small project of mine generated\nthe following report:\n\n```\n$ rake stats\n+----------------------+-------+-------+---------+---------+-----+-------+\n| Name                 | Lines |   LOC | Classes | Methods | M/C | LOC/M |\n+----------------------+-------+-------+---------+---------+-----+-------+\n| Controllers          |   179 |   143 |       4 |      20 |   5 |     5 |\n| Helpers              |    18 |    16 |       0 |       2 |   0 |     6 |\n| Models               |    30 |    22 |       3 |       2 |   0 |     9 |\n| Mailers              |     0 |     0 |       0 |       0 |   0 |     0 |\n| Javascripts          |    53 |    35 |       0 |       6 |   0 |     3 |\n| Libraries            |     0 |     0 |       0 |       0 |   0 |     0 |\n| Controller specs     |    22 |    16 |       0 |       0 |   0 |     0 |\n| Decorator specs      |    30 |    22 |       0 |       0 |   0 |     0 |\n| Feature specs        |   739 |   382 |       0 |      74 |   0 |     3 |\n| Model specs          |    70 |    55 |       0 |       0 |   0 |     0 |\n| Cucumber features    |   412 |   293 |       0 |       0 |   0 |     0 |\n+----------------------+-------+-------+---------+---------+-----+-------+\n| Total                |  1553 |   984 |       7 |     104 |  14 |     7 |\n+----------------------+-------+-------+---------+---------+-----+-------+\n  Code LOC: 216     Test LOC: 768     Code to Test Ratio: 1:3.6\n```\n"
  },
  {
    "path": "rails/columns-with-default-values-are-nil-on-create.md",
    "content": "# Columns With Default Values Are Nil On Create\n\nLet's say I have a `MagicLinks` model backed by `magic_links` Postgres table.\nBoth the `id` and `token` columns are of type `UUID` and have default values of\n`gen_random_uuid()`. That means from the Rails-side when I go to create a\n`MagicLink` record, I don't have to think about specifying values for `id` or\n`token` -- the DB will take care of that.\n\n```ruby\n> magic_link = MagicLink.create(expires_at: Time.zone.now, user: User.last)\n  User Load (5.9ms)  SELECT \"users\".* FROM \"users\" ORDER BY \"users\".\"id\" DESC LIMIT $1  [[\"LIMIT\", 1]]\n  TRANSACTION (0.1ms)  BEGIN\n  MagicLink Create (3.1ms)  INSERT INTO \"magic_links\" (\"user_id\", \"expires_at\", \"created_at\", \"updated_at\") VALUES ($1, $2, $3, $4) RETURNING \"id\"\n...\n\n> magic_link.id\n=> \"6c6dddbf-4427-407d-8dc8-eef8cb65d491\"\n> magic_link.token\n=> nil\n```\n\nThis `create` call is translated into an `insert` SQL statement that includes a\n`returning` clause. For `create` it is always `returning \"id\"`. This means that\nthe `UUID` value generated in Postgres-land for `id` gets passed back into the\nActiveRecord instance. The `UUID` value generated for `token`,  however, is not\nbecause `token` isn't specified in the `returning` clause.\n\n[source](https://github.com/rails/rails/issues/17605)\n"
  },
  {
    "path": "rails/comparing-datetimes-down-to-second-precision.md",
    "content": "# Comparing DateTimes Down To Second Precision\n\nYou may have an RSpec test for your Rails codebase that asserts about the\ndatetime a record gets saved with:\n\n```ruby\ntwo_weeks_ago = 2.weeks.ago\n\nrecord = Thing.create(two_weeks_ago)\n\nexpect(record.some_date_time).to eq(two_weeks_ago)\n```\n\nThis comparison happens with precision down to the nanosecond. Unfortunately,\ndepending on your operating system and backing database, you may see\ninconsistent results due to variations in precision.\n\nOne way to deal with this, if you only care about precision down to the second,\nis to modify the expecationa little with the [`be_within`\nmatcher](https://relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/be-within-matcher).\n\n```ruby\ntwo_weeks_ago = 2.weeks.ago\n\nrecord = Thing.create(two_weeks_ago)\n\nexpect(record.some_date_time).to be_within(1.second).of(two_weeks_ago)\n```\n\nThe `be_within` matcher can also be used as [a nested\nmatcher](https://twitter.com/jbrancha/status/1213162124777869319?s=20).\n"
  },
  {
    "path": "rails/conditional-class-selectors-in-haml.md",
    "content": "# Conditional Class Selectors in Haml\n\nYou can assign a class selector to a tag in HAML like so:\n\n```ruby\n%div.active\n```\n\nYou can conditionally assign a class selector in a concise manner like so:\n\n```ruby\n%div{ class: ( \"active\" if @thing.active? ) }\n```\n\nYou can do multiple conditional class selectors with array syntax:\n\n```ruby\n%div{ class: [ (\"active\" if @thing.active?), (\"highlight\" if @thing.important?) ] }\n```\n\n[source](http://stackoverflow.com/questions/3453560/append-class-if-condition-is-true-in-haml-with-rails)\n"
  },
  {
    "path": "rails/convert-a-symbol-to-a-constant.md",
    "content": "# Convert A Symbol To A Constant\n\nIf you have a symbol and need to convert it to a constant, perhaps because\nof some metaprogramming induced by a polymorphic solution, then you may\nstart off on an approach like the following. In fact, I've seen a number of\nStackOverflow solutions like this.\n\n```ruby\n:module.to_s.capitalize.constantize\n#=> Module\n```\n\nThat is great for one-word constant names, but what about multi-word\nconstants like `OpenStruct`. This approach will not work for the symbol\n`:open_struct`. We need a more general solution.\n\nThe key is to ditch `#capitalize and instead use another ActiveSupport\nmethod, `#classify`.\n\n```ruby\n:open_struct.to_s.classify.constantize\n#=> OpenStruct\n```\n"
  },
  {
    "path": "rails/convert-json-field-to-hash-with-indifferent-access.md",
    "content": "# Convert JSON Field To Hash With Indifferent Access\n\nLet's say we have an `Event` model whose backing table includes a `JSONB` (or\n`JSON`) field called `details`.\n\nWhen we access `details` in a Rails context, digging into that nested data we\nhave to use string keys throughout. However, we may have existing related code\nthat is dealing with this shape of data using symbol keys. This might put us in\na position where we have to rework a bunch of existing code or do defensive\ncoding like `details[:user] || details[\"user\"]`.\n\nTo avoid that, we can instead have the `Event` model override `details`\nconverting that underlying data to `HashWithIndifferentAccess` before returning\nit.\n\n```ruby\nclass Event < ApplicationRecord\n  def details\n    data = super\n    return data if data.nil?\n    \n    case data\n    when Array\n      data.map { |item| item.is_a?(Hash) ? item.with_indifferent_access : item }\n    when Hash\n      data.with_indifferent_access\n    else\n      data\n    end\n  end\nend\n```\n\nWith this in place, anywhere in the codebase where we access `details` on an\ninstance of `Event` we will be able to use string or symbol keys\ninterchangeably.\n"
  },
  {
    "path": "rails/count-the-number-of-records-by-attribute.md",
    "content": "# Count The Number Of Records By Attribute\n\nIn [Count How Many Records There Are Of Each\nType](postgres/count-how-many-records-there-are-of-each-type.md), I walked\nthrough how to use SQL (in PostgreSQL) to get a count of how many records there\nare with each unique value in a given column. This is something I tend to do\nwith a `type` or `status` column.\n\nWe can ask the same question with Rails, with very little code. It produces a\nnearly identical query and the same results.\n\n```ruby\n> Book.group(:status).count\n#=> { nil => 123, \"published\" => 611, \"draft\" => 364, \"review\" => 239 }\n```\n\nWe've picked the `Book` model and we want it to group books by their `status`.\nTacking on the `#count` at the end tells it to apply the `count` aggregate. The\nresult is a hash of each unique value of the specified attribute (`status`)\npaired with the count.\n"
  },
  {
    "path": "rails/create-a-custom-named-references-column.md",
    "content": "# Create A Custom Named References Column\n\nThe `t.references` and `add_reference` methods both create a foreign key column\nname based on the target table.\n\nFor instance,\n\n```ruby\nadd_reference :guests, :user, foreign_key: true, index: true, null: false\n```\n\nwould create a `user_id` column on the `guests` table.\n\nAt times, you'll need to customize the name of the foreign key column. The\nRails migration DSL supports this with the `foreign_key` option.\n\nHere is an example that shows the syntax for both a new table and an existing\ntable.\n\n```ruby\nclass AddInvitedByColumnToUser < ActiveRecord::Migration[6.1]\n  def change\n    create_table :guests, id: :uuid do |t|\n      t.string :email, null: false\n      t.timestamps\n\n      t.references :invited_by,\n        type: :uuid,\n        index: true,\n        null: false,\n        foreign_key: { to_table: :users }\n    end\n\n    add_reference :guests, :signed_up_as,\n      type: :uuid,\n      index: true,\n      null: false,\n      foreign_key: { to_table: :users }\n  end\nend\n```\n\nThe `t.references` call creates a foreign key column to the `users` table named\n`invited_by`. The `add_reference` call adds a `signed_up_as` foreign key column\nto `guests` that points to users.\n\n[source](https://stackoverflow.com/a/42056089/535590)\n"
  },
  {
    "path": "rails/create-a-join-table-with-the-migration-dsl.md",
    "content": "# Create A Join Table With The Migration DSL\n\nThe Rails migration DSL comes with a helper for creating a join table between\ntwo other existing tables.\n\nCall `create_join_table` with two arguments, symbols for the names of the two\ntables.\n\n```ruby\ndef change\n  create_join_table :tags, :posts\nend\n```\n\nThis will create a table with id references columns to each of the tables. The\n`db/schema.rb` addition will look something like this:\n\n```ruby\n  create_table \"posts_tags\", id: false, force: :cascade do |t|\n    t.bigint \"tag_id\", null: false\n    t.bigint \"post_id\", null: false\n  end\n```\n\nA Rails/ActiveRecord convention that comes into play for the creation of this\ntable.\n\n1. The name should be the pluralized versions of the two joined table names.\n2. The joined table names should show up in the table name in alphabetical\n   order.\n\nNotice that despite listing `:tags` before `:posts` it creates a table called\n`posts_tags`. The DSL handles that for us.\n\nSome `create_join_table` defaults to be aware of:\n\n- It doesn't generate foreign key constraints.\n- It uses `bigint` (or `int`) for the keys (even if those tables use UUIDs).\n- The references are named after their respective table names.\n"
  },
  {
    "path": "rails/create-table-with-bigint-id-as-primary-key.md",
    "content": "# Create Table With bigint ID As Primary Key\n\nWhen creating a new table with an ActiveRecord migration, we specify all the\nfields _except_ the `id`. The `id`, which is the primary key, is implicit. We\nget it by default.\n\nThe type of that `id` defaults to `int` which is a 32-bit signed integer.\n\nWe can override the type of `id` in a variety of ways. The one I prefer in most\ncases is to make the `id` of type `bigint`. This is a 64-bit signed integer. It\noffers quite a bit more headroom for the number of unique identifies in our\ntable.\n\nThis can be specified by including `id: :bigint` as an option to the\n`create_table` method.\n\n```ruby\nclass CreatePosts < ActiveRecord::Migration[8.0]\n  def change\n    create_table :posts, id: :bigint do |t|\n      t.string :title, null: false\n      t.string :body, null: false\n\n      t.timestamps\n    end\n  end\nend\n```\n\n[source](https://api.rubyonrails.org/v7.1/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-create_table)\n"
  },
  {
    "path": "rails/creating-records-of-has-one-associations.md",
    "content": "# Creating Records of Has_One Associations\n\nWhen working with a model, say a User, that has a `has_many` association\nwith another model, say a Post, you can create a new post for a user like\nso:\n\n```ruby\nu1 = User.first\n=> #<User:0x...>\nu1.posts.create(title: \"Some Title\", content: \"...\")\n=> #<Post:0x...>\n```\n\nWhat about with a `has_one` association? Consider a Customer that has a\n`has_one` association with an Account. Rails provides this method for you:\n\n```ruby\nc1.create_account(account_number: 123, ...)\n=> #<Account:0x...>\n```\n\nRails also gives you a similar `build` method:\n\n```ruby\nc1.build_account(account_number: 123, ...)\n=> #<Account:0x...>\n```\n"
  },
  {
    "path": "rails/custom-validation-message.md",
    "content": "# Custom Validation Message\n\nWhen using Rails validations, a standard error message will be provided\nwhenever there is a violation. Consider the scenario when there is a\nuniqueness validation on the email attribute and it is violated:\n\n```ruby\n# User model\nvalidates_uniqueness_of :email\n\n# Users controller\nnew_user.errors.full_messages\n#=> [\"Email has already been taken\"]\n```\n\nSometimes you don't want the default validation message. The validation\ndeclaration can be given a `message` option to specify an alternate\nvalidation message.\n\n```ruby\n# User model\nvalidates_uniqueness_of :email, message: 'is not available'\n\n# Users controller\nnew_user.errors.full_messages\n#=> [\"Email is not available\"]\n```\n\nKeep in mind that `full_messages` will prepend the model name to the front\nof the message. You'll want to ensure that the resulting message is\ncoherent.\n"
  },
  {
    "path": "rails/customize-paths-and-helpers-for-devise-routes.md",
    "content": "# Customize Paths And Helpers For Devise Routes\n\nWih a default Devise setup (`devise_for :users`), the sign up/in/out routes are\nlocated at `/users/sign_up`, `/users/sign_in`, and `/users/sign_out`. And the\npath helpers are `new_user_registration_path`, `new_user_session_path`, and\n`destroy_user_session_path`, respectively.\n\nThese can be customized in `config/routes.rb` by opening up the `devise_scope\n:user` block and re-specifying the routes of interest.\n\n```ruby\nRails.application.routes.draw do\n  devise_for :users\n  devise_scope :user do\n    get 'sign_up', to: 'devise/registrations#new'\n    get 'sign_in', to: 'devise/sessions#new'\n    delete 'sign_out', to: 'devise/sessions#destroy'\n  end\nend\n```\n\nThese three custom routes override the paths and helps I described above like\nso:\n\n- `sign_up_path` -> `/sign_up`\n- `sign_in_path` -> `/sign_in`\n- `sign_out_path` -> `/sign_out`\n\nI find these path helpers easier to work with and I like the UX of\nregistration/session paths not nested under `/user`.\n"
  },
  {
    "path": "rails/customize-template-for-new-schema-migration.md",
    "content": "# Customize Template For New Schema Migration\n\nRails has a set of generator functionality that we can use to scaffold entire\nslices of an app all the way down to generating a single migration file.\n\n```bash\n$ rails generate migration MakeUserStatusColumnNotNull\n```\n\nWhen we run a migration generator command like that, Rails reaches for the\n[baked-in migration\ntemplate](https://github.com/rails/rails/blob/92be9af152f721588b7414119c931ea92930947b/activerecord/lib/rails/generators/active_record/migration/templates/migration.rb.tt)\nand creates a new migration file based on the given name and any other local\nvariables that get set internally.\n\nThat's the standard behavior. However, we can override the migration template\nby defining our own template in `lib/templates/migration.rb.tt` of our Rails\napp. We'll need to follow the basic structure, but then we can alter it to our\nneeds.\n\nFor instance, I typically like to use the `#up` and `#down` methods and write\nraw SQL for my migrations. To help with that this template provides a good\nstarting point.\n\n```ruby\nclass <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]\n  def up\n    execute <<~SQL\n    SQL\n  end\n\n  def down\n    execute <<~SQL\n    SQL\n  end\nend\n```\n\nWe can see in\n[`migration_generator.rb`](https://github.com/rails/rails/blob/92be9af152f721588b7414119c931ea92930947b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb#L26-L43)\nhow locals get set and what template gets chosen.\n"
  },
  {
    "path": "rails/customize-the-path-of-a-resource-route.md",
    "content": "# Customize The Path Of A Resource Route\n\nThe `:path` option allows you to customize the path used by a resource route in\nRails' `config/routes.rb` file. This is handy if you have a multi-word resource\nthat you would like to use dashes in the path.\n\nFor instance\n\n```ruby\nresources :audio_books\n```\n\nwould have paths like `/audio_books` and `/audio_books/:id`.\n\nBy specifying the `:path` option\n\n```ruby\nresources :audio_books, path: 'audio-books'\n```\n\nthe paths end up like `/audio-books` and `/audio-books/id`.\n\n[source](https://stackoverflow.com/questions/5334465/routes-with-dash-instead-of-underscore-in-ruby-on-rails)\n"
  },
  {
    "path": "rails/define-the-root-path-for-the-app.md",
    "content": "# Define The Root Path For The App\n\nThe `root_path` helper that you might want to use in Rails controllers and\nviews is not available by default.\n\n```ruby\n> Rails.application.routes.url_helpers.root_path\n\nruby/3.2.2/lib/ruby/gems/3.2.0/gems/irb-1.14.0/lib/irb.rb:1285:in `full_message': undefined method `root_path' for #<Module:0x0000000106d11738> (NoMethodError)\n\nRails.application.routes.url_helpers.root_path\n                                    ^^^^^^^^^^\nDid you mean?  logout_path\n               book_path\n```\n\nIt needs to be declared in the `config/routes.rb` file with the controller\naction that it points to.\n\n```ruby\n# config/routes.rb\nRails.application.routes.draw do\n  root 'home#index'\nend\n```\n\nOnce this is defined the `root_path` will now be available with the rest of\nyour URL helpers.\n\n```ruby\nbetter-reads(dev)> reload!\nReloading...\nbetter-reads(dev)> Rails.application.routes.url_helpers.root_path\n=> \"/\"\n```\n\n[source](https://guides.rubyonrails.org/routing.html#using-root)\n"
  },
  {
    "path": "rails/delete-paranoid-records.md",
    "content": "# Delete Paranoid Records\n\nThe [ActsAsParanoid gem](https://github.com/ActsAsParanoid/acts_as_paranoid)\nprovides soft delete functionality to `ActiveRecord` objects in Rails. You\ncan enhance a model with its functionality like so:\n\n```ruby\nclass User < ActiveRecord::Base\n  acts_as_paranoid\nend\n```\n\nThis gem hijacks `ActiveRecord`'s standard `destroy` and `destroy!`\nfunctionality. If you call either of these methods, instead of the record\nbeing deleted from the database, it's `deleted_at` column is updated from\n`nil` to the current timestamp. Resulting in a _soft deleted_ record.\n\nIf you call `destroy` or `destroy!` a second time (i.e. on a record that has\nalready been soft deleted), it will be actually deleted from the database.\nAlternatively, you can call `destroy_fully!` from the beginning to skip the\nsoft delete.\n"
  },
  {
    "path": "rails/demodulize-a-class-name.md",
    "content": "# Demodulize A Class Name\n\nIf you call `.class.name` on an instance of some class, the fully qualified\nname will be returned, module names and all. Consider the following example\nclass:\n\n```ruby\nmodule One\n  module Two\n    class Three\n      ...\n    end\n  end\nend\n```\n\n```ruby\n> One::Two::Three.new.class.name\n#=> \"One::Two::Three\"\n```\n\nIf you just want the unqualified class name; modules not included, you can\nuse the `#demodulize` method provided by `ActiveSupport`.\n\n```ruby\n> One::Two::Three.new.class.name.demodulize\n#=> \"Three\"\n```\n"
  },
  {
    "path": "rails/determine-the-configured-primary-key-type.md",
    "content": "# Determine The Configured Primary Key Type\n\nI noticed an interesting helper function in the database migration generated by\n`bin/rails active_storage:install`.\n\n```ruby\nclass CreateActiveStorageTables < ActiveRecord::Migration[8.0]\n  def change\n    # Use Active Record's configured type for primary and foreign keys\n    primary_key_type, foreign_key_type = primary_and_foreign_key_types\n\n    # ...\n  end\n\n  private\n\n    def primary_and_foreign_key_types\n      config = Rails.configuration.generators\n      setting = config.options[config.orm][:primary_key_type]\n      primary_key_type = setting || :primary_key\n      foreign_key_type = setting || :bigint\n      [ primary_key_type, foreign_key_type ]\n    end\nend\n```\n\nThe `primary_and_foreign_key_types` method looks in the generators config for\nthe ORM (`:active_record`) to determine the configured `:primary_key_type`. By\ndefault this will return `nil`. This method then uses `:primary_key` as a\nfallback value which will be `bigint`. That's why the `foreign_key_type` falls\nback to `:bigint`.\n\nIf desired, this can be manually configured in `config/application.rb` like\nshown in the [ActiveRecord Migrations\ndocs](https://guides.rubyonrails.org/active_record_migrations.html#enabling-uuids-in-rails).\n"
  },
  {
    "path": "rails/different-ways-to-add-a-foreign-key-reference.md",
    "content": "# Different Ways To Add A Foreign Key Reference\n\nA foreign key reference creates a relationship between two tables that is\nguaranteed by a foreign key constraint.\n\nThis is a minimal example.\n\n```ruby\ncreate_table :books\n  t.references :author, foreign_key: true\nend\n```\n\nThe `foreign_key: true` is needed here, otherwise just the reference column is\ncreated without a backing constraint. When `foreign_key` is true, an index will\nbe created for the column as well.\n\nThis is a maximal example.\n\n```ruby\ncreate_table :books\n  t.references :author, index: true, foreign_key: true, type: :uuid, null: false\nend\n```\n\nIt is explicit about the foreign key and index. It specifies a `not null`\nconstraint. It declares the type as `uuid` assuming the `authors` table's\nprimary key is of type `uuid`.\n\nHere is an example with a custom column name.\n\n```ruby\ncreate_table :books\n  t.references :written_by, foreign_key: { to_table: :authors }\nend\n```\n\nHere is adding a reference to an existing table.\n\n```ruby\ndef up\n  add_reference :books, :author, index: true, foreign_key: true\nend\n```\n\nThere are more combinations of these, but I hope there is enough here to be\nable to iterate to a solution that works for you.\n"
  },
  {
    "path": "rails/disambiguate-where-in-a-joined-relation.md",
    "content": "# Disambiguate Where In A Joined Relation\n\nWhen you join two tables using ActiveRecord\n\n```ruby\nPost.joins(:author)\n```\n\nYou get a relation that involves both of the tables. This allows you to\nwrite queries that work off the data in that join.\n\nThe primary table in the join is `posts`. Any column references in a\n`#where` call will be assumed to be related to `posts`. If you want to\nreference a column on the `authors` table, you'll need to provide that\nspecificity.\n\nThe hash syntax for `#where` is a great way to do that:\n\n```ruby\nPost.joins(:author).where({ authors: { name: \"John Steinbeck\" }})\n```\n\nYou can also use the string syntax:\n\n```ruby\nPost.joins(:author).where(\"authors.name = ?\", \"John Steinbeck\")\n```\n\n[source](https://apidock.com/rails/v4.2.7/ActiveRecord/QueryMethods/where)\n"
  },
  {
    "path": "rails/empty-find-by-returns-first-record.md",
    "content": "# Empty find_by Returns First Record\n\nDuring a RubyConf 2024 talk, a speaker mentioned that if you pass `nil` to\n[ActiveRecord's `#find_by`\nmethod](https://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-find_by),\nit will return the first record from the database. This is a bit unintuitive,\nso lets look at an example and then I'll show you why.\n\n```ruby\n> Book.first\n#=> #<Book:0x00000001142e4c48 id: 13, title: \"The Secret History\", ... >\n\n> Book.find_by(nil)\n#=> #<Book:0x00000001142ca3c0 id: 13, title: \"The Secret History\", ... >\n```\n\nSo, that is the same object in both cases, but why?\n\nOur first hint is in the SQL that gets constructed when making that method\ncall.\n\n```ruby\nBook Load (2.5ms)  SELECT \"books\".* FROM \"books\" LIMIT $1  [[\"LIMIT\", 1]]\n```\n\nIt's grabbing all books and limiting to _one_ result.\n\nLets look at the underlying implementation of the `#find_by` method.\n\n```ruby\n# File activerecord/lib/active_record/relation/finder_methods.rb, line 111\ndef find_by(arg, *args)\n  where(arg, *args).take\nend\n```\n\nSure enough, the implementation is a `#where` followed by a `#take`. Since the\n`#where` is receiving `nil` as its `arg`, there are no conditions _filtering_\nthe query. And the `#take` corresponds to the `limit 1`.\n\nKnowing that, we can understand that we will also get the first record from the\ndatabase if we call `#find_by` with `{}`. Again, no conditions to filter on, so\ngive me all books limited to one.\n\nOne small caveat: notice how there is no `order by` clause in the above SQL\noutput. This differs from `Books.first` which implicitly does an order on the\n`id` column. Though these method are likely to return the same result, the\nordering of `#find_by` is not guaranteed to be the same without an `order by`\nclause.\n"
  },
  {
    "path": "rails/enforce-locals-passed-to-a-partial.md",
    "content": "# Enforce Locals Passed To A Partial\n\nI have a big form partial (`_form.html.erb`) that is rendered by several\ndifferent _new_ and _edit_ views. It's hard to tell at a glance, but the\npartial requires that `blogmark` and `cancel_path` are included as locals when\nit is rendered.\n\nAs of [Rails 7.1](https://github.com/rails/rails/pull/45602), we now have a\nbuilt-in way to enforce locals passed to a partial. We can add a magic comment\nat the top of the partial that specifies the locals:\n\n```ruby\n<%# locals: (blogmark:, cancel_path:) -%>\n<%= form_with(model: blogmark, local: true, class: \"w-full max-w-3xl mb-8\") do |form| %>\n  <% ... %>\n<% end %>\n```\n\nThis particular ERB magic comment declares that\n[`blogmark`](https://still.visualmode.dev/blogmarks) and `cancel_path` are\nrequired locals.\n\nSo, what happens if I have a `new.html.erb` view that looks like this:\n\n```ruby\n<h1>New Blogmark</h1>\n\n<%= render 'blogmarks/form', blogmark: @blogmark %>\n```\n\nWhen I try to view the page, an error is raised:\n\n```\nShowing /Some/path/app/views/blogmarks/_form.html.erb where line # raised:\n\nmissing local: :cancel_path for app/views/blogmarks/_form.html.erb\n```\n\nUpdating the `render` statement to include a `cancel_path` local fixes the\nissue.\n\n[source](https://gorails.com/episodes/template-locals-in-rails-7-1)\n"
  },
  {
    "path": "rails/ensure-a-rake-task-cannot-write-data.md",
    "content": "# Ensure A Rake Task Cannot Write Data\n\nLet's say we are writing a substantially complex rake task for aggregating,\narranging, and exporting data from our app's database. The idea is to run this\nrake task against production.\n\nThere is no part of this rake task that needs to write data. It should act as a\nread-only script. And in fact, we can ensure it isn't able to write any data.\nWe can do that by putting `ApplicationRecord` in read-only mode.\n\n```ruby\ntask big_export_rake_task: :environment do\n  class ApplicationRecord\n    def readonly?\n      true\n    end\n  end\n\n  # a bunch of logic ...\n  puts 'this gets executed'\n\n  # Call method that inadvertently writes data\n  User.update(email: 'readonly@email.com')\n\n  # more logic ...\n  puts 'this does not get executed'\nend\n```\n\nBecause we have made all of `ApplicationRecord` read-only, when we run this\ntask, it is immediately going to rollback the changes that were attempted and\nthen raise an error which aborts the rest of the rake task.\n\nWe'll see some messaging like this:\n\n```\nrake aborted!\nActiveRecord::ReadOnlyRecord: User is marked as readonly\n```\n\nh/t [Dillon Hafer](https://dillonhafer.com/)\n"
  },
  {
    "path": "rails/ensure-migrations-use-the-latest-schema.md",
    "content": "# Ensure Migrations Use The Latest Schema\n\nReal-world migrations in Rails apps can sometimes involve both schema changes\nand data changes. For instance, if you are moving a column from one table to\nanother, you'll need to add a new column, move some data, and then delete the\nold column.\n\n```ruby\n# Assume the following are defined:\n# GenericAuthor for table 'authors'\n# GenericBook for table 'books'\n\ndef up\n  add_column :books, :genre, :string\n\n  GenericAuthor.find_each do |author|\n    book = GenericBook.find_by(author_id: author.id)\n    book.update!(genre: author.genre)\n  end\n\n  remove_column :authors, :genre\nend\n```\n\nThis migration looks straightforward, but you may find that no data actually\ngets transferred to the `genre` column on `books`. This is because as a\nperformance optimization, Rails has cached the scema. Thus an `ActiveRecord`\nmodification like `book.update!` will be working off a version of the schema\nthat doesn't include `genre` as a column.\n\nWe can ensure `ActiveRecord` is using the latest column informtion for the\n`books` table by calling\n[`reset_column_information`](https://api.rubyonrails.org/classes/ActiveRecord/ModelSchema/ClassMethods.html#method-i-reset_column_information).\n\n```ruby\ndef up\n  add_column :books, :genre, :string\n\n  GenericBook.reset_column_information\n\n  GenericAuthor.find_each do |author|\n    book = GenericBook.find_by(author_id: author.id)\n    book.update!(genre: author.genre)\n  end\n\n  remove_column :authors, :genre\nend\n```\n\nNow the update will work and `genre` will be set on `books`.\n"
  },
  {
    "path": "rails/ensure-record-saved-with-after-commit-callback.md",
    "content": "# Ensure Record Saved With after_commit Callback\n\nIn my experience, some of the more common `ActiveRecord` callbacks are ones\nlike `before_save` or `after_update`. While working with some code, where I\nneeded to send a notification when a certain value was updated, I learned that\nsomething like `after_update` wasn't sufficient.\n\nIf my record is updated within a transaction, the `after_update` will get\ntriggered even though the changes could later get rolled back resulting in me\nerroneously sending the notification.\n\n```ruby\nActiveRecord::Base.transaction do\n  user.update(interesting_value: 123)\n\n  do_something # <-- rollback could happen here!\nend\n```\n\nTo ensure I'm not over-eager with my notifications, I should instead use\n[`after_commit`](https://api.rubyonrails.org/v7.0.5/classes/ActiveRecord/Transactions/ClassMethods.html#method-i-after_commit)\nwhich only gets called after the changes have been committed to the database.\n\n```ruby\nclass User < ApplicationRecord\n  after_commit :send_notification,\n    on: [:create, :update],\n    if: :interesting_value_was_changed?\n\n  # rest of class...\n\n  private\n\n  def send_notification\n    # logic...\n  end\n\n  def interesting_value_was_changed?\n    # logic...\n  end\nend\n```\n\nOn either `create` or `update` if my condition is met, then after the _commit_\ngoes through, the `#send_notification` method will be triggered.\n"
  },
  {
    "path": "rails/filter-active-model-validation-errors.md",
    "content": "# Filter ActiveModel Validation Errors\n\nNow that `ActiveModel` has a custom `Errors` class (as of Rails 6.1) instead of\na hash, we get some useful functionality. Namely, we get a [`#where`\nmethod](https://api.rubyonrails.org/classes/ActiveModel/Errors.html#method-i-where)\nthat allows us to filter errors based on the attribute name, type of\nvalidation, and even properties of that validation.\n\nHere I have created a new `Book` without any attributes. All of its validations\nare going to fail and we are going to have an `ActiveModel::Errors` object\nattached to it with several errors.\n\n```ruby\n> book = Book.new\n=>\n#<Book:0x00000001110397a8\n...\n> book.valid?\n=> false\n> book.errors\n=> #<ActiveModel::Errors [#<ActiveModel::Error attribute=added_by, type=blank, options={:message=>:required, :if=>#<Proc:0x0000000110096260 /Users/jbranchaud/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/activerecord-7.2.1/lib/active_record/associations/builder/belongs_to.rb:130 (lambda)>}>, #<ActiveModel::Error attribute=title, type=blank, options={}>, #<ActiveModel::Error attribute=title, type=too_short, options={:count=>3}>, #<ActiveModel::Error attribute=author, type=blank, options={}>, #<ActiveModel::Error attribute=publication_date, type=blank, options={}>]>\n```\n\nLet's say I want to check for a specific validation error. I can use `#where`\nto filter down by attribute name (e.g. `:title`). I can filter even further by\nincluding the validation type as well (e.g. `:too_short`).\n\n```ruby\n> book.errors.where(:title)\n=>\n[#<ActiveModel::Error attribute=title, type=blank, options={}>,\n #<ActiveModel::Error attribute=title, type=too_short, options={:count=>3}>]\n> book.errors.where(:title, :too_short)\n=> [#<ActiveModel::Error attribute=title, type=too_short, options={:count=>3}>]\n> book.errors.where(:title, :too_short).first.message\n=> \"is too short (minimum is 3 characters)\"\n> book.errors.where(:title, :too_short).first.full_message\n=> \"Title is too short (minimum is 3 characters)\"\n```\n\nThis filtering could be used as part of conditional checks for what flash\nmessage gets displayed to the user or even what route/view gets rendered in\nresponse to the error.\n"
  },
  {
    "path": "rails/filter-active-storage-blobs-to-only-images.md",
    "content": "# Filter ActiveStorage Blobs To Only Images\n\nIf your Rails app is using `ActiveStorage` for both images and ActionMailbox\nemails, then you're going to have a mix of both in the `active_storage_blobs`\ntable.\n\n```sql\n> select id, filename, content_type from active_storage_blobs limit 2;\n\n| id | filename           | content_type   |\n|----|--------------------|----------------|\n|  1 | shirt-brothers.jpg | image/jpeg     |\n|  2 | message.eml        | message/rfc822 |\n```\n\nIn that case, you are going to want to make sure that any part of your system\nthat only cares to deal with images filters down to only blobs where the\n`content_type` is one that you care about.\n\nI expect that there might be a couple different image `content_type` values\nthat my system handles, so I filter my `active_storage_blobs` like so:\n\n\n```ruby\n@images =\n  ActiveStorage::Blob\n    .where(content_type: %w[image/jpeg image/png image/gif image/webp])\n    .order(created_at: :desc)\n    .first(10)\n```\n"
  },
  {
    "path": "rails/find-or-create-a-record-with-factory-bot.md",
    "content": "# Find Or Create A Record With FactoryBot\n\nI have a bunch of tests throughout my test suite that rely on a particular kind\nof unique record. Let's say it is a special admin user.\n\n```ruby\nadmin = FactoryBot.create(:user, email: 'admin@company.com')\n```\n\nIf this user has already been created then trying to re-create it with\n[FactoryBot](https://github.com/thoughtbot/factory_bot) will result in a unique\nemail validation error.\n\nAnother way to approach this would be to either find or create the admin user.\nIn some standard Rails code that might look like this:\n\n```ruby\nadmin =\n  User.find_by(email: 'admin@company.com') ||\n  FactoryBot.create(:user, email: 'admin@company.com')\n```\n\nThere is some repetitiveness to this that I'd like to avoid. FactoryBot doesn't\nhave an equivalent to ActiveRecord's `find_and_create_by`, but we can work\naround this.\n\nWe can add an `initialize_with` directive to the `User` factory.\n\n```ruby\nFactoryBot.define do\n  factory :user do\n    sequence(:email) { |n| 'user#{n}@example.com' }\n\n    # a bunch of other attributes\n\n    initialize_with { User.find_or_create_by(email: email) }\n  end\nend\n```\n\nWith this in place, we can call `FactoryBot.create` with the already existing\n_admin_ user and it will look up the record instead of raising a validation\nerror.\n\n[source](https://stackoverflow.com/a/11799674/535590)\n"
  },
  {
    "path": "rails/find-records-with-multiple-associated-records.md",
    "content": "# Find Records With Multiple Associated Records\n\nRelational data often involves a table that has a one-to-many relationship with\nanother table. For instance, a team can be made up of many members. A question\nwe may want to ask of that data is, what are the records (`teams`) that are\nassociated with more than one of this other table (`members`).\n\nWith a few SQL features that are supported by ActiveRecord's query syntax, we\ncan answer that question.\n\nTo make it interesting, let's say we are trying to answer the question, \"what\nare the teams that have multiple _active_ members?\"\n\n```ruby\nTeam\n  .joins(:members)\n  .where(members: { status: 'active' })\n  .having(\"count(*) >= 2\")\n  .group(\"teams.id\")\n  .count\n\n=> {\n  123 => 2,\n  345 => 3,\n  567 => 2,\n  ...\n}\n```\n\nThat final `.count` is going to manifest as a `count(*)` in the `select`\nclause. That `count(*)` aggregate combined with the `group(\"teams.id\")` is\ngoing to flatten the results to be unique by team ID. Then the `having` clause\nwill filter out all teams with a member count less than 2. And before that, the\nwhere will cut down the members to only those that are `active`.\n\nIf you just want the IDs, you can tack a `#keys` call onto the end of that\nquery result.\n"
  },
  {
    "path": "rails/force-all-users-to-sign-out.md",
    "content": "# Force All Users To Sign Out\n\nIf you are using cookie-based authentication and you want to sign out all users\n(so that they have to re-authenticate), you need to invalidate all of the\ncookies.\n\nBecause the cookies live in the client's browser, you cannot simply clear them\nlike you would with session-based authentication. Instead, you need to replace\nthe session token used to create all those cookies.\n\nFirst, get a new token:\n\n```bash\n$ bundle exec rake secret\n538696c1399ff182486e09980ba915d098b8fb23a3ace42c3eea0ab51b18fdff7895cd620f32b263d10d25c2fdba16647f4d8632e9032eccef7406e1ad9cba09\n```\n\nThen, replace the current `secret_key_base` value with that new secret token\n[wherever it is\nstored](https://api.rubyonrails.org/classes/Rails/Application.html#method-i-secret_key_base)\nin the production environment.\n\n[source](https://stackoverflow.com/questions/35190591/rails-4-devise-how-to-log-out-all-users)\n"
  },
  {
    "path": "rails/format-datetime-with-builtin-formats.md",
    "content": "# Format DateTime With Builtin Formats\n\nThe Rails [`Date`](https://api.rubyonrails.org/classes/Date.html)/`DateTime`\nand [`Time`](https://api.rubyonrails.org/classes/Time.html) classes each come\nwith a `DATE_FORMATS` constant that is a hash of symbol names to format\nstrings.\n\n```ruby\n> DateTime::DATE_FORMATS\n=>\n{:short=>\"%d %b\",\n :long=>\"%B %d, %Y\",\n :db=>\"%Y-%m-%d\",\n :inspect=>\"%Y-%m-%d\",\n :number=>\"%Y%m%d\",\n :long_ordinal=>\n  #<Proc:0x0000000105b2cef0 /Users/jbranchaud/.local/share/mise/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/activesupport-8.0.1/lib/active_support/core_ext/date/conversions.rb:15 (lambda)>,\n :rfc822=>\"%d %b %Y\",\n :rfc2822=>\"%d %b %Y\",\n :iso8601=>\n  #<Proc:0x0000000105b2cec8 /Users/jbranchaud/.local/share/mise/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/activesupport-8.0.1/lib/active_support/core_ext/date/conversions.rb:21 (lambda)>}\n```\n\nThese can be used as a standardized, ready-to-use, named formats when turning\n`DateTime` objects into strings.\n\nHere are a few examples\n\n```ruby\n> now = DateTime.now\n=> Wed, 30 Apr 2025 23:08:08 -0500\n\n> now.to_fs(:long)\n=> \"April 30, 2025 23:08\"\n\n> now.to_fs(:long_ordinal)\n=> \"April 30th, 2025 23:08\"\n\n> now.to_fs(:iso8601)\n=> \"2025-04-30T23:08:08-05:00\"\n```\n\nIf an unrecognized key is passed to `#to_fs`, then it falls back to the\n`:iso8601` format.\n\n```ruby\n> now.to_fs(:taco_bell)\n=> \"2025-04-30T23:08:08-05:00\"\n```\n"
  },
  {
    "path": "rails/format-specific-html-erb-template-files.md",
    "content": "# Format Specific html.erb Template Files\n\nThere are a few tools out there that can do formatting of `*.html.erb` template\nfiles. One that I like is\n[nebulab/erb-formatter](https://github.com/nebulab/erb-formatter#readme)\nbecause it is ready to use in many different editors. That means that it is\neasier to adopt on a team of developers with different editor preferences.\n\nThat said, there are projects where I don't necessarily want it wired up to run\non save because the formatting changesets will be too agressive. Instead, I\nwant to run it manually on specific files as I see fit.\n\nTo do this, I install the formatter tool:\n\n```bash\n$ gem install erb-formatter\n```\n\nAnd now it is available as a CLI tool (try `which erb-format`).\n\nAs their docs recommend, I can run it against all files like so:\n\n```\n$ erb-format app/views/**/*.html.erb --write\n```\n\nIf that is too aggressive though, I find it useful to either run against a\nspecific file:\n\n```\n$ erb-format app/views/some/model/index.html.erb --write\n```\n\nOr when I'm wrapping up changes on a branch, I like to run it against all the\nview files that were touched on this branch:\n\n```\n$ git diff --name-only master...HEAD -- app/views | xargs erb-format --write\n```\n"
  },
  {
    "path": "rails/generate-a-model.md",
    "content": "# Generate A Model\n\nThe `rails` CLI comes with a variety of generators. Perhaps the mostly common\none to use is the _model_ generator.\n\nThe model generator will create a migration and a model file for the entity\nthat you name. In the following example `Book` will result in a\n`app/models/book.rb` file as well as a migration file for a `books` table.\nThese generators know the singular and plural conventions.\n\nAt the end of the command is a series of field definitions containing the field\n_name_ and field _type_. These are used in the migration file for defining\ncolumns on the new table.\n\n```bash\n❯ bin/rails generate model Book title:string publication_date:date author:string\n      invoke  active_record\n      create    db/migrate/20240920223447_create_books.rb\n      create    app/models/book.rb\n      invoke    rspec\n      create      spec/models/book_spec.rb\n```\n\nYou may also notice that an `rspec` action was invoked as part of this\ngenerator. That is because I have the `rspec-rails` gem in my project. That gem\nhooks into the model generator so that a model spec also gets generated. Handy!\n"
  },
  {
    "path": "rails/generate-a-rails-app-from-the-main-branch.md",
    "content": "# Generate A Rails App From The Main Branch\n\nTypically you are going to want to generate a Rails app using some officially\nreleased version of the framework. These releases have been thoroughly tested,\nhave received patches, and can guarantee a certain level of stability.\n\nHowever, if you are wanting to try out the latest, unreleased features, you may\nwant to generate a fresh Rails app based off the current state of the `main`\nbranch of the `rails` repository.\n\nTo do this, add the `--main` flag:\n\n```bash\n$ rails new rails_app_on_main --main\n```\n\nToward the top of your app's `Gemfile`, you'll see that `rails` is pointed to\nthe `main` branch of their repo:\n\n```ruby\n# Use main development branch of Rails\ngem \"rails\", github: \"rails/rails\", branch: \"main\"\n```\n\nSee `rails new --help` for more details\n\n[source](https://x.com/gregmolnar/status/1832720168264286571)\n"
  },
  {
    "path": "rails/generating-and-executing-sql.md",
    "content": "# Generating And Executing SQL\n\nRails' ActiveRecord can easily support 90% of the querying we do against the\ntables in our database. However, there is the occasional exceptional query\nthat is more easily written in SQL -- perhaps that query cannot even be\nwritten with the ActiveRecord DSL. For these instances, we need a way to\ngenerate and execute SQL safely. The\n[`sanitize_sql_array`](http://api.rubyonrails.org/classes/ActiveRecord/Sanitization/ClassMethods.html#method-i-sanitize_sql_array)\nmethod is invaluable for this.\n\nFirst, let's get a connection and some variables that we can use downstream\nin our query.\n\n```ruby\n> conn = ActiveRecord::Base.connection\n=> #<ActiveRecord::ConnectionAdapters::PostgreSQLAdapter ...>\n> one, ten = 1, 10\n=> [1, 10]\n```\n\nNow, we are ready to safely generate our SQL query as a string. We have to\nuse `send` because it is not publicly available. Generally, this is frowned\nupon, but in my opinion it is worth breaking the private interface to ensure\nour SQL is sanitized.\n\n```ruby\n> sql = ActiveRecord::Base.send(:sanitize_sql_array, [\"select generate_series(?, ?);\", one, ten])\n=> \"select generate_series(1, 10);\"\n```\n\nLastly, we can execute the query with our connection and inspect the\nresults.\n\n```ruby\n> result = conn.execute(sql)\n   (0.4ms)  select generate_series(1, 10);\n=> #<PG::Result:0x007facd93128a0 status=PGRES_TUPLES_OK ntuples=10 nfields=1 cmd_tuples=10>\n> result.to_a\n=> [{\"generate_series\"=>1},\n {\"generate_series\"=>2},\n {\"generate_series\"=>3},\n {\"generate_series\"=>4},\n {\"generate_series\"=>5},\n {\"generate_series\"=>6},\n {\"generate_series\"=>7},\n {\"generate_series\"=>8},\n {\"generate_series\"=>9},\n {\"generate_series\"=>10}]\n```\n"
  },
  {
    "path": "rails/get-a-quick-approximate-count-of-a-large-table.md",
    "content": "# Get A Quick Approximate Count Of A Large Table\n\nLet's say our Rails app has a massive `events` table in it's Postgres database.\nWe might be tempted to reach for an ActiveRecord API method like `Event.count`\nto get the number of records in the table. For tables with millions of rows,\nthis is going to be slow.\n\nIf all we need is an approximate count, there is a faster way that uses some of\nPostgreSQL's internal bookkeeping.\n\nWe can request the approximate number of tuples recorded for our table by name.\nThis query can be processed as raw SQL by the `#execute` method available on\n`ActiveRecord::Base.connection`.\n\n```ruby\nActiveRecord::Base.connection.execute(<<~SQL)\n  select reltuples::numeric as count\n    from pg_class\n  where relname='events';\nSQL\n```\n\nThat is going to spit out the `PG::Result` object which doesn't look like much\non its own.\n\n```\n#<PG::Result:0x00 ...>\n```\n\nIf we tack on a couple other methods, we can get the count as our result.\n\n```ruby\nActiveRecord::Base.connection.execute(<<~SQL).to_a.first[\"count\"].to_i\n  select reltuples::numeric as count\n    from pg_class\n  where relname='events';\nSQL\n```\n"
  },
  {
    "path": "rails/get-active-record-attribute-directly-from-database.md",
    "content": "# Get ActiveRecord Attribute Directly From Database\n\nIn Rails, an ActiveRecord model will automatically get methods named after each\ncolumn in the backing database table. This can be called to retrieve those\nvalues from the respective columns in the database.\n\nWhat if you wanted to override and alter one of those values? For example,\nensure the `email` value you're passing around is always fully downcased.\n\nSomething like this won't quite work.\n\n```ruby\ndef email\n  email.downcase\nend\n```\n\nBecause the method is named `email`, the `email` reference inside it will call\nitself, recursively, until it exceeds the stack.\n\nInstead, you need a way of referencing the email attribute that is stored in\nthe database.\n[`attribute_in_database`](https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Dirty.html#method-i-attribute_in_database)\nwill do the trick.\n\n```ruby\ndef email\n  attribute_in_database('email').downcase\nend\n```\n\nThat will retrieve the value from the `email` column in the database for this\nrecord, downcase it, and return it. Anyone calling `email` won't notice the\ndifference.\n\nh/t [Dillon Hafer](https://twitter.com/dillonhafer)\n"
  },
  {
    "path": "rails/get-an-array-of-values-from-the-database.md",
    "content": "# Get An Array Of Values From The Database\n\nWe generally get data from our database through [ActiveRecord\nmodels](https://api.rubyonrails.org/classes/ActiveRecord/Base.html):\n\n```ruby\n> Product.where(available: true).pluck(:sku)\n[ \"efg-1234\", \"pqr-3455\", ... ]\n```\n\nIf we need to do a more specialized query, we might reach for\n[`execute`](https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html#method-i-execute):\n\n```ruby\n> ActiveRecord::Base.connection.execute(<<-SQL)\n    select split_part(sku, '-', 1) product_type\n      from products\n      where available = true;\n  SQL\n[{ \"product_type\" => \"efg\" }, { \"product_type\" => \"pqr\" }, ... ]\n```\n\nThe results are bundled up in a predictable, but verbose array of hashes.\n\nWe could trim the result down to just the values using either\n[`select_values`](https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html#method-i-select_values)\nor\n[`select_rows`](https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html#method-i-select_rows):\n\n```ruby\n> ActiveRecord::Base.connection.select_values(<<-SQL)\n    select split_part(sku, '-', 1) product_type\n      from products\n      where available = true;\n  SQL\n[ \"efg\", \"pqr\", ... ]\n```\n\nIf the SQL statement is to return more than one row in the result, then you'll\nwant `select_rows` instead of `select_values`.\n"
  },
  {
    "path": "rails/get-an-empty-activerecord-relation.md",
    "content": "# Get An Empty ActiveRecord Relation\n\nWhen you query for something (with `#where`) and there are no results matching\nthat query, you get something that looks like an empty array (`[]`), but it's\nnot quite.\n\n```ruby\n> result\n[]\n> result.class\nBook::ActiveRecord_Relation\n```\n\nIt's an empty [`ActiveRecord`\nrelation](https://api.rubyonrails.org/classes/ActiveRecord/Relation.html).\n\nYou can get an instance of an empty `ActiveRecord` relation without\nconstructing a _no result_ query.\n\n```ruby\n> Book.none\n[]\n> Book.none.class\nBook::ActiveRecord_Relation\n```\n\nI can think of a couple scenarios where this would be useful:\n\n- as a default value for a method parameter\n- as a test value for a method that expects to have an `ActiveRecord` relation\n  passed in\n\n[source](https://stackoverflow.com/questions/4877931/how-to-return-an-empty-activerecord-relation)\n"
  },
  {
    "path": "rails/get-formatted-utc-offset-value.md",
    "content": "# Get Formatted UTC Offset Value\n\nThe UTC offset (during DST) for Chicago is `-05:00`. And for Newfoundland it is\n`-02:30`.\n\nRails has an [`ActiveSupport::TimeZone`\nmodule](https://api.rubyonrails.org/v7.1.3.2/classes/ActiveSupport/TimeZone.html#method-c-seconds_to_utc_offset)\nthat can turn the UTC offset in seconds into this formatted value.\n\n```ruby\n> chicago = TZInfo::Timezone.get('America/Chicago')\n=> #<TZInfo::DataTimezone: America/Chicago>\n> ActiveSupport::TimeZone.seconds_to_utc_offset(chicago.utc_offset)\n=> \"-05:00\"\n\n> newfoundland = TZInfo::Timezone.get('America/St_Johns')\n=> #<TZInfo::DataTimezone: America/St_Johns>\n> ActiveSupport::TimeZone.seconds_to_utc_offset(newfoundland.utc_offset)\n=> \"-02:30\"\n```\n\nThe underlying `tzinfo` gem is DST-aware and its database even knows which time\nzone identifiers don't observe DST, so you can run this anytime of the year and\nexpect reliable results.\n\nHere is another way at this:\n\n```ruby\n> chicago = TZInfo::Timezone.get('America/Chicago')\n=> #<TZInfo::DataTimezone: America/Chicago>\n> ActiveSupport::TimeZone[chicago.name]\n=> #<ActiveSupport::TimeZone:0x00000001099d8140 @name=\"America/Chicago\", @tzinfo=#<TZInfo::DataTimezone: America/Chicago>, @utc_offset=nil>\n> ActiveSupport::TimeZone[chicago.name].formatted_offset\n=> \"-06:00\"\n> ActiveSupport::TimeZone[chicago.name].formatted_offset(false)\n=> \"-0600\"\n```\n"
  },
  {
    "path": "rails/get-help-with-a-rails-app-update.md",
    "content": "# Get Help With A Rails App Update\n\nRails version upgrades can be pretty involved. The ecosystem and the framework\nare under constant evolution. While each patch version will stay reliably\nstable, as soon as you go to do a minor or major upgrade (which you should stay\non top of), you'll have lots to consider.\n\nRails helps with this via the `app:update` rake task.\n\nWhen run, it will prompt you with a series of files that it wants to change.\nFor each one you'll have some options.\n\n```bash\n$ rails app:update\n\nOverwrite my-app/config/boot.rb? (enter \"h\" for help) [Ynaqdhm]  h\n        Y - yes, overwrite\n        n - no, do not overwrite\n        a - all, overwrite this and all others\n        q - quit, abort\n        d - diff, show the differences between the old and the new\n        h - help, show this help\n        m - merge, run merge tool\n```\n\nStart by using `d` to see a diff of the changes. If it's small and doesn't\noverwrite important, existing settings, then you can use `y` to accept them.\nFor a lot of these files the changes will be too aggressive. So side-by-side\nwith the diff, update the file manually. Then use `n` to go to the next update.\n"
  },
  {
    "path": "rails/get-the-column-names-for-a-model.md",
    "content": "# Get The Column Names For A Model\n\nAn `ActiveRecord` model is backed by a table in your application's database. We\ncan get the column names for a backing table with `ActiveRecord`s help using\nthe `.column_names` method.\n\n```ruby\n> Book.column_names\n=> [\"id\", \"title\", \"publication_year\", \"created_at\", \"updated_at\", \"author_id\", \"genre\"]\n```\n\nAny `ActiveRecord` model will have access to this class method.\n\nSee [the\ndocs](https://devdocs.io/rails~5.2/activerecord/modelschema/classmethods#method-i-column_names)\nfor more details.\n"
  },
  {
    "path": "rails/get-the-current-time.md",
    "content": "# Get The Current Time\n\nWorking with time and time zones in server development can get complicated.\nTime-sensitive code that worked locally can unexpected fail when deployed to a\nserver in a different time zone. Or users can end up seeing timestamps that\nlook a few hours off.\n\nTo avoid this kinds of mistakes in Rails development, we should avoid using\n`Time.now` and instead use `Time.current`.\n\n> Rails saves timestamps to the database in UTC time zone. We should always use\n> Time.current for any database queries, so that Rails will translate and\n> compare the correct times.\n\n```ruby\n> Time.zone\n=> #<ActiveSupport::TimeZone:0x00007fccf6b0a548\n @name=\"UTC\",\n @tzinfo=#<TZInfo::DataTimezone: Etc/UTC>,\n @utc_offset=nil>\n> Time.now\n=> 2021-01-28 19:22:42.312577 -0600\n> Time.current\n=> Fri, 29 Jan 2021 01:22:45.926181000 UTC +00:00\n> Time.zone = 'Eastern Time (US & Canada)'\n=> \"Eastern Time (US & Canada)\"\n> Time.now\n=> 2021-01-28 19:23:28.255106 -0600\n> Time.current\n=> Thu, 28 Jan 2021 20:23:32.150545000 EST -05:00\n```\n\nMy server's default time zone is UTC. `Time.now` gives me my computer's system\ntime (Central Time). `Time.current` gives me the time in UTC. If I then change\nthe server's time zone to Eastern Time, `Time.now` still offers up my system\ntime whereas `Time.current` produces the current time in Easter Time.\n\n[source](https://thoughtbot.com/blog/its-about-time-zones)\n"
  },
  {
    "path": "rails/grab-a-random-record-from-the-database.md",
    "content": "# Grab A Random Record From The Database\n\nI recently learned of a clever way to grab a random record for a particular\nmodel from the database. This is handy if you are poking around in the database\nto see what some records look like.\n\nOrder the records for that table randomly and then grab the first.\n\n```ruby\nEvent.order('random()').first\n```\n\nThis grabs a random `Event` record from the `events` table.\n\nNote, however, that for Rails 6+, this approach won't work. Because of some\nextra safety measures around executing raw SQL, you'll instead have to write\nthe above as:\n\n```ruby\nEvent.order( Arel.sql('random()') ).first\n```\n\nThis uses\n[`Arel.sql`](https://api.rubyonrails.org/classes/Arel.html#method-c-sql) to\nmark `'random()'` as a known-safe string of SQL.\n\nBecause we are explicitly passing a string that represents a known-safe\nfunction call, this is fine. Take care to not pass any user-generated SQL in a\nscenario like this unless you know what you're doing.\n\n[source](https://stackoverflow.com/a/49525874/535590)\n"
  },
  {
    "path": "rails/handle-named-arguments-in-a-rake-task.md",
    "content": "# Handle Named Arguments In A Rake Task\n\nThere are [a number of\nways](https://www.seancdavis.com/blog/4-ways-to-pass-arguments-to-a-rake-task/)\nto pass arguments into a Rake task. The standard approach only allows for\npositional arguments. When I need named and optional arguments, my preferred\napproach is to use environment variables.\n\nHere is a skimmed down version of a user lookup task. Notice the task\ndefinition itself doesn't include any arguments. Instead, a couple optional\nvalues are extracted from the environment (`ENV`) at the beginngin of the task.\n\n```ruby\ndesc \"An example task with named, optional arguments\"\ntask :lookup_user => :environment do\n  user_id = ENV['USER_ID']\n  email = ENV['EMAIL']\n\n  if user_id.present?\n    user = User.find(user_id)\n\n    if user.blank?\n      puts \"No user for id ##{user_id}\"\n    end\n  elsif email.present?\n    user = User.find_by(email: email)\n\n    if user.blank?\n      puts \"No user for email #{email}\"\n    end\n  end\n\n  puts \"User found\" if user.present?\nend\n```\n\nThis task can be invoked in the following ways:\n\n```bash\n$ rake lookup_user USER_ID=123\n```\n\n```bash\n$ rake lookup_user EMAIL=\"user@example.com\"\n```\n\nor even with both arguments included, in which case the task has been written\nto give precedence to `USER_ID`:\n\n```bash\n$ rake lookup_user EMAIL=\"user@example.com\" USER_ID=123\n```\n"
  },
  {
    "path": "rails/hash-slicing.md",
    "content": "# Hash Slicing\n\nRails' ActiveSupport adds\n[`#slice`](http://api.rubyonrails.org/classes/Hash.html#method-i-slice) and\n[`#slice!`](http://api.rubyonrails.org/classes/Hash.html#method-i-slice-21)\nto the `Hash` class. The interface of these two methods seems a little\ninconsistent though.\n\n```ruby\n> {a: 1, b: 2, c: 3}.slice(:a)\n=> {:a=>1}\n```\n\nThe `#slice` method returns what is being sliced.\n\n```ruby\n> {a: 1, b: 2, c: 3}.slice!(:a)\n=> {:b=>2, :c=>3}\n```\n\nThe `#slice!` method, on the other hand, returns what is being excluded.\n"
  },
  {
    "path": "rails/ignore-poltergeist-javascript-errors.md",
    "content": "# Ignore Poltergeist JavaScript Errors\n\nPoltergeist with PhantomJS (<2.0) does not support JavaScript's `bind()`\nmethod. This means that when executing an integration test that exercises\nJavaScript with the `bind()` method, an error will occur. If you cannot\nsimply upgrade to a version of PhantomJS that supports `bind()`, then what\ncan you do?\n\nIgnore the error!\n\nThis can be achieved by placing the following rescue block in the\nappropriate place.\n\n```ruby\nrescue Capybara::Poltergeist::JavascriptError\n```\n\nUse this in moderation. You want to make sure you don't ignore actual\nJavaScript errors.\n\n[source](http://stackoverflow.com/questions/22020680/temporarily-set-js-errors-to-false-in-poltergeist)\n"
  },
  {
    "path": "rails/include-devise-helpers-in-your-controller-tests.md",
    "content": "# Include Devise Helpers In Your Controller Tests\n\nFor past versions of Devise, you could include `DeviseHelpers` as part of\n`controller` or `request` type tests to have access to the `sign_in` and\n`sign_out` helpers.\n\n```ruby\nRSpec.configure do |config|\n  config.include Devise::TestHelpers, :type => :controller\nend\n```\n\nAs of [Devise\n4.2.0+](https://github.com/heartcombo/devise/blob/master/CHANGELOG.md#420---2016-07-01),\nthe `Devise::TestHelpers` have been deprecated. The\n`Devise::Test::ControllerHelpers` module should instead be included.\n\n```ruby\nRSpec.configure do |config|\n  config.include Devise::Test::ControllerHelpers, :type => :controller\nend\n```\n\n[source](https://github.com/heartcombo/devise/blob/98fc5e8e396b66b826528811287ea6680a6d0757/lib/devise/test/controller_helpers.rb#L26)\n"
  },
  {
    "path": "rails/inspect-configuration-of-database-connection.md",
    "content": "# Inspect Configuration Of Database Connection\n\nThere are a lot of factors that can effect the database configuration values.\n\n- What are the settings in each environment in `config/database.yml`?\n- Is there any dynamic ERB code in `config/database.yml`?\n- Is `DATABASE_URL` set in the current environment?\n- Is any other code overriding these settings?\n\nTo check the current _configuration hash_ for the database connection at\nruntime, we can run the following statement:\n\n```ruby\n> ActiveRecord::Base.connection.pool.db_config.configuration_hash\n=>\n{:adapter=>\"postgresql\",\n :encoding=>\"unicode\",\n :host=>\"::1\",\n :user=>\"postgres\",\n :password=>\"postgres\",\n :pool=>5,\n :database=>\"still_development\",\n :port=>9875}\n```\n\nIn this case, I'm running the statement from the Rails console of my app's\ndevelopment environment.\n\nI could even access and print these values as part of debugging in a production\nenvironment with a rake task:\n\n```ruby\n# In lib/tasks/debug.rake\nnamespace :debug do\n  task :db_config => :environment do\n    puts \"==== Database Configuration Debug ====\"\n    puts \"DATABASE_URL: #{ENV['DATABASE_URL']}\"\n    puts \"Active Record Config: #{ActiveRecord::Base.connection.pool.db_config.configuration_hash}\"\n    puts \"Raw ENV dump:\"\n    ENV.sort.each { |k,v| puts \"#{k}: #{v}\" if k.include?('DB') || k.include?('DATABASE') }\n  end\nend\n```\n\n[source](https://api.rubyonrails.org/classes/ActiveRecord/DatabaseConfigurations/HashConfig.html)\n"
  },
  {
    "path": "rails/inspect-previous-changes-to-activerecord-object.md",
    "content": "# Inspect Previous Changes To ActiveRecord Object\n\nIf you modify an ActiveRecord object, before saving it, you can inspect changes\nwith methods like `changed?` and `<attr>_changed?`:\n\n```ruby\nbook.title = \"The Fifth Season\"\n\nbook.changed? #=> true\nbook.title_changed? #=> true\nbook.publication_year_changed? #=> false\n\nbook.changes\n#=> { \"title\" => [\"Original Title\", \"The Fifth Season\"] }\n```\n\nAfter saving an object, it will no longer be in a _dirty_ state and these\nmethods will have no _changes_ to return.\n\nIf you have a reference to the saved ActiveRecord object, you can look at the\n_previous_ changes with methods like `previous_changes` and\n`<attr>_previously_changed?`:\n\n```ruby\nbook.title = \"The Fifth Season\"\nbook.save\n\nbook.title_previously_changed? #=> true\nbook.previous_changes\n#=> { \"title\" => [\"Original Title\", \"The Fifth Season\"] }\n```\n\n[source](https://api.rubyonrails.org/classes/ActiveModel/Dirty.html)\n"
  },
  {
    "path": "rails/link-to-the-current-page-with-query-params.md",
    "content": "# Link To The Current Page With Query Params\n\nThe `link_to` method is an ActionView helper for generating an `a` tag within a\nRails view. There are two arguments that tend to comprise this method: the link\ntext and a path helper.\n\n```ruby\n<%= link_to 'Home', root_path %>\n```\n\nThe `link_to` method can be used to generate a link to the current page with\nquery params. You can do this be providing a hash instead of a path helper as\nthe second argument.\n\n```ruby\n<%= link_to \"All\", {filter: 'all'} %>\n<%= link_to \"New\", {filter: 'new'} %>\n<%= link_to \"Posted\", {filter: 'posted'} %>\n```\n\nThe hash can contain one or more key-value pairs which will be turned into\nquery params and appended to the end of the current base path.\n\nIf these are part of the `posts` index page, then they will render as:\n\n```html\n<a href=\"/posts?filter=all\">All</a>\n<a href=\"/posts?filter=new\">New</a>\n<a href=\"/posts?filter=posted\">Posted</a>\n```\n\nThis is a great way to create links for a Rails action that presents different\ndata based on query params. Often this is an index page where filtering is\nneeded.\n\n[source](https://gorails.com/episodes/rails-link-to-current-page-with-params)\n"
  },
  {
    "path": "rails/list-all-installable-rails-versions.md",
    "content": "# List All Installable Rails Versions\n\n_Here's a [screencast](https://www.youtube.com/watch?v=IizkvqGLkhU) in case you\nwant to watch instead of read._\n\nI [was curious](https://twitter.com/jbrancha/status/1345467867479875584?s=20)\nwhat versions of Rails were remotely available to be installed with `gem`. On\nits own, `gem list rails` will show all _locally_ installed gems that\npartially match `rails`. That'll include gems like `rspec-rails` and\n`sprockets-rails`.\n\nFirst, the `--exact` flag can be added to narrow down the results to an exact\nmatch of `rails`.\n\nThen, the `--remote` flag can be included to request `gem` look for remote\nversions. That is, versions available on the rubygems server.\n\nLastly, the `--all` flag can be included to fetch all versions instead of only\nthe latest version.\n\nPutting it all together:\n\n```bash\n$ gem list rails --exact --remote --all\nrails (6.1.0, 6.0.3.4, 6.0.3.3, ... 0.9.0, 0.8.5, 0.8.0)\n```\n\n[source](https://stackoverflow.com/a/9146057/535590)\n"
  },
  {
    "path": "rails/list-the-enqueued-jobs.md",
    "content": "# List The Enqueued Jobs\n\nMany Rails apps need to delegate work to jobs that can be performed at a\nlater time. Both unit and integration testing can benefit from asserting\nabout the jobs that get enqueued as part of certain methods and workflows.\nRails provides a handy helper method for checking out the set of enqueued\njobs at any given time.\n\nThe\n[`enqueued_jobs`](http://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/TestAdapter.html#method-i-enqueued_jobs)\nmethod will provide a store of all the currently enqueued jobs.\n\nIt provides a number of pieces of information about each job. One way to\nuse the information is like so:\n\n```ruby\ndescribe '#do_thing' do\n  it 'enqueues a job to do a thing later' do\n    Processor.do_thing(arg1, arg2)\n    expect(enqueued_jobs.map { |job| job[:job] }).to match_array([\n      LongProcessJob,\n      SendEmailsJob\n    ])\n  end\nend\n```\n\nTo use this in your Rails project, just enable the adapter in your test\nconfiguration file:\n\n```ruby\nRails.application.config.active_job.queue_adapter = :test\n```\n"
  },
  {
    "path": "rails/load-a-file-when-starting-rails-console.md",
    "content": "# Load A File When Starting Rails Console\n\nThe `rails console` command uses `irb` under the hood. That means you can use\nany of the flags that `irb` supports when running `rails c`. One of those flags\nis `-r` which \"causes `irb` to load the [specified] library using require.\"\n\nThis `-r` flag can come in handy if we want to load a little bit of setup code\nor some utility methods for our `rails console` session.\n\nLet's say we have `vendor/show_env.rb` with this snippet of code:\n\n```ruby\nputs \"#{'*' * 7}  #{Rails.env.upcase}  #{'*' * 7}\n```\n\nAnd we want that to display as we open the console. We can pass the path to\nthat file to the `-r` flag.\n\n```bash\n$ rails console -- -r ./vendor/show_env.rb\n```\n\n[Notice the\n`--`](https://tosbourn.com/speed-up-pasting-text-into-rails-console/). That is\nto indicate that we are done with `console` specific arguments and anything\nelse should be passed along to `irb`. Without the `--`, the `-r` flag won't be\nrecognized.\n\nSee `man irb` to see what other flags `irb` supports.\n"
  },
  {
    "path": "rails/load-records-in-batches-with-find-each.md",
    "content": "# Load Records In Batches With find_each\n\nThe base enumerable method offered by Ruby is `#each`. If you need to interact\nwith an array of elements, that's a method you'll reach for at some point.\n\nWhen working with an `ActiveRecord` collection in Rails, you should use the\n[`#find_each`](https://api.rubyonrails.org/v6.1.0/classes/ActiveRecord/Batches.html#method-i-find_each)\nmethod instead of `#each`. That's because under the hood it batches the records\nthat it will load in 1000 at a time. This is important to keep your server's\nresource usage from exploding when requesting a ton of records.\n\nConsider a `users` table that contains 10,000 records that are _active_.\n\n```ruby\nUser.where(active: true).each do |user|\n  # do something\nend\n```\n\nWith `#each`, all 10,000 records will be loaded into memory at once as\n`ActiveRecord` objects. That's potentially a lot of load on the server's\navailable memory. Then imagine the table contains 100,000 or 1,000,000 records.\nThis can become a big problem.\n\n```ruby\nUser.where(active: true).find_each do |user|\n  # do something\nend\n```\n\nWith `#find_each`, which uses\n[`#find_in_batches`](https://api.rubyonrails.org/v6.1.0/classes/ActiveRecord/Batches.html#method-i-find_in_batches)\nunder the hood, only 1000 `ActiveRecord` objects get loaded into memory at a\ntime.\n\nIf you want to exercise more control over the batching, you can use\n`#find_in_batches` directly.\n"
  },
  {
    "path": "rails/log-sql-queries-executed-by-activerecord.md",
    "content": "# Log SQL Queries Executed By ActiveRecord\n\nWhen entering ActiveRecord statements in a Rails console, it can be useful to\nsee what SQL queries are being executed under the hood.\n\n```ruby\n> Book.first\n  Book Load (25.6ms)  SELECT  \"books\".* FROM \"books\" ORDER BY \"books\".\"id\" ASC LIMIT $1  [[\"LIMIT\", 1]]\n=> #<Book:0x00007f824ec6ff98\n```\n\nNotice the line right after the statement shows the corresponding `select`\nquery.\n\nIf you aren't seeing this line of SQL, then you'll need to turn on logging for\nActiveRecord. For instance, your test environment may not be configured to log\nthe SQL.\n\nRight in your console, try running the following line:\n\n```ruby\n> ActiveRecord::Base.logger = Logger.new(STDOUT)\n```\n\nEnter an ActiveRecord statement, you should now be seeing the corresponding SQL\nqueries.\n\n[source](https://stackoverflow.com/a/2936016/535590)\n"
  },
  {
    "path": "rails/look-up-time-zone-info-for-identifier.md",
    "content": "# Look Up Time Zone Info For Identifier\n\nThe `ActiveSupport::TimeZone` class overrides the `#[]` method to be a lookup\nmechanism for IANA Time Zone Identifier strings. These are strings like\n`America/Chicago` (or anything else listed under `TZInfo::Timezone.all`).\n\nLet's get an instance for `America/Chicago`.\n\n```ruby\n> chi = ActiveSupport::TimeZone['America/Chicago']\n=> #<ActiveSupport::TimeZone:0x00000001099d8140\n @name=\"America/Chicago\",\n @tzinfo=#<TZInfo::DataTimezone: America/Chicago>,\n @utc_offset=nil>\n```\n\nNotice it has a `tzinfo` instance variable that we can access. That object\ncontains all kinds of useful things.\n\n```ruby\n> chi.tzinfo.name\n=> \"America/Chicago\"\n> chi.tzinfo.friendly_identifier\n=> \"America - Chicago\"\n> chi.tzinfo.abbr\n=> \"CDT\"\n> chi.tzinfo.utc_offset\n=> -18000\n> chi.tzinfo.dst?\n=> true\n```\n\nAll of these and more. Run `ls chi.tzinfo` in a `pry` session to see what else.\n"
  },
  {
    "path": "rails/make-a-string-attribute-easy-to-inquire-about.md",
    "content": "# Make A String Attribute Easy to Inquire About\n\nHave you ever been curious why Rails environment checks work the way they do?\n\n```ruby\n> Rails.env\n#=> 'development'\n> Rails.env.development?\n#=> true\n```\n\nWhat is powering this is\n[`ActiveSupport::StringInquirer`](https://api.rubyonrails.org/classes/ActiveSupport/StringInquirer.html).\nAnd since it is part of `ActiveSupport`, you can use that functionality\nelsewhere in your Rails code.\n\nLet's look at an example:\n\n```ruby\nclass UserWithRole\n  attr_reader :name, :role\n\n  def initialize(name, role)\n    @name = name\n    @role = ActiveSupport::StringInquirer.new(role)\n  end\nend\n```\n\nWith that class defined, we can initialize a user and inquire about their role.\n\n```ruby\n> user = UserWithRole.new('Bob', 'instructor')\n#=> <UserWithRole ...>\n> user.role.instructor?\n#=> true\n> user.role.admin?\n#=> false\n> user.role\n#=> 'instructor'\n```\n\nThis helper class makes it much cleaner to inquire about the role of a user.\nNotice we don't have to do a string comparison to check if they are an\ninstructor, e.g.:\n\n```ruby\n> user.role == 'instructor'\n```\n"
  },
  {
    "path": "rails/make-action-mailer-synchronous-in-test.md",
    "content": "# Make ActionMailer Synchronous In Test\n\nWhen you set up an `ActionMailer` email, the default configuration is for it\nto use `ActiveJob` to send the emails. [As of Rails 5, it will do so\nasynchronously.](https://blog.bigbinary.com/2016/03/29/rails-5-changed-default-active-job-adapter-to-async.html).\nDepending on your preferences for testing emails, you may prefer `ActiveJob`\nto send the emails synchronously. This can be done by changing the\n`queue_adapter` back to `:inline` in your `config/environments/test.rb`.\n\n```ruby\nconfig.active_job.queue_adapter = :inline\n```\n\nIf you also configure the `delivery_method` as `:test`:\n\n```ruby\nconfig.action_mailer.delivery_method = :test\n```\n\nthen emails will be queued up in `ActionMailer::Base.deliveries` allowing\nyou to write a test like this:\n\n```ruby\nexpect(ActionMailer::Base.deliveries.count).to eq(1)\n```\n\nCheck out [the\ndocs](https://guides.rubyonrails.org/action_mailer_basics.html) for more on\n`ActionMailer`.\n\n[source](https://stackoverflow.com/a/42987726/535590)\n"
  },
  {
    "path": "rails/make-remove-column-migration-reversible.md",
    "content": "# Make Remove Column Migration Reversible\n\nThe Rails migration DSL includes a\n[`#remove_column`](https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_column)\nmethod for removing a column from a table.\n\nThe two required values are the table name and the column name.\n\n```ruby\nclass RemoveNotesColumnFromTodo < ActiveRecord::Migration[5.2]\n  def change\n    remove_column :todos, :notes\n  end\nend\n```\n\nThis on it's own is not reversible though. If you were to run a `db:rollback`\nwith this migration, Rails wouldn't know what type to use when re-adding the\ncolumn.\n\nTo make it reversible, you need to add in the column type as a third argument.\n\n```ruby\n    remove_column :todos, :notes, :string\n```\n\nNote: perhaps more importantly, this column isn't reversible in the sense that\nwhen you remove the column, you are throwing away all the data associated with\nthat column. Be sure you're ready to part with this data before deploying a\nmigration like this.\n\n[source](https://stackoverflow.com/questions/24520550/how-do-you-make-remove-column-reversible)\n"
  },
  {
    "path": "rails/manage-timestamps-with-upsert.md",
    "content": "# Manage Timestamps With Upsert\n\nModern versions of Rails and ActiveRecord have [an `upsert`\nmethod](https://api.rubyonrails.org/v8.0.2/classes/ActiveRecord/Relation.html#method-i-upsert)\nwhich will, if available, use your database's upsert capability to either\ninsert a new row or update an existing row based on the unique identifier.\n\nThe docs have the following disclaimer:\n\n> It does not instantiate any models nor does it trigger Active Record\n> callbacks or validations. Though passed values go through Active Record’s\n> type casting and serialization.\n\nIt's a bit different to work with than other ActiveRecord methods. It left me\nwondering if it would handle timestamp management or if I would have to do that\nmyself.\n\nLet's upsert a new record into `books`:\n\n```ruby\n> Book.upsert({title: \"Shogun\", author: \"James Clavell\", added_by_id: 1, publication_date: Date.today}, unique_by: :id)\n=> #<ActiveRecord::Result:0x00000001141c3df0 ...\n\n> Book.select(:id, :title, :created_at, :updated_at).last\n=> #<Book:0x0000000113bae898 id: 12, title: \"Shogun\", created_at: \"2025-06-26 14:08:26.035633000 +0000\", updated_at: \"2025-06-26 14:08:26.035633000 +0000\">\n```\n\nNotice that the `created_at` and `updated_at` timestamps get set.\n\nNow, let's upsert the record (notice we're passing in the `id`) to update the title with an `ō`.\n\n```ruby\n> Book.upsert({id: 12, title: \"Shōgun\", author: \"James Clavell\", added_by_id: 1, publication_date: Date.today}, unique_by: :id)\n=> #<ActiveRecord::Result:0x0000000113cace98 ...\n\n> Book.select(:id, :title, :created_at, :updated_at).last\n=> #<Book:0x00000001143aadd0 id: 12, title: \"Shōgun\", created_at: \"2025-06-26 14:08:26.035633000 +0000\", updated_at: \"2025-06-26 14:10:46.280480000 +0000\">\n```\n\nNotice that the `updated_at` gets set to a time about 2 minutes later.\n\nLastly let's look at the `record_timestamps` option. This is `nil` by default\nwhich means the underlying methods default kicks in which _is_ to record the\ntimestamps. We can override that behavior by passing in `false`.\n\n```ruby\n> Book.upsert({id: 12, title: \"Shōgun, Part 2\", author: \"James Clavell\", added_by_id: 1, publication_date: Date.today}, unique_by: :id, record_timestamps: false)\n=> #<ActiveRecord::Result:0x0000000113989428 ...\n\n> Book.select(:id, :title, :created_at, :updated_at).last\n=> #<Book:0x0000000114fe1b80 id: 12, title: \"Shōgun, Part 2\", created_at: \"2025-06-26 14:08:26.035633000 +0000\", updated_at: \"2025-06-26 14:10:46.280480000 +0000\">\n```\n\nNotice that the `updated_at` value doesn't change between this upsert and the\nprevious upsert.\n"
  },
  {
    "path": "rails/manually-run-a-migration-from-rails-console.md",
    "content": "# Manually Run A Migrations From Rails Console\n\nA migration can be manually run from the rails console. In 99% of cases you are\ngoing to be better off using the migration CLI that Rails provides (e.g. `rails\ndb:migrate`, `rails db:rollback`, etc.).\n\nIf you are in a hyper-specific scenario where you need to run the `up` or the\n`down` of a migration without the migration-table check, then you'll want to\nconsider this approach.\n\nFirst, connect to the rails console: `rails c`. Then require your migration\nfile.\n\n```ruby\n> require \"./db/migration/20200220181733_some_migration.rb\"\n#=> true\n```\n\nYou'll now have access to the `SomeMigration` constant. Create an instance of this and then run either the `up`-side of the migration:\n\n```ruby\n> SomeMigration.new.up\n#=> ... # a bunch of migration output\n```\n\nor the `down`-side of it:\n\n```ruby\n> SomeMigration.new.down\n#=> ... # a bunch of migration output\n```\n\n[source](https://stackoverflow.com/a/754316/535590)\n"
  },
  {
    "path": "rails/mark-a-migration-as-irreversible.md",
    "content": "# Mark A Migration As Irreversible\n\nIt is in your best interest to, as much as is possible, write your Rails\nmigrations in a way that they can be safely and reliably rolledback. You want\nyour `down` to mirror your `up`, in case anything goes wrong.\n\nThis isn't always possible though. There are some migrations, in particular\ndata migrations, that cannot be undone. Something is being changed or destroyed\nin an unrecoverable way. When this is the case, you should, by convention,\nraise an `IrreversibleMigration` exception.\n\n```ruby\nclass DestructiveMigration < ActiveRecord::Migration[5.2]\n  def up\n    execute \"-- some destructive SQL\"\n  end\n\n  def down\n    raise ActiveRecord::IrreversibleMigration\n  end\nend\n```\n\nIf anyone ever tries to rollback this migration, they will see the exception.\nIt will be a signal that some manual work is needed to continue rolling back.\n\nSee the\n[docs](https://api.rubyonrails.org/classes/ActiveRecord/Migration.html#class-ActiveRecord::Migration-label-Irreversible+transformations)\nfor more details.\n"
  },
  {
    "path": "rails/mark-for-destruction.md",
    "content": "# Mark For Destruction\n\nDo you have some complicated logic or criteria for deleting associated\nrecords? [ActiveRecord's\n`#mark_for_destruction`](http://api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html#method-i-mark_for_destruction) may come in handy.\n\nLet's say we have _users_ who author _articles_. We want to delete some of\nthe user's articles based on some criteria -- those articles that have odd\n`id`s.\n\n```ruby\n> user = User.first\n#=> #<User...>\n> user.articles.each { |a| a.mark_for_destruction if a.id.odd? }\n#=> [#<Article...>, ...]\n> user.articles.find(1).marked_for_destruction?\n#=> true\n> user.articles.find(2).marked_for_destruction?\n#=> false\n```\n\nWe've marked our articles for destruction and confirmed as much with the\n[`#marked_for_destruction?`](http://api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html#method-i-marked_for_destruction-3F) method. Now, to go through with the destruction, we just have to save the parent record -- the user.\n\n```ruby\n> user.save\n   (0.2ms)  BEGIN\n  User Exists (0.8ms)  SELECT  1 AS one FROM \"users\" WHERE (\"users\".\"email\" = 'person1@example.com' AND \"users\".\"id\" != 1) LIMIT 1\n  SQL (3.0ms)  DELETE FROM \"articles\" WHERE \"articles\".\"id\" = $1  [[\"id\", 1]]\n  SQL (0.2ms)  DELETE FROM \"articles\" WHERE \"articles\".\"id\" = $1  [[\"id\", 3]]\n   (2.1ms)  COMMIT\n=> true\n```\n\nNote: the parent record must have `autosave: true` declared on the\nassociation.\n\n```ruby\nclass User < ActiveRecord::Base\n  has_many :articles, autosave: true\nend\n```\n"
  },
  {
    "path": "rails/mask-an-activerecord-attribute.md",
    "content": "# Mask An ActiveRecord Attribute\n\nLet's say we have a `User` model with backing table that has an `email`\nattribute.\n\nIf we look up a `User` record, we can grab its email because Rails provides an\naccessor to that attribute under the hood.\n\n```ruby\n> user.email\n'Liz.Lemon@example.com'\n```\n\nWe can write a custom `#email` method on `User` to mask that attribute. We\ncould do this for any number of reasons. One might be to always downcase the\nemail before retrieving it and using it througout app code.\n\n```ruby\nclass User < ApplicationRecord\n  def email\n    read_attribute(:email).downcase\n  end\nend\n```\n\nThis uses the\n[`#read_attribute`](https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Read.html#method-i-read_attribute)\nmethod which retreives the type casted value before hitting the accessor\nmethod. We have to do this, rather than calling `#email` directly, because that\nwould result in an infinite loop.\n\n```ruby\n> user.email\n'liz.lemon@example.com'\n```\n\nI'd probably handle this email scenario at the DB-layer. Nevertheless, this\ndemonstrates a technique we can use in a variety of scenarios at the\nRails-layer.\n"
  },
  {
    "path": "rails/merge-a-scope-into-an-activerecord-query.md",
    "content": "# Merge A Scope Into An ActiveRecord Query\n\nConsider an ActiveRecord model with a scope:\n\n```ruby\nclass Book < ApplicationRecord\n  scope :published, -> { where(\"books.published_at is not null\") }\nend\n```\n\nNow let's say we are working in another part of the codebase composing a query\nthat gathers all authors with published books. That might look something like\nthis:\n\n```ruby\npublished_authors =\n  Authors.joins(:book).where(\"books.published_at is not null\")\n```\n\nThis will get the job done, but we've now duplicated the same logic in\ndifferent parts of the app. We can utilize the existing scope on `Book` using\nActiveRecord's\n[`merge`](https://devdocs.io/rails~5.2/activerecord/spawnmethods#method-i-merge)\nmethod.\n\n```ruby\npublished_authors =\n  Authors.joins(:book).merge( Book.published )\n```\n\nThe `merge` method can be used to incorporate any conditions from other partial\nqueries -- this means both `where` clauses and `joins` clauses.\n\n[source](http://aokolish.me/blog/2015/05/26/how-to-simplify-active-record-scopes-that-reference-other-tables/)\n"
  },
  {
    "path": "rails/migrating-up-down-up.md",
    "content": "# Migrating Up Down Up\n\nWhen writing Rails migrations, it is good to define, when possible, what\nshould happen when migrating *up* and what should happen when migrating\n*down*. You'll then want to check that both the *up* and *down* work. This\ncan be accomplished using the following one-liner:\n\n```bash\n$ rake db:migrate && rake db:migrate:redo\n```\n\nThe `rake db:migration` does what we would expect applying our new migration\nand showing us that our *up* works. The `rake db:migrate:redo` first\nperforms a rollback, showing us that our *down* works, and then migrates\nback up again. We now know that our latest migration works going both\ndirections.\n"
  },
  {
    "path": "rails/mock-rails-environment-with-an-inquiry-instance.md",
    "content": "# Mock Rails Environment With An Inquiry Instance\n\nAs discussed in [Make A String Attribute Easy to Inquire\nAbout](make-a-string-attribute-easy-to-inquire-about.md), the `Rails.env` is\nassigned an instance of `ActiveSupport::StringInquirer`. This allows us to ask\nwhether the current Rails environment is `#production?`, `#development?`, etc.\n\nWith this in mind, we can have a test execute in a specific environment by\nmocking how `Rails.env` responds. Though the actual env for a test is going to\nbe `test`, we can simulate a different environment with an RSpec `before` block\nlike the following:\n\n```ruby\nbefore do\n  allow(Rails).to receive(:env) { \"staging\".inquiry }\nend\n```\n\nOr similarly, to simulate the `production` environment:\n\n```ruby\nbefore do\n  allow(Rails).to receive(:env) { \"production\".inquiry }\nend\n```\n\nThe `#inquiry` being monkey-patched onto the `String` class gives you the\nwillies, you could do the following instead:\n\n```ruby\nbefore do\n  allow(Rails).to receive(:env) do\n    ActiveSupport::StringInquirer.new(\"production\")\n  end\nend\n```\n\n[source](https://stackoverflow.com/a/25134591/535590)\n"
  },
  {
    "path": "rails/order-matters-for-rescue-from-blocks.md",
    "content": "# Order Matters For `rescue_from` Blocks\n\nIn a Rails controller, you can declare any number of [`rescue_from`\nblocks](https://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html)\nfor capturing and responding to execeptions that are raised by your\napplication.\n\n```ruby\nclass BooksController < BaseController\n\n  rescue_from ForbiddenAction do |e|\n    render json: { error: e.message }.to_json, status: 403\n  end\n\n  rescue_from StandardError do |e|\n    render json: { error: e.message }.to_json, status: 500\n  end\n\n  def index\n    # ...\n\n    raise ForbiddenAction, \"Which rescue_from is this going to hit?\"\n  end\nend\n```\n\nThe potential problem with above is the ordering of the two `rescue_from`\nblocks. Assume that `ForbiddenAction` is a subclass of the `StandardError`\nclass -- this is likely the case for exceptions you declare in your app. The\ntop `rescue_from` will never get hit because everything that subclasses\n`StandardError` will be trapped by the bottom `rescue_from`.\n\nThese `rescue_from` blocks are applied bottom-up. That means you have to\nconsider the class hierarchy when structuring your code. In the above code\nexample, if we flip the two of them around, we will then get what we are\nexpecting.\n"
  },
  {
    "path": "rails/override-text-displayed-by-form-label.md",
    "content": "# Override Text Displayed By Form Label\n\nRails does a good job with the default text displayed by a form label. It takes\nthe primary symbol value you give it and capitalizes that. And that is often\ngood enough.\n\n```ruby\n<%= form_with(model: post) do |form| %>\n  <%= form.label :title, class: \"text-sm font-medium text-gray-700\" %>\n  <%= form.text_field :title, required: true, class: \"...\" %>\n<% end %>\n```\n\nThis will yield a label value of _Title_.\n\nSometimes, however, the casing needs to be different or you need entirely\ndifferent text. Take this URL field for example. Rails will convert `:url` into\n_Url_ for the label text. Not ideal. I can override the default with a second\npositional argument, in this case, `\"URL\"`.\n\n```ruby\n<%= form_with(model: post) do |form| %>\n  <%= form.label :url, \"URL\", class: \"text-sm font-medium text-gray-700\" %>\n  <%= form.url_field :url, required: true, class: \"...\" %>\n<% end %>\n```\n\nThe [Rails docs have another good\nexample](https://guides.rubyonrails.org/form_helpers.html#a-generic-search-form).\nA label with a value of `query` that is overridden to display \"Search for:\".\n\n```ruby\n<%= form_with url: \"/search\", method: :get do |form| %>\n  <%= form.label :query, \"Search for:\" %>\n  <%= form.search_field :query %>\n  <%= form.submit \"Search\" %>\n<% end %>\n```\n"
  },
  {
    "path": "rails/parameterize-a-string-with-underscores.md",
    "content": "# Parameterize A String With Underscores\n\nI have human-readable status strings that I'm working with like `In progress`,\n`Pending approval`, and `Completed`. I need to deterministically turn those\ninto parameterized values that I can compare. That is, I want them lowercased\nand separated by underscores instead of spaces.\n\nThe `ActiveSupport` `#parameterize` method, as is, gets me pretty close.\n\n```ruby\n> statuses = [\n  \"In progress\",\n  \"Pending approval\",\n  \"Completed\"\n]\n\n> statuses.map(&:parameterize)\n=> [\n  \"in-progress\",\n  \"pending-approval\",\n  \"completed\"\n]\n```\n\nThose are separated by dashes though. Fortunately, `parameterize` takes a\n`separator` option that we can use to verride what character is used to\nseparate words. Let's use an underscore (`_`).\n\n```ruby\n> statuses.map { |str| str.parameterize(separator: '_') }\n=> [\n  \"in_progress\",\n  \"pending_approval\",\n  \"completed\"\n]\n```\n\nSee the [`#paramterize`\ndocs](https://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-parameterize)\nfor more details.\n"
  },
  {
    "path": "rails/params-includes-submission-button-info.md",
    "content": "# Params Includes Submission Button Info\n\nWhen a form is submitted for a Rails app, the respective controller action\nwill have access to a variety of information in the `params` hash. Included\nis an entry with the name and value of the button that submitted the form.\nBy default, Rails will give the name `commit` to a submission button.\n\n```\n<%= f.submit %>\n# results in:\n<input type=\"submit\" name=\"commit\" value=\"Submit\">Submit</input>\n```\n\nThe corresponding `create` action will have parameters that include that\nsubmission button's info:\n\n```ruby\n# in create action\n> params['commit']\n=> 'Submit'\n```\n\nThis is useful when you have multiple buttons that submit the same form, but\nshould have slightly different results in the corresponding action.\nDifferentiating becomes easy when you can easily check which was used to\nsubmit the form. No javascript required.\n"
  },
  {
    "path": "rails/params-is-a-hash-with-indifferent-access.md",
    "content": "# Params Is A Hash With Indifferent Access\n\nWhen you have an instance of `ActionController::Parameters`—which you often do\nwith `params` in a Rails controller—under the hood you have a\n`HashWithIndifferentAccess`.\n\nHere is what the initializer looks like when you call\n`ActionController::Parameters.new(some_hash)`.\n\n```ruby\ndef initialize(parameters = {}, logging_context = {})\n  @parameters = parameters.with_indifferent_access\n  @logging_context = logging_context\n  @permitted = self.class.permit_all_parameters\nend\n```\n\nThis means you can reference the keys in your parameters as either a _string_\nkey or a _symbol_ key.\n\n```ruby\n> params = ActionController::Parameters.new({ username: 'tacocat' })\n=> #<ActionController::Parameters {\"username\"=>\"tacocat\"} permitted: false>\n> params['username']\n=> \"tacocat\"\n> params[:username]\n=> \"tacocat\"\n```\n\nNote that `ActiveSupport::HashWithIndifferentAccess` is not an ancestor of the\n`ActionController::Parameters` class (like it once used to be), but is just how\nthe incoming hash is transformed when initialized.\n"
  },
  {
    "path": "rails/parse-query-params-from-a-url.md",
    "content": "# Parse Query Params From A URL\n\nFor all of the conveniences that Ruby and Rails affords a developer through\ntheir expansive APIs, I am always surprised that it is hard to inspect the\nquery params in a URL.\n\nLet's take a URL and walk through the steps it takes to pull out the value of a\nquery param.\n\nHere's a URL:\n\n```ruby\nurl = \"https://example.com?taco=bell&taco_count=3\"\n=> \"https://example.com?taco=bell&taco_count=3\"\n```\n\nLet's parse the URL with `URI`:\n\n```ruby\n> URI(url)\n=> #<URI::HTTPS https://example.com?taco=bell&taco_count=3>\n```\n\nThen grab the `query` part of that `URI`:\n\n```ruby\n> URI(url).query\n=> \"taco=bell&taco_count=3\"\n```\n\nThis is an unparsed string. In a Rails context, this can be parsed with\n`Rack::Utils.parse_nested_query`:\n\n```ruby\n> query_params = Rack::Utils.parse_nested_query(URI(url).query)\n=> {\"taco\"=>\"bell\", \"taco_count\"=>\"3\"}\n```\n\nAnd now we have a hash of values we can inspect:\n\n```ruby\n> query_params[\"taco_count\"]\n=> \"3\"\n```\n\nBe sure to do _string_ and not _symbol_ hash access here.\n\nThese steps can be wrapped up into a method:\n\n```ruby\nmodule UrlHelpers\n  def query_params(url)\n    unparsed_query_params = URI(url).query\n    Rack::Utils.parse_nested_query(unparsed_query_params)\n  end\nend\n```\n\n[source](https://stackoverflow.com/a/3218018/535590)\n"
  },
  {
    "path": "rails/parse-request-params-in-rack-attack-block.md",
    "content": "# Parse Request Params In Rack::Attack Block\n\nThe [`Rack::Attack` docs](https://github.com/rack/rack-attack) demonstrate a\nway of throttling requests based on a value in the request params. In this\nexample, it is a Sign In endpoint and the `email` is the discriminating value.\n\n```ruby\nRack::Attack.throttle('limit logins per email', limit: 6, period: 60) do |req|\n  if req.path == '/login' && req.post?\n    # Normalize the email, using the same logic as your authentication process, to\n    # protect against rate limit bypasses.\n    req.params['email'].to_s.downcase.gsub(/\\s+/, \"\")\n  end\nend\n```\n\nDepending on the particulars of your middleware, it may be the case that\n`req.params` is empty. That is because the request params need to be manually\nparsed from the body of the request.\n\nAn updated example that parses the params before accessing them could look like\nthis:\n\n```ruby\nRack::Attack.throttle('limit logins per email', limit: 6, period: 60) do |req|\n  if req.path == '/login' && req.post?\n    params = JSON.parse(req.body.string)\n\n    # Normalize the email, using the same logic as your authentication process, to\n    # protect against rate limit bypasses.\n    params['email'].to_s.downcase.gsub(/\\s+/, \"\")\n  end\nend\n```\n\nYou can pry into the block or add some logging to ensure that you are getting\nat the POST params you are interested in.\n\n[source](https://github.com/rack/rack-attack/issues/189#issuecomment-744593703)\n"
  },
  {
    "path": "rails/perform-sql-explain-with-activerecord.md",
    "content": "# Perform SQL Explain With ActiveRecord\n\nWant to check out the performance characteristics of some SQL query from\nwithin a Pry session? `ActiveRecord` allows you to perform a SQL `explain`\non any `ActiveRecord::Relation` object. After chaining some Arel functions\ntogether, add an `#explain`.\n\nHere is an example:\n\n```ruby\nRecipe.all.joins(:ingredient_amounts).explain\n  Recipe Load (0.9ms)  SELECT \"recipes\".* FROM \"recipes\" INNER JOIN \"ingredient_amounts\" ON \"ingredient_amounts\".\"recipe_id\" = \"recipes\".\"id\"\n=> EXPLAIN for: SELECT \"recipes\".* FROM \"recipes\" INNER JOIN \"ingredient_amounts\" ON \"ingredient_amounts\".\"recipe_id\" = \"recipes\".\"id\"\n                                 QUERY PLAN\n----------------------------------------------------------------------------\n Hash Join  (cost=1.09..26.43 rows=22 width=148)\n   Hash Cond: (ingredient_amounts.recipe_id = recipes.id)\n   ->  Seq Scan on ingredient_amounts  (cost=0.00..21.00 rows=1100 width=4)\n   ->  Hash  (cost=1.04..1.04 rows=4 width=148)\n         ->  Seq Scan on recipes  (cost=0.00..1.04 rows=4 width=148)\n(5 rows)\n```\n\n[source](https://robots.thoughtbot.com/why-postgres-wont-always-use-an-index)\n"
  },
  {
    "path": "rails/polymorphic-path-helpers.md",
    "content": "# Polymorphic Path Helpers\n\nUnderlying many of the path helpers that we use day to day when building out\nthe views in our Rails apps are a set of methods in the\n[`ActionDispatch::Routing::PolymorphicRoutes`](http://api.rubyonrails.org/classes/ActionDispatch/Routing/PolymorphicRoutes.html)\nmodule.\n\nThe `#polymorphic_path` method given an instance of a model will produce the\nrelevant show path.\n\n```ruby\n> app.polymorphic_path(Article.first)\n  Article Load (0.5ms)  SELECT  \"articles\".* FROM \"articles\"  ORDER BY \"articles\".\"id\" ASC LIMIT 1\n=> \"/articles/2\"\n```\n\nGiven just the model's constant, it will produce the index path.\n\n```ruby\n> app.polymorphic_path(Article)\n=> \"/articles\"\n```\n\nAdditionally, there are variants with `edit_` and `new_` prefixed for\ngenerating the edit and new paths respectively.\n\n```ruby\n> app.edit_polymorphic_path(Article.first)\n  Article Load (0.6ms)  SELECT  \"articles\".* FROM \"articles\"  ORDER BY \"articles\".\"id\" ASC LIMIT 1\n=> \"/articles/2/edit\"\n> app.new_polymorphic_path(Article)\n=> \"/articles/new\"\n```\n"
  },
  {
    "path": "rails/prefer-select-all-over-execute-for-read-queries.md",
    "content": "# Prefer select_all Over execute For Read Queries\n\nThough the `#execute` function provided by ActiveRecord technically works as a\ngeneral-purpose query runner for strings of raw SQL, it has some downsides.\n\nFirst, let's say we have a large semi-complex (better in SQL than ActiveRecord\nDSL) SQL query defined in a heredoc.\n\n```ruby\nbooks_by_status_query = <<-SQL\n  select\n    books.*,\n    latest_statuses.status as current_status,\n    array_to_json(array_agg(...)) as reading_statuses\n  from books\n  -- plus several left joins\n  -- where clause, group by, and order by\nSQL\n```\n\nI reflexively reach for\n[`#execute`](https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html#method-i-execute)\nin a situation like that:\n\n```ruby\nresult = ActiveRecord::Base.connection.execute(books_by_status_query)\n```\n\nHowever, if we're doing a read-only query and we are expecting multiple rows in\nthe result, then we are better off reaching for\n[`#select_all`](https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html#method-i-select_all).\n\n```ruby\nresult = ActiveRecord::Base.connection.select_all(books_by_status_query)\n```\n\nIt has the advantage of semantically communicating that it's just a read and\nwon't have any side-effects. It also avoids an unnecessary clear of the query\ncache.\n\n> Note: [when execute is used] the query is assumed to have side effects and\n> the query cache will be cleared. If the query is read-only, consider using\n> select_all instead.\n\nThe `#execute` method also has been known to leak memory with some database\nconnectors.\n\n> Note: depending on your database connector, the result returned by this\n> method may be manually memory managed. Consider using exec_query wrapper\n> instead.\n\nWe can then iterate through and transform the results just as we would have\ndone with `#execute`.\n\n```ruby\nresult.map do |row|\n  row.tap do |hash|\n    hash[\"reading_statuses\"] = JSON.parse(hash[\"reading_statuses\"])\n  end\n\n  OpenStruct.new(row)\nend\n```\n"
  },
  {
    "path": "rails/pretend-generations.md",
    "content": "# Pretend Generations\n\nTo get an idea of what a `rails generate` command is going to to\n*generate*, you can do a dry run with the `-p` flag or\nthe `--pretend` flag. If you run\n\n```\n$ rails generate model post -p\n```\n\nthen you will see the following output\n\n```\n    invoke  active_record\n    create    db/migrate/20150513132556_create_posts.rb\n    create    app/models/post.rb\n    invoke    rspec\n    create      spec/models/post_spec.rb\n    invoke      factory_girl\n    create        spec/factories/posts.rb\n```\n\nthough those files will not have actually been created. You now know\nprecisely what rails will generate for you.\n\n[source](http://rubyquicktips.com/post/19223887750/pretend-to-generate)\n"
  },
  {
    "path": "rails/prevent-mailer-previews-from-cluttering-database.md",
    "content": "# Prevent Mailer Previews From Cluttering Database\n\nActionMailer Previews give you a way to view email templates that your system\nsends. This is how I check that it is styled properly and that the logic and\ndata of the template are able to run and render.\n\nData for a preview typically means we need ActiveRecord objects and even their\nassociations. If we start creating one-off records in our previews either with\n`#create` or with something like `FactoryBot`, those records will get left\nbehind in our development database. Every view and refresh of a preview will\ngenerate more of these records.\n\nOne way to get around that is to use `#new` and `#build`. I've found this\ncumbersome and it often leaves assocations missing or inaccessible.\n\nWhat if instead the preview could clean up after itself? That sounds like a\ngreat job for a database transaction.\n\nLet's create a `test/mailers/previews/base_preview.rb` as a base class for all\nour preview classes.\n\n```ruby\nclass BasePreview < ActionMailer::Preview\n  def self.call(...)\n    message = nil\n    ActiveRecord::Base.transaction do\n      message = super(...)\n      raise ActiveRecord::Rollback\n    end\n    message\n  end\nend\n```\n\nThis wraps the existing `self.call` functionality in a transaction that\ncollects the resulting message from the preview and then rolls back the\ndatabase changes.\n\nNow, instead of our individual preview classes inheriting directly from\n`ActionMailer::Preview`, they can inherit from `BasePreview`.\n\n```ruby\nclass UserMailer < BasePreview\n\n  # ...\n\nend\n```\n\n[source](https://stackoverflow.com/a/31289295)\n"
  },
  {
    "path": "rails/prevent-writes-with-a-sandboxed-rails-console.md",
    "content": "# Prevent Writes With A Sandboxed Rails Console\n\nI often open a `rails console` to play around with some data and make sure I\nunderstand how some models can be instantiated while respecting their\nassociations. There are plenty of times where I've created some data in the\n`development` database that doesn't need to be there. It may even be incomplete\ndata from a failed experiment.\n\nThis data accumlates and clutters up the database.\n\nOne way to avoid this is by running the console in a sandboxed mode. Include\nthe `--sandbox` flag when starting up a session to do this.\n\n```bash\n$ rails console --sandbox\nLoading development environment in sandbox (Rails 5.2.6)\nAny modifications you make will be rolled back on exit\n[1] pry(main)>\n```\n\nThis wraps the session in a transaction so that any writes to the database can\nbe rolledback afterward.\n\n[source](https://dev.to/citizen428/rails-quick-tips-1-console-sandbox-4k0c)\n"
  },
  {
    "path": "rails/provide-fake-form-helper-to-controllers.md",
    "content": "# Provide Fake Form Helper To Controllers\n\nI'm rendering a partial from a turbo stream. The partial is meant to be\nrendered within a Rails form object because it contains an input element that\nneeds to reference the form object. The problem is that from the controller\nthat is streaming the partial, there is no\n[FormBuilder](https://api.rubyonrails.org/v6.1.0/classes/ActionView/Helpers/FormBuilder.html)\nobject.\n\nOne way to get around this that I've borrowed from [Justin\nSearls](https://justin.searls.co/posts/instantiate-a-custom-rails-formbuilder-without-using-form_with/)\nis with a `FauxFormHelper`.\n\n```ruby\nmodule FauxFormHelper\n  FauxFormObject = Struct.new do\n    def errors\n    end\n\n    def method_missing(...)\n    end\n\n    def respond_to_missing?(...)\n      true\n    end\n  end\n\n  def faux_form\n    @faux_form ||= ActionView::Helpers::FormBuilder.new(\n      nil,\n      FauxFormObject.new,\n      self,\n      {}\n    )\n  end\nend\n```\n\nThis module defines and exposes a `faux_form` object that controllers and views\ncan access. Then my partial can recieve that form object as a parameter.\n"
  },
  {
    "path": "rails/query-a-single-value-from-the-database.md",
    "content": "# Query A Single Value From The Database\n\nIn a Rails context, most database interactions tend to happen through the ORM\n(e.g. `Book.find(\"123\")`). There is a general purpose escape hatch that lets\nyou execute a SQL statement directly against the DB -- `execute`. The resulting\nvalue of `execute`, however, tends to be a little clunky to work with.\n\nIf you just need a single value from the DB, use the\n[`select_value`](https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html#method-i-select_value)\nmethod.\n\n```ruby\n> statement = \"select gen_random_uuid()\"\n> ActiveRecord::Base.connection.select_value(statement)\n   (5.0ms)  select gen_random_uuid()\n => \"abc2e780-f442-418b-afa3-56f0ccd0a903\"\n```\n\nThis is the cleanest way to get the result of a \"single value\" query.\n\nIf you happen to pass in a query that results in more than one row or column,\nit will return the value of the first column from the first row.\n"
  },
  {
    "path": "rails/read-in-environment-specific-config-values.md",
    "content": "# Read In Environment-Specific Config Values\n\nThe [`config_for`](https://apidock.com/rails/Rails/Application/config_for)\nmethod allows you to read in a YAML file for the current environment in your\nconfig files. These YAML files need to be located in the `config` directory.\n\nFor instance, let's say you have `config/extra_settings.yml`:\n\n```yml\ndevelopment:\n  support_email: support+dev@test.com\n\nproduction:\n  support_email: support@test.com\n```\n\nYou can read that file in as part of your `application.rb` config setup:\n\n```ruby\n# config/application.rb\nmodule MyApp\n  class Application < Rails::Application\n    extra_settings = config_for(:extra_settings)\n    set_support_email(extra_settings.fetch(:support_email))\n  end\nend\n```\n\nIn `development` this call to `config_for` would return a hash of the values\nunder `development`. Likewise in `production`.\n"
  },
  {
    "path": "rails/read-only-models.md",
    "content": "# Read-Only Models\n\nAre you in the midst of a big refactoring that is phasing out an\n`ActiveRecord` model? You may not be ready to wipe it from the project, but\nyou don't want it accidentally used to create any database records. You\nessentially want your model to be read-only until it is time to actually\ndelete it.\n\nThis can be achieved by adding a `readonly?` method to that model that\nalways returns `true`.\n\n```ruby\ndef readonly?\n  true\nend\n```\n\n`ActiveRecord`'s underlying persistence methods always check `readonly?`\nbefore creating or updating any records.\n\n[source](http://stackoverflow.com/questions/5641410/is-there-an-easy-way-to-make-a-rails-activerecord-model-read-only)\n\nh/t Josh Davey\n"
  },
  {
    "path": "rails/rebuild-tailwind-bundle-for-dev-server.md",
    "content": "# Rebuild Tailwind Bundle For Dev Server\n\nIf you're using the TailwindCSS gem in your Rails app:\n\n```ruby\n# Use Tailwind CSS [https://github.com/rails/tailwindcss-rails]\ngem \"tailwindcss-rails\"\n```\n\nyou may find that as you add and adjust styles in your views, refreshing the\npage doesn't take any styling effects. That is because the tailwind bundle gets\nbuilt with just the style rules that were used at the time it was generated.\n\nIn development, as we're working, we expect the styles used by our app to\nactively changed. And we don't mind a little performance hit to have the bundle\nrebuilt. In that case, we can instruct `puma` to _Live Rebuild_ in\n`development` with the `tailwindcss` plugin.\n\n```ruby\n# config/puma.rb\n\n# Enable TailwindCSS rebuild in development\nplugin :tailwindcss if ENV.fetch(\"RAILS_ENV\", \"development\") == \"development\"\n```\n\nThis has `rails server` run a watch process in the background that live\nrebuilds the bundle.\n\n[source](https://github.com/rails/tailwindcss-rails?tab=readme-ov-file#puma-plugin)\n"
  },
  {
    "path": "rails/remove-a-database-column-from-a-table.md",
    "content": "# Remove A Database Column From A Table\n\nThe `ActiveRecord` migration DSL includes a method\n[`remove_column`](https://api.rubyonrails.org/v7.0.3.1/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_column)\nthat can be used to remove an existing column from a table.\n\nIt can be used like so, to remove the `sign_in_count` column from the `users`\ntable.\n\n```ruby\ndef change\n  remove_column :users, :sign_in_count\nend\n```\n\nThough that will work fine, you'll run into an `IrreversibleMigration` error if\nyou try to `rails db:rollback`. It usually a good bet to make migrations\nreversible when it is easy to do so.\n\nAll we need in order to make this migration reversible is to add the column\ntype.\n\n```ruby\ndef change\n  remove_column :users, :sign_in_count, :integer\nend\n```\n\nNow you can rollback (or [migrate up-down-up](migrating-up-down-up.md)) no\nproblem.\n\nKeep in mind that only the structural changes are reversible. When you remove\nthe column, all of the data goes with it, and that cannot be undone with a\nsimple rollback.\n"
  },
  {
    "path": "rails/remove-the-default-value-on-a-column.md",
    "content": "# Remove The Default Value On A Column\n\nYou have a column on one of your database tables with a default value. You'd\nlike to remove the default value. Removing the default is the same as\nsetting it to `nil`. You can do this with the ActiveRecord DSL using the\n`change_column_default` method.\n\n```ruby\ndef change\n  change_column_default :users, :age, nil\nend\n```\n\nSee [the\ndocs](http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-change_column_default)\nfor more details.\n"
  },
  {
    "path": "rails/render-an-alternative-action-mailer-template.md",
    "content": "# Render An Alternative ActionMailer Template\n\nThe convention for Rails's ActionMailer is to render the view template that\ncorresponds to the mailer class's name and the specific action.\n\nFor instance, the `welcome_email` method in the `RegistrationMailer` class will\ncorrespond to the `app/views/registration_mailer/welcome_email.html.erb` view.\n\nThis convention can be overridden. By passing, the `template_name` and\n`template_path` arguments as options to the `mail` method, you can tell the\nmailer to render a different template.\n\n```ruby\nclass RegistrationMailer < ActionMailer::Base\n  def welcome_email\n    # mail setup ...\n\n    mail(to: @user.email,\n        subject: 'Welcome!',\n        template_name: 'new_welcome')\n  end\nend\n```\n\nThis will look for and use the\n`app/views/registration_mailer/new_welcome.html.erb` template.\n\nAlso including the `template_path` option will alter the path to the named\ntemplate:\n\n```ruby\nclass RegistrationMailer < ActionMailer::Base\n  def welcome_email\n    # mail setup ...\n\n    mail(to: @user.email,\n        subject: 'Welcome!',\n        template_path: 'v2_mailer_templates',\n        template_name: 'new_welcome')\n  end\nend\n```\n\nThis will look for the `app/views/v2_mailer_templates/new_welcome.html.erb`\ntemplate.\n\n[source](https://guides.rubyonrails.org/action_mailer_basics.html#mailer-views)\n"
  },
  {
    "path": "rails/render-the-response-body-in-controller-specs.md",
    "content": "# Render The Response Body In Controller Specs\n\nController specs skip the rendering of views by default. If you want to inspect\nsome aspect of what is rendered in the HTML body of a response\n(`response.body`), you can include the `render_views` directive in that spec.\n\n```ruby\nrequire 'rails_helper'\n\nRSpec.describe DashboardController do\n  describe '#index' do\n    render_views\n\n    context 'when there is a signed in user' do\n      it 'includes their email' do\n        user = User.create(email: 'user@example.com')\n\n        sign_in(user)\n\n        get :index\n\n        expect(response.body).to include('user@example.com')\n      end\n    end\n  end\nend\n```\n\nThe `render_views` directive call can go at the top of a spec, and all views\nfor all tests will be rendered. Or you can place it in the nested contexts only\nwhere it is needed.\n\nView rendering is skipped by default in an effort to keep tests speedy. To not\nunnecessarily slow down your test suite, make sure to use it sparingly and only\nin tests where you are actually inspecting `response.body`.\n"
  },
  {
    "path": "rails/replace-an-index-with-a-unique-index.md",
    "content": "# Replace An Index With A Unique Index\n\nIndexes and uniqueness constraints often go together. In fact, in Postgres,\nwhen you create a unique constraint, an index is created under the hood to\nsupport that constraint.\n\nWhat if you already have an index, but you want to turn it into a unique index?\nThere is no way to alter or update the index to be unique. Instead, what you'll\nwant to do is drop the index and then recreate it as a unique index.\n\nHere's how you can do that with the Rails migration DSL:\n\n```ruby\nclass ReplaceIndexWithUniqueIndex < ActiveRecord::Migration[5.2]\n  disable_ddl_transaction!\n\n  def up\n    remove_index :users_roles, [:user_id, :role_id]\n    add_index :users_roles, [:user_id, :role_id], unique: true, algorithm: :concurrently\n  end\n\n  def down\n    remove_index :users_roles, [:user_id, :role_id]\n    add_index :users_roles, [:user_id, :role_id], algorithm: :concurrently\n  end\nend\n```\n\nThis removes the original multi-column index and then adds back in a unique\nindex that covers the same columns. I added `disable_ddl_transactions!` so that\nthe new index could be added concurrently.\n\nI've also included a `down` migration that reverses the process in case a\nrollback is needed.\n"
  },
  {
    "path": "rails/rescue-from-with-a-separate-method.md",
    "content": "# Rescue From With A Separate Method\n\nIn an earlier post on [`rescue_from`](rescue_from.md), I showed how you can\nwrite an exception handler with a block argument.\n\nIf instead you'd prefer to implement the exception handler as a separate\nmethod, you can do that by passing\n[`rescue_from`](http://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html)\na `with` keyword argument. This too will behave as a catch-all for a particular\nexception raised in your controller.\n\nHere is what that can look like:\n\n```ruby\nclass ApplicationController < ActionController::Base\n  rescue_from User::NotAuthorized, with: :handle_unauthorized_user\n\n  def index\n    # ...\n  end\n\n  private\n\n  def handle_unauthorized_user(exception)\n    # respond with some Not Authorized page\n  end\nend\n```\n\nIf the `User::NotAuthorized` exception bubbles up to the `rescue_from`, then it\nwill hand that exception off to the `handle_unauthorized_user` method. We can\ninclude whatever logic and monitoring we want here and then render an\nappropriate response.\n"
  },
  {
    "path": "rails/rescue-from.md",
    "content": "# Rescue From\n\nThe\n[`rescue_from`](http://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html)\nmethod, provided by `ActiveSupport`, is a handy way to provide a catch-all\nresponse to a particular exception in Rails controllers.\n\nFor instance, if many of the controllers in your application raise a\n`User::NotAuthorized` error for unauthorized requests, the\n`ApplicationController` can provide a unified response. This will help dry\nup your controllers and prevent any potential inconsistencies.\n\n```ruby\nclass ApplicationController < ActionController::Base\n  rescue_from User::NotAuthorized do |exception|\n    # respond with some Not Authorized page\n  end\n\n  ...\nend\n```\n"
  },
  {
    "path": "rails/respond-with-json-regardless-of-content-type.md",
    "content": "# Respond With JSON Regardless Of Content Type\n\nLet's say you want to serve some JSON from an endpoint (for example, you might\nbe serving [the `apple-app-site-association` file for iOS Universal\nLinks](https://developer.apple.com/documentation/xcode/supporting-associated-domains)).\nRegardless of whether the endpoint is requested as JSON (`application/json`),\nHTML (`text/html`), or something else (`plain/text`), you want to respond with\nJSON.\n\nThe [`format#any`\nmethod](https://api.rubyonrails.org/classes/ActionController/MimeResponds.html)\ncan be used when defining the `respond_to` block. This tells the controller\nthat _any_ mimetype is accepted.\n\n```ruby\ndef show\n  respond_to do |format|\n    format.any do\n      render params[:page],\n        formats: 'json',\n        content_type: \"application/json\",\n        layout: false\n    end\n  end\nend\n```\n\nThe other important element in this is `formats: 'json'` which helps Rails find\nyour `<template_name>.json.erb` file in the `views` directory.\n\nThough I cannot find any documentation for it, `format.all` appears to work the\nsame as `format.any` as described in the above example.\n\nh/t Dillon Hafer\n"
  },
  {
    "path": "rails/restart-puma-server-by-touching-restart-file.md",
    "content": "# Restart Puma Server By Touching Restart File\n\nPuma includes a plugin that allows us to restart the web server by touching the\n`tmp/restart.txt` file.\n\nIn one terminal pane I have my Rails server running. In another terminal pane\nfrom the Rails directory, where there exists a `tmp` folder, I run the\nfollowing command.\n\n```bash\n$ touch tmp/restart.txt\n```\n\nThen in the pane running the Rails server, I see the following after a second:\n\n```\n* Restarting...\n=> Booting Puma\n=> Rails 8.0.1 application starting in development\n...\n```\n\nWhat is happening is that `touch` updates the modified time of that file, which\nalready exists in the `temp` directory. When the plugin notices (it checks\nevery 2 seconds) that the modified time is now fresher than the original\nmodified time when the plugin started, then it calls `launcher.restart`.\n\n[source](https://github.com/puma/puma/blob/ca201ef69757f8830b636251b0af7a51270eb68a/lib/puma/plugin/tmp_restart.rb)\n"
  },
  {
    "path": "rails/retrieve-an-object-if-it-exists.md",
    "content": "# Retrieve An Object If It Exists\n\nRails' Active Support provides the `blank?` and `present?` convenience\nmethods as extensions to many objects. It also extends the Object class by\nproviding the [`presence`](http://api.rubyonrails.org/classes/Object.html#method-i-presence)\nmethod. This method returns the *receiver* if it is not blank, otherwise\nit returns nil.\n\nInstead of doing\n\n```ruby\nUser.nickname.present? ? User.nickname : User.firstname\n```\n\nI can simply do\n\n```ruby\nUser.nickname.presence || User.firstname\n```\n"
  },
  {
    "path": "rails/rollback-a-couple-migrations.md",
    "content": "# Rollback A Couple Migrations\n\nLet's say we need to rollback a couple Rails migrations that have been applied\nto our local environment. We run `rails db:migrate:status` and see that there\nare _2_ migrations that we want to _undo_.\n\nWe can accomplish this by using the `STEP` env var with the rollback command.\n\n```bash\n$ rails db:rollback STEP=2\n```\n\nJust set `STEP` to the number of migrations that we need to rollback. If we\nthen rerun `rails db:migrate:status` we'll now see those latest two migrations\nare `down`.\n\nNote: by default Rails doesn't like to operate with pending migrations. If we\nwant to temporarily disable the pending migration check, we can alter the\nmigration error config in `config/development.rb`.\n\n```diff\n  # Raise an error on page load if there are pending migrations.\n-  # config.active_record.migration_error = :page_load\n+  config.active_record.migration_error = false\n```\n"
  },
  {
    "path": "rails/rollback-a-specific-migration-out-of-order.md",
    "content": "# Rollback A Specific Migration Out Of Order\n\nIf you want to rollback the latest migration that is `up`, you can use:\n\n```bash\n$ rails db:rollback\n```\n\nIt deals explicitly with the latest `up` migration and nothing else. Even if\nyou name a specific `VERSION`, it will still just rollback the one latest.\n\nInstead, if you want to target a specific past migration for rollback, you'll\nwant the `db:migrate:down` command. You'll need to specify the version, which\nis the timestamp number in the filename of the migration.\n\nHere is what this looks like for a recent migration I had to rollback.\n\n```bash\n$ rails db:migrate:down VERSION=20210302171858\n```\n\n[source](https://stackoverflow.com/a/3647820/535590)\n"
  },
  {
    "path": "rails/rounding-numbers-with-precision.md",
    "content": "# Rounding Numbers With Precision\n\nRuby's `Float#round` method gets the job done, but doesn't offer much\nconfigurability. If you'd like to finely control how a rounded number will\ndisplay, `ActiveSupport::NumberHelper` offers\n[`number_to_rounded`](https://api.rubyonrails.org/classes/ActiveSupport/NumberHelper.html#method-i-number_to_rounded).\n\nWhen a precision is specified, it will apply to the fraction digits:\n\n```ruby\n> ActiveSupport::NumberHelper.number_to_rounded(1.0, precision: 2)\n=> \"1.00\"\n```\n\nUnless you include `significant: true` in which case precision will refer to\nthe number of signficant digits:\n\n```ruby\n> ActiveSupport::NumberHelper.number_to_rounded(1.0, precision: 2, significant: true)\n=> \"1.0\"\n```\n\nBecause this is for display purposes, the return value is a string. You can\nfurther specify that insignificant zeros are stripped from the result:\n\n```ruby\n> ActiveSupport::NumberHelper.number_to_rounded(1.0, precision: 2, significant: true, strip_insignificant_zeros: true)\n=> \"1\"\n```\n\nAnd for completeness, here is an example of a number being rounded up:\n\n```ruby\n> ActiveSupport::NumberHelper.number_to_rounded(1.29, precision: 2, significant: true)\n=> \"1.3\"\n```\n\n[source](https://api.rubyonrails.org/classes/ActiveSupport/NumberHelper.html#method-i-number_to_rounded)\n"
  },
  {
    "path": "rails/run-a-rake-task-programmatically.md",
    "content": "# Run A Rake Task Programmatically\n\nTypically the way to run a rake task is with the `rake` command from the\ncommand line.\n\n```bash\n$ rake example:env\n```\n\nWhat if you have a rake task that you want to invoke as part of a Ruby script\nor from somewhere in your Rails codebase?\n\nYour tasks can be called programmatically as well.\n\nConsider these two rake tasks:\n\n```ruby\nnamespace :example do\n  task :env do\n    puts \"Current Environment: #{Rails.env.upcase}\"\n  end\n\n  task :message, [:msg] do |task, args|\n    puts \"Message: #{args[:msg]}\"\n  end\nend\n```\n\nThese can be called from somewhere else by referencing and invoking them like\nso.\n\n```ruby\nRake::Task[\"example:env\"].invoke\nRake::Task[\"example:message\"].invoke(\"Nice rake task!\")\n```\n"
  },
  {
    "path": "rails/run-commands-with-specific-rails-version.md",
    "content": "# Run Commands With Specific Rails Version\n\nYou can have multiple versions of a gem like `rails` installed with `gem`.\nHowever, when you go to run a rails command, your system will default to using\nthe latest version that you have installed.\n\nSo doing a version check will show that version to currently be `7.1.3` and\nrunning something like `rails new` will set up a new Rails 7.1.3 app.\n\n```bash\n$ rails --version\nRails 7.1.3\n\n$ rails new my_app\n```\n\nIf you want to use a Rails version besides the latest you have installed for\nwhatever command, you can use a `gem` convention which is to put `_<VERSION>_`\nright after the gem name.\n\nLet's try this for Rails 6.1.3:\n\n```bash\n$ rails _6.1.3_ --version\nRails 6.1.3\n\n$ rails _6.1.3_ new my_app\n```\n\n[source](https://stackoverflow.com/a/452458/535590)\n"
  },
  {
    "path": "rails/run-dev-processes-with-overmind-instead-of-foreman.md",
    "content": "# Run Dev Processes With Overmind Instead Of Foreman\n\nMost Rails projects that I have worked on have used\n[`foreman`](https://github.com/ddollar/foreman) as a development dependency for\nrunning all the processes declared in your Procfile (`Procfile.dev`). As far as\nhaving a single command to run everything (Rails server, asset building,\nworker(s), etc.), it does the job.\n\n`foreman` has some serious points of friction though. The one that really stands\nout to me is that when I try to debug the development Rails server with\n`binding.irb` or `binding.pry`, the other processes tend to interfere.\n\nThe alternative to `foreman` that I've been trying out recently is\n[`overmind`](https://github.com/DarthSim/overmind). A specific selling point of\n`overmind` is that it runs all the development processes in a `tmux` session.\nThat means you can individually connect to, inspect, and restart each process.\n\nOnce you've installed `overmind` (`brew install overmind`), then you can easily\nswap it in for `foreman` like so:\n\n```bash\n$ overmind start -f Procfile.dev\n```\n\nYou can connect to any of those processes directly:\n\n```bash\n$ overmind connect sidekiq\n```\n\nWhen you want to `binding.irb` the Rails server, you can specifically connect to\nthe `web` process to do that.\n\n```bash\n$ overmind connect web\n```\n\nIf you need to stop all the process, you can run the `kill` subcommand.\n\n```bash\n$ overmind kill\n```\n\nLastly, if you have a `bin/dev` script in your project, it is probably using\n`foreman`. If you and your team prefer `overmind`, then update that script\naccordingly and you can simply run `bin/dev` going forward.\n"
  },
  {
    "path": "rails/run-rails-console-with-remote-dokku-app.md",
    "content": "# Run Rails Console With Remote Dokku App\n\nWhenever I want to `rails console` into the _staging_ server of an app I'm\nworking on, I first have to `ssh` into server and then I have to come up with\nthe [`dokku`](https://dokku.com/) command to run `rails console` against the app\non that server.\n\n```bash\nlocal> ssh app-staging # app-staging is an SSH alias\nstaging> dokku run my-app rails console\n```\n\nI figured out how to reduce the friction of this by collapsing it into a single\ncommand that I can run locally. I can remotely run the `dokku` command with\n`ssh` using an interactive session (`-t`).\n\n```bash\nlocal> ssh -t app-staging dokku run my-app rails console\n```\n\nThat will open up a `rails console` session directly in the current shell\nsession via a remote SSH connection. The `-t` flag is important because that\nmakes the session interactive so that I can interact with the REPL.\n\nI've even packaged this up into a bin script (`bin/staging-console`) with a\ncouple checks to enhance the DX. I won't put the whole thing here, but the gist\nof it is:\n\n```bash\n#!/usr/bin/env bash\n\nset -e\n\nif [ -z \"$DOKKU_STAGING_SSH_ALIAS\" ]; then\n  echo \"Error: DOKKU_STAGING_SSH_ALIAS environment variable is not set.\"\n  echo \"\"\n  # echo more help details here ...\n  exit 1\nfi\n\n# Check if SSH alias exists\n# ...\n\n# Check if we can reach the server\n# ...\n\n# Run the console\nssh -t \"$DOKKU_STAGING_SSH_ALIAS\" dokku run my-app rails console \"$@\"\n```\n"
  },
  {
    "path": "rails/run-some-code-whenever-rails-console-starts.md",
    "content": "# Run Some Code Whenever Rails Console Starts\n\nIt can be handy to run some code whenever the `rails console` command is run.\nYou may want to have some modules required, some variables set up, or, both\nfancy and practical, default to the read replica database in production.\n\nRails provides a hook into the console startup with the `console` block in\n`config/application.rb`.\n\nHere is what it looks like to `puts` out the environment:\n\n```ruby\nclass Application < Rails::Application\n  # everything else ...\n\n  console do\n    puts '############################################'\n    puts 'Connected to the #{Rails.env.upcase} console'\n    puts '############################################'\n  end\nend\n```\n\nTo avoid cluttering `config/application.rb` with a bunch of console-specific\nlogic, you can move it to another file and then have the console block require\nthat file with the `-r` flag.\n\n```ruby\nclass Application < Rails::Application\n  console do\n    ARGV.push \"-r\", Rails.root.join(\"lib/console.rb\")\n  end\nend\n```\n\n[source](https://til.hashrocket.com/posts/avb2v3ubdt-pass-a-block-on-console-load)\n"
  },
  {
    "path": "rails/scaffold-auth-functionality-with-rails-8-generator.md",
    "content": "# Scaffold Auth Functionality With Rails 8 Generator\n\nRails 8 added a built-in generator for authentication that scaffolds the core\nmodels, controllers, views, routes, etc. needed for a basic email/password\nauthentication flow. It creates a `User` model, if one doesn't already exist,\nas the authenticated object. It uses the `bcrypt` gem for password hashing,\netc.\n\nHere is an example of what you get when running the generator on a relatively\nnew Rails 8 project:\n\n```bash\n$ bin/rails generate authentication\n      invoke  tailwindcss\n      create    app/views/passwords/new.html.erb\n      create    app/views/passwords/edit.html.erb\n      create    app/views/sessions/new.html.erb\n      create  app/models/session.rb\n      create  app/models/user.rb\n      create  app/models/current.rb\n      create  app/controllers/sessions_controller.rb\n      create  app/controllers/concerns/authentication.rb\n      create  app/controllers/passwords_controller.rb\n      create  app/channels/application_cable/connection.rb\n      create  app/mailers/passwords_mailer.rb\n      create  app/views/passwords_mailer/reset.html.erb\n      create  app/views/passwords_mailer/reset.text.erb\n      create  test/mailers/previews/passwords_mailer_preview.rb\n      insert  app/controllers/application_controller.rb\n       route  resources :passwords, param: :token\n       route  resource :session\n        gsub  Gemfile\n      bundle  install --quiet\n    generate  migration CreateUsers email_address:string!:uniq password_digest:string! --force\n       rails  generate migration CreateUsers email_address:string!:uniq password_digest:string! --force\n      invoke  active_record\n      create    db/migrate/20250115224625_create_users.rb\n    generate  migration CreateSessions user:references ip_address:string user_agent:string --force\n       rails  generate migration CreateSessions user:references ip_address:string user_agent:string --force\n      invoke  active_record\n      create    db/migrate/20250115224626_create_sessions.rb\n```\n\n[source](https://www.bigbinary.com/blog/rails-8-introduces-a-basic-authentication-generator)\n"
  },
  {
    "path": "rails/schedule-sidekiq-jobs-out-into-the-future.md",
    "content": "# Schedule Sidekiq Jobs Out Into The Future\n\nThe most common way to schedule a [Sidekiq](https://github.com/mperham/sidekiq)\njob is with the `perform_async` method. That will queue up your job so that it\nis worked as soon as possible.  That may not also be desired. Sometimes you\nwant a bit more say in when jobs are run.\n\nThe `perform_in` and `perform_at` methods can help with scheduling jobs out\ninto the future.\n\nWith `perform_in` we can say how much time from now would be the soonest that\nwe'd like the job performed.\n\n```ruby\nMyWorker.perform_in(10.minutes, arg1, arg2)\n```\n\nWe can do the same thing with `perform_at`.\n\n```ruby\nMyWorker.perform_at(10.minutes.from_now, arg1, arg2)\n```\n\nOr we can schedule something out for a specific point in time in the future.\n\n```ruby\nMyWorker.perform_at(Date.today.end_of_week, arg1, arg2)\n```\n\n[source](https://github.com/mperham/sidekiq/wiki/Scheduled-Jobs)\n"
  },
  {
    "path": "rails/scope-records-to-a-lower-or-upper-bound.md",
    "content": "# Scope Records To A Lower Or Upper Bound\n\nTypically when we use\n[`#where`](https://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-where)\nto scope queries against ActiveRecord models, we are looking to do a direct\n\"equals\" comparison.\n\nSuch as `auth_codes.user_id = 1` in the example below.\n\n```ruby\n> AuthCode.where(user_id: 1)\n  AuthCode Load (0.4ms)  SELECT \"auth_codes\".* FROM \"auth_codes\" WHERE \"auth_codes\".\"user_id\" = 1 /* loading for pp */ LIMIT 11\n```\n\nWe can do more powerful things with `#where` (assuming your database supports\nit, in my case PostgreSQL), such as comparing over ranges of dates. Ruby's\nrange syntax gives us an elegant way to express ranges.\n\n```ruby\n> 2..10 # range with lower bound of 2 and upper bound of 10\n\n> 2.. # 'end'less range\n\n> ..10 # 'begin'less range\n```\n\nThese latter two examples are ranges that are unbounded on one side or the\nother. We can use these in ActiveRecord `#where` queries to do \"greater than or\nequal to\" and \"less than or equal to\" conditionals.\n\nAnd we can do the same with ranges of dates like in the following queries.\n\n\n```ruby\n> AuthCode.where(created_at: 10.days.ago..).count\n  AuthCode Count (97.1ms)  SELECT COUNT(*) FROM \"auth_codes\" WHERE \"auth_codes\".\"created_at\" >= '2025-09-24 00:35:46.937715'\n\n> AuthCode.where(created_at: 10.days.ago..5.days.ago).count\n  AuthCode Count (0.6ms)  SELECT COUNT(*) FROM \"auth_codes\" WHERE \"auth_codes\".\"created_at\" BETWEEN '2025-09-24 00:35:59.901441' AND '2025-09-29 00:35:59.901512'\n\n> AuthCode.where(created_at: ..5.days.ago).count\n  AuthCode Count (0.3ms)  SELECT COUNT(*) FROM \"auth_codes\" WHERE \"auth_codes\".\"created_at\" <= '2025-09-29 00:36:09.731444'\n```\n\nNotice in the generated SQL how the simple `#where` method gets transformed\ninto a `>=`, a `<=`, or a `between` clause.\n\nAnd while dates are a powerful example of this, there is nothing to stop us\nfrom querying against other kinds of ranges like numeric ones.\n\n```ruby\n# Orders under $10\nten_dollars_in_cents = 10 * 100\nOrder.where.not(fulfilled_at: nil).where(amount: ..ten_dollars_in_cents)\n```\n"
  },
  {
    "path": "rails/secure-passwords-with-rails-and-bcrypt.md",
    "content": "# Secure Passwords With Rails And Bcrypt\n\nIf you are using [`bcrypt`](https://github.com/codahale/bcrypt-ruby) (at\nleast version 3.1.7), then you can easily add secure password functionality\nto an\n[ActiveRecord](https://github.com/rails/rails/tree/master/activerecord)\nmodel. First, ensure that the table backing the model has a\n`password_digest` column. Then add\n[`has_secure_password`](https://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html)\nto your model.\n\n```ruby\nclass User < ActiveRecord::Base\n  has_secure_password\n\n  # other logic ...\nend\n```\n\nYou can now instantiate a `User` instance with any required fields as well\nas `password` and `password_confirmation`. As long as `password` and\n`password_confirmation` match then an encrypted `password_digest` will be\ncreated and stored. You can later check a given password for the user using\nthe `authenticate` method.\n\n```ruby\nuser = User.find_by(email: user_params[:email])\n\nif user.authenticate(user_params[:password])\n  puts 'That is the correct password!'\nelse\n  puts 'That password did not match!'\nend\n```\n"
  },
  {
    "path": "rails/select-a-select-by-selector.md",
    "content": "# Select A Select By Selector\n\nGenerally when using Capybara to select from a `select` input, I reference it by its `name`\nwhich rails associates with the label:\n\n```ruby\nselect(\"Charizard\", from: \"Pokemon\")\n```\n\nHowever, not all forms are going to have a label paired with every `select`\ninput. We don't want to let our test coverage suffer, so we are going to\nneed a different way to select. Fortunately, Capybara allows us to chain\n`select` off a `find` like so:\n\n```ruby\nfind('#pokemon_list').select('Charizard')\n```\n"
  },
  {
    "path": "rails/select-a-specific-rails-version-to-install.md",
    "content": "# Select A Specific Rails Version To Install\n\nWe can install a specific Rails version with `gem` using the version flag.\n\n```bash\n$ gem install rails --version 7.1.3\n```\n\nThat's only if we already know which specific version we are intending to\ninstall.\n\nA better version of this would show us a list of available version and let us\nselect the one we want.\n\nWe can do this by fetching all remote Rails versions with `gem`, splitting that\noutput up into a single version per line, and then piping that to an `fzf`\nprompt. The version we navigate to and select will be fed into the `gem\ninstall` command.\n\n```bash\ngem install rails --version $(\n  gem list rails --exact --remote --all \\\n  | sed -n 's/.*(\\([^)]*\\)).*/\\1/p' \\\n  | tr ',' '\\n' \\\n  | sed 's/^ //' \\\n  | fzf\n)\n```\n"
  },
  {
    "path": "rails/select-value-for-sql-counts.md",
    "content": "# Select Value For SQL Counts\n\nIf you are like me and prefer writing raw SQL over the Arel DSL for counting\nstuff in your database, then the `select_value` method will come in handy.\nWrite a command similar to the following with a type cast to get the count\nof _whatever_.\n\n```ruby\n> sql = 'select count(*) from posts where published_at is not null'\n=> \"select count(*) from posts where published_at is not null\"\n> ActiveRecord::Base.connection.select_value(sql).to_i\n   (0.6ms)  select count(*) from posts where published_at is not null\n=> 42\n```\n\nWriting raw SQL for a simple query like this hardly seems like a win.\nHowever when a count query starts to involve joins or other fanciness, I\nfind it much clearer to reason about the raw SQL.\n"
  },
  {
    "path": "rails/serialize-with-fast-jsonapi-in-a-rails-app.md",
    "content": "# Serialize With fast_jsonapi In A Rails App\n\nNetflix put out a Ruby gem for super fast JSON serialization --\n[`fast_jsonapi`](https://github.com/Netflix/fast_jsonapi). It is great for\nserializing JSON responses for Rails API endpoints.\n\nFirst, add `gem 'fast_jsonapi'` to your `Gemfile` and `bundle install`.\n\nThen create the `app/serializers` directory for housing all of your JSON\nserializers.\n\nNext you can create a `serializer` that corresponds to the model you want to\nserialize:\n\n```ruby\n# app/serializers/recipe_serializer.rb\nclass RecipeSerializer\n  include FastJsonapi::ObjectSerializer\n\n  set_id :id\n  attributes :name, :source_url\nend\n```\n\nLast, use it to generate a JSON response in your controller:\n\n```ruby\n# app/controllers/recipes_controller.rb\nclass RecipesController < ApiController\n  def index\n    render json: RecipeSerializer.new(@current_user.recipes)\n  end\nend\n```\n\nRequests to that endpoint will receive a response that looks something like\nthis:\n\n```json\n{\n  data: [\n    {\n      id: 1,\n      attributes: { name: \"Old Fashioned\", source_url: \"http://...\" },\n    },\n    {\n      id: 2,\n      attributes: { name: \"Sazerac\", source_url: \"http://...\" },\n    },\n  ]\n}\n```\n"
  },
  {
    "path": "rails/set-a-timestamp-field-to-the-current-time.md",
    "content": "# Set A Timestamp Field To The Current Time\n\nTo set a timestamp field to the current time, you could reach for the `#update`\nmethod like you would when modifying any other field.\n\n```ruby\nMagicLink\n  .find_by(token: some_token)\n  .update(used_at: Time.zone.now)\n```\n\nThis works, but it's more verbose than is necessary and requires that you\nconstruct the right timestamp for _now_ (time zones and all).\n\nRails has a more concise and idomatic way of doing this:\n[`#touch`](https://api.rubyonrails.org/v6.1.0/classes/ActiveRecord/Persistence.html#method-i-touch).\n\n```ruby\nMagicLink\n  .find_by(token: some_token)\n  .touch(:used_at)\n```\n\nUpdating a timestamp to the current time is a common action in web\napplications, so Rails offers the `#touch` method as a shorthand for doing it.\nThis will set the given field, in this case `:used_at`, to the current time.\nThis will also set the `updated_at/on` field.\n"
  },
  {
    "path": "rails/set-datetime-to-include-time-zone-in-migrations.md",
    "content": "# Set Datetime To Include Time Zone In Migrations\n\nWhen using Rails and PostgreSQL, your migrations will contain DSL syntax like\n`t.datetime` and `t.timestamps` which will produce columns using the\n`timestamp` (`without time zone`) Postgres data type.\n\nWhile reading [A Simple Explanation of Postgres' <code>Timestamp with Time\nZone</code>](https://naildrivin5.com/blog/2024/10/10/a-simple-explanation-of-postgres-timestamp-with-time-zone.html),\nI learned that there is a way to configure your app to instead use\n`timestamptz` by default. This data type is widely recommended as a good\ndefault, so it is nice that we can configure Rails to use it.\n\nFirst, add these lines to a new initializer (`config/initializers/postgres.rb`)\nfile.\n\n```ruby\nrequire \"active_record/connection_adapters/postgresql_adapter\"\nActiveRecord::ConnectionAdapters::PostgreSQLAdapter.datetime_type = :timestamptz\n```\n\nAlternatively, you can configure this via `config/application.rb` per the\n[Configuring ActiveRecord\ndocs](https://guides.rubyonrails.org/configuring.html#activerecord-connectionadapters-postgresqladapter-datetime-type).\n\nThen, if you have a new migration like the following:\n\n```ruby\nclass AddEventsTable < ActiveRecord::Migration[7.2]\n  def change\n    create_table :events do |t|\n      t.string :title\n      t.text :description\n      t.datetime :start_time\n      t.datetime :end_time\n      t.timestamps\n    end\n  end\nend\n```\n\nyou can expect to have four `timestamptz` columns, namely `start_time`,\n`end_time`, `created_at`, and `updated_at`.\n\nHere is the [Rails PR](https://github.com/rails/rails/pull/41084) that adds\nthis config option.\n"
  },
  {
    "path": "rails/set-default-as-sql-function-in-migration.md",
    "content": "# Set Default As SQL Function In Migration\n\nWith static default values, like `0`, `true`, or `'pending'`, we can set them\ndirectly as the value of `default`.\n\n```ruby\nclass CreateActionsTable < ActiveRecord::Migration[7.2]\n  def change\n    create_table :actions do |t|\n      t.string :status, default: 'pending'\n    end\n  end\nend\n```\n\nHowever, if we want our default value to be a SQL function like `now()`, we\nhave to use a lambda.\n\nLet's extend the above example to see what that looks like:\n\n```ruby\nclass CreateActionsTable < ActiveRecord::Migration[7.2]\n  def change\n    create_table :actions do |t|\n      t.string :status, default: 'pending'\n\n      t.column :created_at, :timestamptz, default: -> { 'now()' }, null: false\n    end\n  end\nend\n```\n\nIf we need to alter the default of an existing table's column, we can do\nsomething like this:\n\n```ruby\nclass AddDefaultTimestampsToActions < ActiveRecord::Migration[7.2]\n  def up\n    change_column_default :actions, :created_at, -> { \"now()\" }\n    change_column_default :actions, :updated_at, -> { \"now()\" }\n  end\n\n  def down\n    change_column_default :actions, :created_at, nil\n    change_column_default :actions, :updated_at, nil\n  end\nend\n```\n\nI believe this functionality is available to Rails 5.0 and later.\n\n[source](https://github.com/rails/rails/issues/27077#issuecomment-261155826)\n"
  },
  {
    "path": "rails/set-default-url-options-for-entire-application.md",
    "content": "# Set default_url_options For Entire Application\n\nThere are a [number of\nways](https://github.com/rails/rails/issues/29992#issuecomment-575464112) to\nset `default_url_options` for the various modules that need them. While the\ndevelopment server can infer URL options for the most part, it needs them\nexplicitly defined for `ActionMailer`. You may also see the `ArgumentError:\nMissing host to link to! Please provide the :host parameter, set\ndefault_url_options[:host], or set :only_path to true` error when using a URL\nhelper. That's because the `routes` config also needs to know.\n\nInstead of cobbling together default settings in several different places as\nthe issues arise, you can define them application-wide like so:\n\n```ruby\n# config/environments/development.rb\nRails.application.default_url_options = { host: 'localhost', port: 3000 }\n\nRails.application.configure do\n # ...\nend\n```\n\nAdd the `default_url_options` to `Rails.application` just outside of the\nstandard `configure` block in each of your environment config files. Now\neverything should know how to generate full URLs.\n\nNote: I've tested this out in a Rails 6.1 application.\n\n[source](https://discuss.rubyonrails.org/t/define-host-so-absolute-urls-work-in-development-and-test/75085/10)\n"
  },
  {
    "path": "rails/set-meta-tags-in-erb-views.md",
    "content": "# Set Meta Tags In ERB Views\n\nThere are all kinds of meta tags that we may want to set for the pages that our\nRails app serves. A lot of these are for SEO and social sharing. Let's look at\nhow to add `og:description` meta tags to our views.\n\nI'll start with a helper method in `app/helpers/application_helper.rb`:\n\n```ruby\nmodule ApplicationHelper\n  def meta_description(desc)\n    content_for(:description) { desc }\n  end\nend\n```\n\nThen, I'll update my `app/views/layouts/application.html.erb` to consume the\ndescription when provided.\n\n```ruby\n<!DOCTYPE html>\n<html>\n  <head>\n    <!-- ... -->\n\n    <meta\n      property=\"og:description\"\n      content=\"<%= content_for?(:description) ? yield(:description) : 'Default description' %>\"\n    >\n\n    <!-- ... -->\n  </head>\n\n  <!-- ... -->\n</html>\n```\n\nNow I have a default description for all my views that I can override as needed\nwith the `meta_description` helper.\n\n```ruby\n# app/views/posts/show.html.erb\n<%= meta_description @post.body.split(\"\\n\").first %>\n\n<!-- ... -->\n```\n\nIf I reload the page and inspect the meta tags in `<head>`, I should find the\n`og:description` tag with the corresponding value.\n\nThis can be extended to apply all the different meta tags (e.g. Open Graph and\nTwitter) to make links to these pages render well across the internet.\n"
  },
  {
    "path": "rails/set-schema-search-path.md",
    "content": "# Set Schema Search Path\n\nBy default the schema search path for a PostgreSQL database is going to be\n`\"$user\", public`. Tables created by a Rails migration are going to end up\non the `public` schema by default. If your application has other schemas in\nplay, then you may want to ensure that those schemas are also on the schema\nsearch path. This can be accomplished by adding the `schema_search_path`\nsetting to your `database.yml` file. For instance, to include both the\n`legacy` and `public` schema in the Postgres search path, add the following\nline:\n\n```ruby\nschema_search_path: \"legacy,public\"\n```\n\nh/t Jack Christensen\n"
  },
  {
    "path": "rails/set-statement-timeout-for-all-postgres-connections.md",
    "content": "# Set Statement Timeout For All Postgres Connections\n\nThe\n[`statement_timeout`](postgres/set-a-statement-timeout-threshold-for-a-session.md)\nsetting in PostgreSQL allows you to head off long running queries and\nmigrations that could break your deploys and lock up your production tables.\n\nThis value can be set to a sensible default across all the connections your\nRails app makes to PostgreSQL. To set it, open up your `config/database.yml`\nfile and add a `variables` element to the default section.\n\n```yaml\ndefault: &default\n  adapter: postgresql\n  encoding: unicode\n  # For details on connection pooling, see Rails configuration guide\n  # https://guides.rubyonrails.org/configuring.html#database-pooling\n  pool: <%= ENV.fetch(\"RAILS_MAX_THREADS\") { 5 } %>\n  variables:\n    statement_timeout: 60000\n```\n\nThat's 60 seconds in milliseconds. You can avoid the mental math by using a\nstring argument with a unit such as `s` for seconds.\n\n```yaml\n  variables:\n    statement_timeout: '60s'\n```\n\nIf you then execute a long running query, such as:\n\n```ruby\nActiveRecord::Base.connection.execute('select pg_sleep(62)')\n```\n\nIt will terminate 2 seconds early because of the statement timeout.\n\n[source](https://til.hashrocket.com/posts/b44baf657d-railspg-statement-timeout-)\n"
  },
  {
    "path": "rails/set-the-default-development-port.md",
    "content": "# Set The Default Development Port\n\nFor Rails 5+, Puma has been the default web server that gets installed with new\nRails apps. Puma comes with some configuration in the `config/puma.rb` file.\n\nIf you open that file up, you'll see a number of settings that can be\nconfigured. One of them is the `port` that `puma` uses.\n\n```ruby\n# Specifies the `port` that Puma will listen on to receive requests; default is 3000.\n#\nport        ENV.fetch('PORT') { 3000 }\n```\n\nIt looks for a `PORT` value in the envionrment and uses that if it is present.\nThat means you could run:\n\n```bash\nPORT=5005 rails s\n```\n\nand Puma would server the local development server at `localhost:5005`. If that\nvalue is not present, it will fallback to `#fetch`'s block which contains\n`3000`.\n\nIf you always want to local Rails development server to run at a port other\nthan `3000`, all you need to do is update that line.\n\n```ruby\nport        ENV.fetch('PORT') { 5005 }\n```\n\nNow, running `rails s` on its own will start the dev server up at\n`localhost:5005`.\n\n[source](https://schneems.com/2017/03/13/puma-ports-and-polish/)\n"
  },
  {
    "path": "rails/show-pending-migrations.md",
    "content": "# Show Pending Migrations\n\nRails comes with a built-in rake task that allows you to check the status\nof migrations in the project.\n\n```bash\n$ rake db:migrate:status\n\ndatabase: pokemon_development\n\n Status   Migration ID    Migration Name\n--------------------------------------------------\n   up     20150219143706  Create pokemon table\n  down    20150228003340  Create stats table\n```\n\nFor large projects with lots of migrations, this is going to be a lot of\noutput, so you can trim it down with a simple `grep`:\n\n```bash\n$ rake db:migrate:status | grep '^  down'\n  down    20150228003340  Create stats table\n```\n\n[source](https://github.com/rails/rails/blob/master/activerecord/lib/active_record/railties/databases.rake#L91)\n"
  },
  {
    "path": "rails/show-rails-models-with-pry.md",
    "content": "# Show Rails Models With Pry\n\nWith the [`pry-rails`](https://github.com/rweng/pry-rails) gem, you get some\nextra goodies in the Rails console for your project. One of those goodies is\n`show-models`, a command for printing out a list of all models in the rails\nproject. Add and bundle the `pry-rails` gem, run `rails c`, and then run\n`show-models` to give it a go.\n\n```\n> show-models\nPokemon\n  id: integer\n  name: string\n  level: integer\n  pokemon_type: varchar\n  belongs_to Trainer\n  created_at: datetime\n  updated_at: datetime\nTrainer\n  id: integer\n  name: string\n  has_many Pokemons\n```\n"
  },
  {
    "path": "rails/show-rails-routes-with-pry.md",
    "content": "# Show Rails Routes With Pry\n\nIn [Show Rails Models With Pry](show-rails-models-with-pry.md), I showed\nthat [`pry-rails`](https://github.com/rweng/pry-rails) comes with some handy\nconsole commands. In addition to being able to list all your Rails models,\nyou can list all the routes for your application using `show-routes`.\n\nI get the following output by using that command in a small blog project:\n\n```\n> show-routes\n              Prefix Verb   URI Pattern                     Controller#Action\n                root GET    /                               application#index\nmarkdownify_articles POST   /articles/markdownify(.:format) articles#markdownify\n            articles POST   /articles(.:format)             articles#create\n         new_article GET    /articles/new(.:format)         articles#new\n        edit_article GET    /articles/:id/edit(.:format)    articles#edit\n             article GET    /articles/:id(.:format)         articles#show\n                     PATCH  /articles/:id(.:format)         articles#update\n                     PUT    /articles/:id(.:format)         articles#update\n               users POST   /users(.:format)                users#create\n            new_user GET    /users/new(.:format)            users#new\n                user GET    /users/:id(.:format)            users#show\n            sessions POST   /sessions(.:format)             sessions#create\n         new_session GET    /sessions/new(.:format)         sessions#new\n             session DELETE /sessions/:id(.:format)         sessions#destroy\n              signin GET    /signin(.:format)               sessions#new\n                     POST   /signin(.:format)               sessions#create\n              signup GET    /signup(.:format)               users#new\n```\n"
  },
  {
    "path": "rails/skip-validations-when-creating-a-record.md",
    "content": "# Skip Validations When Creating A Record\n\nValidations on your\n[ActiveRecord](https://api.rubyonrails.org/classes/ActiveRecord/Base.html)\nmodels are there for a reason. They provide application-level feedback about\ndata that doesn't meet business requirements.  In many cases those validations\nshould also be pushed down to the database-layer in the form of constraints.\n\nSometimes, though rarely and probably only in a testing or development context,\nyou'll want to skip validations.\n\nThis is how you can do that when creating a new record:\n\n```ruby\nuser = User.new(\n  name: 'Josh',\n  email: '',\n  password: SecureRandom.uuid\n)\n\nuser.valid?\n#=> false\nuser.errors.messages\n#=> {:email=>[\"can't be blank\"]}\n\nuser.save(validate: false)\n```\n\nAfter newing-up an object with invalid data, you can [save it with the\n`validate` option set to\n`false`](https://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-save).\nThis will skip ActiveRecord validations.\n\nNote: If you also have a database-layer constraint, this won't work. Perhaps\nfor your use case you can get by with a new non-persisted record.\n"
  },
  {
    "path": "rails/specify-new-attributes-for-find-or-create-by.md",
    "content": "# Specify New Attributes For #find_or_create_by\n\nThe ActiveRecord\n[`#find_or_create_by`](https://apidock.com/rails/v4.0.2/ActiveRecord/Relation/find_or_create_by)\nmethod is a handy way to get an object that represents a record. It will\nattempt to look up that record, usually based on a unique value or set of\nvalues. If it can find one, then that's the record you get. If nothing is\nfound, then it will create a new record.\n\nNew records tend to need more data than just the unique lookup attribute. There\nare a couple ways these other attributes can be specified.\n\nThe first is by giving `#find_or_create_by` a block.\n\n```ruby\nUser.find_or_create_by(email: \"some@email.com\") do |new_user|\n  new_user.admin = false\n  new_user.password = params[:password]\n  new_user.password_confirm = params[:password_confirm]\nend\n```\n\nAnother approach is to precede the `#find_or_create_by` call with a\n[`#create_with`](https://apidock.com/rails/ActiveRecord/QueryMethods/create_with)\ncall.\n\n\n```ruby\nUser.create_with(\n  admin: false,\n  password: params[:password],\n  password_confirm: params[:password_confirm]\n).find_or_create_by(email: \"some@email.com\")\n```\n\nIn both cases, the extra attributes will not be applied to the `User` record in\nthe case of a _find_; they are only used in the case of a _create_.\n"
  },
  {
    "path": "rails/temporarily-disable-strong-params.md",
    "content": "# Temporarily Disable strong_params\n\nI was recently doing a Rails upgrade. This old version of the app wasn't\nprepared to deal with `strong_params` right away. I already had a pile of\nmigration path TODOs and fixes on top of addressing the `strong_params` issue.\nI decided to put off dealing with `strong_params` by adding this line the main\ncontroller.\n\n```ruby\n# app/controllers/application_controller.rb\ndef params\n  request.parameters\nend\n```\n\nThis bypasses the `strong_params` check for all controllers inheriting from\n`ApplicationController`.\n\nRemember, this is a _temporary_ fix. You'll eventually want to adhere to\n`strong_params` for your mass assignments.\n\n[source](https://stackoverflow.com/a/41163978/535590)\n"
  },
  {
    "path": "rails/temporarily-turn-off-pending-migrations-error.md",
    "content": "# Temporarily Turn Off Pending Migrations Error\n\nWhenever I'm working on an end-to-end feature in a Rails app, soon or later I\nam going to see the _Pending Migrations_ error page. I try to visit one of the\nroutes in the browser and the Rails app serves this error page instead of my\nactual request response.\n\nThis is typically what I want. If there are migrations just sitting there that\nhaven't been run yet, that's probably an issue. Maybe I just pulled down the\nlatest changes from my teammates. The app isn't going to work properly without\nwhatever schema changes are prescribed in those pending migrations.\n\nThe thing to do is run those migrations.\n\nIn some special cases though, I know what I'm doing and I would like to operate\nmy app locally with specific migrations not yet applied.\n\nTo skip the error, I can change this `config/environments/development.rb`\nsetting from:\n\n```ruby\nconfig.active_record.migration_error = :page_load\n```\n\nto:\n\n```ruby\nconfig.active_record.migration_error = false\n```\n\nI just need to make sure to switch it back when I'm done.\n\n[source](https://til.hashrocket.com/posts/ujcixh5rwi-rails-ignore-pending-migrations)\n"
  },
  {
    "path": "rails/test-for-a-subset-of-attributes-on-a-model.md",
    "content": "# Test For A Subset Of Attributes On A Model\n\nLet's say you are using RSpec to test some code that creates or updates an\nActiveRecord object. To evaluate that the code is working, you want to check\nthe value of a couple different attributes. Though you could have a series of\nassert statements to check each value, you may want to combine them into a\nsingle statement.\n\n```ruby\nbook = process_that_updates_book(params)\n\nexpect(book.attributes).to match(\n  \"title\" => 'Updated title',\n  \"publication_year\" => 2001,\n  # ... you have to check *every* attribute\n)\n```\n\nThe `#match` matcher requires that every attribute in the hash matches. We\ndon't really care to check the `created_at`, `updated_at`, and other irrelevant\nattributes.\n\nInstead, we can `match` on\n[`hash_including`](https://rubydoc.info/gems/rspec-mocks/RSpec%2FMocks%2FArgumentMatchers:hash_including).\nAdditionally, we can `symbolize_keys` on the `attributes` to make the expected\ndata a little cleaner.\n\n```ruby\nbook = process_that_updates_book(params)\n\nexpect(book.attributes).to match(hash_including(\n  title: 'Updated title',\n  publication_year: 2001,\n))\n```\n\nIf the specified attributes match, then the expectation will pass. If at least\none of them doesn't, then it will fail. All other attributes are ignored.\n"
  },
  {
    "path": "rails/test-if-an-instance-variable-was-assigned.md",
    "content": "# Test If An Instance Variable Was Assigned\n\nWhen testing Rails controller actions, you'll often be making assertions about\nthe response to your test request. You may also want to assert about the\ninstance variables being set, as those are headed for your view layer.\n\nFor instance, if an instance variable `@metadata` is supposed to be set in a\n`#show` controller action, you can assert that it is with [RSpec's\n`assigns`](https://relishapp.com/rspec/rspec-rails/docs/controller-specs):\n\n```ruby\ndescribe \"when given valid params\" do\n  it \"sets the metadata\" do\n    get :show, params: valid_params\n\n    expect(assigns(:metadata)).to match(\n      identifier: \"abc123\",\n      session_id: \"fe98f08c-bf2f-4749-9f81-071d9cc7720e\",\n    )\n  end\nend\n```\n\n[source](https://stackoverflow.com/questions/2051373/how-to-test-instance-variable-was-instantiated-in-controller-with-rspec)\n"
  },
  {
    "path": "rails/test-if-deliver-later-is-called-for-a-mailer.md",
    "content": "# Test If deliver_later Is Called For A Mailer\n\nThere are many ways to test in your controller whether emails are going out. A\nconcise and quick way to check is just to see if a `deliver_later` happened.\n\nDepending on how your test environment is configured, this could look one of\ntwo ways.\n\nIf you have your `queue_adapter` set to\n[`:inline`](https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/InlineAdapter.html),\nthen a `deliver_later` will happen synchronously. So, the email will\nimmediately end up in the `deliveries` box.\n\n```ruby\nexpect {\n  post :password_reset, params: valid_params\n}.to change { ActionMailer::Base.deliveries.count }.by(1)\n```\n\nThe behavior is a bit different if your `queue_adapter` is set to something\nlike\n[`:test`](https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/TestAdapter.html).\nIn this case, the email is going to be queued in the app's job queue. Since it\nis not immediately being sent, the expectation will have to be about the job\nqueue instead.\n\n```ruby\nexpect {\n  post :password_reset, params: valid_params\n}.to have_enqueued_job(ActionMailer::DeliveryJob)\n```\n\nWe can even dig into more specifics like this:\n\n```ruby\nexpect {\n  post :password_reset, params: valid_params\n}.to have_enqueued_job(ActionMailer::DeliveryJob)\n  .with('UserMailer', 'password_reset', 'deliver_later', Integer)\n```\n"
  },
  {
    "path": "rails/test-out-url-and-path-helpers-in-the-console.md",
    "content": "# Test Out URL And Path Helpers In The Console\n\nRails has fancy metaprogrammed URL and path helpers generated from the\n`config/routes.rb` file. There is a ton of configurability to these routes. It\ncan sometimes be hard to know exactly how they'll behave or what the generated\nroute helper will look like. In those cases, we may want to test them out in\nthe console.\n\nThe Rails console doesn't have the same things autoloaded as mailers and views\nwhere we tend use these route helpers. So, we can reference them through\n`Rails.application.routes.url_helpers`.\n\nFrom there we can run both `*_path` route helpers.\n\n```ruby\n> Rails.application.routes.url_helpers\n    .api_v1_post_with_slugged_title_path(\n      slug: 123,\n      slugged_title: 'a-recent-path'\n    )\n\n=> \"/api/v1/posts/123/a-recent-path\"\n```\n\nand `*_url` path helpers.\n\n```ruby\n> Rails.application.routes.url_helpers\n    .api_v1_post_with_slugged_title_url(\n      slug: 123,\n      slugged_title: 'a-recent-path'\n    )\n\n=> \"http://localhost:3000/api/v1/posts/123/a-recent-path\"\n```\n\nFor the `*_url` path helpers, make sure you have [`default_url_options`\nset](set-default-url-options-for-entire-application.md).\n\n[source](https://stackoverflow.com/a/13553422/535590)\n"
  },
  {
    "path": "rails/truncate-almost-all-tables.md",
    "content": "# Truncate Almost All Tables\n\nThe\n[`database_cleaner`](https://github.com/DatabaseCleaner/database_cleaner)\ngem is a handy way to make sure you have a consistent database context for\neach test example or suite. One `database_cleaner` strategy that can be used\nis the `truncation` strategy. This truncates the data from all the tables by\ndefault. This is not ideal for *fixed* tables that contain domain-specific\ndata because you end up having to do way more test setup than should be\nnecessary. Fortunately, specific tables can be excepted by the truncation\nstrategy using the `except` option.\n\nFor instance, if we have a standard set of roles for users of our\napplication, we can except that table from truncation with a line like the\nfollowing in our `rails_helper.rb` file:\n\n```ruby\nDatabaseCleaner.strategy = :truncation, {:except => %w[roles]}\n```\n"
  },
  {
    "path": "rails/update-column-versus-update-attribute.md",
    "content": "# Update Column Versus Update Attribute\n\nRails offers a whole variety of methods for making updates to the ActiveRecord\nobjects in your app. Two unique, infrequently-used ones are\n[`#update_column`](https://devdocs.io/rails~5.2/activerecord/persistence#method-i-update_column)\nand\n[`#update_attribute`](https://devdocs.io/rails~5.2/activerecord/persistence#method-i-update_attribute).\nWhat is unique about them is that they are both ways of updating a record while\nskipping the validations defined on the model.\n\nSo, how do they differ?\n\nA call to `#update_attribute` is still going to trigger any callbacks defined\non the model and it will touch the `update_at` column. On the other hand,\n`#update_column` can be thought of as a way of directly interacting with the\ndatabase -- callbacks are skipped and you are truly only touching the specified\ncolumn, `updated_at` is left as is.\n\nThe docs have this recommendation for `#update_attribute`:\n\n> This is especially useful for boolean flags on existing records.\n\nAnd for `#update_column`, they say this:\n\n> This is the fastest way to update attributes because it goes straight to the\n> database, but take into account that in consequence the regular update\n> procedures are totally bypassed.\n\nThese are both useful in specific situations, but be sure to know their\ndifferences and to use them with caution.\n"
  },
  {
    "path": "rails/upgrading-your-manifest-for-sprockets-4.md",
    "content": "# Upgrading Your Manifest For Sprocket's 4\n\nIf you're upgrading [Rails](https://github.com/rails/rails) and it involves\nbumping the [Sprockets](https://github.com/rails/sprockets) dependency from 3.x\nto 4.x, you may need to update your `manifest.js`.\n\n> Since the default logic for determining top-level targets changed, you might\n> find some files that were currently compiled by sprockets for delivery to\n> browser no longer are. You will have to edit the `manifest.js` to specify\n> those files.\n\n> The `manifest.js` file is meant to specify what files to use as a top-level\n> target using sprockets methods `link`, `link_directory`, and `link_tree`.\n\nYou can specify what top-level assets like so:\n\n```javascript\n# app/assets/config/manifest.js\n\n//= link_tree ../images\n//= link_directory ../javascripts .js\n//= link_directory ../stylesheets .css\n//= link some_file.xml\n//= link some/nested/style.css\n```\n\nRead more about the [upgrade process\nhere](https://github.com/rails/sprockets/blob/master/UPGRADING.md#manifestjs)\nas well as in [this blog\npost](https://eileencodes.com/posts/the-sprockets-4-manifest/).\n"
  },
  {
    "path": "rails/use-irb-and-ruby-flags-with-rails-console.md",
    "content": "# Use IRB And Ruby Flags With Rails Console\n\nThe `rails console` command only accepts two flags `--environment` and\n`--[no-]sandbox`. However, the `rails console` is built on top of IRB and Ruby,\nso it can accept flags that those commands understand.\n\nYou can't pass an IRB flag directly to `rails console` though because it\ndoesn't consider those part of its repertoire.\n\n```bash\n$ rails console --sandbox -r './vendor/setup_records.rb'\n```\n\nIt will put the session in sandbox mode, but it doesn't know what to do with\n`-r`.  We have to explicitly separate its flags from flags that should be\npassed through. This is done with the `--` CLI convention.\n\n```bash\n$ rails console --sandbox -- -r './vendor/setup_records.rb'\n```\n\nEverything after the `--` gets passed along to IRB.\n"
  },
  {
    "path": "rails/use-ruby-extension-for-template-file.md",
    "content": "# Use .ruby Extension For Template File\n\nAn interesting feature of Rails that I can't seem to find documented anywhere is\nthat you can write a template file with plain Ruby by using the `.ruby`\nextension. For instance, you might want to render some JSON from a template.\nInstead of using `jbuilder` or `erb`, you can have a `show.json.ruby` file. This\nis also popular with Turbo Stream files -- e.g. `update.turbo_stream.ruby`.\n\nHow this works is that the entire file is evaluated as if it were a `.rb` file.\nThen the return value of the final statement is what is returned and rendered by\nRails.\n\n```ruby\nauthor_byline = @book.authors.map(&:name).to_sentence\n\ndata = {\n  id: @book.id,\n  title: @book.title,\n  author: author_byline,\n  status: @book.published_at > Time.current ? 'Coming Soon' : 'Published',\n  publication_year: @book.published_at.year\n}\n\ndata.to_json\n```\n\nThat final line converts the hash of data that we've built up into a JSON string\nthat can then be rendered by the controller action that corresponds to this view\ntemplate.\n\nSimilarly, you can have a Turbo Stream template `show.turbo_stream.ruby` that\nlooks something like this:\n\n```ruby\n[\n  turbo_stream.prepend(\"posts\", @post),\n  turbo_stream.update(\"form\", partial: \"form\", locals: { post: Post.new })\n].join\n```\n\nThis template file is made up of a single statement which is an array of turbo\nstream results that get joined together.\n"
  },
  {
    "path": "rails/useful-active-support-constants-for-durations.md",
    "content": "# Useful ActiveSupport Constants For Durations\n\nWhenever I'm passing a duration to a function, I like to [name it with the\nunit](https://ruudvanasseldonk.com/2022/03/20/please-put-units-in-names)\nrelative to the value it represents. For instance, if I need to pass in an hour\nduration in seconds, I might write the following line:\n\n```ruby\nhour_in_seconds = 60 * 60\n\n# or\n\nhour_in_seconds = 3600\n```\n\nActiveSupport has a [Duration\nclass](https://api.rubyonrails.org/classes/ActiveSupport/Duration.html) with a\nseries of constants that we can reach for.\n\n```ruby\n> ActiveSupport::Duration::SECONDS_PER_MINUTE\n=> 60\n> ActiveSupport::Duration::SECONDS_PER_HOUR\n=> 3600\n> ActiveSupport::Duration::SECONDS_PER_DAY\n=> 86400\n> ActiveSupport::Duration::SECONDS_PER_WEEK\n=> 604800\n> ActiveSupport::Duration::SECONDS_PER_MONTH\n=> 2629746\n> ActiveSupport::Duration::SECONDS_PER_YEAR\n=> 31556952\n```\n\nThough it is fun to know about these, we should keep in mind that this class\nprovides support for what is likely to be a more useful abstraction layer:\n\n```ruby\n> 1.hour\n=> 1 hour\n> 3.hours\n=> 3 hours\n> 1.day.to_i\n=> 86400\n```\n"
  },
  {
    "path": "rails/validate-column-data-with-check-constraints.md",
    "content": "# Validate Column Data With Check Constraints\n\nA check constraint is a feature of database systems like PostgreSQL that allows\nyou to enforce rules about the data that goes in a table's column. As of Rails\n6.1, ActiveRecord provides a way to add a check constraint via the DSL.\n\nIn this example, we want to ensure that the value going into the\nreading_statuses.status column is one of four values. Nothing else besides\nthese four values should be allowed.\n\n```ruby\nclass AddReadingStatusTable < ActiveRecord::Migration[7.2]\n  def change\n    create_table :reading_statuses do |t|\n      t.references :user, null: false, foreign_key: true\n      t.references :book, null: false, foreign_key: true\n      t.string :status, null: false\n      t.timestamps\n    end\n\n    add_check_constraint\n      :reading_statuses,\n      \"status in ('started', 'completed', 'abandoned', 'already_read')\",\n      name: \"reading_statuses_valid_status_check\"\n  end\nend\n```\n\nThe `#add_check_constraint` method takes the name of the table and a SQL clause\nthat can evaluate to true or false for a given row. We can optionally include\nthe name of the check constraint (e.g. {table_name}_{column_name}_check) like\nwe've done above.\n"
  },
  {
    "path": "rails/verify-and-read-a-signed-cookie-value.md",
    "content": "# Verify And Read A Signed Cookie Value\n\nLet's say a value was added as a [signed\ncookie](https://apidock.com/rails/ActionDispatch/Cookies/CookieJar/signed) in a\nrequest:\n\n```ruby\ncookies.signed[:discount] = 45\n#=> Set-Cookie: discount=BAhpMg==--2c1c6906c90a3bc4fd54a51ffb41dffa4bf6b5f7; path=/\n```\n\nGenerally to verify and read that value, you'd grab it from the signed cookies\nincluded in the request.\n\n```ruby\ncookies.signed[:discount]\n#=> 45\n```\n\nWhat if you have the signed cookie value, but not in the context of a `cookies`\nobject?\n\nYou can build a cookie jar from the current request and read the verified value\nfrom that.\n\n```ruby\ncookie_value = 'BAhpMg==--2c1c6906c90a3bc4fd54a51ffb41dffa4bf6b5f7'\ncookie_hash = { discount: cookie_value }\n\ncookie_jar = ActionDispatch::Cookies::CookieJar.build(request, cookie_hash)\n\ncookie_jar.signed[:discount]\n#=> 45\n```\n\nIt is also possible to [Base64 decode the\nvalue](https://blog.bigbinary.com/2013/03/19/cookies-on-rails.html), however\nthat doesn't ensure that the value hasn't been tampered with.\n\n[source](https://philna.sh/blog/2020/01/15/test-signed-cookies-in-rails/)\n"
  },
  {
    "path": "rails/where-am-i-in-the-partial-iteration.md",
    "content": "# Where Am I In The Partial Iteration?\n\nLet's say I am going to render a collection of posts with a post partial.\n\n```erb\n<%= render collection: @posts, partial: \"post\" %>\n```\n\nThe\n[`ActionView::PartialIteration`](http://api.rubyonrails.org/classes/ActionView/PartialIteration.html)\nmodule provides a couple handy methods when rendering collections.\nI'll have access in the partial template to `#{template_name}_iteration`\n(e.g. `post_iteration`) which will, in turn, give me access to `#index`,\n`#first?`, and `#last?`.\n\nThis is great if I need to do something special with the first or last item\nin the collection or if I'd like to do some sort of numbering based on the\nindex of each item.\n\n[source](http://stackoverflow.com/questions/13397848/rails-render-collection-partial-getting-size-of-collection-inside-partial)\n\nh/t Josh Davey\n"
  },
  {
    "path": "rails/why-redirect-and-return-in-controllers.md",
    "content": "# Why Redirect And Return In Controllers\n\nA fairly common idiom in Rails controller actions is a `redirect_to` followed\nby an `and return`.\n\n```ruby\ndef show\n  redirect_to sign_in_path and return if current_user.blank?\n\n  book = Book.find(params[:id])\n\n  render book\nend\n```\n\nBecause a `render` comes later in the controller action, we need to _early\nreturn_ after the redirect to avoid multiple render/redirect warnings.\n\nIt is important to use `and` here instead of `&&` because of logical operator\nprecedence.\n\nIf we used `&&` instead:\n\n```ruby\n  redirect_to sign_in_path && return if current_user.blank?\n```\n\nThe `redirect_to` would get `nil` (the result of `sign_in_path && nil`). If we\ndid want to use `&&`, we'd need to be diligent with method call parentheses.\n\n```ruby\n  redirect_to(sign_in_path) && return if current_user.blank?\n```\n\nIn this case, `redirect_to` would actually get called with a path string and\nthe `return` would be called after that.\n\n[source](https://stackoverflow.com/a/37211314/535590)\n"
  },
  {
    "path": "rails/wipe-out-all-precompiled-assets.md",
    "content": "# Wipe Out All Precompiled Assets\n\nYou can clean up precompiled assets using:\n\n```bash\n$ rails assets:clean\n```\n\nThis command is built to be safe for situations like rolling deploys. Any\nassets that are still being used will not be cleaned up.\n\nIf you really want to wipe out _all_ precompiled assets, you should _clobber_\nthem:\n\n```bash\n$ rails assets:clobber\n```\n\n[source](https://edgeguides.rubyonrails.org/command_line.html#rails-assets)\n"
  },
  {
    "path": "rails/write-reversible-migration-to-set-default.md",
    "content": "# Write Reversible Migration To Set Default\n\nYou can use the `change_column_default` method to alter the default value of a\ncolumn. If the column doesn't have a default, then you'd essentially be\nchanging the default from `nil` to _some value_.\n\n```ruby\ndef up\n  change_column_default :books, :published, false\nend\n\ndef down\n  change_column_default :books, :published, nil\nend\n```\n\nThis is fine, but you can write the migration as a single, reversible `change`\nmethod using the `:from` and `:to` options.\n\n```ruby\ndef change\n  change_column_default :books, :published, from: nil, to: false\nend\n```\n\nWhen you migrate, the default will be set to `false`. When you rollback, the\ndefault will be removed.\n\n[source](https://blog.arkency.com/how-to-add-a-default-value-to-an-existing-column-in-a-rails-migration/)\n"
  },
  {
    "path": "rails/write-safer-where-clauses-with-placeholders.md",
    "content": "# Write Safer Where Clauses With Placeholders\n\nRuby has a super ergonomic syntax for string interpolation. This can make it\ntempting to build up ActiveRecord `where` clauses like so:\n\n```ruby\ndef get_book_by_title(title)\n  Book.where(\"lower(title) = #{title.downcase}\")\nend\n```\n\nThe `where` clause, as written, is vulnerable to a SQL injection attack.\n\nThere are two kinds of placeholder syntax that you can use instead handle\nsanitization of the SQL.\n\n```ruby\ndef get_book_by_title(title)\n  Book.where(\"lower(title) = ?\", title.downcase)\nend\n```\n\nYou can use multiple `?` in the query and they same number of following\narguments will be interpolated in order.\n\nThere is also the keyword placeholder syntax which can give you more\nflexibility and make the SQL read more clearly.\n\n```ruby\ndef get_book_by_title(title)\n  Book.where(\"lower(title) = :title\", title: title.downcase)\nend\n```\n\n[source](https://devdocs.io/rails~5.2/activerecord/querymethods#method-i-where)\n"
  },
  {
    "path": "react/a-component-is-just-a-bag-of-data.md",
    "content": "# A Component Is Just A Bag Of Data\n\nIf you write enough React using JSX, it is easy to forget that you're not\nworking with markup. Everything -- `div`s, `h1`s, 3rd party components, your\ncomponents -- all get boiled down to JavaScript objects full of data.\n\nAny given React component is really just a bag of data. Try doing a\n`console.log` to see. Here is an example from an [earlier\npost](https://github.com/jbranchaud/til/blob/master/react/dynamically-add-props-to-a-child-component.md).\n\n```javascript\nconst ParentWithClick = ({ children }) => {\n  return (\n    <React.Fragment>\n      {React.Children.map(children || null, (child, i) => {\n        console.log(child);\n        return <child.type {...child.props} key={i} onClick={handleClick} />;\n      })}\n    </React.Fragment>\n  );\n};\n\nconst App = () => (\n  <div>\n    <ParentWithClick>\n      <span>Click this span</span>\n    </ParentWithClick>\n  </div>\n);\n```\n\nLooking in the console, we see the following output:\n\n```\nObject {type: \"span\", key: null, ref: null, props: Object, _owner: Object…}\n type: \"span\"\n key: null\n ref: null\n props: Object\n  children: \"Click this span\"\n _owner: Object\n _store: Object\n```\n\nIt contains information about the component itself and because of the tree\nstructure of this data, you could potentially expand the `props` -->\n`children` sections several times for certain components.\n\nSee a [live example here](https://codesandbox.io/s/l41pj382x7).\n"
  },
  {
    "path": "react/access-the-latest-lifecycle-methods-in-an-old-app.md",
    "content": "# Access The Latest Lifecycle Methods In An Old App\n\nWith [the release of React\n16.3](https://reactjs.org/blog/2018/03/29/react-v-16-3.html) we have access\nto some [new lifecycle\nmethods](https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html)\nand are in the first phase of what will eventually result in the deprecation\nand removal of `componentWillMount`, `componentWillReceiveProps`, and\n`componentWillUpdate`.\n\nYou may not be ready to move your project to React 16.3, but that doesn't\nmean you can't start migrating your lifecycle methods now. We'll need a\npolyfill --\n[react-lifecycles-compat](https://github.com/reactjs/react-lifecycles-compat).\n\n```javascript\nimport React from 'react';\nimport { pollyfill } from 'react-lifecycles-compat';\n\nclass MyComponent extends React.Component {\n  static getDerivedStateFromProps(nextProps, prevState) {\n    // ...\n  }\n\n  render() { ... }\n}\npolyfill(MyComponent)\n\nexport default MyComponent;\n```\n\nFor any of our class components for which we'd like to start using the new\nlifecycle methods, we just need to import the polyfill function and then\ntransform the class component with the polyfill before exporting it.\n\n[source](https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#open-source-project-maintainers)\n"
  },
  {
    "path": "react/accessing-env-vars-in-create-react-app.md",
    "content": "# Access Env Vars In create-react-app\n\nEnvironment-specific configurations are an important part of most\napplications. You can access environment variables in your create-react-app\ncode using `process.env`.\n\nThere are a couple built-in environment variables, such as `NODE_ENV`.\nAnything custom that you want to provide must be prepended with\n`REACT_APP_`. If it isn't, that environment variable will be ignored with no\nwarning.\n\nThe following line of code\n\n```javascript\nconst base_api_url = process.env.REACT_APP_BASE_API_URL;\n```\n\nwill have access to whatever that value is in the environment when the\nserver is started or the app is built.\n\nSet that value inline like so:\n\n```\nREACT_APP_BASE_API_URL=\"https://api.my_app.com\" yarn start\n```\n\n[source](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#adding-custom-environment-variables)\n"
  },
  {
    "path": "react/accessing-location-within-reach-router.md",
    "content": "# Accessing Location Within @reach/router\n\nThe API of [`@reach/router`](https://reach.tech/router) departs a bit from\n[`react-router`](https://reacttraining.com/react-router/) in a couple ways.\nThe `location` prop which you may be used to having access to automatically\nis instead available through the\n[`Location`](https://reach.tech/router/api/Location) component.\n\n```javascript\nimport React from 'react';\nimport { Location } from '@reach/router';\n\nconst MyComponent = () => {\n  return (\n    <Location>\n      {({ location }) => {\n        return <p>Current Location: {location.pathname}</p>;\n      }}\n    </Location>\n  );\n}\n```\n\nThis is a contrived example, but you can imagine how you'd use it to access\n`state` or even create an HOC similar to `withRouter`.\n"
  },
  {
    "path": "react/allow-md-as-an-extension-with-gatsby-mdx.md",
    "content": "# Allow md As An Extension With gatsby-mdx\n\nThe [gatsby-mdx](https://github.com/ChristopherBiscardi/gatsby-mdx) plugin\nallows you to create pages in a Gatsby project using `.mdx` files. If you\nprefer the `.md` extension on your markdown files, then you can adjust the\nplugin options to allow that.\n\n```javascript\n// gatsby-config.js\nplugins: [\n  {\n    resolve: `gatsby-mdx`,\n    options: {\n      extensions: [\".mdx\", \".md\"]\n    }\n  }\n]\n```\n\nThis tells `gatsby-mdx` to recognize both `.mdx` and `.md` extensions when\nprocessing files.\n"
  },
  {
    "path": "react/alter-the-display-name-of-a-component.md",
    "content": "# Alter The Display Name Of A Component\n\nComponents adopt their display name from the class or function that renders\nthem. A component's display name becomes important to know about as soon as\nyou start digging through the [React\ndevtools](https://github.com/facebook/react-devtools) interface -- whether\ndebugging or just perusing the component hierarchy, the display names of\ncomponents is what you'll see. In most circumstances, the display name is\ngood enough as is. If you want or need to, you can change it.\n\n```javascript\nconst Hello = ({ name }) => {\n  return (\n    <h1>{name}</h1>\n  );\n};\nHello.displayName = \"Hola\";\n```\n\nBy setting the `displayName` property on this component, you are able to\nalter what name is used by React devtools.\n\nThis can be useful when bringing in a 3rd party library or\ncomponent that doesn't use a display name that you find helpful -- in\nparticular when using Higher Order Components.\n"
  },
  {
    "path": "react/building-a-react-app-in-the-browser.md",
    "content": "# Building A React App In The Browser\n\nThere are a couple relatively new tools that give you just about everything\nyou need to build a React app in the browser.\n\nThe first is [CodeSandbox](https://codesandbox.io/). It has a couple\npre-configured environments for different technologies. The main one is\nReact. CodeSandbox describes itself as such:\n\n> an online editor that helps you create web applications, from prototype to\n> deployment.\n\nThe second, which just released out of beta, is\n[Glitch](https://glitch.com/) which comes with projects like\n[react-starter](https://glitch.com/~starter-react) so that you can jump into\na React project that is ready to roll. Glitch describes itself as:\n\n> the friendly community where you'll build the app of your dreams\n\nYou can quickly build and publish React apps in either of these and share\nthem with the world.\n"
  },
  {
    "path": "react/check-the-type-of-a-child-component.md",
    "content": "# Check The Type Of A Child Component\n\nThere is a simple way to check the type of a child component.\n\n```javascript\nimport React from 'react';\n\nconst Hello = () => <h1>Hello</h1>;\n\nconst Greeting = ({ children }) => {\n  let hello;\n  React.Children.forEach(children, child => {\n    if(child.type === Hello) {\n      hello = child;\n    }\n  });\n\n  return hello;\n};\n```\n\nThis is a comparison of the child's type to the component constant we are\nlooking for.\n\nThis comparison is not the most robust. For instance, Gatsby does something\ninternally that throws off this comparison. Here is a more robust\ncomparison.\n\n```javascript\nif(child.type === Hello || child.type === <Hello />.type)\n```\n\n[source](https://github.com/gatsbyjs/gatsby/issues/3486)\n"
  },
  {
    "path": "react/conditionally-including-event-handler-functions.md",
    "content": "# Conditionally Including Event Handler Functions\n\nReact makes a variety of [synthetic DOM\nevents](https://reactjs.org/docs/events.html) available to your component.\nEvents such as `onClick`, `onKeyPress`, `onSubmit`, etc. When specifying one of\nthese event handlers, you must supply a function.\n\nTo conditionally include an event handler, you may be tempted to do this:\n\n```javascript\n<Toggler\n  onKeyPress={someCondition && handleKeyPress}\n/>\n```\n\nThis means that `onKeyPress` will receive `false` when `someCondition` is\n`false`. That is a prop type violation. Instead, you should use a ternary\nstatement.\n\n```javascript\n<Toggler\n  onKeyPress={someCondition ? handleKeyPress : undefined}\n/>\n```\n\nIf `someCondition` is `false`, then the prop will be set as `undefined` and\nthat prop won't be defined.\n"
  },
  {
    "path": "react/create-a-snowpack-bundled-react-app.md",
    "content": "# Create A Snowpack-Bundled React App\n\n> [Snowpack](https://www.snowpack.dev/) is a modern, lightweight toolchain for\n> web application development.\n\nYou can get started using snowpack with this `npx` command.\n\n```bash\nnpx create-snowpack-app my-app\n```\n\nThis command uses a base template that is pre-configured to use the snowpack\ndefaults.\n\nYou can take this a step further by using a specialized template for React\napps.\n\n```bash\nnpx create-snowpack-app react-client --template @snowpack/app-template-react\n```\n\nAn advantage this has over\n[create-react-app](https://github.com/facebook/create-react-app) is there is no\nejecting needed to do something like pull in [PostCSS](https://postcss.org/).\n"
  },
  {
    "path": "react/create-dynamically-named-custom-react-components.md",
    "content": "# Create Dynamically Named Custom React Components\n\nA React element is as simple as a function that returns some valid JSX. Any\nfunction will do.\n\n```javascript\nconst CustomComponent = ({ children }) => {\n  return (\n    <React.Fragment>{children}</React.Fragment>\n  );\n};\n```\n\nThis function provides us with a React component that has a fixed name --\n`CustomComponent`. With the help of the [`displayName`\nproperty](https://reactjs.org/docs/react-component.html#displayname), we can\ncreate dynamically named components.\n\n```javascript\nconst ComponentGenerator = ({ customName, children }) => {\n  const CustomComponent = ({ children }) => {\n    return (\n      <React.Fragment>{children}</React.Fragment>\n    );\n  };\n  CustomComponent.displayName = customName;\n\n  return (\n    <CustomComponent>{children}</CustomComponent>\n  );\n};\n\nconst App = () => {\n  return (\n    <ComponentGenerator customName=\"RandomComponentName\">\n      Hello!\n    </ComponentGenerator>\n  );\n}\n```\n\nIf we inspect the generated React tree, we will not see anything called\n`<CustomComponent>`, but instead we will see our `<RandomComponentName>`\ncomponent.\n\nRemember, React components need to have an uppercase name.\n"
  },
  {
    "path": "react/create-react-app-comes-with-lodash.md",
    "content": "# create-react-app Comes With Lodash\n\n[Lodash](https://lodash.com/) is already a dependency of\n[create-react-app](https://github.com/facebook/create-react-app). If you\nneed one of those fancy Lodash functions, there's no need to `yarn add\nlodash` to your project, all you need is an import statement.\n\n```javascript\nimport chunk from 'lodash/chunk';\n```\n\nh/t Dillon Hafer\n"
  },
  {
    "path": "react/create-react-app-has-a-default-test-setup-file.md",
    "content": "# create-react-app Has A Default Test Setup File\n\nIn [_Configure Jest To Run A Test Setup\nFile_](https://github.com/jbranchaud/til/blob/master/javascript/configure-jest-to-run-a-test-setup-file.md),\nI pointed to a way of configuring Jest in either the `package.json` or\n`jest.config.js` file with the `setupTestFrameworkScriptFile` value.\n\nIn a `create-react-app` project, this is not an option because\n`setupTestFrameworkScriptFile` is not one of the permitted config values for\nJest.\n\nThere is a built-in value which happens to match what was recommended in the\nabove post -- `<rootDir>src/setupTests.js`.\n\nThis means that there is no configuration required. Instead, just create a\n`setupTests.js` file in the `src` directory of your CRA project and add any\nframework setup you need there. That file is already configured to run when\nyou invoke `yarn test`.\n\n[source](https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#initializing-test-environment)\n"
  },
  {
    "path": "react/css-important-is-not-supported-by-inline-styles.md",
    "content": "# CSS !important Is Not Supported By Inline Styles\n\nYou can get pretty far with React's inline styling of components. There are\nhowever a few limitations. One such limitation is that the `!important`\nclause is not supported.\n\nIf you try applying `!important` to an inline style like so:\n\n```jsx\n<div style={{ color: \"red !important\" }}>\n  My div\n</div>\n```\n\nYou'll be disappointed when you open up the browser and inspect that `div`\ntag. The `color` rule will be ignored and excluded from the output html.\n\n[source](https://github.com/facebook/react/issues/1881)\n"
  },
  {
    "path": "react/debug-jest-tests-in-create-react-app.md",
    "content": "# Debug Jest Tests In create-react-app\n\nWhen you put a `debugger;` statement in one of your Jest tests and\nrun `yarn test`, the test runner will ignore the debug statement and run to\ncompletion. This is because Jest defaults to parallelizing tests which won't\nmix well with manual debugging intervention.\n\nIf we want to be able to run our Jest tests through a debugger. We will need\ntwo things. First, we need a debugging environment -- Chrome's devtools will\nwork well for this. Second, we need our tests to run in band. The\n[`react-scripts`\ndocumentation](https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#debugging-tests)\nrecommends adding a second, debug-specific test command to your\n`package.json`:\n\n```javascript\n\"scripts\": {\n  \"test:debug\": \"react-scripts --inspect-brk test --runInBand --env=jsdom\"\n}\n```\n\nYou can now run `yarn test:debug` which will start a paused debug session.\nOpen chrome at `chrome://inspect` to access and open the debugging session\npanel. Now, debug away.\n"
  },
  {
    "path": "react/defining-state-in-a-simple-class-component.md",
    "content": "# Defining State In A Simple Class Component\n\nMost class components start off with a constructor which does some\ninitialization of the component including setting the components initial\nstate. It might look something like the following:\n\n```javascript\nclass MyComponent extends React.Component {\n  constructor(props) {\n    super(props);\n    this.state = {\n      loading: true\n    };\n  }\n\n  render() {\n    if (this.state.loading) {\n      return (\n        <p>Loading...</p>\n      );\n    } else {\n      // ...\n    }\n  }\n}\n```\n\nIf setting state is the only thing you need to do in the constructor,\nthen you can skip the constructor all together.\n\n```javascript\nclass MyComponent extends React.Component {\n  state = {\n    loading: true\n  };\n\n  render() {\n    if (this.state.loading) {\n      return (\n        <p>Loading...</p>\n      );\n    } else {\n      // ...\n    }\n  }\n}\n```\n\nThis second example will work the same as the first, and it is a bit more\nconcise.\n"
  },
  {
    "path": "react/destructure-variables-as-props-to-a-component.md",
    "content": "# Destructure Variables As Props To A Component\n\nWhen passing down props, a redundant-feeling pattern can sometimes emerge.\n\n```javascript\nconst MyComponent = ({ handleChange, handleBlur }) => {\n  return (\n    <div>\n      <OtherComponent />\n      <MySubComponent handleChange={handleChange} handleBlur={handleBlur} />\n    </div>\n  )\n};\n```\n\nThe typing feel duplicative, as if there ought to be a better way. One\noption is to simply pass down all the props:\n\n```javascript\n<MySubComponent {...props} />\n```\n\nThis approach may result in passing down props that we don't intend to pass\ndown and clutters the flow of data in our app.\n\nHere is another approach:\n\n```javascript\nconst MyComponent = ({ handleChange, handleBlur }) => {\n  return (\n    <div>\n      <OtherComponent />\n      <MySubComponent {...{handleChange, handleBlur}} />\n    </div>\n  )\n};\n```\n\nHere we are taking advantage of two ES6 features. Since the naming is the\nsame, we can use [property\nshorthands](http://es6-features.org/#PropertyShorthand). Then we immediately\nuse the [spread operator](http://es6-features.org/#SpreadOperator) to splat\nit back out as the props to the component.\n\nh/t Vidal Ekechukwu\n"
  },
  {
    "path": "react/details-tags-are-a-controllable-component.md",
    "content": "# Details Tags Are A Controllable Component\n\nHTML has a lovely, but little-used tag for summarizing a set of collapsed\ndetails. These details can be expanded and recollapsed by clicking the summary.\nThis is the `<details>` tag and it can be controlled with the `open` prop and\n`onToggle` handler.\n\n```jsx\nimport React, { useState } from \"react\";\n\nexport default function Details({ summary, children, onToggle }) {\n  const [open, setOpen] = useState(false);\n\n  return (\n    <details\n      open={open}\n      onToggle={() => {\n        setOpen(prev => !prev);\n        onToggle();\n      }}\n    >\n      <summary>{summary}</summary>\n      {children}\n    </details>\n  );\n}\n```\n\n[live\nexample](https://codesandbox.io/s/loving-merkle-hxlut?file=/src/App.js:0-545),\n[source](https://github.com/facebook/react/issues/15486)\n"
  },
  {
    "path": "react/dispatch-anywhere-with-redux.md",
    "content": "# Dispatch Anywhere With Redux\n\nYour React app is going to have a single top-level `store` which is\nconnected to the app with the `Provider` component. Most of the time, when\nyou create a connected component, you'll create prop functions that dispatch\non a redux action.\n\nThis isn't the only place you can dispatch though.\n\nIf you export your `store`, then it can be imported anywhere along with its\n`dispatch` function.\n\n```javascript\n// src/index.js\nexport const store = createStore(rootReducer);\n```\n\n```javascript\n// src/components/MyComponent.js\nimport { store } from '../index';\nimport { updateData } from '../actions';\n\n// ...\n\n  componentDidMount() {\n    getData().then((json) => {\n      store.dispatch(updateData(json));\n    }\n  }\n```\n\nSee the [`dispatch`](https://redux.js.org/docs/api/Store.html#dispatch)\ndocumentation for more details.\n"
  },
  {
    "path": "react/dynamically-add-props-to-a-child-component.md",
    "content": "# Dynamically Add Props To A Child Component\n\nIf your component has an element nested in it, then it will receive a\n`children` prop. There are a number of things you can do beyond simply\nincluding the `children` as part of the rendered output of the component.\nOne thing you can do is put additional props on the child.\n\n```javascript\nconst ParentWithClick = ({ children }) => {\n  return (\n    <children.type\n      {...children.props}\n      onClick={() => alert(\"You clicked me!\")}\n    />\n  );\n};\n```\n\nThis `ParentWithClick` component will reconstitute its child component with\nits given props and a new `onClick` prop.\n\nHere is how it can be used:\n\n```javascript\nconst App = () => {\n  return (\n    <ParentWithClick>\n      <span>Hello!</span>\n    </ParentWithClick>\n  );\n};\n```\n\nClick on `Hello!` and you'll see the alert.\n\nMinor caveat: multiple children and a string child will need to be handled\ndifferently.\n\nSee a [live example here](https://codesandbox.io/s/n0pyn61yop).\n"
  },
  {
    "path": "react/dynamically-create-html-elements.md",
    "content": "# Dynamically Create HTML Elements\n\nAn HTML element can be created with a string that matches a recognized\nentity.\n\n```javascript\nconst Paragraph = 'p';\nreturn <Paragraph>Some paragraph content</Paragraph>\n```\n\nThis means we can dynamically create HTML elements such as headers:\n\n```javascript\nconst H = ({ level, ...props }) => {\n  const Heading = `h${Math.min(level, 6)}`;\n  return <Heading {...props} />;\n};\n\nreturn (\n  <React.Fragment>\n    <H level={1}>Header 1</H>\n    <H level={2}>Header 2</H>\n    <H level={5}>Header 5</H>\n  </React.Fragment>\n);\n```\n\nWith some\n[inspiration](https://medium.com/@Heydon/managing-heading-levels-in-design-systems-18be9a746fa3),\nI've created a [live example here](https://codesandbox.io/s/3v202wmmy1).\n"
  },
  {
    "path": "react/enforce-specific-values-with-proptypes.md",
    "content": "# Enforce Specific Values With PropTypes\n\nBeing able to constrain our user interfaces to very specific values is\nvaluable. This makes our interfaces easier to reason about and easier to\ntest. PropTypes in general are one of the ways that we constrain our UIs. We\ncan go even further than simple type constraints by limiting a prop to a\nspecific set of values, an enum if you will.\n\n```javascript\nMyComponent.propTypes = {\n  flavor: PropTypes.oneOf(['Vanilla', 'Chocolate', 'Strawberry']),\n};\n```\n\nThe docs say about `oneOf()`:\n\n> You can ensure that your prop is limited to specific values by treating it\n> as an enum.\n\nIf we use `MyComponent` with a value such as `Pistachio`, we'll have a\nconsole warning to answer for.\n\n[source](https://reactjs.org/docs/typechecking-with-proptypes.html)\n"
  },
  {
    "path": "react/focus-an-input-with-useref-hook.md",
    "content": "# Focus An Input With useRef Hook\n\nYou can send focus to an input by calling\n[`focus()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLOrForeignElement/focus)\non it. To do this in a React context, you need to have a reference to the\nunderlying DOM node. You can get this reference with the [`useRef`\nhook](https://reactjs.org/docs/hooks-reference.html#useref).\n\n```jsx\nimport React, { useRef } from 'react';\n\nconst MyComponent = () => {\n  const inputRef = useRef(null);\n\n  const focusInput = () => {\n    inputRef.current.focus();\n  }\n\n  return (\n    <div>\n      <input\n        ref={inputRef}\n        type=\"text\"\n        value=\"\"\n        {...otherProps}\n      />\n      <button onClick={focusInput}>Edit Input</button>\n    </div>\n  );\n}\n```\n\nWhen this component mounts, the underlying `<input>` element will get tied to\n`inputRef`. The `focusInput` handler that I've created can be used to send\nfocus to the corresponding `inputRef`. To demonstrate, I've passed it to the\n`onClick` handler of the button. Clicking the button will focus the input.\n"
  },
  {
    "path": "react/force-a-component-to-only-have-one-child.md",
    "content": "# Force A Component To Only Have One Child\n\nA component can normally have an arbitrary number of elements nested\ndirectly inside it. React's `Children.only` function can be used to force it\nto a single direct child.\n\n```javascript\nimport React, { Children, Component } from \"react\";\n\nclass App extends Component {\n  render() {\n    return (\n      <SingleChildContainer>\n        <span>There can only be one!</span>\n      </SingleChildContainer>\n    );\n  }\n}\n\nconst SingleChildContainer = props => {\n  return Children.only(props.children);\n};\n\nexport default App;\n```\n\nThe React docs describe the behavior of `Children.only` as such,\n_\"Returns the only child in children. Throws otherwise.\"_.\n\nIf you modify the `return` in `App` to contain the following JSX\n\n```javascript\n<SingleChildContainer>\n  <span>There can only be one!</span>\n  <div>What about me?!</div>\n</SingleChildContainer>\n```\n\nthen an error will be thrown (`React.Children.only expected to receive a\nsingle React element child`).\n\nThe [`Provider`\ncomponent](https://github.com/reactjs/react-redux/blob/master/src/components/Provider.js#L36)\nin [`react-redux`](https://github.com/reactjs/react-redux) is an example of\nwhere this is used.\n"
  },
  {
    "path": "react/forcing-a-child-remount-with-the-key-prop.md",
    "content": "# Forcing A Child Remount With The Key Prop\n\nThere are a couple `prop` names that have reserved usage in React. One of\nthose is `key`. We generally use `key` when we are rendering a list of\nthings. It is a way of uniquely identifying each element in a list so that\nReact minimizes re-rendering when parts of the list change.\n\nWe can flip this on its head and utilize `key` as a way of forcing a remount\nand re-render of a child component.\n\nImagine I have a component that does a number of things including rendering\na component with some internal state, such as a counter.\n\n```javascript\nclass MyComponent extends React.Component {\n  state = {\n    remountKey: (new Date()).getTime(),\n  }\n\n  resetCounter = () => {\n    this.setState({\n      remountKey: (new Date()).getTime(),\n    });\n  }\n\n  render() {\n    return (\n      <div>\n        {/* some other stuff in my component */}\n\n        <Counter key={this.state.remountKey} />\n        <button onClick={this.resetCounter}>Reset Counter</button>\n      </div>\n    );\n  }\n}\n```\n\nI can force this `Counter` component to remount, thus resetting its state by\npassing it a new `key` value. The `button` can trigger this by updating the\n`remountKey` value.\n"
  },
  {
    "path": "react/formik-connected-components.md",
    "content": "# Formik Connected Components\n\nFormik comes with a `connect()` HOC that uses the context API as a way of\nconnecting to disparate form elements. This means that form data, change\nhandlers, touched and error data, etc. can be easily accessed without a lot of\n[prop drilling](https://kentcdodds.com/blog/prop-drilling).\n\nAny component that lives somewhere downstream in the tree of a Formik form can\nuse `connect()`.\n\n```javascript\nimport { connect, getIn } from \"formik\";\n\nconst Input = ({ type = \"text\", name, id, label, formik }) => {\n  return (\n    <React.Fragment>\n      <label htmlFor={name}>{label}:</label>{\" \"}\n      <input\n        type={type}\n        onChange={formik.handleChange}\n        onBlur={formik.handleBlur}\n        value={getIn(formik.values, name)}\n        name={name}\n        id={id}\n      />\n    </React.Fragment>\n  );\n};\n\nexport default connect(Input);\n```\n\nThis `Input` component is wrapped in `connect` which means it gets the `formik`\nprop which contains everything that we mentioned and more -- all the context\nyou'll need to make your form element work.\n\nYou can play around with it using this [live\nexample](https://codesandbox.io/s/quizzical-hill-7xlwi).\n"
  },
  {
    "path": "react/formiks-validation-schema-as-a-function.md",
    "content": "# Formik's Validation Schema As A Function\n\nThe most straightforward way to use\n[Formik](https://jaredpalmer.com/formik)'s `validationSchema` is to provide\nit with a [Yup](https://github.com/jquense/yup) object defining your form's\nvalidations.\n\n```javascript\nconst MyComponent = withFormik({\n  // ...\n\n  validationSchema: yup.object().shape({\n    email: yup.string().required(),\n    feedback: yup.string().required(),\n  }),\n  \n  // ...\n})(MyForm);\n```\n\nThere may be a point at which you need access to the `props` being passed\nto `MyComponent` in order to construct the proper set of validations.\nFormik supports this by allowing `validationSchema` to be a function.\n\n```javascript\nconst MyComponent = withFormik({\n  // ...\n\n  validationSchema: (props) => {\n    let emailSchema;\n    if(props.allowAnonymous) {\n      emailSchema = yup.string();\n    } else {\n      emailSchema = yup.string().required();\n    }\n\n    return yup.object().shape({\n      email: emailSchema,\n      feedback: yup.string().required(),\n    });\n  },\n  \n  // ...\n})(MyForm);\n```\n\nWhen `validationSchema` is a function, its first argument is the set of\nprops passed to that component.\n"
  },
  {
    "path": "react/inactive-and-active-component-styles-with-radium.md",
    "content": "# Inactive And Active Component Styles With Radium\n\n[Radium](https://github.com/FormidableLabs/radium) is \"toolchain for React\ncomponent styling\" allowing you to do comprehensive inline styling with CSS.\n\nOften times, especially in the case of a series of nav elements, there is a\nneed to style one element as _active_ while styling the rest as _inactive_.\nThis can be achieved with Radium by defining two groups of styles (`base`\nand `active`) and then relying on props to conditionally apply the active\nstyle.\n\n```javascript\nimport React from 'react';\nimport Radium from 'radium';\n\nconst styles = {\n  base: {\n    textDecoration: \"none\",\n    color: \"gray\",\n  },\n  active: {\n    color: \"black\",\n    backgroundColor: \"lightgray\",\n  },\n};\n\nlet NavItem = ({ label, path, active }) => {\n  return (\n    <a\n      href={path}\n      style={[\n        styles.base,\n        styles[active && 'active'],\n      ]}\n    >{label}</a>\n  );\n};\n\nNavItem = Radium(NavItem);\n```\n\nWith Radium, our `base` (_inactive_) styles always get applied. Then, the\n`active` styles only get applied when the `active` prop is true. We produce\na Radium-ified version of our `NavItem` on the last line so that Radium can\nhandle all of the styling of the component.\n"
  },
  {
    "path": "react/inline-style-attributes-should-be-camel-cased.md",
    "content": "# Inline Style Attributes Should Be Camel Cased\n\nWhen adding a few quick styles to React components, you can add it directly\non the tags in the JSX. To do this, use the `style` tag with a plain old\nJavaScript object of styles.\n\n```javascript\n<div style={{ padding: \"1em\", color: \"#fff\" }}>\n```\n\nIf you are using a CSS attribute that is normally hyphenated like\n`padding-top` or `background-color`, you'll need to camel case it in the\nJSX.\n\n```javascript\n<div style={{ paddingTop: \"1em\", backgroundColor: \"#fff\" }}>\n```\n\nThis is because our styles now need to conform to JavaScript syntax\nrules since they are in the form of a POJO.\n\nRead the [documentation](https://reactjs.org/docs/dom-elements.html#style)\nfor more details.\n"
  },
  {
    "path": "react/manage-state-in-a-functional-component.md",
    "content": "# Manage State In A Functional Component\n\nBefore the introduction of React 16.8, you had a couple options for declaring\nand managing state in your components.\n\nThe first _class_ way was to create a class component and then [add local,\ncomponent state to\nit](https://reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class).\n\nIf you already had a functional component, you could avoid the conversion to a\nclass component with custom HOCs and Render Prop components or any number of\nthird-party libraries such as [React\nPowerPlug](http://rena.to/react-powerplug/#/docs-components-state) and\n[Recompose](https://github.com/acdlite/recompose).\n\nHowever, projects using React 16.8+ have\n[Hooks](https://reactjs.org/docs/hooks-intro.html) at their disposal. The Hooks\nAPI's base offering is a state hook --\n[`useState`](https://reactjs.org/docs/hooks-state.html).\n\n```javascript\nimport React, { useState } from \"react\";\n\nconst Toggler = () => {\n  const [on, setOn] = useState(false);\n  const [toggleCount, setToggleCount] = useState(0);\n\n  const incrementToggleCount = setToggleCount(prev => prev + 1);\n  const handleToggle = () => {\n    setOn(prev => !prev);\n    incrementToggleCount();\n  };\n\n  return (\n    <React.Fragment>\n      <Thing on={on} />\n      <button onClick={handleToggle}>{on ? \"ON\" : \"OFF\"}</button>\n      <p>Toggle Count: {toggleCount}</p>\n    </React.Fragment>\n  );\n}\n```\n\nYou can manage a variety of state values in a functional component with\n`useState`. The `useState` function takes the initial state value as an\nargument and returns a tuple with the current state value and an _setter_\nfunction for updating that piece of state.\n"
  },
  {
    "path": "react/mapping-over-one-or-many-children.md",
    "content": "# Mapping Over One Or Many Children\n\nIn [Dynamically Add Props To A Child\nComponent](https://github.com/jbranchaud/til/blob/master/react/dynamically-add-props-to-a-child-component.md),\nI talked about how a child element can be reconstituted with additional\nprops. The approach I showed will only work in the case of a single child\nbeing nested in that component. What if you want your component to account\nfor one, many, or even children?\n\nReact comes with a built-in function for mapping that handles these cases.\n\n```javascript\nconst ParentWithClick = ({ children }) => {\n  return (\n    <React.Fragment>\n      {React.Children.map(children || null, (child, i) => {\n        return <child.type {...child.props} key={i} onClick={handleClick} />;\n      })}\n    </React.Fragment>\n  );\n};\n```\n\nThe [`React.Children.map`\nfunction](https://reactjs.org/docs/react-api.html#reactchildrenmap) allows\nmapping over one or many elements and if `children` is `null` or\n`undefined`, it will return `null` or `undefined` respectively.\n\nSee a [live example here](https://codesandbox.io/s/kwj29y2j2r).\n"
  },
  {
    "path": "react/mock-a-function-that-a-component-imports.md",
    "content": "# Mock A Function That A Component Imports\n\nYou have a component that relies on an imported function,\n`isAuthenticated()`.\n\n```javascript\n// MyComponent.js\nimport React from 'react';\nimport { isAuthenticated } from './authentication';\n\nconst MyComponent = (props) => {\n  if (isAuthenticated()) {\n    return (<div>{/* ... */}</div>);\n  } else {\n    return (<div>Not authenticated</div>);\n  }\n};\n```\n\nYou'd like to test that component without having to manage the\nauthentication of a user. One option is to mock out that function. This can\nbe done with some help from [`jest.fn()` and the `mock.mockReturnValue()`\nfunction](https://github.com/jbranchaud/til/blob/master/javascript/mock-a-function-with-return-values-using-jest.md).\n\n```javascript\n// MyComponent.test.js\n// ... various testing imports\n\nimport * as authModules from './authentication';\n\nit('renders the component', () => {\n  authModules.isAuthenticated = jest.fn().mockReturnValue(true);\n\n  const wrapper = shallow(<MyComponent />);\n  expect(toJson(wrapper)).toMatchSnapshot();\n});\n```\n\nBy importing the same module and functions used by `MyComponent`, we are\nthen able to replace them (specifically, `isAuthenticated`) with a mocked\nversion of the function that returns whatever value we'd like. As\n`MyComponent` is being rendered, it will invoked our mocked version of\n`isAuthenticated` instead of the actual one.\n\nYou could test the other direction like so:\n\n```javascript\nauthModules.isAuthenticated = jest.fn().mockReturnValue(false);\n```\n"
  },
  {
    "path": "react/navigate-with-state-via-reach-router.md",
    "content": "# Navigate With State Via @reach/router\n\nWith [@reach/router](https://reach.tech/router), you can programmatically\nchange your route using the\n[`navigate`](https://reach.tech/router/api/navigate) function. This utilizes\nthe Context API, so its available anywhere nested under your router. To\nprovide some data to the destination location, include a `state` option in\nthe `navigate` call.\n\n```javascript\nconst onSubmit = ({ data }) => {\n  /* submit logic ... */\n\n  navigate(nextPath, { state: { data }});\n}\n```\n\nThe component that renders in response to this navigation will have access\nto this state.\n\n```javascript\nconst NextComponent = ({ location }) => {\n  const { data } = location.state;\n\n  return (\n    /* ... */\n  )\n}\n```\n"
  },
  {
    "path": "react/pairing-a-callback-with-a-usestate-hook.md",
    "content": "# Pairing A Callback With A useState Hook\n\nReact's Class-based state management allowed you to update the state of your\ncomponent with a call to `this.setState()`. The first argument represents the\nchanges to the state. It also accepts a second argument; a callback that will\nbe invoked after the state has been updated.\n\n```javascript\nthis.setState({ loading: true }, () => console.log(\"Loading...\"));\n```\n\nIf you've transitioned to Hooks-based state management, then you may have\nnoticed that the updaters generated by `useState` calls do not accept a second\ncallback argument.\n\nIf you want to update state and fire a callback in response to it, you can pair\n`useState` with `useEffect`.\n\n```javascript\nimport React, { useState, useEffect } from \"react\";\n\nfunction App() {\n  const [loading, setLoading] = useState(false);\n  const toggleLoading = () => setLoading(prevLoading => !prevLoading);\n  useEffect(() => {\n    if(loading) {\n      console.log(\"We are loading now\");\n    }\n  }, [loading])\n\n  return (\n    <div>\n      {loading && <p>Loading...</p>}\n      <button onClick={toggleLoading}>{loading ? \"Cancel\" : \"Save\"}</button>\n    </div>\n  );\n}\n```\n\nThe `useState` acts on its own. It has no side-effects. We follow it with a\n`useEffect` that responds to changes to the value of `loading` -- this is where\nour _callback_ gets invoked.\n\nSee a [live example](https://codesandbox.io/s/clever-roentgen-kvzze).\n"
  },
  {
    "path": "react/pass-a-function-to-a-usestate-updater.md",
    "content": "# Pass A Function To A useState Updater\n\nLet's say you have a component with a toggle state:\n\n```javascript\nconst [toggle, setToggle] = useState(false);\n```\n\nYou can change the state of the toggle by directly passing a value to\n`setToggle`.\n\n```javascript\nsetToggle(true);\nconsole.log(toggle);\n//=> true\n```\n\nAlternatively, you can pass a function to the updater. This is called a\n[_functional\nupdate_](https://reactjs.org/docs/hooks-reference.html#functional-updates). The\nupdater will call the function with the previous state value and update the\nstate to whatever the function returns.\n\n```javascript\nconst handleToggle = (prevToggle) => {\n  return !prevToggle;\n}\n\nconsole.log(toggle);\n//=> true\n\nsetToggle(handleToggle);\n\nconsole.log(toggle);\n//=> false\n```\n"
  },
  {
    "path": "react/passing-props-down-to-react-router-route.md",
    "content": "# Passing Props Down To React-Router Route\n\nWhen using [react-router](https://github.com/ReactTraining/react-router),\nyou'll often use the `component` prop to have a certain component rendered.\n\n```javascript\n<Route\n  path=\"/my/path\"\n  component={MyComponent}\n/>\n```\n\nIf, however, you need to pass props down into `MyComponent`, then you'll\nwant to use the `render` prop with an inline function.\n\n```javascript\n<Route\n  path=\"/my/path\"\n  render={(routeProps) => (\n    <MyComponent {...routeProps} {...props} />\n  )}\n/>\n```\n\nThe two spread operator statements are essential. They will pass down the\n[route\nprops](https://reacttraining.com/react-router/web/api/Route/Route-props)\nthat `Route` would have passed down plus the additional set of props that\nyou want to pass down.\n"
  },
  {
    "path": "react/prevent-reach-router-redirect-error-screen-in-dev.md",
    "content": "# Prevent reach/router Redirect Error Screen In Dev\n\nWhen using [@reach/router's\n`<Redirect>`](https://reach.tech/router/api/Redirect) with tools like\ncreate-react-app and Gatsby, you'll get those tools' development-mode error\nscreen overlays whenever a redirect happens. This has to do with how\n@reach/router utilizes `componentDidCatch` to change the path without a\nrender. That error screen overlay can get annoying though. Prevent it with\nthe `noThrow` prop.\n\n```javascript\nreturn (\n  <Redirect to={anotherPath} noThrow />\n);\n```\n"
  },
  {
    "path": "react/proxy-to-an-api-server-in-development-with-cra.md",
    "content": "# Proxy To An API Server In Development With CRA\n\n[create-react-app](https://github.com/facebookincubator/create-react-app) is\na great way to bootstrap a React project, especially if you are building a\nsingle-page app. When building an SPA, you more likely than not will have a\nbackend API that you interact with.\n\nYou can set up your React app to interact with that backend API server in\ndevelopment using the `proxy` configuration in `package.json`.\n\n```json\n// package.json\n  ...\n  \"proxy\": \"http://localhost:4000\",\n}\n```\n\nThis will allow you to keep your API calls nice and clean.\n\n```javascript\nfetch(\"/api/session\", ...\n```\n\nNo need to manage some sort of _host URL_ environment variable.\n\nAdditionally, this will remove an CORS issues because the `webpackDevServer`\nwill be proxying any paths that it doesn't recognize to the host and port\nthat you've specified.\n\nSee [the `create-react-app`\ndocs](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#proxying-api-requests-in-development)\nfor more details.\n"
  },
  {
    "path": "react/quickly-search-for-a-component-with-react-devtools.md",
    "content": "# Quickly Search For A Component With React DevTools\n\nAs the size of your React app grows, it can become challenging to track down\nspecific components within the [React\nDevTools](https://github.com/facebook/react-devtools) extension. You opened\nit up with the hopes of quickly inspecting the `props` being received by a\ncomponent, but find yourself navigating through the DOM structure instead.\n\nThe React DevTools extension provides a search bar that can be used to\nquickly filter out most components.\n\n![react devtools component search](https://i.imgur.com/dYd8SZD.gif)\n\nThe search bar is located at the top of the extension. Once you start typing\nthe results are immediate. Then, if you hover over any of the remaining\ncomponents, you'll get some visual feedback as they are highlighted in the\nbrowser.\n"
  },
  {
    "path": "react/reach-router-renders-to-a-div.md",
    "content": "# @reach/router Renders To A Div\n\nCheck out the following snippet that uses\n[`@reach/router`](https://reach.tech/router).\n\n```javascript\nimport { Router } from '@reach/router';\n\nconst Home = () => <h1>Home</h1>;\n\nconst App = () => {\n  return (\n    <div className=\"main\">\n      <Router>\n        <Home path=\"/home\" />\n      </Router>\n    </div>\n  );\n}\n```\n\nWhen you visit '/home', this will render in the DOM as:\n\n```html\n<div class=\"main\">\n  <div tabindex=\"-1\" role=\"group\" style=\"outline: none;\">\n    <h1>Home<h1>\n  </div>\n</div>\n```\n\nNotice the extra `div` -- that is what `<Router>` renders to as part of\n`@reach/router`'s accessibility features. This may throw off the structure\nor styling of your app. This can be fixed. Any props that you give to\n`<Router>` will be passed down to that `div`. For instance, you could remove\nthe most outer `div` and put `className=\"main\"` on the `<Router>`.\n\n[source](https://github.com/reach/router/issues/63#issuecomment-395988602)\n"
  },
  {
    "path": "react/read-only-input-elements.md",
    "content": "# Read Only Input Elements\n\nHere is an input element with a `value` and no `onChange` handler.\n\n```javascript\nconst MyInput = ({ value }) => {\n  return (\n    <input value={value} />\n  );\n};\n```\n\nReact will raise a warning regarding the `input` element because it has a\n`value` without an `onChange` handler leaving React to wonder if it is\nintended to be a _controlled_ or _uncontrolled_ component.\n\nIf our intention is to have the `value` set but not allow the user to\ndirectly change it, we just need to let React know that.\n\n```javascript\nconst MyInput = ({ value }) => {\n  return (\n    <input readOnly value={value} />\n  );\n};\n```\n\nThe `readOnly` prop means we don't intend for the input to be modified by\nuser input. The React warning will now go away.\n\nh/t Dillon Hafer\n"
  },
  {
    "path": "react/rendering-multiple-nodes-with-fragments.md",
    "content": "# Rendering Multiple Nodes With Fragments\n\nWhen rendering, React expects a component to only return a single node. The\nDOM hierarchy of most components will easily follow this rule, but what\nabout those components that do have multiple inline nodes?\n\nThe two solutions have been to either wrap the inline nodes in an outer\n`div` or to return them as a comma separated array of nodes. With React 16,\nwe can avoid the deficiencies of both of these approaches by using a\nfragment.\n\nJust wrap your inline nodes with a `React.Fragment` node. React will\nunderstand your JSX without wrapping the output DOM in a superfluous `div`.\n\n```javascript\nrender() {\n  return (\n    <React.Fragment>\n      <p>Name: {firstName} {lastName}</p>\n      <p>Email: {email}</p>\n      <p>Age: {age}</p>\n    </React.Fragment>\n  );\n}\n```\n\nSee the [docs on fragments](https://reactjs.org/docs/fragments.html) for\nmore details.\n"
  },
  {
    "path": "react/set-the-type-for-a-usestate-hook.md",
    "content": "# Set The Type For A useState Hook\n\nTypeScript can often infer the type of a `useState` hook. For instance, in the following example, TypeScript infers a type of `boolean`:\n\n```typescript\nconst [open, setOpen] = React.useState(false);\n```\n\nIf we have a `useState` hook that can be `null` or a string:\n\n```typescript\nconst [error, setError] = React.useState(null);\n\nsetError('There was an error');\n// Argument of type 'string' is not assignable\n// to parameter of type 'SetStateAction<null>'\n```\n\nthen we'll get a TypeScript warning when we violate the inferred type of\n`SetStateAction<null>`.\n\nThe `useState` can be appropriate typed for this situation like so:\n\n```typescript\nconst [error, setError] =\n  React.useState<null | string>(null);\n```\n\n[source](https://www.carlrippon.com/typed-usestate-with-typescript/)\n"
  },
  {
    "path": "react/specifying-dependencies-of-a-useeffect-hook.md",
    "content": "# Specifying Dependencies Of A useEffect Hook\n\nThe `useEffect` hook is all about performing side-effects. For instance,\nyou'll want to place API calls within `useEffect` hooks.\n\nThe dependency array -- the second argument to `useEffect` -- is where you\ndeclare all of the values that are depended on within the `useEffect`. If\nyou're making an API call, this array is likely made up of parameters passed to\nthat call.\n\nHere is a contrived example of what that could look like:\n\n```javascript\nconst apiCall = (opts) => Promise.resolve(opts);\nconst [param1, param2, param3] = [1,2,3];\n\nuseEffect(() => {\n  const handleApiCall = async () => {\n    apiCall({ param1, param2, param3 })\n      .then((data) => {\n        // do something with the data\n      })\n      .catch((error) => {\n        // do something with the error\n      });\n  }\n\n  handleApiCall();\n}, [param1, param2, param3]);\n```\n\nIf you don't specify all of the values used in the body of the `useEffect`, you\nare opening yourself up to potentially incorrect code. It is safer to specify\nall of them. The [`exhaustive-deps`\nrule](https://www.npmjs.com/package/eslint-plugin-react-hooks) can help.\n\n[This\nsection](https://overreacted.io/a-complete-guide-to-useeffect/#what-happens-when-dependencies-lie)\nof Dan Abramov's \"A Complete Guide to useEffect\" does an excellent job of\nshowing how things can go wrong when you lie to React about your dependencies.\n"
  },
  {
    "path": "react/spelunking-through-components-with-enzymes-dive.md",
    "content": "# Spelunking Through Components With Enzyme's Dive\n\nMost of the components we write have other components nested in them.\n\n```javascript\nconst Hello = ({ name }) => <h1>Hello {name}!</h1>;\n\nconst HelloContainer = (props) => (\n  <div>\n    <Hello {...props} />\n  </div>\n);\n```\n\nIf we are to [shallow render the above component using\nEnzyme](http://airbnb.io/enzyme/docs/api/ShallowWrapper/shallow.html), we'll\nonly see things one layer deep:\n\n```javascript\nconst wrapper = shallow(<HelloContainer name=\"World\" />);\n// wrapper ~= <div><Hello name=\"World\" /></div>\n```\n\nIf we'd like to explore a particular child of the rendered component\nfurther, we can do a little\n[`find`](http://airbnb.io/enzyme/docs/api/ReactWrapper/find.html) and\n[`dive`](http://airbnb.io/enzyme/docs/api/ShallowWrapper/dive.html).\n\n```javascript\nconst wrapper = shallow(<HelloContainer name=\"World\" />);\nconst helloWrapper = wrapper.find(Hello).dive();\nexpect(helloWrapper.text()).toEqual(\"Hello World!\");\n```\n\nThis allows us to make pinpoint assertions about how our components render\nwithout mounting the entire thing.\n\nSee a [live example here](https://codesandbox.io/s/y236wr1kn1).\n\nh/t Vidal Ekechukwu\n"
  },
  {
    "path": "react/sync-your-react-router-state-with-redux.md",
    "content": "# Sync Your react-router State With Redux\n\nIf you are building a React app that uses both `redux` and `react-router`,\nyou'll find that you are managing app state in two places. Most of your app\nstate is in `redux`. The router-specific state is component-state in the\n`Router`.\n\nYou can unify it all in `redux` with\n[`react-router-redux`](https://github.com/ReactTraining/react-router/tree/master/packages/react-router-redux).\n\nYou'll need to apply some middleware, combine `routerReducer` with the rest\nof your reducers, and then swap out your `BrowserRouter` with a\n`ConnectedRouter`. You can read about the details\n[here](https://github.com/ReactTraining/react-router/tree/master/packages/react-router-redux).\n"
  },
  {
    "path": "react/test-files-in-create-react-app.md",
    "content": "# Test Files In create-react-app\n\nAny `.js` files placed in the `__tests__` directory will be treated as tests\nby Jest when running `yarn test`. If you don't want to place all of your\nfiles in that directory and especially if you want to co-located your test\nfiles with the source files, you can name them with the `.test.js` or\n`.spec.js` suffixes.\n\nAny files in your create-react-app project ending in these suffixes will be\ntreated by Jest as test files and included in test runs.\n\nThere are [more\ndetails](https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#running-tests)\nin the docs.\n"
  },
  {
    "path": "react/test-that-element-does-not-render-in-the-component.md",
    "content": "# Test That Element Does Not Render In The Component\n\nWith\n[`react-testing-library`](https://testing-library.com/docs/react-testing-library/intro),\nyou can render a component and make assertions about the different parts of the\ncomponent that get rendered.\n\nYou can also make assertions that certain things _don't_ get rendered. To do that, first render the component:\n\n```javascript\nimport { render, screen } from '@testing-library/react'\nimport '@testing-library/jest-dom/extend-expect'\n\nimport MyComponent from '../MyComponent'\n\ntest('renders component without Click Me button', () => {\n  render(<MyComponent />)\n})\n```\n\nThen add a `not` expectation with a `query*`-style matcher:\n\n```javascript\n  expect(screen.queryByText('Click Me')).not.toBeInTheDocument()\n```\n\nYou'll get an immediate test failure if you try to directly select for the element using a `get*`-style matcher:\n\n\n```javascript\n  // ❌ will fail on `getByText` before the rest of the\n  // assertion can be evaluated.\n  expect(screen.getByText('Click Me')).not.toBeInTheDocument()\n```\n\n[source](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library#using-query-variants-for-anything-except-checking-for-non-existence)\n"
  },
  {
    "path": "react/trigger-effect-only-when-the-component-mounts.md",
    "content": "# Trigger Effect Only When The Component Mounts\n\nWith `useEffect`, you generally want to values used in the function to also be\nincluded in the _dependency list_. This ensures the effect is triggered\nwhenever any of those values change.\n\nBut what if you only want the effect to be triggered when the component first\nmounts?\n\nThis can be done by including an _empty_ dependency list.\n\n```javascript\nimport React, { useState, useEffect } from \"react\";\n\nfunction App() {\n  const [count, setCount] = useState(0);\n  const incrementCount = () => {\n    setCount(prevCount => prevCount + 1);\n  };\n\n  useEffect(() => {\n    console.log(\"The count is:\", count);\n  }, []);\n\n  return (\n    <div>\n      <button onClick={incrementCount}>+</button>\n      <p>Count: {count}</p>\n    </div>\n  );\n}\n```\n\nIn this example, we will see `The count is: 0` get logged when the component\nfirst mounts. As we hit the button to increment the count, nothing else will be\nlogged.\n\nSee the [live example](https://codesandbox.io/s/mystifying-currying-l2rw2).\n"
  },
  {
    "path": "react/update-formik-initial-values-when-props-change.md",
    "content": "# Update Formik Initial Values When Props Change\n\nWhen a [Formik](https://jaredpalmer.com/formik/) form mounts, whatever the\ninitial values are set to is what they will be. Even if the initial values are\ncomputed from props, those props changing will not affect `initialValues` after\nmount.\n\n```javascript\nconst ZipForm = ({ currentZip }) => {\n  return (\n    <Formik\n      initialValues={{ zip: currentZip }}\n      onSubmit={(values, actions) => {\n        // do stuff\n      }}\n      ...\n```\n\nIf we are fetching the user's saved zip code asynchronously from a server while\nthe form is first being rendered, then `currentZip` will start as an empty\nvalue. Once the async request comes back and `currentZip` is set, we won't see\nthe form update the `zip` field.\n\nThere was a time when you would have to jump through some hoops to make sure\nthe freshest prop value made it into the form. Now, Formik provides a handier\nmechanism -- the `enableReinitialize` prop.\n\n```javascript\nconst ZipForm = ({ currentZip }) => {\n  return (\n    <Formik\n      initialValues={{ zip: currentZip }\n      enableReinitialize\n      onSubmit={(values, actions) => {\n        // do stuff\n      }}\n      ...\n```\n\nBy setting `enableReinitialize` to true, we are telling Formik that any prop\nchanges that flow into the `initialValues` object should cause those values to\nbe _reinitialized_.\n\nSee a [live example](https://codesandbox.io/s/sad-mendeleev-4dbbp).\n"
  },
  {
    "path": "react/upgrading-to-the-latest-react-in-codesandbox.md",
    "content": "# Upgrading To The Latest React In CodeSandbox\n\nAt the time of writing this, the latest version of React is 16.3.1. Opening\nup [CodeSandbox](https://codesandbox.io/) and starting a new React project\nhas us working with React 16.2.\n\n![Defaults to React 16.2](https://i.imgur.com/AmgyfGc.png)\n\nBy clicking on the _circular arrow_ upgrade icon next to `react` and\n`react-dom`, we will have upgraded each to 16.3.1.\n\n![Upgrade to React 16.3.1](https://i.imgur.com/0DPLOY2.png)\n"
  },
  {
    "path": "react/use-a-ref-to-autofocus-an-input.md",
    "content": "# Use A Ref To Autofocus An Input\n\nWhen creating highly interactive interfaces with React, we are trying to\nmake the user's experience of our app as smooth as possible. This means that\nwhen an edit button reveals an input field, we want that field to be in\nfocus so that the user can immediately start typing.\n\nThis is a great use for React's `ref` prop. When you supply your component\nwith a function as the `ref` prop, that function will be called with a\nreference to itself on mount and with `null` on unmount.\n\n```javascript\nclass MyAutofocusInput extends React.Component {\n  focusInput = (component) => {\n    if (component) {\n      component.focus();\n    }\n  };\n\n  render() {\n    return (\n      <input\n        ref={this.focusInput}\n        value={this.props.value}\n        onChange={this.props.onChange}\n      />\n    );\n  }\n}\n```\n\nWhen this component gets rendered, the input will be focused via our\n`focusInput` function.\n\nNote: refs only work with class components, so don't try to use it with a\nfunctional component.\n\nSee [Refs and the DOM](https://reactjs.org/docs/refs-and-the-dom.html) in\nReact's documentation for more details.\n"
  },
  {
    "path": "react/use-react-16-with-gatsby.md",
    "content": "# Use React 16 With Gatsby\n\n[Gatsby](https://www.gatsbyjs.org/), the blazing fast static site generator\nfor React, is tied to React 15.6. If you've been using React 16+ for a\nwhile, then this may come as a bit of a buzzkill.\n\nFortunately, there is a Gatsby plugin that let's you use React 16 with a\nGatsby v1 site --\n[gatsby-plugin-react-next](https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-plugin-react-next).\n\nAdd it the plugin as a dependency:\n\n```bash\n$ yarn add gatsby-plugin-react-next\n```\n\nThen add it to the list of plugins in `gatsby-config.js`:\n\n```javascript\nplugins: [`gatsby-plugin-react-next`];\n```\n\n[source](https://twitter.com/gatsbyjs/status/990806495959826432)\n"
  },
  {
    "path": "react/use-withrouter-to-pass-down-react-router-history.md",
    "content": "# Use withRouter To Pass Down React-Router History\n\nA standard way to navigate with\n[react-router](https://github.com/ReactTraining/react-router) besides using\nthe `Link` component is to call `history.push`. Components that are directly\nrendered by a `Route` will have access to this and other router props. But\nwhat about other components?\n\nThe `withRouter` HOC gives us direct access to a `history` prop.\n\n```javascript\nimport React from 'react';\nimport { withRouter } from 'react-router';\n\nconst SpecialButton = withRouter(({ history, path, text }) => {\n  return (\n    <Button\n      onClick={() => { history.push(path); }}\n    >\n      {text}\n    </Button>\n  )\n});\n```\n\nThis special button component is given the `history` prop via the\n`withRouter` HOC along with any props that we directly pass it. With that\nwe are able to directly invoke a route change using `history.push()`.\n"
  },
  {
    "path": "react/visually-select-a-react-element-for-inspection.md",
    "content": "# Visually Select A React Element For Inspection\n\nSimilar to the _Elements_ tab of Chrome devtools, the [React devtools\nextension](https://github.com/facebook/react-devtools) provides a visual\nelement selector to make it easier to inspect an element you can see in the\nbrowser.\n\n![select and inspect a react component](https://i.imgur.com/cGgSZfN.gif)\n\nOpen the React devtools, click the crosshair icon, hover around the browser\nuntil the element you are looking for is visually highlighted, and then\nclick. The React component hierarchy will be expanded to reveal that\nelement. You can now inspect it or quickly navigate to nearby elements.\n"
  },
  {
    "path": "react/who-is-your-favorite-child.md",
    "content": "# Who Is Your Favorite Child?\n\nWhen we put some content inside the open and close tags of one of our\ncomponents, we get access to it as the `children` prop.\n\n```javascript\nconst Parent = ({children}) => {\n  return (\n    <React.Fragment>\n      <p>These are my favorites:</p>\n      {children}\n    </React.Fragment>\n  );\n}\n\nconst App = () => (\n  <div>\n    <Parent>\n      Greg and Marsha\n    </Parent>\n  </div>\n);\n```\n\nWhat happens if we also provide an explicit `children` prop to `Parent`?\n\n```javascript\nconst App = () => (\n  <div>\n    <Parent children={\"Jan and Peter\"}>\n      Greg and Marsha\n    </Parent>\n  </div>\n);\n```\n\nWhich will take precedence when we destructure `children` in the parent\ncomponent?\n\nIn the example above, we'll still see `Greg and Marsha` rendered. The\ncontent placed inside the tags will take precedence over the explicit\n`children` prop.\n\nSee a [live example here](https://codesandbox.io/s/kmo5lk2lr5).\n"
  },
  {
    "path": "react/wrap-the-root-of-a-gatsby-app-in-a-component.md",
    "content": "# Wrap The Root Of A Gatsby App In A Component\n\nEach component that is defined in the `pages` directory of a\n[Gatsby](https://www.gatsbyjs.org/) app will be generated into a separate\nstatic page. Each of these pages is meant to stand on its own. Nevertheless,\nthere is still a behind-the-scenes root component above all of these pages.\nThere are cases where'd you like to wrap this root component with some other\ncomponent, such as a Redux `Provider`.\n\nThis can be done using the `wrapRootElement` hook from the Browser API in\nthe `gatsby-browser.js` file.\n\n```javascript\n// gatsby-browser.js\nimport React from 'react';\nimport { Provider } from 'react-redux';\n\nimport store from './src/store';\n\nexport const wrapRootElement = ({ element }) => {\n  return (\n    <Provider store={store}>{element}</Provider>\n  );\n}\n```\n\nEach page and each component in your Gatsby app will now be downstream from\na Redux provider meaning that they can connect to the Redux store as needed.\nYou can use this technique for any top-level component that need to be\nwrapped around the entire app.\n\n[source](https://www.gatsbyjs.org/docs/browser-apis/#wrapRootElement)\n"
  },
  {
    "path": "react-testing-library/check-that-a-component-renders-as-null.md",
    "content": "# Check That A Component Renders As Null\n\nConsider a component that sometimes renders as `null`.\n\n```javascript\nconst HiddenMessage = ({ message, hidden }) => {\n  if (hidden) return null;\n\n  return <span>{message}</span>;\n};\n```\n\nHow can we test the version of this component that renders as `null` when\n`hidden` is `true`?\n\nWhen\n[react-testing-library](https://testing-library.com/docs/react-testing-library/intro)\nrenders a component, it wraps the whole thing in a surrounding `<div>`. Knowing\nthis, we can check if a component renders to `null` by checking the contents of\nthe wrapping `<div>` container.\n\n```javascript\nimport React from \"react\";\nimport { render } from \"@testing-library/react\";\nimport \"@testing-library/jest-dom/extend-expect\";\n\ntest(\"renders as null\", () => {\n  const { container } = render(\n    <HiddenMessage hidden message=\"You can't see me!\" />\n  );\n\n  expect(container.firstChild).toBeNull();\n});\n```\n\nThe component renders as `null`, so the `firstChild` of the RTL `container`\nwill be `null`.\n"
  },
  {
    "path": "react-testing-library/find-by-queries-have-async-built-in.md",
    "content": "# findBy\\* Queries Have Async Built In\n\nThe `getBy*` queries provided by [DOM Testing\nLibrary](https://testing-library.com/docs/dom-testing-library/api-queries)\nallow you to find an element by various criteria in the rendered component.\nThese queries are synchronous. If you need to find an element in response to an\nasync event, you'll have to wrap it in a `waitFor` call.\n\nDOM Testing Library also provides a set of `findBy*` queries as a convenience\nwhich have essentially wrapped the corresponding `getBy*` calls in `waitFor`\ncalls  under the hood.\n\nYou can use these with async/await:\n\n```javascript\ntest(\"displays validation warnings for required fields\", async () => {\n  render(<MyFormComponent />);\n\n  fireEvent.click(screen.getByText(\"Submit\"));\n\n  // validation on Name field\n  const nameValidation = await screen.findByTestId(\"error-name\");\n  expect(nameValidation.innerHTML).toBe(\"Required\");\n});\n```\n\n[source](https://twitter.com/davidcrespo/status/1296639929376792577?s=20)\n"
  },
  {
    "path": "react-testing-library/pretty-print-some-dom-to-debug-a-test.md",
    "content": "# Pretty Print Some DOM To Debug A Test\n\nOur test's assertions can help guide what needs to change in the code.\nSometimes those test failures can be too opaque to be helpful.\n\nIt'd be easier if we could just take a peek at how the component is rendering.\n\n```javascript\nimport { render, screen } from \"@testing-library/react\";\nimport { prettyDOM } from \"@testing-library/dom\";\nimport \"@testing-library/jest-dom/extend-expect\";\n\nimport MyComponent from \"../MyComponent\";\n\ntest(\"renders MyComponent\", () => {\n  const { container } = render(<MyComponent />);\n\n  console.log(prettyDOM(container));\n\n  const nameInput = screen.getByLabelText(\"Name\");\n\n  console.log(prettyDOM(nameInput));\n\n  // some expectations\n});\n```\n\nPassing the rendered container or elements that we've queried for to the\n[`prettyDOM`](https://testing-library.com/docs/dom-testing-library/api-helpers#prettydom)\nutility creates a formatted, syntax-highlighted version of that part of the\nvirtual DOM (without all the React Internal noise). This can then be logged out\nfor debugging purposes.\n"
  },
  {
    "path": "react-testing-library/test-a-component-that-uses-react-portals.md",
    "content": "# Test A Component That Uses React Portals\n\nWhen using\n[react-testing-library](https://testing-library.com/docs/react-testing-library/intro)\nto render a component that uses\n[Portals](https://reactjs.org/docs/portals.html), you'll probably run into an\nissue with your `Portal` code. When trying to set up the portal, it will fail\nto find the portal's root element in the DOM.\n\n```javascript\nconst portalRoot =\n  global.document && global.document.getElementById(\"portal-root\");\n// portalRoot is null 😱\n```\n\nThere are [a number of\nsolutions](https://github.com/testing-library/react-testing-library/issues/62).\n[One\nsolution](https://github.com/testing-library/react-testing-library/issues/62#issuecomment-438653348),\nrecommended by KCD, is to add the portal's root element to the document if it's\nnot already there.\n\n```javascript\nlet portalRoot =\n  global.document && global.document.getElementById(\"portal-root\");\n\nif (!portalRoot) {\n  portalRoot = global.document.createElement(\"div\");\n  portalRoot.setAttribute(\"id\", \"portal-root\");\n  global.document.body.appendChild(portalRoot);\n}\n```\n\nBy solving this issue directly in the portal's source code, you are making it\nmore reliable and don't have to add extra boilerplate to your test setup.\n\n[source](https://github.com/testing-library/react-testing-library/issues/62#issuecomment-438653348)\n"
  },
  {
    "path": "react_native/avoid-the-notch-with-safeareaview.md",
    "content": "# Avoid The Notch With SafeAreaView\n\niOS devices, especially the iPhone X, have areas of the screen that are cut\noff in ways that present quite a challenge to developers. One of the easiest\nways to deal with rounded corners and the notch when developing for iOS is\nto avoid them all together.\n\n> The purpose of `SafeAreaView` is to render content within the safe area\n> boundaries of a device.\n\n```javascript\nimport { SafeAreaView, View, Text } from 'react-native';\n\nconst App = () => {\n  return (\n    <SafeAreaView style={{ flex: 1, backgroundColor: \"#e6e6e6\" }}>\n      <View>\n        <Text>Safely rendered in the visible area of the device!</Text>\n      </View>\n    </SafeAreaView>\n  );\n}\n```\n\nThe _unsafe_ area can be styled however you like and everything inside\n`<SafeAreaView>` will be pushed into the visible area of the screen.\n\nh/t Dillon Hafer\n\n[source](https://facebook.github.io/react-native/docs/safeareaview.html)\n"
  },
  {
    "path": "reason/break-out-of-a-while-loop.md",
    "content": "# Break Out Of A While Loop\n\nThe `while` construct is a great way to loop indefinitely. You may\neventually want to break out of the loop. For that, you are going to need to\ninvalidate the _while condition_. One way of going about this is creating a\nmutable ref, changing it from true to false when a certain condition is met.\n\n```reason\nlet break = ref(true);\n\nwhile (break^) {\n    switch (Unix.readdir(currentDir)) {\n    | exception End_of_file => break := false\n    | item => print_endline(item);\n    }\n};\n```\n\nHere we have a mutable ref called `break` which starts as `true`. This is\nour _while condition_. Its actual value can be referenced by appending the\n`^` character -- hence `break^`. Once a certain condition is met inside our\n`while` block, we can set `break` to `false` using the `:=` operator.\n\nThe above code snippet can be seen in full details\n[here](https://github.com/jbranchaud/basic-ls-reason-native/blob/master/src/Index.re).\n\n[source](https://reasonml.github.io/docs/en/imperative-loops.html#tips-tricks)\n"
  },
  {
    "path": "reason/compile-reason-to-native-with-dune.md",
    "content": "# Compile Reason To Native With Dune\n\n[Dune](https://github.com/ocaml/dune) is \"a composable build system for\nOCaml\" with out-of-the-box support for ReasonML. Dune can be used for a lot\nof things, but in simplest terms it can be used to compile ReasonML programs\ninto native executables.\n\nConsidering the following ReasonML program.\n\n```reason\n/* hello_reason.re */\nprint_endline(\"Hello, Reason!\")\n```\n\nWe can then create the following Dune build file.\n\n```lisp\n;; dune\n(executable\n (name hello_reason))\n```\n\nIf we then run `dune build hello_reason.exe`, then Dune will compile the\n`hello_reason.re` into a `hello_reason.exe` executable that can be found in\n`build/default`. Run it and see the output.\n\nRead more in the [Quickstart\nguide](https://dune.readthedocs.io/en/latest/quick-start.html).\n"
  },
  {
    "path": "reason/compile-reason-with-an-ocaml-package-using-dune.md",
    "content": "# Compile Reason With An OCaml Package Using Dune\n\nIn [Compile Reason To Native With\nDune](reason/compile-reason-to-native-with-dune.md), I showed how to compile\na basic ReasonML file as a native executable using Dune.\n\nAny non-trivial program will likely involve pulling in an OCaml dependency.\nFor example, you may want to pull in [Lwt](https://github.com/ocsigen/lwt).\nAssuming this package is available, whether you've manually downloaded it\nvia [opam](https://opam.ocaml.org/) or used something like\n[esy](https://github.com/esy/esy), you'll want to let Dune know that Lwt is\nan available library.\n\n```lisp\n;; dune\n(executable\n (name hello_reason)\n (libraries lwt lwt.unix))\n```\n\nThe modules in the Lwt package will now be globally available to your\nReason code.\n\n```reason\nlet () = {\n  Lwt_main.run(\n    Lwt_io.printf(\"Hello, Reason!\\n\")\n  );\n};\n```\n\nWhen Dune builds your code, it will include and compile Lwt.\n\nSee a [full example\nhere](https://github.com/jbranchaud/esy-reasonml-lwt-example).\n"
  },
  {
    "path": "reason/create-a-map-of-strings.md",
    "content": "# Create A Map Of Strings\n\n[ReasonML](https://reasonml.github.io/en) has the [`Map.Make`\nfunctor](https://reasonml.github.io/api/Map.Make.html) in its standard\nlibrary which allows you to create a `Map` module with a specific key type.\nHere is how we can make a map module with string keys.\n\n```reason\nmodule StringMap = Map.Make(String);\n```\n\nWe can then use that module to to create an empty map followed by adding\nkey-value pairs to it.\n\n```reason\nStringMap.empty\n|> StringMap.add(\"Morty\", \"Smith\")\n|> StringMap.add(\"Rick\", \"Sanchez\")\n|> StringMap.add(\"Scary\", \"Terry\")\n|> StringMap.iter((first, last) => {\n  print_endline(Printf.sprintf(\"%s %s\", first, last));\n});\n/*\nMorty Smith\nRick Sanchez\nScary Terry\n*/\n```\n\nSee the [live\nexample](https://reasonml.github.io/en/try?rrjsx=true&reason=LYewJgrgNgpgBAZQC4CcCWA7A5gWQIYAOcAvHPgQHT4DWMAFMutgJQDcAUO45roRTMAJIAnuwA+APkSoe5CnjBg6AIhwgUI5QBo4yhMDRIAFsubip3bHIVLlAJTQBjatt0I8GR0ZgAvU+ekmXkobFQRHPBRhV2UAFRgUKP9JQNk+QwS6OgAzNBQAZyQdKDxC5hIpAG92ODgCJiQAfRgMMChMegAFBuyKfPrMJGyVAFJ8uDHXXIKiuBKytnYAXzYgA).\n"
  },
  {
    "path": "reason/create-a-stream-from-an-array.md",
    "content": "# Create A Stream From An Array\n\nThere are functions in the [`Stream`\nmodule](https://reasonml.github.io/api/Stream.html) for turning a variety of\ndata structures into streams -- lists, input channels, etc.\n\nWhat if you have an array?\n\nThe `Stream.from` function lets you define a function for custom fitting\ndata structures into streams. Let's take a look:\n\n```reason\nlet pokemons = [| \"bulbasaur\", \"charmander\", \"squirtle\" |];\n\nlet poke_stream: Stream.t(string) =\n  Stream.from(i =>\n    switch (pokemons[i]) {\n    | pokemon => Some(pokemon)\n    | exception (Invalid_argument(\"index out of bounds\")) => None\n    }\n  );\n```\n\nThe function takes the current index and needs to either return `Some('a)`\nwith the corresponding value or `None` if the stream is empty.\n\nWith that, we now have a stream on which we can invoke any of the stream\nfunctions.\n\n```reason\nswitch (Stream.next(poke_stream)) {\n| pokemon => print_endline(Printf.sprintf(\"Next Pokemon: %s\", pokemon))\n| exception Stream.Failure => print_endline(\"No pokemon left\")\n};\n```\n"
  },
  {
    "path": "reason/creating-a-2d-array.md",
    "content": "# Creating A 2D Array\n\nIn most languages if I wanted to create a two-dimensional array, I would\nutilize some nested looping construct to generate columns of rows. The\n[ReasonML `Array` module](https://reasonml.github.io/api/Array.html)\nabstracts this away.\n\n```reason\nlet grid = Array.make_matrix(10, 10, 0);\n\ngrid\n|> Array.iter(column => {\n  column\n  |> Array.iter(cell => {\n    print_int(cell);\n  });\n  print_endline(\"\");\n});\n\n/*\n0000000000\n0000000000\n0000000000\n0000000000\n0000000000\n0000000000\n0000000000\n0000000000\n0000000000\n0000000000\n*/\n```\n\nThe `make_matrix` function allows you to specify dimensions of a\ntwo-dimensional array with all positions initialized to the same value --\nthat third argument.\n"
  },
  {
    "path": "reason/data-structures-with-self-referential-types.md",
    "content": "# Data Structures With Self-Referential Types\n\n[ReasonML](https://reasonml.github.io/) has a powerful type system that\nallows us to create types that represent all sorts of things. For data\nstructures like [linked lists](https://en.wikipedia.org/wiki/Linked_list),\nwe need a sort of recursive type, a type that can reference itself -- a\nself-referential type.\n\nReason's type system allows us to define types that reference themselves.\nCombine that with type arguments and variants -- we can create a type\ndefinition to represents something like a linked list.\n\n```reason\ntype linked_list('a) =\n  | Empty\n  | Node('a, linked_list('a));\n```\n\nA linked list is a chain of nodes. It can be an _empty_ list, hence the\nfirst part of the variant. Otherwise, it is a node that has some data and\nthen points to another linked list (chain of nodes).\n\nThe `'a` part is a type argument. When creating a linked list, we can decide\nwhat type the `'a` will be. Here is an `int`-based linked list:\n\n```reason\nlet my_list: linked_list(int) = Node(25, Node(27, Empty));\n/* my_list = [25] => [27] => [] */\n```\n"
  },
  {
    "path": "reason/defining-variants-with-constructor-arguments.md",
    "content": "# Defining Variants With Constructor Arguments\n\nIn [Helping The Compiler Help Us With\nVariants](https://github.com/jbranchaud/til/blob/master/reason/helping-the-compiler-help-us-with-variants.md),\nI introduced the concept of variants with a basic example of how to define\nand use one. The fun doesn't stop there.\n\nWe can take variants a step further by defining them with constructor\narguments.\n\n```reason\ntype listActions =\n  | Length\n  | Nth(int);\n```\n\nThe second variant is defined such that it is paired with some extra data --\na single `int` argument.\n\nHere is how we use that variant in our code:\n\n```reason\nlet performListAction = (l: list(int), action: listActions) => {\n  switch(action) {\n  | Length => List.length(l)\n  | Nth(n) => List.nth(l, n)\n  }\n};\n\nperformListAction([7,8,9], Nth(1)); /* 8 */\nperformListAction([1,2,3], Length); /* 3 */\n```\n\nOur switch statement not only matches on that variant, but it makes the\n`int` argument available as a value we can consume in that step of the\nswitch.\n\n[source\ncode](https://reasonml.github.io/en/try.html?reason=C4TwDgpgBANglgZ2AQQMbDgewHYKgXgCgooAfKAGQmwHNgALYsqAOQYAo5tgBKAbkKEYEYFEgAnAGaZxAWwqIU6LNgJR2MAFyxFnbjwA0UAIbKc2+EjQYcCHgQB8UAN5MEAdzjBU9dqZvY9q4k5FS0DI6UigB0wuG+MDxM5Gy+gZEKSNHcCUaBTAC+hAUChABSCLGYNOwS0nKZSgHsANoA7AYAHAYAnAC6RqnsAIw8YwIVVTV1MvKK1iqtwwYATAYAzAOU1HT040A)\n"
  },
  {
    "path": "reason/dynamically-create-a-printf-string-format.md",
    "content": "# Dynamically Create A Printf String Format\n\nFormatting a string with `Printf` requires defining a format for that\nstring.\n\n```reason\nlet str = Printf.sprintf(\"%6s\", \"dope\");\n/* str => \"  dope\" */\n```\n\nThe _format_ is the first argument. At compile-time it is interpreted as a\n`format6` type value.\n\nSo, what if you want a dynamically created _format_ value? Simply\nconcatenating some strings together won't do it because then the type will\nbe `string` and that's not going to compile.\n\nThe [`Scanf.format_from_string`](https://reasonml.github.io/api/Scanf.html)\nfunction can help.\n\n```reason\nlet some_num = 6;\nlet format_str = \"%\" ++ string_of_int(some_num) ++ \"s\";\nlet format = Scanf.format_from_string(format_str, \"%s\");\n\nlet str = Printf.sprintf(format, \"dope\");\n/* str => \"  dope\" */\n```\n\nWe can convert our string that has the appearance of a format into an actual\n`format6` type. To do this, we have to tell `format_from_string` what types\neach of the formats is going to have -- hence the second argument `%s`.\n\n[source](https://twitter.com/rickyvetter/status/1013476235253436417)\n"
  },
  {
    "path": "reason/exhaustive-pattern-matching-of-list-variants.md",
    "content": "# Exhaustive Pattern Matching Of List Variants\n\nReasonML's `switch` expression allows for powerful pattern matching. When\nusing `switch` to pattern match against a list, the compiler will be sure to\nwarn you if you haven't accounted for all variants of a list.\n\n```reason\nlet getFirst = (numList: list(int)): int => {\n  switch(numList) {\n  | [first, ...rest] => first\n  };\n};\n```\n\n> this pattern-matching is not exhaustive. Here is an example of a value\n> that is not matched: []\n\nThe compiler knows that a list can either be 1) empty (`[]`) or 2) contain\nat least one value and another list (`[a, ...rest]`). To ensure all variants\nare accounted for, we can include the `[]` case in our switch.\n\n```reason\nlet getFirst = (numList: list(int)): int => {\n  switch(numList) {\n  | [] => -1\n  | [first, ...rest] => first\n  };\n};\n```\n\n[source\ncode](https://reasonml.github.io/en/try.html?reason=DYUwLgBAdgrgtgIxAJwM4C4LAJarACmyjAEoIBeCAbQDYAaABjvvoEYBdAbgChvRIA5uABi2NJEr5YcADK4wmHHkLESJTEQkA+CAG9uECKgDu2MAGMAFlPhy8ZfYYA+1AGZi8dCADpfyEHjsFDru4gYQAL48UbwAUqjewAD2AvhCYKLiNogoqGqcQA)\n"
  },
  {
    "path": "reason/format-the-current-file-within-vim.md",
    "content": "# Format The Current File Within Vim\n\nI'm editing a `.re` file within Vim. I haven't yet wired up `refmt` to\nsomething like [ALE](https://github.com/w0rp/ale) for automatic formatting\non save. By the time I'm done with my changes, indentation is a mess.\n\nI can still take advantage of `refmt` to clean up my file.\n\n```\n:!refmt --in-place %\n```\n\nRunning that command in Vim will cause the current file to be formatted.\n\nHow does it work?\n\nIt shells-out to `refmt` which does all the heavy lifting. The `--in-place`\nflag means that the target file will be re-written by the formatted result.\nThe `%` is a handy Vim shorthand for the path and name of the current file.\n"
  },
  {
    "path": "reason/generate-a-native-reasonml-project-with-pesy.md",
    "content": "# Generate A Native ReasonML Project With Pesy\n\n[Pesy](https://github.com/jordwalke/pesy) is a CLI utility available from\nNPM that you can use to generate a ReasonML project that is ready for native\ncompilation. It uses [`esy`](https://github.com/esy/esy) for the management\nof `opam` packages. It uses [Dune](https://github.com/ocaml/dune) for\nbuilding your library code with the ReasonML and OCaml dependencies.\n\nAssuming you already have `pesy` installed globally, create a directory for\nyour project and then run:\n\n```bash\n$ pesy\n```\n\nA project will be generated that is out-of-the-box ready to compile native\nexecutables.\n"
  },
  {
    "path": "reason/generate-starter-reason-projects.md",
    "content": "# Generate Starter Reason Projects\n\nWith the latest `bs-platform` installed, you should have access to the `bsb`\ncommand which contains a number of options -- including `-themes`.\n\n```bash\n$ bsb -themes\nAvailable themes:\nbasic\nbasic-reason\ngenerator\nminimal\nnode\nreact\n```\n\nThis is a list of themes (read: templates) that can be used to generate a\nstarter project.\n\nFor example, if you'd like a basic project structure geared toward writing\nReason, run the following:\n\n```bash\n$ bsb -init my-project -theme basic-reason\n```\n\nOr if you'd like to get started with\n[`reason-react`](https://reasonml.github.io/reason-react/), give this a try:\n\n```bash\n$ bsb -init my-reason-react-project -theme react\n```\n\n[source](https://bucklescript.github.io/docs/en/new-project.html)\n"
  },
  {
    "path": "reason/helping-the-compiler-help-us-with-variants.md",
    "content": "# Helping The Compiler Help Us With Variants\n\n[ReasonML](https://reasonml.github.io/) gives us something called a variant\nwhich is similar to what other language call enums and union types. By\ndefining a variant, we give the compiler some information about exactly what\nvalues a variable can take on -- its allowed variants.\n\nHere we define the kinds of roles that users in our system can have as well\nas a `user` type for representing individual users:\n\n```reason\ntype userType =\n  | Student\n  | Teacher\n  | Admin;\n\ntype user = { role: userType, id: int };\n```\n\nAnd here is how we might use it in some authorization code:\n\n```reason\nlet canCreateClasses(u: user) {\n  switch(u.role) {\n  | Student => false\n  | Teacher => true\n  };\n};\n```\n\nWe've neglected to include `Admin` in our switch statement. The compiler\nwill inform us of this with a warning.\n\n> this pattern-matching is not exhaustive. Here is an example of a value\n> that is not matched: Admin\n\n[source\ncode](https://reasonml.github.io/en/try.html?reason=C4TwDgpgBArgzhATgFXNAvAKClAPlAZWBgBMIA7YbPKZCAQwGMALJa-AQRIFsBLcgNyZQkWAkRR0UAN5REAewA2EAFxikqSABoovEmv7AoAXyGZlRxvXIBhRA2AQbi+nARwAFDDXwkAShlqOAB3XmAWLwA6BWUA6XZCYjJKSQA+KAAzekUEBLomVgl0dOBEGAhqU0wqgCk4SMV5AHMPK1t7ekdnV3cPWRjVRNIKYB09NQBGACYAZhM-PwEgA)\n"
  },
  {
    "path": "reason/inline-component-styles-with-reason-react.md",
    "content": "# Inline Component Styles With Reason React\n\nIf you've written much React.js, the following may look familiar:\n\n```javascript\n<span style={{\n  width: \"10px\",\n  height: \"10px\",\n  backgroundColor: \"rgb(200, 64, 128)\"\n}} />\n```\n\nThis is how we do inline styles with JSX in JavaScript.\n\nWhen it comes to doing inline styles with JSX in our ReasonML code, the best\napproach for now is to use a `make` function for styles provided by the\nReact DOM bindings.\n\n```reason\n<span style=(\n  ReactDOMRe.Style.make(\n    ~width=\"10px\",\n    ~height=\"10px\",\n    ~backgroundColor=\"rgb(200, 64, 128)\",\n    ())\n)/>\n```\n\n[source](https://reasonml.github.io/reason-react/docs/en/style.html)\n"
  },
  {
    "path": "reason/is-this-a-directory-or-a-file.md",
    "content": "# Is This A Directory Or A File?\n\nWhen compiling [ReasonML](https://reasonml.github.io/) natively, we have access to a variety of\nadditional modules including the `Unix` module. We can interact with\ndirectories and files using functions on `Unix`.\n\n```reason\nlet current_dir = Unix.opendir(Unix.getcwd());\nlet first_file = Unix.readdir(current_dir);\n/* is first_file a directory or a file? */\nUnix.closedir(current_dir);\n```\n\nHere we open the current working directory, grab the first thing out of that\ndirectory -- maybe it's a file, maybe it's a directory, maybe it is\nsomething else. Lastly, we close the directory.\n\n```reason\nlet current_dir = Unix.opendir(Unix.getcwd());\nlet first_file = Unix.readdir(current_dir);\n\nswitch(Unix.stat(first_file)) {\n| Unix.stats({ st_kind: Unix.S_REG }) => print_endline(\"Regular File\")\n| Unix.stats({ st_kind: Unix.S_DIR }) => print_endline(\"Directory\")\n| Unix.stats({ st_kind: Unix.S_LINK }) => print_endline(\"Link\")\n| Unix.stats({ st_kind: Unix.S_SOCK }) => print_endline(\"Socket\")\n| _ => print_endline(\"Something else\")\n};\n\nUnix.closedir(current_dir);\n```\n\nThere are a variety of kinds of files to switch on. Here, we are switching\non _Regular Files_, _Directories_, _Links_, and _Sockets_. Everything else\nfalls through.\n\nSee the [`Unix` module docs](https://reasonml.github.io/api/Unix.html) for\nmore details.\n"
  },
  {
    "path": "reason/making-things-mutable.md",
    "content": "# Making Things Mutable\n\nIn [ReasonML](https://reasonml.github.io/en/), things that we create with\n`let` are immutable -- which means that we can't change them.\n\n```reason\nlet num = 5;\n```\n\nOnce `num` is _bound_ to `5` it is stuck with that value for the duration\nof it's scope.\n\nReasonML doesn't completely restrict us to immutability though. The\n`ref` construct allows us to bind a variable to a sort of box that holds a\nvalue. We can then look in the box and change what is in the box.\n\n```reason\nlet num = ref(5); /* put 5 in the box */\n\nJs.log(num^); /* use `^` to look in the box */\n\nnum := 3; /* remove 5, put 3 in the box */\n```\n\nWe use `ref` to bind our variable to a box with some initial value. The `:=`\nassignment operator allows us to change what's in the box. Anytime we want\nto refer to what's in the box, we postfix our variable with `^`.\n\nAlso of note: while `list` instances are not mutable, `array` instances are.\n\n[source](https://reasonml.github.io/docs/en/mutation)\n"
  },
  {
    "path": "reason/modifying-a-string-with-blit-string.md",
    "content": "# Modifying A String With blit_string\n\n[ReasonML's `Bytes` module](https://reasonml.github.io/api/Bytes.html) has a\nfunction called\n[`blit_string`](https://reasonml.github.io/api/Bytes.html#VALblit_string).\nThis function allows you to copy portions of a string into a destination\nbyte sequence. It is a fairly low-level operation, so you have to provide a\nsource string and provide an offset of that source string to start copying\nfrom. You then have to provide a properly sized byte sequence as well as the\ndestination's starting offset and length of bytes to be copied.\n\nHere is an example of how we can use `blit_string` to create a copy of the\nstring with the first character removed.\n\n```reason\nlet remove_first_char = (str: string): string => {\n  let copy_len = String.length(str) - 1;\n  let dst = Bytes.create(copy_len);\n  Bytes.blit_string(str, 1, dst, 0, copy_len);\n  Bytes.to_string(dst);\n};\n```\n\nNotice that once the byte sequence has been copied over, we then need to\nconvert it back into a string.\n"
  },
  {
    "path": "reason/multi-argument-functions-as-syntactic-sugar.md",
    "content": "# Multi-Argument Functions As Syntactic Sugar\n\nWhen writing a multi-argument function, like the following `adder` function:\n\n```reason\nlet adder = (x, y) => x + y;\n\nadder(2, 3); /* => 5 */\n```\n\nWe are utilizing a syntactic sugar of the function syntax. The same function\ncan be written as such:\n\n```reason\nlet adder = (x) => (y) => x + y;\n\nadder(2, 3); /* => 5 */\n```\n\nAs you can see, we can apply the function in the same way.\n\nThis is useful because it means we can partially apply (or _curry_) our\nfunctions to create other functions.\n\n```reason\nlet adder = (x, y) => x + y;\nlet twoAdder = adder(2);\n\ntwoAdder(5); /* => 7 */\n```\n\n[source\ncode](https://reasonml.github.io/en/try.html?reason=DYUwLgBAhgJjICcIF4IAoAeBKFA+dAnjsvhhANQQEDcAULQFIDOAdMAPYDmas8CaAFgA0EAKxYsdWqEhgA7uwCCcRCmgr+AJkn1mbLmnlKNacZKA)\n"
  },
  {
    "path": "reason/pattern-match-on-exceptions.md",
    "content": "# Pattern Match On Exceptions\n\n[ReasonML](https://reasonml.github.io/) supports [powerful pattern\nmatching](https://reasonml.github.io/docs/en/pattern-matching.html) through\nthe `switch` statement.  This even includes pattern matching against\nexceptions that may arise as a way of catching and handling those\nexceptions.\n\n```reason\nlet values: list(int) = [1,3,5,7,9];\n\nlet getValue = (list, index) => {\n  switch (List.nth(values, index)) {\n  | value => value\n  | exception Failure(\"nth\") => 0\n  | exception Invalid_argument(\"List.nth\") => 0\n  };\n};\n\ngetValue(values, 0); /* 1 */\ngetValue(values, 1); /* 3 */\ngetValue(values, 5); /* 0 */\ngetValue(values, -1); /* 0 */\n```\n\nThe [`List.nth` docs](https://reasonml.github.io/api/List.html) detail what\nhappens in the two kinds of out of bounds scenarios that would raise an\nerror -- `Failure` and `Invalid_argument`. You can pattern match against\nthose by declaring the respective cases as exception instances and then\nreturning the desired values in response.\n\n[source\ncode](https://reasonml.github.io/en/try.html?reason=DYUwLgBAbghsCuIDOAuCwCWSwAoMDswBKCAXggG0BGAGgGYaBWGgdhoE4BdAbgChfQkAObgAanERkIOTNhoQCAExAAPEqQB8EAN68IEJAHcMYAMYALaQBksYAHSFzOWAmTylqoiV36APtAkQMi0XRD0If1VTEAAHMAwAe3wIADEYDAQAJxAcACJHXPUtAAZwyJVouMTkgEl8FwxFAH0YTKF4AFsQQjybbAcwc0LgiFL9AF8+Sf4AKSQ7YAShHBEwcVdnQKR5Yq8+OYWllbFAzddtiCo93gPF5dX1xDPEC8Zr26OH09C3CABaK5EbhAA)\n"
  },
  {
    "path": "reason/quickly-bootstrap-a-react-app-using-reason.md",
    "content": "# Quickly Bootstrap A React App Using Reason\n\nThe ReasonML language and ecosystem is great for developing React apps. As\nyou might expect from the React community, there is a set of `reason-scripts`\nfor a ReasonML/React project which works similarly to the standard\n[`create-react-app`](https://github.com/facebook/create-react-app) scripts.\n\nFirst, you need to install the [BuckleScript\nplatform](https://github.com/BuckleScript/bucklescript) and this must be\ndone using `npm`.\n\n```bash\n$ npm install -g bs-platform\n```\n\nFrom there, it is a matter of using the [`yarn\ncreate`](https://yarnpkg.com/lang/en/docs/cli/create/) command to generate a\nReact app that uses the aforementioned\n[`reason-scripts`](https://yarnpkg.com/lang/en/docs/cli/create/).\n\n```\n$ yarn create react-app my-reason-react-app --scripts-version reason-scripts\n```\n\nNext steps from here are documented in the `README.md` and should be\nfamiliar to anyone who has used `create-react-app` in the past.\n"
  },
  {
    "path": "reason/seeding-and-generating-random-integers.md",
    "content": "# Seeding And Generating Random Integers\n\nIt is easy enough to generate a series of random numbers using the `Random`\nmodule's `int` function.\n\n```reason\nRandom.int(10);\n```\n\nThis will generate a random integer between 0 and 9.\n\nYou may notice that the randomness is the same each time you run your\nprogram. That is because you have fixed seed. To make sure you have a\ndifferent seed each time your program runs, you can initialize the random\nnumber generator with something different at each run, such as the current\ntime.\n\n```reason\nRandom.init(int_of_float(Js.Date.now()));\n```\n\nSee a [live example\nhere](https://reasonml.github.io/en/try.html?reason=EoQwdgJg9gtgdASzAgLgCiSg+lAZl3AGyhHQCkBnOAEVIFM4woB3NASg4G4AobyuYgHM0oSLERh0ARgAMXPlSEjw0eJjSz5-JaNUTpctj21Rhu8es1GFA08rFrJGw5yA).\n"
  },
  {
    "path": "reason/stream-a-file-line-by-line.md",
    "content": "# Stream A File Line By Line\n\nWe can use the `Stream` module in [ReasonML](https://reasonml.github.io/en)\nto read a file getting each line on demand. Doing this requires two key\ninsights. First, we can open a file as an _input channel_. Second, we can\nturn an input channel into a _stream_ using `Stream.from`.\n\n```reason\nlet file_in_channel = Pervasives.open_in('file.txt');\n\nlet file_stream =\n  Stream.from(_i => {\n    switch(Pervasives.input_line(file_in_channel)) {\n    | line => Some(line)\n    | exception(End_of_file) => None\n    };\n  });\n\nfile_stream |> Stream.iter(line => do_something(line));\n```\n\nThe `Pervasives` module (which is open by default and is only prefixed above\nso as to be explicit) allow us to open the named file as an input channel\nwith `open_in`. It also allows us to read lines off that file with\n`input_line`. We use `Stream.from` to create a custom stream that consumes\nthe input channel line by line using `input_line`. We either get _some_ line\nor we hit the end of the file. Lastly, we can do whatever we want with the\nstream, such as iterate over it.\n\nSee the docs for\n[`Pervasives`](https://reasonml.github.io/api/Pervasives.html) and\n[`Stream`](https://reasonml.github.io/api/Stream.html) for more details.\n"
  },
  {
    "path": "reason/string-interpolation-with-integers-and-sprintf.md",
    "content": "# String Interpolation With Integers And Sprintf\n\nReasonML's [`Printf`](https://reasonml.github.io/api/Printf.html) module\ncomes with a number of functions for formatting values of various types. The\n`sprintf` function allows for string interpolation.\n\n```reason\nlet red = 64;\nlet green = 256;\nlet blue = 128;\nlet alpha = 1;\n\nlet color =\n  Printf.sprintf(\"rbga(%i, %i, %i, %i)\", red, green, blue, alpha);\n\nJs.log(color);\n```\n\nIt functions the same as `fprintf` but instead of outputting the result to\nsome channel, it returns a string. It enforces type checking as well -- the\n`%i` is specifically for integers, so using that with a type other than an\ninteger will result in a compilation error.\n\nSee the [`Printf`](https://reasonml.github.io/api/Printf.html) docs for more\ndetails.\n\n[source code](https://reasonml.github.io/en/try.html?reason=DYUwLgBATiAmEF4IDYAsBuAUKSBzGIAdohAEwCsyWOEARsAK4gkCMpAHNeBAIbAAOACx6ss2bgGMA9sClREmCBAAKUAJaEwAMwB0AZ37rNWgBQAiKLVw8TAUjUAaCPacvnagJRmnMWE-wgRE70TE58QjweYgBSejqyuCbSslBRQA)\n"
  },
  {
    "path": "reason/string-interpolation-with-quoted-strings.md",
    "content": "# String Interpolation With Quoted Strings\n\nStapling strings together with the `++` operator can be tedious and clunky.\nIf you have string variables that you'd like to interpolate, you can piece\nthem together much more easily using [quoted\nstrings](https://reasonml.github.io/docs/en/string-and-char.html#quoted-string).\n\nWe can get close to a solution with the standard quoted string syntax.\n\n```reason\nlet greeting = (greetee) => {\n  {|Hello, $(greetee)!|}\n};\n\nJs.log(greeting(\"World\")); // => \"Hello, $(greetee)!\"\n```\n\nThis isn't quite right though. We have to take advantage of a preprocessing\nhook provided by\n[Bucklescript](https://bucklescript.github.io/docs/en/common-data-types.html#interpolation).\nThe `j` hook supports unicode and allows variable interpolation.\n\n```reason\nlet greeting = (greetee) => {\n  {j|Hello, $(greetee)!|j}\n};\n\nJs.log(greeting(\"World\")); // => \"Hello, World!\"\n```\n\nTo use this pre-processor we have to include `j` in the quoted string like\nso `{j|...|j}`.\n\nSee a [live example\nhere](https://reasonml.github.io/en/try.html?reason=DYUwLgBA5gTi4EsB2UIF4IApbzPAlOgHwQDeAUBGQFYA+AEiMMAPYA0EAJNnOAQIS1qAX3LCA3OXIApAM4A6VlB65kygEQB1FjGAATdfnzigA).\n"
  },
  {
    "path": "reason/trying-out-reasonml-in-codesandbox.md",
    "content": "# Trying Out ReasonML In CodeSandbox\n\n[CodeSandbox](https://codesandbox.io/) recently added support for a bunch of\nnew technologies.  Among these is [ReasonML](https://reasonml.github.io/).\n\nTo give ReasonML a try, visit this [template\nlink](https://codesandbox.io/s/reason).\n\nThis is a [`reason-react`](https://reasonml.github.io/reason-react/)\ntemplate which allows you to write a React web app using ReasonML.\n"
  },
  {
    "path": "reason/two-ways-to-find-an-item-in-a-list.md",
    "content": "# Two Ways To Find An Item In A List\n\nThe `List` module has the typical `find` function that you'd expect any\nenumerable type to include. It has a very similar `find_opt` function as\nwell. The difference is in the return types.\n\nWhen using `List.find` you'll have to deal with the possibility of a\n`Not_found` exception.\n\n```reasonml\nswitch (List.find(item => item.id == id, my_list)) {\n| exception Not_found => print_endline(\"Not found!\")\n| item => print_endline(\"Found it: \" ++ item.name)\n}\n```\n\nThe `List.find_opt` function has a more familiar interface that doesn't\nrequire you to know the details of what exceptions could arise. All you want\nto know is if it was found or _not_. This is achieved by having an\n`option('a)` return type.\n\n```reasonml\nswitch (List.find_opt(item => item.id == id, my_list)) {\n| None => print_endline(\"Not found!\")\n| Some(item) => print_endline(\"Found it: \" ++ item.name)\n}\n```\n\nSee the [`List` module](https://reasonml.github.io/api/List.html) for more\ndetails.\n"
  },
  {
    "path": "reason/using-optional-labeled-function-arguments.md",
    "content": "# Using Optional Labeled Function Arguments\n\nIf you are constructing a function that takes some arguments, but one of\nthose arguments has a reasonable default value, then you can use an optional\nlabeled argument. Labeled arguments are those arguments prefixed with a `~`.\nIf you give the argument a default value, then it becomes optional.\n\n```reason\nlet thing = (~a=1, b: int, c: int) => {\n  a + b + c;\n};\n```\n\nIn this case `~a` is a labeled argument. It is also optional and will\ndefault to `1` if not specified. The other two arguments, `b` and `c`, are\npositional arguments and thus required in order for the function to\nevaluate.\n\nHere are two ways of using this function either by specifying `~a` or\nexcluding it so that it defaults to `1`.\n\n```reason\nthing(~a=2, 1, 1)\n|> string_of_int\n|> print_endline /* 4 */\n\nthing(1, 1)\n|> string_of_int\n|> print_endline /* 3 */\n```\n\nSee more details [here](https://reasonml.github.io/docs/en/function).\n"
  },
  {
    "path": "reason/wrapping-a-component-for-use-in-javascript.md",
    "content": "# Wrapping A Component For Use In JavaScript\n\nConsider the following\n[ReasonReact](https://reasonml.github.io/reason-react/en) component for\ndisplaying a greeting.\n\n```reason\nlet component = ReasonReact.statelessComponent(\"Hello\");\n\nlet make = (~name, _children) => {\n  ...component,\n  render: _self =>\n    <p> {ReasonReact.string(\"Hello, \")} {ReasonReact.string(name)} </p>,\n};\n```\n\nIf we will just be using this component in a ReasonML context, then that is\nall we need.\n\nIf we want this component available for use in a JavaScript file, we have a\nlittle more work to do. We need to define the shape of the component's props\nusing a bucklescript directive and then wrap the component so that it gets\nappropriate exported for a JavaScript context.\n\nHere is what that looks like.\n\n```reason\n[@bs.deriving abstract]\ntype jsProps = {name: string};\n\nlet default =\n  ReasonReact.wrapReasonForJs(~component, jsProps =>\n    make(~name=jsProps->nameGet, [||])\n  );\n```\n\nOur only prop is `name` which is a `string`. The `wrapReasonForJs` function\nand accompanying binding to `default` mean that we can import the compiled\nJS-equivalent like so:\n\n```javascript\nimport Hello from 'src/components/Hello.bs.js';\n```\n\nSee the [docs](https://reasonml.github.io/reason-react/docs/en/interop) for\nmore details on Reason/JS interop.\n"
  },
  {
    "path": "remix/get-query-params-from-the-request-url.md",
    "content": "# Get Query Params From The Request URL\n\nYou can enable a Remix route to respond to query params in the URL in a\n`loader` function. To do this, you first need to parse them out of the request\nURL.\n\nThe arguments to the `loader` function will include the `request` object which\nitself includes the `url`. From there, you can use the browser's [`URL`\nconstructor](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) to parse\nand extract query params (i.e. search params).\n\n```typescript\nimport type { LoaderFunction } from \"@remix-run/node\";\n\nexport async function loader({ request }): LoaderFunction {\n  const url = new URL(request.url);\n  const query = url.searchParams.get(\"q\");\n\n  results = await getResultsForQuery({ query });\n\n  return { result };\n}\n```\n\nThe constructed `URL` object responds to\n[`searchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URL/searchParams)\nwhich you can call `get()` on to get a specific query param value. This uses\nthe [`URLSearchParams`\nAPI](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams).\n\nIn the above case, we are able to grab the value of the `q` query param.\n\n[source](https://remix.run/docs/en/v1/guides/data-loading#url-search-params)\n"
  },
  {
    "path": "remix/markdown-and-mdx-files-are-rendered-to-routes.md",
    "content": "# Markdown And MDX Files Are Rendered To Routes\n\nIf you put a markdown or [mdx](https://mdxjs.com/) file somewhere within the\n`app/routes` directory of a [Remix](https://remix.run/) app, it knows how to\nrender it to HTML. There is no additional setup necessary, it works out of the\nbox.\n\nFor instance, trying creating an `about.md` file under `app/routes`.\n\n```markdown\n# About\n\nMy name is **Josh Branchaud** and I am an _independent_ software developer.\n\nReach out to me at <a href=\"mailto:josh@email.com\">josh@email.com</a>.\n```\n\nNow, run the app's dev server and visit `localhost:3000/about`. You'll see a\nfairly unstyled page with this text rendered to it. Try inspecting the source\nand you'll see, for instance, that _About_ is wrapped in an `<h1>` tag.\n\nIf you want this markdown styled (e.g. a larger font size for that `<h1>`),\nyou'll either have to write some custom styles or pull in something like\n[`@tailwindcss/typography`](https://tailwindcss.com/docs/typography-plugin).\n"
  },
  {
    "path": "remix/relative-and-absolute-paths-in-links.md",
    "content": "# Relative And Absolute Paths In Links\n\nRemix has its own routing system built in. The directories and files that you\nplace under `app/routes` will all make up the routes of the app. Routes are\npages in the app. And pages are meant to be linked to.\n\nRemix's `Link` component can handle both relative and absolute paths with the\n`to` prop.\n\nHere is a link with relative path.\n\n```jsx\n// app/routes/posts/index.tsx\nimport { Link } from \"@remix-run/react\";\n\nexport default function Posts() {\n  return (\n    <Link to=\"admin\">\n      Admin\n    </Link>\n  )\n}\n```\n\nBecause the `Link` is rendered within the `posts/` directory, the link will\npoint to `localhost:3000/posts/admin`.\n\nAnd here is an absolute path.\n\n```jsx\n// app/routes/posts/index.tsx\nimport { Link } from \"@remix-run/react\";\n\nexport default function Posts() {\n  return (\n    <Link to=\"/admin\">\n      Admin\n    </Link>\n  )\n}\n```\n\nNotice that the only change was putting a leading slash in front of `admin` in\nthe `to` prop. Just like Unix path names, that indicates that the path is an\nabsolute one, anchored to the root. It doesn't matter that it is in the\n`/posts` directory. It will point to `localhost:3000/admin`.\n\n[source](https://remix.run/docs/en/v1/tutorials/blog#nested-routing)\n"
  },
  {
    "path": "remix/run-the-development-server-from-another-port.md",
    "content": "# Run The Development Server From Another Port\n\nBy default the [remix](https://remix.run/) development server runs on port\n`3000`. There are two ways that you can specify a different port using an\nenvironment variable.\n\nFirst, you can specify the port from the command line when starting up the\nserver.\n\n```bash\n$ PORT=4444 npm run dev\n```\n\nSecond, you can include the `PORT` environment variable in your `.env` file so\nthat you don't have to remember to include it from the CLI each time. Add the\nfollowing line to your `.env` file for that.\n\n```\nPORT=4444\n```\n\nRun `npm run dev` and you'll see the server start up at `localhost:4444`.\n"
  },
  {
    "path": "remix/set-the-title-of-a-page.md",
    "content": "# Set The Title Of A Page\n\nOne of the reserved functions in a Remix route is `meta`. Defining this\nfunction allows you to specify meta tags that appear in the `<head>` of a page,\nincluding the `<title>` tag.\n\n```\nimport type {\n  MetaFunction,\n  LoaderFunction\n} from \"@remix-run/node\";\n\nexport const loader: LoaderFunction = async ({ params }) => {\n  // load and return the post\n};\n\nexport const meta: MetaFunction = ({ data }) => {\n  const { title } = data?.posts || {}\n\n  return {\n    title: title || \"An Article\",\n  };\n};\n\nexport default function Post() {\n  /* render the post */\n}\n```\n\nThe `meta` function returns an object that contains key-value pairs of meta\ntags. We can include something like `title: 'Sign Up'` for a static title. Or\nwe can access things like `location`, `params`, and even `data` from the loader\nto produce a content-specific title.\n\nIf open one of these `/posts/$slug` pages in the browser and crack open the\n_View Source_, we'll be able to see the `<title>Name Of My Post</title>` tag\nwithin the `<head>` tag.\n"
  },
  {
    "path": "rspec/avoid-accidentally-disabling-pry.md",
    "content": "# Avoid Accidentally Disabling Pry\n\nI was recently working on a test that needed to mock an environment variable in\norder to observe the behavior under test. I initially ended up with the\nfollowing lines in a `before` block.\n\n```ruby\nbefore do\n  allow(ENV).to receive(:[]).and_return(\"\")\n  allow(ENV).to receive(:[]).with(\"API_SERVER_URL\").and_return(\"localhost\")\nend\n```\n\nThe idea was to create a \"clean\" `ENV` for the test and then layer in any\nrelevant environment variables from there.\n\nThis is a misguided approach for a couple reasons. One particular and\nhard-to-debug issue is that this mocking of `ENV` accidentally disabled Pry\n(i.e. `binding.pry`). So once I was having issues with my test, I couldn't even\ninspect the code at runtime. It would skip right past any `binding.pry`\nstatement I added.\n\nWhat happened is that [Pry (specifically `pry-rails`) looks for\n`ENV['DISABLE_PRY_RAILS']`](https://github.com/pry/pry-rails/blob/d8d0c6d87a5b8a3e570e0c80910fb80068f3553c/lib/pry-rails.rb#L6)\nand if that value is _truthy_ then it won't require the various `pry-rails`\nmodules.\n\nThe first `allow` has `ENV` responding with `\"\"` which is truthy and will\nresult in Pry being disabled.\n\nA more appropriate default would be `nil`. Also consider that there are many\nways to access `ENV`, such as `#fetch`.\n"
  },
  {
    "path": "rspec/check-specific-arguments-to-received-method.md",
    "content": "# Check Specific Arguments To Received Method\n\nLet's say we have a method receiving a big hash of arguments. A hash like this:\n\n```ruby\n{\n  name: 'Taco Tray',\n  product_id: 'taco123',\n  price: 4500,\n  description: 'A big tray of tacos',\n  discounts: {\n    coupon: 'DISCOUNT_TACOS'\n  }\n}\n```\n\nIn an RSpec test we want to check one of those hash values in a certain\nscenario. It can be tedious to type out and check the entire hash. Instead, we\nwant the test to surgically check just one part of the hash.\n\nWe can do this with RSpec's dynamic matcher syntax. The [`hash_including`\nargument\nmatcher](https://rspec.info/documentation/3.4/rspec-mocks/RSpec/Mocks/ArgumentMatchers.html#hash_including-instance_method)\ncan be nested within the `#with` part of `expect().to receive().with()`.\n\n```ruby\nexpect(TacoTruck)\n  .to receive(:take_order)\n  .with(\n    hash_including(\n      discounts: { coupon: 'DISCOUNT_TACOS'}\n    )\n  )\n```\n\nThis will assert about the `discounts` portion of the hash that `#take_order`\ngets called with. The rest of the hash will be ignored.\n\nWithout `hash_including`, the `with` call would result in a failure when trying\nto match against the entire hash.\n"
  },
  {
    "path": "rspec/configure-tests-to-run-in-random-order.md",
    "content": "# Configure Tests To Run In Random Order\n\nBy default, an RSpec test suite is going to run in a predictable, sequential\norder, every time.\n\nWhen testing the parts of a complex Rails app that have all kinds of test data\nthat needs to be set up, I prefer to have my tests always run in a random\n(repeatable with a seed) order. This way I'm more likely to catch sooner,\nrather than later, bugs that are hidden by passing tests due to test data setup\nthat happens to work in a specific order.\n\nRSpec can be configured to run tests in a random, seedable order in the\n`spec_helper.rb` file.\n\n```ruby\nRSpec.configure do |config|\n  config.order = :random\nend\n```\n\nWhenever you run your test suite, the first thing you'll see is a message like\nthis:\n\n```\nRandomized with seed 7011\n```\n\nThat seed number can be used to re-run the suite in a repeatable order when you\nneed to do so to track down an order-dependent failing test.\n\n```bash\n$ be rspec --seed 7011\n```\n"
  },
  {
    "path": "rspec/find-minimal-set-of-tests-causing-a-flicker.md",
    "content": "# Find Minimal Set Of Tests Causing Flicker\n\nYou have a pretty reliable test suite. However, every once in a while CI will\nfail. It fails for some test that doesn't seem to be related to the PR. And if\nyou re-run CI, it may not fail a subsequent time.\n\nYour test suite has a flicker.\n\nBecause this flickering test fails so sporadically, it can be hard to track\ndown when it fails and why.\n\n[RSpec comes with a `--bisect`\nflag](https://relishapp.com/rspec/rspec-core/docs/command-line/bisect) that can\nhelp you track down the _minimal_ sequence of tests that will produce a\nfailure. So, the next time CI fails unexpectedly on this flickering test, grab\nthe seed for that test run and use it locally to perform a bisect.\n\n```bash\n$ rspec --seed 1234 --bisect\n```\n\nThis while take a while to run, but when it is done, it should output an\n`rspec` command with a series of specific tests. Copy, paste, and run this\ncommand as you work on tracking down the issue. One strong possibility is that\none test is altering some global state in a way that the other test doesn't\nexpect. And it is only in this order that you can see that manifest as a\nfailure.\n"
  },
  {
    "path": "rspec/format-test-results-as-a-json-file.md",
    "content": "# Format Test Results As A JSON File\n\nThe most common output format for RSpec test results is _progress_ which shows\nthe dot (`.`) or `F` for each test pass and fail. RSpec supports other formats,\nincluding JSON.\n\nYou'd typically want to use the JSON format when you want to programmatically\nwork with the results. And the results would be most accessible if they ended\nup in a file.\n\nSo, when formatting the results to JSON, we typically also want to specify an\noutput file. We'll need to use two flags — `--format` and `--out`.\n\n```bash\n$ rspec --format json --out test_run_1.json\n```\n\nWhen this test run completes, we will have the results in JSON format in the\nnewly created `test_run_1.json` file in the current directory.\n\nSee `rspec --help` for more details.\n"
  },
  {
    "path": "rspec/run-tests-with-documentation-formatting.md",
    "content": "# Run Tests With Documentation Formatting\n\nTypically when you invoke `rspec` on a file or an entire suite of tests, you'll\nsee a bunch of dots (`.`) and maybe a couple `F`s.\n\n```\n$ rspec spec/models/user_spec.rb\n\n.F...........\n```\n\nThat style of output is called _progress_ formatting.\n\nThat's not the only option for formatting output from RSpec. Another one is\n_documentation_ formatting.\n\nUse the `--format` flag to specify a format like `documentation`. Or `-f d`\nworks as a shorthand.\n\n```\n$ rspec --format documentation spec/models/user_spec.rb\n\nUser\n  #valid?\n    without required fields\n      returns false\n    with invalid email\n      returns false (FAILED - 1)\n    with invalid password\n      too short\n        returns false\n      no upper case letter\n        returns false\n```\n\nThe resulting test output is a readable format that leverages the `describe`,\n`context`, and `it` descriptions that we craft for each test.\n\n[source](https://relishapp.com/rspec/rspec-core/v/2-6/docs/command-line/format-option)\n"
  },
  {
    "path": "rspec/use-specific-cache-store-in-a-single-test.md",
    "content": "# Use Specific Cache Store In A Single Test\n\nIt is generally recommended to use `:null_store` as the default cache store\nacross your test suite. This is defined in `config/environments/test.rb`.\n\n```ruby\n  config.cache_store = :null_store\n```\n\nThis generally simplifies tests by avoiding confusing stateful scenarios.\n\nIf there is a test where you want to observe specific caching behavior, then\nyou'll need to temporarily swap that for another store.\n\nOne way to do that is by mocking the cache with `MemoryStore` in a before\nblock.\n\n```ruby\ndescribe '#caching_feature' do\n  # use MemoryStore cache for these tests\n  before do\n    allow(Rails)\n      .to receive(:cache)\n      .and_return(ActiveSupport::Cache::MemoryStore.new)\n  end\n\n  it 'does caching' do\n    thing = Thing.caching_feature(1)\n\n    expect(thing.value).to eq true\n\n    thing.update(value: false)\n\n    thing = Thing.caching_feature(1)\n\n    expect(thing.value).to eq true\n  end\nend\n```\n\n[One source](https://stackoverflow.com/a/31932795/535590) and [another](https://makandracards.com/makandra/46189-how-to-rails-cache-for-individual-rspec-tests)\n"
  },
  {
    "path": "ruby/a-basic-case-statement.md",
    "content": "# A Basic Case Statement\n\nThe syntax for case statements (or switch statements) is a little different for\neach language. I often confuse the Ruby and JavaScript syntax or wonder if I\nneed to be using a colon anywhere.\n\nHere is a demonstration of how to write a basic case statement in Ruby.\n\n```ruby\ncase ['taco', 'burrito', 'pizza', nil].sample\nwhen 'taco'\n  puts 'Taco, eh. Carne asada or al pastor?'\nwhen 'burrito'\n  puts 'Burrito, eh. Want it smothered?'\nwhen 'pizza'\n  puts 'Pizza, eh. Cheese or pepperoni?'\nelse\n  puts 'What do you want to eat?'\nend\n```\n\nThis next example demonstrates two things. First, you can make things terser\nwith the `then` syntax. Second, the case statement does an implicit return of\nwhatever the last value is from the evaluated case. So it can be used as part\nof a variable assignment.\n\n```ruby\nquestion =\n  case ['taco', 'burrito', 'pizza', nil].sample\n  when 'taco' then 'Taco, eh. Carne asada or al pastor?'\n  when 'burrito' then 'Burrito, eh. Want it smothered?'\n  when 'pizza' then 'Pizza, eh. Cheese or pepperoni?'\n  else 'What do you want to eat?'\n  end\n\nputs question\n```\n"
  },
  {
    "path": "ruby/a-shorthand-for-rerunning-failed-tests-with-rspec.md",
    "content": "# A Shorthand For Rerunning Failed Tests With RSpec\n\nAfter running a group of tests -- whether it is the entire suite or just the\ntests in a file -- you may find that you have a few failures. Often the goal is\nto focus in on these failures and get back to a green test suite. Rather than\nrerunning everything each time you make a change, you can instruct `rspec` to\njust rerun the tests that failed. This can be done with the `--only-failures`\nflag or `--on` flag for short.\n"
  },
  {
    "path": "ruby/add-comments-to-regex-with-free-spacing.md",
    "content": "# Add Comments To Regex With Free-Spacing\n\nRuby's regex syntax supports a [Free-Spacing\nmode](https://ruby-doc.org/core-3.0.1/Regexp.html#class-Regexp-label-Free-Spacing+Mode+and+Comments).\nWhen this mode is enabled, all the literal whitespace in the regular expression\nis ignored and comments can be included at the end of lines. This is enabled by\nappending the `x` option at the end of the regex.\n\nHere is a regex with Free-Spacing mode enabled (see the `x` at the end).\n\n```ruby\nsimple_email = /\\A.+@.+\\z/x\n```\n\nThough it's enabled, it is not really being used.\n\nHere is the same regular expression, but this time I've spaced it out and added\ncomment annotation to make the regex easier to understand.\n\n```ruby\nsimple_email = /\n  \\A  # beginning of the string\n  .+  # any opening characters\n  @   # the email's `@` symbol\n  .+  # the rest of the email\n  \\z  # the end of the string\n/x\n```\n\nTo be sure the extra space and comments aren't messing things up, here is some\ncode to test it out.\n\n```ruby\ntest_emails = [\n  'taco',\n  'email@example.com',\n  'more.complex+email@example.com',\n  '@'\n]\n\ntest_emails.each do |email|\n  if (simple_email =~ email) == 0\n    puts \"#{email} looks like an email\"\n  else\n    puts \"#{email} may not be an email\"\n  end\nend\n```\n\n[source](https://twitter.com/jasonrudolph/status/1413240725064519681?s=20)\n"
  },
  {
    "path": "ruby/add-linux-as-a-bundler-platform.md",
    "content": "# Add Linux As A Bundler Platform\n\nWith a locally developed Ruby project on Mac OSX, I have `darwin` specified as\nthe _platform_ in the `Gemfile.lock`.\n\n```ruby\nPLATFORMS\n  x86_64-darwin-19\n```\n\nWhen setting up CI for my project on a linux container, I'd get an error like\nthis:\n\n> Your bundle only supports platforms [\"x86_64-darwin-19\"] ...\n\nThis platform incompatability can be solved with by adding linux as a platform\nand re-resolving the lock file. This is done with [`bundle\nlock`](https://bundler.io/v2.0/man/bundle-lock.1.html) and the `--add-platform`\nflag.\n\n```bash\n$ bundle lock --add-platform x86_64-linux\n```\n\nIf all existing gems work with the new linux platform, the command will succeed\nand the updated `Gemfile.lock` will have the following `PLATFORMS` section.\n\n```ruby\nPLATFORMS\n  x86_64-darwin-19\n  x86_64-linux\n```\n\n[source](https://github.com/rubygems/rubygems/issues/4269#issuecomment-759591430)\n"
  },
  {
    "path": "ruby/add-progress-reporting-to-long-running-script.md",
    "content": "# Add Progress Reporting To Long-Running Script\n\nA script that is going to iterate over and process a ton of data can take a\nlong time to run. It can be hard to predict how long it will take to run. So,\nit is nice to have some indication of it's progress as it goes.\n\nHere is a small snippet that I add to the main loop so that I have some\nfeedback while the script runs:\n\n```ruby\nrunning_count = 0\n\ntons_of_data.each do |item|\n  running_count += 1\n  if running_count % 1000 == 0\n    print '@'\n  elsif running_count % 100 == 0\n    print '*'\n  else\n    print '.'\n  end\n\n  # process this `item` ...\nend\n```\n\nThen I get some output that looks like this over time as the script runs.\n\n```\n...............................................................................\n....................*..........................................................\n.........................................*.....................................\n..............................................................*................\n...............................................................................\n....*..........................................................................\n.........................*.....................................................\n..............................................*................................\n...................................................................*...........\n...............................................................................\n.........*.....................................................................\n..............................*................................................\n...................................................@..................\n```\n\nI can get a sense of how quickly it is processing each record and roughly count\nhow far along it is.\n"
  },
  {
    "path": "ruby/are-they-all-true.md",
    "content": "# Are They All True?\n\nThere is a method on `Enumerable` that allows you to check against\neverything in a collection. This is the `all?` method.\nFor instance, if you want to check if an array of values are all\ntruthy, you can call it without arguments:\n\n```ruby\n> [true, 1, ''].all?\n# true\n> [true, false, true].all?\n# false\n```\n\nYou can also pass it a block which is helpful if you want to check an\nattribute or method on a collection of objects, like so:\n\n```ruby\n> employees.all?(&:salaried?)\n# true\n> [1,2,3,4,5].all?(&:odd?)\n# false\n```\n"
  },
  {
    "path": "ruby/assert-about-an-objects-attributes-with-rspec.md",
    "content": "# Assert About An Object's Attributes With RSpec\n\nWhen testing an object that gets created as the result of some process, it can\nbe useful to assert about the attributes of that object. Not all of the\nattributes are relevant and some can be hard to reliably test. Rather than\nasserting about the result of calling `#attributes` or `#to_h` on an object, we\ncan focus in with the [`have_attributes`\nmatcher](https://relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/have-attributes-matcher)\nprovided by RSpec.\n\n```ruby\nRSpec.describe \"have_attributes\" do\n  it \"can assert on an ActiveRecord object\" do\n    book = Book.create(title: \"Fledling\", isbn: \"123\")\n\n    expect(book).to have_attributes(title: \"Fledgling\", isbn: \"123\")\n  end\n\n  it \"can assert on a Struct\" do\n    Name = Struct.new(:first, :last)\n    some_name = Name.new(\"Liz\", \"Lemon\")\n\n    expect(some_name).to have_attributes(first: \"Liz\")\n  end\nend\n```\n\nIn this example we were able to assert about all or just a subset of the\nattributes on both an `ActiveRecord` object and a `Struct`.\n\nSee [the docs](https://relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/have-attributes-matcher) for more details.\n"
  },
  {
    "path": "ruby/assoc-for-hashes.md",
    "content": "# Assoc For Hashes\n\nRuby's Hash class comes with a method, `assoc`, which is good for grabbing\nboth the key and value from a hash. If the given key matches it returns a\ntwo element array with the key and value.\n\n```ruby\n> stuff = {a: 1, b: 2, c: 3}\n=> {a: 1, b: 2, c: 3}\n> stuff.assoc(:c)\n=> [:c, 3]\n```\n\nIf a key is used that doesn't exist in the hash, then it simply returns nil.\n\n```ruby\n> {}.assoc(:c)\n=> nil\n```\n"
  },
  {
    "path": "ruby/audit-your-ruby-project-for-any-cves.md",
    "content": "# Audit Your Ruby Project For Any CVEs\n\nThe [`bundler-audit` gem](https://github.com/rubysec/bundler-audit) is a handy\ntool that you can run manually or integrate into your CI workflow to warn you\nabout any CVEs in your dependencies.\n\nRunning this tool without any arguments will perform a check of your\n`Gemfile.lock` file. It will check against the\n[`ruby-advisory-db`](https://github.com/rubysec/ruby-advisory-db) for any CVEs\nlinked to your dependencies, down to the patch-level.\n\n```bash\n$ bundle exec bundler-audit\n\nName: puma\nVersion: 4.3.12\nCVE: CVE-2024-21647\nGHSA: GHSA-c2f4-cvqm-65w2\nCriticality: Medium\nURL: https://github.com/puma/puma/security/advisories/GHSA-c2f4-cvqm-65w2\nTitle: Puma HTTP Request/Response Smuggling vulnerability\nSolution: upgrade to '~> 5.6.8', '>= 6.4.2'\n\nVulnerabilities found!\n```\n\nIn this example run, a vulnerability was found in the currently installed\nversion of the `puma` gem.\n\nI believe a standard `bundler-audit` command will make sure the advisory DB is\nup-to-date, but to be sure, you can run the `update` command.\n\n```bash\n$ bundle exec bundler-audit update\n\nUpdating ruby-advisory-db ...\nFrom https://github.com/rubysec/ruby-advisory-db\n * branch            master     -> FETCH_HEAD\nAlready up to date.\nUpdated ruby-advisory-db\nruby-advisory-db:\n  advisories:   884 advisories\n  last updated: 2024-03-26 16:27:16 -0700\n  commit:       840f21aeeb8a06a93a3c3bf1e2a92d7167029992\n```\n"
  },
  {
    "path": "ruby/avoid-double-negation-with-minitest-refute.md",
    "content": "# Avoid Double Negation With Minitest Refute\n\nAs I'm writing some tests for a recent feature, I end up with various test\ncases that make a variety of assertions.\n\n```ruby\nassert_equal resp_body[\"id\"], expected_id\n\n# ...\n\nassert_not resp_body[\"items\"].empty?\n```\n\nThe first assertion reads pretty naturally. The second one requires some extra\nmental parsing because of the `_not` and then the \"negative\" check of\n`#empty?`.\n\nAnother way to express this that might read more naturally is with\n[`#refute`](https://ruby-doc.org/stdlib-3.0.2/libdoc/minitest/rdoc/Minitest/Assertions.html#method-i-refute).\n\n```ruby\nrefute resp_body[\"items\"].empty?\n```\n\nThis says that we _refute_ that items is empty, so the assertion should fail if\nempty.\n\nRuby is flexible in other ways. We may also prefer to write it as:\n\n```ruby\nassert resp_body[\"items\"].present?\n```\n\nOr we could even take advantage of a more specific variant of refute with\n[`#refute_empty`](https://ruby-doc.org/stdlib-3.0.2/libdoc/minitest/rdoc/Minitest/Assertions.html#method-i-refute_empty):\n\n```ruby\nrefute_empty resp_body[\"items\"]\n```\n"
  },
  {
    "path": "ruby/block-comments.md",
    "content": "# Block Comments\n\nRuby supports (ugly) block comments. They look like this:\n\n```ruby\n=begin\nThis is a block comment.\n\nI can put whatever I want in here.\n=end\ndef do_something\n  ...\nend\n```\n\n[source](http://stackoverflow.com/questions/536760/block-commenting-in-ruby)\n"
  },
  {
    "path": "ruby/block-syntaxes-have-different-precedence.md",
    "content": "# Block Syntaxes Have Different Precedence\n\nThere are two syntaxes for defining a block in Ruby. The semantically shorthand\nsyntax uses the curly braces (`{}`). The semantically multi-line syntax uses\n`do` and `end`. For nearly all intents and purposes they are interchangable.\n\nIt is, however, worth noting that the `do`/`end` version has a lower precedence\nthan the already low precedence of `{}`. That said, you have to write some\nweird code for this to become an issue.\n\nLet's say we have two methods, `method_one` and `method_two`. They are both\ncalled on the same line like below and then followed by a block argument. Which\nmethod receives the block argument?\n\n```ruby\nmethod_one method_two { |n|\n  puts \"Executing a block: #{n}\"\n}\n\nmethod_one method_two do |n|\n  puts \"Executing a block: #{n}\"\nend\n```\n\nIn the first case, with the curly braces, `method_two` receives the block as an\nargument. In the second case, with the `do`/`end`, `method_one` receives the\nblock as an argument.\n\n[source](http://localhost:3131/ruby-operators/curly-braces#block-shorthand)\n"
  },
  {
    "path": "ruby/build-http-and-https-urls.md",
    "content": "# Build HTTP And HTTPS URLs\n\nThere are two modules you can use to build URLs in Ruby. The `URI::HTTP` module\nwill build URLs with the `http` protocol. And then to build URLs with the\n`https` protocol, you can reach for the `URI::HTTPS` module.\n\nWe can specify just the `host` and optionally include a `port` if that is\nneeded.\n\nHere is `URI::HTTP` in action.\n\n```ruby\n> URI::HTTP.build(host: 'example.com', port: 3000)\n=> #<URI::HTTP http://example.com:3000>\n\n> URI::HTTP.build(host: 'example.com', port: 3000, protocol: 'https')\n=> #<URI::HTTP http://example.com:3000>\n```\n\nNote that we can try to override the protocol, but it will be ignored.\n\nHere is the `URI::HTTPS` module.\n\n```ruby\n> URI::HTTPS.build(host: 'example.com', port: 3000)\n=> #<URI::HTTPS https://example.com:3000>\n```\n\nIf we want the URL as a string, we can call `#to_s` on it.\n\n```ruby\n> URI::HTTPS.build(host: 'example.com', port: 3000).to_s\n=> \"https://example.com:3000\"\n```\n\nWe can even include the `path`, though be sure to include the leading slash.\n\n```ruby\n> URI::HTTP.build(host: 'example.com', port: 3000, path: '/taco/bell')\n=> #<URI::HTTP http://example.com:3000/taco/bell>\n\n> URI::HTTP.build(host: 'example.com', port: 3000, path: 'taco/bell')\nURI::InvalidComponentError: bad component(expected absolute path component): taco/bell\nfrom /Users/jbranchaud/.asdf/installs/ruby/2.6.6/lib/ruby/2.6.0/uri/generic.rb:761:in `check_path'\n```\n\n[source](https://ruby-doc.org/stdlib-2.5.1/libdoc/uri/rdoc/URI/HTTP.html)\n"
  },
  {
    "path": "ruby/chaining-multiple-rspec-change-matchers.md",
    "content": "# Chaining Multiple RSpec Change Matchers\n\nIt can be handy to use RSpec's `change` matchers to determine if some method\nor process creates a new record.\n\n```ruby\nexpect{ Registration.create(attrs) }.to change{ User.count }.by(1)\n```\n\nBut what if we are testing a method that creates a couple different records\nin the system?\n\nRSpec allows us to chain together `change` matchers with `and`. Consider\nthis additional contrived example.\n\n```ruby\nexpect {\n  Project.generate(attrs)\n}.to change{ Project.count }.by(1).and \\\n     change{ User.count }.by(1)\n```\n\nIn addition to keeping our tests tight and concise, this approach gives\nsome pretty nice output on failure.\n\nIf we were just beginning our implementation with a failing test, we'd see a\nmulti-part failure like the following.\n\n```ruby\nFailure/Error:\n  expect {\n    Project.generate(attrs)\n  }.to change{ Project.count }.by(1).and \\\n       change{ User.count }.by(1)\n\n     expected result to have changed by 1, but was changed by 0\n\n  ...and:\n\n     expected result to have changed by 1, but was changed by 0\n```\n"
  },
  {
    "path": "ruby/check-for-any-overlaps-in-list-of-ranges.md",
    "content": "# Check For Any Overlaps In List Of Ranges\n\nIf you have a list of things, such as meetings, you may want to be able to tell\nif there are any conflicts. You could determine that by finding any overlaps in\ntheir timeslots.\n\nRanges are a good way to represent any span of data, including a timeslot.\n\nTo do this in Ruby, we'll need two pieces. First, a way to determine if two\n`Range` objects are overlapping. Second, an iterative utility for comparing\neach range to every other range.\n\nHere is an `overlaps?` method that uses `Range#begin` and `Range#end`.\n\n```ruby\ndef overlaps?(range1, range2)\n  range1.begin <= range2.end && range2.begin <= range1.end\nend\n```\n\nAnd here is an `any_overlaps?` method to find any overlaps over a list of\nranges.\n\n```ruby\ndef any_overlaps?(ranges)\n  ranges.each_with_index do |range1, i|\n    ranges.each_with_index do |range2, j|\n      return true if i != j && overlaps?(range1, range2)\n    end\n  end\n\n  false\nend\n\nputs any_overlaps?([(1..2), (3..4)]) #=> false\nputs any_overlaps?([(1..2), (2..4)]) #=> true\nputs any_overlaps?([(3..4), (1..5)]) #=> true\n```\n\nThis second method isn't optimized, but it will work just fine for small lists\nof ranges.\n\n[source](https://stackoverflow.com/questions/39934266/check-if-two-ranges-overlap-in-ruby)\n"
  },
  {
    "path": "ruby/check-if-a-url-resolves-to-200.md",
    "content": "# Check If A URL Resolves To 200\n\nRuby's built-in [`Net::HTTP`\nlibrary](https://ruby-doc.org/stdlib-2.7.0/libdoc/net/http/rdoc/Net/HTTP.html)\nallows us to make different kinds of HTTP requests. We can use it to make a\n`HEAD` request which will request the status of a URL without actually fetching\nits contents.\n\nWe can work directly with `Net::HTTP` using strings, but I find it is easier\nand less error-prone to get help from the `URI` class.\n\nTo make a `#head` request, we first need to establish a connection to the host\nwith [the `#start`\nmethod](https://ruby-doc.org/stdlib-2.7.0/libdoc/net/http/rdoc/Net/HTTP.html#method-i-start).\nThen we can initiate our request from that connection object.\n\n```ruby\nurl = 'https://my.app.com/path/to/video.mp4'\nuri = URI(url)\nconn = Net::HTTP.start(uri.host, uri.port, use_ssl: true)\nresp = conn.head(uri.path)\n\nresp.code\n#=> \"200\"\n```\n\nWe initiate the connection with the host and port of our URL. Then request the\n`HEAD` response for the path of our URL. If we are working with an `https` URL,\nwe need to indicate that with `use_ssl: true` in the `#start` method options.\n"
  },
  {
    "path": "ruby/check-if-an-object-includes-a-module.md",
    "content": "# Check If An Object Includes A Module\n\nYou may want to know if an object's class includes a module because that will\ntell you something about the object's behavior. It is another way of asking if\nan object responds to a method or set of methods, assuming you know what\nmethods the module provides.\n\nThis can be done with the [`Module#include?`\nmethod](https://ruby-doc.org/core-3.0.0/Module.html#method-i-include-3F).\n\n```ruby\n# assuming some object book of type Book that includes Rateable\n> book.class\n=> Book\n> book.class.include?(Rateable)\n=> true\n\n# assuming some object author of type Author that doesn't include Rateable\n> author.class\n=> Author\n> author.class.include?(Rateable)\n=> false\n```\n\n[source](https://stackoverflow.com/a/28667632/535590)\n"
  },
  {
    "path": "ruby/check-return-status-of-running-a-shell-command.md",
    "content": "# Check Return Status Of Running A Shell Command\n\nThere are [many\nways](http://tech.natemurray.com/2007/03/ruby-shell-commands.html) to run a\nshell command in a Ruby context. One of the most common is to place the command\ninside backticks. It runs the command in a subshell.\n\nThe standard output (`stdout`) from running the command is the return value of\nthe statement. Ruby also captures details about the previously run command in\nthe global `$?` variable.\n\n\n```ruby\n> `true`\n=> \"\"\n> $?.exitstatus\n=> 0\n\n> `false`\n=> \"\"\n> $?.exitstatus\n=> 1\n\n> `echo 'hello' && exit 2`\n=> \"hello\\n\"\n> $?\n=> #<Process::Status: pid 12284 exit 2>\n> $?.exitstatus\n=> 2\n```\n\nThe value captured in `$?` is a `Process::Status` object. It can tell us the\nexit status of the process with `#exitstatus`.\n"
  },
  {
    "path": "ruby/clamp-to-an-endless-range.md",
    "content": "# Clamp To An Endless Range\n\nThe\n[`Comparable#clamp`](https://ruby-doc.org/3.3.6/Comparable.html#method-i-clamp)\nmethod allows us to specify the bounds of a value we want. If the target value\nis between the bounds, then we get that value. Otherwise, we gets the nearest\nend of the bounds.\n\nWe can even pass a range to `#clamp` instead of separate lower and upper bound\nvalues. Because Ruby has beginless and endless ranges, this gives us the\nergonomics to, say, clamp to any non-negative value with a `0..` endless range.\n\nHere is what that looks like:\n\n```ruby\n> 22.clamp(0..)\n=> 22\n> (-33).clamp(0..)\n=> 0\n> 0.clamp(0..)\n=> 0\n```\n"
  },
  {
    "path": "ruby/click-on-text-with-capybara.md",
    "content": "# Click On Text With Capybara\n\nTraditionally, web apps have clickable text in the form of links and buttons.\n[Capybara's\n`click_on`](https://www.rubydoc.info/github/jnicklas/capybara/Capybara/Node/Actions#click_link_or_button-instance_method)\nmethod is made for just this.\n\n```ruby\nclick_on(\"Home\") # for <a ... >Home</a>\nclick_on(\"Submit\") # for <button ...>Submit</button>\n```\n\nA lot of more modern, JS-heavy apps stick click handlers on all kinds of\nelements. If you want to test what happens when you click some text that is not\na link or button, `click_on` won't work. Instead, you'll need to find the\nelement and\n[`click`](https://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Element#click-instance_method)\non it.\n\n```ruby\nfind(\"span\", text: \"Click Me\").click\n```\n"
  },
  {
    "path": "ruby/colorful-output-with-minitest.md",
    "content": "# Colorful Output With MiniTest\n\nRuby's\n[`MiniTest`](http://ruby-doc.org/stdlib-2.0.0/libdoc/minitest/rdoc/MiniTest.html)\nis a minimal testing framework that you can easily drop-in to any Ruby\nproject. For those used to using [`RSpec`](http://rspec.info/) with it's fancy\nred/green output, MiniTest can be a little disappointing. It prints boring,\nuncolored text to the screen that lacks visual feedback. Fortunately, red\nand green coloring can be added with\n[`minitest/reporters`](https://github.com/kern/minitest-reporters).\n\nUpdate your `Gemfile`:\n\n```ruby\ngem 'minitest-reporters'\n```\n\nThen require and configure `minitest-reporters` in your testing setup file\n(e.g. `test/test_helper.rb`):\n\n```ruby\nrequire 'minitest/reporters'\nMinitest::Reporters.use! [Minitest::Reporters::DefaultReporter.new(:color => true)]\n```\n\nYou can now enjoy that Red, Green, Refactor cycle.\n"
  },
  {
    "path": "ruby/comparing-arrays-in-rspec.md",
    "content": "# Comparing Arrays In RSpec\n\nAmong its many built-in matchers, RSpec includes a set of array matchers.\nOne of the array matchers is `match_array` which compares two arrays\nindependent of ordering. This is handy if you need to check that a resulting\narray matches your expectations when ordering is unimportant and not\nnecessarily deterministic. It can be used like so:\n\n```ruby\nexpect([1,2,3]).to match_array([3,2,1])\n```\n\nThis expectation is met, the test will pass.\n"
  },
  {
    "path": "ruby/comparing-class-hierarchy-relationships.md",
    "content": "# Comparing Class Hierarchy Relationships\n\nThe comparator methods (`<`,`>`, etc.) can be useful for a lot of things. In\nRuby, they can be used to compare classes in order to understand how they\nrelate to one another on the class hierarchy.\n\n```ruby\n# Fixnum is a subclass of Integer\n> Fixnum < Integer\n=> true\n# Integer is not a subclass of Fixnum\n> Integer < Fixnum\n=> false\n# Fixnum and String are not related to one another\n> Fixnum < String\n=> nil\n```\n\nThe `<` operator will tell you if there is a subclass relationship. The `>`\noperator will tell you if there is an ancestor relationship. When `nil`\nresults, it means the two classes do not have a direct relationship.\n\nThere are a few more of [these types of\noperators](http://ruby-doc.org/core-2.2.2/Module.html#method-i-3C) on the\nModule class.\n\n[source](http://kerrizor.com/blog/2015/05/14/serendipity-and-ruby-objects/)\n"
  },
  {
    "path": "ruby/construct-a-constant-from-a-string.md",
    "content": "# Construct A Constant From A String\n\nRuby's\n[`Module.const_get`](http://ruby-doc.org/core-2.1.0/Module.html#method-i-const_get)\ncan be used to look for and retrieve the constant for a given name.\n\nThis can be used to construct a class name\n\n```ruby\n> Object.const_get(\"Math\")\n#=> Math\n> Object.const_get(\"Math\")::PI\n#=> 3.141592653589793\n```\n\nIt can also be used to reference a constant\n\n```ruby\n> Object.const_get(\"Math::PI\")\n#=> 3.141592653589793\n```\n\nYou can even be more specific if you'd like\n\n```ruby\n> Math.const_get(\"PI\")\n#=> 3.141592653589793\n```\n\nSymbols are valid as well\n\n```ruby\n> Math.const_get(:PI)\n#=> 3.141592653589793\n```\n"
  },
  {
    "path": "ruby/convert-a-unix-epoch-timestamp-to-a-time-object.md",
    "content": "# Convert A Unix Epoch Timestamp To A Time Object\n\nRuby's `Time` class has an [`#at`\nmethod](https://ruby-doc.org/core-2.6.3/Time.html#method-c-at) that allows you\nget the _time_ at a certain unix epoch timestamp. That timestamp is an integer\nvalue representing the number of seconds since the unix epoch. While it is a\nhandy way to store that data, it is hard to tell what time it represents at a\nglance.\n\n```ruby\nTime.at(1669652477)\n=> 2022-11-28 10:21:17 -0600\n```\n\nUsing `Time.at` we are able to turn that integer into a `Time` object that\nrepresents the date and time in a human-readable way.\n\n[source](https://prathamesh.tech/2020/03/02/converting-timestamps-to-ruby-objects/)\n"
  },
  {
    "path": "ruby/create-a-csv-table-object.md",
    "content": "# Create A CSV::Table Object\n\nWhen you parse a file or string using `CSV.parse` (with `headers = true`) you\nget a\n[`CSV::Table`](https://ruby-doc.org/stdlib-2.5.1/libdoc/csv/rdoc/CSV/Table.html)\nobject in response. This object can be used to read what was in a file or it\ncan be used to create a new file. It is also handy as a potential test object\nif you want to assume, but omit, file reading in a unit test.\n\nYou can create a `CSV::Table` one of the following two ways. First, with a file:\n\n```ruby\nrequire 'csv'\n\nfile = # read in file\ncsv_table = CSV.parse(file, headers: true)\n```\n\nSecond, with a string, or even better, a HEREDOC:\n\n```ruby\nrequire 'csv'\n\ncsv_table =\n  CSV.parse(<<-CSV, headers: true)\n    first_name,last_name,taco\n    Josh,Branchaud,\"Al Pastor\"\n    Jake,Worth,Cauliflower\n  CSV\n\ncsv_table.headers\n#=> [\"first_name\", \"last_name\", \"taco\"]\n```\n\nFrom here, you can do what you need with it, whether that is using it in a test\nor writing it to a file.\n\n[source](https://ruby-doc.org/stdlib-2.6.3/libdoc/csv/rdoc/CSV.html#class-CSV-label-CSV+with+headers)\n"
  },
  {
    "path": "ruby/create-a-hash-from-an-array-of-arrays.md",
    "content": "# Create A Hash From An Array Of Arrays\n\nThe `::[]` method on the `Hash` class allows you to succinctly create a hash\nfrom an array of arrays -- or rather an array of tuples which are key value\npairs.\n\n```ruby\n> Hash[ [[\"a\",2],[\"b\",4]] ]\n{\"a\"=>2, \"b\"=>4}\n> Hash[ [[1,2],[3,4]] ]\n{1=>2, 3=>4}\n```\n\nSee the [`Hash::[]`\ndocs](http://ruby-doc.org/core-2.3.0/Hash.html#method-c-5B-5D) for more\ndetails.\n\nh/t Josh Davey\n"
  },
  {
    "path": "ruby/create-a-module-of-utility-functions.md",
    "content": "# Create A Module Of Utility Functions\n\nIn my [latest blog post](https://www.visualmode.dev/create-a-module-of-utility-functions-in-ruby),\nI went into full detail about how the [`Module#module_function` method](https://ruby-doc.org/3.4.1/Module.html#method-i-module_function) works.\nIt creates both a module of utility functions that we can access directly on\nthat module like we would with `self` methods. It can also be included in a\nclass as a way of sharing copies of those utility functions with the class. A\nkey point to them being copies is that they can then be overridden by the\nincluding class.\n\nHere is the example I used in the blog post:\n\n```ruby\nmodule MarkdownHelpers\n  module_function\n\n  def heading(text, level = 1)\n    (\"#\" * level) + \" #{text}\"\n  end\n\n  def link(text, href)\n    \"[#{text}](#{href})\"\n  end\n\n  def image(alt_text, href)\n    \"!#{link(alt_text, href)}\"\n  end\nend\n```\n\nI won't cover everything that the blog post covers, but what I found really nice\nabout this pattern is that I can call those utility functions directly with the\nmodule as the receiver:\n\n```bash\n$ ruby -r ./markdown_helpers.rb -e 'puts MarkdownHelpers.link(\"Click here\", \"https://example.com\")'\n[Click here](https://example.com)\n```\n\nThe alternative to this generally looks like:\n\n```ruby\nmodule MarkdownHelpers\n  def self.heading(text, level = 1)\n    (\"#\" * level) + \" #{text}\"\n  end\n\n  def self.link(text, href)\n    \"[#{text}](#{href})\"\n  end\n\n  def self.image(alt_text, href)\n    \"!#{link(alt_text, href)}\"\n  end\nend\n```\n\nThat would be fine, but we completely lose out on the ability to include it as a\nmix-in with other classes.\n"
  },
  {
    "path": "ruby/create-an-array-of-stringed-numbers.md",
    "content": "# Create an Array of Stringed Numbers\n\nTo create an array of numbers between `1` and `5`, I can do something like\nthe following:\n\n```ruby\n(1..5).to_a\n> [1,2,3,4,5]\n```\n\nHowever, what if I want an array of `\"1\"` to `\"5\"`? That is, what if I want\nan array of consecutive numbers as strings?\n\nI can just reuse the above and map them to strings like so:\n\n```ruby\n(1..5).to_a.map(&:to_s)\n> ['1','2','3','4','5']\n```\n\nThough, that seems more verbose than necessary. Ruby actually allows you to\ndo ranges of characters. Which means that I can modify my original approach\nto look something like this:\n\n```ruby\n('1'..'5').to_a\n> ['1','2','3','4','5']\n```\n"
  },
  {
    "path": "ruby/create-listing-of-all-middleman-pages.md",
    "content": "# Create Listing Of All Middleman Pages\n\nMiddleman is a handy tool for quickly throwing together a bunch of static\npages with layout and templating help at the ready. Once you have a handful\nof pages up and running, you'll probably want a way to quickly navigate to\nthem. You can add a quick listing of all the pages with a couple helpers\nprovided by Middleman.\n\n```erb\n<ul>\n  <% sitemap.resources.each do |resource| %>\n    <li><%= link_to(resource.path, resource.path) %></li>\n  <% end %>\n</ul>\n```\n\nThe `sitemap.resources` variable will contain a list of all the resources\nthat get processed and served by the Middleman app. The `link_to` helper\nmakes it easy to turn those into links.\n\nBecause `resources` includes images and other assets, you may want to filter\ndown to just `html` files which could look something like the following:\n\n```erb\n<ul>\n  <% sitemap.resources\n       .select { |resource| resource.path =~ /html$/ }\n       .each do |resource|\n  %>\n    <li><%= link_to(resource.path, resource.path) %></li>\n  <% end %>\n</ul>\n```\n\nJust add the snippet to whatever page you'd like the page listing to appear\non.\n"
  },
  {
    "path": "ruby/create-mock-class-that-can-be-overridden.md",
    "content": "# Create Mock Class That Can Be Overridden\n\nLet's say I've defined a `MockTwilioClient` class for my system tests so that\nthey don't have to actually make calls out to the Twilio API.\n\n```ruby\nclass MockTwilioClient\n  def send_sms_message\n    \"MSG_SID_123\"\n  end\nend\n```\n\nNow, any test that is exercising behavior that uses those parts of the\n`TwilioClient` can mock those calls in a predictable way.\n\nThe above class always is successful when `send_sms_message` is called. What if\nwe want to simulate an error response? We need a way to override the client for\nspecific testing scenarios.\n\nLet's create a helper that can create `MockTwilioClient` instances, either as is\nor with overrides.\n\n```ruby\ndef create_mock_twilio_client(&block)\n  if block_given?\n    Class.new(MockTwilioClient, &block).new\n  else\n    MockTwilioClient.new\n  end\nend\n```\n\nIf we pass it a block with specific method overrides, it will create a one-off\nanonymous subclass of `MockTwilioClient` with that block which effectively\noverrides the parent class's methods.\n\nWe can put this to use like so:\n\n```ruby\nrequire 'test_helper'\n\nclass SomeSystemTest < SystemTestCase\n  class MockTwilioClient\n    def send_sms_message\n      \"MSG_SID_123\"\n    end\n  end\n\n  def create_mock_twilio_client(&block)\n    if block_given?\n      Class.new(MockTwilioClient, &block).new\n    else\n      MockTwilioClient.new\n    end\n  end\n\n  test \"send message to customer\" do\n    mock_client = create_mock_twilio_client\n\n    TwilioClient.stub(:new, mock_client) do\n      # some action that uses `send_sms_message`\n      \n      # some assertions ...\n    end\n  end\n\n  test \"fail to send message to customer\" do\n    mock_client = create_mock_twilio_client do\n      def send_sms_message\n        raise \"Failed to send message\"\n      end\n    end\n\n    TwilioClient.stub(:new, mock_client) do\n      # some action that uses `send_sms_message`\n      \n      # some assertions ...\n    end\n  end\nend\n```\n\nIn the second test case, I override the _success path_ with a version of\n`send_sms_message` that raises an error.\n"
  },
  {
    "path": "ruby/create-named-structs-with-struct-new.md",
    "content": "# Create Named Structs With Struct.new\n\nI often see `Struct` used to create some one-off anonymous data structure\nlike so:\n\n```ruby\n> person = Struct.new(:name, :age)\n=> #<Class:0x007fc6c89112e8>\n> person.new(\"Alice\", 33)\n=> #<struct name=\"Alice\", age=33>\n```\n\nThis will often get the job done, but on its own the resulting data\nstructure doesn't tell us as much as it could.\n\nWe can say more with a _named_ struct:\n\n```ruby\nStruct.new(\"Person\", :name, :age)\n=> Struct::Person\n> Struct::Person.new(\"Bob\", 24)\n=> #<struct Struct::Person name=\"Bob\", age=24>\n```\n\nWhen the first argument is a string that can be converted to a constant,\nthen we'll get a named struct that is subclassed under `Struct`.\n\nWe can also assign the struct initialization to a constant to do a similar\nthing:\n\n```ruby\n> Person = Struct.new(:name, :age)\n=> Person\n> Person.new(\"Jerry\", 45)\n=> #<struct Person name=\"Jerry\", age=45>\n```\n\n[source](https://ruby-doc.org/core-2.4.2/Struct.html#method-c-new)\n"
  },
  {
    "path": "ruby/create-thumbnail-image-for-a-pdf.md",
    "content": "# Create Thumbnail Image For A PDF\n\nThe [`rmagick`](https://rmagick.github.io/) gem is a wrapper around the\n[ImageMagick](http://www.imagemagick.org/script/index.php) software suite.\nThis gem can be used to create a thumbnail image of a PDF using the\nfollowing snippet of code.\n\n```ruby\nrequire 'rmagick'\npdf = Magick::ImageList.new('document.pdf')\nfirst_page = pdf.first\nscaled_page = first_page.scale(300, 450)\nscaled_page.write('document-thumbnail.jpg')\n```\n\nThe scale can be adjust as necessary to the use case.\n\n[source](http://stackoverflow.com/questions/65250/convert-a-doc-or-pdf-to-an-image-and-display-a-thumbnail-in-ruby)\n"
  },
  {
    "path": "ruby/decompose-unicode-character-with-diacritic-mark.md",
    "content": "# Decompose Unicode Character With Diacritic Mark\n\nA character like the `ñ` is typically represented by the unicode codepoint of\n`U+00F1`. However, it is also possible to represent it with two unicode\ncodepoints -- the `n` (`U+006E`) and the combining diacritical mark `˜`\n(`U+0303`).\n\nWe can see that by comparing a typed `ñ` with one where we split it apart into\nthe separate codepoints. We can do that with\n[`#unicode_normalize`](https://apidock.com/ruby/v2_5_5/String/unicode_normalize)\nand the `:nfd` argument which stands for _Normalized Form Decomposed_.\n\n```ruby\n> \"ñ\" == \"ñ\".unicode_normalize(:nfd)\n=> false\n> \"ñ\".unicode_normalize(:nfd).length\n=> 2\n> \"ñ\".length\n=> 1\n```\n\nWe can inspect the exact codepoints by iterating over each character and\nprinting out the codepoint value.\n\n```ruby\n\"ñ\".each_char.with_index do |char, i|\n  puts \"#{i}: '#{char}' -> U+#{char.ord.to_s(16).upcase.rjust(4, '0')}\"\nend\n# 0: 'ñ' -> U+00F1\n# => \"ñ\"\n\n\"ñ\".unicode_normalize(:nfd).each_char.with_index do |char, i|\n  puts \"#{i}: '#{char}' -> U+#{char.ord.to_s(16).upcase.rjust(4, '0')}\"\nend\n# 0: 'n' -> U+006E\n# 1: '̃' -> U+0303\n#=> \"ñ\"\n```\n\nNotice the difference after the character has been decomposed such that the\ndiacritic is separated from the character.\n\nThis can be done with other characters containing diacritics.\n\nAnd here we go the other direction with\n[`#pack`](https://ruby-doc.org/core-3.0.1/Array.html#method-i-pack).\n\n```ruby\n> [0x006E, 0x0303].pack(\"U*\")\n=> \"ñ\"\n> [0x00F1].pack(\"U*\")\n=> \"ñ\"\n> [0x006E, 0x0303].pack(\"U*\") == [0x00F1].pack(\"U*\")\n=> false\n```\n"
  },
  {
    "path": "ruby/defaulting-to-frozen-string-literals.md",
    "content": "# Defaulting To Frozen String Literals\n\n> The cold never bothered me anyway.\n\nThe release of Ruby 2.2 introduced the ability to freeze string literals,\nmaking them immutable. With the release of Ruby 2.3, strings can be frozen\nby default without the use of `#freeze`. By adding the following magic\ncomment at the top of a file\n\n```ruby\n# frozen_string_literal: true\n```\n\nall string literals will default to frozen. That means that all string\nliterals in that file are immutable, cannot be modified. This gives the Ruby\ninterpreter some performance gains due to reduced object allocation.\n\nThis is the [issue](https://bugs.ruby-lang.org/issues/11473) that introduced\nit.\n"
  },
  {
    "path": "ruby/define-a-custom-rspec-matcher.md",
    "content": "# Define A Custom RSpec Matcher\n\nYou can define your own custom RSpec matchers. This is a great way to keep\nyour spec tight and readable. A custom, domain-specific matcher can convey\nmore intent in a single line than several lines of built-in matchers.\n\nHere is a matcher to check if something is in a range:\n\n```ruby\nrequire 'rspec/expectations'\n\nRSpec::Matchers.define :be_betwen do |lower, upper|\n  match do |operand|\n    expect(operand).to be >= lower\n    expect(operand).to be <= upper\n  end\nend\n\ndescribe MyThing do\n  it \"has a value between 0 and 10\" do\n    thing = MyThing.new\n\n    expect(thing.value).to be_between(0, 10)\n  end\nend\n```\n\nBy requiring `rspec/expectations` we are able to define a matcher that takes\n0 or more arguments (in our case, `lower` and `upper`) and then make\nassertions with them and the `expect` value.\n\n[source](https://relishapp.com/rspec/rspec-expectations/v/2-4/docs/custom-matchers/define-matcher)\n"
  },
  {
    "path": "ruby/define-a-method-on-a-struct.md",
    "content": "# Define A Method On A Struct\n\nWhen defining a Ruby `Struct`, you can optionally pass it a block that defines\nany number of methods as instance methods on that `Struct`. They can reference\nthe attributes of the `Struct`.\n\nHere is an example of a person `Struct` with a `full_name` method that uses the\n`first_name` and `last_name` attributes.\n\n```ruby\nPerson = Struct.new(:first_name, :last_name, :age) do\n  def full_name\n    \"#{first_name} #{last_name}\"\n  end\nend\n```\n\nThis `Struct` can be used like so:\n\n```ruby\n> liz = Person.new(\"Liz\", \"Lemon\", 39)\n=> #<struct Person first_name=\"Liz\", last_name=\"Lemon\", age=39>\n> liz.full_name\n=> \"Liz Lemon\"\n```\n\nThis is a great way to make a `Struct` just a bit more powerful without having\nto convert it into a full-blown PORO (plain old Ruby object).\n"
  },
  {
    "path": "ruby/define-multiline-strings-with-heredocs.md",
    "content": "# Define Multiline Strings With Heredocs\n\n[A _heredoc_ (_here document_) is a special ruby\nsyntax](https://ruby-doc.org/core-2.5.0/doc/syntax/literals_rdoc.html#label-Here+Documents)\nfor defining formatted multiline strings. These are useful for any situation\nwhere you need to define a block of text where newlines and indentation are\npreserved -- e.g. output an error, help message, or some formatted SQL.\n\nThe standard syntax is defined with `<<` and some uppercase identifier (e.g.\n`TXT`, `DOC`, `SQL`, etc.) to open and close the multiline string.\n\n```ruby\ndef lookup_team(team_id)\n  query = <<SQL\n    select users.id from users\n      join teams\n        on teams.id = users.team_id\n      where teams.id = #{team_id}\n      order by created_at desc\n      limit 10;\nSQL\n\n  team_member_ids = db.execute(query)\nend\n```\n\nWith the SQL formatted this way, it is easier to read and we can print/log out\nthis nicely formatted version to make debugging easier.\n\nNotice that the terminating `SQL` identifier is fully left justified. I find\nthat visually off relative to the indentation of everything else, so I like to\nuse the _indented_ heredoc syntax (`<<-`).\n\n```ruby\ndef lookup_team(team_id)\n  query = <<-SQL\n    select users.id from users\n      join teams\n        on teams.id = users.team_id\n      where teams.id = #{team_id}\n      order by created_at desc\n      limit 10;\n  SQL\n\n  team_member_ids = db.execute(query)\nend\n```\n"
  },
  {
    "path": "ruby/destructure-the-first-item-from-an-array.md",
    "content": "# Destructure The First Item From An Array\n\nIn true Ruby fashion, there are plenty of idomatic ways to get the first\nitem from an array.\n\nOne of the ways is with assignment destructuring of the array.\n\nIt is common to see assignment destructuring with tuples:\n\n```ruby\n> name, email = ['Liz', 'liz.lemon@nbc.com']\n=> [\"Liz\", \"liz.lemon@nbc.com\"]\n> name\n=> \"Liz\"\n> email\n=> \"liz.lemon@nbc.com\"\n```\n\nIf you only want the first element, try this:\n\n```ruby\n> name, *rest = ['Liz', 'liz.lemon@nbc.com']\n=> [\"Liz\", \"liz.lemon@nbc.com\"]\n> name\n=> \"Liz\"\n> rest\n=> [\"liz.lemon@nbc.com\"]\n```\n\nThe first element is assigned to `name` and the remaining items in the array\nare assigned to `rest`. That's because of the `*`.\n\nI like to use this approach with an array-returning method.\n\n```ruby\n> def lookup_person(id)\n    ['Liz', 'liz.lemon@nbc.com', id]\n  end\n=> :lookup_person\n> name, *rest = lookup_person(22)\n=> [\"Liz\", \"liz.lemon@nbc.com\", 22]\n> name\n=> \"Liz\"\nirb(main):013:0> rest\n=> [\"liz.lemon@nbc.com\", 22]\n```\n\nThis method works as expected when dealing with an empty array.\n\n```ruby\n> name, *rest = []\n=> []\n> name\n=> nil\n> rest\n=> []\n```\n\nIn all of these, `, *rest` is important because otherwise the statement will be\na standard variable assignment.\n"
  },
  {
    "path": "ruby/destructuring-arrays-in-blocks.md",
    "content": "# Destructuring Arrays In Blocks\n\nIf I am iterating over a collection of arrays (let's say tuples) and I want\nto access the values of those arrays within the iteration block, I may do\nsomething like the following:\n\n```ruby\n> a = [[1,2],[3,4],[5,6]]\n> a.each { |tuple| puts \"#{tuple[0]} - #{tuple[1]}\" }\n1 - 2\n3 - 4\n5 - 6\n```\n\nI can, however, use array destructuring which will not only simplify the\ncode, but also make it more readable, explicit, and intentional.\n\n```ruby\n> a = [[1,2],[3,4],[5,6]]\n> a.each { |x_coord,y_coord| puts \"#{x_coord} - #{y_coord}\" }\n1 - 2\n3 - 4\n5 - 6\n```\n\nIn the same way, I can destructure arrays that are part of a hash like so:\n\n```ruby\n> h = {one: [1,2], two: [3,4], three: [5,6]}\n> h.each { |key, (x_coord, y_coord)| puts \"#{x_coord} - #{y_coord}\" }\n1 - 2\n3 - 4\n5 - 6\n```\n\nNote the parentheses that are placed around the part that is being\ndestructured. Without these parentheses, ruby will interpret `x_coord` as\nthe whole array value and `y_coord` will be `nil`.\n"
  },
  {
    "path": "ruby/disable-interpolation-for-a-heredoc-string.md",
    "content": "# Disable Interpolation For A Heredoc String\n\nAs a matter of convenience, a heredoc performs string interpolation by default.\n\nHere is an example of that.\n\n```ruby\nirb(main):087> word = 'taco'\n=> \"taco\"\nirb(main):088\" puts <<-TEXT\nirb(main):089\"   I want to eat a #{word}!\nirb(main):090> TEXT\n  I want to eat a taco!\n=> nil\n```\n\nA much less common scenario is that we don't want string interpolation to take\nplace. For whatever reason, we want the exact string to be preserved. To\nachieve that, we can wrap the opening heredoc identifier in single quotes.\n\nAs you can see, the `#{word}` portion is preserved.\n\n```ruby\nirb(main):091> word = 'taco'\n=> \"taco\"\nirb(main):092' puts <<-'TEXT'\nirb(main):093'   I want to eat a #{word}!\nirb(main):094> TEXT\n  I want to eat a #{word}!\n=> nil\n```\n\nThis syntax puts the heredoc in single-quote mode. I left the IRB line preamble\nin for each codeblock so that you can see the difference. The first example\n(lines 88 and 89) shows the heredoc is double-quoted. The second example (lines\n92 and 93) shows the heredoc is single quoted.\n\nNote: the closing heredoc identifier (`TEXT` in this case) is not wrapped in\nsingle quotes, just the opening one.\n\n[source](https://ruby-doc.org/3.3.6/syntax/literals_rdoc.html#label-Here+Document+Literals)\n"
  },
  {
    "path": "ruby/disassemble-some-codes.md",
    "content": "# Disassemble Some Codes\n\nThe\n[`RubyVM::InstructionSequence`](http://ruby-doc.org/core-2.2.0/RubyVM/InstructionSequence.html)\nclass makes it easy to compile, disassemble, and inspect bits of Ruby code.\nWe can quickly take a peek under the hood at a simple ruby statement, such\nas `a = 1 + 2`, like so:\n\n```ruby\n> ruby_code = 'a = 1 + 2'\n=> a = 1 + 2\n> compiled_code = RubyVM::InstructionSequence.compile(ruby_code)\n=> <RubyVM::InstructionSequence:<compiled>@<compiled>>\n> puts compiled_code.disasm\n== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========\nlocal table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw:\n-1@-1, kwrest: -1])\n[ 2] a\n0000 trace            1                                               (   1)\n0002 putobject_OP_INT2FIX_O_1_C_\n0003 putobject        2\n0005 opt_plus         <callinfo!mid:+, argc:1, ARGS_SIMPLE>\n0007 dup\n0008 setlocal_OP__WC__0 2\n0010 leave\n=> nil\n```\n\nIt is a bit archaic, but when we get to the line starting with `0002`, we\nsee values (`1` and then `2`) pushed onto the stack, then operated on, and\nfinally set on the local variable `a`. Fun!\n"
  },
  {
    "path": "ruby/double-splat-to-merge-hashes.md",
    "content": "# Double Splat To Merge Hashes\n\nOne way of merging two hashes is with `#merge`:\n\n```ruby\n> h1 = {a: 1, b: 2}\n=> {:a=>1, :b=>2}\n> h2 = {c: 3, d: 4}\n=> {:c=>3, :d=>4}\n> h1.merge(h2)\n=> {:a=>1, :b=>2, :c=>3, :d=>4}\n```\n\nYou can also use double splats for a slightly more concise approach:\n\n```ruby\n> h1 = {a: 1, b: 2}\n=> {:a=>1, :b=>2}\n> h2 = {c: 3, d: 4}\n=> {:c=>3, :d=>4}\n> {**h1, **h2}\n=> {:a=>1, :b=>2, :c=>3, :d=>4}\n```\n\nThis works particularly well when you want to expand an existing hash into a\nhash you are creating on the fly:\n\n```ruby\n> h1 = {a: 1, b: 2}\n=> {:a=>1, :b=>2}\n> {c: 3, d: 4, **h1}\n=> {:c=>3, :d=>4, :a=>1, :b=>2}\n```\n"
  },
  {
    "path": "ruby/edit-previous-parts-of-the-pry-buffer-history.md",
    "content": "# Edit Previous Parts Of The Pry Buffer History\n\nEach line of Ruby you enter into a Pry session is recorded with a number in\nthe buffer history. Pry keeps this buffer history so that you can recall\nparts of it for editing and subsequent execution.\n\nIf you use the `edit` command by itself, Pry will open the previous Ruby\nstatement in your default editor. But what if you want to edit a statement\nfrom a while back? Or even a series of statements?\n\nUse the `--in` flag with `edit` either specifying a single record in the\nbuffer history or a range of records.\n\n```ruby\n$ pry\n[1] pry(main)> puts \"Hello\"\nHello\n=> nil\n[2] pry(main)> puts \"World\"\nWorld\n=> nil\n[3] pry(main)> puts \"People\"\nPeople\n=> nil\n[4] pry(main)> edit --in 1..2\nHello\nWorld\n=> nil\n```\n"
  },
  {
    "path": "ruby/editing-code-in-pry.md",
    "content": "# Editing Code In Pry\n\n[Pry](http://pryrepl.org/) provides an enhanced REPL experience for Ruby.\nOne of the enhancements it provides is the ability to open your preferred\neditor within a pry session. This makes it easy to compose and edit\nmulti-line blocks of code.\n\nTry it out by typing `edit` within a pry session. Once you are ready, you\ncan save the file which will prompt pry to interpret the contents of your\nfile within the context of the pry session.\n"
  },
  {
    "path": "ruby/encode-a-string-as-url-safe-base64.md",
    "content": "# Encode A String As URL-safe Base64\n\nRuby's standard lib comes with a [Base64\nmodule](https://ruby-doc.org/stdlib-2.1.4/libdoc/base64/rdoc/Base64.html)\nwith a number of utilities for encoding and decoding data as\n[Base64](https://en.wikipedia.org/wiki/Base64). One of the methods it\nprovides is `urlsafe_encode64`.\n\n```ruby\n> require 'base64'\ntrue\n> Base64.urlsafe_encode64('hello')\n\"aGVsbG8=\"\n> Base64.urlsafe_encode64('1')\n\"MQ==\"\n```\n\nYou can pass it any string and it will create a URL-safe Base64 encoded\nrepresentation of that string.\n"
  },
  {
    "path": "ruby/enumerate-a-pairing-of-every-two-sequential-items.md",
    "content": "# Enumerate A Pairing Of Every Two Sequential Items\n\nFrom time to time, I've come across a situation where I want to iterate over a\nlist of items and have access to the item right after (or before depending on\nhow you want to think about it) the current item.\n\nIf I had a list like:\n\n```ruby\nitems = [:a, :b, :c, :d, :z]\n```\n\nThen I'd love to turn it into a list of tuples like so:\n\n```ruby\ntuples = [[:a, :b], [:b, :c], [:c, :d], [:d, :z]]\n```\n\nI've finally come up with a one-liner I like for turning `items` into `tuples`.\n\n```ruby\nitems.first(items.size - 1)\n# => [:a, :b, :c, :d]\nitems.last(items.size - 1)\n#=> [:b, :c, :d, :z]\nitems.first(items.size - 1).zip(items.last(items.size - 1))\n#=> [[:a, :b], [:b, :c], [:c, :d], [:d, :z]]\n```\n\nI realized that if I take everything but the last item (using `first`) and take\neverything but the first item (using `last`), then I can `zip` those two arrays\ntogether into the list of tuples I was looking for.\n"
  },
  {
    "path": "ruby/evaluating-one-off-commands.md",
    "content": "# Evaluating One-Off Commands\n\nWhen I need to quickly test something out in Ruby, I will often reach for\n`irb`. However, there is an even quicker way to send a line of code to\nruby for evaluation. Use the `ruby` binary with the `-e` flag followed\nby your line of ruby. For instance,\n\n```\n$ ruby -e 'puts Class.ancestors'\n[Class, Module, Object, Kernel, BasicObject]\n```\n"
  },
  {
    "path": "ruby/exclude-values-from-an-array.md",
    "content": "# Exclude Values From An Array\n\nIn true Ruby fashion, there are all sorts of ways to exclude values from an\narray.\n\nIf you just want to exclude `nil` values, you can use\n[`#compact`](https://ruby-doc.org/core-3.0.0/Array.html#method-i-compact).\n\n```ruby\n> [1,nil,:what,4].compact\n#=> [1, :what, 4]\n```\n\nIf you want to exclude `nil` values and some other named value, you could use\n[`#filter`](https://ruby-doc.org/core-3.0.0/Array.html#method-i-filter) or\n[`#reject`](https://ruby-doc.org/core-3.0.0/Array.html#method-i-reject).\n\n```ruby\n> [1,nil,:what,4].filter { |val| !val.nil? && val != :what }\n#=> [1, 4]\n> [1,nil,:what,4].reject { |val| val.nil? || val == :what }\n#=> [1, 4]\n```\n\nThe filter is clumsy and heavy-handed for this sort of example. A really terse\nway of doing the same thing is with set difference:\n[`#-`](https://ruby-doc.org/core-3.0.0/Array.html#method-i-2D).\n\n```ruby\n> [1,nil,:what,nil,5] - [:what,nil]\n#=> [1, 5]\n```\n\nOr the spelled out\n[`#difference`](https://ruby-doc.org/core-3.0.0/Array.html#method-i-difference)\nmethod.\n\n```ruby\n> [1,nil,:what,nil,5].difference([:what,nil])\n#=> [1, 5]\n```\n"
  },
  {
    "path": "ruby/execute-several-commands-with-backtick-heredoc.md",
    "content": "# Execute Several Commands With Backtick Heredoc\n\nA fun feature of Ruby is that we can execute a command in a subprocess just by\nwrapping it in backticks.\n\nFor instance, we might shell out to `git` to check if a file is tracked:\n\n```ruby\n`git ls-files --error-unmatch #{file_path} 2>/dev/null`\n$?.success?\n```\n\nBut what if we need to execute several commands? Perhaps they depend on one\nanother. We want them to run in the same subprocess.\n\nFor this, we can use the backtick version of a heredoc. That is a special\nversion of a heredoc where the delimiter is wrapped in backticks.\n\n```ruby\nputs <<`SHELL`\n  # Set up trap\n  trap 'echo \"Cleaning up temp files\"; rm -f *.tmp' EXIT\n  \n  # Create temporary file\n  echo \"test data\" > work.tmp\n  \n  # Do some work\n  cat work.tmp\n  \n  # Trap will clean up on exit\nSHELL\n```\n\nHere we set up a `trap` for file cleanup on exit, then create a file, then do\nsomething with the file, and that's it, the process exits (triggering the\ntrap).\n\n[source](https://ruby-doc.org/3.3.6/syntax/literals_rdoc.html#label-Here+Document+Literals)\n"
  },
  {
    "path": "ruby/exit-a-process-with-an-error-message.md",
    "content": "# Exit A Process With An Error Message\n\nIf you want to exit a Ruby process with an unsuccessful error code like `1`,\nyou can use\n[`Kernel.exit`](https://ruby-doc.org/core-3.1.2/Kernel.html#method-i-exit).\n\n```ruby\nif arg_is_missing?\n  exit 1\nend\n```\n\nThe non-zero status code means this will work great in a scripting scenario,\nlike `ruby script.rb && echo 'success'`. If the script has to exit early, it\nwon't print 'success'.\n\nThat's fine, but it doesn't give the program a chance to tell us _why_ the\nprogram exited early.\n\n`Kernel` has another method\n[`abort`](https://ruby-doc.org/core-3.1.2/Kernel.html#method-i-abort) that does\nthe same thing as `exit 1` while also printing a message to `STDERR`.\n\n```ruby\nif arg_is_missing?\n  abort 'The missing argument must be supplied'\nend\n```\n\nThis is handy if you want to communicate more than just the error code. The\nprogram still exits early with an error code of `1`. And it prints that message\nto `STDERR`.\n\n[source](https://stackoverflow.com/a/23340693/535590)\n"
  },
  {
    "path": "ruby/expect-a-method-to-be-called-and-actually-call-it.md",
    "content": "# Expect A Method To Be Called And Actually Call It\n\nYou can assert that a method is called without actually executing it. This is\noften what `expect(...).to receive(:method_name)`  is used for. If you do want\nthat method called, RSpec can accommodate you.\n\nLet's say we have the following two classes:\n\n```ruby\nclass Greeting\n  def self.say_hello\n    raise \"Don't actually execute this\"\n    puts \"Hello\"\n  end\nend\n\nclass GreetingService\n  def self.run\n    Greeting.say_hello\n  end\nend\n```\n\nWe can assert that `say_hello` gets called without actually raising the\nexception (first `it` block). If we tack on `and_call_original` then RSpec will\nmake the assertion and execute the method (second `it` block).\n\n```ruby\ndescribe \"expect and call original\" do\n  it \"expect the message is received\" do\n    expect(Greeting).to receive(:say_hello)\n    GreetingService.run\n    # passes\n  end\n\n  it \"expect and call original\" do\n    expect(Greeting).to receive(:say_hello).and_call_original\n    GreetingService.run\n    # fails, RuntimeError\n  end\nend\n```\n\n[source](https://relishapp.com/rspec/rspec-mocks/v/2-14/docs/message-expectations/calling-the-original-method)\n"
  },
  {
    "path": "ruby/extract-a-column-of-data-from-a-csv-file.md",
    "content": "# Extract A Column Of Data From A CSV File\n\nLet's say I have just downloaded a medium-sized CSV of data onto my hard drive.\nI want to exact one column of data from that CSV to inject into some other\ntool/process.\n\nHere is how I'd go about doing that with Ruby.\n\n```ruby\nrequire 'csv'\n\nfilename = \"#{Dir.home}/Downloads/file.csv\"\ncolumn_index = 2 # zero-indexed column of interest\n\n# an array of collecting the values I want to extract\ncol_data = []\n\n# read in the CSV into memory\ncsv_data = CSV.read(filename)\n\n# pop headers out of the top of the array\ncsv_data.shift\n\n# grab the column of interest from each row\ncsv_data.each { |row| col_data << row[column_index] }\n\n# do something with the extract column of data\ncomma_separated_list = col_data.join(', ')\nsystem \"command -v pbcopy >/dev/null 2>&1 && echo '#{comma_separated_list}' | pbcopy\"\n```\n\nAll but the last two lines are pretty standard. We identify the file and column\nof interest. Read in the CSV from that file and ditch the headers. Then we grab\nthat column's value for every entry in the CSV.\n\nThen we need to do something with that data.\n\nIn my case, I want to turn those values into a comma-separated list and put it\non my clipboard. Those last two lines do just that.\n"
  },
  {
    "path": "ruby/extract-capture-group-matches-with-string-slices.md",
    "content": "# Extract Capture Group Matches With String Slices\n\nRuby's _string slice_ syntax allows us to use the square brackets to access\nportions of a string. It's most common to pass positional integer index\narguments or a range. However, in true Ruby fashion, another way of thinking\nabout defining the slice of a string is based on a regex match.\n\nWe can pass a regex and an int (specifying which match we want) to extract some\nportion of a string based on the regex match. That includes capture groups.\n\nHere are a couple examples of extracting matching capture groups as well as\ngetting the entire regex match:\n\n```ruby\n> \"me+abc123@email.com\"[/.+\\+(.+)@(.+)/, 1]\n=> \"abc123\"\n\n> \"me+abc123@email.com\"[/.+\\+(.+)@(.+)/, 2]\n=> \"email.com\"\n\n> \"me+abc123@email.com\"[/.+\\+(.+)@(.+)/, 0]\n=> \"me+abc123@email.com\"\n\n> \"me+abc123@email.com\"[/.+\\+(.+)@(.+)/]\n=> \"me+abc123@email.com\"\n```\n\nThe `0`th match (which is the default) corresponds to the full match. Each\ninteger position after that corresponds to any capture groups. This maps\ndirectly to the underlying `MatchData` object:\n\n```ruby\n> /.+\\+(.+)@(.+)/.match(\"me+abc123@email.com\")\n=> #<MatchData \"me+abc123@email.com\" 1:\"abc123\" 2:\"email.com\">\n```\n\n[source](https://ruby-doc.org/3.3.6/String.html#class-String-label-String+Slices)\n"
  },
  {
    "path": "ruby/factory-girl-sequences.md",
    "content": "# FactoryGirl Sequences\n\n[FactoryGirl sequences](https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#sequences)\nare often used inline for unique values such as emails:\n\n```ruby\nfactory :user do\n  sequence(:email) { |n| \"person#{n}@example.com\" }\nend\n```\n\nHowever, a sequence can be defined on its own\n\n```ruby\nFactoryGirl.define do\n  sequence :email do |n|\n    \"person#{n}@example.com\"\n  end\nend\n```\n\nThat means it can be invoked outside the context of a factory\n\n```ruby\n> FactoryGirl.generate :email\n=> \"person1@example.com\"\n> FactoryGirl.generate :email\n=> \"person2@example.com\"\n```\n\nOr it can be used as a shared sequence across multiple factories\n\n```ruby\nfactory :customer do\n  ...\n  email\nend\n\nfactory :admin do\n  ...\n  email\nend\n```\n"
  },
  {
    "path": "ruby/fail.md",
    "content": "# Fail\n\nThe `fail` method is synonymous with `raise` in Ruby. Consider the following\ncode snippet:\n\n```ruby\ndef is_odd?(num)\n  num.odd?\nrescue\n  fail StandardError, 'you cannot use odd on this'\nend\n\n> is_odd?(1)\n#=> true\n> is_odd?('hello')\n#=> StandardError: you cannot use odd on this\n```\n\nNevertheless, I believe the `raise` method is preferred to the `fail`\nmethod.\n\n[source](http://ruby-doc.org/core-2.3.0/Kernel.html#method-i-fail)\n\nh/t Dorian Karter\n"
  },
  {
    "path": "ruby/fetch-warns-about-superseding-block-argument.md",
    "content": "# Fetch Warns About Superseding Block Argument\n\n[Ruby's `#fetch`](https://ruby-doc.org/core-2.5.1/Hash.html#method-i-fetch) can\nbe used in a couple ways beyond just grabbing the value out of a hash.\n\nIf you include a second argument in the `#fetch` call, that will be treated as\na default value to fallback to when the first argument key doesn't appear in\nthe hash.\n\nIf you instead specify a block argument, that block will be executed when the\nkey is missing.\n\nWhat happens when you specify both a second argument and a block argument?\n\n```ruby\ndata = { taco: 'bell' }\n\ndata.fetch(:burrito, 'house') do\n  puts 'the block gets executed'\n  'shack'\nend\n\nwarning: block supersedes default value argument\nthe block gets executed\n=> 'shack'\n```\n\nThe block argument wins. The second argument is ignored. And Ruby warns you\nthat, \"block supersedes default value argument\".\n"
  },
  {
    "path": "ruby/filter-by-type.md",
    "content": "# Filter By Type\n\nIn Ruby, we have several ways to check if something is a certain type (class or\nsubclass). A couple common approaches you might see are `#is_a?` and `===`\n(case equality operator):\n\n```ruby\n> 3.is_a?(Integer)\n=> true\n> Integer === 3\n=> true\n> 3 === Integer\n=> false\n```\n\nNotice it is important to get the ordering of class and value right when using\n`===`.\n\nWe can use these concepts to filter collections down to just those values of a\ncertain type. We can also ditch those methods and instead use\n[`#grep`](https://ruby-doc.org/3.4.1/Enumerable.html#method-i-grep) to pattern\nmatch on the type directly.\n\n```ruby\n> nums = [1, :two, 3.0, 'four', 5, -> { 6 }, 0.7]\n=> [1, :two, 3.0, \"four\", 5, #<Proc:0x0000000123af0338 (irb):5 (lambda)>, 0.7]\n> nums.filter { it.is_a?(Numeric) }\n=> [1, 3.0, 5, 0.7]\n> nums.filter { Integer === it }\n=> [1, 5]\n> nums.grep(Integer)\n=> [1, 5]\n> nums.grep(Numeric)\n=> [1, 3.0, 5, 0.7]\n```\n\n[source](https://bsky.app/profile/lucianghinda.com/post/3mhi5xp3xhk25)\n"
  },
  {
    "path": "ruby/find-the-min-and-max-with-a-single-call.md",
    "content": "# Find The Min And Max With A Single Call\n\nRuby's Enumerable comes with the `#min` and `#max` methods for finding,\nrespectively, the minimum and maximum value in the target collection.\n\nIf you wanted to find both the min and the max of the same collection, you\ncould call them one after another.\n\n```ruby\nlist = [3,7,4,15,9,1,2]\n\nlist.min\n#=> 1\nlist.max\n#=> 15\n```\n\nRuby's Enumerable also supports a slightly more efficient way -- it finds both\nat the same time when you call\n[`#minmax`](https://apidock.com/ruby/Enumerable/minmax).\n\n```ruby\nlist = [3,7,4,15,9,1,2]\n#=> [1,15]\n```\n"
  },
  {
    "path": "ruby/finding-the-source-of-ruby-methods.md",
    "content": "# Finding The Source of Ruby Methods\n\nRuby's [`Method`](http://ruby-doc.org/core-1.9.3/Method.html) class\nincludes a feature that can help you quickly find the location of\nsource code files where a particular method is defined. The method is aptly\nnamed [`source_location`](http://ruby-doc.org/core-1.9.3/Method.html#method-i-source_location).\n\nWhen debugging a project that is using the\n[Treat](https://github.com/louismullie/treat) gem, you can take a source dive\nby first finding the relevant source files. For instance, if you want to look\ninto the word creation functionality, you might go through an exploratory\nprocess like the following:\n\n```ruby\n> require 'Treat'\n=> true\n> Treat::Entities::Word.build('stuff')\n=> Word (70331843958460)  --- \"stuff\"  ---  {}   --- []\n> Treat::Entities::Word.method(:build)\n=> #<Method: Class(Treat::Entities::Entity::Buildable)#build>\n> Treat::Entities::Word.method(:build).source_location\n=> [\"/Users/jbranchaud/.gem/ruby/2.1.4/gems/treat-2.1.0/lib/treat/entities/entity/buildable.rb\", 29]\n```\n\nYou can now take a closer look at the implementation of the `build` method.\n\nThe main caveat to this process is that it can only find source locations\nfor methods defined in ruby land. Calling `source_location` on any method\ndefined in C code will result in `nil`.\n"
  },
  {
    "path": "ruby/format-a-hash-into-a-string-template.md",
    "content": "# Format A Hash Into A String Template\n\nThe `%` method as defined by `String`\n([`String#%`](https://ruby-doc.org/core-3.0.0/String.html#method-i-25)) allows\nyou to format (interpolate) an object or array of values into a string. That\nstring needs to contain template markers for where the values should go.\n\nHere is an example of folding an array of values into a string with [`%s`\nformat\nspecifier](https://docs.ruby-lang.org/en/master/format_specifications_rdoc.html#label-Specifier+s):\n\n```ruby\n> User = Struct.new(:id)\n=> User\n> user1 = User.new(123)\n=> #<struct User id=123>\n> \"%s ID: %s\" % [user1.class.to_s, user1.id]\n=> \"User ID: 123\"\n```\n\nOr perhaps more usefully for a string that acts as a template, you can used\nnamed specifiers that correspond to hash keys:\n\n```ruby\n> template = \"You paid %{formatted_price} for %{product}. Enjoy your purchase!\"\n=> \"You paid %{formatted_price} for %{product}. Enjoy your purchase!\"\n\n> data = { product: \"Ruby Explained™\", formatted_price: \"$38.99\" }\n=> {:product=>\"Ruby Explained™\", :formatted_price=>\"$38.99\"}\n\n> template % data\n=> \"You paid $38.99 for Ruby Explained™. Enjoy your purchase!\"\n```\n\n[source](https://hashrocket.com/blog/posts/using-a-hash-of-data-for-string-replacement-in-ruby)\n"
  },
  {
    "path": "ruby/forward-all-arguments-to-another-method.md",
    "content": "# Forward All Arguments To Another Method\n\nThere are three types of arguments that a Ruby method can receive. Positional\narguments, keyword arguments, and a block argument.\n\nA method that deals with all three might be defined like this:\n\n```ruby\ndef forwarding_method(*args, **kwargs, &block)\n  # implementation\nend\n```\n\nNow lets say we have some concrete method that we want to forward these\narguments to:\n\n```ruby\ndef concrete_method(*args, **kwargs)\n  x = args.first || 1\n  key, y = kwargs.first || [:a, 2]\n\n  puts \"Dealing with #{x} and key #{key}: #{y}\"\n\n  yield(x, y)\nend\n```\n\nWe could forward arguments the longhand way like this:\n\n```ruby\ndef forwarding_method(*args, **kwargs, &block)\n  concrete_method(*args, **kwargs, &block)\nend\n```\n\nHowever, since Ruby 2.7 we have access to a shorthand \"triple-dot\" syntax for\nforwarding all arguments.\n\n```ruby\ndef forwarding_method(...)\n  concrete_method(...)\nend\n```\n\n[source](https://ruby-doc.org/3.3.6/syntax/methods_rdoc.html#label-Argument+Forwarding)\n"
  },
  {
    "path": "ruby/gather-positional-arguments-in-method-definition.md",
    "content": "# Gather Positional Arguments In Method Definition\n\nThe `*` symbol can be used in Ruby in a method definition to gather up an\narbitrary number of positional arguments.\n\nFor instance, we can gather all positional arguments with this method\ndefinition:\n\n```ruby\ndef gather_all(*args)\n  puts args\nend\n```\n\nOr we can isolate the first positional arg and then gather the rest:\n\n```ruby\ndef first_and_rest(first, *rest)\n  puts \"First: #{first}, Rest: #{rest}\"\nend\n```\n\nWe can even do something a bit more interesting like isolating the first and\nlast arguments while gathering up everything else in the middle:\n\n```ruby\ndef pop_parens(left, *middle, right)\n  if left != '(' || right != ')'\n    raise \"Uh oh!\"\n  else\n    if middle.size == 1\n      puts \"Found: #{middle.first}\"\n    else\n      pop_parens(*middle)\n    end\n  end\nend\n```\n\nHere is what it looks like if we splat some different sets of arguments into\nthat method call:\n\n```ruby\n> tokens1 = \"((((4))))\".split('')\n=> [\"(\", \"(\", \"(\", \"(\", \"4\", \")\", \")\", \")\", \")\"]\n> tokens2 = \"((4))))\".split('')\n=> [\"(\", \"(\", \"4\", \")\", \")\", \")\", \")\"]\n> pop_parens(*tokens1)\nFound: 4\n=> nil\n> pop_parens(*tokens2)\n(irb):87:in `pop_parens': Uh oh! (RuntimeError)\n```\n\n[source](https://ruby-doc.org/3.3.6/syntax/methods_rdoc.html#label-Array-2FHash+Argument)\n"
  },
  {
    "path": "ruby/generate-a-signed-jwt-token.md",
    "content": "# Generate A Signed JWT Token\n\nThe [`jwt`](https://github.com/jwt/ruby-jwt) gem is a Ruby library for\nencoding and decoding JWT tokens. You can create a signed JWT with the\n`#encode` method by specifying a secret and a hash algorithm.\n\n```ruby\npayload = { id: 1, email: 'user@example.com' }\nsecret = Rails.application.credentials.secret_key_base\n\ntoken = JWT.encode(payload, secret, 'HS256')\n```\n\nThis will create a JWT token that contains some JWT headers, application\ndata, and an encrypted secret that signs the data. This can be passed to and\nfrom your client app as a way of identifying and authenticating a user.\n\nSee the [`jwt-ruby` docs](https://github.com/jwt/ruby-jwt) or\n[jwt.io](https://jwt.io/) for more details.\n"
  },
  {
    "path": "ruby/generate-ruby-version-and-gemset-files-with-rvm.md",
    "content": "# Generate Ruby Version And Gemset Files With RVM\n\n[RVM](https://rvm.io), the ruby version manager, is a fairly flexible tool\nthat supports a number of workflows. The `rvm` utility can be used to\ngenerate both a `.ruby-version` file and a `.ruby-gemset` file for a given\nproject.\n\n```bash\n$ rvm --ruby-version use 2.5.3@my_project\n```\n\nThis will generate a `.ruby-version` file in your current project directory\nthat points RVM to the `2.5.3` version of Ruby. It will also create a\n`.ruby-gemset` file that RVM will use for managing this project's gemset.\n"
  },
  {
    "path": "ruby/get-info-about-your-ruby-gems-environment.md",
    "content": "# Get Info About Your Ruby Gems Environment\n\nWant to know what Ruby version is being used? Or into what directory gems are\nbeing installed?\n\n```bash\n$ gem environment\n```\n\nThis command will answer those questions and give you a whole host of other\ninformation about your RubyGems environment.\n\nThere are more details in their\n[documentation](https://guides.rubygems.org/command-reference/#gem-environment).\n"
  },
  {
    "path": "ruby/get-specific-values-from-hashes-and-arrays.md",
    "content": "# Get Specific Values From Hashes And Arrays\n\nRuby defines a `#values_at` method on both `Hash` and `Array` that can be used\nto grab multiple values from an instance of either of those structures.\n\nHere is an example of grabbing values by key (if they exist) from a hash.\n\n```ruby\n> hash = {one: :two, hello: \"world\", four: 4}\n=> {one: :two, hello: \"world\", four: 4}\n> hash.values_at(:one, :four, :three)\n=> [:two, 4, nil]\n```\n\nAnd here is an example of grabbing values at specific indexes from an array, if\nthose indexes exist.\n\n```ruby\n> arr = [:a, :b, :c, :d, :e]\n=> [:a, :b, :c, :d, :e]\n> arr.values_at(0, 3, 6)\n=> [:a, :d, nil]\n```\n\nNotice that in both cases, `nil` is returned for a key or index that doesn't\nexist.\n\nWhat I like about this method is that in a single call I can grab multiple\nnamed (or indexed) values and get a single array result with those values.\n\nOne way I might use this with a JSON response from an API request could look\nlike this:\n\n```ruby\nresp = client.getSomeData(id: 123)\n\n[status, body] = resp.values_at(\"status\", \"body\")\n\nif status == 200\n  puts body\nend\n```\n\n[source](https://docs.ruby-lang.org/en/3.4/Hash.html#method-i-values_at)\n"
  },
  {
    "path": "ruby/get-the-names-of-the-month.md",
    "content": "# Get The Names Of The Month\n\nRuby's `Date` object has a `MONTHNAMES` constant that returns an array of names\nof the month. You'd think that means the array contains 12 items. However, the\nsize of that array is 13.\n\n```ruby\n> Date::MONTHNAMES\n=> [nil, \"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"]\n```\n\nNotice it has all 12 months, plus an initial value of `nil`.\n\nThis is because it allows us to more intuitive access a month by it's index\nwithout having to do a little subtraction. If I want to know what the 9th month\nis, I can do an array access for `9`.\n\n```ruby\n> Date::MONTHNAMES[9]\n=> \"September\"\n```\n\nBecause arrays in Ruby use 0-based indexing, without this baked in `nil` value,\nyou'd instead get `\"October\"` when passing in `9`.\n"
  },
  {
    "path": "ruby/get-the-output-of-running-a-system-program.md",
    "content": "# Get The Output Of Running A System Program\n\nRuby has a [variety of ways](https://stackoverflow.com/a/18623297/535590) to\nexecute a system program within a Ruby process. The backticks approach is the\nhandy shorthand approach to reach for if you want to capture the output of the\ncommand.\n\nFor instance, let's say I want to capture the connection string credentials\noutput by running a `heroku` command. When the command is wrapped in backticks,\nRuby will execute it in a subprocess and the output of the command will be the\nreturn value.\n\n```ruby\nresult = `heroku pg:credentials:url DATABASE_URL --app my-app`\n\n# extract connection details\nconnection_info = result.split(\"\\n\")[2].strip\n```\n\nWith the result in hand, I can use Ruby to parse out the details I'm interested\nin.\n\nBackticks does two other nice things. It allows for string interpolation and it\nputs the process status (e.g. exit code) on\n[`$?`](check-return-status-of-running-a-shell-command.md).\n"
  },
  {
    "path": "ruby/get-utc-offset-for-different-time-zones.md",
    "content": "# Get UTC Offset For Different Time Zones\n\nThe [IANA Time Zone Database](https://www.iana.org/time-zones) uses identifiers\nlike `America/Chicago`, `Asia/Hong_Kong`, `Africa/Nairobi`, etc. as specifiers\nfor notable locations with time zone information.\n\n> Most timezones correspond to a notable location and the database records all\n> known clock transitions for that location; some timezones correspond instead\n> to a fixed UTC offset.\n—[Theory and pragmatics of the tz code and data](https://data.iana.org/time-zones/theory.html)\n\nThese identifiers can be used to look up time zone details with the [`tzinfo`\ngem](https://github.com/tzinfo/tzinfo).\n\nHere is an example of passing one to the `#get` method and then getting the UTC\noffset in seconds.\n\n```ruby\n> require 'tzinfo'\n\n> mountain = TZInfo::Timezone.get('America/Denver')\n=> #<TZInfo::DataTimezone: America/Denver>\n> mountain.utc_offset\n=> -21600\n```\n\nWe can even get the base UTC offset that doesn't account for DST:\n\n```ruby\n> moutain.base_utc_offset\n=> -25200\n```\n\nNotice, this is the same as the standard offset for a time zone like Phoenix\nthat doesn't observe DST.\n\n```ruby\n> phoenix = TZInfo::Timezone.get('America/Phoenix')\n=> #<TZInfo::DataTimezone: America/Phoenix>\n> phoenix.utc_offset\n=> -25200\n```\n"
  },
  {
    "path": "ruby/identify-outdated-gems.md",
    "content": "# Identify Outdated Gems\n\nBundler can be used to identify outdated gems for a given project. By\nrunning `bundle outdated` in a project's directory, Bundler will compare the\nversions of all stated gem dependencies against the gem server and report a\nlist of those gems that are not up to date.\n\nSee the [Bundler docs](http://bundler.io/v1.1/bundle_outdated.html) for more\ndetails.\n"
  },
  {
    "path": "ruby/if-you-detect-none.md",
    "content": "# If You Detect None\n\nThe\n[`Enumerable#detect`](http://ruby-doc.org/core-2.2.3/Enumerable.html#method-i-detect)\nmethod, which is synonymous with `#find`, can be given an optional argument,\n`ifnone`, that is called when nothing in the array meets the conditional in\nthe block. Though I am not sure how this is practically useful and cannot\nfind an example of it in use, this contrived example illustrates how it\nworks.\n\n```ruby\n# without the fallback behavior\n> [2,4,6,8].detect { |x| x.odd? }\n=> nil\n\n# with a proc as an argument\n> [2,4,6,8].detect(->{0}) { |x| x.odd? }\n=> 0\n```\n\nThe last example can also be written as:\n\n```ruby\n> [2,4,6,8].detect(->{0}, &:odd?)\n=> 0\n```\n\nAnd if you want to be really explicit:\n\n```ruby\n> [2,4,6,8].detect(ifnone=->{0}, &:odd?)\n=> 0\n```\n"
  },
  {
    "path": "ruby/include-extra-context-in-a-honeybadger-notify.md",
    "content": "# Include Extra Context In A Honeybadger Notify\n\nThe simplest way to `notify` [Honeybadger](https://www.honeybadger.io/) of an\nerror is to either pass it the exception directly:\n\n```ruby\nrescue SpecializedError => e\n  Honeybadger.notify(e)\nend\n```\n\nOr to give it a custom message:\n\n```ruby\nHoneybadger.notify(\"The user #{user.id} was unable to access their account.\")\n```\n\nHoneybadger collects a lot of additional context about the report based on\nwhere it is called. More context is usually better though. You can pass\nadditional, specific context with the `context` keyword argument.\n\n```ruby\nmessage = \"The user was unable to access their account.\"\nHoneybadger.notify(\n  message,\n  context: { user_id: user.id, query: params[:query] }\n)\n```\n\nInclude whatever else you might want to know and those values will show up in\nthe Honeybadger web interface.\n\n[source](https://docs.honeybadger.io/lib/ruby/getting-started/reporting-errors/)\n"
  },
  {
    "path": "ruby/ins-and-outs-of-pry.md",
    "content": "# Ins And Outs Of Pry\n\nWhen executing commands during a [Pry](http://pryrepl.org/) session, you'll\nsee an incrementing number for each prompt as you enter each statement.\nThese numbers can be used to look up the inputs and outputs of each\nstatement executed during the session. The statements and their results are\nmade available in the array-like `_in_` and `_out_` objects.\n\n```ruby\n[1] pry(main)> :one\n=> :one\n[2] pry(main)> 1 + 1\n=> 2\n[3] pry(main)> [\"t\", \"h\", \"r\", \"e\", \"e\"].join\n=> \"three\"\n[4] pry(main)> _in_.to_a\n=> [nil, \":one\\n\", \"1 + 1\\n\", \"[\\\"t\\\", \\\"h\\\", \\\"r\\\", \\\"e\\\", \\\"e\\\"].join\\n\"]\n[5] pry(main)> _out_.to_a\n=> [nil, :one, 2, \"three\", [nil, \":one\\n\", \"1 + 1\\n\", \"[\\\"t\\\", \\\"h\\\", \\\"r\\\", \\\"e\\\", \\\"e\\\"].join\\n\"]]\n[6] pry(main)> _out_[2]\n=> 2\n[7] pry(main)> _in_[2]\n=> \"1 + 1\\n\"\n```\n\n[source](https://github.com/pry/pry/wiki/Special-Locals#In_and_out)\n"
  },
  {
    "path": "ruby/install-and-require-gems-inline-without-gemfile.md",
    "content": "# Install And Require Gems Inline Without Gemfile\n\n[Bundler](https://bundler.io/) has an _inline_ feature where you can declare\ngems that should be installed and required for the current file without the use\nof a `Gemfile`. This is useful for creating a single-file Ruby script that can\ndefine its own dependencies.\n\nRequire `\"bundler/inline\"` and then add a `gemfile` block toward the top of the\nscript to specify the source and any gems.\n\n```ruby\nrequire \"bundler/inline\"\n\ngemfile do\n  source \"https://rubygems.org\"\n  gem \"httparty\"\nend\n```\n\nWhen the script gets run (e.g. `ruby script.rb`), it will install the gems (if\nthey haven't already been installed) and then run the script. You can specify\nversion constraints just like you'd do in a `Gemfile`.\n\nHere is a single-file script using this approach that I wrote to interact with\nthe Kit API.\n\n```ruby\n#!/usr/bin/env ruby\nrequire \"bundler/inline\"\n\ngemfile do\n  source \"https://rubygems.org\"\n  gem \"httparty\"\nend\n\nrequire \"json\"\nrequire_relative \"kit_client\"\n\nAPI_SECRET = ENV[\"KIT_API_SECRET\"]\n\ndef fetch_all_tags(api_secret)\n  client = KitClient.new(\"https://api.kit.com/v4\", api_secret)\n\n  tags = []\n  after_cursor = nil\n\n  loop do\n    params = {per_page: 1000}\n    params[:after] = after_cursor if after_cursor\n\n    response = client.get(\"/tags\", params)\n\n    data = JSON.parse(response.body)\n    tags.concat(data[\"tags\"])\n\n    break unless data[\"pagination\"][\"has_next_page\"]\n    after_cursor = data[\"pagination\"][\"end_cursor\"]\n  end\n\n  tags\nend\n\ntags = fetch_all_tags(API_SECRET)\n\ntags.each do |tag|\n  puts tag\nend\n```\n\nBecause I've specified the shebang at the top of the file (and assuming I've\n`chmod +x fetch_tags.rb`), I can run this directly as a script with\n`./fetch_tags.rb`.\n\n[source](https://bundler.io/guides/bundler_in_a_single_file_ruby_script.html)\n"
  },
  {
    "path": "ruby/install-latest-version-of-ruby-with-asdf.md",
    "content": "# Install Latest Version Of Ruby With asdf\n\nWhen I check the `asdf` Ruby plugin for known versions of Ruby:\n\n```bash\n$ asdf list-all ruby | fzf\n```\n\nI don't find the latest (`3.4`).\n\nI need to update the plugin. A newer version of the plugin will know about\nnewer Ruby versions.\n\n```bash\n$ asdf plugin-update ruby\n```\n\nNow, if I run the `list-all` command again, I'll find the version I'm looking\nfor — `3.4.1`.\n\nNow that `asdf` and I both know about the version to be installed, I can tell\n`asdf` to install it:\n\n```bash\n$ asdf install ruby 3.4.1\n```\n\nNow, if I check the current Ruby version, I'll see that it is still set to some\nother version.\n\n```bash\n$ ruby --version\nruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-darwin22]\n```\n\nI need to tell `asdf` to start using this newly installed version instead,\neither globally or locally.\n\n```bash\n$ # globally\n$ asdf global ruby 3.4.1\n$ # or locally\n$ asdf local ruby 3.4.1\n```\n\nAnd now I'm all set:\n\n```bash\n$ asdf current ruby\nruby            3.4.1           /Users/jbranchaud/.tool-versions\n\n$ ruby --version\nruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-darwin22]\n```\n"
  },
  {
    "path": "ruby/invoking-rake-tasks-multiple-times.md",
    "content": "# Invoking Rake Tasks Multiple Times\n\nI have a rake task, `build`, that builds a single record for development\npurposes. I want a supplemental rake task, `build:all`, that builds a bunch\nof different records. To keep things dry, `build:all` should just invoke\n`build` a number of times.\n\n```ruby\nnamespace :build do\n  task :all do\n    predefined_list.each do |data|\n      Rake::Task[\"build\"].invoke(data)\n    end\n  end\nend\n```\n\nThis doesn't work though. No matter how many items are in the list, the\n`build` task only seems to get run once. This is because by default tasks\ncan only be invoked once in a given context. To get around this, the task\nneeds to be _reenabled_ after each invocation.\n\n```ruby\nnamespace :build do\n  task :all do\n    predefined_list.each do |data|\n      Rake::Task[\"build\"].invoke(data)\n      Rake::Task[\"build\"].reenable\n    end\n  end\nend\n```\n"
  },
  {
    "path": "ruby/irb-has-built-in-benchmarking-with-ruby-3.md",
    "content": "# IRB Has Built-In Benchmarking With Ruby 3\n\nAs of Ruby 3.0.0, `irb`—Ruby's interactive console—comes with a `measure`\nmethod. This can be used to turn the processing time feature on and off. With\nit on, you can do rough benchmarking of how long different process take.\n\nRuby `measure` or `measure(true)` to turn on the timing feature.\n\n```ruby\n> measure\nTIME is added.\n=> nil\n```\n\nOnce it is enabled, any command you run will including processing time details:\n\n```ruby\n> array = [1,2,3,4]\nprocessing time: 0.000033s\n=> [1, 2, 3, 4]\n> array.zip(array).map { |a,b| a * b ** (a * b) }\nprocessing time: 0.000057s\n=> [1, 32, 59049, 17179869184]\n```\n\n[source](https://jemma.dev/blog/irb-measure)\n"
  },
  {
    "path": "ruby/iterate-with-an-offset-index.md",
    "content": "# Iterate With An Offset Index\n\nYou can iterate over a collection of items with the\n[`#each`](https://devdocs.io/ruby~2.5/enumerator#method-i-each) method. If you\nwant to know the index of each item as you go, you can use the\n[`#each_with_index`](https://devdocs.io/ruby~2.5/enumerable#method-i-each_with_index)\nvariant.\n\n```ruby\n> [\"one\", \"two\", \"three\"].each_with_index do |item, index|\n    puts \"#{item} - #{index}\"\n  end\none - 0\ntwo - 1\nthree - 2\n=> [\"one\", \"two\", \"three\"]\n```\n\nThe initial index will always be `0` when using `#each_with_index`.\n\nWhat about if you want the index value to be offset by some number?\n\nYou can use the\n[`#with_index`](https://devdocs.io/ruby~2.5/enumerator#method-i-with_index)\nmethod on an _enumerator_. It optionally takes an `offset` argument.\n\n```ruby\n> [\"one\", \"two\", \"three\"].each.with_index(1) do |item, index|\n    puts \"#{item} - #{index}\"\n  end\none - 1\ntwo - 2\nthree - 3\n=> [\"one\", \"two\", \"three\"]\n```\n"
  },
  {
    "path": "ruby/join-uri-path-parts.md",
    "content": "# Join URI Path Parts\n\nThe\n[`URI.join`](https://ruby-doc.org/stdlib-2.5.1/libdoc/uri/rdoc/URI.html#method-c-join)\nmethod seems like a handy way to combine a base URL with some subpath. However,\nthere are some subtle gotchas depending on where forward slashes appear in the\ntwo arguments.\n\nLet's first look at the, in my opinion, desired behavior:\n\n```ruby\n> URI.join(\"https://example.com/api/v1/\", \"users\")\n=> #<URI::HTTPS https://example.com/api/v1/users>\n```\n\nThe base URL has a trailing slash and the path that I want to join to it has no\nleading slash. The result is a path where `users` is joined to the end of the\nbase URL. That's what I'm looking for.\n\nNow, let's see some variations on the above approach that give results that I\nwasn't expecting and don't want.\n\n```ruby\n> URI.join(\"https://example.com/api/v1\", \"/users\") # 1\n=> #<URI::HTTPS https://example.com/users>\n> URI.join(\"https://example.com/api/v1\", \"users\") # 2\n=> #<URI::HTTPS https://example.com/api/users>\n> URI.join(\"https://example.com/api/v1/\", \"/users\") # 3\n=> #<URI::HTTPS https://example.com/users>\n```\n\n1. No trailing slash on the base URL. Leading slash on the path to join. The\n   path portion of the base URL is wiped out and `/users` is joined in.\n2. No trailing slash on the base URL. No leading slash on the path to join. The\n   `users` path replaces the last part of the path in the base URL.\n3. Both a trailing slash in the base URL and a leading slash in the path to\n   join. Same behavior as 1.\n\nI have two takeaways from this:\n- Use with caution. If I'm going to use `URI.join` for this purpose, I need to\n  be careful to only use the form in the first code block.\n- The `URI.join` method is probably meant to be primarily used to join a domain\n  (e.g. `http://example.com`) that has no path with some path segment.\n"
  },
  {
    "path": "ruby/jump-out-of-a-nested-context-with-throw-catch.md",
    "content": "# Jump Out Of A Nested Context With Throw/Catch\n\nRuby's `throw/catch` construct, not to be confused with its `raise/rescue`\nexception handling syntax, allows you to jump out of a nested context. This is\nsimilar to [loop\nlabels](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label)\nin other languages.\n\nFor example, in my recent [Advent of Code\nsolution](https://www.youtube.com/watch?v=Hvp07gTQhF4), I was able to employ\nthis construct. Once within a doubly-nested loop, I can `throw` when I find the\nanswer I'm looking for to both break out of the loop and return an value.\n\n```ruby\nanswer =\n  catch do |obj|\n    input.each_with_index do |input1, x|\n      input.each_with_index do |input2, y|\n        next unless x != y\n\n        next unless input1 + input2 == 2020\n\n        throw(obj, input1 * input2)\n      end\n    end\n\n    raise StandardError, 'No answer found'\n  end\n\nputs answer\n```\n\nIf I were to never reach the `throw` before exhausting the doubly-nested loop,\nthen the catch would product whatever value is returned within the block. In\nthis case, I raise an error because it'd be exceptional for the `throw` to\nnever be reached.\n\n[source](https://apidock.com/ruby/Kernel/catch)\n"
  },
  {
    "path": "ruby/last-raised-exception-in-the-call-stack.md",
    "content": "# Last Raised Exception In The Call Stack\n\nIn Ruby, the `$!` global variable contains the last exception that was\nraised in the current call stack. This makes it trivial to check what error\nis being rescued even if it hasn't been captured in a local variable.\n\n```ruby\nclass MyError < StandardError; end\n\ndef do_stuff\n  raise MyError\nrescue\n  puts \"rescuing #{$!}\"\nend\n\ndo_stuff\n#=> rescuing MyError\n```\n"
  },
  {
    "path": "ruby/limit-split.md",
    "content": "# Limit Split\n\nI've only ever used Ruby's\n[`String#split`](http://ruby-doc.org//core-2.2.0/String.html#method-i-split)\nwith the delimiter argument (e.g. `\"this string has spaces\".split(\" \")`).\nHowever, this method has another argument you can specify; the `limit`\nargument. With `limit`, you can *limit* the number of times that the split\nhappens.\n\n```ruby\n\"this string has many spaces\".split(\" \")\n# => [\"this\", \"string\", \"has\", \"many\", \"spaces\"]\n\"this string has many spaces\".split(\" \", 3)\n# => [\"this\", \"string\", \"has many spaces\"]\n```\n\nThere are surely many use cases, but one that stands out (from [The Rails 4\nWay](https://leanpub.com/tr4w)) is for splitting a name into *first* and\n*last* names.\n\n```ruby\n\"Josh Branchaud\".split(\" \", 2)\n# => [\"Josh\", \"Branchaud\"]\n\"David Heinemeier Hansson\".split(\" \", 2)\n# => [\"David\", \"Heinemeier Hansson\"]\n```\n\nThis really simplifies the code that is needed to make the following example\nwork:\n\n```ruby\ndef create_user(name)\n  user = User.new\n  user.first_name, user.last_name = name.split(\" \", 2)\n  user.save\nend\n```\n"
  },
  {
    "path": "ruby/list-the-running-ruby-version.md",
    "content": "# List The Running Ruby Version\n\nThe running Ruby version can be listed with the `RUBY_VERSION` constant.\n\nFor instance, if my Ruby version is 3.0.0, then I could get the version like\nso:\n\n```ruby\n> RUBY_VERSION\n=> \"3.0.0\"\n```\n\nThis is nice if you just want to check in an IRB session or if you need it as\npart of a script.\n\n[source](https://blog.arkency.com/which-ruby-version-am-i-using-how-to-check/)\n"
  },
  {
    "path": "ruby/listing-local-variables.md",
    "content": "# Listing Local Variables\n\nIn Ruby 2.2, the `binding` object gives us access to a method\n`#local_variables` which returns the symbol names of the binding's local\nvariables. We can see this in action with\n\n```ruby\ndef square(x)\n  puts binding.local_variables.inspect\n  x.times do |a|\n    puts binding.local_variables.inspect\n  end\n  z = x * x\n  puts binding.local_variables.inspect\n  z\nend\nsquare(2)\n```\n\nwhich results in\n\n```ruby\n[:x, :z]\n[:a, :x, :z]\n[:a, :x, :z]\n[:x, :z]\n=> 4\n```\n\n[source](http://ruby-doc.org/core-2.2.0/Binding.html#method-i-local_variables)\n"
  },
  {
    "path": "ruby/load-a-module-and-execute-a-statement.md",
    "content": "# Load A Module And Execute A Statement\n\nHere is a nice one-liner pattern for use with the `ruby` executable.\n\n```bash\n$ ruby -r file.rb -e 'MyClass.do_something'\n```\n\nThe `-r` flag loads (requires, really) a Ruby file at the specified path. The\n`-e` flag will execute the line of Ruby code that you give it, in that context.\nIn combination that means I can load some module into the execution environment\nand then I can run some code that uses that module.\n\nA more practical example of that is how I demonstrated the behavior of a\n`MarkdownHelpers` module in [Create A Module Of Utility\nFunctions](create-a-module-of-utility-functions.md).\n\n```bash\n$ ruby -r ./markdown_helpers.rb -e 'puts MarkdownHelpers.link(\"Click here\", \"https://example.com\")'\n[Click here](https://example.com)\n```\n\nThe `MarkdownHelpers` module that I've defined in `./markdown_helpers.rb` is\nloaded into context and I can now access and execute that module to try out\nparts of it. All in a single line in the terminal.\n"
  },
  {
    "path": "ruby/make-a-long-string-of-text-readable.md",
    "content": "# Make A Long String Of Text Readable\n\nI have a paragraph of text that interpolates a couple user-specific values\nbefore being included in an API request. Because it is being passed to an API,\nit is a single-line string value. However, in the editor it is hard to read like\nthat because it overflows way past the edge of the viewport.\n\n```ruby\ndescription = \"This is the description we need to provide for #{user.name} as part of an API request dealing with compliance and registration for a service. If you need to contact them, their email is #{user.email}.\"\n```\n\nI'd rather make this easier on myself and others to read from the editor while\nstill being able to submit a single-line string to the API. That can be\naccomplished with a heredoc and some combination or `gsub`, `strip`, and\n`squish`.\n\nIf we are in a strictly Ruby-only context, we can use `gsub` and `strip` to\ncollapse line breaks and remove surrounding white space.\n\n```ruby\ndescription = <<~MSG.gsub(/\\s+/, ' ').strip\n  This is the description we need to provide for #{user.name} as part\n  of an API request dealing with compliance and registration for a\n  service. If you need to contact them, their email is #{user.email}.\nMSG\n#=> \"This is the description we need to provide for #{user.name} as part of an API request dealing with compliance and registration for a service. If you need to contact them, their email is #{user.email}.\"\n```\n\nOr in a Rails context, I can instead just use `squish`:\n\n```ruby\ndescription = <<~MSG.squish\n  This is the description we need to provide for #{user.name} as part\n  of an API request dealing with compliance and registration for a\n  service. If you need to contact them, their email is #{user.email}.\nMSG\n#=> \"This is the description we need to provide for #{user.name} as part of an API request dealing with compliance and registration for a service. If you need to contact them, their email is #{user.email}.\"\n```\n"
  },
  {
    "path": "ruby/make-an-executable-ruby-script.md",
    "content": "# Make An Executable Ruby Script\n\nIn a unix environment with Ruby available, I can make a Ruby script. To do this\nI stick some code in a Ruby file, like `database_url.rb`.\n\n```ruby\nresult = `heroku pg:credentials:url DATABASE_URL --app my-app`\nputs result.split(\"\\n\")[2].strip\n```\n\nAnd then execute that file with `ruby`:\n\n```bash\n$ ruby database_url.rb\n```\n\nI can instead make an executable file that doesn't need to be explicitly\ninvoked with the `ruby` command. To do this, I need to prefix my file with a\n[shebang](https://unix.stackexchange.com/a/87600/5916) for\n[`ruby`](https://devcenter.heroku.com/articles/ruby-binstub-shebang).\n\nAnd I'll even just call the file `database_url` now, no file suffix.\n\n```ruby\n#!/usr/bin/env ruby\n\nresult = `heroku pg:credentials:url DATABASE_URL --app my-app`\nputs result.split(\"\\n\")[2].strip\n```\n\nWhen executed, this script will see the first line and understand that it needs\nto execute the rest of the script using `ruby` as the interpreter.\n\nLike any other executable, you can call it as is, like so:\n\n```ruby\n$ database_url\n```\n"
  },
  {
    "path": "ruby/make-structs-easier-to-use-with-keyword-initialization.md",
    "content": "# Make Structs Easier To Use With Keyword Initialization\n\nTypically a [`Struct`](https://ruby-doc.org/3.4.1/Struct.html#method-c-new) in\nRuby is defined and initialized like so:\n\n```ruby\n> Subscriber = Struct.new(:email, :first_name, :status, :tags)\n=> Subscriber\n> s1 = Subscriber.new('bob.burgers@example.com', 'Bob', :active, [:food, :family])\n=> #<struct Subscriber email=\"bob.burgers@example.com\", first_name=\"Bob\", status=:active, tags=[:food, :family]>\n> s1.email\n=> \"bob.burgers@example.com\"\n```\n\nThat's a nice way to structure light-weight objects.\n\nA potential challenge with multi-argument `Struct` definitions like this,\nespecially when they aren't colocated with initialization, is that it can be\nhard to remember or distinguish the argument order when initializing an instance\nof one.\n\nRuby 2.5 added the `keyword_init` option to help with this exact issue. When\nthat option is set to `true` for a `Struct` definition, then we get to\ninitialize it with keyword arguments rather than positional arguments.\n\n```ruby\n> Subscriber = Struct.new(:email, :first_name, :status, :tags, keyword_init: true)\n=> Subscriber(keyword_init: true)\n* s1 = Subscriber.new(\n*   first_name: 'Bob',\n*   email: 'bob.burgers@example.com',\n*   tags: [:food, :family],\n*   status: :active\n> )\n=> #<struct Subscriber email=\"bob.burgers@example.com\", first_name=\"Bob\", status=:active, tags=[:food, :family]>\n> s1.email\n=> \"bob.burgers@example.com\"\n```\n\nNotice I have to use keyword arguments now and that because of that I can\norganize them in whatever order makes sense. Coming back to view this line of\ncode later, it is easy to see attribute each value corresponds to.\n\n[source](https://www.bigbinary.com/blog/ruby-2-5-allows-creating-structs-with-keyword-arguments)\n"
  },
  {
    "path": "ruby/map-with-index-over-an-array.md",
    "content": "# Map With Index Over An Array\n\nThe [`#map`](https://devdocs.io/ruby~2.5/enumerable#method-i-map) method on its\nown allows you to interact with each item of an array, producing a new array.\n\n```ruby\n[1,2,3].map { |item| item * item }\n#=> [1,4,9]\n```\n\nIf you also want access to the index of the item, you'll need some help from\nother enumerable methods. As of Ruby 1.9.3, you can chain on\n[`#with_index`](https://devdocs.io/ruby~2.5/enumerator#method-i-with_index):\n\n```ruby\n[1,2,3].map.with_index { |item, index| item * index }\n#=> [0,2,6]\n```\n\nThis method has the added benefit of allowing you to specify the starting value\nof the index. It normally starts with `0`, but you could just as easily start\nat `1`:\n\n```ruby\n[1,2,3].map.with_index(1) { |item, index| item * index }\n#=> [1,4,9]\n```\n\n[source](https://stackoverflow.com/a/11280903/535590)\n"
  },
  {
    "path": "ruby/mock-method-chain-calls-with-rspec.md",
    "content": "# Mock Method Chain Calls With RSpec\n\nGenerally with RSpec you mock one method call at a time:\n\n```ruby\nallow(User).to receive(:new).and_return(true)\n```\n\nSometimes you are dealing with code that involves a chain of method calls.\n\n```ruby\nUser\n  .new\n  .approve\n  .send_welcome_email\n```\n\nIf it becomes unreasonable to mock out each individual method, you can instead\nmock out the chain of calls.\n\n```ruby\nallow(User).to receive_message_chain('new.approve.send_welcome_email')\n```\n\nAlternatively, you can write this as:\n\n```ruby\nallow(User).to receive_message_chain(:new, :approve, :send_welcome_email)\n```\n\n[source](https://relishapp.com/rspec/rspec-mocks/docs/working-with-legacy-code/message-chains)\n"
  },
  {
    "path": "ruby/mocking-requests-with-partial-uris-using-regex.md",
    "content": "# Mocking Requests With Partial URIs Using Regex\n\nGenerally when mocking out requests with the\n[webmock](https://github.com/bblimke/webmock) gem, we specify full request\nURIs like so:\n\n```ruby\nstub_request(:post, 'http://localhost:4000/api/posts')\n```\n\nWe may not want to specify the entire URI though. For instance, the host may\nchange or be configurable. The `stub_request` method allows us to use regex.\n\n```ruby\nstub_request(:post, %r|/api/posts|)\n```\n\nUsing [the `%r` regex literal\nsyntax](https://ruby-doc.org/core-2.2.0/Regexp.html), we are able to avoid\nescaping all of the `/` characters in our URI.\n\nh/t Brian Dunn\n"
  },
  {
    "path": "ruby/multi-line-comments.md",
    "content": "# Multi-Line Comments\n\nRuby has an obscure syntax for creating multi-line comments.\n\nIn many languages, there is a multi-line comment syntax that looks something\nlike this:\n\n```javascript\n/*\n * multi-line comment in javascript\n */\n```\n\nThis gets used often in those languages.\n\nIn Ruby, the multi-line comment syntax is not something we see very often. It\nis a departure from the single-line comment syntax and it also requires no\nindentation.\n\n```ruby\nRSpec.configure do |config|\n  config.order = :random\n\n# The settings below are suggested to provide a good initial experience\n# with RSpec, but feel free to customize to your heart's content.\n=begin\n  # These two settings work together to allow you to limit a spec run\n  # to individual examples or groups you care about by tagging them with\n  # `:focus` metadata. When nothing is tagged with `:focus`, all examples\n  # get run.\n  config.filter_run :focus\n  config.run_all_when_everything_filtered = true\n\n  # ...\n\n=end\nend\n```\n\nUsing the `=begin` and `=end` syntax (no indentation), we make everything\ninbetween into a comment.\n\nThough we don't see this too often, I did pull this example directly from the\n`spec_helper.rb` file that RSpec generates.\n\n[source](https://docs.ruby-lang.org/en/master/syntax/comments_rdoc.html)\n"
  },
  {
    "path": "ruby/named-regex-captures-are-assigned-to-variables.md",
    "content": "# Named Regex Captures Are Assigned To Variables\n\nBoth `String` and `Regexp` include the `=~` operator as a way of checking if a\nstring and a regex match.\n\nWhen the `Regexp` version of\n[`=~`](https://ruby-doc.org/core-2.5.1/Regexp.html#method-i-3D~) with named\ncapture groups, those named captures will be auto-assigned as local variables.\n\nHere is a regex that includes a named capture: `(?<id>\\d+)`. The parentheses\ndefine the capture area and the `?<id>` specifies that whatever follows in the\ncapture will be named `id`.\n\n```\n/Tile: (?<id>\\d+)/ =~ 'Tile: 1234'\n#=> 0\nid\n=> \"1234\"\n```\n\nAfter the match operator (`=~`) runs in the first line, the local variable `id`\ngets assigned to whatever it matches in the corresponding string.\n\n[source](https://ruby-doc.org/core-2.5.1/Regexp.html#class-Regexp-label-Capturing)\n"
  },
  {
    "path": "ruby/navigate-back-in-the-browser-with-capybara.md",
    "content": "# Navigate Back In The Browser With Capybara\n\nThere are two ways to navigate back to a previous page. Capybara is driving\nthe browser and it can be instructed to go back using its built-in command\nor by executing some JavaScript.\n\n```ruby\npage.go_back\n```\n\nor\n\n```ruby\npage.evaluate_script('window.history.back()')\n```\n"
  },
  {
    "path": "ruby/next-and-previous-floats.md",
    "content": "# Next And Previous Floats\n\nThe `Float` class has two interesting methods for stepping forward or\nbackwards through the numbers that can actually be *represented* by floats.\nThis is handy since floats are not evenly spaced.\n\nUse `#next_float` to go forward\n\n```ruby\n> 2.0\n=> 2.0\n> _.next_float\n=> 2.0000000000000004\n> _.next_float\n=> 2.000000000000001\n> _.next_float\n=> 2.0000000000000013\n> _.next_float\n=> 2.0000000000000018\n```\n\nUse `#prev_float` to go backwards\n\n```ruby\n> 2.0\n=> 2.0\n> _.prev_float\n=> 1.9999999999999998\n> _.prev_float\n=> 1.9999999999999996\n> _.prev_float\n=> 1.9999999999999993\n> _.prev_float\n=> 1.9999999999999991\n```\n\nI cannot think of any practical use cases, but it is fun to know they are\nthere if you need them.\n"
  },
  {
    "path": "ruby/open-struct-has-bad-performance-characteristics.md",
    "content": "# OpenStruct Has Bad Performance Characteristics\n\nThe Ruby docs for `OpenStruct` have a [_Caveats_\nsection](https://ruby-doc.org/3.4.1/stdlibs/ostruct/OpenStruct.html#class-OpenStruct-label-Caveats)\nthat warns about the poor performance characteristics of `OpenStruct` relative\nto `Struct` and `Hash`.\n\n> This should be a consideration if there is a concern about the performance of\n> the objects that are created, as there is much more overhead in the setting\n> of these properties compared to using a Hash or a Struct. Creating an open\n> struct from a small Hash and accessing a few of the entries can be 200 times\n> slower than accessing the hash directly.\n\nThis doesn't mean don't use `OpenStruct`, but do be aware of if you are using\nit in a hot path or if you are allocating and processing tons of them.\n\nIf you turn on _Performance Warnings_ in Ruby, you'll see a warning message\nwhen allocating an `OpenStruct`.\n\n```ruby\n> require 'ostruct'\n=> true\n> os1 = OpenStruct.new\n=> #<OpenStruct>\n> Warning[:performance] = true\n=> true\n> os2 = OpenStruct.new\n(irb):6: warning: OpenStruct use is discouraged for performance reasons\n=> #<OpenStruct>\n```\n\n[source](https://www.reddit.com/r/ruby/comments/1d54mwl/comment/l6jgn59/)\n"
  },
  {
    "path": "ruby/or-operator-precedence.md",
    "content": "# Or Operator Precedence\n\nWhat's the difference between `||` and `or` in Ruby?\n\nLet's look at an example to find out. First, let's start with some boolean\nvariables:\n\n```ruby\n> a, b = false, true\n=> [false, true]\n```\n\nNow, let's try the different _or_ operators:\n\n```ruby\n> a || b\n=> true\n> a or b\n=> true\n```\n\nCool, they seem to work as expected.\n\nFinally, let's capture the result in a variable:\n\n```ruby\n> c = a or b\n=> true\n> c\n=> false\n```\n\nBut why is `c` false and not true? Operator precedence. The assignment\noperator (`=`) takes precedence over the `or` operator causing `c` to be\nassigned to the value of `a` (`false`) before `or`'d with `b`.\n\n[source](http://stackoverflow.com/questions/2083112/difference-between-or-and-in-ruby)\n"
  },
  {
    "path": "ruby/output-bytecode-for-a-ruby-program.md",
    "content": "# Output Bytecode For A Ruby Program\n\nThe `ruby` CLI comes with a flag to dump the disassembled YARV bytecode for the\ngiven Ruby program. This can be a fun way to explore how a Ruby program is\ninterpreted under the hood.\n\nAaron Patterson demoed this behavior during his RubyConf 2024 talk.\n\nPass the `--dump` flag with `insns` along with either the path to your file or\nan inline bit of Ruby.\n\nHere is a really basic example:\n\n```bash\n❯ ruby --dump=insns -e '2 + 3'\n== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,5)> (catch: false)\n0000 putobject                              2                         (   1)[Li]\n0002 putobject                              3\n0004 opt_plus                               <calldata!mid:+, argc:1, ARGS_SIMPLE>[CcCr]\n0006 leave\n```\n\nAnd another quite basic example, but with local variables this time:\n\n```bash\n❯ ruby --dump=insns -e 'x = 2; y = 3; x + y'\n== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,19)> (catch: false)\nlocal table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])\n[ 2] x@0        [ 1] y@1\n0000 putobject                              2                         (   1)[Li]\n0002 setlocal_WC_0                          x@0\n0004 putobject                              3\n0006 setlocal_WC_0                          y@1\n0008 getlocal_WC_0                          x@0\n0010 getlocal_WC_0                          y@1\n0012 opt_plus                               <calldata!mid:+, argc:1, ARGS_SIMPLE>[CcCr]\n0014 leave\n```\n\nIf you want to dig in to how to read everything that is going on in these\noutputs, I'd recommend checking out this [Advent of YARV\nseries](https://kddnewton.com/2022/11/30/advent-of-yarv-part-0.html)\n"
  },
  {
    "path": "ruby/override-the-initial-sequence-value.md",
    "content": "# Override The Initial Sequence Value\n\n[FactoryGirl sequences](https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#sequences)\ncan be defined with an initial starting value\n\n```ruby\nFactoryGirl.define do\n  sequence :email, 1000 do |n|\n    \"person#{n}@example.com\"\n  end\nend\n```\n\nthus:\n\n```ruby\n> FactoryGirl.generate :email\n=> \"person1000@example.com\"\n> FactoryGirl.generate :email\n=> \"person1001@example.com\"\n```\n"
  },
  {
    "path": "ruby/parallel-bundle-install.md",
    "content": "# Parallel Bundle Install\n\nThe `bundle install` command can take quite a while sometimes. This is\nespecially true for when you are setting up a fresh dev environment for an\nexisting project. Fortunately, Bundler provides a flag for parallelizing\nthe gem installs and Bundler is smart enough that it knows how to resolve\nthe dependencies so that this is possible in the first place. Just tell\nBundler how many concurrent jobs you want it to install with (4 is a good\nnumber) and let it do the rest of the work.\n\n```bash\n$ bundle install --jobs 4\n```\n"
  },
  {
    "path": "ruby/parse-json-into-an-open-struct.md",
    "content": "# Parse JSON Into An OpenStruct\n\nThe `json` module that ships with Ruby is something I use a lot in web app\nAPIs. When a request comes in as a string of JSON, I use `JSON.parse` to turn\nit into a hash. That's because a hash is much easier to work with than a string\nrepresentation of some JSON data.\n\n```ruby\n> require 'json'\n=> true\n> data = JSON.parse('{\"name\": \"Josh\", \"city\": \"Chicago\"}')\n=> {\"name\"=>\"Josh\", \"city\"=>\"Chicago\"}\n> data[\"name\"]\n=> \"Josh\"\n```\n\nThe hash access syntax can sometimes get to be clunky. `JSON.parse` is flexible\nenough that it can do more than turn a JSON string into a hash. It can turn it\ninto any object that plays along. `OpenStruct` is a great example of this.\n\nTo tell `JSON.parse` to use a class other than `Hash`, include [the\n`object_class`\noption](https://ruby-doc.org/stdlib-3.0.1/libdoc/json/rdoc/JSON.html#module-JSON-label-Parsing+Options).\n\n```ruby\n> json_str = '{\"name\": \"Josh\", \"city\": \"Chicago\"}'\n=> \"{\\\"name\\\": \\\"Josh\\\", \\\"city\\\": \\\"Chicago\\\"}\"\n> data = JSON.parse(json_str, object_class: OpenStruct)\n=> #<OpenStruct name=\"Josh\", city=\"Chicago\">\n> data.name\n=> \"Josh\"\n```\n\nBecause of how `OpenStruct` objects work, we can use method notation to access\nthe fields parsed from the JSON string.\n\n[source](https://stackoverflow.com/a/48396425/535590)\n"
  },
  {
    "path": "ruby/parsing-a-csv-with-quotes-in-the-data.md",
    "content": "# Parsing A CSV With Quotes In The Data\n\nIf a CSV contains unescaped quote characters--like you might find in a CSV full\nof measurement data--then Ruby's\n[CSV](https://ruby-doc.org/stdlib-2.6.1/libdoc/csv/rdoc/CSV.html) library will\nbe unable to parse it.\n\nHere is what happens with a line of CSV about some lumber:\n\n```ruby\n> require 'csv'\n> CSV.parse_line('oak,2\",4\"')\nCSV::MalformedCSVError (Illegal quoting in line 1.)\n```\n\nHowever, we can enable some more lenient, liberal parsing of the data with the\n`liberal_parsing` argument.\n\n```ruby\n> require 'csv'\n> CSV.parse_line('oak,2\",4\"', liberal_parsing: true)\n=> [\"oak\", \"2\\\"\", \"4\\\"\"]\n```\n\n[source](https://blog.bigbinary.com/2016/11/22/ruby-2-4-introduces-liberal_parsing-option-for-parsing-bad-csv-data.html)\n"
  },
  {
    "path": "ruby/pass-a-block-to-count.md",
    "content": "# Pass A Block To Count\n\nRuby's [`Enumerable`](http://ruby-doc.org/core-2.2.3/Enumerable.html) module\ncomes with the method `#count` for determining how many items are in an\narray or hash.\n\n```ruby\n> [1,2,3].count\n=> 3\n> {a: 1, b: 2}.count\n=> 2\n```\n\nThe `#count` method has a trick up its sleeve though. It can take a block\nwith a predicate that returns `true` or `false`. It essentially acts like\n`#select` returning the count rather than the array subset itself.\n\n```ruby\n> [1,2,3].count { |x| x.odd? }\n=> 2\n> {a: 1, b: 2}.count { |(x,y)| y < 0 }\n=> 0\n```\n"
  },
  {
    "path": "ruby/passing-arbitrary-methods-as-blocks.md",
    "content": "# Passing Arbitrary Methods As Blocks\n\nUse\n[`Object#method`](http://ruby-doc.org/core-1.8.7/Object.html#method-i-method)\nto create a callable `Method` object that can be passed to methods\nthat yield to a block.\n\n```ruby\ndef inc(x)\n  x + 1\nend\n\n[1,2,3].map(&method(:inc))\n#=> [2,3,4]\n```\n"
  },
  {
    "path": "ruby/passing-arguments-to-a-rake-task.md",
    "content": "# Passing Arguments To A Rake Task\n\nYou can create a rake task that takes arguments by including an array of\nnamed arguments in the task declaration.\n\n```ruby\ntask :greeting, [:name] do |task, args|\n  puts \"Hello, #{args.name}!\"\nend\n```\n\nYou can then pass an argument to that task when invoking it.\n\n```bash\n$ rake greeting[World]\nHello, World!\n```\n\n[source](http://davidlesches.com/blog/passing-arguments-to-a-rails-rake-task)\n"
  },
  {
    "path": "ruby/pattern-match-values-from-a-hash.md",
    "content": "# Pattern Match Values From A Hash\n\nAs of Ruby 3.0.0, the _rightward assignment_ operator (`=>`) was introduced as\nanother syntax for assigning values to variables. With it comes an experimental\npattern matching capability. This pattern matching can be used with hashes to\nextract keyed values into local variables.\n\nPattern matching with rightward assignment can be done by placing a hash on the\nleft-hand side of the `=>` operator and then placing a hash-like listing of\nkeys to be matched against.\n\n```ruby\n> some_hash = { name: \"Josh\", handle: \"@jbrancha\", age: :unknown }\n=> {:name=>\"Josh\", :handle=>\"@jbrancha\", :age=>:unknown}\n> some_hash => {name:, handle:}\n(irb):3: warning: One-line pattern matching is experimental, and the behavior may change in future versions of Ruby!\n=> nil\n> name\n=> \"Josh\"\n> handle\n=> \"@jbrancha\"\n```\n\nThis example extracts `name` and `handle` as local variables assigned with the\nvalues of the those keys from the hash.\n\nNote that this feature is _experimental_.\n\nAlso note that referencing a key that doesn't exist in a pattern matching\nstatement will raise a `NoMatchingPatternError`.\n\n[source](https://www.ruby-lang.org/en/news/2020/12/25/ruby-3-0-0-released/)\n"
  },
  {
    "path": "ruby/percent-notation.md",
    "content": "# Percent Notation\n\nRuby has many uses for the `%` character. One of the more obscure uses is as\na notion for custom delimited strings. Use the percent notation with a\nnon-alphanumeric character to surround a string.\n\n```ruby\n> %=Jurassic Park=\n=> \"Jurassic Park\"\n> % Ghostbusters \n=> \"Ghostbusters\"\n```\n\nIt even works with balanced characters\n\n```ruby\n> %(The Goonies)\n=> \"The Goonies\"\n```\n\nThis is useful for defining a string that has both types of quotes\n\n```ruby\n> %[That'll be the \"day\"]\n=> \"That'll be the \\\"day\\\"\"\n```\n\nIt's also useful for creating horribly obfuscated code\n\n```ruby\n> %=what===%?what?\n=> true\n```\n\nh/t [Josh Davey](https://twitter.com/joshuadavey/status/615613617099046912)\n"
  },
  {
    "path": "ruby/precedence-of-logical-operators.md",
    "content": "# Precedence Of Logical Operators\n\nThere are two sets of logical operators that you are going to see in Ruby. The\nmore common and idiomatic set are `!`, `&&`, and `||`. Relative to all the\nother operators in the Ruby language, these three have high precedence.\n\nThe other set of logical operators are `not`, `and`, and `or`. These ones have\nrelatively much lower precedence. Though they work conceptually the same.\n\nThe reason to be aware of the differences in precedence is that if you were to\nmix the two sets, you could end up with unexpected results.\n\n```ruby\n> not true && false\n=> true\n> !true && false\n=> false\n```\n\nTo keep my Ruby code idiomatic and to avoid these kinds of potential logical\nmixups, I stick to using nearly exclusively the first set—`!`, `&&`, and `||`.\n\n[source](https://ruby-doc.org/core-2.6.2/doc/syntax/precedence_rdoc.html)\n"
  },
  {
    "path": "ruby/prevent-erb-lint-from-removing-opening-tags.md",
    "content": "# Prevent erb_lint From Removing Opening Tags\n\nThe [`erb_lint` gem](https://github.com/Shopify/erb_lint) is a tool from\nshopify for linting and auto-formatting ERB files. When I first set it up in a\nRails codebase with the base `.erb-lint.yml` recommended in the README, I ran\ninto a pernicious issue. The linter wanted to remove opening tags (i.e. `<%`\nand `<%=`) from my ERB files.\n\nSo, for a file that looked like this:\n\n```erb\n<div>\n  <%= form_with(url: login_path, scope: :session) do |f| %>\n    <div>\n      <%= f.label :email %>\n      <%= f.email_field :email %>\n    </div>\n</div>\n```\n\nIt would get formatted to this:\n\n```erb\n<div>\nform_with(url: login_path, scope: :session) do |f| %>\n    <div>\nf.label :email %>\nf.email_field :email %>\n    </div>\n</div>\n```\n\nYikes!\n\nI had to disable a couple rules (under `rubocop_config:`) in the `.erb-lint.yml` file to get it to stop\ndoing this.\n\n```yaml\nLayout/InitialIndentation:\n  Enabled: false\nLayout/TrailingEmptyLines:\n  Enabled: false\n```\n\n[source](https://github.com/Shopify/erb_lint/issues/222)\n"
  },
  {
    "path": "ruby/print-data-to-formatted-table.md",
    "content": "# Print Data To Formatted Table\n\nOften when I'm doing some debugging or reporting from the Ruby/Rails console, I\nend up with a chunk of data that I'd like to share. Usually I'd like something\nthat I can copy into the text area of Slack or a project management tool.\nCopying and pasting a pretty-printed hash isn't bad, but a nicely formatted\ntable would be even better.\n\nHere is a small method I can copy and paste into the console:\n\n```ruby\ndef print_to_table(headings, data)\n  # Calculate column widths\n  column_widths = headings.each_with_index.map do |heading, index|\n    [heading.size, *data.map { |row| row[index].to_s.size }].max\n  end\n\n  # Method to format a row\n  def format_row(row, widths)\n    row.each_with_index.map { |item, index| item.to_s.ljust(widths[index]) }.join(\" | \")\n  end\n\n  # Print headings\n  puts format_row(headings, column_widths)\n  puts \"-\" * column_widths.sum + \"-\" * (column_widths.size * 3 - 3)\n\n  # Print data\n  data.each do |row|\n    puts format_row(row, column_widths)\n  end\nend\n```\n\nAnd then I can run it like so to get formatted table that can be copy-pasted\nelsewhere:\n\n```ruby\n> headings = [:id, :name, :role]\n=> [:id, :name, :role]\n> data = [\n    [123, 'Bob', 'Burger flipper'],\n    [456, 'Linda', 'Server'],\n    [789, 'Gene', 'Ketchup Refiller']\n  ]\n=> [[123, \"Bob\", \"Burger flipper\"], [456, \"Linda\", \"Server\"], [789, \"Gene\", \"Ketchup Refiller\"]]\n> print_to_table(headings, data)\n# id  | name  | role\n# ------------------------------\n# 123 | Bob   | Burger flipper\n# 456 | Linda | Server\n# 789 | Gene  | Ketchup Refiller\n```\n"
  },
  {
    "path": "ruby/question-mark-operator.md",
    "content": "# Question Mark Operator\n\nRuby has a question mark (`?`) operator that works like so\n\n```ruby\n> ?a\n=> \"a\"\n> ?\\s\n=> \" \"\n> ??\n=> \"?\"\n> ?a + ?b + ?c\n=> \"abc\"\n```\n\nIt essentially creates single character strings. At least in Ruby 1.9+ it\ndoes. In versions of Ruby before 1.9, the `?` operator could be used to get\nthe ascii character code of the operand character.\n\nh/t Josh Davey\n\n[source](http://stackoverflow.com/questions/16641205/what-does-the-question-mark-operator-do)\n"
  },
  {
    "path": "ruby/rake-only-lists-tasks-with-descriptions.md",
    "content": "# Rake Only Lists Tasks With Descriptions\n\nRake describes the `-T` flag as\n\n> Display the tasks (matching optional PATTERN) with descriptions, then exit.\n\nAnd `rake -T` does just exactly that. It lists all the tasks with\ndescriptions. Any rake task that you define without a `desc` will not be\nincluded.\n\nConsider the following rake task definitions\n\n```ruby\ndesc 'foobar does this and that'\ntask :foobar do\n  puts 'this and that'\nend\n\ntask :foobaz do\n  puts 'not so much'\nend\n```\n\nThis is what I get when listing the rake tasks filtered by _foo_\n\n```bash\n$ rake -T foo\nrake foobar  # foobar does this and that\n```\n\nThe `foobar` task (which has a description) is listed, but `foobaz` is not.\n\nA hack of sorts to get around this is to use the `-P` flag which will end up\nlisting all tasks even if they do not have a description (`rake -P | grep\n'foo'`).\n"
  },
  {
    "path": "ruby/read-the-first-line-from-a-file.md",
    "content": "# Read The First Line From A File\n\nIf I wanted to read the first line from a file with Ruby, I'd probably read the\nwhole thing in, split it by newlines, and grab the first.\n\n```ruby\nFile.read('README.md').split(/\\n/).first\n```\n\nThis is inefficient in that it reads in the entire file. For small files this\nwon't matter, but for larger files it could become a bottleneck.\n\nThere is a method of doing this that is just as concise and streams the first\npart of the file rather than reading it in its entirety. The `File.open` method\ntakes a block. This means you can pass a symbol-to-proc to it as the block\nargument.\n\n```ruby\n> File.open('README.md', &:readline).strip\n=> \"# TIL\"\n> File.open('README.md', &:gets).strip\n=> \"# TIL\"\n```\n\nBoth `#readline` and `#gets` will grab the first line including the newline\ncharacter (hence the `#strip`). The only difference is that `#readline` will\nraise an exception if the file is empty.\n\nThese methods both come from the `IO` module and [stream the file rather than\nslurping the whole thing\nin](https://blog.appsignal.com/2018/07/10/ruby-magic-slurping-and-streaming-files.html).\n\n[source](https://stackoverflow.com/questions/1490138/reading-the-first-line-of-a-file-in-ruby)\n"
  },
  {
    "path": "ruby/refer-to-implicit-block-argument-with-it.md",
    "content": "# Refer To Implicit Block Argument With It\n\nOne of the key features of the Ruby 3.4 release is the `it` implicit block\nargument.\n\nThe vast majority of inline blocks defined in Ruby code receive a single block\nargument. Typically we name and reference a block argument explictly like so:\n\n```ruby\nitems.map { |item| item * item }\n```\n\nRuby likes to cut away excess syntax when possible. To that end, the implicit\n`it` block argument has been added. This is an identifier we can reference in\nthe context of a block and its value is the current\n\n```ruby\nitems = [1,2,3,4,5]\n\nsquares = items.map { it * it }\n\npp squares\n#=> [1, 4, 9, 16, 25]\n```\n\nNote: we cannot mix numbered parameters (`_1`, `_2`) with the `it` parameter.\nIf we do, we'll get the following error:\n\n```ruby\ndef method_using_block(a, b)\n  yield(a, b) if block_given?\nend\n\nputs method_using_block(4,5) { _2 ** _1 } #=> 625\nputs method_using_block(4,5) { _2 ** it }\n# it_block.rb:12: syntax error found (SyntaxError)\n#   10 |\n#   11 | puts method_using_block(4,5) { _2 ** _1 }\n# > 12 | ... it }\n#      |     ^~ `it` is not allowed when a numbered parameter is already used\n```\n\n[source](https://docs.ruby-lang.org/en/3.4/NEWS_md.html)\n"
  },
  {
    "path": "ruby/reference-hash-key-with-safe-navigation.md",
    "content": "# Reference Hash Key With Safe Navigation\n\nLet's say we have a variable that we expect to be a hash, but could also be\n`nil`. We want to try to grab a value from that hash by referencing a specific\nkey. Because it could be `nil`, we cannot simply do:\n\n```ruby\nstuff[:key]\n```\n\nAs that could result in `NoMethodError: undefined method '[]' for nil\n(NoMethodError)`.\n\nWe should use the _safe navigation_ operator (`&`) to avoid raising that error.\nHowever, we should pay attention to a necessary syntax shift from the short-hand\n`[:key]` to the long-hand `[](:key)`.\n\n```ruby\nstuff&.[](:key)\n```\n\nThe meaning of this syntax is that we are calling the `#[]` method and we pass\nit a single argument `:key` wrapped in parentheses.\n\nAnother approach would be to use `#dig` which can feel more ergonomic than the\nabove syntax switch.\n\n```ruby\nstuff&.dig(:key)\n```\n"
  },
  {
    "path": "ruby/regenerate-lock-file-with-newer-bundler.md",
    "content": "# Regenerate Lock File With Newer Bundler\n\nWhile upgrading to the latest Ruby version (4.0.0), I also wanted to upgrade the\nversion of `bundler` that my project uses. This shows up at the bottom of the\n`Gemfile.lock` file as the `BUNDLED WITH` line. Despite installing the latest\nversion of `bundler`, I get the following message when I try to install\ndependencies.\n\n```bash\n$ bundle install\n\nBundler 4.0.3 is running, but your lockfile was generated with 2.6.2.\nInstalling Bundler 2.6.2 and restarting using that version.\n...\n```\n\nInstead, what we need to tell `bundle` to update the locked version of `bundler`\nin the `Gemfile.lock`.\n\n```bash\n$ bundle update --bundler\n\nFetching gem metadata from https://rubygems.org/.........\nResolving dependencies...\nBundle updated!\n```\n\nThe `--bundler` flag for `bundle-update` says the following:\n\n> Update the locked version of bundler to the invoked bundler version.\n\nSo we could pass a specific `bundler` version to that flag, but in this case I\nwant to use the version I'm invoking it with which is the latest that I just\ninstalled.\n"
  },
  {
    "path": "ruby/rendering-erb.md",
    "content": "# Rendering ERB\n\nIf you have a string that contains ERB templating, you can quickly generate\nthe resulting string with the following code snippet:\n\n```ruby\nrequire 'erb'\n\nsome_template_string = <<-TEXT\nThe top\n<% 5.times do |i| %>\nItem <%= i + 1 %>\n<% end %>\nThe bottom\nTEXT\n\nputs ERB.new(some_template_string).result\n```\n\nThis will print the following to stdout:\n\n```\nThe top\nItem 1\nItem 2\nItem 3\nItem 4\nItem 5\nThe bottom\n```\n\n[source](http://www.stuartellis.eu/articles/erb/)\n"
  },
  {
    "path": "ruby/replace-the-current-process-with-an-external-command.md",
    "content": "# Replace The Current Process With An External Command\n\nRuby's\n[`Kernel#exec`](http://ruby-doc.org/core-2.2.3/Kernel.html#method-i-exec)\nmethod can be used to run an external command. What differentiates it from\nexecuting commands with the likes of back ticks or `%x[]` is that instead of\nforking a child process, it replaces the current process.\n\nFor instance, the following ruby script, when executed, will replace itself\nwith an `irb` session.\n\n```ruby\nKernel.exec('irb')\n```\n\nThe external command will even benefit from the existing environment. For\nexample, if I set the following environment variable\n\n```bash\n$ export GREETING=hello\n```\n\nand then execute a file containing\n\n```ruby\nKernel.exec('echo $GREETING')\n```\n\nI can expect to see `hello` printed to stdout.\n"
  },
  {
    "path": "ruby/require-entire-gemfile-in-pry-session.md",
    "content": "# Require Entire Gemfile In Pry Session\n\nWant to experiment in a pry session with some of the gems in your project's\n`Gemfile`? You can quickly require all the gems for your project using\nBundler's `#require` method.\n\nJust require `bundler` itself and then execute `Bundler.require`. Everything\nwill be loaded in.\n\n```ruby\n> require 'bundler'\n=> true\n> Bundler.require\n=> [Gem::Dependency.new(\"devise\", Gem::Requirement.new([\">= 0\"]), :runtime),\n Gem::Dependency.new(\"rails\", Gem::Requirement.new([\"= 4.2.5\"]), :runtime),\n Gem::Dependency.new(\"pg\", Gem::Requirement.new([\"~> 0.15\"]), :runtime),\n...\n```\n"
  },
  {
    "path": "ruby/rerun-only-failures-with-rspec.md",
    "content": "# Rerun Only Failures With RSpec\n\nAfter running a big test suite, I may have a bunch of output on the screen\nincluding the results of a couple test failures. I like to bring the context\nof the test failures front and center and make sure they are consistent test\nfailures (not flickering failures). Instead of copying and pasting each\nfailure, I can rerun `rspec` in a way that executes only the test cases that\nfailed.\n\n```\n$ rspec --only-failures\n```\n\nThis feature requires that you set a file for RSpec to persist some state\nbetween runs. Do this in the `spec/spec_helper.rb` file. For example:\n\n```ruby\nRSpec.configure do |config|\n  config.example_status_persistence_file_path = \"spec/examples.txt\"\nend\n```\n\nSee more details\n[here](https://relishapp.com/rspec/rspec-core/docs/command-line/only-failures).\n\nh/t Brian Dunn\n"
  },
  {
    "path": "ruby/retry-a-block-after-an-exception.md",
    "content": "# Retry A Block After An Exception\n\nRuby comes with a [_retry_\nmechanism](https://ruby-doc.org/docs/keywords/1.9/Object.html#method-i-retry)\nthat allows you to recover from known exceptions by retrying the code that led\nto the exception. In network or timing-based situations where race conditions\nare possible, the most straightforward recourse may be to just _retry_ a couple\ntimes.\n\nSet up a `begin` / `rescue` block like you'd normally do for a chunk of code\nthat may raise an exception. Then add a `retry` call to the `rescue` block.\n\n```ruby\nbegin\n  puts \"About to do a thing (#{retries})\"\n\n  raise StandardError if rand(5) != 4\n\n  puts \"Success!\"\nrescue StandardError => e\n  retry\nend\n```\n\nIf an exception is raised, this will tell Ruby to re-execute the code in the\n`begin` block over and over until the exception isn't raised.\n\nTo avoid an infinite loop, you can limit the retries with a counting variable.\n\n```ruby\nbegin\n  retries ||= 0\n  puts \"About to do a thing (#{retries})\"\n\n  raise StandardError if rand(5) != 4\n\n  puts \"Success!\"\nrescue StandardError => e\n  retry if (retries += 1) < 3\n\n  # all retries failed, re-raise exception\n  raise e\nend\n```\n\nThis will re-raise after 3 tries.\n\nHere is the [full example](https://gist.github.com/jbranchaud/629fb3b9d55c817e5c9fc480790dfabc)\n\n[source](https://www.honeybadger.io/blog/how-to-try-again-when-exceptions-happen-in-ruby/)\n"
  },
  {
    "path": "ruby/return-the-thing-being-printed.md",
    "content": "# Return The Thing Being Printed\n\nThe [`puts`](https://ruby-doc.org/core-3.0.2/Kernel.html#method-i-puts) method\nis the canonical way of priting things to stdout in Ruby. Notably, its return\nvalue is always `nil`. Generally this isn't much of an issue, but can be a\npotential gotcha while debugging.\n\nConsider the following method whose behavior you are trying to investigate:\n\n```ruby\ndef process(arg)\n  thing = do_something(arg)\n\n  thing.value\nend\n```\n\nI want to print out the value of thing when I execute the code to see what it\nis while debugging. So I add a `puts` statement.\n\n```ruby\ndef process(arg)\n  thing = do_something(arg)\n\n  puts thing.value\nend\n```\n\nWell, I just broke the behavior of `process` because it now returns `nil`\ninstead of `thing.value`.\n\nI could add an additional line that returns the correct value. Or I could use\n[`p`](https://ruby-doc.org/core-3.0.2/Kernel.html#method-i-p) which both prints\nits argument to stdout and returns it as is.\n\n```ruby\ndef process(arg)\n  thing = do_something(arg)\n\n  p thing.value\nend\n```\n\n[source](https://dev.to/lofiandcode/ruby-puts-vs-print-vs-p-vs-pp-vs-awesome-5akl)\n"
  },
  {
    "path": "ruby/returning-with-sequel.md",
    "content": "# Returning With Sequel\n\nThe [`sequel`](https://github.com/jeremyevans/sequel) gem is a database\ntoolkit that allows you to interact with most databases. PostgreSQL has\nsupport for composite primary keys, but `sequel`, which is supposed to return\nthe `id` of newly inserted records, isn't sure what to return when faced\nwith a composite primary key. You can get around this by telling `sequel`\nexactly what should be returned using the `#returning` method. For instance,\nget it to return just the `id` of the new record:\n\n```ruby\nDB[:floors].returning(:id).insert(hotel_id: 4, id: 1, ...)\n# [{id: 1}]\n```\n\nTo get it to return both parts of composite key:\n\n```ruby\nDB[:floors].returning(:id, :hotel_id).insert(hotel_id: 4, id: 1, ...)\n# [{id: 1, hotel_id: 4}]\n```\n"
  },
  {
    "path": "ruby/rexml-is-a-bundled-gem-as-of-ruby-3-0-0.md",
    "content": "# rexml Is A Bundled Gem As Of Ruby 3.0.0\n\nAre you seeing an error loading certain\n[`rexml`](https://github.com/ruby/rexml) files?\n\n```\nLoadError: cannot load such file -- rexml/document\n```\n\nIt may be that `rexml` no longer ships as part of the Ruby version you are\nusing. If you are working with Ruby 3.0.0 or later, the `rexml` gem needs to be\nexplicitly installed as it is now a bundled gem.\n\nEither add it to your `Gemfile`:\n\n```\ngem 'rexml'\n```\n\nor install it manually with:\n\n```bash\n$ gem install rexml\n```\n\n[source](https://stackoverflow.com/questions/65479863/rails-6-1-what-is-preventing-tests-from-running)\n"
  },
  {
    "path": "ruby/run-an-older-version-of-bundler.md",
    "content": "# Run An Older Version Of Bundler\n\nYou can check your current version of bundler like so:\n\n```bash\n$ bundle --version\n1.17.3\n```\n\nIf you have older versions of bundler, you run against those by specifying the\nversion in the command:\n\n```bash\n$ bundle _1.16.6_ --version\n1.16.6\n```\n\nLikewise this can be used with any bundler command:\n\n```bash\n$ bundle _1.16.6_ install\n```\n\n[source](https://makandracards.com/makandra/9741-run-specific-version-of-bundler)\n"
  },
  {
    "path": "ruby/running-a-single-minitest-example.md",
    "content": "# Running A Single MiniTest Example\n\nConsider the following\n[MiniTest](http://ruby-doc.org/stdlib-2.0.0/libdoc/minitest/rdoc/MiniTest.html)\nfile:\n\n```ruby\n# test_stuff.rb\nrequire 'minitest/autorun'\n\nclass TestStuff < MiniTest::Unit::TestCase\n  def test_first_thing\n    assert_equal 4, (2 * 2)\n  end\n\n  def test_second_thing\n    assert_equal 9, (3 * 3)\n  end\nend\n```\n\nIf we want to run all the tests in this file, we can do so with:\n\n```bash\n$ ruby test_stuff.rb\n```\n\nBut what if we want to run a specific test? We can target a single MiniTest\nexample with the `--name` flag and the name of that example. We can do\nsomething like the following:\n\n```bash\n$ ruby test_stuff.rb --name test_second_thing\n```\n\n[source](http://stackoverflow.com/a/5292885/535590)\n"
  },
  {
    "path": "ruby/safe-navigation-operator.md",
    "content": "# Safe Navigation Operator\n\nWith the release of Ruby 2.3, the *safe navigation operator* (`&.`) is now\navailable. This addition to the Ruby language allows you to collapse all\nthose pesky `nil` checks into the accessor call they are guarding. Consider\nthis snippet of common Ruby code:\n\n```ruby\nif user && user.authenticate(params[:password])\n  # proceed with logged in user\nend\n```\n\nWith the *safe navigation operator*, the predicate can now be collapsed:\n\n```ruby\nif user&.authenticate(params[:password])\n  # proceed with logged in user\nend\n```\n\nIf `user` is `nil`, then the predicate will evaluate to `false` and the body\nof the if-statement will be passed over.\n\n[Source](http://nithinbekal.com/posts/ruby-2-3-features/)\n"
  },
  {
    "path": "ruby/scripting-with-rvm.md",
    "content": "# Scripting With RVM\n\nBecause of how [RVM](https://rvm.io/) works under the hood, you have to do a\ncouple things to get it to work in a script.\n\nFirst, you need to ensure that your script is using `bash` instead of `sh`,\nso add this to the top of your scripts:\n\n```bash\n#!/bin/bash\n```\n\nYou'll then want to make sure that RVM is sourced. Their\n[docs](https://rvm.io/workflow/scripting) recommend sourcing in a script\nlike this:\n\n```bash\n# Load RVM into a shell session *as a function*\nif [[ -s \"$HOME/.rvm/scripts/rvm\" ]] ; then\n\n  # First try to load from a user install\n  source \"$HOME/.rvm/scripts/rvm\"\n\nelif [[ -s \"/usr/local/rvm/scripts/rvm\" ]] ; then\n\n  # Then try to load from a root install\n  source \"/usr/local/rvm/scripts/rvm\"\n\nelse\n\n  printf \"ERROR: An RVM installation was not found.\\n\"\n\nfi\n```\n\nAfter that, you can utilize any of the capabilities of RVM in your script as\nyou'd like.\n"
  },
  {
    "path": "ruby/scroll-to-top-of-page-with-capybara.md",
    "content": "# Scroll To Top Of Page With Capybara\n\nDuring a browser-based Capybara test, you may get partially scrolled down in\nthe page which can obscure or overlay DOM elements. A sure-fire way to\nscroll back to the top is by executing the following line of JavaScript:\n\n```ruby\npage.execute_script \"window.scrollTo(0,0)\"\n```\n\nThis will scroll to `0,0` which is the top-most, left-most corner of the\nbrowser.\n"
  },
  {
    "path": "ruby/search-for-gem-versions-available-to-install.md",
    "content": "# Search For Gem Versions Available To Install\n\nThe [`gem list`](https://guides.rubygems.org/command-reference/#gem-list)\ncommand combined with a few flags will produce a listing of all available\nversions of that gem like so:\n\n```bash\ngem list rails --exact --remote --all\n\n*** REMOTE GEMS ***\n\nrails (7.1.0, 7.0.8, 7.0.7.2, 7.0.7.1, 7.0.7, ...)\n```\n\nI can then apply a bit of command-line transformation with `sed` and `tr` to\nturn that list of version numbers into a list that can be nicely consumed by\nother commands. In particular, I will pipe that list to `fzf` so that I can\nfuzzy-search through the huge list for specific version matches.\n\n```bash\n$ gem list rails --exact --remote --all \\\n  | sed -n 's/.*(\\([^)]*\\)).*/\\1/p' \\\n  | tr ',' '\\n' \\\n  | sed 's/^ //' \\\n  | fzf\n```\n\nThe first `sed` command captures everything inside the parentheses. The `tr`\ncommand replaces the commas with new lines. And the second `sed` command\nremoves those leading space on each line.\n\nLastly, [`fzf`](https://github.com/junegunn/fzf) provides a fuzzy-search\ninterface over the list of versions.\n"
  },
  {
    "path": "ruby/set-default-tasks-for-rake-to-run.md",
    "content": "# Set Default Tasks For Rake To Run\n\nLet's say our Ruby codebase has a `test` rake task and a `test:system` rake\ntask. One runs our unit tests and the other runs our system (headless\nbrowser-based) tests. They aren't necessary defined in our `Rakefile`. In fact,\nthat's how it is in a Rails codebase where these are defined by Rails itself.\n\nWe want the default action when [`rake`](https://ruby.github.io/rake/) is\ninvoked by itself to be to run both of those test tasks.\n\nThis can be accomplished by specifying a `default` task and specifying both of\nthose tasks as prerequisites.\n\n```ruby\ntask default: [\"test\", \"test:system\"]\n```\n\nThe `default` task itself does nothing. When we invoke it though, it has to run\nour prerequisites. So running `rake` results in `test` and then `test:system`\ngetting run.\n\nIf I have something like\n[`unicornleap`](https://github.com/dkarter/dotfiles/blob/b5aae6a9edd5766f0cc9100235b0955a9d53aa85/installer/mac-setup.sh#L47-L74)\nor\n[`confetti`](https://manual.raycast.com/deeplinks#block-702a9613bc82440d853492f553876a20),\nthen I can have one of those run in the event that all the prerequisites pass.\n\n```ruby\ntask default: [\"test\", \"test:system\"] do\n  system(\"unicornleap\") if system(\"which unicornleap > /dev/null 2>&1\")\nend\n```\n"
  },
  {
    "path": "ruby/set-rvm-default-ruby.md",
    "content": "# Set RVM Default Ruby\n\nThe default version of Ruby can be set for RVM using the `--default` flag.\nFor instance, to set the default version of Ruby to `ruby-2.2.3`, use the\nfollowing command:\n\n```\n$ rvm --default use ruby-2.2.3\n```\n"
  },
  {
    "path": "ruby/shift-the-month-on-a-date-object.md",
    "content": "# Shift The Month On A Date Object\n\nOne of things that Ruby loves to do is overload operators to support\nspecialized class-specific functionality. For instance, with the `Date` class,\nyou can use the `+` and `-` operators to add or remove days from a given\n`Date`.\n\n```ruby\n> Date.today\n=> #<Date: 2023-07-13 ((2460139j,0s,0n),+0s,2299161j)>\n> Date.today + 1\n=> #<Date: 2023-07-14 ((2460140j,0s,0n),+0s,2299161j)>\n> Date.today - 3\n=> #<Date: 2023-07-10 ((2460136j,0s,0n),+0s,2299161j)>\n```\n\nThat one feels pretty natural to me.\n\nThe `Date` class overloads another operator to do something that doesn't feel\nquite as natural.\n\nThe `<<` operator will shift (increment or decrement) the month of the given\n`Date` object. Given a positive number, it will shift the date that many months\nin the future (even wrapping to a new year as necessary). Given a negative\nnumber, it will shift the date back in time that many months.\n\n```ruby\n> Date.today\n=> #<Date: 2023-07-13 ((2460139j,0s,0n),+0s,2299161j)>\n> Date.today << 1\n=> #<Date: 2023-06-13 ((2460109j,0s,0n),+0s,2299161j)>\n> Date.today << -2\n=> #<Date: 2023-09-13 ((2460201j,0s,0n),+0s,2299161j)>\n> Date.today << 6\n=> #<Date: 2023-01-13 ((2459958j,0s,0n),+0s,2299161j)>\n```\n\nThis is a bit clever for my liking, but fun to know about.\n\n[source](https://ruby-doc.org/stdlib-3.0.0/libdoc/date/rdoc/Date.html#method-i-3C-3C)\n"
  },
  {
    "path": "ruby/show-public-methods-with-pry.md",
    "content": "# Show Public Methods With Pry\n\nOpen up a [`pry`](https://github.com/pry/pry) session and use the `-m` flag\nwith the `ls` command to show just the public methods for an object.\n\n```ruby\n> ls -m :hello\nComparable#methods: <  <=  >  >=  between?\nSymbol#methods:\n  <=>  as_json      empty?    length              slice     to_sym\n  ==   capitalize   encoding  match               succ      upcase\n  ===  casecmp      id2name   next                swapcase\n  =~   downcase     inspect   pretty_print_cycle  to_proc\n  []   duplicable?  intern    size                to_s\n```\n\n[source](https://github.com/pry/pry/wiki/State-navigation#Ls)\n"
  },
  {
    "path": "ruby/show-the-bundler-location-of-an-installed-gem.md",
    "content": "# Show The Bundler Location Of An Installed Gem\n\nWhen you run `bundle install` with a project, it is going to install all the\ngems specified by your project in a vendored location relative to the location\nof your Ruby version install.\n\nIf you want to find the location of a specific gem, you can ask bundler with\n`bundle show <gem-name>`.\n\nHere I ask where the `rspec` gem is.\n\n```bash\n$ bundle show rspec\n/Users/jbranchaud/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/rspec-3.12.0\n```\n\nI could `cd` into that directory to have a look around at the source. That's a\ngreat way to learn more about how our dependencies work.\n\nI could even inject some debugging statements (e.g. `binding.irb`) which the\nprogram using these gems will break on. Not often, but sometimes you need to\ndig in this deep to understand what is causing a tricky bug or why code isn't\nbehaving like you'd hoped. Just remember to remove those statements when you're\ndone.\n"
  },
  {
    "path": "ruby/silence-the-output-of-a-ruby-statement-in-pry.md",
    "content": "# Silence The Output Of A Ruby Statement In Pry\n\nSometimes running a command in a [`pry`](https://github.com/pry/pry) session\ncan produce a bunch of verbose output that you aren't interested in seeing.\n\nHere is a contrived line of code whose output will take over the entire screen:\n\n```ruby\n(1..200).map { |i| i*i }\n#=> [1,\n4,\n9,\n16,\n...\n```\n\nYou can silence all of this output by tacking on a single character -- `;`.\n\n```ruby\n(1..200).map { |i| i*i };\n```\n\n[source](https://gist.github.com/lfender6445/9919357)\n"
  },
  {
    "path": "ruby/single-and-double-quoted-string-notation.md",
    "content": "# Single And Double Quoted String Notation\n\nIf you are building a string that involves interpolation and literal double\nquotes, then you'll have to do some escaping. Here is an example:\n\n```ruby\n> feet, inches = [6, 4]\n> puts \"I am #{feet}'#{inches}\\\" tall\"\nI am 6'4\" tall\n```\n\nHaving to escape a single instance of a double quote isn't so bad. If you find\nyourself having to do it a bunch, Ruby has something for you. It is a string\nsyntax feature called [Percent Notation](percent-notation.md).\n\nYou can use percent notation to define double-quoted strings using `Q`:\n\n```ruby\n> puts %Q[I am #{feet}'#{inches}\" tall]\nI am 6'4\" tall\n```\n\nNo need to escape the double quote here.\n\nThere is a single-quoted version as well using `q`:\n\n```ruby\n> puts %q[I am #{feet}'#{inches}\\\" tall]\nI am #{feet}'#{inches}\\\" tall\n```\n\nThis is notably less useful than `%Q`. For that reason, `%Q` makes sense as a\ndefault and it makes up the percent notations unmodified behavior:\n\n```ruby\n> puts %[I am #{feet}'#{inches}\" tall]\nI am 6'4\" tall\n```\n"
  },
  {
    "path": "ruby/skip-specific-cves-when-auditing-your-bundle.md",
    "content": "# Skip Specific CVEs When Auditing Your Bundle\n\nThe [`bundler-audit` gem](https://github.com/rubysec/bundler-audit) is a tool\nthat can check for CVEs (Common Vulnerabilities and Exposures) in the installed\nversions of gems in your Ruby project. This is a great addition to a CI\npipeline to ensure you aren't deploying code with vulnerabilities.\n\nIf you have a known CVE in one of your dependencies, I recommend installing a\npatch as soon as possible. Of course, we have to apply some nuance to that\nstatement.\n\nIt is possible that we need to temporarily ignore the CVE warning to continue\nto ship code while we work on integrating the patch. Or it may be super\nlow-risk and we are comfortable putting it off for a while.\n\nUse the `--ignore` flag to prevent `bundler-audit` from flagging a specific\nCVE.\n\n```bash\n$ bundler-audit check --ignore CVE-2022-23837\n```\n\nOr if you need to ignore multiple, list them one after another.\n\n```bash\n$ bundler-audit check --ignore CVE-2022-23837 CVE-2021-41817\n```\n\nIf you do skip a CVE in your bundle audit, make sure you understand the risks\nand have a plan for dealing with it in the future.\n\nSee `bundler-audit --help` or [their\ndocs](https://github.com/rubysec/bundler-audit) for more details.\n"
  },
  {
    "path": "ruby/skip-the-front-of-an-array-with-drop.md",
    "content": "# Skip The Front Of An Array With Drop\n\nI've long been familiar with Ruby's\n[`Array#take`](https://apidock.com/ruby/Array/take) which is a handy way to\ngrab the first few elements of an array.\n\n```ruby\n> [:a, :b, :c, :d, :e, :f, :g].take(4)\n=> [:a, :b, :c, :d]\n```\n\nBut what if I want to skip those first four elements of the array and get what\nremains. That is where [`Array#drop`](https://apidock.com/ruby/Array/drop)\ncomes in.\n\n```ruby\n> [:a, :b, :c, :d, :e, :f, :g].drop(4)\n=> [:e, :f, :g]\n```\n\nHow about a couple practical situations for use in a Rails app.\n\nHere I want to segment out the first 6 books and whatever remains:\n\n```\ndef index\n  @books = Book.order(created_at: :desc).limit(10)\n\n  @featured_books = @books.take(6)\n  @remaining_books = @books.drop(6)\nend\n```\n\nOr, what about cleaning up all but the first of these duplicate records:\n\n```\nBook\n  .where(title: \"The Murder of Roger Ackroyd\")\n  .drop(1)\n  .each { |duplicate_book| duplicate_book.destroy }\n```\n\nThe first record is ignored (dropped from the array) and the following records\nare processed by the `#each` where they get destroyed.\n"
  },
  {
    "path": "ruby/specify-default-for-data-definition.md",
    "content": "# Specify Default For Data Definition\n\nHere is what a `Data` definition for the concept of a `Permission` might look\nlike:\n\n```ruby\nPermission = Data.define(:id, :name, :description, :enabled)\n\nperm1 = Permission.new(\n  id: 123,\n  name: :can_edit,\n  description: \"User is allowed to edit.\",\n  enabled: true\n)\n```\n\nHowever, as we're creating various `Permission` entities, we may find that the\nvast majority of them are _enabled_ by default and so we'd like to apply `true`\nas a default value.\n\nWe cannot do this directly in the `Data` definition, but we can open a block to\noverride the `initialize` method.\n\n```ruby\nPermission = Data.define(:id, :name, :description, :enabled) do\n  def initialize(:id, :name, :description, enabled: true)\n    super\n  end\nend\n\nperm1 = Permission.new(\n  id: 123,\n  name: :can_edit,\n  description: \"User is allowed to edit.\"\n)\n\nperm1.enabled #=> true\n```\n\nNow we're able to create a `Permission` without specifying the `enabled`\nattribute and it takes on the default of `true`.\n\n[source](https://dev.to/baweaver/new-in-ruby-32-datadefine-2819#comment-254o8)\n"
  },
  {
    "path": "ruby/specify-dependencies-for-a-rake-task.md",
    "content": "# Specify Dependencies For A Rake Task\n\nLet's say you have rake task that performs some important business task. For\ninstance, a book seller might want a task that can tell them the top selling\nbooks from a CSV report.\n\n```ruby\ntask :top_selling_books do\n  # read in CSV and process for top selling books\nend\n```\n\nThis works great if the CSV file already exists on the machine from which this\ntask is run. What if it isn't tho?\n\nThe CSV is a prerequesite for this task. We explicitly define it as a\nprerequisite using the task dependency syntax.\n\n```ruby\ntask :download_latest_book_sales_csv do\n  # saves a CSV of book sales\nend\n\ntask top_selling_books: :download_latest_book_sales_csv do\n  # read in CSV and process for top selling books\nend\n```\n\nWe can even define multiple task dependencies with an array.\n\n```ruby\ntask top_selling_books: [:download_latest_book_sales_csv, :clean_csv] do\n  # read in CSV and process for top selling books\nend\n```\n\n[source](https://subscription.packtpub.com/book/hardware_and_creative/9781783280773/1/ch01lvl1sec13/task-dependencies-prerequisites)\n"
  },
  {
    "path": "ruby/specify-how-random-array-sample-is.md",
    "content": "# Specify How Random Array#sample Is\n\nA typical use of the\n[`sample`](https://ruby-doc.org/core-2.4.0/Array.html#method-i-sample) method\non [`Array`](https://ruby-doc.org/core-2.4.0/Array.html) will look something\nlike this:\n\n```ruby\n> chars = [('a'..'z'), ('A'..'Z'), ('0'..'9')].map(&:to_a).flatten\n\n> chars.sample(6)\n=> [\"o\", \"Z\", \"X\", \"i\", \"8\", \"Y\"]\n```\n\nBy default, this is using `Random` (a pseudo-random number generator) to\nproduce a _random_ sampling of elements from your array.\n\nThe longer form of this looks like:\n\n```ruby\n> chars.sample(6, random: Random)\n=> [\"F\", \"c\", \"g\", \"I\", \"w\", \"E\"]\n```\n\nOr to get reproducible results, you can specify the `Random` seed:\n\n```ruby\n> chars.sample(6, random: Random.new(123))\n=> [\"T\", \"c\", \"D\", \"K\", \"P\", \"s\"]\n```\n\nIf instead you want a cryptographically random sampling of elements from your\narray, you can specify a different random number generator. Such as\n[`SecureRandom`](https://ruby-doc.org/stdlib-2.5.1/libdoc/securerandom/rdoc/SecureRandom.html).\n\n```ruby\n> require 'securerandom'\n=> true\n\n> chars.sample(6, random: SecureRandom)\n=> [\"3\", \"C\", \"o\", \"i\", \"K\", \"4\"]\n```\n\nThe\n[`Array#shuffle`](https://ruby-doc.org/core-2.4.0/Array.html#method-i-shuffle)\nmethod is another example of a method that can take a `random` option.\n"
  },
  {
    "path": "ruby/split-a-float-into-its-integer-and-decimal.md",
    "content": "# Split A Float Into Its Integer And Decimal\n\nLet's say we have a float value like `3.725`. We want to break it up into its\nconstituent parts -- the integer part (`3`) and the decimal part (`0.725`).\n\nThis can be done with the `divmod` method on the `Numeric` class.\n\n```ruby\n3.725.divmod(1)\n=> [3, 0.7250000000000001]\n```\n\nIn the general case, this method gives you the quotient and the modulus of\ndividing the number by the given value. When that given value is specifically\n`1`, it will give you those two parts of the float.\n\nOne place where this might be useful is when trying to convert a float\nrepresenting an amount of time into hours and minutes.\n\n```ruby\nhours = 3.725\n\nhours_digit, percentage_minutes = hours.divmod(1)\n\nminutes = (60 * percentage_minutes).to_i\nhours_standard = \"#{hours_digit}:#{minutes}\"\n```\n\n[source](https://ruby-doc.org/core-2.5.3/Numeric.html#method-i-divmod)\n"
  },
  {
    "path": "ruby/squeeze-out-the-extra-space.md",
    "content": "# Squeeze Out The Extra Space\n\nRemove all the excess spaces from a string using the squeeze method:\n\n```ruby\n> \"this  is   a string\".squeeze(' ')\n=> \"this is a string\"\n```\n"
  },
  {
    "path": "ruby/stack-heredocs-in-a-method-call.md",
    "content": "# Stack Heredocs In A Method Call\n\nWhen you put a heredoc directly in a method call as an argument, it is only the\nopening identifier that goes in the argument list.\n\nThat looks like this:\n\n```ruby\nexecute_in_transaction(<<~SQL)\n  update reading_statuses\n  set status = 'abandoned'\n  where started_at < (now() - '2 years'::interval)\n    and finished_at is null;\nSQL\n```\n\nYou might imagine then that we can put multiple heredocs in a method call. That\nleads to [_stacked\nheredocs_](https://www.visualmode.dev/ruby-operators/heredoc#stacked-heredocs).\n\n```ruby\nexecute_in_transaction(<<~SQL1, <<~SQL2, <<~SQL3)\n  update reading_statuses\n  set status = 'abandoned'\n  where started_at < (now() - '2 years'::interval)\n    and finished_at is null;\nSQL1\n  insert into activity_log (name, description)\n  values ('abandon_books', 'Mark unread books as abandoned');\nSQL2\n  delete from background_jobs\n  where id = #{job_id}; -- better to sanitize values like this\nSQL3\n```\n\nNotice we terminate the body of each heredoc with its closing identifier and\nimmediately begin the body of the next one.\n"
  },
  {
    "path": "ruby/string-interpolation-with-instance-variables.md",
    "content": "# String Interpolation With Instance Variables\n\nWhen using regular variables with string interpolation in Ruby, they must be\nwrapped in curly braces (e.g. `\"This is a #{variable}\"`). With instance\nvariables (and class and global variables) you can just use the _octothorp_\nfollowed directly by the variable.\n\nHere is an example of this in action:\n\n```ruby\nclass Person\n  def initialize(name)\n    @name = name\n  end\n\n  def whoami\n    puts \"I am #@name\"\n  end\nend\n\nbob = Person.new(\"bob\")\n#=> #<Person:0x007fdaf3291618 @name=\"bob\">\n\nbob.whoami\n# I am bob\n```\n\nThis is a handy shortcut, but may affect readability and/or result in an\ninterpolation error at some point. Your mileage may vary.\n\nh/t Josh Davey\n"
  },
  {
    "path": "ruby/summing-collections.md",
    "content": "# Summing Collections\n\nGiven a hash, `my_hash`,\n\n```ruby\nmy_hash = {\n    \"one\" => 1,\n    \"two\" => 2,\n    \"three\" => 5\n}\n```\n\nI want to determine the sum of the values in `my_hash`, which should be `8`.\n\nThis is similar to asking for the sum of the values in an array. In fact,\nusing `#values` on `my_hash` will leave us with the task of summing the\nvalues in an array.\n\nIt turns out that to sum the values in an array, all you need is `#inject`\n\n```ruby\n[1,2,5].inject(:+)\n=> 8\n```\n\nSo, if I want the sum of the values in a hash, such as `my_hash`, then all\nthat is needed is\n\n```ruby\nmy_hash.values.inject(:+)\n=> 8\n```\n\nTo take this one step further, let's consider what will happen with an empty\narray. The above approach will produce `nil`. If we want `0` when the list\nis empty, then tell `#inject` to do just that\n\n```ruby\n[].inject(0, :+)\n=> 0\n```\n\n[source](http://stackoverflow.com/questions/1538789/how-to-sum-array-of-numbers-in-ruby)\n"
  },
  {
    "path": "ruby/triple-equals-the-case-equality-operator.md",
    "content": "# Triple Equals: The Case Equality Operator\n\nThe standard equality operator in Ruby is the double equals (`==`).\n\n```ruby\n> 2 + 2 == 4\n=> true\n```\n\nRuby supports another operator that looks sneakily like this, but with\ndifferent behavior. It's the triple equals (`===`) which is called the [case\nequality\noperator](https://ruby-doc.org/core-3.0.3/Object.html#method-i-3D-3D-3D) (or\ncase subsumption operator).\n\nThough the specific behavior can be overridden on a class by class basis, the\noperator is generally used to check if the first operand is a bucket that the\nsecond operand fits into.\n\nHere are some examples:\n\n```ruby\n> (1..10) === 5\n=> true\n> (1..10) === 13\n=> false\n\n> Integer === 7\n=> true\n> Integer === 'nope'\n=> false\n\n> /fun/ === \"fundamentals\"\n=> true\n> /taco/ === \"fundamentals\"\n=> false\n\n> Object === String\n=> true\n> String === Object\n=> false\n```\n\nIt's important to understand how this works because `===` is the operator used\nunder the hood by Ruby's case statements.\n\n[source](https://stackoverflow.com/questions/4467538/what-does-the-operator-do-in-ruby/4467823#4467823)\n"
  },
  {
    "path": "ruby/turn-key-and-values-arrays-into-a-hash.md",
    "content": "# Turn Key And Value Arrays Into A Hash\n\nLet's say you have an array of keys and an array of values:\n\n```ruby\nkeys = [:title, :author, :year]\nvalues = [\"The Fifth Season\", \"N. K. Jemisin\", 2015]\n```\n\nYou can turn them into a hash where the keys of that hash come from `keys` and\nare tied in order, one-to-one with the `values`.\n\nA `hash` can be created from an array of tuples, where each is a key-value\npairing. Knowing this, we can `zip` the two arrays together and then turn them\ninto a `hash` like so:\n\n```ruby\n> Hash[keys.zip(values)]\n#=> {:title=>\"The Fifth Season\", :author=>\"N. K. Jemisin\", :year=>2015}\n```\n\n[source](https://stackoverflow.com/a/23113943/535590)\n"
  },
  {
    "path": "ruby/turning-any-class-into-an-enumerator.md",
    "content": "# Turning Any Class Into An Enumerator\n\nAt the core of any enumerator is the ability to respond to an `#each` call.\nWith that in mind, we prepare any class for being turned into an enumerator.\n\nConsider this class `SquaresCollection` that allows you to turn an array of\nintegers into an array of its squares.\n\n```ruby\nclass SquaresCollection\n  def initialize(items)\n    @items = items\n  end\n\n  def run\n    @items.map { |item| item * item }\n  end\nend\n\nSquaresCollection.new([1,2,3]).run #=> [1,4,9]\n```\n\nWe can work with this, but it opts out of Ruby's enumerator offerings.\n\nWe can, instead, provide an `#each` method which allows instances of our\n`SquaresCollection` class to be turned into enumerators.\n\n```ruby\nclass SquaresCollection\n  def initialize(items)\n    @items = items\n  end\n\n  def each\n    return enum_for(:each) unless block_given?\n\n    @items.each do |item|\n      yield item * item\n    end\n  end\nend\n```\n\nHere is how we can use it:\n\n```ruby\nsc = SquaresCollection.new([1,2,3])\n\nputs sc.to_enum\n#=> <Enumerator ...>\n\nputs sc.to_enum.map { |item| \"* #{item} *\" }\n#=> [\"* 1 *\", \"* 4 *\", \"* 9 *\"]\n```\n\nThe [`#to_enum`](https://devdocs.io/ruby~2.5/object#method-i-to_enum) method\nlooks for an `#each` method on the instance's class and uses that to create an\nenumerator.\n\n[source](https://blog.arkency.com/2014/01/ruby-to-enum-for-enumerator/)\n"
  },
  {
    "path": "ruby/turning-things-into-hashes.md",
    "content": "# Turning Things Into Hashes\n\nWe have `#to_h` for turning things into hashes.\n\nIt works as an identity function:\n\n```ruby\n> {}.to_h\n=> {}\n> {hello: \"world\"}.to_h\n=> {:hello=>\"world\"}\n```\n\nIt works with `nil`:\n\n```ruby\n> nil.to_h\n=> {}\n```\n\nDoes it work with arrays?\n\n```ruby\n> [:one, 2].to_h\nTypeError: wrong element type Symbol at 0 (expected array)\nfrom (pry):36:in `to_h'\n```\n\nYes, but only if it is an array of pairs:\n\n```ruby\n> [[:one, 2], [:three, 4]].to_h\n=> {:one=>2, :three=>4}\n```\n\nIt also works with `Struct` and `OpenStruct`:\n\n```\n> Person = Struct.new(:name, :age)\n=> Person\n> bob = Person.new(\"bob\", 45)\n=> #<struct Person name=\"bob\", age=45>\n> bob.to_h\n=> {:name=>\"bob\", :age=>45}\n```\n\nYou'll find that many other objects and gems support `#to_h` when it makes\nsense.\n"
  },
  {
    "path": "ruby/uncaught-exceptions-in-pry.md",
    "content": "# Uncaught Exceptions In Pry\n\nYou are fiddling around with some code in a pry session trying to\nfamiliarize yourself with how it all works. You suddenly execute a statement\nthat results in an uncaught exception. You'd like to take a closer look at\nthe exception. Pry makes this easy by exposing the `_ex_` variable which\npoints to the last uncaught exception.\n\nTry it out in a pry session:\n\n```ruby\n> class MyError < StandardError; end\n=> nil\n> def do_stuff; raise MyError, \"Something bad happened\"; end\n=> :do_stuff\n> do_stuff\nMyError: Something bad happened\nfrom (pry):2:in `do_stuff'\n> _ex_\n=> #<MyError: Something bad happened>\n```\n"
  },
  {
    "path": "ruby/undef-method-and-the-inheritance-hierarchy.md",
    "content": "# `undef_method` And The Inheritance Hierarchy\n\nAs the docs state, Ruby's\n[`undef_method`](http://ruby-doc.org/core-2.2.0/Module.html#method-i-undef_method)\n\n> prevents the current class from responding to calls to the named method.\n\nThis means you can do some weird things to the inheritance hierarchy. I'll\nuse the following code example to illustrate.\n\n```ruby\nclass Phone\n  def ring\n    puts 'brrrrriiing'\n  end\nend\n\nclass Smartphone < Phone\n  def ring\n    puts 'boop beep boop'\n  end\nend\n\nclass Iphone < Smartphone\nend\n\nsmartphone = Smartphone.new\niphone = Iphone.new\n\nsmartphone.ring\n#=> boop beep boop\niphone.ring\n#=> boop beep boop\n```\n\nEverything works as expect. Now, I'll use `undef_method`.\n\n```ruby\nclass Smartphone\n  undef_method(:ring)\nend\n\nsmartphone.ring\n#=> NoMethodError: undefined method `ring' for #<Smartphone:0x007fd0a20b7960>\niphone.ring\n#=> NoMethodError: undefined method `ring' for #<Iphone:0x007fd0a20b7938>\n```\n\nNot only have instances of `Smartphone` been prevented from responding to\n`ring`, but any subclasses of `Smartphone` that call `ring` will get tripped\nup when traversing the inheritance hierarchy in search of a definition of\n`ring`.\n"
  },
  {
    "path": "ruby/uninstall-specific-version-of-a-ruby-gem.md",
    "content": "# Uninstall Specific Version Of A Ruby Gem\n\nI have two versions of `bundler` installed on my machine—`2.2.4` and `2.2.10`.\nWhen I check the version of bundler, I see it references the latest one.\n\n```bash\n$ bundle --version\nBundler version 2.2.10\n```\n\nI want to get rid of `2.2.10` so that I can use `2.2.4` instead. This can be\ndone by uninstalling that specific version of `bundler`.\n \nTo do this, specify the `-v` flag when running `gem uninstall`.\n\n```bash\n$ gem uninstall bundler -v 2.2.10\nSuccessfully uninstalled bundler-2.2.10\n$ bundle --version\nBundler version 2.2.4\n```\n\nAlternatively, if you want to use a different version of a gem without\nuninstalling the primary version, you can [specify the version after the gem\nname when calling it](run-an-older-version-of-bundler.md).\n\n[source](https://stackoverflow.com/questions/23887726/rails-uninstall-specific-version-of-a-library-using-gem)\n"
  },
  {
    "path": "ruby/unpacking-strings-into-binary.md",
    "content": "# Unpacking Strings Into Binary\n\nYou can find the binary representation of a given string by decoding it. Ruby\ncomes equipped with the [`#unpack`](https://apidock.com/ruby/String/unpack)\nmethod on the `String` class that can do this decoding.\n\nThough there are a variety of formats to decode a string into, here are some\nexample of decoding different characters into binary.\n\n```ruby\n> \"A\".unpack(\"B*\")\n=> [\"01000001\"]\n```\n\nThe `B*` says _unpack_ this into as many *B*inary digits as are needed. The\nUTF-8 encoding, means only a single byte (8-bits) are needed to represent\n`\"A\"`.\n\n```ruby\nirb(main):002:0> \"Æ\".unpack(\"B*\")\n=> [\"1100001110000110\"]\nirb(main):003:0> \"Æ\".unpack(\"B8 B8\")\n=> [\"11000011\", \"10000110\"]\n```\n\n`\"Æ\"` is represented by two bytes. We can unpack each byte seprarately using\n`\"B8 B8\"`.\n\n```ruby\nirb(main):004:0> \"木\".unpack(\"B*\")\n=> [\"111001101001110010101000\"]\nirb(main):005:0> \"木\".unpack(\"B8 B8 B8\")\n=> [\"11100110\", \"10011100\", \"10101000\"]\n```\n\nSimilarly, this Japanese character is represented by three bytes of data.\n\n```ruby\nirb(main):006:0> \"👻\".unpack(\"B*\")\n=> [\"11110000100111111001000110111011\"]\nirb(main):007:0> \"👻\".unpack(\"B8 B8 B8 B8\")\n=> [\"11110000\", \"10011111\", \"10010001\", \"10111011\"]\n```\n\nLastly, emojis generally require four bytes of data.\n\n[source](https://www.honeybadger.io/blog/the-rubyist-guide-to-unicode-utf8/)\n"
  },
  {
    "path": "ruby/up-and-down-with-integers.md",
    "content": "# Up And Down With Integers\n\nRuby's [`Integer`](http://ruby-doc.org/core-2.2.0/Integer.html) class comes\nwith an `#upto` and a `#downto` method. Both of these methods can be used to\niterate from one number up or down to, respectively, another number.\n\nLet's count to 3\n\n```ruby\n> 1.upto(3) { |x| puts x }\n1\n2\n3\n```\n\nThis of course can easily and perhaps more idiomatically be accomplished\nwith a range and the `#each` method (e.g. `(1..3).each { |x| puts x }`.\n\nWe cannot, however, simulate the `#downto` method with a range (at least,\nnot very cleanly). So, if you need to count down to something, this is going\nto be the cleanest and clearest way.\n\n```ruby\n> 5.downto(2) { |x| puts x }\n5\n4\n3\n2\n```\n\nThe return value for both methods is always the integer we started with.\n"
  },
  {
    "path": "ruby/update-the-gemfile-bundled-with-version.md",
    "content": "# Update The Gemfile Bundled With Version\n\nWhen you run `bundle install`, whatever is the latest version of `bundler`\ninstalled locally will be used. Your `Gemfile` dependencies will be installed\nand the `Gemfile.lock` will be marked at the bottom with a signature for the\nversion of `bundler` that was used.\n\n```ruby\n# Gemfile.lock\n...\n\nBUNDLED WITH\n   1.1.17\n```\n\nOn future `bundle install` calls, a matching major version of Bundler will be\nused. If you'd like to migrate from 1.x.x to 2.x.x or vice versa, or even if\nyou want to explicitly change minor versions, you can run:\n\n```bash\n$ bundle update --bundler=2.2.4\n```\n\nThis will bundle your project with `2.2.4` and update the `BUNDLED WITH`\nsection to reflect that.\n\nUse the version that makes sense for you with the `--bundler` flag.\n\n[source](https://bundler.io/guides/bundler_2_upgrade.html#upgrading-applications-from-bundler-1-to-bundler-2)\n"
  },
  {
    "path": "ruby/use-a-case-statement-as-a-cond-statement.md",
    "content": "# Use A Case Statement As A Cond Statement\n\nMany languages come with a feature that usually takes the name _cond\nstatement_. It is essentially another way of writing an _if-elsif-else_\nstatement. The first conditional in the _cond statement_ to evaluate to true\nwill then have its block evaluated.\n\nRuby doesn't have a _cond statement_, but it does have a _case statement_.\nBy using a _case statement_ with no arguments, we get a _cond statement_. If\nwe exclude arguments and then put arbitrary conditional statements after the\n`when` keywords, we get a construct that acts like a _cond statement_. Check\nout the following example:\n\n```ruby\nsome_string = \"What\"\n\ncase\nwhen some_string.downcase == some_string\n  puts \"The string is all lowercase.\"\nwhen some_string.upcase == some_string\n  puts \"The string is all uppercase.\"\nelse\n  puts \"The string is mixed case.\"\nend\n\n#=> The string is mixed case.\n```\n\n[source](http://www.skorks.com/2009/08/how-a-ruby-case-statement-works-and-what-you-can-do-with-it/)\n"
  },
  {
    "path": "ruby/use-dotenv-in-a-non-rails-project.md",
    "content": "# Use dotenv In A Non-Rails Project\n\nUp to now I've only used [`dotenv`](https://github.com/bkeepers/dotenv) in a\nRails context. It can just as easily be used in a plain old Ruby project.\n\nInstall the non-Rails version of the gem.\n\n```bash\n$ gem install dotenv\n```\n\nThen add the following lines wherever you want `dotenv` included and loaded.\nIn my case, I want it pulled in as part of my RSpec setup in\n`spec_helper.rb`.\n\n```ruby\nrequire 'dotenv'\nDotenv.load\n```\n\nYour environment variables declared in `.env` are now accessible via fetches\nagainst the `ENV` object.\n\n```ruby\nENV.fetch('my_env_var')\n```\n"
  },
  {
    "path": "ruby/use-tap-for-better-test-data-setup.md",
    "content": "# Use Tap For Better Test Data Setup\n\nI often use RSpec's `let` statement to set up some test data.\n\n```ruby\nlet(:order) { create(:order, name: \"My Order\") }\n```\n\nOften times, realistic test data requires setting up peripheral data as well.\n\n```ruby\nlet(:order) do\n  order = create(:order, name: \"My Order\")\n  create(:item, name: \"Burger\", order: order, price: 4.99)\n  create(:item, name: \"Fries\", order: order, price: 2.99)\n  order\nend\n```\n\nThis can get hard to read as the subject of the `let` gets obscured. It is also\nclumsy that we have to end with returning the `order`. This can be cleaned up\nwith the use of [`#tap`](https://devdocs.io/ruby~2.5/object#method-i-tap).\n\n```ruby\nlet(:order) do\n  create(:order, name: \"My Order\").tap do |order|\n    create(:item, name: \"Burger\", order: order, price: 4.99)\n    create(:item, name: \"Fries\", order: order, price: 2.99)\n  end\nend\n```\n\nThe block notation and indentation make it clear that the `order` is what is\ngetting created. Meanwhile, the interior of the block gives us a designated\narea to do what we need to with the newly-created `order` instance.\n"
  },
  {
    "path": "ruby/using-bcrypt-to-create-and-check-hashed-passwords.md",
    "content": "# Using BCrypt To Create And Check Hashed Passwords\n\nThe [BCrypt](https://github.com/codahale/bcrypt-ruby) library is used under\nthe hood by gems like Devise in order to work with passwords securely. You\ncan use it to salt and hash a plain text password. You can also use it to\ncheck whether an encrypted password matches some input password.\n\n```ruby\n> include BCrypt\n=> Object\n\n> encrypted_pass = Password.create('password')\n=> \"$2a$10$te3Y8wdSXf8/gWDeSP5z9eut7alThnuTvq1SvgQyJ1C57F.qit1uq\"\n\n> Password.new(encrypted_pass) == \"not_my_pass\"\n=> false\n\n> Password.new(encrypted_pass) == \"password\"\n=> true\n```\n\nThe `Password.create` method will salt and hash the given password. The\nresulting encrypted password, if it is an instance of `Password`, can be\ndirectly compared to a string. For good measure, in case the encrypted\npassword is a string, you can wrap it in a call to `Password.new` to ensure\nyou are working with a `Password` instance.\n"
  },
  {
    "path": "ruby/what-to-do-when-you-dont-rescue.md",
    "content": "# What To Do When You Don't Rescue\n\nRuby's `rescue` syntax supports a couple different blocks. I was already\nfamiliar with `ensure` which is a block of code that will be executed\nregardless of whether or not an exception was rescued.\n\n```ruby\nbegin\n  do_something_that_could_fail()\nrescue StandardError => e\n  # oh no!\nensure\n  Logging.info(\"We attempted to do the thing.\")\nend\n```\n\nWhat if you want to differentiatee between an instance when your code ran\nwithout incident and when there was an exception? Ruby's `rescue` syntax also\nsupports an `else` block. The `else` block is executed only when nothing is\nrescued.\n\n```ruby\nbegin\n  do_something_that_could_fail()\nrescue StandardError => e\n  Logging.info(\"We tried to do something and it failed.\")\nelse\n  Logging.info(\"We successfully did the thing!\")\nend\n```\n\nThere are a lot of ways to use this. Here I was able to differentiate the\nmessaging in my logging based on whether or not an exception occurred.\n\n[source](https://blog.bigbinary.com/2017/10/24/ruby-2.5-allows-rescue-inside-do-end-blocks.html)\n"
  },
  {
    "path": "ruby/who-are-my-ancestors.md",
    "content": "# Who Are My Ancestors?\n\nRuby's `Module` class provides the\n[`#ancestors`](http://ruby-doc.org/core-2.1.0/Module.html#method-i-ancestors)\nmethod. This method allows you to determine the ancestors (parents,\ngrandparents, etc.) of a given class.\n\n```ruby\n> 5.class.ancestors\n=> [Fixnum, Integer, Numeric, Comparable, Object, PP::ObjectMixin, Kernel, BasicObject]\n> Array.ancestors\n=> [Array, Enumerable, Object, PP::ObjectMixin, Kernel, BasicObject]\n> Class.ancestors\n=> [Class, Module, Object, PP::ObjectMixin, Kernel, BasicObject]\n> BasicObject.ancestors\n=> [BasicObject]\n```\n"
  },
  {
    "path": "ruby/wrap-things-in-an-array-even-hashes.md",
    "content": "# Wrap Things In An Array, Even Hashes\n\nI've always used `Kernel::Array` to wrap things in an array. It works great.\n\n```ruby\n> Array(nil)\n#=> []\n> Array(1)\n#=> [1]\n> Array([\"hello\", \"world\"])\n#=> [\"hello\", \"world\"]\n```\n\nExcept with hashes, it might not do what you expect when given a hash.\n\n```ruby\n> Array({a: 1, b: 2})\n#=> [[:a, 1], [:b, 2]]\n```\n\nI just wanted the hash wrapped in an array, not turned into an array of tuples.\n\nThe `Array` class has a method `#wrap` which behaves similarly to\n`Kernal::Array` while also handling hashes in the way I was wanting.\n\n```ruby\n> Array.wrap(nil)\n#=> []\n> Array.wrap(1)\n#=> [1]\n> Array.wrap([\"hello\", \"world\"])\n#=> [\"hello\", \"world\"]\n> Array.wrap({a: 1, b: 2})\n#=> [{a: 1, b: 2}]\n```\n\n[source](https://devdocs.io/rails~5.2/array#method-c-wrap)\n"
  },
  {
    "path": "ruby/zero-padding.md",
    "content": "# Zero Padding\n\nRuby makes zero-padding strings to a fixed length easy with `String#rjust`.\n\n```ruby\n> \"1234\".rjust(6, \"0\")\n=> \"001234\"\n> \"123456\".rjust(6, \"0\")\n=> \"123456\"\n```\n\nIn the same way, you can pad zeros on the other side of the string with\n`String#ljust`.\n\n```ruby\n> \"12\".ljust(4, \"0\")\n=> \"1200\"\n> \"\".ljust(4, \"0\")\n=> \"0000\"\n```\n\nh/t Dillon Hafer\n"
  },
  {
    "path": "sed/apply-multiple-substitutions-to-the-input.md",
    "content": "# Apply Multiple Substitutions To The Input\n\nYou can apply multiple substitutions to the input of a `sed` command a couple\nways.\n\nOne of those ways is to use the `-e` flag multiple times to define\nsubstitutions that should be _appended_ to the `sed` script.\n\n```bash\n$ echo 123 | sed -e 's/3/three/' -e 's/1/one/'\none2three\n```\n\nAnother way is to define a single string as the `sed` script and separate each\nsubstitution with a `;` (semicolon).\n\n```bash\n$ echo 123 | sed 's/3/three/; s/1/one/'\none2three\n```\n\nEach of these will run each substitution in the `sed` script sequentially for\neach line in the input.\n"
  },
  {
    "path": "sed/equivalence-classes-of-repetition-metachars.md",
    "content": "# Equivalence Classes Of Repetition MetaChars\n\nThere are two types of Repetition MetaChars. The simple ones are `*`, `+`, and\n`?`. The general ones are ranges specified inside `{` and `}`. Here are\nequivalence classes between these two sets.\n\n_These use the -E (extended regex) option for OSX's `sed`._\n\n1. `*` is equivalent to `{0,}`\n\n_Zero or more of the preceeding character._\n\n```bash\n$ echo 'abc123' | sed -E 's/[[:alpha:]]*/!/'\n!123\n\n$ echo 'abc123' | sed -E 's/[[:alpha:]]{0,}/!/'\n!123\n```\n\n2. `+` is equivalent to `{1,}`\n\n_One or more of the preceeding character._\n\n```bash\n$ echo 'fix   the spacing' | sed -E 's/[ ]+/ /g'\nfix the spacing\n\n$ echo 'fix   the spacing' | sed -E 's/[ ]{1,}/ /g'\nfix the spacing\n```\n\n3. `?` is equivalent to `{0,1}`\n\n_Exactly zero or one of the preceeding character._\n\n```bash\n$ echo '#1, 2, 1oz' | sed -E 's/#?1/ONE/g'\nONE, 2, ONEoz\n\n$ echo '#1, 2, 1oz' | sed -E 's/#{0,1}1/ONE/g'\nONE, 2, ONEoz\n```\n\n[source](https://www.goodreads.com/book/show/19407377-definitive-guide-to-sed)\n"
  },
  {
    "path": "sed/extract-value-from-command-output-with-sed.md",
    "content": "# Extract Value From Command Output With Sed\n\nAs part of a shell script, you may need to extract a value from one command to\nbe used as part of a subsequent command.\n\nFor instance, [I recently wrote a\nscript](https://gist.github.com/jbranchaud/3cda6be6e1dc69c6f55435a387018dac)\nthat needed to determine the version of the currently running Postges server.\nThe `postgres` command can tell me that.\n\n```bash\n$ postgres -V\npostgres (PostgreSQL) 12.3\n```\n\nHowever, the output includes extra fluff that I don't need, namely the leading\n`postgres (PostgreSQL) ` part.\n\nThe output of `postgres` can be piped into a `sed` command that can extract\njust what I need.\n\n```bash\n$ postgres -V | sed -n 's/postgres (PostgreSQL) \\(.*\\)/\\1/p'\n12.3\n```\n\nThe `sed` command receives this single line of output and attempts a\nsubstituation. It matches on `postgres (PostgresSQL) ` followed by a capture\ngroup (`\\(.*\\)`) for the remaining characters. This capture group matches the\nversion part of the output. `sed` replaces everything in the first part of the\nsubstitution with `\\1`, which is `12.3`, and outputs that.\n\nThe output of this could then be piped to another command or captured in a\nvariable to be used in the remainder of a script.\n\n[source](https://stackoverflow.com/a/24572880/535590)\n"
  },
  {
    "path": "sed/grab-all-the-method-names-defined-in-a-ruby-file.md",
    "content": "# Grab All The Method Names Defined In A Ruby File\n\nI wanted a listing of all the methods defined in a Ruby file. Metaprogramming\naside, I figured I could write a one-line `sed` script to effectively do this.\n\n```bash\n$ sed -n 's/[[:space:]]*def \\([[:alnum:]_?!]*\\).*/\\1/p' file.rb\n```\n\nLet's break this down.\n\n- `[[:space:]]*` accounts for any level of indentation.\n- `def ` matches againts the start of a method definition.\n- `\\(...\\)` is a capture that can be referenced in the replace side of the\n  script.\n- `[[:alnum:]_?!]*` represents the characters that can make up a Ruby method\n  name, this is equivalent to writing `[a-zA-Z0-9_?!]*`.\n- `.*` is the final part of the regex match which ensures the rest of the line\n  is loaded into the pattern space so that the replacement will only be the\n  method name.\n- `\\1` replaces everything in the first part of the script with the capture\n  which is just the method name.\n- combining the `-n` and `p` flags ensures that only lines with substitutions\n  are printed.\n\nThis probably isn't perfect, but it is good enough to reference from time to\ntime in my shell history.\n"
  },
  {
    "path": "sed/grab-the-first-line-of-a-file.md",
    "content": "# Grab The First Line Of A File\n\nYou can grab the first line of a file with `sed` using either the `p` (print)\ncommand or the `d` (delete) command.\n\nFirst, the _print_ command can be told to print the line matching the line\nnumber `1`. That combined with the `-n` flag, which suppresses all lines not\nexplicitly printed, will print just the first line in the file.\n\n```bash\n$ sed '1 p' README.md\n# TIL\n```\n\nSecond, the _delete_ command can be told to delete all lines that aren't the\nfirst (`1`) line.\n\n```bash\n$ sed '1! d' README.md\n# TIL\n```\n\nThe `1` will match on the first line. By following it with `!`, that will\nnegate it so that it represents all lines except `1`.\n\nSee `man sed` for more details.\n\nNote: there are more efficient ways, not using `sed`, to get the first line in\na file. This is an exercise in using and understanding some `sed` features.\n"
  },
  {
    "path": "sed/osx-sed-does-regex-a-bit-different.md",
    "content": "# OSX sed Does Regex A Bit Different\n\nWith GNU sed, `\\+`, `\\?`, `\\(...\\)` and friends are considered extended regex\ncharacters. You can use them directly with the preceding backslashes. Or you\ncan include the `-r` flag to turn on extended regex and use them without.\n\n```bash\n$ echo '11+1 = 12' | sed 's/1+/3/'\n131 = 12\n$ echo '11+1 = 12' | sed -r 's/1+/3/'\n3+1 = 12\n```\n\nWith OSX sed, `\\+`, `\\?`, and `\\|` are not interpreted as part of the basic\nregex. To use them at all you need to include `-E` to turn on extended regex.\nThe capture characters (`\\(...\\)`) are available with basic regex.\n\n```bash\n# Basic, always treated as literal +\n$ echo '11+1 = 12' | sed 's/1+/3/'\n131 = 12\n$ echo '11+1 = 12' | sed 's/1\\+/3/'\n131 = 12\n\n# Extended, + is now a meta-character\n$ echo '11+1 = 12' | sed -E 's/1+/3/'\n3+1 = 12\n$ echo '11+1 = 12' | sed -E 's/1\\+/3/'\n131 = 12\n```\n\n[source](https://unix.stackexchange.com/a/131940/5916)\n"
  },
  {
    "path": "sed/output-only-lines-involved-in-a-substitution.md",
    "content": "# Output Only Lines Involved In A Substitution\n\nWhen you run a basic `sed` command, it will _autoprint_ the pattern space (a\nline of input) once it is done running the script against it. That means every\nline will get sent to stdout.\n\nYou can supress the autoprint functionality with the `-n` flag like so:\n\n```bash\n$ seq 100 | sed -n 's/1$/one/'\n```\n\nYou can then add the `p` flag to the end of the substitute command to tell it\nto _print_ any line that was affected by that substitution after the\nsubstitution has been applied.\n\n```bash\n$ seq 100 | sed -n 's/1$/one/p'\none\n1one\n2one\n3one\n4one\n5one\n6one\n7one\n8one\n9one\n```\n\nFor all numbers between 1 and 100, this matches those that end in `1` and\nsubstitutes that `1` for `one`. And then it is only those lines that go to\nstdout.\n\nIf you used the `p` flag without `-n`, every line would autoprint and then\nyou'd get duplicate output for each line that had a substitution.\n\nSee `man sed` for more details.\n"
  },
  {
    "path": "sed/reference-a-capture-in-the-regex.md",
    "content": "# Reference A Capture In The Regex\n\nYou create a capture group in a `sed` regex by wrapping a pattern in `\\(` and\n`\\)`. Generally, this capture group is referenced in the substitution\nexpression with `\\1`.\n\nThe capture references (e.g. `\\1`) can also be used in the regex as part of\nspecifying the match.\n\nFor instance, we can do a capture of a single digit followed by a reference to\nthat capture. That will match any line that has a pair of matching consecutive\ndigits.\n\n```bash\n$ seq 111 | sed -n 's/\\([[:digit:]]\\)\\1/&/p'\n11\n22\n33\n44\n55\n66\n77\n88\n99\n100\n110\n111\n```\n\nThis also uses `&` in the subex which represents the entire match. The `-n` and\n`/p` combination suppresses printing of lines to only those that have\nsubstitutions.\n"
  },
  {
    "path": "sed/reference-the-full-match-in-the-replacement.md",
    "content": "# Reference The Full Match In The Replacement\n\nThe `&` can be used in the replacement part of a `sed` expression as reference\nto the string match for this iteration of the expression. The occurrence of `&`\nwill be replaced with that entire match.\n\nAs the `sed` man page puts it:\n\n> An ampersand (“&”) appearing in the replacement is replaced by the string\n> matching the RE.\n\nI made use of this recently with [a `sed` expression that was evaluating a list\nof filenames that I wanted to construct into a sequence of `mv`\ncommands](unix/rename-a-bunch-of-files-by-constructing-mv-commands.md). I needed\nthe filename that I was matching on to appear as the first argument of the `mv`\ncommand I was constructing.\n\nHere is what that looks like:\n\n```bash\n$ ls *.pdf |\n  sed 's/\\(..\\)\\(..\\)\\(..\\) Statement\\.pdf/mv \"&\" \"20\\3-\\1-\\2-statement.pdf\"/'\n```\n\nNotice right after `mv` in literal quotes is the `&`. That will be replaced in\nthe resulting replacement with the full matching string of the regular\nexpression in the first part of the sed statement (`s/<RE>/`).\n"
  },
  {
    "path": "sed/use-an-alternative-delimiter-in-a-substitution.md",
    "content": "# Use An Alternative Delimiter In A Substitution\n\nA pretty standard sed substitution command is going to use `/` (the forward\nslash) as the delimiter. The delimiter separates the different parts of the\ncommand.\n\n```bash\n$ sed 's/critter/creature/' animals.txt\n```\n\nThe first delimiter marks the beginning of the regular express to be replaced.\nThat expression is everything up to the next delimiter. Then the substute\nexpression starts up until the next delimiter.\n\nThere is nothing special about the `/` as the delimiter, it just happens to be\nthe most commonly used character.\n\nIn fact, any visible character can be used as the delimiter with sed.\n\nSome other common ones are `:`, `|`, and `_`. I like how the `pipe` character\nlooks.\n\n```bash\n$ sed 's|critter|creature|' animals.txt\n```\n\nBut like I said, any visible character will work. If you wanted, you could use\n`Q` though that'll look strange and could cause some confusion when reading\nthrough your script.\n\n```bash\n$ sed 'sQcritterQcreatureQ' animals.txt\n```\n"
  },
  {
    "path": "shell/check-if-the-first-argument-is-given.md",
    "content": "# Check If The First Argument Is Given\n\nIn a shell script, you may want to check if an argument was given. Each\nargument is referenced numerically with the `$` prefix, so the first argument\nis `$1`. To check if the first argument is given, you can use the `-z` check.\n\n```bash\nif [ -z \"$1\" ]\n  then\n    echo \"The first argument is missing\"\n    exit 1\nfi\n```\n\nThe `-z` checks if the argument is a zero-length string (so `\"\"` or undefined\nwill be true). If it is missing, then we echo out a message and exit the\nscript. This is how I might fashion a script that requires the first argument.\n\n[source](https://stackoverflow.com/questions/6482377/check-existence-of-input-argument-in-a-bash-shell-script)\n"
  },
  {
    "path": "shell/format-and-print-the-current-date-and-time.md",
    "content": "# Format And Print The Current Date And Time\n\nIf I run the `date` command from the terminal, I get output like the following:\n\n```bash\n$ date\nFri Jan 22 13:45:44 CST 2021\n```\n\nIf I want to format the date output different, perhaps for inclusion in a shell\nscript, I can do something like this:\n\n```bash\n$ date +\"%Y/%m/%d %H:%M:%S\"\n2021/01/22 13:47:55\n```\n\nThen I can incorporate that in a script like this:\n\n```bash\nnow() {\n  echo \"Today: $(date +'%Y/%m/%d %H:%M:%S')\"\n}\n```\n\nThis\n[page](https://www.tutorialkart.com/bash-shell-scripting/bash-date-format-options-examples/)\nincludes some examples and a page of formatting options.\n"
  },
  {
    "path": "sqlite/display-results-in-readable-column-format.md",
    "content": "# Display Results In Readable Column Format\n\nBy default the output of a query or pragma command will be pretty squished and\nunreadable.\n\n```sql\nsqlite> PRAGMA table_info(User);\n0|id|TEXT|1||1\n1|name|TEXT|0||0\n2|email|TEXT|0||0\n3|emailVerified|DATETIME|0||0\n4|image|TEXT|0||0\n```\n\nHowever, this can be improved by setting the output `mode` to `column`.\n\n```sql\nsqlite> .mode column\n```\n\nWith that set, we can run the same command which will now output nicely\nformatted columns with headers.\n\n```sql\nsqlite> PRAGMA table_info(User);\ncid  name           type      notnull  dflt_value  pk\n---  -------------  --------  -------  ----------  --\n0    id             TEXT      1                    1\n1    name           TEXT      0                    0\n2    email          TEXT      0                    0\n3    emailVerified  DATETIME  0                    0\n4    image          TEXT      0                    0\n```\n\nFor more details on this and the many other output modes, check out [the\ndocs](https://sqlite.org/cli.html#changing_output_formats).\n"
  },
  {
    "path": "sqlite/explore-the-database-schema.md",
    "content": "# Explore The Database Schema\n\nThe first thing I like to do when connecting to a database is get a quick lay\nof the land. What are the tables and what do they look like?\n\nI can list all tables with the `.tables` dot-command.\n\n```sql\nsqlite> .tables\ningredient_amounts  ingredients         recipes\n```\n\nI can then look at the `create table` statement for specific tables to see what\ntheir schema looks like:\n\n```sql\nsqlite> .schema recipes\nCREATE TABLE recipes (\n  id integer primary key,\n  name varchar not null,\n  description text not null,\n  instructions text not null\n);\n```\n\nThe `.schema` dot-command can also be used without any argument and it will\ndisplay the schema for all tables of all connected databases.\n\nRun `.help` from the `sqlite3` prompt for more dot-command options.\n\n[source](https://www.sqlite.org/cli.html#querying_the_database_schema)\n"
  },
  {
    "path": "streaming/monitor-an-audio-input-device-in-obs.md",
    "content": "# Monitor An Audio Input Device In OBS\n\nI hooked up a Mirabox HDMI capture card with loop out between my Xbox 360 and\ndisplay. It passes the feed through to my MacBook Pro. Both the video and audio\npass through cleanly to OBS and I've been streaming successfully to Twitch with\nthat setup.\n\nI then wanted to add my headphones and Blue Yeti microphone into the setup so\nthat I could hear the game audio and talk during the stream.\n\nDespite OBS picking up the audio through the Audio Input Device, I couldn't\nhear it in my headphones. That's because by default _Audio Monitoring_ is\nturned off for audio devices.\n\nIf I want to be able to hear the sound and pass it through as output to OBS, I\nhave to change the _Audio Monitoring_ setting for that device. In the _Audio\nMixer_ section, there is a gear icon next to the audio device. I click that and\nchoose _Advanced Audio Properties_. From there, I change that device's Audio\nMonitoring setting from _Monitor Off_ to _Monitor and Output_.\n\nNow I am able to hear the audio that is coming through Mirabox from my Xbox.\nAnd anyone watching my stream can hear it too.\n"
  },
  {
    "path": "tailwind/apply-tailwind-classes-to-existing-css-class.md",
    "content": "# Apply Tailwind Classes To Existing CSS Class\n\nLet's say I have some HTML in my app that I don't totally control -- maybe it's\na 3rd-party component or it was rendered by a markdown transformer. Regardless,\nI am ending up with some HTML where tags have class names that I'd like to\nstyle.\n\n```html\n<div class=\"code-block\">\n  <!-- ... -->\n</div>\n```\n\nIf it was HTML (or JSX) that I was writing, I could stick whatever tailwind\nclass names I wanted on the various tags to get the styling just right. But\nsince I don't control it directly, I have to find another way to _apply_ those\ntailwind classes.\n\nEnter [tailwind's `@apply`\ndirective](https://tailwindcss.com/docs/functions-and-directives#apply). With\nthis, I can target an existing class selector with any tailwind utility classes.\nAdd lines like the following to your root `tailwind.css` file.\n\n```css\n@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n/* additional styling here 👇 */\n.code-block {\n  @apply bg-gray-200 rounded-md p-4;\n}\n```\n"
  },
  {
    "path": "tailwind/base-styles-for-text-link.md",
    "content": "# Base Styles For Text Link\n\n[Tailwind CSS](https://tailwindcss.com/)'s base styles directive includes a CSS\nreset called [Preflight](https://tailwindcss.com/docs/preflight). It normalizes\nstyling inconsistencies between browsers, and in the process it wipes out a\nbunch of default styles you might be expecting.\n\nA notable one is styling for a text link (`<a href ...>link</a>`). These tend\nto be blue with an underline, use the _pointer_ cursor, and sometimes change\ncolor slightly when you hover or _activate_ them.\n\nBreaking from that mold a little, here is a reasonable base style for a text\nlink:\n\n```html\n<a\n  className=\"underline text-purple-600 cursor-pointer hover:text-purple-800\"\n  href=\"https://twitter.com/jbrancha\"\n>\n  twitter\n</a>\n```\n\nThis adds the `text-decoration: underline`, some color, the `cursor: pointer`,\nand a slightly darker color on hover.\n\nAnd for a slight variation, I'll make the `underline` text decoration appear\nonly on hover:\n\n```css\n<a\n  className=\"hover:underline text-purple-600 cursor-pointer hover:text-purple-800\"\n  href=\"https://twitter.com/jbrancha\"\n>\n  twitter\n</a>\n```\n"
  },
  {
    "path": "tailwind/disable-and-enable-a-button.md",
    "content": "# Disable And Enable A Button\n\nWith TailwindCSS we can take a couple different approaches to tie the visual\nand functional interactivity of a button to another elements state using\nclasses.\n\nOne approach is to use\n[`peer`](https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-sibling-state)\nand `peer-checked:<class>`.\n\n```html\n<div>\n  <input\n    type=\"checkbox\"\n    id=\"peer-enable\"\n    class=\"w-5 h-5 cursor-pointer peer\"\n  />\n  <label\n    for=\"peer-enable\"\n    class=\"cursor-pointer text-slate-700 font-medium\"\n  >\n    I agree to the terms and conditions\n  </label>\n  <button\n    class=\"opacity-40 pointer-events-none grayscale cursor-not-allowed peer-checked:opacity-100 peer-checked:pointer-events-auto peer-checked:grayscale-0 peer-checked:cursor-pointer\"\n  >\n    Peer Submit\n  </button>\n</div>\n```\n\nClasses to make to button appear disabled (e.g. `opacity-40`) as well as\nfunctional classes that affect interactivity (e.g. `pointer-events-none`) are\napplied by default. When the sibling checkbox gets checked, the inverted\nclasses take effect making the button enabled.\n\nThe `peer` approach works, but lacks flexibility. As soon as I need to make any\nstructural changes to the HTML that sever the peer (i.e. sibling) relationship\nof the checkbox and the button, those classes stop working.\n\nWith\n[`group`](https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-the-descendants-of-a-group)\nand `group-has-[:checked]:<class>`, I can style the button relative to another\ngroup member as long as everything is nested under some shared group tag.\n\n```html\n<div class=\"group\">\n  <div class=\"flex items-center gap-3\">\n    <input\n      type=\"checkbox\"\n      id=\"group-enable\"\n      class=\"w-5 h-5 cursor-pointer\"\n    />\n    <label\n      for=\"group-enable\"\n      class=\"cursor-pointer text-slate-700 font-medium\"\n    >\n      I agree to the terms and conditions\n    </label>\n  </div>\n  <button\n    class=\"opacity-40 pointer-events-none grayscale cursor-not-allowed group-has-[:checked]:opacity-100 group-has-[:checked]:pointer-events-auto group-has-[:checked]:grayscale-0 group-has-[:checked]:cursor-pointer\"\n  >\n    Group Submit\n  </button>\n</div>\n```\n\nWe can even utilize [named\ngroups](https://tailwindcss.com/docs/hover-focus-and-other-states#differentiating-nested-groups)\nif we have overlapping and conflicting group interactions. But I won't get into\nthat here.\n"
  },
  {
    "path": "tailwind/specify-paths-for-purging-unused-css.md",
    "content": "# Specify Paths For Purging Unused CSS\n\nTailwind CSS is a full-featured utility class CSS framework. It has just about\neverything you need. It also has a bunch of things you probably don't need. And\nthere is no need to ship the CSS you don't need to the client. Tailwind is able\nto exclude the unused CSS through a mechanism called _purging_.\n\nTo turn on purging (for _production_) and for Tailwind to know what can be\nsafely purged, you need to specify one or more _purge paths_ in your\n`tailwind.config.js` file. This is a listing of all the places where you use\nTailwind utility classes.\n\nSpecify it with an array at the `purge` key:\n\n```javascript\nmodule.exports = {\n  purge: [\n    \"./src/components/**/*.jsx\",\n    \"./pages/**/*.js\"\n  ],\n  darkMode: false,\n  theme: {\n    extend: {},\n  },\n  variants: {\n    extend: {},\n  },\n  plugins: [],\n};\n```\n\nNotice that globbed paths can be used as a way of specifying files located in a\nnested directory structure. Above I've stated that any `jsx` files located\nanywhere under `src/components/` as well as any `js` files located anywhere\nunder `pages/` should be checked.\n\n[source](https://tailwindcss.com/docs/optimizing-for-production#basic-usage)\n"
  },
  {
    "path": "tailwind/use-tailwind-typography-prose-in-dark-mode.md",
    "content": "# Use Tailwind Typography Prose In Dark Mode\n\nTailwindcss can be set up to provide styled defaults for both standard (light)\nmode and dark mode. Once this is set up, you can add a toggle mechanism to\nswitch between light and dark mode. [This\npost](https://egghead.io/blog/tailwindcss-dark-mode-nextjs-typography-prose)\ngoes into all those details.\n\nThis can even be used with [Tailwind's\ntypography](https://github.com/tailwindlabs/tailwindcss-typography) plugin.\n`typography` provides default styling which is great if you don't control the\nmarkup that is being rendered or if you want to provide some defaults to a\nchunk of markup.\n\nA chunk of markup that uses typography will minimally look something like this:\n\n```jsx\n<div className=\"prose\">\n  <h1>{title}</h1>\n  {markdownAsHtml}\n</div>\n```\n\nTo give this reasonable dark mode defaults, you'll need to add a `dark`-mode\nclass as well. Using the `dark` prefix, you can apply the `prose-dark` class to\nthe top-level div.\n\n```jsx\n<div className=\"prose dark:prose-dark\">\n  <h1>{title}</h1>\n  {markdownAsHtml}\n</div>\n```\n"
  },
  {
    "path": "taskfile/create-interactive-picker-for-set-of-subtasks.md",
    "content": "# Create Interactive Picker For Set Of Subtasks\n\nFor [my TIL repo](https://github.com/jbranchaud/til), I have a `Taskfile.yml`\nthat defines a set of `notes:*` tasks for interacting with a `NOTES.md` file\nthat lives in a private Git submodule.\n\nI wanted to make it easier on myself to not have to remember all the different\n`notes` subtasks, so I created a helper task to make it easy to see the options\nand run one.\n\nA summary of the Taskfile is shown below including the entirety of the `notes`\ntask. That task will parse a listing of the available tasks (via `task --list`\nand some `sed` commands) and pass those to `fzf` to provide an interactive\npicker of the available subtasks.\n\n```yaml\ntasks:\n  notes:\n    desc: Interactive picker for notes tasks\n    cmds:\n      - |\n        TASK=$(task --list | grep \"^\\* notes:\" | sed 's/^\\* notes://' | sed 's/\\s\\+/ - /' | fzf --prompt=\"Select notes task: \" --height=40% --reverse) || true\n        if [ -n \"$TASK\" ]; then\n          TASK_NAME=$(echo \"$TASK\" | awk '{print $1}' | sed 's/:$//')\n          task notes:$TASK_NAME\n        fi\n    interactive: true\n    silent: true\n\n  notes:edit:\n    ...\n\n  notes:sync:\n    ...\n\n  notes:open:\n    ...\n\n  notes:push:\n    ...\n\n  notes:status:\n    ...\n\n  notes:pull:\n    ...\n\n  notes:diff:\n    ...\n\n  notes:log:\n    ...\n```\n\nNow I can run the `notes` task to get a summary and interactive picker that\nlooks like the following:\n\n```sh\n❯ task notes\nSelect notes task: \n  9/9\n> │                    Interactive picker for notes tasks\n  diff:                Show uncommitted changes in notes\n  edit:                All-in-one edit, commit, and push notes\n  log:                 Show recent commit history for notes\n  open:                Opens NOTES.md (syncs latest changes first) in default editor\n  pull:                Pull latest changes (alias for sync)\n  push:                Commit and push changes to notes submodule\n  status:              Check status of notes submodule\n  sync:                Sync latest changes from the notes submodule\n```\n\nIt pulls in the subtask name and description. I can then use `fzf`'s navigation\nand filtering to narrow down and select the task I want to run.\n"
  },
  {
    "path": "taskfile/run-a-task-if-it-meets-criteria.md",
    "content": "# Run A Task If It Meets Criteria\n\nThe [Taskfile `status`\ndirective](https://taskfile.dev/docs/guide#limiting-when-tasks-run) can be used\nto tell a task when it needs to run. If it doesn't need to run, it can be\nskipped over. The idea being that we're making a status check to see if we're\nup-to-date or need to run the task.\n\nFor instance, here is a `status` check that determines if there are changes to\ncommit and push. If there are changes to `NOTES.md`, then we are out-of-date and\nneed to run the `cmds` that make up the task.\n\n```yaml\n  notes:push:\n    desc: Commit and push changes to notes submodule\n    dir: '{{.NOTES_DIR}}'\n    cmds:\n      - git add NOTES.md\n      - git commit -m \"Update notes - $(date '+%Y-%m-%d %H:%M')\"\n      - git push\n    status:\n      - git diff --exit-code NOTES.md\n    silent: false\n```\n\nThis is useful because I don't want the `git add`, `git commit`, and `git push`\ncommands to run when there is nothing to do.\n\nNote: this is different from the `preconditions` directive. Instead of\nshort-circuiting a sequence of tasks, this will either run or skip the task and\nmove on to the next one.\n"
  },
  {
    "path": "tmux/access-past-copy-buffer-history.md",
    "content": "# Access Past Copy Buffer History\n\nEach time you perform a copy (as in copy/paste) within tmux using its built-in\ncopy functionality (i.e. `set-buffer` and `save-buffer`), the text that you\ncopied to the buffer is recorded in the server's history.\n\n_Note: you may have `Cmd-c` or the mouse configured to copy to a tmux buffer._\n\nSo, while `tmux paste-buffer` (or `Cmd-v` if you have that configured) will\nonly paste in the most recently copied value to a tmux buffer, you can still\naccess more of the history.\n\nRun `tmux choose-buffer` (or `<prefix>:choose-buffer`) to open an interactive\nprompt that lists the tmux buffer history in reverse chronological order (most\nrecent to oldest).\n\nYou can navigate up and down through these buffers until you find the one that\ncontains what you're looking for. Then hit `Enter` and the value will be pasted\nto the current window and pane.\n\nSee `man tmux` and search for `choose-buffer` for more details.\n"
  },
  {
    "path": "tmux/add-bindings-to-split-panes-to-current-directory.md",
    "content": "# Add Bindings To Split Panes To Current Directory\n\nWhen I am vertically or horizontally splitting a pane or opening another window,\nI generally want it to open to the same directory as I'm currently in. The\ndefault behavior in tmux is for those commands to open to the starting directory\nof the session.\n\nLooking through the [tmux.conf in\ndkarter/dotfiles](https://github.com/dkarter/dotfiles/blob/master/config/tmux/tmux.conf#L109-L111),\nI found a good way to achieve the behavior I want.\n\n```\nbind-key - split-window -v  -c '#{pane_current_path}'\nbind-key \\\\ split-window -h  -c '#{pane_current_path}'\nbind-key c new-window -c '#{pane_current_path}'\n```\n\nWhat I like about this is that `-` (vertical) and `\\` (horizontal) look visually\nlike the splits they represent. Meanwhile, I leave `%` and `\"` intact.\n"
  },
  {
    "path": "tmux/adjusting-window-pane-size.md",
    "content": "# Adjusting Window Pane Size\n\nIn tmux, the size of window panes can be adjusted incrementally with the\n`resize-pane` command. For instance, to resize a pane in any direction\n(left, down, up, and right), use one of the following commands\n\n```\nresize-pane -L 10\nresize-pane -D 10\nresize-pane -U 10\nresize-pane -R 10\n```\n\nThis will adjust the pane by *10* units in the corresponding direction. Of\ncourse, other values can be used for more significant size adjustments.\n"
  },
  {
    "path": "tmux/break-current-pane-out-to-separate-window.md",
    "content": "# Break Current Pane Out To Separate Window\n\nYou have a split pane open in your current window. Perhaps it is running a\nlocal server or has a connection to a database. The pane is taking up too\nmuch space in the current window, but it is important so you don't want to\njust kill it. If that is the case, break it out into a separate window.\n\nWith that pane in focus, enter into command mode (`<prefix>:`) and then issue\nthe `break-pane` command.\n\nAlternatively, you can trigger this with a keybinding: `<prefix>!`.\n\nSee `man tmux` for more details.\n"
  },
  {
    "path": "tmux/change-base-directory-of-existing-session.md",
    "content": "# Change Base Directory Of Existing Session\n\nEach tmux session has a base directory. This is determined when you first\ncreate the session. When you open a new window or pane, this will be used as\nthe base directory of your new shell session.\n\nYou can change the base directory of an existing tmux session.\n\nFirst, detach from the session: `<prefix>d`\n\nThen, re-attach using the `-c` flag:\n\n```bash\n$ tmux attach -t your-session-name -c /new/base/dir\n```\n\n[source](https://stackoverflow.com/a/36435535/535590)\n"
  },
  {
    "path": "tmux/change-base-directory-without-detaching.md",
    "content": "# Change Base Directory Without Detaching\n\nIn [Change Base Directory Of Existing\nSession](change-base-directory-of-existing-session.md), I described how you can\ndetach from an existing tmux session and re-attach with a new base directory\nspecified.\n\nWe can do nearly the same thing within the current tmux session without first\ndetaching. The command is going to look much the same, but we will execute it\nfrom the tmux command prompt.\n\nStart the prompt by hitting `<prefix>:` and then enter the following command:\n\n```\n:attach-session -t . -c /path/to/base/directory\n```\n\nHere the `-t` specifies what session we are going to attach to. By giving it\n`.`, we tell it that we want to attach to the current session. The `-c`\nspecifies our new base directory.\n\nHit enter and then try opening a new window or pane to see that the new base\ndirectory has taken effect.\n\n[source](https://stackoverflow.com/questions/27307815/how-do-i-change-the-starting-directory-of-a-tmux-session#comment99821047_54444853)\n"
  },
  {
    "path": "tmux/change-the-default-prefix-key.md",
    "content": "# Change The Default Prefix Key\n\nThe _prefix_ key for tmux is a key that tells an active tmux session that the\nfollowing key should be interpreted as a tmux command instead of regular input\nto the terminal.\n\nBy default, tmux has `Ctrl-b` bound to the prefix.\n\nSo, hitting `Ctrl-b` followed by `?` will open up the tmux help.\n\nTyping `Ctrl-b` involves a bit of a finger stretch. It can be changed to\nsomething more comfortable. My personal preference is `Ctrl-z`. Many\nconfigurations I've seen use `Ctrl-a`.\n\nTo change this, open up your `~/.tmux.conf` file and add two lines.\n\n```\nunbind C-b\nset -g prefix C-z\n```\n\nAnd then run `:source-file ~/.tmux.conf`.\n\nThis tells tmux to unbind `Ctrl-b` so that it no longer is interpreted as the\nprefix, and then it binds `Ctrl-z` as the new prefix key.\n"
  },
  {
    "path": "tmux/create-a-named-tmux-session.md",
    "content": "# Create A Named tmux Session\n\nWhen creating a new tmux session\n\n```bash\n$ tmux new\n```\n\na default name of `0` will be given to the session.\n\nIf you'd like to give your session a name with a bit more meaning, use the\n`-s` flag\n\n```bash\n$ tmux new -s burrito\n```\n\n[source](https://robots.thoughtbot.com/a-tmux-crash-course)\n"
  },
  {
    "path": "tmux/create-a-new-session-in-a-new-server.md",
    "content": "# Create A New Session In A New Server\n\nAny tmux command will, by default, be invoked against the `default`\nserver. You can instruct tmux to perform commands against a different server\nwith the `-L` flag and the name of the server.\n\nIf you name a server that doesn't already exist, tmux will create and start\nthat server for you. So, if you want to start a new session in a new server,\njust run a command like the following:\n\n```bash\n$ tmux -L pokemon_server new-session -s pokedex\n```\n\nIf you are to detach from this session, you will need to specify the name of\nthe server in order to attach again:\n\n```bash\n$ tmux -L pokemon_server attach -t pokedex\n```\n\nSee `man tmux` for more details.\n"
  },
  {
    "path": "tmux/cycle-through-layouts.md",
    "content": "# Cycle Through Layouts\n\nArranging a series of split windows in tmux can take some time. Once those\nsplits windows are arranged, it is difficult to set them up in a new way.\nThere is a way of cycling through layouts that might be able to help though.\nHit `<prefix><space>` over and over to cycle through the layouts until you\nfind the arrangement that you want.\n\n[source](http://superuser.com/questions/493048/how-to-convert-2-horizontal-panes-to-vertical-panes-in-tmux)\n"
  },
  {
    "path": "tmux/display-titles-for-each-pane-in-a-window.md",
    "content": "# Display Titles For Each Pane In A Window\n\nOne of the main reasons I use `tmux` is to be able to organize the various\ndevelopment servers and tools I have to run for a given project. They can be\nspread across several windows in the same session. Or for ease of access, they\ncan all be split across panes in a single window.\n\nIn that latter case, I recently ran into an issue where the server output in\neach pane looked similar enough that I couldn't tell which was which. What I\nneed is titles for each pane that tell me what is running and where.\n\n`tmux` has pretty solid support for just this out-of-the-box with\n`pane-border-status`.\n\nHit `<prefix>:` to issue the following command to `tmux`:\n\n```\n:set pane-border-status top\n```\n\nOr issue the command from one of your pane's terminal prompts:\n\n```\n$ tmux set pane-border-status top\n```\n\nEither way, it will replace the top border line with text telling you the pane\nnumber, the directory, and the last run command in that pane. This is just the\ncontext I need to differentiate each.\n\nThis will only set it for the current window.\n\nIf you want to turn it back off:\n\n```\n:set pane-border-status off\n```\n\n[source](https://stackoverflow.com/a/37602055/535590)\n"
  },
  {
    "path": "tmux/enabling-vi-mode.md",
    "content": "# Enabling Vi Mode\n\nIf you'd like some vim-like bindings in tmux, you can turn on vi mode. To do\nso, add the following line to your `.tmux.conf` file:\n\n```\nsetw -g mode-keys vi\n```\n\nWith this added and tmux re-sourced, you'll now have a variety of vi-like\nbindings. For instance, when in tmux's copy mode, you can now use `v` to\nbegin making a visual selection and `y` to yank that selection into tmux's\ncopy buffer.\n"
  },
  {
    "path": "tmux/get-mouse-copy-paste-working-in-kitty.md",
    "content": "# Get Mouse Copy/Paste Working In Kitty\n\nWith tmux's mouse mode enabled (`set-option -g -q mouse on`), you can use the\nmouse to make a drag selection of some text. You can then paste it within a\ntmux session using `Cmd+v`.\n\nIf you are using tmux within the [Kitty terminal\nemulator](https://sw.kovidgoyal.net/kitty/), you'll get more text pasted than\nyou bargained for. Kitty's clipboard _appends_ by default. So after several\nselections have made there way into tmux's buffer history, a paste will result\nin all of those buffers values being appended together and output to the\nterminal.\n\nTo fix this, you need to change Kitty's clipboard to be `no-append`.\n\n```\n# ~/.config/kitty/kitty.conf\nclipboard_control write-clipboard write-primary no-append\n```\n\n[source](https://github.com/kovidgoyal/kitty/issues/782#issuecomment-502927322)\n"
  },
  {
    "path": "tmux/hiding-the-status-bar.md",
    "content": "# Hiding The Status Bar\n\nThe tmux status bar is a great place to show information about your tmux\nsession as well as things like the time and date. Sometimes you just want to\nhide it though. This command will help.\n\n```\n:set -g status off\n```\n\nHit enter and it is gone. If you want to show the status bar again, simply\nturn it back on.\n\n```\n:set -g status on\n```\n\n[source](https://superuser.com/questions/265320/disable-the-status-bar-in-tmux)\n"
  },
  {
    "path": "tmux/jumping-between-sessions.md",
    "content": "# Jumping Between Sessions\n\nIf you are using tmux to manage multiple projects by putting each project in\na separate session, you may find yourself moving between sessions\nfrequently. Detaching and reattaching can and will get tedious. There are\nbetter ways. tmux provides the `<prefix>)` and `<prefix>(` bindings as a way\nof jumping to the next and previous session, respectively. That should\nreduce some friction.\n"
  },
  {
    "path": "tmux/kill-all-your-tmux-sessions.md",
    "content": "# Kill All Your tmux Sessions\n\nIf you have several tmux sessions running and you'd like to clean house, you\ncan kill all of those sessions with one command.\n\n```bash\n$ tmux kill-session -a\n```\n\nThe `-a` flag says to target all sessions.\n\nYou can also run this as a tmux command.\n"
  },
  {
    "path": "tmux/kill-other-connections-to-a-session.md",
    "content": "# Kill Other Connections To A Session\n\nOne of the best features of tmux is the ability for multiple people to\nconnect to the same session in order to pair. This can, however, sometimes\nresult in a extra session hanging around if someone forgets to detach. This\nis no problem though because you can view and kill other connections.\n\nHit\n\n```\n<prefix>D\n```\n\nto open up an interactive list of all connections to the current session.\nThen navigate over the one you want to kill and hit `enter`. If you are\nviewing the connections but don't want to kill one, you can hit `q` to back\nout.\n\nh/t Josh Davey\n"
  },
  {
    "path": "tmux/kill-the-current-session.md",
    "content": "# Kill The Current Session\n\nWhen you are done with the current tmux session and you no longer need it,\nyou can simply kill it. You can do so within the session with the following\ncommand:\n\n```\n:kill-session\n```\n\nHit `<prefix>:` in order to enter the command.\n\nSee `man tmux` for more details.\n"
  },
  {
    "path": "tmux/list-all-key-bindings.md",
    "content": "# List All Key Bindings\n\nThere are a couple ways to list all the tmux key bindings. If you are not\ncurrently in a tmux session, you can still access the list from the terminal\nwith\n\n```bash\n$ tmux list-keys\n```\n\nIf you are currently in a tmux session, then you can take advantage of the\ntmux environment by either using\n\n```\n<prefix>:list-keys\n```\n\nor\n\n```\n<prefix>?\n```\n\nAny of these will bring up a list of all key bindings available to you\nwithin a tmux session on your machine.\n"
  },
  {
    "path": "tmux/list-processes-running-across-all-sessions.md",
    "content": "# List Processes Running Across All Session\n\nI wanted an overview of all the processes running across all the tmux sessions\nthat I have running on my machine right now. The `list-panes` command (with the\n`-a` flag) gives me a listing of all the panes across all session of the current\ntmux server.\n\nThat output on its own isn't giving me quite the info I'm looking for though.\nWith the `-f` (_format_) flag, I can use variables available in that context\nlike `session_name`, `pane_pid`, and `pane_current_command`.\n\nI can assemble the details I want into a command like this:\n\n```bash\n❯ tmux list-panes -a -F \"#{session_name}:#{window_index}.#{pane_index} #{pane_pid} #{pane_current_command}\"\nPLP:1.1 62364 zsh\nTIL:1.1 62345 nvim\nTIL:1.2 65838 task\nTIL:2.1 11428 tmux\nclient-app:1.1 62373 ssh\nclient-app:1.2 10796 zsh\nclient-app:1.3 63081 zsh\nclient-app:2.1 61115 overmind\nclient-app:3.1 82608 zsh\nvisualmode-dev:1.1 52237 zsh\n```\n\nThis gives me the details I want, but I can take it a step further by piping it\nto the `column` command to improve the formatting a little:\n\n```bash\n❯ tmux list-panes -a -F \"#{session_name}:#{window_index}.#{pane_index} #{pane_pid} #{pane_current_command}\" \\\n  | column -t\nPLP:1.1             62364  zsh\nTIL:1.1             62345  nvim\nTIL:1.2             65838  task\nTIL:2.1             11428  tmux\nclient-app:1.1      62373  ssh\nclient-app:1.2      10796  zsh\nclient-app:1.3      63081  zsh\nclient-app:2.1      61115  overmind\nclient-app:3.1      82608  zsh\nvisualmode-dev:1.1  52237  zsh\n```\n\nSee `man tmux` and, in particular, the `FORMATS` section for more details.\n"
  },
  {
    "path": "tmux/list-sessions.md",
    "content": "# List Sessions\n\nNot sure if `tmux` is running or, if it is, which sessions are available?\nYou can list all the currently running sessions right from the command-line.\n\n```bash\n$ tmux ls\n```\n\nThis command is shorthand for:\n\n```bash\n$ tmux list-sessions\n```\n"
  },
  {
    "path": "tmux/open-new-splits-to-the-current-directory.md",
    "content": "# Open New Splits To The Current Directory\n\nI typically work in one project per tmux session. When I create a given tmux\nsession, the default directory is for that project. All new windows and pane\nsplits will open at that default directory. This generally is the default\nbehavior I want.\n\nOne caveat: I often open a new window within an existing session that I want\nanchored to another directory. This could be because I'm working in a monorepo\nand I need to work from a subdirectory for a specific package or app. Or it\ncould be that I'm temporarily digging into another project and it isn't worth\ncreate a whole new session.\n\nRegardless of the reason, I run into a bit of friction with tmux's defaults.\n\nFirst I open the new window and `cd` to another project. After some working, I\nneed to open a split pane, maybe to run a project command like a build or dev\nserver. Hitting `prefix-\"` (horizontal split) or `prefix-%` (vertical split)\nopens a pane with the shell defaulting back to the original directory, not the\ncurrent directory.\n\nThe trick to fixing this bit of friction is overriding the directory of pane\nsplits. I can do that by adding the following to my `~/.tmux.conf`:\n\n```\n# Pane splits should open to the same path as the current pane\nbind '\"' split-window -v -c \"#{pane_current_path}\"\nbind % split-window -h -c \"#{pane_current_path}\"\n```\n\nMake sure to run `tmux source-file ~/.tmux.conf` to apply these config changes.\n\nThe `pane_current_path` is called a \"Format\" in tmux parlance. It resolves to\nthe absolute path of the current pane's current directory. You can find all the\nformats in the manpage with this command: `man tmux | less +'/^FORMATS'`. You\ncan also show yourself that this format resolves to what you expect by running\n`tmux display-message -p '#{pane_current_path}'`.\n"
  },
  {
    "path": "tmux/open-new-window-with-a-specific-directory.md",
    "content": "# Open New Window With A Specific Directory\n\nWhen you initially start a tmux session, the default directory is based off\nof whatever the current working directory was. Any subsequent windows opened\nwithin that tmux session will be opened with that as the base directory.\n\nTo open a window with a different default directory, use the `-c` flag with\nthe `new-window` command. For example, hit `<prefix>:` and then\n\n```\n:new-window -c ~/\n```\n\nto open a new window with your home directory.\n\n[source](http://unix.stackexchange.com/questions/12032/create-new-window-with-current-directory-in-tmux)\n"
  },
  {
    "path": "tmux/organizing-windows.md",
    "content": "# Organizing Windows\n\nIf you use a number of tmux windows as part of your daily workflow, you may find that they get to be a bit of a mess from time to time. There are gaps in the numbering and they aren't laid out in the order you'd prefer. The `movew` command makes it easy to rearrange these windows.\n\nIf you have a window indexed at 2 and you want it to be the 4th window, then you can:\n\n```\n:movew -s 2 -t 4\n```\n\nIf you have a gap such that the 4th and 5th windows are numbered 4 and 7, then you can focus the 7 window and simply invoke:\n\n```\n:movew\n```\n\nAnd that window will be reinserted at the next available slot, in this case, window 5.\n"
  },
  {
    "path": "tmux/paging-up-and-down.md",
    "content": "# Paging Up And Down\n\nWhen in _copy mode_ (`<prefix>[`), you can move the cursor around like you\nwould in vim with the directional keys (`hjkl`). This works fine until you\nwant to move up or down through pages and pages of text, such as when\nnavigating to the top of a long stack trace. One way to get where you need\nto be more quickly is by paging up and down.\n\nHit `CTRL-u` to page up and `CTRL-d` to page down.\n"
  },
  {
    "path": "tmux/pane-killer.md",
    "content": "# Pane Killer\n\nThe current pane can be _killed_ (closed) using the following key binding:\n\n```\n<prefix>x\n```\n\nYou will be prompted to confirm with either `y` or `n`.\n\nIf there is only one pane in the current window, then the window will be\n_killed_ along with the pane.\n"
  },
  {
    "path": "tmux/reclaiming-the-entire-window.md",
    "content": "# Reclaiming The Entire Window\n\nIf you have attached to a tmux session whose dimensions are being\nconstrained by another connection, you may find an L-shaped portion of your\nwindow filled with dots. tmux defers to the session with smaller dimensions.\nThe easiest way to reclaim the entire window for your session is to attach\nto the session while forcing all other sessions to detach. The `-d` flag will\nhelp with that.\n\n```bash\n$ tmux attach-session -d -t my-session\n```\n\nBy detaching all other sessions, you are ensuring that your machine's\ndimensions are the ones that tmux uses when drawing the window. This is a\ngreat quick fix if you're working on your own, but probably not what you\nwant to do if you are in a pair programming situation.\n\n[source](http://stackoverflow.com/questions/7814612/is-there-any-way-to-redraw-tmux-window-when-switching-smaller-monitor-to-bigger)\n"
  },
  {
    "path": "tmux/remove-the-delay-on-the-escape-key.md",
    "content": "# Remove The Delay On The Escape Key\n\nBy default, tmux imposes a 500ms delay on presses of the escape key. This is in\ncase the escape key is used as part of a tmux key binding.\n\nI don't use the escape key for any of my tmux key bindings, but I do use the\nescape key quite in other contexts, like Vim.\n\nThe 500ms delay on the escape key being registered in contexts like Vim is\nannoying at best. This delay can be removed by overriding the `escape-time`\noption.\n\n```\nset -sg escape-time 0\n```\n\nAdding this line to your `~/.tmux.conf` file will set the delay to 0ms. The\n`-s` and `-g` flags set the option for the _server_ and the _global server_\ncontexts respectively.\n"
  },
  {
    "path": "tmux/rename-the-current-session.md",
    "content": "# Rename The Current Session\n\nIf you've created an unnamed tmux session or you no longer like the original\nname, you can open a prompt to change it by hitting\n\n```\n<prefix>$\n```\n\nReplace the existing name with the desired name and hit enter.\n\nh/t Dorian Karter\n"
  },
  {
    "path": "tmux/reset-an-option-back-to-its-default-value.md",
    "content": "# Reset An Option Back To Its Default Value\n\nOnce you start changing the values of options, tmux can be opaque about what\nthe original default values were.\n\nFor instance, if you change the `escape-time` option with the following\ncommand:\n\n```bash\n$ tmux set-option -g escape-time 0\n```\n\nIt's now set to `0`, so without digging through the tmux man pages, how do you\nfigure out what the default was and restore it?\n\nThe `set-option` command takes the `-u` flag to _unset_ the option. This will\nrestore it to the default.\n\n```bash\n$ tmux set-option -u escape-time\n```\n\nAnd you can now see the original default value with `show-option`.\n\n```bash\n$ tmux show-option escape-time\n500\n```\n\nUse `set-option -u` with any option to restore it to its default.\n\nFind `set-option` in `man tmux` for more details.\n"
  },
  {
    "path": "tmux/set-environment-variables-when-creating-session.md",
    "content": "# Set Environment Variables When Creating Session\n\nIn [Set Session-Specific Environment\nVariables](set-session-specific-environment-variables.md), I showed how env\nvars that are scoped to a tmux session can be set in an existing session.\n\nIt is also possible to set any number of environment variables when creating a\nsession. This is particularly handy if you are scripting the setup of various\ntmux environments.\n\nA base command to start a tmux session might look like this:\n\n```bash\n$ tmux new -s my-project\n```\n\nTo set environment variables on that session, use one or more `-e` flags\nfollowed by the name and value.\n\n```bash\n$ tmux new -s my-project -e EDITOR=code -e PG_VERSION=13.4\n```\n\nSee `man tmux` for more details.\n"
  },
  {
    "path": "tmux/set-session-specific-environment-variables.md",
    "content": "# Set Session-Specific Environment Variables\n\n`tmux` allows you to manage separate environments for separate projects. For me\nthis usually boils down to arrangements of windows and tabs with different\nservers running.\n\n`tmux` can also provide session-specific environment variables. For anything\nthat you use environment variables for.\n\nAs an example, let's say I have one project that I always edit with VS Code.\nAnd another that uses `vim`.\n\nMy default editor, as configured in my `~/.zshrc` file is `nvim`.\n\n```bash\n❯ echo $EDITOR\nnvim\n```\n\nIf I jump into the first project (`one`), I can set the `EDITOR` to `code` like\nso.\n\n```bash\n❯ tmux setenv EDITOR code\n```\n\nIt won't apply to the current pane, but if I open a new one.\n\n```\n❯ echo $EDITOR\ncode\n```\n\nI can then jump to the other project (`two`) to set that one to `vim`. This\ntime using the tmux command prompt.\n\n\n```bash\n<tmux-prefix>:\n:setenv EDITOR vim\n```\n\nAgain, if I open a new pane, the editor will be set.\n\n```\n❯ echo $EDITOR\nvim\n```\n\nAll the while, the value of `EDITOR` is preserved as `nvim` for everything\noutside the context of those two tmux sessions.\n"
  },
  {
    "path": "tmux/set-up-forwarding-prefix-for-nested-session.md",
    "content": "# Set Up Forwarding Prefix For Nested Session\n\nI use\n[`ctrl-z`](https://github.com/jbranchaud/dotfiles/blob/main/config/tmux/tmux.conf#L57)\n(instead of `ctrl-b`) for my tmux prefix key. I also have [`ctrl-z\nctrl-z`](https://github.com/jbranchaud/dotfiles/blob/main/config/tmux/tmux.conf#L138-L139)\nconfigured to toggle back and forth between the previously visited window.\n\nWith that in mind, I needed to set up a specific keybinding to send the prefix\nkey to an inner (nested) tmux session. That's because sometimes, like with a\ntool such as `overmind`, you can end up connected to a tmux session while\nalready within a tmux session.\n\nSo, I have `Ctrl-z a` send the prefix key to the inner tmux session. This is\nwhat I added to my\n[`tmux.conf`](https://github.com/jbranchaud/dotfiles/blob/main/config/tmux/tmux.conf#L167-L168):\n\n```\n# send prefix to inner tmux session (C-z a)\nbind-key a send-prefix\n```\n\nSimply doing `Ctrl-z d` will detach me from the outer tmux session. If I want to\ndetach from an inner tmux session, I can use my new keybinding -- `Ctrl-z a d`.\n"
  },
  {
    "path": "tmux/show-the-current-value-for-an-option.md",
    "content": "# Show The Current Value For An Option\n\nIn the `~/.tmux.conf` file, you are able to define and override the values of\nvarious options. Outside of explicitly setting an option, you may want to know\nwhat its value is.\n\nPerhaps it is unset, perhaps you don't remember, or maybe this particular\nsession or pane is different than the global config.\n\nEither from the CLI, you can run the `tmux` command to check:\n\n`$ tmux show-option -g history-limit`\n\nOr as a command to tmux, using your prefix:\n\n`:show-option -g history-limit`\n\nThe `-g` flag will tell you the option's value as set globally for tmux. `-w`\nfor window, `-p` for pane, or no flag for the current session.\n\nSee `man tmux` for more details.\n"
  },
  {
    "path": "tmux/swap-split-panes.md",
    "content": "# Swap Split Panes\n\nUse `<prefix>}` (or `<prefix>{`) to swap two vertically or horizontally\nsplit tmux panes.\n"
  },
  {
    "path": "tmux/switch-to-a-specific-session-and-window.md",
    "content": "# Switch To A Specific Session And Window\n\nHitting `ctrl-<prefix> w`, similar to `ctrl-<prefix> s`, will open up a pane\nfor switching sessions. However, this one will display each window as an option\nbelow each session.\n\nWhen just switching sessions, you are taken to the last active window. With\n`ctrl-<prefix> w`, you can choose not just the session you want to switch to,\nbut a specific window within that session.\n"
  },
  {
    "path": "tmux/tmux-in-your-tmux.md",
    "content": "# tmux in your tmux\n\nIf you are running tmux locally and you shell into another machine to\naccess tmux remotely, you will suddenly find yourself in tmux inception.\nYou will have a tmux instance running within your local tmux instance. If\nyou have the same prefix key set for both, then you may be wondering how\nyou can send a tmux command to the *inner* tmux instance.\n\nIf you press your prefix twice (e.g. `<C-a> <C-a>`), then the second prefix\nwill be sent to the inner tmux instance which will then be listening for\nthe rest of your command. So, to open a new window within the inner tmux\ninstance, you can hit `<C-a> <C-a> c`.\n"
  },
  {
    "path": "tmux/toggle-between-two-common-sessions.md",
    "content": "# Toggle Between Two Common Sessions\n\nWith certain projects, such as projects that involve separate frontend and\nbackend codebases, I use a separate tmux session for each. This means that for\ncertain tasks and features I find myself flipping back and forth between them\nconstantly.\n\nThis can get tedious with an approach like `<prefix> s` where you then have to\nfind and select the other session from the list.\n\nA more efficient alternative is `<prefix> L` -- this takes you to the last\nsession. So, if you are in the `backend` session and had previously been in the\n`frontend` session, then hitting `<prefix> L` will immediately place you in\n`frontend`. Hitting that exact same binding a second time will take you right\nback to `backend`.\n\nSee `man tmux` for more details.\n"
  },
  {
    "path": "typescript/add-generic-typing-to-an-anonymous-function.md",
    "content": "# Add Generic Typing To An Anonymous Function\n\nA common pattern, especially when dealing with collections of data (read:\narrays), is to have a function that can transform an array of any type of data.\nIn order to keep this kind of function general-purpose and have it preserve\ntypes, we'll need to use generics.\n\nFor an anonymous function to work with a generic type, it needs to open with a\nsignature for the generic type:\n\n```typescript\n<T>() => {}\n```\n\nWith that in mind, we can write a function that accepts an array of type `T`,\ndoes something to that collection, and then returns an array of type `T`.\n\nFor instance, here is a function that takes the first `n` elements from the\narray and returns them.\n\n```typescript\nconst take = <T>(arr: Array<T>, n: number): Array<T> => {\n  return arr.slice(0, n)\n}\n```\n\nThis both enforces and preserves the type of the array. It works well for\nsituations where the array is a bunch of complex objects with specific types\nlike we'd get from a Prisma query.\n"
  },
  {
    "path": "typescript/add-types-to-an-object-destructuring.md",
    "content": "# Add Types To An Object Destructuring\n\nLet's say I'm building a form component that asks the user for their first name\nand email address. I then want to submit these values to some server endpoint\nto subscribe the user to a newsletter.\n\nNow, what if I want to type the destructuring of the form values?\n\nThe standard syntax for doing this with TypeScript conflicts with the\ndestructured renaming ES6 feature:\n\n```javascript\nconst { firstName: string, email: string } = formValues;\n```\n\nThis won't work.\n\nRather than typing the individual values in the destructuring, you'll need to\ntype the destructured object itself.\n\n```typescript\nconst {\n  firstName,\n  email,\n}: { firstName: string; email: string } = formValues;\n```\n\n[source](https://flaviocopes.com/typescript-object-destructuring/)\n"
  },
  {
    "path": "typescript/compiler-checks-for-unused-params-and-variables.md",
    "content": "# Compiler Checks For Unused Params And Variables\n\nThere are a number of linter-esque checks that you can tell the TypeScript\ncompiler to make when it is checking your code. There are two that prevent\nvalues from going unused: one for parameters and the other for variables.\n\nThe [`noUnusedLocals`](https://www.typescriptlang.org/tsconfig#noUnusedLocals)\nconfig, which defaults to `false`, can be set to `true`. This will cause the\ncompiler to fail if a locally declared variable goes unused.\n\n```typescript\nfunction printItem(item: any, index: number) {\n  const indexedItem = `${index}: ${item}`;\n  //    ^^^ 'indexedItem' is declared but its value is never read.\n\n  console.log(item);\n}\n```\n\nThe\n[`noUnusedParameters`](https://www.typescriptlang.org/tsconfig#noUnusedParameters)\nconfig, which also defaults to `false`, can be set to `true`. This will cause\nthe compiler to fail if a function param goes unused.\n\nFixing the previous error could then result in this one.\n\n```typescript\nfunction printItem(item: any, index: number) {\n  //                          ^^^\n  // 'index' is declared but its value is never read.\n\n  console.log(item);\n}\n```\n\nHere is what the `tsconfig.json` would look like:\n\n```json\n{\n  \"compilerOptions\": {\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n  }\n}\n```\n"
  },
  {
    "path": "typescript/create-a-non-empty-array-type.md",
    "content": "# Create A Non-Empty Array Type\n\nAn array type (e.g. `Array<string>`) by default will allow an empty array. We\ncan define a custom array type that does static type checking to ensure arrays\naren't declared as empty.\n\nTo do this, we specify the array type has at least one item in addition to the\n_spread_ of the rest of the array.\n\n```typescript\ntype NonEmptyArray<T> = [T, ...T[]];\n```\n\nIf we declare a `NonEmptyArray` with no items:\n\n```typescript\nconst statuses: NonEmptyArray<string> = [];\n```\n\nWe'll get the following type error:\n\n```\nType '[]' is not assignable to type 'NonEmptyArray<string>'.\n  Source has 0 element(s) but target requires 1.\n```\n\nWhereas as soon as we add at least one item, the type error goes away.\n\n```typescript\nconst statuses: NonEmptyArray<string> = ['active'];\n```\n\nHere is a [TS Playground example of this type](https://www.typescriptlang.org/play?#code/C4TwDgpgBAcg9gOwKIFsygIICcsEMQA8AKgHxQC8UA2kQDRQB0TRVAuqwNwBQXAxogGdgUCGlABlYLmABXARAEAuWIlToQ2PISFYAlggDmZSm259BwodLkLl8ZGI058BHfqMVqAcly9gugDcIL04gA).\n\n[source](https://twitter.com/he_zhenghao/status/1583557892480778240)\n"
  },
  {
    "path": "typescript/create-a-union-type-from-an-array.md",
    "content": "# Create A Union Type From An Array\n\nLet's say we have an array of _actions_ that our program knows how to handle.\n\n```typescript\n// inferred type: string[]\nconst actions = ['increase', 'decrease', 'reset'];\n```\n\nThe inferred type of that array is `string[]` which is a pretty wide type. We\ncan't do much with it. We can prevent the widening of this array's inferred\ntype using `as const`.\n\n```typescript\n// inferred type: readonly ['increase', 'decrease', 'reset']\nconst actions = ['increase', 'decrease', 'reset'] as const;\n```\n\nThat inferred type is specific enough that we can do something with it, like\ncreate a union type.\n\n```typescript\nconst actions = ['increase', 'decrease', 'reset'] as const;\n\ntype Actions = typeof actions[number];\n//=> type Actions = 'increase' | 'decrease' | 'reset'\n```\n\nWe could use the `Actions` type to specify that a function only takes values\nthat correspond to known actions, for instance.\n\n[source](https://bobbyhadz.com/blog/typescript-create-union-type-from-array)\n"
  },
  {
    "path": "typescript/create-union-type-from-constants.md",
    "content": "# Create Union Type From Constants\n\nI like to capture what I call _magic strings_ in constants (variables, really)\nso that I can use them and reuse them with minimal maintenance. Minimal\nmaintenance because if something about the value of the string changes, I only\nneed to make that update in a single place.\n\nI want to extend this reuse to my type system as well.\n\nLet's say I have some constants defined like so:\n\n```typescript\nconst UPGRADE = \"upgrade\";\nconst DOWNGRADE = \"downgrade\";\n```\n\nI can create a union type from those values using the [`typeof`\noperator](https://www.typescriptlang.org/docs/handbook/2/typeof-types.html).\n\n```\ntype IntervalChange = typeof UPGRADE | typeof DOWNGRADE;\n//=> type IntervalChange = 'upgrade' | 'downgrade'\n```\n\nI can then use both the constants and the type throughout my code with only one\nplace to update.\n\n```typescript\nfunction checkForUpgrade(interval: string): IntervalChange {\n  // some logic\n  const result = ...;\n\n  return result ? UPGRADE : DOWNGRADE;\n}\n```\n\n[source](https://twitter.com/jbrancha/status/1565770454052249601?s=20&t=4seYY0mzoTFeDCiFwRB91g)\n"
  },
  {
    "path": "typescript/extract-object-type-keys-into-a-union-type.md",
    "content": "# Extract Object Type Keys Into A Union Type\n\nThe [object type](https://www.typescriptlang.org/docs/handbook/2/objects.html)\nis a way of grouping types together to represent something more complex. For\ninstance, it may be used to represent the types of events that a reducer can\nprocess.\n\n```typescript\ninterface GlobalReducerEvent {\n    ADD_TODO: {\n        text: string\n    }\n    LOG_IN: {\n        email: string\n    }\n    DELETE_TODO: {\n        todo_id: number\n    }\n}\n```\n\nFrom this object type, I can extract a [union\ntype](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types)\nof the keys, perhaps as part of building [a more useful type\nmapping](https://dev.to/jbranchaud/breaking-down-a-complex-mapped-type-in5).\n\nThis can be done with\n[`keyof`](https://www.typescriptlang.org/docs/handbook/2/keyof-types.html).\n\n```typescript\ntype EventTypes = keyof GlobalReducerEvent;\n//=> 'ADD_TODO' | 'LOG_IN' | 'DELETE_TODO'\n```\n\nThe `keyof` type operator extracts each key of the `GlobalReducerEvent` into a\nunion type. This can be mixed into other types in all sorts of interesting\nways.\n"
  },
  {
    "path": "typescript/extract-object-type-values-into-a-union-type.md",
    "content": "# Extract Object Type Values Into A Union Type\n\nLet's say we have an object type like the following:\n\n```typescript\ntype GlobalReducerEvent = {\n    ADD_TODO: {\n        text: string\n    }\n    LOG_IN: {\n        email: string\n    }\n    DELETE_TODO: {\n        todo_id: number\n    }\n}\n```\n\nWe can use the [indexed access\ntype](https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html)\nto access the value indexed at one the type keys. This works a lot like\nJavaScript's object access.\n\n```typescript\ntype AddTodoType = GlobalReducerEvent['ADD_TODO'];\n/*\ntype AddTodoType = {\n  text: string\n}\n*/\n```\n\nWhere it gets more interesting and differs from JavaScript's object access is\nwhen we do an indexed access of a union type.\n\n```typescript\ntype TypesForEvents = GlobalReducerEvent[keyof GlobalReducerEvent];\n/*\ntype TypesForEvents = {\n  text: string\n} | {\n  email: string\n} | {\n  todo_id: number\n}\n*/\n```\n\nThe result is a union of each of the values whose keys had matches in the\nunion.\n\nWhere this gets more interesting and useful is when we use it as part of a\nmapped type like I explore in [Breaking Down a Complex Mapped\nType](https://dev.to/jbranchaud/breaking-down-a-complex-mapped-type-in5).\n"
  },
  {
    "path": "typescript/generate-an-initial-tsconfig-file.md",
    "content": "# Generate An Initial tsconfig File\n\nA new `tsconfig.json` file can be generated using [the `tsc`\nCLI](https://www.typescriptlang.org/docs/handbook/compiler-options.html) which\nis part of the `typescript` node package.\n\nYou'll first want to add `typescript` to your project:\n\n```bash\n$ npm install typescript --save-dev\n```\n\nSince it is a local project dependency, you'll want to add `tsc` as a script in\nyour `package.json`.\n\n```json\n\"scripts\": {\n  \"tsc\": \"tsc\"\n}\n```\n\nNow you can use `npm` to run `tsc --init` like so:\n\n```bash\n$ npm run tsc -- --init\n```\n\nNotice the delimiting `--` which tells `npm` to pass the remaining arguments to\nthe command being invoked. This makes sure `--init` gets passed as an argument\nto `tsc`.\n\nThis will generate a huge, mostly commented-out `tsconfig.json` file full of\nannotations that looks something like this:\n\n```json\n{\n  \"compilerOptions\": {\n    /* Visit https://aka.ms/tsconfig to read more about this file */\n\n    /* Projects */\n    // \"incremental\": true,                              /* Save .tsbuildinfo files to allow for incremental compilation of projects. */\n    /* ... */\n\n    /* Language and Environment */\n    \"target\": \"es2016\",                                  /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */\n    /* ... */\n  }\n}\n```\n\n[source](https://stackoverflow.com/a/57510415/535590)\n"
  },
  {
    "path": "typescript/generate-inferred-type-from-zod-schema.md",
    "content": "# Generate Inferred Type From Zod Schema\n\nOne of the killer features of [`Zod`](https://github.com/colinhacks/zod) is\nthat it does double-duty. When you define a schema, you can use that for\nruntime checks. You can also generate an inferred type from that schema for\nstatic type checking.\n\nLet's say I have the following schema defined for data representing a\n_contact_.\n\n```typescript\nimport {z} from 'zod'\n\nconst contactSchema = z.object({\n  person: z.object({\n    firstName: z.string(),\n    lastName: z.string()\n  }),\n  email: z.string().email(),\n})\n```\n\nI can use this schema along with Zod's\n[`z.infer()`](https://github.com/colinhacks/zod#type-inference) function to\ngenerate a type that I can use throughout my codebase.\n\n```typescript\nconst createContact = (data: z.infer<typeof contactSchema>) => {\n  // ...\n}\n```\n\nIf I inspect data, I can see that I get an object type generated from the\n`contactSchema`.\n\n```typescript\n/* data: {\n *    person: {\n *        firstName: string;\n *        lastName: string;\n *    };\n *    email: string;\n * }\n */\n```\n\nThat works, but looks a bit cluttered. I could pull it out into a defined type.\nOne that could even be exported if I was so inclined.\n\n```typescript\nexport type Contact = z.infer<typeof contactSchema>\n\nconst createContact = (data: Contact) => {\n  // ...\n}\n```\n"
  },
  {
    "path": "typescript/get-the-return-type-of-an-async-function.md",
    "content": "# Get The Return Type Of An Async Function\n\nWhen working with TypeScript-first libraries like Prisma, you'll be working\nwith functions that have useful, but complex type signatures. The TypeScript\nbuilt-in [Utility\nTypes](https://www.typescriptlang.org/docs/handbook/utility-types.html)\nmake a big difference when working with these.\n\nFor instance, a function that makes a couple Prisma calls with join'ed data\nwill have a large return type that you can't easily recreate with imported\ntypes from the Prisma client.\n\nGiven a function like this, we can start out extracting its return type with\nthe\n[`ReturnType`](https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype)\nutility type, passing it the `typeof` the function as the generic.\n\n```typescript\ntype FuncReturnType = ReturnType<typeof getPostsForUser>\n```\n\nA function like this is going to be async, so its return type will be wrapped\nin a promise. We can \"unwrap\" the promise with\n[`Awaited`](https://www.typescriptlang.org/docs/handbook/utility-types.html#awaitedtype).\n\n```typescript\ntype FuncReturnType = ReturnType<typeof getPostsForUser>\ntype ResolvedFuncReturnType = Awaited<FuncReturnType>\n```\n\nWe are often querying for lists of things, so the result will be an array of\nthe type we are interested in. We can extract the type of an array with\n`[number]`.\n\n```typescript\ntype FuncReturnType = ReturnType<typeof getPostsForUser>\ntype ResolvedFuncReturnType = Awaited<FuncReturnType>\ntype PostType = ResolvedFuncReturnType[number]\n```\n\nPutting it all together into a single line looks like this:\n\n```typescript\ntype Post = Awaited<ReturnType<typeof getPostsForUser>>[number]\n```\n\n[source](https://twitter.com/jbrancha/status/1603505456458207232)\n"
  },
  {
    "path": "typescript/ignore-all-errors-in-a-typescript-file.md",
    "content": "# Ignore All Errors In A TypeScript File\n\nAs of TypeScript 3.7, we can mark an entire TypeScript file to be ignored by\nthe TypeScript compiler when it is doing static type checking.\n\nWe can do this by adding the `@ts-nocheck` directive at the top of the file:\n\n```typescript\n// @ts-nocheck\n\ntype User = {\n  id: string;\n  name: string;\n  email: string;\n}\n\nconst user: User = {\n  id: 123,\n  name: \"Liz Lemon\",\n  email: \"liz.lemon@nbc.com\",\n};\n```\n\nNotice that `id` is typed as a `string`, but we are using a `number` with `id`\nfor `user`. That is a type error. But with the `@ts-nocheck` directive at the\ntop, the type checker doesn't run on the file and we see no type errors.\n\nI'd generally suggest to avoid doing this. It can hide real type errors that\nyou should be addressing. That said, in special circumstances, you may need it,\neven if just temporarily, like if an imported package doesn't have types. Here\nis an example of that in [uploadthing's\n`rehype.js`](https://github.com/pingdotgg/uploadthing/blob/d98fbefedddf64d183cc5a00b3fd707e8d8f2f6c/docs/src/mdx/rehype.js#L1)\nwhich is missing types from `mdx-annotations`.\n\n[source](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#-ts-nocheck-in-typescript-files)\n"
  },
  {
    "path": "typescript/interfaces-with-the-same-name-are-merged.md",
    "content": "# Interfaces With The Same Name Are Merged\n\nHere is the declartion of an interface in TypeScript.\n\n```typescript\ninterface Person {\n  name: string\n}\n```\n\nWhat if I were to add a separate interface declaration with the same name,\n`Person`?\n\n```typescript\ninterface Person {\n    age: number\n}\n```\n\nTypeScript performs declaration merging. So the types of the two interfaces\nwould be combined. So, a variable of type `Person` can have an `name` and an\n`age`.\n\n```typescript\nconst person: Person = {\n    age: 22,\n    name: 'Bob'\n}\n```\n\nSee a [live\nexample](https://www.typescriptlang.org/play?ssl=12&ssc=2&pln=5&pc=1#code/JYOwLgpgTgZghgYwgAgArQM4HsTIN4BQyxyIcAthAFzIZhSgDmBAvgQaJLIiulNrkIlkcRtVIBXcgCNordghx1kAB0w4afAcgC8+IiVHiATMYA0B4mUo0A5ACEs02-IJr+OAHRGgA)\nin the TS Playground.\n\nThis is different from how object type declarations handle it. If I were to try\nto define two separate `type`s with the same name, that would result in a type\nerror.\n\n[source](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces)\n"
  },
  {
    "path": "typescript/narrow-the-type-of-an-array-to-its-values.md",
    "content": "# Narrow The Type Of An Array To Its Values\n\nWhen an array of string values is defined in a TypeScript context, the inferred\ntype will be `string[]`. That's because the values of an array can be\nreassigned. The most precise TypeScript can be is to say that it is an array of\nstring.\n\n```typescript\nconst actions = ['increase', 'decrease'];\n// typeof actions => string[]\n```\n\nWe can freeze the array with its values using `as const`, the [const\nassertion](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions).\nThis doesn't actually _freeze_ the array, but it does mark it as `readonly` for\nthe TypeScript compiler.\n\nThat means we can lean on the compiler for a lot more specific feedback.\nConsider for instance this `reducer` function.\n\n```typescript\nconst actions = ['increase', 'decrease'] as const\n\nconst reducer = (action: typeof actions[number]) => {\n  switch (action) {\n    case 'increase':\n      // do an increase\n    case 'decrease':\n      // do a decrease\n    case 'submit': // TYPE ERROR, \"submit\" is not comparable to type 'increase' | 'decrease'\n      // do a submit\n    default:\n      throw Error('Unrecognized action!')\n  }\n}\n\n// TYPE ERROR, \"submit\" is not comparable to type 'increase' | 'decrease'\nreducer('submit')\n```\n"
  },
  {
    "path": "typescript/re-export-an-imported-type.md",
    "content": "# Re-Export An Imported Type\n\nI have a TypeScript module that is defining an XState machine. Among other\nthings, it imports the `DoneEventObject` type from `xstate`. I want to\nre-export that type so that any modules using this machine have access to that\ntype definition.\n\nThis can be done a couple of ways. One way to import it under an aliased name\nand then assign + export it using the original name.\n\n```typescript\nimport {Machine, DoneEventObject as _DoneEventObject} from 'xstate'\n\nexport type DoneEventObject = _DoneEventObject\n```\n\nThis works, but adds some potential indirection and confusion through the\ndouble assignment.\n\nAnother way of doing this is to reference the type off the import statement as\npart of an assignment.\n\n```typescript\nimport {Machine} from 'xstate'\n\nexport type DoneEventObject = import('xstate').DoneEventObject\n```\n\nThis imports, assigns, and exports the type in a single statement.\n\n[source](https://github.com/microsoft/TypeScript/issues/28481#issuecomment-552938424)\n"
  },
  {
    "path": "typescript/set-path-alias-for-cleaner-imports.md",
    "content": "# Set Path Alias For Cleaner Imports\n\nIn the `tsconfig.json` file of a TypeScript project, there are a bunch of\ncompiler options that you can specify. One of those compiler options is\n`paths`. This is an object that can map path aliases to directories in your\nproject.\n\nIn projects where nested files are importing modules from other parts of the\nfile tree, you can end up with cluttered imports like this:\n\n```typescript\nimport { prisma } from '../../server/db.server'\nimport { List } from '../../components/list'\n```\n\nBy setting a path alias in your `tsconfig.json` file, like so, you can tidy\nthese up:\n\n```json\n{\n  \"compilerOptions\": {\n    \"paths\": {\n      \"~/*\": [\"./app/*\"]\n    }\n  }\n}\n```\n\nNow I can write any import such that it anchors to the `app` directory with\n`~`.\n\n```typescript\nimport { prisma } from '~/server/db.server'\nimport { List } from '~/components/list'\n```\n\nI prefer a single path alias if I can get away with it, but you can [add\nseveral](https://learn.saleor.io/setup/typescript-path-aliases/) to suit your\nproject if you'd like.\n\n[source](https://www.typescriptlang.org/tsconfig#paths)\n"
  },
  {
    "path": "typescript/type-narrowing-with-const-vs-let-strings.md",
    "content": "# Type Narrowing With Const VS Let Strings\n\n[TypeScript's `typeof`\noperator](https://www.typescriptlang.org/docs/handbook/2/typeof-types.html) can\nbe used to capture the type of a variable.\n\nFor instance, we can use it with a string variable like so:\n\n```typescript\nlet status = 'active';\n\ntype Status = typeof status;\n//=> type Status = string;\n```\n\nThe result is a type `Status` defined as a `string`.\n\nWhat if we were to do the same with a string variable defined with `const`\n(instead of `let`)?\n\n```typescript\nconst status = 'active';\n\ntype Status = typeof status;\n//=> type Status = 'active';\n```\n\nWe get a different result. A much more specific result. The `Status` type\ndefinition in this case isn't just any `string`. TypeScript knows specifically\nthat it is the string `'active'`.\n\nThis is _Type Narrowing_ at work. With our `let` string, which can be redefined\nat anytime, the most TypeScript can tell us about it is that it is a `string`.\nOur `const` string, on the other hand, is frozen as `'active'`, so TypeScript\ncan narrow the type from `string` to the string `'active'`.\n\nThat can be handy for [defining a union type from existing `const`\nvalues](https://twitter.com/jbrancha/status/1565770454052249601).\n\n[source](https://twitter.com/jbrancha/status/1565752445187358721)\n"
  },
  {
    "path": "typescript/type-narrowing-with-similarly-shaped-objects.md",
    "content": "# Type Narrowing With Similarly Shaped Objects\n\nLet's say we have a type with several properties and a variable of that type.\n\n```typescript\ntype User = {\n  firstName: string\n  lastName: string\n  age: number\n  email: string\n}\n\nconst liz: User = {\n  firstName: 'Liz',\n  lastName: 'Lemon',\n  age: 38,\n  email: 'liz@example.com'\n}\n```\n\nWe can use variables of this type in _narrower_ contexts as long as the\nproperties that are present have aligning types.\n\nFor instance, we can pass a `User` to this `sendNewsletter` function. Even\nthough the types don't match exactly, the type of `sendNewsletter`'s parameter\nis a subset of `User`.\n\n```typescript\nconst sendNewsletter = ({\n  firstName,\n  email,\n}: {\n  firstName: string;\n  email: string;\n}) => {\n  console.log(`Sending newsletter to ${firstName} at ${email}`);\n};\n\nsendNewsletter(liz);\n// \"Sending newsletter to Liz at liz@example.com\"\n```\n\nThis is a form of [_type\nnarrowing_](https://www.typescriptlang.org/docs/handbook/2/narrowing.html)\nthrough [structural\nsubtyping](https://www.typescriptlang.org/docs/handbook/type-compatibility.html).\n"
  },
  {
    "path": "typescript/type-promise-results-with-the-awaited-type.md",
    "content": "# Type Promise Results With the Awaited Type\n\n[TypeScript 4.5 introduces the `Awaited`\ntype](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-5.html#the-awaited-type-and-promise-improvements)\nwhich can be used to model the resulting type of Promise and async/await code.\n\nThe release notes give a couple helpful examples which I'll share:\n\n```typescript\n// A = string\ntype A = Awaited<Promise<string>>;\n\n// B = number\ntype B = Awaited<Promise<Promise<number>>>;\n\n// C = boolean | number\ntype C = Awaited<boolean | Promise<number>>;\n```\n\nThis can be taken a step further with an existing typed function and the help\nof the [`ReturnType`\ntype](https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype).\n\n```typescript\n// getPosts' return type Promise<Array<Post>>\nimport {getPosts} from './getPost'\n\n// type: { posts: Array<Post> }\ntype LoaderData = {\n  posts: Awaited<ReturnType<typeof getPosts>>;\n}\n```\n\nIt gets the full `typeof` of `getPosts`, whittles that down to the\n`ReturnType`, and then `Awaited` unwraps the promise. I learned this from the\n[Remix blog\ntutorial](https://remix.run/docs/en/v1/tutorials/blog#a-little-refactoring).\n"
  },
  {
    "path": "typescript/use-an-array-check-for-type-narrowing.md",
    "content": "# Use An Array Check For Type Narrowing\n\nIf you are typing a concatenation function for melding two values together into\na single array, you may end up with a function signature like this:\n\n```typescript\ntype ConcatFunction = (value: any | any[], array: any[]) => any[];\n```\n\nThat first argument can be an individual value or an array of values. You'll\nneed to handle both scenarios in the function implementation. Using the\n[`Array.isArray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray)\nfunction as a _type guard_, you can check differentiate between those two\ncases.\n\n```typescript\nconst concat: ConcatFunction = (value, array) => {\n    if(Array.isArray(value)) {\n        return [...value, ...array];\n    } else {\n        return [value, ...array];\n    }\n}\n\nconcat(true, [1,2,3]);\n// [true, 1, 2, 3]\n\nconcat([1,2,3], ['a', 'b', 'c'])\n// [1, 2, 3, 'a', 'b', 'c']\n```\n\nThis is a form of [type\nnarrowing](https://www.typescriptlang.org/docs/handbook/2/narrowing.html).\n"
  },
  {
    "path": "typescript/zero-config-environments-for-trying-out-types.md",
    "content": "# Zero-Config Environments For Trying Out Types\n\nI've found a few zero-config environments for trying out TypeScript. These are\nenvironments where you can write out type definitions, use them in code, and\nsee type errors as they arise. These are great if you are following along with\nan article as opposed to working with an existing project.\n\n1. [The TypeScript Playground](https://www.typescriptlang.org/play)\n\nThis is the quickest environment to jump into. Though TS settings can be\nconfigured, it is just a playground. It is to grab a link to share.\n\n2. [Codesandbox's ts.new](https://ts.new)\n\nThis URL shortcut will spin up a brand-new Vanilla TypeScript codesandbox\nproject. This is a more full-fledged development environment for a TypeScript\nproject, though still in the bowser. It is also easy to share, and you can\ndownload/export the code.\n\n3. [TSDX](https://tsdx.io/)\n\nThis is a zero-config CLI for generating a TypeScript project for package\ndevelopment. It can generate Vanilla and React TypeScript projects. This lets\nyou develop on your machine, rather than in a browser.  You'll now need to push\nthe code to somewhere like GitHub to share it.\n\n[source](https://twitter.com/jbrancha/status/1375876670234722306?s=20)\n"
  },
  {
    "path": "unix/all-the-environment-variables.md",
    "content": "# All The Environment Variables\n\nIf you want to see all the environment variables defined on your machine,\nyou can list them all out with `printenv`. If you are like me, you probably\nhave a ton of them. Pipe it through `less` to make it easier to navigate and\nsearch through (i.e. `printenv | less`).\n"
  },
  {
    "path": "unix/apply-successive-filters-to-lines-in-less.md",
    "content": "# Apply Successive Filters To Lines In Less\n\nLet's say I've opened a large Rails log file with `less`:\n\n```bash\n$ less logs/development.log\n```\n\nI have an idea of what I'm looking for, but there is way more noise than signal.\nI can start to filter out some of the noise. The `&` command starts a filter\nprompt. If I start to filter by something like `INSERT INTO`, then a ton of\nlines disappear leaving just those matching that pattern.\n\nScrolling through the current set of lines, I start to have a better idea of\nwhat I'm looking for, but there is still too much noise. I can apply an\nadditional successive filter on the remaining lines by hitting `&` again and\nentering in another pattern -- e.g. `GoodJob`.\n\nNow I only see lines that contain both `INSERT INTO` and `GoodJob` somewhere in\nthem.\n\nAs `less` puts it:\n\n> Multiple & commands may be entered, in which case only lines which match all\n> of the patterns will be displayed.\n\nIf I want to undo all the filtering, I just need to enter an empty `&` filter\nprompt and it will reset things back to displaying all lines.\n\n> If pattern is empty (if you type & immediately followed by ENTER), any\n> filtering is turned off, and all lines are displayed.\n\nSee `man less` for more details.\n"
  },
  {
    "path": "unix/authorize-a-curl-request.md",
    "content": "# Authorize A cURL Request\n\nWhen making a cURL request to an endpoint that requires authentication,\nsometimes you already have a bearer token and other times you have a username\nand password pair. If you have a bearer token, you can format a `Authorization`\nheader with the `-H` flag that includes that value.\n\nIf you have a username and password for the API, you can instead use the `-u`\nflag. The `-u` flag will format the username and password, base64 encode it,\nand then add it as an `Authorization` header.\n\n```bash\n$ curl -v -u \"username:password\" https://some-endpoint.com/api/v1/status\n\n...\n> GET /api/v1/status HTTP/2\n> Host: some-endpoint.com\n> Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQK\n> User-Agent: curl/8.1.2\n...\n```\n\nYou can even pass in only the username to the `-u` flag and cURL will know to\nprompt you for the password. This is a nice way to avoid putting plain text\npasswords in your shell history.\n\n```bash\n$ curl -v -u \"username\" https://some-endpoint.com/api/v1/status\nEnter host password for user 'username':\n```\n\nSee `man curl` for more details.\n"
  },
  {
    "path": "unix/cat-a-file-with-line-numbers.md",
    "content": "# Cat A File With Line Numbers\n\nYou can quickly view a file using `cat`\n\n```\n$ cat Gemfile\nsource 'https://rubygems.org'\n\n\n# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'\ngem 'rails', '4.2.0'\n# Use postgresql as the database for Active Record\ngem 'pg'\n```\n\nWith the `-n` flag you can view that file with line numbers\n\n```\n$ cat -n Gemfile\n 1  source 'https://rubygems.org'\n 2  \n 3  \n 4  # Bundle edge Rails instead: gem 'rails', github: 'rails/rails'\n 5  gem 'rails', '4.2.0'\n 6  # Use postgresql as the database for Active Record\n 7  gem 'pg'\n```\n"
  },
  {
    "path": "unix/cat-files-with-color-using-bat.md",
    "content": "# Cat Files With Color Using Bat\n\nThe time-tested utility `cat` is probably one of the most used unix\ncommands. It prints the contents of the file to stdout. You can use it to\nget a quick view of a file.\n\n![example of cat](https://i.imgur.com/kb1UjPW.png)\n\nWe live in a world of color and our terminal emulators are capable of so\nmuch more. There is an alternative to `cat`, called `bat`, that provides\nsyntax highlighting based on the type of file.\n\n![example of bat](https://i.imgur.com/ieL7v2Q.png)\n\nThis is an open-source utility written in Rust. You can check it out on\n[github](https://github.com/sharkdp/bat).\n"
  },
  {
    "path": "unix/change-default-shell-for-a-user.md",
    "content": "# Change Default Shell For A User\n\nYou can change the default shell program for a particular unix user with the\n`chsh` command. Just tell it what shell program you want to use (e.g. `bash`\nor `zsh`) and which user the change is for:\n\n```\n$ [sudo] chsh -s /usr/bin/zsh username\n```\n\nThis command needs to be invoked with root privileges.\n\nThis command updates the entry for that user in the `/etc/passwd` file.\n\n[source](http://superuser.com/questions/46748/how-do-i-make-bash-my-default-shell-on-ubuntu)\n"
  },
  {
    "path": "unix/change-to-that-new-directory.md",
    "content": "# Change To That New Directory\n\nThe `$_` variable provided by bash is always set to the last argument of the\nprevious command. One handy use of this is for changing directories into a\nnewly created directory.\n\n```bash\n$ mkdir new_dir && cd $_\n```\n\nThis command will leave you in your newly created directory, `new_dir`.\n\nWe can imagine using this bash variable in a number of similar scenarios as\nwell. What if we are using some language specific command that creates a\ndirectory? Will it work when creating a new Phoenix or Rails project?\n\nIt sure will.\n\nGive it a try with Phoenix:\n\n```bash\nmix phx.new my_app && cd $_\n```\n\nor with Rails:\n\n```bash\nrails new app && cd $_\n```\n\n[source](http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html)\n"
  },
  {
    "path": "unix/check-connected-stripe-account-name.md",
    "content": "# Check Connected Stripe Account Name\n\nWith the Stripe CLI, you can be connected one specific account at a time. When\nyou run `stripe login`, the browser window where you authenticate will have you\nselect the account that you want to connect to. This is important because it\nimpacts test keys, webhooks, where you are sending events, etc.\n\nTo check which account you are connected to, you can look in the Stripe config\nfile for the `display_name`. This is located at `~/.config/stripe/config.toml`.\nYou can have the Stripe CLI spit out the contents of that file with:\n\n```bash\n$ stripe config --list\ncolor = ''\n[default]\naccount_id = 'acct_123abc'\ndevice_name = 'My-MacBook-Pro.local'\ndisplay_name = 'Internet Business'\n...\n```\n\nLet's take this a step further. Here is a one-liner scripted version to check\nthis value using `grep`, `awk`, and `xargs`:\n\n```bash\n$ stripe config --list | grep '^display_name' | awk -F'=' '{print $2}' | xargs\nInternet Business\n```\n\nThe `awk` command is tailored toward parsing a value from a `toml` file.\n"
  },
  {
    "path": "unix/check-if-a-port-is-in-use.md",
    "content": "# Check If A Port Is In Use\n\nThe `lsof` command is used to *list open files*. This includes listing\nnetwork connections. This means I can check if a particular port is in use\nand what process is using that port. For instance, I can check if my rails\napplication is currently running on port 3000.\n\n```\n$ lsof -i TCP:3000\nCOMMAND   PID       USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME\nruby    13821 jbranchaud   12u  IPv6 0xdf2e9fd346cc12b5      0t0  TCP localhost:hbci (LISTEN)\nruby    13821 jbranchaud   13u  IPv4 0xdf2e9fd33ca74d65      0t0  TCP localhost:hbci (LISTEN)\n```\n\nI can see that a ruby process (my rails app) is using port 3000. The PID\nand a number of other details are included.\n\nSee more details with `man lsof`.\n\nh/t [Mike Chau](https://twitter.com/money_mikec)\n"
  },
  {
    "path": "unix/check-if-command-is-executable-before-using.md",
    "content": "# Check If Command Is Executable Before Using\n\nWhen writing a quick bash script, you may want to check if a command exists and\nis executable before trying to call it. This can be done with `command`, a builtin shell command, and the `-v` flag.\n\n> If the -V or -v option is supplied, the exit status is 0 if command was found, and 1 if not.\n\nKnowing that, we can redirect the output of the command to `/dev/null` and then\nshort-circuit executing the command if it's not available.\n\n```bash\ncommand -v pbcopy >/dev/null 2>&1 && echo 'something' | pbcopy\n```\n\nIn this example, I execute the `pbcopy` command, which copies text to my system\nclipboard, only if that command is available and executable.\n\nSee `man bash` and find the listing for `command` for more details.\n"
  },
  {
    "path": "unix/check-ssh-key-fingerprints-of-known-hosts.md",
    "content": "# Check SSH Key Fingerprints Of Known Hosts\n\nThe `ssh-keygen` utility can do a bunch of things related to SSH keys including\ngenerating key pairs, removing a key, and even showing the fingerprints for a\npublic keys file.\n\nAfter [the recent GitHub SSH key\nrotation](https://github.blog/2023-03-23-we-updated-our-rsa-ssh-host-key/), I\nwanted to check that the key I had added produced a fingerprint matching what\nthey described in the article.\n\nThe `-l` flag will list the fingerprints and the `-f` flag allows you to\nspecify what file it processes when doing that.\n\n```bash\nssh-keygen -lf ~/.ssh/known_hosts\n```\n\nI have a bunch of known hosts, so I can narrow it down to just the GitHub entry\nlike so.\n\n```bash\nssh-keygen -lf ~/.ssh/known_hosts | grep github.com\n3072 SHA256:uNiVztksCsDhcc0u9e8BujQXVUpKZIDTMczCvj3tD2s github.com (RSA)\n```\n\nAnd [it matches what GitHub\nlists](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/githubs-ssh-key-fingerprints),\nso I'm good to go.\n\nSee `man ssh-keygen` for more details.\n"
  },
  {
    "path": "unix/check-the-current-working-directory.md",
    "content": "# Check The Current Working Directory\n\nUse\n\n```\n$ pwd\n```\n\nto display the absolute path of the current working directory.\n\nSee `man pwd` for more details.\n"
  },
  {
    "path": "unix/check-the-installed-openssl-version.md",
    "content": "# Check The Installed OpenSSL Version\n\nTypically with command line tools, I can use a `--version` or `-v` flag with\nthe command to get it to output the current version. This is not the case with\n`openssl`.\n\nWhen I do this:\n\n```bash\n$ openssl --version\n```\n\nI get an Invalid Command message and then a bunch of subcommands are displayed.\n\nOne of those subcommands listed under _Standard Commands_ is the `version`\ncommand. This is what I can use to list the version.\n\n```bash\n$ openssl version -v\nLibreSSL 2.8.3\n```\n\nSee `man openssl` for more details.\n"
  },
  {
    "path": "unix/clear-the-screen.md",
    "content": "# Clear The Screen\n\nIf you type `clear` into your shell, the screen will be cleared. There is a\nhandy keybinding though that will save you a few keystrokes. Just hit\n`ctrl-l` to achieve the same effect.\n\nsource: [Derek P.](https://twitter.com/DerkTheDaring)\n"
  },
  {
    "path": "unix/combine-all-my-tils-into-a-single-file.md",
    "content": "# Combine All My TILs Into A Single File\n\nIn [Build A Small Text-based Training\nDataset](https://www.visualmode.dev/build-a-small-text-training-dataset), I went\nover my need for a sizeable and interesting corpus of text that I could use as a\ntraining dataset I could use to run against [my own naive Byte Pair Encoding\nimplementation](https://github.com/jbranchaud/build-an-llm-from-scratch/blob/main/chapter-02/bpe_tokenizer.py).\nMy repo of hand-written TILs is a great candidate, but I need those smashed all\ninto one file.\n\nHere is a formatted version of the one-liner I ended up with:\n\n```bash\n{\n  cat README.md; \\\n  find */ -name '*.md' -print0 \\\n  | sort -z \\\n  | xargs -0 -I{} sh -c 'echo \"<|endoftext|>\"; cat \"$1\"' _ {}; \\\n} > combined.md\n```\n\nThis combines all 1700+ of my TILs into a single file separated by the\n`<|endoftext|>` delimiter.\n\nThe two things I find most interesting about this command are:\n\n1. The use of a null byte (`\\0`) separator between the filenames in case there\n   is anything weird (like spaces) in those filenames. This starts with\n   `-print0`. The `-z` of `sort` maintains that null byte separator. And then\n   `xargs` knows to handle it by the `-0` flag.\n\n2. We can coerce `xargs` into running multiple commands by having it spawn a\n   single shell process that runs each of those commands. To reliably pass the\n   filename into that shell process, we have `xargs` constitute it as the second\n   argument (`$1`) by substituting in the filename where `{}` appears.\n"
  },
  {
    "path": "unix/command-line-length-limitations.md",
    "content": "# Command Line Length Limitations\n\nThe other day I tried to run a `rm` command on the contents of a directory\nwith a **LOT** of files.\n\n```\n$ rm images/*\n```\n\nInstead of deleting the contents of the directory, the following message was\ndisplayed:\n\n```\n/bin/rm: cannot execute [Argument list too long]\n```\n\nBash wanted to expand the entire command before executing it. It was too\nlong. But what is too long?\n\nIt turns out that we can figure out the max length of commands with the\nfollowing command:\n\n```\n$ getconf ARG_MAX\n```\n\nFor me, the result is `262144`.\n\n[source\n1](http://stackoverflow.com/questions/11289551/argument-list-too-long-error-for-rm-cp-mv-commands)\nand [source\n2](http://www.cyberciti.biz/faq/argument-list-too-long-error-solution/)\n"
  },
  {
    "path": "unix/compare-two-variables-in-a-bash-script.md",
    "content": "# Compare Two Variables In A Bash Script\n\nYou can compare two variables in a bash script with an `if` block like so:\n\n```bash\nif [ \"$EDITOR\" = \"$PREFERRED_EDITOR\" ]; then\n  # do something ...\nfi\n```\n\nIf those variables are equal, then the contents of the `if` block will be\nexecuted.\n\nNotice that both variables are wrapped in quotes. This is to avoid a potential\nsyntax error. If the quotes were excluded and one of the variables happened to\nbe unset, then the comparison would evaluate to:\n\n```bash\nif [ \"vim\" = ]; then\n  # do something ...\nfi\n```\n\nThat would cause an error, rather than evaluating to false and moving in.\nWrapping each in quotes allows an unset variable to turn into an empty string\n(`\"\"`).\n"
  },
  {
    "path": "unix/configure-cd-to-behave-like-pushd-in-zsh.md",
    "content": "# Configure cd To Behave Like pushd In Zsh\n\nThe Zsh environment has a setting that allows you to make the `cd` command\nbehave like the `pushd` command. Normally when you use `cd` the [remembered\ndirectory stack](list-the-stack-of-remembered-directories.md) is not\neffected. However, if you add the following setting to your `~/.zshrc` file:\n\n```bash\nsetopt auto_pushd\n```\n\nthen using `cd` to navigate directories will cause those directories to be\nadded to the `dirs` stack.\n\nThis is the default in the [oh-my-zsh configuration of\nzsh](https://github.com/robbyrussell/oh-my-zsh/blob/master/lib/directories.zsh#L2).\n"
  },
  {
    "path": "unix/convert-jpeg-to-png-with-ffmpeg.md",
    "content": "# Convert JPEG To PNG With ffmpeg\n\nThe `ffmpeg` utility \"is a universal media converter.\" That means we can use it\nto convert, for instance, a JPEG file to a PNG file.\n\nThere is not a lot to a conversion like this. We use `-i` to specify the\nexisting input file (a JPEG) and then the other argument is the name and\nextension of the output file.\n\n```bash\n$ ls\nprofile.jpg\n\n$ ffmpeg -i profile.jpg profile.png\n\n$ ls\nprofile.jpg  profile.png\n```\n\nSee `man ffmpeg` for more details.\n"
  },
  {
    "path": "unix/convert-svg-to-favicon.md",
    "content": "# Convert SVG To Favicon\n\nThe imagemagick `convert` CLI tool can convert an SVG file into a transparent\nfavicon (ICO) file with the different standard sizes.\n\nAssuming the background that we want to make transparent is white, then include\n`-transparent white` and then to resize the icon include `-define\nicon:auto-resize ...`. Point to the `image.svg` to be converted and specify the\nname of the output file (`favicon.ico`).\n\n```bash\n$ convert image.svg -transparent white -define icon:auto-resize=16,32,48,64,128 favicon.ico\n```\n\nWe can then use the `identify` CLI to inspect the `favicon.ico` file to see\nthat the above worked.\n\n```bash\n$ identify favicon.ico\n\nfavicon.ico[0] ICO 16x16 16x16+0+0 8-bit sRGB 0.000u 0:00.002\nfavicon.ico[1] ICO 32x32 32x32+0+0 8-bit sRGB 0.000u 0:00.004\nfavicon.ico[2] ICO 48x48 48x48+0+0 8-bit sRGB 0.000u 0:00.004\nfavicon.ico[3] ICO 64x64 64x64+0+0 8-bit sRGB 0.000u 0:00.004\nfavicon.ico[4] ICO 128x128 128x128+0+0 8-bit sRGB 99678B 0.000u 0:00.003\n```\n\n[source](https://www.joshmcarthur.com/2024/06/19/Auto-resizing-images-for-.ico-files.html)\n"
  },
  {
    "path": "unix/copying-file-contents-to-system-paste-buffer.md",
    "content": "# Copying File Contents To System Paste Buffer\n\nIf you need to copy and paste the contents of a file, the `pbcopy` command\ncan be one of the best ways to accomplish this. Simply `cat` the file and\npipe that into `pbcopy` to get the contents of the file into the system\npaste buffer.\n\n```\n$ cat some-file.txt | pbcopy\n```\n\nSee `man pbcopy` for more details.\n"
  },
  {
    "path": "unix/copying-nested-directories-with-ditto.md",
    "content": "# Copying Nested Directories With Ditto\n\nYou can copy nested directories with `cp` using the `-R` (_recursive_) flag.\nThe way `cp` works is that it replaces the target location with the source\ndirectory, wiping out whatever files or directories reside at the target\nlocation.\n\nConversely, the `ditto` utility, available on OS X's version of Unix, does\n_recursive_ directory copies by default and merges the contents of any existing\ndirectories.\n\nAs an example, here are two folders, `folder1` and `folder2`:\n\n```bash\n❯ exa -T folder1\nfolder1\n├── cats\n│  └── sneaky\n└── dogs\n   └── fido\n\n❯ exa -T folder2\nfolder2\n└── cats\n   └── oreo\n```\n\nUsing `ditto` to copy `folder1` to `folder2`\n\n```bash\n❯ ditto folder1 folder2\n```\n\nwe get a `folder2` where directories from `folder1` are created and existing\ndirectories are merged together.\n\n```bash\n❯ exa -T folder2\nfolder2\n├── cats\n│  ├── oreo\n│  └── sneaky\n└── dogs\n   └── fido\n```\n\nSee `man ditto` for more details.\n"
  },
  {
    "path": "unix/count-the-lines-in-a-csv-where-a-column-is-empty.md",
    "content": "# Count The Lines In A CSV Where A Column Is Empty\n\nThe [`xsv` utility](https://github.com/BurntSushi/xsv) is a fast way to analyze\nand work with CSV files from the command line.\n\nWith the `search` subcommand, I can seach for lines that match a pattern and\neven narrow that search to focus on a selected column.\n\nFor instance, to search for any lines where column 3 is empty:\n\n```\n$ xsv search -s 3 '^$' data.csv\n```\n\nThe `-s 3` narrows the search to just column 3. The `'^$'` regex pattern\nmatches on cells where there is the start character (`^`) and end character\n(`$`) with nothing in between, hence empty.\n\nI can then pipe that to `wc -l` to get a count of the number of empty lines.\n\n```\n$ xsv search -s 3 '^$' data.csv | wc -l\n```\n\nSee `xsv search --help` for more details.\n"
  },
  {
    "path": "unix/count-the-number-of-matches-in-a-grep.md",
    "content": "# Count The Number Of Matches In A Grep\n\nMy go to way of counting the number of matches in a `grep` of a file is to pipe\nit to another command — `wc`.\n\nHere is what that looks like with the README for [this\nrepo](https://github.com/jbranchaud/til). This counts the number of lines that\nstart with `###`.\n\n```bash\n$ grep '^###' README.md | wc -l\n      48\n```\n\nWhen `wc` is used with the `-l` flag, it gives a count of the number of lines.\nIn this case the number of `grep` matches that get piped to it.\n\nThere is another way to do this solely with the `grep` command — using the `-c`\nflag.\n\n```bash\n$ grep -c '^###' README.md\n48\n```\n\nWhen you include the `-c` (or `--count`) flag with `grep`, instead of the\nmatches being output, the count of the matches is output.\n\nSee `man grep` for more details.\n"
  },
  {
    "path": "unix/count-the-number-of-ripgrep-pattern-matches.md",
    "content": "# Count The Number Of ripgrep Pattern Matches\n\nIf I run [`ripgrep`](https://github.com/BurntSushi/ripgrep) with a pattern\nagainst a project with many files, I may get a bunch of matches. So many\nmatches even that they scroll off the screen.\n\nTo get a summary of the number of matches in each file, I can include the `-c`\nflag:\n\n```bash\n❯ rg -c taco\nrails/parse-query-params-from-a-url.md:6\nrails/params-is-a-hash-with-indifferent-access.md:4\nruby/fetch-warns-about-superseding-block-argument.md:1\nruby/add-comments-to-regex-with-free-spacing.md:1\nruby/create-a-csv-table-object.md:2\nruby/a-basic-case-statement.md:4\nruby/triple-equals-the-case-equality-operator.md:1\nruby/build-http-and-https-urls.md:4\nrspec/check-specific-arguments-to-received-method.md:2\njavascript/check-classes-on-a-dom-element.md:1\njavascript/spread-merging-objects-includes-nil-values.md:2\nxstate/custom-jest-matcher-for-xstate-machine-states.md:1\npostgres/checking-inequality.md:1\ncase.rb:4\npython/test-a-function-with-pytest.md:6\n```\n\nThat is still a bunch of info and I may want to further summarize by getting a\ncount of the total number of matches. I can do this by piping these results to\nan `awk` command that totals them up.\n\n```bash\n❯ rg -c taco | awk -F: '{total += $2} END {print total}'\n40\n```\n\n[Using `:` as the field\nseperator](https://www.gnu.org/software/gawk/manual/html_node/Full-Line-Fields.html),\n`awk` is able to get the number on the left side (`$2`) for each and sum that\nup.\n"
  },
  {
    "path": "unix/count-the-number-of-words-on-a-webpage.md",
    "content": "# Count The Number Of Words On A Webpage\n\nI was reading through a couple sections of the `postfix` documentation and I\nwas astounded at how large the webpage is, and that is just for the `main.cf`\nfile format.\n\nCuriosity got the best of me and I wanted to get a sense of the magnitude of\nthe page. A word count seemed like a good measure.\n\nUsing `pandoc` and a couple other unix utilities, I was able to quickly get\nthat number.\n\n```bash\ncurl -s http://www.postfix.org/postconf.5.html\\#virtual_mailbox_maps | pandoc -f html -t plain | wc -w\n   88383\n```\n\nGenerically, that is:\n\n```bash\ncurl -s url | pandoc -f html -t plain | wc -w\n```\n\nPandoc produces a plain-text version of the HTML page that was pulled in by\n`curl` and then we use `wc` to get a word (`-w`) count.\n"
  },
  {
    "path": "unix/create-a-file-descriptor-with-process-substitution.md",
    "content": "# Create A File Descriptor with Process Substitution\n\nProcess substitution can be used to create a file descriptor from the\nevaluation of a shell command. The syntax for process substitution is\n`<(LIST)` where `LIST` is one or more bash commands.\n\n```\n$ cat <(echo 'hello, world')\nhello, world\n```\n\nThis is particularly useful for commands that expect files, such as diff:\n\n```\n$ diff <(echo 'hello, world') <(echo 'hello, mars')\n1c1\n< hello, world\n---\n> hello, mars\n```\n\nSources: [Brian Dunn](https://twitter.com/higgaion) and\n[Bash Guide for Beginners](http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html#sect_03_04_07)\n"
  },
  {
    "path": "unix/create-a-filename-with-the-current-date.md",
    "content": "# Create A Filename With The Current Date\n\nI was recently working on a script to pull a scrubbed database dump using the\n`pg_dump` Postgres utility. Ultimately, the script does something like this to\ndump a remote database to a local file:\n\n```bash\npg_dump \\\n  -h host.region.rds.amazonaws.com \\\n  -U db_username \\\n  -d db_name \\\n  -F c \\\n  -f scrubbed-database-$(date +%Y-%m-%d).dump\n```\n\nNotice the last part of that command where we define the name of the dump file.\nIt has a `$(...)` that is used to run and interpolate a command as part of the\nfilename.\n\nHere is that `date` command run on its own:\n\n```bash\n$ date +%Y-%m-%d\n2025-04-02\n```\n\nIn the above command, that would mean if I were to run it today, I'd get\n`scrubbed-database-2025-04-02.dump`.\n\nThis approach can be used with any command where you are producing a file that\nyou want to be dated or timestamped.\n\nHere is another example that incorporates the time as well:\n\n```bash\n$ touch $(date +%Y%m%d_%H%M%S)-migration.sql\n# => 20250402_092442-migration.sql\n```\n"
  },
  {
    "path": "unix/create-a-sequence-of-values-with-a-step.md",
    "content": "# Create A Sequence Of Values With A Step\n\nThe `seq` utility allows you to output a sequence of values.\n\nYou can start at `1` by default.\n\n```bash\n$ seq 3\n1\n2\n3\n```\n\nOr you can specify the starting value.\n\n```bash\n$ seq 10 13\n10\n11\n12\n13\n```\n\nAdding a third argument in between those two will specify the step value that\nshould be taken to get from one to the other.\n\n```bash\n$ seq 6 3 15\n6\n9\n12\n15\n```\n\nThat sequence starts at 6 and goes to 15 with a step value of 3.\n\nSee `man seq` for more details.\n"
  },
  {
    "path": "unix/curl-with-cookies.md",
    "content": "# Curl With Cookies\n\nSome endpoints require certain cookies to be included in order to get the\nresponse you are looking for. For instance, if the endpoint is authenticated\nwith a session cookie, then you will need to provide that session cookie when\ncurling.\n\nThe `-b` flag can be used to instruct `curl` to include a cookie in the header\nof a request.\n\n```bash\n$ curl -b session=abc123SessionToken https://authenticated-url.com\n```\n\nSee `man curl` for more details and other flags.\n"
  },
  {
    "path": "unix/curling-for-headers.md",
    "content": "# Curling For Headers\n\nIf you want to inspect the headers of a response from some endpoint, look no\nfurther than a quick `curl` command. By including the `-I` flag, `curl` will\nreturn just the headers.\n\nFor example, if you are developing a web app that is being locally served at\n`localhost:3000` and you'd like to see what the headers look like for a\nparticular URL, you might try something like the following command:\n\n```bash\n$ curl -I localhost:3000/posts\n```\n\nh/t Dillon Hafer\n"
  },
  {
    "path": "unix/curling-with-basic-auth-credentials.md",
    "content": "# Curling With Basic Auth Credentials\n\nI often use `curl` to take a quick look at the responses of particular\nendpoints. If I try to `curl` a URL that is secured with HTTP Basic\nAuthentication, this is what the response looks like:\n\n```bash\n$ curl staging.example.com\nHTTP Basic: Access denied.\n```\n\nI can give the credentials to `curl` so that it can plug them in as it makes\nthe request using the `-u` (or `--user`) flag:\n\n```bash\n$ curl -u username:password staging.example.com\n<html><body>...</body></html>\n```\n\nIf I don't want the password showing up in my command-line history, I can\njust provide the username and `curl` will prompt me for my password:\n\n```bash\n$ curl -u username staging.example.com\nEnter host password for user 'username':\n<html><body>...</body></html>\n```\n\nSee `man curl` for more details.\n"
  },
  {
    "path": "unix/determine-ipv4-and-ipv6-public-ip-addresses.md",
    "content": "# Determine ipv4 And ipv6 Public IP Addresses\n\nThere are a number of ways to do this. The one that I've settled on is sending a\n`curl` request to a public URL that was specifically set up to echo back the\npublic IP of the device making the request. There are many such URLs, but the\none that I tend to use is `ifconfig.io`.\n\nWhen I run this as is, I get something like the following which you may\nrecognize as an _ipv6_ IP address.\n\n```bash\n$ curl ifconfig.io\n2001:db8:3333:4444:5555:6666:7777:8888\n```\n\nThis is because if ipv6 is available, like it is for me, `curl` is going to\nprefer that.\n\nNow, if I'm trying to track down specifically my ipv4 address, I can use the\n`-4` flag (or `--ipv4`).\n\n```bash\n$ curl -4 ifconfig.io\n73.23.45.157\n```\n\nSimilarly, I could explicitly specify ipv6 with `-6` or `--ipv6`.\n\nSee `man curl` for more details.\n"
  },
  {
    "path": "unix/diff-two-files-in-unified-format.md",
    "content": "# Diff Two Files In Unified Format\n\nThe `diff` command is a standalone utility that can be used to get the\ndifference between two files. It is similar to what you might expect when\nrunning `git diff` which compares two different versions of the same file. The\n`diff` command predates `git` and its unified format is what became the standard\nthat `git` uses for its own diff implementation.\n\nRunning `diff` with two files as is gives output like the following:\n\n```bash\n❯ diff startup.sh startup2.sh\n10,13c10,14\n< declare -A SESSIONS=(\n<   [\"TIL\"]=\"$HOME/dev/jbranchaud/til:setup_til\"\n<   [\"PLP\"]=\"$HOME/dev/jbranchaud/pool-league-pro:\"\n<   [\"client-app\"]=\"$HOME/dev/client/client-app:\"\n---\n> # Sessions will be created in the order listed here\n> SESSIONS=(\n>   \"TIL:$HOME/dev/jbranchaud/til:setup_til\"\n>   \"PLP:$HOME/dev/jbranchaud/pool-league-pro:\"\n>   \"client-app:$HOME/dev/client/client-app:\"\n73,74c74,75\n<   for session_name in TIL PLP client-app; do\n<     IFS=':' read -r directory setup_function <<<\"${SESSIONS[$session_name]}\"\n---\n>   for session_config in \"${SESSIONS[@]}\"; do\n>     IFS=':' read -r session_name directory setup_function <<<\"$session_config\"\n```\n\nThat's readable at a glance, but the unified format (with the `-u` flag) can\nprovide more context:\n\n```bash\n❯ diff -u startup.sh startup2.sh\n--- startup.sh  2026-01-10 12:46:52\n+++ startup2.sh 2026-01-10 12:48:00\n@@ -7,10 +7,11 @@\n\n # Session configurations\n # Format: \"session_name:directory:setup_function\"\n-declare -A SESSIONS=(\n-  [\"TIL\"]=\"$HOME/dev/jbranchaud/til:setup_til\"\n-  [\"PLP\"]=\"$HOME/dev/jbranchaud/pool-league-pro:\"\n-  [\"client-app\"]=\"$HOME/dev/client/client-app:\"\n+# Sessions will be created in the order listed here\n+SESSIONS=(\n+  \"TIL:$HOME/dev/jbranchaud/til:setup_til\"\n+  \"PLP:$HOME/dev/jbranchaud/pool-league-pro:\"\n+  \"client-app:$HOME/dev/client/client-app:\"\n )\n\n # Setup function for TIL session\n@@ -70,8 +71,8 @@\n   echo \"\"\n\n   # Create sessions in order\n-  for session_name in TIL PLP client-app; do\n-    IFS=':' read -r directory setup_function <<<\"${SESSIONS[$session_name]}\"\n+  for session_config in \"${SESSIONS[@]}\"; do\n+    IFS=':' read -r session_name directory setup_function <<<\"$session_config\"\n     create_session \"$session_name\" \"$directory\" \"$setup_function\"\n   done\n```\n\nHere we get additional context like surrounding lines and file name details.\n\nWhile this is useful on its own, it also has the added benefit of making the\noutput compatible with other tools we may already be using. For instance, I'm\nalready using [delta](https://github.com/dandavison/delta) as my [git pager](https://github.com/jbranchaud/dotfiles/blob/main/gitconfig#L51) and [git differ](https://github.com/jbranchaud/dotfiles/blob/main/gitconfig#L139).\n\nWith the unified format, I can pipe the output directly to `delta` to get a\nbetter view of the diff that is colorized and includes syntax highlighting.\n\n```bash\n❯ diff -u startup.sh startup2.sh | delta\n```\n"
  },
  {
    "path": "unix/different-ways-to-generate-a-v4-uuid.md",
    "content": "# Different Ways To Generate A v4 UUID\n\nThere have been times where I have needed a random UUID. Usually if I am\nmocking some data or testing something out that needs a value in the shape of a\nUUID. Here are a couple different ways to do this in the terminal, as\none-liners.\n\nWith `ruby` and the `SecureRandom` class:\n\n```bash\n$ ruby -e \"require 'securerandom'; puts SecureRandom.uuid\"\n29e52b97-b43d-4025-a43d-70053b1d1a63\n```\n\nWith `psql` and the `gen_random_uuid()` function:\n\n```bash\n$ psql -Xqtc 'select gen_random_uuid()' postgres | xargs\n5a925ebd-c85f-4d94-a81e-e229c4cbe99f\n```\n\nWith the `uuidgen` function that ships with Unix/Linux OSs:\n\n```bash\n$ uuidgen\nB11555D8-A256-4EC8-A0B0-9259FF88C3FC\n```\n"
  },
  {
    "path": "unix/display-all-the-terminal-colors.md",
    "content": "# Display All The Terminal Colors\n\nThe following snippet of bash scripting will print out a nicely formatted\ncollection of all the terminal colors.\n\n```bash\nfor x in {0..8}; do \n    for i in {30..37}; do \n        for a in {40..47}; do \n            echo -ne \"\\e[$x;$i;$a\"\"m\\\\\\e[$x;$i;$a\"\"m\\e[0;37;40m \"\n        done\n        echo\n    done\ndone\necho \"\"\n```\n\nThis is a great way to figure out the escape codes you need for coloring and\nstyling text in a bash script.\n\n[source](https://askubuntu.com/questions/27314/script-to-display-all-terminal-colors)\n\nh/t Dillon Hafer\n"
  },
  {
    "path": "unix/display-free-disk-space.md",
    "content": "# Display Free Disk Space\n\nThe `df` utility is a handy way to display the free disk space available on\non a specific file system or all mounted file systems.\n\nUse `df` with the `-h` flag to display the disk space usage and availability\nin a human-readable format.\n\nHere is the output from a linode box of mine:\n\n```bash\ndf -h\nFilesystem      Size  Used Avail Use% Mounted on\n/dev/xvda        20G  3.8G   16G  20% /\nnone            4.0K     0  4.0K   0% /sys/fs/cgroup\ndevtmpfs        994M  4.0K  994M   1% /dev\nnone            200M  196K  199M   1% /run\nnone            5.0M     0  5.0M   0% /run/lock\nnone            996M     0  996M   0% /run/shm\nnone            100M     0  100M   0% /run/user\n```\n\nh/t Josh Davey\n"
  },
  {
    "path": "unix/display-line-numbers-while-using-less.md",
    "content": "# Display Line Numbers While Using Less\n\nIncluding line numbers while viewing files with `less` can provide useful\ncontext for understanding where you are within the file. This is especially true\nif you've used `&` to filter down to lines that match a pattern.\n\nYou can start `less` with line numbers with the `-N` flag (or `--LINE-NUMBERS`\nif you really want to spell it out).\n\n```bash\n$ less -N log/development.log\n```\n\nIf you've already started up `less` and wish you had included line numbers,\nthere is no reason to restart it with the flag. Instead, toggle the line numbers\noption on within the `less` process. To do this, type `-N`. It will prompt you\nwith `Constantly display line numbers (press RETURN)`. Hit enter and line\nnumbers will appear to the left of each line in the file.\n\nSimilarly, to toggle line numbers back off within `less`, hit `-n` (lower-case\n`n`), accept the prompt, and back off they go.\n\nBoth of these (`-N`/`-n`) are options being set (toggled) via the `-` command.\nThere are many other options like these that can be configured within a `less`\nsession in the same way.\n\nSee `man less` and find the `-` command and the available `OPTIONS`.\n"
  },
  {
    "path": "unix/display-the-contents-of-a-directory-as-a-tree.md",
    "content": "# Display The Contents Of A Directory As A Tree\n\nThe [`exa` utility](https://github.com/ogham/exa) is a speedy replacement for\n`ls` that offers some additional features. One of those extra features is the\n_tree_ display.\n\nBy including the `-T` (or `--tree`) flag, `exa` will recurse into a directory\nand display the entirety of the contents as a tree.\n\n```bash\n❯ exa -T\n.\n├── folder1\n│  ├── cats\n│  │  └── sneaky\n│  └── dogs\n│     └── fido\n└── folder2\n   ├── cats\n   │  ├── oreo\n   │  └── sneaky\n   └── dogs\n      └── fido\n```\n\nYou can target a specific directory:\n\n```bash\n❯ exa -T folder2\nfolder2\n├── cats\n│  ├── oreo\n│  └── sneaky\n└── dogs\n   └── fido\n```\n\nSee `man exa` for more details.\n"
  },
  {
    "path": "unix/do-a-dry-run-of-an-rsync.md",
    "content": "# Do A Dry Run Of An rsync\n\nThe `rsync` command, especially when running recursively (with the `-a` flag),\nwill create and update a bunch of directories and files. Because of that, you\nmay want to do a _dry run_ of an `rsync` command to make sure it is touching\nthe intended files.\n\nThe `--dry-run` flag (or the `-n` flag for short) will prepare a\nsynchronization of one directory to another. You can use this flag to be sure\nthat the source and target files and directories are correct.\n\nThe `-n` (or `--dry-run`) flag on its own won't _show_ what is going to get\nsynced. To get that information, you need to combine it with the `-v` (verbose)\nflag.\n\n```bash\n$ rsync -anv til-temp/ til-content\n\nbuilding file list ... done\n./\nLICENSE\n...\n\nsent 909 bytes  received 296 bytes  2410.00 bytes/sec\ntotal size is 1058  speedup is 0.88\n```\n\nThat will show everything that is going to be synced from `til-temp/`\nrecursively to `til-content`.\n\nDoing a dry run is a great way to make sure you have the patterns for\n`--exclude` flags correct, before actually syncing anything.\n\n```bash\n$ rsync -anv --exclude='./*.md' --exclude='.*' til-temp/ til-content\n```\n\nThat excludes top-level markdown files and all dotfiles and dot-directories.\n\n[source](https://www.digitalocean.com/community/tutorials/how-to-use-rsync-to-sync-local-and-remote-directories)\n"
  },
  {
    "path": "unix/do-not-overwrite-existing-files.md",
    "content": "# Do Not Overwrite Existing Files\n\nWhen using the `cp` command to copy files, you can use the `-n` flag to make\nsure that you do not overwrite existing files.\n\nh/t [Dillon Hafer](https://twitter.com/dillonhafer)\n"
  },
  {
    "path": "unix/download-a-file-with-curl.md",
    "content": "# Download A File With Curl\n\nThough I typically think of cURL as a way of hitting an API endpoint to check\nits headers or see what it returns, it can also be used as an alternative to\n`wget` to download a file.\n\nWith the `-O` option (short for `--remote-name`) we instruct cURL to save the\ncontents of the remote file to a local file in the current directory _using the\nsame name as the remote_.\n\nHere is an example:\n\n```bash\n$ curl -O https://www.apache.org/dist/db/derby/db-derby-10.17.1.0/db-derby-10.17.1.0-bin.zip.asc\n```\n\nThis creates a file in my current directory called\n`db-derby-10.17.1.0-bin.zip.asc`. Notice it only uses the last part of the path\nfor the file name.\n\nSee `man curl` for more details.\n\n[source](https://stackoverflow.com/questions/4572153/os-x-equivalent-of-linuxs-wget#comment84857090_4572158)\n"
  },
  {
    "path": "unix/enable-multi-select-of-results-with-fzf.md",
    "content": "# Enable Multi-Select Of Results With fzf\n\nYou can pipe the output of any command to\n[`fzf`](https://github.com/junegunn/fzf) and it will display it line-by-line in\na list that you can then fuzzy-find against.\n\nBy default you get to pick _one_ of those results. That result will go to\nstdout, either printing to the terminal or being piped to the next command.\n\nFor some combinations of commands, it makes more sense to be able to select\n_multiple_ results. `fzf` supports this with the `-m` (or `--multi`) flag.\n\n```bash\n$ ls | fzf -m | xargs cat\n```\n\nFor instance, this series of commands pipes the output of `ls` (files and\ndirectoris) to `fzf`. The `-m` flag means that you can hit `Tab` (or\n`Shift+Tab`) to select multile entries. When you hit enter, each of the\nselected entries will be executed one by one with `cat`.\n\nI show a slightly more practical example of this in [Make One-Line Commands\nInteractive with fzf](https://www.youtube.com/watch?v=wf5eXdwfVws).\n\nSee `man fzf` for more details.\n"
  },
  {
    "path": "unix/exclude-a-command-from-the-zsh-history-file.md",
    "content": "# Exclude A Command From The ZSH History File\n\nThe `zsh` shell can be configured to record the commands you run from the\nterminal in a history file. This is great for recalling and retrieving past\ncommands that you want to run again.\n\nWhat about commands that I don't want written to a file on my machine? For\ninstance, if I'm running a command that includes a password, secret key, or\nsome other sensitive value, I don't want that saved in plaintext on my machine.\n\n`zsh` has an affordance for this with the `hist_ignore_space` option. With that\noption enabled, any command preceded by a space (`' '`) will be excluded from\nthe history file.\n\nFirst, turn it on.\n\n```zsh\n$ setopt hist_ignore_space\n```\n\nNow, try a couple commands and see what shows up in the file.\n\n```zsh\n$ echo 'this command will be saved in history'\nthis command will be saved in history\n\n$  echo 'this will be kept secret'\nthis will be kept secret\n\n$ tail ~/.zsh_history\n: 1654378676:0;echo 'this command will be saved in history'\n: 1654378690:0;tail ~/.zsh_history\n```\n\nNotice how the second command with the prefixed space is excluded.\n\n[source](https://unix.stackexchange.com/a/6104/5916)\n"
  },
  {
    "path": "unix/exclude-a-directory-with-find.md",
    "content": "# Exclude A Directory With Find\n\nUsing `find` is a handy way to track down files that meet certain criteria.\nHowever, if there are directories full of irrelevant files, you may end up\nwith a lot of noise. What you want to do is exclude or ignore such\ndirectories. For example, you probably don't want `find` to return results\nfrom the `.git` directory of your project.\n\nSpecific directories can be excluded by combining the `-not` and `-path`\narguments.\n\nFor instance, to see all files modified within the last 10 days, but not\nincluding anything in the `.git` directory, run the following:\n\n```bash\n$ find . -type f -not -path './.git/*' -ctime -10\n```\n\n[source](http://stackoverflow.com/questions/4210042/exclude-directory-from-find-command)\n"
  },
  {
    "path": "unix/exclude-a-specific-file-from-fd-results.md",
    "content": "# Exclude A Specific File From fd Results\n\nI recent wrote a\n[`cat-to-markdown`](https://github.com/jbranchaud/dotfiles/blob/my-dotfiles/bin/cat-to-markdown)\nscript that can be piped a list of files from the output of another command to\ndo its thing. I then used [`fd`](https://github.com/sharkdp/fd) to list a\nspecific set of files by extension that could be piped to this command.\n\n```bash\nfd -e js | cat-to-markdown | pbcopy\n```\n\nThis worked, but I quickly realized that one of the JavaScript files included in\nthat listing was massive and didn't need to be included.\n\nTo exclude it from the list I can use the `-E` flag and then name the file like\nso:\n\n```bash\nfd -e js -E super-large-file.js | cat-to-markdown | pbcopy\n```\n\nI believe this can be an exact match file path or even a pattern that matches\nmultiple files.\n\nSee `man fd` for more details.\n"
  },
  {
    "path": "unix/exclude-certain-files-from-an-rsync-run.md",
    "content": "# Exclude Certain Files From An rsync Run\n\nThe `rsync` command can be used to copy files from one directory to another (as\nwell as to or from a remote system). It is generally used to broadly\nsynchronize all files in the source directory to a destination directory.\n\nI recently ran into a situation where I wanted to recursively (`-a`) sync files\nfrom a cloned git repository. I didn't want quite everything—namely dotfiles,\ndot-directories (such as `.git/`), and top-level markdown files.\n\nThis is where the `--exclude` flag comes in to play.\n\nThe dotfiles and dot-directories can be excluded with the `.*` pattern.\n\n```bash\n$ rsync -anv --exclude='.*' dir1/ dir2\n```\n\nThe top-level markdown files can be excluded, without excluding nested markdown\nfiles, with the `./*.md` pattern.\n\n```bash\n$ rsync -anv --exclude='.*' --exclude='./.*md' dir1/ dir2\n```\n\nThe `-n` and `-v` flags together provide a dry run of this with results that I\ncan check. Once I'm ready to do the real thing, I can remove those.\n\n```bash\n$ rsync -a --exclude='.*' --exclude='./.*md' dir1/ dir2\n```\n\nSee `man rsync` for more details.\n"
  },
  {
    "path": "unix/figure-out-the-week-of-the-year-from-the-terminal.md",
    "content": "# Figure Out The Week Of The Year From The Terminal\n\nWant to know what week of the year we are currently in? You can use the\n[`date`](http://man7.org/linux/man-pages/man1/date.1.html) utility to figure it\nout.\n\n```bash\n$ date +%V\n```\n\nThe `%V` is a formatting directive with this description:\n\n> ISO week number, with Monday as first day of week (01..53)\n\n[source](https://stackoverflow.com/questions/3237882/get-week-of-year-from-day-of-year)\n"
  },
  {
    "path": "unix/file-type-info-with-file.md",
    "content": "# File Type Info With File\n\nUse the `file` utility to determine the type of a file:\n\n```bash\n$ file todo.md\ntodo.md: ASCII English text\n\n$ file Hello.java\nHello.java: ASCII C++ program text\n\n$ file Hello.class\nHello.class: compiled Java class data, version 52.0\n```\n\nThe `Hello.java` file isn't exactly a C++ program, but close enough.\n"
  },
  {
    "path": "unix/find-a-file-installed-by-brew.md",
    "content": "# Find A File Installed By Brew\n\nI installed a homebrew formula to satisfy a dependency for a Rails application.\nRelated to [the whole mimemagic\ndebacle](https://github.com/rails/rails/issues/41750), I had run [`brew install\nshared-mime-info`](https://formulae.brew.sh/formula/shared-mime-info). The\nspecific file that Rails needed from this install was `freedesktop.org.xml`.\n\nIt took me two commands to figure out if that file had been included and where\nit was living.\n\nThe first was to find the _brew prefix directory_ — the place where homebrew\nhad installed everything related to `shared-mime-info`.\n\n```bash\n$ brew --prefix shared-mime-info\n/usr/local/opt/shared-mime-info\n```\n\nNow that I know about that directory, I can use\n[`fd`](https://github.com/sharkdp/fd)—a more user-friendly alternative to\n`find`—to _find_ the specific file in that directory. Not wanting to cast too\nnarrow of a net, I decided to look for any `xml` file in that directory.\n\n```bash\n$ fd -e xml . /usr/local/opt/shared-mime-info\n/usr/local/opt/shared-mime-info/share/shared-mime-info/packages/freedesktop.org.xml\n```\n\nThe `-e` flag specifies the file extension. The `.` is the first argument, the\npattern to look for. In this case, anything. The second argument\n(`/usr/local/opt/shared-mime-info`) is the path to look within. In this case,\nthe brew prefix for the `shared-mime-info` package.\n"
  },
  {
    "path": "unix/find-all-files-matching-a-name-with-fd.md",
    "content": "# Find All Files Matching A Name With fd\n\nThe [`fd` command](https://github.com/sharkdp/fd) can be used to find files in\nyour file system by name. Though it has some nice defaults—it excludes hidden\ndirectories and respects your `.gitignore` file—you may need to configure\nthose.\n\nFor instance, I want to find ALL _sitemap_ files in a monorepo.\n\n```bash\n$ fd -I -H sitemap.xml\n```\n\nThe `-I` flag tells `fd` to not respect the `.gitignore` file. The `-H` flag\nsays to include hidden directories in the recursive search.\n\nThis included a bit too much noise from the `node_modules` directory, so I want\nto exclude that.\n\n```bash\n$ fd -I -H -E node_modules sitemap.xml\n```\n\nThe `-E` flag can specify one-off directories to exclude from the search.\n\nI can even specify a regex to make sure I capture files that look like\n`sitemap-01.xml`, not just `sitemap.xml`.\n\n```bash\n$ fd -I -H -E node_modules 'sitemap.*.xml'\n```\n\nAfter familiarizing myself with a few flags, I'm able to take full advantage of\n`fd`.\n"
  },
  {
    "path": "unix/find-all-files-with-a-specific-extension-with-fd.md",
    "content": "# Find All Files With A Specific Extension With fd\n\nThe best way with [`fd`](https://github.com/sharkdp/fd) to match on files with\na specific extension is to use the `-e` flag.\n\nHere is how you'd find all `.ts` files:\n\n```bash\n$ fd -e ts\n```\n\nYou can use the flag multiple times to specify multiple file extensions. This\nwill turn up all TypeScript and JavaScript files:\n\n```bash\n$ fd -e ts -e js\n```\n\nAlternatively, you can use regex in the filename pattern to match on several\nfile extensions like so:\n\n```bash\n$ fd '.*\\.(js|ts|jsx|tsx)$'\n```\n"
  },
  {
    "path": "unix/find-all-tool-version-files-containing-postgres.md",
    "content": "# Find All Tool Version Files Containing Postgres\n\nI've been using [`asdf`](https://asdf-vm.com/) for many years now which means I\nhave projects and directories all over my machine with `.tool-versions` files.\nMany of them specify Ruby and Node versions. Some of them also include\nPostgreSQL versions. I used to use `asdf` to manage Postgres versions, but no\nlonger do that for new or active projects.\n\nI want to find all the places that a `.tool-versions` file declares `postgres`\nas a tool. That way I can begin to clean up the left behind artifacts of\nasdf-managed Postgres.\n\nBy combining [`fd`](https://github.com/sharkdp/fd) (a better `find`) and\n[`rg`](https://github.com/BurntSushi/ripgrep) (a better `grep`), I'm able to\nquickly track down the list of places.\n\n```bash\n$ fd --hidden .tool-versions ~/ | xargs rg postgres\n\n/Users/jbranchaud/.local/state/nvim/undo/%Users%jbranchaud%.tool-versions: binary file matches (found \"\\0\" byte around offset 9)\n\n/Users/jbranchaud/code/fake-data/.tool-versions\n2:postgres 13.1\n\n/Users/jbranchaud/code/thirty_days/thirty_days_server/.tool-versions\n1:postgres 13.1\n\n/Users/jbranchaud/code/visualmode/.tool-versions\n1:postgres 11.11\n```\n\nThat first instance is a binary file as part of `nvim`'s undo history which I\ncan ignore. The other three are good results.\n\nI tell the `fd` command to not exclude hidden files as it looks for all\noccurrences of `.tool-versions` recursively from my home (`~/`) directory. I\nthen pipe that list of files to `xargs` which makes those filenames arguments\nto the `rg postgres` command.\n"
  },
  {
    "path": "unix/find-and-copy-a-value-from-large-json-output.md",
    "content": "# Find And Copy A Value From Large JSON Output\n\nI've been using [`fx`](https://github.com/antonmedv/fx) for years as a sidekick\nto [`jq`](https://jqlang.org/) when I want to explore a JSON document or JSON\noutput that I'm not yet familiar with. A more recent version of `fx` added the\nability to _yank_ (copy) values and keys you find in the document.\n\nFor instance, I may be looking for some info about my AWS RDS instances, so I\npipe that command to `fx`.\n\n```bash\n$ aws rds describe-db-instances --output json | fx\n```\n\nThis takes a moment to process and then the `fx` viewer is populated with a\nlarge blob of JSON. I can then hit `/` to start a document search, type in\nsomething like `Endpoint`, and then look around for the specific key-value pair\nI'm interested in.\n\nI can then hit `y` to indicate that I want to copy the element under my cursor.\nIf it is a key-value pair I will then be prompted to pick whether I want the\nvalue (`v`), the key (`k`), or the JSON path to this value (`p`).\n"
  },
  {
    "path": "unix/find-any-dotfiles-that-modify-path-env-var.md",
    "content": "# Find Any Dotfiles That Modify Path Env Var\n\nWhether you are using `zsh`, `bash`, or some other shell, there are a variety\nof dotfiles where you can place statements to update the `PATH` env var. These\nfiles don't all run in the same contexts and it can be tricky to debug if one\nis clobbering the path set by another.\n\nOne way to audit how your `PATH` gets set and track down any issues is to find\nany place where the path may be getting modified in your dotfiles.\n\nI like to use [`rg` (ripgrep)](https://github.com/BurntSushi/ripgrep) for tasks\nlike this.\n\nFirst, I want to check where the `PATH` is explicitly modified.\n\n```bash\n$ rg 'export PATH' ~/\\.* --max-depth 0\n```\n\nThis looks at all instances of dotfiles in my home directory where `export\nPATH` appears. That should catch the majority of ways that it gets updated.\n\nNext, because I am using `zsh` as my shell, I want to look for another way my\npath might be set. `zsh` defaults to setting up `path` as proxy for `PATH` that\nacts as an array.\n\nI check for any instances of `path=` or `path+=` in my dotfiles:\n\n```bash\n$ rg 'path\\+?=' ~/\\.* --max-depth 0\n```\n\nNote that the `--max-depth 0` is really important for both because otherwise a\nton of irrelevant stuff buried in deeply-nested dot-directories will be\nsurfaced.\n\nIf you want just a file name summary of the results, tack on a `-l` flag.\n"
  },
  {
    "path": "unix/find-duplicate-lines-in-a-file.md",
    "content": "# Find Duplicate Lines In A File\n\nLet's say I have a large file in a Ruby project. I want to find instances of a\n`field` declaration being duplicated throughout the file. Just searching for\nduplicate lines within the file is going to result in all kinds of false\npositives (think, lots of duplicate `end` lines).\n\nWhat I can do is `grep` for a pattern that will just match on the lines that\nare `field` declarations. The results of the `grep` can then be piped to `sort`\nwhich will order them. This ordering will mean that any duplicates are placed\nnext to each other. Lastly, I'll pipe the sorted lines to `uniq` with the `-d`\nflag which will filter the results down to just those lines that are repeated.\n\nHere is what the whole thing looks like:\n\n```\n$ grep -o \"field :[a-zA-Z_][a-zA-Z_0-9]*\" file.rb | sort | uniq -d\n```\n\nSee `man uniq` for more details on the available flags.\n"
  },
  {
    "path": "unix/find-files-with-fd.md",
    "content": "# Find Files With fd\n\nThe [`fd` command](https://github.com/sharkdp/fd) is an open-source utility\nwritten in Rust. It is a fast and user-friendly way to find files -- as\ncompared to the standard `find` command.\n\nYou can recursively look in the current directory for a file with `git` in\nthe name like so:\n\n```bash\n$ fd git\n```\n\nIf you have a `.gitignore` file, it will ignore those files and directories\nby default.\n\nProviding a second argument, `fd` will start its recursive search from that\ndirectory.\n\n```bash\n$ fd git ~\n```\n\nHere, `fd` will look for filenames with `git` everywhere within my home\ndirectory.\n\nYou can `brew install fd` to get the command and `man fd` for more details.\n"
  },
  {
    "path": "unix/find-newer-files.md",
    "content": "# Find Newer Files\n\nUse the `-newer` flag with the name of a file to find files that have a\nnewer modification date than the named file.\n\nFor instance,\n\n```\n$ find blog -name '*.md' -newer blog/first-post.md\n```\n\nwill find all markdown files in the `blog` directory that have a\nmodification date more recent than `blog/first-post.md`.\n"
  },
  {
    "path": "unix/find-occurrences-of-multiple-values-with-ripgrep.md",
    "content": "# Find Occurrences Of Multiple Values With Ripgrep\n\nLet's say I have a several values that show up throughout the files in my\nproject. They are `Valid`, `Restricted`, `Refunded`, `Disputed`, and `Banned`.\n\nI want to find all occurrences of each of these values.\n\nThis can be done with [`rg` (ripgrep)](https://github.com/BurntSushi/ripgrep)\nand a bit of regex.\n\n```bash\nrg \"\\b(Valid|Restricted|Refunded|Disputed|Banned)\\b\"\n```\n\nThis uses `\\b` on both ends to indicate word boundaries. This ensures it\nmatches on `Valid` without also matching on `Validate`. It then wraps all the\noptions in parentheses separated by `|` which says, \"match on this word, this\nword, ..., or this word\".\n\nI can even take this a step further by only matching on quoted instances of\nthese words like so:\n\n```bash\n$ rg \"[\\\"']\\b(Valid|Restricted|Refunded|Disputed|Banned)\\b[\\\"']\"\n```\n"
  },
  {
    "path": "unix/find-top-level-directories-matching-a-pattern.md",
    "content": "# Find Top-Level Directories Matching A Pattern\n\nI like using [`fd`](https://github.com/sharkdp/fd) as an alternative to `find`.\nIn my experience it is more intuitive to use. For instance, I wanted to find\nall the top-level directories in my current directory that contained the word\n`next`. I was able to get the command mostly right by guessing the flags, only\nchecking the man page once.\n\nOn my first attempt, it prompted me with a suggestion for a flag that wasn't\nquite right. I tried `--depth`, but it should have been `--maxdepth`.\n\n```bash\n$ fd --depth 0 next ./\nerror: Found argument '--depth' which wasn't expected, or isn't valid in this context\n        Did you mean --maxdepth?\n```\n\nThen I checked the man page for how to specify the file type as _directory_ --\nusing `-t` or `--type` with `d`.\n\nAnd here is the command that gets me all top-level directories matching `next`\nin my current directory:\n\n```bash\n$ fd --maxdepth 1 --type d next ./\n\nbookshelf-nextjs-prisma-postgres\nbookshelf-prisma-nextjs-planetscale\nmy-next-app\nnext-bookshelf\nnext-personal-site\nnext-sanity-v3-example\ntry-trpc-next\n```\n\nSee `man fd` for more details.\n"
  },
  {
    "path": "unix/fix-previous-command-with-fc.md",
    "content": "# Fix Previous Command With fc\n\nThe `fc` command is a Bash and ZSH built-in command that allows you to interact\nwith the history of commands issued in the shell. The most straightforward use\ncase I know of for using this command is to fix or edit some aspect of the\nprevious run command.\n\nWhen `fc` is executed with no arguments or flags, it will grab the latest entry\nto the command history and load it into your default editor. For me, that is\nVim.\n\nI can make edits in that Vim session like I'd do in any other Vim session. When\nI write and quit (`:wq`) the file, the updated command will be executed. This\nis useful if, say, I've made a typo in the previous command and would prefer\nthe ergonomics of my default editor to fix it. Or let's say I have a really\nlong command with many flags and long file path arguments. It would be much\neasier and quicker to edit those paths from my editor than from the terminal\nprompt.\n\nIf I've opened my editor (Vim) with `fc` and I decide I don't want to execute\nthe command after all, I can _compiler quit_ Vim (exit with an error code)\nusing `:cq`. The command will not be executed in this case.\n\nSee `man zshbuiltins` for more details about this command and all of its flags.\n\n[source](https://www.computerhope.com/unix/uhistory.htm)\n"
  },
  {
    "path": "unix/fix-shim-path-after-asdf-upgrade.md",
    "content": "# Fix Shim Path After asdf Upgrade\n\nWhile doing [`brew install groff`](aws/aws-cli-requires-groff-executable.md),\nHomebrew decided to upgrade every last thing it knows about on my machine,\nincluding `asdf`.\n\n`asdf` has undergone some big recent changes, including [a rewrite in\nGo](https://stratus3d.com/blog/2025/02/03/asdf-has-been-rewritten-in-go/).\n\nI noticed that `asdf` wasn't picking up my specified tool versions. I tried an\n`asdf reshim`, but that didn't do the trick. Someone else wrote that [asdf\nseems broken after homebrew\nupgrade](https://braytonium.com/2023/01/09/asdf-seems-broken-after-homebrew-upgrade/)\nwhich gave some hints and pointed me to some interesting GitHub issues.\n\nAdditionally, I noticed when opening a fresh terminal session the following error from `zsh`:\n\n```bash\n/Users/jbranchaud/.zshrc:.:225: no such file or directory: /usr/local/opt/asdf/libexec/asdf.sh\n```\n\nThat directory and file is gone. So, how does `asdf` now want you to configure\nits path with `zsh`? Revisiting their updated docs, I can see that the instead\nof sourcing that shell script, we should now export shims to the path:\n\n```bash\n# . /usr/local/opt/asdf/libexec/asdf.sh\nexport PATH=\"${ASDF_DATA_DIR:-$HOME/.asdf}/shims:$PATH\"\n```\n\nUpdating my `.zshrc` to the above and then reloading did the trick. My tool\nversions are registering now.\n\n[source](https://asdf-vm.com/guide/getting-started.html#_2-configure-asdf)\n"
  },
  {
    "path": "unix/fix-unlinked-node-binaries-with-asdf.md",
    "content": "# Fix Unlinked Node Binaries With asdf\n\nYou're using `asdf` to manage your version(s) of `node.js`. You have some\npackages globally installed with `yarn` that are available as executable\nbinaries. When you install and switch to a new version of Node, those global\nbinaries no longer work.\n\nEven uninstalling and re-installing those particular packages doesn't\nnecesarily fix it. That's because broken symlinks have been left behind.\n\n`asdf` can help fix this with its `reshim` command:\n\n```bash\n$ asdf reshim <name> <version>\n```\n\nFor instance, if you want to start using `14.4.0`, you can reshim like this:\n\n```bash\n$ asdf reshim nodejs 14.4.0\n```\n\nThis will re-sync all the symlinks so that you are able to access and run those\nbinaries again.\n"
  },
  {
    "path": "unix/format-and-display-small-amounts-of-columnar-data.md",
    "content": "# Format And Display Small Amounts Of Columnar Data\n\nIn [_List Processes Running Across All (tmux)\nSessions](tmux/list-processes-running-across-all-sessions.md), I showed an\nexample of piping some data from `tmux` to the `column -t` command to nicely format\nand display the columnar data as a table. By default is uses spaces as the\ndelimiter.\n\n```bash\n❯ tmux list-panes -a -F \"#{session_name}:#{window_index}.#{pane_index} #{pane_pid} #{pane_current_command}\" \\\n  | column -t\n\nPLP:1.1             62364  zsh\nTIL:1.1             62345  nvim\nTIL:1.2             65838  task\nTIL:2.1             11428  tmux\nclient-app:1.1      62373  ssh\nclient-app:1.2      10796  zsh\nclient-app:1.3      63081  zsh\nclient-app:2.1      61115  overmind\nclient-app:3.1      82608  zsh\nvisualmode-dev:1.1  52237  zsh\n```\n\nThis can be useful for formatting data from all kinds of commands and tools.\nSometimes the columns of data are separated by something other than spaces. For\ninstance, here is some git branch information (for my [dotfiles\nrepo](https://github.com/jbranchaud/dotfiles)) separated by the `|` character.\nTo format that with `column`, I need to also include the `-s '|'` flag to\noverride the delimiter.\n\n```bash\n❯ git for-each-ref --format='%(refname:short)|%(authordate:short)|%(authorname)' refs/heads/ \\\n  | column -t -s '|'\n\nclaude/sync-dotfiles-011CUP87cRV6c51eEi3Chg99  2025-10-22  jbranchaud\njb/add-rhubarb-for-fugitive-github-browse      2025-11-02  jbranchaud\njb/fix-hardcoded-paths                         2025-11-02  jbranchaud\njb/set-nvim-to-default-manpager                2025-10-19  jbranchaud\nmain                                           2026-01-10  jbranchaud\nmaster                                         2025-10-30  Dorian Karter\nmy-dotfiles                                    2025-11-01  jbranchaud\nupstream-master                                2026-01-01  Dorian Karter\n```\n"
  },
  {
    "path": "unix/forward-multiple-ports-over-ssh.md",
    "content": "# Forward Multiple Ports Over SSH\n\nI sometimes find myself doing web app development on another machine via an SSH\nconnection. If I have the server running on port 3000, then I like to use\nSSH's port forwarding feature so that I can access `localhost:3000` on my\nphysical machine.\n\n```bash\n$ ssh dev@server.com -L 3000:localhost:3000\n```\n\nWhat if I have two different servers running? I'd like to port forward both\nof them -- that way I can access both.\n\nSSH allows you to forward as many ports as you need. The trick is to specify\na `-L` for each.\n\n```bash\n$ ssh dev@server.com -L 3000:localhost:3000 -L 9009:localhost:9009\n```\n"
  },
  {
    "path": "unix/generate-a-saml-key-and-certificate-pair.md",
    "content": "# Generate A SAML Key And Certificate Pair\n\nThe `openssl` utility can be used to generate a SAML (Security Assertion Markup\nLanguage) key pair which consists of a public certificate and a private key.\n\n```bash\nopenssl req -new -x509 -days 365 -nodes -sha256 \\\n  -out saml.crt \\\n  -keyout saml.key\n```\n\n> The req command primarily creates and processes certificate requests in\n> PKCS#10 format. It can additionally create self-signed certificates, for use\n> as root CAs, for example.\n\nThe flags to `req` are as follows:\n- `-new` for a new certificate (cert) request\n- `-x509` to output a self-signed cert instead of a cert request\n- `-days 365` for a year-long cert\n- `-nodes` to not encrypt the private key\n- `-sha256` is the digest algorithm for signing the cert\n- `-out saml.crt` specifies the certificate output file\n- `-keyout saml.key` specifies the private key output file\n\nSee `man openssl` and search for `openssl req` for more details.\n\n[source](https://www.lightsaml.com/LightSAML-Core/Cookbook/How-to-generate-key-pair/)\n"
  },
  {
    "path": "unix/generate-a-sequence-of-numbered-items.md",
    "content": "# Generate A Sequence Of Numbered Items\n\nThe `seq` command will output the specified sequence of numbers.\n\n```bash\n❯ seq 1 5\n1\n2\n3\n4\n5\n```\n\nWith the `-f` (`--format`) flag we can interpolate those numbers as part of a\nstring.\n\n```bash\n❯ seq -f \"day_%02g\" 1 5\nday_01\nday_02\nday_03\nday_04\nday_05\n```\n\nThe `%g` indicates that there is a format specifier for a numeric type which is\nwhere `seq` will inject the current value in the sequence. The `02` indicates\nthat it should be `0` padded to `2` digits.\n\nWe can then pipe this to another unix command, such as `mkdir` in order to\nquickly create a bunch of directories for, say, [Advent of Code](https://adventofcode.com/2024).\n\n```bash\n❯ mkdir aoc_2024\n❯ cd aoc_2024\n❯ seq -f \"day_%02g\" 1 25 | xargs mkdir\n```\n\nSee `man seq` for more details.\n"
  },
  {
    "path": "unix/generate-base64-encoding-without-newlines.md",
    "content": "# Generate Base64 Encoding Without Newlines\n\nThere are a variety of tools that can generate a Base64 encoding of given text.\nMost of them that I've encountered have a number of characters at which they\nintroduce a newline character. Here is `openssl` as an example:\n\n```bash\n❯ echo \"here is a long bit of text to base64 encode with openssl\" | openssl base64\naGVyZSBpcyBhIGxvbmcgYml0IG9mIHRleHQgdG8gYmFzZTY0IGVuY29kZSB3aXRo\nIG9wZW5zc2wK\n```\n\n[The theory I've seen](https://superuser.com/a/1225139) is that this is to\naccommodate 80-character terminal screens when chunks of encoding were included\nin emails.\n\nWith the `openssl base64` command, there is not an option to exclude the\nnewlines, but we can pipe it through `tr` to remove them.\n\n```bash\n❯ echo \"here is a long bit of text to base64 encode with openssl\" | \\\n  openssl base64 | \\\n  tr -d '\\n'\naGVyZSBpcyBhIGxvbmcgYml0IG9mIHRleHQgdG8gYmFzZTY0IGVuY29kZSB3aXRoIG9wZW5zc2wK\n```\n"
  },
  {
    "path": "unix/generate-random-20-character-hex-string.md",
    "content": "# Generate Random 20-Character Hex String\n\nThe `openssl` utility has a bunch of subcommands including `rand`. The `rand`\nsubcommand can be used to generate pseudo-random numbers.\n\n```bash\nopenssl rand -hex 10\n5ce459896581abc81a65\n```\n\nThe number at the end of the command tells `rand` how many bytes of output to\ngenerate. When the `-hex` flag is used, it will encode the output in hex.\n\nThe 10 bytes of output in hex will result in a 20-character string. That number\ncan be adjusted to your needs.\n\nSee `man openssl` or `openssl rand -help` for more details.\n"
  },
  {
    "path": "unix/get-a-list-of-locales-on-your-system.md",
    "content": "# Get A List Of Locales On Your System\n\nThe `locale -a` command will list all the available locales on your system.\n\nYou'll see a giant list that probably includes these and many more values.\n\n```bash\n$ locale -a\n\nen_NZ\nnl_NL.UTF-8\npt_BR.UTF-8\nfr_CH.ISO8859-15\neu_ES.ISO8859-15\nen_US.US-ASCII\naf_ZA\nbg_BG\ncs_CZ.UTF-8\nfi_FI\nzh_CN.UTF-8\neu_ES\nsk_SK.ISO8859-2\nnl_BE\nfr_BE\nsk_SK\nen_US.UTF-8\n...\n```\n\nEach of these locales identifies itself by the language and the manner in which\nthe language is used in a particular place. For example, `en_NZ` is _English as\nit is spoken in New Zealand_. `fr_BE` is _French as it is spoken in Belgium_.\n`en_US.UTF-8` is _English as it is spoken in the US, with a UTF-8 character set\nencoding_.\n\n[source](https://www.postgresql.org/docs/current/locale.html#LOCALE-OVERVIEW)\n"
  },
  {
    "path": "unix/get-matching-filenames-as-output-from-grep.md",
    "content": "# Get Matching Filenames As Output From Grep\n\nStandard use of the [`grep`\ncommand](http://man7.org/linux/man-pages/man1/grep.1.html) outputs the lines\nthat match the specified pattern. You can instead output just the names of\nthe files where those matches occur. To do this, include the `-l` flag.\n\n```bash\n$ grep -Rl hashrocket .\n./elixir/run-exunit-tests-in-a-deterministic-order.md\n./git/show-file-diffs-when-viewing-git-log.md\n./git/single-key-presses-in-interactive-mode.md\n./internet/enable-keyboard-shortcuts-in-gmail.md\n...\n```\n\nThis recursive grep finds all the files where `hashrocket` appears. It only\nlooks for the first match in a file, so each file will only be listed once\neven if there may have been multiple matches.\n\nSee `man grep` for more details.\n"
  },
  {
    "path": "unix/get-the-sha256-hash-for-a-file.md",
    "content": "# Get The SHA256 Hash For A File\n\nUnix systems come with a `sha256sum` utility that we can use to compute the\nSHA256 hash of a file. This means the contents of file are compressed into a\n256-bit digest.\n\nHere I use it on a SQL migration file that I've generated.\n\n```bash\n$ sha256sum migrations/0001_large_doctor_spectrum.sql\nb75e61451e2ce37d831608b1bc9231bf3af09e0ab54bf169be117de9d4ff6805  migrations/0001_large_doctor_spectrum.sql\n```\n\nEach file passed to this utility gets output to a separate line which is why we\nsee the filename next to the hash. Since I am only running it on a single file\nand I may want to pipe the output to some other program, I can clip off just\nthe part I need.\n\n```bash\nsha256sum migrations/0001_large_doctor_spectrum.sql | cut -d ' ' -f 1\nb75e61451e2ce37d831608b1bc9231bf3af09e0ab54bf169be117de9d4ff6805\n```\n\nWe can also produce these digests with `openssl`:\n\n```bash\n$ openssl dgst -sha256 migrations/0001_large_doctor_spectrum.sql\nSHA2-256(migrations/0001_large_doctor_spectrum.sql)= b75e61451e2ce37d831608b1bc9231bf3af09e0ab54bf169be117de9d4ff6805\n\n$ openssl dgst -sha256 migrations/0001_large_doctor_spectrum.sql | cut -d ' ' -f 2\nb75e61451e2ce37d831608b1bc9231bf3af09e0ab54bf169be117de9d4ff6805\n```\n\nSee `sha256sum --help` or `openssl dgst --help` for more details.\n"
  },
  {
    "path": "unix/get-the-unix-timestamp.md",
    "content": "# Get The Unix Timestamp\n\nTo get the Unix timestamp from your shell, use the `time` command with the\nappropriate format:\n\n```bash\n$ date +%s\n```\n\n[source](http://stackoverflow.com/questions/1092631/get-current-time-in-seconds-since-the-epoch-on-linux-bash)\n"
  },
  {
    "path": "unix/get-word-count-for-all-files-in-git-repo.md",
    "content": "# Get Word Count For All Files In Git Repo\n\nAs part of gathering numbers for [A Decade of TILs](), I wanted to get an word\ncount of all the TIL markdown files I've committed to this project over its 10\nyear history. By using `git ls-files` with a pattern, I can get a list of all\nfile names. Then with `xargs` I can pass that entire list to `wc -w` which\ngives a word count of each. The final line that `wc -w` outputs is a sum total\nof all the file word counts. Lastly, piping that through `tail -n1` gives me\njust that last total count line.\n\n```bash\n$ git ls-files \"*/**.md\" | xargs wc -w | tail -n1\n  206816 total\n```\n\nSince the `tail -n1` obfuscates what the `wc -w` is doing, here is what that\nlooks like before that final pipe.\n\n```bash\n$ git ls-files \"*/**.md\" | tail -n3 | xargs wc -w\n     115 zsh/add-to-the-path-via-path-array.md\n     190 zsh/link-a-scalar-to-an-array.md\n     214 zsh/use-a-space-to-exclude-command-from-history.md\n     519 total\n```\n\nI can even clean up the final output a bit more with `awk`:\n\n```bash\n$ git ls-files \"*/**.md\" | xargs wc -w | tail -n1 | awk '{print $1}'\n206816\n```\n"
  },
  {
    "path": "unix/global-substitution-on-the-previous-command.md",
    "content": "# Global Substitution On The Previous Command\n\nLet's say we just executed the following command:\n\n```bash\n$ grep 'foo' foo.md\n```\n\nIt gave us the information we were looking for and now we want to execute\na similar command to find the occurrences of `bar` in `bar.md`. The `^`\ntrick won't quite work here.\n\n```bash\n$ ^foo^bar<tab>\n$ grep 'bar' foo.md\n```\n\nWhat we need is a global replace of `foo` in our previous command. The `!!`\ncommand can help when we sprinkle in some `sed`-like syntax.\n\n```bash\n$ !!gs/foo/bar<tab>\n$ grep 'bar' bar.md\n```\n\nFor a short command like this, we haven't gained much. However, for large\ncommands that span the length of the terminal, this can definitely save us\na little trouble.\n"
  },
  {
    "path": "unix/globbing-for-all-directories-in-zsh.md",
    "content": "# Globbing For All Directories In Zsh\n\nGlobbing in Zsh is an expressive way to generate filenames for commands.\nThis includes working with directories. If I'd like to run a command against\nall directories in the current directory, I can employ the `*(/)` globbing\npattern.\n\n```bash\n$ echo *(/)\none three two\n```\n\nWhat about all directories in the root directory?\n\n```bash\n$ echo /*(/)\n/Applications /Library /Network /System /Users /Volumes /bin /cores /dev /home /net /opt /private /sbin /usr\n```\n\nYou can go ahead and use that with any other command now (e.g. `ls`).\n\n[source](http://zsh.sourceforge.net/Intro/intro_2.html)\n"
  },
  {
    "path": "unix/globbing-for-filenames-in-zsh.md",
    "content": "# Globbing For Filenames In Zsh\n\nZsh has extensive support for _globbing_ for filenames. _Globbing_ is a\nshort-hand, of sorts, for generating filenames that meet certain criteria.\nThe generated filenames can be used with any command you might otherwise\nprovide a filename to in a unix setting.\n\nFor example, consider a directory full of files including many that are\nnamed with numbers. You'd like to list all files that have numeric names.\n\nDoing `ls` by itself gives the following result:\n\n```bash\n$ ls\n10        11        2         3         4         801       92        code.rb   hello.txt\n```\n\nWith the use of a numeric pattern, Zsh's _globbing_ helps `ls` limit the set\nof listed files to just those with numeric names:\n\n```bash\n$ ls *[0-9]\n10  11  2   3   4   801 92\n```\n\nThis only scrapes the surface of what can be done with globbing in Zsh.\n\n[source](http://zsh.sourceforge.net/Intro/intro_2.html)\n\nh/t Josh Davey\n"
  },
  {
    "path": "unix/gracefully-exit-a-script-with-trap.md",
    "content": "# Gracefully Exit A Script With Trap\n\nWith `trap` you can intercept signals that would cause your script to exit and\nthen inject some additional behavior. Perhaps you want to make sure the script\ncleans up after itself before it exists.\n\nDuring this script's execution, it creates a file in the filesystem. It would\nbe nice to make sure that no matter path this script ends up down that it will\nclean up after itself as it exits. We set up a `trap` that looks for the `EXIT`\nsignal to do this.\n\n```bash\n# Set up trap\ntrap 'echo \"Cleaning up temp files\"; rm -f *.tmp' EXIT\n\n# Create temporary file\necho \"test data\" > work.tmp\n\n# Do some work\ncat work.tmp\n\n# Trap will clean up on exit\n```\n\nWhatever is in quotes is what the trap will execute when it is triggered. The\nfollowing one or more signals are what the trap listens for, in this case\n`EXIT`.\n\n[source](https://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html)\n"
  },
  {
    "path": "unix/grep-for-files-with-multiple-matches.md",
    "content": "# Grep For Files With Multiple Matches\n\nThe `grep` utility is a great way to find files that contain a certain\npattern:\n\n```bash\n$ grep -r \".class-name\" src/css/\n```\n\nThis will recursively look through all the files in your css directory to\nfind matches of `.class-name`.\n\nOften times these kinds of searches can turn up too many results and you'll\nwant to pare it back by providing some additional context.\n\nFor instance, we may only want results where `@media only screen` also\nappears, but on a different line. To do this, we need to chain a series of\n`greps` together.\n\n```bash\n$ grep -rl \"@media only screen\" src/css |\n    xargs grep -l \".class-name\"\n```\n\nThis will produce a list of filenames (hence the `-l` flag) that contain\nboth a line with `@media only screen` and a line with `.class-name`.\n\nIf you need to, chain more `grep` commands on to narrow things down even\nfarther.\n\nSee `man grep` for more details.\n"
  },
  {
    "path": "unix/grep-for-files-without-a-match.md",
    "content": "# Grep For Files Without A Match\n\nThe `grep` command is generally used to find files whose contents match a\npattern. With the `-L` (`--files-without-match`) flag, `grep` can be used to\nfind files that don't match the given pattern.\n\nFor instance, to find files in the current directory that don't have\n`foobar` anywhere in their content, run:\n\n```bash\n$ grep -L \"foobar\" ./*\n```\n\n[source](http://stackoverflow.com/questions/1748129/using-grep-to-find-files-that-dont-contain-a-given-string-pattern)\n"
  },
  {
    "path": "unix/grep-for-multiple-patterns.md",
    "content": "# Grep For Multiple Patterns\n\nYou can use the `-e` flag with the `grep` command to search for a pattern.\nAdditionally, you can use multiple `-e` flags to search for multiple\npatterns. For instance, if you want to search for occurrences of `ruby` and\n`clojure` in a `README.md` file, use the following command:\n\n```\n$ grep -e ruby -e clojure README.md\n```\n\nSee `man grep` for more details.\n"
  },
  {
    "path": "unix/have-script-shellcheck-itself-when-executing.md",
    "content": "# Have Script ShellCheck Itself When Executing\n\nThe [ShellCheck](https://www.shellcheck.net/) utility can be run against bash\nscripts to check if there are any warnings or errors we should fix. It works\ngreat as long as we remember to run it.\n\nI wondered if I could make it easier on myself by not having to remember to run\nit. What if my bash script were to `shellcheck` itself?\n\nHere is an example script where at the beginning it looks for and runs the\n`shellcheck` utility against `$0` (the path of the script). This is kind of\nmeta. As the script is executing, it has an external program run against the\nentire contents of itself. If there are any `shellcheck` issues, they get\ndisplayed and the program exits early.\n\n```bash\n#!/bin/bash\n\n# Exit immediately if any command fails\nset -e\n\n# Self-validation using ShellCheck\nif command -v shellcheck &> /dev/null; then\n    echo \"Validating script with ShellCheck...\"\n\n    # $0 refers to the script itself\n    if ! shellcheck \"$0\"; then\n        echo \"ShellCheck found issues in the script. Exiting.\"\n        exit 1\n    fi\n    echo \"Script validation passed.\"\nelse\n    echo \"Warning: ShellCheck not found. Skipping validation.\"\nfi\n\necho \"Script execution continuing...\"\n\n# shellcheck warning here\nread -p \"Continue with current operation? (yes/no): \" CONTINUE_WITH_EXISTING\nif [[ ! \"$CONTINUE_WITH_EXISTING\" =~ ^[Yy][Ee][Ss]$ ]]; then\n    echo \"Operation cancelled.\"\n    exit 1\nfi\n```\n\nThis last bit of the script with the `read` command will trigger a warning from\n`shellcheck`.\n\n```bash\n$ ./check.sh\nValidating script with ShellCheck...\n\nIn ./check.sh line 23:\nread -p \"Continue with current operation? (yes/no): \" CONTINUE_WITH_EXISTING\n^--^ SC2162 (info): read without -r will mangle backslashes.\n\nFor more information:\n  https://www.shellcheck.net/wiki/SC2162 -- read without -r will mangle backs...\nShellCheck found issues in the script. Exiting.\n```\n"
  },
  {
    "path": "unix/hexdump-a-compiled-file.md",
    "content": "# Hexdump A Compiled File\n\nThe `hexdump` unix utility allows you to dump the contents of a\ncompiled/executable file in a _readable_ hexadecimal format. Adding the `-C`\nflag includes a sidebar with a formatted version of that row of hexadecimal.\n\nFor example, a compiled _Hello World_ java program, `Hello.java`, will look\nsomething like this:\n\n```\n> cat Hello.class | hexdump -C\n00000000  ca fe ba be 00 00 00 34  00 1d 0a 00 06 00 0f 09  |.......4........|\n00000010  00 10 00 11 08 00 12 0a  00 13 00 14 07 00 15 07  |................|\n00000020  00 16 01 00 06 3c 69 6e  69 74 3e 01 00 03 28 29  |.....<init>...()|\n00000030  56 01 00 04 43 6f 64 65  01 00 0f 4c 69 6e 65 4e  |V...Code...LineN|\n00000040  75 6d 62 65 72 54 61 62  6c 65 01 00 04 6d 61 69  |umberTable...mai|\n00000050  6e 01 00 16 28 5b 4c 6a  61 76 61 2f 6c 61 6e 67  |n...([Ljava/lang|\n00000060  2f 53 74 72 69 6e 67 3b  29 56 01 00 0a 53 6f 75  |/String;)V...Sou|\n00000070  72 63 65 46 69 6c 65 01  00 0a 48 65 6c 6c 6f 2e  |rceFile...Hello.|\n00000080  6a 61 76 61 0c 00 07 00  08 07 00 17 0c 00 18 00  |java............|\n00000090  19 01 00 0d 48 65 6c 6c  6f 2c 20 57 6f 72 6c 64  |....Hello, World|\n000000a0  21 07 00 1a 0c 00 1b 00  1c 01 00 05 48 65 6c 6c  |!...........Hell|\n000000b0  6f 01 00 10 6a 61 76 61  2f 6c 61 6e 67 2f 4f 62  |o...java/lang/Ob|\n000000c0  6a 65 63 74 01 00 10 6a  61 76 61 2f 6c 61 6e 67  |ject...java/lang|\n000000d0  2f 53 79 73 74 65 6d 01  00 03 6f 75 74 01 00 15  |/System...out...|\n000000e0  4c 6a 61 76 61 2f 69 6f  2f 50 72 69 6e 74 53 74  |Ljava/io/PrintSt|\n000000f0  72 65 61 6d 3b 01 00 13  6a 61 76 61 2f 69 6f 2f  |ream;...java/io/|\n00000100  50 72 69 6e 74 53 74 72  65 61 6d 01 00 07 70 72  |PrintStream...pr|\n00000110  69 6e 74 6c 6e 01 00 15  28 4c 6a 61 76 61 2f 6c  |intln...(Ljava/l|\n00000120  61 6e 67 2f 53 74 72 69  6e 67 3b 29 56 00 20 00  |ang/String;)V. .|\n00000130  05 00 06 00 00 00 00 00  02 00 00 00 07 00 08 00  |................|\n00000140  01 00 09 00 00 00 1d 00  01 00 01 00 00 00 05 2a  |...............*|\n00000150  b7 00 01 b1 00 00 00 01  00 0a 00 00 00 06 00 01  |................|\n00000160  00 00 00 01 00 09 00 0b  00 0c 00 01 00 09 00 00  |................|\n00000170  00 25 00 02 00 01 00 00  00 09 b2 00 02 12 03 b6  |.%..............|\n00000180  00 04 b1 00 00 00 01 00  0a 00 00 00 0a 00 02 00  |................|\n00000190  00 00 03 00 08 00 04 00  01 00 0d 00 00 00 02 00  |................|\n000001a0  0e                                                |.|\n000001a1\n```\n"
  },
  {
    "path": "unix/ignore-a-directory-during-ripgrep-search.md",
    "content": "# Ignore A Directory During ripgrep Search\n\nWhen searching for patterns in project with many directories and files using\n`ripgrep`, it is easy to end up with an overwhelming amount of results. If you\nknow that a certain directory of results isn't of interest, you can exclude\nthat directory. This is done with the glob flag (`-g`) and the inverse (`!`)\noperator.\n\nHere is an example of just using the `-g` flag. This will find all matches of\nthe pattern within that directory.\n\n```bash\n$ rg 'some pattern' -g 'dir/'\n```\n\nTo instead exclude that directory and by extension search everywhere else, we\ncan invert the glob match with `!`.\n\n```bash\n$ rg 'some pattern' -g '!dir/'\n```\n\nThis says, find the pattern anywhere that is not in `dir/`.\n\n[source](https://blog.wxm.be/2020/11/08/ignore-folder-in-ripgrep.html)\n"
  },
  {
    "path": "unix/ignore-the-alias-when-running-a-command.md",
    "content": "# Ignore The Alias When Running A Command\n\nI have a number of shell aliases set up to override one command with another.\nFor instance, I want to run `bat` anytime I type `cat`, so I have `alias\ncat=bat` in my shell configuration.\n\nBut what if I were to ever want to run `cat` instead of `bat`?\n\nAliases can be ignored several ways:\n\n1. Precede the command with a backslash.\n\n```bash\n$ \\cat\n```\n\n2. Wrap the command in quotes.\n\n```bash\n$ 'cat'\n```\n\n3. Pass the command to `command`.\n\n```bash\n$ command cat\n```\n\n[source](https://unix.stackexchange.com/questions/39291/run-a-command-that-is-shadowed-by-an-alias)\n"
  },
  {
    "path": "unix/include-ignore-files-in-ripgrep-search.md",
    "content": "# Include Ignore Files In Ripgrep Search\n\nBy default, [ripgrep (`rg`)](https://github.com/BurntSushi/ripgrep) will look\nfor and respect _ignore_ files like `.gitignore`. Any file and directory marked\nby those ignore files will no be included in an `rg` search.\n\nThis is usually what you want. Sometimes, however, it can be useful to get\nresults from this ignored files as well.\n\nIn order to ignore your ignore files, pass the `--no-ignore` flag to `rg`:\n\n```bash\n$ rg --no-ignore ENV_VAR_KEY\n```\n\nSomething to keep in mind is that `rg` also ignores _hidden_ files and\ndirectories (those things that are prefixed with a `.`, such as `.env` or\n`.config/`). If some of your ignored files are also _hidden_ files, then they\nstill won't show up in search. You'll need the `--hidden` flag as well.\n\n```bash\n$ rg --no-ignore --hidden ENV_VAR_KEY\n```\n\nA shorthand equivalent for that is `-uu`:\n\n```bash\n$ rg -uu ENV_VAR_KEY\n```\n\nSee `man rg` for more details.\n"
  },
  {
    "path": "unix/inspect-exif-data-for-an-image-file.md",
    "content": "# Inspect EXIF Data For An Image File\n\nThe `exiftool` CLI (which can be downloaded via `brew`) is a useful tool for\ninspecting all the EXIF data attached to a media file. A media file like an\nimage has a bunch of additional details embedded in it like timestamps, image\nmetadata, and sometimes location information.\n\nHere is all the data attached to a screenshot I found on my desktop:\n\n```bash\n❯ exiftool ~/Desktop/CleanShot\\ 2025-11-17\\ at\\ 11.22.18@2x.png\nExifTool Version Number         : 13.50\nFile Name                       : CleanShot 2025-11-17 at 11.22.18@2x.png\nDirectory                       : /Users/lastword/Desktop\nFile Size                       : 1194 kB\nFile Modification Date/Time     : 2025:11:17 11:22:21-06:00\nFile Access Date/Time           : 2025:12:15 10:43:55-06:00\nFile Inode Change Date/Time     : 2025:12:05 15:37:48-06:00\nFile Permissions                : -rw-r--r--\nFile Type                       : PNG\nFile Type Extension             : png\nMIME Type                       : image/png\nImage Width                     : 2502\nImage Height                    : 1232\nBit Depth                       : 8\nColor Type                      : RGB with Alpha\nCompression                     : Deflate/Inflate\nFilter                          : Adaptive\nInterlace                       : Noninterlaced\nXMP Toolkit                     : XMP Core 6.0.0\nY Resolution                    : 144\nResolution Unit                 : inches\nX Resolution                    : 144\nExif Image Width                : 2502\nColor Space                     : sRGB\nUser Comment                    : Screenshot\nExif Image Height               : 1232\nSRGB Rendering                  : Perceptual\nImage Size                      : 2502x1232\nMegapixels                      : 3.1\n```\n\nThis works with other kinds of media files. For instance, I ran this against an\nMP4 screen recording file which contained even more metadata.\n\nIn addition to reading data, `exiftool` can also write it. See `man exiftool`\nfor more details on what else it can do.\n"
  },
  {
    "path": "unix/interactively-browse-availabile-node-versions.md",
    "content": "# Interactively Browse Available Node Versions\n\nThere are a variety of ways to install and manage your version(s) of Node. My\ntool of choice is [`asdf`](https://github.com/asdf-vm/asdf).\n\nOnce I have the [Node.js asdf plugin](https://github.com/asdf-vm/asdf-nodejs)\ninstalled, I can view the versions of Node that are available to install.\n\n```bash\n$ asdf list-all nodejs\n```\n\nThis is a massive list. Normally my next step would be to `grep` against the\noutput. We can take it a step further by making the results interactively\nbrowsable with [`FZF`](https://github.com/junegunn/fzf).\n\n```bash\n$ asdf list-all nodejs | fzf\n```\n\nI can type into the FZF prompt which will fuzzily narrow down the results. I\ncan even add a splash of regex to anchor agains the major version.\n\nFor instance, `10` will show `10.x.x` as well as pre-1.0 results that contain\n`10`. If, however, I prompt FZF with `^10`, then the `10` is anchored to the\nfront of the string which is the major version -- so `10.x.x` results.\n"
  },
  {
    "path": "unix/interactively-switch-asdf-package-versions.md",
    "content": "# Interactively Switch asdf Package Versions\n\nI use [`asdf`](https://asdf-vm.com/) to manage versions for a couple different\nlanguages that I use across projects. I mostly use it for `node` and `ruby`.\n\nWhen setting up a new project or needing to set the version for an existing\none, I run some version of:\n\n```bash\n$ asdf local nodejs <some-version-here>\n```\n\nBut before I can do that, I need to figure out what versions I have installed\n(`asdf list nodejs`), so I end up running two commands and having to remember\nthe nuances of the sub-commands for each.\n\nI decided to make this small interaction easier by making it _interactive_ with\n[`fzf`](https://github.com/junegunn/fzf).\n\n```bash\nasdf local nodejs $(\n  asdf list nodejs | fzf | xargs | sed 's/^\\*//'\n)\n```\n\nThis grabs the list of installed `nodejs` versions, turns it into an\ninteractive list with `fzf`, and then passes my selection to `asdf local` to\nset that version.\n\nI can substitute `ruby` for `nodejs` to do the same thing for Ruby versions.\n"
  },
  {
    "path": "unix/interpret-cron-schedule-from-the-cli.md",
    "content": "# Interpret Cron Schedule From The CLI\n\nI encounter cron task schedules infrequently enough that I don't remember how\nto reliably interpret them at a glance. So when I'm looking over some code and\nI see something like `12 2,16 * * *`, I need to translate it to a\nhuman-readable format.\n\nI've typically opened up a browser tab to\n[crontab.guru](https://crontab.guru/#12_2,16_*_*_*) for this. However, I did\njust learn about a tool for getting the same information from the CLI.\n\nWith the [`hcron`](https://github.com/lnquy/cron) binary, I can pass in a\nsingle cron schedule and get the same details right from my terminal.\n\n```bash\n$ hcron '12 2,16 * * *'\n12 2,16 * * *: At 02:12 AM and 04:12 PM\n```\n\nI decided to clone this repo, build the binary from source (it is Go), and then\nplace the `hcron` binary in my `~/bin` directory which is on my path. Once I\ndid that, I could start using the command like above.\n"
  },
  {
    "path": "unix/jump-to-the-ends-of-your-shell-history.md",
    "content": "# Jump To The Ends Of Your Shell History\n\nThere are all sorts of ways to do things in your shell environment without\nreaching for the arrow keys. For instance, if you want to move _up_ to the\nprevious command, you can hit `Ctrl-p`. To move _down_ to the next\ncommand in your shell history, you can hit `Ctrl-n`.\n\nBut what if you want to move to the beginning and end of your entire shell\nhistory?\n\nFind your meta key (probably the one labeled `alt`) and hit `META-<` and\n`META->` to move to the end and beginning of your shell history,\nrespectively.\n\n[source](https://www.gnu.org/software/bash/manual/html_node/Commands-For-History.html)\n"
  },
  {
    "path": "unix/kill-everything-running-on-a-certain-port.md",
    "content": "# Kill Everything Running On A Certain Port\n\nYou can quickly kill everything running on a certain port with the following\ncommand.\n\n```bash\nsudo kill `sudo lsof -t -i:3000`\n```\n\nThis gets a list of pids for all the processes and then kills them.\n\n[source](http://stackoverflow.com/questions/9346211/how-to-kill-a-process-on-a-port-on-ubuntu)\n"
  },
  {
    "path": "unix/killing-a-frozen-ssh-session.md",
    "content": "# Killing A Frozen SSH Session\n\nWhenever an SSH session freezes, I usually mash the keyboard in desperation\nand then kill the terminal session. This can be avoided though. SSH will\nlisten for the following kill command:\n\n```\n~.<cr>\n```\n\nThis will kill the frozen SSH session and leave you in the terminal where\nyou were before you SSH'd.\n\nh/t [Jack C.](http://hashrocket.com/team/jack-christensen)\n\nMore details on this and other SSH secret commands are in [this\nthread](https://x.com/freebsdfrau/status/1748451200448823475).\n"
  },
  {
    "path": "unix/last-argument-of-the-last-command.md",
    "content": "# Last Argument Of The Last Command\n\nYou can use `!$` as a way to reference the last argument in the last\ncommand. This makes for an easy shortcut when you want to switch out\ncommands for the same long file name. For instance, if you just ran `cat` on\na file to see its contents\n\n```bash\n$ cat /Users/jbranchaud/.ssh/config\n```\n\nand now you want to edit that file. You can just pass `!$` to the `vim`\ncommand:\n\n```bash\n$ vim !$\n```\n\nHit enter or tab to get the full command:\n\n```bash\n$ vim /Users/jbranchaud/.ssh/config\n```\n\nh/t Dorian Karter\n"
  },
  {
    "path": "unix/less-with-style.md",
    "content": "# Less With Style\n\nI was using `less` the other day to look at a log file. The log file was\nfilled with ANSI color escape sequences which made it pretty painful to\nread. I was stuck looking at a white, unparsed log file instead of a\ncolorful, stylish one.\n\nThe `-R` flag fixes this. It tells `less` to display the ANSI color escape\nsequences as colors rather than the caret notation.\n\nThe tradeoff is that `less` has _less_ control over the overall display of\nthe screen. This may result in some buggy display behavior, but not\nnecessarily.\n\n[source](http://superuser.com/questions/117841/get-colors-in-less-command)\n"
  },
  {
    "path": "unix/limit-protocols-used-in-a-curl-command.md",
    "content": "# Limit Protocols Used In A cURL Command\n\nI was about to install [`atuin`](https://github.com/atuinsh/atuin). I went to\ntheir _Quick Start_ section to grab whatever command I would need to install\nit. It was a `curl` statement piped to `sh`. The thing that caught my attention\nthough was I `curl` flag that I didn't recognize — `--proto`.\n\n> Tells curl to limit what protocols it may use for transfers.\n\nUsing `curl --proto '=https' ...` we can enforce that only an `https` URL can\nbe used in this command.\n\nHere is what happens if I try to run the `atuin`-provided `curl` command after\nI have downgraded their URL to be `http`:\n\n```bash\ncurl --proto '=https' --tlsv1.2 -LsSf http://setup.atuin.sh | sh\ncurl: (1) Protocol \"http\" not supported or disabled in libcurl\n```\n\nIt doesn't even attempt the request. The protocol is considered unsupported and\nthe command immediately fails.\n\nIn addition to only installing software we trust, we should make sure we are\nonly doing so over a protocol we trust (namely, `https`).\n\nSee `man curl` for more details, including about the modifiers (`=`, `+`, `-`).\n"
  },
  {
    "path": "unix/list-all-fonts-on-your-machine.md",
    "content": "# List All Fonts On Your Machine\n\nIn trying to figure out what _FiraCode_ font I have installed on my machine\nand what it is called, I came across [this StackOverflow\nanswer](https://stackoverflow.com/a/52789662/535590) which shares the\nfollowing one-liner:\n\n```bash\n$ fc-list | awk '{$1=\"\"}1' | cut -d: -f1 | sort | uniq\n```\n\nThis uses `fc-list` to get the names of all the fonts available on your\nmachine. This seems to work on both Linux and Mac. Through a series of `awk`,\n`cut`, and `sort | uniq`, this command produces a clean, easily-browsed list\nof fonts.\n\nI like to take this a step further by piping it all to `fzf` where I can then\nnarrow down the output to just lines that match _FiraCode_.\n\n```bash\n$ fc-list | awk '{$1=\"\"}1' | cut -d: -f1 | sort | uniq | fzf\n```\n\nSee also [`system_profiler SPFontsDataType`](https://apple.stackexchange.com/questions/35852/list-of-activated-fonts-with-shell-command-in-os-x/243746#243746).\n"
  },
  {
    "path": "unix/list-all-the-enabled-zsh-options.md",
    "content": "# List All The Enabled ZSH Options\n\nThe zsh shell has a [ton of\noptions](https://zsh.sourceforge.io/Doc/Release/Options.html) that can be\nenabled and disabled for all kinds of functionality. Some of these options are\nenabled by default, some of them may be enabled by a script like\n[oh-my-zsh](https://ohmyz.sh/), and even more might have been enabled or\ndisabled by you in your `~/.zshrc` file.\n\nTo quickly produce a list of all options that are currently enabled, run:\n\n```bash\n$ setopt\n```\n\nAll enabled options will be output by that command. That might be a lot of\noutput, so if you know what you are looking for, you can `grep` through the\noutput. Or, even better, if you have [`fzf`](https://github.com/junegunn/fzf)\ninstalled, you can interactively fuzzy search through it.\n\n```bash\n$ setopt | fzf\n```\n\n[source](https://unix.stackexchange.com/questions/121802/zsh-how-to-check-if-an-option-is-enabled/121810#121810)\n"
  },
  {
    "path": "unix/list-all-users.md",
    "content": "# List All Users\n\nOn unix-based systems, all system users are listed with other relevant\ninformation in the `/etc/passwd` file. You can output a quick list of the\nusers by name with the following command:\n\n```\n$ cut -d: -f1 /etc/passwd\n```\n\n[source](http://askubuntu.com/questions/410244/a-command-to-list-all-users-and-how-to-add-delete-modify-users)\n"
  },
  {
    "path": "unix/list-files-in-a-single-column.md",
    "content": "# List Files In A Single Column\n\nThe `ls` command lists out the files and directories in your current directory\nor a specified directory.\n\nThe standard output for an `ls` command expands the fit the width of your\nterminal screen.\n\n```bash\n❯ ls *.(ts|js)\ncypress.config.ts  postcss.config.js  remix.config.js    remix.env.d.ts     server.ts          tailwind.config.ts vitest.config.ts\n```\n\nThis might not always be the ideal way to view that output. For instance, the\nabove example when shared as a code block like in this post ends up with\nhorizontal scroll.\n\nWith the `-1` flag, we can tell `ls` to display the results in a single\nvertical column.\n\n```bash\n❯ ls -1 *.(ts|js)\ncypress.config.ts\npostcss.config.js\nremix.config.js\nremix.env.d.ts\nserver.ts\ntailwind.config.ts\nvitest.config.ts\n```\n\nSee `man ls` for more details.\n\n[source](https://askubuntu.com/questions/954924/listing-files-in-directory-in-one-column)\n"
  },
  {
    "path": "unix/list-files-ordered-by-modification-date.md",
    "content": "# List Files Ordered By Modification Date\n\nThe `ls` command lists the files in a directory. Tacking on the `-l` flag\nwill list it in long format. By default, everything is listed in\nlexicographical order. This is what `ls -l` looks like for this repository.\n\n```\n-rw-r--r--    1 jbranchaud  staff    628 Feb 14  2016 CONTRIBUTING.md\n-rw-r--r--    1 jbranchaud  staff   1058 Feb 19  2015 LICENSE\n-rw-r--r--    1 jbranchaud  staff  40983 Aug 18 16:59 README.md\ndrwxr-xr-x    5 jbranchaud  staff    170 Apr  1 14:45 ack\ndrwxr-xr-x    5 jbranchaud  staff    170 Feb 24 16:31 chrome\n...\n```\n\nSometimes you want a sense of what has been modified and when.\nLexicographical order isn't going to help much here. By tacking on the `-t`\nflag, the files will be listed in order of their modification dates. Here is\n`ls -lt` for the same repository.\n\n```\n-rw-r--r--    1 jbranchaud  staff  40983 Aug 18 16:59 README.md\ndrwxr-xr-x  119 jbranchaud  staff   4046 Aug 17 11:38 vim\ndrwxr-xr-x    5 jbranchaud  staff    170 Aug 16 10:47 internet\ndrwxr-xr-x   23 jbranchaud  staff    782 Aug  1 10:17 javascript\ndrwxr-xr-x    7 jbranchaud  staff    238 Jul 22 14:04 webpack\n...\n```\n\nSee `man ls` for more details.\n"
  },
  {
    "path": "unix/list-names-of-files-with-matches.md",
    "content": "# List Names Of Files With Matches\n\nI often use `grep` and `ag` to search for patterns in a group or directory\nof files. Generally I am interested in looking at the matching lines\nthemselves. However, sometimes I just want to know the set of files that\nhave matches. Both `grep` and `ag` can be told to output nothing more than\nthe names of the files with matches when given the `-l` flag.\n\nThis can come in particularly handy if you just want a list of files that\ncan be piped (or copied) for use with another command. This eliminates all\nthe extra noise.\n\nh/t Dillon Hafer\n"
  },
  {
    "path": "unix/list-of-sessions-to-a-machine.md",
    "content": "# List Of Sessions To A Machine\n\nThe `last` command is a handy way to find out who has been connecting to a\nmachine and when.\n\n> Last will list the sessions of specified users, ttys, and hosts, in\n> reverse time order.  Each line of output contains the user name, the tty\n> from which the session was conducted, any hostname, the start and stop\n> times for the session, and the duration of the session.  If the session is\n> still continuing or was cut short by a crash or shutdown, last will so\n> indicate.\n\nIn particular, this can be useful for finding an IP address that you want to\nconnect to.\n\nSee `man last` for more details.\n"
  },
  {
    "path": "unix/list-parent-pid-with-ps.md",
    "content": "# List Parent pid With ps\n\nThe `ps` command, which stands for `process status`, is a great way to find\ndifferent processes running on a machine. Information like their `pid`\n(_process id_) is included. If you are tracking down a process to kill and\nfind that that process is an unkillable zombie, then you may need to\nsimultaneously kill the process' parent as well.\n\nSo, you'll need the parent `pid` as well. You can get both the `pid` and the\nparent `pid` of a process by including the `-f` flag with `ps`.\n\nYou may also want to include the `-e` flag to make sure that information\nabout other users' processes is included in the results.\n"
  },
  {
    "path": "unix/list-stats-for-a-file.md",
    "content": "# List Stats For A File\n\nThe `ls` command is good for listing files. Tacking on the `-la` flags gives\nyou a bunch of info about each of the listed files. To get even more info,\nwe can use the `stat` command.\n\n```bash\n$ stat README.md\n16777220 143994676 -rw-r--r-- 1 jbranchaud staff 0 53557 \"Jul 14 14:53:44 2018\" \"Jul 10 14:54:39 2018\" \"Jul 10 14:54:39 2018\" \"Jul 10 14:54:39 2018\" 4096 112 0 README.md\n```\n\nThat's definitely more info, but it is unlabeled and a lot to parse. We can\nimprove the output with the `-x` flag.\n\n```bash\n$ stat -x README.md\n  File: \"README.md\"\n  Size: 53557        FileType: Regular File\n  Mode: (0644/-rw-r--r--)         Uid: (  501/jbranchaud)  Gid: (   20/   staff)\nDevice: 1,4   Inode: 143994676    Links: 1\nAccess: Sat Jul 14 14:53:44 2018\nModify: Tue Jul 10 14:54:39 2018\nChange: Tue Jul 10 14:54:39 2018\n```\n\nSee `man stat` for more details.\n\n[source](https://www.unixtutorial.org/2008/11/how-to-update-atime-and-mtime-for-a-file-in-unix/)\n"
  },
  {
    "path": "unix/list-the-available-jdks.md",
    "content": "# List The Available JDKs\n\nWant to know what JDK versions are installed and available on your machine?\nThere is a command for that.\n\n```bash\n$ /usr/libexec/java_home -V\nMatching Java Virtual Machines (3):\n    9.0.4, x86_64:      \"Java SE 9.0.4\" /Library/Java/JavaVirtualMachines/jdk-9.0.4.jdk/Contents/Home\n    1.8.0_162, x86_64:  \"Java SE 8\"     /Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home\n    1.8.0_161, x86_64:  \"Java SE 8\"     /Library/Java/JavaVirtualMachines/jdk1.8.0_161.jdk/Contents/Home\n\n/Library/Java/JavaVirtualMachines/jdk-9.0.4.jdk/Contents/Home\n```\n\nThe listed VMs show what JDK versions you have and the final line shows\nwhich is currently the default version.\n"
  },
  {
    "path": "unix/list-the-pid-and-name-of-current-shell-process.md",
    "content": "# List PID And Name Of Current Shell Process\n\nIn Julia Evans' [How to add a directory to your\nPATH](https://jvns.ca/blog/2025/02/13/how-to-add-a-directory-to-your-path/),\nshe shows off an odd-looking command for determining what shell (e.g. bash or\nzsh) you are currently running.\n\n```bash\n$ ps -p $$ -o pid=,comm=\n\n38105 -zsh\n```\n\nI already know I'm running `zsh`, but I thought this command was interesting\nenough to dig into and break down.\n\n- The `ps` command lists processes that \"have controlling terminals\"\n- The `$$` is a special shell variable representing the PID of the current process (try `echo $$`)\n- The `-p` flag allows you to specify a PID for `ps` to grab, in this case, the `$$` PID\n- The `-o` flag allows us to specify the output format, such as the PID and command name\n- The `=` after `pid` and `comm` tell `ps` to exclude headers from the output\n\nAdditionally, I noticed that it output `-zsh` (not just `zsh`). That leading\nhyphen seems to indicate that [this `zsh` process is a _login\nshell_](https://unix.stackexchange.com/a/46856/5916). That means it was the\nprocess used to initiate an interactive shell session and something like the\n`.zprofile` would have been sourced as part of that.\n"
  },
  {
    "path": "unix/list-the-stack-of-remembered-directories.md",
    "content": "# List The Stack Of Remembered Directories\n\nWhen you open a new Unix shell, you start in some directory, probably your\nhome (`~/`) directory. If you use `pushd` to navigate to different\ndirectories, there is a paper trail of your movements, a listing of where\nyou've been.  You can view this listing of directories with the `dirs`\ncommand.\n\n```\n$ dirs\n~/\n$ pushd code\n$ dirs\n~/code ~/\n$ pushd /usr/bin\n$ dirs\n/usr/bin ~/code ~/\n```\n\nEach time you `pushd`, the directory you have moved to is pushed onto the stack of\nvisited directories. Alternatively, you can use the `popd` command to return\nto the previous directory, removing the current directory from the stack.\n\n[source](http://www.gnu.org/software/bash/manual/html_node/Directory-Stack-Builtins.html#Directory-Stack-Builtins)\n"
  },
  {
    "path": "unix/list-txt-dns-records-for-a-domain.md",
    "content": "# List TXT DNS Records For A Domain\n\nThe `dig` command can be used to list specifically the `TXT` DNS records for a\ndomain using the `-t TXT` flag like so:\n\n```bash\n$ dig -t TXT visualmode.dev\n\n; <<>> DiG 9.10.6 <<>> -t TXT visualmode.dev\n;; global options: +cmd\n;; Got answer:\n;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41226\n;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1\n\n;; OPT PSEUDOSECTION:\n; EDNS: version: 0, flags:; udp: 4096\n;; QUESTION SECTION:\n;visualmode.dev.                        IN      TXT\n\n;; ANSWER SECTION:\nvisualmode.dev.         377     IN      TXT     \"v=spf1 include:_spf.mx.cloudflare.net ~all\"\nvisualmode.dev.         377     IN      TXT     \"google-site-verification=MBZ2S2fhnh2gHRxFniRrYW-O6mdyimJDRFj-f\nvblwtk\"\n\n;; Query time: 103 msec\n;; SERVER: fe80::7c4b:26ff:fe85:e164%6#53(fe80::7c4b:26ff:fe85:e164%6)\n;; WHEN: Tue Dec 03 12:49:38 CST 2024\n;; MSG SIZE  rcvd: 179\n```\n\nThis is still rather verbose though. With the `+short` option we can pare down\nthe output to the values of any TXT records and nothing else.\n\n```bash\n$ dig -t TXT visualmode.dev +short\n\"v=spf1 include:_spf.mx.cloudflare.net ~all\"\n\"google-site-verification=MBZ2S2fhnh2gHRxFniRrYW-O6mdyimJDRFj-fvblwtk\"\n```\n\nNeat! Now I can see that [my domain is correctly identifying itself with Google\nSearch Console](internet/verify-site-ownership-with-dns-record.md).\n\n[source](https://serverfault.com/a/148724)\n"
  },
  {
    "path": "unix/load-env-vars-in-bash-script.md",
    "content": "# Load Env Vars In Bash Script\n\nI have a file with environment variables in my current directory named\nsomething like `.env.local`. I want to load those variabls into my environment\nin the context of a bash script. That can be accomplished by exporting them at\nthe beginning of the script with a line like this:\n\n```bash\nexport $(egrep -v '^#' .env.local | xargs)\n```\n\nThis uses `egrep` with the `-v '^#'` inverted match pattern to excluded any\ncomment lines. Then `xargs` is going to remove any excess whitespace and echo\nthe sequence env var entries. All of which will be the argument passed to\n`export` which adds them to the environment.\n\nHere is an example of using it in a script that uses one of those secret env\nvar values as a bearer token in a cURL request.\n\n```bash\n#!/bin/bash\n\n# Load environment variables from .env.local file\nexport $(egrep -v '^#' .env.local | xargs)\n\n# Now you can use the environment variable in your CURL command\ncurl -L \\\n  -X POST \\\n  -H \"Accept: application/vnd.github+json\" \\\n  -H \"Authorization: Bearer $GITHUB_ACCESS_TOKEN\"\\\n  -H \"X-GitHub-Api-Version: 2022-11-28\" \\\n  https://api.github.com/repos/jbranchaud/github-actions-experiment/actions/workflows/playwright.yml/dispatches \\\n  -d '{\"ref\":\"main\"}'\n```\n"
  },
  {
    "path": "unix/look-through-all-files-that-have-been-git-stashed.md",
    "content": "# Look Through All Files That Have Been Git Stashed\n\nWhen I use `git stash`, I typically _pop_ the stash not long after to continue\nworking with those changes. Still, over time the stash list tends to build up,\nespecially if I'm bouncing between lots of different work.\n\nI wired together a series of commands with the unix piping to make it easy to\nexplore the entire contents of the stash.\n\n```bash\n$ git stash list \\\n  | awk -F: '{print $1}' \\\n  | xargs -I stash-ref git stash show stash-ref --name-only \\\n  | sort \\\n  | uniq\n```\n\nThat \"one-liner\" on its own gives me a uniq list of all files across all my\nstashes in the current git repo.\n\nI can then explore it by tacking on something like `fzf` or `grep`:\n\n```bash\n$ git stash list \\\n  | awk -F: '{print $1}' \\\n  | xargs -I stash-ref git stash show stash-ref --name-only \\\n  | sort \\\n  | uniq \\\n  | grep '.*.md'\n```\n"
  },
  {
    "path": "unix/make-direnv-less-noisy.md",
    "content": "# Make Direnv Less Noisy\n\nI've been using [`direnv`](https://direnv.net/) to manage project and folder\nspecific environment variables for a bit now. I've found it to be pretty\nseamless. It can feel like it is littering my shell with too much output when I\nchange directories though.\n\nThere are two levers to control its output.\n\nFirst, the direnv logs (e.g. `direnv: loading ~/.../.envrc`) can be controlled\nwith the `DIRENV_LOG_FORMAT` env var. Add this to the\n`~/.config/direnv/direnvrc` file (add that directory and file if necessary).\nYou can leave it blank to altogether hide log messages or you can gray-out the\nlog messages like this:\n\n```\nexport DIRENV_LOG_FORMAT=$'\\033[2mdirenv: %s\\033[0m'\n```\n\nSecond, you can hide the env var diff with a separate config. This diff is not\ncovered under the umbrella of logs controlled by the above setting. Set\n[`hide_env_diff` in the `~/.config/direnv/direnv.toml`\nfile](https://direnv.net/man/direnv.toml.1.html#codehideenvdiffcode):\n\n```toml\n[global]\nhide_env_diff = true\n```\n\nThis second config was only added as of `v2.34.0`.\n\n[source](https://esham.io/2023/10/direnv)\n"
  },
  {
    "path": "unix/make-neovim-the-default-way-to-view-man-pages.md",
    "content": "# Make Neovim The Default Way To View Man Pages\n\nI was reading the help page for `:Man` which is the built-in plugin to Neovim\nfor viewing man pages within a Neovim session. In it, they mentioned that the\n`MANPAGER` can be set to use Neovim instead of the default man page viewer.\n\nThis can be done by setting `MANPAGER` like so:\n\n```bash\n$ export MANPAGER='nvim +Man!'\n```\n\nAfter setting this, you can run something like `man git-restore` which will\nopen the man page for that command in a Neovim session using the Man page\nplugin which can do things like follow links to other man pages (`K` or\n`Ctrl=]`), quit by hitting `q`, as well as all the motions and search behavior\nof Vim.\n\nFor long-term use, this can be set in your shell config, e.g. `~/.zshrc`. For\none-off use, you can include it as an env var for a single call to `man`:\n\n```bash\nMANPAGER='nvim +Man!' man git-restore\n```\n\nSee `:h :Man` within a Neovim session for more details.\n"
  },
  {
    "path": "unix/manually-pass-two-git-files-to-delta.md",
    "content": "# Manually Pass Two Git Files To Delta\n\nI recently [wired up `delta` as my default pager and differ for\n`git`](git/better-diffs-with-delta.md). However, when I installed `delta`, I\nfirst wanted to see what its diff output looked like.\n\nHow can I pass two versions of the same file from `git` to `delta`?\n\nI can show the current contents of a file with `git show` referencing the\n`HEAD` commit.\n\n```bash\n$ git show HEAD:main.go\n```\n\nSimiliarly, I can show the contents of that file _one_ commit ago with `HEAD~`.\n\n```bash\n$ git show HEAD~:main.go\n```\n\nI can then pass each of those commands as virtual files to `delta` using the\n`<()` syntax. The older file goes first and the newer second.\n\n```bash\n$ delta <(git show HEAD~:main.go) <(git show HEAD:main.go)\n```\n\nThat works and comes in handy if you need to compare two things that aren't\nnecessarily files or aren't necessarily under version control. However, in\nhindsight, I'd say it is easier to add delta as the pager and differ and try it\nout directly.\n"
  },
  {
    "path": "unix/map-a-domain-to-localhost.md",
    "content": "# Map A Domain To localhost\n\nDo you want your computer to treat a domain as `localhost`? You can map it\nas such in your `/etc/hosts` file. For example, if I have an web app that\nrefers to itself with the `dev.app.com` domain, I can add the following line\nto my `/etc/hosts` file to make sure the domain resolves to `localhost`:\n\n```\n127.0.0.1 dev.app.com\n```\n\nNow, if I pop open my browser and visit `dev.app.com:3000`, I will see\nwhatever is being served to `localhost:3000`.\n\nh/t Chris Erin\n"
  },
  {
    "path": "unix/negative-look-ahead-search-with-ripgrep.md",
    "content": "# Negative Look-Ahead Search With ripgrep\n\nI have a huge monorepo with a bunch of instances of the\n`NEXT_PUBLIC_SANITY_DATASET` env var that need to be updated to\n`NEXT_PUBLIC_SANITY_DATASET_ID` (notice the `_ID` appended to the end). If I do\na basic search for `NEXT_PUBLIC_SANITY_DATASET`, I get a huge list of results\ncluttered with all the instances where this env var has already been updated.\n\nTo get a list of _only_ the places where the old env var, and not the new env\nvar, appear, I need to use [a regex feature called a negative\nlook-ahead](https://www.regular-expressions.info/lookaround.html). That looks\nsomething like `PATTERN(?!NLA)` where we want to match on `PATTERN`, but not if\nit is immediately followed by `NLA`.\n\nLet's try that with [ripgrep](https://github.com/BurntSushi/ripgrep):\n\n```bash\n$ rg 'NEXT_PUBLIC_SANITY_DATASET(?!_ID)' --hidden --glob '!node_modules/**' --glob '!.git/**'\nregex parse error:\n    NEXT_PUBLIC_SANITY_DATASET(?!_ID)\n                              ^^^\nerror: look-around, including look-ahead and look-behind, is not supported\n\nConsider enabling PCRE2 with the --pcre2 flag, which can handle backreferences\nand look-around.\n```\n\nIt doesn't work as is, but the error message helpfully tells me that I need to\ninclude the `--pcre2` flag for look-ahead to work.\n\nLet's try that again:\n\n```bash\n❯ rg --pcre2 'NEXT_PUBLIC_SANITY_DATASET(?!_ID)' --hidden --glob '!node_modules/**' --glob '!.git/**'\napps/testing-javascript/.env.development\n37:NEXT_PUBLIC_SANITY_DATASET=production\n...\n```\n\nThat works!\n"
  },
  {
    "path": "unix/occupy-a-local-port-with-netcat.md",
    "content": "# Occupy A Local Port With Netcat\n\nThe `netcat` (`nc`) utility can listen to a specific port on your local\nmachine. This, in effect, occupies that port. This is handy for a variety of\nreasons. In my case, I find it useful for testing out a web server script that\ncan gracefully react to its desired port being occupied.\n\nThe `-l` flag is how you tell `nc` to listen. Then you specify `localhost` as\nthe host and whatever port you want to occupy after that.\n\n```bash\n$ nc -l localhost 5000\n```\n\nNow if I try to run my web server script for port `5000`, I see the `Address\nalready in use` error.\n\nSee `nc -h` for more details.\n\n[source](https://twitter.com/jbrancha/status/1566820110366654474?s=20&t=HcUMm1aRXpEgCAzONhy34w)\n"
  },
  {
    "path": "unix/only-show-the-matches.md",
    "content": "# Only Show The Matches\n\nTools like `grep`, `ack`, and `ag` make it easy to search for lines in a\nfile that contain certain text and patterns. They all come with the `-o`\nflag which tells them to only show the part that matches.\n\nThis is particularly powerful when used with regex and piped into other\nprograms.\n\nh/t Dillon Hafer\n"
  },
  {
    "path": "unix/open-the-current-command-in-an-editor.md",
    "content": "# Open The Current Command In An Editor\n\nIf you are working with a complicated command in the terminal trying to get\nthe arguments just right. Such as this `curl`:\n\n```bash\ncurl https://api.stripe.com/v1/customers \\\n   -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \\\n   -d description=\"Customer for test@example.com\" \\\n   -d source=tok_189fCz2eZvKYlo2CsGERUNIW\n```\n\nIt can be tedious to move to and modify various parts of the command.\nHowever, by hitting `Ctrl-x Ctrl-e`, the contents of the command buffer\nwill be opened into your default editor (i.e. `$EDITOR`). This will make\nediting the command a bit easier. Saving and quitting the editor will put\nthe updated command in the command buffer, ready to run.\n\nHit `Ctrl-x Ctrl-e` with an empty command buffer if you want to start\ncrafting a command from scratch or if you are pasting one in from somewhere.\n\nh/t Josh Davey\n"
  },
  {
    "path": "unix/output-the-last-n-bytes-of-a-large-file.md",
    "content": "# Output The Last N Bytes Of A Large File\n\nAfter creating a massive JSON file as part of a data export, I wanted to check\nthe timestamp of the last value in the file. However, even for Vim, the file\nwas big and it was taking a while to bring the whole thing into memory.\n\nI didn't really need to open it in a full-fledged editor, I just needed to grab\nthe trailing bits (bytes!) of the file until I could see enough data to verify\nthe export.\n\nThe `tail` command is a great tool for this because it can quickly read\ninformation from the end of a file. The `-c` flag in particular allows you to\ngrab the last N bytes of the file and output them.\n\nSo, I started with:\n\n```bash\n$ tail -c 100 data.json\n```\n\nThat didn't quite show me enough info, so I bumped it up:\n\n```bash\n$ tail -c 1000 data.json\n```\n\nThat time I was able to see enough to verify the export.\n\nBoth commands ran instantaneously, meanwhile my editor was still opening the\nfile.\n\nSee `man tail` for more details.\n"
  },
  {
    "path": "unix/partial-string-matching-in-bash-scripts.md",
    "content": "# Partial String Matching In Bash Scripts\n\nTo compare two strings in a bash script, you will have a snippet of code\nsimilar to the following:\n\n```bash\nif [[ $(pwd) == \"/path/to/current/directory\" ]]\nthen\n  echo \"You are in that directory\";\nfi\n```\n\nYou may only want to do a partial string match. For this, you can use the\n`*` wildcard symbol.\n\n```bash\nif [[ $(pwd) == *\"directory\"* ]]\nthen\n  echo \"You are in that directory\";\nfi\n```\n\n[source](http://stackoverflow.com/questions/229551/string-contains-in-bash)\n"
  },
  {
    "path": "unix/pid-of-the-current-shell.md",
    "content": "# PID Of The Current Shell\n\n`$` expands to the process ID of the shell. So, you can see the PID of the\ncurrent shell with `echo $$`.\n\n```bash\n> echo $$\n36609\n\n> zsh\n\n> echo $$\n45431\n\n> exit\n\n> echo $$\n36609\n```\n\nSee the `Special Paramaters` section of `man bash` for more details.\n\n[source](http://stackoverflow.com/questions/21063765/get-pid-in-shell-bash)\n"
  },
  {
    "path": "unix/print-a-range-of-lines-for-a-file-with-bat.md",
    "content": "# Print A Range Of Lines For A File With Bat\n\nI recently learned about a [faster and more colorful alternative to\ncat](https://chireviewofbooks.com/2018/12/11/here-are-the-winners-of-the-2018-chicago-review-of-books-awards/)\n-- [`bat`](https://github.com/sharkdp/bat). Like `cat`, the standard usage\nis to print the entire contents of a file. You can instruct `bat` to only\nprint a range of lines from a file using the `--line-range` flag.\n\nFor instance the following command\n\n```bash\n$ bat --line-range=918:925 README.md\n```\n\nwill produce the following output\n\n![a range of lines from the README](https://i.imgur.com/MmKbNvl.png)\n\nSee `man bat` for more details.\n"
  },
  {
    "path": "unix/print-datetime-represented-by-unix-timestamp.md",
    "content": "# Print DateTime Represented By Unix Timestamp\n\nA lot of tools and systems use a Unix timestamp to represent a point in time.\nIt is the number of seconds since the Unix epoch (Jan 1, 1970). However, just\nlooking at a timestamp like `1623867544` doesn't tell a human much. I can't\nmentally translate that to the date and time that it is representing.\n\nThe `date` utility can help. Give it the `-r` flag with the timestamp value (in\nseconds) and it will display the date and time in a human-readable format.\n\n```bash\n❯ date -r '1623867544'\nWed Jun 16 13:19:04 CDT 2021\n```\n\nSee `man date` for more details.\n"
  },
  {
    "path": "unix/print-milliseconds-in-human-readable-format.md",
    "content": "# Print Milliseconds In Human-Readable Format\n\nI ran a command in a program. It doesn't really matter what command or program.\nWhat does matter is that it took a long time and when it finished, it told me\nhow long it took, but in milliseconds.\n\n```\n835953ms\n```\n\nTypically, when I see a timing number like this, I open Alfred and do some\nquick math (`N / 1000 / 60 / 60` or something like that).\n\nThere is an easier way, using the\n[`pretty-ms-cli`](https://github.com/sindresorhus/pretty-ms-cli). This\npurpose-built CLI can be run using something like\n[`npx`](https://www.npmjs.com/package/npx). All I do is hand it the number of\nmilliseconds and it prints out how long that is in something that I can\nunderstand.\n\n```bash\n❯ npx pretty-ms-cli 835953\n13m 56s\n```\n"
  },
  {
    "path": "unix/print-out-files-in-reverse.md",
    "content": "# Print Out Files In Reverse\n\nIf you're familiar with `cat` -- the command you might use to print out a file\nin the terminal -- then you may appreciate a similar command: `tac`.\n\nWith `tac` you can\n\n> Write each FILE to standard output, last line first.\n\nNotice that `tac` is `cat` spelled in reverse. That's what it does with your\nfiles, prints them out in reverse.\n\nGive it a try just as you'd use `cat`:\n\n```bash\n$ tac README.md\n```\n\nSee `man tac` for more details.\n"
  },
  {
    "path": "unix/print-the-current-date-in-human-readable-format.md",
    "content": "# Print The Current Date In Human-Readable Format\n\nThe `date` utility by default does a good job of displaying the current date in\na human-readable format.\n\n```bash\n❯ date\nFri Jun  2 11:30:03 CDT 2023\n```\n\nIt has some additional info like the time and timezone.\n\nIf I just want to see the date with the day of the week, I can call `date` with\na format string that uses special identifiers for each part of the date. This\ngives me control over exactly how it is displayed. For example, the following\nformat string works for my purposes.\n\n```bash\n❯ date '+%A %B %d, %Y'\nFriday June 02, 2023\n```\n\nThe `+` indicates that it is a user-specified format string and the rest of the\nspecial identifiers are defined by `strftime`.\n\nSee `man date` and `man strftime` for more details.\n"
  },
  {
    "path": "unix/produce-a-lowercase-v4-uuid.md",
    "content": "# Produce A Lowercase V4 UUID\n\nThere are [a variety of ways to produce a v4\nUUID](different-ways-to-generate-a-v4-uuid.md) on Unix-based machines. Of the\noptions I listed in that post, my favorite is the `uuidgen` command. My only\ngripe with it is that it produces an all uppercase UUID.\n\n```bash\n$ uuidgen\nB7918C26-12AE-4093-B6DA-0D7D41C59FB6\n```\n\nOften when I need a UUID, it is to plug in as the ID value for some test data\nin a system that is using lowercase UUIDs. For the sake of consistency, I'd\nlike it to be lowercase as well.\n\nThe `tr` command comes in handy for this because I can _tr_anslate the\nuppercase characters to lowercase ones.\n\n```bash\n$ uuidgen | tr '[:upper:]' '[:lower:]'\ned817cf3-8f70-4838-82bc-8e5b328c0b93\n```\n\nSo now anytime I need a lowercase UUID, I hit `ctrl-r` and search back for\neither `uuid` or `lower` and find this command pretty quickly.\n"
  },
  {
    "path": "unix/provide-a-fallback-value-for-unset-parameter.md",
    "content": "# Provide A Fallback Value For Unset Parameter\n\nIf you are using a value in a parameter expansion expression that isn't set,\nthe result will be empty.\n\nFor instance, the XDG paths are not defined for me on OSX.\n\n```bash\n$ echo \"${XDG_CONFIG_HOME}\"\n\n```\n\nTo make a script more robust, you can provide a fallback value (i.e. [default\nvalue](https://wiki.bash-hackers.org/syntax/pe#use_a_default_value)). The\nparameter expansion will use the fallback value if the primary value is either\nunset or null.\n\nThe syntax for this is to follow the primary parameter with `:-` and then the\nfallback parameter.\n\n```bash\n$ echo \"${XDG_CONFIG_HOME:-$HOME/.local/share}\"\n/Users/jbranchaud/.local/share\n```\n\nBecause I'm on OSX, this expands to my `$HOME` directory with `/.local/share`\nappended.\n\n[source](https://unix.stackexchange.com/a/122848/5916)\n"
  },
  {
    "path": "unix/remove-a-directory-called-dash-p.md",
    "content": "# Remove A Directory Called `-p`\n\nI accidentally created a directory from the terminal called `-p`. It is sitting\nthere next to other directories like `app` and `public`. I need to get rid of\nit. The `rmdir` command is the best way to do that.\n\n```bash\n$ rmdir -p\nusage: rmdir [-p] directory ...\n```\n\nNot so fast. `-p` is also a valid flag for the `rmdir` command. It doesn't know\nthat I mean it as the name of the directory. So instead, I am missing a\nrequired argument to `rmdir` – the directory.\n\nTo get this to work, I need to tell `rmdir` that I intend `-p` as the name of\nthe directory to remove.\n\n```\n$ rmdir -- -p\n```\n\nThe `--` is a command-line convention. It tells the command that anything after\nthe `--` is not a flag, but instead an argument. This time the `-p` directory\nwill be removed.\n"
  },
  {
    "path": "unix/rename-a-bunch-of-files-by-constructing-mv-commands.md",
    "content": "# Rename A Bunch Of Files By Constructing mv Commands\n\nI downloaded a bunch of bank statements as PDFs. On the upside they all were\nconsistently named. On the downside they used an unhelpful date format. With a\ndate format that puts year before month before day, the files easily sort\nalphanumerically. However, these filenames used a date format that put month\nbefore day before year.\n\nHere is a subset of the files\n\n```bash\n$ ls *.pdf\n'012524 Statement.pdf'\n'012725 Statement.pdf'\n'022624 Statement.pdf'\n'022625 Statement.pdf'\n'032524 Statement.pdf'\n'032525 Statement.pdf'\n```\n\nNotice they are named with `MMDDYY Statement.pdf`. I would instead like for them\nto be named as `YYYY-MM-DD-statement.pdf`.\n\nI can generate a series of `mv` statements that then get piped to `sh` which\n_evaluates_ them. But first, let's do a dry run of a `sed` statement that\nrearranges the date parts.\n\n```bash\n$ ls *.pdf | sed 's/\\(..\\)\\(..\\)\\(..\\) Statement\\.pdf/mv \"&\" \"20\\3-\\1-\\2-statement.pdf\"/'\nmv \"012524 Statement.pdf\" \"2024-01-25-statement.pdf\"\nmv \"012725 Statement.pdf\" \"2025-01-27-statement.pdf\"\nmv \"022624 Statement.pdf\" \"2024-02-26-statement.pdf\"\nmv \"022625 Statement.pdf\" \"2025-02-26-statement.pdf\"\nmv \"032524 Statement.pdf\" \"2024-03-25-statement.pdf\"\nmv \"032525 Statement.pdf\" \"2025-03-25-statement.pdf\"\n```\n\nThe way this works is that all the `pdf` files in the current directly get\nlisted out. That gets piped to a `sed` statement that matches on capture groups\nagainst the first three pairs of characters (the date parts) in the filenames.\nIt matches on the rest of the filename (` Statement.pdf`). This is then replaced\nby a `mv `, the full match of the original filename (`&`), and then the new\nfilename made up of the rearranged date parts.\n\nI can then pipe it to `sh` to run those `mv` commands.\n\n```bash\n$ ls *.pdf |\n  sed 's/\\(..\\)\\(..\\)\\(..\\) Statement\\.pdf/mv \"&\" \"20\\3-\\1-\\2-statement.pdf\"/' |\n  sh\n```\n"
  },
  {
    "path": "unix/repeat-yourself.md",
    "content": "# Repeat Yourself\n\nUse the `repeat` command to repeat some other command.\n\nYou can repeat a command any number of times like so\n\n```\n$ repeat 5 say Hello World\n```\n"
  },
  {
    "path": "unix/replace-pattern-across-many-files-in-a-project.md",
    "content": "# Replace Pattern Across Many Files In A Project\n\nLet's say I have a bunch of files in the `db/migrate` directory of my project\nthat contain a line of text I'd like to update. I want to replace all\noccurrences of `t.bigint` with `t.integer`.\n\nFirst, I can get an idea of the scope of the change by listing out all the\nfiles and lines where this pattern exists using\n[`ripgrep`](https://github.com/BurntSushi/ripgrep).\n\n```bash\n$ rg 't.bigint' db/migrate\n```\n\nI can visually do a quick scan to make sure I'm not picking up results with my\npattern that weren't intended.\n\nThen, I can include the `--files-with-matches` flag to limit the `ripgrep`\noutput to just filenames. Those filenames can be piped to `sed` (via `xargs`)\nwhich will do the pattern replacement.\n\n```bash\n$ rg --files-with-matches 't.bigint' db/migrate | \\\n  xargs sed -i '' 's/t.bigint/t.integer/g'\n```\n\nThis does an in-place (`-i ''`) edit of the files substituting (`s///g`)\nglobally the occurrences of `t.bigint` for `t.integer`.\n"
  },
  {
    "path": "unix/run-a-command-repeatedly-several-times.md",
    "content": "# Run A Command Repeatedly Several Times\n\nFrom the terminal in a Bash or Zsh shell session, I can loop on a command to\nhave it run a specific number of times.\n\nIf I want to run a test command (e.g. `bin/test some_file.spec:123`) 12 times\nin a row, I could use a for loop like so:\n\n```bash\nfor i in {1..12}; do bin/test some_file.spec:123; done\n```\n\nAnd the shell will run the command one time after another until it has been run\n12 times. That range `{1..12}` can be adjusted to whatever I want. For\ninstance, to have it loop 3 times, I'd make it into `{1..3}`.\n\n[source](https://serverfault.com/questions/273238/how-to-run-a-command-multiple-times-using-bash-shell)\n"
  },
  {
    "path": "unix/run-a-curl-command-without-the-progress-meter.md",
    "content": "# Run A cURL Command Without The Progress Meter\n\nBy default when you run a `curl` command that will output to the terminal, it\ndisables the progress meter for the request. When the response output is\nredirected or piped somewhere else however, the progress meter will be\ndisplayed in the terminal.\n\n```bash\n$ curl -H \"Content-Type: application/json\" -G http://myurl.com | jq\n  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current\n                                 Dload  Upload   Total   Spent    Left  Speed\n100  2515    0  2515    0     0   4184      0 --:--:-- --:--:-- --:--:--  4184\n```\n\nThis can be disabled with the `-s` flag (which is short for `--silent`).\n\n```bash\n$ curl -s -H \"Content-Type: application/json\" -G http://myurl.com | jq\n```\n\nHowever, the `-s` flag will also suppress error messages. This is a bit\nunhelpful. You can then add in the `-S` flag (short for `--show-error`) to\nensure that error messages are shown even while the progress meter is\nsuppressed.\n\n```bash\n$ curl -sS -H \"Content-Type: application/json\" -G http://myurl.com | jq\n```\n\nSee `man curl` for more details.\n"
  },
  {
    "path": "unix/safely-edit-the-sudoers-file-with-vim.md",
    "content": "# Safely Edit The Sudoers File With Vim\n\nThe sudoers file is a way on Unix systems to administer various levels of\npermissions to different users. It is important to make sure you \"know what\nyou're doing\" when editing this file. Especially so because if you mangle the\nsyntax of the file, you could lock out yourself and even the root user from\ndoing all kinds of things. Even from being able to update and fix this file.\n\nFortunately, there is a command—`visudo`—that opens the sudoers file in an\neditor that will perform pre-save checks to ensure the file is valid syntax.\n\n```bash\n$ visudo\n```\n\nThis command has `vi` in the name because it used to be that it would default\nto `vi` as the editor. On Ubuntu, at the very least, this has changed and the\ndefault is now `nano`.\n\nIf you'd like to still have `visudo` open to `vi` (or `vim`), you can specify\nthat with the `SUDO_EDITOR` env var.\n\n```bash\n$ SUDO_EDITOR=vim visudo\n```\n\n[source](https://manpages.ubuntu.com/manpages/impish/en/man8/visudo.8.html#environment)\n"
  },
  {
    "path": "unix/saying-yes.md",
    "content": "# Saying Yes\n\nTired of being prompted for confirmation by command-line utilities? Wish you\ncould blindly respond 'yes' to whatever it is they are bugging you about?\nThe `yes` command is what you've been looking for.\n\n```\n$ yes | rm -r ~/some/dir\n```\n\nThis will respond `y` as `rm` asks for confirmation on removing each and\nevery file in that directory.\n\n`yes` is just as good at saying *no*. Give it `no` as an argument and it\nwill happily (and endlessly) print `no`.\n\n```\n$ yes no\n```\n\nh/t [Chris Erin](https://twitter.com/MCNormalMode)\n"
  },
  {
    "path": "unix/search-files-specific-to-a-language.md",
    "content": "# Search Files Specific To A Language\n\nThe `ack` command makes it easy to narrow the set of searched files to those\nof a specific programming language. For instance, if you have a rails\nproject and only want to search the ruby files, use the `--ruby` flag with\nyour `ack` command.\n\n```bash\n$ ack --ruby Active\n```\n\nWith the `--ruby` flag, I get a manageable number of results. Without it,\nnot so much.\n\n```bash\n$ ack --ruby Active | wc -l\n      26\n$ ack Active | wc -l\n    5253\n```\n\nSee `man ack` for more details.\n"
  },
  {
    "path": "unix/search-for-homebrew-packages-to-install.md",
    "content": "# Search For Homebrew Packages To Install\n\nLet's say we want to install the latest version of PostgreSQL with `brew`, but\nwe aren't sure either what formulas are available nor what the exact name would\nbe.\n\nWe can run a search with the `brew search` subcommand to get an idea of what is\navailable.\n\nIf I run this for even the shorthand of `postgres`, I get a useful set of\nresults showing me what versions I already have installed and what else is\navailable.\n\n```bash\n$ brew search postgres\n==> Formulae\ncheck_postgres    postgresql@11 ✔   postgresql@13     postgresql@15     postgrest         postgis\npostgresql@10     postgresql@12     postgresql@14     postgresql@16     qt-postgresql\n\n==> Casks\nnavicat-for-postgresql               postgres-unofficial                  sqlpro-for-postgres\npostbird                             postgrespreferencepane\n\nIf you meant \"postgres\" specifically:\npostgresql breaks existing databases on upgrade without human intervention.\n\nSee a more specific version to install with:\n  brew formulae | grep postgresql@\n```\n\nI can then go on to run `brew install postgresql@16` to get the latest.\n\nSee `brew search --help` for more details.\n"
  },
  {
    "path": "unix/search-history.md",
    "content": "# Search History\n\nOften times there is a very specific command you have entered into your bash\nprompt that you need to run again. You don't want to have to type it again\nand stepping manually through your history may be suboptimal if you typed it\nquite a while ago. Fortunately, there is a simple history search feature\nthat you can use in this kind of situation.\n\nHit `Ctrl+r` and then start typing a moderately specific search term. Your\nsearch history will be filtered by that term. Subsequent hitting of\n`Ctrl+r` will step forward through that filtered history. Once you find the\ncommand you are looking for, hit enter to execute it.\n"
  },
  {
    "path": "unix/search-man-page-descriptions.md",
    "content": "# Search Man Page Descriptions\n\nYou can use the `apropos` command with a keyword argument to search for that\nwords occurrence throughout all the man pages on your system. For instance,\ninvoking `apropos whatis` will bring up a list of entries including the\n`apropos` command itself.\n\nSee `man apropos` for more details.\n"
  },
  {
    "path": "unix/securely-remove-files.md",
    "content": "# Securely Remove Files\n\nIf you really want to make sure you have wiped a file from your hard drive,\nyou are going to want to use `srm` instead of `rm`. The man page for `srm`\ngives the following description:\n\n> srm  removes  each  specified file by overwriting, renaming, and truncating\n> it before unlinking. This prevents other people from undeleting or\n> recovering any information about the file from the command line.\n\nh/t Dillon Hafer\n"
  },
  {
    "path": "unix/see-where-asdf-gets-current-tool-version.md",
    "content": "# See Where asdf Gets Current Tool Version\n\nThe other day I [installed the latest version of\nRuby](ruby/install-latest-version-of-ruby-with-asdf.md) with `asdf`. I then set\nthat version (`3.4.1`) as the global default. However, when I then ran `ruby\n--version`, I was getting a `3.2.x` version. I checked my current project's\ndirectory and there was no `.tool-versions` file, so it wasn't being set by my\ncurrent directory.\n\n`asdf` looks up the current chain of directories until it encounters a\n`.tool-versions` file, so it must have been finding one somewhere up there, but\nbefore it was getting to the _global_ `.tool-versions` file. But where?\n\nThe `asdf current` command can tell us for a specific tool what the current\nversion it is set to and what file is giving that directive.\n\n```bash\nasdf current ruby\nruby            3.2.2           /Users/jbranchaud/code/.tool-versions\n```\n\nAs it turns out, I had a `.tool-versions` file in `$HOME/code` that was setting\nthat `3.2.x` Ruby version.\n\nI didn't want that directory controlling the Ruby version, so I removed `ruby`\nfrom that file. `asdf` was then able to traverse up to `$HOME/.tool-versions`\nfor the global setting.\n\nSee `asdf help` for more details.\n"
  },
  {
    "path": "unix/set-the-asdf-package-version-for-a-single-shell.md",
    "content": "# Set The asdf Package Version For A Single Shell\n\nGenerally when using [`asdf`](https://asdf-vm.com/), I set the global version\nfor a package/language to a good up-to-date default. And then I set `local`\nversions for specific projects which get written to the `.tool-versions` file.\n\nThere is another option that `asdf` supports for when you want to use a version\nwithout it being so _sticky_.\n\n```bash\n$ asdf shell postgres 12.3\n\n$ psql --version\npsql (PostgreSQL) 12.3\n\n$ postgres --version\npostgres (PostgreSQL) 12.3\n```\n\nWith the\n[`shell`](https://asdf-vm.com/#/core-manage-versions?id=set-current-version)\ncommand, I tell `asdf` to shim the specified package version just for this\nshell instance. If I switch back to another tab or open a new one, neither of\nthem will have been impacted by this shell-constrained setting.\n\nThis is handy for a one-off situation where you want to try something at a\nspecific version without impact the rest of your terminal session.\n"
  },
  {
    "path": "unix/shorten-ssh-commands-with-aliases.md",
    "content": "# Shorten SSH Commands With Aliases\n\nEach time I need to SSH into one of my remote app boxes, like _staging_, I run a\ncommand like the following:\n\n```bash\n$ ssh root@staging-box.com\n```\n\nInstead of having to remember the user and domain, I can add aliases to my\n`~/.ssh/config` file.\n\n```\n# Staging Server\nHost staging\n    HostName staging-box.com\n    User root\n\n# Sandbox Server\nHost sandbox\n    HostName sandbox-box.com\n    User root\n```\n\nThen I can SSH to each of these like so:\n\n```bash\n$ ssh staging\n\n$ ssh sandbox\n```\n\nThese aliases help a little bit, but they will help even more in situations\nwhere I need other settings configured for the SSH sessions like `Port` or\n`ForwardAgent`.\n"
  },
  {
    "path": "unix/show-a-file-preview-when-searching-with-fzf.md",
    "content": "# Show A File Preview When Searching With FZF\n\n[FZF](https://github.com/junegunn/fzf) by itself is a great way to fuzzy\nfind files. It gets even better when you can view a preview of a file before\nopening it up. The `--preview` flag lets you do just this.\n\nAdd a basic file preview with `cat`:\n\n```bash\n$ fzf --preview 'cat {}'\n```\n\nThe `{}` will get replaced a single-quoted string of the highlighted file.\n\nYou can spice up the preview a bit with color and line numbers using\n[`bat`](https://github.com/sharkdp/bat):\n\n```bash\n$ fzf --preview 'bat --color \"always\" {}'\n```\n\nThe `--color` flag tells `bat` to produce syntax highlighted output even\nthough it isn't in interactive mode.\n\nLastly, you can keep it performant by only showing the first 100 lines:\n\n```bash\n$ fzf --preview 'bat --color \"always\" --line-range 0:100 {}'\n```\n\nSee `man fzf` for more details.\n\n[source](https://github.com/dkarter/dotfiles/blob/master/vimrc#L362)\n"
  },
  {
    "path": "unix/show-disk-usage-for-the-current-directory.md",
    "content": "# Show Disk Usage For The Current Directory\n\nThe `du` utility can be used to show disk usage for a particular directory\nor set of directories. When used without any arguments, it will show the\ndisk usage for the current directory.\n\n```bash\n$ du\n80      ./.git/hooks\n8       ./.git/info\n256     ./.git/logs/refs/heads\n...\n```\n\nwith the `-h` command we can see it all in a human-readable format\n\n```bash\n$ du -h\n 40K    ./.git/hooks\n4.0K    ./.git/info\n128K    ./.git/logs/refs/heads\n```\n\nand to get an even clearer picture we can pipe that through `sort -nr`\n\n```bash\n$ du -h | sort -nr\n412K    ./vim\n352K    ./postgres\n340K    ./.git/logs\n216K    ./.git/logs/refs\n184K    ./ruby\n156K    ./unix\n148K    ./git\n...\n```\n\nThis sorts it numerically in reverse order putting the largest stuff at the\ntop.\n"
  },
  {
    "path": "unix/show-the-size-of-everything-in-a-directory.md",
    "content": "# Show The Size Of Everything In A Directory\n\nThe `ls` command will list everything in a given directory.  The `du`\ncommand is used to display disk usage statistics -- with the `-sh` flag, it\nwill display the file size in a human readable format.\n\nWe can combine these two commands with `xargs` to get a listing of the sizes\nof everything in a directory.\n\n```\nls | xargs du -sh\n```\n\nSee `man du` and `man xargs` for more details.\n"
  },
  {
    "path": "unix/show-tree-view-of-processes-and-subprocesses.md",
    "content": "# Show Tree View Of Processes And Subprocesses\n\nThough you can cobble together a command on a MacOS Unix system to output a\nhierarchical tree view of a parent process and its descendent subprocesses, it\nis easier to [`brew install pstree`](https://github.com/FredHucht/pstree) and\nuse that.\n\nHere is what I see when I run it for a _pid_ that corresponds to a `tmux`\nsession that I have running locally:\n\n```bash\n❯ pstree 61690\n-+= 61690 lastword tmux new-session -d -s TIL -c /Users/lastword/dev/jbranchaud/til\n |--= 63081 lastword /bin/zsh\n |-+= 11428 lastword zsh\n | \\-+= 48511 lastword pstree 61690\n |   \\--- 48512 root ps -axwwo user,pid,ppid,pgid,command\n |-+= 62345 lastword zsh\n | \\--= 06031 lastword claude\n |--= 62364 lastword /bin/zsh\n |-+= 62373 lastword zsh\n | \\--= 64407 lastword ssh my-app-staging\n |-+= 61115 lastword /bin/zsh\n | \\-+= 61579 lastword overmind start -f Procfile.dev\n |   \\--- 61586 lastword tmux -C -L overmind-my-app-abc123 new -n web -s my-app -P -F %overmind-process #{pane_id} web #{pane_pid} /var/folders/zc/abc123/T/overmin\n |--= 52237 lastword /bin/zsh\n |--= 82608 lastword /bin/zsh\n \\--= 10796 lastword /bin/zsh\n```\n\nI was looking for a frozen `claude` process that was part of this session. And I\nfound it about halfway down that list -- `06031`. Now I can run `kill` on that\nprocess as needed.\n\nFor some additional context, I initially found the _pid_ for the `tmux` session\nby running `ps aux | grep tmux` and looking through those results.\n"
  },
  {
    "path": "unix/skip-paging-if-output-fits-on-screen-with-less.md",
    "content": "# Skip Paging If Output Fits On Screen With Less\n\nThe `less` command can be used to display a file or the output of a command. It\nis sometimes referred to as a pager because it paginates text that won't fit\nonto a single screen.\n\n```bash\n$ ls | less\n```\n\nThis will list the files for the current directory with `less`.\n\nBy default it will even display a small amount of text output within the pager.\nIf you want `less` to output text that fits onto a single screen directly to\nthe terminal, you can pass the `-F` and `-X` flags.\n\n```bash\n$ ls | less -FX\n```\n\nThe `-F` flag tells `less` to exit if the output fits onto a single screen. The\n`-X` tells `less` to skip screen clearing.\n\nThis is handy if you want the output of a command to show up in your shell\nhistory.\n\nSee `man less` for more details.\n"
  },
  {
    "path": "unix/sort-in-numerical-order.md",
    "content": "# Sort In Numerical Order\n\nBy default, the `sort` command will sort things alphabetically. If you have\nnumerical input though, you may want a numerical sort. This is what the `-n`\nflag is for.\n\nIf I have a directory of files with numbered names, sort doesn't quite do\nthe job by itself.\n\n```bash\n$ ls | sort\n1.txt\n10.txt\n11.txt\n12.txt\n2.txt\n3.txt\n4.txt\n5.txt\n```\n\nwith the `-n` flag, I get the sort order I am looking for.\n\n```bash\n$ ls | sort -n\n1.txt\n2.txt\n3.txt\n4.txt\n5.txt\n10.txt\n11.txt\n12.txt\n```\n"
  },
  {
    "path": "unix/specify-the-language-for-a-file-with-bat.md",
    "content": "# Specify The Language For A File With Bat\n\nThe [`bat`](https://github.com/sharkdp/bat) utility is able to correctly\ninfer the language of most files it prints based on the file extension. In\nsome cases, you may want to specify a language other than the one it\nguesses.\n\nFor instance, here is a React file printed with `bat`:\n\n![bat with no CLI args](https://i.imgur.com/Jk0L6tB.png)\n\nThe `jsx` syntax doesn't look great because of the inferred language\nhighlighting doesn't account for it. We can get better results by telling\n`bat` that the file should be parsed as `JavaScript (Babel)`.\n\n![bat with language specified](https://i.imgur.com/yB1rYW4.png)\n\nBy including `--language=jsx` as a flag, `bat` uses a different language\nparser and the output is now what I'm looking for.\n"
  },
  {
    "path": "unix/ssh-escape-sequences.md",
    "content": "# SSH Escape Sequences\n\nIn [Killing A Frozen SSH Session](killing-a-frozen-ssh-session.md), I talked\nabout an escape sequence for breaking out of an SSH session when the pipe\nhas been broken. This isn't the only SSH escape sequence though. To see the\nothers, hit `<Enter>~?`. This displays a help list with all the other escape\nsequences.\n\n```\n> ~?\nSupported escape sequences:\n ~.   - terminate connection (and any multiplexed sessions)\n ~B   - send a BREAK to the remote system\n ~C   - open a command line\n ~R   - request rekey\n ~V/v - decrease/increase verbosity (LogLevel)\n ~^Z  - suspend ssh\n ~#   - list forwarded connections\n ~&   - background ssh (when waiting for connections to terminate)\n ~?   - this message\n ~~   - send the escape character by typing it twice\n(Note that escapes are only recognized immediately after newline.)\n```\n\nh/t Josh Davey\n"
  },
  {
    "path": "unix/ssh-with-a-specific-key.md",
    "content": "# SSH With A Specific Key\n\nWhen you SSH into another machine using public key authentication, the\nkey pair from either `~/.ssh/id_dsa`, `~/.ssh/id_ecdsa`, or `~/.ssh/id_rsa`\nis used by default. This is generally what you want. But what if the target\nserver is expecting to identify you with a different SSH key pair?\n\nThe `-i` option can be used with `ssh` to specify a different _identity\nfile_ when the default isn't what you want.\n"
  },
  {
    "path": "unix/ssh-with-port-forwarding.md",
    "content": "# SSH With Port Forwarding\n\nUse the `-L` flag with `ssh` to forward a connection to a remote server\n\n```\n$ ssh someserver -L3000:localhost:3000\n```\n"
  },
  {
    "path": "unix/switch-versions-of-a-brew-formula.md",
    "content": "# Switch Versions of a Brew Formula\n\nIf you've installed a couple versions of a program via brew and you'd like\nto switch from the currently linked version to the other installed version,\nyou can use the `switch` command. For instance, if you are on version\n`1.8.2` of `phantomjs` and you'd like to switch to `1.9.0`, you can simply\ninvoke:\n\n```\n$ brew switch phantomjs 1.9.0\n```\n\nMore generically:\n\n```\n$ brew switch <formula> <version>\n```\n"
  },
  {
    "path": "unix/tell-direnv-to-load-the-env-file.md",
    "content": "# Tell direnv To Load The Env File\n\nBy default [`direnv`](https://direnv.net/) looks for and evaluates the `.envrc`\nfile that appears in a given project directory. This default behavior is good\nfor things like setting certain path dependencies (e.g. a specific version of\nnode or postgres).\n\nTo the end of using `direnv` to set up the development environment, it can be\nuseful to have it also load the `.env` file into the current shell's\nenvironment.\n\nTo get `direnv` to do that, add this line to the `.envrc` file:\n\n```\ndotenv_if_exists .env\n```\n\nThis specific loads all the environment variables in `.env`. If there are other\nfiles, such as `.env.development` that need to be loaded in, those can be\nincluded with additional\n[`dotenv_if_exists`](https://direnv.net/man/direnv-stdlib.1.html#codedotenvifexists-ltdotenvpathgtcode)\ndeclarations.\n"
  },
  {
    "path": "unix/touch-access-and-modify-times-individually.md",
    "content": "# Touch Access And Modify Times Individually\n\nWhen running the `touch` command on an existing file:\n\n```bash\n$ touch README.md\n```\n\nThe `Access` and `Modify` times of that file will be updated to the current\ntime.\n\nYou can update these values individually with the `-a` and `-m` flags.\n\nTo update just the access time:\n\n```bash\n$ touch -a README.md\n```\n\nTo update just the modify time:\n\n```bash\n$ touch -m README.md\n```\n\nSee `man touch` for more details.\n"
  },
  {
    "path": "unix/transform-text-to-lowercase.md",
    "content": "# Transform Text To Lowercase\n\nI was reading through [`setup.sh` in\ndkarter/dotfiles](https://github.com/dkarter/dotfiles/blob/master/setup.sh#L7-L9)\nand noticed this function for converting a given bit of text to all lowercase\nletters.\n\n```bash\nlowercase() {\n  echo \"$1\" | sed \"y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/\"\n}\n```\n\nIt's an interesting use of `sed`, but it made me wonder if `tr` was a better\ntool for this job. I looked into it and `tr` is better suited to the task, more\nexpressive, and also compatible across Mac and Linux.\n\nHere is what it looks like with `tr`:\n\n```bash\nlowercase() {\n  echo \"$1\" | tr '[:upper:]' '[:lower:]'\n}\n```\n\nThis has the added benefit of working across all kinds of UTF-8 characters.\n\n```bash\n$ echo \"ΑΛΦΑΒΗΤΟ ΕΛΛΑΔΑ\" | tr '[:upper:]' '[:lower:]'\nαλφαβητο ελλαδα\n```\n\nSee `man tr` for more details.\n"
  },
  {
    "path": "unix/type-fewer-paths-with-brace-expansion.md",
    "content": "# Type Fewer Paths With Brace Expansion\n\nBash has a feature called _brace expansion_ that allows us to do a kind of\nshorthand when writing out file paths. We can specify multiple variants\ncomma-separated between curly braces and they'll each be expanded into separate\narguments.\n\nIt's easier to understand this by seeing it. If we type the following (don't\nhit `Enter` yet):\n\n```bash\n$ mkdir src/{one,two,three}\n```\n\nAnd then hit _Tab_:\n\n```bash\n$ mkdir src/one src/two src/three\n```\n\nBash uses the portion in braces to expand into separate arguments. The part\noutside the braces gets reused for each. That's where we get some savings from\ntyping out the same path each time.\n\nHere is another example where we use `mv` to rename a file deeply nested in our\nproject:\n\n```bash\n$ mv projects/project1/src/app/utils/{names,constants}.js\n```\n\nWe don't even have to _Tab_ it out. We can hit _Enter_ directly and `mv` gets\nboth arguments.\n\nSimilarly, how about we change the extension of our renamed file:\n\n```bash\n$ mv projects/project1/src/app/utils/constants.{js,ts}\n```\n\nI've always found this feature most useful with paths and filenames, but you\ncan do brace expansion with any arguments.\n\n```bash\n$ echo 1{3,1,6,4,9,2,7,5}\n13 11 16 14 19 12 17 15\n```\n\n[source](https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html)\n"
  },
  {
    "path": "unix/undo-changes-made-to-current-terminal-prompt.md",
    "content": "# Undo Change Made to Current Terminal Prompt\n\nI frequently use a variety of ASCII command characters like `ctrl-u` to delete\nthe entire line or `ctrl-a` to jump to the front of a long line so I can make\nsome edits toward that side of the command or `ctrl-e` to jump to the end of\nthe command for the same reason. I sometimes even use `ctrl-k` to delete\neverything after the cursor to the end of the line.\n\nWhat I didn't realize until now is that any of those commands the modify the\ncurrent line of the termianl prompt plus regular typing and hitting the\nbackspace are all _undoable_.\n\nSo, if I just wiped out half the line (with `ctrl-k`) and I immediately regret\nit, I can restore it with `ctrl-_`. The system keeps of history of the actions\nyou've taken, so you can keep hitting `ctrl-_` to undo even further.\n\nThe `ctrl-/` command does the same, per GNU's [Undo Changes in the Emacs\ndocs](https://www.gnu.org/software/emacs/manual/html_node/emacs/Basic-Undo.html).\n\n[source](https://jvns.ca/ascii)\n"
  },
  {
    "path": "unix/undo-some-command-line-editing.md",
    "content": "# Undo Some Command Line Editing\n\nWhen using some of the fancy command line editing shortcuts, such as\n`ctrl-u`, you may end up erroneously changing or deleting part of the\ncurrent command. Retyping it may be a pain or impossible if you've forgotten\nexactly what was changed. Fortunately, bash's command line editing has undo\nbuilt in. Just hit `ctrl-_` a couple times to get back to where you want to\nbe.\n\nh/t Chris Erin\n\n[source](https://www.gnu.org/software/bash/manual/bashref.html#Command-Line-Editing)\n"
  },
  {
    "path": "unix/unrestrict-where-ripgrep-searches.md",
    "content": "# Unrestrict Where ripgrep Searches\n\nOne of the conveniences of [`rg`\n(ripgrep)](https://github.com/BurntSushi/ripgrep) is that by default it doesn't\nsearch in places you probably don't want it to search. That means it ignores\nanything specified by your `.gitignore` file, it excludes hidden files and\ndirectories (dotfiles, e.g. `.git/` or `.env`), and it excludes binary files.\n\nThese restrictions can be incrementally undone as needed using the `-u` flag.\n\nThe `-u` flag on its own will remove the ignored files restriction. This is\nequivalent to the `--no-ignore` flag.\n\n```bash\n$ rg -u pattern\n```\n\nAdding an additional `u` (`-uu`) to that flag will remove both the ignored files and\nhidden files restrictions. This is a shorthand equivalent to both `--no-ignore`\nand `--hidden`.\n\n```bash\n$ rg -uu pattern\n```\n\nAdding one more `u` (`-uuu`) will additionally remove the binary file\nrestriction. Equivalent to those other two flags plus `--text`.\n\n```bash\n$ rg -uuu pattern\n```\n\n[source](https://github.com/BurntSushi/ripgrep/blob/master/GUIDE.md#automatic-filtering)\n"
  },
  {
    "path": "unix/update-package-versions-known-by-asdf-plugin.md",
    "content": "# Update Package Versions Known By asdf Plugin\n\nWhen you run `asdf list-all ruby`, asdf will list all the package versions it\nknows about for that plugin. This list is based on when the plugin was most\nrecently installed or updated. If it has been a while, there are likely new\nversions that asdf doesn't know about.\n\nThis list can be updated with the [`plugin-update`\ncommand](https://asdf-vm.com/manage/plugins.html#update):\n\n```bash\n$ asdf update-plugin ruby\n$ asdf plugin-update ruby\n```\n\nNow, the next time you run `asdf list-all ruby`, you'll have an up-to-date\nlisting of available package versions.\n"
  },
  {
    "path": "unix/use-fzf-to-change-directories.md",
    "content": "# Use fzf To Change Directories\n\nWhen you install fzf (e.g. `brew install fzf`), you can also install\ncompletions and a few keybindings by running the `/usr/local/opt/fzf/install`\nbinary.\n\nIncluded with the keybindings is `Alt+c` which opens an fzf prompt for the\ndirectories nested under your current directory. You can type into the prompt\nto narrow down the results with fzf's fuzzy-finding capabilities. When you see\nthe directory you wan, you can use the arrows to navigate over it and then hit\nend. You'll be `cd`'ed into that directory.\n\nOn my Mac, the `Alt` key is the `Option` key. Hitting `Opt+c` outputs the `ç`\ncharacter instead of opening this fzf prompt. It turns out, you can\nalternatively hit `Esc+c` to trigger this prompt.\n"
  },
  {
    "path": "unix/use-negative-lookbehind-matching-with-ripgrep.md",
    "content": "# Use Negative Lookbehind Matching With ripgrep\n\nThe most straightforward way to use `ripgrep` is to hand it a pattern. It will\ntake that pattern and move forward through each file trying to find matches.\n\n```bash\n$ rg 'TwilioClient\\.new'\n```\n\nThat will find all occurrences of `TwilioClient.new` in available project files.\n\nWhat if that pattern is too permissive though? That is going to match on\noccurrences of `TwilioClient.new` as well as things like\n`LoggingTwilioClient.new`. If we want to exclude the latter, there are a few\nways to do that. One of them being the use of [the _negative lookbehind_ regex\nfeature](https://www.pcre.org/current/doc/html/pcre2syntax.html#SEC23) that is\navailable with PCRE2 (Perl-Compatible Regular Expressions).\n\nA _negative lookbehind_ is like a standard pattern. We look forward through the\ndocument for the base pattern (like `TwilioClient\\.new`). However, once we find\nthat match, we then look back at the previous characters and if they match our\nnegative lookbehind pattern, then it is no longer a positive match.\n\nWe can use one of the following to forms to achieve this:\n\n```\n  (?<!...)                    )\n  (*nlb:...)                  ) negative lookbehind\n  (*negative_lookbehind:...)  )\n```\n\nFor instance, here is what this looks like for our example:\n\n```bash\n$ rg -P '(?<!Logging)TwilioClient\\.new'\n```\n\nNote: we have to use the `-P` flag to tell `ripgrep` that we are using PCRE2\nsyntax. Otherwise, it assumes a simpler regex syntax that doesn't support\n_negative lookbehind_.\n\nSee `man rg` for more details.\n"
  },
  {
    "path": "unix/use-regex-pattern-matching-with-grep.md",
    "content": "# Use Regex Pattern Matching With Grep\n\nThe `grep` command supports perl-flavored regular expression pattern matching.\nRather than grepping for specific words, you can use regex with grep to find\npatterns throughout a text or command output.\n\nAs an example, I can list all Ruby versions available for install with\n[`asdf`](https://github.com/asdf-vm/asdf) using the following command.\n\n```bash\n$ asdf list-all ruby\n```\n\nThis produces a ton of lines of output including versions of `jruby` and\n`truffleruby`.\n\nI can use grep to filter this list down to the MRI versions which all start\nwith a digit (e.g. `2.6.5`).\n\n```bash\n$ asdf list-all ruby | grep \"^[[:digit:]]\"\n```\n\nThat regex says, find all lines that begin (`^`) with a number (`[[:digit:]]`).\nThis means grep will filter down the output to things like `1.9.3-p551`,\n`2.6.5`, and `2.7.0-preview2` whereas it will exclude `truffleruby-19.0.0` and\n`jruby-9.2.9.0`.\n\n[source](https://www.digitalocean.com/community/tutorials/using-grep-regular-expressions-to-search-for-text-patterns-in-linux)\n"
  },
  {
    "path": "unix/view-a-web-page-in-the-terminal.md",
    "content": "# View A Web Page In The Terminal\n\nThere are a number of programs out there that allow you to view a web page\nfrom right within the terminal. These text-based browsers are great for\nviewing pages that make basic use of html without relying on JavaScript for\nfancy user interactions, such as the docs page for a language.\n\nOne such program is `link`. If you don't already have it, you can install it\nwith something like `homebrew`. Then run `links` with any URL for a\nmagnificent, ad-free experience:\n\n```\nlinks http://www.postgresql.org/docs/current/static/functions-string.html\n```\n\nh/t Jack Christensen\n"
  },
  {
    "path": "unix/view-the-source-for-a-brew-formula.md",
    "content": "# View The Source For A Brew Formula\n\n[Homebrew](https://brew.sh/) uses formulas to know how to install things. If\nyou want to see what a given thing's formula file (written in Ruby) looks like,\nthere are two ways to get at it.\n\nIf you already have the thing installed, the formula is available on your\nmachine. You can `cat` it to stdout with `brew cat`.\n\n```bash\n❯ brew cat bat\n```\n\nHere is what `bat` looks like:\n\n```ruby\nclass Bat < Formula\n  desc \"Clone of cat(1) with syntax highlighting and Git integration\"\n  homepage \"https://github.com/sharkdp/bat\"\n  url \"https://github.com/sharkdp/bat/archive/v0.17.1.tar.gz\"\n  sha256 \"16d39414e8a3b80d890cfdbca6c0e6ff280058397f4a3066c37e0998985d87c4\"\n  license \"Apache-2.0\"\n\n  depends_on \"rust\" => :build\n\n  uses_from_macos \"zlib\"\n\n  def install\n    ENV[\"SHELL_COMPLETIONS_DIR\"] = buildpath\n    system \"cargo\", \"install\", *std_cargo_args\n\n    assets_dir = Dir[\"target/release/build/bat-*/out/assets\"].first\n    man1.install \"#{assets_dir}/manual/bat.1\"\n    fish_completion.install \"#{assets_dir}/completions/bat.fish\"\n    zsh_completion.install \"#{assets_dir}/completions/bat.zsh\" => \"_bat\"\n  end\n\n  test do\n    pdf = test_fixtures(\"test.pdf\")\n    output = shell_output(\"#{bin}/bat #{pdf} --color=never\")\n    assert_match \"Homebrew test\", output\n  end\nend\n```\n\nIf you don't have the thing installed, you'll have to access the formula\nremotely.\n\n```bash\n❯ brew info --github bat\n```\n\nThis will open up the formula on GitHub in your default browser.\n"
  },
  {
    "path": "unix/watch-the-difference.md",
    "content": "# Watch The Difference\n\nThe `watch` command is a simple way to repeatedly run a particular command.\nI'll sometimes use it to monitor the response from some endpoint. `watch`\ncan make monitoring responses even easier when the `-d` flag is employed.\nThis flag instructs `watch` to highlight the parts of the output that are\n*different* from the previous run of the command.\n\nSo if I run\n\n```\n$ watch -d curl -LIs localhost:3000\n```\n\nI can easily see if the http status of the request changes.\n"
  },
  {
    "path": "unix/watch-this-run-repeatedly.md",
    "content": "# Watch This Run Repeatedly\n\nI usually reach for a quick bash for loop when I want to run a particular\nprocess a bunch of times in a row. The `watch` command is another way to\nrun a process repeatedly.\n\n```\nwatch rspec spec/some/test.rb\n```\n\nThe default is 2 seconds in between subsequent executions of the command.\nThe period can be changed with the `-n` flag though:\n\n```\nwatch -n 2 rspec spec/some/test.rb\n```\n"
  },
  {
    "path": "unix/where-are-the-binaries.md",
    "content": "# Where Are The Binaries?\n\nWhen I want to know where an executable is, I use `which` like so:\n\n```\n$ which rails\n/Users/jbranchaud/.gem/ruby/2.1.4/bin/rails\n```\n\nThat is the rails binary on my path that will be used if I enter a rails command.\n\nHowever, with something like rails, there may be multiple versions on your\npath. If you want to know where all of them are, you can use `where`, like\nso:\n\n```\n$ where rails\n/Users/jbranchaud/.gem/ruby/2.1.4/bin/rails\n/Users/jbranchaud/.rubies/2.1.4/bin/rails\n/usr/bin/rails\n```\n"
  },
  {
    "path": "unix/xargs-default-command-is-echo.md",
    "content": "# xargs Default Command Is echo\n\nWith the `fd` command, all the found files are output line by line like so.\n\n```bash\n❯ fd '.*.md' --max-depth=1\nCONTRIBUTING.md\nREADME.md\nTODO.md\nbuilt-in-commands.md\nnewsletter.md\ntailwind.md\n```\n\nI can normalize the whitespace, squishing everything to be separated by single\nspaces by piping it to `xargs`. This is equivalent to call `xargs` with `echo`.\nThat is because `echo` is the default command that `xargs` uses when another\ncommand isn't given.\n\n```bash\n❯ fd '.*.md' --max-depth=1 | xargs\nCONTRIBUTING.md README.md TODO.md built-in-commands.md newsletter.md tailwind.md\n\n❯ fd '.*.md' --max-depth=1 | xargs echo\nCONTRIBUTING.md README.md TODO.md built-in-commands.md newsletter.md tailwind.md\n```\n\nWe can see further evidence of that by using the `-n` flag with `2` to have it\nprocess results two at a time. In either case, each pair of file names is\necho'd before the next two are processed.\n\n```bash\n❯ fd '.*.md' --max-depth=1 | xargs -n2\nCONTRIBUTING.md README.md\nTODO.md built-in-commands.md\nnewsletter.md tailwind.md\n\n❯ fd '.*.md' --max-depth=1 | xargs -n2 echo\nCONTRIBUTING.md README.md\nTODO.md built-in-commands.md\nnewsletter.md tailwind.md\n```\n\nSee `man xargs` for more details, as well as this [excellent\narticle](https://abhinavg.net/2022/06/04/xargs-spaces/).\n"
  },
  {
    "path": "unix/xargs-ignores-alias-substitution-by-default.md",
    "content": "# xargs Ignores Alias Substitution By Default\n\nI have a number of aliases set up in my shell's RC file. For instance, I use\n`nvim` as my main editor, but because of muscle memory, I've aliased `vim` to\n`nvim`.\n\n```bash\n❯ alias vim\nvim=nvim\n```\n\nSo, I was surprised when I ran the following `xargs` command.\n\n```bash\n❯ rg 'some pattern' -l | xargs vim\n```\n\nIt opened the matching files in `vim` rather than `nvim`.\n\nThe reason for this is that `xargs` is a separate function that does not have\nan internal concept of aliases that need to be substituted.\n\nThere is, however, a trick built in to `alias` that we can use. By leaving a\ntrailing space in an alias, we tell the shell to check for an alias\nsubstitution to expand in the following word.\n\nSo, I can alias `xargs` to `'xargs '` and it will respect my `vim` alias.\n\n```\n❯ alias xargs='xargs '\n```\n\n[source](https://unix.stackexchange.com/a/244516/5916)\n"
  },
  {
    "path": "vercel/add-web-server-layer-redirects.md",
    "content": "# Add Web Server Layer Redirects\n\nPeople create links and bookmark URLs. Content, for a variety of reasons, has\nto move from one place to another. For everyone's sake, you don't want to break\nthe URLs that people have come to rely on.\n\nYou need to setup some\n[redirects](https://vercel.com/docs/configuration#project/redirects).\n\nThough a [Next.js](https://nextjs.org/) app is just frontend code, when\ndistributed through [Vercel](https://vercel.com/), you can include some\nconfiguration of the web server layer.\n\nAdd the `vercel.json` file to the top-level directory of your Next.js project\nand then include any needed redirect rules.\n\n```json\n{\n  \"redirects\": [\n    {\n      \"source\": \"blog/old-blog-post-name\",\n      \"destination\": \"blog/new-blog-post-name\"\n    },\n    {\n      \"source\": \"/store\",\n      \"destination\": \"store.example.com\"\n    }\n  ]\n}\n```\n\nIn the first rule, one path is redirected to another for the same domain. In\nthe second rule, the path is redirected to an external URL.\n\nBy default, these redirects get a [308 status\ncode](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/308).\n"
  },
  {
    "path": "vercel/deploy-an-app-without-pushing-an-empty-commit.md",
    "content": "# Deploy An App Without Pushing An Empty Commit\n\nThe [Vercel CLI](https://vercel.com/docs/cli) allows you to make updated\ndeployments of an app right from the command line.\n\nMany providers require you to push a new commit to the main branch to trigger a\ndeployment. If there are changes, you can trigger a deployment by pushing\nthese. If there aren't changes, but you want to re-deploy what is already\nthere, then you have to create an empty commit and push that.\n\nWith the [Vercel CLI](https://vercel.com/docs/platform/deployments#vercel-cli),\nyou can re-deploy your app without pushing commits. You do this by including\nthe `--force` flag.\n\nTo re-deploy the preview environment:\n\n```bash\n$ vercel --force\n```\n\nTo re-deploy the production environment:\n\n```bash\n$ vercel --prod --force\n```\n"
  },
  {
    "path": "vercel/naming-of-the-vercel-config-file.md",
    "content": "# Naming Of The Vercel Config File\n\n[Vercel](https://vercel.com/), the company/service, used to be called Now. With\nany renaming comes some consistency challenges, even at the level of software.\n\nThe naming of the file for configuring your project used to be `now.json`. It\nis _now_ `vercel.json`.\n\nFor [backwards compatibility\nreasons](https://vercel.com/docs/platform/frequently-asked-questions#conflicting-configuration-files),\nyou can still use either. You cannot and should not have both though.\n\nIf you're working with an existing project that uses `now.json`. It is fine to\ncontinue with that naming. It may eliminate some future confusion if you are to\nrename it to `vercel.json`. If you're starting a new project, I'd recommend\nusing `vercel.json`. All the documentation you'll read uses this newer naming\nconvention.\n"
  },
  {
    "path": "vercel/pin-specific-pnpm-version-for-builds.md",
    "content": "# Pin Specific pnpm Version For Builds\n\nVercel recognizes when [a project contain a `pnpm-lock.yaml`\nfile](https://vercel.com/changelog/projects-using-pnpm-can-now-be-deployed-with-zero-configuration)\nand will automatically use [`pnpm`](https://pnpm.io/) for builds of that\nproject.\n\nIt looks for [the `lockfileVersion` in `pnpm-lock.yaml` to determine what major\nversion of `pnpm` to\ninstall](https://vercel.com/docs/concepts/deployments/configure-a-build#install-command).\nIf the `lockfileVersion` is `5.4`, then it will use the latest pnpm v7.\nOtherwise it will fallback to the latest pnpm v6.\n\nThat's the extent of the control you have over the `pnpm` version. That is,\nunless you are to use [this experimental corepack\nfeature](https://vercel.com/docs/concepts/deployments/configure-a-build#corepack).\nSet the `ENABLE_EXPERIMENTAL_COREPACK` environment variable to `1` in your\nproject's _Environment Variables_ under _Settings_.\n\nThen specify the `pnpm` version with the `packageManager` key in your\n`package.json`.\n\n```json\n{\n  \"packageManager\": \"pnpm@7.13.2\"\n}\n```\n\nEven though the current latest is `7.13.5`, Vercel will see the Corepack\nenvironment variables and the `packageManager` version and use `7.13.2`\ninstead.\n\nSee [this PR](https://github.com/skillrecordings/products/pull/535) and [this\nissue](https://github.com/prisma/prisma/issues/12921#issuecomment-1284425847)\nfor more details.\n"
  },
  {
    "path": "vercel/share-development-environment-variables-via-cli.md",
    "content": "# Share Development Environment Variables Via CLI\n\n[Vercel](https://vercel.com/)'s web UI as well as it's CLI make it easy to\nstore and manage environment variables for your different environments. It is\nalso safe because it encrypts them.\n\nYou and your team can safely access the environment variables for the\ndevelopment environment with the following CLI command.\n\n```\n$ vercel env pull\n```\n\nAssuming you have already connected with and authenticated yourself for the\ncurrent project, this command will fetch the env vars and write them to the\n`.env` file.\n\nIf the env vars are ever updated, you can run the command again and it will\nrewrite the local file.\n"
  },
  {
    "path": "vim/aborting-git-commits-and-rebases.md",
    "content": "# Aborting Git Commits And Rebases\n\nWhen you are amending a commit or doing an interactive rebase of a series of\ncommits, Vim will be open to a buffer full of content related to the\nrespective action. Normally, you'll make some changes, save the buffer, and\nthen quit -- Git will take over from there by processing the commit or\nrebase.\n\nWhat if you find yourself in this situation and you want to cancel the commit or\nrebase? Simply quitting with text already in the buffer will be interpreted\nby Git as a signal to go ahead and process the commit/rebase.\n\nSo, how do we quit without confirming the action?\n\nVim allows you to quit with an error code.\n\n```\n:cq\n```\n\nThis means that irrespective of the content of the buffer, Vim will signal\nto Git with an error code to not process the commit or rebase, effectively\naborting the action.\n\nSee `:help cq` for more details.\n"
  },
  {
    "path": "vim/absolute-and-relative-line-numbers.md",
    "content": "# Absolute And Relative Line Numbers\n\nBy default, vim uses absolute line numbering. This can be turned off with\n`set nonumber` or more concisely `set nonu`. Turn it back on with `set nu`.\nGet more details at `:h number`.\n\nVim also supports relative line numbers. If you'd rather use relative line\nnumbers, first turn off absolute line numbers (`set nonu`) and then turn on\nrelative line numbers with `set relativenumber`. Shave off some characters\nwith `set rnu`. As you might expect, you can turn off relative numbering\nwith `set nornu`.\n\nSee `:h relativenumber` for more details.\n"
  },
  {
    "path": "vim/add-a-file-without-loading-it.md",
    "content": "# Add A File Without Loading It\n\nGenerally, when you interact with files (e.g. `:e some-file.txt`), you are\nboth adding it to the buffer list and loading the contents of the file as a\nseparate buffer. The `:bad` command allows you to add a file to the buffer\nlist without loading it. For instance, you can add your `README.md` to the\nbuffer list and leave the current buffer in focus with:\n\n```\n:bad README.md\n```\n\nThis command seems particularly useful for scripting the setup of an initial\nvim environment or preparing for a `:bufdo` command.\n"
  },
  {
    "path": "vim/add-custom-dictionary-words.md",
    "content": "# Add Custom Dictionary Words\n\nWhen editing a file with `spell` turned on, you may find vim highlighting\nsome of your content in red. This red highlighting indicates a misspelling.\nSure, these words technically aren't going to show up in something like the\nMerriam-Webster dictionary, but as far as you are concerned, they are words.\nThey are part of your internal, shared language. The word *admin* is a great\nexample. Why not just tell vim once and for all that such words are valid.\n\nYou can do just that by moving your cursor over the *misspelled* word and\nhitting `zg`. That will add it to the `spellfile`, a list of words, which\nvim includes in its spell checking. This means vim will no longer highlight\nthat word red.\n"
  },
  {
    "path": "vim/all-the-ways-to-write-and-quit-in-vim.md",
    "content": "# All The Ways To Write And Quit In Vim\n\nThere are a bunch of different ways to write files, to quit out of a Vim\nsession, and to write and quit.\n\nThe standard is `:wq` to write to the file and quit. There is `:xall` which\nwill write changes to all buffers and quit.\n\n`:q`, `:q!`, and `ZQ`—the latter being a normal mode command—are all ways of\nquitting Vim. The first will warn of unsaved changes. The other two will\ndiscard unsaved changes.\n\nAnother favorite of mine, when bailing on a `git commit`, is `:cq`.\n\nThese and more can be found in the help files by running `:h Q_wq`.\n"
  },
  {
    "path": "vim/almost-the-end-of-the-line.md",
    "content": "# Almost The End Of The Line\n\nIf you are visually selecting from the cursor to the end of the line, you\nwill probably hit:\n\n```\nv$\n```\n\nThis isn't always ideal though because the visual selection includes the\nnewline character at the end of the line. If instead you'd like to motion to\nthe last non-blank character on the line you can use the `g_` motion. This\nis great for deleting to the end of the line.\n\n```\ndg_\n```\n\nSee `:h g_` for more details.\n\nh/t Dorian Karter\n"
  },
  {
    "path": "vim/alternate-files-with-vim-rails.md",
    "content": "# Alternate Files With vim-rails\n\nIf you are doing a good job of testing all the code you write in a rails\nproject, then most of your code files should be paired with test (or spec)\nfiles. You can think of these as alternate files. The alternate file of\n`user.rb` is `user_spec.rb` and vice versa.\n\nThe [`vim-rails`](https://github.com/tpope/vim-rails) plugin makes it easy\nto jump back and forth between alternate files. Enter `:A` and you will go\nto the alternate file of the current file. This makes a common navigation\npath for rails projects all the more efficient.\n"
  },
  {
    "path": "vim/always-keep-the-gutter-open.md",
    "content": "# Always Keep The Gutter Open\n\nVim has an area off to the left where it can display information for specific\nlines in a buffer. This is sometimes called the gutter or the tray. In the Vim\nhelp files it is called the `signcolumn`. That names makes sense. It is a\ncolumn to the left of the line numbers where _signs_ can be shown to indicate\ngit status, type errors, and lint warnings.\n\nBy default, the `signcolumn` is set to `auto` which means that as a sign\nappears, the column shifts open moving the editor text with it. When you've\nresolved whatever cause the sign to disappear, everything will shift back to\nthe left.\n\nThis jumpy layout shift can be avoiding by keeping the `signcolumn` always\nopen. That's done by setting it to `yes` in your `~/.vimrc`.\n\n```vim\nset signcolumn=yes\n```\n\nSee `:h signcolumn` for more details.\n"
  },
  {
    "path": "vim/amend-commits-with-fugitive.md",
    "content": "# Amend Commits With Fugitive\n\nLet's assume you are using [fugitive](https://github.com/tpope/vim-fugitive)\nfor Git integration with Vim. You've made a commit that you want to amend.\nFirst, stage any changes that should be included in the amend with `:Gstatus` or\n`:Ge:`. Then hit `ca` to open up the commit window for amending. Save and\nquit when you are finished.\n\nWant to view the aggregate changes? Open the commit window for amending in\nverbose mode with `cva`.\n\nSee the [vim-fugitive\ndocs](https://github.com/tpope/vim-fugitive/blob/master/doc/fugitive.txt)\nfor more details.\n"
  },
  {
    "path": "vim/backspace-options.md",
    "content": "# Backspace Options\n\nThe `backspace` option determines the behavior of pressing the backspace key\n(`<BS>`). By default, Vim's `backspace` option is set to an empty list.\nThere are three values that can be added that each independently alter the\nbehavior of the backspace key. These are `indent`, `eol`, and `start`.\n\nWhen `indent` is included, you can backspace over indentation from\n`autoindent`. Without it, Vim will not allow you to backspace over\nindentation.\n\nWhen `eol` is included, you can backspace over an end of line (eol)\ncharacter. If the cursor is at the first position of a line and you hit\nbackspace, it will essentially be joined with the line above it. Without\n`eol`, this won't happen.\n\nWhen `start` is included, you can backspace past the position where you\nstarted Insert mode. Without `start`, you can enter Insert mode, type a bit,\nand then when backspacing, only delete back as far as the start of Insert\nmode.\n\nThe `backspace` default is absurd, you are going to want to add all of the\nabove to your Vim settings.\n\nSee `:h 'backspace'` for more details.\n"
  },
  {
    "path": "vim/beginning-and-end-of-previous-change.md",
    "content": "# Beginning And End Of Previous Change\n\nYou can jump to the beginning of the previous change with the `[` mark by\nhitting `'[` from normal mode. Similarly, you can jump to the end of the\nprevious change with the `]` mark by hitting `']`.\n\nText that was just pasted is also considered a change. Thus, hitting `'[`\nand `']` will jump to the beginning and end, respectively, of the text that\nwas just pasted into the buffer.\n\nSee `:h '[` and `:h ']` for more details.\n"
  },
  {
    "path": "vim/blank-lines-above-and-below.md",
    "content": "# Blank Lines Above And Below\n\nGenerally when I want to add a line above or below the line that the cursor\nis on, I use `O` and `o`, respectively. This has a couple potential\ndrawbacks. First and most prominent, the cursor is moved to the new line and\nleft in insert mode. Usually, I'd like to remain in normal mode and stay on\nthe current line. Second, these commands will emulate indentation and other\nformatting rules. This is either exactly what you want or a bit of an\nannoyance.\n\nThe [`vim-unimpaired` plugin](https://github.com/tpope/vim-unimpaired)\nprovides an alternative worth adding to your toolbelt. By hitting `[<space>`\nand `]<space>`, a new line will be opened above and below the current line,\nrespectively. Additionally, it leaves you in normal mode, keeps the cursor\non the current line, and moves the cursor to the first non-indented\ncharacter. In the case of performing this command in the midst of a comment\nin a source code file, neither the indentation nor the comment character\nwill be propagated onto the new line.\n\nHold on to `O`/`o` and `[<space>`/`]<space>` and know the difference. You'll\nlikely need each of them from time to time.\n\nh/t Josh Davey\n"
  },
  {
    "path": "vim/breaking-the-undo-sequence.md",
    "content": "# Breaking The Undo Sequence\n\nGenerally, the sequence of undo-able actions is segmented by command. When\nentering Insert mode, everything typed until exiting Insert mode is part of\na single undo-able segment. If you are going to be typing in Insert mode for\na while though, you may want to break it up a bit. Without leaving Insert\nmode, hit `ctrl-g u` to mark a break in the sequence of undos.\n\nFor example, starting in Normal mode and then typing\n`iabc<CTRL-G>udef<CTRL-G>ughi<ESC>` will leave the buffer with:\n\n```\nabcdefghi\n```\n\nHitting `u` once will leave the buffer with:\n\n```\nabcdef\n```\n\nHitting `u` again:\n\n```\nabc\n```\n\nHitting `ctrl-r`:\n\n```\nabcdef\n```\n\nSee `:h i_CTRL-G_u` for more details.\n"
  },
  {
    "path": "vim/buffer-time-travel.md",
    "content": "# Buffer Time Travel\n\nVim allows you to go to an *earlier* text state for a buffer with\n`:earlier`. For instance, if you want to see the state of the buffer from 10\nminutes ago:\n\n```\n:earlier 10m\n```\n\nSimilarly, you can move back toward the present text state of the buffer\nwith `:later`. If 10 minutes earlier was too far, you can come back 5\nminutes like so:\n\n```\n:later 5m\n```\n\nI encountered these in [Nick Nisi's 'Vim +\nTmux'](https://www.youtube.com/watch?v=5r6yzFEXajQ) talk.\n"
  },
  {
    "path": "vim/build-and-install-a-go-program.md",
    "content": "# Build And Install A Go Program\n\nWith the [`vim-go`](https://github.com/fatih/vim-go) plugin, Vim gets all\nkinds of support for working with a Go project. Generally, with a Go\nproject, you have to run `go build` to compile the project and if that is\nsuccessful, you can run `go install` to put the executable binary on the\n`$GOPATH`.\n\nThis plugin allows you to tighten the feedback loop. You can build right\nwithin your Vim session using\n\n```\n:GoBuild\n```\n\nwhich will alert you to any compilation errors.\n\nYou can then install the program using\n\n```\n:GoInstall\n```\n\nYour program is now ready to run.\n\nIt's worth noting that this plugin will also notify you about syntax errors\nwhen you save, if they exist.\n"
  },
  {
    "path": "vim/bypass-on-save-tooling-when-writing-file.md",
    "content": "# Bypass On-Save Tooling When Writing File\n\nEvery once in a while I run into an issue where my code formatters or linters\nare misconfigured for a project. I try to save a file and it applies formatting\nthat I don't want. Or in an extreme case, the error ouput of the tool is what\noverwrites the file.\n\nI need to troubleshoot my dev tooling eventually, but I don't want to get\nsidetracked at the moment. I just want to save the file. What can I do?\n\nTools like linters and code formatters are typically hooked up to Vim via\nautocommands on certain actions like `FileWrite*` or `BufWrite*`. We can\nexecute a Vim command like writing a file (`w`) while disregarding autocommands\nlike so:\n\n```vim\n:noautocmd w\n```\n\nor, write and quit:\n\n```vim\n:noautocmd wq\n```\n\nThis disables all autocommands for this one command. The file gets saved and\nthe misconfigured formatters and linters don't clobber the changes you\nintended.\n\nSee `:h noautocmd` for more details.\n"
  },
  {
    "path": "vim/case-aware-substitution-with-vim-abolish.md",
    "content": "# Case-Aware Substitution With vim-abolish\n\nSubstitution in vim is, by default, case-sensitive. Adding the `i` `s-flag`\nmakes it case-insensitive.\n[`vim-abolish`](https://github.com/tpope/vim-abolish), on the other hand, lets\nyou perform a case-insensitive substitution that preserves three case\nvariants (foo, Foo, and FOO). Substitution with `vim-abolish` can be\nperformed with `Subvert` or `S`.\n\nFor instance, `:%S/blog/article/g` will turn\n\n```\nblog Blog bLOg BLOG\n```\n\ninto\n\n```\narticle Article bLOg ARTICLE\n```\n\nInstall `vim-abolish` and see `:h Subvert` for more details.\n"
  },
  {
    "path": "vim/case-insensitive-substitution.md",
    "content": "# Case-Insensitive Substitution\n\nUse the `i` `s-flag` to perform a case-insensitive substitution (search and\nreplace).\n\nFor instance, `:%s/blog/article/gi` will turn\n\n```\nblog bLOg BLOG Blog\n```\n\ninto\n\n```\narticle article article article\n```\n\nSee `:h s_flags` for more details.\n"
  },
  {
    "path": "vim/center-the-cursor.md",
    "content": "# Center The Cursor\n\nIf you've moved the cursor to a particular line towards the top or bottom of\nthe screen, you may want to center the screen on that line. This can be\nachieved by hitting `zz`. It is a quick way to center the cursor and ensure\nthat you have an equal amount of context on either side of the line of\ninterest.\n\nTake care to not mistake this for `ZZ` which will save and quit the buffer.\n\nSee `:h zz` and `:h z.` for more details.\n\nh/t Chris Erin\n"
  },
  {
    "path": "vim/check-for-an-executable.md",
    "content": "# Check For An Executable\n\nSometimes Vim needs to reach outside of itself to use an existing program.\nFor example, wiring up [auto-formatting of JavaScript\ncode](https://hashrocket.com/blog/posts/writing-prettier-javascript-in-vim)\nrequires Vim to call out to the\n[`prettier`](https://github.com/prettier/prettier) binary.\n\nWe want our `.vimrc` files and plugins to, generally, be as portable as\npossible. What happens if you haven't yet installed a particular program?\nVim will likely experience a runtime exception. One way to get around this\nis to check for the presence of that program on the path. If it isn't there,\ndon't do the thing. We can use the `executable()` function for this.\n\n```vimscript\nif executable('prettier')\n  ...\nendif\n```\n\nIt will return `1` (true) if `prettier` is an executable on the path,\notherwise it will return `0` (false).\n\nSee `:help executable()` for more details.\n"
  },
  {
    "path": "vim/check-your-current-color-scheme.md",
    "content": "# Check Your Current Color Scheme\n\nVim ships with a number of different color schemes. There is also a plethora\nof color schemes built by the open source community. If you'd like to know\nwhat color scheme you are currently using, you can check with\n\n```\n:echo g:colors_name\n```\n\nSo more details at both `:h g:colors_name` and `:h colorscheme`.\n"
  },
  {
    "path": "vim/clear-out-the-jump-list.md",
    "content": "# Clear Out The Jump List\n\nVim uses a [jump list to track all they jumps you've\nmade](jump-back-to-the-latest-jump-position.md) during a session.  Vim can\neven be configured to keep a record of those jumps between sessions.  This\nis really handy for a long-lived project, but what if you want those jumps\ncleared out?\n\nYou can clear them out for the current and subsequent windows using\n`:clearjumps`. The jump list for existing windows will be unchanged and once\nyou start a new session, the full jump list will be restored.\n\nSee `:h :clearjumps` for more details.\n"
  },
  {
    "path": "vim/close-all-other-splits.md",
    "content": "# Close All Other Splits\n\nIf you have a couple other splits open, but you only want the window in\nfocus, you may find yourself doing some finger gymnastics to navigate to\nthose other split windows to close out of them.\n\nThere is an easier way.\n\nThe Ex command `:only` will close all other splits, excluding the window\nthat is currently in focus.\n\nSee `:h :only` for more details.\n"
  },
  {
    "path": "vim/close-all-other-windows.md",
    "content": "# Close All Other Windows\n\nOpening split windows can be useful in a number of circumstances. Eventually\nthough, you are going to want to go back to just one window. Generally when\nthis happens to me, I navigate to each of the other split windows that I\ndon't want and execute `:q`. What I want to do is essentially close all the\nother split windows except for my current one. Vim provides a single command\nfor doing this. By hitting\n\n```\n<CTRL>w <CTRL>o\n```\n\nall other windows are closed leaving the current window as the only one on\nthe screen.\n\nIf you want this command to be able to work with windows containing modified\nbuffers, you are going to want to have the `hidden` option turned on.\n\nSee `:h CTRL-W_CTRL-O` for more details.\n"
  },
  {
    "path": "vim/close-the-current-buffer.md",
    "content": "# Close the Current Buffer\n\nThere are a number of ways in Vim to close the current buffer. Obviously,\n`:q` will do the trick, but that kills all of your buffers which isn't ideal\nif you are still editing other files.\n\nIf you start digging through the Vim docs, you might come across both `:bd`\n(`:bdelete`) and `:bw` (`:bwipe`). At surface level, these seem like aliases\nof each other. Give them both a try and in both cases the current buffer\nwill go away, dropping you into one of the other buffers you have open.\n\nThe difference between `:bd` and `:bw` is in the details, namely in the\nside-effects. The `:bd` command is sort of a soft delete that removes the\nfile from the buffer list (do an `:ls` to check). If you have set marks on\nthat buffer, you'll notice that they are still there (check with `:marks`).\nYou may also notice that that buffer may still appear all over the jump list\n(see `:jump`). The `:bd` command is going to leave traces of your file all\nover the place (which could either be really handy or really annoying\ndepending on what you are doing). The `:bw` command on the other hand is\ngoing to *wipe out* all of this stuff, hence its name. The Vim docs for\n`:bw` warn us to only use it if we know what we are doing.\n\nSomething worth noting for both commands is that if the buffer is *dirty*\n(modified, but unsaved), then they won't work, unless you force them to with\n`:bd!` or `:bw!`.\n"
  },
  {
    "path": "vim/coerce-the-current-filetype.md",
    "content": "# Coerce The Current Filetype\n\nIf Vim doesn't recognize the filetype of the currently edited file, I can\ntell Vim what filetype to use. Consider, for instance, that I have a draft\nof a markdown file with the name, `documentation.md.draft`. Vim will not\nrecognize this as a markdown file and will, thus, not apply markdown\nsyntax highlighting to that file. I can easily tell Vim to treat this as a\nmarkdown file by setting its filetype:\n\n```\n:set filetype=markdown\n```\n\nMarkdown syntax highlighting and other relevant options will now be applied\nto the current buffer.\n\nSee `:h filetype` for more details.\n"
  },
  {
    "path": "vim/coercing-casing-with-vim-abolish.md",
    "content": "# Coercing Casing With vim-abolish\n\nThe [`vim-abolish`](https://github.com/tpope/vim-abolish) plugin provides a\ncouple handy shortcuts for quickly coercing the casing of a variable.\n\nFor instance, if you have a variable in camel case and you want to change it\nsnake case, you can navigate over the variable and hit `crs` (e.g.\n`myFavoriteVariable` -> `my_favorite_variable`).\n\nSimilarly, you can hit `crc` to change a variable to camel case.\n\nIt even has support for mixed case (`crm`) and uppercase (`cru`).\n\nh/t Jake Worth\n"
  },
  {
    "path": "vim/configure-fzf-to-use-fd-for-file-finding.md",
    "content": "# Configure FZF To Use fd For File Finding\n\nBy default, FZF uses the `find` command as its source for fuzzy finding\nfiles. So [`fzf.vim`](https://github.com/junegunn/fzf.vim) will also be\nusing `find` when you invoke `:Files`.  There are some speedier, more\nintelligent, and more user-friendly alternatives to `find`. I like\n[`fd`](https://github.com/sharkdp/fd).\n\nWe can configure `FZF` to use `fd` by adding a line like the following to\nour `~/.vimrc` file.\n\n```vimscript\nlet $FZF_DEFAULT_COMMAND = 'fd --type f --color=always'\n```\n\nThis will use `fd` to find files (`--type f`) using colorful output.\n\nWe can remove some noise from the output by adding a couple extra flags:\n\n```vimscript\nlet $FZF_DEFAULT_COMMAND = 'fd --type f --color=always' --exclude .git --ignore-file ~/.gitignore'\n```\n\nThis will keep the `.git` directory out of the result and prevent anything\nlisted in the main `.gitignore` file from being found.\n"
  },
  {
    "path": "vim/count-the-number-of-matches.md",
    "content": "# Count the Number of Matches\n\nYou can use the substitution functionality in vim to count the number\nof matches for a given search term like so:\n\n```\n:%s/transaction_id//n\n```\n\nYou will see the result in the command tray like so:\n\n```\n8 matches on 8 lines\n```\n\nIf you want to find matches globally (that is, counting multiples per line),\nyou can add the `g` flag:\n\n```\n:%s/transaction_id//gn\n```\n\nfor a response like:\n\n```\n13 matches on 8 lines\n```\n\nThe magic is in the `n` flag which tells vim to report a count of the\nmatches and not actually perform the substitution. See `:h :s_flags` for\nmore details. Also, check out `:h count-items`.\n"
  },
  {
    "path": "vim/create-a-new-directory-in-netrw.md",
    "content": "# Create A New Directory In netrw\n\nWith `netrw` open (try `vi .`), navigate to the parent directory you want to\ncreate a new directory in and then hit `d`. Type the name of the new\ndirectory in the provided prompt and then hit enter.\n"
  },
  {
    "path": "vim/create-a-new-file-in-a-new-directory.md",
    "content": "# Create A New File In A New Directory\n\nFrom within a vim session, if you create a buffer for a new file in a\ndirectory that doesn't exist. For instance, let's say that `/features`\ndoesn't exist and the new file is `my_latest_feature_spec.rb`:\n\n```\n:e spec/features/my_latest_feature_spec.rb\n```\n\nVim's command line will inform you that this is a buffer for a `[New\nDIRECTORY]`. If you then make some changes and subsequently try to save the\nfile, Vim will present you with:\n\n```\n\"spec/features/my_latest_feature_spec.rb\" E212: Can't open file for writing\n```\n\nThis is because the containing directory doesn't exist. You can quickly\ncreate that directory with a combination of Vim filename shorthands and\nshelling out to the `mkdir` command.\n\n```\n:!mkdir -p %:h\n```\n\nThe `%` is shorthand for the qualified path of the current file. The `:h` is\na filename modifier that returns the *head of the filename*, that is, it\nresolves to the path with everything except the name of the file.\n\nThus, this command is essentially resolving to:\n\n```\n:!mkdir -p spec/features/\n```\n\nVim will shell out with this command making directories for all non-existent\ndirectories in the given path. Now you can happily save your new file.\n"
  },
  {
    "path": "vim/creating-non-existent-directories.md",
    "content": "# Creating Non-Existent Directories\n\nWhen creating new files from within vim, using `:e`, you may find yourself\ncreating that file in a directory that doesn't yet exist. Vim will tell you\nas much if you then try to save that file. To get around this, I have often\nshelled out with `:!mkdir %:h`. This is a bit awkward to type though.\n\nThe [`vim-eunuch`](https://github.com/tpope/vim-eunuch) plugin comes with a\nhandy command for this. `:Mkdir` will create the parent directory for the\ncurrent buffer. If you're in a situation where multiple levels of the\nbuffer's directory don't exist, you can use `:Mkdir!` which will invoke\n`mkdir` with the `-p` flag.\n"
  },
  {
    "path": "vim/default-netrw-to-tree-liststyle.md",
    "content": "# Default netrw To Tree Liststyle\n\nThe built-in `netrw` plugin is a great way to browse files and directories\nwithin a Vim session. `netrw` supports four ways of displaying files and\ndirectories. That is, there are four liststyles. You can toggle through\nthese by hitting `i`.\n\nI prefer the tree liststyle, which is not the default. I can set the tree\nliststyle as the default by adding the following line to my `.vimrc` file.\n\n```vimscript\nlet g:netrw_liststyle = 3\n```\n\nNow, every time I visit or revisit a `netrw` window, I'll see everything\nnicely displayed as a tree.\n"
  },
  {
    "path": "vim/delete-every-other-line.md",
    "content": "# Delete Every Other Line\n\nYou can delete every other line in the current buffer using the following\ncommand.\n\nThere is a fairly elegant way in vim to delete every other line in the\ncurrent buffer. Why would you want to do that? I don't know. Nevertheless,\nhere it is:\n\n```\n:g/^/+d\n```\n\nThis will essentially delete all even numbered lines. If you'd like to\ndelete all odd numbered lines, delete the first line in the file (`ggdd`)\nand then run the same command as above.\n\nThis syntax is a bit awkward, so you may be better off going straight for a\nmacro (e.g. `qqjddq5@q` or `qqddjq5@q`).\n\n[source](http://stackoverflow.com/questions/1946738/vim-how-to-delete-every-second-row)\n"
  },
  {
    "path": "vim/delete-lines-that-match-a-pattern.md",
    "content": "# Delete Lines That Match A Pattern\n\nThe `:g` command can be used to execute an Ex command over the entire buffer\nfor all lines that match a given pattern. By choosing `d` (delete) as the Ex\ncommand, all lines that match the given pattern will be deleted. For\ninstance, if I want to remove all lines that contain `binding.pry`, I can\nexecute the following command:\n\n```\n:g/binding\\.pry/d\n```\n\nSee `:h :g` for more details.\n\nh/t Chris Erin\n"
  },
  {
    "path": "vim/delete-to-the-end-of-the-line.md",
    "content": "# Delete To The End Of The Line\n\nThere are a number of ways to delete from the cursor position to the end of\nthe line. Generally when I am doing this, I want delete to the end of the\nline and then start typing something different. Perhaps the best way to do\nthis is by hitting `C`. It deletes to the end of the line and then leaves\nyou in insert mode. This also makes for easier repetition with the dot\ncommand.\n\nThis is synonymous with hitting `c$`.\n\nSee `:h C` for more details.\n\nh/t Dorian Karter\n"
  },
  {
    "path": "vim/deleting-buffers-in-bufexplorer.md",
    "content": "# Deleting Buffers In BufExplorer\n\nThe [BufExplorer](https://github.com/jlanzarotta/bufexplorer) plugin makes\nit easy to browse and navigate to the various buffers open in a Vim session.\nIt is based on your buffer list. After a bit of coding, your buffer list can\nstart to get a bit out of control. There are surely going to be buffers that\nyou want to close out, *delete* if you will.\n\nWithin the BufExplorer browser you can move your cursor onto a buffer and\ndelete it.\n\nTo delete it by *unloading* the buffer (see `:h bd`), you can hit `d`.\n\nTo delete it by *wiping out* the buffer (see `:h bw`), you can hit `D`.\n\nIf you already have the plugin installed, see `:h bufexplorer` for more\ndetails.\n"
  },
  {
    "path": "vim/deleting-directories-of-files-from-netrw.md",
    "content": "# Deleting Directories Of Files From netrw\n\nIn `netrw`, you can delete files and directories by navigating over the\ntarget of deletion and hitting `D`.\n\nBy default, `netrw` will use `rmdir` when deleting directories. This means\nthat if a directory has files in it, then it won't be deleted. `rmdir`\nrightly gives an error when the target directory isn't empty.\n\nNot to worry though, `netrw` can be configured to use `rm -r` instead of\n`rmdir` when deleting directories.\n\n```\n:let g:netrw_localrmdir='rm -r'\n```\n\n[source](https://gist.github.com/KevinSjoberg/5068370)\n"
  },
  {
    "path": "vim/detect-if-you-are-on-a-mac.md",
    "content": "# Detect If You Are On A Mac\n\nThere are a couple ways of detecting with vimscript if you are on a mac.\nThis can be useful if you are writing a plugin with OS-specific\nfunctionality. Here are two ways to make that check.\n\n```vimscript\nif has('macunix') || has('mac') || has('osx')\n  ...\nendif\n```\n\nAlternatively, you can use Vim's `system()` function to execute unix's\n`uname` command. This command will give you the name of the operating\nsystem. In the event you are using a Mac, the result of `uname` should be\n`Darwin`. The following regex match is a good way to make this check.\n\n```vimscript\nif system('uname') =~ \"Darwin\"\n  ...\nendif\n```\n\nSee `:h has()`, `:h system()`, and `man uname` for more details.\n"
  },
  {
    "path": "vim/difference-between-wq-and-x.md",
    "content": "# Difference Between :wq and :x\n\nThe `:wq` command is used in Vim to write and quit. The contents of the\nbuffer are written to disk for the associated file and then the Vim session\nis terminated. So, what is the difference between this and the `:x` command.\nThe Vim help files give the following description of the `:x` command:\n\n> Like \":wq\", but write only when changes have been made.\n\nSo, `:wq` writes the buffer to disk either way, whereas `:x` just exits if the\nbuffer hasn't changed. Either way the contents of the resulting file are\ngoing to be the same. So what's the difference?\n\nModification time.\n\nIf you `:x` a buffer that hasn't changed, the modification time will be\nuntouched because the file isn't *re-saved*. The `:wq` command will alter\nthe modification time no matter what.\n\nThis matters if the modification time is used by anything. For instance, a\nbackground process that monitors a directory for changed files based on\nmodification times will get some false positives if you use `:wq` too\nliberally.\n\n[source](http://docstore.mik.ua/orelly/unix3/vi/ch05_03.htm)\n"
  },
  {
    "path": "vim/display-word-count-stats.md",
    "content": "# Display Word Count Stats\n\nYou can display counts for the current file including line count, word\ncount, and byte count by hitting `g CTRL-g`. This also displays the line,\nword, and byte that your cursor is currently at. The output looks something\nlike the following:\n\n```\nCol 1 of 0; Line 108 of 337; Word 397 of 1451; Byte 4571 of 18077\n```\n\nSee `:h 12.5` for more details.\n"
  },
  {
    "path": "vim/edges-of-the-selection.md",
    "content": "# Edges Of The Selection\n\nWhen you make a visual selection, Vim stores the position of the first\ncharacter of the selection in the `<` mark and the position of the last\ncharacter of the selection in the `>` mark.\n\nThus moving to the edges of your previous selection is easy. To move to the\nbeginning of the selection, press\n\n    `<\n\nTo move to the end, press\n\n    `>\n"
  },
  {
    "path": "vim/edit-a-file-at-a-specific-line-number.md",
    "content": "# Edit A File At A Specific Line Number\n\nI use long-running Vim sessions where I constantly open files as new buffers\nwith the `:edit` (or `:e`) command. Generally, when I open a new file I\nend up with the cursor at the top of the buffer and go from there. But what\nif I have a specific line number in mind and I want the cursor to start\nthere?\n\nThe `:edit` command can receive arguments, including a line number argument. To\nopen up to line 159, I can include the `+159` argument in the command.\n\n```\n:edit +159 path/to/the/file.txt\n```\n\nSee `:h :edit` and `:h +cmd` for more details about how `:edit` works and\nwhat the different arguments can do.\n"
  },
  {
    "path": "vim/edit-a-file-starting-on-the-last-line.md",
    "content": "# Edit A File Starting On The Last Line\n\nGenerally when you start editing a file whether as a new Vim session (`vim\nfile.txt`) or in an existing Vim session (`:e file.txt`), your cursor will\nbe positioned at the beginning of the file.\n\nYou can start editing a file with the cursor positioned at the end of a file\nusing an _edit command_ -- include `+` with no line number. This may be\nuseful for a large file or even if you just know that you'll be adding\ncontent directly to the bottom of the file.\n\nIf you are starting a new Vim session:\n\n```bash\n$ vim + file.txt\n```\n\nor if you are already in a Vim session:\n\n```\n:e + file.txt\n```\n\nSee `man vim` or `:h +cmd` for more details.\n"
  },
  {
    "path": "vim/end-of-the-word.md",
    "content": "# End Of The Word\n\nWord-based movement can serve as a quick way to get around locally in Vim. I\nmost often use `w` and `b` for this kind of movement. While `w` and `b` move\nme to the beginning of the next and previous word, respectively, I find that\nsometimes it would be more convenient if I were at the end of a word.\n\nThe `e` and `ge` commands serve this purpose well. `e` will move me to the\nend of the next word and `ge` will move me to the end of the previous word.\n"
  },
  {
    "path": "vim/escaping-terminal-mode-in-an-nvim-terminal.md",
    "content": "# Escaping Terminal-Mode In An Nvim Terminal\n\nA recent\n[TIL](https://til.hashrocket.com/posts/iity78ly38-open-a-zsh-terminal-in-a-split-window-in-neovim)\nby Chris Erin showed how to split open a terminal in a\n[Neovim](https://neovim.io/) session -- `:sp term://zsh`.\n\nThe terminal is emulated into a Vim buffer which means that you can treat it\nsort of like any other Vim buffer. You start in Normal mode. Once you use\nany mapping that would transition you into Insert mode, you'll instead find\nyourself in _Terminal_ mode. Terminal mode works just like any `zsh`\nsession (give `ls` a try).\n\nTry hitting `<Esc>` though and you'll see that you stay in Terminal mode\ninstead of being transitioned back to Normal mode.\n\nSo how do you get back to Normal mode?\n\nHit `<Ctrl-\\><Ctrl-n>`.\n\nThis is a pretty awkward key mapping though, so follow [the Nvim Terminal\ndocs](https://neovim.io/doc/user/nvim_terminal_emulator.html) and bring back\nthe Escape key.\n\n```vimscript\n:tnoremap <Esc> <C-\\><C-n>\n```\n"
  },
  {
    "path": "vim/filter-lines-through-an-external-program.md",
    "content": "# Filter Lines Through An External Program\n\nVim allows you to filter lines from your current buffer through an external\nprogram. For instance, if you have some ugly looking json that you'd like to\nformat in a readable way, you might want to filter it through an external\njson pretty printer program.\n\nTo filter the entire file through an external program, use\n\n```\n:%!! <external-program>\n```\n\nOr you can make a visual selection and just filter that\n\n```\n:'<,'>!! <external-program>\n```\n\nSee `:h !!` for more details.\n"
  },
  {
    "path": "vim/find-the-nth-character-position-in-a-file.md",
    "content": "# Find The Nth Character Position In A File\n\nWhile trying to load a JSON file in a JavaScript program, I got an error\nmessage. The error message said that there was an issue parsing the JSON file\nat the 9010th character position in the file. Though highly specific, this\ndidn't feel particularly actionable. I'm not going to count out 9010 characters\nin a massive JSON file.\n\nIt turns out that Vim can help with this. After opening the file, I can then\nrun this search:\n\n```\n/\\%^\\_.\\{9010}/e\n```\n\nThis will put my cursor right on the 9010th character.\n\nIt matches on the first character position in the file (`\\%^`), then it matches\non _any single character or end-of-line_ (`:h /\\_.`), and then it matches on\nthat character class the number of times specified (`\\{N}`) — in this case,\n9010 times. \n\nLastly, the second `/` marks the end of the search pattern and the `e` tells\nthe search to place the cursor at the end of the match. Without the `e`, the\ncursor will be placed at the beginning of the match. For a match on thousands\nof characters, that's not too helpful.\n\n[source](https://vi.stackexchange.com/a/25308/28962)\n"
  },
  {
    "path": "vim/fix-the-spelling-of-a-word.md",
    "content": "# Fix The Spelling Of A Word\n\nIf there is a misspelled word (`:set spell` to see what is misspelled), you\ncan navigate the cursor over that word and hit (from normal mode) `z=`. This\nwill open up a screen of possible corrections. The one you are most likely\nlooking for will be toward the top. Each possible spelling will have a\nnumber next to it. Enter the number of the word you are looking for and hit\nenter. The spelling of that word will have been updated.\n\nTry misspelling something and give it a try yourself.\n\nSee `:h z=` for more details.\n\nh/t Jake Worth\n"
  },
  {
    "path": "vim/fold-a-visual-selection-and-expand-it-back.md",
    "content": "# Fold A Visual Selection And Expand It Back\n\nIf I visually select a series of lines -- say the open and close tags of a\nlarge `div` in an HTML file I am reading through -- and then hit `zf`, it\nwill be _folded_ into a single line. That line will list how many lines are\nincluded in the fold as well as the content of the first line of the fold.\n\nIf I later come back to that fold and want to expand it again, I can hit\n`zd` to delete (or undo) the fold.\n\nTo do this, you'll want to make sure your `foldmethod` is set to `manual`.\nThis can be done by running the following command:\n\n```\n:set foldmethod=manual\n```\n\nSee the vim helpfiles (`:h fold`) for more details.\n"
  },
  {
    "path": "vim/for-when-that-escape-key-is-hard-to-reach.md",
    "content": "# For When That Escape Key Is Hard To Reach\n\nUsing Vim to its full potential requires using just about every key on the\nkeyboard. Of all those keys, the escape key is particularly important. It's\nhow you get back to normal node.\n\nIf you find the escape key hard to reach or your laptop vendor decided you\ndon't need it anymore, what's the alternative?\n\nThere is a built-in alternative:\n\n```\nCtrl-[\n```\n\n> Note: If your `<Esc>` key is hard to hit on your keyboard, train yourself to\n> use `CTRL-[`.\n\nSee `:help Ctrl-[` for more details.\n\n[source](https://twitter.com/tenderlove/status/1021412757805993984?s=11)\n"
  },
  {
    "path": "vim/format-long-lines-to-text-width.md",
    "content": "# Format Long Lines To Text Width\n\nVim allows you to set the maximum width for text per line in a buffer with\nthe `textwidth` setting. For example, you can set the maximum text width to\n80 characters like so:\n\n```\n:set textwidth=80\n```\n\nWith this set, vim will automatically break on whitespace whenever you hit\n80 characters. However, there are two places where this doesn't quite pan\nout. You will see this as soon as you open a file with lines of text that\nexceed 80 characters and when you paste long lines of text into your buffer.\nYou can quickly remedy this with `gw`.\n\nMake a visual selection of the lines that need formatting and then hit `gw`.\nAll the lines should then we truncated to 80 or less characters.\n\nSee `:h gw` and `:h gq` for more details.\n"
  },
  {
    "path": "vim/from-ruby-variables-to-javascript-variables.md",
    "content": "# From Ruby Variables To JavaScript Variables\n\nI sometimes find myself writing so much Ruby that as soon as I am back in\na JavaScript file, my code starts looking like this:\n\n```javascript\nconst my_javascript_var = 123;\n```\n\nIt would be easy enough to hit `caw` to the delete the entire word and then\nretype it as camel case. I happen to have the\n[Abolish.vim](https://github.com/tpope/vim-abolish) plugin installed, so\nthere is an even quicker way.\n\nIf I hit `crc` over the variable, it will be _coerced_ to camel case.\n\n```javascript\nconst myJavascriptVar = 123;\n```\n\nIf I hit `crs` then it will be _coerced_ back to snake case. Hit `crc` one\nmore time and I can get back to writing some JavaScript.\n\nSee `:h abolish-coercion` for more details.\n"
  },
  {
    "path": "vim/generate-and-edit-rails-migration.md",
    "content": "# Generate and Edit Rails Migration\n\nCreating a new Rails migration has always involved two distinct steps for\nme. The first is to run `rails g migration CreateSomeTable` to create a\nmigration file. The second is to copy and paste the migration's filename\nafter `vi` to actually start editing it.\n\n[Rails.vim](https://github.com/tpope/vim-rails) collapses these steps into\none:\n\n```\n:Rgenerate migration CreateSomeTable\n```\n\n[source](http://stackoverflow.com/questions/7857177/with-vim-rails-can-you-create-a-new-migration-file-and-open-it-in-one-go)\n"
  },
  {
    "path": "vim/get-the-pid-of-the-session.md",
    "content": "# Get The pid Of The Session\n\nYour current Vim session is a process running on your machine. That means\nthat this session is tied to a particular process id, _pid_.\n\nWant to know what the pid is?\n\n```vim\n:echo getpid()\n```\n\nThis will echo the pid of your current Vim session.\n\nSee `:h getpid()` for more details.\n"
  },
  {
    "path": "vim/go-back-to-the-previous-window.md",
    "content": "# Go Back To The Previous Window\n\nWhen working with multiple files, you may have one or more window splits\nopen. You may even be moving back and forth between two in particular --\nperhaps if you are iterating on a test and its implementation. You can move\nback to the previous window using `Ctrl-w Ctrl-w`. This is the same as\nhitting `Ctrl-w w`.\n\nOnce you've moved back to the previous window, the window you were just in\nis now the previous window. That means you can keep hitting `Ctrl-w Ctrl-w`\nto toggle back and forth.\n\nSee `:h ctrl-w w` for the exact command and `:h ctrl-w` for more on window\ncommands.\n"
  },
  {
    "path": "vim/go-to-beginning-and-end-of-line.md",
    "content": "# Go To Beginning And End Of Line\n\nThere are two movements that I often find useful in Vim when trying to position\nmy cursor relative to the current line.\n\n- `0` - go to the first character of the line\n- `$` - go to the end of the line\n\nFor instance, I may use `0` to jump to beginning of a line so that I can then\nmake a block-visual selection of several lines to insert some text in front of\neach line.\n\nOr perhaps I'm already in visual mode and I want to move the cursor (and visual\nselection) to the end of the line. I hit `$` to do that. Then I might `y`\n(yank) or `c` (delete into insert mode).\n\nIt's also worth noting that with code indentation, `0` moves the cursor to the\nvery first position of the line whereas `^` moves the cursor to the first\nnon-whitespace character. The former essentially accounts for code indentation.\nFor example, imagine you're in the middle of line 3 in the following example.\nDepending on what you're trying to do, you may want to jump to one or the other\nposition.\n\n```ruby\nclass Greeting\n  def hello(name)\n    puts \"Hello, #{name || 'world'}!\" # say hi\n  end\nend\n```\n\nSee `:h 0` for Vim help files on these motions. They are all located near each\nother.\n"
  },
  {
    "path": "vim/go-to-file-with-line-number.md",
    "content": "# Go To File With Line Number\n\nI often use `gf` as supported by Vim or with the help of plugins like\n[`rails.vim`](https://github.com/tpope/vim-rails) as a way of quickly\nnavigating to existing files. For unloaded files, this loads a buffer with\nthe cursor at the top of the buffer. For existing buffers, it opens to that\nbuffer with the cursor where it was when you left.\n\nVim also supports a slightly fancier goto file command, `gF`. If this\ncommand is used while the cursor is over a file with a line number appended\nto the end, it will not only open up a buffer with that file, it will move\nthe cursor to the specified line number.\n\nWith this repository, I could try it out by moving the cursor over the\nfollowing text and hitting `gF`.\n\n```text\nREADME.md:100\n```\n\nThis will open up a buffer for `README.md` with the cursor at line 100.\n\nSee `:h gF` for more details.\n"
  },
  {
    "path": "vim/grepping-through-the-vim-help-files.md",
    "content": "# Grepping Through The Vim Help Files\n\nTrying to look up the help file for a Vim feature, but you cannot quite\nremember the right keyword? Use `:helpgrep`. With `:helpgrep`, you can\nsearch across all of the Vim help files for not just the specific keywords,\nbut any pattern of text. For instance, if you want to find where\n`substitution` is mentioned in the help files, try:\n\n```\n:helpgrep substitution\n```\n\nIt makes a list of all occurrences in the quick fix window and then opens up\na split with the cursor on the line of the first occurrence. You can then\nhit `:copen` to see the rest of the entries.\n\nSee `:h helpgrep` for more details.\n"
  },
  {
    "path": "vim/head-of-file-name.md",
    "content": "# Head of File Name\n\nAt Hashrocket, I kept seeing my coworkers type a variety of commands into\nvim command mode that included `%:h`. I finally decided to ask what was\ngoing on. It turns out that it produces the directory of the file in your\ncurrent vim buffer.\n\nThe `%` represents the current file and `:h` is a filename modifier,\n*head of the filename*, that truncates the last component and any\nseparators. So if you remove the file part of the current file (`%`), you\nare left with the (relative) directory of the current file. Your imagination\nand vim's flexibility can now take over.\n\nA common use case is to use it to quickly edit another file that you know is\nin the same directory. Why type out a long pathname over and over throughout\nthe day, when you can type:\n\n```\n:e %:h<tab>\n```\n\nAfter hitting tab, the pathname will be auto-completed. Complete the rest of the\nfilename as you do.\n\nOr perhaps you aren't sure what file you want to edit and you'd rather just\nget a picture of the whole directory:\n\n```\n:e %:h\n```\n\nYou are now exploring the whole directory in netrw mode. Yay!\n\nIf you want to find out more about similar features,\nthere is a section in the Vim documentation that talks all about [filename\nmodifiers](http://vimdoc.sourceforge.net/htmldoc/cmdline.html#filename-modifiers).\n"
  },
  {
    "path": "vim/help-for-non-normal-mode-features.md",
    "content": "# Help For Non-Normal Mode Features\n\nThe majority of your time in vim will be spent in normal mode. You will\noften look to the documentation for help on any number of commands and\nbindings available in normal mode. For instance, to find out more about\n*goto file*, you may do `:h gf`. And if you want to read more about\n*yanking* lines of code, you may do `:h y`.\n\nBut what about commands and bindings that aren't found in normal mode? What\nif you want to read about *yanking* text from visual mode? What if you want\nto get more details on insert's x-mode? Doing `:h y` and `:h ctrl-x`,\nrespectively, won't do the trick because vim thinks you are talking about\nnormal mode bindings.\n\nThe docs for these and other non-normal mode features can be found by\nprepending `i_` and `v_` to the binding in question.\n\nTo get at the docs for *yanking* from visual mode:\n\n```\n:h v_y\n```\n\nAnd to read up on insert's x-mode:\n\n```\n:h i_ctrl-x\n```\n"
  },
  {
    "path": "vim/highlighting-search-matches.md",
    "content": "# Highlighting Search Matches\n\nWant to see all the places in the buffer that match a search pattern? Turn\non `hlsearch` and Vim will highlight all the matches of the previous search.\n\nTry turning it on with `:set hlsearch` and then search for some pattern\nusing `/`.\n\nIf you no longer want to see all the highlighted matches, turn it off with\n`:set nohlsearch`.\n\nSee `:h hlsearch` for more details.\n"
  },
  {
    "path": "vim/horizontal-to-vertical-and-back-again.md",
    "content": "# Horizontal to Vertical and Back Again\n\nIf you have two Vim windows open with a horizontal split and you want to\nquickly switch them to be vertically split, you can type the following two\nkey bindings:\n\n```\nCtrl-w t\nCtrl-w H\n```\n\nTo go from vertically split windows to horizontally split windows you can\ninstead use:\n\n```\nCtrl-w t\nCtrl-w K\n```\n\n[source](http://stackoverflow.com/questions/1269603/to-switch-from-vertical-split-to-horizontal-split-fast-in-vim)\n"
  },
  {
    "path": "vim/increment-all-the-numbers.md",
    "content": "# Increment All The Numbers\n\nVim's substitution feature can be used for more than simple static text\nreplacement. Each replacement can be the result of some operation on the\noriginal text. For instance, what if we'd like to increment all numbers in the\nbuffer? We can achieve this by searching for all numbers and then using `\\=`\nwith `submatch`. Whenever the replacement string of a substitution starts\nwith `\\=`, the remainder of the string is evaluated as an expression.\n\nGiven the following text in our buffer:\n\n```\n1 2 a b c 45 123 1982\n```\n\nWe can run the following substitution command:\n\n```\n:%s/\\d\\+/\\=submatch(0)+1/g\n```\n\nThis will transform all digits in the buffer, resulting in:\n\n```\n2 3 a b c 46 124 1983\n```\n\nWant to decrement all the numbers instead?\n\n```\n:%s/\\d\\+/\\=submatch(0)-1/g\n```\n\nSee `:h sub-replace-expression` for more details.\n"
  },
  {
    "path": "vim/incremental-searching.md",
    "content": "# Incremental Searching\n\nYou can do a text-based search on the contents of your current buffer by\nhitting `/` and then beginning to type a pattern (including regex). The\n`incsearch` feature makes searching for text even easier. As you type your\npattern, the first valid match will be located and highlighted. As you\ncontinue to type the pattern, it will continue to update the highlighted\nmatch. Incremental searching makes it easy to see when you've made\na typo in your pattern. By default `incsearch` is turned off in Vim. You\ncan enable it with `:set incsearch`.\n\nSee `:h incsearch` for more details.\n"
  },
  {
    "path": "vim/interact-with-the-alternate-file.md",
    "content": "# Interact With The Alternate File\n\nIf you have a couple buffers going in a Vim session and you check out the\nbuffer list with `:ls`, you'll notice that one of those buffers has a `#`\nindicator next to it. That means the file for this buffer is considered the\nalternate file of the current, visible buffer. In addition to hitting\n`CTRL-^` to switch to that buffer, you can reference it in other commands\nwith `#`. This means you can quickly `:edit`, `:split`, `:vsplit`, and so\nforth the alternate file by just giving `#` as the argument to those\ncommands.\n\nQuickly open the alternate file in a vertical split with:\n\n```\n:vsp #\n```\n\nSee `:h alternate-file` for more details.\n"
  },
  {
    "path": "vim/interactive-buffer-list.md",
    "content": "# Interactive Buffer List\n\nThe `:ls` command is a great way to see what buffers you currently have open\nduring a vim session. However, if you are trying to find and open a specific\nbuffer it can be tedious to have to find it in the list and then enter a\nwhole different command to move to it (e.g. `:b 10`).\n\nThe [`bufexplorer`](https://github.com/jlanzarotta/bufexplorer) plugin gives\nyou quick access to an interactive buffer list. By using `<leader>bs` and\n`<leader>bv` you can open horizontally and vertically split windows,\nrespectively, that allow you to navigate through and open specific buffers\nfrom your buffer list. This is a simple plugin you can add to your workflow\nthat can make working with a lot of buffers a bit more efficient.\n"
  },
  {
    "path": "vim/joining-lines-together.md",
    "content": "# Joining Lines Together\n\nYou can quickly join a series of lines onto a single line using the `J`\ncommand. Simply hitting 'J' in normal mode will join the current line with\nthe line below it leaving a space in between the two. If you want to join\nthe next 5 lines, you can hit `5J`. Hitting '5J' on this:\n\n```\nfirst,\nsecond,\nthird,\nfourth,\nfifth\n```\n\nwill transform it into this:\n\n```\nfirst, second, third, fourth, fifth\n```\n\nSimilarly, you can perform a line by line join on a visual selection by\nhitting `J` after making the desired visual selection.\n"
  },
  {
    "path": "vim/jump-back-to-the-latest-jump-position.md",
    "content": "# Jump Back To The Latest Jump Position\n\nAny sort of jump motion, such as `gg` or `121G`, will be recorded in your\nVim session's jump list. If you'd like to return to the latest position in\nyour jump list, you can tap `''` within normal mode.\n\nYou can then tap `''` again and you'll be returned to the position you were\njust at. This is great if you want to toggle back and forth between your\ncurrent position and the previous position.\n\nIf the latest jump position is not within the current buffer, then you will\nbe jumped to the initial cursor position at the top of the file.\n\nYou can learn more about this by reference `:help jump-motions`, `:help\njumplist`, and `:help ''`.\n\nh/t Jake Worth\n"
  },
  {
    "path": "vim/jump-between-and-stage-git-hunks-with-fugitive.md",
    "content": "# Jump Between And Stage Git Hunks With Fugitive\n\nOnce you [open vim-fugitive's git summary\nwindow](open-the-fugitive-git-summary-window.md), you'll see a listing of the\ntracked files with unstaged changes. Each of those files is made up of one or\nmore _hunks_—a semi-contiguous chunk of changes in a Git diff.\n\nYou can jump forward and backward through these hunks with `]c` and `[c`,\nrespectively. If the inline diff view of a given file has not already been\nexpanding, these navigational keybindings will auto-expand it.\n\nWith the cursor over the heading of a particular hunk, you can hit `s`\n(assuming you're looking at unstaged changes) to _stage_ the entire hunk.\nSimilarly, if the cursor is over the hunk heading of a change in the staged\narea, you can hit `u` to unstage that entire hunk.\n\nFor more details and a visual walkthrough, [check out this screencast on\nstaging commits within Vim](https://www.youtube.com/watch?v=41OI6pszvv0).\n"
  },
  {
    "path": "vim/jump-to-matching-pair.md",
    "content": "# Jump To Matching Pair\n\nIf you are dealing with code or data that contains parentheses or brackets\nthat are hard to follow, you can easily jump between them with `%`.\n\nFor example, if you move over a `[` and hit `%`, Vim will jump your cursor\nto the matching `]`. Hit `%` one more time and it will jump back.\n\nSee `:h %` for more details.\n\nh/t Jake Worth\n"
  },
  {
    "path": "vim/jump-to-the-next-misspelling.md",
    "content": "# Jump To The Next Misspelling\n\nIf spelling is turned on (`:set spell`), you can jump back and forth between\nwords that are misspelled. To jump to the next misspelling, hit `]s`. To\njump to the previous misspelling, hit `[s`.\n\nSee `:h ]s` and `:h [s` for more details.\n"
  },
  {
    "path": "vim/list-all-buffers.md",
    "content": "# List All Buffers\n\nThe `:ls` command will list the buffers you have open. What vim doesn't tell\nyou though is that there are some unlisted buffers that it isn't displaying.\nTo see *all* of the buffers, you can use `:ls!`. According to the vim help\nfile:\n\n> When the [!] is included the list will show unlisted buffers\n> (the term \"unlisted\" is a bit confusing then...).\n\nThis reveals buffers for `netrw`, `:help` files, etc. This helps explain the\nsometimes sporadic numbering that vim uses for buffers.\n"
  },
  {
    "path": "vim/list-autocmds-configured-for-the-current-buffer.md",
    "content": "# List autocmds Configured For The Current Buffer\n\nVim itself and many of the plugins you use will configure `autocmd` triggers.\nThis are commands that get executed when a certain editor event takes place in\ncertain types of files.\n\nA common example is having a tool like `prettier` configured to format the\ncontents of JavaScript files when the `BufWritePost` event happens, that is,\nright after the buffer gets written.\n\nYou can list each `autocmd` that is configured for your current buffer using\n`:au` and a couple arguments.\n\n```\n:au * <buffer>\n```\n\nThe `*` says match against all events. The `<buffer>` filters them down to just\nwhat is configured for the current buffer.\n\nIf you just wanted to know about `BufWritePost` events for the current buffer,\ntry this.\n\n```\n:au BufWritePost <buffer>\n```\n\nOr if you want to know about buffer number `4`:\n\n```\n:au BufWritePost <buffer=4>\n```\n\nSee `:h :au` for more details.\n"
  },
  {
    "path": "vim/list-of-plugins.md",
    "content": "# List Of Plugins\n\nGet a list of all your plugins (and other sourced scripts) with\n\n```\n:scriptnames\n```\n\nSee `:h scriptnames` for more details.\n"
  },
  {
    "path": "vim/load-a-directory-of-files-into-the-buffer-list.md",
    "content": "# Load A Directory Of Files Into The Buffer List\n\nConsider the scenario where I want to go through all files in a directory to\nmake a series of minor, related changes. After editing each file, I can type\nsomething like `:e path/to/next/file.md` to bring up the next file. That can\nget a bit tedious though. Instead, I can load up all the files in the\ndirectory with the `args` command:\n\n```\n:args path/to/files/*.md\n```\n\nFrom there, I can use `:bnext` (or `:bn) and `:bprev` to more quickly jump\nthrough those files I want to edit.\n\nI can also run `:ls` to see all the files loaded in to the buffer list at\nthat point.\n\n[source](http://superuser.com/questions/396481/how-to-load-multiple-files-in-multiple-subdirectories-into-vim-buffers)\n"
  },
  {
    "path": "vim/make-directories-for-the-current-file.md",
    "content": "# Make Directories For The Current File\n\nThe [`vim-eunuch` plugin](https://github.com/tpope/vim-eunuch) provides Vim\ncommands that correspond to many common Unix shell commands. One such command\nis an equivalent to the `mkdir` command.\n\nThe `mkdir` command creates the given directory if it doesn't already exist. If\nmultiples levels of new directories are specified, the `-p` flag can be\nincluded to create each successive level.\n\nThe `vim-eunuch` equivalents are `Mkdir` and `Mkdir!`.\n\nLet's say I'm working within a project that doesn't currently have a `docs`\ndirectory. When I open up a buffer to `docs/setup.md`, before I can write that\nnew file, I need to create the `docs` directory. Running `:Mkdir` will do that.\n\nNow let's say I open up a buffer to `src/api/util/base.js`. The `src` directory\nalready exists, but neither `/api` nor `util/` nested under it exist. Before I\ncan write the buffer, I need to create both of those directories. `:Mkdir` on\nits own won't create these nested directories. Instead I need to reach for the\n`-p` equivalent which is `:Mkdir!`.\n\nSee `:h eunuch-:Mkdir` for more details.\n"
  },
  {
    "path": "vim/marks-across-vim-sessions.md",
    "content": "# Marks Across Vim Sessions\n\nAny mark set with a capital letter (that is, `A-Z`) is called a *file mark*.\nFile marks can be used to move from file to file. File marks will also be\nwritten to the Vim Info file (`~/.viminfo`) which means that if you close\nVim and open it again, it will still know about those file marks. This means\nthat your file marks are persisted across vim sessions which will save you\nthe trouble of having to redefine them each time.\n\nA more detailed description of marks is at `:help marks`.\n"
  },
  {
    "path": "vim/match-the-beginning-and-end-of-words.md",
    "content": "# Match The Beginning And End Of Words\n\nOften when doing a substitution for an exact word, say `user` to\n`admin`, I will include spaces on either end of the regex pattern to avoid\nunintentional replacements. For example, I may use something like\n\n```\n:%s/ user / admin /\n```\n\nin order to avoid a substitution like `username` to `adminname`.\n\nIn this case, the spaces can be replaced with zero-width regex characters\nthat match the beginning and end of a word. These are `\\<` and `\\>`,\nrespectively. Utilizing these, the previous substitution can be achieved\nwith\n\n```\n:%s/\\<user\\>/admin/\n```\n\nSee `:h /\\<` and `:h /\\>` for more details.\n"
  },
  {
    "path": "vim/moving-to-a-specific-line.md",
    "content": "# Moving To A Specific Line\n\nOften times when I open a new buffer, it is with the intention of moving to\na particular line. For example, if I am trying to move to line 55 in the\nfile, then I will hit `55j`\\*. This works fine when I am dealing with a\nfreshly opened buffer. That is, this works fine if I am starting from the\ntop of the buffer.\n\nIn general, there is a better approach. I can move to an exact line number\nfrom normal mode with `:{N}` where `{N}` is the line number. So, if I want\nto get to line 55 regardless of where I am currently positioned in the\nbuffer, I can simply hit `:55<cr>`.\n\n\\* *This actually is slightly inaccurate, it moves me to line 56, not 55.\nIf I need to be precise, `55j` doesn't cut it.*\n\n\\*\\* Also, I can apparently use `55G` to achieve the same thing\n([source](https://twitter.com/rossnelson/status/591239951032983553)).\n"
  },
  {
    "path": "vim/navigate-to-the-nth-column-on-a-line.md",
    "content": "# Navigate To The Nth Column On A Line\n\nYou can navigate the cursor to a specific column of the current line using\nthe `|` character. For instance typing\n\n```\n45|\n```\n\nwill navigate your cursor to the 45th column of the current line. If you\ntype a number that exceeds the number of columns on the line, your cursor\nwill be placed on the last column.\n\nHere is what the help files have to say about `|`:\n\n```\n|\t\t\tTo screen column [count] in the current line.\n\t\t\t|exclusive| motion.  Ceci n'est pas une pipe.\n```\n"
  },
  {
    "path": "vim/navigating-by-blank-lines.md",
    "content": "# Navigating By Blank Lines\n\nUse vim to open a file full of code (or text) that has some blank lines.\nMove the cursor to the middle of the file. Then start hitting `{` or `}`.\nYou'll see that the cursor jumps from blank line to blank line.\n\nUse `{` to jump to the closest blank line _behind_ the cursor. Use `}` to\njump to the closest blank line _ahead_ of the cursor.\n\nThis may not seem like the most practical or obvious way to navigate, but it\ncan help move you around a bit quicker than just tapping `k` and `j`.\n"
  },
  {
    "path": "vim/netrw-listing-styles.md",
    "content": "# NETRW Listing Styles\n\nWhen you edit a directory with vim (`vim .`), you are taken into netrw which allows\nyou to explore the contents of that directory. By default, you will see a\nlist of the files and directories in the target directory, like so:\n\n```\n\" ============================================================================\n\" Netrw Directory Listing                                        (netrw v151)\n\"   /Users/jbranchaud/code/til\n\"   Sorted by      name\n\"   Sort sequence: [\\/]$,\\<core\\%(\\.\\d\\+\\)\\=\\>,\\.h$,\\.c$,\\.cpp$,\\~\\=\\*$,*,\\.o$,\\.obj$,\\.info$,\\.swp$,\\.bak$,\\~$\n\"   Quick Help: <F1>:help  -:go up dir  D:delete  R:rename  s:sort-by  x:special\n\" ==============================================================================\n../\n./\n.git/\ngit/\ngo/\npostgres/\nrails/\nruby/\nvim/\nzsh/\nLICENSE\nREADME.md\n```\n\nThis (`thin`) is only one of a few listing styles that you can use to explore a\ndirectory. The other styles are `long`, `wide`, and `tree`. You can cycle\nbetween them by pressing `i`. For instance, if you cycle through to the `tree`\nformat, you will be presented with navigable tree structure like so:\n\n```\n\" ============================================================================\n\" Netrw Directory Listing                                        (netrw v151)\n\"   /Users/jbranchaud/code/til/git\n\"   Sorted by      name\n\"   Sort sequence: [\\/]$,\\<core\\%(\\.\\d\\+\\)\\=\\>,\\.h$,\\.c$,\\.cpp$,\\~\\=\\*$,*,\\.o$,\\.obj$,\\.info$,\\.swp$,\\.bak$,\\~$\n\"   Quick Help: <F1>:help  -:go up dir  D:delete  R:rename  s:sort-by  x:special\n\" ==============================================================================\n../\ntil/\n| .git/\n| git/\n| | checkout-previous-branch.md\n| | delete-all-untracked-files.md\n| | dry-runs-in-git.md\n| | intent-to-add.md\n| | staging-changes-within-vim.md\n| | stashing-untracked-files.md\n| | verbose-commit-message.md\n| go/\n| postgres/\n| rails/\n| ruby/\n| | create-an-array-of-stringed-numbers.md\n| | limit-split.md\n| | parallel-bundle-install.md\n| | summing-collections.md\n| vim/\n| zsh/\n| LICENSE\n| README.md\n```\n\n[source](http://vimdoc.sourceforge.net/htmldoc/pi_netrw.html)\n"
  },
  {
    "path": "vim/next-modified-buffer.md",
    "content": "# Next Modified Buffer\n\nAfter working for a while on a feature that involves looking at a number of\nfiles, I end up with a decent buffer list. I will have inevitably edited a\nfew of those files and occasionally I'll inadvertently leave one of the\nbuffers modified. Instead of opening\nthe buffer list (`:ls`), finding the modified buffer, and navigating to it,\nI can just jump straight to it. I can do this with `:bmodified` or just\n`:bm`. This jumps straight to the next modified buffer. If there is no\nmodified buffer, it tells me *No modified buffer found*.\n\nSee `:h bmodified` for more details.\n"
  },
  {
    "path": "vim/normal-mode-binding-to-just-quit.md",
    "content": "# Normal Mode Binding To Just Quit\n\nI'm already familiar with the normal mode binding to write and quit -- `ZZ`.\nIt turns out there is an equivalent binding to quit without writing. Hit\n`ZQ` and Vim will quit the current window disregarding any unsaved changes.\nThis behaves in the same way as if you had executed the `:q!` command.\n\nSee `:help ZQ`.\n"
  },
  {
    "path": "vim/open-a-tag-in-a-split-window.md",
    "content": "# Open A Tag In A Split Window\n\nUsing tags and `ctrl-]` is a quick way to jump from the use of a keyword to\nthe declaration or definition whether in the same file or another file.\nSometimes what you really want is that tag definition opened up in a\n(horizontal) split window. That way you can see the definition without\nlosing context. This can be accomplished with `ctrl-w ]`.\n\nThe Vim help file gives the following definition of this command:\n\n> Use identifier under cursor as a tag and jump to it in the new upper window.\n\nSee `:h CTRL-W_]` for more details.\n\nh/t Dorian Karter\n"
  },
  {
    "path": "vim/open-an-unnamed-buffer.md",
    "content": "# Open An Unnamed Buffer\n\nThere are two ways (that I know of) to open an unnamed buffer.\n\nThe first is before vim has even been launched. You can simply execute `vim`\nfrom the command-line without any arguments. Follow that by invoking `:ls`\nto see that the current and only buffer has *no name*.\n\nThe second method is with a vim session that is already open. If you invoke\n`:new`, a new buffer will be created that, like the first method, has *no\nname*.\n"
  },
  {
    "path": "vim/open-fzf-result-in-a-split.md",
    "content": "# Open FZF Result In A Split\n\nThe [`fzf.vim` plugin](https://github.com/junegunn/fzf.vim) allows you to do\nspeedy fuzzy searches for filenames and line-by-line content.\n\nOnce you've narrowed down the results and found what you're interested in,\nyou can hit `<enter>` and a new buffer will open over what was already in\nthe window. You can also open that file as a split.\n\nHitting `Ctrl-x` will open the file under the cursor as a horizontal split.\n\nHitting `Ctrl-v` will alternatively open that file as a vertical split.\n"
  },
  {
    "path": "vim/open-routes-file-with-vim-rails.md",
    "content": "# Open Routes File With vim-rails\n\nYou can quickly pop open the `config/routes.rb` file for a Rails project by\nusing the following command provided by\n[`vim-rails`](https://github.com/tpope/vim-rails).\n\n```\n:Einit\n```\n\nThis is a shortcut for opening initializer files the default of which is the\nroutes file.\n"
  },
  {
    "path": "vim/open-the-directory-of-the-current-file.md",
    "content": "# Open The Directory Of The Current File\n\nIn one of my first TILs ever, [Head Of File\nName](https://github.com/jbranchaud/til/blob/master/vim/head-of-file-name.md),\nI wrote about a fancy, archaic way of popping open a netrw view for the\ndirectory of the current file. To this day, I still use it all the time when\nI'm curious about the other files co-located with the file I'm editing.\n\nThere are a couple other ways to do this that arguably require less finger\ngymnastics.\n\n```\n:Explore\n```\n\nThis has the same behavior `:e %:h` at the cost of a few extra (easier to\nreach) keys.\n\nThere is also\n\n```\n:Sex\n```\n\nwhich opens it up in a split. And as you'd expect, you can also use `:Vex`\nfor a vertical split.\n\n[source](http://superuser.com/questions/31677/how-do-i-open-the-directory-of-the-current-open-file)\n"
  },
  {
    "path": "vim/open-the-fugitive-git-summary-window.md",
    "content": "# Open The Fugitive Git Summary Window\n\nThe [`vim-fugitive` plugin](https://github.com/tpope/vim-fugitive) can show a\ngit summary window that is \"akin to git-status\". There are two ways to open up\nthis window.\n\nThe short-hand way of doing this is with `:G` (or `:Git`) with no arguments.\nFor me, this opens the `fugitive-summary` in a split.\n\nThe other way is with the `:Gedit` command. This command can take a variety of\narguments, and when you pass it `:` as an argument, it will open a window with\nthe `fugitive-summary` (i.e. `:Gedit :`).\n\nI tend to short-hand this as `:Ge:`.\n\nSee `:h fugitive-summary` and `:h fugitive-object` for more details on this.\n\n[source](https://www.youtube.com/watch?v=rzUMjqD6NMQ)\n"
  },
  {
    "path": "vim/open-the-gemfile.md",
    "content": "# Open The Gemfile\n\nOne of the central files to any Ruby or Rails project is the `Gemfile`. When\nit is time to add or remove a Gem, that is the place to go. The\n[`vim-bundler`](https://github.com/tpope/vim-bundler) plugin allows you to\nquickly navigate to the project's `Gemfile` by entering the following\ncommand:\n\n```\n:Bopen\n```\n\nThat command is primarily used for navigating to the source of a particular\nGem, but when used alone, it pops open the `Gemfile`.\n"
  },
  {
    "path": "vim/open-the-latest-rails-migration.md",
    "content": "# Open The Latest Rails Migration\n\nThe [`rails.vim`](https://github.com/tpope/vim-rails) plugin comes with a\nlot of handy helpers for quickly navigating to many parts of a Rails\nproject. Among these helpers is the `:Emigration` command that makes it easy\nto tab complete and navigate to Rails migration files. Often times the\nmigration you want is the latest migration. There is no need for tab\ncomplete here, just type:\n\n```\n:Emigration\n```\n\nBy default this command opens the latest migration in a new buffer.\n\nSee `:h rails-:Emigration` for more details.\n"
  },
  {
    "path": "vim/open-the-selected-lines-in-github-with-gbrowse.md",
    "content": "# Open the Selected Lines In GitHub With GBrowse\n\nThe [`vim-fugitive`](https://github.com/tpope/vim-fugitive) plugin comes with\nthe `:Gbrowse` command.\n\n> Open the current file, blob, tree, commit, or tag in your browser at the\n> upstream hosting provider.  If a range is given, it is appropriately appended\n> to the URL as an anchor.\n\nI would try this from repositories hosted on GitHub and get an error. Reading a\nbit further into the `:Gbrowse` documentation I can see why.\n\n> Upstream providers can be added by installing an appropriate Vim plugin.  For\n> example, GitHub can be supported by installing rhubarb.vim, available at\n> <https://github.com/tpope/vim-rhubarb>.\n\nI was missing the [`vim-rhubarb` plugin](https://github.com/tpope/vim-rhubarb).\nAfter installing that, I can open the current file in GitHub by running\n`:Gbrowse`.\n\nIf I make a visual selection of any number of lines, then I can go into command\nmode again typing out `Gbrowse` with the automatically preceding visual\nselection tags. This will open the file on GitHub with those lines selected.\n\n```\n:'<,'>Gbrowse\n```\n"
  },
  {
    "path": "vim/open-vim-to-a-tag-definition.md",
    "content": "# Open Vim To A Tag Definition\n\nIf you are using [ctags with Vim](https://andrew.stwrt.ca/posts/vim-ctags/),\nyou can provide a tag name when opening Vim. This signals to Vim that it\nshould open to the file and location of the tag's definition. For instance,\nif you have a Rails project going and you provide Vim with the\n`UsersController` tag name, it will open the\n`app/controllers/users_controller.rb`. Just use the `-t` flag like so:\n\n```bash\n$ vim -t UsersController\n```\n\nSee `man vim` for more details.\n"
  },
  {
    "path": "vim/opening-a-url.md",
    "content": "# Opening a URL\n\nVim makes it easy to quickly open a URL that appears in a file. Simply move\nthe cursor over the URL and hit `gx`. This will use your respective\noperating system's *open* command (e.g. `open` for Mac OS X) to open the\nURL.\n\nOne caveat is that the URL must contain the protocol/scheme. That is,\n`www.duckduckgo.com` won't work, but `https://www.duckduckgo.com` will.\n\nYou can also use `gx` to open files on your system.\n"
  },
  {
    "path": "vim/opening-man-pages-in-vim.md",
    "content": "# Opening Man Pages In Vim\n\nIn [Quick Man Pages](quick-man-pages.md), I explained how you can quickly\nopen man pages with `K`. For times when the particular command isn't in the\nbuffer or the command contains a hyphen, you can instead use `:Man`. With\nthe `ft-man-plugin` enabled, you can use `:Man` with the name of any command\nthat has a manual page and the respective man page will be opened in a split\nbuffer. For example, check out `git log` with:\n\n```\n:Man git-log\n```\n\nIf you don't want the first manual entry, provide a specific number. For\ninstance, you can open the `echo(3)` man page with:\n\n```\n:Man 3 echo\n```\n\nSee `:h :Man` for more details.\n"
  },
  {
    "path": "vim/paste-a-register-from-insert-mode.md",
    "content": "# Paste A Register From Insert Mode\n\nGenerally pasting a register is done from Normal mode using `p` or something\nlike `'1p` (the former pasting from the default register, `0`, and the\nlatter pasting from register `1`). Vim also allows you to paste from a\nregister without leaving Insert mode. By hitting `CTRL-R` and then the name\nof the register, Vim will insert the contents of the register in front of\nthe cursor.\n\nFor example, to paste from the default register from Insert mode, hit\n`CTRL-R 0`.\n\nNote, mappings and abbreviations will not be applied to the inserted text.\n\nSee `:h i_CTRL-R` for more details.\n\nh/t Chris Erin\n"
  },
  {
    "path": "vim/preventing-typos-with-abbreviations.md",
    "content": "# Preventing Typos with Abbreviations\n\nAre you are prone to mistyping *the* as *teh* or *function* as *funciton*?\nYou can add one-line abbreviations to your `.vimrc` file to auto-correct\nthese mistakes for you.\n\n```\nabbr teh the\nabbr funciton function\n```\n\nBy adding these (or others) to your vim configuration, whenever you type\nthe misspelled version, vim will know to instantly replace it with the\ncorrect version. This can be handy, but use it sparingly.\n"
  },
  {
    "path": "vim/previous-buffer.md",
    "content": "# Previous Buffer\n\nI often find myself needing to jump back and forth between two buffers. For\ninstance, if I am iterating on a test and the implementation, there is a lot\nof switching from one to the other and then back again.\n\nThis quickest way to do this is to use the command for going to the previous\nbuffer. The default binding for that is `ctrl-^`.\n\nWith that binding, it is fast and easy to toggle between two buffers.\n\n[source](http://vimdoc.sourceforge.net/htmldoc/editing.html#CTRL-^)\n"
  },
  {
    "path": "vim/previous-visual-selection.md",
    "content": "# Previous Visual Selection\n\nTyping `gv` in normal mode will re-select the previous visual selection.\nThis makes it easy to re-select a specific block of text. For instance, if\nyou are performing a search and replace on a visual selection and you didn't\nget the regex quite right, you can quickly type `gv` and then edit the regex\nof your previous command.\n"
  },
  {
    "path": "vim/print-the-relative-path-of-the-current-file.md",
    "content": "# Print The Relative Path Of The Current File\n\nAs a project grows and there are many directories and long path names, Vim\nwill not always have enough room to display the full relative path of the\ncurrent file. It may have to cut off the initial directories which can make\nit hard to know where you are.\n\nYou can hit `Ctrl-g` to quickly display the relative path of the current\nfile below the status bar.\n\n![example of using ctrl-g](https://i.imgur.com/w7gzIIV.gif)\n\nSee `:help Ctrl-g` for more details.\n"
  },
  {
    "path": "vim/print-version-information.md",
    "content": "# Print Version Information\n\nWant to know what version of Vim you are using, plus a bunch of other\ninformation? Try entering\n\n```\n:version\n```\n\nThis will display the version including patches. It will tell you when it\nwas compiled. A list of available and unavailable features is also included.\n\nh/t Chris Erin\n"
  },
  {
    "path": "vim/quick-file-info.md",
    "content": "# Quick File Info\n\nIf you are browsing a directory with vim (e.g. `vim .`) and you want to\nsee information about a file such as the *last modification date* and *file\nsize*, move your cursor to that file's name and type `qf`.\n"
  },
  {
    "path": "vim/quick-man-pages.md",
    "content": "# Quick Man Pages\n\nWithin Vim, if you encounter a command that has man pages (such as `grep`),\nyou can move your cursor over that word in normal mode and press `K`\n(`shift+k`) to view the man pages for that command.\n\n[source](https://twitter.com/vimchi/status/571438478027837440)\n"
  },
  {
    "path": "vim/quick-quickfix-list-navigation.md",
    "content": "# Quick Quickfix List Navigation\n\nThere are lots of commands that will load up Vim's quickfix list with\nresults that you'll want to traverse. For instance, if you use [Fugitive's\n`:Ggrep`](https://github.com/tpope/vim-fugitive/blob/master/doc/fugitive.txt#L94),\nit'll load up the quickfix list with line by line occurrences of the search\nterm.\n\nYou can go forwards and backwards through this list using `:cnext` and\n`:cprevious`. Though this gets a bit tedious to type over and over,\nespecially for long lists of results.\n\nYou can quickly navigate forwards and backwards through these results\nwith two bindings provided by\n[vim-unimpaired](https://github.com/tpope/vim-unimpaired).\n`]q` is mapped to `:cnext`, for going forwards, and `[q` is mapped to\n`:cprevious`, for going backwards.\n"
  },
  {
    "path": "vim/quickly-fix-a-misspelled-word.md",
    "content": "# Quickly Fix A Misspelled Word\n\nIn [Fix The Spelling Of A Word](fix-the-spelling-of-a-word.md), I describe how\nto use Vim's built-in spell files to fix a misspelling. After turning on\n`:spell` and navigating the cursor to a typo, you can open a prompt with dozens\nof spelling replacement options.\n\nYou generally don't need dozens of options to choose from. If you were remotely\nclose in the spelling of the word, you will likely end up choosing the first\noption.\n\nInstead of the multi-step open and choose, you can tell Vim to replace the\nmisspelled word with its top suggestion.\n\nNavigate the cursor over the misspelled word and hit:\n\n```\n1z=\n```\n\nThis skips the prompt and tells Vim to grab the first spelling suggestion.\n\nIf it's not what you were looking for, you can always hit `u` (to undo) and\nthen `z=` to open the full prompt.\n\nSee `:h z=` for more details.\n"
  },
  {
    "path": "vim/quickly-switch-to-a-buffer-by-number.md",
    "content": "# Quickly Switch To A Buffer By Number\n\nThere are a number of different commands you can use for switching to a\nbuffer by its number. For example, if you want to switch to the buffer\nassigned `7`, you can do `:7b` or `:e #7`. However, there is a quicker way\nthan typing out either of those commands.\n\nYou may already be familiar with `CTRL-^` for switching to the _alternate\nfile_ which is generally the previous buffer. If you precede that command\nwith a number, you will switch to the buffer with that number instead of the\nalternate file.\n\nFrom normal mode\n\n```vimscript\n7 Ctrl-^\n```\n\nwill switch to buffer `7`.\n\nSee `:h Ctrl-^` for more details.\n"
  },
  {
    "path": "vim/quit-when-there-is-an-argument-list.md",
    "content": "# Quit When There Is An Argument List\n\nTo start a Vim session with multiple files in the argument list, name\nmultiple files when invoking Vim:\n\n```bash\n$ vim README.md LICENSE\n```\n\nThe first file in the argument list, and the current buffer, is `README.md`.\nThe last file in the argument list is `LICENSE`.\n\nAt this point if you try to quit, Vim will prevent you saying `1 more file\nto edit`. If we look at the docs for `:q` and `:wq`, we see something along\nthe lines of:\n\n> This fails when the last file in the argument list has not been edited.\n\nVim wants to ensure that you've paid attention to every file that you loaded\nup into your argument list. If you'd like to quit regardless. then this is\nwhere the `:q!` and `:wq!` variants come in handy. This commands will skip\nthe argument list check.\n"
  },
  {
    "path": "vim/read-in-the-contents-of-a-rails-file.md",
    "content": "# Read In The Contents Of A Rails File\n\nThe [`rails.vim` plugin](https://github.com/tpope/vim-rails) allows you to\nquickly navigate to specific types of files with the `E` prefix. For\ninstance, `:Emodel` will scope you to just the models directory.\n\nYou can use this same approach with the `D` prefix. Instead of navigating to\nthe specified file though, this will read in the contents of that file into\nthe current buffer.\n\nDo you need to copy and tweak the contents of a similar view? Open up your\nnew view file (e.g. `:Eview posts/edit.html.erb`) and then enter `:Dview\nposts/new` to quickly copy in its contents.\n\nh/t Josh Davey\n"
  },
  {
    "path": "vim/reindenting-your-code.md",
    "content": "# Re-indenting Your Code\n\nIf you have pasted some poorly formatted code or you've written a portion\nof code in a way that mangled the indentation, you can quickly re-indent\nthat code for you. Or at least do its best to try and indent it correctly.\n\nMake a visual selection of the code that you want to re-indent and then\nhit `=`.\n\nFor instance, this ruby code\n\n```ruby\nif this_thing\np something\nelse\np nothing\nend\n```\n\nwill be indented by Vim as\n\n```ruby\nif this_thing\n  p something\nelse\n  p nothing\nend\n```\n\nSee `:h =` for more details on how vim decides what formatting and\nindenting it will do.\n\nh/t [Chris Erin](https://twitter.com/MCNormalMode)\n"
  },
  {
    "path": "vim/rename-a-file-through-netrw.md",
    "content": "# Rename A File Through netrw\n\nYou can browse files in a directory through Vim using netrw. This can be done\nby _editing_ a directory with Vim:\n\n```bash\n$ vim src/\n```\n\nYou'll see a listing of the files and directories in `src`:\n\n```\napp/\nindex.js\nREADME.md\nutils/\n```\n\nYou can move your cursor over one of those files and hit `R` to rename it. A\nprompt will appear at the bottom of your Vim session with the file's current\nname spelled out. You can edit inline and then hit enter to apply the renaming.\n\n[source](https://superuser.com/questions/767026/can-i-rename-files-in-a-directory-with-vim#)\n"
  },
  {
    "path": "vim/rename-current-file.md",
    "content": "# Rename Current File\n\nVim doesn't come with an easy way to rename the existing, current file. The\nclosest you will get with a one-off command is `:saveas {new file name}`\nwhich renames the current buffer, but also leaves you with your old file.\n\nAnother approach that you can take is to chain two commands together. You\ncan start be *deleting* the current file (don't worry, you've still got the\nfile contents in your buffer) and then *saving* the buffer with the new\nname. Like so:\n\n```\n:call delete(expand('%')) | saveas new-file-name.txt\n```\n\nWhile this seems to do the job well enough, your mileage may vary.\nConsider using a more robust plugin, such as\n[vim-eunuch](https://github.com/tpope/vim-eunuch) or\n[rename.vim](https://github.com/danro/rename.vim/blob/master/plugin/rename.vim).\n"
  },
  {
    "path": "vim/repeat-the-previous-change.md",
    "content": "# Repeat The Previous Change\n\nIf you have just performed a change and you realize you want to immediately\ndo it again, you can hit `.` instead of retyping it. This is a good way to\nquickly repeat simple changes.\n\nFor instance, if you are adding indentation to a code block with `>`, you\ncan estimate the number of indents that need to happen and type `3>` or you\ncan indent once and then hit `.` for additional indentation until you reach\nthe right level of indentation.\n\nCheck out the docs for more details: `:help .`\n"
  },
  {
    "path": "vim/repeating-characters.md",
    "content": "# Repeating Characters\n\nIt's not common to need to type 39 space characters in a row, but when the\nmoment arises, you don't want to be caught hitting the space bar 39 times.\nVim makes it easy. From normal mode, type the number, then `i`, and then the\ncharacter to be repeated followed by an escape.\n\nFor instance, for 39 spaces, hit:\n\n```\n39i <esc>\n```\n\nor for 80 dashes, hit:\n\n```\n80i-<esc>\n```\n"
  },
  {
    "path": "vim/replace-a-character.md",
    "content": "# Replace A Character\n\nThroughout the day I'll often find myself deleting a single character and\nputting a different one in its place. I usually navigate over the target\ncharacter and hit `s` which removes the character under the cursor and puts\nme in insert mode. From there I type the new character and hit escape to\nreturn to normal node. This isn't the best way to perform such an edit\nthough. Vim has a command specifically for replacing a character. The `r`\ncommand. It does essentially the same thing as my current approach but\ninstead of putting me in insert mode, it simply replaces the character and\nleaves me in normal node.\n\nSee `:h r` for more details.\n"
  },
  {
    "path": "vim/reset-target-tslime-pane.md",
    "content": "# Reset Target tslime Pane\n\nThe combination of [`tslime`](https://github.com/jgdavey/tslime.vim) and\n[`turbux`](https://github.com/jgdavey/vim-turbux) makes running tests from\nVim in a tmux session as easy as a single key binding. One problem that can\narise from time to time is having `tslime` focused on an undesired tmux\nwindow/pane combination. There is no binding to tell `tslime` that you'd\nlike to re-select the target window and pane.\n\nI've often resorted to closing out of Vim in order to reset the prompt.\nThere is a better way and it doesn't require you to wipe out your Vim\nsession.\n\nJust `unlet` the global Vim variable for the `tslime` plugin like so:\n\n```\n:unlet g:tslime\n```\n\nThe next time you invoke `turbux` it will see that `g:tslime` isn't set and\nwill prompt you for a new window and pane combination.\n\nh/t Josh Davey\n"
  },
  {
    "path": "vim/reverse-a-group-of-lines.md",
    "content": "# Reverse A Group Of Lines\n\nThe following command can be used to reverse the order of all lines in a\nfile by doing a global move on all lines that match the beginning of line\ncharacter starting at the theoretical 0th character:\n\n```\n:g/^/m 0\n```\n\nReversing a range of lines is a little more work. Just as the previous\nexample needs to be anchored against the 0th character, a specific range of\nlines needs to be anchored at the line just before the range. Thus reversing\nthe lines 5 to 10 requires being anchored at line 4, like so:\n\n```\n:4,10g/^/m 4\n```\n\nSee `:h 12.4` for more details on how this works.\n\n[source](http://superuser.com/questions/189947/how-reverse-selected-lines-order-in-vim#)\n"
  },
  {
    "path": "vim/reword-a-commit-message-with-fugitive.md",
    "content": "# Reword A Commit Message With Fugitive\n\nWhen you have the fugitive summary buffer (`:Gedit :`) open and there are\nunpushed commits, you'll see them listed below the working tree and staging area\ndetails. If you notice an issue with the wording of any of those commits, you\ncan initiate an interactive rebase to reword the commit from that window.\n\nNavigate the cursor over that commit and then hit `rw` (for _reword_).\n\nThis will split open an interactive rebase buffer with `reword <SHA>`. Save that\nbuffer and the commit message will be opened into a buffer where it can be\namended, just like if you were to amend a commit with an interactive rebase from\nthe CLI.\n\nThe `rw` binding can be used in any fugitive view where commits are listed. For\ninstance run `:Git log`, navigate to any commit, and then hit `rw`.\n\nSee `:h fugitive_r` for details about all the rebase mappings.\n"
  },
  {
    "path": "vim/rotate-everything-by-13-letters.md",
    "content": "# Rotate Everything By 13 Letters\n\nFor some inane reason, Vim comes with a\n[ROT-13](https://en.wikipedia.org/wiki/ROT13) feature. So, if you are ever\nin need of rotating the letters of some portion of the file by 13, you can\ndo that with the simple `g?` binding.\n\nFor example, if you hit `g??` on the following line:\n\n```\nSix dollar eggs\n```\n\nyou will get\n\n```\nFvk qbyyne rttf\n```\n\nAs you can see, casing is preserved.\n\nThe only practical uses of this are Vimgolf and convincing people at coffee\nshops that you are a hacker.\n\nSee `:h g?` for more details.\n"
  },
  {
    "path": "vim/rotate-the-orientation-of-split-windows.md",
    "content": "# Rotate The Orientation Of Split Windows\n\nLet's say you have a vim session going with a single window/buffer open. If you\nwere to then open another file with the split command (e.g. `:sp README.md`),\nthen you'd have a horizontal split. With one file above and one file below.\n\nYou can rotate the orientation of the split to be a vertical split with one\nfile on the left and another on the right. You can do this with a _Window\nCommand_—`Ctrl-W H` (that's `ctrl-w` and then capital `H`).\n\nIf you want to go the other direction—from a vertical split to a horizontal\nsplit—you can use `Ctrl-W J` (that's `ctrl-w` and then capital `J`).\n\nThis trick only works when there is a split between two windows. When\nadditional splits are involved, it will rotate the focused window to that\norientation and leave the others stacked in their current orientation.\n\nSee `:h CTRL-W` for more details on these and other Window Commands.\n"
  },
  {
    "path": "vim/running-bundle-with-vim-bundler.md",
    "content": "# Running Bundle With vim-bundler\n\nThe [`vim-bundler`](https://github.com/tpope/vim-bundler) plugin is a\ncompanion of the [`rake.vim`](https://github.com/tpope/vim-rake) and [`rails.vim`](https://github.com/tpope/vim-rails) plugins. It is a lightweight plugin that exposes some bundler-related convenience methods.\n\nThe Vim `:Bundle` command exposes the `bundle` command. To install the latest\nchanges to the `Gemfile`, you can invoke `:Bundle` or `:Bundle install` from\ninside of Vim.\n"
  },
  {
    "path": "vim/scrolling-relative-to-the-cursor.md",
    "content": "# Scrolling Relative to the Cursor\n\nIf you hit `zt` while in normal mode, the window will be redrawn such that\nthe line the cursor is positioned on is at the top of the window. Similarly,\nif you hit `zb`, the window will be redrawn such that the line the cursor is\ncurrently on will be at the bottom of the window.\n\nThe one that comes in really handy, though, is `zz` (note: this is not\n`ZZ`) which will reposition the current line to the center of the screen.\nThis can come in really handy if you have scrolled to the top (or bottom) of\nthe visible part of the buffer and you want to quickly view more of the\ncontext around the current line.\n\nSee `:h scroll-cursor` for more details and commands.\n"
  },
  {
    "path": "vim/search-backward-through-a-file.md",
    "content": "# Search Backward Through A File\n\nThere are a number of ways to search for a match in a file. One I use quite\noften is hitting `*` while the cursor is over the word I want to find\nmatches for. It searches forward jumping to the next occurrence of that\nword.\n\nIt turns out there is a way of doing the same thing, but searching backward\nto the previous occurrence of the word. If you hit `#` with the cursor over\na word, it will jump backward through the file until it finds an occurrence\nof that word. Keep hitting `#` to keep searching backward.\n\nSee `:h #` for more details.\n"
  },
  {
    "path": "vim/searching-for-hex-digits.md",
    "content": "# Searching For Hex Digits\n\nIf you want to find sequences of hex digits (`A-F`, `a-f` and `0-9`) in a\nsearch, you can hack together something like:\n\n```\n/[A-Fa-f0-9]\\+\n```\n\nThis is a bit verbose, though. Vim has a number of built in character\nclasses that can be referenced in searches and substitutions. For hex\ndigits, there is `\\x`. Using this, the search above can be achieved with:\n\n```\n/\\x\\+\n```\n\nSee `:h \\x` for more details and other character classes.\n"
  },
  {
    "path": "vim/select-several-results-from-an-fzf-search.md",
    "content": "# Select Several Results From An FZF Search\n\nWhen performing a fuzzy search in Vim with\n[FZF](https://github.com/junegunn/fzf.vim), you likely get a mix of results\nyou care about and results that are just noise. FZF allows you to narrow\ndown to just the results you care about. Move the cursor over each result of\ninterest and hit tab. Little red arrows will show next to each item you have\nselected.\n\n![multi-select with fzf](https://i.imgur.com/6nJY5Ik.png)\n\nWhen you are done hit enter. Each result will be opened as a separate\nbuffer. You can then navigate between them using your preferred method of\nmoving between buffers -- i.e. `:bnext` and `:bprev`.\n"
  },
  {
    "path": "vim/set-end-of-line-markers.md",
    "content": "# Set End Of Line Markers\n\nVim has a number of invisible characters that you can set.\nOne of those characters is the end of line (`eol`) character.\nWhatever character you\nset this to will appear at the end of each line in your file. This is great\nfor highlighting extra whitespace at the end of a line that would otherwise\nappear invisible.\n\nSet the `eol` invisible character like so\n\n```\n:set listchars=eol:¬\n```\n\nor append it to the existing list of invisible characters like so\n\n```\n:set listchars+=eol:¬\n```\n\nSee `:h listchars` to see what other invisible characters you can set.\n"
  },
  {
    "path": "vim/set-your-color-scheme.md",
    "content": "# Set Your Color Scheme\n\nVim ships with a number of standard color schemes for both light and dark\nbackgrounds. You can also find and install many others. To set your color\nscheme, you can use the `:colorscheme` command. You can quickly see what\ncolor schemes are available by typing `:colorscheme` and then tabbing for\ncompletion. For instance, you can set the *delek* color scheme by entering\n\n```\n:colorscheme delek\n```\n\nSee `:h colorscheme` for more details.\n"
  },
  {
    "path": "vim/setting-filetype-with-modelines.md",
    "content": "# Setting Filetype With Modelines\n\nVim and various plugins generally use known file extensions to determine the\nfiletype of a file. This is important because it is how Vim decides which\nfiletype-specific settings to enable, such as syntax highlighting.\n\nIf I am editing a file such as `build.boot`, Vim is not going to know that\nits filetype should be set to `clojure`. The `build.boot` file is full of\nclojure code though, so I'm losing out on syntax highlighting and so forth.\nI can settle for manually setting the filetype to clojure (e.g. `:set\nft=clojure`) each time I open up the file.\n\nOr I can use a modeline setting. By including a comment at the top or\nbottom of the file specifying the filetype setting, I can ensure that each\ntime I go to edit the file, the appropriate filetype will be set.\n\nThat modeline comment will look something like:\n\n```clojure\n; vim: set ft=clojure:\n```\n\nSee `:h modeline` for more details.\n\nh/t Brian Dunn\n"
  },
  {
    "path": "vim/show-all-syntax-highlighting-rules.md",
    "content": "# Show All Syntax Highlighting Rules\n\nWhen Vim adds syntax highlighting to the contents of a buffer based on its\n`filetype`, it does so with a set of rules. These rules specify particular\ncolors for each set of named tokens that match particular patterns. You can\ncheck out the syntax highlighting rules for the current `filetype` of the\ncurrent buffer by running:\n\n```\n:syntax\n```\n\nSee `:h :syntax` for more details.\n"
  },
  {
    "path": "vim/show-matching-entries-for-help.md",
    "content": "# Show Matching Entries For Help\n\nLooking up things with Vim's `:help` command can be error prone if you don't\nknow exactly how to format what you are looking up. Bypass some of the\nguesswork by hitting `Ctrl-d` after writing part of the `:help` command.\nThis will populate a wildmenu of possible matches.\n\nFor instance, if you know there is a command containing `?`, but you aren't\nsure how to look it up, try the following:\n\n```\n:help ?<Ctrl-d>\n```\n\nYou can tab through to the one you want and hit enter to read up on it. Who\nknew there were so many Vim bindings involving a `?`.\n\nSee `:h help-context` for more details.\n"
  },
  {
    "path": "vim/source-original-vimrc-when-using-neovim.md",
    "content": "# Source Original vimrc When Using Neovim\n\nIf you install [Neovim](https://neovim.io/) and open up a new `nvim` session,\nyou might notice that none of your carefully crafted `~/.vimrc` configuration\nis taking effect.\n\nThis is because the `~/.vimrc` file is not part of Neovim's default\n`runtimepath` (see `:h runtimepath` for details on what is included).\n\nFor custom user-land configuration of your Neovim sessions, you should start\nwith an `init.vim` file. For Mac users, it will likely be placed in\n`~/.config/nvim/`. To be sure where it belongs, you can run `:echo\nstdpath('config')`.\n\nIn that file, you can add any Neovim-specific configuration. You can also take\nthe opportunity to source your `~/.vimrc` file so that you get all those\nconfigurations. These lines will do the trick.\n\n```vimrc\nif filereadable(expand('~/.vimrc'))\n  source ~/.vimrc\nendif\n```\n\nThings tend to be backward compatible, so you aren't likely to run into issues\nwith what's in your `~/.vimrc`. At any rate, it is a good starting point for\ngetting back to a familiar configuration.\n\nSee `:h nvim` for more details about how to transition.\n"
  },
  {
    "path": "vim/specify-the-line-height-of-the-quick-fix-window.md",
    "content": "# Specify The Line Height Of The Quick Fix Window\n\nYou can use the following command to open the Quick Fix window:\n\n```\n:copen\n```\n\nBy default the Quick Fix window will open with a height of 10 lines, meaning\nit can fit 10 lines of text. You may want to specify the height of the quick\nfix window when you open it, especially if you are working with limited\nscreen space. This can be done by prepending the command with a _height_.\n\n```\n:5copen\n```\n\nThis will open the Quick Fix window with a height of 5 lines.\n\nSee `:h copen` for more details.\n"
  },
  {
    "path": "vim/split-different.md",
    "content": "# Split Different\n\nVim's defaults for `:split` and `:vsplit` are to open the splits above and\nto the left, respectively. I prefer for them to the split below and to the\nright, respectively. To get `:split` to split below:\n\n```\n:set splitbelow\n```\n\nand to get `:vsplit` to split to the right:\n\n```\n:set splitright\n```\n\nAdd those two lines to your `.vimrc` to have them set that way all the time.\n\nIf you have them set as such in `.vimrc` and want to temporarily revert the\nsetting for the current file, type:\n\n```\n:set nosplitbelow\n```\n\nor\n\n```\n:set nosplitright\n```\n\nas commands.\n"
  },
  {
    "path": "vim/split-the-current-window.md",
    "content": "# Split The Current Window\n\nGenerally when I want to open up a buffer in a window split, I use `:sp` or\n`:vsp` and type out the filename. It may be a bit more convenient to use\nwindow commands to create the splits.\n\nTo open a horizontal split:\n\n```\nCtrl-w s\n```\n\nTo open a vertical split:\n\n```\nCtrl-w v\n```\n\nWith the split made, you can use `Ctrl-o`/`Ctrl-i`,\n[BufExplorer](https://github.com/jlanzarotta/bufexplorer), or whatever way\nyou like to navigate between buffers.\n\nh/t Ryan Messner\n"
  },
  {
    "path": "vim/splitting-for-new-files.md",
    "content": "# Splitting For New Files\n\nLet's assume you already have a vim session open. You now want to open a new\nfile. You can open a new horizontally split window with the `:new` command.\nAlternatively, if you'd like the new window to open with a vertical split,\nyou can use the `:vnew` command.\n\nSee `:new` and `:vnew` for more details.\n"
  },
  {
    "path": "vim/sum-a-bunch-of-numbers-in-the-current-file.md",
    "content": "# Sum A Bunch Of Numbers In The Current File\n\nLet's say I have a bunch of big numbers on consecutive lines in the file I\ncurrently have open in Vim. Like this:\n\n```\n   418564\n   921550\n  1180181\n  1234458\n  2706100\n 15954945\n 16254608\n```\n\nIf I make a visual selection of those numbers and then hit `:`, it will open a\ncommand prompt for the beginning (`'<`) to the end (`'>`) of the visual\nselection. I can then shell out those lines to an external command by starting\nthe command with `!`. The command to shell out to for this scenario is `awk`\nwhich can sum up values from a \"file\" in a single line.\n\nThe whole thing will look like this:\n\n```\n:'<,'>!awk '{s+=$1} END {print s}'\n```\n\nHit enter. Then `awk` will produce the sum and replace the highlighted lines\nwith that value.\n\n```\n38670406\n```\n\n[source](https://stackoverflow.com/a/450821)\n"
  },
  {
    "path": "vim/swap-occurrences-of-two-words.md",
    "content": "# Swap Occurrences Of Two Words\n\nImagine I have a file with `foo` and `bar` all over the place. The tables\nhave turned and now I want all occurrences of `foo` to be `bar` and all\noccurrences of `bar` to be `foo`.\n\nReaching for a simple substitution won't work because after flipping all the\noccurrences of `foo` to `bar`. I will no longer be able to distinguish\nbetween the new `bar`s and the `bar`s that need to be flipped.\n\n[Abolish.vim](https://github.com/tpope/vim-abolish) enhances Vim's\nsubstitution capabilities making it easy to flip these strings in one\nrelatively simple command.\n\n```\n:%S/{foo,bar}/{bar,foo}/g\n```\n\nNotice the uppercase `S` as well as the ordering of `foo` and `bar` in the before\nand after sequences.\n"
  },
  {
    "path": "vim/swap-the-position-of-two-split-windows.md",
    "content": "# Swap The Position Of Two Split Windows\n\nA Vim workflow that I often end up in is one where I have two windows split\neither vertically or horizontally. I'm usually editing in one side of the split\nand referencing something from the other side of the split.\n\nI typically like to have the split them I'm editing in on the top or to the\nleft. If the split that I want to edit from ends up in the bottom or to the\nright, I can swap its position with the other window using one of Vim's window\ncommands. These are typically prefixed with `Ctrl-w`.\n\nSwapping the position of two windows is the same as rotating them, either to\nthe left or to the right. In that case, I can use either of these commands:\n\n```\nCtrl-w Ctrl-r # rotates windows downwards/rightwards\nCtrl-w r      # rotates windows upwards/leftwards\n```\n\nSee `Ctrl-W_Ctrl-R` for more details.\n"
  },
  {
    "path": "vim/swapping-split-windows.md",
    "content": "# Swapping Split Windows\n\nConsider a scenario where you have a vim window that has been split\nhorizontally into two viewports. You'd prefer the top one to be on bottom\nand the bottom one to be on top. You want to swap them.\n\nIf you are currently focused on the top viewport, then tell vim to move that\nviewport down with `CTRL-w J`. As you might guess, moving the bottom\nviewport up can be done with `CTRL-w K`. `J` and `K` mean down and up in\nother contexts; vim is consistent with their meaning here.\n\nViewports of a vertical split can be swapped in the same sort of way. Use\n`CTRL-w L` to move the left viewport to the right. Use `CTRL-w H` to move\nthe right viewport to the left.\n"
  },
  {
    "path": "vim/switch-moving-end-of-visual-selection.md",
    "content": "# Switch Moving End Of Visual Selection\n\nWhen I go into character-wise visual selection mode, one end of the visual\nselection is fixed while I move my cursor around to define the other end of it.\n\nLet's say I've arranged a visual selection that encompasses several lines of my\nfile. And then I realize that the fixed front-end of my visual selection is off\nby a bit. Maybe I've selected an entire function definition and I just want to\ninner part of the function.\n\nInstead of starting over with my visual selection. I can leave the right-end of\nthe visual selection where it is, hit `o` which will switch the moving end to\nthe other side, and then continue making adjustments from there.\n\nI can always hit `o` again to switch it back to the original side.\n\nSee `:h v_o` for more details.\n"
  },
  {
    "path": "vim/tabs-to-spaces.md",
    "content": "# Tabs To Spaces\n\nIf you prefer spaces over tabs in your files, then opening up a file full of\ntabbed indentation is not ideal. You can quickly convert all tabs in the\ncurrent buffer to spaces using:\n\n```\n:retab\n```\n\nThis assumes that you have `expandtab` set. See `:help :retab` for more\ndetails.\n"
  },
  {
    "path": "vim/the-black-hole-register.md",
    "content": "# The Black Hole Register\n\nVim has a variety of registers for storing and moving around text. Vim also\nhas a special register called the *black hole register*. This black hole\nregister is associated with the `_` character.\n\n> When writing to this register, nothing happens.  This can be used to delete\n> text without affecting the normal registers.  When reading from this register,\n> nothing is returned.\n\nAs stated in the docs, if you don't want to overwrite the unnamed register or\nsome other register when deleting text, you can use the black hole register.\nFor instance, deleting the current line without any register side-effects\nlooks like this:\n\n```\n\"_dd\n```\n\nSee `:h registers` for more info on Vim's registers.\n"
  },
  {
    "path": "vim/the-vim-info-file.md",
    "content": "# The Vim Info File\n\nVim serializes a bunch of useful information as you edit files, jump around,\nand execute commands. This is so that vim can recall this information in\nbetween sessions. Vim creates a Vim Info file (`~/.viminfo`) in your home\ndirectory which it uses to enhance your long-term experience with the\neditor. File marks, registers, command and search history, and jump history\nare some of the more interesting things that vim stores there.\n\nRead more about it at `:help viminfo` or just take a look at the file with\n`vim ~/.viminfo`.\n"
  },
  {
    "path": "vim/toggle-absolute-and-relative-paths-in-bufexplorer.md",
    "content": "# Toggle Absolute And Relative Paths In BufExplorer\n\nAfter opening [BufExplorer](https://github.com/jlanzarotta/bufexplorer)\nusing `<leader>bs`, you will see both files and the paths to those files. By\ndefault you will see absolute paths to the files. You can use `R` to toggle\nbetween relative and absolute paths.\n\nFor relative paths, the path will be relative to the current working\ndirectory of the Vim session (`:pwd`).\n"
  },
  {
    "path": "vim/toggling-syntax-highlighting.md",
    "content": "# Toggling Syntax Highlighting\n\nSyntax highlighting in Vim is generally a good thing, but sometimes you need\nto turn it off. This can be achieved with the `syntax` command.\n\n```vim\n:syntax off\n```\n\nWhen you need that syntax highlighting back again, you can turn it right\nback on like so:\n\n```vim\n:syntax on\n```\n\nSee `:h syntax-on` for more details.\n\nh/t Steve Klabnik\n"
  },
  {
    "path": "vim/turning-of-search-highlighting.md",
    "content": "# Turning Off Search Highlighting\n\nAfter performing a search for a common word, you end up with that word\nhighlighted all over the place. To turn it off, I generally use the `set`\ncommand with `no` prepended to the `hlsearch` option -- as is convention in\nVim.\n\nIt turns out though, that `nohlsearch` is a command in its own right. I can\nsave a few characters by invoking:\n\n```\n:nohlsearch\n```\n\nSee `:h nohlsearch` for more details.\n"
  },
  {
    "path": "vim/unloading-a-buffer.md",
    "content": "# Unloading A Buffer\n\nMy preferred workflow with vim involves working across as many buffers as I\nneed in a single window. I open files in new buffers as needed and navigate\nbetween existing ones with a number of built-in vim features and plugin\nshortcuts. Eventually though, my list of buffers gets a bit crowded making\nit difficult to move around and keep everything straight. One method for\ndealing with this is occasionally unloading the buffers you no longer need.\nThis can be accomplished with `:bd`.\n\nTo unload the current buffer:\n\n```\n:bd\n```\n\nTo unload some other buffer by buffer number, say buffer 10:\n\n```\n:10bd\n```\n\nCaveats: unloading a buffer marks it as *unlisted* in the buffer list,\nmeaning it won't appear in your normal view of the buffer list. It should\nalso be noted that it does not remove the buffer from the jump list or the\nglobal mark list.\n\nSee `:h :bd` for more details.\n"
  },
  {
    "path": "vim/use-active-window-with-bufexplorer.md",
    "content": "# Use Active Window With BufExplorer\n\nI often use [BufExplorer](https://github.com/jlanzarotta/bufexplorer) within\nlong-running Vim sessions as a way of quickly jumping between the various\nbuffers in my buffer list. After working with one buffer, I use `<leader>bs`\nto open BufExplorer, move my cursor to the next buffer of interest, and hit\nenter to open it in place of the current buffer. This is the default\nbehavior at least.\n\nWith this setting toggled on, BufExplorer will open buffers in the _active\nwindow_. The _active window_ is the window that was active before\nBufExplorer was opened. If this setting is toggled off, BufExplorer doesn't\nbother finding the active window, it just opens the buffer up in place of\nitself in whatever split window was created for itself.\n\nThis setting can be toggled within the BufExplorer window by hitting `f`. It\nwill toggle between `Locate Buffer` and `Don't Locate Buffer`. I prefer the\ndefault of `Locate Buffer`.\n\nh/t Vidal Ekechukwu\n"
  },
  {
    "path": "vim/use-the-terminal-inside-a-vim-session.md",
    "content": "# Use The Terminal Inside A Vim Session\n\nWith [the release of Vim 8.1](https://www.vim.org/vim-8.1-released.php) comes\nthe ability to open a terminal window _within_ a Vim session.\n\nThe `:terminal` command (or `:term` for short) opens up a buffer window that\nlooks like a strange mix between any old Vim session and your terminal's shell\nprompt.\n\nOnce the `:terminal` window is open, you can hit `i` to switch to\n_terminal-mode_. This puts the cursor on the shell prompt so that you can start\nexecuting shell commands. Once in this mode, you most of your keybindings will\nbe ignored as Vim is providing terminal emulation.\n\nOnce you are done with the terminal, you can type `exit` like you would in any\nother shell and it will terminate that process.\n\nAlternatively, you can hit `Ctrl-\\ Ctrl-n` which takes you out of terminal-mode\nand back into Normal mode. From here, you can use all the Vim things to\nnavigate, search, yank, etc. from the terminal output.\n\nYou can also (if `hidden` is set), switch to another buffer. The Vim `:term`\nbuffer is preserved and you can return to it later, hitting `i` to start\ninteracting with it again.\n\nSee `:h :term` for more details.\n"
  },
  {
    "path": "vim/using-vim-surround-with-a-visual-selection.md",
    "content": "# Using vim-surround With A Visual Selection\n\nThe [`vim-surround`](https://github.com/tpope/vim-surround) plugin allows\nyou to do a variety of actions that have to do with the surrounding\ncharacters of text objects.\n\nThe `S` keystroke allows you to surround a visual selection with the\nfollowing character.\n\nFirst, make a visual selection. Then hit `S`. Then hit a surround character\nsuch as `(` or `[` and the area of text that has been visually selected will\nbe wrapped with the respective surround characters.\n"
  },
  {
    "path": "vim/verbose-commits-with-fugitive.md",
    "content": "# Verbose Commits With Fugitive\n\nLet's say you are using [fugitive.vim](https://github.com/tpope/vim-fugitive).\nYou've staged some changes within the git index buffer using `:Ge:` and now\nyou want to make a commit. From the git index buffer, you can hit `cvc` to\npop open the commit message window in verbose mode. The verbose part means\nthat all the staged changes are shown below as a reference for composing the\ncommit message.\n"
  },
  {
    "path": "vim/view-commit-history-of-a-file.md",
    "content": "# View Commit History of a File\n\n[Gitv](https://github.com/gregsexton/gitv) is an extension of the\n[Fugitive](https://github.com/tpope/vim-fugitive) plugin that allows you to\nview and step through the commit history of a file (among other things).\n\nOpen a file in Vim and enter the `:Gitv!` command to open a preview window\nlisting the commits involving the current file. It will look something like\nthis:\n\n```\n-- [plugin/fugitive.vim] --\n*  (HEAD, r:origin/master, r:origin/HEAD, master) Provide g:fugitive_no_maps to disable key maps  4 weeks ago            Fedor Gusev    [0095769]\n*  Support browsing with new netrw.vim                                                            2 weeks ago            Eli Young      [e8b9409]\n*  Support for browsing with recent Vim                                                           4 weeks ago            Tim Pope       [eb8eb18]\n*  s:Diff: use winnr with `<C-W>w` instead of `<C-W>p`                                            6 weeks ago            Daniel Hahler  [933f6a1]\n*  (tag: t:v2.2) fugitive.vim 2.2                                                                 7 weeks ago            Tim Pope       [3471901]\n*  Use `<nomodeline>` with Fugitive autocmds, and un-silent them                                  4 months ago           Daniel Hahler  [2c8461d]\n*  Make configured_tree a caching global function                                                 4 months ago           John Whitley   [d3b98d9]\n*  Fix instaweb support                                                                           4 months ago           Tim Pope       [5699f46]\n*  Fix :Glog                                                                                      6 months ago           Tim Pope       [0374322]\n```\n\nYou can skim over these commits and when one looks interesting, just hit\n`enter` when your cursor is over its respective line to view the file as it\nwas at the time of that commit.\n\nRestore your buffer to its original state by navigating to the top of the\npreview and hitting `enter` for the filename on the first line.\n\nThis tool is great for use in a team setting when you want to figure out\nwhat changes a file has undergone recently, especially when something about\na file seems a little fishy. This is also great for individual and team use\nwhen you simply cannot remember why you changed a file or what it used to\nlook like before that *clever* refactoring.\n"
  },
  {
    "path": "vim/view-the-current-file-in-github.md",
    "content": "# View The Current File In GitHub\n\nSometimes when I'm browsing some code in Vim, I'll want to open up the a file\nin GitHub. This is usually so that I can grab a URL to share as a point of\nreference in a conversation.\n\nTo do this, I run [`vim-fugitive`](https://github.com/tpope/vim-fugitive)'s\n`:Gbrowse` which will open up the current file for the current commit on the\ncurrent branch.\n\nThis works great if your current branch is the `main` branch. Or if your\ncurrent branch has previously been pushed up as a remote. It doesn't work so\nwell if you are on a local-only feature branch. You'll get the classic Star\nWars themed GitHub 404 page.\n\nThere is a handy workaround. You can specify the branch and file you want when\nyou run the command.\n\n```\n:Gbrowse main:app/models/user.rb\n```\n\nThat will open the specified file (`app/models/user.rb`) as it exists on the\nspecified branch (`main`).\n\nA shorthand of that for the current file looks like this:\n\n```\n:Gbrowse main:%\n```\n"
  },
  {
    "path": "vim/viewing-man-pages-with-man-vim.md",
    "content": "# Viewing Man Pages with man.vim\n\nIn [Quick Man Pages](quick-man-pages.md), I introduced `K` which shells\nout to the man page for the unix command under the cursor. It gets better\nthough. Vim has a built-in plugin, `man.vim`, that you can enable which\nallows you to view man pages without shelling out.\n\nAdd the following to your `.vimrc` file\n\n```vimscript\nruntime! ftplugin/man.vim\n\" grep\n```\n\nThen save it and re-source the configuration with `:source %`.\n\nWith the `man.vim` plugin enabled, you can now move your cursor over the\nword `grep` and hit `<leader>K` which will pop open the man page for `grep`\nin a unnamed, split buffer.\n\nNot only does this prevent context-switching when viewing a man page, but it\nalso gives you the full power of vim over the content of the man page. You\ncan search, you can yank text, or you can even pop open the man page for\nanother command.\n\nSee `:h ft-man-plugin` for more details.\n"
  },
  {
    "path": "vim/vim-without-the-extras.md",
    "content": "# Vim Without The Extras\n\nIf you want to start up vim without loading all the usual plugins, you\ncan supply the `--noplugin` flag\n\n```\n$ vim --noplugin coffee.rb\n```\n\nYou can take things even further by instead telling vim to open without\nloading any plugins or configuration files. That is, you can tell vim to\nskip all initializations.\n\n```\n$ vim -u NONE coffee.rb\n```\n\nIf you are used to lots of syntax highlighting, custom bindings, and\nother niceties, this may feel rather foreign.\n\nh/t [Jake Worth](https://twitter.com/jwworth)\n"
  },
  {
    "path": "vim/what-is-on-the-runtime-path.md",
    "content": "# What Is On The Runtime Path?\n\nAll of the plugins, syntax highlighting, language-specific indentation that\nextend the default behavior of Vim are on the runtime path. If something\nisn't on Vim's runtime path, then Vim won't know about and as a result will\nnot load it at _runtime_.\n\nHow do we see what is on the runtime path?\n\nThe `rtp` option is the shorthand for `runtimepath`. Calling `set` on either\nof these will show us the list of runtime paths, or at least some of them.\n\n```\n:set rtp\n```\n\nThis will generally be a truncated list if you have a lot of plugins. To be\nsure you are seeing all of them, use `echo` instead.\n\n```\n:echo &rtp\n```\n\nSee `:h rtp` for more details.\n\nh/t Chris Erin\n"
  },
  {
    "path": "vim/whole-line-auto-completion.md",
    "content": "# Whole Line Auto-Completion\n\nTo get whole line auto-completion in Vim, you don't need a fancy plugin. It\nis built right in. There is a sub-mode of insert mode called *X mode* that\nallows you to do various kinds of special insertions. The `ctrl-x ctrl-l`\nbinding corresponds to whole line completion. So, if you start typing a few\ncharacters and then (while still in insert mode) hit `ctrl-x ctrl-l` you\nwill see a completed line that matches the initial characters you typed as\nwell as a list of subsequent matches. You can cycle through the matches\nusing `ctrl-n` and `ctrl-p` (going forward and backward, respectively).\n\nThe completion is done based on the configured completion sources.\nGenerally, the completion sources will include the current buffer, other\nloaded and unloaded buffers, plus others. You can see which sources are\nconfigured with `:set complete?` and read more about the completion\nconfiguration at `:h 'complete'`.\n"
  },
  {
    "path": "vim/wrap-with-some-room.md",
    "content": "# Wrap With Some Room\n\nThe [surround.vim](https://github.com/tpope/vim-surround) plugin allows\nyou to wrap text objects with various surrounding characters\n(e.g. `( )`, `{ }`, `\" \"`).\nIf you have a visual selection on `1 2 3 4 5` and type `S]` you will get:\n\n```\n[1 2 3 4 5]\n```\n\nThat works, but if you prefer a more readable version with some extra\nbreathing room, you can make the visual selection and hit `S[` which will\nstick a space on either end:\n\n```\n[ 1 2 3 4 5 ]\n```\n\nNow, if you already have some text wrapped in square braces, like the\nfirst example, and you want to convert it to the more spacious second\nexample, you can do a *change surround* command followed by hitting the\nopen square brace twice (that is, `cs[[`) which will convert\n`[1 2 3 4 5]` to `[ 1 2 3 4 5 ]`.\n"
  },
  {
    "path": "vscode/add-the-vscode-cli-to-your-path.md",
    "content": "# Add The VSCode CLI To Your Path\n\nVisual Studio Code has a command line tool that can do a bunch of things.\nPerhaps the most common is opening up the current directory from the\ncommand line.\n\nFirst, you need to add `code` to your path. This can be done from within\nCode itself.\n\nHit `Cmd+Shift+p` to pop open the command palette. Then start typing `Shell\nCommand ...` until the `Shell Command: Install \"code\" command in shell PATH`\noption appears. Select this and Code will add `code` to your path.\n\nTry `code .` to open the current directory or run `code --help` for more\ndetails on what's available.\n"
  },
  {
    "path": "vscode/advance-through-search-results.md",
    "content": "# Advance Through Search Results\n\nDoing a project-wide search can turn up a bunch of results. If you'd like to\nlook over them one by one, there are keybindings to help you out.\n\nHit `F4` to move forward one by one through the search results.\n\nTo move backward through the results, hit `Shift+F4`.\n"
  },
  {
    "path": "vscode/enable-breadcrumbs-for-version-126-release.md",
    "content": "# Enable Breadcrumbs For Version 1.26 Release\n\nThe latest release of Code ([Version\n1.26](https://code.visualstudio.com/updates/v1_26)) brings about a lot of\nexciting new features -- including file breadcrumbs at the top of each file\neditor view.\n\n![Breadcrumbs feature in action](https://i.imgur.com/wubUn6c.png)\n\nBy default this feature is not enabled. You can enable it from User Settings\n(`Cmd+Shift+P`, 'User Settings'). From the User Settings view, you can\nsearch for `breadcrumbs` and you'll see the following item:\n\n```json\n  \"breadcrumbs.enabled\": false,\n```\n\nUse the pencil to override it to `true` and you'll have that trail of\nbreadcrumbs waiting for you.\n"
  },
  {
    "path": "vscode/find-the-location-of-user-settings-json-file.md",
    "content": "# Find The Location Of User Settings JSON File\n\nThere are a ton ways to customize and fine-tune VS Code. All of the settings\nhave defaults which can then be customized on a workspace and user level.\nTypically you'll access these files within VS Code via the Command Palette. I\nwas curious though: since it is just a JSON file, surely I can view and modify\nit with any editor.\n\nOn a Mac, the user-level `settings.json` file is located at\n`~/Library/Application\\ Support/Code/User/settings.json`.\n\nOpen it up and you might see something like this:\n\n```json\n{\n  \"editor.formatOnSave\": true,\n  \"editor.defaultFormatter\": \"esbenp.prettier-vscode\",\n  \"window.zoomLevel\": 1,\n  \"workbench.editor.showTabs\": \"single\"\n}\n```\n\nA handful of settings with specific overrides.\n\nFeel free to edit what is in here or add other settings that you want to set.\nJust make sure you know what you're doing and that you set valid values.\n\nThe VS Code docs list [the locations of these files on other operating\nsystems](https://code.visualstudio.com/docs/getstarted/settings#_settings-file-locations).\n\n[source](https://stackoverflow.com/questions/53840644/location-of-vs-code-preferences)\n"
  },
  {
    "path": "vscode/jump-to-problems-in-the-current-file.md",
    "content": "# Jump To Problems In The Current File\n\nVSCode has a system for different extensions to report problems. The editor\nwill visually flag those problems in the editor with a red squiggly underline.\nIt will also list them in the _Problems_ tab of the bottom tray (hit `Cmd+j` to\npop that tray open).\n\nIf there are some active problems in your current file, you can jump right to\nthem.\n\nHit `F8` and you'll jump to the next problem after wherever the cursor is. Hit\n`F8` again and it will go to the next one.\n\nWant to track back through the file? Hit `Shift+F8` and you'll jump to the\nclosest problem _behind_ the current cursor position.\n\nUsing these two, you can quickly survey the current problems in your file\nbefore deciding how to proceed.\n"
  },
  {
    "path": "vscode/open-an-integrated-terminal-window.md",
    "content": "# Open An Integrated Terminal Window\n\nVisual Studio's Code editor offers an integrated terminal that can be used\nfor any of your bash needs -- tests, various git commands, etc.\n\nYou can toggle the integrated terminal window open and closed with\n\n```\nCtrl+`\n```\n\nThe shell session will be opened to the working directory of your current\nproject.\n"
  },
  {
    "path": "vscode/open-file-on-remote-like-github.md",
    "content": "# Open File On Remote Like GitHub\n\nOne of my favorite `vim-fugitive` features is being able to run the `:GBrowse`\ncommand to open the current file or current selection of lines to GitHub in the\nbrowser. This is useful for getting a shareable URL or even just being a\nstarting point for browsing the codebase from GitHub.\n\nVSCode (as well as Cursor) supports this functionality as well. There are a\ncouple ways to do it.\n\nFirst, from the File Browser sidebar you can right click on a particular file or\ndirectory. Find the _Open on Remote (Web)_ submenu. From there select _Open File\non Remote_. That will open the file in GitHub with the focused line highlighted\n(or will open to that directory, as the case may be).\n\nAlternatively, you can right click in the file editor and follow the exact same\nsteps as described above.\n\nIf you're wanting a permalink to the remote that highlights a selection of\nlines, you can highlight that section of lines and right-click the selected\nlines and again follow the steps above.\n\nIf your remote is some other host like BitBucket, it will recognize that from\nyour project's gitconfig and open to that instead of GitHub.\n"
  },
  {
    "path": "vscode/pop-open-the-quick-fix-window.md",
    "content": "# Pop Open The Quick Fix Window\n\nOften when I see a red squiggly in VS Code, it is because I'm missing an import\nfor entity in my code. I have a couple options.\n\n1. I could scroll to the top of the file and manually add the import to my list\n   of imports.\n2. I can mouse over the offending function to see the error, carefully mouse\n   over to _Quick Fix_ link, and get at the quick fix list that way.\n\nThere is a better third way.\n\nOnce my cursor (not the just the mouse pointer) is on the offending item, I can\nhit `Cmd+.`. That directly pops open the Quick Fix window with focus on the\nfirst item in that window. I can navigate to the fix I want and hit enter.\n\nAnother thing to keep in mind. As you're typing out an un-imported entity, if\nVS Code knows about it, it will show it as an auto-complete option with the\npackage it comes from. If you tab-out the one you want, not only will it fill\nin the rest of the entity name, but it will also auto-add the import at the top\nof your file.\n"
  },
  {
    "path": "vscode/step-through-project-wide-search-results.md",
    "content": "# Step Through Project-Wide Search Results\n\nWhen you do a project-wide search in VS Code, the Search tray opens and\ndisplays a listing of all the matches file-by-file. This view is handy to\nglance at the results and quickly navigate to a specific one. If you need to\nlook at every single result, clicking through them one by one is slow and\ntedious.\n\nA better option for doing this is to use the keybindings for stepping forward\nand backward through the results.\n\nHitting `F4` will go to the next match in the search results. Hitting\n`shift+F4` will go to the previous match. Even if you move around, make edits,\nand navigate to other files, your position in the search results will be\npreserved for the next time you hit `F4`.\n\n[source](https://github.com/Microsoft/vscode/pull/18073)\n"
  },
  {
    "path": "vscode/synchronize-vim-clipboard-with-system-clipboard.md",
    "content": "# Synchronize Vim Clipboard With System Clipboard\n\nWhen I use Vim-mode in VSCode, I _yank_ text onto the Vim clipboard by visually\nselecting some text and hitting `y`. Then I can move the cursor somewhere else\nin the file (or another file in VSCode) and _paste_ it by hitting `p`.\n\nBut what if I want the thing I yanked from a file to be pasted into another\nprogram, like Chrome? Or if I've copied some text from another program and I\nwant to paste it into a file in VSCode?\n\nThis cross-program copy and pasting is what the _system clipboard_ on your\noperating system is for. By default, the Vim clipboard is separate from the\nsystem clipboard. I personally prefer for them to be one and the same.\n\nTo achieve this, I added the following line to my VSCode config in\n`settings.json`:\n\n```json\n{\n  \"vim.useSystemClipboard\": true\n}\n```\n\nIt takes a little getting used to having them integrated, but I've done it for\nso long that it is muscle memory. It's hard to not have them integrated now.\nIt's even better when I have a clipboard history tool like Raycast available\nfor accessing past clipboard values.\n"
  },
  {
    "path": "vscode/toggle-between-terminals.md",
    "content": "# Toggle Between Terminals\n\nVSCode allows you to have multiple terminal tabs, but you have to manually\nswitch between them with a drop down. For me, that is a lot of mouse action.\nI'd prefer to have a keyboard shortcut that allows me to switch between\nthem. Fortunately, there are commands for going to the next and previous\nterminal which can be attached to keybindings.\n\nTry adding the following two entries to your `keybindings.json` file:\n\n```json\n[\n  { \"key\": \"cmd+shift+k\", \"command\": \"workbench.action.terminal.focusNext\" },\n  { \"key\": \"cmd+shift+j\", \"command\": \"workbench.action.terminal.focusPrevious\" },\n]\n```\n\nSave the file and then start toggling between your different VSCode\nterminals.\n\n[source](https://github.com/Microsoft/vscode/issues/37937)\n"
  },
  {
    "path": "vscode/turn-off-display-of-tabs-for-files.md",
    "content": "# Turn Off Display Of Tabs For Files\n\nEach time a file is opened in VS Code, it appears as one of many toward the top\nof the window right above the text editor area. It shows the name of the file\nand the 'dirty' status. Over time as more and more files are opened and edited,\nthe tabs accumulate and can only be viewed by horizontally scrolling left and\nright.\n\nThere are other ways to navigate to files besides selecting tabs of already\nopened files. So, if you'd like to reclaim some screen real estate and reduce\nthe visual clutter of the tabs, you can turn them off.\n\nHit `Cmd+Shift+P`, then search for and go to _Preferences: Open Settings (UI)_.\nSearch for _Show Tabs_ which will show up under _Workbench > Editor_.\n\nThe default is _Multiple_. You can switch it to _None_ to completely hide tabs.\nYou can also set it to _Single_ which will display file name and path for the\ncurrent file, but eliminate the clutter of all other tabs.\n"
  },
  {
    "path": "webpack/better-module-imports-with-aliases.md",
    "content": "# Better Module Imports With Aliases\n\nDepending on how your JavaScript project is structured, you can end up with\nimport statements that look like this:\n\n```javascript\nimport SomeComponent from 'app/assets/javascripts/components/SomeComponent.jsx';\n```\n\nor this:\n\n```javascript\nimport SomeComponent from '../components/SomeComponent.jsx';\n```\n\nThe first is simply too long and the second is both ugly and brittle to\nchanges in file location. This can all be _resolved_ with a\n[Webpack](https://webpack.github.io/) alias.\n\n```javascript\n// webpack.config.js\nresolve: {\n  alias: {\n    components: \"app/assets/javascripts/components\",\n  },\n},\n```\n\nWebpack will use this `alias` when resolving module imports like the\nfollowing updated example:\n\n```javascript\nimport SomeComponent from 'components/SomeComponent.jsx';\n```\n\nSee the\n[`resolve.alias`](https://webpack.github.io/docs/configuration.html#resolve-alias)\nsection of the Webpack docs for more details.\n\nh/t Vidal Ekechukwu\n"
  },
  {
    "path": "webpack/debugging-with-full-source-maps.md",
    "content": "# Debugging With Full Source Maps\n\nAfter Webpack runs your JavaScript through various loaders, it no longer\nlooks like the code you were writing in your editor. This can make debugging\ndifficult when you inspect the source of an error in the browser's devtools.\nFortunately, Webpack makes it easy to enhance debugging with full source\nmaps of your code. Just add the following option to your Webpack config:\n\n```javascript\n{\n  devtool: \"source-map\",\n  ...\n}\n```\n\nThis will generate a full source map with a filename that is something like\n`bundle.js.map`.\n\nNote: this will slow down the webpack build process a bit.\n\nRead more about the `devtool` configuration and all the possible options in\nthe [Webpack\ndocs](https://webpack.github.io/docs/configuration.html#devtool).\n"
  },
  {
    "path": "webpack/run-eslint-as-a-preloader.md",
    "content": "# Run ESLint As A Preloader\n\nYou may already be running [ESLint](http://eslint.org/) manually or as a\nscript command via `npm`.  You can also include it as part of the Webpack\nbuild process. By adding it as a *preloader*, Webpack will lint your\nJavaScript files before running other loaders. The results of\nlinting will be reported in the terminal. Assuming you've already installed\n`eslint` and set up your `.eslintrc` file, all you need to do is `npm\ninstall --save-dev eslint-loader` and then add something like the following\nto your `webpack.config.js` file:\n\n```javascript\nmodule: {\n  preLoaders: [\n    {\n      test: /\\.js$/,\n      loaders: ['eslint'],\n      exclude: /node_modules/,\n    }\n  ],\n  ...\n}\n```\n\nRunning something like `webpack -w` will now lint your JavaScript before\nrunning other loaders.\n\nDepending on your project, you may also want to include `babel-eslint` and\n`eslint-plugin-react` with your setup.\n"
  },
  {
    "path": "webpack/specify-port-of-cra-webpack-dev-server.md",
    "content": "# Specify Port Of CRA's Webpack Dev Server\n\n[`create-react-app`](https://github.com/facebookincubator/create-react-app)\ngives you a set of scripts, one of which allows you to start a development\nserver that bundles and serves your javascript. This is handled under the\nhood via `webpack-dev-server`. By default it attempts to serve from port\n`3000`. If port `3000` is taken it will attempt to connect to another\nsequential port.\n\nAlternatively, you can just specify the port when starting the development\nserver. This can be done with the `PORT` env var.\n\n```bash\n$ PORT=3333 yarn start\n```\n"
  },
  {
    "path": "webpack/use-a-specific-config-file.md",
    "content": "# Use A Specific Config File\n\nWhen running `webpack`, the default config file that it looks for is\n`webpack.config.js`. If you have a project that uses different webpack\nconfig files for different environments, you will need to specify which\nconfig file webpack should use. The `--config` flag can be used with\n`webpack` to specify that file. For instance, if you want to use your\nproduction webpack config, run a command like the following:\n\n```\n$ webpack --config webpack.config.production.js\n```\n"
  },
  {
    "path": "workflow/access-1password-credential-from-cli.md",
    "content": "# Access 1Password Credential From CLI\n\nWith the `op` CLI, I can store things like API keys and secrets in my 1Password\nvault and then access them from the command line. This assumes I've already\ninstalled the CLI (`brew install 1password-cli`) and connected it to the\n1Password app via the _Developer_ settings.\n\nThe `op item get` command takes a credential name and returns all the details\nfor the entry with that _Title_. Here is how I can access my _Anthropic Claude\nAPI Key_ details.\n\n```bash\n$ op item get \"Anthropic Claude API Key\"\n```\n\nWith the `--field` flag, I can grab a specific field, such as the `credential`,\nfrom that entry.\n\n```bash\n$ op item get \"Anthropic Claude API Key\" --field credential\nsk-ant-api03-abc......xyz\n```\n\nA command like this can be embedded in other commands as a way of referencing\nsecrets without explicitly entering them into your shell history.\n\n```bash\n$ curl https://api -H \"x-api-key: $(op item get \"Anthropic Claude API Key\" --field credential)\" ...\n```\n"
  },
  {
    "path": "workflow/add-hotkeys-for-specific-raycast-extensions.md",
    "content": "# Add Hotkeys For Specific Raycast Extensions\n\nOne of the main things I use [Raycast](https://www.raycast.com/) for is its\nbuilt-in clipboard history extension. It's super handy when I've copied a Git\nSHA or a URL or a bit of text several copies ago and I want to be able to refer\nback to it. It keeps 7 days of clipboard history by default, so anything that I\nremember copying is going to be there.\n\nTo get there, I have to trigger Raycast, which I usually open via Alfred (I\nknow, 😅). Then I search for Clipboard History (or find it under recent\nsuggestions).\n\nRaycast supports arbitrary hotkey bindings for triggering different extensions\nand their features. So I can get to the Clipboard History in a single step --\ne.g. with `Ctrl+Shift+V`.\n\nFrom Raycast _Settings_, go to the _Extensions_ tab. Find _Clipboard History_\nin the list and then click the _Record Hotkey_ input for it. I then type\n`Ctrl+Shift+V` and I'm all set.\n"
  },
  {
    "path": "workflow/add-subscriber-to-kit-form-via-api.md",
    "content": "# Add Subscriber To Kit Form Via API\n\nBecause the Kit API is a bit sparse in words, I found it difficult to figure\nout exactly what I needed to do to add a subscriber via a custom form. After\nsome experimenting and reading through [Course\nBuilder](https://github.com/badass-courses/course-builder/blob/main/packages/core/src/providers/convertkit.ts)\ncode, I was able to figure out that with the Kit v4 API there are two separate\ncalls that need to be made.\n\nFirst, you need to create an `inactive` subscriber with the user's email (and\nfirst name if given) via the [Create a subscriber\nendpoint](https://developers.kit.com/v4#create-a-subscriber).\n\n```typescript\nasync function createSubscriber(\n  data: SubscriberData,\n  apiKey: string,\n): Promise<Response> {\n  return fetch('https://api.convertkit.com/v4/subscribers', {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application/json',\n      'X-Kit-Api-Key': apiKey,\n    },\n    body: JSON.stringify({\n      email_address: data.email,\n      first_name: data.name,\n      state: 'inactive',\n    }),\n  })\n}\n```\n\nSince this subscriber is `inactive`, they won't show up in the Kit dashboard,\nbut a subscriber record of them has been created.\n\nSecond, you need to add the subscriber to something, like a form or a sequence.\nIn my case, I had already created a form via the Kit dashboard, so I grab that\n_Form ID_ and stick it in my `.env`. That way I am able to [add the subscriber\nto the form by email\naddress](https://developers.kit.com/v4#add-subscriber-to-form-by-email-address).\n\n```typescript\nasync function addSubscriberToForm(\n  email: string,\n  apiKey: string,\n  formId: string,\n): Promise<Response> {\n  const url = `https://api.convertkit.com/v4/forms/${formId}/subscribers`\n  return fetch(url, {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application/json',\n      'X-Kit-Api-Key': apiKey,\n    },\n    body: JSON.stringify({ email_address: email }),\n  })\n}\n```\n\nThis will send a confirmation email to the email address. Once the person has\nopened the email and hit 'Confirm', their corresponding `subscriber` record\nwill be marked as `active` and they will be added to the list of subscribers\nfor that form.\n"
  },
  {
    "path": "workflow/add-subtitles-to-existing-mux-video-asset.md",
    "content": "# Add Subtitles To Existing Mux Video Asset\n\nThere is a [JavaScript/TypeScript Mux\nSDK](https://github.com/muxinc/mux-node-sdk) for interacting with Mux via their\n[API](https://docs.mux.com/api-reference).\n\nWith a Mux client (initialized from `MUX_ACCESS_TOKEN` and `MUX_SECRET_KEY` in\nour environment), we can destructure `Video` which will allow us to call\n`Video.Assets.createTrack`. We pass that function the ID of an existing video\nasset and then an object of data defining the subtitle track. In this case, it\nis an English subtitle track. We need to point Mux to a `url` where the WebVTT\nformatted subtitles are hosted.\n\n```typescript\n// add-srt-to-specific-video.ts\n\nimport Mux from '@mux/mux-node'\n\nrequire('dotenv-flow').config({\n  default_node_env: 'development',\n})\n\nconst assetId = \"mux-asset-id\" // set this value\nconst srtUrl = \"https://public-webvtt-file\" // set this value\n\n// Set up Mux API Client\nconst MUX_ACCESS_TOKEN = process.env.MUX_ACCESS_TOKEN as string\nconst MUX_SECRET_KEY = process.env.MUX_SECRET_KEY as string\nconst muxClient = new Mux(MUX_ACCESS_TOKEN, MUX_SECRET_KEY)\nconst {Video} = muxClient\n\nawait Video.Assets.createTrack(assetId, {\n  url: srtUrl,\n  type: 'text',\n  text_type: 'subtitles',\n  closed_captions: false,\n  language_code: 'en-US',\n  name: 'English',\n  passthrough: 'English',\n})\n```\n\nWe can run the above script with `ts-node` from the command-line like so:\n\n```bash\n$ npx ts-node --files --skipProject add-srt-to-specific-video.ts\n```\n\nWe'll see the new track on the existing asset in the Mux dashboard.\n"
  },
  {
    "path": "workflow/allow-key-repeating-with-cursor.md",
    "content": "# Allow Key-Repeating With Cursor\n\nI recently installed the Vim extension for Cursor. This is the same extension\nfor VSCode since Cursor is built on VSCode. A lot of the expected Vim behavior\nwas working. However there was one glaring point of friction.\n\nI often hold down keys like `k` and `j` to go up and down several lines when\nI'm absent-mindedly scrolling around. This wasn't working with the Vim mode\nextension. I'd hold `j` down and the cursor would move down a single line and then\nstop.\n\nThe first thing the Vim extension tells you to do is run a command to enable\nkey-repeating. These instructions are specific to VSCode:\n\n```bash\n$ defaults write com.microsoft.VSCode ApplePressAndHoldEnabled -bool false\n```\n\nThat won't work for cursor which is a separate application with a distinct\n`CFBundleIdentifier`. You can check the current identifier in Cursor's\n`Info.plist` file to be sure, but it should be `com.todesktop.230313mzl4w4u92`.\n\nRun this to target Cursor:\n\n```bash\n$ defaults write com.todesktop.230313mzl4w4u92 ApplePressAndHoldEnabled -bool false\n```\n\nThen restart Cursor.\n\nNow key-repeating in Vim mode should be working.\n\n[source](https://github.com/getcursor/cursor/issues/777#issuecomment-1690996370)\n"
  },
  {
    "path": "workflow/break-justfile-into-separate-hidden-steps.md",
    "content": "# Break Justfile Into Separate Hidden Steps\n\nWith `just` and a project's `justfile`, I can get a summary of the commands\navailable to run against my project by running `just --list`. If I try to\nbreakdown a complex, multi-step command into separate `just` commands, it will\nbe nice for organization, but it will clutter the list output. I can mark\nspecific commands as hidden or internal by preceding them with an underscore\n(`_`).\n\nHere is a `justfile` from one of my projects that only lists a single command\n`setup` which itself is supported by three internal commands: `_check-brew`,\n`_install-deps`, and `_install-go-tools`.\n\n```justfile\n# Install all required development dependencies\nsetup: _check-brew _install-deps _install-go-tools\n\n# Check if brew is installed\n_check-brew:\n    #!/usr/bin/env bash\n    if ! command -v brew &> /dev/null; then\n        echo \"Error: Homebrew is not installed\"\n        echo \"Please install from https://brew.sh\"\n        exit 1\n    fi\n\nbrew_deps := '''\n    go\n    sqlite3\n'''\n\n# Install brew dependencies\n_install-deps:\n    #!/usr/bin/env bash\n    deps=$(echo '{{brew_deps}}' | tr -s '[:space:]' ' ' | xargs)\n    for pkg in $deps; do\n        if ! brew list $pkg &>/dev/null; then\n            echo \"Installing $pkg...\"\n            brew install $pkg\n        else\n            echo \"✓ $pkg already installed\"\n        fi\n    done\n\n# Install Go development tools\n_install-go-tools:\n    go install github.com/pressly/goose/v3/cmd/goose@latest\n```\n"
  },
  {
    "path": "workflow/change-window-name-in-iterm.md",
    "content": "# Change Window Name In iTerm\n\nBy default, the name that appears in the top bar of the\n[iTerm2](https://www.iterm2.com/) window is the session name plus the job that\nis running. This can be changed to some static value of your choosing.\n\nTo change this, hit `Cmd+i` and change the field labeled \"Window Title\".\n\n[source](https://superuser.com/questions/419775/with-bash-iterm2-how-to-name-tabs)\n"
  },
  {
    "path": "workflow/configure-email-redirect-with-cloudflare.md",
    "content": "# Configure Email Redirect With Cloudflare\n\nI have a domain registered with Cloudflare --\n[visualmode.dev](https://www.visualmode.dev). I want to be able to sign up for\nservices and receive emails as `josh@visualmode.dev`. I don't want a separate\ninbox that I have to check though.\n\nThe solution, for me, is to have Cloudflare redirect incoming emails to an\nemail address/inbox that I'm already regularly checking.\n\nOn the _Email_ dashboard there is a _Routing Rules_ tab. In the _Custom\nAddresses_ section, I can click _Create Address_. There I specify the custom\naddress (what will appear before the `@`), the action to make (\"Send to an\nemail\"), and the destination (the existing email address for an inbox I\nregularly check).\n\nFinally, I hit _Save_. If they don't already exist, I'll be prompted to confirm\nthe setup of MX records for the domain. After confirming that, I should be able\nto receive emails via that new address.\n\nThe Email Routing dashboard will even show me a summary of all rerouted emails.\n\n[source](https://blog.cloudflare.com/introducing-email-routing/#cloudflare-email-routing)\n"
  },
  {
    "path": "workflow/control-media-with-drop-keyboard.md",
    "content": "# Control Media With Drop Keyboard\n\nI have a [Drop CTRL](https://drop.com/buy/drop-ctrl-v2-mechanical-keyboard)\nmechanical keyboard which mostly works like any other keyboard. It also has a\nset of functionality that can be accessed via the `fn` (function) key. The\nfunction key can be used to configure the keyboard's LEDs, but I tend to set\nand forget that.\n\nInstead, I like to use the function key to control media. That is, adjust the\nvolume, play and pause, and skip to the next song.\n\nHere is a listing of the ones I use:\n\n- `Fn + Insert` to Pause / Play\n- `Fn + PgUp/PgDown` to Increase / Decrease the volume\n- `Fn + Del/End` to go to the Previous / Next song\n\nHere is a [full listing of the function\nkeys](https://drop.com/talk/9382/how-to-configure-your-drop-keyboard) for Drop\nkeyboards.\n"
  },
  {
    "path": "workflow/convert-an-epub-document-to-pdf-on-mac.md",
    "content": "# Convert An ePub Document To PDF On Mac\n\nIf you have an ePub document and you'd like it in PDF format, you can\nconvert it using the `ebook-convert` binary from `Calibre`.\n\nFirst, install `Calibre`:\n\n```bash\n$ brew cask install calibre\n```\n\nThen convert your ePub using `ebook-convert`:\n\n```bash\n$ ebook-convert book.epub book.pdf\n```\n\nYou'll see a bunch of output as it processes the document. When it\ncompletes, you'll have a nice pdf waiting for you.\n\n[source](https://gist.github.com/AaronO/9962667)\n"
  },
  {
    "path": "workflow/create-a-local-sanity-dataset-backup.md",
    "content": "# Create A Local Sanity Dataset Backup\n\nLet's say you've put together a script that is going to mutate some data in\nyour production dataset on Sanity. Before you run that script, it would be\nprudent to capture a backup in case something goes wrong. That way you can\nalways restore to how the data was in the event that you need to.\n\nYou can do this from the command line with the `sanity` CLI.\n\nFirst, ensure you are signed in via the CLI.\n\n```bash\n$ sanity login\n```\n\nThen, you can issue the `dataset export` command, naming the dataset (in this\ncase, `production`) to target and the name of the backup file to be created\nlocally.\n\n```bash\n$ sanity dataset export production my-project-backup.tar.gz\n```\n\nI believe the Sanity CLI goes off the `sanity.cli.{ts,js}` file in your local\nproject directory to determine what Sanity project it should be working with.\n\nSee the [`export dataset`](https://www.sanity.io/docs/dataset#fd38ca03b011)\ndocs for more details.\n"
  },
  {
    "path": "workflow/create-a-public-url-for-a-local-server.md",
    "content": "# Create A Public URL For A Local Server\n\nAt times while developing an app locally, you need to expose the local server\nto the public internet. This can be useful and necessary when working on a\n3rd-party integration or when you want to show what you have running locally to\nsomeone else.\n\nIn addition to tools like [ngrok](https://ngrok.com/), I've found the\n[`localtunnel`](https://github.com/localtunnel/localtunnel) npm package to be\nan effective way to quickly expose a localhost port.\n\n```\n$ npx localtunnel --port 3000 --subdomain some-custom-subdomain\nyour url is: https://some-custom-subdomain.loca.lt\n```\n\nThis will create a `loca.lt` URL with the given subdomain that tunnels\nrequests to `localhost:3000`. If the `--subdomain` flag is not specified or\nwhat you've specified isn't available, `localtunnel` will generate a random\nsubdomain.\n\nFor the subdomain, I recommend using something sufficiently unique like\n`josh-branchaud-04092021`. Using the date has the added benefit of\ncontextualizing when I generated the URL.\n\nIn my experience, these are not long-lived domains. Sometimes the connection\ngets interrupted and you'll have to restart it. Often when restarting, the\nspecified subdomain will then be flagged as unavailable, so you have to tweak\nit a little.\n\nBecause it is using `npx`, there is nothing to install as long as you already\nhave `node` itself installed.\n"
  },
  {
    "path": "workflow/create-todo-items-in-logseq.md",
    "content": "# Create Todo Items In Logseq\n\nHaving used GitHub flavored markdown and tools like Roam Research and Obsidian,\nI'm used to being able to add interactive todo items to a document with square\nbrackets, like so:\n\n```\n- [ ] Do this\n- [ ] Do that\n```\n\nThis exact syntax doesn't work in Logseq, but I've figured out two ways of\nadding todo items.\n\nFirst, you can access the todo syntax with a forward slash command. Type `/`\nand then start typing `TODO`. It will show up as a top result. Hit enter and\nyou'll have a fresh todo item that you can add a description to.\n\nSecond, as the above hints at, we can get right to the todo syntax by typing\none of `TODO`, `NOW`, or `LATER` in all caps followed by a description. For\nexample:\n\n```\nTODO Send out invoices\nNOW Reply to those emails\nLATER Schedule that meeting\n```\n\nThese will render as checkable boxes marked as either `TODO`, `NOW`, or\n`LATER`, until they are checked off.\n\nYou can also search for blocks that match one of these three categories.\n"
  },
  {
    "path": "workflow/do-project-time-tracking-from-the-cli.md",
    "content": "# Do Project Time Tracking From The CLI\n\nThe [`watson` CLI utility](https://github.com/jazzband/Watson) is built to help\ntrack time across projects right from the terminal. It is written in Python and\ncan be installed via `brew` or `pip3`.\n\nTo start tracking a new or existing project, I can specify it by name like so:\n\n```bash\n$ watson start my-project +reporting\nStarting project my-project [reporting] at 00:28\n```\n\nThis starts a timer for the `my-project` project and includes the tag\n`reporting`. Tags are optional but can give some context to what part of a given\nproject this time session is for.\n\nAt any point during a session, we can check the status.\n\n```bash\n$ watson status\nProject my-project [reporting] started 14 seconds ago (2025.11.14 00:28:31-0600)\n```\n\nAnd when we are done working on that project for the time being, we can stop it.\n\n```bash\n$ watson stop\nStopping project my-project [reporting], started a minute ago and stopped just now. (id: e8e8ed5)\n```\n\nOnce we're ready to start another session (`timeframe`), we just need to run\n`watson start ...` again.\n\nSee `watson --help` for other subcommands provided by the utility.\n"
  },
  {
    "path": "workflow/enable-dev-tools-for-safari.md",
    "content": "# Enable Dev Tools For Safari\n\nBy default Safari's developer tools are hidden. To enable them, you need to go\ninto the _Advanced_ section of _Preferences_ and check the box at the bottom of\nthe screen that reads \"Show Develop menu in menu bar.\"\n\n![Advanced Safari Preferences Pane](https://i.imgur.com/TFhUXoA.png)\n\nThis will give you access to all sorts of menu items like \"Show web inspector\"\nand \"Disable JavaScript\".\n\n[source](https://support.apple.com/guide/safari/use-the-developer-tools-in-the-develop-menu-sfri20948/mac)\n"
  },
  {
    "path": "workflow/forward-stripe-events-to-local-server.md",
    "content": "# Forward Stripe Events To Local Server\n\nStripe offers a robust test mode for developing and testing your app with a\npayments sandbox.\n\nThe [Stripe CLI](https://stripe.com/docs/stripe-cli/webhooks#forward-events)\nhas a `listen` command that can be used to foward any and all Stripe events\nfrom the test account to a locally running server.\n\nAssuming you've installed the `stripe` CLI, you can run a command like the\nfollowing to forward all events to your local server.\n\n```bash\n$ stripe listen --forward-to localhost:5000/hooks\n```\n\nWhile this is running you'll see incoming events and your servers outgoing\nresponses.\n\nIf you'd like to filter down to receive specific events, you can use the\n[`--events`\nflag](https://stripe.com/docs/stripe-cli/webhooks#supported-events).\n"
  },
  {
    "path": "workflow/get-url-for-github-user-profile-photo.md",
    "content": "# Get URL For GitHub User Profile Photo\n\nYou can access your (or really any user's) profile photo by visiting the GitHub\nprofile URL with `.png` added on to the end.\n\nSo, my GitHub profile URL is:\n\n```\nhttps://github.com/jbranchaud\n```\n\nIf I were to add `.png` on to that and visit it in my browser:\n\n```\nhttps://github.com/jbranchaud.png\n```\n\nI'd be redirected to the following URL:\n\n```\nhttps://avatars.githubusercontent.com/u/694063?v=4\n```\n\nThis is the stable URL for my GitHub avatar. In the browser I will see the full\nresolution image which I can download as needed.\n\n[source](https://dev.to/10xlearner/how-to-get-the-profile-picture-of-a-github-account-1d82)\n"
  },
  {
    "path": "workflow/get-your-public-ip-address.md",
    "content": "# Get Your Public IP Address\n\nIf you're trying to figure out what your current public IP address is, there is\na server you can ask. It is a server running at `https://ifconfig.me`.\n\nYou can visit that URL in your browser to find your IP address and some other\nUser Agent/Request details. The site also mentions several `cURL` commands you\ncan run to get these details in your terminal.\n\n```bash\n$ curl ifconfig.me\n```\n\nThat will respond with just your public IP address. It is equivalent to curling\n`ifconfig.me/ip`.\n\nThere are other options as well, such as curling for a JSON response of all the\ndata attributes.\n\n```bash\n$ curl ifconfig.me/all.json\n```\n\nSee [ifconfig.me](https://ifconfig.me) for more details.\n\n[source](https://www.mfitzp.com/article/use-ifconfigme-to-return-your-ip-and-host/)\n"
  },
  {
    "path": "workflow/import-a-github-project-into-codesandbox.md",
    "content": "# Import A Github Project Into CodeSandbox\n\nA really fancy feature that [CodeSandbox](https://codesandbox.io/) offers is\nthe ability to import a Github project. If you go to the [Create\nSandbox](https://codesandbox.io/s/) page, you'll see some options including\n_Import from Github_. From there, paste in the URL to a public github\nrepository and a matter of seconds your entire project will be synced into\na new CodeSandbox project.\n\nI recently did this with a [create-react-app\nproject](https://codesandbox.io/s/github/jbranchaud/redux-little-router-example)\nand CodeSandbox even knew how to recognize that it was a CRA app so that it\ncould run and display it in the web view.\n"
  },
  {
    "path": "workflow/interactively-kill-a-process-with-fkill.md",
    "content": "# Interactively Kill A Process With fkill\n\nThe cross-platform [`fkill`](https://github.com/sindresorhus/fkill-cli) tool\nis a modern, friendly CLI for fabulously killing processes. It provides an\ninteractive interface for searching for the name or pid of a process that\nneeds killing.\n\nInstall it with yarn (or npm):\n\n```bash\n$ yarn global add fkill-cli\n```\n\nThen run it with no arguments to trigger the interactive mode.\n\n![use fkill interactively](https://raw.githubusercontent.com/sindresorhus/fkill-cli/master/screenshot.gif)\n\ngif credit: [`fkill-cli` repo](https://github.com/sindresorhus/fkill-cli)\n"
  },
  {
    "path": "workflow/open-slacks-keyboard-shortcuts-reference-panel.md",
    "content": "# Open Slack's Keyboard Shortcuts Reference Panel\n\nSlack has a ton of keyboard shortcuts, but you might only be familiar with\nsome of the more obvious ones. When I started using Slack, I quickly\ndiscovered that `Cmd+}` and `Cmd+{` allow you to navigate forward and\nbackward through your different Slack workspaces.\n\nBut there is a whole world of Slack keyboard shortcuts that I didn't know\nabout. By hitting `Cmd+/` a Keyboard Shortcuts reference panel will be\ntoggled open. This lists all of the keyboard shortcuts you didn't know you\nneeded.\n"
  },
  {
    "path": "workflow/pop-videos-out-as-picture-in-picture.md",
    "content": "# Pop Videos Out As Picture-in-Picture\n\nI recently learned that just about any video playing in Chrome and Firefox can\nbe popped out to a picture-in-picture (PIP) player. A PIP player gives you a sidecar\nvideo player window that you can arrange and resize anywhere on your screen. It\nsits on top of other windows so that you can view it while working from other\napps. This is useful if, for instance, you are working through a coding\ntutorial on youtube.\n\nFor most video players, you can right click on the video and the menu that\nappears will include a \"Picture in Picture\" option. Select that and the arrange\nthe player to your liking.\n\nYoutube overrides right-click. If you right-click, you'll see one menu of\nYoutube-specific options. Right-click a second time to open the standard\nbrowser menu which will include the PIP option.\n\nI noticed while also testing this on Firefox, that they have a PIP icon that\nappears as a small overlay on the right side of the video player that you can\nclick as well. This is useful because I found some site's video players were\n(inadvertently) preventing right-click.\n"
  },
  {
    "path": "workflow/prune-the-excess-from-node-modules.md",
    "content": "# Prune The Excess From node_modules\n\nThe `node_modules` directory, which is part of every JavaScript project, is\ninfamously heavy. It is a massive directory of all your project's dependencies\nand those dependencies' dependencies.\n\nThe size of `node_modules` can become a problem on CI build servers with\nlimited disk space. You can significantly reduce the size of `node_modules` by\npruning away all the excess files that aren't needed during builds like\nmarkdown files, typescript source files, etc.\n\nInclude the [`node-prune`](https://github.com/tj/node-prune) binary as part of\nyour build pipeline to handle this.\n\n```bash\n$ node-prune /path/to/node_modules\n```\n\nIn one instance, I saw a reduction from 400MB to 11MB in the `node_modules`\ndirectory size.\n"
  },
  {
    "path": "workflow/rotate-an-image-to-be-oriented-upright.md",
    "content": "# Rotate An Image To Be Oriented Upright\n\nMany programs that display JPEG images will read the EXIF data for\n'Orientation' headers so that they can correctly display the image. Not all of\nthem though. For instance, when a browser renders an `<img>` tag for such a\nJPEG image, it won't account for the 'Orientation' header and you might end up\nwith a sideways image.\n\nYou can normalize the orientation with the\n[`jhead`](https://www.sentex.ca/~mwandel/jhead/usage.html) utility which uses\n[`jpegtran`](https://linux.die.net/man/1/jpegtran) under the hood. This is done\nwith the `-autorot` flag.\n\n```bash\n$ jhead -autorot my_image.jpeg\n```\n\n> Using the 'Orientation' tag of the Exif header, rotate the image so that it\n> is upright. The program 'jpegtran' is used to perform the rotation. After\n> rotation, the orientation tag of the Exif header is set to '1' (normal\n> orientation). The Exif thumbnail is also rotated.\n\n> This feature is especially useful with newer digital cameras [and\n> smartphones], which set the orientation field in the Exif header\n> automatically using a built in orientation sensor in the camera.\n\nThe image will now be upright in all programs.\n"
  },
  {
    "path": "workflow/see-overlaps-for-a-set-of-time-zones.md",
    "content": "# See Overlaps For A Set Of Time Zones\n\nThe `tz` command (`brew install tz`) will display by default your local time\nand UTC for comparison. By including the `TZ_LIST` env var with a semi-colon\nseparated list of time zones, you can display several time zones to see how\nthey compare. The results are even color coded for working, flex, and\nnon-working hours.\n\n```bash\n❯ TZ_LIST=\"US/Pacific;US/Central;Europe/Paris\" tz\n\n  What time is it?\n\n  🕕 (CST) Local 6:59PM, Tue 05\n   0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23\n\n  🕓 (PST) US/Pacific 4:59PM, Tue 05\n  22  23   0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21\n\n  🕕 (CST) US/Central 6:59PM, Tue 05\n   0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23\n\n  🕐 (CET) Europe/Paris 1:59AM, Wed 06\n   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23   0   1   2   3   4   5   6\n```\n"
  },
  {
    "path": "workflow/send-a-message-to-a-discord-channel.md",
    "content": "# Send A Message To A Discord Channel\n\nI recently added a form to [visualmode.dev](https://www.visualmode.dev) that\nwhen submitted should send the details to an internal channel in my discord\nserver.\n\nI didn't need to set up an _App_ or a _Bot_ to do this. It is much simpler than\nthat. All I needed was a valid [_webhook_\nendpoint](https://discord.com/developers/docs/resources/webhook) for my channel\nthat I can `POST` to.\n\nFrom Discord, I can select _Edit Channel_ for a specific channel, go to the\n_Integrations_ tab, go to _Webhooks_, and then create a _New Webhook_. I can\nname it, save it, and then copy the webhook URL.\n\nAs a demonstration, I can `POST` to that webhook URL using `cURL` like so:\n\n```bash\ncurl -H \"Content-Type: application/json\" -X POST -d '{\"content\":\"Hello from cURL!\"}' <YOUR_WEBHOOK_URL>\n```\n\nSimilarly, in some non-public-facing code like a Next.js serverless function, I\ncan `POST` to that webhook URL with the `content` that I want to appear in my\nchannel.\n\n```\nimport { NextResponse } from 'next/server'\n\nexport async function POST(request: Request) {\n  const data = await request.json()\n\n  const discordWebhookUrl = process.env.DISCORD_WEBHOOK_URL\n  if (discordWebhookUrl) {\n    try {\n      const response = await fetch(discordWebhookUrl, {\n        method: 'POST',\n        headers: {\n          'Content-Type': 'application/json',\n        },\n        body: JSON.stringify({\n          content: `New contact form submission:\\nName: ${data.name}\\nEmail: ${data.email}\\nCompany: ${data.company}\\nPhone: ${data.phone}\\nMessage: ${data.message}`,\n        }),\n      })\n\n      if (!response.ok) {\n        throw new Error('Failed to send Discord message')\n      }\n    } catch (error) {\n      console.error('Error sending to Discord:', error)\n      return NextResponse.json(\n        { error: 'Failed to process form submission' },\n        { status: 500 },\n      )\n    }\n  }\n\n  return NextResponse.json({ message: 'Form submitted successfully' })\n}\n```\n\nThis [Structure of Webhook\nguide](https://birdie0.github.io/discord-webhooks-guide/discord_webhook.html)\nhas more details on how to specifically structure and format a more complex\nmessage.\n"
  },
  {
    "path": "workflow/send-a-pdf-to-your-kindle.md",
    "content": "# Send A PDF To Your Kindle\n\nI recently got a Kindle. I already have a bunch of PDF and ePub books on my\ncomputer that I've bought over the years. I wanted to be able to read some of\nthose books on the Kindle. I found that there is a way to send these formats to\nyour Kindle via email.\n\nThere are a couple steps to get this working.\n\nFirst, from the Amazon account that is tied to the Kindle device, open the\n_Account_ dropdown and click _Devices. Any devices tied to your account will be\nlisted there. Navigate to the one you want to send to. Under the _Device\nSummary_ with be a custom email address for that device. Something like\n`youremail_abc123@kindle.com`.\n\nThat's the email you'll send the PDF or ePub attachment to.\n\nSecond, that Kindle email address will only receive and process documents from\na known, verified email address. Back on the _Devices_page, click on the\n_Preferences_ tab. Under _Personal Document Preferences_ make sure that the\n_Approved Personal Document Email List_ includes the email address you'll be\nsending from. Add it if not.\n\nEverything is set up. Now compose an email to that Kindle address, add the\nattachment, and send. Give it 5 or so minutes to process and it should show up\non your device.\n\nAdditionally, you can go to the _Content_ tab and then to _Digital Content_ to\nsee what documents you have set and which devices have received them.\n\n[source](https://goodereader.com/blog/kindle/here-is-how-you-can-read-pdf-files-on-the-amazon-kindle)\n"
  },
  {
    "path": "workflow/set-recurring-reminders-in-slack.md",
    "content": "# Set Recurring Reminders In Slack\n\nI usually just talk to my coworkers in Slack. There are also ways of talking\nto slackbot. For instance, you can ask slackbot to remind you of things.\nHere is the structure of that kind of request:\n\n```\n/remind [who] [what] [when]\n```\n\nI can use this to set a recurring reminder for myself.\n\n```\n/remind @jbranchaud Drink a beer at 5pm on Fridays\n```\n\nSlackbot assures me that my reminder has been noted.\n\n![slackbot reminder](https://i.imgur.com/qVAWohn.png)\n\n[source](https://get.slack.help/hc/en-us/articles/208423427-Set-a-reminder)\n"
  },
  {
    "path": "workflow/show-linting-errors-in-zed.md",
    "content": "# Show Linting Errors In Zed\n\nWhen working in a language like TypeScript or Go, the language server tooling\nin [Zed](https://zed.dev/) can draw my attention to errors in my code. This\ncould be an unrecognized function or variable, a type error, or a syntax error.\nWhen these linting errors are detected, the editor underlines them with a red\nsquiggly. I can hover over offending token or statement and see what the error\nis.\n\nThere are also a few mouse-free ways to do this.\n\nFirst, I can hit `F8` to jump to the next one of these errors in the current\nfile. That will move my cursor to that location and display a small overlay\nwith the error details.\n\nSecond, assuming Vim mode, I can navigate my cursor over a specific highlighted\ntoken and then hit `Shift+k`. That will pop open the same small overlay to\ndisplay the error details.\n\nThird, I can hit `Cmd+Shift+M` to open the _Project Diagnostics_ tab which\ndisplays a series of file buffer results with the offending lines and the error\ndescription.\n"
  },
  {
    "path": "workflow/temporarily-hide-cleanshot-x-capture-previews.md",
    "content": "# Temporarily Hide CleanShot X Capture Previews\n\nThe _capture previews_ that CleanShot X provides are a useful part of my\nworkflow. I often capture a screenshot or recording a bit in advance of needing\nto add it as, say, an attachment. The preview icons float off to the right of\nmy screen, generally out of the way. As soon as I need them, I can annotate,\ndrag-n-drop, etc.\n\nSometimes, however, they do get in the way. But I'm not ready to dismiss them\nand I don't want to save them off to some folder buried in my file system.\n\nTo temporarily slide the capture previews down off the screen, I can hit the\nshortcut `Ctrl+Opt+Cmd+H`. The arrow at the butto of the screen can be clicked\nto unhide them, or I can hit the same shortcut sequence to reveal them.\n"
  },
  {
    "path": "workflow/toggle-between-stories-in-storybook.md",
    "content": "# Toggle Between Stories In Storybook\n\n[Storybook](https://storybook.js.org/) is a great tool for UI development,\nespecially in the React world. Storybook has a sidebar built in for\nnavigating between all your stories, with a mouse. You can also navigate\nbetween them with just your keyboard.\n\nUse `Cmd-Shift-←` and `Cmd-Shift-→` to move backward and forward through\nyour stories.\n\nThis even works when the navigation sidebar is hidden.\n"
  },
  {
    "path": "workflow/update-asdf-plugins-with-latest-package-versions.md",
    "content": "# Update asdf Plugins With Latest Package Versions\n\nIf you've been using [`asdf`](https://github.com/asdf-vm/asdf) for a while,\nthen the various plugins you are using may be a bit out of date. That means\nthat they won't have information about the latest versions of their respective\ntechnologies.\n\nYou can update all of them at once with the `--all` flag:\n\n```bash\n$ asdf plugin update --all\n```\n\nThis will grab all the latest package version information for each `asdf`\nplugin you have installed.\n\nSee `asdf help` for more details.\n"
  },
  {
    "path": "workflow/view-a-nicely-formatted-csv-in-terminal.md",
    "content": "# View Nicely-Formatted CSV In Terminal\n\nI'd just written and run a script to generate a CSV of data requested by a\nstakeholder. Before sending it over to them, I wanted to briefly browse through\nit to make sure the data passed a spot-check and that the way I structured\nthings looked reasonable.\n\nThere are a dozen ways I can view a CSV file on my machine, but I wasn't\ninterested in opening another program or navigating to the file in Finder.app.\n\nI had generated the file in the terminal and I wanted to view it there.\n\nThe Rust-built [`csvlens`](https://github.com/YS-L/csvlens) CLI is just what I\nwas looking for.\n\n```bash\n$ csvlens data_report_20250627.csv\n```\n\nThis shows the data spaced out with columns and rows and has a set of\nkeybindings that can be browsed with `?`.\n\nI got this tool from `brew install csvlens`.\n"
  },
  {
    "path": "workflow/view-the-pr-for-the-current-github-branch.md",
    "content": "# View The PR For The Current GitHub Branch\n\nAs you're working on a feature branch, you may push up an early PR to get your\nwork-in-progress out in public. You can then continue to work locally and push\nup changes.\n\nIf at any point in this process you want to view the PR, you can open a browser\ntab, visit GitHub, and navigate a few pages to the specific PR. There is a\nfaster using GitHub's CLI -- [`gh`](https://cli.github.com/).\n\nYou can view the main details of the PR for the current branch right in your\nterminal with:\n\n```bash\n$ gh pr view\n```\n\nYou can also open up the PR for the current branch in your browser by adding in\nthe `--web` flag.\n\n```bash\n$ gh pr view --web\n```\n\nSee `gh pr --help` for more details.\n"
  },
  {
    "path": "xstate/always-use-inline-functions-with-assign.md",
    "content": "# Always Use Inline Functions With Assign\n\nThe [`assign`\naction](https://xstate.js.org/docs/guides/context.html#assign-action) allows\nyou to update the context of the state machine.  There are a couple ways to use\n`assign`, but you should prefer the inline function style.\n\nTechnically `assign` can be passed an object literal like so to set a static\nvalue:\n\n```javascript\n{\n  actions: {\n    resetCount: assign({\n      count: 0\n    })\n  }\n}\n```\n\nHowever, this causes confusion for the TypeScript compiler and can create\nsurprising and unrelated type errors in the parts the code that use the\nmachine.\n\nTo keep the compiler happy, you should instead use inline functions. Either\nlike this:\n\n```javascript\n{\n  actions: {\n    resetCount: assign((_context) => {\n      return {\n        count: 0\n      }\n    })\n  }\n}\n```\n\nor like this:\n\n```javascript\n{\n  actions: {\n    resetCount: assign({\n      count: (_context) => 0\n    })\n  }\n}\n```\n"
  },
  {
    "path": "xstate/custom-jest-matcher-for-xstate-machine-states.md",
    "content": "# Custom Jest Matcher For XState Machine States\n\nHere is a custom matcher for asserting the current state of an XState machine\nfor Jest-based tests. I made some adaptations to it, but it was mostly\ndeveloped by [Nick\nNisi](https://discord.com/channels/795785288994652170/809564635614150686/897559009077362738).\n\n```typescript\nimport {State} from 'xstate'\n\ndeclare global {\n  namespace jest {\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    interface Matchers<R> {\n      toMatchState(state: string): CustomMatcherResult\n    }\n  }\n}\n\nexpect.extend({\n  toMatchState(state: State<unknown>, value: string) {\n    return {\n      pass: state.matches(value),\n      message: () =>\n        `Expected\n  \"${JSON.stringify(state.value)}\"\nstate to match\n  \"${JSON.stringify(value)}\"`,\n    }\n  },\n})\n```\n\nTo make this available to your tests, place it in your `setupTests.ts` (or\n`.js`) file, assuming that is configured in your `jest.config.js`.\n\nIt can be used in your tests like so:\n\n```javascript\ntest(\"it transitions to open and back to closed\", async () => {\n  const service = interpret(confirmationMachine);\n\n  service.start();\n\n  service.send({\n    type: \"OPEN_DIALOG\",\n    doubleConfirmText: \"taco\",\n    action: jest.fn()\n  });\n\n  expect(service.state).toMatchState({ open: \"idle\" })\n\n  service.send({ type: \"CANCEL\" });\n\n  expect(service.state).toMatchState(\"closed\")\n});\n```\n\nNotice you can pass either a string or object representation of the state, if\nthere is nesting.\n\nWhat is nice about this custom matcher is the informative failure messaging.\n"
  },
  {
    "path": "xstate/define-event-that-does-internal-self-transition.md",
    "content": "# Define Event That Does Internal Self Transition\n\nAn XState `state` can contain a state transition in the `on` object that\nrepresents a [_self\ntransition_](https://xstate.js.org/docs/guides/transitions.html#self-transitions).\nA self transition means that the state points to itself. In response to that\nevent, it will transition directly to itself, instead of to another state node.\n\nAn\n[_internal_](https://xstate.js.org/docs/guides/transitions.html#internal-transitions)\nself transition is one in which the transition occurs, but it never _exits_ its\nstate node. That means `entry` and `exit` actions won't be triggered.\n\nThe parent state node can transition directly to itself or to a child node.\nHere are a couple ways to define internal self transitions directly to the\nparent node.\n\n1. Implicit\n\n```\nstates: {\n  counting: {\n    on: {\n      INCREMENT: {\n        actions: ['incrementCount'],\n      },\n    },\n  },\n},\n```\n\nNo `target` is declared for `INCREMENT`, so an internal, self-transition is\nimplicit.\n\n2. Explicit\n\n```\nstates: {\n  counting: {\n    on: {\n      INCREMENT: {\n        internal: true,\n        actions: ['incrementCount'],\n      },\n    },\n  },\n},\n```\n\nThis says that the transition should be an `internal` one.\n\n3. Undefined Target\n\n```\nstates: {\n  counting: {\n    on: {\n      INCREMENT: {\n        target: undefined,\n        actions: ['incrementCount'],\n      },\n    },\n  },\n},\n```\n\nAn undefined target is an internal, self-transition.\n\n[source](https://dev.to/jbranchaud/1-7-gui-tasks-with-react-and-xstate-counter-4l9i)\n"
  },
  {
    "path": "xstate/events-stop-propagating-once-handled.md",
    "content": "# Events Stop Propagating Once Handled\n\nIn a hierarchical (or nested) XState machine, events are sent to the inner most sub-state of\nthe current state. If that state handles the event, then it won't propagate up\nto parent states. If a state receives an event that it doesn't handle, that\nevent will propagate up to parent states until it is handled or there is\nnothing to handle it.\n\nLet's look at an example.\n\n```javascript\n{\n  initial: \"active\",\n  context: { count: 0 },\n  states: {\n    active: {\n      on: {\n        COUNT: {\n          actions: \"changeCount\",\n        },\n      },\n      initial: \"increment\",\n      states: {\n        increment: {\n          on: {\n            SWITCH_COUNT_DIRECTION: \"decrement\",\n          },\n        },\n        decrement: {\n          on: {\n            SWITCH_COUNT_DIRECTION: \"increment\",\n            COUNT: {\n              actions: 'logEvent'\n            },\n          },\n        },\n      },\n    },\n  },\n};\n```\n\nThis machine starts in the `active.increment` state.\n\nIf I send the `COUNT` event, it will first go to the `active.increment` state.\nIt isn't handled there, so it will propagate up to `active` where it is\nhandled.\n\nNow let's say I transition to `active.decrement`. If I send the `COUNT` event,\nit will first go to `active.decrement` where it is handled. The `logEvent`\naction happens and then the event stops. The `active` state does not receive\nnor handle the `COUNT` event.\n\n[source](https://twitter.com/jbrancha/status/1418269852398129152?s=20)\n"
  },
  {
    "path": "xstate/inline-actions-vs-actions-in-machine-options.md",
    "content": "# Inline Actions vs Actions In Machine Options\n\nWhen first spec'ing out a machine, I find it easiest to add my on-transition\nactions directly inline.\n\n```javascript\nconst countingMachine = createMachine({\n  initial: \"counting\",\n  context: { count: 0 },\n  states: {\n    counting: {\n      on: {\n        INCREMENT: {\n          actions: assign({\n            count: (context) => context.count + 1,\n          }),\n        },\n      },\n    },\n  },\n});\n```\n\nThis is not what the XState docs recommend once you move beyond prototyping\nyour machine.\n\n> It is not recommended to keep the machine config like this in production\n> code, as this makes it difficult to debug, serialize, test, and accurately\n> visualize actions.\n\nWhen you're ready, you can refactor this by referencing the action by name and\nthen moving the action declaration to the `actions` object of the machine\noptions (second argument to `createMachine`).\n\n```javascript\nconst countingMachine = createMachine({\n  initial: \"counting\",\n  context: { count: 0 },\n  states: {\n    counting: {\n      on: {\n        INCREMENT: {\n          actions: 'incrementCount',\n        },\n      },\n    },\n  },\n},\n{\n  actions: {\n    incrementCount: assign({\n      count: (context) => context.count + 1,\n    }),\n  },\n});\n```\n\nWhen the machine interpreter sees `'incrementCount'`, it knows to look for an\naction by that name in the machine options.\n\n[source](https://xstate.js.org/docs/guides/actions.html)\n"
  },
  {
    "path": "xstate/make-immediate-and-delayed-transitions.md",
    "content": "# Make Immediate And Delayed Transitions\n\nAn [XState](https://xstate.js.org/docs/) state can define an `on` key with an\nobject. The object can define one or more events that the state listens for and\ntransitions in response to. In addition to transitioning in response to an\nevent, you can have a state do both _immediate_ and _delayed_ transitions.\n\nHere is an example state machine.\n\n```javascript\nexport const loadingSpinner = createMachine(\n  {\n    initial: 'pending',\n    context: {},\n    states: {\n      pending: {\n        always: [\n          { target: 'loading' }\n        ]\n      },\n      loading: {\n        after: {\n          5000: { target: 'done' }\n        }\n      },\n      done: {\n        final: true\n      }\n    }\n  }\n);\n```\n\nThis machine will start in the `pending` state. The `always` object will\nimmediately fire which will trigger a transition to the `loading` state. There\nthe `after` object will schedule a transition to the `done` state to happen in\n5 seconds (5000ms).\n\nThe\n[`always`](https://xstate.js.org/docs/guides/transitions.html#eventless-always-transitions)\nis the immediate transition. The\n[`after`](https://xstate.js.org/docs/guides/delays.html#delayed-transitions) is\nthe delayed transition.\n\nThe \"eventless\" `always` transition, in practice, is more useful when combined\nwith a condition. That allows you to define an immediate transition that only\ntakes place if some condition has already been met (e.g. does the `context`\nalready contain the thing we were about to look up?).\n"
  },
  {
    "path": "xstate/simple-states-and-composite-states.md",
    "content": "# Simple States And Composite States\n\nXState allows you to build [hierarchical state\nmachines](https://xstate.js.org/docs/guides/hierarchical.html). A hierarchical\nstate machine is one where there are substates nested under states.\n\nStates with nothing nested under them are _simple states_. States that have\nsubstates are _composite states_.\n\n```javascript\nconst machine = createMachine({\n  // Starting State\n  initial: \"active\",\n  // Starting Context\n  context: { count: 0 },\n  // States\n  states: {\n    inactive: {\n      always: { target: \"active\" },\n    },\n    active: {\n      on: {\n        SWITCH_COUNT_DIRECTION: {\n          actions: [\"logSwitch\", \"consoleLogSwitch\"],\n        },\n        COUNT: {\n          actions: \"changeCount\",\n        },\n      },\n      initial: \"increment\",\n      states: {\n        increment: {\n          on: {\n            SWITCH_COUNT_DIRECTION: \"decrement\",\n          },\n        },\n        decrement: {\n          on: {\n            SWITCH_COUNT_DIRECTION: \"increment\",\n          },\n        },\n      },\n    },\n  },\n});\n```\n\n- The `inactive` state is a _simple state_. There is nothing nested under it.\n- The `active` state is a _composite state_. There are two substates\n  (`increment` and `decrement`) nested under it.\n- The `increment` and `decrement` states are both _simple states_. Nothing is\n  nested under them.\n"
  },
  {
    "path": "xstate/start-a-machine-in-a-specific-state.md",
    "content": "# Start A Machine In A Specific State\n\nFor testing (or debugging) purposes, it can be handy to get an XState machine\nrunning from a specific state.\n\nLet's say a machine has an initial state of `green` and the other states it can\nbe in are `yellow` and `red`. And `yellow` has sub-states of `walk` and\n`hurry`.\n\nBy default, a machine will start in the specified initial state.\n\n```javascript\nconst service = interpret(trafficLightMachine);\n\nservice.start();\n\nservice.state.value; //=> 'green'\n```\n\nWe can tell the traffic light service to start in the `red` state instead.\n\n```javascript\nservice.start('red');\n\nservice.state.value; //=> 'red'\n```\n\nWe can even tell it to start in a sub-state (nested state) of a particular\nstate.\n\n```javascript\nservice.start({ yellow: 'hurry' });\n\nservice.state.value; //=> { yellow: 'hurry' }\n```\n\n[source](https://xstate.js.org/docs/guides/interpretation.html#starting-and-stopping)\n"
  },
  {
    "path": "xstate/use-an-xstate-machine-with-react.md",
    "content": "# Use An XState Machine With React\n\nThere are a bunch of well-constructed XState machines available to directly\ncopy into your project from [XState Catalogue](https://xstate-catalogue.com/).\nFor instance, I can grab the [Confirmation Dialog\nmachine](https://xstate-catalogue.com/machines/confirmation-dialog) and paste\nit into `confirmMachine.js`. Then I can grab\n[`@xstate/react`](https://xstate.js.org/docs/packages/xstate-react/) which\ncomes with a `useMachine` hook.\n\n```javascript\nimport * as React from \"react\";\nimport { useMachine } from \"@xstate/react\";\nimport confirmMachine from \"./confirmMachine\";\nimport Dialog from \"./dialog\";\n\nexport default function App() {\n  const [current, send] = useMachine(confirmMachine);\n\n  const deleteAction = () => { /* ... */ };\n\n  const showDialog = current.value !== \"closed\";\n  const open = () => {\n    send({ type: \"OPEN_DIALOG\", action: deleteAction });\n  };\n  const close = () => {\n    send(\"CANCEL\");\n  };\n  const confirm = () => {\n    send(\"CONFIRM\");\n  };\n\n  return (\n    <div className=\"App\">\n      <Dialog\n        message=\"Are you sure you want to delete something?\"\n        handleConfirm={confirm}\n        handleClose={close}\n        showDialog={showDialog}\n        errorMessage={current.context.errorMessage}\n      />\n      {/* other stuff */}\n    </div>\n  )\n}\n```\n\nThe `useMachine` call both interprets and starts up the machine service. The\n`current` value is everything about the _current_ state of the machine. The\n`send` is a function for dispatching transitions between machine states.\n"
  },
  {
    "path": "yaml/create-multi-line-strings-without-the-line-breaks.md",
    "content": "# Create Multi-Line Strings Without The Line Breaks\n\nThere are [many ways](https://stackoverflow.com/a/21699210/535590) to add\nmulti-line strings to a YAML document. Most of them preserve the literal\nnewlines present in the multi-line string. And generally that is what you want\nin a multi-line string.\n\nSometimes, however, you want a multi-line string just for its readability in\nthe file. The literal representation of the string should exclude the newlines.\nTo achieve this, you can use either `>-` or `|-`.\n\n```yaml\nrun: >-\n  echo \"::set-output name=NODE_VERSION::$(\n    cat .tool-versions\n    | grep nodejs\n    | sed 's/nodejs \\(.*\\)$/\\1/'\n  )\"\n```\n\nThis creates a readable key-value pair without introducing newline characters\ninto the string that represents a shell command.\n"
  },
  {
    "path": "yaml/yaml-is-a-superset-of-json.md",
    "content": "# YAML Is A Superset Of JSON\n\nPut another way, JSON is a subset of YAML.\n\nHere is what the YAML spec has to say:\n\n> YAML can therefore be viewed as a natural superset of JSON, offering improved\n> human readability and a more complete information model. This is also the\n> case in practice; every JSON file is also a valid YAML file.\n\nWe can _see_ this in practice by using our favorite YAML parse to read a JSON\nfile. For me that is Ruby and its built-in YAML library.\n\nFirst, consider the following JSON file (`data.json`):\n\n```json\n{\n  \"data\": [\n    \"one\",\n    \"two\",\n    \"three\"\n  ],\n  \"number\": 22\n}\n```\n\nNow, I'll open up an IRB session (Ruby's interactive REPL) and read it in.\n\n```ruby\n> require 'yaml'\n=> true\n> YAML.load_file('data.json')\n=> {\"data\"=>[\"one\", \"two\", \"three\"], \"number\"=>22}\n```\n\nIt works. And for me, having not considered those two format related, this\nisn't something I would have expected to work.\n\n[source](http://yaml.org/spec/1.2/spec.html#id2759572)\n"
  },
  {
    "path": "zod/check-if-an-object-is-empty-with-zod.md",
    "content": "# Check If An Object Is Empty With Zod\n\nZod is a schema validation library. It can be used to check all sorts of\nproperties about the data moving through our system.\n\nLet's look at how to implement a common type of check -- is this object empty?\n\n```javascript\nimport {z} from 'zod';\n\nconst emptyObjectSchema = z.object({}).strict();\nconst isEmpty = (obj: object): boolean => {\n  const result = emptyObjectSchema.safeParse(obj);\n  return result.success;\n}\n\nisEmpty({});\n//=> true\n\nisEmpty({ hello: 'world' });\n//=> false\n```\n\nThis `emptyObjectSchema` _strictly_ defines the schema as an empty object\n(`{}`). Without the [`strict()`](https://github.com/colinhacks/zod#strict)\npart, we'd be allowing an object with key-value pairs to quietly pass the\nvalidation.\n\n[source](https://twitter.com/jbrancha/status/1565728882082385920)\n"
  },
  {
    "path": "zod/create-a-schema-that-matches-on-any-object.md",
    "content": "# Create A Schema That Matches On Any Object\n\nTypically when creating an object schema with Zod, you have to specify the keys\nand their types that make up the object.\n\n```typescript\nimport {z} from 'zod'\n\nconst objectSchema = z.object({ id: z.string() })\n\nconst obj = objectSchema.parse({ id: 1, type: 'user' })\n//=> { id: 1 }\n\nobjectSchema.parse({ _id: 1, _type: 'user' })\n//=> ZodError\n```\n\nIf, however, you want a generic object schema that is ostensibly only checking\nthat the thing is an object and then allows any and all key-value pairs, you\ncan use the [`passthrough()`](https://github.com/colinhacks/zod#passthrough)\nfunction.\n\n```typescript\nimport {z} from 'zod'\n\nconst anyObjectSchema = z.object({}).passthrough()\n\nconst obj = anyObjectSchema.parse({ id: 1, type: 'user' })\n//=> { id: 1, type: 'user' }\n```\n"
  },
  {
    "path": "zod/create-union-type-of-nearly-identical-objects.md",
    "content": "# Create Union Type Of Nearly Identical Objects\n\nLet's say I have a data layer that can return data in two nearly identical\nshapes. Either shape has all of the same keys except one has an `_id` key and\nthe other has a `key` key. I want a Zod schema that can validate either of\nthese shapes and produce a union type.\n\nLet's start with an intermediate Zod object that holds all possible keys.\n\n```typescript\nconst intermediateObject = z.object({\n  _id: z.string(),\n  key: z.string(),\n  name: z.string(),\n  age: z.number()\n  // any other shared keys\n})\n```\n\nI can then manipulate this into the desired schema using\n[`or()`](https://github.com/colinhacks/zod#unions) and\n[`omit()`](https://github.com/colinhacks/zod#pickomit).\n\n```typescript\nconst objectWithoutId = intermediateObject.omit({ _id: true })\nconst objectWithoutKey = intermediateObject.omit({ key: true })\n\nconst unionSchema = objectWithoutId.or(objectWithoutKey)\n```\n\nAnd this produces the schema and union type I was looking for:\n\n```typescript\ntype Union = z.infer<typeof unionSchema>;\n/*\ntype Union = {\n    key: string;\n    name: string;\n    age: number;\n} | {\n    _id: string;\n    name: string;\n    age: number;\n}\n*/\n```\n\n[source](https://twitter.com/jbrancha/status/1572357904266850305)\n"
  },
  {
    "path": "zod/get-readable-errors-from-schema-parse.md",
    "content": "# Get Readable Errors From Schema Parse\n\nLet's say we have the following schema for validating the data used to create a\nnew post record:\n\n```typescript\nconst NewPostSchema = z.object({\n  title: z.string().min(1, \"Title is required\"),\n  slug: z.string().min(1, \"Slug is required\"),\n  markdown: z.string().min(1, \"Markdown is required\"),\n});\n```\n\nWhen we (safe) parse some incoming user input with that schema and, for\nexample, one of the fields is empty, then the validation will fail and we'll\nget some errors.\n\n```typescript\nconst result = NewPostSchema.safeParse(userInput)\n\nif(!result.success) {\n  result.error;\n  // ZodError: [\n  //   {\n  //     \"code\": \"too_small\",\n  //     \"minimum\": 1,\n  //     \"type\": \"string\",\n  //     \"inclusive\": true,\n  //     \"exact\": false,\n  //     \"message\": \"Slug is required\",\n  //     \"path\": [\n  //       \"slug\"\n  //     ]\n  //   }\n  // ]\n}\n```\n\nThat packs a lot of information. But if we are just trying to get something\nminimal and actionable we can show to a user, we might want to flatten the\nerrors:\n\n```typescript\nconst result = NewPostSchema.safeParse(userInput)\n\nif(!result.success) {\n  result.error.flatten().fieldErrors;\n  // { slug: [ 'Slug is required' ] }\n}\n```\n\n[source](https://github.com/colinhacks/zod/blob/master/ERROR_HANDLING.md#flattening-errors)\n"
  },
  {
    "path": "zod/incorporate-existing-type-into-zod-schema.md",
    "content": "# Incorporate Existing Type Into Zod Schema\n\nZod's API is great for quickly scaffolding the shape of data that we're\nworking with. This breaks down when data has a more complex shape and is coming\nfrom somewhere else, like a Prisma client. The shape of the data, and types\nprovided by the library, are determined somewhere else. We want to leverage\nthat rather than redefine it.\n\nFortunately, Zod has a way for us to incorporate an existing type into a Zod\nschema that we're building.\n\n```typescript\nimport {z} from 'zod'\nimport {Book} from '@prisma/client'\n\nconst BookOrder = z.object({\n  customer: z.object({\n    email: z.string().email(),\n    name: z.string()\n  }),\n  books: // how do we use the `Book` type here?\n})\n```\n\nWe can turn the `Book` type into a Zod type that we can use in our schema with\n`z.ZodType` and `z.any`.\n\n```typescript\nimport {z} from 'zod'\nimport {Book} from '@prisma/client'\n\nconst BookSchema: z.ZodType<Book> = z.any()\n\nconst BookOrder = z.object({\n  customer: z.object({\n    email: z.string().email(),\n    name: z.string()\n  }),\n  books: BookSchema.array()\n})\n```\n\nWe create a `BookSchema` with `z.any` and then narrow it to a `z.ZodType` with\nour `Book` type.\n\n[source](https://github.com/colinhacks/zod/issues/52#issuecomment-629897855)\n"
  },
  {
    "path": "zod/set-custom-error-message-for-nonempty-array.md",
    "content": "# Set Custom Error Message For Nonempty Array\n\nLet's say we have the following schema that represents a team:\n\n```typescript\nconst TeamSchema = z.object({\n  name: z.string(),\n  members: z.array(\n    z.object({ firstName: z.string(), lastName: z.string() })\n  )\n})\n```\n\nIf we want to enforce that a team must contain at least _one_ member in order\nto be valid, we can chain the `nonempty` function on the `members` array.\n\n```typescript\nconst TeamSchema = z.object({\n  name: z.string(),\n  members: z.array(\n    z.object({ firstName: z.string(), lastName: z.string() })\n  ).nonempty()\n})\n```\n\nThen we can set a custom error message for when that _nonempty_ requirement is\nviolated by adding an object argument with a `message`:\n\n```typescript\nconst TeamSchema = z.object({\n  name: z.string(),\n  members: z.array(\n    z.object({ firstName: z.string(), lastName: z.string() })\n  ).nonempty({\n    message: 'A team must contain at least one member'\n  })\n})\n```\n\nHere is that schema in action, not the `message` in the error:\n\n```typescript\nTeamSchema.parse({ name: 'A-Team', members: [] })\n// Error: [{\n//   \"code\": \"too_small\",\n//   \"minimum\": 1,\n//   \"type\": \"array\",\n//   \"inclusive\": true,\n//   \"exact\": false,\n//   \"message\": \"A team must contain at least one member\",\n//   \"path\": [\n//     \"members\"\n//   ]\n// }]\n```\n\n[source](https://github.com/colinhacks/zod#nonempty)\n"
  },
  {
    "path": "zsh/a-better-way-to-reload-zsh-configuration.md",
    "content": "# A Better Way To Reload ZSH Configuration\n\nI have an alias in my `~/.zshrc` that I set up to make it easy to \"reload\" my\nZSH configuration. This is handy if I'm iterating on some changes to my\n`~/.zshrc` file and need verify them as I go.\n\n```bash\nalias reload='source ~/.zshrc'\n```\n\nWith this alias, I can call `reload` from the terminal and the latest version\nof my configuration (according to the `~/.zshrc` file) will be loaded for that\nshell instance.\n\nThis has some downsides. It doesn't account for the other kinds of files that\ncontribute to your shell configuration (e.g. `~/.zprofile`) and it can lead to\nduplicate values in your `PATH` and init scripts being run an additional time.\n\nA better way is to use:\n\n```bash\n$ omz reload\n```\n\nThis is [a wrapper call around `exec\nzsh`](https://github.com/ohmyzsh/ohmyzsh/blob/master/lib/cli.zsh#L669-L677),\nwhich restarts the `zsh` process. It also clears the completion cache.\n\nI've since updated my `~/.zshrc` alias for `reload`:\n\n```bash\nalias reload='omz reload'\n```\n\n[source](https://batsov.com/articles/2022/09/15/reload-zsh-configuration/)\n"
  },
  {
    "path": "zsh/add-to-the-path-via-path-array.md",
    "content": "# Add To Path Via Path Array\n\nTypically when managing what is on your path in a Unix shell environment, you\noverride the `PATH` environment variable with `export`. This is usually an\nappend or prepend to bring along the existing path entries.\n\n```bash\n$ export PATH=\"$PATH:/Users/me/.local/bin\"\n```\n\nThe `zsh` shell environment exposes another way of adding to your path. They\nhave a `path` array which can be a little easier to work with since you can use\nan array operation instead of string interpolation.\n\nHere is how we'd do the same as above:\n\n```bash\n$ path+=/Users/me/.local/bin\n```\n\nThis works because there is an automatic linking in zsh between arrays and\ncolon-separated strings (_scalars_).\n[source](https://www.zsh.org/mla/users//2005/msg01132.html)\n\n[source](https://superuser.com/a/1447959)\n"
  },
  {
    "path": "zsh/create-and-jump-into-a-directory.md",
    "content": "# Create And Jump Into A Directory\n\n[Oh My Zsh](https://github.com/ohmyzsh/ohmyzsh) defines a function `take` that\nwe can use to both create and `cd` into a directory. If the directory already\nexists, it will simply `cd` into that directory.\n\n```bash\n~/code\n❯ take take-demo\n\n~/code/take-demo\n❯ mkdir already-exists\n\n~/code/take-demo\n❯ take already-exists\n\n~/code/take-demo/already-exists\n❯ cd ..\n\n~/code/take-demo\n❯ take one/two/three\n\n~/code/take-demo/one/two/three\n❯\n```\n\nFirst `take` creates and `cd`s into `take-demo`. Then `take` only `cd`s into\n`already-exists`. Then we see that `take` can create multiple levels of nested\ndirectories.\n\nWith the help of `which` we can see how `take` is defined:\n\n```bash\n$ which take\ntake () {\n        if [[ $1 =~ ^(https?|ftp).*\\.tar\\.(gz|bz2|xz)$ ]]\n        then\n                takeurl \"$1\"\n        elif [[ $1 =~ ^([A-Za-z0-9]\\+@|https?|git|ssh|ftps?|rsync).*\\.git/?$ ]]\n        then\n                takegit \"$1\"\n        else\n                takedir \"$@\"\n        fi\n}\n```\n\nWe're not dealing with compressed files or git URLs, so we fall through to the\n`else` block with invokes `takedir`.\n\n```bash\n$ which takedir\ntakedir () {\n        mkdir -p $@ && cd ${@:$#}\n}\n```\n\nThe `mkdir -p $@` is what allows it make new, nested directories and then we\n`cd` to it. The `${@:$#}` is a way of [grabbing the last argument to the\nfunction](https://stackoverflow.com/a/37601842/535590). This suggests that you\ncan pass multiple things to `take`, it will create all of them, and then `cd`\nyou into the last one.\n\n[source](https://github.com/ohmyzsh/ohmyzsh/blob/master/lib/functions.zsh#L75-L85)\n"
  },
  {
    "path": "zsh/link-a-scalar-to-an-array.md",
    "content": "# Link A Scalar To An Array\n\n`Zsh` has a builtin command `typeset` that does a variety of things. When given\nthe `-T` flag and the names of a scalar and an array, it will link them\ntogether so that a change to one is reflected in the other.\n\nThe scalar is a string of values delimited by a colon (`:`). The array is an\narray that can be interacted with using array operations like append (`+=`).\n\n```bash\n$ typeset -T FOO foo\n\n$ echo $FOO\n\n\n$ export FOO=\"one:two\"\n\n$ echo $foo\none two\n\n$ foo+=three\n\n$ echo $FOO\none:two:three\n```\n\nNotice `FOO` is initially empty. I then `export` it to overwrite it with two\nvalues delimited by a colon. Since `foo` is automatically kept in sync, I can\n`echo $foo` and see those values displayed as an array. I can then append a\nthird value using an array operation on `foo`. The update will be automatically\nreflected in `FOO`.\n\n`Zsh` does this under the hood for `PATH` and `path` which is why you can [add\nto the path via the path array](add-to-the-path-via-path-array.md).\n\nSee `man zshbuiltins` for more details.\n\n[source](http://devlib.symbian.slions.net/s3/GUID-D87C96CE-3F23-552D-927C-B6A1D61691BF.html)\n"
  },
  {
    "path": "zsh/use-a-space-to-exclude-command-from-history.md",
    "content": "# Use A Space To Exclude Command From History\n\nWhen using a shell like `zsh`, you get the benefit of it keeping track of the\nhistory of the commands you've entered into the shell. This means you can\nquickly traverse pack to a previous command that you want to run again. It also\nmeans [a tool like `fzf` can hook into your history\nfile](https://github.com/junegunn/fzf?tab=readme-ov-file#key-bindings-for-command-line)\nso that you can fuzzy-search for a command you may have executed weeks ago.\n\nThe history is stored on your machine in a plaintext file. Not every command\nshould be stored in a plaintext file. For instance, you don't want `zsh` to\npersist a command that includes a password.\n\nWith the `histignorespace` option enabled in `zsh`, we can put a leading space\nin front of our command and it will be excluded from the history file.\n\nTry it yourself:\n\n```bash\n$ echo 'this command will be remembered'\nthis command will be remembered\n\n$  echo 'this command will be forgotten'\nthis command will be forgotten\n```\n\nNotice the leading space in the second command. Trying pressing your _up_ arrow\nand notice only that first `echo` is remembered.\n\nMake sure `histignorespace` is included in the list when you run `setopt`. If\nit isn't, then add it:\n\n```bash\n$ setopt histignorespace\n```\n\n[source](https://stackoverflow.com/questions/8473121/execute-a-command-without-keeping-it-in-history/49643320#49643320)\n"
  }
]