- 開発
週刊Railsウォッチ(20190513-1/2前編)6.0の地味に嬉しい機能、ActiveModelエラーの扱いが変更、Railsのリクエスト/レスポンスをビジュアル表示ほか
こんにちは、hachi8833です。
- 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
- 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
- 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください
5/9の令和初の公開つっつきはおかげさまで盛況となりました。お集まりいただいた皆さまありがとうございます!🙇
⚓Rails: 先週の改修(Rails公式ニュースより)
今回はGW前の公式ニュースから見繕いました。最近のコミットリストを見るとドキュメントの更新が増えていて、リリースが遠くないことを感じさせます。
⚓モデルのエラーをオブジェクト化、APIを変更
単一のエラーをカプセル化する
ActiveModel::Error
を追加。メッセージ生成や詳細へのアクセスを扱う。これをErrors
クラスで使い、ハッシュベースのインターフェイスからError
オブジェクトの配列に変更する。where
などのより柔軟なクエリメソッド群を追加。
PRより大意
# activemodel/lib/active_model/error.rb#L3
module ActiveModel
+ # == Active \Model \Error
+ #
+ # Represents one single error
+ class Error
+ CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank, :strict]
+ MESSAGE_OPTIONS = [:message]
+
+ def initialize(base, attribute, type = :invalid, **options)
+ @base = base
+ @attribute = attribute
+ @raw_type = type
+ @type = type || :invalid
+ @options = options
+ end
...
+ attr_reader :base, :attribute, :type, :raw_type, :options
+
+ def message
+ case raw_type
+ when Symbol
+ base.errors.generate_message(attribute, raw_type, options.except(*CALLBACKS_OPTIONS))
+ else
+ raw_type
+ end
+ end
...
+ protected
+
+ def attributes_for_hash
+ [@base, @attribute, @raw_type, @options]
+ end
+ end
+end
つっつきボイス:「おー、ActiveModel::Error
クラスを作ったと」「変更追加の行数がかなり多いからがっつり再実装してるっぽい」「Active Modelのエラーをwhere
とかで絞り込めるようになったように見える」「ほんとだ、プルリクの解説にも書いてありますね↓」「これは確かにありがたい!🙏」
model.errors.where(:name, :foo, bar: 3).first
「今まではできなかったんですね」「従来のハッシュだと気合いでeach
するしかなかったし😆: 今までのだと、Active Modelにバリデーションエラーを追加するときにキーがかぶると困ったんですよ😭」「arrayに変わったことで、そのあたりをあまり気にせずにやれるようになった😋」
「これかなりよさそうなのでPRの👍押しとこうっと: でも既存のgemへの影響とかそこそこありそうな気も🤔」「言われてみればテストにもassert_deprecated
がいっぱい付いてますね」「割と大きな変更だと思う」
「Active Modelをどの程度までオブジェクト指向に作るかという設計の話の気もしますね: ハッシュの方が何も考えずに使えるという考え方もあるだろうし、オブジェクト指向的にきれいにやろうとするなら今回みたいにする方があるべき姿だろうし」「ふーむ」「自分は今回の変更の方が好き❤️」
⚓API変更を抜粋しました。
[]
- 変更なし、非推奨化(今後は
messages_for
) as_json
,blank?
,clear
,count
,empty?
,add
- 変更なし
added?
- ほぼ変更なし(1箇所変更: "Testing is more precise and flexible"を参照)
delete
- 拡張された(エラーの種類やオプションなどの詳しい条件を指定できるようになった)
each
each{|attr,msgs|}
は従来どおり(非推奨化)
each{|error|}
はError
の配列をループで回すfull_message
- 非推奨化(不要になった)
変更されなかったメッセージはError
で生成される full_messages
,full_messages_for
,include?
,size
,to_hash
,to_xml
,to_a
,messages
,details
- 変更なし
messages_for
- 追加(非推奨の
[]
を置き換える) where
- 追加(エラーオブジェクトへのクエリ)
generate_message
,has_key?
,key?
,keys
,values
- 非推奨化
import
- 追加(ネステッドエラーとしてエラーを1つインポート)(Form Objectやnested attributesでのエラーのインポートに便利)
⚓zeitwerk:check
タスクを実装
アプリケーションをRails 6にアップグレードするときに、従来のオートローダーを用いているプロジェクト構造が
:zeitwerk
モードと互換性があるかどうかを以下のコマンドでチェックできる。
PRより大意
bin/rails zeitwerk:check
つっつきボイス:「以前のオートローダーとzeitwerkモードで互換性があるかどうかをチェックするんだそうです」「そんなの動かしてみないとわからなそうだけど😆: 従来のオートローダーは実行時解決だから」「あー」「コード読まないとわかんないけど、空のRailsランナーを動かして通るかどうかをチェックしてるとかそういうノリ?」「コンパチブルチェックと言いつつ、zeitwerkに変えて動くかどうかぐらいのレベルのように思えるけど😆」「ここはひとつRails 6を触っている人たちにぜひチャレンジしていただきたい😆」
⚓Active Jobの古いジョブのリトライ
# activejob/lib/active_job/exceptions.rb#L50
def retry_on(*exceptions, wait: 3.seconds, attempts: 5, queue: nil, priority: nil)
rescue_from(*exceptions) do |error|
- # Guard against jobs that were persisted before we started having individual executions counters per retry_on
- self.exception_executions ||= {}
- self.exception_executions[exceptions.to_s] = (exception_executions[exceptions.to_s] || 0) + 1
+ executions = executions_for(exceptions)
- if exception_executions[exceptions.to_s] < attempts
- retry_job wait: determine_delay(seconds_or_duration_or_algorithm: wait, executions: exception_executions[exceptions.to_s]), queue: queue, priority: priority, error: error
+ if executions < attempts
+ retry_job wait: determine_delay(seconds_or_duration_or_algorithm: wait, executions: executions), queue: queue, priority: priority, error: error
else
if block_given?
instrument :retry_stopped, error: error do
yield self, error
end
else
instrument :retry_stopped, error: error
raise error
end
end
end
つっつきボイス:「ジョブのリトライか〜😅」「プルリクメッセージを見ると、Rails 6にアップグレードしたときに、Rails 5.2のときの古いジョブをリトライできるようにしたとある」「ジョブのフォーマットが5.2と6で変わっていたということなのかな」
「たしかにこれやっておかないといけないヤツ: Rails 6から始まったプロジェクトならいいけど、Rails 5.2でジョブキューがたまっている状態で6にアップグレードするとジョブキューが動かなくなってたという話なんでしょうね」「これ現場で起きたらめちゃめちゃ悲惨ですよね😅」「これ踏んだらヤバい😇: リトライできないジョブをどうやって復旧させるかを考えるだけで🤣」「Sidekiqの生のジョブキューとにらめっこして復元方法を考えるとかやりたくない〜😭」「果たしてロールバックできるんしょうか😭」
⚓Active Record高速化2連発
- PR: Avoid method call if `@transaction_state` is not finalized by kamipo · Pull Request #36049 · rails/rails
- PR: PERF: 20% faster pk attribute access by kamipo · Pull Request #36052 · rails/rails
# activerecord/lib/active_record/attribute_methods/before_type_cast.rb#L48
def read_attribute_before_type_cast(attr_name)
- sync_with_transaction_state
+ sync_with_transaction_state if @transaction_state&.finalized?
@attributes[attr_name.to_s].value_before_type_cast
end
# activerecord/lib/active_record/attribute_methods.rb#L467
def pk_attribute?(name)
- name == self.class.primary_key
+ name == @primary_key
end
つっつきボイス:「またしても@kamipoさんの高速化です」「やっぱり@kamipoさんはすごい人💪」「こういう地道な改修がホント大事🙏」「Active Recordのコード生成系の処理にこういうのが残ってたのか」「Active Recordのソースコードをここまで読み込んでる人って他にいなさそう」「@kamipoさんはこういうのをどうやって見つけるんでしょう?」「わがんね🤣: frozenでないものとかを地道に見つけて修正してるのかも」
「以下の差分の-
って何でしたっけ?」「これはfreezeしたstringを返すヤツですね」「そうでした😅」「3回ぐらい見かけたのでさすがに覚えた😆」
# activerecord/lib/active_record/attribute_methods/primary_key.rb#L43
def primary_key=(value)
- @primary_key = value && value.to_s
+ @primary_key = value && -value.to_s
@quoted_primary_key = nil
@attributes_builder = nil
end
参考: instance method String#-@
(Ruby 2.6.0)
⚓番外: 孤立化したレコードを検索するmissing
メソッド
# activerecord/lib/active_record/relation/query_methods.rb#L
+ def missing(*args)
+ args.each do |arg|
+ reflection = @scope.klass._reflect_on_association(arg)
+ opts = { reflection.table_name => { reflection.association_primary_key => nil } }
+ @scope.left_outer_joins!(arg)
+ @scope.where!(opts)
+ end
+
+ @scope
+ end
つっつきボイス:「まだマージされていませんが、Gobyの@st0012さんが『これよさそう』って教えてくれたPRです」「missing
はあれば使うかも😋: has_many関係で、manyされている側で参照元がなくなっているものを探せるヤツですね」「お〜」「この間ぐぐってみたところ、このorphan recordはデータベース用語として一般的に使われているもののようです🧐」「たまにデータベースの掃除をしたいときなんかにmissing
が便利そう🥰」
Post.where.missing(:author)
{他動} : 〜を孤児にする、親を失わせる、独りぼっちにさせる
{名・形-1} : 孤児(の)、親のない(人)、親をなくした(人)
{名・形-2} : オーファン(の)、孤立行(の)◆ページの末尾に残された、段落の最初の1行。2行目以降は次のページに送られている。
参考: What is an Orphaned Record? | Database.Guide
⚓その他改修
つっつきボイス:「HashWithIndifferentAccessってHWIAと略されることありますよね: 最初見たときわかんなかった😆」「HABTMなんて略語もありましたね」「はぶたむはもういいや😆: Railsにはもう存在しないし」
参考: ActiveSupport::HashWithIndifferentAccess
参考: HABTMリレーションシップは悪であるという論争 | A-Listers
つっつきボイス:「はー、where.not
の動作がRails 6.1でNORからNANDに変わると」「あんまり使ってる人いなかったのかな?」「where.not
って個人的には、気持ち悪いとまではいかなくても、ドットも含めてワンセットになっているのが何となく使いづらい気がするんですけど😅」「使うは使うけど、他にもメソッドがチェインされているとto_sql
してどんなSQLが出てくるのか調べないと落ち着かない😆」「not_where
みたいな名前ならよかったかも☺️」
つっつきボイス:「ActiveModel::Attributes
にattribute_names
ってなかったんだ!」「ハッシュのkeys
に相当するものを付けた感じ」
つっつきボイス:「join_type
...だと?」「あ、InnerJoin
やOuterJoin
を指定できるようになったのか」「これはあっていい気がする、というかこの方がどういうSQLができるか見当がつきやすいし😆」「自分はORM登場前からSQL使ってたのもあって、メソッドチェインが深くなるとto_sql
してSQLを確認しないと不安になるところがあるんですが、こういうやり方なら多少気持ちの安寧を得られるかなと😆」「このあたりORMネイティブ世代だとどう思うか知りたいところではありますね☺️」
⚓Rails
⚓Rails 6の地味に嬉しい機能たち(Ruby Weeklyより)
つっつきボイス:「これ系の記事は定期的に出てきますね☺️」「TechRachoの翻訳記事でお世話になってるEvil Martiansさんの記事です」「お、Evil Martiansの人たちはRubyKaigi 2019にも来てましたね、つーか発表してた↓」
「記事の方ですが、Railsウォッチを読んでいる方にはだいたいお馴染みのものが多そうでした」「Action MailboxにAction Textにマルチデータベースにパラレルテストあたりはだいたい言い尽くされている感ありますね」
「おー、Active Storageのダイレクトアップロード機能: ちょうど以下の図↓みたいに、Railsサーバーを経由せずにS3みたいなクラウドストレージにアップロードする機能ということだと思います」「お〜」「普通に実装するとまずRailsサーバーにアップロードしてからS3にアップロードするみたいになるんですが、ダイレクトアップロードではS3の使い捨てトークンを使って直接S3に投げられる🧐」
参考: Active Storage meets GraphQL: Direct Uploads - DEV Community 👩💻👨💻
「ダイレクトアップロードみたいな方式がありがたいのは、ファイルのアップロードのためだけにRailsのワーカーを保持しないで済むところ😋」「ある程度の規模のアプリになったらこういうのを真面目に実装しておかないと、管理者が管理画面で巨大ファイルをアップロードするとユーザーのフロント側が詰まるなんてことが起きかねないので😇」「あ〜なるほど」「こういうのを自前で実装するのは大変なので、Railsの機能にお任せでやれるのはありがたい🙏」
参考: ダイレクトアップロード -- Active Storage の概要 - Rails ガイド
「insert_all
とかupsert_all
あたりはウォッチでやったかな」「dirty
周りでは、PostgreSQLのJSONBでもchanged?
的なことができるようになってるらしい」「optimizer hintsもあったな〜」
「destroy_by
とかtouch_all
あたりは使いそうだけどそのときに忘れてそうな気も🤣」「人が使ってるのを見て思い出したりして😆」
⚓最近のService Object
社内SlackでService Objectの話題が出たので。Service Objectには「Facadeパターン」か「Commandパターン」の2つの方法があるという流れでした。
春の新作です(( ⁰⊖⁰)/) / “Railsで処理を別クラスに切り出す方法について - メドピア開発者ブログ” https://t.co/men6GHn5oR
— willnet (@netwillnet) May 8, 2019
つっつきボイス:「そうそう、最近Service ObjectがBPS社内でも話題になってたタイミングでwillnetさんがとてもいい記事を書いてくれてた❤️」
「記事は以下のように、publicなメソッドはcall
だけにしておいてあとは全部privateにするタイプの、単機能を使い捨てで実行するだけのService Objectの話ですね」
# https://tech.medpeer.co.jp/entry/2019/05/08/180000 より
class HereMentionCreator
delegate :channel, :creator, to: :message
def self.call(message:)
new(message: message).call
end
def initialize(message:)
@message = message
end
def call
members.each do |member|
message.mentions.create!(to: member, chennel: channel)
end
end
private
attr_reader :message
def members
@members ||= channel.members.active - [creator]
end
end
「そしてはてブを追いかけてたらちょうどMastodonのソースコードでも同じような感じでやってるのを見つけたりしました」
「Mastodonのもcall
だけがpublicで、後は全部private↓」「こういうのはわかりやすくていいですね😋」
# https://github.com/tootsuite/mastodon/blob/master/app/services/notify_service.rb
class NotifyService < BaseService
def call(recipient, activity)
@recipient = recipient
@activity = activity
@notification = Notification.new(account: @recipient, activity: @activity)
return if recipient.user.nil? || blocked?
create_notification!
push_notification! if @notification.browserable?
push_to_conversation! if direct_message?
send_email! if email_enabled?
rescue ActiveRecord::RecordInvalid
return
end
private
def blocked_mention?
FeedManager.instance.filter?(:mentions, @notification.mention.status, @recipient.id)
end
...
「ゲストの皆さんにお伺いしますけど、こういうService Objectって使います?」「まさに今そういうのを使ってます☺️」「お〜やはり」
「ついでに伺いますけど、呼び出しのメソッド名は何にしてます?call
とかexecute
とかperform
とか流派があるようですけど」「クラス名を踏襲するという意味でcall
派です😎」「意味のある名前を付ける派の人もいますけど、統一する方がわかりやすそうな気はしますね☺️」「たしかJavaだとperform
を使ったりします」
「run
はだめでしょうか?」「run
はService Objectだとちょっとニュアンスが違うかな〜: マルチスレッドで実行するイメージがあるので」「あ〜なるほど!」「Thread.run
的な印象が強いかも」
「Service Objectは未だに統一見解がない感じですね😆」「Rubyだとcall
が多いような印象ある」「後は上みたいにパラメータが増え過ぎたらParameter Object作ったりする、なんてのもありますね」
⚓RailsでFacadeパターンを使う
# 同記事より
# app/facades/users_facade.rb
class UsersFacade
attr_reader :current_user, :vip_presenter
def initialize(current_user, vip_presenter=VipUsersPresenter)
@current_user = current_user
@vip_presenter = vip_presenter
end
def new_user
User.new
end
def last_active_users
@last_active_users ||= active_users.order(created_at: :desc).limit(10)
end
def vip_users
@vip_users ||= vip_presenter.new(active_users.vip).users
end
def messages
@messages ||= current_user.messages
end
private
def active_users
User.active
end
end
つっつきボイス:「Service ObjectでもCommand的に書くのとFacade的に書くのがあるという話があったのでこういうのを探してみました」「Facadeって正直デザインパターンで名前付けるほどのものだろうかという気持ちはある🤣」「app/の下にservices/じゃなくてfacades/を置いて名前にFacadeと入っているところぐらいしか違わないっぽいですね」「utils/の下に置く何とかUtilityクラスをこうやってFacadeで書いているのは見たことあったかも」
⚓Rails Trace: Railsのリクエスト/レスポンスをビジュアル表示(Ruby Weeklyより)
- 元記事: Rails Trace
つっつきボイス:「左下の『Show Key』を押すと凡例が表示されます」「ほほう、コールスタックを追う的な?」「Metal呼んだりRack呼んだりしてる」「お、右にスクロールするし!結構長い」「Metal呼んだだけじゃまだまだ終わらないので☺️」
「Railsのリクエスト/レスポンスを旅するみたいな」「チャートの色をクリックすると機能とメソッドが表示されるし」「横に広がっている紫色がRackの層なのか: Rackのコンテキストがどこからどこまであるのかなんてのがわかるし」
「こういうリクエスト/レスポンスのイメージってどこかで意識しておくといいでしょうね☺️」「学習用にもよさそうですね🥰」
後で気が付きましたが、ビジュアル表示方法の解説記事とソースコードへのリンクも同サイトにありました。ReactでSVGを生成しているそうです。
- 関連記事: Visualising How Rails Responds to HTTP Requests
- リポジトリ: zetter/rails-trace: Display an interactive trace of a request for a Ruby on Rails application
⚓その他Rails
- 元記事: Upgrading Rails apps with dual boot – O'Reilly Engineering – Medium -- オライリーもRails使ってる(RubyFlowより)
つっつきボイス:「記事は普通っぽいんですが、オライリーのサイトというのが面白かったので拾ってみました☺️」「これは普通にアップグレード記事ですね: Railsに限りませんが、デュアルブートでやるのはベストプラクティスのひとつ」
つっつきボイス:「これははてブに上がってた記事ですね」「2018年の記事?」「あ、気が付かなかった😅」「大バズりした記事を定期的に広告としてはてブに浮かび上がらせてるからでしょうね」「見事釣られました🎣」
「無駄に長いコメントがだいたいよろしくないというのは確かに」「ところで皆さんはソースコードにコメントを書きたくない派ですか?」「いや〜ははは😅」「記事の『検討したけどやらなかったことをコメントにする』は、どこかでMatzが『Why notはソースコードでは表せない』と言ってたのにも通じていて、why notを表すのは大事」
「ソースコードを読めばわかることはコメントに書く必要はないと思うけど、なぜこういうコードになったのかという理由はコメントで表すしかなさそうですよね☺️」「『普通ならpluckでやるけどなぜかmapじゃないと動かなかったのでこう書きました』とか😆」「『ここはActive Recordのバグらしいので回避のためにこう書きました』とか😆」「あと正規表現を究極にこじらせたときなんかも『こういうことをする正規表現です』ぐらいのコメントは欲しい😆」
⚓Ruby
⚓Rubyで関数合成
Thoughtbotの記事です。
# 同記事より
BENEFIT_COST_IN_CENTS = 1000 * 100
TAX_RATE = 0.4
subtract_benefit = ->(salary) { salary - BENEFIT_COST_IN_CENTS }
pay_tax = ->(salary) { salary * (1 - TAX_RATE) }
calculate_take_home_pay = subtract_benefit >> pay_tax
calculate_take_home_pay.call(SALARY_IN_CENTS) # => 840000.0
つっつきボイス:「Rubyでやらんでもええやん🤣」「compositionってどっち方面の言葉かなと思ったらやっぱり数学で言う合成関数みたいでした😆」
⚓Procodile: Ruby製プロセスマネージャ
- サイト: Procodile - A simple process manager for development and production
- リポジトリ: adamcooke/procodile: 🐊 Run processes in the background (and foreground) on Mac & Linux from a Procfile (for production and/or development environments)
$ procodile start --foreground
16:13:41 system | Procodile supervisor started with PID 24532
16:13:41 system | Application root is /Users/swagman/Development/my-app
16:13:41 system | Listening at /Users/swagman/Development/my-app/pids/procodile.sock
16:13:41 system | Reloading configuration
16:13:41 web.1 | Started with PID 24548
16:13:41 worker.1| Started with PID 24549
16:13:41 worker.2| Started with PID 24550
16:13:41 cron.1 | Started with PID 24551
16:13:41 web.1 | => Puma starting in cluster mode...
16:13:42 web.1 | => * Version 3.12.0 (ruby 2.5.3), codename: Llamas in Pajamas
16:13:42 web.1 | => * Min threads: 5, max threads: 5
16:13:46 cron.1 | => Starting clock for 2 events: [ daily hourly ]
16:13:46 worker.1| => Starting worker... waiting for jobs
16:13:46 worker.2| => Starting worker... waiting for jobs
16:13:50 web.1 | => ::1 - - [26/Mar/2019:16:13:50 +0000] "GET /style.css HTTP/1.0" 302 - 0.2817
16:20:00 worker.1| => [3871] Beginning execution of job 3871 with DownloadLatestTweets
16:20:00 worker.1| => [3871] Downloaded 322 new tweets from 3 Twitter accounts
16:20:00 worker.1| => [3871] Finished processing
A brief introduction to Procodile from aTech Media on Vimeo.
つっつきボイス:「Procodileという名前の由来はワニの絵で丸わかりですね😆」「ぱっと見た感じforemanみたいなヤツ?」「ですです、リポジトリにそう書いてあって、バックグラウンドでもフォアグラウンドでも動くそうです」
「今さらですが、プロセスマネージャってどういうときに使うんでしょう?」「複数のプロセスを立ち上げないといけないものをまとめるときですね: サーバー以外にRedisなんかも含めて全部1個のコンテナの中で立ち上げたいときとか」
「ワーカーのプロセスを立ち上げ忘れたせいで非同期系の処理が実行されていなかった😇、というような事態を避けるためにプロセスマネージャをよく使います」「プロセスマネージャはワーカーを立ち上げることはもちろん、スーパバイザーとしても動作するので、ワーカーがout of memoryで死んだときに自動で再起動してくれたりと面倒を見てくれる」「なるほど!」「要するにスーパバイザーですね🧐」
「Rubyだとforemanが定番なんでしょうか?」「Rubyならforemanだったり、Dockerだとsupervisorだったり↓」
「あとは古き良きUnixではMonitなんてのもありますね」
- サイト: Easy, proactive monitoring of processes, programs, files, directories, filesystems and hosts | Monit
「これまた昔にGODというRuby製のプロセス監視ツールもありましたね」「名前が強い!⛩」「プロセスマネージャはしょっちゅう使うものではありませんが、こんな感じでいろんなものがあります☺️」
⚓scientist: GitHub製のクリティカルパスリファクタリング用ライブラリ(Ruby Weeklyより)
★が5000近くあります。
# 同リポジトリより
require "scientist"
class MyWidget
def allows?(user)
experiment = Scientist::Default.new "widget-permissions"
experiment.use { model.check_user?(user).valid? } # 変更前のコード
experiment.try { user.can?(:read, model) } # 変更後のコード
experiment.run
end
end
つっつきボイス:「さいえんてぃすと?」「これもスゴい名前😆」「use
とtry
を使って振る舞いやパフォーマンスを比較できるみたいです」「developmentモードとかtestモードで使う感じ」「コミットには入れないんでしょうね」「README、長っ😆」
「あ、末尾にいろんな言語のAlternativeがずらっとある!」「scientistっていう一般的なフレームワークがあるのかな?」「PHP版すらあるし」「今気づきましたが、これGitHub自身がやってるリポジトリなんですね😳」
「たぶん具体的には、リファクタリングの前と後で動作が変わってないかどうかをチェックするのかも?」「あ〜、それならtry
とかrun
も含めてしっくりくる😋」「compare
なんてのもあるし」
「以下で言うとuse
に既存のコード、try
にリファクタ後のコードを入れて、結果がcontrol
とcandidate
に入って、それをcompare
で比較するみたいな感じでやれるようだ」「リファクタリングテストのフレームワークと理解するとよさそう」「出力データの例がなぜかREADMEにないけど、だいたいそんな感じかなと☺️」
class MyWidget
include Scientist
def users
science "users" do |e|
e.use { User.all } # Userインスタンスを返す
e.try { UserService.list } # UserService::Userインスタンスを返す
e.compare do |control, candidate|
control.map(&:login) == candidate.map(&:login)
end
end
end
end
後で気が付きましたが、他の言語のはRuby版のscientistから移植されたようです。以下のGitHub技術ブログに解説とともに整形済みグラフや出力サンプルっぽいものもありました。「副作用のあるコードへの利用は想定されていない」そうです。
# github.blogより
{
context:
repo: 3
user: 1
name: "repository.pullable-by"
execution_order: ["candidate", "control"]
candidate:
duration: 0.0015689999999999999
exception: nil
value: true
control:
duration: 0.000735
exception: nil
value: false
}
⚓その他Ruby
- サイト: Ruby Conferences -- 今後開催されるRuby関連カンファレンス一覧(Ruby Weeklyより)
- 過去リスト: Past -- Ruby Conferences
つっつきボイス:「前にも似たようなサイトを紹介したことがあったような気がするんですが、今後開催されるRuby関連のカンファレンスが開催期日順にずらっとリストアップされています(ほとんどは日本以外ですが😆)」「Balkan Rubyは毎年やってた気がする」 「RubyConf Colombiaって南米のコロンビアかな?」「大小さまざま☺️」
元PDFはhttps://t.co/UPUpOJIKPr にありますが、クラウドインフラへの適合の話(4章)や開発体制(6章)の話もあってすごく面白いですよ!
— imuno@シリコンバレー6年目 (@imunolion) May 9, 2019
⚓Ruby trunkより
⚓リクエスト: Module#name_components
Foo::Bar.name.split('::').last #=> "Bar"
# 上と同等の以下が欲しい
Foo::Bar.name_components #=> "Bar"
つっつきボイス:「@mrknさんのリクエストですね」「名前空間を切り落としたコンポーネント名をシンボルで取れるメソッドがあるといいよね、みたいな」「コードを検査するようなコードを書くときに欲しいのは何となくわかる」
前編は以上です。
バックナンバー(2019年度第2四半期)
週刊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など)です。