More Related Content Similar to マニアックなRuby 2.7新機能紹介 (20) マニアックなRuby 2.7新機能紹介6. プログラミング言語 Ruby
• 日本発のプログラミング言語(1993~)
• まつもとゆきひろ氏(matz)が設計・開発している
• Ruby on Railsというフレームワークが有名で、
Webアプリの市場を(たぶんまだ)獲得している
• 処理系本体はほぼC言語で書かれている
• 最近Rubyで書くところが徐々に増えている
• 添付ライブラリはフルRubyのものも多数
• https://github.com/ruby/ruby
7. Rubyの開発コミュニティ
• "Ruby core team"
• アクティブな開発者たちを漠然と指す謎ワード
• Ruby界隈では開発者を「コミッタ」と呼ぶ
• アクティブな開発者は10~30人程度
• 1回でもコミットしたことのある人の数:約100人
• 直近1年間で100コミット以上:約10人
• 直近1年間で10コミット以上:約20人
• 直近1年間で1コミット以上:約35人
19. Rubyの配列で木を表現する
19
x y
[x, y]
IK
[:K, :I] K SIK S K I K
[[[:K,:I],[:S,:K]], [[:K,:S],[:I,:K]]][[[:K,:I],[:S,:K]],[[:K,:S],[:I,:K]]]
22. 変形ルールをプログラムで書く
22
S
x
y
z
x z y z
def ski(e)
if e[0] == :I
e[1]
elsif e[0][0] == :K
e[0][1]
elsif e[0][0][0]==:S
[[e[0][0][1], # x
e[1]], # z
[e[0][1], # y
e[1]]] # z
else
...
end
end
[[[:S, x], y], z] [[x,z], [y,z]]
26. 変形ルールをパターンマッチで書く
26
S
x
y
z
x z y z
def ski(e)
case e
in [:I, x]
x
in [[:K, x], y]
x
in [[[:S,x],y],z]
[[x,z],[y,z]]
else
...
end
end[[[:S, x], y], z] [[x,z], [y,z]]
30. キーワード引数の理想と現実
• 理想(Ruby 3.0予定)
• 現実(Ruby 2.X)
30
def foo(a,b,c,x:42)
...
end
foo(1, 2, x: 43)
メソッド
呼び出し
普通の引数に1と2を渡してね
キーワード引数xは43でお願い
あっ、引数cの分が足りないよ!
見直してね
1, 2, {:x=>43}の3引数を渡せ
def foo(a,b,c,x:42)
...
end
a=1、b=2、c={:x=>43}で
xは未指定な➔あとでクラッシュ
foo(1, 2, x: 43)
31. Ruby 2におけるキーワード引数
• キーワード引数は、普通の引数の一部
• 一番最後にあるハッシュオブジェクト
• どちらも同じ意味 →
• Ruby 2.0設計時はこれでいいと思っていた
• しかし直感に合わないというバグ報告が次々と来た
• 直感にあわせるためにad-hocな仕様変更が繰り返された
• 今では完全なカオスになってしまった
31
foo(x: 43) foo({x: 43})
32. Ruby 2.6のカオスな挙動の例
• x には何が渡るか?
• 答え:何もわたらない(デフォルト式のnilになる)
• 理由
32
def foo(x=nil, **y)
p x
end
foo({}, **{})
def foo(x=nil, **kw)
p x #=> nil
end
foo({}, **{}) foo({})
kw={}
x=デフォルト
は、無と
同じ意味が自然
**{} 最後のハッシュは
キーワード引数
35. Ruby 2.7は移行支援バージョン
• 基本的にはRuby 2.6と同じ意味
• しかし3.0で変わる挙動に警告を出す
• www.ruby-lang.orgに移行ガイドを掲載する予定です
35
def foo(a,b,c,opt: 42)
end
foo(1, 2, opt:43)
#=> -:3: warning: The keyword argument is passed as the last hash parameter
# -:1: warning: for `foo' defined here
36. 委譲の新記法: (...)
• 委譲:引数をすべて別メソッドに横流しすること
36
def bar(a, b, c)
end
def foo(...)
bar(...)
end
foo(1, 2, 3)
def foo(*args, &blk)
bar(*args, &blk)
end
Ruby 2でまじめに書く場合
def foo(*args, **opts, &blk)
bar(*args, **opts, &blk)
end
Ruby 3でまじめに書く場合
39. numbered parameter:背景
• 簡単 (?) な書き方がある
• ちょっと複雑になると簡単 (?) にできなかった
• &:to_s を魔拡張する提案が繰り返された
39
ary.map {|x| x.to_s } ary.map(&:to_s)
ary.map {|x| x.to_s(16) } ×
ary.map {|x| JSON.parse(x) } ×
ary.map { _1.to_s(16) }
ary.map { JSON.parse(_1) }
ary.map(&:to_s << 16) ary.map(&.to_s(16)) ary.map.as_self{to_s(16)}
ary.map(&(:to_s.proc >> :ord.to_proc)) ary.map(&(&:to_s >> &:ord))
40. numbered parameter: 複数引数の罠
• _2を読み出すだけで_1の意味が変わる
• こういう意味になってる
40
h = { 1 => 2 }
h.map { p _1 } #=> [1, 2]
h.map { x = _2; p _1 } #=> 1
h = { 1 => 2 }
h.map {|a| p a } #=> [1, 2]
h.map {|k, v| p k } #=> 1
41. numbered parameter: 書けない場所
• 入れ子のブロックでは1回しか書けない
41
1: n.times {
2: _1.times {
3: _1
4: }
5: }
-:3: numbered parameter is already used in
-:2: outer block here
こういう
ややこしいのは
書いてほしくない
43. 余談:決まるまでの長大な議論
• 2019/01: $_, @0,@1,@2, {|x|なのか {|x,|なのか
• 2019/02: nobuが@1でパッチ書いてみることに
• 2019/03: @1入りでpreview1リリースの方向
• 2019/04: eregonがブロック引数の利用例統計
• 2019/06: @, @0, it, $it, ¥it, _, 複引数必要か、{|x,|
• 2019/07: it, _, %0, @, @1,@2, %1,%2, :1, :2
• 2019/09: _0 / _1,_2,_3の方向で固まる
• 2019/10: _0 が消える
• 開発者会議の議事録は公開されています(バグトラッカから)
43
45. 令和対応:Date.jisx0301
• 2019/04/01 令和発表
• 2019/04/17 Ruby 2.6.3リリース(投機実行)
• 2019/05/01 令和施行
• 2019/05/20 JIS X 0301改正
45
$ ruby -rdate -e 'puts Date.new(2019, 4, 30).jisx0301'
H31.04.30
$ ruby -rdate -e 'puts Date.new(2019, 5, 1).jisx0301'
R01.05.01
46. 令和対応:Unicode ¥u32FF (㋿)
• 2019/04/01 令和発表
• 2019/04/?? Unicode 12.1.0 beta
• 2019/04/17 Ruby 2.6.3リリース(beta採用)
• 2019/05/01 令和施行
• 2019/05/07 Unicode 12.1.0リリース
46
$ ruby -e 'puts "㍻".unicode_normalize(:nfkd)'
平成
$ ruby -e 'puts "㋿".unicode_normalize(:nfkd)'
令和
54. LISP-1とLISP-2
• Python (LISP-1)
• 括弧無→メソッド取出
• 括弧付→メソッド呼出
• 一貫している
•Ruby (LISP-2)
• 括弧ありでも無しでも
メソッド呼び出し
• メソッド取出が面倒
• 取出してから呼出も面倒
54
"str".upper() #=> "STR"
"str".upper
#=> <built-in method upper
of str object at…>
"str".upcase #=> "STR"
"str".method(:upcase)
#=> #<Method: String#upcase>
"str".:upcase.call
"str".:upcase
#=> #<Method: String#upcase>
56. 消された理由
• 「関数型プログラミング?」の用途には不完全
• ↓のケースは .: で解決しない
• 今後も &:to_s を魔拡張しつづけるのか……?
• Rubyの関数型プログラミングのgrand planを
(誰かが)考えてから再挑戦することに
56
[json1, json2].map {|x| JSON.parse(x, symbolize_names: true) }
57. 2.7は他にも新機能や改善や非互換がたくさん
• IRBの刷新
• $SAFE消滅
• filter_map
• Enumerable#tally
• GC.compact
• Time#floor, #ceil
57
• beginless range
• self.private_method
• Array#intersection
• Comparable#clamp with range
• CESU-8
• Enumerator.produce
• Enumerator::Lazy#eager
• Enumerator::Yielder#to_proc
• Fiber#raise
• FrozenError#receiver
• IO#set_encoding_by_bom
• Integer#[] with range
• Method#inspect
• Module#const_source_location
• 一部のto_sがfrozen
• ObjectSpace::WeakMap#[]=
• Regexp#match?(nil)
• RubyVM.resolve_feature_pathの移動
• UnboundMethod#bind_call
• Bundler更新
• CGI.escapeHTML高速化
• CSV更新
• Net::FTP改良
• Net::IMAP改良
• open-uri改良
• OptionParser did_you_mean
• Racc 更新
• REXML更新
• RSS更新
• RubyGems更新
• StringScanner更新
• 一部の標準ライブラリがgem化
• ほか
クックパッド開発者ブログで網羅解説予定 w/ ko1
59. まとめ
• Ruby 2.7にご期待ください
• 数多くの新機能や改良
• Ruby 3を見据えた準備
• 意外といろいろ考えてやってます
• あなたもRuby開発に参加できます
• メーリングリストやバグトラッカをウォッチ
• もしくは、検索:"Ruby Hack Challenge"
59