- Ruby / Rails関連
週刊Railsウォッチ(20190128)Rails 6のオートローダーがZeitwerkに置き換わる?Rails 6はRuby 2.5が必須、最近のSQLiteほか
こんにちは、hachi8833です。LinuCLPI-JapanのLinux標準教科書は無料のPDF版よりKindle版(200円)の方がKindleでは見やすいことに気づきました。ついでに英語版↓も制作されていたことを知りました。
つっつきボイス:「Linux標準教科書って何か英語版を元にしてるとかじゃなくって?🤔」「かなと思ったんですが、『JICAボランティアのご協力によりLinux標準教科書が英語化されました』とあるので日本語から訳したみたいです」「ま英語圏にはいい教科書がいっぱいあるし😆」「😆」「日本人が英語の書籍を読まなさすぎというか📚」
- 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
- 「つっつきボイス」はRailsウォッチ公開前ドラフトを社内有志でつっついたときの会話の再構成です👄
- 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください
⚓週刊Railsウォッチ「公開つっつき会#7」開催のお知らせ
次回の公開つっつき会は2/7(木)に開催いたします。皆さまのご参加をお待ちしております🙇。
⚓Rails: 先週の改修(Rails公式ニュースより)
先週のウォッチまでに公式の更新情報をだいぶ先回りしたので、コミットログからも少し見繕いました。
⚓Rails 6.0.0 beta1リリース
- 元記事: Rails 6.0.0 beta1: Action Mailbox, Action Text, Multiple DBs, Parallel Testing, Webpacker by default | Riding Rails
- 見やすいChangelog: rails/rails/releases/tag/v6.0.0.beta1
- 今後のスケジュール: Timeline for the release of Rails 6.0 | Riding Rails
- 2/1: Beta 2
- 3/1: RC1
- 4/1: RC2
- 4/30: 最終リリース
6.0.0の機能は、だいたいこれまでウォッチで追ってきたとおりですね。
- Action Mailbox
- Action Text
- マルチデータベースのサポート
- パラレルテストのサポート
- WebpackerがRailsのデフォルトJavaScripバンドラーに
- Zeitworkコードローダー(後述)
- Action Cableテストヘルパー(後述)
つっつきボイス:「おー、タイムラインが発表されてるし📅」「とりあえず餅の絵は描き終わったようだ😆」「4月末のRailsConf 2019にリリースって、もうすぐじゃん!: そんなに期間残ってないし、果たしてどのぐらずれ込むか😆」「もろもろ織り込み済みでしょうね☺️」
「そしてRails 6ではRuby 2.5以上が必須か〜: Rubyのバージョンアップが必要になることが増えるから大変そう😅」「気のせいか、以前のRailsよりRubyバージョンの要件の幅が狭くなっているような?🤔」「以前のRubyが結構切り捨てられてますね: まああまり古いRubyで動かすのも考えものだし」
「Rails 6のマルチデータベース、果たして今後落ち着いてくれるんだろうかとも思ったり🤔」「あー」「ま、いきなり使うことはなさそうだけど😆」
⚓ActionCable::Connection::TestCase
が完全にマージ
# actioncable/lib/action_cable/connection.rb#L3
module ActionCable
module Connection
extend ActiveSupport::Autoload
eager_autoload do
autoload :Authorization
autoload :Base
autoload :ClientSocket
autoload :Identification
autoload :InternalChannel
autoload :MessageBuffer
autoload :Stream
autoload :StreamEventLoop
autoload :Subscriptions
autoload :TaggedLoggerProxy
+ autoload :TestCase
autoload :WebSocket
end
end
end
# 同PRより: 利用例
class ConnectionTest < ActionCable::Connection::TestCase
def test_connected_with_signed_cookies_and_headers
cookies.signed["user_id"] = "456"
connect headers: { "X-API-TOKEN" => "abc" }
assert_equal "abc", connection.token
assert_equal "456", connection.current_user_id
end
def test_connected_when_no_signed_cookies_set
cookies["user_id"] = "456"
assert_reject_connection { connect }
end
def test_connection_rejected
assert_reject_connection { connect }
end
end
つっつきボイス:「Action Cableのテストがひととおり入ったのね☺️」「入ったヘルパーは思ったほど長くないですね」「長々と書く意味ないですし😆」「😆」
⚓親ディレクトリの監視を止めた
# activesupport/lib/active_support/evented_file_update_checker.rb#L125
def directories_to_watch
- dtw = (@files + @dirs.keys).map { |f| @ph.existing_parent(f) }
+ dtw = @files.map(&:dirname) + @dirs.keys
dtw.compact!
dtw.uniq!
normalized_gem_paths = Gem.path.map { |path| File.join path, "" }
dtw = dtw.reject do |path|
normalized_gem_paths.any? { |gem_path| path.to_s.start_with?(gem_path) }
end
@ph.filter_out_descendants(dtw)
end
つっつきボイス:「y-yagiさんの改修です」「指定のディレクトリが存在しないとEventedFileUpdateChecker
が親ディレクトリをチェックしてたのか: そういえば今日ちょうどチームでこのあたりが話題になってた🥺」「node_modules
まで対象に加わってたんですね」「確かに遅くなるやつ」「社内SlackのJavaScript板にこの間貼られてたこれ↓を思い出しちゃいました🦆」
npm install... pic.twitter.com/c0YCG9Rk9f
— Glen Arrowsmith garrows@infosec.exchange Mastodon (@garrows) November 21, 2018
⚓render_template
の引数が変更された
# actionview/lib/action_view/renderer/streaming_template_renderer.rb#L46
- def render_template(template, layout_name = nil, locals = {}) #:nodoc:
+ def render_template(view, template, layout_name = nil, locals = {}) #:nodoc:
return [super] unless layout_name && template.supports_streaming?
locals ||= {}
layout = layout_name && find_layout(layout_name, locals.keys, [formats.first])
Body.new do |buffer|
- delayed_render(buffer, template, layout, @view, locals)
+ delayed_render(buffer, template, layout, view, locals)
end
end
つっつきボイス:「tenderloveさんの改修です」「お?render_template
が変更されてるし...」「インスタンス変数で渡すのをやめたということでしょうか?」「逆ですね: インスタンス変数を渡すようになった」「あっと失礼しました💦」「従来はビューのコンテキストから@view
を取っていたのを、改修後は引数経由で取るようになったというということですね🧐」
# actionview/lib/action_view/renderer/template_renderer.rb#L5
module ActionView
class TemplateRenderer < AbstractRenderer #:nodoc:
def render(context, options)
+ @view = context
@details = extract_details(options)
template = determine_template(options)
prepend_formats(template.formats)
@lookup_context.rendered_format ||= (template.formats.first || formats.first)
- render_template(template, options[:layout], options[:locals])
+ render_template(context, template, options[:layout], options[:locals])
end
「この部分のAPIインターフェイスが変わるということだから、render_template
を生で書いてた人たちは影響を受けるかも?🤓」「あー🤭」「render_template
はRailsの内部向けのものだから、テンプレートを直にいじることは普通そんなにありませんけどね☺️: その代り、ビュー周りを扱うgemたちが影響を受ける可能性はありそう...TemplateRenderer
クラス↑も変わってるし🤔」「そっかー😳: そういえばこの記事↓ではAction Viewの基本設計はこれまでほとんど変わってなかったと解説されてました」「gemによってはデカい変更かも⚡️」
なお、上の記事を書いた@st0012さん(Gobyの作者)にもこの変更のことを知らせたところ、「100%納得いく変更🥰」とのことでした。
「ついでですが、ivarって何だろうと思ったらインスタンス変数の略記でした↓」「果たして一般に通じるのかと😆」「Railsだけなのかな😆: instance variableってやっぱ長いですよね」
参考: ruby - What is ivar in Rails controller? - Stack Overflow
⚓ActiveRecord::StatementCache::Substitute
のキャッシュのバグを修正
- PR: activerecord: Fix statement cache for strictly cast attributes by dylanahsmith · Pull Request #35029 · rails/rails
- デグレ: Use
unboundable?
rather thanboundable?
· rails/rails@5b6daff
# activerecord/lib/active_record/relation/query_attribute.rb#L
def unboundable?
if defined?(@_unboundable)
@_unboundable
else
- value_for_database
+ value_for_database unless value_before_type_cast.is_a?(StatementCache::Substitute)
@_unboundable = nil
end
rescue ::RangeError
@_unboundable = type.cast(value_before_type_cast) <=> 0
end
問題: ステートメントキャッシュ(
find
とかfind_by
とか)で使うステートメントをビルドするときに、ActiveRecord::StatementCache::Substitute
オブジェクトがその属性の型のcast
メソッドに渡される。キャスト呼び出しの戻り値はさして重要ではないが、このときに例外が出ないことを当てにしている。たとえば、ActiveRecord::StatementCache::Substitute
オブジェクトでActiveModel::Type::Float#cast_value
をto_f
を呼ぼうとすると例外が発生する。これはカスタム属性の型で問題になる可能性もある(PRとは別に含めたリグレッションテストを参照)。
解決: Active Modelの属性の型ではActiveRecord::StatementCache::Substitute
オブジェクトを扱うべきではないので、ActiveRecord::Relation::QueryAttribute#value_for_database
が北ときはsuper
を呼ばないようにした。nil?
メソッドでそうしたオブジェクトの型チェックが既にあったので、このクラスではそうしたクラスで既に特殊なキャストも行われていたことになる。
同PRより大意
つっつきボイス:「とりあえず普通にバグ: 使う人はビビるだろうな😨」「5b6daffのデグレだったとkamipoさんがフォローしてますね」
# activerecord/lib/active_record/relation/query_attribute.rb#L25
- def boundable?
- return @_boundable if defined?(@_boundable)
- nil?
- @_boundable = true
+ def infinite?
+ infinity?(value_before_type_cast) || infinity?(value_for_database)
rescue ::RangeError
- @_boundable = false
end
- def infinite?
- infinity?(value_before_type_cast) || boundable? && infinity?(value_for_database)
- def unboundable?
+ if defined?(@_unboundable)
+ @_unboundable
+ else
+ value_for_database
+ @_unboundable = nil
+ end
+ rescue ::RangeError
+ @_unboundable = type.cast(value_before_type_cast) <=> 0
end
「ついでに5b6daff↑を見ると、unless bind.boundable?
がif bind.unboundable?
に改められてる」「unless
をif
に変えて読みやすくしたんでしょうね」「infinite?
と同じロジックで扱えるようにunboundable?
にしたのね: まあ言い回しレベルかな」
⚓Rails
⚓新しい「Zeitwerkコードローダー」をRails 6で導入の動き(Rails公式ニュースより)
Zeitwerk: 時間(time)と仕事(work)に相当するドイツ語
Zeitwerkという高級時計メーカーがあるんだそうです。「時の工匠」的な?
つっつきボイス:「これが例の新しいオートローダー」「ツァイトヴェルクっていう響きがいかにもドイツ語🇩🇪」「Zで始まる英単語ってあんまりないし😆」「そういえばドイツ語だとZの利用頻度がめちゃめちゃ高くて、逆にYがほとんど使われないのでキーが入れ替わってますね↓」
参考: Mac OS と iOS の融合 | Mein dritter Blog -- ドイツ語のキーボードレイアウトが解説されてます
「Mediumの記事では、Zeitwerkは高効率かつスレッドセーフのRubyローダー、とある」「known gotchaとあるのは、Railsガイドに載ってる今のオートローダーのハマりポイント↓ですね」「たしかにRailsのオートローダーはハマるときはハマるからな〜😭」「いつぞやの名前空間地獄とかですね😱」
「で、Railsでは従来const_missing
が使われていていろいろ限度があったけど、ZeitwerkではKernel#autoload
を使ってるのか」「Mediumの記事には古いローダーは2004年から使われてきたと書いてますね」
Railsの旧来のローダーは
const_missing
を使っているため、ネストや、定数が見当たらない場合に使われるアルゴリズムをコールバックで取れないという根本的な限界がある。旧ローダー自身が持つ情報を使う分には間違いなく最適であり、2004年からずっとうまく動いていた。しかしRuby言語に新機能が加わったことで、さらに優れたアプローチが可能になった。
Zeitwerk gemはKernel#autoload
をベースにしており、ここ数年の私にとってはまさしく聖杯であった。
同記事の抜粋・大意
参考: const_missing
-- ActiveSupport::Deprecation::DeprecatedConstantAccessor
「Railsの既存のオートロードの仕組みってめっちゃ古いままだったのね👴」「Kernel#autoload
ってRubyのメソッドでしょうか?新しいのかな?」「ざっとググってみると、Kernel.#autoload
はRubyの1.8.6とかには入ってるらしい」「そんなに前から!😳」「最初のRailsができた頃には既にあったのかもしれないけど、これまでKernel.#autoload
が活用されてなかったってことなのかな?🤔: 何にしろオートロードの仕組みが今後変わるとしたらデカい🗻」
参考: module function Kernel.#autoload
(Ruby 2.6.0)
参考: requireとrequire_relativeとautoload - Qiita
「まーrequire
とか何も気にしないで使えるようになればいいことだし☺️」「まだRailsに入れる作業は進行中なのか...」「Zeitworkのリポジトリも見てみるか: ネステッドrootディレクトリにも対応とか、loader.setup
でセットアップできるとか↓」
# 同リポジトリより
loader.push_dir(...)
loader.push_dir(...)
loader.setup
「お、loader.reload
でリロードもできるし、eager loadingもプリローディングもできるし↓: いいじゃないですか〜❤️」
loader.reload
loader.eager_load
loader.preload("app/models/videogame.rb")
loader.preload("app/models/book.rb")
「inflection、つまりクラスとかの単数形複数形の活用も対応してますね↓」「どことなく想定外の動きをしそうな匂いがしそうではあるけど😅、カスタムinflectorもあるというのが何ともRailsらしい: つかRailsのオートローダーは活用形周りも扱ってるはずだから、確かにこういうこともできないと」
user -> User
users_controller -> UsersController
html_parser -> HtmlParser
# frozen_string_literal: true
class MyInflector < Zeitwerk::Inflector
def camelize(basename, _abspath)
case basename
when "api"
"API"
when "mysql_adapter"
"MySQLAdapter"
else
super
end
end
end
「名前空間になるクラスやモジュールはclass
やmodule
キーワードで定義しないといけない」「Trip::Geolocation
は名前空間を生書きしてるんでしたね」
# trip.rb
class Trip
include Geolocation
end
# trip/geolocation.rb
module Trip::Geolocation
...
end
「この書き方↓はできないと: この記法では普通でもオートロードはサポートしないし、納得」
# trip.rb
Trip = Class.new { ... } # NOT SUPPORTED
Trip = Struct.new { ... } # NOT SUPPORTED
「Zeitwerk自体Ruby 2.4.1以上が必要ということだから、もしかするとそれでRailsが2.5以上必須になったのかも?🤔」
「これがZeitwerkを作った動機かー↓」「今さらですけど、require
がグローバルということは、特定のファイルでだけrequire
したりできないんですね?」「ですです: Rubyではできません😅」
require
の副作用がグローバルであるがゆえに、自分が依存するファイルのコードを読み込むrequire
の呼び出しが完了したかどうかを安定して検証する方法が存在せず、実際一部が呼び出されてないなんてことが簡単に発生する。そしてこれのせいで、読み込み順に依存するバグが引き起こされる。Zeitwerkは、自分のコードでrequire
のことなんか忘れて普通に書けばいいようにする方法を提供する。
その一方、Railsのオートロードはconst_missing
ベースであり、実際に使われた解決アルゴリズムやネストといった基本的な情報を欠いている。このせいで、RailsのオートロードはRubyのセマンティクスと一致することができず、さまざまなハマりポイントを生み出している。このプロジェクトは元々、改善されたオートロードをRails 6にもたらそうと思って始めたものである。
同リポジトリより大意
「Zeitwerkをざっと眺めてみて、必要そうなものはひととおり揃ってそうな感じ」「何だか期待できそうですね😍」「とにかくRailsの既存のオートローダーってたまにものすごいハマり方するから😭」「オートローダー地獄、何とかしないといかんですね...🥺」「あれは知ってても脱出が難しい、ホント😇」
⚓開発者目線から見たタイムゾーン
つっつきボイス:「データベースとRailsとJavaScriptについてタイムゾーンを説明してるようです」「それぞれのタイムゾーンの設定が噛み合わないと大変なことになるみたいな話でしょうね🤕: 実によくある話」
「そういえば今のRailsは全部UTCに揃えるんだったけか?: configでタイムゾーンを変更しても保存はUTCになってた気がする」「取り出して使うときにローカルのタイムゾーンにするということなのかなと想像しました」「Railsで保存したタイムゾーンはRubyの世界では参照可能になるんですが、後で変更が効かない部分もあるんで厄介なんですよ」「えー😱」「システムタイムゾーンが違うとつらいことが起きたりします😇: JSも然り」
「LinuxのサーバーってUTCで運用するのが普通だったりするんでしょうか?」「んなことはない😆: システムタイムゾーンがJSTとか普通にあります」「そっかー」「だからややこしくなってしまうんですが、UTCのタイムスタンプが取れないシステムはさすがにないので、その点はマシ」
⚓Ransackか生SQLか
昨日はこのスライドでいうところの「ちょっと凝った検索条件」をこの方式で作った。やっぱりなかなか便利!Ransackもいいけど、「この条件、Ransackだったらどう書くの?」みたいなことに時間を使うなら、ガリガリRubyのコードとSQLを書いた方が柔軟で速い💨
Rails❤️SQL https://t.co/rBfeMNCQHL— Junichi Ito (伊藤淳一) (@jnchito) January 22, 2019
つっつきボイス:「jnchitoさんのスライドで、どこまでRansackでやってどこから生SQLにするかみたいな話をしてました」「これは自分もよく同じ話をしてますね: スライドでも『9割はRansackでいけるけど』とあるようにRansackで頑張りすぎるぐらいなら生SQLにする方がいいし」「いつぞやのRansackでOR使うと死ねるという話もありましたね」「複雑になるなら生SQLの方が全然いいし☺️: スライドでやってるみたいにQuery ObjectとかFormクラスとか使ったり、conditions自分で書いたりとかして」
「お、『SQLはERBに書く』方針か、うーんなるほどー😎」「え、それってあり?と思ったら『Railsのビューとは関係ない素のERB』でしたか😅」「言われてみれば、最終的に完全なSQLができるならERBのような何らかのテンプレート言語を使って書くというのは悪くないですね: いろいろ融通が効くし、自分もちょうど昨日muninのコンフィグをERBで書いたりしてたし」「へー!」
- サイト: Munin
「いいスライド👍」「🥰」
⚓2019年の今、RailsをWindows 10で動かす(Hacklinesより)
つっつきボイス:「Windows 10でRails、割と動きますけどね」「昔は大変だったみたいですね」「むしろDockerとかの方が言うこと聞いてくれない😆: で、この記事はというと...なーんだ、WSLでやってるのか」「ほんとだ」「WindowsにネイティブにインストールするんじゃなくてWSL使うんだったら、たいてい動くんじゃないかなー普通に: 遅いとかあるかもしれないけど😆」
⚓ActiveModelとActiveRecordの関係と、ActiveModel::Attributes
熱烈なファンのいるActiveModel::Attributes
はもっと前からあってよさそうなのに、なぜこんなに最近になってできたのかが気になったので、Webチームの名メンターであるkazzさんに教わったことを中心にメモしてみました。
- ActiveRecordとActiveModelには継承関係はない(共通なヘルパーが多いというkazzさんの印象)
- 調べたらActiveModelはクラスではなくモジュール
- ActiveModelはバリデーションが使え、永続化についての責務は持たない
- ActiveModelができたのはRails 3からだった
- 5.2から入った
ActiveModel::Attributes
はkazzさんもラブラブだそうです😍
参考: ActiveModel::Attributes が最高すぎるんだよな。 - Qiita
ActiveModel::Attributes
は前から欲しがられていた↓- 元記事: Introduction to ActiveRecord and ActiveModel Attributes API - Karol Galanciak - Ruby on Rails and Ember.js consultant
- リポジトリ: Azdaroth/active_model_attributes -- 待ちきれなくて自分で作っちゃった人
- リポジトリ: alpaca-tc/active_model_attributes_backport -- 待ちきれなくて自分で作ったら上と名前がかぶったのでリネームした人
- 2016年にPRがあがってたのにcloseされてた
- 2017年11月にActiveRecordからの引っ越しという形でマージされた
つっつきボイス:「ちょっとメモするつもりが雑然としてしまったのでこの項スキップでもいいです💦」「あーそうそう、ActiveRecordとActiveModelって、インターフェイスはかなり似通っているのに直接の関係がないというのがややこしいんですよ🧐」「やっぱり〜」「そしてActiveModelは永続化のインターフェイスも少し持っているんですが、永続化についての責務は持たないというか永続化の実装がない🧐」「なるほど!」「スタブというか'口'だけを持ってるみたいな感じですね👄」
「そうそう、ActiveModelはRails 3からだった: そしてActiveModel::Attributes
が登場する前にもactive_attrとか、Dry-rbの前身だったvirtusみたいな似た感じのgemがあって、自分も使ってましたね😋」
- リポジトリ: cgriego/active_attr
- リポジトリ: solnic/virtus
「そして今はActiveModel::Attributes
があるからこれでいいんじゃねって思うし😘: ActiveRecordは重いけど、ActiveModelは使いたいなんていうケースはあるかも」「ActiveModel::Attributes
みたいなのってRailsでも何度かプルリクされてたんですね」「active_attrもそうですけど、みんな同じようなものを作ってたし😆」
「実はActiveModel::Attributes
って、アトリビュートを生やすだけなら実装はそんなに難しくなくて、自分で一度作ってみるととってもいい勉強になります🍖」「おー😍」「誰もが同じことをやってるぐらいだし、RubyでDSLをどう実装するかという練習にはぴったりだし、かつ実用的: ActiveModel::Dirty
みたいなことをするんでなければ大丈夫😉」「いいですね!😋」
追いかけボイス「ActiveModel::Attributes
の登場は自分は遅いとは思わなかったなー: むしろ早い方だと思うし」
⚓Railsで巨大データを扱ってみた
つっつきボイス:「ぱっと見activerecord_importあたりを使うとか、ActiveRecordを通さないでやるとかそういう話かなと想像」
- リポジトリ: zdennis/activerecord-import
「ほほー、IO
でforeach
のLazy Enumでこういう書き方↓できるんだ: だしかにlazy
を通さないとサイズによってはメモリが溢れて死ぬだろうし😇」「CSVのエクスポートでやる方法も紹介されてますね」
# 同記事より
imported_products_old_ids = Work.pluck(:old_version_id).uniq
IO
.foreach('tmp/export_products.txt')
.lazy
.map { |raw_line| JSON.parse(raw_line) }
.select { |product_hash| imported_products_old_ids.include?(product_hash.fetch('id')) }
.each do |product_hash|
# ...
end
「YAML.storeにPStoreか↓」「どっちもRubyのライブラリなんですね: PStoreの方が速いっぽい」
# 同記事より
# export
require 'yaml/store'
def product_hash(product)
hash = { id: product.id, id: product.title }
hash.merge! product.media.map do |medium|
{ ... } #media data
end
hash.merge! product.comments.map do |comment|
{ ... } #comment data
end
hash
end
store = YAML::Store.new(Rails.root.join('tmp/products.yaml'))
store.transaction do
store[:products] = []
end
Product.find_each do |product|
store.transaction do
store[:products] << product_hash(product)
end
end
# import
store = YAML::Store.new(Rails.root.join('tmp/products.yaml'))
store.transaction(true) do
store[:products].each do |product_hash|
# ...
end
end
「おー、PStore.new
してPStoreの形式でダンプしてロードできるっぽい: マーシャリング的なことを高速にやれるこういう仕組みがあったとは知らなかったなー☺️」「おー」「たしかにYAMLとかに比べれば変換が発生しない分速そう❤️」
require 'pstore'
db = PStore.new("/tmp/foo")
db.transaction do
p db.roots # => []
ary = db["root"] = [1,2,3,4]
ary[0] = [1,1.5]
end
db.transaction do
p db["root"] # => [[1, 1.5], 2, 3, 4]
end
「元記事はSQLで頑張る方の話かと思ったら、どちらかというとRubyの世界で頑張る話か: こういうの社内に好きな人がいそう🥰」
⚓ReactとRailsを統合する方法(Hacklinesより)
つっつきボイス:「APIサーバーで頑張るとかかな?」「やり方が3つ紹介されてました」
「1つはWebpackerかやっぱりー☺️」
「2つ目はreact_on_railsと」「これは前からあるヤツですよね?」「ですね: まあこういうのは今後どんなふうに変わるかわかりませんけどっ😆」「😆」「生で書く方がいいような気はするけどな〜」
「3つ目はやはりAPIサーバーとReactフロントですね」
- リポジトリ: shakacode/react_on_rails
⚓Ruby
⚓Pythonで欲しかったRubyの機能(RubyFlowより)
# 同記事より: Python
engineers = [e for e in employees if e.department == 'engineering'] # filter
engineer_salaries = [e.salary for e in engineers] # map
sum(engineer_salaries) # reduce
# 同記事より: Ruby
employees
.select { |e| e.department == 'engineering' } # filter
.collect { |e| e.salary } # map
.sum # reduce
つっつきボイス:「いろいろわかりみはある: Pythonほとんど使ってないけど😆」「Pythonってprivateメソッドがないんですね: __
付けて紳士協定的にこれはprivateだよみたいな感じでやってるみたい」「へー、privateがないとは😳」
「Pythonは多重継承でやることが多い一方、Rubyはmixinでやれるともありますね」「Rubyだと式展開を引用符の中に置ける↓とか」「まあそういう違いはもうしょうがないっすね☺️」「記事でも違いは微妙だけどと言ってました😌」
# 同記事より: Python
"Hello, {}! Welcome to {}.".format(employee_name, company_name)
# 同記事より: Ruby
"Hello, #{employee_name}! Welcome to #{company_name}."
Pythonの「モジュール」は個人的にちょっと好きです😘。名前空間が他と別になっているあたりとか。
参考: 6. モジュール (module) — Python 3.6.5 ドキュメント
⚓自分が作ったgemをバズらせる方法(RubyFlowより)
つっつきボイス:「技術畑のマーケティング話的な」「READMEとかのドキュメントをちゃんと書いて、ドメイン取ってWebサイトも立てて、コミュニティを盛り上げる方向に頑張ってと、いたって王道な感じ☺️」「もうこういうのが普通なんでしょうね」
「今のオープンソースはだいたいこういう感じでやってますね: 最初に立ち上げるものをキレイに作っておかないとものが良くても見向きもされなかったりするし、逆に見た目優先で立ち上げてもそこに人が集まってきて後から実体が伴ってくるなんてこともあるし☺️」「☺️」
⚓Rubyのメソッドブロックを取り出してみた(Hacklinesより)
短い記事なので結果を載せます。
# 同記事より
require_relative 'block_source'
def foo
pp block_source
end
foo { 'hello' } #=> " { 'hello' }"
foo { |i| i * 3 } #=> " { |i| i * 3 }"
foo #=> nil
つっつきボイス:「お〜〜ブロックのソースを抜き出すなんて、そんなことができるとは!」「Ruby標準の機能にはなさそうですね」「ないんじゃないかな🤓: 今動いているコードの行を引っ張ってくる機能は最近のRubyにあったと思いますが」「あーそうでしたっけ」「今動いているコードがソースのファイルの何行目なのかを知るみたいな機能をRubyKaigiで見た気がする」「デバッグで便利そうですね😋」
探してみたのですがうまく見つけられませんでした🙇。
参考: instance method IO#lineno
(Ruby 2.6.0)
参考: Ruby で今読み込んでいるファイルの行数を取得する - Qiita
参考: 変数と定数 (Ruby 2.6.0) -- 疑似変数__LINE__
で取れるようです。
「お、caller_locations
やlineno
↓を使ってソースを取り出してるっぽい: Railsコンソールとかでこういうの使いたくなることがあるかも😋」
# 元記事より
module Kernel
# RUBY_VERSION >= '2.6.0'
def block_source
@file_specs ||= {}
bl = caller_locations.last
source = @file_specs.dig(bl.path, :source) || File.readlines(bl.path)
@file_specs[bl.path] ||= { source: source, ast: RubyVM::AbstractSyntaxTree.parse(source.join) }
node = find_node(
ast: @file_specs.dig(bl.path, :ast),
type: :ITER,
lineno: bl.lineno
)
extract_source(node: node.children[1], source: source) if node
end
end
参考: module function Kernel.#caller_locations
(Ruby 2.6.0)
「あれ?この記事書いた人のアバター見たことあると思ったら安川さんのところの人だ」「沖縄在住ですね☺️」
⚓Rubyist Magazine 0059号がリリース
るびま応援いたします❤️。
今度のるびまは凄いですよ。最近発刊された書籍紹介やmrubyc、ovtoの技術技術、各地域RubyKaigiのレポートやRailsGirlsのレポート記事など盛りだくさんです。今週末リリース予定です。お楽しみに。
— みよひで画伯 (@miyohide) January 22, 2019
その後リリースされました🎊🎉。Ovto面白そう!
Rubyist Magazine 0059号をリリースしました。https://t.co/o82zKq38gq
今号はフロントエンドフレームワークOvtoやmruby/cの紹介記事、書籍紹介2本、地域Ruby会議レポート3本、RailsGirlsレポート2本とかなり盛りだくさんです。それぞれ素晴らしい内容です。ぜひじっくりとお楽しみください。— みよひで画伯 (@miyohide) January 26, 2019
⚓その他Ruby
Link: Sansan CTO藤倉氏とまつもとゆきひろ氏が語る「知の共有」 オープンソース時代のものづくりのゆくえ - ログミーTech: https://t.co/slK1IrdkJu
— Yukihiro Matz (@yukihiro_matz) January 23, 2019
つっつきボイス:「伽藍とバザール、懐かし!」「90年代でしたよね」「今や古典📚」「MINIXのタネンバウムがLinuxを巡ってリーヌスとやりあった話とか思い出しちゃいました」
参考: 伽藍とバザール - Wikipedia
参考: アンドリュー・タネンバウム - Wikipedia
参考: MINIX - Wikipedia
⚓Ruby trunkより
⚓卜部さんが手がけたRuby高速化
trunkではありませんが。
つっつきボイス:「今朝電車の中で読んでて高速化の追い込みがスゲーと思ったので: エン・ジャパンのエンジニアHubはいい記事が多いなと改めて感じました😍」「あそこはかなり頑張っていい記事書いてますね👍」「シンタックスハイライトがスマホで読みにくかったぐらいでした😅」「まあそのぐらいは😆: コードをスマホで読むのもどうかと😆」「ですね😆」
⚓クラウド/コンテナ/インフラ/Linux/Serverless
⚓Podman: Docker互換の新コンテナエンジン(Publickeyより)
- 元記事: Red Hatが開発するDocker互換の新コンテナエンジン「Podman」、バージョン1.0に到達 - Publickey
- サイト: Podman | podman.io
- リポジトリ: containers/libpod
とりあえずかわいい❤️。
つっつきボイス:「おーこういうの出てましたね: Red Hatは元々Dockerに相当つぎ込んでるし、わかる気はする」「おー」「PodmanってDockerエンジンと差し替えられるのかな?」「デーモンがないのと、KubernetesのPodもサポートしてるのが特徴みたいですね」「だからPodmanなのかな?知らんけど😆」
「OCI↓に対応してるというのも筋がよさそう: 後はみんながどれだけ使ってくれるかですが☺️」「Dockerに追いつけ追い越せの気合いがPodmanのマスコットの可愛らしさに表れてる気がしました🐹」「Dockerと完全互換ならワンチャンあるかもしれないけど😆」
参考: Home - Open Containers Initiative
「PodmanのRootlessコンテナもかなりありがたい🙏」「ということはDockerはそうじゃないんですね?」「です: DockerはDockerデーモンが基本的にはroot権限で動くので」「権限強すぎな感じですね...」「Dockerの中のファイルのUIDはDockerホスト側のUIDと同じもので作ることを強いられるので、root権限で動かすか権限昇格するかしないとファイルを作れなかったりするし😅」「なるほど!」「Dockerはそこが不便なんですよね😢: 特に-v
とか付けるとDockerホストを汚染する可能性があって危険⚠」「ほあっ😨」「だからKubernetesとかの方が分離しやすかったりしますね」
⚓SQL
⚓AWS DocumentDBはほんとはPostgreSQLじゃね?(DB Weeklyより)
つっつきボイス:「AWS DocumentDBが実はPostgreSQLでできてるんじゃないかと睨んでるそうです」「内部的に同じものを使ってる可能性はまああるかもですが、ずばりそのものを使ってるんじゃないかという勢いで書かれてるっぽい☺️」「っぽいですね」
「でもDocumentDBが自動でAvailability Zoneにコピーを6つ作成するなんてのは、データベースというよりはAuroraファイルシステムの特徴なので、その上にDocumentDBやPostgreSQLが乗ってるならそこが同じだとしても不思議じゃない」「おー」「ま、こういうものがフルスクラッチで書かれているかどうかとか気にしないけどっ😆」
⚓最近のSQLiteは何だかスゴイ(DB Weeklyより)
つっつきボイス:「お、SQLiteにいつの間にかwindow関数が入ってるし」「マジっすか!?😳」「FILTER構文に、それからON CONFLICTって何だろう?」「衝突したらUPDATEできるみたいなヤツかな?UPSERTみたいな」「複数プロセスが開いているときの挙動とか?知らんけど」
-- 同記事より
INSERT INTO target
SELECT *
FROM source
ON CONFLICT (id)
DO UPDATE SET val = excluded.val
「実はSQLiteってかなり頑張ってますね: 新しいSQLiteは相当ちゃんとしていて、結構いい❤️」「おぉ〜」「実際使っててホント速いと思いました(参照のみだけど)」 「規模が小さければもうSQLiteでいいんじゃねというぐらいの勢い」「そうそう🥰」
「SQLiteは特にクライアントで動くアプリで使うのに最適: 何てったって速いし🚅」「ですね〜」「サーバーだとどうしても同時アクセスが多数発生するから、それをちゃんと捌けるRDBMSが必要になるけど、クライアントアプリなら自分しか使ってないからそんな心配もいらないし🤓」「Webアプリでも、リードオンリーのマスターデータ専用に使う手もあるかも(やったことないけど😆)」
- サイト: SQLite Home Page
⚓その他SQL
- リポジトリ: agershun/alasql -- ブラウザで使うJS向けSQLデータベース(Ruby Weeklyより)
- サイト: Home Page
つっつきボイス:「ほーNodeで動くSQLデータベース」「SQLiteを使いたくても使えないような環境で使うとか?もしかするとGAS(Google Apps Script)でも動いたりして」「それありそう」「頑張るところが何か違う気もするけどっ😆」「😆」
参考: Apps Script | Google Developers
⚓JavaScript
⚓私はいかにしてJSモジュールのデフォルトexport
をやめたか(JavaScript Weeklyより)
つっつきボイス:「export default class LinkedList {}
なんて書き方できるんだー: JSそこまで詳しくない〜😅」「exportをデフォルトでやって何かつらい目にあったのかしら?」「exports.LinkedList = class LinkedList {};
みたいな名前付きexportもできるのか: 昔見た気もするけど」
「あーimport
でこうやってas
名前変えられると↓」「ないと困りそう」「import
する側で何とかしてくれみたいな☺️」「こういう文化の言語ってありますよね: Pythonとか」「Go言語もそうですね」「みんな同じような名前で作っちゃうという想定の世界」
// 同記事より
import { LinkedList as MyList } from "./list.js";
⚓JSでタイムゾーンを扱う(JavaScript Weeklyより)
つっつきボイス:「GMTって最近この業界ではめっきり見かけないな〜」「そういや見ませんね」「グリニッジ標準時でしたっけ: イギリスが覇権を失った感🇬🇧」「そしてサマータイムの話題も😆」
「そして恐怖のDate
オブジェクト↓」「Local Storageにマーシャリングして保存した後で元が変わったりしたときにつらくなった覚えが: 変わってもいいように書いておけばいいんだけど、それを忘れて死んだりとか😇」「新しいタイムゾーンを読み込むとローカルで持っているデータがぶっ壊れたり🧨」
// 同記事より
const d1 = new Date(1489199400000);
d1.toString(); // Sat Mar 11 2017 11:30:00 GMT+0900 (KST)
「Momentsって何だろうと思ったらライブラリでしたか」「Moments.jsといえば日時関連処理で結構メジャーですね🧐」「JSの日付時刻処理が非力すぎるからこういうMoments.jsとか昔流行ってた」
- サイト: Moment.js | Home
↑サイトでは時計が実際に動いています。
⚓TypeScriptなしで型厳密にやる方法(JavaScript Weeklyより)
割と短い記事です。
つっつきボイス:「TypeScriptなんかなくたって型厳密にやれるんだぜみたいな😆」「ランタイムでannotationを解決しながら実行するとかそんな雰囲気」「まあでもTypeScriptは中で実際にこういうことをしてるわけだし、手作りできるっちゃできるし」
⚓wpk: Webpackの非公式CLI(JavaScript Weeklyより)
- リポジトリ: wpk-cli/wpk
つっつきボイス:「アンオフィシャルなWebpack CLIとな」「オフィシャルのCLIってつらいんでしょうかね: いっそBundlerと一緒のコマンド体系だったらいいのに」「きっと逆も真なりで、Webpackを使ってるJSエンジニアもRubyに対してそう思ってるかも😆」「😆」「何にしろ公式に入ってくれないとどう変わるかわかんないし」
⚓sockette: 薄いWebSocketラッパー(JavaScript Weeklyより)
- リポジトリ: lukeed/sockette
// 同リポジトリより
const Sockette = require('sockette');
const ws = new Sockette('ws://localhost:3000', {
timeout: 5e3,
maxAttempts: 10,
onopen: e => console.log('Connected!', e),
onmessage: e => console.log('Received:', e),
onreconnect: e => console.log('Reconnecting...', e),
onmaximum: e => console.log('Stop Attempting!', e),
onclose: e => console.log('Closed!', e),
onerror: e => console.log('Error:', e)
});
ws.send('Hello, world!');
ws.json({type: 'ping'});
ws.close(); // graceful shutdown
// Reconnect 10s later
setTimeout(ws.reconnect, 10e3);
つっつきボイス:「ロゴと名前はsocketとsocksの掛詞っぽいですね🧦」「なるほどカワイイ🐼」「これはWebSocketに限らずできるのかな?WebSocketが対象っぽい」「サイズが348バイト!」「えれえ小さい🐁!」「ソースも50行ちょい!」
⚓CSS/HTML/フロントエンド/テスト
⚓手動テストで必ずやってる4つのこと
つっつきボイス:「1つ目はブラウザでアプリをキーボード操作してみること」「アコーディオンがちゃんと開くかとか」「こんなふうに↓マウスオーバーで選択するタブがキーボードでも選択できるかどうかとか: 確かにこういうのは実際にやらないとわからないし: スクリーンリーダー使ってる人はそれできないと困るし」「ちょうど2番目がスクリーンリーダーの話ですね」「スクリーンリーダーのチェックも必要☺️」
「4番目のWave Toolって知りませんでした」「おー、これはいわゆるWeb評価用ツールですね: こんな感じ↓で評価してくれるのか」
「Web評価ツールといえば、日本の官公庁が出してるアクセシビリティチェッカーがあるんですよ: 何て名前だったかな...miChekcer!↓」「へーこんなのがあったとは」「このmiChekcerというツール、恐ろしく古いんですが今もすごく使われているという」「官公庁向けだと使わないわけにいかないんでしょうね😢」「でないと納品できなかったり」「音声読み上げとか、そういうチェックも入ってるのね」「32ビットとか書いてますけど😆」「Javaのサポートが変わったお知らせも書いてある: ああ例のアレ」「ActiveX...だと...?🥶」「そもそもIEが対象だし」「ひえぇ〜」「こういうツールを公のところが出す意義は間違いなくあるけど、その後も更新してくれないとね😅」
参考: ActiveX - Wikipedia
参考: 行政サイトを作る時に気をつけておいた方がいい事 - Qiita
⚓言語
⚓ミューテーション解析とは
つっつきボイス:「ひところ卜部さんがRuby TrunkすごくエッジなバグをRubyで次々にアップしてたことがあったんですが、もしかしてこういうミューテーション解析みたいに、ソースをランダムに機械的にちょっと書き換えてバグをあぶり出すとかしていたのかなと思って」「ああそういえばRubyKaigiでそういうのを自動で回してるみたいなことを言ってたかも🤔」「ミューテーション解析っていう言葉があるというのを今頃知りました😅」「これはまさにソフトウェアテストのコアな手法のひとつ」「パーサーの仕様を把握したら後は総当たりで回して、落ちたところを掘っていくみたいな」
⚓PPL 2019: 第21回プログラミングおよびプログラミング言語ワークショップ
"PPL 2019: 第21回プログラミングおよびプログラミング言語ワークショップ" https://t.co/Ai4ViCdn99 明日が「カテゴリ2 (国外既発表論文)」および「カテゴリ4 (サーベイ・チュートリアル発表)」の締め切りです。どうぞよろしくお願いします。
— _ko1 (@_ko1) January 24, 2019
つっつきボイス:「東北地方(岩手県花巻市)で開催されるそうです」「JSSSTということは日本ソフトウェア科学会↓なので普通に学会ですね🧐」
- サイト: 日本ソフトウェア科学会
「ちなみに、日本には日本ソフトウェア科学会の他に情報処理学会と電子情報通信学会という3つの大きな学会があります」「おー知らんかった😳」
- サイト: 情報処理学会
- サイト: 電子情報通信学会
「下の2つは歴史が長くて、情報処理学会は数学寄りでコンピュータサイエンスをガチでやってる」「なるほど!」「電子情報通信学会は名前からも想像できるように通信とか工学系も扱っていて、ネットワークのような下のレイヤにも強い」「へぇ〜」
「日本ソフトウェア科学会は比較的新しくて、いわゆる学術論文になりづらいようなテーマ(何かソフトウェアを構築したとか)でも提出できるところが他の2つと違う特徴ですね」「あーそういう違いですか!」「論文にはなりにくいけど意義のある研究というのはやはりあって、日本ソフトウェア科学会はそういうのも扱う」
「一方他の2つはソフトを書いたというだけじゃ論文や研究として認められないんですね」「下の2つはガチ勢という感じですか」「書きましただけじゃダメと」「学術の世界は、極端に言えば理論があればコードは実際には書かなくてもよかったりするので」「わかるわかる☺️」「せいぜいシミュレーターとか」
「たとえばRubyを作りましただけでは、それは研究ではなくて開発だろとみなされる: 新しいアルゴリズムの研究とか、論文として新規性などを満たさないといけなかったりしますね🧐」「そうすると学生がたとえばRubyで何か凄いものを作ってもそのままではドクターが取れないことになってしまう😆」
「日本ソフトウェア科学会はそういうのも論文として評価することで門戸を開いているので、オープンソース方面と親和性が高いですね☺️」「学術の世界、知らないことだらけでした😅」
⚓COBOLが去りゆく
代わりにPythonが加わるそうです。
つっつきボイス:「CASLを試験に出すぐらいならRuby入れればいいのに🤣」「🤣」「CASL、日本でしか通用しなくて実物もないという🤣」「ベンダに依存しないアセンブラの問題を出すための苦肉の策だったのかしら🤔」「知人はES2015を入れればいいのにと言ってました😆」
参考: CASL - Wikipedia
「Rubyは言語仕様の動きが激しいから試験にしづらいとか?」「でもJIS規格でしたよね?」「ISOも取ってた気が」「お〜どっちもやってる↓」「更新もされてるんだし、Rubyにしとけばいいのに」「まさか試験に出るPythonってPython 2じゃないよね?🤣」「🤣」
参考: JIS X 3017 「プログラム言語Ruby」が改正されました:IPA 独立行政法人 情報処理推進機構
参考: ISO/IEC 30170:2012 - Information technology -- Programming languages -- Ruby
後日
情報処理技術者試験、Rubyを入れるように動いてくれてた中の人がいたとは聞いていたが、結局Pythonが採用されるあたり、敗北感(いつものこと)
— Yukihiro Matz (@yukihiro_matz) January 26, 2019
⚓その他言語
⚓その他
⚓「HRTの原則」とは
「このメソッドの制御フローは完全に間違ってますよ。みんなが使ってる標準的なxyzzyコードパターンを使うべきですよ」
Team Geek p.21
上のメッセージはもっとえげつない感じで訳す方が伝わったのかなと思いました。
なおHRTの原則を見かけたのは永和さんの記事でした。
参考: 知識差−スキル差を埋めるためのペアプロ+αのコツ(2) – 時を超えたプログラミングの道
⚓whatthecommit.com: コミットメッセージをひたすらランダムに表示するサイト
以下で見かけました。
- リポジトリ: azu/awesome-commit-english
つっつきボイス:「リロードするたびに変わりますね」「いわゆる面白コミットメッセージ😆」「どこからクロールしてきたんだろうか😆」「そんなにたくさんはないっぽいですが☺️」
⚓ビデオ会議のノイズキャンセルアプリ
- 元記事: 環境音などのノイズを軽減できる Krisp を試してみた - YassLab 株式会社
- サイト: Mute Background Noise | Noise Cancelling Software | krisp
Great news! @krispHQ won the 1st place as the Audio & Voice Product of the Year in the @ProductHunt Golden Kitty Awards!! 🥇🏆🎉🎉🎉 https://t.co/q2CHo6jG8I
Thanks to everyone for your participation and support!❤️😻 pic.twitter.com/ZNHDOS3udA
— Krisp (@krispHQ) January 18, 2019
つっつきボイス:「Yasslabの安川さんの記事を見つけたので」「ノイズをキャンセルするアプリってどういう仕組なんだろ?🤔」「なるほど、このパネルからしてスピーカーやマイクのドライバとして選択すると機能するのか↓🎤」「ビデオ会議を頻繁に使うなら便利かも😋」
⚓番外
⚓宅配ロボット
参考: Amazonがついに宅配ロボットを開発! 名前は「Amazon Scout」 | ロボスタ
つっつきボイス:「名前はスカウト!」「階段はクリアできないことが確定😆」「道路事情からして日本は蚊帳の外🇯🇵」「弓矢やボウガンを持った一団にヒャッハー🏹される事案がちょっと心配😆」
「でも米国だとこういう無人配達はある意味切実に求められてたりしますよね: 地域によっては他人の敷地にうっかり入ると撃たれることがたまにあったりするし🔫」「そういえば随分昔にそんな事件あった!😢」「宅配便や郵便配達も油断ならなかったりしそう😢」
今回は以上です。
おたより発掘
Zeitwork良さそう / 週刊Railsウォッチ(20190128)Rails 6のオートローダーがZeitwerkに置き換わる?Rails 6はRuby 2.5が必須、最近のSQLiteほか https://t.co/WMYaQERbPF
— sheepland (@sheepland) January 29, 2019
お、ちょっと前の僕のツイートが引用されてた。どうもありがとうございますー❤️
週刊Railsウォッチ(20190128)Rails 6のオートローダーがZeitwerkに置き換わる?Rails 6はRuby 2.5が必須、最近のSQLiteほか https://t.co/QqKYY804Jb— Junichi Ito (伊藤淳一) (@jnchito) January 28, 2019
こちらこそありがとうございます🙇。
バックナンバー(2019年度第1四半期)
週刊Railsウォッチ(20190121)Rails 6.0.0 beta1リリース、Railsは2019年も「あり」か、Jetsでサーバーレス、ES2018の新機能、RSpecの心ほか
- 20190115 Rubyの<=でクラス同士を比較、Rubyの記号の読み方いろいろ、Ruby C API解説サイトほか
- 20190107 Railsのパフォーマンス改善Tips集、Rubyの
&:シンボル
ほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやRSSなど)です。