昨日の日記を書いていなくて、書きたいことはたくさんあったけど、とりあえず今日のことから書く。
今日は 6 時半に目覚めた。ゴミ出しの日だ。
普段、ゴミはゴミ出しの日の前日の夜に出すのだが、昨日の夜はあまりにも疲れていて寝落ちしてしまったので出せなかった。でも 6 時半に起きたので今からなら全然間に合うな、と思い、ゴミを出すために起きた。そのせいかどうか知らないけど今日の目覚めは非常に良かった。
お金も降ろさないといけなかったので、ついでに近くの郵便局(ゆうちょ)に行ったが、ATM が使えるのが 8 時からだったので、諦めて帰ってきた。
今日は目覚めがとても良かったので開発のモチベーションが高かった。家に帰ってきて早速開発を始めた。今日はプライベートタグの改良をした。タグを囲む記号を <>
から {}
に変更して、プライベートタグで囲まれた内容を正しくピンク色にしたかった。
ところが、これがなかなかどうして難しかった。
方針として、先にマークダウンでパースしてからプライベートタグを処理するか、先にプライベートタグを処理してからマークダウンでパースするかの 2 通りがある。
先にマークダウンでパースする場合、プライベートタグに <>
記号を使ってしまうと HTML の不正なタグとして解釈されてしまい、プライベートタグが消えてしまう。なので、別の記号 {}
に変えなければならなかった。
そこまでは良いのだが、先にマークダウンでパースすると、プライベートタグ自体が <p>
で囲まれてしまうことがある。その <p>
を単純に取り除いて良いかどうかは、どういうふうにプライベートタグを書いたかによるので、かなり複雑になってしまうことがわかった。
次に、先にプライベートタグを処理する場合だが、この場合は先ほどのようにプライベートタグ自体がマークダウンとしてパースされてしまうことがない代わりに、プライベートタグで囲まれた部分のマークダウンがパースされない問題が発生する。
なぜなら、プライベートタグ変換後は <div>
で囲まれるので、その中はパースされない仕様だからだ。
なので、プライベートタグを <div>
や <span>
に変換しつつ、その中の部分を一つずつマークダウンでパースするというやり方をした。プライベートタグで囲まれた文字列を正規表現でマッチさせて抽出して、その抽出した文字列をパースするという方法、つまり文字列の一部を写像するということだ。
これをどのように書こうか結構迷ったが、実は String#gsub
は第 2 引数にブロックを受け取ることができ、第 1 引数でマッチした文字列に対して何かしらのメソッドをかけたりすることができる。つまり、文字列の一部を写像することができるわけだ。
このサイト を参考にした。
これを使ってすべての文字列をマークダウンでパースしつつ、プライベートタグを処理することができた。
ところがこれでもまだ問題があって、Qiita::Markdown の注釈機能1をプライベート化させることができないのだ。
こんな感じで、注釈をつける部分と、注釈をそれぞれプライベートタグで囲んだ場合、それぞれ別々にパースされるので、Qiita::Markdown 側では注釈をつける側とつけられる側がリンクしない。つまりここはまとめてパースしないと注釈として正しくパースされないのだ。
これは困った。ここだけまとめてパースさせるように実装するとしても、<div>
や <span>
で囲まれてしまっているとやはり正しくパースできない。単にプライベートタグだけ除去してしまうと、もはやピンク色にすることができない(<div>
や <span>
をつけることができない)。
その他、プライベートタグの中がリストになっていた場合は、プライベートタグの開きタグがある行とリストを開始する行の間に空行を入れなければ正しくパースされないという問題もある(これがなぜ発生するのかはまだ調べていない)。
などなど、マークダウンパーサとの間に独自のパース機構を入れると、恐ろしいくらいめんどくさくなることがわかった。
もう諦めて注釈部分はプライベートにはできない仕様にしてしまおう(リストのほうは今後調査してなんとかする)かなとか思ってる。たぶん注釈機能って一般的なマークダウンパーサの仕様じゃなくて Qiita::Markdown の独自実装な気がするから、まあその部分だけプライベート機能と併用できないってのはある意味では自然なんじゃないかなとか負け惜しみしてみる。
まあそんなわけで、今日はそれを一日中実装していた。まだ終わっていない。ある程度機能するようになったら本番にデプロイしようかな。
夕方ごろに開発を一時中断してお金を下ろしに行ってきた。本当はもっと早く行こうかと思っていたが、開発に熱中していた。
お金下ろして、自分の銀行口座に振り込んだ。
で、帰ってきて、調子が良かったので HIIT バーピー(4 セット)もやった。
そのあと、メインクレカの会社 (this is a private diary) に電話した。実は今日、SMS が届いていたのだ。1 日が引き落とし日だったが、銀行口座の残高不足で引き落としができなかったので電話してくれということだった。
電話したら、一括で支払うには銀行振込する必要があると言われた。そのまま放っておいた場合、15 日にリボ払いとなって請求されてしまうらしい。というか銀行振込で一括払いするか、リボ払いにするかという選択を電話でしてくれということみたい。
リボ払いは困るので、一括で支払うことにした。その場合はリボにならない。
ついさっきお金を下ろしてきて自分の口座に振り込んだばかりだったので支払うこと自体はできる。でも、さっきお金入れてきて、また行くのは面倒なので、今回は、何気にはじめてインターネットバンキングで振込を行うことにした。
ログインして振込を選択したあとの手順は ATM での支払い方法とほぼ同じで、実に簡単に振り込むことができた。手数料はかかってしまうが、たしか ATM でも手数料はかかってしまったのでそれは問題ないだろう。
このクレカは引き落としに失敗して何も連絡しないとリボ払いになるという恐ろしい仕様なので今後は引き落とし日に残高不足になっていないように気をつけよう。
インターネットバンキングで振込を終わったあとは、開発に戻ろうと思ったんだけど、なんだか頭が痛くなって身体がだるくなってしまったので開発はせずにダラダラしていた。
ダラダラとはいっても、実際には Money Forward の未確認決済を確認して、先月や先々月の家計を振り返っていた。
趣味の支払いが圧倒的に多くてびっくりした。ヒキニート中にもかかわらずこんなに趣味にお金を使っているのはやばいなと思ったので今後は気をつけよう。
趣味の支出の内訳として、AirPods Pro とか Oculus Quest とか Blackmagic eGPU Pro とかがある。どれもヒキニートで買うものじゃない。
Blackmagic eGPU Pro は生産終了してしまってこれを逃すともう手に入らないかもしれないと思ったので仕方なかったが、Oculus Quest は今買うべきじゃなかったな。AirPods Pro は外出するときに音楽聴くのに超便利なので、まあ仕方ない……w。
その他、Steam でセール中のゲームとか、PS4 用のゲームとかが支出に含まれていた。Steam のゲーム、自作 PC 組まないとほとんどできないのに今買うのはなんか違う気もするけど、セールだと思うと買ってしまう。いつかやるだろうから。うーん、こういう考えがいけないのかな? ちゃんと必要なときに必要なものやサービスにお金を使うようにしたい。
スーパー行って食料品を買って、帰ってきてお風呂入ったら頭痛いのとだるいのが治ったので今この日記を書いている。
んで、昨日は夜疲れていて日記書かずに寝てしまった。サーバに入って、
Article.create!(text: 'foo', year: XXXX, month: YY, day: ZZ, date: Date.new(year: XXXX, month: YY, day: ZZ))
でズルして昨日の日記を書こうと思ったんだけど、テンプレート機能を実装してからはそのズルも安易にできないことに気づいた。
なぜなら、こうやってレコードを作ってしまうと、テンプレートが反映されないからだ。一つ一つテンプレートを関連付けてやることもできるが、とってもめんどくさい。やっぱりフォームから一気に関連付けないときつい。それはつまりズルをせずにちゃんとフォームから入力しないといけない(昨日の日記を今日書いたりはできないという、本来の仕様として使う)というわけだ。
まあぶっちゃけ書きそびれた日のテンプレートはなしでも良い気もするが、やっぱり気分 10 段階評価とかは入れておきたいじゃん。ってなるとやっぱりちゃんとその日に日記を更新する(毎日更新する)べきだよなと思った。
だから、本当に簡単で良いから日記は毎日更新したいなあと思った。書く気力が全然なかったら、とりあえず日記本文は "a"
とか適当にしておいて、気分 10 段階評価とかだけ記録する、みたいな。あれは星をクリックするだけで良いからね。
そうそう、んで、昨日は最悪なことがあった。昨日の昨日、つまり一昨日に久しぶりに Anova を使って鶏むね肉を低温調理していた。一昨日に食べるつもりだったが、眠くて食べる気力がなかったのでそのまま放置していた。
そしたらよ、明け方 4 時くらいに、金属製の爆音(「ぎゅぃいぃいぃいぃいぃいぃいぃいぃいぃん!!!!!!!」っていう爆音)が聞こえて、慌てて飛び起きた。原因は Anova だ。こいつたまにこういう金属製の爆音を鳴らすことがある。前にも一度か二度あった気がする。それが寝ている間に発生してびっくりして飛び起きたというわけだ。
寝たのは覚えていないが 0 時過ぎであることは確実だったから、3 時間かそれ以下しか寝られなかった。しかも一昨日もかなり疲れていて寝たので、とにかく最悪な目覚めだった。最悪 of 最&悪だった。
二度寝しようにも、こんな急な起こされ方したら冴えちゃって寝られない。でも頭はぼーっとする。本当に最悪だった。
今後は就寝中に Anova は使わないようにしようと思った。
前に緊急地震速報で起こされたこともあった。寝ているときに音で起こされると本当に不快だからマジで勘弁してほしい。
起きてからしばらくは、あまりにも頭がぼんやりしていて何もする気が起こらなかった(ただぼーっとしまくっていた)が、そのあとは開発をしていた。睡眠不足で頭ぼんやりなんだけど、なぜか開発できた。最近日記の開発欲があるからやる気もあった。冷静に考えると不思議なものだ。
で、昨日は一日中開発をやってたんだけど2、ついに検索機能を強化した。
まず最初はリファクタリングから入った。検索キーワードのバリデーションをコントローラに書いてしまっていた(いわゆる fat controller というやつになっていた)ので、それを form object という Rails の機構に移行した。
form object は、簡単に言えば DB への書き込みを伴わないデータのバリデーションを、Model のバリデーションと同じような書き方でできるようになるというもの。まさに検索キーワードのバリデーションなんかは、DB に保存する値ではない(つまり Model は存在しない)けど Model みたいにバリデーションしたいから最適だと思う。
実はこのリファクタリングで大半を使っていたんだけど、そのあと検索機能を追加した。具体的には、OR 検索と完全一致検索とネガティブキーワード検索に対応した。
今まで apple watch
と検索すると、”apple watch” が含まれるものしかヒットしなかった(いわゆる完全一致検索)んだけど、”apple” または “watch” が含まれているものがヒットするようにした。
逆に “apple watch” を検索したい(”apple” だけとか “watch” だけはヒットさせない)場合は "apple watch"
とダブルクォートで囲めば良い。Google 検索と一緒だ。
それから特定の文字列を除外するネガティブキーワード検索もついでに対応しておいた。-keyword
で keyword
を除外できる機能だ。
これらの組み合わせで検索ワードを入力されたときにちゃんと正しい SQL を発行する ORM を書くのに苦労したが、まあなんとかできた。この記事のコメント が大変参考になった。
あとは AND 検索が実装できれば良いなと思っている。それから未ログイン時にプライベートワードがヒットしないようにしないと(まあ見ることはできないから大丈夫ではあるんだけど)。あとテンプレートのほうも検索にヒットするようにしたいね。
だいぶ長いこと書いてしまった。この日記だけで 2 時間くらいかかっている気がする。それは言い過ぎかな。1 時半はかかっている。
まあ日記はもっと気楽で良いと思う。気楽で良いから、毎日書けるようにしたい(定期)。
食べたもの
プロテインとかバナナとかフルグラとか。
写真貼るのめんどくさいから文字だけで。
ちなみに昨日は鶏むね肉とカット野菜のサラダ食べた。
今日の学び
String#gsub
はブロックを受け取ることができる- 文字列の一部分を写像することができる
- プライベート機能の実装むずい!
成長記録
- プライベート機能の改良をすることができた!
- お金を下ろしたりクレカの支払いをした!
「成長記録」っていうか、自分を褒めて自己肯定感あげる感じになってる。まあそれはそれで良いことだ。いや、だからこそ「成長記録」で良いのか?
気分レベル
8
今日の気分はどうだったか
目覚めも良かったし、開発もできた。昼過ぎから頭が働かなくなって一気に進みが悪くなったけど、それでもプライベート機能の改良にかなり前進することができた。