週刊Railsウォッチ(20170908)Rails 5.1.4と5.0.6リリース、コード書換え支援gem「synvert」、遅いテストを分析するTestProfほか

追記: るびまのRubyKaigi 2017特集に本記事のリンクを掲載いただきました。
ありがとうございます!

こんにちは、hachi8833です。ジェットコースターみたいに上下する気候はこたえますね。

6日に発生した太陽表面での大規模爆発の影響が本日15:00から夜半にかけて地球規模で生じるそうで、高緯度を中心にオーロラ発生が見込まれるほか、通信機器やGPSに障害が出るかもしれないとのことです。この時期に大きなリリースや祝賀ミサイル発射などをご検討の方は十分ご注意ください。


https://www.nict.go.jp/press/2017/09/07-1.htmlより

臨時ニュース: Rails 5.1.4と5.0.6が正式リリース

本日出たてほやほや。バグ修正が中心です。

いつもの記念写真です。

RubyKaigi 2017@Hiroshima開催迫る

今年のRubyKaigiももう再来週ですね。9/18(月)〜9/20(水)、広島の国際会議場です。

RubyKaigiは、ビジネス志向寄りのRuby World Conferenceと対照的にギーク色が強く、Rubyエンジニアの祭典という側面が前面に出ています。

年号付きの大規模なRubyKaigiは、会場のご当地名物をシンボルに採り入れています。昨年は京都の風景でしたが、今年はやはり広島・厳島神社の鳥居が使われています。

私も昨年のRubyKaigi 2016@京都や今年の大江戸Ruby会議に参加してみましたが、いずれもいい年こいてギンギンに意識が高まってしまったのが思い出されます。

Ruby界隈の特徴として、うかつな質問とかしたら後ろからバッサリ斬られそうなコワイ人がとんと見当たらないのがとてもありがたい点です。社交辞令ではなく、ユーモアやジョークを真面目に愛するいい人たちばかりだったという思いです。今回気になる点があるとすれば、今年の会場ではどのぐらいスムーズにWiFiにつなげるかぐらいでしょうか。

皆さまも今年こそ思い切って参加してみてはいかがでしょう。得られるものは想像以上に大きいと思います。
弊社からはTechRachoでおなじみmorimorihogeと、不肖私めも参加いたします。

Ruby Kaigi 2016に全日参加しました!(hachi8833)

追記

Rails公式

Rails公式の更新情報がここ数週間怒涛のように増えていて、遠い昔の夏休みの宿題を思い出してしまいました。

RailsのSDocを更新

group :doc do
-  gem "sdoc", "> 1.0.0.rc1", "< 2.0"
+  gem "sdoc", github: "robin850/sdoc", branch: "upgrade"
   gem "redcarpet", "~> 3.2.3", platforms: :ruby
   gem "w3c_validators"
   gem "kindlerb", "~> 1.2.0"

コードの変更量は少ないですが、SDocのテーマ変更やSEOタグ追加などいろいろ変わるようです。

SDocドキュメントってどこに行ったら見られるんだろうかと一瞬考えてしまいましたが、Railsディレクトリでsdocを実行して生成するのでした。すっかり忘れていましたが、ドキュメントの生成はかなり時間がかかるので、.gemrcに以下を書いてスキップしている人がほとんどかと思います。

# ~/.gemrc
install: --no-rdoc --no-ri
update:  --no-rdoc --no-ri

今回の変更はまだmasterブランチにしかないので、今日の5.1.4にはまだ含まれていません。以下は更新前のSDoc動画です。そのうちhttp://api.rubyonrails.org/で使えるようになるのでしょうか。

ActiveStorageのドキュメント更新

# activestorage/README.md
...
-Image files can further more be transformed using on-demand variants for quality, aspect ratio, size, or any other
-MiniMagick supported transformation.
+Image files can furthermore be transformed using on-demand variants for quality, aspect ratio, size, or any other [MiniMagick](https://github.com/minimagick/minimagick) supported transformation.
...

つっつきボイス: 「最初はからっぽだったActiveStorageドキュメントも着々と整備されてますね」「エライエライ」

「ところで、Railsガイドにはもう反映されてるかしら」「うむ、ないでござる」「じゃEdgeGuidesはどうだろう: こっちに先に掲載されるのが普通なので」


edgeguides.rubyonrails.orgより

「こっちにもまだないか」「EdgeGuidesなんてのがあったのね: シラナカッター」

Rails: 先々週の改修

Hash#deep_mergeの改良

あまり見かけない1ファイルのみの変更です。

# activesupport/lib/active_support/core_ext/hash/deep_merge.rb
  # Same as +deep_merge+, but modifies +self+.
   def deep_merge!(other_hash, &block)
-    other_hash.each_pair do |current_key, other_value|
-      this_value = self[current_key]
-
-      self[current_key] = if this_value.is_a?(Hash) && other_value.is_a?(Hash)
-        this_value.deep_merge(other_value, &block)
+    merge!(other_hash) do |key, this_val, other_val|
+      if this_val.is_a?(Hash) && other_val.is_a?(Hash)
+        this_val.deep_merge(other_val, &block)
+      elsif block_given?
+        block.call(key, this_val, other_val)
       else
-        if block_given? && key?(current_key)
-          block.call(current_key, this_value, other_value)
-        else
-          other_value
-        end
+        other_val
       end
     end
-
-    self
    end
  end

つっつきボイス: 「↑再帰やってるかなと思ったけどやってなさげ」「deepの付くコピーやマージはRuby言語側で直接サポートしていないこともあって実装もいろいろ、かつ改良が絶えない感じですね。」

「deepなんちゃらって、やっぱり言語でやらない方がいいんでしょうか?」「ワイはそう思う: deepなんちゃらは一般化しづらいし、言語で責任取りきれないっしょ」

Eager loadingで一発目のレスポンスタイムを短縮

次のPRとも関連しているようです。

# actionmailer/lib/action_mailer/railtie.rb
+    initializer "action_mailer.eager_load_actions" do
+      ActiveSupport.on_load(:after_initialize) do
+        ActionMailer::Base.descendants.each(&:action_methods) if config.eager_load
+      end
+    end
+
     config.after_initialize do |app|
       options = app.config.action_mailer

:action_controllerでのパラメータ設定読み込みを繰り返さないようにした

# actionpack/lib/action_controller/railtie.rb
-      ActiveSupport.on_load(:action_controller) do
+      ActiveSupport.on_load(:action_controller, run_once: true) do
         ActionController::Parameters.permit_all_parameters = options.delete(:permit_all_parameters) { false }
         if app.config.action_controller[:always_permitted_parameters]
           ActionController::Parameters.always_permitted_parameters =
# activesupport/lib/active_support/lazy_load_hooks.rb
       base.class_eval do
         @load_hooks = Hash.new { |h, k| h[k] = [] }
         @loaded     = Hash.new { |h, k| h[k] = [] }
+        @run_once   = Hash.new { |h, k| h[k] = [] }
       end
     end

...

+    private
+
+      def with_execution_control(name, block, once)
+        unless @run_once[name].include?(block)
+          @run_once[name] << block if once
+
+          yield
+        end
+      end
+
+      def execute_hook(base, options, block)
+        with_execution_control(name, block, options[:run_once]) do

つっつきボイス: 「この2つのコミット、関連してそうですね」「実装上はたぶん独立してるけど、目的は関連してるかも」
「1つめのif config.eager_loadで、設定ファイルからでもコントロールできるようにしてるのか」

uniquenessバリデーションで:scopeが効かないことがあったのを修正

# activerecord/test/cases/validations/uniqueness_validation_test.rb
+  def test_validate_uniqueness_with_scope_invalid_syntax
+    error = assert_raises(ArgumentError) do
+      Reply.validates_uniqueness_of(:content, scope: { parent_id: false })
+    end
+    assert_match(/Pass a symbol or an array of symbols instead/, error.to_s)
+  end

つっつきボイス: 「おおー、uniquenessでは今まで:scope使えてなかったのか」「改修部分よりテストの方がわかりやすいかと思ってテストを引用してみました」


ソースのactive_record/validations/uniqueness.rbを見ると、scopeのドキュメントは前からあったようです。

Ruby trunkより

String#valid_encoding?の副作用

content = "\xE5".dup.force_encoding(Encoding::ASCII_8BIT)

content.encode(Encoding::UTF_8, Encoding::UTF_8, invalid: :replace, replace: '?')
=> "?"

content.valid_encoding?

content.encode(Encoding::UTF_8, Encoding::UTF_8, invalid: :replace, replace: '?')
=> "\xE5"

つっつきボイス:content.valid_encoding?って何じゃらほいと思ったら、これを実行したら結果が変わってたってことか: これはイヤなバグだ」「破壊的でないはずのメソッドが破壊的に振る舞ってたのか(怖」

「ところでEncoding::ASCII_8BITってエンコードひどいw: UTF-8とすら互換性なくなりますね」

ハッシュが空なのにHash#compact!nilを返す

irb(main):001:0> {}.compact!
=> nil

# For Comparison
irb(main):002:0> { foo: nil }.compact!
=> {}
irb(main):003:0> {}.compact
=> {}
irb(main):004:0> { foo: nil }.compact
=> {}

つっつきボイス: 「Rubyだと{x: 3}.compact!{x: 3}じゃなくてnil返してる? 一瞬意味わからんと思ったけど、配列だと[3].compact!nilになるから、それと揃えたってことか」
!系メソッドの戻り値ってあてにしない方がよさげですなー」
「どうやら、挙動はこのままが正しくて、ドキュメントの方が違ってたってことみたいですね↓」

compact! → hsh
Removes all nil values from the hash. Returns the hash.

Rubyだと、他に返すものがないからとりあえずnilを返す、みたいな破壊的メソッドがそこそこある気がしました。
nilを埋め草的に使うのはあんまりよくなさそうな気がします。

Rails

JOINすべきかどうか、それが問題だ(Ruby Weeklyより)

良記事です。


つっつきボイス: 「このタイトルも、記事の小見出しもシェークスピアのハムレットをもじりまくってるんですよw: 誰がうまいこと言えと」「何人わかるんかしらそれ: ドラクエで説明してくれー」「イギリス人かと思ったけど著者名ラテン系だし」

「N+1を回避するために、INNER JOINなのかOUTER JOINなのか迷うのに、さらにRailsで eager_load とか #includes とか色々あって、どれにしたらいいのか考えるのがつらいでござるよ」「この記事、まさにそのあたりを衝いてるみたい: 翻訳したろ」

Rails: N+1クエリを「バッチング」で解決するBatchLoader gem(翻訳)


ついでながら、actの本来の意味は「演技する」や「(劇の)場面」のことだったりします。サブタイトルに「An act of #includes」とあるのもまさにそれです。第一幕、第二幕みたいなのをact I、act IIなどと表したりします。

英語だと「演技する」「演じる」「上演する」「演奏する」がplayやperformanceやactという基本的過ぎる言葉で表されることがとっても多いので、こういう言葉が短い見出しで使われていると意味を取り違えないよう緊張してしまいます。

⭐synvert: Rubyのコードをいろいろ変換するリファクタリングgem⭐(Ruby Weeklyより)


xinminlabs.github.io/synvertより

あまり追えていませんが、かなりよさげなコード変換ツールです。

gem install synvert  # これでインストールできる
synvert --sync       #最初に一回だけ実行: スニペットを取ってくる
synvert -l           #現在のスニペットのリストを表示↓

default
check_syntax
factory_girl
fix_deprecations
use_new_syntax
use_short_syntax
rails
convert_dynamic_finders
convert_mailers_2_3_to_3_0
convert_models_2_3_to_3_0
convert_rails_env
convert_rails_logger
convert_rails_root
convert_routes_2_3_to_3_0
convert_views_2_3_to_3_0
redirect_with_flash
strong_parameters
upgrade_2_3_to_3_0
upgrade_3_0_to_3_1
upgrade_3_1_to_3_2
upgrade_3_2_to_4_0
upgrade_4_0_to_4_1
upgrade_4_1_to_4_2
upgrade_4_2_to_5_0
upgrade_5_0_to_5_1
rspec
be_close_to_be_within
block_to_expect
boolean_matcher
collection_matcher
custom_matcher_new_syntax
explicit_spec_type
its_to_it
message_expectation
method_stub
negative_error_expectation
new_config_options
new_hook_scope
one_liner_expectation
pending_to_skip
remove_monkey_patches
should_to_expect
stub_and_mock_to_double
use_new_syntax
ruby
block_to_yield
fast_syntax
gsub_to_tr
iconv_to_encode
keys_each_to_each_key
map_and_flatten_to_flat_map
merge_to_square_brackets
new_hash_syntax
new_lambda_syntax
new_safe_navigation_operator
parallel_assignment_to_sequential_assignment
remove_debug_code
use_symbol_to_proc
shoulda
fix_deprecations
use_matcher_syntax
use_new_syntax
will_paginate
use_new_syntax

備え付けのスニペットもいろいろあり、upgrade_5_0_to_5_1のようなアップグレード向けの書き換えや、new_hash_syntaxのような非推奨文法を推奨文法に書き換えられるスニペットだけでも便利そうです。

convert_models_2_3_to_3_0のようなスニペットは、Rails 2系から3系へのアップグレードのような考えるだけでつらくなる作業を助けてくれそうです。DSLでスニペットを書くこともできます。

railsdiffと合わせて使えば、Railsのアップグレードがとってもはかどりそうな予感。


つっつきボイス: 「こやつはrubocopチャンと喧嘩するやつ?」「どっちかというと書き換えがメインなんで、住み分けできそうですね」


期待を込めて、今週の⭐を進呈いたします。おめでとうございます。

ドメインイベントでRailsの複雑なドメインを分割する(Ruby Weeklyより)


blog.carbonfive.comより


つっつきボイス: 「この場合のドメインは設計上の話でござるか」「ドメインって言葉、文脈でいろいろ変わってくるのでめんどいですね」
「Passengerとルーティングを例に取ってる: このぐらいだったらまとめて扱ってもいい気はするけど、分離してイベントでゴニョゴニョする方が幸せになれるっていう意図なのかな」「ビジネスロジックを分離するみたいな、理想だけど実践するのは大変なやつに見えますね: この間のウォッチ↓で扱ったTrailbrazerをちょっとだけ連想しました」

週刊Railsウォッチ(20170804)Rails 5.1.3と5.0.5が正式リリース、GitHubでローカライズ基盤サービス、正規表現で迷路を解くほか


trailblazer.toより

Rails + ActionCableで即応性の高いアプリを作る(RubyFlowより)


www.icicletech.comより


つっつきボイス: 「原文でReal Timeって言ってるけど、ガチでリアルタイム処理研究している人からツッコミ入りそうな気がしましたw: そのあたりよくわかってませんが」「記事は実用的でよさげ」

TestProf: Rubyのテストが遅くなる原因を診断するツール(Ruby Weeklyより)


evilmartians.comより

テストのどこで時間がかかっているのかをプロファイリングしてくれます。CIに組み込んでくれとツールが私の耳元でささやいているような気がしました。
記事もツールの紹介だけではなく、自分でプロファイルするうえでも役に立つことが書かれており、Tips to improve speed of your test suiteという記事を参考にリストアップしています。


つっつきボイス: 「このツールよさそう: アプリの改修が進むとテストも増えて時間かかるので、こういう問題は切実」「遅いテストは、開発者の意欲をザクザク削ってしまうのもデメリットですね」「そうなんでござるよ: デプロイのたびにCIで何十分も待たされるとか、耐え難い」

関数は小さい方がよいとは限らない(Awesome Rubyより)


edium.com/@copyconstructより

Rubyなどの言語ではコードをDRYに書くことが推奨されていますが、ルールを盲目的に守ればいいというものではないという主張です。ちょっと長いですが、良記事だと思います。


つっつきボイス: 「DRYに書けばいいってもんじゃない、と言ってますね」「確かに: メソッドを細かく割りすぎると今度は読みにくいんですよ、マジで」
「関数やメソッドを細かく分割しすぎると、名前つけるだけで大変だし、切れっ端みたいなコードがあちこちで再利用されると副作用が変なところに出てきたりする、とも言ってます」「まったくじゃわいw」


ところで、「considered Harmful」は最近流行りの煽り見出しのようですね。↓こういう記事の見出しなら内容に合ってると思いますが、何度も見かけるとちょっと鼻についてしまいます。

Railsの`CurrentAttributes`は有害である(翻訳)

コード品質ツールチェックの効果についてのアンケート(Awesome Rubyより)

さっと読める記事です。


rubyblog.proより


つっつきボイス: 「ツールで品質が良くなりましたか?というアンケート↑、2割近くが『なってない』って答えてるw」
「↓これも切実だなー: ツールにどこをチェックして欲しい?の回答みると、complexity(複雑さ)とかデザパタとかOOP準拠とかコードの臭いとかが上位」「ツールが苦手なところばっかりですねw: スタイルみたいな型にはめるチェックはだいぶできるようになりましたが」
「もちろんツールがないと困るし、コードレビューでスペースインデントみたいなどうでもいいところで時間取られたくないでござるよ」「まったく」


rubyblog.proより

FabricationとFactoryGirl、どっちがいいの?(Ruby Weeklyより)


ksylvest.comより

ざっくりベンチ取ってるだけの記事なので、すぐ読めます。結果はここには書きません。

factoryとfixtureを両方使いたいお(RubyFlowより)


evilmartians.comより


つっつきボイス: 「一つ前の記事と見出しがよく似てますw」
「あー、factoryとfixtureか: 自分の理解ではfixtureは↓こんなyamlとかの固定テストデータ、factoryは動的に生成されるテストデータ」「fixtureの本来の意味は『簡単に取り外せない(ホテルなんかの)備品』ですね」「まさしく、fixtureは備品のイメージだわ: 無理してどっちかに統一することはないでござるよ」

rubyonrails:
  id: 1
  name: Ruby on Rails
  url: http://www.rubyonrails.org

google:
  id: 2
  ;name: Google
  url: http://www.google.com

「記事の結論↓: factoryとfixtureは適材適所で使い分けよ、って」

Our conclusion is obvious: do not oppose factories and fixtures, bring them all and in the darkness bind them to rule your test suites mightily.


ところで、年がバレるのも構わずにIT業界の英語でやたら使われるのが、RPGの遠いご先祖とも言える「ロード・オブ・ザ・リング」の冒頭のナレーション↓のもじりです。上のは無理やり過ぎてだいぶ壊れてますが。

Three Rings for the Elven-kings under the sky,
Seven for the Dwarf-lords in their halls of stone,
Nine for Mortal Men doomed to die,
One for the Dark Lord on his dark throne
In the Land of Mordor where the Shadows lie.

One Ring to rule them all, One Ring to find them,
One Ring to bring them all and in the darkness bind them
In the Land of Mordor where the Shadows lie.
https://en.wikipedia.org/wiki/One_Ringより

「Oneなんとか、Oneなんとか、Oneなんとか」が出てきたら、「ああアレね」と生暖かい目で華麗にスルーしてあげてください。ついでながら、Martian Chroniclesというブログサイト名にも年を感じてしまいました

Railsのポリモーフィック関連付けを学ぶ(Ruby Weeklyより)


semaphoreci.comより

目新しい内容ではなさそうですが、シンプルなのですぐ読めそうです。

Visual Studio CodeでRailsしてみたった


medium.com/@PaulWritesCodeより

言われてみればVS Studioでもできそうですね。やってる人をまだ見たことがありません。

Rubyで混乱しやすい機能6つ(RubyFlowより)

著者はどことなくヴェトナム人っぽい名前ですね。rsyncを6歳児にもわかるように説明するという記事なども面白そうです。

  1. []メソッド
  2. %演算子
  3. Integer#zero?メソッド
  4. $[数字]グローバル変数
  5. 万能すぎてつらいTime.parse
  6. delegatorの挙動がRubyドキュメント↓と違う

Equality — At the Object level, == returns true only if obj and other are the same object. – Ruby documentation.


つっつきボイス: 「↓6.はちょっと言い過ぎな気がするかも: equalityとは何かみたいなのは文脈にもよるんだし、obj idが違うから同じではいけないというものでもないんじゃなかろうか」

# https://hqc.io/posts/six-confusing-features-in-ruby より
# 6.のコード
class Foo < Delegator
  def initialize(the_obj)
    @the_obj = the_obj
  end

  def __getobj__
    @the_obj
  end
end

foo = Foo.new(1)
foo.inspect # => 1
foo == 1 # => true

「そういえばRubyのトリプルイコール===case文の条件以外では使わないこと、というのがRubyスタイルガイドにありました」「そうそう」「RubyとJavaScriptで===の挙動が全然違うのってつらいですね、あれw」

Rubyの===演算子についてまとめてみた

Gemを書くときのチェックリスト(RubyFlowより)


gemcheck.evilmartians.ioより

ブラウザ上でそのままチェックリストをオンオフできます。
こういう形式の記事、結構便利かもです。

RubyでSlackコマンドAPIを書く

Railsでの画像アップロードをShrine.rbとDropzone.jsで実現(RubyFlowより)


codyeatworld.comより

4回シリーズの記事です。


つっつきボイス: 「Amazon S3に置くのが前提みたいです: ところでRailsの定番アップローダーgemって何でしたっけ」「carrierwave

JavaScript

deeplearn.jsをGoogleが発表

元記事: Harness the Power of Machine Learning in Your Browser with Deeplearn.js
公式サイト: https://pair-code.github.io/deeplearnjs/


research.googleblog.comより

機械学習も着々とパッケージ化されてきてますね。実は日本語記事も出ています。

Upterm: Electronベースのターミナルソフトウェア

★16000超えの快挙です。


つっつきボイス: 「自分のMacbook Proに入れてみました: ほれほれ」「おおお、凄いでないのコレ!: htopの後に自動で画面キャプチャまでしてくれた」
.bashrcとかまったく読み込まれなかったので、ほとんど素っ裸のシェルですが、それでもこれだけ使えるので、とにかく見せ方がうまいですね」

Android

flexbox-android


github.com/google/flexbox-layoutより

こちらもGoogle公式のライブラリです。こちらも★9000超えです。


つっつきボイス: 「これイイナー: Androidじゃなくても使いたい」

その他

homebrew-cask-upgrade: caskのバージョンチェックとアップグレードツール

個人的にとても便利だったので。合言葉はbrew cu
むしろ、これなしでbrew cask使いたくないくらいです。

プログラマーが健康と引き換えに失ったもの(RubyFlowより)


hackernoon.comより

急な激しい運動は身体を痛める元になるので、皆さまもご注意。

bettercap: 侵入テスト向けの中間者攻撃ツール(Ruby Weeklyより)

いわゆる『人に向けてはいけない』ツールです。

番外

これ欲しい

神経線維が光ファイバーになる日は来るか

あれは何だったのか


今週は以上です。

バックナンバー(2017年度)

今週の主なニュースソース

ソースの表記されていない項目は独自ルート(TwitterやRSSなど)です。

Rails公式ニュース

Ruby Weekly

Awesome Ruby

RubyFlow

160928_1638_XvIP4h

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833

コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。
これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。
かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。
実は最近Go言語が好き。
仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ