roundtrip_xml 0.2.2 → 1.0.0
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/base_cleanroom.rb +5 -0
- data/lib/roundtrip_xml/dsl_runtime.rb +5 -5
- data/lib/roundtrip_xml/extractor.rb +77 -11
- data/lib/roundtrip_xml/plain_accessors.rb +2 -2
- data/lib/roundtrip_xml/sexp_dsl_builder.rb +7 -5
- data/lib/roundtrip_xml/utils.rb +8 -3
- metadata +16 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e2a828a5eed9aa3a533c7d19e959f9dd4ff3f1fd
|
|
4
|
+
data.tar.gz: 26585d066af79709c1f972fa82902af574a58881
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9d875f5ee525541bafbe6068aa54cbb186fe5b9eddef5b726bc717ccbbcabdd00435d0cd11ee98d3a7bb4e872725f9d04b02a18283a07e39b03a652ca8792742
|
|
7
|
+
data.tar.gz: d1f17f80df1b8d92886c81a9cd9c1b19c9cf37482144eda6075c20bce5ea76ae085ff3ca4b0370f905976b5d12b7e053a571171bd6a4a352f1414dfd5d00bc61
|
|
@@ -34,7 +34,7 @@ class DslRuntime
|
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
# @param block Proc This proc is passed each health rule and must return a string value which specifies the partition for it
|
|
37
|
-
def write_dsl(xml, root_class_name, root_method, helpers =
|
|
37
|
+
def write_dsl(xml, root_class_name, root_method, helpers = nil, &block)
|
|
38
38
|
roxml_root = fetch(root_class_name).from_xml xml
|
|
39
39
|
|
|
40
40
|
extractor = Extractor.new roxml_root.send(root_method), self, root_class_name, helpers
|
|
@@ -83,10 +83,10 @@ class DslRuntime
|
|
|
83
83
|
|
|
84
84
|
def evaluate_raw(dsl, root_class, templates = [], &block)
|
|
85
85
|
cleanroom = RootCleanroom.new(fetch(root_class).new, self)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
templates.each { |t| cleanroom.evaluate t }
|
|
87
|
+
if block_given?
|
|
88
|
+
cleanroom.evaluate &block
|
|
89
|
+
else
|
|
90
90
|
cleanroom.evaluate dsl
|
|
91
91
|
end
|
|
92
92
|
|
|
@@ -6,6 +6,7 @@ require 'set'
|
|
|
6
6
|
require 'roundtrip_xml/utils'
|
|
7
7
|
require 'multiset'
|
|
8
8
|
require 'roundtrip_xml/roxml_subclass_helpers.rb'
|
|
9
|
+
require 'differ'
|
|
9
10
|
|
|
10
11
|
class Extractor
|
|
11
12
|
|
|
@@ -13,10 +14,11 @@ class Extractor
|
|
|
13
14
|
@roxml_objs = roxml_objs
|
|
14
15
|
@runtime = runtime
|
|
15
16
|
@root_class = root_class
|
|
17
|
+
@definitions = {}
|
|
16
18
|
if block_given?
|
|
17
|
-
|
|
19
|
+
eval_definitions root_class, &block
|
|
18
20
|
else
|
|
19
|
-
|
|
21
|
+
definitions.each {|defin| eval_definitions root_class, defin } if definitions
|
|
20
22
|
end
|
|
21
23
|
end
|
|
22
24
|
|
|
@@ -29,7 +31,7 @@ class Extractor
|
|
|
29
31
|
end
|
|
30
32
|
new_names = @runtime.instance_variable_get(:@classes).keys
|
|
31
33
|
def_names = new_names - old_names
|
|
32
|
-
def_names.inject(
|
|
34
|
+
@definitions = def_names.inject(@definitions) do |out, name|
|
|
33
35
|
clazz = @runtime.fetch(name)
|
|
34
36
|
parent = get_root_class clazz
|
|
35
37
|
obj = clazz.new
|
|
@@ -57,7 +59,14 @@ class Extractor
|
|
|
57
59
|
h.delete '__class'
|
|
58
60
|
end
|
|
59
61
|
diffs = HashDiff.diff(obj_hash, def_hash).map do |diff|
|
|
60
|
-
|
|
62
|
+
accessor_name = if diff[3].is_a?(String) && match = diff[3].match(/#{Utils::UNDEFINED_PARAM}:(\w*)/)
|
|
63
|
+
match[1].to_sym
|
|
64
|
+
end
|
|
65
|
+
if accessor_name && defin.class.plain_accessors.include?(accessor_name)
|
|
66
|
+
matcher = defin.class.plain_accessors(true)[accessor_name]
|
|
67
|
+
end
|
|
68
|
+
template_val = diff[3].is_a?(String) && accessor_name ? Utils::UndefinedParam.new(accessor_name, diff[3]) : diff[3]
|
|
69
|
+
ROXMLDiff.new diff[0], diff[1], from_hash(diff[2]), template_val, matcher
|
|
61
70
|
end
|
|
62
71
|
|
|
63
72
|
diffs
|
|
@@ -82,11 +91,11 @@ class Extractor
|
|
|
82
91
|
|
|
83
92
|
defs.each do |defin|
|
|
84
93
|
diffs = diff_definition(defin, obj)
|
|
85
|
-
if diffs.all? {|diff| diff.template_val.is_a?(Utils::UndefinedParam) || diff.template_val == nil }
|
|
94
|
+
if diffs.all? {|diff| diff.operation == '~' && (diff.template_val.is_a?(Utils::UndefinedParam) || diff.template_val == nil || interpolated_diff(diff)) }
|
|
86
95
|
new_obj = defin.class.new
|
|
87
96
|
param_values = diffs.inject({}) do |values, diff|
|
|
88
97
|
name = diff.template_val ? diff.template_val.name : diff.key
|
|
89
|
-
values[name] = diff.obj_val
|
|
98
|
+
values[name] = interpolated_diff(diff) ? extract_interpolated_diff(diff) : diff.obj_val
|
|
90
99
|
values
|
|
91
100
|
end
|
|
92
101
|
set_attributes new_obj, param_values
|
|
@@ -97,7 +106,8 @@ class Extractor
|
|
|
97
106
|
|
|
98
107
|
obj.class.roxml_attrs.each do |a|
|
|
99
108
|
if a.array?
|
|
100
|
-
elements =
|
|
109
|
+
elements = a.sought_type.class == Class ?
|
|
110
|
+
obj.send(a.accessor).map {|el| convert_roxml_obj el} : obj.send(a.accessor)
|
|
101
111
|
obj.send a.setter.to_sym, elements
|
|
102
112
|
elsif a.sought_type.class == Class
|
|
103
113
|
current_value = obj.send(a.accessor)
|
|
@@ -107,22 +117,78 @@ class Extractor
|
|
|
107
117
|
obj
|
|
108
118
|
end
|
|
109
119
|
|
|
120
|
+
def interpolated_diff(diff)
|
|
121
|
+
diff.obj_val.is_a?(String) && diff.template_val.is_a?(Utils::UndefinedParam) && diff.template_val.original && diff.template_val.original.match(/#{Utils::UNDEFINED_PARAM}:/)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def extract_interpolated_diff(diff)
|
|
125
|
+
s_diff = Differ.diff_by_word(diff.obj_val, diff.template_val.original).to_s
|
|
126
|
+
value = s_diff.match(/(\{"\s*#{Utils::UNDEFINED_PARAM}:([\S]*)\s*" >> "(.*)"})/)[3]
|
|
127
|
+
value.strip.match(diff.matcher)[1]
|
|
128
|
+
end
|
|
129
|
+
|
|
110
130
|
def set_attributes(obj, params)
|
|
111
131
|
params.each do |param, val|
|
|
112
132
|
methods = param.to_s.split '.'
|
|
113
|
-
|
|
114
|
-
obj
|
|
133
|
+
methods << val
|
|
134
|
+
set_deep_attributes obj, methods
|
|
135
|
+
# obj.send "#{param}=", val
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def set_deep_attributes(obj, methods)
|
|
141
|
+
index = methods[0].match(/\[(\d+)\]/)
|
|
142
|
+
child = index ? nil : obj.send(methods[0])
|
|
143
|
+
method = methods[0]
|
|
144
|
+
method.gsub!(/\[\d+\]/, '')
|
|
145
|
+
if child
|
|
146
|
+
set_deep_attributes child, methods[1..methods.size]
|
|
147
|
+
else
|
|
148
|
+
if index
|
|
149
|
+
arr = obj.send(method) || []
|
|
150
|
+
arr[Integer(index[1])] = methods[1..1][0] # hacky way to get second element
|
|
151
|
+
obj.send("#{method}=", arr)
|
|
152
|
+
else
|
|
153
|
+
obj.send(methods[0] + '=', set_deep_attributes_helper(obj, methods))
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def set_deep_attributes_helper(obj, methods)
|
|
159
|
+
method = methods.shift
|
|
160
|
+
index = method.match(/\[(\d+)\]/)
|
|
161
|
+
return obj.send(method + '=', methods.first) if !index && methods.size == 1
|
|
162
|
+
|
|
163
|
+
method.gsub!(/\[\d+\]/, '')
|
|
164
|
+
child = obj.send(method)
|
|
165
|
+
unless child || methods.size == 1
|
|
166
|
+
clazz_name = method.dup
|
|
167
|
+
clazz_name[0] = clazz_name[0].upcase
|
|
168
|
+
child = @runtime.fetch(clazz_name.to_sym).new
|
|
169
|
+
obj.send("#{method}=", child)
|
|
170
|
+
|
|
171
|
+
end
|
|
172
|
+
if index
|
|
173
|
+
arr = obj.send(method) || []
|
|
174
|
+
arr[Integer(index[1])] = methods.first
|
|
175
|
+
obj.send("#{method}=", arr)
|
|
176
|
+
else
|
|
177
|
+
obj.send(method + '=', set_deep_attributes_helper(child, methods))
|
|
115
178
|
end
|
|
116
179
|
|
|
180
|
+
child.is_a?(Array) ? obj : child || obj
|
|
117
181
|
end
|
|
118
182
|
|
|
119
183
|
end
|
|
120
184
|
|
|
121
185
|
class ROXMLDiff
|
|
122
|
-
attr_reader :key, :obj_val, :template_val
|
|
123
|
-
def initialize(key, obj_val, template_val)
|
|
186
|
+
attr_reader :operation, :key, :obj_val, :template_val, :matcher
|
|
187
|
+
def initialize(operation, key, obj_val, template_val, matcher = nil)
|
|
188
|
+
@operation = operation
|
|
124
189
|
@key = key.to_sym
|
|
125
190
|
@obj_val = obj_val
|
|
126
191
|
@template_val = template_val
|
|
192
|
+
@matcher = matcher
|
|
127
193
|
end
|
|
128
194
|
end
|
|
@@ -5,9 +5,9 @@ module PlainAccessors
|
|
|
5
5
|
end
|
|
6
6
|
|
|
7
7
|
module ClassMethods
|
|
8
|
-
def plain_accessor(name,
|
|
8
|
+
def plain_accessor(name, matcher = /(\S*)/)
|
|
9
9
|
@plain_accessors ||= {}
|
|
10
|
-
@plain_accessors[name] =
|
|
10
|
+
@plain_accessors[name] = matcher
|
|
11
11
|
attr_writer name
|
|
12
12
|
define_method(name) do
|
|
13
13
|
val = instance_variable_get "@#{name}"
|
|
@@ -43,11 +43,13 @@ EOF
|
|
|
43
43
|
obj.attributes.each do |attr|
|
|
44
44
|
val = obj.send attr.accessor
|
|
45
45
|
next unless val
|
|
46
|
-
|
|
47
|
-
# next
|
|
48
|
-
# end
|
|
46
|
+
|
|
49
47
|
if attr.sought_type.class == Symbol
|
|
50
|
-
|
|
48
|
+
if val.is_a? Array
|
|
49
|
+
val.each {|v| accessors << [:call, nil, attr.accessor, [:str, v]]}
|
|
50
|
+
else
|
|
51
|
+
accessors << [:call, nil, attr.accessor, [:str, val]]
|
|
52
|
+
end
|
|
51
53
|
elsif val.class == Array
|
|
52
54
|
val.each { |v| accessors << create_sexp_for_roxml_obj(v, attr.accessor) }
|
|
53
55
|
else
|
|
@@ -79,7 +81,7 @@ EOF
|
|
|
79
81
|
sexp = Sexp.from_array s
|
|
80
82
|
processor = Ruby2Ruby.new
|
|
81
83
|
str = processor.process(sexp)
|
|
82
|
-
str.gsub(
|
|
84
|
+
str.gsub(/([^"])\(([^\(\)]*|".*")\)([^"])([^{]|$)/, '\\1 \\2\\3\\4').gsub(/"([^'\n]+)"/, "'\\1'").gsub(/# do nothing/, '')
|
|
83
85
|
end
|
|
84
86
|
|
|
85
87
|
def write_full_dsl(root_method)
|
data/lib/roundtrip_xml/utils.rb
CHANGED
|
@@ -7,11 +7,16 @@ def name_to_sym_helper(name, lower_case = false)
|
|
|
7
7
|
new_name.to_sym
|
|
8
8
|
end
|
|
9
9
|
module Utils
|
|
10
|
-
|
|
10
|
+
UNDEFINED_PARAM = 'UNDEFINED_PARAM'.freeze
|
|
11
11
|
class UndefinedParam
|
|
12
|
-
attr_reader :name
|
|
13
|
-
def initialize(name)
|
|
12
|
+
attr_reader :name, :original
|
|
13
|
+
def initialize(name, original = nil)
|
|
14
14
|
@name = name
|
|
15
|
+
@original = original
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_s
|
|
19
|
+
"#{Utils::UNDEFINED_PARAM}:#{@name}"
|
|
15
20
|
end
|
|
16
21
|
end
|
|
17
22
|
|
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.
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chris Usick
|
|
@@ -108,6 +108,20 @@ dependencies:
|
|
|
108
108
|
- - "~>"
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
110
|
version: '0.3'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: differ
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - "~>"
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '0.1'
|
|
118
|
+
type: :runtime
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - "~>"
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '0.1'
|
|
111
125
|
- !ruby/object:Gem::Dependency
|
|
112
126
|
name: multiset
|
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -175,7 +189,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
175
189
|
version: '0'
|
|
176
190
|
requirements: []
|
|
177
191
|
rubyforge_project:
|
|
178
|
-
rubygems_version: 2.4.
|
|
192
|
+
rubygems_version: 2.4.8
|
|
179
193
|
signing_key:
|
|
180
194
|
specification_version: 4
|
|
181
195
|
summary: DSL which learns from XML
|