2020年になりました
来年できることは来年やりましょう
2019年 まとめ
今年一年の振り返りです
Ruby
- Ruby にパッチ投げたりチケット立てたりした
知り合いのコネで開発者会議に参加させてもらった- いつも内容が濃ゆい
- 勉強会で Ruby の LT しまくった
- 詳細は後述参照
- reline に GitHub Actions 追加したりとか少し貢献できた
- gem はあんまりつくれなかった
- 勉強会の懇親会で Ruby にいろいろと議論する事ができた
- ActiveRecord の実装読みまくって ActiveRecord 力が上がった気がする
勉強会
- 年の後半にめっちゃ勉強会言った
- LT しまくった
- つくったスライド一覧
- Ruby にコミットしよう 表参道.rb #45
- Ruby にコミットしよう プログラミングLT 2019
- 5分ぐらいでわかる Ruby 2.7 表参道.rb #48
- ここがつらいよ無限 Range 表参道.rb #49
- 日常生活で全く役に立たない 時間の小話 プログラミングLT 2019 Summer
- いろいろ回答 表参道.rb #50
- メタプログラミングと SAD STORY 表参道.rb #51
- Ruby でフィボナッチ数を求めよう! 恵比寿.rb #25
- Ruby 2.7.0-preview2 のリリースノートを読もう 表参道.rb #52
- Ruby 2.7 の Numbered parameter の予習をしよう 恵比寿.rb #26
- reline に GitHub Actions を追加した話 Omotesando.rb #53
- Numbered parameter の注意点 Ruby Hack Challenge Holiday #9
- もくもく会にも行ってみた
買ってよかったもの
- 10GB の使い切りプリペイドSIM
- いざと言う時にあると便利
- 3in1 巻き取り充電ケーブル
- 端子が3つあるので複数のケーブルを持たなくていいし、巻取り式なのでコンパクト
- [Honor Note 10]
買ってよかったマンガ
- まどろみバーメイド
- バーテンダーのマンガ、おっぱいとお酒が飲みたくなる
- BEASTARS
- 今更買ってみて読んでみた、思ったよりもテーマが深い、推しはルイ先輩
- その着せ替え人形は恋をする
- ヒロインに嫌味がなくてよい
- イジらないで、長瀞さん
- よい
- ゾンビ屋れい子 / サタニスター
- ぶっ飛んでてよい
- サイコアゲンスト
- 4巻のカタルシスがやばい
- ローカル女子の遠吠え
- 静岡のご当地ネタマンガ、静岡に行きたくなる
- 僕の心のヤバイやつ
- 読んでる方の心がやばくなる
反省点
- おもしろ gem がつくれなかった
- 全然アウトプットできなかった
- 6月ぐらいから kindle でマンガ買うのにハマって気づいたら 600冊以上買ってた
- 全体的に進捗がない
2020年の目標
- Ruby にもっと貢献したい
- Refinements 周りのバグ修正した
- gem もっと作るぞ!
- 勉強会でもっと LT したい
- Ruby 以外の勉強会にも行きたい
- Vim 8.2 もリリースされたのでモダンな開発環境つくっていきたい
- もっと雑にブログを書いていきたい
- もっと雑に bugs.ruby にコメントしていきたい
- Ruby 以外にも手を出していきたい
ではでは、よいお年を〜。
つよつよパソコンを新しく組み立てた
勢いでつよつよパソコンを新しく組み立てました。
構成は以下の通り。
構成
- 【CPU】AMD Ryzen 9 3900X BOX \62,443 @最安
- 【CPUクーラー】Corsair H150i PRO RGB CW-9060031-WW \19,200 @最安
- 【メモリ】G.Skill F4-3600C16D-32GTZNC [DDR4 PC4-28800 16GB 2枚組] \21,980 @最安
- 【マザーボード】ASRock X570 Steel Legend \22,064 @最安
- 【ビデオカード】MSI Radeon RX 580 ARMOR 8G OC [PCIExp 8GB] \18,616 @最安
- 【SSD】CFD PG3VNF CSSD-M2B5GPG3VNF \12,078 @最安
- 【ケース】ANTEC P101 Silent \10,164 @最安
- 【電源】ANTEC NeoECO Gold NE750G \9,551 @最安
- 【合計】¥ 176,096
※ 2019/12/30 現在 http://niku.webcrow.jp/?MwkNTdQxyUpN0TGJSDXWMQkzytYx8XZ30dExCc111AFSbt5A4YyMbB09Qx0YBCEwQw8IyowA
AMD Ryzen 9 3900X BOX
もともとは 3900X が77000円ぐらいしててそれなら +2万出して 3950X 買ったほうがいいなーと思っていたんですが、3950X が売り切れ + 3950X が発売した影響で 3900X が6万ちょいぐらいまで値下がっていたので 3900X にしました、 Intel CPU と比べて AMD CPU はコスパよくていいですね!!
Corsair H150i PRO RGB CW-9060031-WW
NH-D15S と迷ったんですが 3900X ならやっぱり簡易水冷がいいかな〜〜〜と思って初めて簡易水冷にしました。
あとクソデカヒートシンクだとメモリとかが指しづらいので空間的余裕がある簡易水冷の方がよさそうだな〜〜〜思ってこっちにしました。
実際ケースに取り付けるのは大変だったんですが、つけた後は空間的余裕ができてかなり使い勝手がよくなりました。
あとサイバーマンデーで安くなっていたので勢いでポチった。
G.Skill F4-3600C16D-32GTZNC [DDR4 PC4-28800 16GB 2枚組]
メモリは適当に 16GB x 2 の安いやつを買おうと思っていたんですが、ここの記事とかを参考にして Ryzen に適しているらしい F4-3600C16D-32GTZNC にしました。
無駄にめっちゃ光る
ASRock X570 Steel Legend
高耐久性でコスパがいいってことでこのマザボにしました。
概ね問題なかったんですが、M.2 を取り外す時にヒートシンクをいちいち外さないとダメなのがちょっと手間でした。
MSI Radeon RX 580 ARMOR 8G OC [PCIExp 8GB]
唯一前のパソコンから引き継いだパーツです。
特にゲームなどしないので 2万ぐらいでコスパのいいグラボを付けてます。
CFD PG3VNF CSSD-M2B5GPG3VNF
第3世代Ryzen ならやっぱり PCI-Express4.0 に対応している NVMe M.2 でしょ!ってことでこれにしました。
カタログスペックだけでも
- 読込速度 : 5000 MB/s
- 書込速度 : 2500 MB/s
とチョッパヤです。
500GB でも1万ちょいなのでかなりコスパがいいです。
本当は 1TB がほしかったんですが売り切れてて 500GB にしました
ANTEC P101 Silent
360mm の簡易水冷が設置できるケースを選びました。
その結果かなり大きなケースになってしまいなんと 3.5インチベイが 8個も置けます。
ANTEC NeoECO Gold NE750G
電源はまあなんか適当に選びました。
所感
前回パソコンを新しくしたのは 3年前でした。
前回は Core2Duo → Core i7 6700K へステップアップだったので劇的に早くなったことを体感したんですが、今回はそこまで感じなかったっていうのが正直なところですね。
いや、スペック的には Core i7 6700K → Ryzen 9 3900X でも 3倍ぐらいスコアは上がっているはずなんですけどね。
あとケースが原因かもしれないんですが簡易水冷の取り付けにめっちゃ苦労しました。
今回買ったケースだと一旦 3.5インチベイを全部取り外さないとダメだったりケースについてるファンも取り替えないとダメでいろいろと手間でした。
その分、付けてしまえばケースの中はかなりすっきりしたんですが。
あとめっちゃ光ります。
メモリちゃんと刺さってないやんけー置くまで刺したらめっちゃ光るし pic.twitter.com/kEDjDJfFdX
— バンビちゃん@実際クソザコナメクジ (@pink_bangbi) 2019年12月21日
ひとまずこれで10年ぐらい戦えるぞ!!
ちなみに諸々移行作業が終わってからグラボのドライバをアップデートしたらログインマネージャが起動しなくなり OS から入れ直しました
RSpec の satisfy マッチャを便利に使う
Model のテストなどを書く時に次のように任意のリレーションに対して意図するクエリが追加されているかどうかをテストすることがあると思います。
class User < ActiveRecord::Base # rate 基準で上位10人を絞り込む scope :top10, -> { where(active: true).order(:rate).limit(10) } end RSpec.describe User do describe ".top10" do # scope top10 に対して意図するクエリが追加されていることをテストする subject { User.top10.to_sql } it { expect(subject.scan('WHERE "users"."active" = TRUE').one?).to be_truthy } it { expect(subject.scan('ORDER BY "users"."rate" ASC').one?).to be_truthy } it { expect(subject.scan('ASC LIMIT 10').one?).to be_truthy } end end
テストとしては別に問題ないと思うんですが、 expect
に負担がかかり過ぎてますね。
これを expect
に負担をかけるのではなくてマッチャでがんばって書きたいと思います。
satisfy
マッチャを使う
RSpec には satisfy
マッチャがあります。
これは expect
に渡した値を引数としたブロックを渡し、テストが成功しているか失敗しているかを判定することができるようになります。
例えば、次のように利用することができます。
describe "test" do # satisfy に渡したブロックが真を返せばテストがパスする # x = 1 it { expect(1).to satisfy { |x| x.odd? } } # x = 2 it { expect(2).to satisfy { |x| x.even? } } end
先程の Model のテストは satisfy
を利用すると次のように書くことができます。
RSpec.describe User do describe ".top10" do subject { User.top10.to_sql } # is_expected で書くことができる! it { is_expected.to satisfy { |sql| sql.scan('WHERE "users"."active" = TRUE').one? } } it { is_expected.to satisfy { |sql| sql.scan('ORDER BY "users"."rate" ASC').one? } } it { is_expected.to satisfy { |sql| sql.scan('ASC LIMIT 10').one? } } end end
更にヘルパメソッドを定義することでオレオレマッチャみたいなのをさくっと定義することもできます。
RSpec.describe User do describe ".top10" do # let っぽく記述 define_method(:scan_once) { |query| satisfy { |sql| sql.scan(query).one? } } subject { User.top10.to_sql } # 簡略化してかける it { is_expected.to scan_once 'WHERE "users"."active" = TRUE' } it { is_expected.to scan_once 'ORDER BY "users"."rate" ASC' } it { is_expected.to scan_once 'ASC LIMIT 10' } end end
これは便利。
Ruby の remove_method と undef_method の違い
さてさて、せっかくアドベントカレンダーでブログを書き続けているのでどうせならこのまま書き続けていこうかなーと思います。
まあすぐに止まりそうですが。
今回の内容は某所でちょっと話題になっていたので覚書。
remove_method と undef_method の違い
remove_method
はメソッドを『削除』にし、undef_method
はメソッドを『未定義』します。
どういうことかというと継承リストに呼び出せるメソッドが複数ある場合に違いがあります。
class Base def hoge "Base#hoge" end end class Super < Base def hoge "Super#hoge" end end # Super クラスで定義したメソッドが呼ばれる pp Super.new.hoge # => "Super#hoge" class Super # Super で定義されているメソッドを削除する remove_method :hoge end # Base クラスで定義したメソッドが呼ばれる pp Super.new.hoge # => "Base#hoge" class Super # Super で定義されているメソッドを未定義 undef_method :hoge end # Super クラスからは undef_method したメソッドが呼べなくなる # error: undefined method `hoge' for #<Super:0x00005631f4397278> (NoMethodError) # pp Super.new.hoge # こういう書き方だと呼び出すことは可能 pp Base.instance_method(:hoge).bind(Super.new).call
remove_method
だとまさに『そのクラスのメソッドを削除する』っていう動作になるんですが、 undef_method
だと『メソッドを呼び出せなくする』っていう動作になります。
たまーーーーーーに一時的にメソッドを生やしてその後削除することがあるんですが remove_method
と undef_method
の違いがわかってないと思わぬところで嵌りそうですねえ。
Ruby 2.7 がリリース
例年どおり昨日 25日に Ruby 2.7 がリリースされました。
Ruby 2.7 の開発はだいぶ追っていたんですが追加された機能もあれば実装されたけど最終的に Revert されてしまった機能もあり割と起伏が激しい印象です。
なんだよ、最終的に Revert されたじゃん!!と気持ちが強かったんですが、実際リリースされるとやっぱり便利機能が多く追加されたので便利。
irb めっちゃ強くなったとかパターンマッチが(実験的に)実装されたとかキーワード引数めっちゃ警告出過ぎワロスみたいなのがあるんですが、地味にわたしが投げたパッチも取り込まれているのでいくつか紹介してみたいと思います。
Time#floor / Time#ceil
Time
にはもともとミリ秒を丸める Time#round
があったんですが、切り捨てと切り上げがなかったので追加しました。
time = Time.now pp time # => 2019-12-26 22:14:44.389964779 +0900 # 丸め込み pp time.round(6) # => 2019-12-26 22:14:44.389965 +0900 # 切り捨て pp time.floor(6) # => 2019-12-26 22:14:44.389964 +0900 # 切り上げ pp time.ceil(6) # => 2019-12-26 22:14:44.389965 +0900
自分で追加した程度にはめっちゃほしかったので Ruby 2.7 使いたい。
Refinements が method / instance_method
に対応
Refinements の制限を緩和していこうキャンペーンで method
と instance_method
でも Refinements で定義したメソッドを参照できるようにしました。
using Module.new { refine String do def twice self + self end end } # 2.7 では method や instance_method で Refinements で定義したメソッドが取得できるようになった p "homu".method(:twice).call p String.instance_method(:twice).bind("homu").call
便利。
その他個人的な注目機能
Ruby 2.7 ではいろいろな魅力的な機能が追加されているんですがその中でも個人的に「お、これめっちゃええやん!!」みたいなのをいくつか紹介してみます。
Time#inspect
がミリ秒まで含まれるようになった
Time#inspect
がミリ秒まで含まれるようになりました。
require "time" time = Time.now # 今まではミリ秒は切り捨てられていた pp time # => 2019-12-26 22:22:12 +0900 # ミリ秒まで表示する場合は iso8601 など使う必要があった pp time.iso8601(10) # => 2019-12-26 22:22:12.660985941 +0900 # Ruby 2.7 ではミリ秒まで表示されるようになった pp time # => 2019-12-26 22:22:12.660985941 +0900
一日に iso8601(10)
って10000万回ぐらい書いているのでこれはありがたい…。
Method#inspect
にシグネチャと定義場所が含まれるようにあった
Method#inspect
にシグネチャと定義場所が含まれるようになりました。
def plus(a, b) a + b end # Ruby 2.6 p method(:plus) # => #<Method: main.plus> # RUby 2.7 p method(:plus) # => <Method: main.plus(a, b) /tmp/test.rb/69:1>
ActiveRecord とか読む時にメソッドの定義場所を調べることは多かったんですが、定義場所の情報を取得する場合 Method#source_location
を使う必要がありました。
source_location
も今年100000億回ぐらい書いたのでもう書かなくていいのは便利ですね。
警告の制御
Ruby 2.7 ではキーワード引数で警告が出たり、新しい機能であるパターンマッチを使うと experimental であると警告が出るようになります。
この警告の出力を制御するために新しいオプションが追加されました。
例えば -W:no-deprecated
を使用すればキーワード引数などの deprecated
な警告が出力されなくなり、 -W:no-experimental
を使用すればパターンマッチを使用した場合の警告などが出力されなくなります。
Ruby 2.7 を使いたいが外部ライブラリで警告が出てつらい、みたいな場合はこのオプションを利用してみるとよいです。
これからは
され、Ruby 2.7 が無事にリリースされたということはこれから Ruby 3.0 の開発が始まります。
Ruby 3.0 でも何かしら開発に貢献できていければいいかなーと思います。
とりあえず Refinements 周りのバグを見直していきたいですねえ…。
参照
【一人 C++20 Advent Calendar 2019】C++ にコンセプトがやってくる!【25日目】
一人 C++20 Advent Calendar 2019 25日目の記事になります。
C++ にコンセプトがやってくる!
ついに C++ にコンセプトがやってきました!
C++11 の時代から長かった…。
コンセプトとはテンプレートパラメータに対して任意の制約を指定することができるようになる機能になります。
細かいところを話し出すと止まらないので簡単な例を記述すると以下のような使い方になります。
#include <string> #include <iostream> // T 型に対する制約を定義する template<typename T> concept printable = requires (T& t) { // T に対して任意のメンバ関数が呼べるかどうかの条件 t.name(); // 複数書くことで複数の制約を定義できる // また、以下のように書くことでメソッドの戻り値に対する制約も定義できる { t.sound() } -> std::string; }; // テンプレート引数を定義する時に typename や class の代わりに // concept で定義した制約名を記述できる // この場合は printable の条件の型のみをテンプレートで受け取ることになる template<printable T> void print(T const& obj) { std::cout << obj.name() << " : " << obj.sound() << std::endl; } // こちらは通常の関数テンプレートになる // printable の制約に当てはまらなかった場合にこちらを呼び出す template<typename T> void print(T const& obj) { std::cout << "出力できません" << std::endl; } struct cat { std::string name() const { return "ねこ"; } std::string sound() const { return "にゃーん"; } }; struct dog { std::string name() const { return "いぬ"; } std::string sound() const { return "わーん"; } }; struct X { int name() const { return 42; } int sound() const { return 42; } }; int main(){ // OK: printable の条件に当てはまってる print(cat{}); print(dog{}); // NG: printable の条件に当てはまらない print(X{}); return 0; } /* output: ねこ : にゃーん いぬ : わーん 出力できません */
C++ でメタプログラミングをやったことがある人なら必ず書いたことがあると思うんですが SFINAE を使ったテンプレート型の条件分岐ってめちゃくちゃむずかしいんですよね。
しかし、それがコンセプトを使うことで上のコードのようにめちゃくちゃすっきりと記述することができます。
そうそう、これだよこれ、これでいいんだよ。
もちろん上の使い方以外にも様々な用途でコンセプトを利用することができます。
詳しくは以下のまとめを読んでみてください。
いやー C++11 から長かったんですがやっとコンセプトが入りましたねえ…。
また、言語機能として追加されるだけではなくて標準ライブラリにもいくつか汎用的な制約が定義されています。
C++20 が楽しみですねー。
アドベントカレンダーを終えて
と、言うことで今日がクリスマス!そしてアドベントカレンダーが終わり!!!
勢いで始めたアドベントカレンダーだったんですがなんとか無事に完走することができました。
一つ一つの内容はとても薄っぺらいですが
始める前は C++20 って何が追加されるんじゃ???って感じだったんですが実際にどういう機能が追加されるのかを調べてみると細かい追加や修正がかなりされていることがわかりました。
特に「C++ で絶対に constexpr
するぞ!!!」という気持ちはめっちゃ伝わってきました。
まだ各コンパイラでは追加されてない機能やライブラリがあるので「ホンマに来年使えるようになるの???」みたいな気持ちがあるんですが、各コンパイラが対応されたらまた触ってみたいですねー。
それでは皆さん良いお年を。