RubyKaigi 2022 に参加してきた

RubyKaigi 2022

抜粋してトークの感想を列挙していく。フル参加していたはずなのに数が少ない理由はあとで述べる……

Ruby meets WebAssembly

今まで、Opal とかを使って Ruby で書いたコードを JavaScript に変換してブラウザ上で動かす、みたいなものは存在したけど、CRuby そのものがブラウザ上で動くという信じられない偉業について、その実現方法を解説してくれた講演だった。初日の最初のトークがこれなの、めっちゃすごいなって思った。後述する Code Puzzle も、この WebAssembly が使われていて、わしにとって今回の RubyKaigi を象徴するトークだった。

Making *MaNy* threads on Ruby

「あっちの言語では出来てることが、なんで Ruby では出来ないんだっけ?」みたいな感じで出来ない理由を列挙していって、それら一つ一つについて解決の糸口を探っていくと、だんだん「なんかできそうな気がしてきた」ってなってくる様子を見て、問題解決かくあるべしという気がしたし、憧れを持った。Ruby のすごいところの1つとして、Ruby ならではの機能とか改善をやりつつ、他言語の利点も強力に吸収していくところがあると思っていて、それが現れてるトークだった。

TRICK 2022 (Returns)

なんというか、言葉にならない感動が得られるコマだった…… やんちゃには芸術はわからぬ、であるにも関わらず、あれほど感動させられてしまう事に驚きを感じた……

Packet analysis with mruby on Wireshark – dRuby as example

Wireshark を Ruby で使いたいけど Lua とかでしか使えないので mruby が使えるようにした。という話なんだけど、やりたいことが明白で、とにかく自分がやるしか実現する方法がないし、やれば実現しそうだしやるしかない、という、営みのお手本みたいなトークで、見習いたいなと思った。

The Better RuboCop World to enjoy Ruby

人間と Ruby と、という感じの、とても考えさせられる良いトークだった。RuboCop がとても便利なツールである反面、人間との関係性を設計した上で使わないと、ある人間の人生にとっての Ruby という存在を歪めかねない一面をもっており、仕事でのことならそれが許されるのだろうか、もっとよく出来ないか、など色々と考えた。

Fast data processing with Ruby and Apache Arrow

普段、仕事で DWH を使っているので、Data Processing を Ruby でやるということに興味はあるものの、使っている DWH が BigQuery なので、Apache Arrow と関わる事がなくて寂しい。BigQuery と Ruby との間で Apache Arrow を使って何か得するような事が見つかったら何かをしたいと常々思っている事を再確認したトークだった。

Cookpad Code Puzzle for RubyKaigi 2022

スポンサーのクックパッドから提供されていた Ruby のパズルが面白すぎた…… RubyKaigi の会期中であるにもかかわらず、トークを聴く集中が途切れて、気がついたらパズルに取り組んでいる自分がいた…… Web Assembly の CRuby がブラウザ上で動いており、その上で課題を解いていくという、この RubyKaigi にピッタリのエンタメだった。

標準では func10 までが出題されており、エクストラステージとして func20 まで出題されていたが、ギリギリ会期中に func20 まで解くことができた。ただ、途中、何問かは出題意図を掴みきれないまま嘘回答で乗り切っており、会期が終わってから他の参加者と相談しながら正規の解き方を探った。でも、それもまた楽しかった。

どういう解き方をしたのか、Gists にまとめてあるので、興味のある人は見てもらったらよい。func10 までは公式の解説がでているけど、func20 までの解説は来週になるらしいので、それまでの間に自力で解きたい人は、ここで読むのをやめて、後日また見に来て欲しい。

# You can call `func1`
p func1(0) #=> 1
p func1(1) #=> 2
p func1(2) #=> 3
# Can you tell how `func1` is defined?
# Hint: def func1(n) = n + ???
# Define `answer1` that works like `func1`
def answer1(n)
n.succ
end
view raw answer01.rb hosted with ❤ by GitHub
# Congrats! You've solved the first puzzle!
# Next, challenge func2!
p func2("Hello") # => ??? (press "Run Ruby" to see output)
p func2("world") # => ???
def answer2(str)
str.upcase
end
view raw answer02.rb hosted with ❤ by GitHub
# Next, challenge func3!
p func3(1)
p func3(2)
p func3(3)
def answer3(n)
n.succ.times.to_a
end
view raw answer03.rb hosted with ❤ by GitHub
# Still want to play?
# You may want to try func4
# This call raises an error!
# Try to find a correct way to call it.
func4{9}
def answer4(&f)
f[] + 42
end
view raw answer04.rb hosted with ❤ by GitHub
p func5(0)
p func5(1)
p func5(2)
p func5(0,2)
def answer5(a, b=1)
a + b
end
# Hint: Check the parameters
view raw answer05.rb hosted with ❤ by GitHub
def answer6(n)
case
when n < 10 then n
else
n2 = eval(n.to_s.chars.join('+'))
n2 < 10 ? eval(n2.to_s.chars.join('+')) : answer6(n2)
end
end
0.upto(1000) do |n|
func, ans = func6(n), answer6(n)
puts "#{func == ans ? 'OK' : '—-NG'} n: #{n}, func: #{func}, ans: #{ans}"
end
view raw answer06.rb hosted with ❤ by GitHub
p func7(0)
p func7(1)
p func7(2)
# Hint: Try to pass non-Integer!
def answer7(n)
n.succ
end
view raw answer07.rb hosted with ❤ by GitHub
# Hint: %b
def answer8(n)
sprintf("%b", n).chars.select{|c| c == '1'}.size
end
1.upto(1000) do |n|
f = func8(n)
a = answer8(n)
p [n, f, a]
end
view raw answer08.rb hosted with ❤ by GitHub
# Can you tell what string is replaced?
# Hint: Pass a spy (or mock) object to func9
class Hoge
def gsub(a, b)
p [a, b]
end
end
def answer9(s)
s.gsub("u-g0t-me", "yikes")
end
((%w[foo bar baz])+[Hoge.new]).each do |c|
res = func9(c)
p [c, res]
end
view raw answer09.rb hosted with ❤ by GitHub
def answer10(reset=false)
if reset
@counter = nil
end
@counter ||= -1
@counter += 1
end
p func10(true)
p answer10(true)
view raw answer10.rb hosted with ❤ by GitHub
def answer11(o)
o.hash
end
view raw answer11.rb hosted with ❤ by GitHub
def answer12(n)
n.
to_s.
chars.
sort.
chunk_while{|i,j| i==j}.
to_a.
map(&:size).
reduce(:*)
end
view raw answer12.rb hosted with ❤ by GitHub
TABLE = Encoding.list.map{|e|e.to_s[0..1]}
def answer13(n)
TABLE[n]
end
view raw answer13.rb hosted with ❤ by GitHub
def answer14(n)
case n.to_s
when '0' then 'Z' # Zero
when '10' then 'T' # Ten
when '1000' then 'T' # Thousand
when /^(2|3)/ then 'T' # Two, Twenty Three, Thirty
when /^(4|5)/ then 'F' # Four, Five, Forty, Fifty
when /^(6|7)/ then 'S' # Six, Seven, Sixty, Seventy
when /^8/ then 'E' # Eight, Eighty
when /^9/ then 'N' # Nine, Ninety
when '11' then 'E' # Eleven
when '12' then 'T' # Twelve
when '13' then 'T' # Thirteen
when '14' then 'F' # Fourteen
when '15' then 'F' # Fifteen
when '16' then 'S' # Sixteen
when '17' then 'S' # Seventeen
when '18' then 'E' # Eighteen
when '19' then 'N' # Nineteen
when /^1/ then 'O' # One
end
end
0.upto(1000) do |i|
f, a = func14(i), answer14(i)
next if f == a
p [i, f, a, f == a]
end
view raw answer14.rb hosted with ❤ by GitHub
TABLE = Object.constants.sort.map{ |s| s[0..1] }
def answer15(n)
TABLE[n]
end
view raw answer15.rb hosted with ❤ by GitHub
def answer16(&f)
return false if f.parameters.empty?
f.call do
true
end
end
view raw answer16.rb hosted with ❤ by GitHub
def answer17(msg)
JS.eval("alert('#{msg}')")
end
view raw answer17.rb hosted with ❤ by GitHub
def answer18(s)
a = s.scan(/\d+/)
b = s.scan(/[^\d]+/)
pair = s.match?(/^\d/) ? [a,b] : [b,a]
pair.reduce(:zip).flatten.compact.map { |s|
case s
when /\d+/
s.to_i
else
s.split(//)
end
}.flatten
end
view raw answer18.rb hosted with ❤ by GitHub
def polandnize(ast)
case ast
in String => s
return s
in ['value', Integer]
return ast
else
# do nothing
end
case ast.children
in [Array, nil, node]
polandnize(node)
in [Integer => n]
['value', n]
in [node1, operator, node2]
[operator.to_s, node1, node2].map { |n| polandnize(n) }
in [next_ast, nil]
polandnize(next_ast)
end
end
def answer19(a)
ast = RubyVM::AbstractSyntaxTree.parse(a.map(&:to_s).join)
polandnize(ast)
end
view raw answer19.rb hosted with ❤ by GitHub
def solve(input)
case input
in ["value", Integer => n]
["value", n]
in [String => op, ["value", Integer => a], ["value", Integer => b]]
solve(["value", eval("#{a} #{op} #{b}")])
in [String => op, Array => a, Array => b]
solve([op, solve(a), solve(b)])
in [String => op, ["value", Integer] => a, Array => b]
solve([op, a, solve(b)])
in [String => op, Array => a, ["value", Integer] => b]
solve([op, solve(a), b])
in [String => op, ["value", Integer] => a, ["value", Integer] => b]
solve([op, solve(a), solve(b)])
end
end
def answer20(input)
solve(input)[1]
end
view raw answer20.rb hosted with ❤ by GitHub

Ruby Music Mixin 2022

RubyKaigi の最終日の夜、ピクシブ社のRuby Music Mixinというイベントに参加させて貰った。結構前から、ライブハウスで色んな音楽を聴くのが好きだったんだけど、ここ2、3年は色々あって遠ざかっており、このイベントで久しぶりに良い気持ちになって嬉しかった。盆踊りサークルモッシュみたいな謎な集団行動が発生する感じ、とても懐かしかったです。

行き帰り

今回、どうやって三重県津市まで行って帰って来るか、非常に悩んだ。というのも、地図を見ていると名古屋の南あたりに、いかにもショートカット出来そうな湾があって、調べてみると実際に伊勢湾フェリーというフェリーが運航されていて、とても楽しそうだったからだ。

伊勢湾フェリーを使うとなると、新幹線を中途半端な駅で降りないといけないし、港まで行く渥美半島の鉄道はすべて各駅停車で大変そうすぎる。伊勢湾フェリーの仕様を見ていると、バイクや車を積むことが出来るとある。わしは原付二種のスクーターを所持しているので、スクーターで行けばスクーターごと向こう岸に渡ることができて便利そう。これは機運なのでは?と思った。

ここまで書いていて、それは嘘だなぁって思う。結局、要するに、面白そうだったので原付二種のスクーターで三重まで行って帰ってきた。詳細は Twitter のハッシュタグにまとまっているので、興味のある人はのぞいてみてほしい。 やんちゃの旅

行きは、9/6 の 13:00 に家を出て、湯河原の Airbnb の宿で一泊。翌朝 9/7 の 07:00 くらいに出発して、19:00 くらいに三重の宿に着いた。帰りは 9/11 の 07:00 くらいに宿を出て、23:45 くらいに家に着いた。いわゆる強行軍というやつだ。

道中、一番辛かったのは一部のバイパス道の途中が自動車専用道路に指定されているせいで、125cc 以下の車両は強制的に下ろされてしまい、信号待ちのキツイ道を延々と走らされるという事に現地で気づいたことだった。イイカンジで流れている道の途中で「ここから先は遠慮してくれるか?」って看板が出て下ろされて、降りたところに「9km先でまた合流させてあげるから頑張ってねw」って看板が出てるのを見たときの感情はしばらくのあいだ忘れられないだろう。

行きはまだしも、帰りを1日でやりきろうとしたのは失敗だった。神奈川に入ってから家までの道中、かなりの疲労感があったし、危険だった。かといって中途半端なところで臨時で宿を取るという決断もできず、最初から富士市とか御殿場市で一泊する予定にすべきだったなという反省がある。

自動 二輪車でフェリーに乗ったのは初めてだったけど、とても楽しかったので、総じて成功ではある。次回、似たようなことをやることになったときには、今回の反省を活かして、イイカンジにやっていきたいと思った。

やんちゃハウス

2017 年から、やんちゃハウスという、RubyKaigi 期間限定のシェアハウスを主催しているんだけど、今回、3年ぶりにやんちゃハウスを実施した。やんちゃハウス2022は色々な事を加味して、3LDKの家をAirbnbで借りて3人でシェアするというスカスカ構成にした。今までのやんちゃハウスでは家にある布団の数だけRubyistを詰め込んでワイワイやる、というスタイルだったので家を借りる費用を頭数で薄めることが出来るメリットがあったが、今回は四泊25,000円くらいになってしまい、下手すると普通のビジネスホテルの方が安かった可能性すらある。

そこまでして、どうしてやんちゃハウスを実施したのかというと、一回中断してしまうと、再開するハードルが上がるだろうから、という理由だった。種火程度でも残っていれば、またあの頃のやんちゃハウスが戻ってくるかもしれないし、あるいは未来の違う形のやんちゃハウスが現れるかもしれない。それらの可能性が潰えないように、こじんまりでも実施したというのが今回のやんちゃハウスだった。

ところで、やんちゃハウス2023について。RubyKaigi 2023 は松本で開催されると予告されたわけだけど、これは 2020 のリベンジであり、やんちゃハウス2020のリベンジでもある。なので2020の時に借りようとしていた家にはオファーを出していて、少しずつ準備は進んでいる。もう次の話が進んでいるんだなぁ。

あと、年内に RubyWorld Conference 2022 というイベントが島根県松江市で行われる事になっていて、こちらで『やんちゃWorldハウス2022』というのをやろうかという話が進んでいる。マジか、という感じ。今後、募集開始するとしても1枠しか残ってないので、もしも強い興味を持っている人がいたら、公募が始まる前にネジ込みに来て欲しい。

まとめ

こころもち
カテゴリー: 未分類 パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください