心理医生说:“在中级阶段正在建立AST…",但是,究竟如何呢? [英] Psych doc says «At the mid level is building an AST…» but, how exactly?

查看:128
本文介绍了心理医生说:“在中级阶段正在建立AST…",但是,究竟如何呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用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,因此,我阅读了文档并做了:

Now, I'm upgrading that old code, going to Psych so, I read the doc and did :

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服务器的输出,而且人类对它的可读性也较低……

It's nice YAML but, it's supposed to be the output of a whois server, and it's way less readable by humans…

因此,我回到文档上来,研究了第二种处理方式,即构建AST.现在,除非我没看到任何东西,否则没有任何东西可以向您说明如何使用您构建的AST,并以Psych.dump(obj)仍能正常工作的方式将其插入…

So, I went back to the doc, and looked at the second way of doing things, that is, building an AST. Now, unless I'm not seeing something, nothing explains you how to take the AST you built, and plug it in a way Psych.dump(obj) would still work…

我尝试做(没有太大希望):

I tried doing (without much hope) :

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

但是,显然,它没有实现我希望的那样……我也尝试过:

but, obviously, it did not do what I hoped it'd do… I also tried :

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

但是,我看不到如何将其插入编码器中……

But, I could not see how to plug it into the coder…

此外,做递归操作时答案需要起作用,这是一个Contact对象,但是人们可以要求一个包含几个联系人的Domain,我希望它尽可能地干:-)

Also, the answer needs to work when doing recursive things, this is a Contact objet, but one can ask for a Domain which will contain a few contacts and I want it as DRY as possible :-)

那么,任何人都有关于如何执行此操作的提示吗?

So, anyone has a hint on how to do this ?

推荐答案

如果要创建自己的AST,则不能使用Psych.dump. Psych.dump使用Psych默认值创建自己的AST.在您的情况下,您想自定义AST创建过程.

If you want to create your own AST then you can’t use Psych.dump. Psych.dump creates its own AST using the Psych defaults. In your case you want to customise the AST creation process.

查看Psych.dump来源您会看到它使用了 Psych::Visitors::YAMLTree 创建AST.您可以将此子类化,并自定义其处理Contact类的方式以获取所需的输出.特别是,您需要覆盖 方法.

Looking at the source of Psych.dump you can see it uses a Psych::Visitors::YAMLTree to create the AST. You can subclass this and customise how it handles your Contact class to get the output you want. In particular you need to override the accept method.

这是一个简单的示例,其中只是Contact类的特殊情况:

Here’s a simple example that just special cases the Contact class:

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

请注意,调用encode_with的是Psych::Visitors::YAMLTree类,这将在您的课程中完全绕开它.

Note that it’s the Psych::Visitors::YAMLTree class that calls encode_with, this will bypass it altogether for your class.

要使用此功能,请使用类似的东西(这基本上是使用MyYAMLTree的Psych.dump的简化版本):

In order to use this, use something like (this is basically a simplified version of Psych.dump using MyYAMLTree):

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

这显然只是一个简单的示例,但希望它将为您指明正确的方向.

This is obviously just a simple example, but hopefully it’ll point you in the right direction.

这篇关于心理医生说:“在中级阶段正在建立AST…",但是,究竟如何呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆