- Ruby / Rails関連
週刊Railsウォッチ(20180709)Rails Developers Meetup Day 3 Extreme今週末開催、RailsのSTI/キャッシュ/添付ファイル/Redis/PDF出力、ECMAScript 2018、プロフェッショナルIPv6ほか
こんにちは、hachi8833です。年々夏が苦手になっています。
各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
ウォッチを継続するためにも皆さまからのフィードバックをぜひお待ちしています。@hachi8833までどうぞ🙇
⚓臨時ニュース: Rails Developers Meetup 2018 Day 3 Extremeが7/14(土)開催
すべての登壇テーマが出揃いました。来週、7/14(土)開催です。 #railsdmhttps://t.co/CRc1czTU7u
— 無題のドキュメント (@yoshi_hirano) July 6, 2018
何とkamipoさんにActive Recordの質問を出せるそうです。
今週末のRailsdmでの『[特別講演] Rails 6 に向けた ActiveRecord の改善』の質問を募集しております。Railsコミッターであるkamipoさんに質問があればぜひぜひご投稿ください。 #railsdmhttps://t.co/TZmswRThpa
— 無題のドキュメント (@yoshi_hirano) July 9, 2018
⚓Rails: 先週の改修(Rails公式ニュースより)
つっつきボイス: 「ややこしいんですが、『先週の改修』という見出しは月曜公開時点で真になるので、つっつきの日である木曜日の今の時点では今週の改修ということになります😅」
⚓STIでのActiveRecordオブジェクト割り当てを高速化
- PR: Speed up homogeneous AR lists / reduce allocations by tenderlove · Pull Request #33223 · rails/rails
このコミットはActive Record(AR)オブジェクトの同質なリストのアロケーションを高速化する。結果セットにSTIカラムが含まれていることはすべてのARオブジェクトを初期化する前に知ることができるので、今回の変更では「結果セットにSTIカラムがあるか?」というテストを加えて特殊なインスタンス化関数を用いている。こうすることでSTIカラムのチェックをN回ではなく1回で済ませられる。
今回の変更にはデータベースから得たARオブジェクトのアロケーション時に使う初期化関数も新たに導入した。これにより、ARインスタンスごとにハッシュを1つアロケーションせずに済むようになった。
同PRより大意
Before:
[aaron@TC activerecord (master)]$ be ruby -I lib:~/git/allocation_tracer/lib speed.rb
Warming up --------------------------------------
find 5.000 i/100ms
Calculating -------------------------------------
find 56.192 (± 3.6%) i/s - 285.000 in 5.080940s
After:
[aaron@TC activerecord (homogeneous-allocation)]$ be ruby -I lib:~/git/allocation_tracer/lib speed.rb
Warming up --------------------------------------
find 7.000 i/100ms
Calculating -------------------------------------
find 72.204 (± 2.8%) i/s - 364.000 in 5.044592s
# activerecord/lib/active_record/persistence.rb#L80
+ def instantiate_instance_of(klass, attributes, column_types = {}, &block)
attributes = klass.attributes_builder.build_from_database(attributes, column_types)
- klass.allocate.init_with("attributes" => attributes, "new_record" => false, &block)
+ klass.allocate.init_from_db(attributes, &block)
end
つっつきボイス: 「(今回の社内つっつき初参加者🔰へ)これはtenderloveことAaron Pattersonさんのコミットですね: この方はGitHubの中の人かつRubyとRailsの両方のコミッターです」「そんな凄い人がいるんですね...😲」「ウォッチつっつきにちょくちょく参加しているととこうした事情にもだんだん慣れてきますよ😋」
「(初参加者へ)ところでSTI(Single Table Inheritance)ってご存知です?」「いやー...😅」「あ、ご心配なく❤️つっつき会は気楽な集まりなんでわからないこととか知らないことはどんどん聞いてくださいね😋」「😃」「😃」
参考: Active Record の基礎 2.2 スキーマのルール| Rails ガイド -- STIに少しだけ言及
「初参加の皆さんが入社する前の社内勉強会『エンタープライズアプリケーションアーキテクチャパターン』でSTIを説明したことがあったのでG-Suiteからスライドを引っ張り出してみるか(作っといてよかったー😉): これこれ↓、STIはデータの持ち方のひとつで、要は継承関係を持つデータを(個別のテーブルではなく)1つのテーブルにまとめてそこにマッピングするという手法です」「おー」
「メリット/デメリットはスライドにも書いてあるとおりですが、RailsはこのSTIをデフォルトでサポートしているので、ActiveRecordのモデルを普通に継承して使うとこのようにSTIとしてデータを持ちます: type
フィールドにそのクラス名が入るとか」「😃」
「この書籍では他にもClass Table Inheritance(クラステーブル継承)パターンやConcrete Table Inheritance(具象テーブル継承)パターンなんかも紹介されてますので、後で社内スライドをどぞ😎」「はいー😀」
「どうやら改修箇所のこの辺↓がSTIっぽいかな: コードだけざっと見たところでは以前はイニシャライザが継承の数だけ呼ばれてたのかも」「『privateにつき呼んではならない』ってありますね😆」
# activerecord/lib/active_record/persistence.rb#L68
def instantiate(attributes, column_types = {}, &block)
klass = discriminate_class_for_record(attributes)
+ instantiate_instance_of(klass, attributes, column_types, &block)
+ end
+
+ # Given a class, an attributes hash, +instantiate_instance_of+ returns a
+ # new instance of the class. Accepts only keys as strings.
+ #
+ # This is private, don't call it. :)
+ #
+ # :nodoc:
+ def instantiate_instance_of(klass, attributes, column_types = {}, &block)
attributes = klass.attributes_builder.build_from_database(attributes, column_types)
- klass.allocate.init_with("attributes" => attributes, "new_record" => false, &block)
+ klass.allocate.init_from_db(attributes, &block)
end
⚓RedisCacheStoreのincrement
/decrement
にexpires_in
オプションを追加
# 同PRより
irb> Rails.cache.increment("my_counter", 1, expires_in: 100)
1
irb> Rails.cache.data.ttl("my_counter")
=> 99
# skip set expire when "my_counter" has ttl
irb> Rails.cache.increment("my_counter", 1, expires_in: 200)
2
irb> Rails.cache.data.ttl("my_counter")
=> 98
つっつきボイス: 「100とか200は秒なんでしょうね」「ChangeLogにそう書かれてますね: 普通にありそうな機能だけど今までできなかったとはねー😌」
⚓Railsガイドのセクション編成が変更
「Digging Deeper」の一部を「Other Components」に移したそうです(左が現状、右が変更後)。
つっつきボイス: 「実は今個人的にYassLabさんとRailsガイドの5.1対応翻訳を進めているところで、ガイドの編成が変わるとそれなりに影響があるので」「こうやってガイドが充実するというのはいいですね❤️: フラットに増えると読みづらくなるしこうやってセクション分けしてもらった方がいいし」
直接関係ありませんが、#33270で「コマンドラインガイドが冗長すぎるのでもっとmanページっぽく簡潔に書いて欲しい」というリクエストを見かけました。
つっつきボイス: 「そこのバランスも考えちゃいますね🤔: 初心者ほど言葉を尽くして書いて欲しいだろうし、慣れてくるとそれが邪魔になってきたりするし」「慣れてきたら--help
付けて実行するでしょうね」「それにたとえばrails generate
とだけ打てばサブコマンドが表示されますし😋」
「ガイドのDigging DeeperのあたりはRailsチュートリアルやってからの方がいいんでしょうか?」「それはあるかも: チュートリアルにはひととおり盛り込まれているので、そこでキーワードを押さえておいてからこういうページを眺める方が入りやすいかもですね😉」「とはいうもののRailsチュートリアルには実際に使わない機能もいっぱい盛り込まれているので無理して片っ端から機能を使おうとしなくてもいいですよ😆」「😆」
⚓#has_secure_password
の属性名を設定可能に
# activemodel/test/cases/secure_password_test.rb#L185
test "authenticate" do
@user.password = "secret"
+ @user.activation_token = "new_token"
assert !@user.authenticate("wrong")
assert @user.authenticate("secret")
+
+ assert !@user.authenticate_activation_token("wrong")
+ assert @user.authenticate_activation_token("new_token")
end
つっつきボイス: 「なるほど、パスワードがあるかどうかをチェックするメソッドが今まではRails側で決め打ちだったのを変更できるようにしたと: この修正ならそれだけのために自分でメソッド再定義とかしなくて済む😋」「😃」「そんなに頻繁に使う機能ではなさそうですけどね😉」
⚓retry_on
/discard_on
に例外を複数渡せるようにした
# activejob/lib/active_job/exceptions.rb#L45
- def retry_on(exception, wait: 3.seconds, attempts: 5, queue: nil, priority: nil)
- rescue_from exception do |error|
+ def retry_on(*exceptions, wait: 3.seconds, attempts: 5, queue: nil, priority: nil)
+ rescue_from(*exceptions) do |error|
if executions < attempts
- logger.error "Retrying #{self.class} in #{wait} seconds, due to a #{exception}. The original exception was #{error.cause.inspect}."
+ logger.error "Retrying #{self.class} in #{wait} seconds, due to a #{error.class}. The original exception was #{error.cause.inspect}."
retry_job wait: determine_delay(wait), queue: queue, priority: priority
else
if block_given?
yield self, error
else
- logger.error "Stopped retrying #{self.class} due to a #{exception}, which reoccurred on #{executions} attempts. The original exception was #{error.cause.inspect}."
+ logger.error "Stopped retrying #{self.class} due to a #{error.class}, which reoccurred on #{executions} attempts. The original exception was #{error.cause.inspect}."
raise error
end
end
end
end
つっつきボイス: 「exception
が*exceptions
になったのか」「あー、retryのたびに少しずつ異なる例外が発生するというのはありうるから、それをまとめて渡せるようにしたということね」
「そしてこれはActiveJob」「ActiveJobはジョブ制御のラッパーという理解で合ってます?」「そのはずです: 後ろで動かすのはSidekiqとかDelayed_jobとかResqueあたりが多いです」
「非同期処理には本質的にワーカーが必要になります: たとえば巨大なCSVを生成して完了したらダウンロードリンクを作るみたいな時間のかかる処理はフロントのWebサーバーではできないので、それとは別にワーカープロセスを立ち上げてそこにジョブを投げるという形を取る」「ActiveJobはそういう非同期ジョブを扱うもので、そのバックエンドで動くミドルウェアがいろいろあり、それをどう使い分けるかですね」
「一番メジャーで実績があるのはおそらくSidekiqかResqueあたりかな: Delayed_jobはもう少し古くて実装もちょっとしょぼい😆」
「SidekiqやResqueだとその背後にさらにRedisという機能豊富なKVS(Key-Value Store)があってジョブのプッシュ通知なんかをそのRedisでサポートしている」「これを使うとジョブを投げたら待ち構えていたワーカーがすぐそれを動かすなんてこともできる」「SidekiqやResqueはRedisのおかげで、ジョブの優先順位付けやリトライ処理とか、重いジョブ/軽いジョブに応じて複数キューを使い分けるようなより高度な処理とかもできる: たとえば有料会員だけキューを別にしてジョブにリソースを多く割り当てるとか」「アダルトサイトなんかにありそうなやつですね🤣」「ま、どこでもやってる機能ですね: YouTubeとかG-Suiteとかもそうですし」
「ただねー、そのためにはRedisを立ち上げて常駐させないといけないわけですよ😓」「😆」「すると今度はRedisが死んでないかどうか確認したりとかRedisのバックアップが必要になったりとか、そっちの手間がかかる😂」
「逆にDelayed_jobはRedisではなくデータベースに専用のテーブルを作って保存するので既存のデータベースに乗せればそういう手間がかからないのが利点: その代りデータベースに定期的に5秒に1回とかポーリングかけたりするので実装の効率はよくない😭」「なるほど、用途に合わせてどれにするか検討すると🤔」
「Redisって思った以上にいろいろやれるヤツだったんですね😲」「実際Redisは当初はキーバリューストアとして出発したのがその後機能がいろいろ追加されてきたので今や単なるキーバリューストアとは言い切れないですね💪(PostgreSQLほどではないにしても)」「ふーむ」「なのでRedisっていろんな使い方ができるし、どの機能を使っているかによって将来Redisを別のミドルウェアに置き換えるときの選択肢も違ってきます」「なるほど!😃」
参考: Active Job の基礎 | Rails ガイド
⚓ドキュメント更新: OS XをmacOSに置き換え
つっつきボイス: 「TechRachoをやっているうちにいつの間にか呼び名がmacOSって変わってて当時おやって思いましたね」「OSの名前が猫さんシリーズというかネコ科の動物シリーズでなくなったあたりで変わった気がする?」
さらに、2016年にリリースされたmacOS Sierraより、iOSなどアップルの他のOSの名前との親和性を図るため、「OS X」から「macOS」へと改称された
Wikipediaより
⚓Rails
⚓fie: RailsのWebSocket接続上で動くフロントエンドフレームワーク(Ruby Weeklyより)
- サイト: Fie
- リポジトリ: raen79/fie
- クイックスタート: Fie QuickStart
- ガイド: Fie Guides
特徴:
- 3-wayデータバインディング
- HTMLバインディング(DOMイベント用)
- deep nested構造のサポート
- pub/subが組み込み済み
- isomorphicな作りでJavaScriptへの依存をほぼ排除可能
- 開発期間の短縮
つっつきボイス: 「ふんふん、TurboLinksを使ったり...おーっと、Opal使ってるぞこれ😲!」「OpalってRubyをJavaScriptに変換するアレか」「Opalってproductionでどのぐらい使われてるんだろか?😅OpalってRubyのコードを1対1対応的にJavaScriptのコードに置き換えるかなり泥臭いというか力技なやつ」「アセンブラみたいな」「RubyとJavaScriptってIntegerやStringの扱いに違いがあるからOpalもそういう部分で動かなかったりすることもあるわけで: ともあれこのfieはJavaScriptなしでRubyだけで書けるぜということか」「人類の夢🚀」「なかなかアツい: 面白そうなのは間違いないっすね😀」「😆」
isopmorphicというと数学の「同型写像」かな?っと思ったら、Opalの力でRubyがJavaScriptと同じように動くということのようです。
参考: 同型写像 - Wikipedia
⚓PaperclipからActive Storageへの移行を安全に行う(Ruby Weeklyより)
↓Paperclipの移行ガイド(翻訳済み)が既にありますが、それよりもっと詳しく書かれているそうです。
つっつきボイス: 「初めての人🔰もいるので説明しておくと、PaperclipはRailsで添付ファイルを扱うのによく使われてたんですが、Rails 5.2でActive Storageという同じ機能↓が公式に導入されたんですね」「でPaperclipはその後開発が終了したので上の移行ガイドが開発元のThoughtBotから出されました」
「Webアプリでの添付ファイルの扱いってRailsに限らずなかなか面倒で、たとえばアップロードのフォームの後に確認画面を追加するだけで一気に面倒になる」「おー😲どの辺が面倒に?」「添付ファイルってフォームをPOST
するときにアップロードされるんで、確認画面がなければアップロードしてバリデーションすればおしまいなのに、確認画面があると一部のデータでバリデーションエラーが起きて戻ったフォームに、あたかもさっきと同じ添付ファイルが残っているかのように再表示したいじゃないですか: でもエラーの場合はまだデータベースに添付ファイルがsaveされてなくてそのままだと添付ファイルが再表示されない😓なのでいろいろ工夫しないといけないとか」
「その場合フロント側のJavaScriptでどうにか再表示することになるんでしょうか?」「いや、結局サーバー側に一度は一時的に保存しないといけなくなることが多いですね: 他にも、再アップロードしたときに一度目のアップロードファイルをIDを頼りに正確に取り出さないといけなくなったりとか、Webアプリでは誰しも一度はやる作業なんですけど本当に面倒😭」「ActiveStorageはそういうところも一応やってくれます😋」「😃」
⚓Railsのフラグメントキャッシュを分解調査する(Ruby Weeklyより)
珍しくつっつきより先に翻訳公開しました。
つっつきボイス: 「st0012さんがこの記事を書いた動機のひとつが、フラグメントキャッシュについての情報が意外にネット上に見当たらないからだったそうです」「たぶんフラグメントキャッシュってインターフェイスも含めて昔からほとんど変わってないからじゃないかな?🤔フラグメントキャッシュそのものは割と普通のキャッシュ」「😃」
「Railsだと他にもロシアンドールキャッシュっていう、普段表に出てこないキャッシュもありますけどフラグメントキャッシュとどんな関係でしたっけ?」「ロシアンドールキャッシュの末端がフラグメントキャッシュ」「なるほど😃」
「Railsのキャッシュはいくつかの階層になっているんですが、フラグメントキャッシュはその中のひとつで、たとえば以下のようにcache なんちゃら
と書くことで範囲を指定し、そこがキーになって、キーが変わらない限りキャッシュから返すようになり、更新されていれば再レンダリングするというものです」「ふむふむ」「まあ他の言語とかフレームワークでも似たようなことはやっているはず」
<% cache project do %>
<b>All the topics on this project</b>
<%= render project.topics %>
<% end %>
「そしてRailsのキャッシュの賢いところは、キャッシュを入れ子にしたときに、入れ子の外側が更新されたら内側のキャッシュも全部廃棄して再レンダリングし、入れ子の内側だけが更新された場合は外側は更新せずにこれまでどおりキャッシュを返せることで、これがロシアンドールキャッシュですね」「キャッシュが入れ子になっていれば自動でよしなにやってくれるということか」「そうそう」
「ただ、キャッシュはあまり気軽に使うとはまります: 特にパフォーマンスが要求される箇所でもないのにむやみにキャッシュすると後で自分の首を締めることになるかもしれないので😇自分は必要がない限り使わないですね」「😵」「それはたとえば画面が更新されるべきときに更新されないとか?」「他にもキャッシュで他人のデータが表示されたりするとか、とってもよくあるパターン🕶」「😲」
「Railsでない素のCSSなんかでも、更新したのにキャッシュに反映されなくてはまるなんてよくありますね」「キャッシュは実は難しいです: 上でいうとproject
が更新されれば当然キャッシュも更新されますが、project
の下にたとえばusers
なんてリストがあったときにそちらが更新されない、なんてことがあったりする😭そういうときはusers
が更新されたときにproject
に明示的にtouchするとかして更新しないといけなくなったり」「😲」「Railsのキャッシュはそれなりに賢くできてますが、そういうわけでこれに全面的に頼るのはどうかなーと思うわけです: キャッシュを使うのは遅くなったときぐらいで」「😃」
参考: Rails のキャッシュ - ロシアンドールキャッシュ: 概要 | Rails ガイド
ガイドからの写しですが、Rails 3まであった「ページキャッシュ」と「アクションキャッシュ」はRails 4からgemに切り出されてデフォルトでは含まれなくなりました。
⚓RailsでのStripe支払いを管理する(Ruby Weeklyより)
↓TechRachoでも一般的なStripe記事を公開しました。
つっつきボイス: 「決済代行サービスのStripe、BPS社内でもどんどん使われ始めてますね」「Stripeのいいところは、公式ドキュメントが非常にしっかりしていることと、Rubyのコードもあること: そういえばRubyKaigi 2018にもStripeの人が来てたと思うけど↓、もしかするとStripeってRailsで書かれてるんじゃないかな?なんてね」「ありそう」「Stripeは問題なく実装できるいいヤツ❤️」
参考: A practical type system for Ruby at Stripe. - RubyKaigi 2018
参考: A practical type system for Ruby at Stripe. - mactkg-pub -- セッションのメモです
⚓breezy_pdf_lite-ruby: HTML->PDF変換サービスのRubyバインディング(Ruby Weeklyより)
- リポジトリ: danielwestendorf/breezy_pdf_lite-ruby
- リポジトリ: danielwestendorf/breezy-pdf-lite
- サイト: Create Beautiful PDF Reports
つっつきボイス: 「最終的にChromeでレンダリングさせてるみたいです」「そうそう、この種の変換はだいたい裏でヘッドレスブラウザを立ち上げてやってますね: html2pdfあたりは独自のエンジンを持ってたような気がするけどどうだったかな...」
「ま、HTMLからPDFを作成するだけなら意外と簡単です😎普通の紙に印刷して人間が読めればそれでいいので、プリント用CSS(@media print
)を書くのが実は編集も含めて圧倒的に楽😋」「😃」
「一方、専用の帳票に印刷するための本格的なPDF帳票(宅配便の帳票出力↓とか)なんかを作ろうとすると一気に大変になる: インチ単位とかmm単位で座標を合わせないといけないし、文字が帳票からはみ出たりとか、特定のフォントファイルを使わないといけないとか、ページまたぎの処理が面倒とか、もろもろ大変😭」「😆」
パソコン宅急便を発送して来た!#パソコン宅急便 #ヤマト運輸 #パソコン修復 pic.twitter.com/1VulzLFkbw
— KENT (@prowrestle) July 2, 2017
「確か日本製の帳票PDF作成gemでおすすめしてたのありましたよね?」「あーThinReportsですね: これはかなり優秀で、GUIのエディターがついているのがとてもエライ💪」「😃」
「そういう帳票作成の実装って、たいてい帳票を定規で測って印刷しては神微調整を繰り返すみたいな古典的な作業になっちゃうんですね: あれはつらい🤮」「😭」「古典的なペーパーフィード付きのドットインパクトプリンタ↓って、帳票のために長らく使われてましたよね」「今でもカーボン紙なんかのために現役で使われてます: 宅急便の会社によっては帳票枠なしの普通のPDF印刷に移行したところもあるみたいですが」
↑何だか曲を演奏してます。
⚓11月開催のRubyWorld Conference 2018情報
Link: 2018年11月1日(木)2日(金) RubyWorld Conference 2018 まつもとゆきひろ 基調講演 | ネットワーク応用通信研究所 https://t.co/y5aezRLdtf
— Yukihiro Matz (@yukihiro_matz) July 5, 2018
だいぶ先になりますが、RubyWorld Conference 2018のお知らせです。参加登録は現在準備中です。
⚓その他Rails
- 元記事: Ignore PHP bots with Rack::Attack - Andy Croll(Ruby Weeklyより)
- 元記事: Sidekiq-ifying Emails at Reflektive – Julia Chou – Medium(Awesome Rubyより)
- 元記事: Notes on writing Service Objects - DEV Community 👩💻👨💻(Hacklinesより)
- 元記事: We no longer maintain the rspec_candy gem - makandra dev(Hacklinesより)
⚓Ruby trunkより
⚓signal.cでバッファオーバーフロー
- Bug #14893: Global buffer overflow in signm2signo of signal.c. - Ruby trunk - Ruby Issue Tracking System
- PR: Fix global buffer overflow in signal.c. by take-cheeze · Pull Request #1904 · ruby/ruby
# signal.c#L262
if (prefix_ptr) *prefix_ptr = prefix;
+ left_len = len - prefix;
for (sigs = siglist + !exit; sigs->signm; sigs++) {
- if (memcmp(sigs->signm, nm + prefix, len - prefix) == 0 &&
+ if (left_len != strlen(sigs->signm)) { continue; }
+ if (memcmp(sigs->signm, nm + prefix, left_len) == 0 &&
sigs->signm[len - prefix] == '\0') {
return negative ? -sigs->signo : sigs->signo;
}
つっつきボイス: 「C言語で普通によくあるメモリ範囲のあふれみたい🕶」
⚓-DMJIT_FORCE_ENABLE=1
が動かない
k0kubunさんが「RubyBenchの後で見てみるのでそれまで無視で」と返信付けてました。
# 同issueより再現コード
ruby --jit-wait --disable=gems -e '1000.times { a, b = nil }'
# または
ruby --jit-wait --disable-gems -e '1000.times { break if /a/ =~ "ab" && !$~[0] }'
追伸: その後#63875でk0kubunさんによって修正されました。
⚓Pathname#join
の挙動がFile.join
と異なる
# 同issueより
Pathname.new('/a').join('/b').to_s
# => "/b"
File.join(Pathname.new('/a'), '/b').to_s
# => "/a/b"
つっつきボイス: 「あーこれねー😅、Pathname.new
だと/b
みたいにスラッシュを付けてjoin
した時点で/b
だけになっちゃうと: 普通はjoin
の引数には変数が置かれるだろうし、ちょっとつらい」「RailsだとFile.join
の方がよく使われてたように思うけど、挙動を揃えて欲しいというのは分かりみある」
⚓Ruby
⚓Rubyのメモリ設定でスラッシングを防ぐ(Ruby Weeklyより)
- スライド: Faster Apps, No Memory Thrash
- RubyKaigi 2018ページ: Faster Apps, No Memory Thrash: Get Your Memory Config Right - RubyKaigi 2018
RubyKaigi 2018で見ました❤️。
つっつきボイス: 「TechRachoの翻訳記事↓でお馴染みのRubyチューニングの鬼Noah Gibbsさんです: 昨年の広島のRubyKaigiで何度も見かけたのに気づけなかったので、今年やっとお礼を伝えられました😀」「チューニングお世話になってます🙇」「スライドをすごく簡単にまとめると、mallocじゃなくjemallocを使おう、環境変数はしっかり設定しよう、自作のEnvMemというgemはチューニングに便利、という感じです」
「しかしスラッシングになるとカーネルパラメータとの絡みもあるからなー」「そういえばスラッシングと断片化ってまた違うんでしょうか?」「そうですね、一般的には、断片化が進んだ結果、本来ならばひとかたまりのデータなのにあちこちから読み出さなければならなくなって遅くなった状態をスラッシングって言いますね」「なるほど!😀」「そういえば情報処理技術者試験にスラッシング出てました😋」「そうそう、一般にはスワップ処理なんかで出てきますね☺️」
「ところで実物のNoah Gibbsさんの話す英語、自分史上最大ぐらいに早口だったのでもうスライド画面が頼りでした😅: TechRachoでRubyメモリ関連の記事を翻訳してなかったらマジでついていけなかったかも」「RubyKaigiはRubyの非常にコアな部分に関する発表がとても多いので、TechRacho記事のこの辺↓とか読んで予習しとかないと大変ですね😎」「もっともっとー😂」
⚓RubyのForwardable
でメソッドを委譲(Ruby Weeklyより)
つっつきボイス: 「Forwardable
はRuby標準の委譲ライブラリだそうです」「委譲は普通に使うけどこれは知らなかったー」「社内の方で確か知ってた人いました」「やるなー🕶: def_delegators
なんてのがあるし↓」「これはRuby Goldの試験にも出なかった?」「...出てなかったかも...」
# 同記事より
module Decorator
class StudentDecorator
extend Forwardable
def_delegators :@student, :first_name, :last_name, :professors, :birthday, :course
def_delegator '@student.course', :name, :course_name
def initialize(student:)
@student = student
end
def full_name
"#{@student.first_name} #{@student.last_name}"
end
def professors_names
@student.professors.map(&:name).join(', ')
end
end
end
参考: るびま0012号 標準添付ライブラリ紹介 【第 6 回】 委譲 -- 公式ドキュメントの内容もるびまに委譲されてます。
⚓Rydux: ReduxをRubyで実装(Ruby Weeklyより)
- リポジトリ: alexdovzhanyn/rydux
# 同リポジトリより
require 'rydux'
class UserReducer < Rydux::Reducer
@@initial_state = { name: 'Alex', age: 20 }
def self.map_state(action, state = @@initial_state)
case action[:type]
when 'CHANGE_USER_NAME'
state.merge(name: action[:payload][:name])
else
state
end
end
end
Store = Rydux::Store.new(user: UserReducer)
class Friend
def initialize
Store.subscribe(self)
@users_name = Store.state.user.name
end
def state_changed(state)
@users_name = state.user.name
end
def greet_user
puts "Hello, #{@users_name}"
end
end
# Create a new friend (this will subscribe it to the store)
friend = Friend.new
friend.greet_user #=> Hello, Alex
# Change a value in the store
Store.dispatch(type: 'CHANGE_USER_NAME', payload: { name: 'Mike' })
friend.greet_user #=> Hello, Mike
つっつきボイス: 「Rydux!発音はライダックス?リダックス?」「やっぱりステート管理欲しいんですね: Vue.jsにも状態管理があるぐらいだし」「JavaScriptはこういうライブラリがないとステートがマジでわけわからなくなるから欲しくなると思うけど、Rubyには果たして必要かなー?とは思う🤔」「たとえばサーバーサイドレンダリングをやってればこういうのが欲しくなるかもしれないけど、普通のビジネス系のデータはデータベースに入れるからあまり複雑なステートを使う機会がない気がする」「😃」「SPAなんかでどうしてもサーバー側でレンダリングしたい!みたいなときなら要るのかもしれないけど、そんな状況ってあるのか?」「😆」「😆」
参考: シングルページアプリケーション - Wikipedia
⚓ビジネスルールもオブジェクト(RubyFlowより)
Service Object反対派のAvdi Grimm氏の動画付き記事です。
つっつきボイス: 「これは割と基本的な記事かなー: 何とかRule
みたいなクラスを作ってそれをDIするみたいな」「Strategyパターン的な」
class MemberEligibleForTierRule
attr_reader :member, :tier
def initialize(member:,tier:)
@member, @tier = member, tier
end
def satisfied?
(((member.miles + member.qualifying_partner_miles) >= tier.required_miles) ||
(member.segments >= tier.required_segments)) &&
(member.dollars >= tier.required_dollars)
end
end
⚓Rubyアソシエーション開発助成成果報告会(終了)
"Rubyアソシエーション開発助成成果報告会 - Rubyアソシエーション | Doorkeeper" https://t.co/Kidwqd2PBb まだあいてます。
— _ko1 (@_ko1) July 4, 2018
ウォッチ公開の頃には終わってますね💦。気づくのが遅すぎました。#ragrantハッシュタグで追えます。
#ragrant Rubyアソシエーション開発助成成果報告会はじまりました pic.twitter.com/bvKcn9ImVW
— Koichiro Ohba (@koichiroo) July 7, 2018
今日の #ragrant のスライド上げました https://t.co/gj6ZMSHCjL
— k0kubun (@k0kubun) July 7, 2018
https://t.co/UQj7Odx2NQ
今日の資料です #ragrant— Uchio Kondo🍙 (@udzura) July 7, 2018
⚓その他Ruby
#RubyKaigiKaigi pic.twitter.com/ayftSvUNP7
— Akira Matsuda (@a_matsuda) July 6, 2018
#RubyKaigiKaigi pic.twitter.com/LihnSS0sWg
— Akira Matsuda (@a_matsuda) July 7, 2018
来年のRubyKaigi会場です。こちらは#rubykaigikaigiハッシュタグで追えます。
参考: RubyKaigiKaigi に行ってきた - 虚無庵 -- 「RubyKaigiはCFPを応募すると割引になる」そうです👀👁
⚓クラウド/コンテナ/インフラ/Linux
⚓「プロフェッショナル IPv6」が無料ダウンロード
つっつきボイス: 「おー、あきみちさんの本!: IPv6の知識って学部生以来だから勉強しなきゃ💦」「IPv6っていうとNTTのフレッツのバックボーンとかで使われている印象でした」「NGNですね: ところがですねー、NGNの仕様はIPv6と同じじゃないんですよ」「えー!😲」「NTTのNGNはIPv6の仕様が固まる前に使われ始めたからしょうがないんですが、インターネットのIPv6とNGNではそのまま接続できない」「何だかガラケーの独自HTMLみたいな話ですね😅」
参考: IPv6とNGN | テクノロジーコラム | 情報畑でつかまえて
「(目次を見ながら)変わってないところも結構ありそう、かと思うと知らないものもある...お、ネイバーディスカバリーかいいなー💪、お、『第11章 Path MTU discovery』のあたりとか面白いし、知っておくとネットワークに詳しい感出せるかもですよ😎」「MTU=Maximum Transfer Unit」「MTUは通信路によって異なるんですが、最大でどれぐらい大きなMTUが通るかというのはは調べるしかないので、それを調べるためのアルゴリズムがこのPath MTU discovery」「おー、IPv4だとよくPCのネットワーク設定のMTUいじって大きくするみたいな素人ネットワークチューニング記事を見かけますけど」「MTUが実際に詰まるのはどちらかというとL2つまりイーサネットのフレームサイズ(たとえばすごく古いイーサネットだと確かフレームサイズは1536バイト)で、通信経路に1つでもMTUの小さいルーターやスイッチがあると通らなくなったりします」「そっかー😃」「とにかくPath MTU discoveryのあたりはいろいろ面白いので勉強してみるといいですよ😋」
「『第13章 IPv6エニーキャスト』は日本でも早くから使われてましたね」「ついでにすみません、エニーキャストはマルチキャストとどの辺が違うんでしたっけ?」「あーかなり違いますね: まずマルチキャストは動画なんかの配信が目的で、大勢の人が1つのマルチキャストアドレスを共有すると、そのアドレスに送信した動画データが全員に配信されるというものです」
「エニーキャストの目的はむしろ逆で、同じアドレスを複数ユーザーが共有する点は同じなんですが、全員に届けるのではなく誰か1人に届けばいいというヤツです」「エニーキャストはたとえばDNSとかタイムサーバー(NTPサーバー)なんかに使います: でないと特にNTPサーバーは世界中ですごく沢山の人が同じアドレスを指定したりしているので、エニーキャストしないとたちまちパンクする😇」「どちらかというと分散が目的なんですね」「それもあります: ただし冗長化とは違いますが🧐」「😃」
⚓BOSH: 分散システムのリリース/デプロイ/ライフサイクル管理(Awesome Rubyより)
- サイト: Cloud Foundry BOSH
- リポジトリ: cloudfoundry/bosh
⚓SQL
⚓Google BigQueryの公式インサイド情報
つっつきボイス: 「先週BigQueryが話題に出たので今回そのあたりを見てみました😋」
⚓Google BigQueryとは
参考: なぜ私たちはSumo Logicを捨ててBigQueryを選んだのか - tech.guitarrapc.cóm
参考: BigQueryで150万円溶かした人の顔 - Qiita
つっつきボイス: 「溶かした記事は有名なヤツですね: 記事にもありますけどBigQueryはスキャンしたデータ量で課金されるので、毎回全部readするような非効率なクエリを凄い頻度で実行するとこうなる😇」「BigQueryは普通のSQLと同じに考えない方がいいということでしょうか?」「というよりは課金体系の違いですね: 普通のSQLではそういう課金の仕方はしてないので😉」「なるほど😃」「データセットが極端に大きい時は忘れずに事前に動かして試す方がいいでしょうけど、そうでなければそんなに怖がらなくてもいいと思います😉」「😃」
⚓pgquarrel: PostgreSQLスキーマ比較ツール(Postgres Weeklyより)
# 同記事より
$ pgquarrel --source-dbname=dev --target-dbname=prod --source-host=192.168.0.8 --target-host=192.168.0.6 --function=false --comment=true
--
-- pgquarrel 0.4.0
-- quarrel between 9.1.24 and 10.4
--
CREATE DOMAIN public.cep AS text
CONSTRAINT cep_check CHECK ((VALUE ~ '^\d{5}-d{3}$'::text));
CREATE TABLE public.bar (
description character varying(30) NOT NULL,
foo_id integer,
id integer NOT NULL
);
ALTER TABLE ONLY public.bar
ADD CONSTRAINT bar_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.bar
ADD CONSTRAINT bar_foo_id_fkey FOREIGN KEY (foo_id) REFERENCES foo(id);
COMMENT ON TABLE public.bar IS 'this is another table';
COMMENT ON COLUMN public.bar.description IS 'this is a column';
ALTER TABLE ONLY public.foo DROP COLUMN removeit;
ALTER TABLE public.foo RESET (autovacuum_enabled);
⚓JavaScript
⚓先週のflutter
We just launched a new Github repo for samples and @redbrogdon's already added a JSON example app! It shows how to deserialize with 3 different libraries.
Check it out at → https://t.co/kbGCdCwgf5 pic.twitter.com/vRsyXXMiz0
— Flutter (@FlutterDev) July 3, 2018
- リポジトリ: flutter/samples
参考: JSON and serialization - Flutter
参考: samples/built_complex_object.g.dart at master · flutter/samples
⚓ECMAScript 2018仕様が公開(JavaScript Weeklyより)
つっつきボイス: 「こうやって仕様が毎年出ると、結局どのバージョンで書けばいいんだ?問題が終わらない😭」「JavaScriptトランスパイラのBabelは真っ先に対応しそうですね」「そうなるでしょうね: ChromeやFirefoxもじきに追従するだろうし、問題になるとすれば更新の止まった古いスマホのブラウザかなー🤔」「ECMAScript 2018で書いても大丈夫になるのはいつだろう...」
⚓ECMAScriptのプロポーザルを追うサイト(JavaScript Weeklyより)
- サイト: The TC39 Process
- リポジトリ: tc39/proposals
オフィシャルなんだそうです。
つっつきボイス: 「TC39は有名ですね: ECMAのタスクフォース的なグループ」
⚓Chrome 69でLayoutNGが登場
つっつきボイス: 「先週のbabaさん速報記事そのままですが💦」
⚓CSS/HTML/フロントエンド/テスト
⚓テスト自動化に関する書籍情報
つっつきボイス: 「何冊か家に本があった気がする」「テスト自動化の難しさは、会社とか案件によってテスト内容がものすごく違うというところにありますねー🤔」「フロント界隈の動向が激しいのも一因でしょうか?」「そこはそれほどでもないです: Seleniumドライバ↓なんかは歴史も長いし」「そっかー😲」「『こういうときはこうする』みたいなテストのノウハウが、案件や組織が異なるとまるで通用しないなんてこともざらにあるので、そこが大変😵」
⚓headless chromeでcookieを扱う
つっつきボイス: 「えー、headless chromeにcookie扱うAPIがないのか😲」「page.driver.browser.manage.all_cookies
みたいにすると取れるのね↓😋」
module FeatureHelper
def cookie_value_from(name:)
cookies = page.driver.browser.manage.all_cookies
cookie = cookies.find { |c| c[:name] == name }
cookie && cookie[:value]
end
def add_cookie(name:, value:)
page.driver.browser.manage.add_cookie(
name: name,
value: value.to_s
)
end
end
「Poltergeistって今も使われてるんでしたっけ?」
終わってたのはPhantomJSの方でした↓。PoltergeistはCapybara向けのPhantomJSドライバです。
週刊Railsウォッチ(20171026)factory_girlが突然factory_botに改名、Ruby Prize最終候補者決定、PhantomJS廃止、FireFoxのFireBug終了ほか
⚓LayoutIt: CSS Gridレイアウトのインターフェイスビルダー(Frontend Focusより)
つっつきボイス: 「なるほど、こういう縦横で割り切れないいやらしいレイアウト↑なんかをCSS Gridで作れるGUIツールってことか」「コーディングで嫌がられるレイアウト😆」「layoutitってlayoutが動詞になってるし😅」
⚓Feature Policyとは(Frontend Weeklyより)
Googleのドキュメントです。
Feature-Policy: unsized-media 'none'
Feature-Policy: geolocation 'self' https://example.com
Feature-Policy: camera *;
つっつきボイス: 「Feature Policyヘッダーって聞いたことぐらいはあったけどこんなにいっぱいあったとは...😲」「このcamera
とかは見たことある😋」
参考: Feature Policy -- W3Cの仕様
参考: Feature Policy、ブラウザの特定機能を無効にする仕様 - ASnoKaze blog
⚓言語よろずの間
⚓Rutie: RubyとRustをつなぐ(Ruby Weeklyより)
- リポジトリ: danielpclark/rutie
- Crate: rutie - Rust
類似のRuru↓とruby-sysの続編プロジェクトだそうです。
extern crate rutie;
use rutie::{Object, RString, VM};
fn try_it(s: &str) -> String {
let a = RString::new(s);
// The `send` method returns an AnyObject type.
let b = a.send("reverse", None);
// We must try to convert the AnyObject
// type back to our usable type.
match b.try_convert_to::<RString>() {
Ok(ruby_string) => ruby_string.to_string(),
Err(_) => "Fail!".to_string(),
}
}
#[test]
fn it_works() {
// Rust projects must start the Ruby VM
VM::init();
assert_eq!("selppa", try_it("apples"));
}
fn main() {}
つっつきボイス: 「RubyでRustを使ったり、RustからRubyを使ったりできるみたい」「😲」
⚓termtosvg: ターミナル操作をSVGでキャプチャする(GitHub Trendingより)
- リポジトリ: nbedos/termtosvg
Pythonで書かれています。READMEのアニメーションもこれで作成されていて、気のせいか文字がぐにゃぐにゃ揺れています。
つっつきボイス: 「SVGでアニメーションができるって初めて知った😲文字の再生ならSVGの方が軽そうだけど」「そのせいか画面がちょっと揺れますね」
参考: UI改善にキラリと役立つ! SVGアニメーションの作り方まとめ - ICS MEDIA
⚓Form: Goのstructでフォーム生成
struct から HTML の入力フォームを生成するパッケージ。おもしろい。 #golang / “GitHub - joncalhoun/form: Easily create HTML forms with Go stru…” https://t.co/SdLmKdNlkq
— mattn (@mattn_jp) July 5, 2018
- リポジトリ: joncalhoun/form
何だか既視感あります。
// 同リポジトリより
type Address struct {
Street1 string `form:"label=Street;placeholder=123 Sample St"`
Street2 string `form:"label=Street (cont);placeholder=Apt 123"`
City string
State string `form:"footer=Or your Province"`
Zip string `form:"label=Postal Code"`
Country string
}
func main() {
tpl := template.Must(template.New("").Parse(inputTpl))
fb := form.Builder{
InputTemplate: tpl,
}
pageTpl := template.Must(template.New("").Funcs(fb.FuncMap()).Parse(`
<html>
<body>
<form>
{{inputs_for .}}
</form>
</body>
</html>`))
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html")
pageTpl.Execute(w, Address{
Street1: "123 Known St",
Country: "United States",
})
})
http.ListenAndServe(":3000", nil)
}
つっつきボイス: 「しかしこのFormってパッケージ名はひどい🤣」「探しにくすぎるー🤣」
⚓その他
⚓Java11のAPI変更
つっつきボイス: 「Javaってもう11になったのかー」「Java勢の方に思ったけど今日のつっつきにはいなかった💦」「strip()
が今までなかったなんて😅」
参考: instance method String#strip
(Ruby 2.5.0)
⚓VDIとは
VDI運用がメインの会社の場合、まだ多くはメモリ4GBでございます、、 https://t.co/byeZQlsYIR
— もっさん (@wmossanh) July 5, 2018
参考: VDI(デスクトップ仮想化)とは | シンクライアントとの違い・サービス比較 - VDI(デスクトップ仮想化) | ボクシルマガジン
つっつきボイス: 「AWSにもシンクライアント的なサービスがあるってこの記事で初めて知りました」「ああAWS WorkSpacesですね↓」「メモリ4GBかー」「ネットワークさえ速ければもの凄いロースペックマシンよりはVDIの方がいいんじゃね?😎」
参考: Amazon WorkSpaces (完全マネージド型でセキュアな仮想クラウドデスクトップ - VDI)| AWS
⚓「ためしがき」フォント表示チェックサイト
- サイト: ためしがき
入力すればわかります。
⚓その他のその他
やはり一流のVimmerともなるとラーメン画像で語るので格が違う https://t.co/T7raFbvSfy
— 鯖太郎🐟 (@develop_oni) June 28, 2018
⚓番外
⚓apollo: 自動運転プラットフォーム
- リポジトリ: ApolloAuto/apollo
同リポジトリより
つっつきボイス: 「Baiduがやってるオープンソースの自動運転だそうです」「とりあえず日本の公道は当面走れないナ😆」「法律が追いついてない😆」
⚓スラッシュvsバックスラッシュ
数字を見せ消しにするにはスラッシュ(/)を使うと思っていたが,日本の小学校ではバックスラッシュ(\)を使う指導をしているらしいことが,ここにも書いてあった→ https://t.co/sBybYbn8Qb UNIX派とDOS派の戦いか
— Haruhiko Okumura (@h_okumura) July 4, 2018
⚓ダークマターなしでも安定している銀河
定説がひっくり返る瞬間を目にすることができるかもしれないと思うとワクワクします。
参考: 「ダークマターを含まない銀河」の発見が、世界中の宇宙物理学者を驚かせた|WIRED.jp
今回は以上です。
おたより発掘
我がブログのリンクを貼ってもらってありがたや。 / 週刊Railsウォッチ(20180709)Rails Developers Meetup Day 3 Extreme今週末開催、RailsのSTI/キャッシュ/添付ファイル/Redis/PDF出力、ECMAScript 2018、プロフェッショナルIPv6ほか https://t.co/bib9u3v032
— 齋藤甚六 (@jimlock) July 10, 2018
バックナンバー(2018年度後半)
週刊Railsウォッチ(20180702)Ruby 2.2メンテ正式終了、Ransackがつらくなるとき、書籍『Domain-Driven Rails』、GitHubの高可用MySQLほか
- 20180622 Railsの需要未だ巨大、Unicode 11.0リリース、WebDriverがW3Cで勧告、Flutter.io、2封筒問題ほか
- 20180615 TTY gemとHTTPClient gemは優秀、Rubyの謎フリップフロップ、ちょいゆるRubyスタイルガイドほか
- 20180608 特集「RubyKaigi 2018後の祭り」、
Enumerable#index_with
は優秀、コントローラから@
を消し去るほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやRSSなど)です。