0

私は次のことを使用してこの古いコードを持ってSychいます:

yaml_as "tag:yaml.org,2002:#{self}"
def to_yaml(opts = {})
  YAML::quick_emit(self, opts) do |out|
    out.map(taguri, to_yaml_style) do |map|
      map.add('name', name)
      map.add('address', full_address.upcase) if full_address?
    end
  end
end

そのようなものを出力します:

--- !Contact
name: SMOKE OIL
address: |-
  SMOKE OIL
  1 RUE DE LA PAIX
  75002 PARIS
  FRANCE

今、私はその古いコードをアップグレードしています、そうするつもりです、Psych私はドキュメントを読んでしました:

yaml_as "tag:yaml.org,2002:#{self}"
def encode_with(coder)
  coder['name'] = name
  coder['address'] = full_address.upcase if full_address?
end

そしてそれはします:

--- !Contact
name: SMOKE OIL
address: ! "SMOKE OIL\n1 RUE DE LA PAIX\n75002 PARIS\nFRANCE"

これは素晴らしいYAMLですが、whoisサーバーの出力であると想定されており、人間には読みにくいです…</ p>

それで、私はドキュメントに戻って、物事を行う2番目の方法、つまりASTを構築する方法を検討しました。さて、私が何かを見ない限り、あなたが構築したASTを取得し、Psych.dump(obj)が引き続き機能する方法でプラグインする方法を説明するものは何もありません…</ p>

私は(多くの希望なしに)やってみました:

a = Psych::Nodes::Scalar(full_address.upcase)
a.style = Psych::Nodes::LITTERAL
coder['address'] = a if full_address?

しかし、明らかに、それは私が望んでいたことをしませんでした…私も試しました:

def encode_with(coder)
  Psych::Nodes::Mapping.new.tap do |map|
    map.children << Psych::Nodes::Scalar.new("name")
    map.children << Psych::Nodes::Scalar.new(name)
    map.children << Psych::Nodes::Scalar.new("address")
    a = Psych::Nodes::Scalar.new(full_address.upcase)
    a.style = 4
    map.children << a
  end
end

しかし、それをコーダーに接続する方法がわかりませんでした…

また、再帰的なことを行うときは答えが機能する必要があります。これはContactオブジェクトですがDomain、いくつかの連絡先が含まれるものを要求することができ、可能な限り乾燥させたいです:-)

だから、誰もがこれを行う方法についてのヒントを持っていますか?

4

1 に答える 1

1

独自のASTを作成する場合は、を使用できませんPsych.dumpPsych.dumpPsychのデフォルトを使用して独自のASTを作成します。あなたの場合、AST作成プロセスをカスタマイズしたいと思います。

ソースをPsych.dump見るとPsych::Visitors::YAMLTree、ASTを作成するためにを使用していることがわかります。これをサブクラス化し、クラスの処理方法をカスタマイズしてContact、必要な出力を取得できます。accept特に、メソッドをオーバーライドする必要があります。

Contactこれは、クラスの特殊なケースである簡単な例です。

class MyYAMLTree < Psych::Visitors::YAMLTree
  def accept target
    return super unless target.is_a? Contact

    @emitter.start_mapping(nil, "tag:yaml.org,2002:#{target.class}", false, Psych::Nodes::Mapping::BLOCK)

    @emitter.scalar 'name', nil, nil, true, false, Psych::Nodes::Scalar::ANY
    @emitter.scalar target.name, nil, nil, true, false, Psych::Nodes::Scalar::ANY

    @emitter.scalar 'address', nil, nil, true, false, Psych::Nodes::Scalar::ANY

    #this is the where we make the address string a literal
    @emitter.scalar target.full_address, nil, nil, true, false, Psych::Nodes::Scalar::LITERAL

    @emitter.end_mapping
  end
end

Psych::Visitors::YAMLTreeを呼び出すのはクラスであることに注意してencode_withください。これにより、クラスでそれが完全にバイパスされます。

これを使用するには、次のようなものを使用します(これは、基本的にPsych.dumpMyYAMLTreeを使用する単純化されたバージョンです)。

def my_yaml o
  visitor = MyYAMLTree.new
  visitor << o
  visitor.tree.yaml
end

これは明らかに単純な例ですが、うまくいけば、正しい方向を示すことができます。

于 2012-09-30T20:33:07.533 に答える