2021/12/16 今回の気になった bugs.ruby のチケット
今週は {Method,UnboundMethod}#{public?,private?,protected?}
が追加されました。
[Bug #18405] Regression in Struct member setter method parameters
Struct
の最適化をした際にデグレしているというバグ報告
S = Struct.new(:foo) S.instance_method(:foo=).parameters # 最適化前 => [[:req, :_]] # 最適化後 => [[:req]]
- セッターメソッドなのに引数を受け取らないのはおかしいんじゃないか?との事
- 確かに
- これは既に修正済み
[Bug #18408] Rightward assignment into instance variable
- 右代入でインスタンス変数に代入できないのは意図しているのか?というバグ報告
# error: syntax error, unexpected instance variable 42 => @v
- 右代入はパターンマッチの機能を使っているんですがパターンマッチがインスタンス変数などを束縛できないからですね
# error: syntax error, unexpected instance variable case 42 in @v end
[Bug #18396] An unexpected "hash value omission" syntax error when without parentheses call expr follows
- 先週話していた Hash の省略記法で『次の行の式』が値になってしまうというバグ報告の続き
key = "key" # p(key:) ではなくて p(key: 42) になる p key: 42 # => {:key=>42}
- 元々は仕様ということで Reject されていたが matz 的には改善したいらしいので再度 Open された
- https://bugs.ruby-lang.org/issues/18396#note-4
- 動作的には非互換になるが試してみよう、って試みみたい
- コメントでは例えば以下のような Rails DSL を書いていると非互換になるので問題があると書かれている
validate :something, if: -> {condition } # コード長いとここで改行している可能性がある validate :something, if: -> {condition }
[Feature #18384] Pattern Match Object
- パターンマッチを保持するオブジェクトを定義する提案
- 例えば次のように
pattern
でパターンマッチを保持し、ブロック引数に渡すような感じ?
list_of_people.select(&pattern( first_name: /^F/, last_name: /r$/, age: 20..40 ))
Proc
やRegexp
と同じようなイメージ
TARGET_PERSON = PatternMatch.new(first_name: 'something') list_of_people.select(&TARGET_PERSON)
- 同じようなパターンマッチを DRY 的に使い回す場合には便利そう?
- パターンマッチの場合は変数に束縛する機能もあるのでそこをどうするのがいいんだろうか
[Feature #11689] Add methods allow us to get visibility from Method and UnboundMethod object.
- メソッドのアクセシビリティを返す
Method#visibility
UnboundMethod#visibility
を追加する提案:public
:protected
:private
が返ってくる
- ユースケースとしては任意のメソッドをラップする場合に元のメソッドと合わせるために使用できる
class Object def debugging(name) original = instance_method(name) # 提案 # visibility が `:public` `:protected` `:private` を返す method_visibility = original.visibility # 既存の実装だとこう書く必要がある # method_visibility = if private_method_defined?(name) # :private # elsif protected_method_defined?(name) # :protected # else # :public # end define_method(name) { |*args, &block| pp name original.bind(self).call(*args, &block) } # 元のメソッドに合わせる send(method_visibility, name) end end class X def hoge pp 1 + 2 end private :hoge debugging :hoge end # error: private method `hoge' called for #<X:0x000055f0b1abf3e0> (NoMethodError) X.new.hoge
- 元々の提案の
#visibility
は入らなかったが{Method,UnboundMethod}#{public?,private?,protected?}
のように判定するメソッドが追加された
class Object def debugging(name) original = instance_method(name) # 既存の実装だとこう書く必要がある method_visibility = if original.private? :private elsif original.protected? :protected else :public end define_method(name) { |*args, &block| pp name original.bind(self).call(*args, &block) } # 元のメソッドに合わせる send(method_visibility, name) end end class X def hoge pp 1 + 2 end private :hoge debugging :hoge end # error: private method `hoge' called for #<X:0x000055f0b1abf3e0> (NoMethodError) X.new.hoge
- どちらかと判定メソッドが必要なケースが多そうなのでこっちのほうが汎用性は高そうですね
[Feature #18402] Argument Labels
- 次のようにキーワード引数に予約語を使用することはできるが参照する事はむずかしい
def change_color(to:, for:, until:) new_color, user, end_date = to, for, until do_something_with(to) do_something_else_with(for, until) # What does this do with which data again? end change_color(to: :blue, for: user, until: DateTime.tomorrow)
- これを対応するために以下のようにキーワード引数とは別に参照する名前を定義できるようにする提案
def change_color(to new_color:, for user:, until end_date:) do_something_with(new_color) do_something_else_with(user, end_date) # No use of reserved keywords anymore, and readable variable name! end change_color(to: :blue, for: user, until: DateTime.tomorrow)
- これは Swift の『内部引数名と外部引数名』という機能からヒントを得たらしい
- よさそうな気がしつつまたメソッドのシグネチャが複雑になるのか…というお気持ち
- また、以下のように
=>
を使う記法の提案もされている
def change_color(to: => new_color, for: @current_user => user, until: DateTime.tomorrow => end_date)
- ちなみに以下のように Hash の省略記法を使うとスムーズにアクセスができる
def change_color(to:, for:, until:) do_something_with({to:}[:to]) do_something_else_with({for:}[:for], {until:}[:until]) # What does this do with which data again? end change_color(to: :blue, for: user, until: DateTime.tomorrow)
[Feature #18410] Proposal to make inspect include underscores on numerics
964218442
のような数値を表示する際に964_218_442
みたいな表示にする提案- これは便利そうな気がしつつ非互換になってしまうのがちょっと気になる…
- あと単に数値として表示したい場合もあるので必ずしも
_
を付けたいとは限らないんじゃないかなあ - ロケールによって
_
も変える必要があるとコメントされている