@ledsun blog

無味の味は佳境に入らざればすなわち知れず

またまた Gitのdiffを振り返る

ふたたび Gitのdiffを振り返る - @ledsun blog で日単位で集計しました。

週、月、年単位の集計結果も見ていきましょう。

gnuplot> set xdata time
gnuplot> set timefmt "%Y-%m-%d_%H:%M:%S"
gnuplot> plot 'all_log_week.dat' using 1:2 w i title 'insertions' lw 2, 'all_log_week.dat' using 1:3 w i title 'deletions' lw 2

f:id:ledsun:20201230223748p:plain
週毎のファイルの変更行数

グラフが見やすくてよいです。

gnuplot> plot 'all_log_month.dat' using 1:2 w i title 'insertions' lw 2, 'all_log_month.dat' using 1:3 w p title 'deletions'

f:id:ledsun:20201230223936p:plain
月毎のファイルの変更行数

これも全体的な傾向をつかめているように思います。

今後の追跡調査は、週または月で集計するのが良さそうです。

gnuplot> plot 'all_log_year.dat' using 1:2 w l title 'insertions', 'all_log_year.dat' using 1:3 w l title 'deletions'

f:id:ledsun:20201230224127p:plain
年毎のファイルの変更行数

2019年が5月開始なので、8ヶ月分のデータしかありません。 期間が1.5倍なので、増加量としては妥当な感じです。

insertions/deletionsの比率が1.1から1.3に増えているのが興味深いです。 機能追加が多かったのでしょうか?

ふたたび Gitのdiffを振り返る

続々 Gitのdiffを振り返る - @ledsun blogでコミット単位でのファイルの変更行数の遷移をふりかえりました。

コミット単位では列間が詰まりすぎてグラフが見にくいです。 特に、Gitのコミット数を振り返る - @ledsun blog で見たように、2020年9月以降コミット粒度を小さくしています。

f:id:ledsun:20201220211139p:plain
2020年の月別コミット数

このため列間がますます詰まり、グラフから情報が読み取りにくくなっています。 そこで、ファイルの変更行数を、再び、日、週、月、年の単位で集計します。

次のRubyスクリプトを使います。

require "Time"
require "Date"

duration = $*.shift.to_s.to_sym

Commit = Struct.new(:at, :insertions, :deletions)

# カウントしたくないファイルを除外
EXCLUDE = "':(exclude)package-lock.json' ':(exclude)*.min.js' ':(exclude)*.css' ':(exclude)dist/*' ':(exclude)dev/vender' ':(exclude)src/lib/modules' ':(exclude)*.md'"

`git log --after='2019-05-22 00:00' --format=format:'---%n%ai' --shortstat #{EXCLUDE}`
  .split("---\n")[1..] # 1行目は空なので捨てる
  .map { _1.split("\n") }
  .filter { |time, stats| !stats.empty? } # 除外しているファイルがあるのでstatsが出ないことがある
  .map { |time, stats| Commit.new(Time.parse(time), stats.split(",")[1].to_i, stats.split(",")[2].to_i) } # " 1 file changed, 10 insertions(+), 9 deletions(-)" をパース
  .filter { _1.insertions < 1000 } # 1000行以上の変更はツールによるので除外する
  .sort_by { _1.at.to_i }
  .reduce({}) do |result, item|
  case duration
  when :day
    date = Date.parse item.at.to_s # 日
  when :week
    date = Date.parse(item.at.to_s) - item.at.wday # 週
  when :month
    date = Date.parse item.at.strftime("%Y-%m-01") # 月
  when :year
    date = Date.parse item.at.strftime("%Y-01-01") # 年 は期間が違い過ぎるので、比較には向かない
  else
    date = item.at
  end
  if result.key? date
    result[date].insertions += item.insertions
    result[date].deletions += item.deletions
  else
    result[date] = Commit.new(date, item.insertions, item.deletions)
  end

  result
end
  .each_value do
  puts "#{_1.at.strftime("%F_%T")} #{_1.insertions} #{_1.deletions}"
end

引数で、dayweekmonthyearを受け取り、それぞれの単位で集計します。 出力データ形式続々 Gitのdiffを振り返る - @ledsun blogと一緒です。

gnuplot> set xdata time
gnuplot> set timefmt "%Y-%m-%d_%H:%M:%S"
gnuplot> plot 'all_log_day.dat' using 1:2 w i title 'insertions' lw 2, 'all_log_day.dat' using 1:3 w i title 'deletions' lw 2

f:id:ledsun:20201230165055p:plain
日毎のファイルの変更行数

続 Gitのdiffを振り返る - @ledsun blogのグラフと比べると大分ちがいます。 変更行数の変動が少なく、現実の作業効率を反映していそうです。

f:id:ledsun:20201227231409p:plain
異常値を除いた一日毎のファイルの変更行数

どうやら、本当に一日に2000〜2500行の変更をしているようです。

今年は 「論理的思考の放棄」をパクる - @ledsun blog に書いたように 1日1000行のリファクタリング を目指してプログラミングスタイルを工夫していました。半年を経て、どうやら達成したようです。 現時点では、一回しか達成していないので、再現性がないかもしれません。 来年は、これがフロックでないことを確認したいと思います。

「1日1万行とか、絶対無理じゃん」という思いもありましたが、あと4倍なら、俄然現実味が帯びて参りました。

続々 Gitのdiffを振り返る

続 Gitのdiffを振り返る - @ledsun blog で1000行以上の変更があるコミットはツールによるフォーマット変更であることがわかりました。

また、日付でまとめてしまうと一日の変更行数が2000を超えます。 これはgit rev-listのbeforeやafterの挙動によるものです。 必ずしもコミットした日にまとまっていません。

例えば、つぎとコミットがあったとします。

  • 1/10に機能追加のコミットA
  • 1/15にバグ修正のコミットB

バグ修正を先にpushしたかったので、rebaseして、コミットBをコミットAの前に移動します。 するとコミットAは1/15日以降のコミットにカウントされます。 このように実際の作業日とはずれて集計されます。 特にリリース直前の日に作業が固まりやすい傾向があります。

そこで期間中の全コミットをもってきて、そのままグラフ化します。

次のRubyスクリプトを使います。

require "Time"

Commit = Struct.new(:at, :insertions, :deletions)

# カウントしたくないファイルを除外
EXCLUDE = "':(exclude)package-lock.json' ':(exclude)*.min.js' ':(exclude)*.css' ':(exclude)dist/*' ':(exclude)dev/vender' ':(exclude)src/lib/modules' ':(exclude)*.md'"

`git log --after='2019-05-22 00:00' --format=format:'---%n%ai' --shortstat #{EXCLUDE}`
  .split("---\n")[1..] # 1行目は空なので捨てる
  .map { _1.split("\n") }
  .filter { |time, stats| !stats.empty? } # 除外しているファイルがあるのでstatsが出ないことがある
  .map { |time, stats| Commit.new(Time.parse(time), stats.split(",")[1].to_i, stats.split(",")[2].to_i) } # " 1 file changed, 10 insertions(+), 9 deletions(-)" をパース
  .filter { _1.insertions < 1000 } # 1000行以上の変更はツールによるので除外する
  .sort_by { _1.at.to_i }
  .each { puts "#{_1.at.strftime("%F_%T")} #{_1.insertions} #{_1.deletions}" }

次のような行が3000行続きます。

2020-12-25_17:22:45 4 4
2020-12-25_17:24:41 10 9
2020-12-25_17:27:11 9 3

結果をファイルにいれてgnuplotで表示します。

gnuplot> set xdata time
gnuplot> set timefmt "%Y-%m-%d_%H:%M:%S"
gnuplot> plot 'all_log.dat' using 1:2 with line title 'insertions', 'all_log.dat' using 1:3 with line title 'deletions'

f:id:ledsun:20201229222555p:plain
Gitコミット毎 の ファイルへの追加行数と削除行数

2019年と2020年で、プログラミングのピーク性能は特段変わっていないことがわかりました。

2020年に作ったGithubリポジトリ

2020年に作ったGitHubリポジトリ - pockestrapにインスパイアされました。

次の条件でGithubを検索します。

Search · is:public user:ledsun created:2020 · GitHub

f:id:ledsun:20201229123657p:plain
2020年にGithubに作ったリポジトリ

大体どれも作りかけです。

GitHub - ledsun/svg-playground: SVGの学習用の実験場です。

SVGおじさんに憧れて素振りしていた時のものです。素材をSVGにする部分が難しいなあ、素振りしてもなかなか身につかないなあ・・・というところで止まりました。

GitHub - ledsun/github-actions-continuous-delivery

Github Actionsの練習用

GitHub - ledsun/echos: Echosは、短い音声にURLを与える音声ストレージ

ブラウザで音声を保存します。構想では永続化しようと思っていました。getUserMediaで取得したデータをWaveフォーマットにエンコードするところまで書いて止まりました。

GitHub - ledsun/three-js-playground: Three.jsをスブって遊ぶ場所

WebGLの勉強がてらthree.jsを素振りしていた時のものです。three.jsがいい感じに抽象化してくれているおかげで、WebGLの概念が身につかないなあ・・・というところで止まりました。

GitHub - ledsun/ruby_of_aja: Rubyプログラミング学習用の練習問題管理アプリケーション

Rubyプログラミングの練習問題を管理するアプリケーションです。 問題文はMarkdownで書けます。 問題の解答をPostするとサーバサイドで実行して正解か不正かを判定する機能があります。 テストデータをどうやって書こうかな?と悩んだあたりで止まりました。

2021年はなにか形があるものを残したいですね。

2020年のプルリクエストをふりかえる

2020年のプルリクエストを振り返る - kakakakakku blogを参考にしました。 あまりにも少なかったのでissueも入れました。 次の条件でGithubを検索します。

is:public author:ledsun created:2020

Search · is:public author:ledsun created:2020 · GitHub

f:id:ledsun:20201229104051p:plain
2020年のIssueとPull Request

2番目のIssueが解決済みなことを思い出したので、閉じておきました。ふりかえりは大事ですね。

rbenvでRuby 3.0を使う

Homebrewをインストールし直す - @ledsun blogrbenvをgitから入れました。

git pullします。

~ cd .rbenv/
~ git pull --ff-only
Already up to date.

んー、rbenv install --list-allしても3.0.0が出てきません。

~ cd ~/.rbenv/plugins/ruby-build
~ git pull --ff-only

が、必要でした。

~ ruby --version
ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin18]

続 Gitのdiffを振り返る

Gitのdiffを振り返る - @ledsun blog でGitの記録から、約2年間の毎日のファイルの変更行数を見ました。 1日に4000行の人力では不可能に思える変更が見つかりました。 今度は巨大な変更を含むコミットを探してみましょう。

次のRubyスクリプトを使います。

require 'date'

EXCLUDE = "':(exclude)package-lock.json' ':(exclude)*.min.js' ':(exclude)*.css' ':(exclude)dist/*' ':(exclude)dev/vender' ':(exclude)src/lib/modules' ':(exclude)*.md'"

start_date = Date.parse $*.shift
end_date = Date.parse $*.shift
limit = $*.shift.to_i

git_rev_list_command = "git rev-list --after='#{start_date} 00:00' --before='#{end_date} 23:59' current"
p git_rev_list_command

revs = `#{git_rev_list_command}`.split("\n")
revs.reverse.each do |revision|
  result_of_git_show = `git show --shortstat --oneline #{revision} #{EXCLUDE}`
  short_stat = result_of_git_show.split("\n")[1]
  next unless short_stat

  insertions, deletions = short_stat.split(",")[1..].map { _1.to_i}
  next unless insertions
  next unless deletions

  if insertions > limit || deletions > limit
    system "git show #{revision} --format=format:'%H%n%ai%n%s' --shortstat #{EXCLUDE}"
    puts "\n"
  end
end

実行してみると、次の結果が得られました。 1000行以上の変更をしているコミットを探しました。

~ ruby gitdiffindate.rb 2019/05/22 2020/12/31 1000
"git rev-list --after='2019-05-22 00:00' --before='2020-12-31 23:59' current"
663c84dbf80a105b22078418f87c2474ac9487a5
2019-07-24 14:58:23 +0900
code-style: Introduce the Prettier code formatter
 330 files changed, 3990 insertions(+), 1883 deletions(-)

5c3f2c2122f676df8f91a03df5ef12830082cb93
2019-07-24 15:01:49 +0900
code-style: Ban one-var
 56 files changed, 1077 insertions(+), 1086 deletions(-)

cf2acd9f917e2652048df97050c0e885aaec0731
2019-11-12 11:18:55 +0900
refactor: Format annotation files
 10 files changed, 2543 insertions(+), 2158 deletions(-)

d5c2b8881c9edbececee8b7753a8f04b2dd3f5cd
2019-11-19 15:35:29 +0900
refactor: Format less files
 6 files changed, 1181 insertions(+), 968 deletions(-)

5bb834fca322388da6b3ca94db99e4910f6f774a
2019-11-07 20:28:24 +0900
feature: Show attribute tabs in the Pallet
 25 files changed, 1180 insertions(+), 69 deletions(-)

発見したコミットログを見ると、ほとんどがツールを使ったフォーマット変更でした。

feature: Show attribute tabs in the Palletは、機能追加です。 機能追加とはいえ、1コミットで1000行入れるのは、我ながらよくなかったと反省です。

この5つのコミットが2019-07-292019-12-02に集計された結果、1日4000行オーバーになっていました。 つまりノイズです。これらの異常値を除いてグラフを作り直してみます。

f:id:ledsun:20201227231409p:plain
異常値を除いた一日毎のファイルの変更行数

今度は2000行近い変更が異常値に思えてきました。

Gitのdiffを振り返る

Gitのコミット数を振り返る - @ledsun blogで、Gitのコミット数をふりかえりました。 今年はコミットの粒度を変えたためコミット数が増えています。 その結果、作業効率は上がったのでしょうか?今度はGitのdiffをふりかえってみます。

日付単位でgit diffのsohrtstatをとります。

3 files changed, 8 insertions(+), 3 deletions(-)

こんなやつです。

次のRubyスクリプトを使いました。

require 'date'

base_date = Date.new(2019, 5, 22)
0.upto(585) do |i|
  target_date = base_date + i

  start_commit = `git rev-list -1 --before="#{target_date} 00:00" current`.chomp
  end_commit = `git rev-list -1 --before="#{target_date} 23:59" current`.chomp

  # An expected output string format is like " 3 files changed, 8 insertions(+), 3 deletions(-)".
  stats = `git diff --shortstat #{start_commit} #{end_commit} ':(exclude)package-lock.json' ':(exclude)*.min.js' ':(exclude)*.css' ':(exclude)dist/*' ':(exclude)dev/vender' ':(exclude)src/lib/modules' ':(exclude)*.md'`
  parsed_stats = stats.split(",").map { _1.to_i }
  if parsed_stats.size == 3
    puts [target_date].concat(parsed_stats).concat([start_commit, end_commit]).join(" ")
  else
    puts [target_date, 0, 0, 0].join(" ")
  end
end

gitのcommitの日付を元にしています。 git rebaseなどで順序が入れ替えていると、本当にその日付にコミットしたとは限りません。 全体的な傾向がわかればいいので、ここでは無視します。

gunplotでグラフ化します。

gnuplot> set xdata time
gnuplot> set timefmt "%Y-%m-%d"
gnuplot> plot 'daily_git_stast.dat' using 1:3 with steps title 'insertions', '4col.csv' using 1:4 with steps title 'deletions'

f:id:ledsun:20201226100949p:plain
daily git diff

4000行を超える変更をした日が二つあります。

Gitのコミット数を振り返る

次のRubyスクリプトを使って、あるリポジトリの2020年のGitコミット数を月単位で集計します。

require 'date'

1.upto(12) do |i|
  start_date = Date.new(2020, i, 1)
  end_date = (start_date >> 1) - 1

  commits = `git log --oneline --since #{start_date} --until #{end_date} | wc -l`
  puts "#{i}, #{commits.chop.to_i}"
end

結果は次のとおりです。

1, 60
2, 76
3, 32
4, 45
5, 19
6, 53
7, 47
8, 57
9, 138
10, 482
11, 432
12, 432

gnuplotを使ってグラフにします。

gnuplot> plot "./commits.dat" with line

f:id:ledsun:20201220211139p:plain
2020年の月別コミット数

10月からコミット数が通常の3倍に増えていました。

参考

たのしいプログラミング練習法

プログラミングが上達するのに、プログラミングする以外の方法はありません。

なるべくたくさんのプログラミング練習法を知っていて、 その時の自分の気分に合ったプログラミング練習法を使いわけて、 なるべく長い時間飽きずに、プログラミングを続ければ、スーパープログラマになれます。

練習法の名前は軽い気持ちでつけています。 かっこいい名前があれば教えて下さい。

練習法カタログ

写経

初めて使うプログラミング言語やライブラリをチュートリアルGetting Startedに従い、自分の手で打って動作を確かめます。

未知の道具の典型的な使い方を体験します。 「デッサン」のようなものです。 説明を読んでもチンプンカンプンなプログラミング言語やライブラリも、自分でプログラムを書いて動かしてみると、あっさりわかります。

初歩的なプログラムでも動くと楽しいものです。 チュートリアルはその趣旨から、手軽な例が多く応用例が少なく、飽きやすい側面もあります。 飽きたらやめましょう。

今は、動画での解説もたくさんあります。 ターミナルやエディタの使い方も、動かしているところを見ながら学んでいけます。

写経は、書き写しながら「ここを変えたらどうなるだろう」と、脱線していく過程に学びがあります。 脱線が苦手な人には向かないようです。

CodeKata

プログラミングの練習問題を解きます。

典型的なプログラムの実装方法と用法を体験します。 「なぞなぞ」のようなものです。問題が解けた瞬間が嬉しいです。

頭を使って疲れる割に、応用に近づいているのかわかりにくいです。 作成したプログラムがうまく動いているか判定するため、 プログラムの入出力を文字列やファイルに制限していることが多いです。 Webアプリケーションやジェネラティブアートのような、見た目の華やかさがありません。 算数の問題を解いるときに感じる「これ何の役に立つんだっけ?」という気分にもなります。

この名前は CodeKata に敬意を払ったものです。 現代では、プログラミングコンテストの練習問題などがこれに当たると思います。

RTA(リアルタイムアタック

なるべく短い時間でプログラムします。

誰かと競い合うのは楽しいものです。 「かけっこ」のようなものです。 要求から実装までの速度の早さは、要求の正しさを検証するときの武器になります。

現代では、競技プログラミングプログラミングコンテストのような成果を公に誇れるような競技があります。 開始時間が決まっていることがあり、生活リズムと合う合わないなどの問題はあります。

競技だけを繰り返しても、速度が上がらないパラドックスもあります。 苦手部分を繰り返し練習するなど、本番とは別に練習を工夫する必要はあります。

ソラプログラミング

似たようなプログラムを何度か書いたら、今度はリファレンスやサンプルコードを見ずに書いてみます。

お手本を見ずにプログラミングできる自信が付きます。 今後、同じことをするときは、調べ直す時間が要らなくなり、コーディング速度が早くなります。

レビューのとき、その場でサンプルコードを書いたり、APIの使い方を説明するときにライブコーディングしたりできるようになります。 応用の効きやすい練習です。

調べることで、新しい手法やAPIを知ることもあります。 常に調べないほうが良いわけではありません。

治具

自分が使うための道具をプログラミングします。

ユーザーが自分なので用途を明確にできます。 レアケースを考慮しないシンプルな機能を、プログラミングできます。 不特定多数の人が使うためのプログラムは、汎用的に書くため手間がかかります。

シンプルなプログラミングを早く実装すると効果がすぐに出ます。 これはソフトウェアの本質的な力強さです。 素早く変えることでいろいろな仕事に対応できる、ハードではないソフトな力です。 どの程度の繰り返し作業には、どの程度のプログラムを書けば効率がよくなるかわかります。 どのような場面でどのようなプログラムが効果を発揮するか知ることができます。

普段、Webアプリケーションを書いているプログラマが、 大量のファイルにを処理するプログラムを書いたりするなど、 いつもとは違う入出力を使う事が多いです。 ソフトウェアの普段知っているのとは違う側面が知れます。 普段と違うプログラミングするのは勉強になります。

使い捨てのプログラムは役に立ちますが、汎用性が低く、 他人に自慢しても「僕の役には立たなさそう」と思われ、反応が得にくい、自慢しにくいのが玉に瑕です。

車輪の再発明

普段使っているライブラリやフレームワークを自分で実装してみます。

自分で実装すると、魔法としか思えなかったものが、現実的な技術に見えてきます。 魔法だと思っていると、何でも解決できると誤解しがちです。 ライブラリやフレームワークの制約や制限が見えてきます。

似た用途のライブラリやフレームワークを比較するときに、 内部の実装がイメージできると、他人の声に惑わされずに、細部を評価できるようになります。 すべてのものを一つのフレームワークで解決する必要がなくなります。

自分の抱えている問題とうまくマッチする、ライブラリやフレームワークが見つからなければ 「ならば作ってしまえ」と思えます。

マズローの言う「ハンマーを持つ人にはすべてが釘に見える」病気に効きます。

パーサープログラミング

パーサーのように一定量を実装するまで価値が出ないプログラムを作ります。

量が価値を生む体験をします。 治具でピンポイントで効果的なプログラミングを体験したのと対象的に、実装量が価値を生むプログラミングをします。 量を作り込むコストを評価できるようになります。

価値が出るまで時間がかかりしんどいです。 実装中「作りきっても価値が出ないのではないか」という不安にさいなまれます。

プログラムオーナー

あるプログラムの発案から設計、実装、ユーザーへのデリバリー、サポートまで自分でやります。

プログラミングに関する、プログラミング以外の部分を一通り体験します。 ソフトウェアと世界の境界を自分が超えることで、現実世界で使いやすいプログラムの届け方、要望の変化に対応しやすい設計方法を習得します。

自分の書いたプログラムが人の役に立つ楽しさがある反面、サポートの煩わしさもあります。

おわり

ネタ切れです。 皆さんが普段やっているプログラミング練習方法にも名前をつけてみてください。

日記を書く

きっかけ

「スーパーエンジニアへの道」の「第七章 自分自身への気づきを高める方法」に「日誌をつける」と書いてありました。 スーパーエンジニアになりたいので、仕方なく日記を書き始めました。

ブログとは違い人に見せないつもりで書いています。 ですので、サンプルは見せません。

メモ帳

日記は物理的なメモ帳に書いています。 具体的にはジェネリックモレスキンです。 たまにしか書いていなかったのでジェネリックでも良かったです。 日記のように、まめに書くと書き味が気になります。 今のメモ帳を使い終わったら、次は正規のモレスキンにしようと思います。

万年筆

筆記具は万年筆を使っています。 20年前に入手したパイロットの万年筆です。 10年ほど使っていませんでしたが、インクを入れ替えたら普通に書けました。 万年筆、マジで万年書けるのか、すげー。

内容

その日、考えているアイデアを列挙しています。 最初はその日にやったこと書いていましたが、イマイチ面白くなかったです。

列挙すると自然と優先順位が決まります。 GTDの収集ステップみたいです。

深く考えるのはTwitterに書いたり、そのテーマでマインドマップを書いたりすれば良いので、 日記では、思考を深めたりしません。 自分は考えて行動しないことが多いので、考えるより行動することに力点を置いています。

効果

前述のように優先順位がつくのが一つです。 迷っている時間を減らして、行動を増やせます。

もう一つ、アイデアを忘れられます。 脳は短期記憶を忘れないために定期的リフレッシュします。 メモ帳に書いて、後日参照可能にすれば、忘れてもよくなります。 リフレッシュに使っていた脳のリソースを、別のことを考えることに使えます。

Legacy on Rails

最近古いバージョンのRailsに触ることが多かったので、二度と使わないで済むことを祈りつつ、得た知見をメモします。

Ruby 2.4 と PostgreSQLRails 3.2

Rails 3.2 と PostgreSQLRuby 2.4で rake db:create だけコケるおもしろ現象に出会いました。

https://github.com/rails/rails/blob/1f2192e46d78ee0ba2b06373f2c24caf8440ff5b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L747

        option_string = options.symbolize_keys.sum do |key, value|
          case key
          when :owner
            " OWNER = \"#{value}\""
          when :template
            " TEMPLATE = \"#{value}\""
          when :encoding
            " ENCODING = '#{value}'"
          when :tablespace
            " TABLESPACE = \"#{value}\""
          when :connection_limit
            " CONNECTION LIMIT = #{value}"
          else
            ""
          end
        end

のsumでエラーになります。

https://github.com/rails/rails/blob/e17e25cd23e8abd45b1706463dd57c90fa6dcb7c/activesupport/lib/active_support/core_ext/enumerable.rb#L58

  def sum(identity = 0, &block)
    if block_given?
      map(&block).sum(identity)
    else
      inject(:+) || identity
    end
  end

で、identityの初期値0と文字列を結合しようとして String can't be coerced into Integer が出ます。 Ruby 2.4 以降はArray#sumが使われて型変換が起きる、のかな?

回避策もおもしろくて、どうもrake db:create以外は大体動くっぽいです。 ので rake db:create の代わりにSQLで直接 CREATE DATABASE "hogehoge" ENCODING = 'unicode'; するのが、Rubyのバージョンを変えたりするより、てっとり早かったです。

Ruby 2.5 と devise 3

Ruby 2.5では、deviseの3系は最新版(3.5.10)が動きません。 github3-stableブランチには修正版が上がっています。

次のようにGemfileでgithubのブランチを指定すれば、Ruby 2.5 と devise 3 を組み合わせて使えます。

gem 'devise', git: 'https://github.com/plataformatec/devise' , branch: '3-stable'

Turbolinks 2.5

Turbolinks.enableProgressBarは2.5までしかありません。 https://github.com/turbolinks/turbolinks-classic/tree/2-5-stable#progress-bar

In Turbolinks 3.0, the progress bar will be turned on by default.

3.0 以上に上げるときは、Turbolinks.enableProgressBarは消しましょう。

mysql2 0.4.10とrails 4.2.5

mysql2 は 0.4.10からMySQL 8 をサポートしています。 https://github.com/brianmario/mysql2/issues/980

rails は 4.2.5からmysql2 0.4.5をサポートしています。 https://qiita.com/park-jh/items/93ec6e967c1731fd90b3

MySQL 8 を使うためにmysql2のバージョンを上げるときは、Railsのバージョンも一緒に上げる必要があります。

Homebrewをインストールし直す

Homebrewの再インストール

GitHub - Homebrew/install: 📥 Homebrew (un)installer を見て

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/uninstall.sh)"

Homebrewでインストールしていた諸々も消えたので入れ直します。

fish-shell

brew install fish

PostgresSQL

brew install postgres
~ pg_ctl -D /usr/local/var/postgres start
pg_ctl: another server might be running; trying to start server anyway
waiting for server to start....2020-06-21 01:06:21.086 JST [59996] FATAL:  lock file "postmaster.pid" already exists
2020-06-21 01:06:21.086 JST [59996] HINT:  Is another postmaster (PID 607) running in data directory "/usr/local/var/postgres"?
 stopped waiting
pg_ctl: could not start server
Examine the log output.

起動時に色々言われるので地道に対応します。

rm /usr/local/var/postgres/postmaster.pid
mkdir /usr/local/var/postgres/{pg_tblspc,pg_twophase,pg_stat,pg_stat_tmp,pg_replslot,pg_snapshots}/
cd /usr/local/var/postgres/
mkdir pg_commit_ts
mkdir -p pg_logical/snapshots
mkdir -p pg_logical/mappings

Ruby

せっかくなのでrbenvをgitから入れます。

過去に入れたバージョンを一旦逃します。 再インストールするとそれぞれコンパイルする必要があって時間がかかります。

mv .rbenv/ .rbenv_old/
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
cd ~/.rbenv && src/configure && make -C src
set -Ux fish_user_paths $HOME/.rbenv/bin $fish_user_paths
~/.rbenv/bin/rbenv init

インストール済みのバージョンを戻します。

mv .rbenv_old/versions/* .rbenv/versions/.

ruby-buildも入れます。

mkdir -p "$(rbenv root)"/plugins
git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build

最新のRubyはHomebrewで入れていたので、rbenvでインストールします。

rbenv install 2.7.1
rbenv global 2.7.1

Ruby 2.6.5を動かそうとすると

~ ruby
dyld: Library not loaded: /usr/local/opt/gmp/lib/libgmp.10.dylib
  Referenced from: /Users/shigerunakajima/.rbenv/versions/2.6.5/bin/ruby
  Reason: image not found
fish: 'ruby' terminated by signal SIGABRT (Abort)

libgmpを求められるので、インストール

brew install gmp

Ruby on Rails

Railsを動かそうとすると

~ rails c
/Users/shigerunakajima/.rbenv/versions/2.6.5/lib/ruby/2.6.0/yaml.rb:3: warning: It seems your ruby installation is missing psych (for YAML output).
To eliminate this warning, please install libyaml and reinstall your ruby.

libyamlを求められるので、インストール

brew install libyaml

現在のbrew list

~ brew list
fish        gmp     icu4c       krb5        libyaml     openssl@1.1   pcre2       postgresql  readline

再インストール前のも取っておけばよかったな・・・

追記

gitを入れ忘れていました。

brew install git

追記追記

RubyMineのターミナルに教えるrbenvのパスを更新しました。 ~/.config/fish/config.fish にset PATH /usr/local/bin $PATHと書いていたのを、set PATH /Users/shigerunakajima/.rbenv/bin/ $PATHに更新しました。

RubyMineのターミナルが壊れた話 - @ledsun blog