xml_active 0.0.5 → 0.0.6
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.
- data/lib/xml_active.rb +137 -133
- data/lib/xml_active/version.rb +1 -1
- metadata +3 -3
data/lib/xml_active.rb
CHANGED
@@ -11,7 +11,7 @@ module XmlActive
|
|
11
11
|
end while self.class.exists?(name => self[name])
|
12
12
|
end
|
13
13
|
|
14
|
-
VALID_FROM_XML_OPTIONS = [:sync, :create, :update, :destroy]
|
14
|
+
VALID_FROM_XML_OPTIONS = [:sync, :create, :update, :destroy, :fail_on_invalid]
|
15
15
|
|
16
16
|
module ClassMethods
|
17
17
|
def many_from_xml(source_xml, options = [])
|
@@ -19,84 +19,6 @@ module XmlActive
|
|
19
19
|
many_from root_node_in source_xml
|
20
20
|
end
|
21
21
|
|
22
|
-
def many_from(current_node)
|
23
|
-
case
|
24
|
-
when self.name.pluralize.underscore.eql?(current_node.name.underscore)
|
25
|
-
many_from_rails_xml current_node
|
26
|
-
|
27
|
-
when (current_node.name.eql?('dataroot') \
|
28
|
-
and current_node.namespace_definitions.map { |ns| ns.href }.include?('urn:schemas-microsoft-com:officedata'))
|
29
|
-
# Identified as data generated from Microsoft Access
|
30
|
-
many_from_ms_xml current_node
|
31
|
-
|
32
|
-
when self.name.underscore.eql?(current_node.name.underscore)
|
33
|
-
raise "The supplied XML (#{current_node.name}) is a single instance of '#{self.name}'. Please use one_from_xml"
|
34
|
-
|
35
|
-
else
|
36
|
-
raise "The supplied XML (#{current_node.name}) cannot be mapped to this class (#{self.name})"
|
37
|
-
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def many_from_ms_xml(current_node)
|
42
|
-
records = []
|
43
|
-
recorded_ids = []
|
44
|
-
|
45
|
-
current_node.element_children.each do |node|
|
46
|
-
if self.name.underscore.eql?(node.name.underscore)
|
47
|
-
record = self.one_from_xml(node, @data_active_options)
|
48
|
-
if record
|
49
|
-
recorded_ids << record[primary_key.to_sym]
|
50
|
-
records << record
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
remove_records_not_in recorded_ids
|
56
|
-
|
57
|
-
records
|
58
|
-
end
|
59
|
-
|
60
|
-
def many_from_rails_xml(current_node)
|
61
|
-
records = []
|
62
|
-
recorded_ids = []
|
63
|
-
|
64
|
-
current_node.element_children.each do |node|
|
65
|
-
record = self.one_from_xml(node, @data_active_options)
|
66
|
-
if record
|
67
|
-
recorded_ids << record[primary_key.to_sym]
|
68
|
-
records << record
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
remove_records_not_in recorded_ids
|
73
|
-
|
74
|
-
records
|
75
|
-
end
|
76
|
-
|
77
|
-
def remove_records_not_in(recorded_ids)
|
78
|
-
if @data_active_options.include?(:sync)
|
79
|
-
if recorded_ids.length > 0
|
80
|
-
self.destroy_all [self.primary_key.to_s + " not in (?)", recorded_ids.collect]
|
81
|
-
end
|
82
|
-
elsif @data_active_options.include?(:destroy)
|
83
|
-
if recorded_ids.length > 0
|
84
|
-
self.destroy_all [self.primary_key.to_s + " not in (?)", recorded_ids.collect]
|
85
|
-
else
|
86
|
-
self.destroy_all
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def root_node_in(source_xml)
|
92
|
-
if source_xml.is_a?(String)
|
93
|
-
doc = Nokogiri::XML(source_xml)
|
94
|
-
doc.children.first
|
95
|
-
else
|
96
|
-
source_xml
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
22
|
def one_from_xml(source_xml, options = [])
|
101
23
|
@data_active_options = options
|
102
24
|
|
@@ -108,21 +30,14 @@ module XmlActive
|
|
108
30
|
|
109
31
|
active_record = find_record_based_on(pk_node)
|
110
32
|
|
111
|
-
|
112
33
|
unless active_record.nil?
|
113
34
|
# Process the attributes
|
114
35
|
if options.include? :update or options.include? :sync or options.include? :create
|
115
36
|
assign_attributes_from current_node, :to => active_record
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
# Doing complete synchronisation with XML
|
121
|
-
active_record.save
|
122
|
-
elsif options.include?(:create) and active_record.new_record?
|
123
|
-
active_record.save
|
124
|
-
elsif options.include?(:update) and not active_record.new_record?
|
125
|
-
active_record.save
|
37
|
+
if options.include? :fail_on_invalid and !active_record.valid?
|
38
|
+
messages = active_record.errors.messages.map {|attribute, messages| "#{attribute} #{messages.map{|message| message }.join(', ')}"}.join(', ')
|
39
|
+
raise "Found an invalid #{active_record.class.name} with the following errors: #{messages}. Source: #{current_node.to_s}"
|
40
|
+
end
|
126
41
|
end
|
127
42
|
|
128
43
|
# Check through associations and apply sync appropriately
|
@@ -199,6 +114,16 @@ module XmlActive
|
|
199
114
|
raise "unsupported association #{association.macro} for #{association.name } on #{self.name}"
|
200
115
|
end
|
201
116
|
end
|
117
|
+
|
118
|
+
# Save the record
|
119
|
+
if options.include? :sync
|
120
|
+
# Doing complete synchronisation with XML
|
121
|
+
active_record.save
|
122
|
+
elsif options.include?(:create) and active_record.new_record?
|
123
|
+
active_record.save
|
124
|
+
elsif options.include?(:update) and not active_record.new_record?
|
125
|
+
active_record.save
|
126
|
+
end
|
202
127
|
end
|
203
128
|
|
204
129
|
active_record
|
@@ -207,17 +132,50 @@ module XmlActive
|
|
207
132
|
end
|
208
133
|
end
|
209
134
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
elsif ActiveRecord::Reflection::AssociationReflection.method_defined? :primary_key_name
|
215
|
-
# Support for Rails earlier than 3.1
|
216
|
-
foreign_key = association.primary_key_name
|
135
|
+
private
|
136
|
+
def xml_node_matches_class(xml_node)
|
137
|
+
if xml_node.attributes['type'].blank?
|
138
|
+
xml_node.name.underscore == self.name.underscore
|
217
139
|
else
|
218
|
-
|
140
|
+
xml_node.attributes['type'].value.underscore == self.name.underscore
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def find_record_based_on(pk_node)
|
145
|
+
ar = nil
|
146
|
+
if pk_node
|
147
|
+
begin
|
148
|
+
ar = find pk_node.text
|
149
|
+
rescue
|
150
|
+
# No record exists, create a new one
|
151
|
+
if @data_active_options.include?(:sync) or @data_active_options.include?(:create)
|
152
|
+
ar = self.new
|
153
|
+
end
|
154
|
+
end
|
155
|
+
else
|
156
|
+
# No primary key value, must be a new record
|
157
|
+
if @data_active_options.include?(:sync) or @data_active_options.include?(:create)
|
158
|
+
ar = self.new
|
159
|
+
end
|
160
|
+
end
|
161
|
+
ar
|
162
|
+
end
|
163
|
+
|
164
|
+
def assign_attributes_from(current_node, options)
|
165
|
+
record = options[:to]
|
166
|
+
|
167
|
+
record.attributes.each do |name, value|
|
168
|
+
attribute_nodes = current_node.xpath name.to_s
|
169
|
+
if attribute_nodes.count == 1
|
170
|
+
if attribute_nodes[0].attributes['nil'].try(:value)
|
171
|
+
record[name] = nil
|
172
|
+
else
|
173
|
+
record[name] = attribute_nodes[0].text
|
174
|
+
end
|
175
|
+
elsif attribute_nodes.count > 1
|
176
|
+
raise "Found duplicate elements in xml for active record attribute '#{name}'"
|
177
|
+
end
|
219
178
|
end
|
220
|
-
foreign_key
|
221
179
|
end
|
222
180
|
|
223
181
|
def instances_for(association, options)
|
@@ -234,7 +192,7 @@ module XmlActive
|
|
234
192
|
# </book>
|
235
193
|
# </books>
|
236
194
|
if active_record.new_record?
|
237
|
-
results = current_node.xpath("
|
195
|
+
results = current_node.xpath("#{association.name}")
|
238
196
|
else
|
239
197
|
results = current_node.xpath("//#{self.name.underscore}[#{self.primary_key}=#{active_record.attributes[self.primary_key.to_s]}]/#{association.name}")
|
240
198
|
end
|
@@ -246,7 +204,7 @@ module XmlActive
|
|
246
204
|
# ...
|
247
205
|
# </book>
|
248
206
|
if active_record.new_record?
|
249
|
-
results = current_node.xpath("
|
207
|
+
results = current_node.xpath("#{association.name.to_s.singularize}")
|
250
208
|
else
|
251
209
|
results = current_node.xpath("//#{self.name.underscore}[#{self.primary_key}=#{active_record.attributes[self.primary_key.to_s]}]/#{association.name.to_s.singularize}")
|
252
210
|
end
|
@@ -257,48 +215,94 @@ module XmlActive
|
|
257
215
|
results
|
258
216
|
end
|
259
217
|
|
260
|
-
def
|
261
|
-
|
218
|
+
def foreign_key_from(association)
|
219
|
+
if ActiveRecord::Reflection::AssociationReflection.method_defined? :foreign_key
|
220
|
+
# Support for Rails 3.1 and later
|
221
|
+
foreign_key = association.foreign_key
|
222
|
+
elsif ActiveRecord::Reflection::AssociationReflection.method_defined? :primary_key_name
|
223
|
+
# Support for Rails earlier than 3.1
|
224
|
+
foreign_key = association.primary_key_name
|
225
|
+
else
|
226
|
+
raise "Unsupported version of ActiveRecord. Unable to identify the foreign key."
|
227
|
+
end
|
228
|
+
foreign_key
|
229
|
+
end
|
262
230
|
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
231
|
+
def root_node_in(source_xml)
|
232
|
+
if source_xml.is_a?(String)
|
233
|
+
doc = Nokogiri::XML(source_xml)
|
234
|
+
doc.children.first
|
235
|
+
else
|
236
|
+
source_xml
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def remove_records_not_in(recorded_ids)
|
241
|
+
if @data_active_options.include?(:sync)
|
242
|
+
if recorded_ids.length > 0
|
243
|
+
self.destroy_all [self.primary_key.to_s + " not in (?)", recorded_ids.collect]
|
244
|
+
end
|
245
|
+
elsif @data_active_options.include?(:destroy)
|
246
|
+
if recorded_ids.length > 0
|
247
|
+
self.destroy_all [self.primary_key.to_s + " not in (?)", recorded_ids.collect]
|
248
|
+
else
|
249
|
+
self.destroy_all
|
273
250
|
end
|
274
251
|
end
|
275
252
|
end
|
276
253
|
|
277
|
-
def
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
end
|
254
|
+
def many_from_rails_xml(current_node)
|
255
|
+
records = []
|
256
|
+
recorded_ids = []
|
257
|
+
|
258
|
+
current_node.element_children.each do |node|
|
259
|
+
record = self.one_from_xml(node, @data_active_options)
|
260
|
+
if record
|
261
|
+
recorded_ids << record[primary_key.to_sym]
|
262
|
+
records << record
|
287
263
|
end
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
264
|
+
end
|
265
|
+
|
266
|
+
remove_records_not_in recorded_ids
|
267
|
+
|
268
|
+
records
|
269
|
+
end
|
270
|
+
|
271
|
+
def many_from_ms_xml(current_node)
|
272
|
+
records = []
|
273
|
+
recorded_ids = []
|
274
|
+
|
275
|
+
current_node.element_children.each do |node|
|
276
|
+
if self.name.underscore.eql?(node.name.underscore)
|
277
|
+
record = self.one_from_xml(node, @data_active_options)
|
278
|
+
if record
|
279
|
+
recorded_ids << record[primary_key.to_sym]
|
280
|
+
records << record
|
281
|
+
end
|
292
282
|
end
|
293
283
|
end
|
294
|
-
|
284
|
+
|
285
|
+
remove_records_not_in recorded_ids
|
286
|
+
|
287
|
+
records
|
295
288
|
end
|
296
289
|
|
297
|
-
def
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
290
|
+
def many_from(current_node)
|
291
|
+
case
|
292
|
+
when self.name.pluralize.underscore.eql?(current_node.name.underscore)
|
293
|
+
many_from_rails_xml current_node
|
294
|
+
|
295
|
+
when (current_node.name.eql?('dataroot') \
|
296
|
+
and current_node.namespace_definitions.map { |ns| ns.href }.include?('urn:schemas-microsoft-com:officedata'))
|
297
|
+
# Identified as data generated from Microsoft Access
|
298
|
+
many_from_ms_xml current_node
|
299
|
+
|
300
|
+
when self.name.underscore.eql?(current_node.name.underscore)
|
301
|
+
raise "The supplied XML (#{current_node.name}) is a single instance of '#{self.name}'. Please use one_from_xml"
|
302
|
+
|
303
|
+
else
|
304
|
+
raise "The supplied XML (#{current_node.name}) cannot be mapped to this class (#{self.name})"
|
305
|
+
|
302
306
|
end
|
303
307
|
end
|
304
308
|
end
|
data/lib/xml_active/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xml_active
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-07-
|
12
|
+
date: 2012-07-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
@@ -97,5 +97,5 @@ rubyforge_project: xml_active
|
|
97
97
|
rubygems_version: 1.8.22
|
98
98
|
signing_key:
|
99
99
|
specification_version: 3
|
100
|
-
summary: xml_active 0.0.
|
100
|
+
summary: xml_active 0.0.6
|
101
101
|
test_files: []
|