[ruby-core:78213] [Ruby trunk Feature#12960] [psych] new visitor class to generate custom object instead of Hash
From:
kwa@...
Date:
2016-11-19 03:54:48 UTC
List:
ruby-core #78213
Issue #12960 has been updated by makoto kuwata.
File 0010-feat-psych-add-another-test-case.patch added
----------------------------------------
Feature #12960: [psych] new visitor class to generate custom object instead of Hash
https://bugs.ruby-lang.org/issues/12960#change-61578
* Author: makoto kuwata
* Status: Open
* 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>