[ruby-core:78214] [Ruby trunk Feature#12960][Third Party's Issue] [psych] new visitor class to generate custom object instead of Hash

From: nobu@...
Date: 2016-11-19 04:02:08 UTC
List: ruby-core #78214
Issue #12960 has been updated by Nobuyoshi Nakada.

Status changed from Open to Third Party's Issue

Please send to the [upstream](https://github.com/ruby/psych).

----------------------------------------
Feature #12960: [psych] new visitor class to generate custom object instead of Hash
https://bugs.ruby-lang.org/issues/12960#change-61579

* Author: makoto kuwata
* Status: Third Party's Issue
* Priority: Normal
* Assignee: 
----------------------------------------
I create a patch to define new useful visitor class for Psych.
It generates custom object as mapping data instead of Hash.

Normally, you must access YAML document data like `ydoc["foo"]["bar"]["baz"]`.
Using this class, you can access data like `ydoc.foo.bar.baz`.

Example1: create custom object instead of Hash according to context

~~~ ruby
    ## define custom classes
    Team   = Struct.new('Team', 'name', 'members')
    Member = Struct.new('Member', 'name', 'gender')
    ## create visitor object
    require 'psych'
    require 'psych/visitors/custom_class'
    classmap = {
      "teams"   => Team,
      "members" => Member,
    }
    visitor = Psych::Visitors::CustomClassVisitor.create(classmap)
    ## example YAML string
    input = <<-'END'
    teams:
      - name: SOS Brigade
        members:
          - {name: Haruhi, gender: F}
          - {name: Kyon,   gender: M}
          - {name: Mikuru, gender: F}
          - {name: Itsuki, gender: M}
          - {name: Yuki,   gender: F}
    END
    ## parse YAML string with creating Team or Member objects according to context
    tree = Psych.parse(input)
    ydoc = visitor.accept(tree)
    p ydoc['teams'][0].class                #=> Struct::Team
    p ydoc['teams'][0]['members'][0].class  #=> Struct::Member
    team = ydoc['teams'][0]
    p team.name                #=> "SOS Brigade"
    p team.members[0].name     #=> "Haruhi"
    p team.members[0].gender   #=> "F"
~~~

Example2: create custom hash object

~~~ ruby
    ## allows `hash.foo` instead of `hash["foo"]`
    class MagicHash < Hash
      def method_missing(method, *args)
        return super unless args.empty?
        return self[method.to_s]
      end
    end
    ## create visitor with MagicHash
    require 'psych'
    require 'psych/visitors/custom_class'
    classmap = {'*' => MagicHash}   # '*' means default class
    visitor = Psych::Visitors::CustomClassVisitor.create(classmap)
    ## example YAML document
    input = <<-'END'
    teams:
      - name: SOS Brigade
        members:
          - {name: Haruhi, gender: F}
          - {name: Kyon,   gender: M}
          - {name: Mikuru, gender: F}
          - {name: Itsuki, gender: M}
          - {name: Yuki,   gender: F}
    END
    ## parse YAML string with creating custom hash object instead of Hash
    tree = Psych.parse(input)
    ydoc = visitor.accept(tree)
    p ydoc.class                            #=> MagicHash
    p ydoc['teams'][0].class                #=> MagicHash
    p ydoc['teams'][0]['members'][0].class  #=> MagicHash
    p ydoc.teams[0].members[0].name    #=> "Haruhi"
    p ydoc.teams[0].members[0].gender  #=> "F"
~~~

I believe this class is very useful, and hope it to be imported into ruby repository.
Let me know your opinion or impression.

---Files--------------------------------
0002-feat-psych-allow-custom-Hash-object-for-unknown-tagg.patch (781 Bytes)
0001-feat-psych-allow-to-generate-custom-Hash-object.patch (2.04 KB)
0003-feat-psych-add-hook-point-for-mapping-key-and-value.patch (2.35 KB)
0004-feat-psych-add-hook-points-for-mapping-like-object.patch (2.7 KB)
0005-feat-psych-add-hook-points-for-merge.patch (1.53 KB)
0006-feat-psych-refactor-hook-point-methods-for-merge.patch (883 Bytes)
0008-feat-psych-support-key-for-default-custom-class.patch (2.38 KB)
0007-feat-psych-define-Psych-Visitors-CustomClassVisitor-.patch (3.14 KB)
0009-feat-psych-add-test-script.patch (2.7 KB)
0010-feat-psych-add-another-test-case.patch (1.74 KB)


-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:[email protected]?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>

In This Thread

Prev Next