Slide 1

Slide 1 text

Good to know yaml

Slide 2

Slide 2 text

self.introduction.to_yaml

Slide 3

Slide 3 text

今日話すこと/話さないこと 今日話すこと - YAMLのAST周り (※ざっくり) - 実世界でYAMLのASTを理解して解決できる問題とは 今日話さないこと - syckについて - Psych::Nodes以外はあまり触れない - yamlの詳細な仕様について - JSONとの規格の違い

Slide 4

Slide 4 text

基本編

Slide 5

Slide 5 text

YAMLとPsych

Slide 6

Slide 6 text

yamlとは https://en.wikipedia.org/wiki/YAML

Slide 7

Slide 7 text

yamlとは (簡潔に & ほぼ「るびま」からコピペ) - 構造化されたデータを表現するためのフォーマット - YAMLでは主に次の 3 つの組み合わせでデータを表現する - Sequence: Rubyで言うと `Array` - Mapping: Rubyで言うと `Hash` - Scalar: (文字列、数値、真偽値など ) https://magazine.rubyist.net/articles/0009/0009-YAML.html

Slide 8

Slide 8 text

gem ‘psych’とは - yamlのバックエンドライブラリ(Ruby 1.9.3から標準化) - YAML バージョン 1.1に対応 - 過去のyamlバックエンドライブラリは `Syck ` - YAML バージョン 1.0に対応していた - libyamlのRubyで扱えるwrapper - `YAML.load`, `.load_file`, `.parse`, `.parse_file`とかをよく使うと思うんですけど、 Rubyオブジェクトへの変換処理はgem ‘psych’ が担っています https://github.com/ruby/psych

Slide 9

Slide 9 text

Psych::Nodes

Slide 10

Slide 10 text

Psych::Nodes::Stream - AST のルートノード - ノードの子ノードは1個以上 && Psych::Nodes::Documentオブジェクトである - `#children` で Array にアクセス出来る https://docs.ruby-lang.org/ja/latest/class/Psych=3a=3aNodes=3a=3aStream.html

Slide 11

Slide 11 text

Psych::Nodes::Document - Psych::Nodes::Stream の子ノード - 1個の子ノードを持つ - 子ノードは以下のいずれかのインスタンス - Psych::Nodes::Sequence - Psych::Nodes::Mapping - Psych::Nodes::Scalar - 唯一の子ノードには `#root` でアクセス出来る https://docs.ruby-lang.org/ja/latest/class/Psych=3a=3aNodes=3a=3aDocument.html

Slide 12

Slide 12 text

Psych::Nodes::Mapping - Rubyで言うところの `Hash` - 0 個以上の子ノードを持つ - 子ノードの個数は偶数である - 子ノードは以下のいずれかのインスタンス - Psych::Nodes::Sequence - Psych::Nodes::Mapping - Psych::Nodes::Scalar - Psych::Nodes::Alias https://docs.ruby-lang.org/ja/latest/class/Psych=3a=3aNodes=3a=3aMapping.html

Slide 13

Slide 13 text

Psych::Nodes::Scalar - ASTの葉ノード #<- これだけでも覚えて帰ってくだ さい - よって、子ノード(children)を持ちません - `#value` でscalarの値にアクセスできる https://docs.ruby-lang.org/ja/latest/class/Psych=3a=3aNodes=3a=3aScalar.html

Slide 14

Slide 14 text

Psych::Nodes::Sequence - Rubyで言うところの `Array` - 0 個以上の子ノードを持つ - 子ノードは以下のいずれかのインスタンス - Psych::Nodes::Sequence - Psych::Nodes::Mapping - Psych::Nodes::Scalar - Psych::Nodes::Alias https://docs.ruby-lang.org/ja/latest/class/Psych=3a=3aNodes=3a=3aSequence.html

Slide 15

Slide 15 text

Psych::Nodes::Alias - ASTの葉ノード - よって、子ノード(children)を持ちません
 - `#anchor` で別の YAML の要素を指す https://docs.ruby-lang.org/ja/latest/class/Psych=3a=3aNodes=3a=3aAlias.html

Slide 16

Slide 16 text

ちょっと詳しく

Slide 17

Slide 17 text

こんなyamlがあったとさ

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

実践編

Slide 22

Slide 22 text

[問題] 重複したkeyを持つyamlファイルの検出 - grepだと階層構造意識できず辛い - `YAML.load_file(‘/sample.yml’)` 時には既に消失 - Hash#mergeと同じで同名keyがある場合は上書かれます - Rubyで検出する方法 is ... ※リッチなIDEとかだとwarning出してくれることを昨日知ったのは話さない

Slide 23

Slide 23 text

[問題] 重複したkeyを持つyamlファイルの検出 - gem 'doorkeeper' に活きがいいyml があったのでそれを使います - ↑ファイルに重複したkeyを仕込みま した - 計: 147行のymlファイル https://gist.github.com/MITSUBOSHI/5085468e763c5cd74854df854f8e4ae8

Slide 24

Slide 24 text

案1 オープンクラス https://gist.github.com/MITSUBOSHI/82840c8bad7a07f722ae241bd7f8e892

Slide 25

Slide 25 text

案1 オープンクラス 解決 https://gist.github.com/MITSUBOSHI/82840c8bad7a07f722ae241bd7f8e892

Slide 26

Slide 26 text

案2 Psych::TreeBuilderの継承 https://gist.github.com/MITSUBOSHI/77e4903e6a6274a30b997488234d535c

Slide 27

Slide 27 text

案2 Psych::TreeBuilderの継承 解決 https://gist.github.com/MITSUBOSHI/77e4903e6a6274a30b997488234d535c

Slide 28

Slide 28 text

案3 ASTから頑張る - `Psych::Handler#end_mapping` (`Psych::TreeBuilder` の継承元クラス)を使った ほうが断然スマートではある - けど、YAMLのAST nodeの理解のためにちょっと頑張ってみる

Slide 29

Slide 29 text

過去(平成時代)の自分への挑戦 - 某何かで重複したmapping keyを持つyamlファイルがあった - すごくイラッとした - YAMLのASTから検出出来るんじゃない?と思って頑張った - 当時 `Psych::Handler#end_mapping` を知らなかった... - 今見ると何をしているのかわからない実装... https://gist.github.com/MITSUBOSHI/ef3e8724715ed094f7737372186e59ed

Slide 30

Slide 30 text

※コードの断片

Slide 31

Slide 31 text

読めない

Slide 32

Slide 32 text

gem ‘yamcha’ なので、今回の登壇を期に作り直して、gemにしました 名前の由来は - Yaml Checker -> やむちぇ -> やむちゃ -> Yamcha(飲茶) ※栽培マンに負けるほど貧弱なgemです https://github.com/MITSUBOSHI/yamcha

Slide 33

Slide 33 text

Yamchaの構成 Yamcha::Validator -> メインで呼び出される Yamcha::Composer -> ASTからhashを組み立てるもの Yamcha::NodeResolver -> AST nodeを上手い感じで隠蔽する なにか (※上手い感じ = 雰囲気)

Slide 34

Slide 34 text

Yamcha::NodeResolver

Slide 35

Slide 35 text

Yamcha::NodeResolver#resolver

Slide 36

Slide 36 text

Yamcha::NodeResolver::Base ※Abstract Class

Slide 37

Slide 37 text

Yamcha::NodeResolver::Mapping

Slide 38

Slide 38 text

Yamcha::NodeResolver::Scalar

Slide 39

Slide 39 text

Yamcha::Composer

Slide 40

Slide 40 text

Yamcha::Composer#recursively_compose

Slide 41

Slide 41 text

Yamcha::Composer

Slide 42

Slide 42 text

Yamcha::Composer#scalar_and_sequence?

Slide 43

Slide 43 text

Yamcha::Composer#scalar_and_mapping?

Slide 44

Slide 44 text

Yamcha::Composer#scalar_and_saclar?

Slide 45

Slide 45 text

Yamcha::Validator

Slide 46

Slide 46 text

Yamcha::Validator::DuplicatedMappingKey

Slide 47

Slide 47 text

Yamcha::Composer#compose_hash

Slide 48

Slide 48 text

案3 ASTから頑張る 解決 https://github.com/MITSUBOSHI/yamcha

Slide 49

Slide 49 text

時間の関係上出来ていないこと(言い訳) - Psych::Nodes::Aliasに未対応 - database.yml等はalias記法用いることが多いと思っているが、mapping keyの 重複しがちなケースは肥大化しがちなi18n系のymlであって... - Psych::Nodes::Scalarを値は文字列のまま - Psych::Nodes::Sequenceの対応雑

Slide 50

Slide 50 text

Psych::Nodes::Sequenceの対応雑 - SequenceのchildrenがMappingであるケースが考慮できていない

Slide 51

Slide 51 text

参考資料 - https://github.com/ruby/psych - https://magazine.rubyist.net/articles/0009/0009-YAML.html 関連の記事(※syckについて) - https://ruby-doc.org/stdlib-2.6.5/libdoc/psych/rdoc/Psych.html - https://docs.ruby-lang.org/ja/latest/library/psych.html - https://www.arp242.net/yaml-config.html

Slide 52

Slide 52 text

Thank you!!

Slide 53

Slide 53 text

時間が余ったら

Slide 54

Slide 54 text

Psych::ScalarScanner - YAMLのScalar型を読み込み、Rubyのbuilt-in型に変換するクラス - gem ‘yamcha’ ではScalar型を文字列のまま放置している実装だった - Psych::Nodes::Nodeを継承するクラスインスンタンスの`#to_ruby` 実行時に呼ば れる - 「このScalar型は最終的にRubyでは何のクラスとして扱われるのか?」を知るのに 便利 & 楽しい https://docs.ruby-lang.org/ja/latest/class/Psych=3a=3aScalarScanner.html

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

https://github.com/ruby/psych/blob/master/lib/psych/scalar_scanner.rb ※コードの断片

Slide 57

Slide 57 text

Thank you again!!