1
0
mirror of https://github.com/jbranchaud/til synced 2026-01-20 15:38:02 +00:00

Compare commits

...

8 Commits

Author SHA1 Message Date
Nuno Vieira
6984685276 Merge 460473a87f into 877537228f 2024-11-16 17:08:36 +01:00
jbranchaud
877537228f Add Gracefully Exit A Script With Trap as a Unix TIL 2024-11-15 19:55:22 -06:00
jbranchaud
1513611857 Add Execute Several Commands With Backtick Heredoc as a Ruby TIL 2024-11-14 23:47:07 -06:00
jbranchaud
74514b462d Add a caveat to the latest TIL 2024-11-13 20:31:25 -06:00
jbranchaud
484dec8e24 Add Empty find_by Returns First Record as a Rails TIL 2024-11-13 20:24:59 -06:00
jbranchaud
8574113dc6 Add Dunder Methods as a Python TIL 2024-11-12 17:45:53 -06:00
jbranchaud
1c4e37ed8a Add Count All Files Of Specific Type Tracked By Git as a Git TIL 2024-11-11 20:15:43 -06:00
Nuno Vieira
460473a87f Fix expected result of immutable remove operation 2020-07-30 14:32:08 +01:00
7 changed files with 173 additions and 5 deletions

View File

@@ -10,7 +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).
_1503 TILs and counting..._
_1508 TILs and counting..._
---
@@ -297,6 +297,7 @@ _1503 TILs and counting..._
- [Configure Global gitignore File](git/configure-global-gitignore-file.md)
- [Configuring The Pager](git/configuring-the-pager.md)
- [Copy A File From Another Branch](git/copy-a-file-from-another-branch.md)
- [Count All Files Of Specific Type Tracked By Git](git/count-all-files-of-specific-type-tracked-by-git.md)
- [Create A New Branch With Git Switch](git/create-a-new-branch-with-git-switch.md)
- [Delete All Untracked Files](git/delete-all-untracked-files.md)
- [Determine The Hash Id For A Blob](git/determine-the-hash-id-for-a-blob.md)
@@ -886,6 +887,7 @@ _1503 TILs and counting..._
- [Access Instance Variables](python/access-instance-variables.md)
- [Create A Dummy DataFrame In Pandas](python/create-a-dummy-dataframe-in-pandas.md)
- [Dunder Methods](python/dunder-methods.md)
- [Store And Access Immutable Data In A Tuple](python/store-and-access-immutable-data-in-a-tuple.md)
- [Test A Function With Pytest](python/test-a-function-with-pytest.md)
- [Use pipx To Install End User Apps](python/use-pipx-to-install-end-user-apps.md)
@@ -940,6 +942,7 @@ _1503 TILs and counting..._
- [Demodulize A Class Name](rails/demodulize-a-class-name.md)
- [Different Ways To Add A Foreign Key Reference](rails/different-ways-to-add-a-foreign-key-reference.md)
- [Disambiguate Where In A Joined Relation](rails/disambiguate-where-in-a-joined-relation.md)
- [Empty find_by Returns First Record](rails/empty-find-by-returns-first-record.md)
- [Ensure A Rake Task Cannot Write Data](rails/ensure-a-rake-task-cannot-write-data.md)
- [Ensure Migrations Use The Latest Schema](rails/ensure-migrations-use-the-latest-schema.md)
- [Ensure Record Saved With after_commit Callback](rails/ensure-record-saved-with-after-commit-callback.md)
@@ -1208,6 +1211,7 @@ _1503 TILs and counting..._
- [Enumerate A Pairing Of Every Two Sequential Items](ruby/enumerate-a-pairing-of-every-two-sequential-items.md)
- [Evaluating One-Off Commands](ruby/evaluating-one-off-commands.md)
- [Exclude Values From An Array](ruby/exclude-values-from-an-array.md)
- [Execute Several Commands With Backtick Heredoc](ruby/execute-several-commands-with-backtick-heredoc.md)
- [Exit A Process With An Error Message](ruby/exit-a-process-with-an-error-message.md)
- [Expect A Method To Be Called And Actually Call It](ruby/expect-a-method-to-be-called-and-actually-call-it.md)
- [Extract A Column Of Data From A CSV File](ruby/extract-a-column-of-data-from-a-csv-file.md)
@@ -1461,6 +1465,7 @@ _1503 TILs and counting..._
- [Global Substitution On The Previous Command](unix/global-substitution-on-the-previous-command.md)
- [Globbing For All Directories In Zsh](unix/globbing-for-all-directories-in-zsh.md)
- [Globbing For Filenames In Zsh](unix/globbing-for-filenames-in-zsh.md)
- [Gracefully Exit A Script With Trap](unix/gracefully-exit-a-script-with-trap.md)
- [Grep For Files Without A Match](unix/grep-for-files-without-a-match.md)
- [Grep For Files With Multiple Matches](unix/grep-for-files-with-multiple-matches.md)
- [Grep For Multiple Patterns](unix/grep-for-multiple-patterns.md)

View File

@@ -0,0 +1,27 @@
# Count All Files Of Specific Type Tracked By Git
I want to get a count of all the markdown files in my [TIL
repo](https://github.com/jbranchaud/til). Since all the files I care about are
tracked by `git`, I can use `git ls-files` to get a listing of all files. That
command on its own lists all files tracked by your git repository. Though there
are many other flags we can apply, that will do for my purposes.
By giving `git ls-files` a pattern to match against, I can turn up just, for
instance, markdown files (`*.md`). I can pipe that to `wc -l` to get a count
rather than exploding my terminal with a list of file names.
```bash
git ls-files '*.md' | wc -l
1503
```
That command includes `README.md` and `CONTRIBUTING.md`, but really I only want
to count the markdown files that constitute a TIL. Those all happen to be
nested under a single directory. So I can tweak the glob pattern like so:
```bash
git ls-files '*/*.md' | wc -l
1501
```
See `man git-ls-files` for more details.

View File

@@ -15,10 +15,8 @@ const remove = (items,index) => {
};
const list = [1,2,3,4,5];
remove(list, 2);
// [1,2,3,4]
list
// [1,2,3,4,5]
remove(list, 2); // [1,2,4,5]
// list still [1,2,3,4,5]
```
It only took a couple lines of code and immutability is baked in.

22
python/dunder-methods.md Normal file
View File

@@ -0,0 +1,22 @@
# Dunder Methods
Python has all kinds of special, or rather, _magic_ methods that allow for
customizing all kinds of class behavior. There is `__init__()`, `__bool__()`,
and so many others.
The thing they all have in common is that their names are wrapped in _double
underscores_. This is why they are called _dunder methods_.
Some of these are used every single day, like the `__init__()` method for
defining how a class should create an object. Others, used from time to time,
are for overriding how comparisons or conversions happen. E.g. you may want to
override `__bool__()` or `__len__()` to customize the truthiness of a custom
class.
There are so many others, ones you probably haven't even heard of. To see a
full listing, check out this [cheat sheet of every dunder
method](https://www.pythonmorsels.com/every-dunder-method/#cheat-sheet).
Note: these are not to be confused with _dunder attributes_ which are things
like `__name__`, `__file__`, and `__version__` which correspond to a value that
you can access in a specific context rather than behavior to override.

View File

@@ -0,0 +1,49 @@
# Empty find_by Returns First Record
During a RubyConf 2024 talk, a speaker mentioned that if you pass `nil` to
[ActiveRecord's `#find_by`
method](https://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-find_by),
it will return the first record from the database. This is a bit unintuitive,
so lets look at an example and then I'll show you why.
```ruby
> Book.first
#=> #<Book:0x00000001142e4c48 id: 13, title: "The Secret History", ... >
> Book.find_by(nil)
#=> #<Book:0x00000001142ca3c0 id: 13, title: "The Secret History", ... >
```
So, that is the same object in both cases, but why?
Our first hint is in the SQL that gets constructed when making that method
call.
```ruby
Book Load (2.5ms) SELECT "books".* FROM "books" LIMIT $1 [["LIMIT", 1]]
```
It's grabbing all books and limiting to _one_ result.
Lets look at the underlying implementation of the `#find_by` method.
```ruby
# File activerecord/lib/active_record/relation/finder_methods.rb, line 111
def find_by(arg, *args)
where(arg, *args).take
end
```
Sure enough, the implementation is a `#where` followed by a `#take`. Since the
`#where` is receiving `nil` as its `arg`, there are no conditions _filtering_
the query. And the `#take` corresponds to the `limit 1`.
Knowing that, we can understand that we will also get the first record from the
database if we call `#find_by` with `{}`. Again, no conditions to filter on, so
give me all books limited to one.
One small caveat: notice how there is no `order by` clause in the above SQL
output. This differs from `Books.first` which implicitly does an order on the
`id` column. Though these method are likely to return the same result, the
ordering of `#find_by` is not guaranteed to be the same without an `order by`
clause.

View File

@@ -0,0 +1,38 @@
# Execute Several Commands With Backtick Heredoc
A fun feature of Ruby is that we can execute a command in a subprocess just by
wrapping it in backticks.
For instance, we might shell out to `git` to check if a file is tracked:
```ruby
`git ls-files --error-unmatch #{file_path} 2>/dev/null`
$?.success?
```
But what if we need to execute several commands? Perhaps they depend on one
another. We want them to run in the same subprocess.
For this, we can use the backtick version of a heredoc. That is a special
version of a heredoc where the delimiter is wrapped in backticks.
```ruby
puts <<`SHELL`
# Set up trap
trap 'echo "Cleaning up temp files"; rm -f *.tmp' EXIT
# Create temporary file
echo "test data" > work.tmp
# Do some work
cat work.tmp
# Trap will clean up on exit
SHELL
```
Here we set up a `trap` for file cleanup on exit, then create a file, then do
something with the file, and that's it, the process exits (triggering the
trap).
[source](https://ruby-doc.org/3.3.6/syntax/literals_rdoc.html#label-Here+Document+Literals)

View File

@@ -0,0 +1,29 @@
# Gracefully Exit A Script With Trap
With `trap` you can intercept signals that would cause your script to exit and
then inject some additional behavior. Perhaps you want to make sure the script
cleans up after itself before it exists.
During this script's execution, it creates a file in the filesystem. It would
be nice to make sure that no matter path this script ends up down that it will
clean up after itself as it exits. We set up a `trap` that looks for the `EXIT`
signal to do this.
```bash
# Set up trap
trap 'echo "Cleaning up temp files"; rm -f *.tmp' EXIT
# Create temporary file
echo "test data" > work.tmp
# Do some work
cat work.tmp
# Trap will clean up on exit
```
Whatever is in quotes is what the trap will execute when it is triggered. The
following one or more signals are what the trap listens for, in this case
`EXIT`.
[source](https://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html)