roundtrip_xml 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/roundtrip_xml.rb +4 -0
- data/lib/roundtrip_xml/base_cleanroom.rb +4 -11
- data/lib/roundtrip_xml/dsl_runtime.rb +133 -6
- data/lib/roundtrip_xml/extractor.rb +81 -0
- data/lib/roundtrip_xml/plain_accessors.rb +10 -6
- data/lib/roundtrip_xml/roxml_builder.rb +6 -19
- data/lib/roundtrip_xml/roxml_subclass_helpers.rb +11 -0
- data/lib/roundtrip_xml/sexp_dsl_builder.rb +108 -0
- data/lib/roundtrip_xml/utils.rb +53 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b5d0171291e731011fc69e726421dc68b3ceb039
|
4
|
+
data.tar.gz: 1aaaa7152a29b616cbfd7e43b003ccf1b625ffa9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de71838561d98d183d2e83b2a0311cd3db0c66f89911771ba8ea90a954b9d9ad7d6aa97e14cfd8b5aac6a78a4f5f34c13b56e7825aebac5496f866c63fb6a42a
|
7
|
+
data.tar.gz: bf4e7a4d49cccafad9ec1c21a4953bd9ccc9dd7b5eca652b8cdb65daecc0b04deafbcf3b5aa18000fa7342c0dc2babcf28a33ab45db1bfc6685471de0f5e24b3
|
data/lib/roundtrip_xml.rb
CHANGED
@@ -4,3 +4,7 @@ require './lib/roundtrip_xml/base_cleanroom'
|
|
4
4
|
require './lib/roundtrip_xml/root_cleanroom'
|
5
5
|
require './lib/roundtrip_xml/roxml_builder'
|
6
6
|
require './lib/roundtrip_xml/plain_accessors'
|
7
|
+
require './lib/roundtrip_xml/utils'
|
8
|
+
require './lib/roundtrip_xml/extractor'
|
9
|
+
require './lib/roundtrip_xml/roxml_subclass_helpers'
|
10
|
+
require './lib/roundtrip_xml/sexp_dsl_builder'
|
@@ -53,27 +53,20 @@ class BaseCleanroom
|
|
53
53
|
plain_accessors = @el.class.plain_accessors
|
54
54
|
hash = {}
|
55
55
|
@value_holder ||= {}
|
56
|
-
|
57
|
-
hash = plain_accessors.inject({}) {|h, a| h[a] = @el.send(a); h}
|
58
|
-
end
|
56
|
+
hash = plain_accessors.inject({}) {|h, a| h[a] = @el.send(a); h}
|
59
57
|
child = @runtime.create_cleanroom(clazz)
|
60
58
|
child.inherit_properties @value_holder.merge(hash)
|
61
|
-
|
59
|
+
|
62
60
|
child.evaluate &block
|
63
61
|
child.evaluate &child.get_el.process if child.get_el.respond_to? :process
|
64
|
-
|
65
|
-
# child.evaluate &child.get_el.class.proc if child.respond_to? :proc
|
62
|
+
|
66
63
|
child.get_el
|
67
64
|
end
|
68
65
|
|
69
66
|
def inherit_properties(props)
|
70
67
|
@value_holder = props
|
71
68
|
props.each do |name, val|
|
72
|
-
|
73
|
-
# @value_holder.send("#{arg}=".to_sym, value_holder.send(arg))
|
74
|
-
# create_method(arg) do
|
75
|
-
# @value_holder.send(arg)
|
76
|
-
# end
|
69
|
+
|
77
70
|
self.class.send(:attr_reader, name)
|
78
71
|
self.instance_variable_set("@#{name}".to_sym, val)
|
79
72
|
self.class.send(:expose, name)
|
@@ -3,26 +3,44 @@ require 'nokogiri'
|
|
3
3
|
require 'roundtrip_xml/roxml_builder'
|
4
4
|
require 'roundtrip_xml/root_cleanroom'
|
5
5
|
require 'roundtrip_xml/base_cleanroom'
|
6
|
+
require 'roundtrip_xml/utils'
|
7
|
+
require 'roundtrip_xml/sexp_dsl_builder'
|
8
|
+
require 'tree'
|
9
|
+
require 'set'
|
6
10
|
# Class which evaluates DSL and read XML files to populate the namespace with classes
|
7
11
|
class DslRuntime
|
12
|
+
include Utils
|
8
13
|
def initialize()
|
9
14
|
@classes = {}
|
15
|
+
@root_classes = Set.new
|
10
16
|
end
|
11
|
-
def populate(files)
|
12
|
-
files.
|
17
|
+
def populate(files, root_method=nil)
|
18
|
+
files.map {|f| populate_from_file f, root_method }
|
13
19
|
end
|
14
20
|
|
15
|
-
def populate_from_file (file)
|
16
|
-
populate_raw File.read(file)
|
21
|
+
def populate_from_file (file, root_method=nil)
|
22
|
+
populate_raw File.read(file), root_method
|
17
23
|
|
18
24
|
end
|
19
25
|
|
20
|
-
def populate_raw (raw)
|
26
|
+
def populate_raw (raw, root_method = nil)
|
21
27
|
builder = RoxmlBuilder.new (Nokogiri::XML(raw).root), @classes
|
22
28
|
new_classes = builder.build_classes
|
29
|
+
@root_classes << builder.root_class_name
|
23
30
|
@classes.merge! new_classes
|
24
|
-
|
31
|
+
if root_method
|
32
|
+
roxml_root = fetch(builder.root_class_name).from_xml raw
|
33
|
+
|
34
|
+
extractor = Extractor.new roxml_root.send(root_method), self
|
25
35
|
|
36
|
+
new_objs = extractor.convert_roxml_objs
|
37
|
+
subclasses = extractor.subclasses
|
38
|
+
roxml_root.send("#{root_method}=", new_objs)
|
39
|
+
builder = SexpDslBuilder.new [roxml_root], subclasses, self
|
40
|
+
|
41
|
+
builder.write_roxml_objs
|
42
|
+
end
|
43
|
+
end
|
26
44
|
|
27
45
|
def fetch(class_name)
|
28
46
|
@classes[class_name]
|
@@ -47,7 +65,116 @@ class DslRuntime
|
|
47
65
|
def fetch_cleanroom(root_class)
|
48
66
|
BaseCleanroom.new(fetch(root_class).new, self)
|
49
67
|
end
|
68
|
+
|
50
69
|
def create_cleanroom(root_class)
|
51
70
|
BaseCleanroom.new(root_class.new, self)
|
52
71
|
end
|
72
|
+
|
73
|
+
def marshal_dump
|
74
|
+
classes = @classes.inject({}) do |hash, (name, clazz)|
|
75
|
+
hash[name] = {xml_name: clazz.tag_name }
|
76
|
+
hash[name][:attrs] = clazz.roxml_attrs.map do |accessor|
|
77
|
+
type = accessor.sought_type.class == Class ?
|
78
|
+
accessor.sought_type.class_name : accessor.sought_type
|
79
|
+
from = accessor.sought_type == :attr ? "@#{accessor.name}" : accessor.name
|
80
|
+
{
|
81
|
+
name: accessor.accessor,
|
82
|
+
opts: {
|
83
|
+
as: accessor.array? ? [type] : type,
|
84
|
+
from: from
|
85
|
+
}
|
86
|
+
}
|
87
|
+
end
|
88
|
+
hash
|
89
|
+
end
|
90
|
+
|
91
|
+
{
|
92
|
+
root_classes: @root_classes,
|
93
|
+
classes: classes
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
def deserialize_class(node, config)
|
98
|
+
clazz = fetch(node.name) || new_roxml_class(config[:xml_name])
|
99
|
+
config[:attrs].each do |attr|
|
100
|
+
type_is_parent = node.parentage && node.parentage.any? {|n| n.name == attr[:opts][:as]}
|
101
|
+
if type_is_parent
|
102
|
+
add_unprocessed_attr attr, clazz
|
103
|
+
else
|
104
|
+
clazz.xml_accessor attr[:name], transform_accessor_opts(attr[:opts])
|
105
|
+
end
|
106
|
+
end
|
107
|
+
clazz
|
108
|
+
end
|
109
|
+
|
110
|
+
def add_unprocessed_attr(attr_config, clazz)
|
111
|
+
@unprocessed_attrs ||= []
|
112
|
+
@unprocessed_attrs << AttrJob.new(attr_config, clazz)
|
113
|
+
end
|
114
|
+
|
115
|
+
def transform_accessor_opts(opts)
|
116
|
+
attr_type = opts[:as]
|
117
|
+
is_array = attr_type.class == Array
|
118
|
+
type = is_array ? attr_type.first : attr_type
|
119
|
+
if is_array
|
120
|
+
opts[:as] = [fetch(type)]
|
121
|
+
else
|
122
|
+
opts[:as] = fetch type
|
123
|
+
end
|
124
|
+
opts
|
125
|
+
end
|
126
|
+
|
127
|
+
def marshal_load(data)
|
128
|
+
initialize
|
129
|
+
@root_classes.merge data[:root_classes]
|
130
|
+
trees = @root_classes.map {|clazz| hash_to_tree data[:classes], clazz}
|
131
|
+
trees.each do |tree|
|
132
|
+
tree.postordered_each do |node|
|
133
|
+
@classes[node.name] = deserialize_class(node, node.content)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
@unprocessed_attrs.each do |job|
|
137
|
+
clazz = job.class
|
138
|
+
config = job.config
|
139
|
+
clazz.xml_accessor config[:name], transform_accessor_opts(config[:opts])
|
140
|
+
end if @unprocessed_attrs
|
141
|
+
end
|
142
|
+
|
143
|
+
def hash_to_tree(hash, root_name, processed = [])
|
144
|
+
node = Tree::TreeNode.new(root_name, hash[root_name])
|
145
|
+
processed << root_name
|
146
|
+
children = child_classes(hash, hash[root_name])
|
147
|
+
children.each do |name|
|
148
|
+
node << hash_to_tree(hash, name, processed) unless processed.include? name
|
149
|
+
end
|
150
|
+
node
|
151
|
+
end
|
152
|
+
|
153
|
+
def child_classes(hash, config)
|
154
|
+
config[:attrs].map do |attr|
|
155
|
+
attr_type = attr[:opts][:as]
|
156
|
+
type = attr_type.class == Array ? attr_type.first : attr_type
|
157
|
+
type if hash.key? type
|
158
|
+
end.compact
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
def serialize(path)
|
163
|
+
file = File.new path, 'w'
|
164
|
+
Marshal.dump self, file
|
165
|
+
file.close
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.load(path)
|
169
|
+
file = File.open path, 'r'
|
170
|
+
Marshal.load file
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
class AttrJob
|
175
|
+
attr_accessor :class, :config
|
176
|
+
def initialize(config, clazz)
|
177
|
+
self.config = config
|
178
|
+
self.class = clazz
|
179
|
+
end
|
53
180
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'roxml'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'roundtrip_xml/utils'
|
4
|
+
require 'hashdiff'
|
5
|
+
require 'set'
|
6
|
+
require 'roundtrip_xml/utils'
|
7
|
+
require 'multiset'
|
8
|
+
require 'roundtrip_xml/roxml_subclass_helpers.rb'
|
9
|
+
|
10
|
+
class Extractor
|
11
|
+
include Utils
|
12
|
+
attr_reader :subclasses
|
13
|
+
def initialize(roxml_objs, runtime)
|
14
|
+
@roxml_objs = roxml_objs
|
15
|
+
@hashes = @roxml_objs.map { |obj| obj.to_hash }
|
16
|
+
@runtime = runtime
|
17
|
+
@subclass_names = Multiset.new
|
18
|
+
@subclasses = []
|
19
|
+
end
|
20
|
+
def list_diffs
|
21
|
+
|
22
|
+
HashDiff.best_diff(@hashes[0], @hashes[6]).sort_by do |diff|
|
23
|
+
m = diff[1].match(/\./)
|
24
|
+
m ? m.size : 0
|
25
|
+
end.map {|diff| diff[1]}
|
26
|
+
end
|
27
|
+
|
28
|
+
def similar_fields
|
29
|
+
keys = Set.new @hashes[0].keys
|
30
|
+
diff_keys = Set.new
|
31
|
+
@hashes.each do |hash_1|
|
32
|
+
@hashes.each do |hash_2|
|
33
|
+
diffs = HashDiff.best_diff(hash_1, hash_2).map do |diff|
|
34
|
+
diff[1].match(/(\w+)\.?/)[1]
|
35
|
+
end
|
36
|
+
diff_keys.merge diffs
|
37
|
+
end
|
38
|
+
end
|
39
|
+
keys = keys - diff_keys
|
40
|
+
key_hash = keys.inject({}) do |hash, key|
|
41
|
+
hash[key] = @hashes[0][key]
|
42
|
+
hash
|
43
|
+
end
|
44
|
+
[key_hash, diff_keys]
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_romxl_class(keys, parent)
|
48
|
+
@subclass_names << parent
|
49
|
+
name = "#{parent.to_s}#{@subclass_names.count(parent)}"
|
50
|
+
clazz = new_roxml_class name, @runtime.fetch(parent) do
|
51
|
+
include RoxmlSubclassHelpers
|
52
|
+
end
|
53
|
+
clazz.defaults = keys
|
54
|
+
@runtime.add_class name, clazz
|
55
|
+
@subclasses << clazz
|
56
|
+
name
|
57
|
+
end
|
58
|
+
|
59
|
+
def convert_roxml(obj, keys, class_name)
|
60
|
+
parent = @runtime.fetch(class_name)
|
61
|
+
new = parent.new
|
62
|
+
parent.plain_accessors.each do |new_accessor|
|
63
|
+
old_accessor = new_accessor.to_s.gsub(VAR_SUFIX, '').to_sym
|
64
|
+
new.send "#{new_accessor}=", obj.send(old_accessor)
|
65
|
+
end
|
66
|
+
|
67
|
+
keys.each do |accessor|
|
68
|
+
new.send "#{accessor}=", obj.send(accessor)
|
69
|
+
end
|
70
|
+
new
|
71
|
+
end
|
72
|
+
|
73
|
+
def convert_roxml_objs
|
74
|
+
fields, diff_keys = similar_fields
|
75
|
+
parent_name = @roxml_objs[0].class.class_name
|
76
|
+
name = create_romxl_class fields, parent_name
|
77
|
+
@roxml_objs.map do |roxml|
|
78
|
+
convert_roxml roxml, diff_keys, name
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -4,14 +4,18 @@ module PlainAccessors
|
|
4
4
|
end
|
5
5
|
|
6
6
|
module ClassMethods
|
7
|
-
def plain_accessor(name)
|
8
|
-
@plain_accessors ||=
|
9
|
-
@plain_accessors
|
10
|
-
|
7
|
+
def plain_accessor(name, default = nil)
|
8
|
+
@plain_accessors ||= {}
|
9
|
+
@plain_accessors[name] = default
|
10
|
+
attr_writer name
|
11
|
+
define_method(name) do
|
12
|
+
instance_variable_get "@#{name}" || @plain_accessors[name]
|
13
|
+
end
|
11
14
|
end
|
12
15
|
|
13
|
-
def plain_accessors
|
14
|
-
@plain_accessors ||
|
16
|
+
def plain_accessors(hash = false)
|
17
|
+
return @plain_accessors || {} if hash
|
18
|
+
(@plain_accessors && @plain_accessors.keys) || []
|
15
19
|
end
|
16
20
|
end
|
17
21
|
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
# require 'roxml'
|
2
2
|
require 'nokogiri'
|
3
|
-
require 'roundtrip_xml/
|
3
|
+
require 'roundtrip_xml/utils'
|
4
4
|
# Builds dynamic classes based on an XML file.
|
5
5
|
# Classes that already exist in the DslRuntime instance are modified if necessary, not overridden.
|
6
6
|
class RoxmlBuilder
|
7
|
+
include Utils
|
7
8
|
def initialize (root, current_classes = {})
|
8
9
|
# @type Nokogiri::Element
|
9
10
|
@root = root
|
@@ -11,21 +12,15 @@ class RoxmlBuilder
|
|
11
12
|
# @type Map<Symbol, ROXML>
|
12
13
|
@generated_classes = current_classes
|
13
14
|
|
14
|
-
@root_class = @generated_classes[name_to_sym(root.name)] ||
|
15
|
-
include ROXML
|
16
|
-
include PlainAccessors
|
17
|
-
xml_convention :dasherize
|
18
|
-
xml_name root.name
|
19
|
-
def attributes
|
20
|
-
self.class.roxml_attrs
|
21
|
-
end
|
22
|
-
end
|
15
|
+
@root_class = @generated_classes[name_to_sym(root.name)] || new_roxml_class(@root.name)
|
23
16
|
|
24
17
|
@generated_classes[ name_to_sym(@root.name)] = @root_class
|
25
18
|
@nodes = {}
|
26
19
|
end
|
20
|
+
def root_class_name
|
21
|
+
name_to_sym @root.name
|
22
|
+
end
|
27
23
|
def build_classes
|
28
|
-
# @root_class.xml_name (@root.name)
|
29
24
|
@root.attributes.values.to_a.concat(@root.children.to_a).each do |child|
|
30
25
|
default_opts = {from:child.name}
|
31
26
|
if is_leaf_element?(child)
|
@@ -46,14 +41,6 @@ class RoxmlBuilder
|
|
46
41
|
@generated_classes
|
47
42
|
end
|
48
43
|
|
49
|
-
def name_to_sym(name, lower_case = false)
|
50
|
-
# name.gsub('-', '_').to_sym
|
51
|
-
new_name = name.split('-').collect(&:capitalize).join
|
52
|
-
new_name[0] = new_name[0].downcase! if lower_case
|
53
|
-
new_name.to_sym
|
54
|
-
end
|
55
|
-
|
56
|
-
|
57
44
|
def add_accessor(name, opts = {}, node)
|
58
45
|
attrs = @root_class.roxml_attrs
|
59
46
|
attr = attrs.find do |a|
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# require 'rubygems'
|
2
|
+
require 'ruby2ruby'
|
3
|
+
require 'ruby_parser'
|
4
|
+
require 'pp'
|
5
|
+
require 'sexp_processor'
|
6
|
+
|
7
|
+
class SexpDslBuilder
|
8
|
+
def exp
|
9
|
+
rub = <<EOF
|
10
|
+
bar 'adf'
|
11
|
+
foo do
|
12
|
+
a "a" do
|
13
|
+
a1 1
|
14
|
+
a2 2
|
15
|
+
end
|
16
|
+
a "a" do
|
17
|
+
a1 3
|
18
|
+
a2 4
|
19
|
+
end
|
20
|
+
b "b"
|
21
|
+
c "c"
|
22
|
+
end
|
23
|
+
EOF
|
24
|
+
|
25
|
+
# s = Sexp.from_array arr
|
26
|
+
# processor = Ruby2Ruby.new
|
27
|
+
# processor.process(s)
|
28
|
+
parser = RubyParser.new
|
29
|
+
s = parser.process(rub)
|
30
|
+
s
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_accessor :roxml_objs, :subclasses, :runtime
|
34
|
+
def initialize(roxml_objs, subclasses, runtime)
|
35
|
+
self.roxml_objs = roxml_objs
|
36
|
+
self.subclasses = subclasses
|
37
|
+
self.runtime = runtime
|
38
|
+
end
|
39
|
+
|
40
|
+
def write_def_classes
|
41
|
+
arr = []
|
42
|
+
subclasses.each do |clazz|
|
43
|
+
defaults = clazz.defaults.map do |accessor, default|
|
44
|
+
[:call, nil, accessor, [:str, default]]
|
45
|
+
end
|
46
|
+
arr = [:iter,
|
47
|
+
[:call, nil, :define,
|
48
|
+
[:lit, clazz.class_name],
|
49
|
+
[:lit, clazz.superclass.class_name]
|
50
|
+
], 0, [:block, *defaults]]
|
51
|
+
end
|
52
|
+
|
53
|
+
sexp = Sexp.from_array arr
|
54
|
+
processor = Ruby2Ruby.new
|
55
|
+
processor.process(sexp)
|
56
|
+
end
|
57
|
+
|
58
|
+
def create_sexp_for_roxml_obj(obj, root_method = nil)
|
59
|
+
is_subclass = obj.class.respond_to?(:defaults)
|
60
|
+
subclass_value = obj.class.respond_to?(:defaults) ? [:lit, obj.class.class_name] : nil
|
61
|
+
accessors = []
|
62
|
+
obj.attributes.each do |attr|
|
63
|
+
val = obj.send attr.accessor
|
64
|
+
if !val || (is_subclass && obj.class.defaults.keys.include?(attr.accessor))
|
65
|
+
next
|
66
|
+
end
|
67
|
+
if attr.sought_type.class == Symbol
|
68
|
+
accessors << [:call, nil, attr.accessor, [:str, val || '']]
|
69
|
+
elsif val.class == Array
|
70
|
+
val.each { |v| accessors << create_sexp_for_roxml_obj(v, attr.accessor) }
|
71
|
+
else
|
72
|
+
accessors << create_sexp_for_roxml_obj(val, attr.accessor) if val
|
73
|
+
end
|
74
|
+
end.compact
|
75
|
+
root_call = [:call, nil, root_method]
|
76
|
+
root_call << subclass_value if subclass_value
|
77
|
+
if root_method
|
78
|
+
[:iter, root_call,
|
79
|
+
0,
|
80
|
+
[:block, *accessors]
|
81
|
+
]
|
82
|
+
else
|
83
|
+
[:block,
|
84
|
+
*accessors]
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
def write_roxml_obj(obj, root_method)
|
91
|
+
s = create_sexp_for_roxml_obj obj, root_method
|
92
|
+
|
93
|
+
sexp = Sexp.from_array s
|
94
|
+
processor = Ruby2Ruby.new
|
95
|
+
processor.process(sexp).gsub "\"", "'"
|
96
|
+
end
|
97
|
+
|
98
|
+
def write_roxml_objs(root_method = nil)
|
99
|
+
roxml_objs.inject('') do |out, obj|
|
100
|
+
out += write_roxml_obj obj, root_method
|
101
|
+
out += "\n\n"
|
102
|
+
out
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'roxml'
|
2
|
+
require 'roundtrip_xml/plain_accessors'
|
3
|
+
require 'set'
|
4
|
+
def name_to_sym_helper(name, lower_case = false)
|
5
|
+
new_name = name.split('-').collect(&:capitalize).join
|
6
|
+
new_name[0] = new_name[0].downcase! if lower_case
|
7
|
+
new_name.to_sym
|
8
|
+
end
|
9
|
+
module Utils
|
10
|
+
|
11
|
+
VAR_SUFIX = '_v'.freeze
|
12
|
+
def self.included(base)
|
13
|
+
unless base.const_defined?(:VAR_SUFIX)
|
14
|
+
base.const_set :VAR_SUFIX, Utils::VAR_SUFIX
|
15
|
+
end
|
16
|
+
end
|
17
|
+
def new_roxml_class(name, parent = Object, &block)
|
18
|
+
Class.new(parent) do
|
19
|
+
include ROXML
|
20
|
+
include PlainAccessors
|
21
|
+
xml_convention :dasherize
|
22
|
+
xml_name name
|
23
|
+
def attributes
|
24
|
+
self.class.roxml_attrs
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.class_name
|
28
|
+
name_to_sym_helper self.tag_name
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_hash
|
32
|
+
attributes.inject({}) do |hash, a|
|
33
|
+
value = a.to_ref(self).to_xml(self)
|
34
|
+
value = value.to_hash if value.respond_to? :to_hash
|
35
|
+
|
36
|
+
hash[a.accessor] = value
|
37
|
+
hash
|
38
|
+
end
|
39
|
+
end
|
40
|
+
def self.unique_parent_accessors
|
41
|
+
plain = Set.new(plain_accessors.map {|accessor| accessor.to_s.gsub(VAR_SUFIX, '').to_sym})
|
42
|
+
parent_accessors = Set.new(roxml_attrs.map { |attr| attr.accessor })
|
43
|
+
parent_accessors - plain
|
44
|
+
end
|
45
|
+
class_eval &block if block_given?
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
def name_to_sym(name, lower_case = false)
|
51
|
+
name_to_sym_helper(name, lower_case)
|
52
|
+
end
|
53
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roundtrip_xml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Usick
|
@@ -77,10 +77,14 @@ files:
|
|
77
77
|
- lib/roundtrip_xml/base_cleanroom.rb
|
78
78
|
- lib/roundtrip_xml/dsl_builder.rb
|
79
79
|
- lib/roundtrip_xml/dsl_runtime.rb
|
80
|
+
- lib/roundtrip_xml/extractor.rb
|
80
81
|
- lib/roundtrip_xml/plain_accessors.rb
|
81
82
|
- lib/roundtrip_xml/root_cleanroom.rb
|
82
83
|
- lib/roundtrip_xml/roxml_builder.rb
|
83
|
-
|
84
|
+
- lib/roundtrip_xml/roxml_subclass_helpers.rb
|
85
|
+
- lib/roundtrip_xml/sexp_dsl_builder.rb
|
86
|
+
- lib/roundtrip_xml/utils.rb
|
87
|
+
homepage: https://github.com/chrisUsick/roundtrip_xml
|
84
88
|
licenses:
|
85
89
|
- MIT
|
86
90
|
metadata: {}
|