Ruby コミッターになりました + 2024年活動記録
Ruby コミッターになりました。他にも今年は色々なことがあったのでまとめておきたくなった。
登壇
RubyKaigi 2024 キーノート
地元沖縄開催のRubyKaigiでキーノートをすることに決まって準備含め頑張った。
大阪Ruby会議04登壇
去年11月頃くらいからやっていたRelineのレンダリングのリアーキテクチャの話をまとめた。
元々RubyKaigiにプロポーザルを出してた内容の供養(キーノートに変わった)
言いたいことを3行くらいでまとめると
これから発表する「Re-line 〜 IRB・Reline 複数行編集の裏側」の資料です #osrk04https://t.co/rD974NPvAN
— ぺん! (@tompng) 2024年8月24日
OSS活動
特に覚えている範囲のもの
IRB
コマンドの実装変更 コマンドをmain objectのメソッドではない形で実装した。
Ruby 3.4からデフォルトで型を使った補完を使うよう変更
そのためにBundled gemsにrepl_type_completorを追加
Reline
去年に引き続きRelineのリファクタリング
レンダリング周りは今年前半で一区切りついたので、今年後半では入力の扱いのリファクタリングをやっていた
去年の12月時点から lib/**/*.rb を1300行減らした
E2Eテストの高速化など
RDoc
コードリーディング会に参加したのがきっかけでちょっと読むようになった。
RDocの ruby parser(Ruby 3.0のendless method definition未対応)のメンテが辛そうだったのでPrismを使った新しいものを追加した。(libを +1000 テストコードを: +2000)
今はexperimentalとして追加した段階で、そのうち置き換えることになると思う。
Prism
parse.yとの違いを色々見つけて報告
10進数表記の整数リテラルのkaratsuba法による基数変換 (その後直すべきところが色々あったようで...)
REXML
DoS脆弱性の修正 (すでにされていたDoS対策の内容が少し変な気がして別の直し方に変えた)
PP
Hash#inspectのスタイル変更への対応
nil..nil false..false のinspect修正
Ruby本体
Integer.sqrt(巨大整数) の高速化
Hash#inspect の出力を変えた "{:x=>1, :y=>1}" → "{x: 1, y: 1}"
compile.c をちょっと触った(pull request 3つくらい)
parse.y をほんの少し触った(pull request 2つくらい)
出来事
ジェネラティブアートアワード入賞
TRICK 2022で金賞だった水槽のQuineをジェネラティブアートのコンテストに応募したら入賞しました。優秀賞とかには届かなかったのはちょっと残念。
僕自身は今回は説明文を書いて出しただけで、過去に書いたコードが勝手に頑張ってくれた、という感覚。
Ruby Prize受賞
今年は確かに結構頑張ったけど、ここまで評価されているとは思ってなかったのもあってすごく嬉しい。
トロフィーでかい。これからはトロフィーのある生活を送っていこうと思います。
Ruby Prize のトロフィー無事に届きました!
— ぺん! (@tompng) 2024年12月20日
かっこいい pic.twitter.com/aNB6DGBvM7
Ruby Committerになりました
松田さんの推薦でRubyのコミッターになりました。
しおいさん、ydahさんと同期ですね。同期がいるって嬉しい。ydahさんとはコミッターになった日付も同じ。よろしくお願いします。
引き続きIRBとRelineを中心に活動しつつ、Ruby本体と他の標準ライブラリもちょっとずつ見ていけると良いかな
TRICK 2025 準備中
ずっと考えてる。難しい。みんなも正月休みはTRICKをやろう!そして応募しよう!
RubyKaigi 2024でキーノートをしてきました
丁度1ヶ月前の5月15日、RubyKaigi 2024 初日のキーノートでしゃべってきました。
タイトルは「Writing Weird Code 奇妙なコードを書くということ」
発表スライドはこちら
RubyKaigiは僕にとってすごく特別なカンファレンスだし、それが地元沖縄で開催されるということで、絶対何か喋りたいと思って真面目な内容のCFPを出していたんですが、
気づいたら真面目じゃない内容のキーノートをしていました。RubyKaigi本当に楽しかったし。すごかった。
RubyKaigiが終わってしばらくは「RubyKaigi本当にすごいイベントだった」という言葉が頭の中をループしていて、その時にこのブログを書いていれば、文章の半分くらいが「やばい」で埋め尽くされていたんじゃないかなぁ。
本当にすごいイベントだった。だってRubyKaigiでキーノートするなんて一生に一回あるとも思ってなかったし。
感想もたくさんもらえて嬉しかった。毎日RubyKaigi感想ブログ読み漁った。もう一度2024/05/15の12:03頃にワープしたい。
以下、箇条書き風ですが、キーノートを話すまでの出来事とかについての感想とか補足とか意図とかをまとめてみました。
キーノートが決まるまで
- 2月に入ってから、キーノートどうですか、という話が来た。
- その日の夜、発表で大失敗する夢を見た。
- 数日考えて、以下の内容で話せそうだったので、やりたいと返事を返した。
- 奇妙なコードについて30分くらい話せそう
- 沖縄をテーマに一人TRICKと称して5作品くらい作れば後半30分話せそう
- 他に考えていたこと
トーク全体の構成
- 奇妙なコードというと、Rubyの悪いところだと思われるかもしれない。
- そうならないように、Rubyは楽しい・Rubyのこんなところが良い、みたいなのを全面に押し出すようにしたかった。
- 一人TRICKの前にいい話っぽいまとめをして、そこから一人TRICKへと話が飛躍するようにしたい。
スライドの前半
- 30分くらい、短い奇妙なコードについての話をする
- ruby-jp slackのtimes-tompngに奇妙な短いコードを時々貼っていたので、それらをまとめてストーリーを作る
- 気になった奇妙なコードは積極的にtimesに書くようにした。(ネタのいくつかは見たことある人もいたかな)
- 自分のgistを見返して面白そうなのがないか探す
- 福岡Rubyist会議で話したキーノートの一部分の続きみたいな話をする
- IRB関連で見つけたもの、bugsなどにissue報告したものなどから使えそうなネタを探す
- 奇妙な短いコードのうちいくつかはPrismのバグを見つけた時のもの(実は60issueくらい報告してた)
スライドの後半・一人TRICK
- TRICKが開催された時にネタ切れにならないよう・沖縄らしい話にしたいので沖縄をテーマに
- Rubyに詳しくない人が見ても楽しめるもの(妻に感想を聞きながら)、見た目が派手なもの、ビジュアル的にインパクトがあるものを多めに作る
- QuineはTRICKみたいなコードの一分野に過ぎないので、ほとんどをQuineでは無いものにする
- ビジュアル重視によりすぎるのも良くないので、Quineも最低一つは入れる
- 使うTRICKの種類・沖縄らしい題材・Rubyの何を使うか、を沢山リストアップして、どの組み合わせで作るか考える
- 全ての要素をある程度ばらけさせたかった。題材も、自然・生物・工芸、といった感じで。
- 全部並行して作り始める。スライドの準備期間も十分取りたいので、1ヶ月くらいで大体完成させるのを目標に。
スライドの締め
- TRICKでそのまま終わってしまうとあまりに投げやりすぎる
- RubyKaigiが始まるよ、楽しんでいこう、で締める
- そのためにはどう話を繋げよう、というのを最後まで試行錯誤していた
ホットトピック全部盛り
- 3月になった頃、多少こじつければ今年のホットトピック全部入りにできるんじゃないかと思い始める。
- 基調講演は「基本方針についての講演」らしい。RubyKaigiのキーノートがそうである必要は全然ないけど、そうであっても良い
- TRICKの話をしながら自然に他のセッション全てのトークについて触れることができればすごくキーノートっぽい気がする
- この構成の発表ができるのは初日のキーノートだけなので、初日で本当に助かった。
- スピーカーが発表されたあたりで、この人はきっとこの話をするんだろうな、というのをジャンルごとに分けてメモしていた。
- どうしても近い要素を入れられなかったトークもあって申し訳なかった。割と頑張ったと思う。
- 作りかけの作品にどの要素を入れるか考え直したりもした。
一人TRICK作品詳細
- Most Floral (画像かつruby)
- 沖縄で昔LTした時に使ったネタを多少グレードアップした。
- これだけ使いまわしのネタで、見たことがある人もいるかもしれないけど、盛り上がるので入れたかった。開花時期もちょうど良いし。
- トーク前半で話した「一部のヒアドキュメントやコメントや__END__の後ろには任意のバイト列が書ける」の活用例でもある
- Most Fresh (国際通り入り口の広告 Wasm)
- 国際通り入り口のディスプレイに表示する映像を何か作れないかと松田さんに聞かれた。最初断ったけど、やってみたかった・一人TRICKに入れれそうなので作ってみることにした。
- 国際通りに流れていて不自然ではない映像(お土産のジュースっぽいと思わせてRuby)普通のアスキーアートだけのQuineだと派手さが足りない
- コードについて語るRubyKaigiらしくなるよう、コードを見せる映像にする、つまりQuineのようなものにする
- これでWasmネタ(および、いろんなところでRubyが動く話の種)確保したぞ、という気持ち
- 見た目優先(つまりTRICK成分薄め)で作ったので、作品自体について話せる内容はそんなに多くなかった。代わりにMakingの話でRubyの良さを伝えることにした。
- Most Wavy
- Quine要素。TRICK2022の金賞作品に対する別解とも解釈できるというのを伝えたかった
- Most Dangerous
- Most Kaigi-ish
- SelfTRICKとは無関係に気分転換で作ったもの。いろんなトークに話を繋げるのに都合が良いので使うことにした。
- Relineのリファクタの話をしたくて、LTでやろうかとも思ったが流石に辛いと思ってやめた。ここで軽く話せてよかった。
- Most Eternal
作品の順序について
- ミンサー織りは(模様の意味から)最後が相応しい
- テッポウユリは最初でガッと盛り上げるのに良さそう
- 海繋がりでWavyの次はクラゲにする
- 残り二つは、聞く人があまり疲れなさそうな順番で紹介
発表してみて
- みんなの反応が良くてよかった。途中で静かになった場面はウケてないのか、滑ったのかな、と不安になったりもした。静かに聴くのが普通のはずなのに。
- 時間ぴったりだったらしいけど偶然です。時計見て調整する余裕もないので見てないし、練習の時も時間は全然安定しなかったので。
- たくさん感想貰えたのは本当に嬉しかった。他の人の発表でふれられていたのも嬉しかった。
- どの作品がよかったか聞いてみたところ、テッポウユリとクラゲが人気でした。
- RubyKaigi後に、TRICKやってみたい、Quine書いてみた、という声も多数聞こえてきた。まさかこんなkaigi effectを発生させることになるとは。Weird Codeはいいぞ!
- 他のみんなのセッションの前座のような立ち位置のトークをしたはずなのにこんなに感想もらってしまっていいのかなぁと思いながらも感想ブログ読みながらニヤニヤさせてもらいました。
Quineとそうでないものについて
Quineが6作品だと誤解されていそうな感想を結構見かけたけど、Quineのようなものは6作品中2作品だけです。TRICK2022も、10作品のうちQuineは4作品。
見分け方ですが、出力がvalidなコードではなさそうなもの、出力に元のコードと同程度の情報量がエンコードされていなさそうなものはQuineではないです。
今後
今回のRubyKaigi、元々はRelineのリアーキテクチャについて話すつもりでCFPを出していました。
最近1年間で僕がやったことはこんな感じ。
- IRBのバグ修正とリファクタリング(katakata_irbのコードの一部を使った)
- IRBの型補完gem repl_type_completor
- Relineのリアーキテクチャリング(約1000行減)
- Prismに割と多くのissue報告をした
このあたりの真面目な発表もどこかでしたいなー
RubyKaigi 2024 本当にすごいイベントだった
来年のRubyKaigi 2025では奇妙なRubyのコンテスト TRICK2025が開催されます。奇妙なコードを書いて投稿しよう。Let's write weird ruby code!
GraphQLのライブラリをなぜか書いている話 GraphQLは良いぞ!
RailsのモデルをフロントのJavaScriptで持っているデータとリアルタイム同期させるためのgem(ar_sync)を作っている。
そのために、俺の考えた最強のシリアライザ(ar_serializer)を作っていたら、ほぼGraphQL互換(mutationはないけど)ぽい作りになった。
せっかくなのでGraphQLのパーサを書いて、GraphiQLが動くところまでできた。 GraphQLは良いぞ
ar_serializerについて
https://github.com/tompng/ar_serializer
queryは、as_jsonとかincludesの引数みたいな(見慣れたものに近い)記法で書く
GraphQLのqueryと機能的にはだいたい同じ
モデルにガリガリfield書いてく 個人的には書きやすいと思う(typeも指定しなければ適当にassociationとかから引っ張ってくる)
N+1回避しつつqueryで柔軟にjson作る、のが目的で作っているので、graphql-batch内臓みたいなもの
aliasの内部表現がgraphqlと逆(response_key:field_name
field_name: {as: response_key}
ちょっとここは直したい)
権限管理用にnamespaceってものをつけた ArSerializer.serialize model, query, use: current_user.namespace_for_role
GraphQLのparserは気合いで書いたので、対応してない記法も多分ある(graphql-rubyも文字列escape周り似たようなものだけど)
雑感
GraphQL、すごくよくできてる。最高!
少なくともqueryの部分は。
理想のものを作ろうとした結果、もうすでにあるものにたどり着いて、自分は何をやっていたんだろうという気分にさせられた。
graphql-ruby 大変そう
ActiveRecord(かActiveModel)で使うの前提だとしてgraphql-rubyは記述がちょっとだるそう
graphql-batch 微妙じゃない?(graphql-rubyが提供すべき機能がないせいで無理してない?)
Query Language 別にJSONで良くなかった?
argumentsの書式がjsonじゃないので、文字列で埋め込めない
{post(${JSON.stringify(param)}){name}}
などができない。代わりに、 {post($param){name}}
とvariablesを使えばいいけど
それならもともと独自言語じゃなくてJSONだったらよかったんじゃないかなぁ、param埋め込みも自由だしvariablesなんて要らなかったのでは
確かに読みやすい言語だけど、そのparserを各言語用にみんなそれぞれ作らなきゃいけないし...
mutationはメリットが良くわからない
accepts_nested_attributes_forでできることを別に解決してないように見える
postに対して、commentを10件つける、ということがGraphQL使えばうまくいく、わけでも無さそう
RESTで、返り値(@post
)に対するgraphqlのqueryを指定できれば良くない?
(取得系はGraphQL 更新系はREST+返り値のquery がいいんじゃないかな、特にRailsだと)
Relay connectionsもちょっと引っかかるところがある
ページネーション実現するならこうなるだろうな、とは思うけど
複数のpostsに対して、commentsを(after指定で)取れてもあまり意味無さそうで、
特に使わない方向に自由度が高くなっているような(別にいいんだけど、なんかもやっとする)
{ allPosts { comments(first: 5, after: "id15") { edges{ cursor node{ id text } } } } }
REST apiでpagination実現+データの形式はGraphQLのqueryで指定、でも良いような気がする
どうしよう
ar_syncを、ar_serializer捨ててgraphql-ruby依存で作るべきかどうか悩み中(答えはnoな気がする)
とはいえ、mutationもrelayもまだ使ってないから使ったら感想変わるかもしれない
TRICKボツ案集
TRICK2018に出そうと思ったけど作らなかった、途中まで作ってやめた、ボツ案集
ruby迷路パズル
StartからGoalまで、実行可能な順にたどるルートを探す迷路 実行すると(探索して)正解を表示する
実験段階で探索全然終わらなかったから諦めた
# イメージとしてこんな感じ(左がコード、右が正解) pu))ell pu ell )ts:h)o ts:h o def*[{! !
アスキーアートでバージョン表示するQuine
rubyバージョン間の挙動違いを使って分岐する
判定コードのリストは作ったけどRUBY_VERSION==でできることを長ったらしく書いてるだけな気がしてやめた
# こういう判定コードを全バージョン間で見つけたかった def a x: 1;end def a(x: 1); end # 2.0 def a(x:); 1; end # > 2.1
# 2.1 true.frozen? # 2.2 class Object;def dig*;end;end;[1].dig(0) # 2.3 (1<<10).class==(1<<100).class # 2.4 1.round(1)/2 # 2.5
成長する植物Quine
育成要素があるQuine 種から育って、花が咲いて、種を落として元に戻る(たまに枯れてもいいかも)
結局やらなかった(成長するQuineはTRICK2015で既出だし いつかやるかも)
bmp画像とrubyのpolyglot
invalid multibyte char (UTF-8)
をうまいこと避けないといけない
けど__END__
とか#
使えば楽勝ぽいから面白みが少ない
裏側に人間がいてやっと成り立つChatBot Webサーバ
偽チェスロボットの「トルコ人」みたいに、裏に人がいるWebサーバ
存在意義が意味不明だけど、あんまりTRICK向きじゃない気がした
一応動くところまでは作ったものがこちら
https://gist.github.com/tompng/0ff8cf33046cb312dd66d55195c91eee
実行して、ブラウザでlocalhost:3000を開くとテキスト会話できる
javascript無しでブラウザ画面をリアルタイム更新する技を使ってるところが見所
(javascript完全排除できるけどpost後のinputのクリアにだけ使った)
TRICK FINAL 5作品入選
RubyKaigi 2018で、意味不明なプログラムコンテスト「TRICK FINAL」に6作品投稿して5作品が入選しました!
1つくらいは入選するかなと思ったけど予想以上に評価されて嬉しい(3位悔しい)
https://git@github.com/tric/trick2018
どうやって作ったか、git log公開します。
興味あればどうぞ。難読化前のコードも含まれてるので読みやすいはず。
(試行錯誤していけそうだぞ、とわかった時にinitial commitしてるのでその時点で割と出来上がってるけども)
アイデアは過去にやったことのブラシュアップだったり考えたけどやらなかったのを思い出して、記憶のゴミ箱から拾い集めました。
1作目 png viewer(3位)
https://gist.github.com/tompng/fc18db09114f4e3ba52de593303b8580
フォーマット(Zlib+method_missingでアスキーアート化)をまず決めて、そのあとでネタとして画像viewerを選んだ
予約語が現れるのを避けるためにSyntaxErrorをcatchして再生成試すようにした。もっと別の方法があったかもしれない
2作目 infinite monkey(選外佳作)
https://gist.github.com/tompng/e24fd79f303393244d003225baba0931
ランダムな6文字をevalしたらたまたまruby tric と出るような乱数のseedを力任せにCPUぶん回して探すことで作った
3作目 wineglass(5位)
https://gist.github.com/tompng/c87ff0b298867491ce47343fe9a5a4e2
method_missing -, +, -@, +@を使ってワイングラス・おちょこ用のDSLを作った
整形は割と簡単で、まずある程度コードゴルフ→整形→短くしたコードを一部崩して長くして瓶の形を細かく調整
ワインボトルで余った文字を水滴の部分で吸収できて整形しやすかった。
4作目 christmas(11位)
https://gist.github.com/tompng/923ad9fb233cdb37fbc032ff6200c98e
Merryの部分が3DデータをMath系の関数で表現したもの、残りがレンダラになってます。
レンダリングの前処理がすごく重いので、その待ち時間にMerry Christmas!の文字を出してます。(プログレスバーみたいな感じ)
かなり力を入れたけども、rubyらしい黒魔術成分はないです。
5作目 brainf*ck(7か8位)
https://gist.github.com/tompng/0a9a407b57d34b75c0b46c6a8b7e56c5
部品を横に繋げても動くコード(かつQuineみたいな)
誰もやってないすごい良いアイデアのつもりだったけどColinさんのライフゲームが上下左右連結で完全に上を行ってた
6作目 whitespace(10位)
https://gist.github.com/tompng/c445259784f99a5bb52d44f9092b450c
全角の空白文字を混ぜたら見た目と実際のコードが乖離できるサンプル。
空白をこっそり混ぜた、一見まともに見えるプルリクを送りつけてmergeさせる攻撃が成立する実証コードかもしれない
1位、2位の二人が本当に強かった。
アニメーション(escape sequence入り)がQuineにできるってのがかなり衝撃だったし、
縦横繋げるのも今後は当たり前の技術になってしまうのかなぁ
短くてすごいコード書ける人にはすごく憧れる(書こうと試してできたのが佳作のあれ)
parse.y読み込んだとか なるほどそこまでやれば思いつく(かもしれない)のかー
次回があればああいうのを書きたいな
YAPC::Okinawaに参加してきた
前夜祭
前夜祭で「綺麗なコードの書き方」についてLTしてきました。
(先週あったLTのイベント(okinawa-nuyaga)で話した内容をブラッシュアップして)
内容はタイトル詐欺で、ちょっと錯乱拡大解釈した、綺麗なコードについての話です。
https://github.com/tompng/executable_image
(perl、配列、リファレンスあたりからあんまり理解してなくて結構苦労した)
本編
sinya8282さんの文脈自由文法の話が楽しみだった&面白かった。
あとは最近気になってるGraphQL、Dan KogaiさんのPerl6の数字の話を聞いたり、勉強会・コミュニティの話聞いたり、
準備片付け、疲れで仮眠など。
GraphQLの話
client側よりの話だった
未来だと思うんだけど、既存のRDBのRailsにどう載せるの、ってのが気になってる。
(N+1起きるでしょ、notificationsあたりの実装どうなってるの、繋ぎの別技術がしばらく要るのでは)
apollo serverが何をしてくれるものなのかわかってなかったりあまりついていけなかった。
backendのDB何使ってるんだろ
HTTP2の話(聞けなかった)
HTTP1がHTTP2より速いケース(パケットロス)もあるとか(をTLでちらっと見ただけ)
TCPが賢くないのが悪いような気がした。(だって同じ伝送路だよ、おかしい)
再送がすごく遅れてもいいから帯域ほしい、ってのはTCPのやってくれることとは目的が違うから
TCP以外の別のプロトコルが速いってことかな(TCP複数接続束ねたものを別のプロトコルと見立てたり)
HTTP2 over TCP
vs HTTP1 over TCPx10
文法と曖昧さの話
プログラミング言語の曖昧さ
if elsif if else
の最後の else
はどのifにかかるのか
rubyだと method1 arg1,arg2,method2 do end
の `do end ``はどっちにかかるか
ありえる構文木が複数あっても、最初に見つかった方を使うから1つに確定してると思うんだけど
昔それのバグ(ブロックが時々method2にかかる)踏んだりしたから、やっぱりなるべく無曖昧であってほしい。
C言語とか、仕様自体が曖昧(実行順序が未定義)とかなかったっけ?実行順序はまた別かもしれないけど。
無曖昧な言語の組み合わせが何通りあるかの話
s → ε | (s)s な書き換えでできる言語の例だと(= ((()()))()
みたいな括弧が対応してるもの)
プログラム的には
組み合わせ(n文字) = Σ 組み合わせ(i文字) * 組み合わせ(n-2-i文字)
みたいに再帰的に計算したくなるけど、
S(z) = 1 + z*S(z)*z*S(z) # S(z)は母関数 組み合わせを係数にもつ多項式
でできるぽい。いきなりεを1に、|を+に置き換え出した時は頭の中に?が沢山並んだ。
(多項式の積を展開する部分がΣに、z*z(係数を2つずらす)が(n-2-i)の2つずらしに、1が再帰の終了条件に対応してそう)
表現が違うだけだけど四則演算が便利に使えてすごい(小並感 数学忘れてる感)
これが何にどう使えるのかあたりの話はよくわからなかった。
memo=[]; count = -> n { memo[n] ||= n.odd? ? 0 : n.zero? ? 1 : 0.step(n-2,2).sum{|i|count[i]*count[n-2-i]} }
数値の話
1.2345
で書いた数値が全部floatじゃなくrationalになるのは、一見便利そうだけどあんまりメリットないよなー、とか
log(2)とかも全部floatじゃなくlogに2を渡したものとして内部で表現してたら面白いなーって話を他の参加者としたりした。
> 1/3 == Num(1/3) True > 1/3 == 0.3333333...(数十個) False
がTrueにならなくて不思議だったけど(限界超えたらfloatになるんじゃないの?と)
0.33333333333333333333 #=> 0.33333333333333333333 0.333333333333333333333 #=> 0.33333333333333330372739 # (1行目より2行めの方が小さくなったように見えるけど<比較すると大小関係正しいので表示上の問題?) (0.33333333333333333333).WHAT #=> (Rat) (0.33333333333333333333*1).WHAT #=> (Num) 0.333333333333333*3 #=> 0.999999999999999 (Rat) 0.3333333333333333*3 #=> 1 (Rat) 正確な値じゃなくなった
なるほど?
大小関係逆転するのも見つけた。
my $a = 0.33333333333333333333333; my $b = 0.333333333333333333333333; say($a > $b) #=> True
(1/2**62/2).WHAT #=> (Rat) (1/2**62/4).WHAT #=> (Num)
分母は64bitまで
ボランティアスタッフ
してきました。他イベントも含めボランティアスタッフをすること自体初めてで、かなり疲れた(今週体調よくなかったのが主因だけど)
ボランティアスタッフではないけど早めに会場に着いて手伝う、みたいな手軽なボランティアなら今後もやれそう(だけどそれじゃ回せないだろうからなー)
コアスタッフの皆さんありがとうございました。
来週は
沖縄Ruby会議02があるのでぜひ http://ruby.okinawa/okrk02/
RailsのActionCableでリアクティブプログラミング
コメントを投稿したら、いいねをしたら、他の人のブラウザ画面にリアルタイムに反映される
そういうWEBアプリを簡単に作れる仕組みを作りたくて今gem作ってます。
https://github.com/tompng/ar_sync AR(Active Record)Sync 名前は変わるかも)
ActionCableで自前でbroadcast頑張ればできるけど、データ同期するモデルが増えると複雑になって破綻すると思うので、
宣言的に定義しておけば全部うまくやってくれる仕組みが必要なはず。
このgemでできること
- 欲しいJSONデータの形をクライアント側からリクエストできる
- だけどSQLのN+1問題が起きない、または楽に回避できる
- そのデータがRails側のmodelと同期していてリアルタイムに更新されていく
- Vue(もしくはReact)と繋げば、リアルタイムにデータ同期されるWEBアプリの完成
多分、GraphQLやMeteorがやってることに近いかな
Railsと何らかのJSフレームワークを使ってるところに簡単に乗せれるところを目指してます。
使い方
モデルの定義
データ同期するカラムと親子関係を記述
class User < ApplicationRecord has_many :posts sync_self sync_data :name sync_has_many :posts # 逆の関係(sync_parent)も定義する end class Post < ApplicationRecord belongs_to :user sync_self sync_data :title, :body, :created_at, :updated_at, :user sync_parent :user, inverse_of: :posts # sync_has_many :postsの逆 end
API作成
class SyncApiController < ApplicationController include ARSync::ApiControllerConcern api(:profile) { |_params| current_user } api(:user) { |params| User.find params[:id] } api(:post) { |params| Post.find params[:id] } end
さくっとView作成
postsまで、postsについたcommentまで、commentについたいいね数まで、など
任意の深さのデータを要求して、vueに渡すだけ
<script> new ARSyncData({ currentUser: { api: 'profile', query: ['id', 'name', { posts: ['title', 'created_at'] }] } post: { api: 'post', params: { id: 3 }, query: ['title', 'body', 'created_at'] } }).load((vueData) => { new Vue({ el: '#foobar', data: vueData }) }) </script> <div id='foobar'> <h1> {{post.title}} by {{post.user.name}} <small>date: {{post.created_at}}</small> </h1> <p>{{post.body}}</p> <hr> <h2>my posts</h2> <div v-for='post in currentUser.posts'> <a :href="'/posts/' + post.id">{{post.title}}</a> <small>date: {{post.created_at}}</small> <!-- remote: true なformやボタンを足すだけで動く --> <a :href="'/posts/' + post.id" data-remote=true data-method=delete>delete</a> </div> </div>
仕組み
Rails側
ActiveRecordのafter_commitでhookをかけて、
そのデータが必要なクライアントにだけ、データのpatchをActionCable経由でbroadcast
JS側
初期データをAPI経由で読み込んで、ActionCableで必要なkeyだけsubscribe
送られてきたpatchをデータに適用して、最新に保つ
VueやReactがそれを勝手に画面に反映してくれる
デモページ
http://arsyncdemo.herokuapp.com/
2つのウィンドウで開くと、いいねやコメントがリアルタイムに反映される様子が見れます
デモのソースコード
https://github.com/tompng/ar_sync/tree/master/sampleapp
今後
- それ、**でできるよ みたいなのあるのかな?
- 関連してそうなライブラリとか色々調べる
- どうしよう