- 開発
週刊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 Rubyという別のサイト↓もあるのでややこしいですね。
つっつきボイス:「Awesomeなんちゃらって流行ってましたよね😆」「特にGitHub Trendingにやんなるほどありますね😆」
「とりあえずこういうのやるなら年度付けて欲しいし😆」「たしかに〜😆」「こういうのは、いつのAwesomeほげかですごく変わりますし😆」「年と、あと月も欲しいです」
後で気づきましたが、リポジトリは★10000越えてますね😳。issueには追加リクエストがずらりと並んでいます。
⚓RuboCop1.4.1のPerformance/RegexpMatch
改修
あざます!
リリース通知来てたのでそっこー手元の手動regexp書き換えブランチに取り込みました! pic.twitter.com/fZB5rPIqph— Ryuta Kamizono (@kamipo) July 30, 2019
#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リポジトリを拾ってみました。
- rubocop-hq/rubocop: A Ruby static code analyzer and formatter, based on the community Ruby style guide.
- rubocop-hq/rubocop-rails: A RuboCop extension focused on enforcing Rails best practices and coding conventions.
- rubocop-hq/rubocop-performance: An extension of RuboCop focused on code performance checks.
- rubocop-hq/rubocop-rspec: Code style checking for RSpec files
- rubocop-hq/rubocop-minitest -- ついさっき作られたようです!
⚓ブロック内の定数がトップレベルから参照できる問題(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
ちょっと真面目にpixivFANBOXを運営しようと思い、たまにRuby雑記を投稿することにしました。よかったらご支援いただければありがたいです。
pixivFANBOXで支援者のみなさんへを公開しました! https://t.co/GCAzyPC8x4
— igaiga (@igaiga555) July 30, 2019
⚓クラウド/コンテナ/インフラ/Linux/Serverless
⚓ECSがロードバランサーのターゲットグループを複数サポート
はてブで見つけました。
Amazon ECS services now support multiple load balancer target groups
これのせいで多段リバプロをしていたな
参考: Application Load Balancer を作成し ECS タスクを自動登録する
つっつきボイス:「この記事も含めて、最近いくつかの記事情報を社内Slackで寄せてもらってとってもうれしいです😂」「タイトルのmultiple load balancer target groupsですけど、これはmultipleがtarget groupsにかかってるのでは?」「あ、仮タイトルが『マルチプルロードバランサーのターゲットグループ』という直球のままでした😅(今は修正済み)」「この辺は知らないとわかりにくいですし☺️」
⚓今度はserveo登場
- 元記事: ngrokよりserveoがすごい。0秒で localhostを固定URLで公開 - Qiita
- サイト: Serveo: expose local servers to the internet using SSH
つっつきボイス:「serveoも先週あたりに話題になってましたね: 先週話題にしたngrok(ウォッチ20190731)のオープンソース版的な」「サーヴェオ」
「つまりngrokはオープンソースではない?」「ngrokはバイナリが配布されていて、フリーでも使えるけどお金払わないと自分のドメインが使えないなどの違いがありますね」「なるほど!」
「今回お集まりの皆さんの中で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、どれがパフォーマンスいい?
- 元記事: Vue・React・Angularのパフォーマンス比較検証 - ICS MEDIA
- デモ: Angular Performance Svg
- デモ: React App
- デモ: vue-svg
- デモ: Vanilla JS App
つっつきボイス:「フロントエンド寄りのパフォーマンス比較をあまり見たことがなかったので」「あ、パーティクルをばらまくアニメーションで比較してるのね😳」
補足。
検証デモに粒子表現を使っているのは視覚的にわかりやすいからで、例えばsvg要素でなくtable>tr要素などを使っても目的の検証ができます。
(tableだと実際の用途との乖離は少ないはず)
検証で大事にしたのは次の観点での性能です
・仮想DOMの追加・更新・削除
・仮想DOMから実DOMへの反映— 池田 泰延 (@clockmaker) August 1, 2019
今回の検証のように大量のオブジェクトをリアルタイムで描画更新するようなケースは、ReactやAngularではほとんどありません。フレームレートとメモリ使用量については、極限の状態においての負荷を検証したので、小規模なプロダクトにおいて負荷が問題になる場面が少ないことは補足しておきます。
ライブラリの特性を知ったうえで技術選定をすることはリスクの早期発見につながるはずです。本記事が技術選定の一助になれば幸いです。
同記事より
「まあ自分たちだとパーティクルを動かすのにAngularとかReactとか使わないかな😆、どのぐらい実用的なベンチマークなんだろう?」「記事の最後のまとめにこう↑書いてあるし😋」「実用的かどうかは別にして、ひとつのベンチマークというか」「RubyのベンチマークをOptCarrotでやってるのにもちょっと似ているというか、OptcarrotでGCが速くなってもRailsが速くなるとは限らないみたいな😆」「Optcarrotはファミコンのエミュレータでしたね」
「上の記事を書いた方はこういうサイト↓をやっているそうです」「すごい凝ってる...!」「フロント強そう」
- サイト: Clockmaker Labs
つっつき終了後の親睦会で、こちらのサイトを環境映像的に映しました😋。
⚓言語・ツール
⚓Pythonのregex
の挙動が変わる😨
- 元記事: regex · PyPI
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の大文字小文字変換が拡張されました
⚓その他言語
LISPの思い出話,いくらでも書けそう(私もMZ-80上の自作コンパイラでLISP 1.5相当を作り始めたけれど,LISP処理系を入手してしまったので,中途半端になってしまった) https://t.co/L5epk6ThfV
— Haruhiko Okumura (@h_okumura) July 29, 2019
つっつきボイス:「自分は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の嘆き
It is painful for me to hear how trade restrictions have hurt people. We have gone to great lengths to do no more than what is required by the law, but of course people are still affected. GitHub is subject to US trade law, just like any company that does business in the US.
— Nat Friedman (@natfriedman) July 28, 2019
つっつきボイス:「最初上のツイートをたまたま見かけて、何の話だろうと思っていたらツイート主はGitHubのCEOで、以下の話のことだったそうです↓」「あ〜この話ね: 実際にはイランだけじゃなくて他にも対象になった国があるらしいですけど」「パブリックなリポジトリは閉じないけど、プライベートリポジトリが閉じるって聞きました」「そうそう、そうらしい」「『やりたくてやってるんじゃない』というのが切実ですね」「米国企業がこれを跳ね返すのは難しそう...」
参考: GitHubがイランなどからアクセス不可に、米国の経済制裁により。CEOのフリードマン氏「望んでやっているのではない」 - Publickey
「で、その動きに反対するリポジトリもできてました↓」「オープンソースに貢献したIranian developerのリストも載ってる」
↑今日見たらarchivedになってました😢。
⚓番外
⚓頭に輪っかはめる?
- 元記事: A small electrical zap to the brain could help you retrieve a forgotten memory - Neuroscience News
つっつきボイス:「どういう種類の電磁刺激なのかな😆」「効果が持続するならいいけど一時的にしか持たなかったら😆」「四六時中装着しないと😆」「時計じかけのオレンジ的な世界🍊」「それ〜😆」「眠くなったら通電とか⚡️」
参考: 脳に電磁刺激を与えれば、高齢者の記憶力が“若者並み”に改善される:研究結果|WIRED.jp
原作で特徴的なのは、主にロシア語をもじる形で人工的に作られた若者言葉「Nadsat」だそうです。「トルチョック」だけ覚えています。
後編は以上です。
おたより発掘
「「冒頭のnは誤植じゃなかった😆」」はい https://t.co/IBovXAC2R3
— 専門性・売上・原稿 (@golden_lucky) August 10, 2019
バックナンバー(2019年度第3四半期)
- 20190730-2/2後編 Docker 19.03の新機能に注目、ngrokはスゴい、redis-namespaceほか
- 20190729-1/2前編 Rails 6のリリースは近そう?、Evil MartiansのRails+Docker記事、Railsパフォーマンス測定ほか
- 20190723-2/2後編 Rails 6 rc2がリリース、「MySQLパフォーマンスチューニングTips」が超便利、Aurora Serverlessほか
- 20190722-1/2前編 Rails 6エラー画面の改良点、Dateを四捨五入できるtime_calc、Rackミドルウェアのデザインパターンほか
- 20190717-2/2後編 NFSのよさとは、Linuxカーネル5.2リリース、Puppeteerでメモリリーク検出ほか
- 20190709-2/2後編 strong_password v0.0.7がハイジャックされていた、TerraformとCloudFormation、CSSの設計ミスリストほか
- 20190708-1/2前編 ActiveRecord::FixtureSetがめちゃ強くなってた、MacだとRubyが遅い理由、Puma 4登場ほか
- 20190701 RMagickのメモリ使用量が劇的に改善、インスタンス変数の定義順で速度が変わる?、GitLab CIランナーをローカルで回すほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSなど)です。