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

Good to know yaml

66342ecb106aed81b83d9fb608d73c92?s=47 MITSUMITSU
December 14, 2019

Good to know yaml

66342ecb106aed81b83d9fb608d73c92?s=128

MITSUMITSU

December 14, 2019
Tweet

Transcript

  1. Good to know yaml

  2. self.introduction.to_yaml

  3. 今日話すこと/話さないこと 今日話すこと - YAMLのAST周り (※ざっくり) - 実世界でYAMLのASTを理解して解決できる問題とは 今日話さないこと - syckについて

    - Psych::Nodes以外はあまり触れない - yamlの詳細な仕様について - JSONとの規格の違い
  4. 基本編

  5. YAMLとPsych

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

  7. yamlとは (簡潔に & ほぼ「るびま」からコピペ) - 構造化されたデータを表現するためのフォーマット - YAMLでは主に次の 3 つの組み合わせでデータを表現する

    - Sequence: Rubyで言うと `Array` - Mapping: Rubyで言うと `Hash` - Scalar: (文字列、数値、真偽値など ) https://magazine.rubyist.net/articles/0009/0009-YAML.html
  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
  9. Psych::Nodes

  10. Psych::Nodes::Stream - AST のルートノード - ノードの子ノードは1個以上 && Psych::Nodes::Documentオブジェクトである - `#children`

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

    でscalarの値にアクセスできる https://docs.ruby-lang.org/ja/latest/class/Psych=3a=3aNodes=3a=3aScalar.html
  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
  15. Psych::Nodes::Alias - ASTの葉ノード - よって、子ノード(children)を持ちません
 - `#anchor` で別の YAML の要素を指す

    https://docs.ruby-lang.org/ja/latest/class/Psych=3a=3aNodes=3a=3aAlias.html
  16. ちょっと詳しく

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

  18. None
  19. None
  20. None
  21. 実践編

  22. [問題] 重複したkeyを持つyamlファイルの検出 - grepだと階層構造意識できず辛い - `YAML.load_file(‘/sample.yml’)` 時には既に消失 - Hash#mergeと同じで同名keyがある場合は上書かれます -

    Rubyで検出する方法 is ... ※リッチなIDEとかだとwarning出してくれることを昨日知ったのは話さない
  23. [問題] 重複したkeyを持つyamlファイルの検出 - gem 'doorkeeper' に活きがいいyml があったのでそれを使います - ↑ファイルに重複したkeyを仕込みま した

    - 計: 147行のymlファイル https://gist.github.com/MITSUBOSHI/5085468e763c5cd74854df854f8e4ae8
  24. 案1 オープンクラス https://gist.github.com/MITSUBOSHI/82840c8bad7a07f722ae241bd7f8e892

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

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

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

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

  29. 過去(平成時代)の自分への挑戦 - 某何かで重複したmapping keyを持つyamlファイルがあった - すごくイラッとした - YAMLのASTから検出出来るんじゃない?と思って頑張った - 当時

    `Psych::Handler#end_mapping` を知らなかった... - 今見ると何をしているのかわからない実装... https://gist.github.com/MITSUBOSHI/ef3e8724715ed094f7737372186e59ed
  30. ※コードの断片

  31. 読めない

  32. gem ‘yamcha’ なので、今回の登壇を期に作り直して、gemにしました 名前の由来は - Yaml Checker -> やむちぇ ->

    やむちゃ -> Yamcha(飲茶) ※栽培マンに負けるほど貧弱なgemです https://github.com/MITSUBOSHI/yamcha
  33. Yamchaの構成 Yamcha::Validator -> メインで呼び出される Yamcha::Composer -> ASTからhashを組み立てるもの Yamcha::NodeResolver -> AST

    nodeを上手い感じで隠蔽する なにか (※上手い感じ = 雰囲気)
  34. Yamcha::NodeResolver

  35. Yamcha::NodeResolver#resolver

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

  37. Yamcha::NodeResolver::Mapping

  38. Yamcha::NodeResolver::Scalar

  39. Yamcha::Composer

  40. Yamcha::Composer#recursively_compose

  41. Yamcha::Composer

  42. Yamcha::Composer#scalar_and_sequence?

  43. Yamcha::Composer#scalar_and_mapping?

  44. Yamcha::Composer#scalar_and_saclar?

  45. Yamcha::Validator

  46. Yamcha::Validator::DuplicatedMappingKey

  47. Yamcha::Composer#compose_hash

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

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

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

  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
  52. Thank you!!

  53. 時間が余ったら

  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
  55. None
  56. https://github.com/ruby/psych/blob/master/lib/psych/scalar_scanner.rb ※コードの断片

  57. Thank you again!!