2013-08-12 3 views
3

Hash의 하위 클래스 인 클래스 Foo이 있습니다.Ruby YAML에서 해시 하위 클래스를 간단한 해시로 덤프하는 방법은 무엇입니까?

class Foo < Hash 
    # whatever Foo-specific methods/etc 
end 

YAML을 사용하여 파일에 덤프 할 때 클래스를 나타내는 태그가 작성됩니다.

> f = Foo.new 
> f[:bar] = "baz" 
> puts YAML.dump(f) 
--- !ruby/hash:Foo 
:bar: baz 

내 데이터의 소비자에 대한 Foo을 알 필요가 없습니다 있도록이 그냥 평범한 오래된 해시 (하지 !ruby/hash:Foo)

> puts YAML.dump({bar:"baz"}) 
--- 
:bar: baz 

과 같이 쓸 수 싶습니다. 직렬화를 위해 자체 클래스로 변환하는 마법 클래스를 추가하거나 마법 옵션을 YAML.dump로 전달하는 마법 메서드가 있습니까?

물론 하나의 Foo 개체를 해시로 변환하는 것은 쉽지만 실제로 덤프 할 실제 해시 내부의 모든 수준에 중첩되어 표시 될 수 있습니다. 검색을 수행하지 않아도됩니다. 바꾸다.

+0

당신이 예제 코드, 당신이보고 싶은 방법을 보여주는 문제와 예제 출력을 보여줍니다 예를 들어, YAML 출력을 보여 주면 그것은 도움을 것입니다. http://sscce.org/ –

+0

@theTinMan의 "e"부분을보십시오 - done – sosiouxme

답변

3

encode_withrepresent_map 방법을 사용하면이 문제를 해결할 수 있습니다. 객체의 YAML 직렬화를 사용자 정의하려면 coder 객체를 받아들이는 encode_with 메소드를 제공하고 그 중 하나는 represent_map입니다.

class Foo < Hash 

    # other methods ... 

    def encode_with coder 
    coder.represent_map nil, self 
    end 

end 

이제 YAML.dump은 개체를 일반 해시로 출력합니다. 이 장애의 원인이 될 수 있고, only fixed in the latest Gem version of Psych 인 것이다 버그가 있기 때문에

그러나

약간의 문제가있다. 이 아니고 현재 최신 Ruby 버전 (ruby 2.0.0p247)으로 수정되었습니다.이 아닙니다. 그것 is fixed in Ruby trunk 그래서 나중에 패치 릴리스 괜찮을해야합니다.

이것을 사용하려면 Ruby에 번들로 제공되는 버전이 아닌 최신 Psych Gem을 사용해야합니다. Yaml이 필요하기 전에 이것은

gem 'psych', '2.0.0' 

으로 쉬워야하지만 Ruby 2.0에서는 이것이 알 수없는 몇 가지 이유 때문에 작동하지 않는 것으로 보입니다. Bundler를 사용하여 Gem 버전을 지정하면 작동하지만 Gemfile을 작성하고 Psych를 지정해야 할 수도 있습니다. 및 교체

+0

이것은 아마도 옳은 대답 일 것입니다. 지금은 루비 1.9.3 코드베이스에서 제가 필요하다고 생각합니다. 검색 및 교체를 구현하십시오. – sosiouxme

0

검색은 실제로 너무 나쁘지 않았다 :

# Convert Hash/Array subclasses into plain hashes/arrays for YAML dump. 
# Assumptions: 
# Hash keys will be simple objects - don't need to clear them 
# No custom objects containing Hash/Array subclass instances 
def deep_clear_subclasses(obj, dedup = {}) 
    case obj 
    when Hash 
    return dedup[obj] if dedup.has_key? obj 
    dedup[obj] = copy = {} 
    obj.each {|k,v| copy[k] = deep_clear_subclasses(v, dedup)} 
    copy 
    when Array 
    return dedup[obj] if dedup.has_key? obj 
    obj.inject(dedup[obj] = []) {|a,v| a << deep_clear_subclasses(v,dedup)} 
    else 
    obj # not going to operate on other kinds of objects 
    end 
end 
관련 문제