Tech Racho エンジニアの「?」を「!」に。
  • 開発

週刊Railsウォッチ(20190806-2/2後編)RSpec CopのLeakyConstantDeclaration、serveoでゼロコンフィグ公開、RuboCopのPerformance/RegexpMatch改修ほか

こんにちは、hachi8833です。来週の週刊Railsウォッチはお盆休みのためお休みをいただきます🙇。先祖の供養を忘れずに。

  • 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください

今回は「公開つっつき会」第13回を元にしています。ご参加いただいた皆さま、ありがとうございます!

Ruby

awesome-ruby.com: 巨大なおすすめgemリストサイト(Ruby Weeklyより)


同サイトより

巨大すぎてつっつき中にチェックしきれないのは確実です。Awesome Rubyという別のサイト↓もあるのでややこしいですね。


つっつきボイス:「Awesomeなんちゃらって流行ってましたよね😆」「特にGitHub Trendingにやんなるほどありますね😆」

「とりあえずこういうのやるなら年度付けて欲しいし😆」「たしかに〜😆」「こういうのは、いつのAwesomeほげかですごく変わりますし😆」「年と、あと月も欲しいです」

後で気づきましたが、リポジトリは★10000越えてますね😳。issueには追加リクエストがずらりと並んでいます。


同リポジトリより

RuboCop1.4.1のPerformance/RegexpMatch改修

#5589のフォロー。
このPRは、ガード条件のif分岐でMatchDataが検出されない場合にPerformance/RegexpMatchが以下のようにfalse negative(偽陰性)になる問題を修正する。
この問題はこのコードで検出された。@kamipoさんからのフィードバックに感謝。

% cat example.rb
# frozen_string_literal: true

raise unless ex.message =~ /can't modify frozen IOError/

% bundle exec rubocop --only Performance/RegexpMatch
Inspecting 1 file
.

1 file inspected, no offenses detected

他に#5569のコメントもフォローした。
このPRは、ガード条件の後にMatchDataが存在する場合にPerformance/RegexpMatchがfalse negative(偽陽性)になる問題を防止する。以下はfalse negativeの例。

def foo
  return if /re/ =~ str

  # `Regexp.last_match[1]` cannot be referenced if changed from `=~` to `match?`.
  do_something(Regexp.last_match[1])
end

#73より大意


つっつきボイス:「@kamipoさんが喜んでるツイートを見かけたので拾いました」「performance copのfalse negativeとfalse positiveを修正したのね😋」「こういうのが前は通ってたのか〜」「どこにあるのかなと思って最初うっかりRuboCop本家を探しちゃったんですけど、rubocop-performanceにありました😅」「今のRuboCopは分かれてますね☺️」「rubocop-performanceを-aでざざっとオートコレクトするのは便利だったりしますよね」「怒られた箇所を全部修正するのは大変ですけど😅」

現在の主なRuboCopリポジトリを拾ってみました。

ブロック内の定数がトップレベルから参照できる問題(Ruby Weeklyより)

# 同記事より
    A = Class.new do
      B = 1
    end
    A::B # NameError: uninitialized constant A::B
    B # => 1

つっつきボイス:「leaky constants?」「ブロックの中で定数を宣言するとトップレベルの定数になるんだそうです」「つかClass.newってブロック取れるんだ!😳」「Module.newとかClass.newブロック取れたと思いますけど、Object.newだとブロック取れるかな?」

なお、後でRuby 2.6.3+Pryで試すとObject.newもブロックを取ることは一応できました↓。ただしObject.newのブロック内で宣言した定数にはトップレベル/名前空間どちらからもアクセスできませんでした。

» E = Object.new do
»   F = 3
» end
#» #<Object:0x000055f0d6492290>
» E::F
TypeError: #<Object:0x000055f0d6492290> is not a class/module
from (pry):14:in `__pry__'
» F
NameError: uninitialized constant F
from (pry):15:in `__pry__'

Class.newの中で宣言したモジュール名やクラス名もトップレベルになると↓」

# 同記事より
    A = Class.new do
      module B
      end
      class C
      end
    end
    A::B # NameError: uninitialized constant A::B
    A::C # NameError: uninitialized constant A::C

「そしてモジュールの中でClass.newすると、トップレベルではなくそのモジュールのレベルになる↓...」「うひょ〜😅」

# 同記事より
    module M
      A = Class.new do
        B = 1
      end
    end
    M::A::B # NameError: uninitialized constant M::A::B
    M::B # => 1

「この辺の挙動がRSpecで問題になることがあるっぽいです」「このRSpecコード↓だと名前空間がかぶるということかな」「記事では上と下が逆順で実行されるとsuperclass mismatchが起きるそうです😇」「特定のテストだけで使うモックの名前がどちらもトップレベルでかぶると上書きしちゃうみたいな」「ありそう〜😅」

# 同記事より
    # spec/a_spec.rb
    RSpec.describe A do
      class DummyClass < described_class
      end

      it { ... }
    end

    # spec/b_spec.rb
    RSpec.describe A do
      class DummyClass
      end

      it { ... }
    end

「たしかにこれ知らずに踏みそう😇」「ぱっと見にわかりづらいけど😅」「実行順序をランダムにしておくとたまに起きて、実行順序を固定すると起きなくなるみたいな😅」「しかも、たとえテストが動いたとしても実はちゃんとテストできてないという😆」

「これ、仕様としてどうなんでしょう?🤔」「どうなんでしょう〜😅」「モジュールの中とかではなくて.newブロックの中だからいいのかなという気もしますけど😅: 定義スコープではないところでの定数宣言ですし」「単なるブロックの中での定数宣言だから、グローバルな定数という扱いになるというか」「インデントだけ見ると軽くギョッとしますけど😆」

「というような問題をRSpec CopのLeakyConstantDeclaration↓で検出できるようになったと記事にありますね😋」「ほほぉ〜😍」

valvat: VAT番号をバリデーション(Ruby Weeklyより)

# 同リポジトリより
Valvat.new("DE345789003").valid?
=> true or false

Valvat.new("DE345789003").exists?
=> true or false or nil

Valvat::Syntax.validate("DE345789003")
=> true or false

つっつきボイス:「VAT番号ってこれで初めて知りました」「VATはヨーロッパの国で使われてるヤツですね☺️」「納税のために企業に付けられる番号だとか」「海外旅行とかでレシートを集めて申請すると後で還付されるとかそういう感じだったかな?」「自分らに関係あるとしたらそういうときぐらいかも🤔」「あとは個人輸入するときにこういうのを税務署申請するとかもありそう」「ヨーロッパの人ならこういうgem欲しいでしょうね☺️」「EU圏内に限った話のようですし」

参考: 付加価値税登録番号(VAT number) - Wikipedia
参考: 海外通販では、VAT(付加価値税)を請求されるの!? | HUNADE EPA/FTA/貿易ガイダンス


「ついでに日本にもマイナンバーのgemあるかなと思って探したんですが、意外にも以下のtsubakiというgemぐらいしか見つからなくて😅」「このgemはシンプルなマイナンバーの番号チェッカーのようですね☺️」

参考: マイナンバーを検証する gem を作った - Qiita
* リポジトリ: kufu/tsubaki: My Number & Corporate Number validator


同リポジトリより

# 同リポジトリより
# Verifies the format and its check digit with `strict` option:
validates :digits, my_number: { strict: true, allow_blank: true }

# Without strict option, it verifies only the length of the digits:
validates :digits, my_number: true

# Or if a My Number contains any dividers, specify it:
validates :digits, my_number: { strict: true, divider: '-' } # => 4652-8126-6333 should be valid

なお、同リポジトリに以下のサイトも紹介されていました。

参考: 擬似マイナンバーくん

その他Ruby

クラウド/コンテナ/インフラ/Linux/Serverless

ECSがロードバランサーのターゲットグループを複数サポート

はてブで見つけました。

Amazon ECS services now support multiple load balancer target groups

これのせいで多段リバプロをしていたな

2019/07/31 08:54

参考: Application Load Balancer を作成し ECS タスクを自動登録する


つっつきボイス:「この記事も含めて、最近いくつかの記事情報を社内Slackで寄せてもらってとってもうれしいです😂」「タイトルのmultiple load balancer target groupsですけど、これはmultipleがtarget groupsにかかってるのでは?」「あ、仮タイトルが『マルチプルロードバランサーのターゲットグループ』という直球のままでした😅(今は修正済み)」「この辺は知らないとわかりにくいですし☺️」

今度はserveo登場


同サイトより


つっつきボイス:「serveoも先週あたりに話題になってましたね: 先週話題にしたngrok(ウォッチ20190731)のオープンソース版的な」「サーヴェオ」

「つまりngrokはオープンソースではない?」「ngrokはバイナリが配布されていて、フリーでも使えるけどお金払わないと自分のドメインが使えないなどの違いがありますね」「なるほど!」


ngrok.comより

「今回お集まりの皆さんの中でngrokお使いの方は?」「まだほとんどいないか...」

「ngrokは知らないよりは知っておいた方がいい便利ツールです👍」「特にスマホでテストするときに、自分のローカル環境で立ち上げて接続するときにいちいちプライベートIPアドレスをチェックするのって面倒じゃないですか: そこでngrokとかこのserveoを使うと、普通にインターネット上にURLをHTTPSで公開できるので便利ですよぉ〜❤️」「Railsでなくてもいいんですよね?」「普通にポートをつないでくれるので、だいたい何でも公開できます」「おぉ〜」

「たとえばローカルでRailsサーバーを立てて、顧客とSlackでやりとりしながらURLを渡して、こっちで編集しながら変更点をその場で見てもらえたりできますし😋」「今までだとたとえばcapistranoデプロイとかしないと見せられなかったのがコマンド一発で公開できますし💪」「『顧客が本当に必要だったもの』感😆」

「最初はserveoがどういう仕組みでやってるのかと思ったけど基本的にngrokと同じようなことやってますし😆」「なるほど!」「ngrokは公式のバイナリを取ってきて実行するんですけど、serveoはこんなふうに↓sshでポートフォワーディングすればできるのでツールをインストールする必要すらない😋」

$ ssh -R 80:localhost:3000 serveo.net

参考: ポートフォワーディングとは - IT用語辞典 e-Words

その他Linux


つっつきボイス:「始まる前の雑談でもこの話出てましたね☺️」「今のLinuxでも/dev/fd0とかデフォルトで使えてるのかな?...だめだ、自分の環境だと見えない😇: 物理Linuxサーバーを見ればわかりそうだけど」「どっちにしろ今後フロッピー使いそうにないですし😆」「FDドライバがなくなるとかじゃなくて、単にメンテする人がいなくなったと」

参考: FD/CD のマウント

I'm not sentimental. Good riddance.
同コミットより

Good riddanceが「せいせいした」なんですね。

JavaScript

Vue・React・Angular、どれがパフォーマンスいい?


同記事より


つっつきボイス:「フロントエンド寄りのパフォーマンス比較をあまり見たことがなかったので」「あ、パーティクルをばらまくアニメーションで比較してるのね😳」

今回の検証のように大量のオブジェクトをリアルタイムで描画更新するようなケースは、ReactやAngularではほとんどありません。フレームレートとメモリ使用量については、極限の状態においての負荷を検証したので、小規模なプロダクトにおいて負荷が問題になる場面が少ないことは補足しておきます
ライブラリの特性を知ったうえで技術選定をすることはリスクの早期発見につながるはずです。本記事が技術選定の一助になれば幸いです。
同記事より

「まあ自分たちだとパーティクルを動かすのにAngularとかReactとか使わないかな😆、どのぐらい実用的なベンチマークなんだろう?」「記事の最後のまとめにこう↑書いてあるし😋」「実用的かどうかは別にして、ひとつのベンチマークというか」「RubyのベンチマークをOptCarrotでやってるのにもちょっと似ているというか、OptcarrotでGCが速くなってもRailsが速くなるとは限らないみたいな😆」「Optcarrotはファミコンのエミュレータでしたね」

「上の記事を書いた方はこういうサイト↓をやっているそうです」「すごい凝ってる...!」「フロント強そう」

つっつき終了後の親睦会で、こちらのサイトを環境映像的に映しました😋。

言語・ツール

Pythonのregexの挙動が変わる😨

RubyのOnigmoはどうなんだろう...

Python 3.7まで(VERSION0)の主な古い振る舞い:

  • ゼロ幅マッチの扱いが正しくなかった
    • .splitはゼロ幅マッチの箇所でsplitしない
    • .subはゼロ幅マッチの箇所から1文字先へ進む
  • Unicode文字のcase-insensitiveマッチはデフォルトでsimple case-folding

新しい振る舞い(VERSION1):

  • ゼロ幅マッチが正しく扱われるようになった
  • Unicode文字のcase-insensitiveはデフォルトでfull case-foldingになる

つっつきボイス:「Pythonで正規表現の仕様が微妙に修正されるそうで、Rubyではこの辺ってどう扱われているのかなと思って拾ってみました」「ちなみにPythonやってる方ってこの中にいます?」「やはりいないか〜😆」「じゃPythonは深追いしないことに🤣」

「上はその中で個人的に気になった部分をピックアップしたんですけど、Case FoldingとかCase Mappinngとか知らない用語が続々出てきたので以下にひとまずリンクを貼りました😅」

参考: www.unicode.org/Public/UCD/latest/ucd/SpecialCasing.txt
参考: W3C Case folding - Internationalization
参考: toLowerCaseの落とし穴とCase Foldingの話 - LINE ENGINEERING

一方で、我々は toLowerCase() や toUpperCase() といった操作を別の目的で使うこともよくあります。それは「大文字・小文字の違いを無視して文字列を比較したい」という目的のために文字列を一旦どちらかの文字種に統一する、というようなものです。Unicode標準は、このような目的のために “Case Folding” という操作を定義しています。Case Foldingは小文字へのCase Mappingとよく似ていますが、「caseless matchingを言語独立に行う」ために最適化されており、例えばギリシア文字の Σ は単語内の位置に関わらず常に σ (U+03C3) に変換されます。
engineering.linecorp.comより

「上の記事を急いで見た範囲だと、大文字と小文字の変換方法が言語によって違うという問題に関連してるようです」「あ〜その辺の問題か」「以前RubyのUnicodeマルチリンガル絡みで、トルコ語などで大文字小文字の変換が一律にはできないみたいな話を読んだことがあって、そのあたりに絡んでそうです」「このあたりは自然言語の強者に任せたっ😆」

参考: instance method String#downcase (Ruby 2.6.0)
参考: Feature #10085: Add non-ASCII case conversion to String#upcase/downcase/swapcase/capitalize - CommonRuby - Ruby Issue Tracking System -- Ruby 2.4で非ASCIIの大文字小文字変換が拡張されました

その他言語


つっつきボイス:「自分はEmacs LISPでコンフィグ書く以上のことをしたことないんですけど😆、LISPやったことある方はいます?」「...少ないけどいますね」「大学で、チョット、ヤッタ😆」「かっこが多い言語🤣」

「ツイートで紹介されているこの『n月刊ラムダノート』という雑誌↓が、好きな人はすごく好きそうだったので😆」「1,500円!」「冒頭のnは誤植じゃなかった😆」「川合史朗さんとかも書いてますね」「そうそう、『ハッカーと画家』で『エンジニアはLISPをやれ』みたいなことめっちゃ書いてた〜😆」「LISP 1.5とか言われてもわがんね😆」「わからない〜😆」

参考: 『n月刊ラムダノート Vol.1, No.2』を読むべき1つめの理由 - golden-luckyの日記

「LISPを今から真面目に始めるかと言われると、ね😆」「でもLISPは言語の歴史では必ず出てくる言語ですし、『本当の』プログラマーというとLISPやってる印象ってちょっとありますね☺️」「たしかMatzもLISPから影響受けたりしてましたね」「言語系をガチでやってる人にLISP多そう」

参考: まつもとゆきひろさん,Rubyに影響を与えた言語とRuby開発初期を語る。 ~ RubyKaigi 2013 基調講演 1日目:RubyKaigi 2013 レポート|gihyo.jp … 技術評論社

その他

GitHub CEOの嘆き


つっつきボイス:「最初上のツイートをたまたま見かけて、何の話だろうと思っていたらツイート主はGitHubのCEOで、以下の話のことだったそうです↓」「あ〜この話ね: 実際にはイランだけじゃなくて他にも対象になった国があるらしいですけど」「パブリックなリポジトリは閉じないけど、プライベートリポジトリが閉じるって聞きました」「そうそう、そうらしい」「『やりたくてやってるんじゃない』というのが切実ですね」「米国企業がこれを跳ね返すのは難しそう...」

参考: GitHubがイランなどからアクセス不可に、米国の経済制裁により。CEOのフリードマン氏「望んでやっているのではない」 - Publickey

「で、その動きに反対するリポジトリもできてました↓」「オープンソースに貢献したIranian developerのリストも載ってる」


同リポジトリより

↑今日見たらarchivedになってました😢。

番外

頭に輪っかはめる?


つっつきボイス:「どういう種類の電磁刺激なのかな😆」「効果が持続するならいいけど一時的にしか持たなかったら😆」「四六時中装着しないと😆」「時計じかけのオレンジ的な世界🍊」「それ〜😆」「眠くなったら通電とか⚡️」

参考: 脳に電磁刺激を与えれば、高齢者の記憶力が“若者並み”に改善される:研究結果|WIRED.jp

参考: 時計じかけのオレンジ - Wikipedia

原作で特徴的なのは、主にロシア語をもじる形で人工的に作られた若者言葉「Nadsat」だそうです。「トルチョック」だけ覚えています。

参考: ナッドサット - Wikipedia


後編は以上です。

おたより発掘

バックナンバー(2019年度第3四半期)

週刊Railsウォッチ(20190805-1/2前編)Rails 6のActive Recordは速くなった、Windows WSL2+VSCodeでのRails開発、Martin Fowler記事ほか

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

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

Ruby Weekly


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。