Ruby本体読みはじめた人に届けたいドキュメント

RubyKaigi2017に参加してやる気が高まったので最近は ruby/ruby のコードを読むようになってます。

github.com

しかしこれがなかなか読むのにコツがいる感じです。
RubyKaigi参加前は “Ruby under a microscope”1 を読んで「Rubyの内側面白い!!!」ってなってたのですが、実際にCのソース読みはじめると全然違いますね。マクロ多いし、C言語のこともわからんし……。
Ruby Hacking Guide こと 『Rubyソースコード完全解説』2 を読んだほうがいいのかもと悩むようになりました。

でもそんな悩みも今日解決されました。これ読めばとりあえずはRubyのレポジトリを泳げるようになりそうです。

ruby/extension.ja.rdoc at trunk · ruby/ruby · GitHub

これが非常によいです。まず読んでて面白いし噛み砕かれている感じがある。飽きずに読める感じです。
RubyKaigiに参加して Ruby 本体読むぞーって人はまずここからやってみてはいかがでしょうか。

いまだいたい25%くらい読んだのでメモった内容(というかslackログ)を以下に記しておきます。
まだまだわからんことだらけですのでこれ読んどけとか、このへんから入るのが手頃とか教えてもらえるとうれしいです〜


せっかくだからメモっておくか

INT2FIX() :: もとの整数が31bitまたは63bit以内に収まる自信
             がある時

「自信がある時」

rb_str_resize(VALUE str, long len) ::

  Rubyの文字列のサイズをlenバイトに変更する.strの長さは前
  以てセットされていなければならない.lenが元の長さよりも短
  い時は,lenバイトを越えた部分の内容は捨てられる.lenが元
  の長さよりも長い時は,元の長さを越えた部分の内容は保存さ
  れないでゴミになるだろう.この関数の呼び出しによって

“”“ゴミになるだろう”“”

さっきから思ってたんだが rb_ary_new2 とか rb_ary_new3とかあるのな

~/.g/g/h/ruby ❯❯❯ git grep rb_ary_new2 | wc -l
     123
~/.g/g/h/ruby ❯❯❯ git grep rb_ary_new3 | wc -l
     110

4まであって草

VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)

なんかしてるのかなーって思ったら定義済みの定数があるか探して、あればクラスであること、スーパークラスが同じであることを確認、なければ普通にクラスつくってからouterにassign

まあ想定どおりの動きであった

これ rb_define_class も rb_cObject に対して同じことやってね?
ああ、でも細かいところの処理違うのだな。

これらの関数の argcという引数はCの関数へ渡される引数の数(と
形式)を決めます.argcが0以上の時は関数に引き渡す引数の数を意
味します.16個以上の引数は使えません(が,要りませんよね,そ
んなに).実際の関数には先頭の引数としてselfが与えられますの
で,指定した数より1多い引数を持つことになります.

cfuncは必須引数15個までなのか

void
rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_visibility_t visi)
{
    if (argc < -2 || 15 < argc) rb_raise(rb_eArgError, "arity out of range: %d for -2..15", argc);
argcが負の時は引数の数ではなく,形式を指定したことになります.
argcが-1の時は引数を配列に入れて渡されます.argcが-2の時は引
数はRubyの配列として渡されます.

-2のとき……

~/.g/g/h/ruby ❯❯❯ git grep 'rb_define_method.*-2'
enumerator.c:    rb_define_method(rb_cYielder, "yield", yielder_yield, -2);
enumerator.c:    rb_define_method(rb_cYielder, "<<", yielder_yield_push, -2);
ext/win32ole/win32ole_typelib.c:    rb_define_method(cWIN32OLE_TYPELIB, "initialize", foletypelib_initialize, -2);
ext/win32ole/win32ole_variant.c:    rb_define_method(cWIN32OLE_VARIANT, "initialize", folevariant_initialize, -2);
io.c:    rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
thread.c:    rb_define_method(rb_cThread, "initialize", thread_initialize, -2);

-2なんで使うのかよくわからんかった
Cの世界を通らずにそのままRuby to Rubyで動かせるからかな


  1. https://www.amazon.co.jp/dp/B01IGW56CU/Rubyのしくみ』なんだけど『言語のしくみ』と紛らわしいのでよくマイクロスコープ、アンダーアマイクロスコープと呼ばれている気がする。

  2. https://www.amazon.co.jp/dp/4844317210 中古が高いことで有名

RubyKaigi 1日目メモ

改行いれるのめんどかったからmdをWYSIWYGモードで。ほぼただのメモです

 

---


# RubyKaigi 1日目

## introduction

### まつださん

こんくらいなら聞き取れるけど英語スピーカーのトークは大丈夫だろうか
Brazilから来てる人もいる


### マネーフォワード

「3人のRubyコミッターがいる暮らし」


## day1 10:30~

http://rubykaigi.org/2017/presentations/n0kada.html

patch monster


ゆるふわ

fulltime ruby committer at Salesforce (Heroku)

Matzチーム

- Matz
- Nobu
- ~Ko1~

svnで開発。GitHubのPRはあくまで裏口

Ruby is older than Git
Window is not supported officially(Git)

ruby-core: en
ruby-dev: ja

taking inventory of bug tickets 棚卸し

how to build ruby
configure + make

Out-of-Place build #とは

baseruby miniruby
baseruby
parse.y -> parse.c
defs/id.def -> id.h
insns.def -> vm.inc

miniruby
no dynamic loading = runnable alone
convenient for debuggng

2.4までのparallel build
building miniruby -? parallel
building extension -> parallel
extconf.rb -> seequential

2.5 はそこをディレクトリ親子関係の依存関係以外は別プロセスで parallel でやるぞって話

https://gist.github.com/hkdnet/1c42ff3b807048cf548763326a7ec2e0

EXPR_END: 式がおわってもおかしくないところ
EXPR_LABEL: キーワード引数の名前がかけるところ

No eye-catcher in 2.5

2.3 safe navigation

Kernel#yield_self

rejected:
neko operator
user-defined operator

under discuttion:
method extraction operator
rightward assignment

## day1 13:00〜
http://rubykaigi.org/2017/presentations/ko1.html

Fiberは明示的な感じ
状態をもつものを、どこで実行状態をとめてるかに依存させたり

capturing continuation: callcc
thread より軽いから fiber

coroutine → どれを実行するのが指定するタイプの concurrency の話?
どこにでもとべるからパワフルなんだけど難しい

動いてるものを親としてresumeしたら子供として動く
先祖をresumeしたらエラー

Fiberの実装

コンテキストのスイッチ: スレッドの状態(pc, sp), VM stack, machine stack(C言語レベルのスタック)

最初はコピってstore, restoreする

中盤でOSの機能とかをつかうようにした

最近スレッドの状態をコピるのをやめた
(すこしは改善したりなんだり)

Guildとかで使うよてい

Auto Fiber proposal → インタプリタでスケジューラが動くようにしておく?
勝手に切り替わるようになってブロッキング時間を有効に使えるかも
でも逆に勝手に変わっちゃうから次にどのFiberが使われるかわかんないし、synchronizationが不要
こういうのは非決定的なバグをうみかちだからあんまり好きじゃない(_ko1)
??「Fiberっぽくないから名前かえたい」

## day1 13:50~

休憩しておりました

## day1 14:40~

http://rubykaigi.org/2017/presentations/kddeisz.html

read, tokenize, build ast, build iseq, exec iseq

Ruby 1.8まではASTを直接
ASTからinstruction sequencesへ

Ruby1.9かあら(だっけ)Iseq使う

2.3からiseqの読み書きができるように

ex:
yomikomu https://github.com/ko1/yomikomu
bootsnap https://github.com/Shopify/bootsnap

ソースを文字列で持ってるからいじれる!!!
gsubしてどうにかする → ここgsubなのか
日→秒変換: 24 * 60 * 60
掛け算はメソッド呼び出しなのでうんぬん
memo: コンパイル時に計算したいのかな

gem: vernacular
https://rubygems.org/gems/vernacular
https://github.com/kddeisz/vernacular/


自分で生成したIseqを食わせる
tuby使う

https://github.com/kddeisz/tuby

memo: JVMみたいにフロントの言語増えたらいいよねみたいなこと言ってた気がする
memo: iseqの仕様って安定的なんだっけね
→Q&A で補足。かわるかもね

## day1 15:50〜

http://rubykaigi.org/2017/presentations/watson1978.html
Ubiregi

モチベ: Ruby 3x3

パフォーマンス・チューニング
→まずは計測だ!

ツールとしてはiprofilerを使っている

```
$ iprofiler -tiemprofiler ./minruby ~/benchmark.rb
```

```
loop do
hash1.merge(hash2)
end
```

iprofilerでボトルネックを探して最適化する
メソッドを実行する処理 = dispatch メソッド探索 + execution メソッドの実実行

dispatchは広範囲に及ぶ処理なので影響範囲がデカかったりすでに最適化済みだったりする、みたいなことを言ってた

あるメソッドの execution 時間を短くしよう!

- メソッドディスパッチを減らす(実行中に別メソッドを呼んでいるので)
- 冗長なアロケーションを減らす

memo: ディスパッチを減らすというのは具体的にはインライン化とか

 


## day1 16:40~

http://rubykaigi.org/2017/presentations/narittan.html

streaming data importing
gatewayserver with h2o
mruby
benchmark

## day1 17:30

http://rubykaigi.org/2017/presentations/rubylangorg.html

sponsored: cookpad

よしおりさん
Ruby Commiters Sponsor

What will you do if a better language than Ruby comes along?
Make Ruby even stronger!!!

RHCとかね

Static type checking
mameさんクッ社へ fulltime committer

Ruby program を ロバスト
使い捨てじゃないプログラムを書くようになってきているので無理がきている
そこをなんとかしたい


型注釈絶対いれたくないのか問題

1. コードに書いてもいいよ
2. 書かせたくない
3. コメントになら書かせてやってもいいぞ

type inference がすすんだときにコード側に書いてあるとつらい
structual type はドキュメントに使いにくい

青春のアフター4を読んだ

以下ネタバレ前回でいきますのでご注意ください。

続きを読む

転職して1ヶ月が経っていたようです

タイトルのとおりです。
いつものも置いておくのでよろしくお願い致します。誰からかわかるとうれしいです

http://amzn.asia/ehpcSIc

(毎度のことなんだけどkindle版をほしいものリストから贈れるようにしてほしいし、並び替えはかんたんにできるようにして欲しいし、並び順は覚えておいて欲しいんだけどなあ……)

さて、2017年6月末日づけで某社を退職し、7月1日づけで、某お金を前にするような会社に勤めています。
職種としてはいわゆるWEB系プログラマー(サーバー寄り)という感じです。変わんないですね。
インフラまわりに手を出さなくなったのが前職との違いだと思います。

これは転職とはあんまり関係ないのですが、ついでにせっかくの機会なので一人暮らしを始めてみました。
さらには脱vimしてRubymineを使ってみたりスプラトゥーン2で3D酔いしてみたりしています。

引っ越しのドタバタで6月末の振り返りをすっとばし、なんやかんやで7月の振り返りもすっとばし現在に至ります。
環境が変われば現在の自分に感じる課題というのも変わっていて最近は日々頭を抱えているのですが、うまく言葉にできなくてなんだかにゃーとずっと言っています。
ぜんぶうまくいけ

さて、繰り返しにはなりますが、そんな悩めるカエルへの温かいご支援をお待ちしておりますのでなにとぞ

http://amzn.asia/ehpcSIc

Linux + Thinkpad X1 Carbon 5th Genでトラックポイント、タッチパッドが安定しなかったけど直した話

解決したから書く

環境

Thinkpad X1 Carbon 5th Gen
Ubuntu 16.04(Arch使ってたときも現象は同じ。治るかは未確認)

現象

タッチパッドトラックポイントがうまく動かない。
具体的には0.5秒くらい動いたあとに動かなくなる。
また何回か動かしていると10秒に1回くらい動く。

やったこと

参考に書いてあるブログ記事の内容を2つ試したら動くようになった。
ためしてないけど2つ目だけで動くかもしれない。

  1. カーネルパッチ当てる
  2. 以下のコマンドを叩く
sudo modprobe -r psmouse
sudo modprobe psmouse proto=imps

なんか2つ目だけでなおりそうな気がするけど。

参考

fredrik.wendt.se

Dockerのイメージとかタグとかの云々

だいたいこれで終わりだが一応書いておく。

前提その1

Docker は image をもとにして動く。image は Dockerfile に定義を記載しビルドすることで得ることができる。自分の image を作成するときには他人が作った image をもとにすることができる( FROM で記載する)。それらを共有する仕組みとして Docker Hub という Docker image を多数ホスティングしているところがある。

前提その2

Docker imageは名前とタグで管理される。名前はURLみたいなもので、 (host/)?(namespace/)*image_name という形式で表される (気がする)1
host が省略されていればDocker Hubという意味。namespace はそのホスト毎に管理が違う。Docker Hubだとユーザー個人のものはユーザー名のネームスペースに置かれ、公式と認められたものはネームスペースがない。

例: nginx → Docker Hub にある nginx という公式イメージ
例: hkdnet/app → Docker Hub にある hkdnet さんの app というイメージ
例: hkdnet.net/nginx → hkdnet.net という Docker registry の nginx

タグは同名イメージの中で区別するためのもの。イメージ名のあとに : を続けて記載する。だいたい公開されているものはメインのソフトウェアのバージョンを示していることが多い。自分のアプリケーションを Docker image にするときはブランチ名とタイムスタンプかCIのビルド番号をつけている。

例: nginx:1.12
例: ruby:2.4.1
例: hkdnet/app:master-build001

タグは好きなようにつけてよいし、一度 Docker registry に push されたイメージのタグも簡単に書き換えることができる。タグはイメージにおいて一意でなくてはならないので同名タグを push した場合は古いイメージについているタグは新しいイメージに移動する。

例: 4月に app:latest を push
5月に app:latest を push
このとき app:latest は5月のほうに移動する。4月のイメージのlatestタグは剥がされる。

余談だが Docker image には複数のタグをつけることができる。Docker image の一意性を担保しているのは Image ID であり、名前とタグはImage ID への参照だと言える。

先程の例をもうちょっと複雑にするとこんな感じ。

例: 4月にビルドしたイメージのIDを APRILXXXXX とする。これに app:latest という名前をつけ push する。また app:201704 という名前をつけて push する。
5月にビルドしたイメージのIDを MAYXXXXXXX とする。 これにも app:latest という名前をつけ push する。また app:201705 という名前をつけて push する。
このとき app:latest は5月のほうに移動する。4月のイメージのlatestタグは剥がされ、参照するには Image ID を直接指定するか app:201704 として参照すればよい。2

Docker image は基本的には FROM 指定したり run したり compose に書いたりするといい感じに pull される。しかし、ローカルにキャッシュがある。また、キャッシュヒットがタグ名で行われる。この2つによってタグまで一致するものがローカルにあると自動で pull されなくなる。
具体的にどういうときに困るかというと4月時点の app:latest が手元にあると5月で更新されたとしても app:latest は古いものを指したままになってしまう。対応策としては明示的に pull すればよい。あるいはローカルの app:latest のタグを消すか。


さて、 Docker を語る際のよい点に環境が変わらないことが挙げられることが多い。確かに同じ Dockerfile からは同じようなイメージが作られると期待できるが期待は裏切られることがある。

その1つが FROM 元の変更である(ようやく本題)。
Ubuntuは上述の公式イメージがある。だがそんなものを見なくても俺はUbuntuの最新LTSが16.04なのを知っている。

FROM ubuntu:16.04

ということをやると冒頭のように死にます。

https://hub.docker.com/_/ubuntu/

xenialも日時バージョン付けているのでちゃんと日時バージョンまで指定しておきましょう3


  1. 分類は公式に決まっているのかは調べてないが、だいたい使っているときはそう捉えておいて問題ない程度の意味

  2. さすがにアレなので図がほしいがめんどい

  3. 本題に対して前提が長すぎる……

Credenatial Management APIの発表聞いたメモ

developers.google.com

僕はchrome使いなのですが、まあモダンなブラウザを使っている皆様ならばだいたいログインフォームに入力したあとに「このログイン情報を保存しますか?」系のダイアログが出るのをご存知かと思います。
インターネットの普及に伴い様々なサービスをwebで享受することが可能になりました。webを見るのはだいたいブラウザでしょうし、各ブラウザベンダーとしてはwebサービスが増えていること、webサービスを使う人が増えていること、webサービスが扱う情報がより重要なものになっていることなどからブラウザでのログイン、セキュリティまわりもよくしていかないといけないよね、という問題意識があるような気がします[要出典]。
またスマートフォンの普及にともなって1人の人間が使うデバイスが複数あることが一般的になりました。そうするとPCでのchromeandroidchromeでログイン情報を同期したいというのはユーザーの要望として当然のことですし、webサービスとしてはユーザー体験を損なわないように努力する価値があるところでしょう。

というわけで Credential Management APIwebサービス開発者として結構気になる内容なのでトークをざっと聞いてみました。
以下そのまとめとメモです。
メモは話していたことを雑にメモってあって、 memo: で始まるのが僕が思ったことです。

まとめ

  • Sign-UpにCredential Management APIを使うのはめちゃくちゃよさそう
  • 一方でweb標準なのか?という疑問が残る
  • ブラウザに寄せたい人にはいいけどそうでない人はどうするのがいいんだろうなーという懸念がある

メモ

主な関心事は3つ。Sign-In, Sign-Up, AuthN1
Sign-Inがサインイン・ログイン時の話で、ある登録済みユーザーがあるサービスを利用開始するときの話。
Sign-Upは初回登録時の話。
AuthNは認証の話。特に2FAにフォーカスしてた気がする。

memo: AuthNが一番よくわからんかった

Sign-In

chromeのパスワードマネージャがうまく動かない理由トップ3

  • マークアップが壊れている、アノテーションがおかしいなどHTMLレベルの問題
  • サインインフォームである、サインインに成功したとchromeが検知できない
    • chromeは遷移後の画面にまたフォームがあるとログイン失敗とみなす
    • fetch APIなど画面遷移を伴わない場合は history を操作することで navigation が発生したとみなしてくれる
  • HTTPとHTTPSが混ざってる
    • HTTPなページにHTTPSなフォームがあっても insecure である
    • HTTPページの改ざんの可能性があるのでjsを仕込んでpasswordを別サイトにも送信、とかができちゃう
    • 当然HTTPなページにHTTPSのiframe仕込んでもダメ

chromeがランダム生成した文字列をパスワードにしてくれる機能がつく2。ランダム生成したものをchromeに覚えさせるので推測されにくくなる。自分で覚えてないからフィッシング詐欺にも遭いにくくなる。

memo: これいつデフォルトでオンになるんだか言ってたっけかなあ

Sign-Up

Credential Management APIでやるといろいろいいいことがある

  1. アカウント選択画面が画面が出てワンタップしたらログインみたいになる
  2. 規格に対応している認証情報提供元ならどれでも使える
  3. 入力のめんどうがない
    • ECサイトとかの事例で登録率とかコンバージョン率がめっちゃ改善した例が載ってた
    • memo: こういうの、UIの改善も同時に行ってそうな気はするのでほんとに独立な結果なのかわからんというかそうでない気がするが、フォーム入力の完了率を気にすることがなくなるのでマジで重要っぽい

こんな感じで使う

let settings = {
  password: true,
  federated: {
    providers: [
      "https://accounts.google.com"
    ],
  },
};
navigators.credentials
  .get(settings)
  .then(credentials => {
    // ユーザーに「これ使っていい?」あるいは「どれ使う?」ってダイアログが出る
    // ユーザー操作で選ばれたらresolveされるっぽい
  });

memo: これweb standardになるのかなあ。そのへんがよくわからん

AuthN

memo: けっこーはやくちなのでツラかった

いま2FAといえばOTPだけどsecurity keyというのを使うようにしたい。
security keyはデバイスに挿して使うやつでワンタップすることで二段階認証OKということにできるっぽい。
memo: 仕様としてはFIDO Universal 2nd Factorというやつっぽい。


  1. AutheNtication(認証)の略。AuthZ(AuthoriZation, 認可)との区別のために使う略語だと思う。認証とは「ユーザーが確かにこのアカウトであるか」という本人確認のこと。認可は「このユーザーならこの情報は見てもいいよ」などの許可だと思ってればよさそう。

  2. Chrome 59だとまだデフォルトではオンでないっぽい。 chrome://flags でいじれる。参考 -> How to Automatically Generate Random Secure Passwords in Google Chrome?