mirror of
https://github.com/jbranchaud/til
synced 2026-03-05 07:28:46 +00:00
Compare commits
1 Commits
059eafdca2
...
179ec70c2f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
179ec70c2f |
14
README.md
14
README.md
@@ -10,11 +10,7 @@ pairing with smart people at Hashrocket.
|
|||||||
|
|
||||||
For a steady stream of TILs, [sign up for my newsletter](https://crafty-builder-6996.ck.page/e169c61186).
|
For a steady stream of TILs, [sign up for my newsletter](https://crafty-builder-6996.ck.page/e169c61186).
|
||||||
|
|
||||||
_1555 TILs and counting..._
|
_1552 TILs and counting..._
|
||||||
|
|
||||||
See some of the other learning resources I work on:
|
|
||||||
- [Ruby Operator Lookup](https://www.visualmode.dev/ruby-operators)
|
|
||||||
- [Vim Un-Alphabet](https://www.youtube.com/playlist?list=PL46-cKSxMYYCMpzXo6p0Cof8hJInYgohU)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -407,11 +403,9 @@ See some of the other learning resources I work on:
|
|||||||
|
|
||||||
- [Access Go Docs Offline](go/access-go-docs-offline.md)
|
- [Access Go Docs Offline](go/access-go-docs-offline.md)
|
||||||
- [Add A Method To A Struct](go/add-a-method-to-a-struct.md)
|
- [Add A Method To A Struct](go/add-a-method-to-a-struct.md)
|
||||||
- [Basic Delve Debugging Session](go/basic-delve-debugging-session.md)
|
|
||||||
- [Build For A Specific OS And Architecture](go/build-for-a-specific-os-and-architecture.md)
|
- [Build For A Specific OS And Architecture](go/build-for-a-specific-os-and-architecture.md)
|
||||||
- [Check If Cobra Flag Was Set](go/check-if-cobra-flag-was-set.md)
|
- [Check If Cobra Flag Was Set](go/check-if-cobra-flag-was-set.md)
|
||||||
- [Combine Two Slices](go/combine-two-slices.md)
|
- [Combine Two Slices](go/combine-two-slices.md)
|
||||||
- [Connect To A SQLite Database](go/connect-to-a-sqlite-database.md)
|
|
||||||
- [Create A Slice From An Array](go/create-a-slice-from-an-array.md)
|
- [Create A Slice From An Array](go/create-a-slice-from-an-array.md)
|
||||||
- [Detect If Stdin Comes From A Redirect](go/detect-if-stdin-comes-from-a-redirect.md)
|
- [Detect If Stdin Comes From A Redirect](go/detect-if-stdin-comes-from-a-redirect.md)
|
||||||
- [Deterministically Seed A Random Number Generator](go/deterministically-seed-a-random-number-generator.md)
|
- [Deterministically Seed A Random Number Generator](go/deterministically-seed-a-random-number-generator.md)
|
||||||
@@ -1275,7 +1269,6 @@ See some of the other learning resources I work on:
|
|||||||
- [Iterate With An Offset Index](ruby/iterate-with-an-offset-index.md)
|
- [Iterate With An Offset Index](ruby/iterate-with-an-offset-index.md)
|
||||||
- [Include Extra Context In A Honeybadger Notify](ruby/include-extra-context-in-a-honeybadger-notify.md)
|
- [Include Extra Context In A Honeybadger Notify](ruby/include-extra-context-in-a-honeybadger-notify.md)
|
||||||
- [Ins And Outs Of Pry](ruby/ins-and-outs-of-pry.md)
|
- [Ins And Outs Of Pry](ruby/ins-and-outs-of-pry.md)
|
||||||
- [Install Latest Version Of Ruby With asdf](ruby/install-latest-version-of-ruby-with-asdf.md)
|
|
||||||
- [Invoking Rake Tasks Multiple Times](ruby/invoking-rake-tasks-multiple-times.md)
|
- [Invoking Rake Tasks Multiple Times](ruby/invoking-rake-tasks-multiple-times.md)
|
||||||
- [IRB Has Built-In Benchmarking With Ruby 3](ruby/irb-has-built-in-benchmarking-with-ruby-3.md)
|
- [IRB Has Built-In Benchmarking With Ruby 3](ruby/irb-has-built-in-benchmarking-with-ruby-3.md)
|
||||||
- [Jump Out Of A Nested Context With Throw/Catch](ruby/jump-out-of-a-nested-context-with-throw-catch.md)
|
- [Jump Out Of A Nested Context With Throw/Catch](ruby/jump-out-of-a-nested-context-with-throw-catch.md)
|
||||||
@@ -1308,7 +1301,6 @@ See some of the other learning resources I work on:
|
|||||||
- [Question Mark Operator](ruby/question-mark-operator.md)
|
- [Question Mark Operator](ruby/question-mark-operator.md)
|
||||||
- [Rake Only Lists Tasks With Descriptions](ruby/rake-only-lists-tasks-with-descriptions.md)
|
- [Rake Only Lists Tasks With Descriptions](ruby/rake-only-lists-tasks-with-descriptions.md)
|
||||||
- [Read The First Line From A File](ruby/read-the-first-line-from-a-file.md)
|
- [Read The First Line From A File](ruby/read-the-first-line-from-a-file.md)
|
||||||
- [Refer To Implicit Block Argument With It](ruby/refer-to-implicit-block-argument-with-it.md)
|
|
||||||
- [Rendering ERB](ruby/rendering-erb.md)
|
- [Rendering ERB](ruby/rendering-erb.md)
|
||||||
- [Replace The Current Process With An External Command](ruby/replace-the-current-process-with-an-external-command.md)
|
- [Replace The Current Process With An External Command](ruby/replace-the-current-process-with-an-external-command.md)
|
||||||
- [Require Entire Gemfile In Pry Session](ruby/require-entire-gemfile-in-pry-session.md)
|
- [Require Entire Gemfile In Pry Session](ruby/require-entire-gemfile-in-pry-session.md)
|
||||||
@@ -1864,11 +1856,11 @@ I shamelessly stole this idea from
|
|||||||
|
|
||||||
* [Today I Learned by Hashrocket](https://til.hashrocket.com)
|
* [Today I Learned by Hashrocket](https://til.hashrocket.com)
|
||||||
* [jwworth/til](https://github.com/jwworth/til)
|
* [jwworth/til](https://github.com/jwworth/til)
|
||||||
* [til.simonwillison.net](https://til.simonwillison.net/)
|
* [thoughtbot/til](https://github.com/thoughtbot/til)
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
© 2015-2025 Josh Branchaud
|
© 2015-2022 Josh Branchaud
|
||||||
|
|
||||||
This repository is licensed under the MIT license. See `LICENSE` for
|
This repository is licensed under the MIT license. See `LICENSE` for
|
||||||
details.
|
details.
|
||||||
|
|||||||
@@ -1,63 +0,0 @@
|
|||||||
# Basic Delve Debugging Session
|
|
||||||
|
|
||||||
When using [delve](https://github.com/go-delve/delve) to debug a Go program,
|
|
||||||
these are the series of things I usually find myself doing.
|
|
||||||
|
|
||||||
First, I start running the program with `dlv` including any arguments after a `--` (in my case, the `solve` subcommand and a filename).
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ dlv debug . -- solve samples/001.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
`dlv` starts up and is ready to run my program from the beginning. I'll need to
|
|
||||||
set a couple breakpoints before continuing. I do this with the `break` command,
|
|
||||||
specifying the filename and line number.
|
|
||||||
|
|
||||||
```
|
|
||||||
(dlv) break main.go:528
|
|
||||||
Breakpoint 1 set at 0x10c1a5bea for main.traversePuzzleIterative() ./main.go:528
|
|
||||||
(dlv) break main.go:599
|
|
||||||
Breakpoint 2 set at 0x10c1a6dcc for main.traversePuzzleIterative() ./main.go:599
|
|
||||||
```
|
|
||||||
|
|
||||||
Now I can continue which will run the program until hitting a breakpoint.
|
|
||||||
|
|
||||||
```
|
|
||||||
(dlv) continue
|
|
||||||
> [Breakpoint 2] main.traversePuzzleIterative() ./main.go:599 (hits goroutine(1):1 total:1) (PC: 0x10c1a6dcc)
|
|
||||||
594: }
|
|
||||||
595: }
|
|
||||||
596:
|
|
||||||
597: topStackFrame := stack[len(stack)-1]
|
|
||||||
598: // if the current stack frame has more values, try the next
|
|
||||||
=> 599: if len(topStackFrame.PossibleValues) > 0 {
|
|
||||||
600: nextValue := topStackFrame.PossibleValues[0]
|
|
||||||
601: topStackFrame.PossibleValues = topStackFrame.PossibleValues[1:]
|
|
||||||
602: topStackFrame.CurrValue = nextValue
|
|
||||||
603:
|
|
||||||
604: // Undo the last placement and make a new one
|
|
||||||
```
|
|
||||||
|
|
||||||
I can see the context around the line we've stopped on. From here I can dig
|
|
||||||
into the current state of the program by looking at local variables (`locals`)
|
|
||||||
or printing out a specific value (`print someVar`). I can continue to step
|
|
||||||
through the program line by line with `next` or eventually run `continue` to
|
|
||||||
proceed to the next breakpoint.
|
|
||||||
|
|
||||||
```
|
|
||||||
(dlv) locals
|
|
||||||
diagnostics = main.Diagnostics {BacktrackCount: 0, NodeVisitCount: 1, ValidityCheckCount: 2,...+2 more}
|
|
||||||
stack = []main.StackData len: 1, cap: 1, [...]
|
|
||||||
emptyCellPositions = [][]int len: 3, cap: 4, [...]
|
|
||||||
emptyCellIndex = 1
|
|
||||||
status = "Invalid"
|
|
||||||
topStackFrame = main.StackData {RowIndex: 1, ColumnIndex: 7, PossibleValues: []int len: 8, cap: 8, [...],...+1 more}
|
|
||||||
(dlv) print topStackFrame
|
|
||||||
main.StackData {
|
|
||||||
RowIndex: 1,
|
|
||||||
ColumnIndex: 7,
|
|
||||||
PossibleValues: []int len: 8, cap: 8, [2,3,4,5,6,7,8,9],
|
|
||||||
CurrValue: 1,}
|
|
||||||
(dlv) next
|
|
||||||
> main.traversePuzzleIterative() ./main.go:600 (PC: 0x10c1a6dea)
|
|
||||||
```
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
# Connect To A SQLite Database
|
|
||||||
|
|
||||||
Using the `database/sql` module and the `github.com/mattn/go-sqlite3` package,
|
|
||||||
we can connect to a SQLite database and run some queries. In my case, I have a
|
|
||||||
SQLite connection string exported to my environment, so I can access that with
|
|
||||||
`os.Getenv`. It's a local SQLite file, `./test.db`.
|
|
||||||
|
|
||||||
Calling `sql.Open`, I'm able to connect with a SQLite3 driver to the database
|
|
||||||
at that connection string. The `setupDatabase` function returns that database
|
|
||||||
connection pointer. Things like `Exec` and `QueryRow` can be called on `db`. I
|
|
||||||
also need to make sure I close the connection to the database with a `defer`.
|
|
||||||
|
|
||||||
Here is a full example of connecting to a local SQLite database and inserting a
|
|
||||||
record:
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
_ "github.com/mattn/go-sqlite3"
|
|
||||||
)
|
|
||||||
|
|
||||||
func setupDatabase() *sql.DB {
|
|
||||||
databaseString := os.Getenv("GOOSE_DBSTRING")
|
|
||||||
if len(databaseString) == 0 {
|
|
||||||
fmt.Println("Error retrieving `GOOSE_DBSTRING` from env")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
db, err := sql.Open("sqlite3", databaseString)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error opening database: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return db
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
db := setupDatabase()
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
sql := `insert into users (name) values (?);`
|
|
||||||
|
|
||||||
db.Exec(sql, "Josh")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
# Install Latest Version Of Ruby With asdf
|
|
||||||
|
|
||||||
When I check the `asdf` Ruby plugin for known versions of Ruby:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ asdf list-all ruby | fzf
|
|
||||||
```
|
|
||||||
|
|
||||||
I don't find the latest (`3.4`).
|
|
||||||
|
|
||||||
I need to update the plugin. A newer version of the plugin will know about
|
|
||||||
newer Ruby versions.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ asdf plugin-update ruby
|
|
||||||
```
|
|
||||||
|
|
||||||
Now, if I run the `list-all` command again, I'll find the version I'm looking
|
|
||||||
for — `3.4.1`.
|
|
||||||
|
|
||||||
Now that `asdf` and I both know about the version to be installed, I can tell
|
|
||||||
`asdf` to install it:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ asdf install ruby 3.4.1
|
|
||||||
```
|
|
||||||
|
|
||||||
Now, if I check the current Ruby version, I'll see that it is still set to some
|
|
||||||
other version.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ ruby --version
|
|
||||||
ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-darwin22]
|
|
||||||
```
|
|
||||||
|
|
||||||
I need to tell `asdf` to start using this newly installed version instead,
|
|
||||||
either globally or locally.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ # globally
|
|
||||||
$ asdf global ruby 3.4.1
|
|
||||||
$ # or locally
|
|
||||||
$ asdf local ruby 3.4.1
|
|
||||||
```
|
|
||||||
|
|
||||||
And now I'm all set:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ asdf current ruby
|
|
||||||
ruby 3.4.1 /Users/jbranchaud/.tool-versions
|
|
||||||
|
|
||||||
$ ruby --version
|
|
||||||
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-darwin22]
|
|
||||||
```
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
# Refer To Implicit Block Argument With It
|
|
||||||
|
|
||||||
One of the key features of the Ruby 3.4 release is the `it` implicit block
|
|
||||||
argument.
|
|
||||||
|
|
||||||
The vast majority of inline blocks defined in Ruby code receive a single block
|
|
||||||
argument. Typically we name and reference a block argument explictly like so:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
items.map { |item| item * item }
|
|
||||||
```
|
|
||||||
|
|
||||||
Ruby likes to cut away excess syntax when possible. To that end, the implicit
|
|
||||||
`it` block argument has been added. This is an identifier we can reference in
|
|
||||||
the context of a block and its value is the current
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
items = [1,2,3,4,5]
|
|
||||||
|
|
||||||
squares = items.map { it * it }
|
|
||||||
|
|
||||||
pp squares
|
|
||||||
#=> [1, 4, 9, 16, 25]
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: we cannot mix numbered parameters (`_1`, `_2`) with the `it` parameter.
|
|
||||||
If we do, we'll get the following error:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
def method_using_block(a, b)
|
|
||||||
yield(a, b) if block_given?
|
|
||||||
end
|
|
||||||
|
|
||||||
puts method_using_block(4,5) { _2 ** _1 } #=> 625
|
|
||||||
puts method_using_block(4,5) { _2 ** it }
|
|
||||||
# it_block.rb:12: syntax error found (SyntaxError)
|
|
||||||
# 10 |
|
|
||||||
# 11 | puts method_using_block(4,5) { _2 ** _1 }
|
|
||||||
# > 12 | ... it }
|
|
||||||
# | ^~ `it` is not allowed when a numbered parameter is already used
|
|
||||||
```
|
|
||||||
|
|
||||||
[source](https://docs.ruby-lang.org/en/3.4/NEWS_md.html)
|
|
||||||
Reference in New Issue
Block a user