-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
attempt to add serializable annotations
- Loading branch information
1 parent
3eea07d
commit 0991900
Showing
6 changed files
with
295 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
require "../spec_helper" | ||
|
||
class TestChild | ||
include KDL::Serializable | ||
|
||
@[KDL::Argument] | ||
property value : String | ||
|
||
def initialize(@value) | ||
end | ||
end | ||
|
||
class TestNode | ||
include KDL::Serializable | ||
|
||
@[KDL::Argument] | ||
property first : String | ||
|
||
@[KDL::Argument] | ||
property second : Bool | ||
|
||
@[KDL::Arguments] | ||
property numbers : Array(UInt32) | ||
|
||
@[KDL::Property] | ||
property foo : String | ||
|
||
@[KDL::Property(name: "bardle")] | ||
property bar : String | ||
|
||
@[KDL::Properties] | ||
property map : Hash(String, String) | ||
|
||
@[KDL::Child(unwrap: "argument")] | ||
property arg : String | ||
|
||
@[KDL::Child(unwrap: "arguments")] | ||
property args : Array(String) | ||
|
||
@[KDL::Child(unwrap: "properties")] | ||
property props : Hash(String, String) | ||
|
||
@[KDL::Child] | ||
property norf : TestChild | ||
|
||
@[KDL::Children(name: "thing")] | ||
property things : Array(TestChild) | ||
|
||
def initialize(@first, @second, @numbers, @foo, @bar, @map, @arg, @args, @props, @norf, @things) | ||
end | ||
end | ||
|
||
class TestDocument | ||
include KDL::Serializable | ||
|
||
@[KDL::Child] | ||
property node : TestNode | ||
|
||
def initialize(@node) | ||
end | ||
end | ||
|
||
describe KDL::Serializable do | ||
it "serializes documents" do | ||
doc = KDL.parse <<-KDL | ||
node "arg1" #true 1 22 33 foo="a" bardle="b" baz="c" qux="d" { | ||
arg "arg2" | ||
args "x" "y" "z" | ||
props a="x" b="y" c="z" | ||
norf "wat" | ||
thing "foo" | ||
thing "bar" | ||
thing "baz" | ||
} | ||
KDL | ||
|
||
obj = TestDocument.from_kdl(doc) | ||
obj.node.first.should eq "arg1" | ||
obj.node.second.should eq true | ||
obj.node.numbers.should eq [1, 22, 333] | ||
obj.node.foo.should eq "a" | ||
obj.node.bar.should eq "b" | ||
obj.node.map.should eq({ "baz": "c", "qux": "d" }) | ||
obj.node.arg.should eq "arg2" | ||
obj.node.args.should eq ["x", "y", "z"] | ||
obj.node.props.should eq({ "a": "x", "b": "y", "c": "z" }) | ||
obj.node.norf.value.should eq "wat" | ||
obj.node.things.size.should eq 3 | ||
obj.node.things[0].value.should eq "foo" | ||
obj.node.things[1].value.should eq "bar" | ||
obj.node.things[2].value.should eq "baz" | ||
|
||
obj.to_kdl.should eq doc | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
module KDL | ||
annotation Argument; end | ||
annotation Arguments; end | ||
annotation Property; end | ||
annotation Properties; end | ||
annotation Child; end | ||
annotation Children; end | ||
|
||
module Serializable | ||
macro included | ||
def self.new(node : ::KDL::Node) | ||
new_from_kdl_node(node) | ||
end | ||
|
||
def self.new(doc : ::KDL::Document) | ||
new_from_kdl_node(::KDL::Node.new("__root", children: doc)) | ||
end | ||
|
||
private def self.new_from_kdl_node(node : ::KDL::Node) | ||
instance = allocate | ||
instance.initialize(__node_for_kdl_serializable: node) | ||
::GC.add_finalizer(instance) if instance.responds_to?(:finalize) | ||
instance | ||
end | ||
|
||
macro inherited | ||
def self.new(doc : ::KDL::Document) | ||
new_from_kdl_document(doc) | ||
end | ||
end | ||
end | ||
|
||
def initialize(*, __node_for_kdl_serializable node : ::KDL::Node) | ||
{% begin %} | ||
{% argument_annos = [] of Nil %} | ||
{% arguments_anno = nil %} | ||
{% property_annos = {} of Nil => Nil %} | ||
{% properties_anno = nil %} | ||
{% child_annos = {} of Nil => Nil %} | ||
{% children_annos = {} of Nil => Nil %} | ||
{% other_properties = {} of Nil => Nil %} | ||
|
||
{% for ivar in @type.instance_vars %} | ||
{% if ann = ivar.annotation(::KDL::Argument) %} | ||
{% unless ann[:ignore] || ann[:ignore_deserialize] %} | ||
{% | ||
argument_annos << { | ||
id: ivar.id, | ||
has_default: ivar.has_default_value?, | ||
default: ivar.default_value, | ||
nilable: ivar.type.nilable?, | ||
type: ivar.type, | ||
converter: ann[:converter], | ||
presence: ann[:presence] | ||
} | ||
%} | ||
{% end %} | ||
{% elsif ann = ivar.annotation(::KDL::Arguments) %} | ||
{% unless ann[:ignore] || ann[:ignore_deserialize] %} | ||
{% | ||
arguments_anno = { | ||
id: ivar.id, | ||
has_default: ivar.has_default_value?, | ||
default: ivar.default_value, | ||
nilable: ivar.type.nilable?, | ||
type: ivar.type, | ||
converter: ann[:converter], | ||
presence: ann[:presence] | ||
} | ||
%} | ||
{% end %} | ||
{% elsif ann = ivar.annotation(::KDL::Property) %} | ||
{% unless ann[:ignore] || ann[:ignore_deserialize] %} | ||
{% | ||
property_annos[ivar.id] = { | ||
key: (ann[:key] || ivar).id.stringify, | ||
has_default: ivar.has_default_value?, | ||
default: ivar.default_value, | ||
nilable: ivar.type.nilable?, | ||
type: ivar.type, | ||
converter: ann[:converter], | ||
presence: ann[:presence] | ||
} | ||
%} | ||
{% end %} | ||
{% elsif ann = ivar.annotation(::KDL::Properties) %} | ||
{% unless ann[:ignore] || ann[:ignore_deserialize] %} | ||
{% | ||
properties_anno = { | ||
id: ivar.id, | ||
has_default: ivar.has_default_value?, | ||
default: ivar.default_value, | ||
nilable: ivar.type.nilable?, | ||
type: ivar.type, | ||
converter: ann[:converter], | ||
presence: ann[:presence] | ||
} | ||
%} | ||
{% end %} | ||
{% elsif ann = ivar.annotation(::KDL::Child) %} | ||
{% unless ann[:ignore] || ann[:ignore_deserialize] %} | ||
{% | ||
child_annos[ivar.id] = { | ||
key: (ann[:key] || ivar).id.stringify, | ||
has_default: ivar.has_default_value?, | ||
default: ivar.default_value, | ||
nilable: ivar.type.nilable?, | ||
type: ivar.type, | ||
converter: ann[:converter], | ||
presence: ann[:presence], | ||
unwrap: ann[:unwrap] | ||
} | ||
%} | ||
{% end %} | ||
{% elsif ann = ivar.annotation(::KDL::Children) %} | ||
{% unless ann[:ignore] || ann[:ignore_deserialize] %} | ||
{% | ||
children_annos[ivar.id] = { | ||
key: (ann[:key] || ivar).id.stringify, | ||
has_default: ivar.has_default_value?, | ||
default: ivar.default_value, | ||
nilable: ivar.type.nilable?, | ||
type: ivar.type, | ||
converter: ann[:converter], | ||
presence: ann[:presence] | ||
} | ||
%} | ||
{% end %} | ||
{% else %} | ||
{% | ||
other_children[ivar.id] = { | ||
key: ivar.id.stringify, | ||
has_default: ivar.has_default_value?, | ||
default: ivar.default_value, | ||
nilable: ivar.type.nilable?, | ||
type: ivar.type | ||
} | ||
%} | ||
{% end %} | ||
{% end %} | ||
|
||
{% for value, index in argument_annos %} | ||
%var{value[:id]} = node[{{index}}] | ||
%found{value[:id]} = true | ||
{% end %} | ||
{% if arguments_anno %} | ||
%var{arguments_anno[:id]} = node.arguments[{{argument_annos.size}}..].map(&.value) | ||
%found{arguments_anno[:id]} = true | ||
{% end %} | ||
found_props = [] of String | ||
{% for name, value in property_annos %} | ||
%var{name} = node[{{name.stringify}}] | ||
%found{name} = true | ||
found_props << {{name.stringify}} | ||
{% end %} | ||
{% if properties_anno %} | ||
%var{properties_anno[:id]} = node.properties.reject(found_props) | ||
%found{properties_anno[:id]} = true | ||
{% end %} | ||
{% for name, value in child_annos %} | ||
{% if value[:unwrap] == "argument" %} | ||
%var{name} = node.arg({{name.stringify}}) | ||
{% elsif value[:unwrap] == "arguments" %} | ||
%var{name} = node.args({{name.stringify}}) | ||
{% elsif value[:unwrap] == "properties" %} | ||
%var{name} = node.child({{name.stringify}}).properties.transform_values { |v, _| v.value } | ||
{% else %} | ||
%var{name} = {{value[:type]}}.from_kdl(node.child({{name.stringify}})) | ||
{% end %} | ||
%found{name} = true | ||
{% end %} | ||
{% for name, value in children_annos %} | ||
%var{name} = node.children.select { |n| n.name == {{name.stringify}} }.map { |n| {{value[:type]}}.from_kdl(n) } | ||
%found{name} = true | ||
{% end %} | ||
{% end %} | ||
end | ||
end | ||
end | ||
|
||
def Object.from_kdl(doc) | ||
new doc | ||
end |