om 1.8.0 → 1.8.1
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 +7 -0
- data/.rspec +1 -0
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +382 -0
- data/.travis.yml +10 -0
- data/Rakefile +1 -1
- data/container_spec.rb +14 -14
- data/gemfiles/gemfile.rails3 +11 -0
- data/gemfiles/gemfile.rails4 +10 -0
- data/lib/om.rb +9 -12
- data/lib/om/samples/mods_article.rb +9 -9
- data/lib/om/tree_node.rb +6 -6
- data/lib/om/version.rb +1 -1
- data/lib/om/xml.rb +18 -20
- data/lib/om/xml/container.rb +12 -12
- data/lib/om/xml/document.rb +3 -7
- data/lib/om/xml/dynamic_node.rb +45 -50
- data/lib/om/xml/named_term_proxy.rb +13 -13
- data/lib/om/xml/node_generator.rb +3 -3
- data/lib/om/xml/template_registry.rb +18 -26
- data/lib/om/xml/term.rb +30 -46
- data/lib/om/xml/term_value_operators.rb +52 -56
- data/lib/om/xml/term_xpath_generator.rb +51 -57
- data/lib/om/xml/terminology.rb +8 -10
- data/lib/om/xml/validation.rb +19 -19
- data/lib/om/xml/vocabulary.rb +4 -4
- data/lib/tasks/om.rake +4 -6
- data/om.gemspec +1 -2
- data/spec/integration/differentiated_elements_spec.rb +2 -2
- data/spec/integration/element_value_spec.rb +13 -13
- data/spec/integration/proxies_and_ref_spec.rb +15 -15
- data/spec/integration/querying_documents_spec.rb +24 -18
- data/spec/integration/rights_metadata_integration_example_spec.rb +18 -18
- data/spec/integration/selective_querying_spec.rb +1 -1
- data/spec/integration/serialization_spec.rb +13 -13
- data/spec/integration/set_reentrant_terminology_spec.rb +7 -7
- data/spec/integration/xpathy_stuff_spec.rb +16 -16
- data/spec/spec_helper.rb +2 -3
- data/spec/unit/container_spec.rb +28 -29
- data/spec/unit/document_spec.rb +49 -50
- data/spec/unit/dynamic_node_spec.rb +55 -47
- data/spec/unit/named_term_proxy_spec.rb +16 -16
- data/spec/unit/node_generator_spec.rb +7 -7
- data/spec/unit/nokogiri_sanity_spec.rb +30 -30
- data/spec/unit/om_spec.rb +5 -5
- data/spec/unit/template_registry_spec.rb +69 -69
- data/spec/unit/term_builder_spec.rb +77 -77
- data/spec/unit/term_spec.rb +78 -72
- data/spec/unit/term_value_operators_spec.rb +186 -191
- data/spec/unit/term_xpath_generator_spec.rb +37 -43
- data/spec/unit/terminology_builder_spec.rb +85 -85
- data/spec/unit/terminology_spec.rb +98 -98
- data/spec/unit/validation_spec.rb +22 -22
- data/spec/unit/xml_serialization_spec.rb +21 -22
- data/spec/unit/xml_spec.rb +7 -7
- metadata +143 -147
@@ -1,9 +1,9 @@
|
|
1
1
|
class OM::XML::NamedTermProxy
|
2
|
-
|
2
|
+
|
3
3
|
attr_accessor :proxy_pointer, :name, :terminology
|
4
|
-
|
4
|
+
|
5
5
|
include OM::TreeNode
|
6
|
-
|
6
|
+
|
7
7
|
# Creates a Named Proxy that points to another term in the Terminology.
|
8
8
|
# Unlike regular terms, NamedTermProxy requires you to provide a reference to the containing Terminology.
|
9
9
|
# This is to ensure that it will always be able to look up the term that it's referencing.
|
@@ -14,13 +14,13 @@ class OM::XML::NamedTermProxy
|
|
14
14
|
def initialize(name, proxy_pointer, terminology, opts={})
|
15
15
|
opts = {:namespace_prefix=>"oxns", :ancestors=>[], :children=>{}}.merge(opts)
|
16
16
|
[:children, :ancestors, :index_as].each do |accessor_name|
|
17
|
-
instance_variable_set("@#{accessor_name}", opts.fetch(accessor_name, nil) )
|
17
|
+
instance_variable_set("@#{accessor_name}", opts.fetch(accessor_name, nil) )
|
18
18
|
end
|
19
19
|
@terminology = terminology
|
20
20
|
@name = name
|
21
21
|
@proxy_pointer = proxy_pointer
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
def proxied_term
|
25
25
|
if self.parent.nil?
|
26
26
|
pt = self.terminology.retrieve_term(*self.proxy_pointer)
|
@@ -33,18 +33,18 @@ class OM::XML::NamedTermProxy
|
|
33
33
|
return pt
|
34
34
|
end
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
# do nothing -- this is to prevent errors when the parent term calls generate_xpath_queries! on its children
|
38
38
|
def generate_xpath_queries!
|
39
39
|
# do nothing
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
# A proxy term can never serve as the root term of a Terminology.
|
43
43
|
# Explicitly setting is_root_term? to return false to support proxies that are _at_ the root of the Terminology but aren't _the_ root term.
|
44
44
|
def is_root_term?
|
45
|
-
|
45
|
+
false
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
##
|
49
49
|
# Always co-erce :index_as attributes into an Array
|
50
50
|
def index_as
|
@@ -54,10 +54,10 @@ class OM::XML::NamedTermProxy
|
|
54
54
|
self.proxied_term.index_as
|
55
55
|
end
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
# Any unknown method calls will be proxied to the proxied term
|
59
|
-
def method_missing method, *args, &block
|
60
|
-
|
59
|
+
def method_missing method, *args, &block
|
60
|
+
self.proxied_term.send(method, *args)
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module OM::XML::NodeGenerator
|
2
|
-
|
2
|
+
|
3
3
|
# Module Methods -- These methods can be called directly on the Module itself
|
4
4
|
# @param OM::XML::Term term The term to generate a node based on
|
5
5
|
# @param String builder_new_value The new value to insert into the generated node
|
@@ -14,8 +14,8 @@ module OM::XML::NodeGenerator
|
|
14
14
|
builder = Nokogiri::XML::Builder.new do |xml|
|
15
15
|
eval( builder_call_body )
|
16
16
|
end
|
17
|
-
|
18
|
-
|
17
|
+
|
18
|
+
builder.doc
|
19
19
|
end
|
20
20
|
|
21
21
|
end
|
@@ -1,10 +1,10 @@
|
|
1
|
-
# Extend an OM::XML::Document with reusable templates, then use them to add content to
|
1
|
+
# Extend an OM::XML::Document with reusable templates, then use them to add content to
|
2
2
|
# instance documents.
|
3
3
|
#
|
4
4
|
# Example:
|
5
5
|
#
|
6
6
|
# require 'om/samples/mods_article'
|
7
|
-
#
|
7
|
+
#
|
8
8
|
# class OM::Samples::ModsArticle
|
9
9
|
# define_template :personalName do |xml, family, given, address|
|
10
10
|
# xml.name(:type => 'personal') do
|
@@ -13,7 +13,7 @@
|
|
13
13
|
# xml.namePart(:type => 'termsOfAddress') { xml.text(address) }
|
14
14
|
# end
|
15
15
|
# end
|
16
|
-
#
|
16
|
+
#
|
17
17
|
# define_template :role do |xml, text, attrs|
|
18
18
|
# xml.role do
|
19
19
|
# attrs = { :type => 'text' }.merge(attrs)
|
@@ -21,9 +21,9 @@
|
|
21
21
|
# end
|
22
22
|
# end
|
23
23
|
# end
|
24
|
-
#
|
24
|
+
#
|
25
25
|
# mods = OM::Samples::ModsArticle.from_xml(File.read('./spec/fixtures/CBF_MODS/ARS0025_016.xml'))
|
26
|
-
#
|
26
|
+
#
|
27
27
|
# mods.add_previous_sibling_node([:person => 0], :personalName, 'Shmoe', 'Joseph', 'Dr.') { |person|
|
28
28
|
# person.add_child(mods.template(:role, 'author', :authority => 'marcrelator'))
|
29
29
|
# person.add_child(mods.template(:role, 'sub', :authority => 'local', :type => 'code'))
|
@@ -44,7 +44,7 @@ class OM::XML::TemplateRegistry
|
|
44
44
|
unless node_type.is_a?(Symbol)
|
45
45
|
raise TypeError, "Registered node type must be a Symbol (e.g., :person)"
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
@templates[node_type] = block
|
49
49
|
node_type
|
50
50
|
end
|
@@ -77,11 +77,9 @@ class OM::XML::TemplateRegistry
|
|
77
77
|
result = create_detached_node(nil, node_type, *args)
|
78
78
|
# Strip namespaces from text and CDATA nodes. Stupid Nokogiri.
|
79
79
|
result.traverse { |node|
|
80
|
-
if node.is_a?(Nokogiri::XML::CharacterData)
|
81
|
-
node.namespace = nil
|
82
|
-
end
|
80
|
+
node.namespace = nil if node.is_a?(Nokogiri::XML::CharacterData)
|
83
81
|
}
|
84
|
-
|
82
|
+
result
|
85
83
|
end
|
86
84
|
|
87
85
|
# +instantiate+ a node and add it as a child of the [Nokogiri::XML::Node] specified by +target_node+
|
@@ -125,7 +123,7 @@ class OM::XML::TemplateRegistry
|
|
125
123
|
def swap(target_node, node_type, *args, &block)
|
126
124
|
attach_node(:swap, target_node, :parent, node_type, *args, &block)
|
127
125
|
end
|
128
|
-
|
126
|
+
|
129
127
|
def methods
|
130
128
|
super + @templates.keys.collect { |k| k.to_s }
|
131
129
|
end
|
@@ -140,7 +138,7 @@ class OM::XML::TemplateRegistry
|
|
140
138
|
end
|
141
139
|
|
142
140
|
private
|
143
|
-
|
141
|
+
|
144
142
|
# Create a new Nokogiri::XML::Node based on the template for +node_type+
|
145
143
|
#
|
146
144
|
# @param [Nokogiri::XML::Node] builder_node The node to use as starting point for building the node using Nokogiri::XML::Builder.with(builder_node). This provides namespace info, etc for constructing the new Node object. If nil, defaults to {OM::XML::TemplateRegistry#empty_root_node}. This is just used to create the new node and will not be included in the response.
|
@@ -148,13 +146,9 @@ class OM::XML::TemplateRegistry
|
|
148
146
|
# @param [Array] args any additional args
|
149
147
|
def create_detached_node(builder_node, node_type, *args)
|
150
148
|
proc = @templates[node_type]
|
151
|
-
if proc.nil?
|
152
|
-
|
153
|
-
|
154
|
-
if builder_node.nil?
|
155
|
-
builder_node = empty_root_node
|
156
|
-
end
|
157
|
-
|
149
|
+
raise NameError, "Unknown node type: #{node_type.to_s}" if proc.nil?
|
150
|
+
builder_node = empty_root_node if builder_node.nil?
|
151
|
+
|
158
152
|
builder = Nokogiri::XML::Builder.with(builder_node) do |xml|
|
159
153
|
proc.call(xml,*args)
|
160
154
|
end
|
@@ -165,11 +159,11 @@ class OM::XML::TemplateRegistry
|
|
165
159
|
#
|
166
160
|
# @param [Symbol] method name that should be called on +target_node+, usually a Nokogiri::XML::Node instance method
|
167
161
|
# @param [Nokogiri::XML::Node or Nokogiri::XML::NodeSet with only one Node in it] target_node
|
168
|
-
# @param [Symbol] builder_node_offset Indicates node to use as the starting point for _constructing_ the new node using {OM::XML::TemplateRegistry#create_detached_node}. If this is set to :parent, target_node.parent will be used. Otherwise, target_node will be used.
|
162
|
+
# @param [Symbol] builder_node_offset Indicates node to use as the starting point for _constructing_ the new node using {OM::XML::TemplateRegistry#create_detached_node}. If this is set to :parent, target_node.parent will be used. Otherwise, target_node will be used.
|
169
163
|
# @param node_type
|
170
164
|
# @param [Array] args any additional arguments for creating the node
|
171
165
|
def attach_node(method, target_node, builder_node_offset, node_type, *args, &block)
|
172
|
-
if target_node.is_a?(Nokogiri::XML::NodeSet)
|
166
|
+
if target_node.is_a?(Nokogiri::XML::NodeSet) && target_node.length == 1
|
173
167
|
target_node = target_node.first
|
174
168
|
end
|
175
169
|
builder_node = builder_node_offset == :parent ? target_node.parent : target_node
|
@@ -177,9 +171,7 @@ class OM::XML::TemplateRegistry
|
|
177
171
|
result = target_node.send(method, new_node)
|
178
172
|
# Strip namespaces from text and CDATA nodes. Stupid Nokogiri.
|
179
173
|
new_node.traverse { |node|
|
180
|
-
if node.is_a?(Nokogiri::XML::CharacterData)
|
181
|
-
node.namespace = nil
|
182
|
-
end
|
174
|
+
node.namespace = nil if node.is_a?(Nokogiri::XML::CharacterData)
|
183
175
|
}
|
184
176
|
if block_given?
|
185
177
|
yield result
|
@@ -187,9 +179,9 @@ class OM::XML::TemplateRegistry
|
|
187
179
|
return result
|
188
180
|
end
|
189
181
|
end
|
190
|
-
|
182
|
+
|
191
183
|
def empty_root_node
|
192
184
|
Nokogiri::XML('<root/>').root
|
193
185
|
end
|
194
|
-
|
186
|
+
|
195
187
|
end
|
data/lib/om/xml/term.rb
CHANGED
@@ -56,16 +56,14 @@ class OM::XML::Term
|
|
56
56
|
trail = ""
|
57
57
|
nodes_visited.each_with_index do |node, z|
|
58
58
|
trail << node.name.inspect
|
59
|
-
unless z == nodes_visited.length-1
|
60
|
-
trail << " => "
|
61
|
-
end
|
59
|
+
trail << " => " unless z == nodes_visited.length-1
|
62
60
|
end
|
63
61
|
raise OM::XML::Terminology::CircularReferenceError, "Circular reference in Terminology: #{trail}"
|
64
62
|
end
|
65
63
|
result << target
|
66
64
|
result.concat( target.lookup_refs(nodes_visited << self) )
|
67
65
|
end
|
68
|
-
|
66
|
+
result
|
69
67
|
end
|
70
68
|
|
71
69
|
# If a :ref value has been set, looks up the target of that ref and merges the target's settings & children with the current builder's settings & children
|
@@ -81,7 +79,7 @@ class OM::XML::Term
|
|
81
79
|
@settings[:path] = name_of_last_ref.to_s
|
82
80
|
end
|
83
81
|
@settings.delete :ref
|
84
|
-
|
82
|
+
self
|
85
83
|
end
|
86
84
|
|
87
85
|
# Returns a new Hash that merges +downstream_hash+ with +upstream_hash+
|
@@ -96,7 +94,7 @@ class OM::XML::Term
|
|
96
94
|
up.delete(setting_name)
|
97
95
|
end
|
98
96
|
end
|
99
|
-
|
97
|
+
up.merge(dn)
|
100
98
|
end
|
101
99
|
|
102
100
|
# Builds a new OM::XML::Term based on the Builder object's current settings
|
@@ -121,31 +119,29 @@ class OM::XML::Term
|
|
121
119
|
term.generate_xpath_queries!
|
122
120
|
end
|
123
121
|
|
124
|
-
|
122
|
+
term
|
125
123
|
end
|
126
124
|
|
127
125
|
# :data_type accessor has been deprecated in favor of :type
|
128
126
|
# Any value set for :data_type will get set for :type instead
|
129
127
|
def data_type value
|
130
128
|
@settings[:type] = value
|
131
|
-
|
129
|
+
self
|
132
130
|
end
|
133
131
|
deprecation_deprecate :data_type
|
134
132
|
|
135
133
|
# We have to add this method so it will play nice with ruby 1.8.7
|
136
134
|
def type value
|
137
135
|
@settings[:type] = value
|
138
|
-
|
136
|
+
self
|
139
137
|
end
|
140
138
|
|
141
139
|
|
142
140
|
# Any unknown method calls will add an entry to the settings hash and return the current object
|
143
141
|
def method_missing method, *args, &block
|
144
|
-
if args.length == 1
|
145
|
-
args = args.first
|
146
|
-
end
|
142
|
+
args = args.first if args.length == 1
|
147
143
|
@settings[method] = args
|
148
|
-
|
144
|
+
self
|
149
145
|
end
|
150
146
|
end
|
151
147
|
|
@@ -197,9 +193,9 @@ class OM::XML::Term
|
|
197
193
|
# @param name [Symbol] the name to refer to this term by
|
198
194
|
# @param opts [Hash]
|
199
195
|
# @options opts [Array] :index_as a list of indexing hints provided to to_solr
|
200
|
-
# @options opts [String] :path partial xpath that points to the node.
|
201
|
-
# @options opts [Hash] :attributes xml attributes to match in the selector
|
202
|
-
# @options opts [String] :namespace_prefix xml namespace for this node
|
196
|
+
# @options opts [String] :path partial xpath that points to the node.
|
197
|
+
# @options opts [Hash] :attributes xml attributes to match in the selector
|
198
|
+
# @options opts [String] :namespace_prefix xml namespace for this node
|
203
199
|
# @options opts [Symbol] :type one of :string, :date, :integer. Defaults to :string
|
204
200
|
def initialize(name, opts={}, terminology=nil)
|
205
201
|
opts = {:ancestors=>[], :children=>{}}.merge(opts)
|
@@ -211,15 +207,11 @@ class OM::XML::Term
|
|
211
207
|
|
212
208
|
unless terminology.nil?
|
213
209
|
if opts[:namespace_prefix].nil?
|
214
|
-
unless terminology.namespaces["xmlns"].nil?
|
215
|
-
@namespace_prefix = "oxns"
|
216
|
-
end
|
210
|
+
@namespace_prefix = "oxns" unless terminology.namespaces["xmlns"].nil?
|
217
211
|
end
|
218
212
|
end
|
219
213
|
@name = name
|
220
|
-
if @path.nil? || @path.empty?
|
221
|
-
@path = name.to_s
|
222
|
-
end
|
214
|
+
@path = name.to_s if @path.nil? || @path.empty?
|
223
215
|
end
|
224
216
|
|
225
217
|
|
@@ -237,7 +229,7 @@ class OM::XML::Term
|
|
237
229
|
end
|
238
230
|
new_values
|
239
231
|
end
|
240
|
-
|
232
|
+
|
241
233
|
# @param val [String,Date,Integer]
|
242
234
|
def serialize (val)
|
243
235
|
case type
|
@@ -245,7 +237,7 @@ class OM::XML::Term
|
|
245
237
|
val.to_s
|
246
238
|
when :boolean
|
247
239
|
val.to_s
|
248
|
-
else
|
240
|
+
else
|
249
241
|
val
|
250
242
|
end
|
251
243
|
end
|
@@ -255,14 +247,14 @@ class OM::XML::Term
|
|
255
247
|
def deserialize(val)
|
256
248
|
case type
|
257
249
|
when :date
|
258
|
-
#TODO use present?
|
250
|
+
# TODO use present?
|
259
251
|
val.map { |v| !v.empty? ? Date.parse(v) : nil}
|
260
252
|
when :integer
|
261
|
-
#TODO use blank?
|
253
|
+
# TODO use blank?
|
262
254
|
val.map { |v| v.empty? ? nil : v.to_i}
|
263
255
|
when :boolean
|
264
256
|
val.map { |v| v == 'true' }
|
265
|
-
else
|
257
|
+
else
|
266
258
|
val
|
267
259
|
end
|
268
260
|
end
|
@@ -287,7 +279,7 @@ class OM::XML::Term
|
|
287
279
|
new_mapper.add_child(child)
|
288
280
|
end
|
289
281
|
|
290
|
-
|
282
|
+
new_mapper
|
291
283
|
end
|
292
284
|
|
293
285
|
##
|
@@ -312,7 +304,7 @@ class OM::XML::Term
|
|
312
304
|
return nil
|
313
305
|
end
|
314
306
|
end
|
315
|
-
|
307
|
+
target
|
316
308
|
end
|
317
309
|
|
318
310
|
def is_root_term?
|
@@ -336,7 +328,7 @@ class OM::XML::Term
|
|
336
328
|
else
|
337
329
|
node_options = ["\':::builder_new_value:::\'"]
|
338
330
|
end
|
339
|
-
|
331
|
+
unless self.attributes.nil?
|
340
332
|
self.attributes.merge(extra_attributes).each_pair do |k,v|
|
341
333
|
node_options << "\'#{k}\'=>\'#{v}\'" unless v == :none
|
342
334
|
end
|
@@ -346,7 +338,7 @@ class OM::XML::Term
|
|
346
338
|
if builder_method.include?(":")
|
347
339
|
builder_ref = "xml['#{self.path[0..path.index(":")-1]}']"
|
348
340
|
builder_method = self.path[path.index(":")+1..-1]
|
349
|
-
elsif !self.namespace_prefix.nil?
|
341
|
+
elsif !self.namespace_prefix.nil? && self.namespace_prefix != 'oxns'
|
350
342
|
builder_ref = "xml['#{self.namespace_prefix}']"
|
351
343
|
elsif self.path.kind_of?(Hash) && self.path[:attribute]
|
352
344
|
builder_method = "@#{self.path[:attribute]}"
|
@@ -355,7 +347,7 @@ class OM::XML::Term
|
|
355
347
|
builder_method += "_"
|
356
348
|
end
|
357
349
|
template = "#{builder_ref}.#{builder_method}( #{OM::XML.delimited_list(node_options)} )" + node_child_template
|
358
|
-
|
350
|
+
template.gsub( /:::(.*?):::/ ) { '#{'+$1+'}' }
|
359
351
|
end
|
360
352
|
|
361
353
|
# Generates absolute, relative, and constrained xpaths for the term, setting xpath, xpath_relative, and xpath_constrained accordingly.
|
@@ -365,7 +357,7 @@ class OM::XML::Term
|
|
365
357
|
self.xpath_constrained = OM::XML::TermXpathGenerator.generate_constrained_xpath(self)
|
366
358
|
self.xpath_relative = OM::XML::TermXpathGenerator.generate_relative_xpath(self)
|
367
359
|
self.children.each_value {|child| child.generate_xpath_queries! }
|
368
|
-
|
360
|
+
self
|
369
361
|
end
|
370
362
|
|
371
363
|
# Return an XML representation of the Term
|
@@ -380,9 +372,7 @@ class OM::XML::Term
|
|
380
372
|
def to_xml(options={}, document=Nokogiri::XML::Document.new)
|
381
373
|
builder = Nokogiri::XML::Builder.with(document) do |xml|
|
382
374
|
xml.term(:name=>name) {
|
383
|
-
if is_root_term?
|
384
|
-
xml.is_root_term("true")
|
385
|
-
end
|
375
|
+
xml.is_root_term("true") if is_root_term?
|
386
376
|
xml.path path
|
387
377
|
xml.namespace_prefix namespace_prefix
|
388
378
|
unless attributes.nil? || attributes.empty?
|
@@ -393,15 +383,11 @@ class OM::XML::Term
|
|
393
383
|
}
|
394
384
|
end
|
395
385
|
xml.index_as {
|
396
|
-
unless index_as.nil?
|
397
|
-
index_as.each { |index_type| xml.index_type }
|
398
|
-
end
|
386
|
+
index_as.each { |index_type| xml.index_type } unless index_as.nil?
|
399
387
|
}
|
400
388
|
xml.required required
|
401
389
|
xml.data_type type
|
402
|
-
unless variant_of.nil?
|
403
|
-
xml.variant_of variant_of
|
404
|
-
end
|
390
|
+
xml.variant_of variant_of unless variant_of.nil?
|
405
391
|
unless default_content_path.nil?
|
406
392
|
xml.default_content_path default_content_path
|
407
393
|
end
|
@@ -410,16 +396,14 @@ class OM::XML::Term
|
|
410
396
|
xml.absolute xpath
|
411
397
|
xml.constrained xpath_constrained
|
412
398
|
}
|
413
|
-
if options.fetch(:children, true)
|
414
|
-
xml.children
|
415
|
-
end
|
399
|
+
xml.children if options.fetch(:children, true)
|
416
400
|
}
|
417
401
|
end
|
418
402
|
doc = builder.doc
|
419
403
|
if options.fetch(:children, true)
|
420
404
|
children.values.each {|child| child.to_xml(options, doc.xpath("//term[@name=\"#{name}\"]/children").first)}
|
421
405
|
end
|
422
|
-
|
406
|
+
doc
|
423
407
|
end
|
424
408
|
|
425
409
|
# private :update_xpath_values
|
@@ -3,12 +3,12 @@ require "logger"
|
|
3
3
|
|
4
4
|
class OM::XML::ParentNodeNotFoundError < RuntimeError; end
|
5
5
|
module OM::XML::TermValueOperators
|
6
|
-
|
6
|
+
|
7
7
|
# Retrieves all of the nodes from the current document that match +term_pointer+ and returns an array of their values
|
8
8
|
def term_values(*term_pointer)
|
9
9
|
result = []
|
10
10
|
xpath = self.class.terminology.xpath_with_indexes(*term_pointer)
|
11
|
-
#if value is on line by itself sometimes does not trim leading and trailing whitespace for a text node so will detect and fix it
|
11
|
+
# if value is on line by itself sometimes does not trim leading and trailing whitespace for a text node so will detect and fix it
|
12
12
|
trim_text = !xpath.nil? && !xpath.index("text()").nil?
|
13
13
|
find_by_terms(*term_pointer).each {|node| result << (trim_text ? node.text.strip : node.text) }
|
14
14
|
|
@@ -20,61 +20,59 @@ module OM::XML::TermValueOperators
|
|
20
20
|
term.deserialize(result)
|
21
21
|
end
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
# alias for term_values
|
25
25
|
def property_values(*lookup_args)
|
26
26
|
term_values(*lookup_args)
|
27
27
|
end
|
28
|
-
|
29
|
-
#
|
28
|
+
|
29
|
+
#
|
30
30
|
# example term values hash: {[{":person"=>"0"}, "role", "text"]=>{"0"=>"role1", "1"=>"role2", "2"=>"role3"}, [{:person=>1}, :family_name]=>"Andronicus", [{"person"=>"1"},:given_name]=>["Titus"],[{:person=>1},:role,:text]=>["otherrole1","otherrole2"] }
|
31
31
|
def update_values(params={})
|
32
|
-
# remove any terms from params that this datastream doesn't recognize
|
33
|
-
|
34
|
-
params.delete_if do |term_pointer,new_values|
|
32
|
+
# remove any terms from params that this datastream doesn't recognize
|
33
|
+
|
34
|
+
params.delete_if do |term_pointer,new_values|
|
35
35
|
if term_pointer.kind_of?(String)
|
36
36
|
true
|
37
37
|
else
|
38
38
|
!self.class.terminology.has_term?(*OM.destringify(term_pointer))
|
39
39
|
end
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
result = params.dup
|
43
|
-
|
43
|
+
|
44
44
|
params.each_pair do |term_pointer,new_values|
|
45
45
|
pointer = OM.destringify(term_pointer)
|
46
46
|
template_pointer = OM.pointers_to_flat_array(pointer,false)
|
47
47
|
hn = OM::XML::Terminology.term_hierarchical_name(*pointer)
|
48
|
-
|
48
|
+
|
49
49
|
term = self.class.terminology.retrieve_term( *OM.pointers_to_flat_array(pointer,false) )
|
50
50
|
|
51
51
|
# Sanitize new_values to always be a hash with indexes
|
52
52
|
new_values = term.sanitize_new_values(new_values)
|
53
|
-
|
53
|
+
|
54
54
|
# Populate the response hash appropriately, using hierarchical names for terms as keys rather than the given pointers.
|
55
55
|
result.delete(term_pointer)
|
56
56
|
result[hn] = new_values.dup
|
57
|
-
|
57
|
+
|
58
58
|
# Skip any submitted values if the new value matches the current values
|
59
59
|
current_values = term_values(*pointer)
|
60
60
|
new_values.keys.sort { |a,b| a.to_i <=> b.to_i }.each do |y|
|
61
61
|
z = new_values[y]
|
62
|
-
if current_values[y.to_i]==z
|
63
|
-
|
64
|
-
|
65
|
-
end
|
66
|
-
|
62
|
+
new_values.delete(y) if current_values[y.to_i]==z && y.to_i > -1
|
63
|
+
end
|
64
|
+
|
67
65
|
# Fill out the pointer completely if the final term is a NamedTermProxy
|
68
66
|
if term.kind_of? OM::XML::NamedTermProxy
|
69
67
|
pointer.pop
|
70
68
|
pointer = pointer.concat(term.proxy_pointer)
|
71
69
|
end
|
72
|
-
|
70
|
+
|
73
71
|
xpath = self.class.terminology.xpath_with_indexes(*pointer)
|
74
72
|
parent_pointer = pointer.dup
|
75
73
|
parent_pointer.pop
|
76
74
|
parent_xpath = self.class.terminology.xpath_with_indexes(*parent_pointer)
|
77
|
-
|
75
|
+
|
78
76
|
# If the value doesn't exist yet, append it. Otherwise, update the existing value.
|
79
77
|
new_values.keys.sort { |a,b| a.to_i <=> b.to_i }.each do |y|
|
80
78
|
z = new_values[y]
|
@@ -89,18 +87,18 @@ module OM::XML::TermValueOperators
|
|
89
87
|
end
|
90
88
|
end
|
91
89
|
end
|
92
|
-
|
90
|
+
result
|
93
91
|
end
|
94
|
-
|
92
|
+
|
95
93
|
def term_values_append(opts={})
|
96
94
|
parent_select = Array( opts[:parent_select] )
|
97
95
|
parent_index = opts[:parent_index]
|
98
96
|
template = opts[:template]
|
99
|
-
new_values = Array( opts[:values] )
|
100
|
-
|
97
|
+
new_values = Array( opts[:values] )
|
98
|
+
|
101
99
|
parent_nodeset = find_by_terms(*parent_select)
|
102
100
|
parent_node = node_from_set(parent_nodeset, parent_index)
|
103
|
-
|
101
|
+
|
104
102
|
if parent_node.nil?
|
105
103
|
if parent_select.empty?
|
106
104
|
parent_node = ng_xml.root
|
@@ -110,12 +108,12 @@ module OM::XML::TermValueOperators
|
|
110
108
|
end
|
111
109
|
|
112
110
|
insert_from_template(parent_node, new_values, template)
|
113
|
-
|
114
|
-
|
115
|
-
|
111
|
+
|
112
|
+
parent_node
|
113
|
+
|
116
114
|
end
|
117
115
|
|
118
|
-
# Insert xml containing +new_values+ into +parent_node+. Generate the xml based on +template+
|
116
|
+
# Insert xml containing +new_values+ into +parent_node+. Generate the xml based on +template+
|
119
117
|
# @param [Nokogiri::XML::Node] parent_node to insert new xml into
|
120
118
|
# @param [Array] new_values to build the xml around
|
121
119
|
# @param [Array -- (OM term pointer array) OR String -- (like what you would pass into Nokogiri::XML::Builder.new)] template for building the new xml. Use the syntax that Nokogiri::XML::Builder uses.
|
@@ -133,23 +131,23 @@ module OM::XML::TermValueOperators
|
|
133
131
|
template = self.class.terminology.xml_builder_template( *template_args )
|
134
132
|
end
|
135
133
|
|
136
|
-
#if there is an xpath element pointing to text() need to change to just 'text' so it references the text method for the parent node
|
134
|
+
# if there is an xpath element pointing to text() need to change to just 'text' so it references the text method for the parent node
|
137
135
|
template.gsub!(/text\(\)/, 'text')
|
138
|
-
|
136
|
+
|
139
137
|
builder = Nokogiri::XML::Builder.with(parent_node) do |xml|
|
140
138
|
new_values.each do |builder_new_value|
|
141
139
|
builder_new_value = builder_new_value.gsub(/'/, "\\\\'") # escape any apostrophes in the new value
|
142
140
|
if matchdata = /xml\.@(\w+)/.match(template)
|
143
141
|
parent_node.set_attribute(matchdata[1], builder_new_value)
|
144
|
-
else
|
142
|
+
else
|
145
143
|
builder_arg = eval('"'+ template + '"') # this inserts builder_new_value into the builder template
|
146
144
|
eval(builder_arg)
|
147
145
|
end
|
148
146
|
end
|
149
147
|
end
|
150
|
-
|
148
|
+
parent_node
|
151
149
|
end
|
152
|
-
|
150
|
+
|
153
151
|
# Creates necesary ancestor nodes to support inserting a new term value where the ancestor node(s) don't exist yet.
|
154
152
|
# Corrects node indexes in the pointer array to correspond to the ancestors that it creates.
|
155
153
|
# Returns a two-value array with the 'parent' node and a corrected pointer array
|
@@ -159,20 +157,18 @@ module OM::XML::TermValueOperators
|
|
159
157
|
parent_select = Array(parent_select)
|
160
158
|
parent_nodeset = find_by_terms(*parent_select)
|
161
159
|
starting_point = node_from_set(parent_nodeset, parent_index)
|
162
|
-
if starting_point.nil?
|
163
|
-
starting_point = []
|
164
|
-
end
|
160
|
+
starting_point = [] if starting_point.nil?
|
165
161
|
to_build = []
|
166
|
-
|
162
|
+
while starting_point.empty?
|
167
163
|
to_build = [parent_select.pop] + to_build
|
168
164
|
starting_point = find_by_terms(*parent_select)
|
169
|
-
if starting_point.empty? && parent_select.empty?
|
165
|
+
if starting_point.empty? && parent_select.empty?
|
170
166
|
raise OM::XML::TemplateMissingException, "Cannot insert nodes into the document because it is empty. Try defining self.xml_template on the #{self.class} class."
|
171
167
|
end
|
172
168
|
end
|
173
|
-
to_build.each do |term_pointer|
|
169
|
+
to_build.each do |term_pointer|
|
174
170
|
parent_select << term_pointer
|
175
|
-
|
171
|
+
|
176
172
|
# If pointers in parent_select don't match with the indexes of built ancestors, correct the hash
|
177
173
|
if find_by_terms(*parent_select+[{}]).length == 0
|
178
174
|
if parent_select.last.kind_of?(Hash)
|
@@ -198,13 +194,13 @@ module OM::XML::TermValueOperators
|
|
198
194
|
if parent_index > starting_point.length
|
199
195
|
parent_index = starting_point.length - 1
|
200
196
|
end
|
201
|
-
|
197
|
+
node_from_set(starting_point, parent_index)
|
202
198
|
end
|
203
|
-
|
199
|
+
|
204
200
|
def term_value_update(node_select,node_index,new_value,opts={})
|
205
201
|
ng_xml_will_change!
|
206
202
|
# template = opts.fetch(:template,nil)
|
207
|
-
|
203
|
+
|
208
204
|
node = find_by_terms_and_value(*node_select)[node_index]
|
209
205
|
if delete_on_update?(node, new_value)
|
210
206
|
node.remove
|
@@ -216,23 +212,23 @@ module OM::XML::TermValueOperators
|
|
216
212
|
def delete_on_update?(node, new_value)
|
217
213
|
new_value == "" || new_value == :delete
|
218
214
|
end
|
219
|
-
|
215
|
+
|
220
216
|
# def term_value_set(term_ref, query_opts, node_index, new_value)
|
221
217
|
# end
|
222
|
-
|
218
|
+
|
223
219
|
def term_value_delete(opts={})
|
224
220
|
ng_xml_will_change!
|
225
221
|
parent_select = Array( opts[:parent_select] )
|
226
222
|
parent_index = opts[:parent_index]
|
227
223
|
child_index = opts[:child_index]
|
228
224
|
xpath_select = opts[:select]
|
229
|
-
|
225
|
+
|
230
226
|
if !xpath_select.nil?
|
231
227
|
node = find_by_terms_and_value(xpath_select).first
|
232
228
|
else
|
233
229
|
# parent_nodeset = find_by_terms_and_value(parent_select, parent_select)
|
234
230
|
parent_nodeset = find_by_terms_and_value(*parent_select)
|
235
|
-
|
231
|
+
|
236
232
|
if parent_index.nil?
|
237
233
|
node = node_from_set(parent_nodeset, child_index)
|
238
234
|
else
|
@@ -241,24 +237,24 @@ module OM::XML::TermValueOperators
|
|
241
237
|
node = node_from_set(parent.xpath("*"), child_index)
|
242
238
|
end
|
243
239
|
end
|
244
|
-
|
240
|
+
|
245
241
|
node.remove
|
246
242
|
end
|
247
|
-
|
248
|
-
|
243
|
+
|
244
|
+
|
249
245
|
# Allows you to provide an array index _or_ a symbol representing the function to call on the nodeset in order to retrieve the node.
|
250
246
|
def node_from_set(nodeset, index)
|
251
247
|
if index.kind_of?(Integer)
|
252
248
|
node = nodeset[index]
|
253
|
-
elsif index.kind_of?(Symbol) && nodeset.respond_to?(index)
|
249
|
+
elsif index.kind_of?(Symbol) && nodeset.respond_to?(index)
|
254
250
|
node = nodeset.send(index)
|
255
251
|
else
|
256
252
|
raise "Could not retrieve node using index #{index}."
|
257
253
|
end
|
258
|
-
|
259
|
-
|
254
|
+
|
255
|
+
node
|
260
256
|
end
|
261
|
-
|
257
|
+
|
262
258
|
private :node_from_set
|
263
|
-
|
259
|
+
|
264
260
|
end
|