- Ruby / Rails関連
週刊Railsウォッチ(20190527-1/2前編)RuboCopが3分割へ、Railsリクエストのライフサイクル、Opal 1.0、Railsベンチマーク、Rubyパターンマッチングの現状ほか
こんにちは、hachi8833です。Macbook Pro 2019をポチりそうになったのを危うく踏みとどまりました。
Macbook Pro の TouchBar要らないと言っているウェブ系エンジニアの皆様、WSL2とWindows terminal来たら開発環境という点でWindowsの評価急上昇の可能性あるので急がないなら待つのも手かと。
— masa寿司 (@masa_iwasaki) May 22, 2019
- 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
- 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
- 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください
⚓お知らせ: 第11回公開つっつき会(無料)
第11回目を迎えた公開つっつき会は6月6日(木)19:30〜にBPS会議スペースにて開催されます。皆さまのお気軽なご参加をお待ちしております🙇。
⚓Rails: 先週の改修(Rails公式ニュースより)
今回は公式の更新情報から見繕いました。
⚓システムテストにTrixエディタ入力ヘルパーを追加
# 同PRより
# <trix-editor id="message_content" ...></trix-editor>
fill_in_rich_text_area "message_content", with: "Hello <em>world!</em>"
# <trix-editor placeholder="Your message here" ...></trix-editor>
fill_in_rich_text_area "Your message here", with: "Hello <em>world!</em>"
# <trix-editor aria-label="Message content" ...></trix-editor>
fill_in_rich_text_area "Message content", with: "Hello <em>world!</em>"
# <input id="trix_input_1" name="message[content]" type="hidden">
# <trix-editor input="trix_input_1"></trix-editor>
fill_in_rich_text_area "message[content]", with: "Hello <em>world!</em>"
つっつきボイス:「fill_in_rich_text_area
が入った」「with:
に任意のHTMLでテキストを渡せるようになったんですって」「Action TextというかTrixはまだ使ったことないけど、チャンスがあれば使うかなぐらいの気持ち☺️」
⚓ActiveRecord#respond_to?
の文字列アロケーションをやめて1.5倍高速化
# activerecord/lib/active_record/attribute_methods.rb#L261
def respond_to?(name, include_private = false)
return false unless super
- case name
- when :to_partial_path
- name = "to_partial_path"
- when :to_model
- name = "to_model"
- else
- name = name.to_s
- end
-
- if defined?(@attributes) && self.class.column_names.include?(name)
- return has_attribute?(name)
+ if defined?(@attributes)
+ if name = self.class.symbol_column_to_string(name.to_sym)
+ return has_attribute?(name)
+ end
end
true
end
# activerecord/lib/active_record/model_schema.rb#L391
+ def symbol_column_to_string(name_symbol) # :nodoc:
+ @symbol_column_to_string_name_hash ||= column_names.index_by(&:to_sym)
+ @symbol_column_to_string_name_hash[name_symbol]
+ end
つっつきボイス:「高速化なので@kamipoさんかと思ったら@schneemsさんだった☺️」「上のcase
文を汎用化して不要にしたということか」「else
の後のname = name.to_s
とかはsymbol_column_to_string
の方でやってるのと同じだし」「リファクタリングですね」
「ところで、この辺の書き方↓Rubocopに怒られそうではある👮」「あは、代入のシングルイコール=
を条件で使ってるし😆」
+ if name = self.class.symbol_column_to_string(name.to_sym)
「ダブルイコール==
のつもりだったのを間違えたのかと一瞬思っちゃうし😆」「とはいえ、このイディオムは高速化のためには有効だったりしますね☺️」「まあこのぐらいだったら許容範囲と思うし」「ビジネスロジックでは使って欲しくないけど、ライブラリコードの最適化ならしゃーない」
⚓S3に5GBより大きいファイルをアップロードできるようになった
- PR: S3: permit uploading files larger than 5 GB by georgeclaghorn · Pull Request #35931 · rails/rails
# activestorage/lib/active_storage/service/s3_service.rb#L8
module ActiveStorage
class Service::S3Service < Service
- attr_reader :client, :bucket, :upload_options
+ attr_reader :client, :bucket
+ attr_reader :multipart_upload_threshold, :upload_options
def initialize(bucket:, upload: {}, **options)
@client = Aws::S3::Resource.new(**options)
@bucket = @client.bucket(bucket)
+ @multipart_upload_threshold = upload.fetch(:multipart_threshold, 100.megabytes)
@upload_options = upload
end
def upload(key, io, checksum: nil, content_type: nil, **)
instrument :upload, key: key, checksum: checksum do
- object_for(key).put(upload_options.merge(body: io, content_md5: checksum, content_type: content_type))
- rescue Aws::S3::Errors::BadDigest
- raise ActiveStorage::IntegrityError
+ if io.size < multipart_upload_threshold
+ upload_with_single_part key, io, checksum: checksum, content_type: content_type
+ else
+ upload_with_multipart key, io, content_type: content_type
+ end
end
end
つっつきボイス:「ほほー、ついにマルチパートアップロードに対応!」「マルチパートがポイントなんですね」
「AWSのS3には元々マルチパートアップロードモードというのがあるんですが、何もしないとシングルモードになります」「シングルモードは文字通り1つのHTTP PUTで投げるんですけど、その場合の最大サイズが5GBです」「なるほど!」「それ以上のサイズでアップロードしたいときは複数のHTTP PUTで投げるマルチパートアップロードを使うことになるんですけど、この改修はそれに対応したということですね🧐」「コミットにもマルチパートって書いてありますね」
参考: マルチパートアップロードの概要 - Amazon Simple Storage Service
「100MB以上の場合は自動的にマルチパートモードになるんですね」「5GBとあるのはあくまでシングルモードの場合の上限ですし、それ以下の場合でもマルチパートモードの方が帯域を有効に使えますし☺️」「つか今まで対応してなかったんかい😆」「😆」
「マルチパートアップロードはかなり大事: 実際、S3にでかいファイルをどっかん置くとか割とやりますし(ホームディレクトリをtarで固めて投げたりとか)、マルチパートアップロードができなかったらかなりつらいし、しかもアップロードでさんざん待たされた後で終わった頃にやっと失敗してたことがわかったり😇」「あるある〜🤣」
「だからこの辺の制約は知っておくべき☺️: AWS SDKとかAWS CLIのコマンドでやる場合は自動的にマルチパートアップロードになってくれるからいいんですけど、S3 APIに直接HTTP PUTするようなコードを自分で書くときなんかは注意が必要⚠」「たしかに〜」
⚓HashWithIndifferentAccess#initialize
のパフォーマンスを改善
# activesupport/lib/active_support/hash_with_indifferent_access.rb#L52
def initialize(constructor = {})
if constructor.respond_to?(:to_hash)
super()
update(constructor)
- hash = constructor.to_hash
+ hash = constructor.is_a?(Hash) ? constructor : constructor.to_hash
self.default = hash.default if hash.default
self.default_proc = hash.default_proc if hash.default_proc
else
super(constructor)
end
end
つっつきボイス:「HashWithIndifferentAccess
の更新は久々に見た気がする」「is_a?(Hash)
してる?」「あ〜to_hash
がめちゃ重くなることがあるから、しなくていい場合はto_hash
をやめたのか」「わかりみ〜😋」「中身の構造にもよるけどto_hash
が重くなることあるし」
「プルリクに貼られているGist↓でもでかいハッシュ作って試してる👀」「HWIAにどでかいものを渡すことがどれぐらいの頻度であるのかにもよりそうですが😆、速くなるのはいいですね」
⚓mailbox_for
をpublicに
# actionmailbox/lib/action_mailbox/router.rb#L23
def route(inbound_email)
- if mailbox = match_to_mailbox(inbound_email)
+ if mailbox = mailbox_for(inbound_email)
mailbox.receive(inbound_email)
else
inbound_email.bounced!
raise RoutingError
end
end
+ def mailbox_for(inbound_email)
+ routes.detect { |route| route.match?(inbound_email) }.try(:mailbox_class)
+ end
private
attr_reader :routes
+ def match_to_mailbox(inbound_email)
+ routes.detect { |route| route.match?(inbound_email) }.try(:mailbox_class)
+ end
end
end
つっつきボイス:「いかにもAction Mailboxですね」「メソッド名も変更されてる」「メールのルーティングもroutesで扱うというのは言われてみればごもっとも☺️」
ApplicationMailboxの設定済みルーティングシステムへのエントリポイントとして現在公開されているのは
route
への呼び出ししかなく、受信メールを完全にprocess
する処理が大量に走ってしまう。テストなどで、そうした処理を行わずに、メールがどのメールボックスにルーティングされるかをチェックする手段があるとよさそう。
これにインラインドキュメントをもっと追記して、どういうメソッドをpublicにしてサポートするか、どういうメソッドではそれをやらないかという基準を示しておくとありがたみが増すと思われる。「その価値あり」と皆さんに賛成してもらえるなら、このPRか別のPRで自分がドキュメントを追加してもよい。
同PRより大意
⚓Rails
⚓RailsをAWS->GCPに移行
つっつきボイス:「この間BPSの社内Slackに貼っていただいたヤツです」「これかなり面白かった😋タイトルは釣り記事っぽかったけど読めば読むほど『こ、この会社...大変だったんだな』って苦労が偲ばれる😆」「何しろ元のRailsアプリを作った人もいなくなっててチームもほぼ解散状態で誰にも質問できないところからのスタート😇」「そこまで!😇」「はにゃーん😇」「CTOやRailsエンジニアが全員退職...😇」「『よくしらんRailsアプリ』ってそういう意味でしたか!」「『全社的な退職のビッグウェーブ』って🤣」「もはや災害レベル🤣」
「それにしてもよくここまで頑張ったと思うし」「マジで偉業!」「こういう究極の案件を1人で回して切り抜けるとめちゃめちゃ知見がたまります☺️」
⚓Railsリクエストのライフサイクル(Ruby Weeklyより)
つっつきボイス:「これは次のRailsConf 2019のセッションのスライドと記事だそうです」「なるほどなるほど、DNS lookupから始まってRackミドルウェアを通ったりしてRailsのリクエストをひととおり辿ると: これはとてもためになる👍」「採用面接で志望者にこれをひととおり説明してもらったりしますね😆」「この間のRails Traceにも通じそう」
「四六時中Railsのコードを追いかけている人ならこのスライドの内容は自明ですけど、Railsをしばらく触っていなかった人とか、Rails一応触っているけど中で何が起こっているか今ひとつわかってない人にはうってつけの教材😋」「エンジニア全員とまではいかなくても、Railsをメインで触っている人ならこのスライドで説明されていることぐらいは知ってて欲しいです☺️」「同じ内容が元記事でも読めますし」「Railsチュートリアルをやったら次に学んでおきたい感じですね😃」
⚓RailsConf 2019のセッション
つっつきボイス:「日本ではGW中にミネアポリスで開催されたRailsConf 2019のタイムテーブルです」「スロット7つで3日間!」「これをまともに追うのは大変すぎ😅」「6月の公開つっつきのときに、もう少し絞り込んでおこうと思います」
⚓Railsのシンプルなベンチマーク(Ruby Weeklyより)
TechRachoでパフォーマンス関連の記事を何度か翻訳させてもらっているNoah Gibbsさんの記事です🙇。
つっつきボイス:「特にこういうPumaとかコンカレンシーとかのベンチマークって、やっぱり自分で書くしかないんですよね: ベンチマークソフトに丸投げしてストンと結果が出るなんてことはまずないので☺️」「先週のウォッチの話にも通じますね」
「Pumaやコンカレンシーのベンチマークをやるということは、つまりスレッド周りとかGILとかをチェックすることになるし、そういう下のレイヤの中身を理解した上でコードを書かないといけないから、しんど〜😭」
参考: グローバルインタプリタロック - Wikipedia
「こんなにみっちり取ってる↑😳」「ああ、こういうのとても大事: 結構前にUnicornとかPumaはどういうパラメータが適切なのかというのが話題になりましたけど、こういうのはCPUの種類やカーネルのバージョンなどによっても変わってくることを知っておくべき」「うんうん」「シビアに考えるのであれば、ベンチマークはあくまで特定のスペックのサーバーでの結果であるということですね🧐」
「ところで、こんな感じのベンチマークって取ったりします?」「バージョンごとのベンチマークまではやったことないです〜」「インスタンスタイプを変えて最適なものがどれかを試したりは?」「それもやってないかな〜😅」「自分はスループットチェックはたまにやってますけど、結局自分で取るしかないし、ダルいので自動化したりします😆」
「記事ではRSBというベンチマークgemを新たに書き下ろしたそうです↓」「改めて思うんですけど、ちゃんとしたベンチマークを書くのって、OSを正しく理解しておかないといけなくてとても難しい😭」
「こういう必要なパラメータ↓渡して一発でベンチマーク回せるようにしてるのって、すげっ!」「複数バージョンのRubyで一気に回せるようになってるし💪」「ウォームアップ時間もちゃんと指定できるようになってるし❤️」「これらのパラメータはしっかり押さえてあるということですね」「ウォームアップはめちゃめちゃ重要」「ウォームアップしないベンチマークはマジで意味ないし」「ウォームアップに実際にかかった時間もチェックしておきたいし」「たしかに〜」「もっと言えば再起動から始めるとかありますし」
RSB_NUM_RUNS=10 RSB_RUBIES="2.6.0 2.4.5 2.0.0-p0" RSB_DURATION=180 RSB_WARMUP=20 RSB_FRAMEWORKS=rack RSB_APP_SERVER=puma RSB_PROCESSES=1 RSB_THREADS=1 ./runners/rvm_rubies.rb
同リポジトリより
「しかしよくこれだけ網羅してますね」「そこがベンチマークを自作したくない理由🤣: パラメータ入れ忘れそう」「🤣」「🤣」
「Noah Gibbsさんはコンピュータサイエンスをきちんと押さえている人なので、彼のベンチマークコードはめちゃめちゃ勉強になります❤️」「何度か翻訳させてもらいましたけどホント濃厚でした😅」「そこはどうしても濃厚にならざるを得ませんね〜: 下のレイヤを正しく理解してないと、まったく違う結果を出してしまうことすらあるので😇」
⚓ route_translator: Railsのルーティングを多言語化(Ruby Weeklyより)
# 同リポジトリより
Prefix Verb URI Pattern Controller#Action
admin_cars GET /admin/cars(.:format) admin/cars#index
POST /admin/cars(.:format) admin/cars#create
new_admin_car GET /admin/cars/new(.:format) admin/cars#new
edit_admin_car GET /admin/cars/:id/edit(.:format) admin/cars#edit
admin_car GET /admin/cars/:id(.:format) admin/cars#show
PATCH /admin/cars/:id(.:format) admin/cars#update
PUT /admin/cars/:id(.:format) admin/cars#update
DELETE /admin/cars/:id(.:format) admin/cars#destroy
cars_fr GET /fr/voitures(.:format) cars#index {:locale=>"fr"}
cars_es GET /es/coches(.:format) cars#index {:locale=>"es"}
cars_en GET /cars(.:format) cars#index {:locale=>"en"}
POST /fr/voitures(.:format) cars#create {:locale=>"fr"}
POST /es/coches(.:format) cars#create {:locale=>"es"}
POST /cars(.:format) cars#create {:locale=>"en"}
new_car_fr GET /fr/voitures/nouveau(.:format) cars#new {:locale=>"fr"}
new_car_es GET /es/coches/nuevo(.:format) cars#new {:locale=>"es"}
new_car_en GET /cars/new(.:format) cars#new {:locale=>"en"}
edit_car_fr GET /fr/voitures/:id/edit(.:format) cars#edit {:locale=>"fr"}
edit_car_es GET /es/coches/:id/edit(.:format) cars#edit {:locale=>"es"}
edit_car_en GET /cars/:id/edit(.:format) cars#edit {:locale=>"en"}
car_fr GET /fr/voitures/:id(.:format) cars#show {:locale=>"fr"}
car_es GET /es/coches/:id(.:format) cars#show {:locale=>"es"}
car_en GET /cars/:id(.:format) cars#show {:locale=>"en"}
PATCH /fr/voitures/:id(.:format) cars#update {:locale=>"fr"}
PATCH /es/coches/:id(.:format) cars#update {:locale=>"es"}
PATCH /cars/:id(.:format) cars#update {:locale=>"en"}
PUT /fr/voitures/:id(.:format) cars#update {:locale=>"fr"}
PUT /es/coches/:id(.:format) cars#update {:locale=>"es"}
PUT /cars/:id(.:format) cars#update {:locale=>"en"}
DELETE /fr/voitures/:id(.:format) cars#destroy {:locale=>"fr"}
DELETE /es/coches/:id(.:format) cars#destroy {:locale=>"es"}
DELETE /cars/:id(.:format) cars#destroy {:locale=>"en"}
pricing_fr GET /fr/prix(.:format) home#pricing {:locale=>"fr"}
pricing_es GET /es/precios(.:format) home#pricing {:locale=>"es"}
pricing_en GET /pricing(.:format) home#pricing {:locale=>"en"}
つっつきボイス:「↑こんな感じでルーティングを多言語化するそうです」「ははぁ、URLのSlugを多言語化するということか!」「Slugのローカライズって必要なんでしょうか?」「SEO的には欲しいヤツですね☺️: CMSの代わりにRailsを使うとこういう感じになりそう」「Rails標準のi18nではここまでできないんでしょうか?」「Slugはi18nとは別の機能なので😆」
参考: Slug (スラグ) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN
「enが英語のcarでデフォルトか」「ということはvoituresがフランス語、cochesがスペイン語でそれぞれ自動車という意味なんでしょうね」「ヴォアチュ?」「ヨーロッパではこういう機能欲しいでしょうね」「ここまでやるか〜?とは思いますけど😆」
「ということはSlugに日本語も置けると🤣」「やめて〜🤣」
「そもそもこういうことするとめちゃルーティングが増えるし😇」「やりたい気持ちはワカル☺️」
⚓logidze: データベース変更ロガー(Ruby Weeklyより)
現時点ではPostgreSQL 9.5以降のみをサポートするそうです。
つっつきボイス:「Evil Martiansの人のgemで、logidzeという名前はグルジア(ジョージア)語由来だそうです」「じゃ読み方わからなくて当然😆」「Evil Martiansにはロシア系メンバーがいるからなのかな🤔」「なるほど、いわゆるaudit(監査)系のgem」
参考: 第1回 データベース監査の現場 [監査とは]|知って得する! Oracle知識|Oracleソリューションサービス|日立ソリューションズ
「paper_trailより速いそうです」「paper_trail、あれは重いよ〜😆」「やっぱり😆」「paper_trailは内部展開までやってるからそりゃ重い😆」
参考: paper-trail-gem/paper_trail: Track changes to your rails models
「logidzeはこうやってバージョンをトラックしたりundoしたりとかもやれるのか↓」「ほほー」「保存先はデータベースでしょうか?」「rake db:migrate
やってるからほぼ確実にそうでしょうね☺️」「軽いpaper_trailとして使えそう」「auditツールは信頼性もチェックしときたいですけど☺️」
post = Post.create!(title: "first post") # v1
post.update!(title: "new title") # v2
post.undo!(append: true) # v3 (with same attributes as v1)
⚓high_voltage: Railsで静的ページを扱う(Ruby Weeklyより)
# 同リポジトリより
# app/controllers/pages_controller.rb
class PagesController < ApplicationController
include HighVoltage::StaticPage
before_filter :authenticate
layout :layout_for_page
private
def layout_for_page
case params[:id]
when 'home'
'home'
else
'application'
end
end
end
つっつきボイス:「『高電圧注意』とか書いてあるけど別に危険な気はしませんね😆」「いわゆる静的ページを普通のRailsビューのように使えるという感じでしょうか?」「それっぽい」「Railsのキャッシュをいい感じに効かせてくれるようだ」
「静的ページを普通にpublic/の下に置くとできないことってあるんでしょうか?」「ビューのレイアウト機能なんかはpublic/ではできないでしょうね: ヘッダーを静的ページでも共通化してレンダリングしたい、というのはよくあるし」「レイアウトは共通化したいけど中身は固定ページ、みたいなときなんでしょうね」「『ご挨拶』ページとか😆」
「わざわざgem入れる?とは思いますが😆、キャッシュのこととかを考えずに静的ページを楽に扱えるのはよさそうだし、Thoughtbotなら一応ちゃんとしてそう😋」
⚓その他Rails
- Screencast: How to use Action Mailbox in Rails 6 (Example) | GoRails(Ruby Weeklyより)
- 元記事: Rails 6 Upgrade Best Practices -- hint.io(Ruby Weeklyより)
⚓Ruby
⚓ruby-regexp_trie: 文字列リストを正規表現に圧縮するgem
# 同リポジトリより
#!/usr/bin/env ruby
require 'regexp_trie'
# Regexp.union()のように使う
p RegexpTrie.union(%w(foobar fooxar foozap fooza)) # /foo(?:bar|xar|zap?)/
p RegexpTrie.union(%w(foobar fooxar foozap fooza), option: Regexp::IGNORECASE) # /foo(?:bar|xar|zap?)/i
# オブジェクト指向インターフェイスっぽくもやれる
rt = RegexpTrie.new
%w(foobar fooxar foozap fooza).each do |word|
rt.add(word)
end
p rt.to_regexp # /foo(?:bar|xar|zap?)/
PerlのRegexp::List
(小飼弾作)を元にしているそうです。Perl版はえらく短いコードです。
つっつきボイス:「ruby-regexp_trieは近々記事を出そうと思ってます: Trie(トライ木)っていうデータ構造をこれで知りました」「Trieは割と最近のヤツだったかな」「自然言語処理方面で辞書を作るのによく使われているみたいで、単なる二分木と得意不得意がちょっと違うようです」
参考: トライ木 - Wikipedia
参考: 簡潔データ構造 LOUDS の解説(全12回、練習問題付き) - アスペ日記
参考: 情報系修士にもわかるダブル配列 - アスペ日記
「PerlだけにやはりCPANに置いてある☺️」「ところで小飼弾氏ってだいぶ前からコードも書く論客というイメージがあったんですが、やはりPerlの人だからなのか、つっつきでは名前出たことがなかったなと思って」「コードも書くけど今はどちらかというビジネスとか経営寄りな印象かな〜🤔」「元ライブドアのCTO」
参考: CPAN - Wikipedia
参考: 404 Blog Not Found -- 小飼弾氏のブログ
⚓Opalが1.0になって高速化(Ruby Weeklyより)
- プレスリリース: Opal 1.0
- プロトタイプチェーン探索がネイティブに
Module.prepend
の追加- c_lexerによる高速化
- エラーメッセージやsource mapの改善
- コンパイル時に見つからないrequireを実行時にのみエラーにできるようになった(MRIと同様)
- Ruby 2.4や2.5の機能が多数使えるようになった
- MRIと同じアルゴリズムの疑似乱数ジェネレータ、
pack
とunpack
、Node.jsでFile
やDir
クラスへのアクセスほか
コミットリスト: Comparing v0.11.4...v1.0.0 · opal/opal
つっつきボイス:「ついにOpalが1.0に!」「0.x系だと警戒して使わない人がいるからだったりして😆」「OpalってLambda系のサーバーレスアプリを作るときなんかに全部Rubyで書けるのがよさそうなんですよね〜🥰」
⚓zxcvbn-ruby: パスワード強度チェッカー(Ruby Weeklyより)
# 同リポジトリより
>> pp Zxcvbn.test('@lfred2004', ['alfred'])
#<Zxcvbn::Score:0x00007f7f590610c8
@calc_time=0.0055760000250302255,
@crack_time=0.012,
@crack_time_display="instant",
@entropy=7.895,
@feedback=
#<Zxcvbn::Feedback:0x00007f7f59060150
@suggestions=
["Add another word or two. Uncommon words are better.",
"Predictable substitutions like '@' instead of 'a' don't help very much"],
@warning=nil>,
@match_sequence=
[#<Zxcvbn::Match matched_word="alfred", token="@lfred", i=0, j=5, rank=1, pattern="dictionary", dictionary_name="user_inputs", l33t=true, sub={"@"=>"a"}, sub_display="@ -> a", base_entropy=0.0, uppercase_entropy=0.0, l33t_entropy=1, entropy=1.0>,
#<Zxcvbn::Match i=6, j=9, token="2004", pattern="year", entropy=6.894817763307944>],
@password="@lfred2004",
@score=0>
=> #<Zxcvbn::Score:0x00007f7f59060150>
Dropboxがやっているzxcvbn.jsをRubyに移植したそうです。ダメパスワードリストもあります。
つっつきボイス:「zxcvbn発音できない😅」「Dropboxがこういうのやってるのか〜」「そのRuby版ですね☺️」
参考: Dropbox開発のzxcvbn(パスワード強度メーター)のブログ記事を全訳してみた - Qiita
USENIXで以下のプレゼンが2017年に行われていたようです。
usenix.orgより
⚓RuboCopを3つのgemに分割(Hacklinesより)
つっつきボイス:「RuboCopが以下の3つのgemに分けられるそうです」「ほほぉ〜」
- リポジトリ: rubocop-hq/rubocop: A Ruby static code analyzer and formatter, based on the community Ruby style guide.
- リポジトリ: rubocop-hq/rubocop-performance: An extension of RuboCop focused on code performance checks.
- リポジトリ: rubocop-hq/rubocop-rails: A RuboCop extension focused on enforcing Rails best practices and coding conventions.
「たしかにRuboCop Railsは分かれていて欲しいかも: 今のRuboCopは色々入れすぎてるから、gemとしてRails用だけ選択できたらうれしいし❤️」「たしかに〜」「RuboCop Railsって単体で使えるかしら?」「まあRuboCop本体にdependするでしょうね☺️」「RSpecみたく😆」
「RuboCopをRailsでもっとデフォルトで使いたいからgemを分けて欲しいというのは気持ちちょっとワカル☺️」「分けないとメンテが大変そうですし😅」「RuboCopは割とプルリクをガンガン受け付ける敷居の低さがあるんですけど、その分ちょっとやりすぎ感はありますし😆」「RuboCopのプルリクの数すごいですよ」
後で気づきましたが、従来のrubocop-railsがRuboCopチームに移管されるというアナウンスが昨年あったんですね。
⚓その他Ruby
- リポジトリ: tuwukee/blab: A debugging tool(Ruby Weeklyより)
つっつきボイス:「PySnooperにヒントを得ためっちゃexperimentalなデバッガーだそうです」「おー、この情報↓ってMac固有のものだったりするのかな?」「4番目の数値がRubyのメモリ使用量っぽいから、これが急激に増えていたら何かおかしいと」「GCすれば普通減りますけどね😆」
Var......... a=["Bored", "Curious"]
Var......... b=["cat", "frog"]
18:38:15.188 line test/support/test.rb:54 13770752 a << "Insane"
18:38:15.188 line test/support/test.rb:55 13807616 shuffle(b)
Var......... arr=["cat", "frog"]
18:38:15.188 call test/support/test.rb:45 13807616 def shuffle(arr)
18:38:15.189 line test/support/test.rb:46 13807616 for n in 0...arr.size
Var......... n=0
18:38:15.189 line test/support/test.rb:47 13811712 targ = n + rand(arr.size - n)
Var......... targ=0
18:38:15.189 line test/support/test.rb:48 13811712 arr[n], arr[targ] = arr[targ], arr[n] if n != targ
Var......... n=1
18:38:15.189 line test/support/test.rb:47 13811712 targ = n + rand(arr.size - n)
Var......... targ=1
18:38:15.189 line test/support/test.rb:48 13811712 arr[n], arr[targ] = arr[targ], arr[n] if n != targ
18:38:15.189 return test/support/test.rb:50 13811712 end
短いtips記事です。
# 同記事より
land = 'Mordor'
verse = <<-'TEXT'
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 #{land} where the Shadows lie.
TEXT
つっつきボイス:「ヒアドキュメントで式展開#{}
を無効にしたい場合に、'TEXT'
みたいにキーワードを一重引用符で囲むと展開されなくなるんだそうです」「へぇ〜😆」「これはマジ知る人ぞ知る😆」「シンタックスシュガーなんですけど、これで効くのがちょっと不思議」
「...このシンタックス、Bashだとメジャーなんですよね😆」「えぇぇ?!」「じゃそこから持ってきた文法なのかな」「そんな気がします: この文法キライなんですけど🤣」「Bashなんかだと使える記号にいろいろ制限があってそうなったんだろうけど、何もそれを踏襲しなくても😆」「Bashに強い人はいいんでしょうけど😆」
↓たぶんこれだと思います。
参考: sh での変数とワイルドカードの落とし穴|てくめも@ecoop.net
# 同記事より
foo="SELECT * FROM table"
echo "$foo"
#=> SELECT * FROM table
⚓Ruby trunkより
⚓パターンマッチングの現状の仕様
つっつきボイス:「この間出した記事↓をまとめていて、パターンマッチングのうれしさがやっと少し見えてきたので、現時点のまとまった仕様と思われるものをこのissueから抜き書きしました」
キーワードで振り返るRubyKaigi 2019@博多(#4)最適化、パターンマッチング、mruby、ブランチメンテナンスほか
case obj
in pat [if|unless cond]
...
in pat [if|unless cond]
...
else
...
end
pat: var # 変数渡しのパターン(任意の値にマッチ可能、その値の変数名にバインドされる)
| literal # 値渡しのパターン(pattern === objectのようにオブジェクトとマッチする)
| Constant # 同上
| ^var # 同上(Elixirのピン演算子^と同等)
| pat | pat | ... # alternateパターン(いずれかのpatとマッチする)
| pat => var # asパターン(patにマッチする場合、その値の変数にバインドされる)
| Constant(pat, ..., *var, pat, ...) # arrayパターン(後述)
| Constant[pat, ..., *var, pat, ...] # 同上
| [pat, ..., *var, pat, ...] # 同上(`BasicObject(pat, ...)`と同じ)(トップレベルでのみ丸かっこを省略可)
| Constant(id:, id: pat, "id": pat, ..., **var) # hashパターン(後述)
| Constant[id:, id: pat, "id": pat, ..., **var] # 同上
| {id:, id: pat, "id": pat, ..., **var} # 同上(`BasicObject(id:, ...)`と同じ)(トップレベルでのみ波かっこを省略可)
arrayパターンは以下のいずれかの場合にマッチする:
* Constant === objectがtrueを返す
* Arrayを返す#deconstructメソッドがオブジェクトにある
* ネストしたパターンをobject.deconstructに適用した結果がtrueになる
hashパターンは以下のいずれかの場合にマッチする:
* Constant === objectがtrueを返す
* Hashを返す#deconstructメソッドがオブジェクトにある
* ネストしたパターンをobject.deconstruct_keys(keys)に適用した結果がtrueになる
参考: Pattern matching - New feature in Ruby 2.7 - Speaker Deck
参考: パターンマッチング · Elixir School -- ピン演算子^
の解説
前半は以上です。
バックナンバー(2019年度第2四半期)
週刊Railsウォッチ(20190521-2/2後編)サーバーレスクラウドのベンチマーク比較サイト、VueJSパフォーマンス向上、GraalVM 19.0ほか
- 20190520-1/2前編 Evil Martians愛用の便利gemたち、render_asyncでRails表示を高速化、split gemでA/Bテストほか
- 20190514-2/2後編 Webpackerを現場で使う、Dockerfileベストプラクティス、SONYのユニークID生成ツールsonyflakeほか
- 20190513-1/2前編 6.0の地味に嬉しい機能、ActiveModelエラーの扱いが変更、Railsのリクエスト/レスポンスをビジュアル表示ほか
- 20190508-2/2後編 サロゲートキーのコスト、Cloud RunとLambdaの違い、miniredis、CSS Subgridほか
- 20190507-1/2前編 Rails 6.0.0rc1が4/24にリリース、Rails 6の新メソッド群、RubyリポジトリがCgitに移行ほか
- 20190416-2/2後編 最近のRDBMS市場、Flutterがデスクトップにも向かう、書籍『失敗から学ぶRDBの正しい歩き方』ほか
- 20190415-1/2前編 Railsバージョンアップに便利なstill_life gem、Zeitwerkの改修進む、named_capture追加ほか
- 20190409-2/2後編 Ruby 2.3系サポート終了、Thoughtbotのコーディング指南書、PostgreSQLのgenerated column、Chromebrewほか
- 20190408-1/2前編 RubyKaigiの予習資料、Rails「今年ベストのプルリク」、numbered parametersの議論ほか
- 20190402-2/2後編 Apache Arrowとは何か、prop drillingはアンチパターン、Node-REDほか
- 20190401-1/2前編 Rails 5.2.3/5.1.7がリリース、Railsdmの「Railsの正体」、Ruby 2.7のnumbered parameter、新元号「令和」ほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSなど)です。