2022/06/11 今回の気になった bugs.ruby のチケット

今週は標準ライブラリをパターンマッチに対応させる提案がありました。

[Feature #18821] Expose Pattern Matching interfaces in core classes

  • Ruby のいくつかの標準ライブラリをパターンマッチに対応させるチケット
  • 提案されているのは以下の通り

Set

  • Array のようなパターンマッチを行う
# Hypothetical implementation
class Set
  alias_method :deconstruct, :to_a
end

Set[1, 2, 3] in [1, 2, *]
# => true

Matrix

  • Array のようなパターンマッチを行う
class Matrix
  alias_method :deconstruct, :to_a
end
# => :deconstruct

Matrix[[25, 93], [-1, 66]] in [[20..30, _], [..0, _]]
# => true

CSV

  • ヘッダーカラムをキーにして Hash のようなパターンマッチを行う
require "csv"
require "net/http"
require "json"

# Hypothetical implementation
class CSV::Row
  def deconstruct_keys(keys)
    # Symbol/String is contentious, yes, I will address in a moment
    self.to_h.transform_keys(&:to_sym)
  end
end

# Creating some sample data for example:
json_data = URI("https://jsonplaceholder.typicode.com/todos")
  .then { Net::HTTP.get(_1) }
  .then { JSON.parse(_1, symbolize_names: true) }

headers = json_data.first.keys
rows = json_data.map(&:values)

# Yes yes, hacky
csv_data = CSV.generate do |csv|
  csv << headers
  rows.each { csv << _1 }
end.then { CSV.parse(_1, headers: true) }

# But can provide very interesting results:
csv_data.select { _1 in userId: "1", completed: "true" }.size
# => 11

RegexpMatchData

  • 名前付きキャプチャに対して Hash のようなパターンマッチを行う
class MatchData
  alias_method :deconstruct, :to_a

  def deconstruct_keys(keys)
    named_captures.transform_keys(&:to_sym).slice(*keys)
  end
end

IP_REGEX = /
  (?<first_octet>\d{1,3})\.
  (?<second_octet>\d{1,3})\.
  (?<third_octet>\d{1,3})\.
  (?<fourth_octet>\d{1,3})
/x

'192.168.1.1'.match(IP_REGEX) in {
  first_octet: '198',
  fourth_octet: '1'
}
# => true

[Feature #18183] make SecureRandom.choose public

  • SecureRandom.choose という private メソッドを public メソッドにするチケット
require "securerandom"

# 第一引数の配列の中からランダムで10文字を返す
pp SecureRandom.send(:choose, ['a', 'b', 'c'], 10)
# => "cabbbaaaab"

pp SecureRandom.send(:choose, [*'A'..'Z', *'0'..'9'], 10)
# => "7JZMZUK4GD"
def alphanumeric(n=nil, alphabet: ALPHANUMERIC)
  n = 16 if n.nil?
  choose(alphabet, n)
end

[Feature #11689] Add methods allow us to get visibility from Method and UnboundMethod object.

  • Ruby 3.1 で {Method,UnboundMethod}#{public?,private?,protected?} が新しく追加された
class X
  private def private_method
  end

  public def public_method
  end
end

# 該当する可視性であれば true を返す
pp X.instance_method(:private_method).private?   # => true
pp X.instance_method(:private_method).public?    # => false
pp X.instance_method(:public_method).private?    # => false
pp X.instance_method(:public_method).public?     # => true
  • 最近この実装に対して matz がコメントしており Ruby 3.2 では Revert される流れになっている
    • https://bugs.ruby-lang.org/issues/11689#note-24
    • このチケットでは可視性はメソッドの属性という前提だったが、実際には各クラスで可視性ごとのメソッドのリストが必要とのこと
      • ##18435 を調べていて気づいたとのこと
      • そうしないと #18729#18751 のような問題が発生する
  • 参照しているメソッドは同じでもクラスによって可視性が変わる、ってことなんですかねー

[Bug #18790] cannot load such file -- digest (LoadError)

  • 特定の環境で CRuby をビルドすると require': cannot load such file -- digest (LoadError) になってビルドに失敗するので対処するチケット
  • 地味に困っているので何かしら本体で対応されるとうれしいなあ