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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3e77511e2e2d2f257ab080cebb04b0f66ee25af7
4
- data.tar.gz: 6a3ebee19eeffa57d16e80c18a87942d58edbfe4
3
+ metadata.gz: e2a828a5eed9aa3a533c7d19e959f9dd4ff3f1fd
4
+ data.tar.gz: 26585d066af79709c1f972fa82902af574a58881
5
5
  SHA512:
6
- metadata.gz: cd50200ff25f0195d300e5c0d25ffff38dbb7ec84ce534ab0f7bf8e3a686e09eefd58f837012f8c31a695182535956753643d2c1f7fd69db46b318fc22a6dd28
7
- data.tar.gz: 872b94b1378169aafd2efcdb979c8649dbbc1d9530cebbef70dc57143bc7de41fdfc94babbddeae3e5757eb1543ca67ca8c26dfef9ff9dd6dac6838d6ffa7fc3
6
+ metadata.gz: 9d875f5ee525541bafbe6068aa54cbb186fe5b9eddef5b726bc717ccbbcabdd00435d0cd11ee98d3a7bb4e872725f9d04b02a18283a07e39b03a652ca8792742
7
+ data.tar.gz: d1f17f80df1b8d92886c81a9cd9c1b19c9cf37482144eda6075c20bce5ea76ae085ff3ca4b0370f905976b5d12b7e053a571171bd6a4a352f1414dfd5d00bc61
@@ -96,4 +96,9 @@ class BaseCleanroom
96
96
  self.class.send(:expose, name)
97
97
  end
98
98
  end
99
+
100
+ def _matcher(accessor, matcher)
101
+ @el.class.plain_accessor accessor, matcher
102
+ end
103
+ expose :_matcher
99
104
  end
@@ -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 = '', &block)
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
- templates.each { |t| cleanroom.evaluate_file t }
87
- if block_given?
88
- cleanroom.evaluate &block
89
- else
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
- @definitions = eval_definitions root_class, &block
19
+ eval_definitions root_class, &block
18
20
  else
19
- @definitions = eval_definitions root_class, definitions
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({}) do |out, name|
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
- ROXMLDiff.new diff[1], from_hash(diff[2]), diff[3]
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 = obj.send(a.accessor).map {|el| convert_roxml_obj el}
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
- # set_deep_attribute obj, methods, val
114
- obj.send "#{param}=", val
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, default = nil)
8
+ def plain_accessor(name, matcher = /(\S*)/)
9
9
  @plain_accessors ||= {}
10
- @plain_accessors[name] = default
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
- # if !val || (is_subclass && obj.class.defaults.keys.include?(attr.accessor))
47
- # next
48
- # end
46
+
49
47
  if attr.sought_type.class == Symbol
50
- accessors << [:call, nil, attr.accessor, [:str, val]]
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(/\((.*)\)/, ' \\1').gsub(/"([^'\n]+)"/, "'\\1'")
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)
@@ -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
- # UNDEFINED_PARAM = 'UNDEFINED_PARAM_VALUE'
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.2.2
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.6
192
+ rubygems_version: 2.4.8
179
193
  signing_key:
180
194
  specification_version: 4
181
195
  summary: DSL which learns from XML