Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Good to know yaml

MITSUMITSU
December 14, 2019

Good to know yaml

MITSUMITSU

December 14, 2019
Tweet

More Decks by MITSUMITSU

Other Decks in Technology

Transcript

  1. Good to know yaml

    View Slide

  2. self.introduction.to_yaml

    View Slide

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

    View Slide

  4. 基本編

    View Slide

  5. YAMLとPsych

    View Slide

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

    View Slide

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

    View Slide

  8. 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

    View Slide

  9. Psych::Nodes

    View Slide

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

    View Slide

  11. 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

    View Slide

  12. 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

    View Slide

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

    View Slide

  14. 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

    View Slide

  15. Psych::Nodes::Alias
    - ASTの葉ノード
    - よって、子ノード(children)を持ちません

    - `#anchor` で別の YAML の要素を指す
    https://docs.ruby-lang.org/ja/latest/class/Psych=3a=3aNodes=3a=3aAlias.html

    View Slide

  16. ちょっと詳しく

    View Slide

  17. こんなyamlがあったとさ

    View Slide

  18. View Slide

  19. View Slide

  20. View Slide

  21. 実践編

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  30. ※コードの断片

    View Slide

  31. 読めない

    View Slide

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

    View Slide

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

    View Slide

  34. Yamcha::NodeResolver

    View Slide

  35. Yamcha::NodeResolver#resolver

    View Slide

  36. Yamcha::NodeResolver::Base
    ※Abstract Class

    View Slide

  37. Yamcha::NodeResolver::Mapping

    View Slide

  38. Yamcha::NodeResolver::Scalar

    View Slide

  39. Yamcha::Composer

    View Slide

  40. Yamcha::Composer#recursively_compose

    View Slide

  41. Yamcha::Composer

    View Slide

  42. Yamcha::Composer#scalar_and_sequence?

    View Slide

  43. Yamcha::Composer#scalar_and_mapping?

    View Slide

  44. Yamcha::Composer#scalar_and_saclar?

    View Slide

  45. Yamcha::Validator

    View Slide

  46. Yamcha::Validator::DuplicatedMappingKey

    View Slide

  47. Yamcha::Composer#compose_hash

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  51. 参考資料
    - 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

    View Slide

  52. Thank you!!

    View Slide

  53. 時間が余ったら

    View Slide

  54. 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

    View Slide

  55. View Slide

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

    View Slide

  57. Thank you again!!

    View Slide