From 2d7c9f64a4cb1988add56208943b7aa0d1f2530d Mon Sep 17 00:00:00 2001 From: Timur Date: Mon, 18 Nov 2024 12:10:14 +0100 Subject: [PATCH 1/2] stuff i do not need --- ack/ack-bar.md | 10 --- .../sign-up-user-with-email-and-password.md | 32 --------- ...generate-types-for-a-content-collection.md | 56 --------------- ...own-files-are-of-type-markdown-instance.md | 53 -------------- clojure/aggregation-using-merge-with.md | 22 ------ .../argument-requirements-for-a-function.md | 14 ---- .../combinations-of-items-from-a-sequence.md | 24 ------- clojure/define-something-only-once.md | 22 ------ clojure/evaluate-one-liners-with-lein-exec.md | 10 --- clojure/expanding-macros.md | 24 ------- ...et-the-value-of-an-environment-variable.md | 16 ----- clojure/list-functions-for-a-namespace.md | 42 ----------- clojure/load-a-file-into-the-repl.md | 13 ---- clojure/mapping-with-an-index.md | 18 ----- clojure/open-javadocs.md | 17 ----- clojure/pretty-print-the-last-thing.md | 19 ----- clojure/quick-clojure-docs.md | 9 --- clojure/reductions.md | 25 ------- clojure/set-max-heap-size.md | 11 --- ...pecify-the-directory-of-a-shell-command.md | 27 -------- clojure/splitting-on-whitespace.md | 34 --------- clojure/swap-two-items-in-a-vector.md | 31 --------- clojure/try-a-clojure-project-in-the-repl.md | 26 ------- clojure/type-of-anything.md | 25 ------- clojure/when-overflow-is-desired.md | 18 ----- deno/read-in-the-contents-of-a-file.md | 23 ------- ...-bigint-identity-column-for-primary-key.md | 48 ------------- ...rizzle-tracks-migrations-in-a-log-table.md | 39 ----------- drizzle/get-fields-for-inserted-row.md | 56 --------------- .../all-values-for-a-key-in-a-keyword-list.md | 22 ------ elixir/append-to-a-keyword-list.md | 42 ----------- elixir/assert-an-exception-is-raised.md | 27 -------- elixir/binary-representation-of-a-string.md | 15 ---- elixir/check-for-a-substring-match.md | 20 ------ elixir/check-list-membership.md | 21 ------ elixir/comparing-datetime-structs.md | 26 ------- ...intermediate-values-in-a-with-construct.md | 23 ------- elixir/compute-md5-digest-of-a-string.md | 22 ------ elixir/counting-records-with-ecto.md | 40 ----------- elixir/create-a-date-with-the-date-sigil.md | 17 ----- elixir/create-a-list-of-atoms.md | 19 ----- elixir/creating-a-pid.md | 40 ----------- elixir/creating-indexes-with-ecto.md | 19 ----- ...ltiple-clauses-in-an-anonymous-function.md | 29 -------- ...ine-the-latest-release-of-a-hex-package.md | 27 -------- elixir/do-you-have-the-time-part-2.md | 23 ------- elixir/do-you-have-the-time.md | 21 ------ ...mentation-lookup-with-vim-and-alchemist.md | 16 ----- elixir/dynamically-generating-atoms.md | 15 ---- .../execute-raw-sql-in-an-ecto-migration.md | 36 ---------- elixir/expose-internal-representation.md | 16 ----- elixir/include-captures-with-string-split.md | 33 --------- .../inspecting-the-process-message-queue.md | 33 --------- elixir/list-functions-for-a-module.md | 25 ------- elixir/listing-files-in-iex.md | 20 ------ elixir/match-on-a-map-in-a-with-construct.md | 25 ------- elixir/passing-around-and-using-modules.md | 38 ---------- ...pattern-matching-in-anonymous-functions.md | 25 ------- elixir/pipe-into-a-case-statement.md | 33 --------- elixir/quitting-iex.md | 14 ---- .../range-into-list-using-comprehensions.md | 13 ---- elixir/refer-to-a-module-within-itself.md | 29 -------- elixir/referencing-values-in-iexs-history.md | 44 ------------ elixir/remove-one-list-from-another.md | 29 -------- .../replace-duplicates-in-a-keyword-list.md | 26 ------- elixir/requiring-keys-for-structs.md | 39 ----------- elixir/reversing-a-list-part-2.md | 13 ---- elixir/reversing-a-list.md | 19 ----- elixir/root-directory-of-a-project.md | 15 ---- elixir/round-floats-to-integers.md | 28 -------- ...n-exunit-tests-in-a-deterministic-order.md | 29 -------- .../run-the-test-at-a-specific-line-number.md | 25 ------- ...me-functions-should-be-grouped-together.md | 30 -------- elixir/skip-a-specific-test.md | 19 ----- ...-interpolation-with-just-about-anything.md | 22 ------ elixir/unique-indexes-with-ecto.md | 23 ------- elixir/updating-values-in-a-map.md | 41 ----------- .../using-when-clauses-in-a-with-construct.md | 21 ------ elixir/virtual-fields-with-ecto-schemas.md | 30 -------- ...n-things-dont-match-the-with-statements.md | 30 -------- elixir/word-lists-for-atoms.md | 34 --------- .../add-javascript-to-body-of-the-document.md | 29 -------- groq/grab-multiple-values-from-a-reference.md | 43 ------------ ...grab-values-from-an-array-of-references.md | 29 -------- ...ttributes-when-conditional-check-passes.md | 40 ----------- ...e-type-of-operation-in-webhook-response.md | 26 ------- heroku/connect-to-a-database-by-color.md | 29 -------- ...eploy-a-review-app-to-a-different-stack.md | 29 -------- ...-problems-in-a-heroku-postgres-database.md | 23 ------- heroku/open-dashboard-for-specific-add-on.md | 17 ----- ...un-sql-against-remote-postgres-database.md | 27 -------- heroku/set-and-show-heroku-env-variables.md | 30 -------- heroku/ssh-into-heroku-server-hosting-app.md | 17 ----- inngest/ensure-lookup-can-be-retried.md | 57 --------------- .../exit-function-early-without-retries.md | 44 ------------ ...n-array-of-objects-into-a-single-object.md | 40 ----------- jq/count-each-collection-in-a-json-object.md | 34 --------- ...unt-the-number-of-things-in-a-json-file.md | 43 ------------ jq/extract-a-list-of-values.md | 49 ------------- ...ter-out-results-based-on-list-of-values.md | 34 --------- ...ll-objects-in-an-array-where-key-is-set.md | 50 -------------- ...-objects-with-a-matching-key-value-pair.md | 45 ------------ jq/get-a-slice-of-the-ends-of-an-array.md | 37 ---------- ...-the-first-item-for-every-top-level-key.md | 37 ---------- jq/get-the-last-item-from-an-array.md | 22 ------ ...ject-to-just-entries-of-a-specific-type.md | 28 -------- jq/turn-a-list-from-a-command-into-json.md | 32 --------- ...-json-files-together-based-on-shared-id.md | 52 -------------- mongodb/determine-the-database-version.md | 14 ---- mongodb/dump-a-remote-database.md | 37 ---------- ...ump-and-restore-with-a-single-gzip-file.md | 40 ----------- mongodb/get-size-stats-for-a-collection.md | 30 -------- .../list-size-stats-for-all-collections.md | 25 ------- netlify/override-the-default-yarn-version.md | 11 --- phoenix/bypass-template-rendering.md | 32 --------- phoenix/check-the-installed-version.md | 10 --- phoenix/generate-new-app-without-brunch.md | 16 ----- phoenix/render-a-template-to-a-string.md | 24 ------- ...rve-static-assets-from-custom-directory.md | 27 -------- phoenix/specifying-the-digest-directory.md | 19 ----- phoenix/specifying-the-server-port.md | 30 -------- ...eed-production-data-into-another-branch.md | 28 -------- ...y-separate-formatting-with-a-blank-line.md | 42 ----------- .../batch-insert-records-with-create-many.md | 41 ----------- ...-if-database-and-schema-are-not-in-sync.md | 37 ---------- prisma/configure-client-to-log-sql-queries.md | 33 --------- prisma/execute-a-raw-sql-query.md | 45 ------------ prisma/grab-a-limited-set-of-records.md | 27 -------- .../open-connections-to-multiple-databases.md | 39 ----------- .../override-table-name-for-prisma-model.md | 42 ----------- ...fy-alternate-location-for-prisma-schema.md | 28 -------- reason/break-out-of-a-while-loop.md | 27 -------- reason/compile-reason-to-native-with-dune.md | 28 -------- ...reason-with-an-ocaml-package-using-dune.md | 35 ---------- reason/create-a-map-of-strings.md | 31 --------- reason/create-a-stream-from-an-array.md | 35 ---------- reason/creating-a-2d-array.md | 36 ---------- ...-structures-with-self-referential-types.md | 29 -------- ...ing-variants-with-constructor-arguments.md | 39 ----------- ...namically-create-a-printf-string-format.md | 34 --------- ...stive-pattern-matching-of-list-variants.md | 32 --------- reason/format-the-current-file-within-vim.md | 19 ----- ...ate-a-native-reasonml-project-with-pesy.md | 17 ----- reason/generate-starter-reason-projects.md | 34 --------- ...ping-the-compiler-help-us-with-variants.md | 38 ---------- ...line-component-styles-with-reason-react.md | 29 -------- reason/is-this-a-directory-or-a-file.md | 38 ---------- reason/making-things-mutable.md | 31 --------- reason/modifying-a-string-with-blit-string.md | 25 ------- ...i-argument-functions-as-syntactic-sugar.md | 33 --------- reason/pattern-match-on-exceptions.md | 33 --------- ...ckly-bootstrap-a-react-app-using-reason.md | 26 ------- .../seeding-and-generating-random-integers.md | 23 ------- reason/stream-a-file-line-by-line.md | 32 --------- ...interpolation-with-integers-and-sprintf.md | 27 -------- ...tring-interpolation-with-quoted-strings.md | 35 ---------- reason/trying-out-reasonml-in-codesandbox.md | 10 --- reason/two-ways-to-find-an-item-in-a-list.md | 30 -------- ...ing-optional-labeled-function-arguments.md | 32 --------- ...pping-a-component-for-use-in-javascript.md | 46 ------------- .../monitor-an-audio-input-device-in-obs.md | 22 ------ vercel/add-web-server-layer-redirects.md | 36 ---------- ...-an-app-without-pushing-an-empty-commit.md | 25 ------- vercel/naming-of-the-vercel-config-file.md | 17 ----- .../pin-specific-pnpm-version-for-builds.md | 35 ---------- ...velopment-environment-variables-via-cli.md | 19 ----- webpack/better-module-imports-with-aliases.md | 40 ----------- webpack/debugging-with-full-source-maps.md | 23 ------- webpack/run-eslint-as-a-preloader.md | 29 -------- .../specify-port-of-cra-webpack-dev-server.md | 15 ---- webpack/use-a-specific-config-file.md | 12 ---- ...always-use-inline-functions-with-assign.md | 50 -------------- ...-jest-matcher-for-xstate-machine-states.md | 62 ----------------- ...vent-that-does-internal-self-transition.md | 69 ------------------- .../events-stop-propagating-once-handled.md | 54 --------------- ...e-actions-vs-actions-in-machine-options.md | 61 ---------------- .../make-immediate-and-delayed-transitions.md | 48 ------------- xstate/simple-states-and-composite-states.md | 52 -------------- xstate/start-a-machine-in-a-specific-state.md | 37 ---------- xstate/use-an-xstate-machine-with-react.md | 50 -------------- 180 files changed, 5365 deletions(-) delete mode 100644 ack/ack-bar.md delete mode 100644 amplify/sign-up-user-with-email-and-password.md delete mode 100644 astro/generate-types-for-a-content-collection.md delete mode 100644 astro/markdown-files-are-of-type-markdown-instance.md delete mode 100644 clojure/aggregation-using-merge-with.md delete mode 100644 clojure/argument-requirements-for-a-function.md delete mode 100644 clojure/combinations-of-items-from-a-sequence.md delete mode 100644 clojure/define-something-only-once.md delete mode 100644 clojure/evaluate-one-liners-with-lein-exec.md delete mode 100644 clojure/expanding-macros.md delete mode 100644 clojure/get-the-value-of-an-environment-variable.md delete mode 100644 clojure/list-functions-for-a-namespace.md delete mode 100644 clojure/load-a-file-into-the-repl.md delete mode 100644 clojure/mapping-with-an-index.md delete mode 100644 clojure/open-javadocs.md delete mode 100644 clojure/pretty-print-the-last-thing.md delete mode 100644 clojure/quick-clojure-docs.md delete mode 100644 clojure/reductions.md delete mode 100644 clojure/set-max-heap-size.md delete mode 100644 clojure/specify-the-directory-of-a-shell-command.md delete mode 100644 clojure/splitting-on-whitespace.md delete mode 100644 clojure/swap-two-items-in-a-vector.md delete mode 100644 clojure/try-a-clojure-project-in-the-repl.md delete mode 100644 clojure/type-of-anything.md delete mode 100644 clojure/when-overflow-is-desired.md delete mode 100644 deno/read-in-the-contents-of-a-file.md delete mode 100644 drizzle/create-bigint-identity-column-for-primary-key.md delete mode 100644 drizzle/drizzle-tracks-migrations-in-a-log-table.md delete mode 100644 drizzle/get-fields-for-inserted-row.md delete mode 100644 elixir/all-values-for-a-key-in-a-keyword-list.md delete mode 100644 elixir/append-to-a-keyword-list.md delete mode 100644 elixir/assert-an-exception-is-raised.md delete mode 100644 elixir/binary-representation-of-a-string.md delete mode 100644 elixir/check-for-a-substring-match.md delete mode 100644 elixir/check-list-membership.md delete mode 100644 elixir/comparing-datetime-structs.md delete mode 100644 elixir/compute-intermediate-values-in-a-with-construct.md delete mode 100644 elixir/compute-md5-digest-of-a-string.md delete mode 100644 elixir/counting-records-with-ecto.md delete mode 100644 elixir/create-a-date-with-the-date-sigil.md delete mode 100644 elixir/create-a-list-of-atoms.md delete mode 100644 elixir/creating-a-pid.md delete mode 100644 elixir/creating-indexes-with-ecto.md delete mode 100644 elixir/defining-multiple-clauses-in-an-anonymous-function.md delete mode 100644 elixir/determine-the-latest-release-of-a-hex-package.md delete mode 100644 elixir/do-you-have-the-time-part-2.md delete mode 100644 elixir/do-you-have-the-time.md delete mode 100644 elixir/documentation-lookup-with-vim-and-alchemist.md delete mode 100644 elixir/dynamically-generating-atoms.md delete mode 100644 elixir/execute-raw-sql-in-an-ecto-migration.md delete mode 100644 elixir/expose-internal-representation.md delete mode 100644 elixir/include-captures-with-string-split.md delete mode 100644 elixir/inspecting-the-process-message-queue.md delete mode 100644 elixir/list-functions-for-a-module.md delete mode 100644 elixir/listing-files-in-iex.md delete mode 100644 elixir/match-on-a-map-in-a-with-construct.md delete mode 100644 elixir/passing-around-and-using-modules.md delete mode 100644 elixir/pattern-matching-in-anonymous-functions.md delete mode 100644 elixir/pipe-into-a-case-statement.md delete mode 100644 elixir/quitting-iex.md delete mode 100644 elixir/range-into-list-using-comprehensions.md delete mode 100644 elixir/refer-to-a-module-within-itself.md delete mode 100644 elixir/referencing-values-in-iexs-history.md delete mode 100644 elixir/remove-one-list-from-another.md delete mode 100644 elixir/replace-duplicates-in-a-keyword-list.md delete mode 100644 elixir/requiring-keys-for-structs.md delete mode 100644 elixir/reversing-a-list-part-2.md delete mode 100644 elixir/reversing-a-list.md delete mode 100644 elixir/root-directory-of-a-project.md delete mode 100644 elixir/round-floats-to-integers.md delete mode 100644 elixir/run-exunit-tests-in-a-deterministic-order.md delete mode 100644 elixir/run-the-test-at-a-specific-line-number.md delete mode 100644 elixir/same-functions-should-be-grouped-together.md delete mode 100644 elixir/skip-a-specific-test.md delete mode 100644 elixir/string-interpolation-with-just-about-anything.md delete mode 100644 elixir/unique-indexes-with-ecto.md delete mode 100644 elixir/updating-values-in-a-map.md delete mode 100644 elixir/using-when-clauses-in-a-with-construct.md delete mode 100644 elixir/virtual-fields-with-ecto-schemas.md delete mode 100644 elixir/when-things-dont-match-the-with-statements.md delete mode 100644 elixir/word-lists-for-atoms.md delete mode 100644 gatsby/add-javascript-to-body-of-the-document.md delete mode 100644 groq/grab-multiple-values-from-a-reference.md delete mode 100644 groq/grab-values-from-an-array-of-references.md delete mode 100644 groq/include-attributes-when-conditional-check-passes.md delete mode 100644 groq/include-type-of-operation-in-webhook-response.md delete mode 100644 heroku/connect-to-a-database-by-color.md delete mode 100644 heroku/deploy-a-review-app-to-a-different-stack.md delete mode 100644 heroku/diagnose-problems-in-a-heroku-postgres-database.md delete mode 100644 heroku/open-dashboard-for-specific-add-on.md delete mode 100644 heroku/run-sql-against-remote-postgres-database.md delete mode 100644 heroku/set-and-show-heroku-env-variables.md delete mode 100644 heroku/ssh-into-heroku-server-hosting-app.md delete mode 100644 inngest/ensure-lookup-can-be-retried.md delete mode 100644 inngest/exit-function-early-without-retries.md delete mode 100644 jq/combine-an-array-of-objects-into-a-single-object.md delete mode 100644 jq/count-each-collection-in-a-json-object.md delete mode 100644 jq/count-the-number-of-things-in-a-json-file.md delete mode 100644 jq/extract-a-list-of-values.md delete mode 100644 jq/filter-out-results-based-on-list-of-values.md delete mode 100644 jq/find-all-objects-in-an-array-where-key-is-set.md delete mode 100644 jq/find-all-objects-with-a-matching-key-value-pair.md delete mode 100644 jq/get-a-slice-of-the-ends-of-an-array.md delete mode 100644 jq/get-the-first-item-for-every-top-level-key.md delete mode 100644 jq/get-the-last-item-from-an-array.md delete mode 100644 jq/reduce-object-to-just-entries-of-a-specific-type.md delete mode 100644 jq/turn-a-list-from-a-command-into-json.md delete mode 100644 jq/zip-two-json-files-together-based-on-shared-id.md delete mode 100644 mongodb/determine-the-database-version.md delete mode 100644 mongodb/dump-a-remote-database.md delete mode 100644 mongodb/dump-and-restore-with-a-single-gzip-file.md delete mode 100644 mongodb/get-size-stats-for-a-collection.md delete mode 100644 mongodb/list-size-stats-for-all-collections.md delete mode 100644 netlify/override-the-default-yarn-version.md delete mode 100644 phoenix/bypass-template-rendering.md delete mode 100644 phoenix/check-the-installed-version.md delete mode 100644 phoenix/generate-new-app-without-brunch.md delete mode 100644 phoenix/render-a-template-to-a-string.md delete mode 100644 phoenix/serve-static-assets-from-custom-directory.md delete mode 100644 phoenix/specifying-the-digest-directory.md delete mode 100644 phoenix/specifying-the-server-port.md delete mode 100644 planetscale/seed-production-data-into-another-branch.md delete mode 100644 prisma/apply-separate-formatting-with-a-blank-line.md delete mode 100644 prisma/batch-insert-records-with-create-many.md delete mode 100644 prisma/check-if-database-and-schema-are-not-in-sync.md delete mode 100644 prisma/configure-client-to-log-sql-queries.md delete mode 100644 prisma/execute-a-raw-sql-query.md delete mode 100644 prisma/grab-a-limited-set-of-records.md delete mode 100644 prisma/open-connections-to-multiple-databases.md delete mode 100644 prisma/override-table-name-for-prisma-model.md delete mode 100644 prisma/specify-alternate-location-for-prisma-schema.md delete mode 100644 reason/break-out-of-a-while-loop.md delete mode 100644 reason/compile-reason-to-native-with-dune.md delete mode 100644 reason/compile-reason-with-an-ocaml-package-using-dune.md delete mode 100644 reason/create-a-map-of-strings.md delete mode 100644 reason/create-a-stream-from-an-array.md delete mode 100644 reason/creating-a-2d-array.md delete mode 100644 reason/data-structures-with-self-referential-types.md delete mode 100644 reason/defining-variants-with-constructor-arguments.md delete mode 100644 reason/dynamically-create-a-printf-string-format.md delete mode 100644 reason/exhaustive-pattern-matching-of-list-variants.md delete mode 100644 reason/format-the-current-file-within-vim.md delete mode 100644 reason/generate-a-native-reasonml-project-with-pesy.md delete mode 100644 reason/generate-starter-reason-projects.md delete mode 100644 reason/helping-the-compiler-help-us-with-variants.md delete mode 100644 reason/inline-component-styles-with-reason-react.md delete mode 100644 reason/is-this-a-directory-or-a-file.md delete mode 100644 reason/making-things-mutable.md delete mode 100644 reason/modifying-a-string-with-blit-string.md delete mode 100644 reason/multi-argument-functions-as-syntactic-sugar.md delete mode 100644 reason/pattern-match-on-exceptions.md delete mode 100644 reason/quickly-bootstrap-a-react-app-using-reason.md delete mode 100644 reason/seeding-and-generating-random-integers.md delete mode 100644 reason/stream-a-file-line-by-line.md delete mode 100644 reason/string-interpolation-with-integers-and-sprintf.md delete mode 100644 reason/string-interpolation-with-quoted-strings.md delete mode 100644 reason/trying-out-reasonml-in-codesandbox.md delete mode 100644 reason/two-ways-to-find-an-item-in-a-list.md delete mode 100644 reason/using-optional-labeled-function-arguments.md delete mode 100644 reason/wrapping-a-component-for-use-in-javascript.md delete mode 100644 streaming/monitor-an-audio-input-device-in-obs.md delete mode 100644 vercel/add-web-server-layer-redirects.md delete mode 100644 vercel/deploy-an-app-without-pushing-an-empty-commit.md delete mode 100644 vercel/naming-of-the-vercel-config-file.md delete mode 100644 vercel/pin-specific-pnpm-version-for-builds.md delete mode 100644 vercel/share-development-environment-variables-via-cli.md delete mode 100644 webpack/better-module-imports-with-aliases.md delete mode 100644 webpack/debugging-with-full-source-maps.md delete mode 100644 webpack/run-eslint-as-a-preloader.md delete mode 100644 webpack/specify-port-of-cra-webpack-dev-server.md delete mode 100644 webpack/use-a-specific-config-file.md delete mode 100644 xstate/always-use-inline-functions-with-assign.md delete mode 100644 xstate/custom-jest-matcher-for-xstate-machine-states.md delete mode 100644 xstate/define-event-that-does-internal-self-transition.md delete mode 100644 xstate/events-stop-propagating-once-handled.md delete mode 100644 xstate/inline-actions-vs-actions-in-machine-options.md delete mode 100644 xstate/make-immediate-and-delayed-transitions.md delete mode 100644 xstate/simple-states-and-composite-states.md delete mode 100644 xstate/start-a-machine-in-a-specific-state.md delete mode 100644 xstate/use-an-xstate-machine-with-react.md diff --git a/ack/ack-bar.md b/ack/ack-bar.md deleted file mode 100644 index f925237e..00000000 --- a/ack/ack-bar.md +++ /dev/null @@ -1,10 +0,0 @@ -# ack --bar - -The [`ack`](https://beyondgrep.com/) utility has a fun Easter egg that dumps -a Star Wars meme to the command line. Give it a try. - -```bash -$ ack --bar -``` - -See `man ack` for more details. diff --git a/amplify/sign-up-user-with-email-and-password.md b/amplify/sign-up-user-with-email-and-password.md deleted file mode 100644 index 705d200c..00000000 --- a/amplify/sign-up-user-with-email-and-password.md +++ /dev/null @@ -1,32 +0,0 @@ -# Sign Up User With Email And Password - -[AWS Amplify](https://aws.amazon.com/amplify/) -[Auth](https://docs.amplify.aws/lib/auth/getting-started/q/platform/js) offers -both federated and username/password based authentication. Though the docs -aren't clear, the required `username` parameter can be used as the email field -with the [`signUp` -API](https://aws-amplify.github.io/amplify-js/api/classes/authclass.html#signup). - -```javascript -import { Auth } from 'aws-amplify'; - -async function signUp({ email, password }) { - try { - const user = await Auth.signUp({ - username: email, - password, - attributes: {}, - }); - console.log({ user }); - } catch (error) { - console.log('error signing up:', error); - } -} -``` - -Once the user has entered an email and password into the Sign Up form, those -values can be passed to this `signUp` function. The `email` value is passed as -the `username` and the `password` goes in as is. - -Amplify Auth will interpret the `username` as an email and register it as the -contact email for this user. diff --git a/astro/generate-types-for-a-content-collection.md b/astro/generate-types-for-a-content-collection.md deleted file mode 100644 index 4ee81be5..00000000 --- a/astro/generate-types-for-a-content-collection.md +++ /dev/null @@ -1,56 +0,0 @@ -# Generate Types For A Content Collection - -Let's say I'm using Astro to publish posts via markdown. One of the best ways -to do that is as a _Content Collection_. The posts will live in `src/content` -probably under a `posts` directory. Plus a config file will define the -collection and specify validations for the frontmatter. - -```typescript -// src/content/config.ts -import { defineCollection, z } from 'astro:content'; - -const postsCollection = defineCollection({ - schema: z.object({ - title: z.string(), - description: z.string(), - tags: z.array(z.string()) - }) -}); - -export const collections = { - 'posts': postsCollection, -}; -``` - -When I first add this to my project and get the collection, it won't know what -the types are. - -```astro ---- -import { getCollection } from "astro:content"; - -export async function getStaticPaths() { - const blogEntries = await getCollection("posts"); - // ^^^ any - - return blogEntries.map((entry) => ({ - params: { slug: entry.slug }, - props: { entry }, - })); -} ---- -``` - -I can tell Astro to generate a fresh set of types for things like content -collections by running the [`astro sync` -command](https://docs.astro.build/en/reference/cli-reference/#astro-sync). - -```bash -$ npm run astro sync -``` - -This updates auto-generated files under the `.astro` directory which get pulled -in to your project's `env.d.ts` file. - -All of these types will also be synced anytime I run `astro dev`, `astro -build`, or `astro check`. diff --git a/astro/markdown-files-are-of-type-markdown-instance.md b/astro/markdown-files-are-of-type-markdown-instance.md deleted file mode 100644 index 8671441d..00000000 --- a/astro/markdown-files-are-of-type-markdown-instance.md +++ /dev/null @@ -1,53 +0,0 @@ -# Markdown Files Are Of Type MarkdownInstance - -One of the things Astro excels at is rendering markdown files as HTML pages in -your site. And at some point we'll want to access a listing of those markdown -files in order to do something like display a list of them on an index page. -For that, we'll use -[`Astro.glob()`](https://docs.astro.build/en/reference/api-reference/#astroglob). - -```typescript ---- -const allPosts = await Astro.glob("../posts/*.md"); ---- - - -``` - -This looks great, but we'll run into a type error on that first line: -`'allPosts' implicitly has type 'any'`. We need to declare the type -of these post instances that are being read-in by Astro. - -These are of [type -`MarkdownInstance`](https://docs.astro.build/en/reference/api-reference/#markdown-files). -That's a generic though, so we need to tell it a bit more about the shape of a -post. - -```typescript -import type { MarkdownInstance } from "astro"; - -export type BarePost = { - layout: string; - title: string; - slug: string; - tags: string[]; -}; - -export type Post = MarkdownInstance; -``` - -We can then update that first line: - -```typescript -const allPosts: Post[] = await Astro.glob("../posts/*.md"); -``` - -Alternatively, you can specify the generic on `glob`: - -```typescript -const allPosts = await Astro.glob("../posts/*.md"); -``` diff --git a/clojure/aggregation-using-merge-with.md b/clojure/aggregation-using-merge-with.md deleted file mode 100644 index 5698e81b..00000000 --- a/clojure/aggregation-using-merge-with.md +++ /dev/null @@ -1,22 +0,0 @@ -# Aggregation Using merge-with - -Clojure provides the `merge-with` function as a way of conjoining a series -of maps. You must provide `merge-with` a function that it can use to merge -two values for matching keys. For instance, imagine you have a bunch of maps -that contain counts for entities identified by keywords. You can consolidate -the sum of all the counts into a single map using the `merge-with` function -combined with the `+` function. - -```clojure -> (merge-with + {:a 1 :b 3} {:b 2 :c 3} {:c 1 :d 4}) -{:a 1, :b 5, :c 4, :d 4} -``` - -For different kinds of data, a different function argument may be more -appropriate. For instance, aggregating lists instead of integers calls for -the `concat` function: - -```clojure -> (merge-with concat {:a '(1 2) :b '(3 4)} {:c '(3 4) :a '(5 4 1)}) -{:a (1 2 5 4 1), :b (3 4), :c (3 4)} -``` diff --git a/clojure/argument-requirements-for-a-function.md b/clojure/argument-requirements-for-a-function.md deleted file mode 100644 index c90b7254..00000000 --- a/clojure/argument-requirements-for-a-function.md +++ /dev/null @@ -1,14 +0,0 @@ -# Argument Requirements For A Function - -When defining a function, you must declare one or more function definitions, -each of which will require a different set of arguments. These argument -lists are stored as metadata for the function. So, if you are trying to -figure out what arity a function is or what variations of arguments it -takes, you can check the metadata like so: - -```clojure -> (:arglists (meta #'str)) -([] [x] [x & ys]) -``` - -[source](http://stackoverflow.com/questions/1696693/clojure-how-to-find-out-the-arity-of-function-at-runtime) diff --git a/clojure/combinations-of-items-from-a-sequence.md b/clojure/combinations-of-items-from-a-sequence.md deleted file mode 100644 index 412e9958..00000000 --- a/clojure/combinations-of-items-from-a-sequence.md +++ /dev/null @@ -1,24 +0,0 @@ -# Combinations Of Items From A Sequence - -Sometimes we want all combinations of items from a list. For instance, we -may have 5 people and we want to know all the ways that we can unique pair -up 2 people from that group of 5. What we want is the number of -combinations of 2 people from the 5. - -The -[clojure/math.combinatorics](https://github.com/clojure/math.combinatorics) -library provides a `combinations` function that gives us exactly that -functionality. - -```clojure -(use '[clojure.math.combinatorics :as combo]) - -(combo/combinations ["Liz", "Tracy", "Kenneth", "Jack", "Jenna"] 2) -; (("Liz" "Tracy") ("Liz" "Kenneth") ("Liz" "Jack") -; ("Liz" "Jenna") ("Tracy" "Kenneth") ("Tracy" "Jack") -; ("Tracy" "Jenna") ("Kenneth" "Jack") ("Kenneth" "Jenna") -; ("Jack" "Jenna")) -``` - -The `combinations` function takes a list of items and then a number for the -size of the grouping combinations that it is supposed to produce. diff --git a/clojure/define-something-only-once.md b/clojure/define-something-only-once.md deleted file mode 100644 index dad48a2d..00000000 --- a/clojure/define-something-only-once.md +++ /dev/null @@ -1,22 +0,0 @@ -# Define Something Only Once - -Clojure provides [`defonce`](https://clojuredocs.org/clojure.core/defonce) -which is a macro that defines something only once. Once a variable has been -bound to a value, subsequent attempts to do `defounce` for that variable -will go unevaluated. This will have no implications for how the `def` -special form works. - -Here is an example: - -```clojure -(defonce stuff 5) -#'user/stuff -user=> (defonce stuff "what") -nil -user=> stuff -5 -user=> (def stuff "okay") -#'user/stuff -user=> stuff -"okay" -``` diff --git a/clojure/evaluate-one-liners-with-lein-exec.md b/clojure/evaluate-one-liners-with-lein-exec.md deleted file mode 100644 index 2aedf560..00000000 --- a/clojure/evaluate-one-liners-with-lein-exec.md +++ /dev/null @@ -1,10 +0,0 @@ -# Evaluate One Liners With lein-exec - -You can install the [`lein-exec`](https://github.com/kumarshantanu/lein-exec) -plugin and then use it to evaluate one liner bits of code with the `-e` -flag. - -```bash -$ lein exec -e '(println "foo" (+ 20 30))' -foo 50 -``` diff --git a/clojure/expanding-macros.md b/clojure/expanding-macros.md deleted file mode 100644 index 12c3fde0..00000000 --- a/clojure/expanding-macros.md +++ /dev/null @@ -1,24 +0,0 @@ -# Expanding Macros - -Macros are an important part of Clojure's syntax. They allow you to write -cleaner, terser, more expressive code. -Though sometimes you may want to inspect the -clojure code that is actually produced by a particular macro. The -`macroexpand` function allows for just this. - -For instance, if you have a snippet of code using the `->>` operator: - -```clojure -(->> 4 (+ 1) (- 2) (* 3)) -``` - -You can wrap that form with the `macroexpand` function to see the form that -is ultimately evaluated: - -```clojure -> (macroexpand (->> 4 (+ 1) (- 2) (* 3))) -; (* 3 (- 2 (+ 1 4))) -``` - -It doesn't buy us much in a contrived example like this, but can prove -useful for better understanding clojure and the more complex code we write. diff --git a/clojure/get-the-value-of-an-environment-variable.md b/clojure/get-the-value-of-an-environment-variable.md deleted file mode 100644 index 6ca9db55..00000000 --- a/clojure/get-the-value-of-an-environment-variable.md +++ /dev/null @@ -1,16 +0,0 @@ -# Get The Value Of An Environment Variable - -You can get the value of an environment variable on your system using the -`System/getenv` function. Just pass it the environment variable as a string: - -```clojure -> (System/getenv "HOME") -"/Users/jbranchaud" -``` - -It returns `nil` when the environment variable doesn't exist. - -```clojure -> (System/getenv "HOUSE") -nil -``` diff --git a/clojure/list-functions-for-a-namespace.md b/clojure/list-functions-for-a-namespace.md deleted file mode 100644 index f8c7c89f..00000000 --- a/clojure/list-functions-for-a-namespace.md +++ /dev/null @@ -1,42 +0,0 @@ -# List Functions For A Namespace - -You know that `clojure.string` has a function for uppercasing a string, but -you can't quite remember the name of the function. You'd remember if you saw -the name though. What you'd like to do is list all the functions in the -`clojure.string` namespace to see if you can pick it out. - -You can do just that. There are a couple ways to do it, in fact. - -You can use the `dir` function with Clojure 1.6+. Alternatively, you can -grab all the keys from the public intern mappings of the namespace. - -```clojure -> (dir clojure.string) -blank? -capitalize -ends-with? -escape -includes? -index-of -join -last-index-of -lower-case -re-quote-replacement -replace -replace-first -reverse -split -split-lines -starts-with? -trim -trim-newline -triml -trimr -upper-case -nil - -> (keys (ns-publics 'clojure.string)) -(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?) -``` - -[source](http://stackoverflow.com/questions/2747294/how-to-list-the-functions-of-a-namespace) diff --git a/clojure/load-a-file-into-the-repl.md b/clojure/load-a-file-into-the-repl.md deleted file mode 100644 index fe048b89..00000000 --- a/clojure/load-a-file-into-the-repl.md +++ /dev/null @@ -1,13 +0,0 @@ -# Load A File Into The REPL - -You can quickly load a file into a REPL session using the `load-file` -function. You can specify an absolute or relative path and it will - -> sequentially read and evaluate the set of forms contained in the file. - -```clojure -(load-file "path/to/file.clj") -``` - -See the [`load-file` docs](https://clojuredocs.org/clojure.core/load-file) -for more details. diff --git a/clojure/mapping-with-an-index.md b/clojure/mapping-with-an-index.md deleted file mode 100644 index 12964d2f..00000000 --- a/clojure/mapping-with-an-index.md +++ /dev/null @@ -1,18 +0,0 @@ -# Mapping With An Index - -If you're mapping over a collection and you need an index for each item, you -can reach for `map-indexed`. The `map-indexed` function can be used like so: - -```clojure -> (def foods ["pizza" "hotdog" "chicken alfredo"]) -#'cljs.user/foods -> (map-indexed (fn [idx item] (str idx " - " item)) foods) -("0 - pizza" "1 - hotdog" "2 - chicken alfredo") -``` - -Alternatively, `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: - -```clojure -> (map (fn [idx item] (str idx " - " item)) (range) foods) -("0 - pizza" "1 - hotdog" "2 - chicken alfredo") -``` diff --git a/clojure/open-javadocs.md b/clojure/open-javadocs.md deleted file mode 100644 index 640dd3c4..00000000 --- a/clojure/open-javadocs.md +++ /dev/null @@ -1,17 +0,0 @@ -# Open JavaDocs - -Clojure has all kinds of Java interop including a fancy function called -`javadoc`. The `javadoc` function _opens a browser window displaying the -javadoc for the argument_. - -Thinking about using Java's `ArrayList` class, but want to read up on it -first? Try - -``` -> (javadoc java.util.ArrayList) -true -``` - -The javadoc page for -[ArrayList](http://docs.oracle.com/javase/6/docs/api/java/util/ArrayList.html) -will be opened up in your default browser. diff --git a/clojure/pretty-print-the-last-thing.md b/clojure/pretty-print-the-last-thing.md deleted file mode 100644 index e637f9d9..00000000 --- a/clojure/pretty-print-the-last-thing.md +++ /dev/null @@ -1,19 +0,0 @@ -# Pretty Print The Last Thing - -Clojure provides `pp` as a convenience macro for pretty printing the last -thing that was output. If you are playing around with a function in the -repl, trying to get the output just right, `pp` can come in handy. - -```clojure -> (fancy-func) -{:one {:a 1, :b 2, :c 3, :d 4}, :two {:b 2, :c 3, :d 4, :e 5}, :three {:c 3, -:d 4, :e 5, :f 6}, :four {:d 4, :e 5, :f 6, :g 7}} -> (clojure.pprint/pp) -{:one {:a 1, :b 2, :c 3, :d 4}, - :two {:b 2, :c 3, :d 4, :e 5}, - :three {:c 3, :d 4, :e 5, :f 6}, - :four {:d 4, :e 5, :f 6, :g 7}} -nil -``` - -See `(doc pp)` for more details. diff --git a/clojure/quick-clojure-docs.md b/clojure/quick-clojure-docs.md deleted file mode 100644 index 2aabb95b..00000000 --- a/clojure/quick-clojure-docs.md +++ /dev/null @@ -1,9 +0,0 @@ -# Quick Clojure Docs - -Assuming you already have the -[`fireplace.vim`](https://github.com/tpope/vim-fireplace) plugin installed -and a repl running, you can quickly pull up the docs for any clojure -function. Navigate the cursor over the keyword in question and hit `K` in -normal mode. This will instruct `fireplace.vim` to use the `doc` function on -the symbol for that keyword. The docs associated with that keyword will be -displayed at the bottom of the window. diff --git a/clojure/reductions.md b/clojure/reductions.md deleted file mode 100644 index 9432ddef..00000000 --- a/clojure/reductions.md +++ /dev/null @@ -1,25 +0,0 @@ -# Reductions - -One of the core functions in Clojure is -[`reduce`](https://clojuredocs.org/clojure.core/reduce). It allows you to -build up some result based on applying a function to each value in a -collection. Clojure provides a similar function that builds up a (lazy) -sequence of intermediate values as it is performing a reduce. -This function is -[`reductions`](https://clojuredocs.org/clojure.core/reductions). - -Using `reduce` to sum a collection of integers looks like this - -```clojure -> (reduce + 0 [1 2 3 4 5]) -=> 15 -``` - -whereas `reductions` performing the same task will look like this - -```clojure -> (reductions + 0 [1 2 3 4 5]) -=> (0 1 3 6 10 15) -``` - -h/t Josh Davey diff --git a/clojure/set-max-heap-size.md b/clojure/set-max-heap-size.md deleted file mode 100644 index 235058c5..00000000 --- a/clojure/set-max-heap-size.md +++ /dev/null @@ -1,11 +0,0 @@ -# Set Max Heap Size - -For `lein`-based projects, the maximum heap size can be set by including the -`-Xmx` option in the `jvm-opts` portion of the `project.clj` file. For -instance, to set the maximum JVM heap size to 2 gigabytes, include: - -```clojure - :jvm-opts ["-Xmx2g"] -``` - -in your `project.clj` file. diff --git a/clojure/specify-the-directory-of-a-shell-command.md b/clojure/specify-the-directory-of-a-shell-command.md deleted file mode 100644 index f001228e..00000000 --- a/clojure/specify-the-directory-of-a-shell-command.md +++ /dev/null @@ -1,27 +0,0 @@ -# Specify the Directory of a Shell Command - -Clojure gives us access to Java's shell capabilities through -`clojure.java.shell`. For instance, if you want to list the contents of your -project's directory, you can issue an `ls` command: - -``` -> (clojure.java.shell/sh "ls") -; {:exit 0, -; :out "LICENSE\nREADME.md\ndoc\nproject.clj\nresources\nsrc\ntarget\ntest\n", -; :err ""} -``` - -The default will always be to execute the command in the directory of the -containing project. It is likely that you'd like to specify a different -directory though. There is a function for that: - -```clojure -(clojure.java.shell/with-sh-dir "some/dir" (clojure.java.shell/sh "ls")) -``` - -Or more concisely, you can specify the directory as part of the `sh` -function: - -```clojure -(clojure.java.shell/sh "ls" :dir "some/dir") -``` diff --git a/clojure/splitting-on-whitespace.md b/clojure/splitting-on-whitespace.md deleted file mode 100644 index 09ce35d2..00000000 --- a/clojure/splitting-on-whitespace.md +++ /dev/null @@ -1,34 +0,0 @@ -# Splitting On Whitespace - -If you have a string with spaces and you want to split the string into a -vector of strings (delimited by the spaces), then you can do something like -this: - -```clojure -(clojure.string/split "split me up" #" ") -; ["split" "me" "up"] -``` - -However, if you have extra spaces in your string, the output may not be quite -what you want: - -```clojure -(clojure.string/split "double spacing wtf?" #" ") -; ["double" "" "spacing" "" "wtf?"] -``` - -A quick fix might look like this: - -```clojure -(clojure.string/split "double spacing wtf?" #" +") -; ["double" "spacing" "wtf?"] -``` - -That's nice, but it is going to fall over as soon as we run into input with -tabs and new lines. Assuming we want to split on all whitespace, we should -tell our regular expression to do just that: - -```clojure -(clojure.string/split "we\thave new\nlines and tabs\n" #"\s+") -; ["we" "have" "new" "lines" "and" "tabs"] -``` diff --git a/clojure/swap-two-items-in-a-vector.md b/clojure/swap-two-items-in-a-vector.md deleted file mode 100644 index 7867e4e1..00000000 --- a/clojure/swap-two-items-in-a-vector.md +++ /dev/null @@ -1,31 +0,0 @@ -# Swap Two Items in a Vector - -If you want to replace the value at an index in a vector, you can use the -`assoc` function supplied by `clojure.core` like so: - -```clojure -> (assoc [5 6 7 8] 1 9) -; [5 9 7 8] -``` - -Likewise, if you want to replace two items in a vector, you can extend the -above like so: - -```clojure -> (assoc [5 6 7 8] 1 2 2 4) -; [5 2 4 8] -``` - -We can take advantage of that second example to construct a function that -will swap two values: - -```clojure -(defn swap - [items i j] - (assoc items i (items j) j (items i))) -``` - -This function will break on values of `i` and `j` that are out of the bounds -of `items`, but dealing with that is left as an exercise to the reader. - -[source](http://stackoverflow.com/questions/5979538/what-is-the-idiomatic-way-to-swap-two-elements-in-a-vector) diff --git a/clojure/try-a-clojure-project-in-the-repl.md b/clojure/try-a-clojure-project-in-the-repl.md deleted file mode 100644 index 2ac316cb..00000000 --- a/clojure/try-a-clojure-project-in-the-repl.md +++ /dev/null @@ -1,26 +0,0 @@ -# Try A Clojure Project In The REPL - -The `lein-try` plugin is a tool that makes it easy to quickly try out a -clojure project in the lein repl. Given the name and version of a clojure -project, it will drop you into a repl with that project loaded in. This is a -great way to get the feel for the features of an unfamiliar clojure library -before dropping it in as a dependency to your own project. - -First, add the plugin to your `~/.lein/profiles.clj` file by including the -following line in the `:plugins` vector: - -``` -[lein-try "0.4.3"] -``` - -Then simply invoke the plugin with whatever project you want to try: - -``` -$ lein try automat -``` - -And to include a specific version number: - -``` -$ lein try automat "0.1.3" -``` diff --git a/clojure/type-of-anything.md b/clojure/type-of-anything.md deleted file mode 100644 index be9b3c91..00000000 --- a/clojure/type-of-anything.md +++ /dev/null @@ -1,25 +0,0 @@ -# Type of Anything - -You can get the type of anything with the `type` function. Because Clojure -is built on Java, many of these types may be types you recognize form Java. - -Boot up the repl to try some of these out: - -```clojure -> (type 5) -; java.lang.Long -> (type 5.2) -; java.lang.Double -> (type 5/4) -; clojure.lang.Ratio -> (type (int 2)) -; java.lang.Integer -> (type "hello, world!") -; java.lang.String -> (type [1 2 3]) -; clojure.lang.PersistentVector -> (type '(1 2 3)) -; clojure.lang.PersistentList -``` - -[source](https://aphyr.com/posts/302-clojure-from-the-ground-up-basic-types) diff --git a/clojure/when-overflow-is-desired.md b/clojure/when-overflow-is-desired.md deleted file mode 100644 index 4eebba00..00000000 --- a/clojure/when-overflow-is-desired.md +++ /dev/null @@ -1,18 +0,0 @@ -# When Overflow Is Desired - -If you try to add two `MAX_VALUE` Longs, Clojure is kind enough to warn you. - -```clojure -> (+ Long/MAX_VALUE Long/MAX_VALUE) -ArithmeticException integer overflow clojure.lang.Numbers.throwIntOverflow (Numbers.java:1424) -``` - -However, when overflow is desired, you can use the *unchecked* operators -(e.g. `unchecked-add`). - -```clojure -> (unchecked-add Long/MAX_VALUE Long/MAX_VALUE) --2 -``` - -See also `unchecked-subtract` and `unchecked-multiply`. diff --git a/deno/read-in-the-contents-of-a-file.md b/deno/read-in-the-contents-of-a-file.md deleted file mode 100644 index 5a6dd5b6..00000000 --- a/deno/read-in-the-contents-of-a-file.md +++ /dev/null @@ -1,23 +0,0 @@ -# Read In The Contents Of A File - -Deno offers some nice utilities out of the box like reading in the contents of -a file from the filesystem. The `readTextFile` function is available on the -`Deno` object. - -```typescript -// Read a file using Deno -const text: string = await Deno.readTextFile("./first_input.txt"); -``` - -You use a top-level await with the function call and, assuming the file exists, -it will read the contents in. In this case, I assign them to the `text` -variable. - -For the file reading to work when the program is executed, you must use the -`--allow-read` flag. - -```bash -$ deno run --allow-read program.ts -``` - -[source](https://deno.land/manual@v1.14.0/examples/read_write_files) diff --git a/drizzle/create-bigint-identity-column-for-primary-key.md b/drizzle/create-bigint-identity-column-for-primary-key.md deleted file mode 100644 index 99a28e35..00000000 --- a/drizzle/create-bigint-identity-column-for-primary-key.md +++ /dev/null @@ -1,48 +0,0 @@ -# Create bigint Identity Column For Primary Key - -Using the Drizzle ORM with Postgres, here is how we can create a table that -uses a [`bigint` data -type](https://orm.drizzle.team/docs/column-types/pg#bigint) as a primary key -[identity -column](https://www.postgresql.org/docs/current/ddl-identity-columns.html). - -```typescript -import { - pgTable, - bigint, - text, - timestamp, -} from "drizzle-orm/pg-core"; - -// Users table -export const users = pgTable("users", { - id: bigint({ mode: 'bigint' }).primaryKey().generatedAlwaysAsIdentity(), - email: text("email").unique().notNull(), - name: text("name").notNull(), - createdAt: timestamp("created_at").defaultNow().notNull(), -}); -``` - -There are a couple key pieces here: - -1. We import `bigint` so that we can declare a column of that type. -2. We specify that it is a primary key with `.primaryKey()`. -3. We declare its default value as `generated always as identity` via - `.generatedAlwaysAsIdentity()`. - -Note: you need to specify the `mode` for `bigint` or else you will see a -`TypeError: Cannot read properties of undefined (reading 'mode')` error. - -If we run `npx drizzle-kit generate` the SQL migration file that gets -generated will contain something like this: - -```sql ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "users" ( - "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), - "email" text NOT NULL, - "name" text NOT NULL, - "created_at" timestamp DEFAULT now() NOT NULL, - CONSTRAINT "users_email_unique" UNIQUE("email") -); -``` diff --git a/drizzle/drizzle-tracks-migrations-in-a-log-table.md b/drizzle/drizzle-tracks-migrations-in-a-log-table.md deleted file mode 100644 index 260d0514..00000000 --- a/drizzle/drizzle-tracks-migrations-in-a-log-table.md +++ /dev/null @@ -1,39 +0,0 @@ -# Drizzle Tracks Migrations In A Log Table - -When I generate (`npx drizzle-kit generate`) and apply (`npx drizzle-kit -migrate`) schema migrations against my database with Drizzle, there are SQL -files that get created and run. - -How does Drizzle know which SQL files have been run and which haven't? - -Like many SQL schema migration tools, it uses a table in the database to record -this metadata. Drizzle defaults to calling this table `__drizzle_migrations` -and puts it in the `drizzle` schema (which is like a database namespace). - -Let's take a look at this table for a project with two migrations: - -```sql -postgres> \d drizzle.__drizzle_migrations - Table "drizzle.__drizzle_migrations" - Column | Type | Collation | Nullable | Default -------------+---------+-----------+----------+---------------------------------------------------------- - id | integer | | not null | nextval('drizzle.__drizzle_migrations_id_seq'::regclass) - hash | text | | not null | - created_at | bigint | | | -Indexes: - "__drizzle_migrations_pkey" PRIMARY KEY, btree (id) - -postgres> select * from drizzle.__drizzle_migrations; - id | hash | created_at -----+------------------------------------------------------------------+--------------- - 1 | 8961353bf66f9b3fe1a715f6ea9d9ef2bc65697bb8a5c2569df939a61e72a318 | 1730219291288 - 2 | b75e61451e2ce37d831608b1bc9231bf3af09e0ab54bf169be117de9d4ff6805 | 1730224013018 -(2 rows) -``` - -Notice that Drizzle stores each migration record as [a SHA256 hash of the -migration -file](https://github.com/drizzle-team/drizzle-orm/blob/526996bd2ea20d5b1a0d65e743b47e23329d441c/drizzle-orm/src/migrator.ts#L52) -and a timestamp of when the migration was run. - -[source](https://orm.drizzle.team/docs/drizzle-kit-migrate#applied-migrations-log-in-the-database) diff --git a/drizzle/get-fields-for-inserted-row.md b/drizzle/get-fields-for-inserted-row.md deleted file mode 100644 index 0f96ba56..00000000 --- a/drizzle/get-fields-for-inserted-row.md +++ /dev/null @@ -1,56 +0,0 @@ -# Get Fields For Inserted Row - -With Drizzle, we can insert a row with a set of values like so: - -```typescript -await db - .insert(todoItems) - .values({ - title, - userId, - description, - }) -``` - -The result of this is `QueryResult`. In other words, nothing useful is -coming back to us from the database. - -Sometimes an insert is treated as a fire-and-forget (as long as it succeeds) or -since we know what data we are inserting, we don't need the database to -response. But what about values that are generated or computed by the database --- such as an id from a sequence, timestamp columns that default to `now()`, or -generated columns. - -To get all the fields of a freshly inserted row, we can tack on [the -`returning()` function](https://orm.drizzle.team/docs/insert#insert-returning) -(which likely adds something like [`returning -*`](https://www.postgresql.org/docs/current/dml-returning.html)) to the insert -query under the hood). - -```typescript -await db - .insert(todoItems) - .values({ - title, - userId, - description, - }) - .returning() -``` - -This will have a return type of `Array` which means that for -each inserted row we'll have all the fields (columns) for that row. - -Alternatively, if we just need the generated ID for the new row(s), we can use -a partial return like so: - -```typescript -await db - .insert(todoItems) - .values({ - title, - userId, - description, - }) - .returning({ id: todoItems.id }) -``` diff --git a/elixir/all-values-for-a-key-in-a-keyword-list.md b/elixir/all-values-for-a-key-in-a-keyword-list.md deleted file mode 100644 index ee79173c..00000000 --- a/elixir/all-values-for-a-key-in-a-keyword-list.md +++ /dev/null @@ -1,22 +0,0 @@ -# All Values For A Key In A Keyword List - -A keyword list in Elixir can contain the same key multiple times. - -```elixir -kwl = [a: 1, b: 2, a: 3, c: 4] -#=> [a: 1, b: 2, a: 3, c: 4] -``` - -The `get/2` function will only grab the value of the first occurrence. - -```elixir -Keyword.get(kwl, :a) -#=> 1 -``` - -You can use `get_values/2` to retrieve _all_ values associated with the key. - -```elixir -Keyword.get_values(kwl, :a) -#=> [1, 3] -``` diff --git a/elixir/append-to-a-keyword-list.md b/elixir/append-to-a-keyword-list.md deleted file mode 100644 index a43448b7..00000000 --- a/elixir/append-to-a-keyword-list.md +++ /dev/null @@ -1,42 +0,0 @@ -# Append To A Keyword List - -If you have two keyword lists, you can append them like so: - -```elixir -> a = [a: 1] -[a: 1] -> b = [b: 2] -[b: 2] -> a ++ b -[a: 1, b: 2] -``` - -But what if something a bit more programmatic is happening and you are -building up the additions to the keyword list based on variables? - -```elixir -> x = :x -:x -> c = a ++ [x 5] -** (CompileError) iex:5: undefined function x/1 - (stdlib) lists.erl:1353: :lists.mapfoldl/3 - (stdlib) lists.erl:1354: :lists.mapfoldl/3 -``` - -That makes elixir think `x` is some function when in fact it is just a -variable containing the keyword `:x`. - -Simply adding a comma doesn't quite do it either. - -```elixir -> c = a ++ [x, 5] -[{:a, 1}, :x, 5] -``` - -We need to wrap the internal part with curly braces to create the tuple that -can then be appended to `a`. - -```elixir -> c = a ++ [{x, 5}] -[a: 1, x: 5] -``` diff --git a/elixir/assert-an-exception-is-raised.md b/elixir/assert-an-exception-is-raised.md deleted file mode 100644 index 8f7cd3ff..00000000 --- a/elixir/assert-an-exception-is-raised.md +++ /dev/null @@ -1,27 +0,0 @@ -# Assert An Exception Is Raised - -Elixir's [`ExUnit`](http://elixir-lang.org/docs.html) comes with a number of -different ways to make assertions in your tests. One of those functions is -[`assert_raise`](http://elixir-lang.org/docs/stable/ex_unit/ExUnit.Assertions.html#assert_raise/2) -which allows you to test that a particular exception is raised when the -given function is invoked. - -Using `assert_raise/2` looks something like this: - -```elixir -assert_raise FunctionClauseError, fn -> - Enum.chunk([1,2,3], 0) -end -``` - -The `assert_raise/3` form is also available which allows you to test both -the type of exception and the resulting message. - -```elixir -assert_raise FunctionClauseError, ~r/^no function clause matching/, fn -> - Enum.chunk([1,2,3], 0) -end -``` - -Using the regex sigil for the second argument is generally a good way to go -to keep tests from getting too brittle. diff --git a/elixir/binary-representation-of-a-string.md b/elixir/binary-representation-of-a-string.md deleted file mode 100644 index 382f61c9..00000000 --- a/elixir/binary-representation-of-a-string.md +++ /dev/null @@ -1,15 +0,0 @@ -# Binary Representation Of A String - -> A common trick in Elixir is to concatenate the null byte <<0>> to a string -> to see its inner binary representation. - -A couple example of this can be seen in the following snippet of code: - -```elixir -> "hello" <> <<0>> -<<104, 101, 108, 108, 111, 0>> -> "ƒå®øü†" <> <<0>> -<<198, 146, 195, 165, 194, 174, 195, 184, 195, 188, 226, 128, 160, 0>> -``` - -[source](http://elixir-lang.org/getting-started/binaries-strings-and-char-lists.html) diff --git a/elixir/check-for-a-substring-match.md b/elixir/check-for-a-substring-match.md deleted file mode 100644 index bcfb628a..00000000 --- a/elixir/check-for-a-substring-match.md +++ /dev/null @@ -1,20 +0,0 @@ -# Check For A Substring Match - -Using Erlang's `:binary.match` function, you can easily check if a string -has a matching substring. - -```elixir -> :binary.match("all food is good", "foo") -{4, 3} -> :binary.match("all food is good", "bar") -:nomatch -``` - -As you can see, the return value on a successful match is a tuple with the -index of where the match starts and the length of the match. If there is no -match, the `:nomatch` atom is returned. - -See the [`match/2` and `match/3` -docs](http://erlang.org/doc/man/binary.html#match-2) for more details. - -[source](http://stackoverflow.com/questions/35551072/how-to-find-index-of-a-substring) diff --git a/elixir/check-list-membership.md b/elixir/check-list-membership.md deleted file mode 100644 index ca4b67bf..00000000 --- a/elixir/check-list-membership.md +++ /dev/null @@ -1,21 +0,0 @@ -# Check List Membership - -You can use the [`in` operator](https://hexdocs.pm/elixir/operators.html) to -check if something appears in a list. This is a handy way of checking if a -variable is one of a few acceptable or expected values. - -For instance, a common DateTime comparison pattern relies on this to check -if a DateTime is `>=` or `<=` to another DateTime. - -```elixir -{:ok, datetime} = DateTime.from_naive(~N[2016-05-24 13:26:08.003], "Etc/UTC") - -DateTime.compare(datetime, DateTime.utc_now()) in [:lt, :eq] -``` - -Alternatively, you can check that something does not have membership in a -list by also including the `not` operator. - -```elixir -DateTime.compare(datetime, DateTime.utc_now()) not in [:lt, :eq] -``` diff --git a/elixir/comparing-datetime-structs.md b/elixir/comparing-datetime-structs.md deleted file mode 100644 index 2b409471..00000000 --- a/elixir/comparing-datetime-structs.md +++ /dev/null @@ -1,26 +0,0 @@ -# Comparing DateTime Structs - -> Remember, comparisons in Elixir using ==/2, >/2, structural and based on the DateTime struct fields. For proper comparison -> between datetimes, use the compare/2 function. - -As the [DateTime docs](https://hexdocs.pm/elixir/DateTime.html) say, you'll -want to use [`compare/2`](https://hexdocs.pm/elixir/DateTime.html#compare/2) -in order to accurately compare two `DateTime` structs. - -```elixir -{:ok, older} = DateTime.from_naive(~N[2016-05-24 13:26:08.003], "Etc/UTC") -{:ok, newer} = DateTime.from_naive(~N[2017-11-24 13:26:08.003], "Etc/UTC") - -DateTime.compare(older, newer) -#=> :lt - -DateTime.compare(newer, older) -#=> :gt - -DateTime.compare(newer, newer) -#=> :eq -``` - -When using `compare/2`, you'll get one of `:lt`, `:gt`, or `:eq` as a -result, meaning _less than_, _greater than_, or _equal_ respectively. diff --git a/elixir/compute-intermediate-values-in-a-with-construct.md b/elixir/compute-intermediate-values-in-a-with-construct.md deleted file mode 100644 index c42f4d77..00000000 --- a/elixir/compute-intermediate-values-in-a-with-construct.md +++ /dev/null @@ -1,23 +0,0 @@ -# Compute Intermediate Values In A With Construct - -The expressions you use in a `with` construct do not have to contain the -`<-` syntax. You can pattern match and bind values along the way as well. - -```elixir -with %{id: id} <- get_user(), - url = "/api/#{id}/blogs", - %{status_code: 200, body: body} <- HTTPoison.get(url), - {:ok, decoded_body} <- Poison.decode(body) do - {:ok, decoded_body} -end -``` - -In the above (sorta contrived) example we were able to construct a URL in -the middle of the series of expressions. - -The values we compute inline will be closed into the `with` construct, so -they won't leak. - -See the [`with` -docs](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#with/1) for more -details. diff --git a/elixir/compute-md5-digest-of-a-string.md b/elixir/compute-md5-digest-of-a-string.md deleted file mode 100644 index 2b192e1e..00000000 --- a/elixir/compute-md5-digest-of-a-string.md +++ /dev/null @@ -1,22 +0,0 @@ -# Compute md5 Digest Of A String - -To compute the md5 digest of a string, we can use Erlang's top-level `md5` -function. - -```elixir -> :erlang.md5("#myelixirstatus") -<<145, 148, 139, 99, 194, 176, 105, 18, 242, 246, 37, 69, 142, 69, 226, 199>> -``` - -This, however, gives us the result in the raw binary representation. We -would like it in a base 16 encoding, as md5 digests tend to be. - -We can wrap (or pipe) this with `Base.encode16` to get the result we are -looking for. - -```elixir -> Base.encode16(:erlang.md5("#myelixirstatus"), case: :lower) -"91948b63c2b06912f2f625458e45e2c7" -``` - -[source](https://gist.github.com/10nin/5713366#gistcomment-1445219) diff --git a/elixir/counting-records-with-ecto.md b/elixir/counting-records-with-ecto.md deleted file mode 100644 index 671eb573..00000000 --- a/elixir/counting-records-with-ecto.md +++ /dev/null @@ -1,40 +0,0 @@ -# Counting Records With Ecto - -Sometimes you want to know how many records there are in a table. Ecto gives -us a couple ways to approach this. - -We can use the -[`count\1`](https://hexdocs.pm/ecto/Ecto.Query.API.html#count/1) function -that the Ecto query API provides. - -```elixir -> Repo.one(from p in "people", select: count(p.id)) - -16:09:52.759 [debug] QUERY OK source="people" db=1.6ms -SELECT count(p0."id") FROM "people" AS p0 [] -168 -``` - -Alternatively, we can use the -[`fragment/1`](https://hexdocs.pm/ecto/Ecto.Query.API.html#fragment/1) -function to use PostgreSQL's `count` function. - -```elixir -> Repo.one(from p in "people", select: fragment("count(*)")) - -16:11:19.818 [debug] QUERY OK source="people" db=1.5ms -SELECT count(*) FROM "people" AS p0 [] -168 -``` - -Lastly, `Ecto.Repo` has the -[`aggregate/4`](https://hexdocs.pm/ecto/Ecto.Repo.html#c:aggregate/4) -function which provides a `:count` option. - -```elixir -> Repo.aggregate(from(p in "people"), :count, :id) - -16:11:23.786 [debug] QUERY OK source="people" db=1.7ms -SELECT count(p0."id") FROM "people" AS p0 [] -168 -``` diff --git a/elixir/create-a-date-with-the-date-sigil.md b/elixir/create-a-date-with-the-date-sigil.md deleted file mode 100644 index 719dc76d..00000000 --- a/elixir/create-a-date-with-the-date-sigil.md +++ /dev/null @@ -1,17 +0,0 @@ -# Create A Date With The Date Sigil - -Elixir 1.3 introduced a new sigil for creating dates, `~D`. It works in the -same way as Date's -[`new/3`](http://elixir-lang.org/docs/stable/elixir/Date.html#new/3) -function producing the Date struct with each of the date parts. - -```elixir -> ~D[2016-01-01] -~D[2016-01-01] -> ~D[2016-01-01].year -2016 -> ~D[2016-01-01].month -1 -> ~D[2016-01-01].day -1 -``` diff --git a/elixir/create-a-list-of-atoms.md b/elixir/create-a-list-of-atoms.md deleted file mode 100644 index 8438212c..00000000 --- a/elixir/create-a-list-of-atoms.md +++ /dev/null @@ -1,19 +0,0 @@ -# Create A List Of Atoms - -The `~w` sigil makes it easy to create a word list -- a list of strings -- -where each word is separated by a space. - -```elixir -> ~w(bulbasaur charmander squirtle) -["bulbasaur", "charmander", "squirtle"] -``` - -By appending an `a` onto that sigil construct, you are instructing Elixir -that you would instead like a list of atoms. - -```elixir -> ~w(bulbasaur charmander squirtle)a -[:bulbasaur, :charmander, :squirtle] -``` - -[source](http://elixir-lang.org/getting-started/sigils.html#strings) diff --git a/elixir/creating-a-pid.md b/elixir/creating-a-pid.md deleted file mode 100644 index 334de870..00000000 --- a/elixir/creating-a-pid.md +++ /dev/null @@ -1,40 +0,0 @@ -# Creating A PID - -Often times, when invoking a function that spawns a process, the PID of the -spawned process is returned and we bind to it. That PID is a reference to -some BEAM process in our system. - -We can create our own references using the `pid/3` function. - -Let's assume we have the following processes, among others, in our system at -the moment. - -```elixir -> Process.list |> Enum.reverse |> Enum.take(3) -[#PID<0.284.0>, #PID<0.283.0>, #PID<0.282.0>] -``` - -We can create a reference to any of them using the three number parts that -they are made up of. - -```elixir -> pid(0, 284, 0) -#PID<0.284.0> -``` - -See, it's alive. - -```elixir -> pid(0, 284, 0) |> Process.alive? -true -``` - -What if we make up a PID that doesn't actually reference any process? - -```elixir -> pid(0, 333, 0) |> Process.alive? -false -``` - -Note: there is also a `pid/1` version of the function. See `h pid` for more -details. diff --git a/elixir/creating-indexes-with-ecto.md b/elixir/creating-indexes-with-ecto.md deleted file mode 100644 index 4963b404..00000000 --- a/elixir/creating-indexes-with-ecto.md +++ /dev/null @@ -1,19 +0,0 @@ -# Creating Indexes With Ecto - -Using indexes in the right places within relational databases is a great way -to speed up queries. - -To add a basic index in an Ecto migration, use `Ecto.Migration.index\2`: - -```elixir -create index(:users, [:email]) -``` - -Creating a composite index doesn't require jumping through any hoops; just -put the relevant column names in the list: - -```elixir -create index(:posts, [:user_id, :title]) -``` - -See `h Ecto.Migration.index` for more details. diff --git a/elixir/defining-multiple-clauses-in-an-anonymous-function.md b/elixir/defining-multiple-clauses-in-an-anonymous-function.md deleted file mode 100644 index 171efa8b..00000000 --- a/elixir/defining-multiple-clauses-in-an-anonymous-function.md +++ /dev/null @@ -1,29 +0,0 @@ -# Defining Multiple Clauses In An Anonymous Function - -Anonymous functions often take the approach of doing a single thing with the -inputs, regardless of their shape or values. There is no need to limit -ourselves though. The same pattern matching that we use all over our Elixir -programs can be utilized to define multiple clauses in an anonymous function -as well. - -Consider the following example: - -```elixir -iex> my_function = fn - {:ok, x} -> "Everything is ok: #{x}" - {:error, x} -> "There was an error: #{x}" -end -#Function<6.52032458/1 in :erl_eval.expr/5> -``` - -We can then invoke our anonymous function using the bound variable to see -what results we get with different kinds of inputs. - -```elixir -iex> my_function.({:ok, 123}) -"Everything is ok: 123" -iex> my_function.({:error, "be warned"}) -"There was an error: be warned" -``` - -[source](http://stackoverflow.com/a/18023790/535590) diff --git a/elixir/determine-the-latest-release-of-a-hex-package.md b/elixir/determine-the-latest-release-of-a-hex-package.md deleted file mode 100644 index 940f5ea7..00000000 --- a/elixir/determine-the-latest-release-of-a-hex-package.md +++ /dev/null @@ -1,27 +0,0 @@ -# Determine The Latest Release Of A Hex Package - -I will often pop open the browser and do a Google search in order to figure -out the latest release of a package when adding it to my dependencies. -However, lately I've been getting in the habit of using a quicker approach. -The `mix` CLI has a way of looking up info about a package and we don't have -to leave the terminal to use it. - -For instance, if I need to determine the latest version of the `postgrex` -package, I can run the following command. - -```bash -$ mix hex.info postgrex -PostgreSQL driver for Elixir. - -Config: {:postgrex, "~> 0.12.0"} -Releases: 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, ... - -Maintainers: Eric Meadows-Jönsson, James Fish -Licenses: Apache 2.0 -Links: - Github: https://github.com/elixir-ecto/postgrex -``` - -The third line gives me the info I need (`{:postgrex, "~> 0.12.0"}`) and it -is already formatted as a tuple that I can paste right into my `mix.exs` -file. diff --git a/elixir/do-you-have-the-time-part-2.md b/elixir/do-you-have-the-time-part-2.md deleted file mode 100644 index 76a3f9d1..00000000 --- a/elixir/do-you-have-the-time-part-2.md +++ /dev/null @@ -1,23 +0,0 @@ -# Do You Have The Time? - Part 2 - -In [_Do You Have The -Time?_](https://github.com/jbranchaud/til/blob/master/elixir/do-you-have-the-time.md), -I demonstrated a way of using an Erlang function to get at and work with -time in Elixir. As of Elixir 1.3, there is now a [`Time` -module](http://elixir-lang.org/docs/stable/elixir/Time.html) that provides a -sigil and some functions for working with time. - -We can use Elixir's `Time` module to simplify the example from the previous -iteration of this TIL: - -```elixir -defmodule TickTock do - def current_time do - Time.from_erl!(:erlang.time) - |> Time.to_string - end -end - -> TickTock.current_time -"19:58:12" -``` diff --git a/elixir/do-you-have-the-time.md b/elixir/do-you-have-the-time.md deleted file mode 100644 index 552b29a8..00000000 --- a/elixir/do-you-have-the-time.md +++ /dev/null @@ -1,21 +0,0 @@ -# Do You Have The Time? - -Elixir doesn't come with any standard ways of getting at or working with -time. There are packages like [Timex](https://github.com/bitwalker/timex) -out there that we can pull in to our projects. However, if we don't have -need for a full-featured date/time library, we can opt for a simpler -solution. - -Erlang can give us the time. - -```elixir -defmodule TickTock do - def current_time do - {hh,mm,ss} = :erlang.time - "#{hh}:#{mm}:#{ss}" - end -end - -> TickTock.current_time -"11:47:13" -``` diff --git a/elixir/documentation-lookup-with-vim-and-alchemist.md b/elixir/documentation-lookup-with-vim-and-alchemist.md deleted file mode 100644 index 46f79323..00000000 --- a/elixir/documentation-lookup-with-vim-and-alchemist.md +++ /dev/null @@ -1,16 +0,0 @@ -# Documentation Lookup With Vim And Alchemist - -_Which argument position is the accumulator for `Enum.reduce/3`?_ - -_How does `group_by` work?_ - -I find myself fairly frequently jumping from vim to Chrome to do Google -searches for Elixir standard lib documentation. It gets the job done, but it -is kinda slow and I'd prefer to avoid the context switch. - -With [alchemist.vim](https://github.com/slashmili/alchemist.vim), Elixir -documentation lookup is at your finger tips. Just move the cursor over the -module or function you are curious about and hit `K` (from normal mode). - -Curious about `Enum.reduce`? Type it out in your current Vim buffer, move -the cursor over it, and hit `K`. diff --git a/elixir/dynamically-generating-atoms.md b/elixir/dynamically-generating-atoms.md deleted file mode 100644 index 3c26cdfa..00000000 --- a/elixir/dynamically-generating-atoms.md +++ /dev/null @@ -1,15 +0,0 @@ -# Dynamically Generating Atoms - -> Atoms are constants where their name is their own value. - -The use of atoms like `:ok` and `:error` show up all over the place in -Elixir. These are atoms that tend to be statically defined. Atoms can also -be dynamically defined using string interpolation. - -For example, I can generate a handful of atoms by mapping over a range of -integers. - -```elixir -> Enum.map(1..5, &(:"some_atom_#{&1}")) -[:some_atom_1, :some_atom_2, :some_atom_3, :some_atom_4, :some_atom_5] -``` diff --git a/elixir/execute-raw-sql-in-an-ecto-migration.md b/elixir/execute-raw-sql-in-an-ecto-migration.md deleted file mode 100644 index 207f67d3..00000000 --- a/elixir/execute-raw-sql-in-an-ecto-migration.md +++ /dev/null @@ -1,36 +0,0 @@ -# Execute Raw SQL In An Ecto Migration - -If you are performing a database migration with -[Ecto](https://hexdocs.pm/ecto/Ecto.html), perhaps the most straightforward -approach is to use Ecto's DSL. However, the DSL may not always be the best -choice. Being able to write raw SQL gives you more control. It will also -enable you to use database features that may not be directly or easily -available through the DSL. - -Raw SQL can be included in a Ecto migration with a combination of Elixir's -heredoc syntax and the [`Ecto.Migration#execute/1` -function](https://hexdocs.pm/ecto/Ecto.Migration.html#execute/1). You'll -also need to provide both an `up` and `down` function to ensure that your -migrations are reversible. - -```elixir -defmodule MyApp.Repo.Migrations.CreatePostsTable do - use Ecto.Migration - - def up do - execute """ - create table posts ( - id serial primary key, - title varchar not null, - body varchar not null default '', - inserted_at timestamptz not null default now(), - updated_at timestamptz not null default now() - ); - """ - end - - def down do - execute "drop table posts;" - end -end -``` diff --git a/elixir/expose-internal-representation.md b/elixir/expose-internal-representation.md deleted file mode 100644 index aeb1e4b9..00000000 --- a/elixir/expose-internal-representation.md +++ /dev/null @@ -1,16 +0,0 @@ -# Expose Internal Representation - -Elixir is a language that has strong support for metaprogramming. It -provides easy access to an internal representation of the code in the form -of an Abstract Syntax Tree (AST) using maps and keyword lists. The `quote` -macro is used to expose this internal representation. - -```elixir -> quote do: 2 * 2 -{:*, [context: Elixir, import: Kernel], [2, 2]} -> quote do: 2 * 2 == 4 -{:==, [context: Elixir, import: Kernel], - [{:*, [context: Elixir, import: Kernel], [2, 2]}, 4]} -``` - -[source](http://elixir-lang.org/getting-started/meta/quote-and-unquote.html) diff --git a/elixir/include-captures-with-string-split.md b/elixir/include-captures-with-string-split.md deleted file mode 100644 index 9eec9a7a..00000000 --- a/elixir/include-captures-with-string-split.md +++ /dev/null @@ -1,33 +0,0 @@ -# Include Captures With String.split - -The -[`String.split/3`](http://elixir-lang.org/docs/stable/elixir/String.html#split/3) -function comes with two options: `trim` and `parts`. However, when using it -with a regex pattern, you gain access to a couple extra options, including -`include_captures`. This is because when used with a regex pattern, -`String.split` just invokes `Regex.split` which comes with extra options -like `include_captures`. - -Here is `String.split` in action by itself and with the supported `trim` -option. - -```elixir -> String.split("23d", ~r/\d+/) -["", "d"] -> String.split("23d", ~r/\d+/, trim: true) -["d"] -``` - -Adding in the `include_captures` option, we get a resulting list that -includes the value captured by the splitting regex. - -``` -> String.split("23d", ~r/\d+/, trim: true, include_captures: true) -["23", "d"] -``` - -This isn't a documented feature, so it is only supported as long as -`Regex.split` supports it and as long as `String.split` continues to -delegate to `Regex.split`. - -h/t Chris Erin diff --git a/elixir/inspecting-the-process-message-queue.md b/elixir/inspecting-the-process-message-queue.md deleted file mode 100644 index 47ef9829..00000000 --- a/elixir/inspecting-the-process-message-queue.md +++ /dev/null @@ -1,33 +0,0 @@ -# Inspecting The Process Message Queue - -A core tenant of Elixir is message passing between processes. So, if a -process is sent a message, where does that message go? What happens if it -gets sent many messages? The `Process.info/2` function allows us to inspect -the message queue. - -First, let's send some messages (to ourself) and then keep an eye on the -length of the message queue as we go. - -```elixir -> send self(), {:error, "this is bad"} -{:error, "this is bad"} -> Process.info(self(), :message_queue_len) -{:message_queue_len, 1} -> send self(), {:hello, "world"} -{:hello, "world"} -> Process.info(self(), :message_queue_len) -{:message_queue_len, 2} -``` - -Now, I am curious what those specific messages are. Let's ask -`Process.info/2` for the messages that are in the message queue. - -```elixir -> Process.info(self(), :messages) -{:messages, [error: "this is bad", hello: "world"]} -``` - -There are a lot of other things that `Process.info/2` can tell us about a -process. See [the Erlang docs for -`process_info`](http://erlang.org/doc/man/erlang.html#process_info-2) for -more details. diff --git a/elixir/list-functions-for-a-module.md b/elixir/list-functions-for-a-module.md deleted file mode 100644 index a6524f8e..00000000 --- a/elixir/list-functions-for-a-module.md +++ /dev/null @@ -1,25 +0,0 @@ -# List Functions For A Module - -During an `iex` session, I can do a little introspection on modules using -either the -[`__info__/1`](http://elixir-lang.org/docs/stable/elixir/Module.html#__info__/1) -function or Erlang's -[`module_info/0`](http://erlang.org/doc/man/erlang.html#module_info-0) -function. In particular, I can pass `:functions` to either one to get a list -of the functions for that module. - -This is what `__info__/1` looks like for the functions of the `List` -module: - -```elixir -> List.__info__(:functions) -[delete: 2, delete_at: 2, duplicate: 2, first: 1, - flatten: 1, flatten: 2, foldl: 3, foldr: 3, insert_at: 3, - keydelete: 3, keyfind: 3, keyfind: 4, keymember?: 3, - keyreplace: 4, keysort: 2, keystore: 4, keytake: 3, - last: 1, replace_at: 3, to_atom: 1, to_existing_atom: 1, - to_float: 1, to_integer: 1, to_integer: 2, to_string: 1, - to_tuple: 1, update_at: 3, wrap: 1, zip: 1] -``` - -[source](http://stackoverflow.com/questions/28664119/in-elixir-is-there-any-way-to-get-a-module-to-list-its-functions) diff --git a/elixir/listing-files-in-iex.md b/elixir/listing-files-in-iex.md deleted file mode 100644 index 697b57ef..00000000 --- a/elixir/listing-files-in-iex.md +++ /dev/null @@ -1,20 +0,0 @@ -# Listing Files In IEx - -When you start an IEx session, you do so in the context of some directory -- -the current working directory. This context can be important if you need to -do something like import a file. In fact, you may want to know what files -are available in the current working directory. - -You can list them all out within IEx using `ls/0`. - -```elixir -iex(1)> ls() - .git .gitignore README.md _build assets config - deps lib mix.exs mix.lock priv test - tmp -``` - -You can also list the contents of some other specific directory by naming it -when invoking `ls/1`. - -See `h()` within IEx for more details. diff --git a/elixir/match-on-a-map-in-a-with-construct.md b/elixir/match-on-a-map-in-a-with-construct.md deleted file mode 100644 index 4bd0b988..00000000 --- a/elixir/match-on-a-map-in-a-with-construct.md +++ /dev/null @@ -1,25 +0,0 @@ -# Match On A Map In A With Construct - -Many usage example of the -[`with`](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#with/1) -construct show a series of matches on a tuple. - -```elixir -with {:ok, width} <- Map.fetch(opts, :width), - {:ok, height} <- Map.fetch(opts, :height) do - {:ok, width * height} -end -``` - -You can match on more than just tuples though. Here is how you might match -on a map. - -```elixir -with %{status_code: 200, body: body} <- HTTPoison.get!(url), - {:ok, decoded_body} <- Poison.decode(body) do - {:ok, decoded_body} -end -``` - -In fact, you have the full power of Elixir's pattern matching available to -you in your series of matches for a `with` construct. diff --git a/elixir/passing-around-and-using-modules.md b/elixir/passing-around-and-using-modules.md deleted file mode 100644 index 49346ac4..00000000 --- a/elixir/passing-around-and-using-modules.md +++ /dev/null @@ -1,38 +0,0 @@ -# Passing Around And Using Modules - -A module is a bag of functions. When we define a module, we are tying it to -an atom. If we pass around the atom that references this module, then we can -use it to call its functions. - -For example, consider two types of greetings: - -```elixir -defmodule Hello do - def get_greeting do - "Hello, World!" - end -end - -defmodule Hola do - def get_greeting do - "Hola, Mundo!" - end -end -``` - -And a generic greeting module that accepts a language module: - -```elixir -defmodule Greeting do - def say_hello(language_module) do - language_module.get_greeting - |> IO.puts - end -end - -Greeting.say_hello(Hello) # => "Hello, World!" -Greeting.say_hello(Hola) # => "Hola, Mundo!" -``` - -The module reference that we pass in to `Greeting.say_hello` can be used to -invoke the `get_greeting` function. diff --git a/elixir/pattern-matching-in-anonymous-functions.md b/elixir/pattern-matching-in-anonymous-functions.md deleted file mode 100644 index c2c41a12..00000000 --- a/elixir/pattern-matching-in-anonymous-functions.md +++ /dev/null @@ -1,25 +0,0 @@ -# Pattern Matching In Anonymous Functions - -Pattern matching shows up everywhere in Elixir, even where you may not be -expecting it. When declaring an anonymous function, you can use pattern -matching against different sets and shapes of input parameters to invoke -different behaviors. - -Here is an example of how you might use this: - -```elixir -> handle_result = fn - {:ok, result} -> IO.puts "The result is #{result}" - :error -> IO.puts "Error: couldn't find anything" -end -#Function<6.50752066/1 in :erl_eval.expr/5> - -> Map.fetch(%{a: 1}, :a) |> handle_result.() -The result is 1 -:ok -> Map.fetch(%{a: 1}, :b) |> handle_result.() -Error: couldn't find anything -:ok -``` - -[source](https://elixirschool.com/lessons/basics/functions#pattern-matching) diff --git a/elixir/pipe-into-a-case-statement.md b/elixir/pipe-into-a-case-statement.md deleted file mode 100644 index b336caab..00000000 --- a/elixir/pipe-into-a-case-statement.md +++ /dev/null @@ -1,33 +0,0 @@ -# Pipe Into A Case Statement - -The standard use of a case statement looks something like this: - -```elixir -case HTTPoison.get(url) do - {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> - IO.puts body - {:ok, %HTTPoison.Response{status_code: 404}} -> - IO.puts "Not found :(" - {:error, %HTTPoison.Error{reason: reason}} -> - IO.inspect reason -end -``` - -If you are a fan of the pipe syntax, then you may enjoying writing the above -like this: - -```elixir -url -|> HTTPoison.get() -|> case do - {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> - IO.puts body - {:ok, %HTTPoison.Response{status_code: 404}} -> - IO.puts "Not found :(" - {:error, %HTTPoison.Error{reason: reason}} -> - IO.inspect reason -end -``` - -Just like any function, the value from the previous line in the pipe will be -passed in and used as the value switched over in the case statement. diff --git a/elixir/quitting-iex.md b/elixir/quitting-iex.md deleted file mode 100644 index dfd72585..00000000 --- a/elixir/quitting-iex.md +++ /dev/null @@ -1,14 +0,0 @@ -# Quitting IEx - -There are two ways to quit out of an Interactive Elixir shell. The standard -way is with `Ctrl-c`. This gives you a list of options, one of which is `a` -for _abort_. This will terminate your IEx session and drop you back on the -command line where the process started. - -Additionally, IEx also understands `Ctrl-\` which is control key that will -terminate just about any interactive environment. This command will cause -IEx to immediately exit with no prompt. - -Note: IEx does not, however, respond to `Ctrl-d`. - -[source](http://blog.plataformatec.com.br/2016/03/how-to-quit-the-elixir-shell-iex/) diff --git a/elixir/range-into-list-using-comprehensions.md b/elixir/range-into-list-using-comprehensions.md deleted file mode 100644 index 71ad6f2b..00000000 --- a/elixir/range-into-list-using-comprehensions.md +++ /dev/null @@ -1,13 +0,0 @@ -# Range Into List Using Comprehensions - -Using an _identity_ comprehension and the `:into` option, we can easily -convert a range into a list. - -```elixir -> for x <- 1..10, into: [], do: x -[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] -``` - -Check out [the docs for the `:into` -option](http://elixir-lang.org/getting-started/comprehensions.html#the-into-option) -for more details. diff --git a/elixir/refer-to-a-module-within-itself.md b/elixir/refer-to-a-module-within-itself.md deleted file mode 100644 index 271d14f3..00000000 --- a/elixir/refer-to-a-module-within-itself.md +++ /dev/null @@ -1,29 +0,0 @@ -# Refer To A Module Within Itself - -Elixir comes with the `__MODULE__` reserve word for referencing a module -within itself. This is handy for things like structs. - -```elixir -defmodule SomeNamespace.MyModule do - defstruct [:id] - - def do_thing(%__MODULE__{}=thing) do - # ... - end -end -``` - -You can use an alias in order to ditch `__MODULE__` and perhaps make your -code a bit more human readable. - -```elixir -defmodule SomeNamespace.MyModule do - alias __MODULE__, as: MyModule - - defstruct [:id] - - def do_thing(%MyModule{}=thing) do - # ... - end -end -``` diff --git a/elixir/referencing-values-in-iexs-history.md b/elixir/referencing-values-in-iexs-history.md deleted file mode 100644 index 06c1db42..00000000 --- a/elixir/referencing-values-in-iexs-history.md +++ /dev/null @@ -1,44 +0,0 @@ -# Referencing Values In IEx's History - -Each time we execute a statement in an `iex` session, the counter is -incremented. These numbers are references to the history of the session. We -can use these references to _refer_ to previously executed values using -`v/1`. This is particularly handy for multi-line statements or when we -forget to bind to the result of some function. - -Consider the following `iex` session: - -```elixir -iex(1)> :one -:one -iex(2)> 1 + 1 -2 -iex(3)> "three" |> String.to_atom() -:three -``` - -If we execute `v()` on its own, it is the same as `v(-1)` in that it will -give us the latest value in the history. - -```elixir -iex(4)> v() -:three -``` - -Providing any positive number will refer to the references we see next to -each statement. - -```elixir -iex(5)> v(1) -:one -``` - -Negative numbers, as we saw with `v(-1)`, will count backwards in the -history from where we are. - -```elixir -iex(6)> v(-4) -2 -``` - -See `h v` for more details. diff --git a/elixir/remove-one-list-from-another.md b/elixir/remove-one-list-from-another.md deleted file mode 100644 index c8eb15d3..00000000 --- a/elixir/remove-one-list-from-another.md +++ /dev/null @@ -1,29 +0,0 @@ -# Remove One List From Another - -The `--/2` operator allows you to subtract two lists, that is, remove all -elements in the _right_ list from the _left_ list. Each occurrence of an -element is removed if there is a corresponding element. If there is no -corresponding element, it is ignored. - -Here are some examples. - -```elixir -> [1, 2, 3] -- [2, 4] -[1, 3] -> [:a, :b, :c, :a, :d, :a] -- [:a, :a] -[:b, :c, :d, :a] -``` - -This kind of list operation is not particularly efficient, so for large -lists it can be quite slow. The following example took several minutes to -run. - -```elixir -> Enum.into(1..1000000, []) -- Enum.into(2..1000000, []) -[1] -``` - -To achieve a true set difference, you'll note that the docs for this -operator recommend checking out `MapSet.difference/2`. - -See `h Kernel.--` for more details. diff --git a/elixir/replace-duplicates-in-a-keyword-list.md b/elixir/replace-duplicates-in-a-keyword-list.md deleted file mode 100644 index acf5e1a5..00000000 --- a/elixir/replace-duplicates-in-a-keyword-list.md +++ /dev/null @@ -1,26 +0,0 @@ -# Replace Duplicates In A Keyword List - -Use the -[`Keyword.put`](http://elixir-lang.org/docs/stable/elixir/Keyword.html#put/3) -function to replace duplicate key entries in a keyword list. - -If there are no duplicate entries, the entry will just be added. - -```elixir -Keyword.put([a: 1], :b, 2) -[b: 2, a: 1] -``` - -If there is a duplicate entry, it will be replaced by the new value. - -```elixir -> Keyword.put([b: 1, a: 1], :b, 2) -[b: 2, a: 1] -``` - -If there are multiple duplicate entries, they will all be replaced. - -```elixir -> Keyword.put([b: 3, b: 4, a: 1], :b, 2) -[b: 2, a: 1] -``` diff --git a/elixir/requiring-keys-for-structs.md b/elixir/requiring-keys-for-structs.md deleted file mode 100644 index 343e007b..00000000 --- a/elixir/requiring-keys-for-structs.md +++ /dev/null @@ -1,39 +0,0 @@ -# Requiring Keys For Structs - -When defining a -[`struct`](http://elixir-lang.org/getting-started/structs.html) in Elixir, -we may want to ensure that certain values are provided. We can require that -certain keys are used in the creation of a struct with the -[`@enforce_keys`](https://hexdocs.pm/elixir/Kernel.html#defstruct/1) -attribute. Here is an example of a `Name` struct. - -```elixir -defmodule Name do - @enforce_keys [:first, :last] - defstruct [:first, :middle, :last] -end -``` - -With this defined, we can create a struct that uses all of the keys. - -```elixir -> jack = %Name{first: "Jack", middle: "Francis", last: "Donaghy"} -%Name{first: "Jack", last: "Donaghy", middle: "Francis"} -``` - -We can also ignore `:middle` and just provide the required keys. - -```elixir -> liz = %Name{first: "Liz", last: "Lemon"} -%Name{first: "Liz", last: "Lemon", middle: nil} -``` - -We cannot, however, omit any of the keys specified in `@enforce_keys`. If we -do omit any of them, Elixir will raise an error. - -``` elixir -> tracy = %Name{first: "Tracy"} -** (ArgumentError) the following keys must also be given when building struct Name: [:last] - expanding struct: Name.__struct__/1 - iex:6: (file) -``` diff --git a/elixir/reversing-a-list-part-2.md b/elixir/reversing-a-list-part-2.md deleted file mode 100644 index 36a5011e..00000000 --- a/elixir/reversing-a-list-part-2.md +++ /dev/null @@ -1,13 +0,0 @@ -# Reversing A List - Part 2 - -In [Reversing A List](reversing-a-list.md), I showed how Erlang's -`:lists.reverse()` function could be used to reverse a list. Since then, -Elixir now has a built-in function for reversing lists. In fact, it works -with anything that implements the `Enumerable` protocol. - -```elixir -> Enum.reverse([1,2,3,4,5]) -[5, 4, 3, 2, 1] -> Enum.reverse(%{a: 1, b: 2, c: 3}) -[c: 3, b: 2, a: 1] -``` diff --git a/elixir/reversing-a-list.md b/elixir/reversing-a-list.md deleted file mode 100644 index 845d43e0..00000000 --- a/elixir/reversing-a-list.md +++ /dev/null @@ -1,19 +0,0 @@ -# Reversing A List - -To efficiently work with and _transform_ lists in Elixir, you will likely -need utilize a list reversing function from time to time. Your best bet is -to reach for the Erlang implementation which is available as part of the -`lists` module. - -Here are a couple examples of how to use it: - -```elixir -> :lists.reverse([1,2,3]) -[3, 2, 1] -> :lists.reverse([1, :a, true, "what", 5]) -[5, "what", true, :a, 1] -``` - -Note: though I said "_transform_ lists" above, what is actually going on is -that a new version of the list representing my transformation is being -created, per Elixir's functional nature. diff --git a/elixir/root-directory-of-a-project.md b/elixir/root-directory-of-a-project.md deleted file mode 100644 index f7e964bc..00000000 --- a/elixir/root-directory-of-a-project.md +++ /dev/null @@ -1,15 +0,0 @@ -# Root Directory Of A Project - -Do you need the root directory of an elixir project? The -[`File.cwd!/0`](http://elixir-lang.org/docs/stable/elixir/File.html#cwd!/0) -function can help. - -```elixir -iex> File.cwd! -"/home/dev/code/my_app" -``` - -Keep in mind though, this will only work reliably with projects that are -compiled using Mix. - -[source](https://groups.google.com/forum/#!msg/elixir-lang-talk/Ls0eJDdMMW8/1Lmg5K2MAQAJ) diff --git a/elixir/round-floats-to-integers.md b/elixir/round-floats-to-integers.md deleted file mode 100644 index 0be49ef0..00000000 --- a/elixir/round-floats-to-integers.md +++ /dev/null @@ -1,28 +0,0 @@ -# Round Floats To Integers - -The -[`Float.round/2`](http://elixir-lang.org/docs/stable/elixir/Float.html#round/2) -function allows you to round floating point numbers. The result is another -floating point number. - -```elixir -> Float.round(1.5) -2.0 -> Float.round(1.3) -1.0 -``` - -If, instead, you always want an integer as the result of rounding, you can -use `Kernel`'s version of a rounding function: - -```elixir -> Kernel.round(1.5) -2 -> Kernel.round(1.3) -1 -``` - -The -[`Kernel.round/1`](http://elixir-lang.org/docs/stable/elixir/Kernel.html#round/1) -function accepts both integers and floats, and always returns an integer. -Additionally, it can be used in guard tests. diff --git a/elixir/run-exunit-tests-in-a-deterministic-order.md b/elixir/run-exunit-tests-in-a-deterministic-order.md deleted file mode 100644 index 90ace7b4..00000000 --- a/elixir/run-exunit-tests-in-a-deterministic-order.md +++ /dev/null @@ -1,29 +0,0 @@ -# Run ExUnit Tests In A Deterministic Order - -When running a file of -[`ExUnit`](http://elixir-lang.org/docs/stable/ex_unit/ExUnit.html) tests, -they will be executed in a pseudo-random order based on a seed value. In -general, `ExUnit` will pick a random seed each time you run your tests. If -you'd like to add some determinism to the order that your tests run in, you -can specify the seed in the `ExUnit` configuration. - -```elixir -ExUnit.configure seed: 42 -ExUnit.start - -defmodule AssertionTest do - use ExUnit.Case, async: true - - test "the truth" do - assert true - end - - test "more truth" do - assert 2 + 2 = 4 - end -end -``` - -[source](https://til.hashrocket.com/posts/4a7dc5fd94-run-exunit-tests-in-the-order-they-are-defined) - -h/t Chris Erin diff --git a/elixir/run-the-test-at-a-specific-line-number.md b/elixir/run-the-test-at-a-specific-line-number.md deleted file mode 100644 index 7c09a59c..00000000 --- a/elixir/run-the-test-at-a-specific-line-number.md +++ /dev/null @@ -1,25 +0,0 @@ -# Run The Test At A Specific Line Number - -You can tell `mix test` to only run tests that appear in a specific file by -naming the file: - -```bash -$ mix test test/module/file_test.exs -``` - -You can even point it to a specific line number in that file like so: - -```bash -$ mix test test/module/file_test.exs:45 -``` - -Behind the scenes, `mix test` is using tags to build a list of exclusions -and inclusions that result in only the test at line 45 running. Here is an -equivalent of the above command: - -```bash -$ mix test test/module/file_test.exs --exclude test --include line:45 -``` - -This will exclude every test. It will then re-include the test that -corresponds to having a tag `line:45`. diff --git a/elixir/same-functions-should-be-grouped-together.md b/elixir/same-functions-should-be-grouped-together.md deleted file mode 100644 index c1e3002f..00000000 --- a/elixir/same-functions-should-be-grouped-together.md +++ /dev/null @@ -1,30 +0,0 @@ -# Same Functions Should Be Grouped Together - -A favorite feature of Elixir is the function clauses that can be defined in -multiple ways with pattern matching. I've always grouped same-named function -clauses together. It seems like good form and it's what I see everyone else -doing. It also makes for readable, maintainable code. - -This is more than just personal preference though. It is the correct, -idiomatic way to organize your Elixir function clauses. The compiler will -let you know if anything gets out of place. - -Consider the following snippet of code: - -```elixir -defmodule MeterToLengthConverter do - def convert(:feet, m), do: m * 3.28084 - def convert(:inch, m), do: m * 39.3701 - def hello(), do: IO.puts "Hello, World!" - def convert(:yard, m), do: m * 1.09361 -end -``` - -It is syntactically correct, so it will compile. However, the compiler will -emit a warning like the following: - -``` -warning: clauses for the same def should be grouped together, def convert/2 -was previously defined (length_converter.ex:2) - length_converter.ex:5 -``` diff --git a/elixir/skip-a-specific-test.md b/elixir/skip-a-specific-test.md deleted file mode 100644 index e8920663..00000000 --- a/elixir/skip-a-specific-test.md +++ /dev/null @@ -1,19 +0,0 @@ -# Skip A Specific Test - -Elixir's `ExUnit` supports all kinds of tags for customizing the behavior of -your test suite. The `:skip` tag signals that `ExUnit` should skip over that -specific test. - -```elixir -@tag :skip -test "this is a test that should not run" do - assert false -end -``` - -When you run `mix test`, it will make sure to not execute any tests with the -`:skip` tag. - -Using the `:skip` tag can be a great temporary measure in a lot of -situations. It is not a good long-term practice to keep these around and -check them in. diff --git a/elixir/string-interpolation-with-just-about-anything.md b/elixir/string-interpolation-with-just-about-anything.md deleted file mode 100644 index 77160bce..00000000 --- a/elixir/string-interpolation-with-just-about-anything.md +++ /dev/null @@ -1,22 +0,0 @@ -# String Interpolation With Just About Anything - -Coming to Elixir from Ruby, I am used to being able to interpolate literally -_anything_ into a string. In Elixir, this is not the case. - -> By default, it handles strings, atoms (including nil, true, false and -> module name aliases like String – which are all just atoms behind the -> scenes), integers, floats, and some lists. That's it. - -There are two approaches you can take to interpolate everything else into a -string. The easier approach is to use -[`Kernel.inspect/2`](http://elixir-lang.org/docs/stable/elixir/Kernel.html#inspect/2). - -```elixir -> IO.puts "A map #{inspect %{a: 1, b: 2}}" -A map %{a: 1, b: 2} -``` - -The other approach is to implement the `String.Chars` protocol for the thing -that you are trying to print. You can read more about that in [_Elixir -String Interpolation for -Rubyists_](http://thepugautomatic.com/2016/01/elixir-string-interpolation-for-the-rubyist/). diff --git a/elixir/unique-indexes-with-ecto.md b/elixir/unique-indexes-with-ecto.md deleted file mode 100644 index 7880fe61..00000000 --- a/elixir/unique-indexes-with-ecto.md +++ /dev/null @@ -1,23 +0,0 @@ -# Unique Indexes With Ecto - -You can create a unique index in a migration for one or more columns using -the -[`unique_index/3`](https://hexdocs.pm/ecto/Ecto.Migration.html#unique_index/3) -function. - -For example, if you are creating a join table for `followers` and want to -ensure that duplicate _follower_ entries are prevented, you may want to -include a unique index like so: - -```elixir -create table(:followers) do - add :followed_user, references(:users), null: false - add :following_user, references(:users), null: false -end - -create unique_index(:followers, [:followed_user, :following_user]) -``` - -Keep in mind that `unique_index/3` is a shorthand for -[`index/3`](https://hexdocs.pm/ecto/Ecto.Migration.html#index/3) when you -set `unique: true`. diff --git a/elixir/updating-values-in-a-map.md b/elixir/updating-values-in-a-map.md deleted file mode 100644 index 2b2a6ae1..00000000 --- a/elixir/updating-values-in-a-map.md +++ /dev/null @@ -1,41 +0,0 @@ -# Updating Values In A Map - -When working with maps in any language, you often need a way to update -key-value pairs. Furthermore, you will need a way to handle keys that are -not already present in the map, generally associating some default value. - -In Elixir, the `Map` module provides the `get_and_update/3` function as a -way of accomplishing such a task. - -You need to provide the map, the key to be fetched and updated, and a -function for _transforming_ (or updating) the existing value. - -Let's use a score counting example to see it in action: - -```elixir -> scores = %{} -%{} -# jake scores a point -> {_, scores} = Map.get_and_update(scores, :jake, fn(x) -> {x, (x || 0) + 1} end) -{nil, %{jake: 1}} -# chris scores a point -> {_, scores} = Map.get_and_update(scores, :chris, fn(x) -> {x, (x || 0) + 1} end) -{nil, %{chris: 1, jake: 1}} -# jake scores another point -> {_, scores} = Map.get_and_update(scores, :jake, fn(x) -> {x, (x || 0) + 1} end) -{1, %{chris: 1, jake: 2}} -# final scores -> scores -%{chris: 1, jake: 2} -``` - -We use `(x || 0) + 1` as the updated value. This is a simple way of -providing a default value for when the key is not already present in the -map. - -The update function is expected to return a tuple with the _original_ value -and the _updated_ value. - -See [the -docs](http://elixir-lang.org/docs/stable/elixir/Map.html#get_and_update/3) -for more details. diff --git a/elixir/using-when-clauses-in-a-with-construct.md b/elixir/using-when-clauses-in-a-with-construct.md deleted file mode 100644 index 958269b6..00000000 --- a/elixir/using-when-clauses-in-a-with-construct.md +++ /dev/null @@ -1,21 +0,0 @@ -# Using When Clauses In A With Construct - -Because Elixir's `with` construct supports the full power of the language's -pattern matching, we can use `when` clauses to further narrow down our -matches. - -For instance, if we want to match against the response to an API request, -but only for response status codes in the 2xx range, we can do something -like the following: - -```elixir -with %{status_code: code, body: body} - when code >= 200 && code < 300 <- HTTPoison.get!(url), - {:ok, decoded_body} <- Poison.decode(body) do - {:ok, decoded_body} -end -``` - -See the [docs for -`with`](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#with/1) for more -details. diff --git a/elixir/virtual-fields-with-ecto-schemas.md b/elixir/virtual-fields-with-ecto-schemas.md deleted file mode 100644 index 37e7a96f..00000000 --- a/elixir/virtual-fields-with-ecto-schemas.md +++ /dev/null @@ -1,30 +0,0 @@ -# Virtual Fields With Ecto Schemas - -If you'd like to include a particular key-value pair in an Ecto changeset, -it needs to be included as a field in the schema. In the case of something -akin to a password field, you want to be able to perform validations against -it, but the password itself does not have a column in the database. In other -words, you want to use the password in memory as part of the validation -process but not save it to the database. To accomplish this, you need to -specify that it is a `virtual` field. - -```elixir -schema "users" do - field :username, :string - field :password_digest, :string - field :password, :string, virtual: true -end -``` - -With that schema, you can then validate the `:password` and transform it -into the corresponding `:password_digest` field. - -```elixir -def registration_changeset(model, params) do - model - |> changeset(params) # do other standard validations - |> cast(params, [:password]) # include :password in the changeset - |> validate_length(:password, min: 8) # validations - |> put_pass_hash() # transform into :password_digest -end -``` diff --git a/elixir/when-things-dont-match-the-with-statements.md b/elixir/when-things-dont-match-the-with-statements.md deleted file mode 100644 index 4531fefc..00000000 --- a/elixir/when-things-dont-match-the-with-statements.md +++ /dev/null @@ -1,30 +0,0 @@ -# When Things Don't Match The With Statements - -You set up a series of match statements in a `with` construct as a way of -avoiding a bunch of nested if statements. Inevitably you will be passing -data through that doesn't meet all of the match criteria. By default, the -`with` construct will short circuit and your program will continue from -there. - -You can, however, take more control over how you handle the _failure_ cases -by employing an `else` block. The `else` block works a lot like a case -statement. - -```elixir -with %{status_code: 200, body: body} <- HTTPoison.get!(url), - {:ok, decoded_body} <- Poison.decode(body) do - {:ok, decoded_body} -else - %{status_code: 401} -> - reauthenticate() - _ -> - log_error() -end -``` - -Here we are able to anticipate a _failure_ case and respond accordingly. For -everything else, we have a generic action that we take. - -See the [docs for -`with`](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#with/1) for more -details. diff --git a/elixir/word-lists-for-atoms.md b/elixir/word-lists-for-atoms.md deleted file mode 100644 index 7f9a192c..00000000 --- a/elixir/word-lists-for-atoms.md +++ /dev/null @@ -1,34 +0,0 @@ -# Word Lists For Atoms - -The `~w` sigil works similarly to Ruby's `%w` (word array notation). It -allows you to create a list of words (i.e. strings). - -```elixir -> ~w(one two three) -["one", "two", "three"] -``` - -It sets itself apart though with some modifiers. The default behavior -matches the `s` modifier (for strings). - -```elixir -> ~w(one two three)s -["one", "two", "three"] -``` - -Where it gets more interesting is with the `a` modifier allowing you to -create a list of atoms. - -```elixir -> ~w(one two three)a -[:one, :two, :three] -``` - -Note: there is a third modifier, `c`, for char lists. - -```elixir -> ~w(one two three)c -['one', 'two', 'three'] -``` - -[source](http://elixir-lang.org/getting-started/sigils.html) diff --git a/gatsby/add-javascript-to-body-of-the-document.md b/gatsby/add-javascript-to-body-of-the-document.md deleted file mode 100644 index 2ce20232..00000000 --- a/gatsby/add-javascript-to-body-of-the-document.md +++ /dev/null @@ -1,29 +0,0 @@ -# Add JavaScript To Body Of The Document - -Sometimes your JavaScript script tag needs to be placed in the body of the -document. Like inside the `` tag toward the bottom. With Gatsby you don't -have direct access to the outer HTML document without copying it out of the -cache. - -And you don't need to copy it out of the cache. Gatsby offers an SSR -(server-side rendering) API for rendering content into various parts of the -document. Here is how we can use the -[`onRenderBody`](https://www.gatsbyjs.org/docs/ssr-apis/#onRenderBody) callback -to add a `, - ]) -} -``` - -`onRenderBody` provides several functions including `setPostBodyComponents`. -This takes an array of React fragments that will be injected at the bottom of -the document body. - -[source](https://github.com/gaearon/overreacted.io/pull/55/files) diff --git a/groq/grab-multiple-values-from-a-reference.md b/groq/grab-multiple-values-from-a-reference.md deleted file mode 100644 index fe285a13..00000000 --- a/groq/grab-multiple-values-from-a-reference.md +++ /dev/null @@ -1,43 +0,0 @@ -# Grab Multiple Values From A Reference - -Let's say we have an `author` with some attributes including a reference to a -`person` which contains more data about the person. Here is one way to write a -query to access that data. - -```groq -*[_type == 'author' && slug.current == 'donna-tartt']{ - website, - 'firstName': person->firstName, - 'lastName': person->lastName, - 'age': person->age -} -``` - -Here is another way to write this query that doesn't do three separate accesses -on the `person` reference. - -```groq -*[_type == 'author' && slug.current == 'donna-tartt']{ - website, - person-> { - 'firstName': firstName, - 'lastName': lastName, - 'age': age - } -} -``` - -This isn't quite right though because it leaves the three reference values -nested under `person`. We can get back to the original shape of our query by -flattening the `person` object using familiar looking spread syntax (`...`). - -```groq -*[_type == 'author' && slug.current == 'donna-tartt']{ - website, - ...person-> { - 'firstName': firstName, - 'lastName': lastName, - 'age': age - } -} -``` diff --git a/groq/grab-values-from-an-array-of-references.md b/groq/grab-values-from-an-array-of-references.md deleted file mode 100644 index a13e0b14..00000000 --- a/groq/grab-values-from-an-array-of-references.md +++ /dev/null @@ -1,29 +0,0 @@ -# Grab Values From An Array Of References - -Let's say we have a `post` object in our schema. A `post` can have an array of -references to `tags` telling you what topics the post covers. Each `tag` has a -slug and we want to get the `string` value for each slug. - -Let's say we are interested in the post with `_id` of `123`. - -Here is how we can achieve that with a `groq` query: - -```groq -*[ - _type == 'post' && _id == 123 -]{ - 'tags': tags[]->slug.current -}.tags - -=> ["javascript", "react-js"] -``` - -If the schema was such that each `post` just had a single tag reference, then -you could write the chain of references as `tag->slug.current`. Because it is -an array of references, we need the `[]` to declare that we want each value. - -The `->` operator follows the reference. Otherwise we'd just have access to the -`_ref` and `_type` values. - -The final `.tags` unnests the `tags` value we gathered into an object. Then the -result is just the array of slug values. diff --git a/groq/include-attributes-when-conditional-check-passes.md b/groq/include-attributes-when-conditional-check-passes.md deleted file mode 100644 index 76a68e06..00000000 --- a/groq/include-attributes-when-conditional-check-passes.md +++ /dev/null @@ -1,40 +0,0 @@ -# Include Attributes When Conditional Check Passes - -The graph-like nature of Sanity means that you'll often be querying for data -that spans a variety of document types. For instance, your front-end could be -requesting content in the shape of a blog post, video, and podcast. Though -there are some similarities, each of these document types will have some unique -attributes. - -When using GROQ to query for data that spans different types of documents, you -can use [a conditional query -syntax](https://www.sanity.io/docs/query-cheat-sheet#64a36d80be73) to include -type-specific attributes. - -```groq -*[_type == 'blog' || _type == 'video' || _type == 'podcast'][]{ - title, - 'slug': slug.current, - _type == 'blog' => { - body, - read_time - }, - _type == 'video' => { - description, - mp4_url - }, - _type == 'podcast' => { - description, - mp3_url - } -} -``` - -Notice that there are some attributes that are common across each type (i.e. -`title` and `slug`). Each type then has attributes unique to its document type -(i.e. `blog` has `body` and `read_time`). - -This conditional query syntax allows us to both define flexible schemas in -Sanity and then query against that flexible schema. - -[source](https://www.youtube.com/watch?v=dCGPNkcTseQ) diff --git a/groq/include-type-of-operation-in-webhook-response.md b/groq/include-type-of-operation-in-webhook-response.md deleted file mode 100644 index 310a0ea9..00000000 --- a/groq/include-type-of-operation-in-webhook-response.md +++ /dev/null @@ -1,26 +0,0 @@ -# Include Type Of Operation In Webhook Response - -When setting up a webhook in Sanity Studio, you can specify what types of -operations you want to trigger the webhook: `create`, `update`, and `delete`. - -If you include all three for a webhook, then you'll probably want to know in -your webhook handler which type of operation you're receiving. - -Webhooks are run in _Delta Mode_ which means that a collection of GROQ -functions are available in the _filter_ and _projection_ blocks. These -functions include -[`delta::operation`](https://www.sanity.io/docs/groq-functions#a64594a50318). - -Here is what a projection using `delta::operation` might look like: - -```groq -{ - _id, - firstName, - lastName, - email, - 'operation': delta::operation() -} -``` - -This function can resolve to either `create`, `update`, or `delete`. diff --git a/heroku/connect-to-a-database-by-color.md b/heroku/connect-to-a-database-by-color.md deleted file mode 100644 index a0c653ce..00000000 --- a/heroku/connect-to-a-database-by-color.md +++ /dev/null @@ -1,29 +0,0 @@ -# Connect To A Database By Color - -All of your PostgreSQL databases in Heroku are given attachment names that use -a random color. This might be _pink_, _brown_, _cobalt_, etc. And the -attachment names then look like `HEROKU_POSTGRESQL_PINK`, -`HEROKU_POSTGRESQL_BROWN`, `HEROKU_POSTGRESQL_COBALT`, etc. - -We can connect to a Heroku-managed PostgreSQL instance from the command-line -like so: - -```bash -$ heroku pg:psql --app my-app -``` - -This is going to connect to the _default_ database which is the one with the -`DATABASE_URL` attachment. - -There are lots of instances where we may have other databases besides the -primary (e.g. let's say we have a read replica follower). If we want to connect -to that one, we can do so by _color_. - -If that database's attachment is `HEROKU_POSTGRESQL_IVORY`, then we'd connect -to it like so: - -```bash -$ heroku pg:psql ivory --app my-app -``` - -[source](https://devcenter.heroku.com/articles/managing-heroku-postgres-using-cli#pg-psql) diff --git a/heroku/deploy-a-review-app-to-a-different-stack.md b/heroku/deploy-a-review-app-to-a-different-stack.md deleted file mode 100644 index 5cef8d2e..00000000 --- a/heroku/deploy-a-review-app-to-a-different-stack.md +++ /dev/null @@ -1,29 +0,0 @@ -# Deploy A Review App To A Different Stack - -Heroku has different stacks for deploying apps. As newer versions of Linux -distros (such as Ubuntu) come out and software packages need patching and -updating, Heroku releases new stacks. And deprecates older ones. - -Before upgrading a production app to a new stack, you should test it out first. -The recommended way to test this out is with a Review App. - -If you need to bump the Ruby version or make any other changes, do that first. - -Then add or update your `app.json` file. This is a Heroku-specific file that -tells Heroku what stack to use when creating a new app or review app. - -```json -{ - "stack": "heroku-18" -} -``` - -Let's say my app is currently on the Heroku-16 stack. I can set the `stack` to -be `heroku-18` in `app.json`. Then I can push up a branch with all these -changes and turn it into a PR. From the Heroku dashboard, I can click the -Heroku Button that builds a Review App from the PR. - -Once it it finishes building and deploying, Heroku will give me a custom URL -for visiting the app so that I can manually evaluate it. - -[source](https://devcenter.heroku.com/articles/upgrading-to-the-latest-stack#testing-an-app-on-a-new-stack) diff --git a/heroku/diagnose-problems-in-a-heroku-postgres-database.md b/heroku/diagnose-problems-in-a-heroku-postgres-database.md deleted file mode 100644 index bf385ab7..00000000 --- a/heroku/diagnose-problems-in-a-heroku-postgres-database.md +++ /dev/null @@ -1,23 +0,0 @@ -# Diagnose Problems In A Heroku Postgres Database - -Heroku keeps track of all kinds of diagnostics on the performance of your app's -database. From long running queries and transactions to index cache hit rates -to unused indexes to tables with bloat. - -Running the `pg:diagnose` command for your Heroku app will surface all of these -details in the terminal. - -```bash -$ heroku pg:diagnose -a APP_NAME -``` - -The report will start with the biggest problem areas which it color codes in -red. If your app is experiencing degraded performance, the list of red items -would be a good place to start investigating. - -The report will then list less urgent problem areas. Those will be color coded -yellow. Though Heroku has deemed these less serious, you may still want to deal -with these. - -All the other areas of diagnose will fall into the _green_ bucket. Meaning -Heroku doesn't see any issues in those areas. diff --git a/heroku/open-dashboard-for-specific-add-on.md b/heroku/open-dashboard-for-specific-add-on.md deleted file mode 100644 index 2e569b7f..00000000 --- a/heroku/open-dashboard-for-specific-add-on.md +++ /dev/null @@ -1,17 +0,0 @@ -# Open Dashboard For Specific Add-On - -The number of times I've needed to check the papertrail logs for my -Heroku-hosted Rails app is a lot. I open a browser tab, go through several -layers of navigation to get to my app's dashboard, and then click the -papertrail link under _Add-ons_. - -There is a much quicker way using the Heroku CLI. - -```bash -$ heroku addons:open papertrail -a my-app-name -Opening https://addons-sso.heroku.com/apps/abc123/addons/efg456... -``` - -It sends you to an add-ons SSO link in the browser which authenticates you and -drops you into the dashboard for that specific add-on. You just need to specify -the add-on name and the app name. diff --git a/heroku/run-sql-against-remote-postgres-database.md b/heroku/run-sql-against-remote-postgres-database.md deleted file mode 100644 index b66bf1fc..00000000 --- a/heroku/run-sql-against-remote-postgres-database.md +++ /dev/null @@ -1,27 +0,0 @@ -# Run SQL Against Remote Postgres Database - -You can access a remote Heroku PostgreSQL database through a `psql` session -using the following command: - -```bash -heroku pg:psql --app my-app -``` - -That opens an interactive psql session. - -If instead you'd like to run a single SQL script against that remote database, -you can redirect that script to the connection. - -```bash -heroku pg:psql --app my-app < query.sql -``` - -The results of running that SQL will be written to stdout. - -You can take this a step further by redirecting the output into another file so -that you can review and search the results at your convenience, rather than -only having them appear in your terminal. - -```bash -heroku pg:psql --app my-app < query.sql > results.out -``` diff --git a/heroku/set-and-show-heroku-env-variables.md b/heroku/set-and-show-heroku-env-variables.md deleted file mode 100644 index 16d0d77c..00000000 --- a/heroku/set-and-show-heroku-env-variables.md +++ /dev/null @@ -1,30 +0,0 @@ -# Set And Show Heroku Env Variables - -The `heroku` CLI includes the `config` command which will show all the env -variables for the current app. - -```bash -$ heroku config -=== my-app Config Vars - -``` - -At this point I have none set. - -I can set one with the `config:set` command and a key-value parameter. - -```bash -$ heroku config:set PUBLIC_NEXT_URL=http://localhost:1235 -Setting PUBLIC_NEXT_URL and restarting ⬢ my-app... done, v3 -PUBLIC_NEXT_URL: http://localhost:1235 -``` - -I can see the value that this specific variable is set to by calling it with -`config:get`. - -```bash -$ heroku config:get PUBLIC_NEXT_URL -http://localhost:1235 -``` - -[source](https://devcenter.heroku.com/articles/config-vars#using-the-heroku-cli) diff --git a/heroku/ssh-into-heroku-server-hosting-app.md b/heroku/ssh-into-heroku-server-hosting-app.md deleted file mode 100644 index 685573ec..00000000 --- a/heroku/ssh-into-heroku-server-hosting-app.md +++ /dev/null @@ -1,17 +0,0 @@ -# SSH Into Heroku Server Hosting App - -Heroku hosts and deploys your app on a remote server. One of Heroku's primary -offerings is that it abstracts away the details of that server. You generally -don't need to think about it. Instead you can use the Heroku CLI to interact -with it indirectly. - -There will inevitably be a time when you need to access that server directly. -Heroku gives you a way to do this with their CLI through -[`ps:exec`](https://devcenter.heroku.com/articles/exec). - -```bash -$ heroku ps:exec --app my-app -``` - -This will connect you to an SSH session with the server that the app is running -on. diff --git a/inngest/ensure-lookup-can-be-retried.md b/inngest/ensure-lookup-can-be-retried.md deleted file mode 100644 index 016ffb49..00000000 --- a/inngest/ensure-lookup-can-be-retried.md +++ /dev/null @@ -1,57 +0,0 @@ -# Ensure Lookup Can Be Retried - -A common thing to do in a workflow step is to look up a record. This might be a -record that was created or updated around the time that the workflow was -triggered. - -You need to be sure the record was found before proceeding. That might end up -looking like this: - -```typescript -export default inngest.createFunction( - { id: "record-user-purchase" }, - { event: "app/record.purchase" }, - async ({ event, step }) => { - const checkoutSession = - await step.run("find checkout session", async () => { - const cs = provider.lookupSession(event.checkoutSessionId) - - return cs; - }); - - if(!checkoutSession) { - throw new Error('Checkout session not found') - } - } -); -``` - -This approach has a subtle problem which is that the error for a missing -checkout session is raised _outside_ the step that sets `checkoutSession`. As -inngest does a series of retries, the memorized `checkoutSession` step won't be -rerun and the error will continue to be thrown. - -It is better to raise the error _within_ the lookup step: - -```typescript -export default inngest.createFunction( - { id: "record-user-purchase" }, - { event: "app/record.purchase" }, - async ({ event, step }) => { - const checkoutSession = - await step.run("find checkout session", async () => { - const cs = provider.lookupSession(event.checkoutSessionId) - - if(!cs) { - throw new Error('Checkout session not found') - } - - return cs; - }); - } -); -``` - -If the checkout session is missing on the first couple tries, the step will -have a chance to retry the lookup and maybe eventually find what it is looking -for. diff --git a/inngest/exit-function-early-without-retries.md b/inngest/exit-function-early-without-retries.md deleted file mode 100644 index 7482e165..00000000 --- a/inngest/exit-function-early-without-retries.md +++ /dev/null @@ -1,44 +0,0 @@ -# Exit Function Early Without Retries - -When an Inngest function fails due to an error, it will be retried up to 3 -times with a scheduled back-off. That functionality is built-in. In some cases, -there is no sense retrying because the failure case isn't going to change. No -sense in wasting resources on retries that are going to yield the same result. - -In this case, we can have our code raise a `NonRetriableError`. - -```javascript -import { NonRetriableError } from "inngest" -import {inngest} from '@/inngest/inngest.server' -import {database} from '@/server/database' - -export default inngest.createFunction( - { id: "reindex-post-for-search" }, - { event: "post.updated" }, - async ({ event }) => { - const post = await database.findPost({ id: event.data.postId }) - - if(!post) { - throw new NonRetriableError(`Post not found for id (${event.data.postId})`) - } - - // handle reindexing of the post - } -) -``` - -When inngest catches a `NonRetriableError` it knows to not schedule retries. - -In the context of a try/catch block where some other error has been raised, we -can pass that error as a second argument to the `NonRetriableError` for -additional info: - -```javascript -catch(err) { - const message = `Post not found for id (${event.data.postId})` - - throw new NonRetriableError(message, { cause: err }) -} -``` - -[source](https://www.inngest.com/docs/functions/retries) diff --git a/jq/combine-an-array-of-objects-into-a-single-object.md b/jq/combine-an-array-of-objects-into-a-single-object.md deleted file mode 100644 index bad18ff2..00000000 --- a/jq/combine-an-array-of-objects-into-a-single-object.md +++ /dev/null @@ -1,40 +0,0 @@ -# Combine An Array Of Objects Into A Single Object - -If you've spent any amount of time pulling data out of a JSON file with `jq`, -you may have run into a result set that looks a little too spacious. It's this -array of single key-value pair objects. - -```bash -$ jq '.items | map({(.slug)}: .amount})' my-data.json - -[ - { - "key-1": 123 - }, - { - "key-2": 345 - }, - { - "key-3": 456 - }, - ... -] -``` - -When what you really wanted was a single object full of those unique key-value -pairs. - -That query has you 90% of the way there. The trick is to pipe that array -through the [`add` function](https://jqlang.github.io/jq/manual/#add) which -will combine each of those individual objects into a single object. - -```bash -$ jq '.items | map({(.slug)}: .amount}) | add' my-data.json - -{ - "key-1": 123, - "key-2": 345, - "key-3": 456, - ... -} -``` diff --git a/jq/count-each-collection-in-a-json-object.md b/jq/count-each-collection-in-a-json-object.md deleted file mode 100644 index 843b2352..00000000 --- a/jq/count-each-collection-in-a-json-object.md +++ /dev/null @@ -1,34 +0,0 @@ -# Count Each Collection In A JSON Object - -Let's say your JSON file is an object that represents several different -collections (arrays) of data. - -```json -{ - "users": [ ... ], - "orders": [ ... ], - "carts": [ ... ] -} -``` - -We can get a nice summary of the counts of those collections using -[`jq`](https://stedolan.github.io/jq/). We can do that with the [`with_entries` -function](https://stedolan.github.io/jq/manual/#to_entries,from_entries,with_entries). -We preserve the key (name) of each collection and then process each list with -the `length` function. - -```bash -jq '. | with_entries({ "key": .key, "value": (.value | length)})' data.json -{ - "users": 1234, - "orders": 5432, - "carts": 89 -} -``` - -The `with_entries` function essentially maps over each key-value pair -processing it with the given expression. It will then convert that `{"key": -some_key, "value": 123}` mapping back into a key-value pair that gets combined -with all the others. - -[source](https://til.simonwillison.net/jq/flatten-nested-json-objects-jq) diff --git a/jq/count-the-number-of-things-in-a-json-file.md b/jq/count-the-number-of-things-in-a-json-file.md deleted file mode 100644 index e6dc0507..00000000 --- a/jq/count-the-number-of-things-in-a-json-file.md +++ /dev/null @@ -1,43 +0,0 @@ -# Count The Number Of Things In A JSON File - -JQ is a great tool for finding out the number of things in a JSON file. - -If the top-level contents of the JSON is a list, then you can pipe it directly -to the [`length` function](https://stedolan.github.io/jq/manual/#length). - -```bash -// [1, 2, {"three": 4}] -$ jq '. | length' data.json -3 -``` - -It works the same for counting the number of entries (key-value pairs) in a -top-level JSON object. - -```bash -// { "hello": "world", "list": [1,2,3] } -$ jq '. | length' data.json -2 -``` - -If you are trying to get the count of a nested value, navigate to it and then -pipe that to `length`. - -```bash -// { "hello": "world", "list": [1,2,3] } -$ jq '.list | length' data.json -3 -``` - -You can even count each value in a JSON object by transforming it into an array -of the values with `[]`. - -```bash -// { "hello": "world", "list": [1,2,3] } -$ jq '.[] | length' data.json -5 -3 -``` - -Notice, the length of `"world"` is `5` characters and the length of `[1,2,3]` -is `3` elements. diff --git a/jq/extract-a-list-of-values.md b/jq/extract-a-list-of-values.md deleted file mode 100644 index 7b295d4c..00000000 --- a/jq/extract-a-list-of-values.md +++ /dev/null @@ -1,49 +0,0 @@ -# Extract A List Of Values - -[`jq`](https://stedolan.github.io/jq/) can be used to extract a list of values -from an array in a JSON file. - -Consider the following JSON: - -```json -{ - "items": [ - { "id": 1, "name": "Liz Lemon" }, - { "id": 2, "name": "Pete Hornberger" }, - { "id": 3, "name": "Tracy Jordan" }, - { "id": 4, "name": "Jenna Maroney" } - ] -} -``` - -First, you need to specify the selector path to the list. One it's own that -will grab the list. - -```bash -$ jq '.items' data.json -[ - { - "id": 1, - "name": "Liz Lemon" - }, - ... -] -``` - -Then you need to use brackets to interact with the list. `.items[0]` and -`.items[1]` would grab the first and second item in the list, respectively. -Leaving the brackets empty (`.items[]`) tells `jq` that you want to interact -with each item in the list. - -Then tack on a selector for what you want out of each item. - -```bash -$ jq '.items[].name' data.json -"Liz Lemon" -"Pete Hornberger" -"Tracy Jordan" -"Jenna Maroney" -``` - -This grabs the name from each of the objects within the _items_ array. The -results are printed to stdout. diff --git a/jq/filter-out-results-based-on-list-of-values.md b/jq/filter-out-results-based-on-list-of-values.md deleted file mode 100644 index 95d34218..00000000 --- a/jq/filter-out-results-based-on-list-of-values.md +++ /dev/null @@ -1,34 +0,0 @@ -# Filter Out Results Based On List Of Values - -Let's say we have an array of objects in a JSON file. We want to extract some -data about each of those objects, but first we want to filter out some of the -objects that we don't need. This will be based on a list of IDs. - -The JSON might look something like this: - -```json -[ - {'id': '123', ...}, - {'id': '456', ...}, - {'id': '789', ...}, - {'id': '963', ...}, - ... -] -``` - -With the [`select`](https://jqlang.github.io/jq/manual/#select) function, we -can filter the array down to those objects whose IDs are -[`not`](https://jqlang.github.io/jq/manual/#and-or-not) -[`inside`](https://jqlang.github.io/jq/manual/#inside) the list of IDs to -exclude. - -``` -jq '.[] | select([.id] | inside["456", "963"] | not)' data.json -``` - -Inside that `select`, we grab the `id` as a single value array, check if that -value is inside our _exclude_ array, and then invert that result. If there is a -match, that object will be filtered out. - -We can then chain additional filtering and extraction on to the end of the -query to produce the result we want. diff --git a/jq/find-all-objects-in-an-array-where-key-is-set.md b/jq/find-all-objects-in-an-array-where-key-is-set.md deleted file mode 100644 index c9d26079..00000000 --- a/jq/find-all-objects-in-an-array-where-key-is-set.md +++ /dev/null @@ -1,50 +0,0 @@ -# Find All Objects In An Array Where Key Is Set - -Let's say we have a large array of objects. And the data in those objects, -while generally having the same shape, does not always have certain values set. - -For instance, here is some data where the `token` is sometimes set, sometimes -`null`, and sometimes missing altogether. - -```json -[ - { - "id": 1, - "token": "abc" - }, - { - "id": 3, - "token": null - }, - { - "id": 5 - }, - ... -] -``` - -We can find out how many objects in this collection have the `token` key set to -an actual value with [a `jq` query](https://stedolan.github.io/jq/manual) like -the following. - -```bash -jq '. | map(select(has("token") and .token != null)) | length' data.json -``` - -This maps over each object selecting those where it has `token` and `token` is -not `null`. - -We can instead produce the inverse count—those objects where `token` is not set -to a value—with the `not` operator. - -```bash -jq '. | map(select(has("token") and .token != null | not)) | length' data.json -``` - -If you want to inspect the array of objects that either of these queries filters down to, you can drop the `| length` part. - -```bash -jq '. | map(select(has("token") and .token != null))' data.json -``` - -Here 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). diff --git a/jq/find-all-objects-with-a-matching-key-value-pair.md b/jq/find-all-objects-with-a-matching-key-value-pair.md deleted file mode 100644 index 7954cdf9..00000000 --- a/jq/find-all-objects-with-a-matching-key-value-pair.md +++ /dev/null @@ -1,45 +0,0 @@ -# Find All Objects With A Matching Key Value Pair - -Let's say I have a JSON file representing a bunch of people's reading lists. -That means it is an array of objects where each object is a person's reading -profile and contains a _list_ of books. Some of those books have a _status_ of -`reading` meaning the person is currently reading that book. - -How can we find all books that are currently being read? - -``` -jq '. | map( - { - name: .username, - in_progress_books: (.books | map(select(.status == "reading"))) - } - )' -``` - -``` -[ - { name: 'bobr', in_progress_books: [...] }, - { name: 'sallyf', in_progress_books: [...] }, - ... -] -``` - -That will show us for each reader what books they are currently reading. - -Alternatively, we could roll that all up into a single list of books. - -``` -jq '. | - map(.books | map(select(.status == "reading"))) | - flatten' -``` - -``` -[ - { title: 'Moby Dick', status: 'reading', ... } - { title: 'The Great Gatsby', status: 'reading', ... } - ... -] -``` - -[source](https://stackoverflow.com/a/18608100/535590) diff --git a/jq/get-a-slice-of-the-ends-of-an-array.md b/jq/get-a-slice-of-the-ends-of-an-array.md deleted file mode 100644 index 1f65e458..00000000 --- a/jq/get-a-slice-of-the-ends-of-an-array.md +++ /dev/null @@ -1,37 +0,0 @@ -# Get A Slice Of The Ends Of An Array - -[`jq`](https://jqlang.github.io/jq/) has an array slice syntax that allows us -to grab a subset of values from an array. The general form of this syntax is -`[n:m]` where `n` is the index of the start of our slice (inclusive) and `m` is -the index of the end of our slice (non-inclusive). - -If we omit the `n`, it defaults to `0`, or the start of the array. Similarly, -if we omit the `m`, it defaults to the end of the list. - -Knowing that, we can grab the first few elements of the list like so: - -```bash -❯ echo '["a","b","c","d","e","f","g"]' | jq '.[:3]' -[ - "a", - "b", - "c" -] -``` - -We can also use a negative index value to count back from the end of the array. -This allows us to grab a slice from some point relative to the end of the list. -Instead of having to compute it based on knowing the length of the array. - -Knowing that, we can grab the last few elements of the list like so: - -```bash -❯ echo '["a","b","c","d","e","f","g"]' | jq '.[-3:]' -[ - "e", - "f", - "g" -] -``` - -[source](https://jqlang.github.io/jq/manual/#array-string-slice) diff --git a/jq/get-the-first-item-for-every-top-level-key.md b/jq/get-the-first-item-for-every-top-level-key.md deleted file mode 100644 index 7c36f794..00000000 --- a/jq/get-the-first-item-for-every-top-level-key.md +++ /dev/null @@ -1,37 +0,0 @@ -# Get The First Item For Every Top-Level Key - -Let's say we have a JSON object where each key in that object is tied to a -large array of values. To get a better idea of what the data looks like, we -want to trim down the JSON a bit. Essentially, we want to tie each key to the -first value in each of their respective arrays. - -We can do this by reducing the object into a new object where each top-level -key is tied to the first item in its array. - -```bash -$ jq '. as $object | reduce keys[] as $k ({}; .[$k] = $object[$k][0])' data.json -``` - -This uses variables (`$object` and `$k`) and the [`reduce` -function](https://stedolan.github.io/jq/manual/#Reduce) to iterate over the -incoming JSON object and produce a new object with the trimmed down data. - -JSON like this: - -```json -{ - "key1": ["a", "b", "c"], - "key2": [1, 2, 3], - "key3": ["x", "y", "z"] -} -``` - -will be turned into this: - -```json -{ - "key1": "a", - "key2": 1, - "key3": "x" -} -``` diff --git a/jq/get-the-last-item-from-an-array.md b/jq/get-the-last-item-from-an-array.md deleted file mode 100644 index 1aeaed0b..00000000 --- a/jq/get-the-last-item-from-an-array.md +++ /dev/null @@ -1,22 +0,0 @@ -# Get The Last Item From An Array - -There are two ways to get the last item from an array using -[`jq`](https://jqlang.github.io/jq/). - -The one that is perhaps a bit more intuitive is to pipe the array to the -[`last`](https://jqlang.github.io/jq/manual/#first-last-nth-2) function. - -```bash -$ echo '[1,2,3]' | jq '. | last' -3 -``` - -Another approach is to use an [array index -expression](https://jqlang.github.io/jq/manual/#array-index) to positionally -grab the last element of the array. As is the case with some languages and -libraries, `-1` positionally refers to the last item in the array. - -```bash -$ echo '[1,2,3]' | jq '.[-1]' -3 -``` diff --git a/jq/reduce-object-to-just-entries-of-a-specific-type.md b/jq/reduce-object-to-just-entries-of-a-specific-type.md deleted file mode 100644 index f0d0547f..00000000 --- a/jq/reduce-object-to-just-entries-of-a-specific-type.md +++ /dev/null @@ -1,28 +0,0 @@ -# Reduce Object To Just Entries Of A Specific Type - -Let's say I have a large JSON data file with a ton of top-level fields of -varying types. It can be hard to wade through it as is. [The `jq` -utility](https://stedolan.github.io/jq/manual/) can help. I can filter a JSON -object down to just the fields of a certain type. - -For instance, I may want to start with a view of the JSON that is restricted to -just the values of type `array`. - -To do this, I need to use a couple different `jq` helper functions. - -```bash -jq '. | to_entries | map(select(.value | type | match("array"))) | from_entries' data.json -``` - -This starts with `to_entries` to convert an object into an array of key-value -pairs. I then `map` over those pairs selecting just the pairs whose value -matches the `"array"` type. I then use `from_entries` to turn the reduced array -back into an object. - -There is a less verbose way to do the above. The `to_entries` and -`from_entries` can be collapsed into a `with_entries` that wraps the `map` -call. - -```bash -jq '. | with_entries(map(select(.value | type | match("array")))' data.json -``` diff --git a/jq/turn-a-list-from-a-command-into-json.md b/jq/turn-a-list-from-a-command-into-json.md deleted file mode 100644 index dd144a07..00000000 --- a/jq/turn-a-list-from-a-command-into-json.md +++ /dev/null @@ -1,32 +0,0 @@ -# Turn A List From A Command Into JSON - -There are a lot of command-line utilities that produce a list of things. Since -JSON is a universal data format, it would be useful to be able to quickly turn -some items from `stdout` into a JSON list. - -The [`jq`](https://jqlang.github.io/jq/) utility can help with this. - -Let's say I'm working with the following `git` command that lists changed files -in a specific directory. - -```bash -$ git diff --name-only | grep some/dir -``` - -I can then pipe that list of files to `jq` with a few flags. - -```bash -$ git diff --name-only \ - | grep some/dir \ - | jq -R -s 'split("\n")[:-1]' -``` - -Here's what is going on: - -- The `-R` flag tells `jq` to accept raw input, rather than looking for JSON. -- The `-s` flag is short for `--slurp` and tells `jq` to read in the entire - input before applying the filter. -- The string argument is the filter to be applied to the output. It splits on - newlines and then takes the entire array except for the last item (`[:-1]`) - which would be an empty string for the trailing newline. -- `jq` automatically turns the whole thing into a formatted JSON list. diff --git a/jq/zip-two-json-files-together-based-on-shared-id.md b/jq/zip-two-json-files-together-based-on-shared-id.md deleted file mode 100644 index e6a465ba..00000000 --- a/jq/zip-two-json-files-together-based-on-shared-id.md +++ /dev/null @@ -1,52 +0,0 @@ -# Zip Two JSON Files Together Based On Shared ID - -Let's say we have JSON file (`list1.json`) that contains an array of objects. -Maybe they represent metadata about some books. Something like this: - -```json -[ - { 'slug': 'the-subtle-knife', 'title': 'The Subtle Knife', ... }, - { 'slug': 'all-systems-red', 'title': 'All Systems Red', ... }, - { 'slug': 'piranesi-abc123', 'title': 'Piranesi', ... }, - ... -] -``` - -And then we have another JSON file (`list2.json`) in a similar format that -contains an additional piece of metadata tied to each slug: - -```json -[ - { 'slug': 'the-subtle-knife', 'author': 'Philip Pullman' }, - { 'slug': 'all-systems-red', 'author': 'Martha Wells' }, - { 'slug': 'piranesi-abc123', 'author': 'Susanna Clarke' }, - ... -] -``` - -And we want to pull the details from the second file and combine them into the -first file based on that shared identifier, in this case, the `slug`. - -Instead of copying over a ton of values manually or writing a full-fledged -script to do this, we can use a `jq` one-liner with the `--slurpfile` flag. - -``` -jq --slurpfile list1 list1.json --slurpfile list2 list2.json -n ' - $list1[] as $item1 - | $list2[] as $item2 - | select($item1.slug == $item2.slug) - | $item1 + $item2 -' - -[ - { 'slug': 'the-subtle-knife', 'title': 'The Subtle Knife', 'author': 'Philip Pullman', ... }, - { 'slug': 'all-systems-red', 'title': 'All Systems Red', 'author': 'Martha Wells', ... }, - { 'slug': 'piranesi-abc123', 'title': 'Piranesi', 'author': 'Susanna Clarke', ... }, - ... -] -``` - -This reads in both files as lists into named variables, selects for the items -that have matching `slug` values, and then unions those objects together. The -result will go to standard out, but it could also be redirected into a new JSON -file. diff --git a/mongodb/determine-the-database-version.md b/mongodb/determine-the-database-version.md deleted file mode 100644 index bd0a1480..00000000 --- a/mongodb/determine-the-database-version.md +++ /dev/null @@ -1,14 +0,0 @@ -# Determine The Database Version - -Whether your Mongo database is local or remote, you should connect to it using -the [`mongo` CLI](https://docs.mongodb.com/manual/mongo/). - -Once connected, you can issue the following query: - -``` -db.version() -``` - -This will output the version of your Mongo database. - -[source](https://docs.mongodb.com/manual/reference/method/db.version/) diff --git a/mongodb/dump-a-remote-database.md b/mongodb/dump-a-remote-database.md deleted file mode 100644 index 1a296633..00000000 --- a/mongodb/dump-a-remote-database.md +++ /dev/null @@ -1,37 +0,0 @@ -# Dump A Remote Database - -Here is a single-line script for dumping a remote mongo database. This will -dump it to your local filesystem in a binary format (`.bson`) that you can then -restore to another mongo instance. - -Create a file like this called `mongdump-cmd` and replace the various -placeholder values (e.g. ``) with valid values for your remote mongo -instance. - -```bash -mongodump --host ':' \ - --ssl \ - --username '' \ - --password '' \ - --authenticationDatabase 'admin' \ - --out ./mongo-backups/-dump -``` - -Create the backup directory: - -```bash -$ mkdir mongo-backups -``` - -Then execute the bash script: - -```bash -$ bash mongodump-cmd -``` - -This will dump everything on the remote instance into the -`mongo-backups/2020-06-20-dump/` directory. You can also include the `--db` -flag to dump a specific database. - -This can later be used with `mongoresetore` to restore the data to the mongo -instance you specify. diff --git a/mongodb/dump-and-restore-with-a-single-gzip-file.md b/mongodb/dump-and-restore-with-a-single-gzip-file.md deleted file mode 100644 index 6ce6d5e7..00000000 --- a/mongodb/dump-and-restore-with-a-single-gzip-file.md +++ /dev/null @@ -1,40 +0,0 @@ -# Dump And Restore With A Single gzip File - -The `mongodump` and `mongorestore` utilities provide a way for grabbing all the -data from one database and putting it into another database. These commands are -useful for transitioning production data to a database instance with more -computing resources. - -The `--archive` and `--gzip` flags, supported by both commands, are what allow -us to do the whole process with a single file. Without flags, `mongodump` will -output multiple `.bson` files. - -Here is what the `mongodump` command might look like pointed at a remote URI: - -```bash -mongodump \ - --uri="mongodb+srv://:@" \ - --archive="myapp-dump.20221105.gz" \ - --gzip -``` - -This will take a little while to run based on the size of the database. The -result will be a file in your current directory with the name -`myapp-dump.20221105.gz`. Because it is gzip'd, it will be a few times smaller -than the standing database. - -To then load all the data into your new Mongo database cluster, you'll use -`mongorestore` with all the same flags, making sure to swap out the destination -URI details with those of the new instance. - -```bash -mongorestore \ - --uri="mongodb+srv://:@" \ - --archive="myapp-dump.20221105.gz" \ - --gzip -``` - -For more details, see [Output an Archive -File](https://www.mongodb.com/docs/database-tools/mongodump/#output-to-an-archive-file) -and [Compress the -Output](https://www.mongodb.com/docs/database-tools/mongodump/#compress-the-output). diff --git a/mongodb/get-size-stats-for-a-collection.md b/mongodb/get-size-stats-for-a-collection.md deleted file mode 100644 index e8e25837..00000000 --- a/mongodb/get-size-stats-for-a-collection.md +++ /dev/null @@ -1,30 +0,0 @@ -# Get Size Stats For A Collection - -For any collection in your MongoDB instance. - -```javascript -> db.getCollectionNames() -["books", "authors", "genres"] -``` - -You can list a collection of stats, which include the amount of disk space that -collection is utilizing. - -```javascript -> db.books.stats().size -11057056 -``` - -By default this size is in bytes, which isn't all that human-readable of a -value. - -By passing in a `scale` value to `stats()`, you can get a value that is a bit -more understandable. A scale of `1024` would give you kilobytes, so a scale of -`1024 * 1024` would give you megabytes. - -```javascript -> db.books.stats({ scale: 1024 * 1024 }).size -10 -``` - -[source](https://docs.mongodb.com/manual/reference/method/db.collection.stats/) diff --git a/mongodb/list-size-stats-for-all-collections.md b/mongodb/list-size-stats-for-all-collections.md deleted file mode 100644 index 7265a85a..00000000 --- a/mongodb/list-size-stats-for-all-collections.md +++ /dev/null @@ -1,25 +0,0 @@ -# List Size Stats For All Collections - -In [Get Size Stats for a Collection](get-size-stats-for-a-collection.md), we -saw how to use `db.collection.stats()` and its `scale` parameter to get a -useful size metric for a given collection. - -We can combine some of this concepts with some scripting to list human-readable -size metrics for all of our database's collections: - -```javascript -> db.getCollectionNames().forEach(function (collectionName) { - sizeInMb = db[collectionName].stats({ scale: 1024 * 1024 }).size; - print(collectionName + ": " + sizeInMb + "MB"); - }) -books: 10MB -authors: 2MB -genres: 1MB -``` - -This snippet gets all the collections for the current database and iterates -over them. For each collection name, it looks up the `size` stat for that -collection scaled to megabytes and then prints it all out with some contextual -information. - -[source](https://docs.mongodb.com/manual/faq/storage/#data-storage-diagnostics) diff --git a/netlify/override-the-default-yarn-version.md b/netlify/override-the-default-yarn-version.md deleted file mode 100644 index 5cfa63bd..00000000 --- a/netlify/override-the-default-yarn-version.md +++ /dev/null @@ -1,11 +0,0 @@ -# Override The Default Yarn Version - -When you first deploy an app to [Netlify](https://www.netlify.com/), the -current default [Yarn](https://yarnpkg.com/) version will be locked in. This -Yarn version will be used for future builds and deployments. - -You can override the default Yarn version by including the `YARN_VERSION` -environment variable. Set it to the desired major and minor version in the app -settings panel. The next deployment will use that new version. - -[source](https://community.netlify.com/t/default-yarn-version-is-now-1-17/2297) diff --git a/phoenix/bypass-template-rendering.md b/phoenix/bypass-template-rendering.md deleted file mode 100644 index aaebd072..00000000 --- a/phoenix/bypass-template-rendering.md +++ /dev/null @@ -1,32 +0,0 @@ -# Bypass Template Rendering - -Generally when rendering a response to a request in a Phoenix app, the -controller will make a render call that targets a specific template. If it -suits our needs, we can skip writing a template and bypass the template -portion of the response pipeline by implementing our own `render` function -directly in the view module. - -Consider the following route and controller action: - -```elixir -# web/router.ex -get "/hello", UserController, :hello - -# web/controllers/user_controller.ex -def hello(conn, _params) do - render(conn, "hello.html") -end -``` - -The render call would normally trigger a corresponding template function, -but we bypass it by adding the following function to our view module: - -```elixir -# web/views/user_view.ex -def render("hello.html", _assigns) do - "Hello, World!" -end -``` - -Visiting `/hello` will render a page with the view's layout and the words -"Hello, World!". diff --git a/phoenix/check-the-installed-version.md b/phoenix/check-the-installed-version.md deleted file mode 100644 index 75d99c8b..00000000 --- a/phoenix/check-the-installed-version.md +++ /dev/null @@ -1,10 +0,0 @@ -# Check The Installed Version - -Check what the installed version of Phoenix is with the `-v` flag. - -```bash -$ mix phoenix.new -v -Phoenix v1.2.0 -``` - -[source](http://shorts.jeffkreeftmeijer.com/2015/find-the-currently-installed-phoenix-version-number/) diff --git a/phoenix/generate-new-app-without-brunch.md b/phoenix/generate-new-app-without-brunch.md deleted file mode 100644 index 3cca72de..00000000 --- a/phoenix/generate-new-app-without-brunch.md +++ /dev/null @@ -1,16 +0,0 @@ -# Generate New App Without Brunch - -By default when you create a new Phoenix app using `phx.new`, a set of files -and configurations will be generated for [Brunch](http://brunch.io/). Though -the Phoenix team decided to use Brunch, you don't have to. You may not want -Phoenix to handle asset building or you may just prefer another tool. Either -way, if you'd like to opt out, you can include the `--no-brunch` flag when -generating the project. - -```bash -$ mix phx.new --no-brunch my_app -``` - -If you have an existing project that you'd like to remove Brunch from, there -is some information in [Phoenix's Static Assets -documentation](http://phoenixframework.org/blog/static-assets). diff --git a/phoenix/render-a-template-to-a-string.md b/phoenix/render-a-template-to-a-string.md deleted file mode 100644 index 23cb7159..00000000 --- a/phoenix/render-a-template-to-a-string.md +++ /dev/null @@ -1,24 +0,0 @@ -# Render A Template To A String - -Templates in a [Phoenix](http://www.phoenixframework.org/) application -ultimately get compiled to functions that can be quickly rendered with the -necessary data. We can take a look at how a template will be rendered using -[`Phoenix.View.render_to_string/3`](https://hexdocs.pm/phoenix/Phoenix.View.html#render_to_string/3). - -First, we need a template: - -```elixir -# user.html.eex -

<%= @user.first_name %>

-
<%= @user.username %> (<%= @user.email %>)
-``` - -We can then render that template for the view with some user: - -```elixir -> user = %User{first_name: "Liz", last_name: "Lemon", username: "llemon", email: "lizlemon@nbc.com"} -%MyApp.User{...} - -> Phoenix.View.Render_to_string(MyApp.UserView, "user.html", user: user) -"

Liz

\n
llemon (lizlemon@nbc.com)
\n" -``` diff --git a/phoenix/serve-static-assets-from-custom-directory.md b/phoenix/serve-static-assets-from-custom-directory.md deleted file mode 100644 index 70334379..00000000 --- a/phoenix/serve-static-assets-from-custom-directory.md +++ /dev/null @@ -1,27 +0,0 @@ -# Serve Static Assets From Custom Directory - -When you new up a Phoenix project, an `endpoint.ex` file will be generated. -This file is full of different plugs for handling incoming traffic. The -`Plug.Static` declaration specifies how your application will handle and -serve requests for static files. - -```elixir - plug Plug.Static, - at: "/", from: :my_app, gzip: false, - only: ~w(css fonts images js favicon.ico robots.txt) -``` - -The `from` options declares where these static files are located. In this -case it references our application (`:my_app`) as the target which will -translate to its `priv/static` directory. - -If you instead want to serve your files from a different, custom directory, -you can replace it with the path to that directory. - -```elixir - plug Plug.Static, - at: "/", from: "priv/my_frontend/static", gzip: false, - only: ~w(css fonts images js favicon.ico robots.txt) -``` - -[source](https://hexdocs.pm/plug/Plug.Static.html) diff --git a/phoenix/specifying-the-digest-directory.md b/phoenix/specifying-the-digest-directory.md deleted file mode 100644 index 30e24f4c..00000000 --- a/phoenix/specifying-the-digest-directory.md +++ /dev/null @@ -1,19 +0,0 @@ -# Specifying The Digest Directory - -By default, Phoenix targets `priv/static` when preparing digested assets for -production. This process happens when running `mix phx.digest`. - -If you are doing some custom work with your assets such that they are in a -different location, you'll need to tell Phoenix where to look. To do this, -just include an optional path argument. - -```bash -$ mix phx.digest path/to/my/assets -``` - -The digests will be put in that target directory. If you'd like to specify a -different output directory, such as `priv/static`, include the `-o` flag. - -```bash -$ mix phx.digest path/to/my/assets -o priv/static -``` diff --git a/phoenix/specifying-the-server-port.md b/phoenix/specifying-the-server-port.md deleted file mode 100644 index bb9dba3f..00000000 --- a/phoenix/specifying-the-server-port.md +++ /dev/null @@ -1,30 +0,0 @@ -# Specifying The Server Port - -Running `mix phx.server` for a Phoenix project with the default settings -will attach the server to port `4000`. - -If you'd like to use a different port in development, you can change it in -`config/dev.exs`. - -```elixir -config :my_app, MyApp.Web.Endpoint, - http: [port: 4444], - ... -``` - -Alternatively, you can allow it to be configurable from the command line -with an environment variable and a fallback port. - -```elixir -config :my_app, MyApp.Web.Endpoint, - http: [port: System.get_env("PORT") || 4000], - ... -``` - -Running - -```bash -$ PORT=4444 mix phx.server -``` - -will launch the server on port `4444`. diff --git a/planetscale/seed-production-data-into-another-branch.md b/planetscale/seed-production-data-into-another-branch.md deleted file mode 100644 index 321c9e10..00000000 --- a/planetscale/seed-production-data-into-another-branch.md +++ /dev/null @@ -1,28 +0,0 @@ -# Seed Production Data Into Another Branch - -When you [create a Planetscale -branch](https://planetscale.com/docs/reference/branch) off `main`, it will only -copy over the schema. No data will be copied over to that new branch. - -You can copy data over from the initial branch (`main`) in two steps from the -CLI. First, create a dump of the branch. Then restore the dump into your new -branch. - -```bash -$ pscale database dump database-name main --output ./dump -``` - -That creates SQL files locally in the `dump` folder with both schema and data -statements. - -That folder of SQL files can then be restored into one of your branches. - -```bash -$ pscale database restore-dump database-name branch-name --dir ./dump --overwrite-tables -``` - -The `--overwrite-tables` flag is needed because your branch's existing schema -will conflict with the `create` schema statements in the SQL files. - -You can `pscale shell` into that branch and run a `select ...` statement to -check out the data. diff --git a/prisma/apply-separate-formatting-with-a-blank-line.md b/prisma/apply-separate-formatting-with-a-blank-line.md deleted file mode 100644 index 16e1ae8c..00000000 --- a/prisma/apply-separate-formatting-with-a-blank-line.md +++ /dev/null @@ -1,42 +0,0 @@ -# Apply Separate Formatting With A Blank Line - -Prisma's CLI includes a `format` command. When run, this will standardize the -layout of the `schema.prisma` file. This is variable based on the length of -column and attribute names. - -You can exercise some control over the formatting and visually organize the -parts of a model by injecting blank lines between sets of statements. - -Here is what a formatted model might look like with no blank lines: - -```prisma -model Book { - id String @id @default(uuid()) - title String - publicationDate DateTime - author Author @relation(fields: [authorId], references: [id]) - authorId String - createdAt DateTime @default(now()) @map(name: "created_at") - updatedAt DateTime @updatedAt @map(name: "updated_at") -} -``` - -All the types get aligned based on the longest column name. - -Now, here is what it looks like if I use a blank line to separate all the -primary fields from the `createdAt` and `updatedAt`. - -```prisma -model Book { - id String @id @default(uuid()) - title String - publicationDate DateTime - author Author @relation(fields: [authorId], references: [id]) - authorId String - - createdAt DateTime @default(now()) @map(name: "created_at") - updatedAt DateTime @updatedAt @map(name: "updated_at") -} -``` - -Notice how the second block of lines is aligned independent of the first. diff --git a/prisma/batch-insert-records-with-create-many.md b/prisma/batch-insert-records-with-create-many.md deleted file mode 100644 index 81f966f4..00000000 --- a/prisma/batch-insert-records-with-create-many.md +++ /dev/null @@ -1,41 +0,0 @@ -# Batch Insert Records With createMany - -As part of its suite of CRUD functionality, [Prisma has a `createMany` -function](https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#createmany) -that allows you to `insert` many records at once with your target database. -This will perform one large insert statement which will generally be faster -than an equivalent series of individual insert statements. - -```javascript -const createResult = await prisma.books.createMany({ - data: [ - { isbn: '123', title: 'The Goldfinch' }, - { isbn: '345', title: 'Piranesi' }, - { isbn: '987', title: 'The Fifth Season' }, - ], - skipDuplicates: true -}) -``` - -With the `skipDuplicates` option, any inserts that would result in a duplicate -record (`isbn` is my unique key in this example) will be skipped. - -The result of the query will include a `count` key to let you know how many -records were actually inserted. - -If I'm bulk inserting a _ton_ of data, I like to chunk it up so that I'm not -creating queries that are too big. For a recent script, I found that `1000` was -a good chunking number. - -```javascript -import 'chunk' from 'lodash/chunk' - -const chunkedBatchInsert = async (records) => { - for(const batch of chunk(records, 1000)) { - await prisma.books.createMany({ - data: batch, - skipDuplicates: true - }) - } -} -``` diff --git a/prisma/check-if-database-and-schema-are-not-in-sync.md b/prisma/check-if-database-and-schema-are-not-in-sync.md deleted file mode 100644 index dec906b2..00000000 --- a/prisma/check-if-database-and-schema-are-not-in-sync.md +++ /dev/null @@ -1,37 +0,0 @@ -# Check If Database And Schema Are Not In Sync - -The [`prisma migrate -diff`](https://www.prisma.io/docs/orm/reference/prisma-cli-reference#migrate-diff) -command is a versatile tool that can be used to check if there is a difference -between two sources. In this case, we want to check if our database is in sync -with the `schema.prisma` file for our project. - -If we have made changes to the schema file, but haven't yet migrated or pushed -those changes to our local database, then we want to be notified of that -mismatch. - -We'll point at the schema file with `--to-schema-datamodel` and at our local -database with `--from-url`. - -```bash -❯ npx prisma migrate diff \ - --to-schema-datamodel ./prisma/schema.prisma \ - --from-url mysql://root@localhost:3309/kcd-products - -[*] Changed the `User` table - [+] Added column `metadata` -``` - -In the case where there is a different, we see an output summary of the diff. - -Let's say we've applied our changes (`prisma db push`) to our local database. -If we now run that same command again, we can see that no difference is -detected and our database is in sync with our schema. - -```bash -❯ npx prisma migrate diff \ - --to-schema-datamodel ./prisma/schema.prisma \ - --from-url mysql://root@localhost:3309/kcd-products - -No difference detected. -``` diff --git a/prisma/configure-client-to-log-sql-queries.md b/prisma/configure-client-to-log-sql-queries.md deleted file mode 100644 index bb8ced5a..00000000 --- a/prisma/configure-client-to-log-sql-queries.md +++ /dev/null @@ -1,33 +0,0 @@ -# Configure Client To Log SQL Queries - -During development, especially while debugging, it can be helpful to see the -actual SQL queries generated by Prisma queries we are formulating. Because an -ORM is an abstraction over SQL, it isn't always obvious what the resulting SQL -will turn out to be. - -By adding the `log` configuration to where we initialize our Prisma client, we -can tell it to log things like errors and the SQL of the queries it executes. - -```javascript -export const prisma = - new PrismaClient({ - log: ['error', 'query'] - }) -``` - -If we only want the SQL logged in development, we could do something like this: - -```javascript -export const prisma = - new PrismaClient({ - log: - process.env.NODE_ENV === 'development' - ? ['query', 'error'] - : ['error'], - }) -``` - -If we look in our app server logs when a code path that contains a Prisma query -executes, we'll see a line for each SQL statement. - -[source](https://github.com/prisma/prisma/discussions/3967) diff --git a/prisma/execute-a-raw-sql-query.md b/prisma/execute-a-raw-sql-query.md deleted file mode 100644 index fa75fca5..00000000 --- a/prisma/execute-a-raw-sql-query.md +++ /dev/null @@ -1,45 +0,0 @@ -# Execute A Raw SQL Query - -[Prisma](https://www.prisma.io/) with TypeScript acts as a powerful -[ORM](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping) for -interacting with your database. However, not every kind of query that you may -need can be represented with the API generated from your schema. For instance, -certain tables might be ignored in your `prisma.schema` file. Or you may want -to hand-craft a query for performance or ergonomics reasons. - -Like any good ORM, Prisma provides an escape hatch for this kind of situation -with the -[`$queryRaw`](https://www.prisma.io/docs/concepts/components/prisma-client/raw-database-access#queryraw) -tag function. - -```typescript -function getExpiresIn({ email }) { - const prisma = new PrismaClient() - - const result: Array = await prisma.$queryRaw` - select - id, - code, - date_trunc('days', expires_at - now())::varchar as expires_in - from tickets - where email = ${email} - ` - - // result - // => [{ id: 123, code: 'abc123', expires_in: '3 days' }] - - return result -} -``` - -This runs the raw SQL in the template literal against the database. The result -is returned as an array of objects with key-value pairs for each selected -value. - -Writing the SQL query myself, in this case, means I can take advantage of -database (Postgres) specific features (e.g. -[`date_trunc`](https://www.postgresqltutorial.com/postgresql-date-functions/postgresql-date_trunc/) -and [interval -math](https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-interval/)). - -[source](https://www.prisma.io/docs/concepts/components/prisma-client/raw-database-access) diff --git a/prisma/grab-a-limited-set-of-records.md b/prisma/grab-a-limited-set-of-records.md deleted file mode 100644 index 6e37f349..00000000 --- a/prisma/grab-a-limited-set-of-records.md +++ /dev/null @@ -1,27 +0,0 @@ -# Grab A Limited Set Of Records - -Let's say you want to grab some records from a table, but you want to limit the -result set to 10 records. - -You can do that with the `take` option. - -```javascript -const posts = await prisma.post.findMany({ - take: 10 -}); -``` - -It is generally good to not assume anything about the ordering. Instead, you -should be explicit about the order you want, so let's include an `orderBy` as -well. - -```javascript -const posts = await prisma.post.findMany({ - take: 10, - orderBy: { createdAt: "asc" }, -}); -``` - -This will return the 10 most recently created posts. - -[source](https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#findmany) diff --git a/prisma/open-connections-to-multiple-databases.md b/prisma/open-connections-to-multiple-databases.md deleted file mode 100644 index a92f833d..00000000 --- a/prisma/open-connections-to-multiple-databases.md +++ /dev/null @@ -1,39 +0,0 @@ -# Open Connections To Multiple Databases - -A standard database connection with Prisma is determined by a `DATABASE_URL` -env var set in the `.env` file of your project. Typically, the Prisma client -connecting to that URL will be configured in a separate file and imported -wherever it is used. - -```javascript -import {prisma} from './utils/prisma' -``` - -What if you want to connect to a second, alternate database? - -You can create a new Prisma client with the data source configured to be a -different connection URL. - -```javascript -import {prisma as primaryPrismaClient} from '@skillrecordings/database' -import {PrismaClient} from '@prisma/client' - -const secondaryDatabaseUrl = 'mysql://root@localhost:3399/my-database' - -const secondaryPrismaClient = new PrismaClient({ - datasources: { - db: { - url: secondaryDatabaseUrl - } - }, -}) -``` - -And with that, you can execute queries against both databases. - -```javascript -const primaryUserCount = await primaryPrismaClient.user.count() -const secondaryUserCount = await secondaryPrismaClient.user.count() -``` - -[source](https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#programmatically-override-a-datasource-url) diff --git a/prisma/override-table-name-for-prisma-model.md b/prisma/override-table-name-for-prisma-model.md deleted file mode 100644 index 13b2a240..00000000 --- a/prisma/override-table-name-for-prisma-model.md +++ /dev/null @@ -1,42 +0,0 @@ -# Override Table Name For Prisma Model - -When defining your Prisma schema, you'll add models to your -`prisma/schema.prisma` file that look something like this: - -``` -model Book { - id BigInt @id @default(autoincrement()) @db.BigInt - title String - author String - publication_year Int - created_at DateTime @default(now()) - updated_at DateTime @updatedAt -} -``` - -The prisma client (ORM-layer) that gets generated will have a `Book` type and -you'll be able to reference the model to, for instance, create a record with -`prisma.book.create(...)`. Both of these things are derived from the model -name: `Book`. - -The other thing that is derived from the model name is the name given to the -underlying database table. So you end up with a table called `Book`. You may, -however, prefer a table naming convention where this one would be named `books` -(snake_case and pluralized). - -To achieve that, you have to manually override the table name with [the `@@map` -directive](https://www.prisma.io/docs/orm/reference/prisma-schema-reference#map-1). -Add it toward the bottom of the model like so: - -``` -model Book { - id BigInt @id @default(autoincrement()) @db.BigInt - title String - author String - publication_year Int - created_at DateTime @default(now()) - updated_at DateTime @updatedAt - - @@map("books") -} -``` diff --git a/prisma/specify-alternate-location-for-prisma-schema.md b/prisma/specify-alternate-location-for-prisma-schema.md deleted file mode 100644 index bac34ed5..00000000 --- a/prisma/specify-alternate-location-for-prisma-schema.md +++ /dev/null @@ -1,28 +0,0 @@ -# Specify Alternate Location For Prisma Schema - -By default, Prisma looks for a schema in one of two locations: - -- `./prisma/schema.prisma` -- `./schema.prisma` - -If it isn't in one of those two spots, then you'll get an error. - -You can manually specify an alternate location. One way is to use the -`--schema` flag with all `prisma` commands. A less tedious approach -([introduced in this PR](https://github.com/prisma/prisma/pull/3566)) is to -specify the location in your `package.json`. - -```json -{ - "prisma": { - "schema": "../../packages/database/prisma/schema.prisma" - } -} -``` - -This is handy in situations where your database schema and utils are packaged -up separately, like in a monorepo. Here is an example of [a monorepo -referencing a prisma schema in a separate -package](https://github.com/skillrecordings/products/blob/b10dece7170abcb9076221c0863549e2291541ae/apps/testingaccessibility/package.json#L201-L203). - -[source](https://www.prisma.io/docs/concepts/components/prisma-schema#prisma-schema-file-location) diff --git a/reason/break-out-of-a-while-loop.md b/reason/break-out-of-a-while-loop.md deleted file mode 100644 index fd02b51d..00000000 --- a/reason/break-out-of-a-while-loop.md +++ /dev/null @@ -1,27 +0,0 @@ -# Break Out Of A While Loop - -The `while` construct is a great way to loop indefinitely. You may -eventually want to break out of the loop. For that, you are going to need to -invalidate the _while condition_. One way of going about this is creating a -mutable ref, changing it from true to false when a certain condition is met. - -```reason -let break = ref(true); - -while (break^) { - switch (Unix.readdir(currentDir)) { - | exception End_of_file => break := false - | item => print_endline(item); - } -}; -``` - -Here we have a mutable ref called `break` which starts as `true`. This is -our _while condition_. Its actual value can be referenced by appending the -`^` character -- hence `break^`. Once a certain condition is met inside our -`while` block, we can set `break` to `false` using the `:=` operator. - -The above code snippet can be seen in full details -[here](https://github.com/jbranchaud/basic-ls-reason-native/blob/master/src/Index.re). - -[source](https://reasonml.github.io/docs/en/imperative-loops.html#tips-tricks) diff --git a/reason/compile-reason-to-native-with-dune.md b/reason/compile-reason-to-native-with-dune.md deleted file mode 100644 index 07d1269a..00000000 --- a/reason/compile-reason-to-native-with-dune.md +++ /dev/null @@ -1,28 +0,0 @@ -# Compile Reason To Native With Dune - -[Dune](https://github.com/ocaml/dune) is "a composable build system for -OCaml" with out-of-the-box support for ReasonML. Dune can be used for a lot -of things, but in simplest terms it can be used to compile ReasonML programs -into native executables. - -Considering the following ReasonML program. - -```reason -/* hello_reason.re */ -print_endline("Hello, Reason!") -``` - -We can then create the following Dune build file. - -```lisp -;; dune -(executable - (name hello_reason)) -``` - -If we then run `dune build hello_reason.exe`, then Dune will compile the -`hello_reason.re` into a `hello_reason.exe` executable that can be found in -`build/default`. Run it and see the output. - -Read more in the [Quickstart -guide](https://dune.readthedocs.io/en/latest/quick-start.html). diff --git a/reason/compile-reason-with-an-ocaml-package-using-dune.md b/reason/compile-reason-with-an-ocaml-package-using-dune.md deleted file mode 100644 index 627400bd..00000000 --- a/reason/compile-reason-with-an-ocaml-package-using-dune.md +++ /dev/null @@ -1,35 +0,0 @@ -# Compile Reason With An OCaml Package Using Dune - -In [Compile Reason To Native With -Dune](reason/compile-reason-to-native-with-dune.md), I showed how to compile -a basic ReasonML file as a native executable using Dune. - -Any non-trivial program will likely involve pulling in an OCaml dependency. -For example, you may want to pull in [Lwt](https://github.com/ocsigen/lwt). -Assuming this package is available, whether you've manually downloaded it -via [opam](https://opam.ocaml.org/) or used something like -[esy](https://github.com/esy/esy), you'll want to let Dune know that Lwt is -an available library. - -```lisp -;; dune -(executable - (name hello_reason) - (libraries lwt lwt.unix)) -``` - -The modules in the Lwt package will now be globally available to your -Reason code. - -```reason -let () = { - Lwt_main.run( - Lwt_io.printf("Hello, Reason!\n") - ); -}; -``` - -When Dune builds your code, it will include and compile Lwt. - -See a [full example -here](https://github.com/jbranchaud/esy-reasonml-lwt-example). diff --git a/reason/create-a-map-of-strings.md b/reason/create-a-map-of-strings.md deleted file mode 100644 index e21b34b0..00000000 --- a/reason/create-a-map-of-strings.md +++ /dev/null @@ -1,31 +0,0 @@ -# Create A Map Of Strings - -[ReasonML](https://reasonml.github.io/en) has the [`Map.Make` -functor](https://reasonml.github.io/api/Map.Make.html) in its standard -library which allows you to create a `Map` module with a specific key type. -Here is how we can make a map module with string keys. - -```reason -module StringMap = Map.Make(String); -``` - -We can then use that module to to create an empty map followed by adding -key-value pairs to it. - -```reason -StringMap.empty -|> StringMap.add("Morty", "Smith") -|> StringMap.add("Rick", "Sanchez") -|> StringMap.add("Scary", "Terry") -|> StringMap.iter((first, last) => { - print_endline(Printf.sprintf("%s %s", first, last)); -}); -/* -Morty Smith -Rick Sanchez -Scary Terry -*/ -``` - -See the [live -example](https://reasonml.github.io/en/try?rrjsx=true&reason=LYewJgrgNgpgBAZQC4CcCWA7A5gWQIYAOcAvHPgQHT4DWMAFMutgJQDcAUO45roRTMAJIAnuwA+APkSoe5CnjBg6AIhwgUI5QBo4yhMDRIAFsubip3bHIVLlAJTQBjatt0I8GR0ZgAvU+ekmXkobFQRHPBRhV2UAFRgUKP9JQNk+QwS6OgAzNBQAZyQdKDxC5hIpAG92ODgCJiQAfRgMMChMegAFBuyKfPrMJGyVAFJ8uDHXXIKiuBKytnYAXzYgA). diff --git a/reason/create-a-stream-from-an-array.md b/reason/create-a-stream-from-an-array.md deleted file mode 100644 index 09ffb8de..00000000 --- a/reason/create-a-stream-from-an-array.md +++ /dev/null @@ -1,35 +0,0 @@ -# Create A Stream From An Array - -There are functions in the [`Stream` -module](https://reasonml.github.io/api/Stream.html) for turning a variety of -data structures into streams -- lists, input channels, etc. - -What if you have an array? - -The `Stream.from` function lets you define a function for custom fitting -data structures into streams. Let's take a look: - -```reason -let pokemons = [| "bulbasaur", "charmander", "squirtle" |]; - -let poke_stream: Stream.t(string) = - Stream.from(i => - switch (pokemons[i]) { - | pokemon => Some(pokemon) - | exception (Invalid_argument("index out of bounds")) => None - } - ); -``` - -The function takes the current index and needs to either return `Some('a)` -with the corresponding value or `None` if the stream is empty. - -With that, we now have a stream on which we can invoke any of the stream -functions. - -```reason -switch (Stream.next(poke_stream)) { -| pokemon => print_endline(Printf.sprintf("Next Pokemon: %s", pokemon)) -| exception Stream.Failure => print_endline("No pokemon left") -}; -``` diff --git a/reason/creating-a-2d-array.md b/reason/creating-a-2d-array.md deleted file mode 100644 index 9f6267e8..00000000 --- a/reason/creating-a-2d-array.md +++ /dev/null @@ -1,36 +0,0 @@ -# Creating A 2D Array - -In most languages if I wanted to create a two-dimensional array, I would -utilize some nested looping construct to generate columns of rows. The -[ReasonML `Array` module](https://reasonml.github.io/api/Array.html) -abstracts this away. - -```reason -let grid = Array.make_matrix(10, 10, 0); - -grid -|> Array.iter(column => { - column - |> Array.iter(cell => { - print_int(cell); - }); - print_endline(""); -}); - -/* -0000000000 -0000000000 -0000000000 -0000000000 -0000000000 -0000000000 -0000000000 -0000000000 -0000000000 -0000000000 -*/ -``` - -The `make_matrix` function allows you to specify dimensions of a -two-dimensional array with all positions initialized to the same value -- -that third argument. diff --git a/reason/data-structures-with-self-referential-types.md b/reason/data-structures-with-self-referential-types.md deleted file mode 100644 index 1f91171a..00000000 --- a/reason/data-structures-with-self-referential-types.md +++ /dev/null @@ -1,29 +0,0 @@ -# Data Structures With Self-Referential Types - -[ReasonML](https://reasonml.github.io/) has a powerful type system that -allows us to create types that represent all sorts of things. For data -structures like [linked lists](https://en.wikipedia.org/wiki/Linked_list), -we need a sort of recursive type, a type that can reference itself -- a -self-referential type. - -Reason's type system allows us to define types that reference themselves. -Combine that with type arguments and variants -- we can create a type -definition to represents something like a linked list. - -```reason -type linked_list('a) = - | Empty - | Node('a, linked_list('a)); -``` - -A linked list is a chain of nodes. It can be an _empty_ list, hence the -first part of the variant. Otherwise, it is a node that has some data and -then points to another linked list (chain of nodes). - -The `'a` part is a type argument. When creating a linked list, we can decide -what type the `'a` will be. Here is an `int`-based linked list: - -```reason -let my_list: linked_list(int) = Node(25, Node(27, Empty)); -/* my_list = [25] => [27] => [] */ -``` diff --git a/reason/defining-variants-with-constructor-arguments.md b/reason/defining-variants-with-constructor-arguments.md deleted file mode 100644 index 2b14fa77..00000000 --- a/reason/defining-variants-with-constructor-arguments.md +++ /dev/null @@ -1,39 +0,0 @@ -# Defining Variants With Constructor Arguments - -In [Helping The Compiler Help Us With -Variants](https://github.com/jbranchaud/til/blob/master/reason/helping-the-compiler-help-us-with-variants.md), -I introduced the concept of variants with a basic example of how to define -and use one. The fun doesn't stop there. - -We can take variants a step further by defining them with constructor -arguments. - -```reason -type listActions = - | Length - | Nth(int); -``` - -The second variant is defined such that it is paired with some extra data -- -a single `int` argument. - -Here is how we use that variant in our code: - -```reason -let performListAction = (l: list(int), action: listActions) => { - switch(action) { - | Length => List.length(l) - | Nth(n) => List.nth(l, n) - } -}; - -performListAction([7,8,9], Nth(1)); /* 8 */ -performListAction([1,2,3], Length); /* 3 */ -``` - -Our switch statement not only matches on that variant, but it makes the -`int` argument available as a value we can consume in that step of the -switch. - -[source -code](https://reasonml.github.io/en/try.html?reason=C4TwDgpgBANglgZ2AQQMbDgewHYKgXgCgooAfKAGQmwHNgALYsqAOQYAo5tgBKAbkKEYEYFEgAnAGaZxAWwqIU6LNgJR2MAFyxFnbjwA0UAIbKc2+EjQYcCHgQB8UAN5MEAdzjBU9dqZvY9q4k5FS0DI6UigB0wuG+MDxM5Gy+gZEKSNHcCUaBTAC+hAUChABSCLGYNOwS0nKZSgHsANoA7AYAHAYAnAC6RqnsAIw8YwIVVTV1MvKK1iqtwwYATAYAzAOU1HT040A) diff --git a/reason/dynamically-create-a-printf-string-format.md b/reason/dynamically-create-a-printf-string-format.md deleted file mode 100644 index 96edb170..00000000 --- a/reason/dynamically-create-a-printf-string-format.md +++ /dev/null @@ -1,34 +0,0 @@ -# Dynamically Create A Printf String Format - -Formatting a string with `Printf` requires defining a format for that -string. - -```reason -let str = Printf.sprintf("%6s", "dope"); -/* str => " dope" */ -``` - -The _format_ is the first argument. At compile-time it is interpreted as a -`format6` type value. - -So, what if you want a dynamically created _format_ value? Simply -concatenating some strings together won't do it because then the type will -be `string` and that's not going to compile. - -The [`Scanf.format_from_string`](https://reasonml.github.io/api/Scanf.html) -function can help. - -```reason -let some_num = 6; -let format_str = "%" ++ string_of_int(some_num) ++ "s"; -let format = Scanf.format_from_string(format_str, "%s"); - -let str = Printf.sprintf(format, "dope"); -/* str => " dope" */ -``` - -We can convert our string that has the appearance of a format into an actual -`format6` type. To do this, we have to tell `format_from_string` what types -each of the formats is going to have -- hence the second argument `%s`. - -[source](https://twitter.com/rickyvetter/status/1013476235253436417) diff --git a/reason/exhaustive-pattern-matching-of-list-variants.md b/reason/exhaustive-pattern-matching-of-list-variants.md deleted file mode 100644 index b4b59917..00000000 --- a/reason/exhaustive-pattern-matching-of-list-variants.md +++ /dev/null @@ -1,32 +0,0 @@ -# Exhaustive Pattern Matching Of List Variants - -ReasonML's `switch` expression allows for powerful pattern matching. When -using `switch` to pattern match against a list, the compiler will be sure to -warn you if you haven't accounted for all variants of a list. - -```reason -let getFirst = (numList: list(int)): int => { - switch(numList) { - | [first, ...rest] => first - }; -}; -``` - -> this pattern-matching is not exhaustive. Here is an example of a value -> that is not matched: [] - -The compiler knows that a list can either be 1) empty (`[]`) or 2) contain -at least one value and another list (`[a, ...rest]`). To ensure all variants -are accounted for, we can include the `[]` case in our switch. - -```reason -let getFirst = (numList: list(int)): int => { - switch(numList) { - | [] => -1 - | [first, ...rest] => first - }; -}; -``` - -[source -code](https://reasonml.github.io/en/try.html?reason=DYUwLgBAdgrgtgIxAJwM4C4LAJarACmyjAEoIBeCAbQDYAaABjvvoEYBdAbgChvRIA5uABi2NJEr5YcADK4wmHHkLESJTEQkA+CAG9uECKgDu2MAGMAFlPhy8ZfYYA+1AGZi8dCADpfyEHjsFDru4gYQAL48UbwAUqjewAD2AvhCYKLiNogoqGqcQA) diff --git a/reason/format-the-current-file-within-vim.md b/reason/format-the-current-file-within-vim.md deleted file mode 100644 index b76c4a45..00000000 --- a/reason/format-the-current-file-within-vim.md +++ /dev/null @@ -1,19 +0,0 @@ -# Format The Current File Within Vim - -I'm editing a `.re` file within Vim. I haven't yet wired up `refmt` to -something like [ALE](https://github.com/w0rp/ale) for automatic formatting -on save. By the time I'm done with my changes, indentation is a mess. - -I can still take advantage of `refmt` to clean up my file. - -``` -:!refmt --in-place % -``` - -Running that command in Vim will cause the current file to be formatted. - -How does it work? - -It shells-out to `refmt` which does all the heavy lifting. The `--in-place` -flag means that the target file will be re-written by the formatted result. -The `%` is a handy Vim shorthand for the path and name of the current file. diff --git a/reason/generate-a-native-reasonml-project-with-pesy.md b/reason/generate-a-native-reasonml-project-with-pesy.md deleted file mode 100644 index d9d8cf72..00000000 --- a/reason/generate-a-native-reasonml-project-with-pesy.md +++ /dev/null @@ -1,17 +0,0 @@ -# Generate A Native ReasonML Project With Pesy - -[Pesy](https://github.com/jordwalke/pesy) is a CLI utility available from -NPM that you can use to generate a ReasonML project that is ready for native -compilation. It uses [`esy`](https://github.com/esy/esy) for the management -of `opam` packages. It uses [Dune](https://github.com/ocaml/dune) for -building your library code with the ReasonML and OCaml dependencies. - -Assuming you already have `pesy` installed globally, create a directory for -your project and then run: - -```bash -$ pesy -``` - -A project will be generated that is out-of-the-box ready to compile native -executables. diff --git a/reason/generate-starter-reason-projects.md b/reason/generate-starter-reason-projects.md deleted file mode 100644 index 0fa919c7..00000000 --- a/reason/generate-starter-reason-projects.md +++ /dev/null @@ -1,34 +0,0 @@ -# Generate Starter Reason Projects - -With the latest `bs-platform` installed, you should have access to the `bsb` -command which contains a number of options -- including `-themes`. - -```bash -$ bsb -themes -Available themes: -basic -basic-reason -generator -minimal -node -react -``` - -This is a list of themes (read: templates) that can be used to generate a -starter project. - -For example, if you'd like a basic project structure geared toward writing -Reason, run the following: - -```bash -$ bsb -init my-project -theme basic-reason -``` - -Or if you'd like to get started with -[`reason-react`](https://reasonml.github.io/reason-react/), give this a try: - -```bash -$ bsb -init my-reason-react-project -theme react -``` - -[source](https://bucklescript.github.io/docs/en/new-project.html) diff --git a/reason/helping-the-compiler-help-us-with-variants.md b/reason/helping-the-compiler-help-us-with-variants.md deleted file mode 100644 index cba28f50..00000000 --- a/reason/helping-the-compiler-help-us-with-variants.md +++ /dev/null @@ -1,38 +0,0 @@ -# Helping The Compiler Help Us With Variants - -[ReasonML](https://reasonml.github.io/) gives us something called a variant -which is similar to what other language call enums and union types. By -defining a variant, we give the compiler some information about exactly what -values a variable can take on -- its allowed variants. - -Here we define the kinds of roles that users in our system can have as well -as a `user` type for representing individual users: - -```reason -type userType = - | Student - | Teacher - | Admin; - -type user = { role: userType, id: int }; -``` - -And here is how we might use it in some authorization code: - -```reason -let canCreateClasses(u: user) { - switch(u.role) { - | Student => false - | Teacher => true - }; -}; -``` - -We've neglected to include `Admin` in our switch statement. The compiler -will inform us of this with a warning. - -> this pattern-matching is not exhaustive. Here is an example of a value -> that is not matched: Admin - -[source -code](https://reasonml.github.io/en/try.html?reason=C4TwDgpgBArgzhATgFXNAvAKClAPlAZWBgBMIA7YbPKZCAQwGMALJa-AQRIFsBLcgNyZQkWAkRR0UAN5REAewA2EAFxikqSABoovEmv7AoAXyGZlRxvXIBhRA2AQbi+nARwAFDDXwkAShlqOAB3XmAWLwA6BWUA6XZCYjJKSQA+KAAzekUEBLomVgl0dOBEGAhqU0wqgCk4SMV5AHMPK1t7ekdnV3cPWRjVRNIKYB09NQBGACYAZhM-PwEgA) diff --git a/reason/inline-component-styles-with-reason-react.md b/reason/inline-component-styles-with-reason-react.md deleted file mode 100644 index 78b9dab4..00000000 --- a/reason/inline-component-styles-with-reason-react.md +++ /dev/null @@ -1,29 +0,0 @@ -# Inline Component Styles With Reason React - -If you've written much React.js, the following may look familiar: - -```javascript - -``` - -This is how we do inline styles with JSX in JavaScript. - -When it comes to doing inline styles with JSX in our ReasonML code, the best -approach for now is to use a `make` function for styles provided by the -React DOM bindings. - -```reason - -``` - -[source](https://reasonml.github.io/reason-react/docs/en/style.html) diff --git a/reason/is-this-a-directory-or-a-file.md b/reason/is-this-a-directory-or-a-file.md deleted file mode 100644 index acc4c043..00000000 --- a/reason/is-this-a-directory-or-a-file.md +++ /dev/null @@ -1,38 +0,0 @@ -# Is This A Directory Or A File? - -When compiling [ReasonML](https://reasonml.github.io/) natively, we have access to a variety of -additional modules including the `Unix` module. We can interact with -directories and files using functions on `Unix`. - -```reason -let current_dir = Unix.opendir(Unix.getcwd()); -let first_file = Unix.readdir(current_dir); -/* is first_file a directory or a file? */ -Unix.closedir(current_dir); -``` - -Here we open the current working directory, grab the first thing out of that -directory -- maybe it's a file, maybe it's a directory, maybe it is -something else. Lastly, we close the directory. - -```reason -let current_dir = Unix.opendir(Unix.getcwd()); -let first_file = Unix.readdir(current_dir); - -switch(Unix.stat(first_file)) { -| Unix.stats({ st_kind: Unix.S_REG }) => print_endline("Regular File") -| Unix.stats({ st_kind: Unix.S_DIR }) => print_endline("Directory") -| Unix.stats({ st_kind: Unix.S_LINK }) => print_endline("Link") -| Unix.stats({ st_kind: Unix.S_SOCK }) => print_endline("Socket") -| _ => print_endline("Something else") -}; - -Unix.closedir(current_dir); -``` - -There are a variety of kinds of files to switch on. Here, we are switching -on _Regular Files_, _Directories_, _Links_, and _Sockets_. Everything else -falls through. - -See the [`Unix` module docs](https://reasonml.github.io/api/Unix.html) for -more details. diff --git a/reason/making-things-mutable.md b/reason/making-things-mutable.md deleted file mode 100644 index f12fc22e..00000000 --- a/reason/making-things-mutable.md +++ /dev/null @@ -1,31 +0,0 @@ -# Making Things Mutable - -In [ReasonML](https://reasonml.github.io/en/), things that we create with -`let` are immutable -- which means that we can't change them. - -```reason -let num = 5; -``` - -Once `num` is _bound_ to `5` it is stuck with that value for the duration -of it's scope. - -ReasonML doesn't completely restrict us to immutability though. The -`ref` construct allows us to bind a variable to a sort of box that holds a -value. We can then look in the box and change what is in the box. - -```reason -let num = ref(5); /* put 5 in the box */ - -Js.log(num^); /* use `^` to look in the box */ - -num := 3; /* remove 5, put 3 in the box */ -``` - -We use `ref` to bind our variable to a box with some initial value. The `:=` -assignment operator allows us to change what's in the box. Anytime we want -to refer to what's in the box, we postfix our variable with `^`. - -Also of note: while `list` instances are not mutable, `array` instances are. - -[source](https://reasonml.github.io/docs/en/mutation) diff --git a/reason/modifying-a-string-with-blit-string.md b/reason/modifying-a-string-with-blit-string.md deleted file mode 100644 index fb98d13f..00000000 --- a/reason/modifying-a-string-with-blit-string.md +++ /dev/null @@ -1,25 +0,0 @@ -# Modifying A String With blit_string - -[ReasonML's `Bytes` module](https://reasonml.github.io/api/Bytes.html) has a -function called -[`blit_string`](https://reasonml.github.io/api/Bytes.html#VALblit_string). -This function allows you to copy portions of a string into a destination -byte sequence. It is a fairly low-level operation, so you have to provide a -source string and provide an offset of that source string to start copying -from. You then have to provide a properly sized byte sequence as well as the -destination's starting offset and length of bytes to be copied. - -Here is an example of how we can use `blit_string` to create a copy of the -string with the first character removed. - -```reason -let remove_first_char = (str: string): string => { - let copy_len = String.length(str) - 1; - let dst = Bytes.create(copy_len); - Bytes.blit_string(str, 1, dst, 0, copy_len); - Bytes.to_string(dst); -}; -``` - -Notice that once the byte sequence has been copied over, we then need to -convert it back into a string. diff --git a/reason/multi-argument-functions-as-syntactic-sugar.md b/reason/multi-argument-functions-as-syntactic-sugar.md deleted file mode 100644 index 3564e783..00000000 --- a/reason/multi-argument-functions-as-syntactic-sugar.md +++ /dev/null @@ -1,33 +0,0 @@ -# Multi-Argument Functions As Syntactic Sugar - -When writing a multi-argument function, like the following `adder` function: - -```reason -let adder = (x, y) => x + y; - -adder(2, 3); /* => 5 */ -``` - -We are utilizing a syntactic sugar of the function syntax. The same function -can be written as such: - -```reason -let adder = (x) => (y) => x + y; - -adder(2, 3); /* => 5 */ -``` - -As you can see, we can apply the function in the same way. - -This is useful because it means we can partially apply (or _curry_) our -functions to create other functions. - -```reason -let adder = (x, y) => x + y; -let twoAdder = adder(2); - -twoAdder(5); /* => 7 */ -``` - -[source -code](https://reasonml.github.io/en/try.html?reason=DYUwLgBAhgJjICcIF4IAoAeBKFA+dAnjsvhhANQQEDcAULQFIDOAdMAPYDmas8CaAFgA0EAKxYsdWqEhgA7uwCCcRCmgr+AJkn1mbLmnlKNacZKA) diff --git a/reason/pattern-match-on-exceptions.md b/reason/pattern-match-on-exceptions.md deleted file mode 100644 index ef8bff2d..00000000 --- a/reason/pattern-match-on-exceptions.md +++ /dev/null @@ -1,33 +0,0 @@ -# Pattern Match On Exceptions - -[ReasonML](https://reasonml.github.io/) supports [powerful pattern -matching](https://reasonml.github.io/docs/en/pattern-matching.html) through -the `switch` statement. This even includes pattern matching against -exceptions that may arise as a way of catching and handling those -exceptions. - -```reason -let values: list(int) = [1,3,5,7,9]; - -let getValue = (list, index) => { - switch (List.nth(values, index)) { - | value => value - | exception Failure("nth") => 0 - | exception Invalid_argument("List.nth") => 0 - }; -}; - -getValue(values, 0); /* 1 */ -getValue(values, 1); /* 3 */ -getValue(values, 5); /* 0 */ -getValue(values, -1); /* 0 */ -``` - -The [`List.nth` docs](https://reasonml.github.io/api/List.html) detail what -happens in the two kinds of out of bounds scenarios that would raise an -error -- `Failure` and `Invalid_argument`. You can pattern match against -those by declaring the respective cases as exception instances and then -returning the desired values in response. - -[source -code](https://reasonml.github.io/en/try.html?reason=DYUwLgBAbghsCuIDOAuCwCWSwAoMDswBKCAXggG0BGAGgGYaBWGgdhoE4BdAbgChfQkAObgAanERkIOTNhoQCAExAAPEqQB8EAN68IEJAHcMYAMYALaQBksYAHSFzOWAmTylqoiV36APtAkQMi0XRD0If1VTEAAHMAwAe3wIADEYDAQAJxAcACJHXPUtAAZwyJVouMTkgEl8FwxFAH0YTKF4AFsQQjybbAcwc0LgiFL9AF8+Sf4AKSQ7YAShHBEwcVdnQKR5Yq8+OYWllbFAzddtiCo93gPF5dX1xDPEC8Zr26OH09C3CABaK5EbhAA) diff --git a/reason/quickly-bootstrap-a-react-app-using-reason.md b/reason/quickly-bootstrap-a-react-app-using-reason.md deleted file mode 100644 index 2bfbce2c..00000000 --- a/reason/quickly-bootstrap-a-react-app-using-reason.md +++ /dev/null @@ -1,26 +0,0 @@ -# Quickly Bootstrap A React App Using Reason - -The ReasonML language and ecosystem is great for developing React apps. As -you might expect from the React community, there is a set of `reason-scripts` -for a ReasonML/React project which works similarly to the standard -[`create-react-app`](https://github.com/facebook/create-react-app) scripts. - -First, you need to install the [BuckleScript -platform](https://github.com/BuckleScript/bucklescript) and this must be -done using `npm`. - -```bash -$ npm install -g bs-platform -``` - -From there, it is a matter of using the [`yarn -create`](https://yarnpkg.com/lang/en/docs/cli/create/) command to generate a -React app that uses the aforementioned -[`reason-scripts`](https://yarnpkg.com/lang/en/docs/cli/create/). - -``` -$ yarn create react-app my-reason-react-app --scripts-version reason-scripts -``` - -Next steps from here are documented in the `README.md` and should be -familiar to anyone who has used `create-react-app` in the past. diff --git a/reason/seeding-and-generating-random-integers.md b/reason/seeding-and-generating-random-integers.md deleted file mode 100644 index 9d973d2d..00000000 --- a/reason/seeding-and-generating-random-integers.md +++ /dev/null @@ -1,23 +0,0 @@ -# Seeding And Generating Random Integers - -It is easy enough to generate a series of random numbers using the `Random` -module's `int` function. - -```reason -Random.int(10); -``` - -This will generate a random integer between 0 and 9. - -You may notice that the randomness is the same each time you run your -program. That is because you have fixed seed. To make sure you have a -different seed each time your program runs, you can initialize the random -number generator with something different at each run, such as the current -time. - -```reason -Random.init(int_of_float(Js.Date.now())); -``` - -See a [live example -here](https://reasonml.github.io/en/try.html?reason=EoQwdgJg9gtgdASzAgLgCiSg+lAZl3AGyhHQCkBnOAEVIFM4woB3NASg4G4AobyuYgHM0oSLERh0ARgAMXPlSEjw0eJjSz5-JaNUTpctj21Rhu8es1GFA08rFrJGw5yA). diff --git a/reason/stream-a-file-line-by-line.md b/reason/stream-a-file-line-by-line.md deleted file mode 100644 index 4af6d626..00000000 --- a/reason/stream-a-file-line-by-line.md +++ /dev/null @@ -1,32 +0,0 @@ -# Stream A File Line By Line - -We can use the `Stream` module in [ReasonML](https://reasonml.github.io/en) -to read a file getting each line on demand. Doing this requires two key -insights. First, we can open a file as an _input channel_. Second, we can -turn an input channel into a _stream_ using `Stream.from`. - -```reason -let file_in_channel = Pervasives.open_in('file.txt'); - -let file_stream = - Stream.from(_i => { - switch(Pervasives.input_line(file_in_channel)) { - | line => Some(line) - | exception(End_of_file) => None - }; - }); - -file_stream |> Stream.iter(line => do_something(line)); -``` - -The `Pervasives` module (which is open by default and is only prefixed above -so as to be explicit) allow us to open the named file as an input channel -with `open_in`. It also allows us to read lines off that file with -`input_line`. We use `Stream.from` to create a custom stream that consumes -the input channel line by line using `input_line`. We either get _some_ line -or we hit the end of the file. Lastly, we can do whatever we want with the -stream, such as iterate over it. - -See the docs for -[`Pervasives`](https://reasonml.github.io/api/Pervasives.html) and -[`Stream`](https://reasonml.github.io/api/Stream.html) for more details. diff --git a/reason/string-interpolation-with-integers-and-sprintf.md b/reason/string-interpolation-with-integers-and-sprintf.md deleted file mode 100644 index 1e58e186..00000000 --- a/reason/string-interpolation-with-integers-and-sprintf.md +++ /dev/null @@ -1,27 +0,0 @@ -# String Interpolation With Integers And Sprintf - -ReasonML's [`Printf`](https://reasonml.github.io/api/Printf.html) module -comes with a number of functions for formatting values of various types. The -`sprintf` function allows for string interpolation. - -```reason -let red = 64; -let green = 256; -let blue = 128; -let alpha = 1; - -let color = - Printf.sprintf("rbga(%i, %i, %i, %i)", red, green, blue, alpha); - -Js.log(color); -``` - -It functions the same as `fprintf` but instead of outputting the result to -some channel, it returns a string. It enforces type checking as well -- the -`%i` is specifically for integers, so using that with a type other than an -integer will result in a compilation error. - -See the [`Printf`](https://reasonml.github.io/api/Printf.html) docs for more -details. - -[source code](https://reasonml.github.io/en/try.html?reason=DYUwLgBATiAmEF4IDYAsBuAUKSBzGIAdohAEwCsyWOEARsAK4gkCMpAHNeBAIbAAOACx6ss2bgGMA9sClREmCBAAKUAJaEwAMwB0AZ37rNWgBQAiKLVw8TAUjUAaCPacvnagJRmnMWE-wgRE70TE58QjweYgBSejqyuCbSslBRQA) diff --git a/reason/string-interpolation-with-quoted-strings.md b/reason/string-interpolation-with-quoted-strings.md deleted file mode 100644 index 24ef0e2f..00000000 --- a/reason/string-interpolation-with-quoted-strings.md +++ /dev/null @@ -1,35 +0,0 @@ -# String Interpolation With Quoted Strings - -Stapling strings together with the `++` operator can be tedious and clunky. -If you have string variables that you'd like to interpolate, you can piece -them together much more easily using [quoted -strings](https://reasonml.github.io/docs/en/string-and-char.html#quoted-string). - -We can get close to a solution with the standard quoted string syntax. - -```reason -let greeting = (greetee) => { - {|Hello, $(greetee)!|} -}; - -Js.log(greeting("World")); // => "Hello, $(greetee)!" -``` - -This isn't quite right though. We have to take advantage of a preprocessing -hook provided by -[Bucklescript](https://bucklescript.github.io/docs/en/common-data-types.html#interpolation). -The `j` hook supports unicode and allows variable interpolation. - -```reason -let greeting = (greetee) => { - {j|Hello, $(greetee)!|j} -}; - -Js.log(greeting("World")); // => "Hello, World!" -``` - -To use this pre-processor we have to include `j` in the quoted string like -so `{j|...|j}`. - -See a [live example -here](https://reasonml.github.io/en/try.html?reason=DYUwLgBA5gTi4EsB2UIF4IApbzPAlOgHwQDeAUBGQFYA+AEiMMAPYA0EAJNnOAQIS1qAX3LCA3OXIApAM4A6VlB65kygEQB1FjGAATdfnzigA). diff --git a/reason/trying-out-reasonml-in-codesandbox.md b/reason/trying-out-reasonml-in-codesandbox.md deleted file mode 100644 index d0d37806..00000000 --- a/reason/trying-out-reasonml-in-codesandbox.md +++ /dev/null @@ -1,10 +0,0 @@ -# Trying Out ReasonML In CodeSandbox - -[CodeSandbox](https://codesandbox.io/) recently added support for a bunch of -new technologies. Among these is [ReasonML](https://reasonml.github.io/). - -To give ReasonML a try, visit this [template -link](https://codesandbox.io/s/reason). - -This is a [`reason-react`](https://reasonml.github.io/reason-react/) -template which allows you to write a React web app using ReasonML. diff --git a/reason/two-ways-to-find-an-item-in-a-list.md b/reason/two-ways-to-find-an-item-in-a-list.md deleted file mode 100644 index 2140a21a..00000000 --- a/reason/two-ways-to-find-an-item-in-a-list.md +++ /dev/null @@ -1,30 +0,0 @@ -# Two Ways To Find An Item In A List - -The `List` module has the typical `find` function that you'd expect any -enumerable type to include. It has a very similar `find_opt` function as -well. The difference is in the return types. - -When using `List.find` you'll have to deal with the possibility of a -`Not_found` exception. - -```reasonml -switch (List.find(item => item.id == id, my_list)) { -| exception Not_found => print_endline("Not found!") -| item => print_endline("Found it: " ++ item.name) -} -``` - -The `List.find_opt` function has a more familiar interface that doesn't -require you to know the details of what exceptions could arise. All you want -to know is if it was found or _not_. This is achieved by having an -`option('a)` return type. - -```reasonml -switch (List.find_opt(item => item.id == id, my_list)) { -| None => print_endline("Not found!") -| Some(item) => print_endline("Found it: " ++ item.name) -} -``` - -See the [`List` module](https://reasonml.github.io/api/List.html) for more -details. diff --git a/reason/using-optional-labeled-function-arguments.md b/reason/using-optional-labeled-function-arguments.md deleted file mode 100644 index ef61dc2b..00000000 --- a/reason/using-optional-labeled-function-arguments.md +++ /dev/null @@ -1,32 +0,0 @@ -# Using Optional Labeled Function Arguments - -If you are constructing a function that takes some arguments, but one of -those arguments has a reasonable default value, then you can use an optional -labeled argument. Labeled arguments are those arguments prefixed with a `~`. -If you give the argument a default value, then it becomes optional. - -```reason -let thing = (~a=1, b: int, c: int) => { - a + b + c; -}; -``` - -In this case `~a` is a labeled argument. It is also optional and will -default to `1` if not specified. The other two arguments, `b` and `c`, are -positional arguments and thus required in order for the function to -evaluate. - -Here are two ways of using this function either by specifying `~a` or -excluding it so that it defaults to `1`. - -```reason -thing(~a=2, 1, 1) -|> string_of_int -|> print_endline /* 4 */ - -thing(1, 1) -|> string_of_int -|> print_endline /* 3 */ -``` - -See more details [here](https://reasonml.github.io/docs/en/function). diff --git a/reason/wrapping-a-component-for-use-in-javascript.md b/reason/wrapping-a-component-for-use-in-javascript.md deleted file mode 100644 index 3db74783..00000000 --- a/reason/wrapping-a-component-for-use-in-javascript.md +++ /dev/null @@ -1,46 +0,0 @@ -# Wrapping A Component For Use In JavaScript - -Consider the following -[ReasonReact](https://reasonml.github.io/reason-react/en) component for -displaying a greeting. - -```reason -let component = ReasonReact.statelessComponent("Hello"); - -let make = (~name, _children) => { - ...component, - render: _self => -

{ReasonReact.string("Hello, ")} {ReasonReact.string(name)}

, -}; -``` - -If we will just be using this component in a ReasonML context, then that is -all we need. - -If we want this component available for use in a JavaScript file, we have a -little more work to do. We need to define the shape of the component's props -using a bucklescript directive and then wrap the component so that it gets -appropriate exported for a JavaScript context. - -Here is what that looks like. - -```reason -[@bs.deriving abstract] -type jsProps = {name: string}; - -let default = - ReasonReact.wrapReasonForJs(~component, jsProps => - make(~name=jsProps->nameGet, [||]) - ); -``` - -Our only prop is `name` which is a `string`. The `wrapReasonForJs` function -and accompanying binding to `default` mean that we can import the compiled -JS-equivalent like so: - -```javascript -import Hello from 'src/components/Hello.bs.js'; -``` - -See the [docs](https://reasonml.github.io/reason-react/docs/en/interop) for -more details on Reason/JS interop. diff --git a/streaming/monitor-an-audio-input-device-in-obs.md b/streaming/monitor-an-audio-input-device-in-obs.md deleted file mode 100644 index c9d2945d..00000000 --- a/streaming/monitor-an-audio-input-device-in-obs.md +++ /dev/null @@ -1,22 +0,0 @@ -# Monitor An Audio Input Device In OBS - -I hooked up a Mirabox HDMI capture card with loop out between my Xbox 360 and -display. It passes the feed through to my MacBook Pro. Both the video and audio -pass through cleanly to OBS and I've been streaming successfully to Twitch with -that setup. - -I then wanted to add my headphones and Blue Yeti microphone into the setup so -that I could hear the game audio and talk during the stream. - -Despite OBS picking up the audio through the Audio Input Device, I couldn't -hear it in my headphones. That's because by default _Audio Monitoring_ is -turned off for audio devices. - -If I want to be able to hear the sound and pass it through as output to OBS, I -have to change the _Audio Monitoring_ setting for that device. In the _Audio -Mixer_ section, there is a gear icon next to the audio device. I click that and -choose _Advanced Audio Properties_. From there, I change that device's Audio -Monitoring setting from _Monitor Off_ to _Monitor and Output_. - -Now I am able to hear the audio that is coming through Mirabox from my Xbox. -And anyone watching my stream can hear it too. diff --git a/vercel/add-web-server-layer-redirects.md b/vercel/add-web-server-layer-redirects.md deleted file mode 100644 index 8228dc5e..00000000 --- a/vercel/add-web-server-layer-redirects.md +++ /dev/null @@ -1,36 +0,0 @@ -# Add Web Server Layer Redirects - -People create links and bookmark URLs. Content, for a variety of reasons, has -to move from one place to another. For everyone's sake, you don't want to break -the URLs that people have come to rely on. - -You need to setup some -[redirects](https://vercel.com/docs/configuration#project/redirects). - -Though a [Next.js](https://nextjs.org/) app is just frontend code, when -distributed through [Vercel](https://vercel.com/), you can include some -configuration of the web server layer. - -Add the `vercel.json` file to the top-level directory of your Next.js project -and then include any needed redirect rules. - -```json -{ - "redirects": [ - { - "source": "blog/old-blog-post-name", - "destination": "blog/new-blog-post-name" - }, - { - "source": "/store", - "destination": "store.example.com" - } - ] -} -``` - -In the first rule, one path is redirected to another for the same domain. In -the second rule, the path is redirected to an external URL. - -By default, these redirects get a [308 status -code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/308). diff --git a/vercel/deploy-an-app-without-pushing-an-empty-commit.md b/vercel/deploy-an-app-without-pushing-an-empty-commit.md deleted file mode 100644 index b0b0d9ea..00000000 --- a/vercel/deploy-an-app-without-pushing-an-empty-commit.md +++ /dev/null @@ -1,25 +0,0 @@ -# Deploy An App Without Pushing An Empty Commit - -The [Vercel CLI](https://vercel.com/docs/cli) allows you to make updated -deployments of an app right from the command line. - -Many providers require you to push a new commit to the main branch to trigger a -deployment. If there are changes, you can trigger a deployment by pushing -these. If there aren't changes, but you want to re-deploy what is already -there, then you have to create an empty commit and push that. - -With the [Vercel CLI](https://vercel.com/docs/platform/deployments#vercel-cli), -you can re-deploy your app without pushing commits. You do this by including -the `--force` flag. - -To re-deploy the preview environment: - -```bash -$ vercel --force -``` - -To re-deploy the production environment: - -```bash -$ vercel --prod --force -``` diff --git a/vercel/naming-of-the-vercel-config-file.md b/vercel/naming-of-the-vercel-config-file.md deleted file mode 100644 index 72e8db4f..00000000 --- a/vercel/naming-of-the-vercel-config-file.md +++ /dev/null @@ -1,17 +0,0 @@ -# Naming Of The Vercel Config File - -[Vercel](https://vercel.com/), the company/service, used to be called Now. With -any renaming comes some consistency challenges, even at the level of software. - -The naming of the file for configuring your project used to be `now.json`. It -is _now_ `vercel.json`. - -For [backwards compatibility -reasons](https://vercel.com/docs/platform/frequently-asked-questions#conflicting-configuration-files), -you can still use either. You cannot and should not have both though. - -If you're working with an existing project that uses `now.json`. It is fine to -continue with that naming. It may eliminate some future confusion if you are to -rename it to `vercel.json`. If you're starting a new project, I'd recommend -using `vercel.json`. All the documentation you'll read uses this newer naming -convention. diff --git a/vercel/pin-specific-pnpm-version-for-builds.md b/vercel/pin-specific-pnpm-version-for-builds.md deleted file mode 100644 index adbd58ac..00000000 --- a/vercel/pin-specific-pnpm-version-for-builds.md +++ /dev/null @@ -1,35 +0,0 @@ -# Pin Specific pnpm Version For Builds - -Vercel recognizes when [a project contain a `pnpm-lock.yaml` -file](https://vercel.com/changelog/projects-using-pnpm-can-now-be-deployed-with-zero-configuration) -and will automatically use [`pnpm`](https://pnpm.io/) for builds of that -project. - -It looks for [the `lockfileVersion` in `pnpm-lock.yaml` to determine what major -version of `pnpm` to -install](https://vercel.com/docs/concepts/deployments/configure-a-build#install-command). -If the `lockfileVersion` is `5.4`, then it will use the latest pnpm v7. -Otherwise it will fallback to the latest pnpm v6. - -That's the extent of the control you have over the `pnpm` version. That is, -unless you are to use [this experimental corepack -feature](https://vercel.com/docs/concepts/deployments/configure-a-build#corepack). -Set the `ENABLE_EXPERIMENTAL_COREPACK` environment variable to `1` in your -project's _Environment Variables_ under _Settings_. - -Then specify the `pnpm` version with the `packageManager` key in your -`package.json`. - -```json -{ - "packageManager": "pnpm@7.13.2" -} -``` - -Even though the current latest is `7.13.5`, Vercel will see the Corepack -environment variables and the `packageManager` version and use `7.13.2` -instead. - -See [this PR](https://github.com/skillrecordings/products/pull/535) and [this -issue](https://github.com/prisma/prisma/issues/12921#issuecomment-1284425847) -for more details. diff --git a/vercel/share-development-environment-variables-via-cli.md b/vercel/share-development-environment-variables-via-cli.md deleted file mode 100644 index 19c5eebd..00000000 --- a/vercel/share-development-environment-variables-via-cli.md +++ /dev/null @@ -1,19 +0,0 @@ -# Share Development Environment Variables Via CLI - -[Vercel](https://vercel.com/)'s web UI as well as it's CLI make it easy to -store and manage environment variables for your different environments. It is -also safe because it encrypts them. - -You and your team can safely access the environment variables for the -development environment with the following CLI command. - -``` -$ vercel env pull -``` - -Assuming you have already connected with and authenticated yourself for the -current project, this command will fetch the env vars and write them to the -`.env` file. - -If the env vars are ever updated, you can run the command again and it will -rewrite the local file. diff --git a/webpack/better-module-imports-with-aliases.md b/webpack/better-module-imports-with-aliases.md deleted file mode 100644 index ff507d93..00000000 --- a/webpack/better-module-imports-with-aliases.md +++ /dev/null @@ -1,40 +0,0 @@ -# Better Module Imports With Aliases - -Depending on how your JavaScript project is structured, you can end up with -import statements that look like this: - -```javascript -import SomeComponent from 'app/assets/javascripts/components/SomeComponent.jsx'; -``` - -or this: - -```javascript -import SomeComponent from '../components/SomeComponent.jsx'; -``` - -The first is simply too long and the second is both ugly and brittle to -changes in file location. This can all be _resolved_ with a -[Webpack](https://webpack.github.io/) alias. - -```javascript -// webpack.config.js -resolve: { - alias: { - components: "app/assets/javascripts/components", - }, -}, -``` - -Webpack will use this `alias` when resolving module imports like the -following updated example: - -```javascript -import SomeComponent from 'components/SomeComponent.jsx'; -``` - -See the -[`resolve.alias`](https://webpack.github.io/docs/configuration.html#resolve-alias) -section of the Webpack docs for more details. - -h/t Vidal Ekechukwu diff --git a/webpack/debugging-with-full-source-maps.md b/webpack/debugging-with-full-source-maps.md deleted file mode 100644 index 1d5618c2..00000000 --- a/webpack/debugging-with-full-source-maps.md +++ /dev/null @@ -1,23 +0,0 @@ -# Debugging With Full Source Maps - -After Webpack runs your JavaScript through various loaders, it no longer -looks like the code you were writing in your editor. This can make debugging -difficult when you inspect the source of an error in the browser's devtools. -Fortunately, Webpack makes it easy to enhance debugging with full source -maps of your code. Just add the following option to your Webpack config: - -```javascript -{ - devtool: "source-map", - ... -} -``` - -This will generate a full source map with a filename that is something like -`bundle.js.map`. - -Note: this will slow down the webpack build process a bit. - -Read more about the `devtool` configuration and all the possible options in -the [Webpack -docs](https://webpack.github.io/docs/configuration.html#devtool). diff --git a/webpack/run-eslint-as-a-preloader.md b/webpack/run-eslint-as-a-preloader.md deleted file mode 100644 index bdd43ebb..00000000 --- a/webpack/run-eslint-as-a-preloader.md +++ /dev/null @@ -1,29 +0,0 @@ -# Run ESLint As A Preloader - -You may already be running [ESLint](http://eslint.org/) manually or as a -script command via `npm`. You can also include it as part of the Webpack -build process. By adding it as a *preloader*, Webpack will lint your -JavaScript files before running other loaders. The results of -linting will be reported in the terminal. Assuming you've already installed -`eslint` and set up your `.eslintrc` file, all you need to do is `npm -install --save-dev eslint-loader` and then add something like the following -to your `webpack.config.js` file: - -```javascript -module: { - preLoaders: [ - { - test: /\.js$/, - loaders: ['eslint'], - exclude: /node_modules/, - } - ], - ... -} -``` - -Running something like `webpack -w` will now lint your JavaScript before -running other loaders. - -Depending on your project, you may also want to include `babel-eslint` and -`eslint-plugin-react` with your setup. diff --git a/webpack/specify-port-of-cra-webpack-dev-server.md b/webpack/specify-port-of-cra-webpack-dev-server.md deleted file mode 100644 index 3310cbad..00000000 --- a/webpack/specify-port-of-cra-webpack-dev-server.md +++ /dev/null @@ -1,15 +0,0 @@ -# Specify Port Of CRA's Webpack Dev Server - -[`create-react-app`](https://github.com/facebookincubator/create-react-app) -gives you a set of scripts, one of which allows you to start a development -server that bundles and serves your javascript. This is handled under the -hood via `webpack-dev-server`. By default it attempts to serve from port -`3000`. If port `3000` is taken it will attempt to connect to another -sequential port. - -Alternatively, you can just specify the port when starting the development -server. This can be done with the `PORT` env var. - -```bash -$ PORT=3333 yarn start -``` diff --git a/webpack/use-a-specific-config-file.md b/webpack/use-a-specific-config-file.md deleted file mode 100644 index d7a714d2..00000000 --- a/webpack/use-a-specific-config-file.md +++ /dev/null @@ -1,12 +0,0 @@ -# Use A Specific Config File - -When running `webpack`, the default config file that it looks for is -`webpack.config.js`. If you have a project that uses different webpack -config files for different environments, you will need to specify which -config file webpack should use. The `--config` flag can be used with -`webpack` to specify that file. For instance, if you want to use your -production webpack config, run a command like the following: - -``` -$ webpack --config webpack.config.production.js -``` diff --git a/xstate/always-use-inline-functions-with-assign.md b/xstate/always-use-inline-functions-with-assign.md deleted file mode 100644 index a1d6ab9f..00000000 --- a/xstate/always-use-inline-functions-with-assign.md +++ /dev/null @@ -1,50 +0,0 @@ -# Always Use Inline Functions With Assign - -The [`assign` -action](https://xstate.js.org/docs/guides/context.html#assign-action) allows -you to update the context of the state machine. There are a couple ways to use -`assign`, but you should prefer the inline function style. - -Technically `assign` can be passed an object literal like so to set a static -value: - -```javascript -{ - actions: { - resetCount: assign({ - count: 0 - }) - } -} -``` - -However, this causes confusion for the TypeScript compiler and can create -surprising and unrelated type errors in the parts the code that use the -machine. - -To keep the compiler happy, you should instead use inline functions. Either -like this: - -```javascript -{ - actions: { - resetCount: assign((_context) => { - return { - count: 0 - } - }) - } -} -``` - -or like this: - -```javascript -{ - actions: { - resetCount: assign({ - count: (_context) => 0 - }) - } -} -``` diff --git a/xstate/custom-jest-matcher-for-xstate-machine-states.md b/xstate/custom-jest-matcher-for-xstate-machine-states.md deleted file mode 100644 index 799f11bd..00000000 --- a/xstate/custom-jest-matcher-for-xstate-machine-states.md +++ /dev/null @@ -1,62 +0,0 @@ -# Custom Jest Matcher For XState Machine States - -Here is a custom matcher for asserting the current state of an XState machine -for Jest-based tests. I made some adaptations to it, but it was mostly -developed by [Nick -Nisi](https://discord.com/channels/795785288994652170/809564635614150686/897559009077362738). - -```typescript -import {State} from 'xstate' - -declare global { - namespace jest { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - interface Matchers { - toMatchState(state: string): CustomMatcherResult - } - } -} - -expect.extend({ - toMatchState(state: State, value: string) { - return { - pass: state.matches(value), - message: () => - `Expected - "${JSON.stringify(state.value)}" -state to match - "${JSON.stringify(value)}"`, - } - }, -}) -``` - -To make this available to your tests, place it in your `setupTests.ts` (or -`.js`) file, assuming that is configured in your `jest.config.js`. - -It can be used in your tests like so: - -```javascript -test("it transitions to open and back to closed", async () => { - const service = interpret(confirmationMachine); - - service.start(); - - service.send({ - type: "OPEN_DIALOG", - doubleConfirmText: "taco", - action: jest.fn() - }); - - expect(service.state).toMatchState({ open: "idle" }) - - service.send({ type: "CANCEL" }); - - expect(service.state).toMatchState("closed") -}); -``` - -Notice you can pass either a string or object representation of the state, if -there is nesting. - -What is nice about this custom matcher is the informative failure messaging. diff --git a/xstate/define-event-that-does-internal-self-transition.md b/xstate/define-event-that-does-internal-self-transition.md deleted file mode 100644 index 9637af53..00000000 --- a/xstate/define-event-that-does-internal-self-transition.md +++ /dev/null @@ -1,69 +0,0 @@ -# Define Event That Does Internal Self Transition - -An XState `state` can contain a state transition in the `on` object that -represents a [_self -transition_](https://xstate.js.org/docs/guides/transitions.html#self-transitions). -A self transition means that the state points to itself. In response to that -event, it will transition directly to itself, instead of to another state node. - -An -[_internal_](https://xstate.js.org/docs/guides/transitions.html#internal-transitions) -self transition is one in which the transition occurs, but it never _exits_ its -state node. That means `entry` and `exit` actions won't be triggered. - -The parent state node can transition directly to itself or to a child node. -Here are a couple ways to define internal self transitions directly to the -parent node. - -1. Implicit - -``` -states: { - counting: { - on: { - INCREMENT: { - actions: ['incrementCount'], - }, - }, - }, -}, -``` - -No `target` is declared for `INCREMENT`, so an internal, self-transition is -implicit. - -2. Explicit - -``` -states: { - counting: { - on: { - INCREMENT: { - internal: true, - actions: ['incrementCount'], - }, - }, - }, -}, -``` - -This says that the transition should be an `internal` one. - -3. Undefined Target - -``` -states: { - counting: { - on: { - INCREMENT: { - target: undefined, - actions: ['incrementCount'], - }, - }, - }, -}, -``` - -An undefined target is an internal, self-transition. - -[source](https://dev.to/jbranchaud/1-7-gui-tasks-with-react-and-xstate-counter-4l9i) diff --git a/xstate/events-stop-propagating-once-handled.md b/xstate/events-stop-propagating-once-handled.md deleted file mode 100644 index e5a69c7e..00000000 --- a/xstate/events-stop-propagating-once-handled.md +++ /dev/null @@ -1,54 +0,0 @@ -# Events Stop Propagating Once Handled - -In a hierarchical (or nested) XState machine, events are sent to the inner most sub-state of -the current state. If that state handles the event, then it won't propagate up -to parent states. If a state receives an event that it doesn't handle, that -event will propagate up to parent states until it is handled or there is -nothing to handle it. - -Let's look at an example. - -```javascript -{ - initial: "active", - context: { count: 0 }, - states: { - active: { - on: { - COUNT: { - actions: "changeCount", - }, - }, - initial: "increment", - states: { - increment: { - on: { - SWITCH_COUNT_DIRECTION: "decrement", - }, - }, - decrement: { - on: { - SWITCH_COUNT_DIRECTION: "increment", - COUNT: { - actions: 'logEvent' - }, - }, - }, - }, - }, - }, -}; -``` - -This machine starts in the `active.increment` state. - -If I send the `COUNT` event, it will first go to the `active.increment` state. -It isn't handled there, so it will propagate up to `active` where it is -handled. - -Now let's say I transition to `active.decrement`. If I send the `COUNT` event, -it will first go to `active.decrement` where it is handled. The `logEvent` -action happens and then the event stops. The `active` state does not receive -nor handle the `COUNT` event. - -[source](https://twitter.com/jbrancha/status/1418269852398129152?s=20) diff --git a/xstate/inline-actions-vs-actions-in-machine-options.md b/xstate/inline-actions-vs-actions-in-machine-options.md deleted file mode 100644 index 0bd908ca..00000000 --- a/xstate/inline-actions-vs-actions-in-machine-options.md +++ /dev/null @@ -1,61 +0,0 @@ -# Inline Actions vs Actions In Machine Options - -When first spec'ing out a machine, I find it easiest to add my on-transition -actions directly inline. - -```javascript -const countingMachine = createMachine({ - initial: "counting", - context: { count: 0 }, - states: { - counting: { - on: { - INCREMENT: { - actions: assign({ - count: (context) => context.count + 1, - }), - }, - }, - }, - }, -}); -``` - -This is not what the XState docs recommend once you move beyond prototyping -your machine. - -> It is not recommended to keep the machine config like this in production -> code, as this makes it difficult to debug, serialize, test, and accurately -> visualize actions. - -When you're ready, you can refactor this by referencing the action by name and -then moving the action declaration to the `actions` object of the machine -options (second argument to `createMachine`). - -```javascript -const countingMachine = createMachine({ - initial: "counting", - context: { count: 0 }, - states: { - counting: { - on: { - INCREMENT: { - actions: 'incrementCount', - }, - }, - }, - }, -}, -{ - actions: { - incrementCount: assign({ - count: (context) => context.count + 1, - }), - }, -}); -``` - -When the machine interpreter sees `'incrementCount'`, it knows to look for an -action by that name in the machine options. - -[source](https://xstate.js.org/docs/guides/actions.html) diff --git a/xstate/make-immediate-and-delayed-transitions.md b/xstate/make-immediate-and-delayed-transitions.md deleted file mode 100644 index aa38d076..00000000 --- a/xstate/make-immediate-and-delayed-transitions.md +++ /dev/null @@ -1,48 +0,0 @@ -# Make Immediate And Delayed Transitions - -An [XState](https://xstate.js.org/docs/) state can define an `on` key with an -object. The object can define one or more events that the state listens for and -transitions in response to. In addition to transitioning in response to an -event, you can have a state do both _immediate_ and _delayed_ transitions. - -Here is an example state machine. - -```javascript -export const loadingSpinner = createMachine( - { - initial: 'pending', - context: {}, - states: { - pending: { - always: [ - { target: 'loading' } - ] - }, - loading: { - after: { - 5000: { target: 'done' } - } - }, - done: { - final: true - } - } - } -); -``` - -This machine will start in the `pending` state. The `always` object will -immediately fire which will trigger a transition to the `loading` state. There -the `after` object will schedule a transition to the `done` state to happen in -5 seconds (5000ms). - -The -[`always`](https://xstate.js.org/docs/guides/transitions.html#eventless-always-transitions) -is the immediate transition. The -[`after`](https://xstate.js.org/docs/guides/delays.html#delayed-transitions) is -the delayed transition. - -The "eventless" `always` transition, in practice, is more useful when combined -with a condition. That allows you to define an immediate transition that only -takes place if some condition has already been met (e.g. does the `context` -already contain the thing we were about to look up?). diff --git a/xstate/simple-states-and-composite-states.md b/xstate/simple-states-and-composite-states.md deleted file mode 100644 index 4d3d8909..00000000 --- a/xstate/simple-states-and-composite-states.md +++ /dev/null @@ -1,52 +0,0 @@ -# Simple States And Composite States - -XState allows you to build [hierarchical state -machines](https://xstate.js.org/docs/guides/hierarchical.html). A hierarchical -state machine is one where there are substates nested under states. - -States with nothing nested under them are _simple states_. States that have -substates are _composite states_. - -```javascript -const machine = createMachine({ - // Starting State - initial: "active", - // Starting Context - context: { count: 0 }, - // States - states: { - inactive: { - always: { target: "active" }, - }, - active: { - on: { - SWITCH_COUNT_DIRECTION: { - actions: ["logSwitch", "consoleLogSwitch"], - }, - COUNT: { - actions: "changeCount", - }, - }, - initial: "increment", - states: { - increment: { - on: { - SWITCH_COUNT_DIRECTION: "decrement", - }, - }, - decrement: { - on: { - SWITCH_COUNT_DIRECTION: "increment", - }, - }, - }, - }, - }, -}); -``` - -- The `inactive` state is a _simple state_. There is nothing nested under it. -- The `active` state is a _composite state_. There are two substates - (`increment` and `decrement`) nested under it. -- The `increment` and `decrement` states are both _simple states_. Nothing is - nested under them. diff --git a/xstate/start-a-machine-in-a-specific-state.md b/xstate/start-a-machine-in-a-specific-state.md deleted file mode 100644 index b340b3e0..00000000 --- a/xstate/start-a-machine-in-a-specific-state.md +++ /dev/null @@ -1,37 +0,0 @@ -# Start A Machine In A Specific State - -For testing (or debugging) purposes, it can be handy to get an XState machine -running from a specific state. - -Let's say a machine has an initial state of `green` and the other states it can -be in are `yellow` and `red`. And `yellow` has sub-states of `walk` and -`hurry`. - -By default, a machine will start in the specified initial state. - -```javascript -const service = interpret(trafficLightMachine); - -service.start(); - -service.state.value; //=> 'green' -``` - -We can tell the traffic light service to start in the `red` state instead. - -```javascript -service.start('red'); - -service.state.value; //=> 'red' -``` - -We can even tell it to start in a sub-state (nested state) of a particular -state. - -```javascript -service.start({ yellow: 'hurry' }); - -service.state.value; //=> { yellow: 'hurry' } -``` - -[source](https://xstate.js.org/docs/guides/interpretation.html#starting-and-stopping) diff --git a/xstate/use-an-xstate-machine-with-react.md b/xstate/use-an-xstate-machine-with-react.md deleted file mode 100644 index 207d4121..00000000 --- a/xstate/use-an-xstate-machine-with-react.md +++ /dev/null @@ -1,50 +0,0 @@ -# Use An XState Machine With React - -There are a bunch of well-constructed XState machines available to directly -copy into your project from [XState Catalogue](https://xstate-catalogue.com/). -For instance, I can grab the [Confirmation Dialog -machine](https://xstate-catalogue.com/machines/confirmation-dialog) and paste -it into `confirmMachine.js`. Then I can grab -[`@xstate/react`](https://xstate.js.org/docs/packages/xstate-react/) which -comes with a `useMachine` hook. - -```javascript -import * as React from "react"; -import { useMachine } from "@xstate/react"; -import confirmMachine from "./confirmMachine"; -import Dialog from "./dialog"; - -export default function App() { - const [current, send] = useMachine(confirmMachine); - - const deleteAction = () => { /* ... */ }; - - const showDialog = current.value !== "closed"; - const open = () => { - send({ type: "OPEN_DIALOG", action: deleteAction }); - }; - const close = () => { - send("CANCEL"); - }; - const confirm = () => { - send("CONFIRM"); - }; - - return ( -
- - {/* other stuff */} -
- ) -} -``` - -The `useMachine` call both interprets and starts up the machine service. The -`current` value is everything about the _current_ state of the machine. The -`send` is a function for dispatching transitions between machine states. From 41f5812b11b3fd175ed4f233f8312f00cc3b3496 Mon Sep 17 00:00:00 2001 From: Timur Yalcin Date: Wed, 20 Nov 2024 21:11:27 +0100 Subject: [PATCH 2/2] rails controller --- rails/controller-rest.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 rails/controller-rest.md diff --git a/rails/controller-rest.md b/rails/controller-rest.md new file mode 100644 index 00000000..0b6f1bc3 --- /dev/null +++ b/rails/controller-rest.md @@ -0,0 +1,21 @@ +# Vortrag zum Thema Rest in controllern + +- Resource and Actions +- als erstes routes.rb öffnen, zeigt viel über die App +- Anti Pattern Complex Actions + +[Vortrag RailsConf 2017: In Relentless Pursuit of REST by Derek Prior 36:18](https://www.youtube.com/watch?v=HctYHe-YjnE&ab_channel=Confreaks) + + +```ruby +users#edit_password +users#update_password +noun#verb_noun +``` + +Hier müsste es heissen. Password ist die Resource => noun. Es muss nicht unbedingt ein Model sein. Das Argument das ist keinen neuen Controller wert, ist kein gutes. Es muss nicht immer eine 1:1 Beziehung zwischen Controller und Model sein. + +```ruby +passwords#edit +passwords#update +```