om 1.0.2 → 1.1.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.
@@ -1,399 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
- require "om"
3
-
4
- describe "OM::XML::PropertyValueOperators" do
5
-
6
- before(:all) do
7
- #ModsHelpers.name_("Beethoven, Ludwig van", :date=>"1770-1827", :role=>"creator")
8
- class PropertiesValueOperatorsTest
9
-
10
- include OM::XML::Container
11
- include OM::XML::Accessors
12
- include OM::XML::Properties
13
- include OM::XML::PropertyValueOperators
14
-
15
-
16
- # Could add support for multiple root declarations.
17
- # For now, assume that any modsCollections have already been broken up and fed in as individual mods documents
18
- # root :mods_collection, :path=>"modsCollection",
19
- # :attributes=>[],
20
- # :subelements => :mods
21
-
22
- root_property :mods, "mods", "http://www.loc.gov/mods/v3", :attributes=>["id", "version"], :schema=>"http://www.loc.gov/standards/mods/v3/mods-3-2.xsd"
23
-
24
- property :title_info, :path=>"titleInfo",
25
- :convenience_methods => {
26
- :main_title => {:path=>"title"},
27
- :language => {:path=>"@lang"},
28
- }
29
-
30
- property :name_, :path=>"name",
31
- :attributes=>[:xlink, :lang, "xml:lang", :script, :transliteration, {:type=>["personal", "enumerated", "corporate"]} ],
32
- :subelements=>["namePart", "displayForm", "affiliation", :role, "description"],
33
- :default_content_path => "namePart",
34
- :convenience_methods => {
35
- :date => {:path=>"namePart", :attributes=>{:type=>"date"}},
36
- :family_name => {:path=>"namePart", :attributes=>{:type=>"family"}},
37
- :first_name => {:path=>"namePart", :attributes=>{:type=>"given"}},
38
- :terms_of_address => {:path=>"namePart", :attributes=>{:type=>"termsOfAddress"}}
39
- }
40
-
41
- property :person, :variant_of=>:name_, :attributes=>{:type=>"personal"}
42
-
43
- property :role, :path=>"role",
44
- :parents=>[:name_],
45
- :attributes=>[ { "type"=>["text", "code"] } , "authority"],
46
- :convenience_methods => {
47
- :text => {:path=>"roleTerm", :attributes=>{:type=>"text"}},
48
- :code => {:path=>"roleTerm", :attributes=>{:type=>"code"}},
49
- }
50
-
51
- generate_accessors_from_properties
52
-
53
- end
54
-
55
- end
56
-
57
- before(:each) do
58
- @sample = PropertiesValueOperatorsTest.from_xml( fixture( File.join("test_dummy_mods.xml") ) )
59
- end
60
-
61
- after(:all) do
62
- Object.send(:remove_const, :PropertiesValueOperatorsTest)
63
- end
64
-
65
- describe ".property_values" do
66
-
67
- it "should call .lookup and then build an array of values from the returned nodeset (using default_node, etc as nessesary)" do
68
- lookup_opts = "insert args here"
69
- mock_node = mock("node")
70
- mock_node.expects(:text).returns("sample value").times(3)
71
- mock_nodeset = [mock_node, mock_node, mock_node]
72
- @sample.expects(:retrieve).with(*lookup_opts).returns(mock_nodeset)
73
-
74
- @sample.property_values(lookup_opts).should == ["sample value","sample value","sample value"]
75
- end
76
-
77
- end
78
-
79
-
80
- describe ".update_properties" do
81
- before(:each) do
82
- @article = PropertiesValueOperatorsTest.from_xml( fixture( File.join("mods_articles","hydrangea_article1.xml") ) )
83
- end
84
- it "should update the xml according to the lookups in the given hash" do
85
- properties_update_hash = {[{":person"=>"0"}, "affiliation"]=>{"0"=>"affiliation1", "1"=>"affiliation2", "2"=>"affiliation3"}, [{:person=>1}, :family_name]=>"Andronicus", [{"person"=>"1"},:first_name]=>["Titus"],[{:person=>1},:role]=>["otherrole1","otherrole2"] }
86
- result = @article.update_properties(properties_update_hash)
87
- result.should == {"person_0_affiliation"=>{"0"=>"affiliation1", "1"=>"affiliation2", "2"=>"affiliation3"}, "person_1_family_name"=>{"0"=>"Andronicus"},"person_1_first_name"=>{"0"=>"Titus"}, "person_1_role"=>{"0"=>"otherrole1","1"=>"otherrole2"}}
88
- person_0_affiliation = @article.retrieve({:person=>0}, :affiliation)
89
- person_0_affiliation[0].text.should == "affiliation1"
90
- person_0_affiliation[1].text.should == "affiliation2"
91
- person_0_affiliation[2].text.should == "affiliation3"
92
-
93
- person_1_family_names = @article.retrieve({:person=>1}, :family_name)
94
- person_1_family_names.length.should == 1
95
- person_1_family_names.first.text.should == "Andronicus"
96
-
97
- person_1_first_names = @article.retrieve({:person=>1}, :first_name)
98
- person_1_first_names.first.text.should == "Titus"
99
-
100
- person_1_roles = @article.retrieve({:person=>1}, :role)
101
- person_1_roles[0].text.should == "otherrole1"
102
- person_1_roles[1].text.should == "otherrole2"
103
- end
104
- it "should call property_value_update if the corresponding node already exists" do
105
- @article.expects(:property_value_update).with('//oxns:titleInfo/oxns:title', 0, "My New Title")
106
- @article.update_properties( {[:title_info, :main_title] => "My New Title"} )
107
- end
108
- it "should call property_values_append if the corresponding node does not already exist or if the requested index is -1" do
109
- expected_args = {
110
- :parent_select => PropertiesValueOperatorsTest.accessor_xpath(*[{:person=>0}]) ,
111
- :child_index => 0,
112
- :template => [:person, :role],
113
- :values => "My New Role"
114
- }
115
- @article.expects(:property_values_append).with(expected_args).times(2)
116
- @article.update_properties( {[{:person=>0}, :role] => {"4"=>"My New Role"}} )
117
- @article.update_properties( {[{:person=>0}, :role] => {"-1"=>"My New Role"}} )
118
- end
119
- it "should call property_value_delete where appropriate"
120
-
121
- it "should destringify the field key/lookup pointer" do
122
- PropertiesValueOperatorsTest.expects(:accessor_xpath).with( *[{:person=>0}, :role]).times(10).returns("//oxns:name[@type=\"personal\"][1]/oxns:role")
123
- PropertiesValueOperatorsTest.stubs(:accessor_xpath).with( *[{:person=>0}]).returns("//oxns:name[@type=\"personal\"][1]")
124
- @article.update_properties( { [{":person"=>"0"}, "role"]=>"the role" } )
125
- @article.update_properties( { [{"person"=>"0"}, "role"]=>"the role" } )
126
- @article.update_properties( { [{:person=>0}, :role]=>"the role" } )
127
- end
128
-
129
- ### Examples copied over form nokogiri_datastream_spec
130
-
131
- it "should apply submitted hash to corresponding datastream field values" do
132
- result = @article.update_properties( {[{":person"=>"0"}, "first_name"]=>{"0"=>"Billy", "1"=>"Bob", "2"=>"Joe"} })
133
- result.should == {"person_0_first_name"=>{"0"=>"Billy", "1"=>"Bob", "2"=>"Joe"}}
134
- # xpath = ds.class.accessor_xpath(*field_key)
135
- # result = ds.property_values(xpath)
136
- @article.property_values({:person=>0}, :first_name).should == ["Billy","Bob","Joe"]
137
- @article.property_values('//oxns:name[@type="personal"][1]/oxns:namePart[@type="given"]').should == ["Billy","Bob","Joe"]
138
- end
139
- it "should support single-value arguments (as opposed to a hash of values with array indexes as keys)" do
140
- # In other words, { "fubar"=>"dork" } should have the same effect as { "fubar"=>{"0"=>"dork"} }
141
- result = @article.update_properties( { [{":person"=>"0"}, "role"]=>"the role" } )
142
- result.should == {"person_0_role"=>{"0"=>"the role"}}
143
- @article.property_values({:person=>0}, :role).first.should == "the role"
144
- @article.property_values('//oxns:name[@type="personal"][1]/oxns:role').first.should == "the role"
145
- end
146
- it "should do nothing if field key is a string (must be an array or symbol). Will not accept xpath queries!" do
147
- xml_before = @article.to_xml
148
- @article.update_properties( { "fubar"=>"the role" } ).should == {}
149
- @article.to_xml.should == xml_before
150
- end
151
- it "should do nothing if there is no accessor corresponding to the given field key" do
152
- xml_before = @article.to_xml
153
- @article.update_properties( { [{"fubar"=>"0"}]=>"the role" } ).should == {}
154
- @article.to_xml.should == xml_before
155
- end
156
-
157
- ### Examples copied over form metadata_datastream_spec
158
-
159
- # it "should support single-value arguments (as opposed to a hash of values with array indexes as keys)" do
160
- # # In other words, { "fubar"=>"dork" } should have the same effect as { "fubar"=>{"0"=>"dork"} }
161
- # pending "this should be working, but for some reason, the updates don't stick"
162
- # result = @test_ds.update_indexed_attributes( { "fubar"=>"dork" } )
163
- # result.should == {"fubar"=>{"0"=>"dork"}}
164
- # @test_ds.fubar_values.should == ["dork"]
165
- # end
166
- #
167
- it "should work for text fields" do
168
- att= {[{"person"=>"0"},"description"]=>{"-1"=>"mork", "1"=>"york"}}
169
- result = @article.update_properties(att)
170
- result.should == {"person_0_description"=>{"0"=>"mork","1"=>"york"}}
171
- @article.property_values({:person=>0},:description).should == ['mork', 'york']
172
- att= {[{"person"=>"0"},"description"]=>{"-1"=>"dork"}}
173
- result2 = @article.update_properties(att)
174
- result2.should == {"person_0_description"=>{"2"=>"dork"}}
175
- @article.property_values({:person=>0},:description).should == ['mork', 'york', 'dork']
176
- end
177
-
178
- it "should return the new index of any added values" do
179
- @article.property_values({:title_info=>0},:main_title).should == ["ARTICLE TITLE HYDRANGEA ARTICLE 1", "TITLE OF HOST JOURNAL"]
180
- result = @article.update_properties [{"title_info"=>"0"},"main_title"]=>{"-1"=>"mork"}
181
- result.should == {"title_info_0_main_title"=>{"2"=>"mork"}}
182
- end
183
- #
184
- # it "should return accurate response when multiple values have been added in a single run" do
185
- # pending
186
- # att= {"swank"=>{"-1"=>"mork", "0"=>"york"}}
187
- # @test_ds.update_indexed_attributes(att).should == {"swank"=>{"0"=>"york", "1"=>"mork"}}
188
- # end
189
-
190
- # it "should deal gracefully with adding new values at explicitly declared indexes" do
191
- # @article.update_properties([:journal, :title]=>["all", "for", "the"]
192
- # att = {"fubar"=>{"3"=>'glory'}}
193
- # result = @test_ds.update_indexed_attributes(att)
194
- # result.should == {"fubar"=>{"3"=>"glory"}}
195
- # @test_ds.fubar_values.should == ["all", "for", "the", "glory"]
196
- #
197
- # @test_ds.fubar_values = []
198
- # result = @test_ds.update_indexed_attributes(att)
199
- # result.should == {"fubar"=>{"0"=>"glory"}}
200
- # @test_ds.fubar_values.should == ["glory"]
201
- # end
202
- #
203
- # it "should allow deleting of values and should delete values so that to_xml does not return emtpy nodes" do
204
- # att= {"fubar"=>{"-1"=>"mork", "0"=>"york", "1"=>"mangle"}}
205
- # @test_ds.update_indexed_attributes(att)
206
- # @test_ds.fubar_values.should == ['mork', 'york', 'mangle']
207
- # rexml = REXML::Document.new(@test_ds.to_xml)
208
- # #puts rexml.root.elements.each {|el| el.to_s}
209
- # #puts rexml.root.elements.to_a.inspect
210
- # rexml.root.elements.to_a.length.should == 3
211
- # @test_ds.update_indexed_attributes({"fubar"=>{"1"=>""}})
212
- # @test_ds.fubar_values.should == ['mork', 'mangle']
213
- # rexml = REXML::Document.new(@test_ds.to_xml)
214
- # rexml.root.elements.to_a.length.should == 2
215
- # @test_ds.update_indexed_attributes({"fubar"=>{"0"=>:delete}})
216
- # @test_ds.fubar_values.should == ['mangle']
217
- # rexml = REXML::Document.new(@test_ds.to_xml)
218
- # rexml.root.elements.to_a.length.should == 1
219
- #
220
- # @test_ds.fubar_values = ["val1", nil, "val2"]
221
- # @test_ds.update_indexed_attributes({"fubar"=>{"1"=>""}})
222
- # @test_ds.fubar_values.should == ["val1", "val2"]
223
- # end
224
-
225
- end
226
-
227
- describe ".property_values_append" do
228
-
229
- it "looks up the parent using :parent_select, uses :child_index to choose the parent node from the result set, uses :template to build the node(s) to be inserted, inserts the :values(s) into the node(s) and adds the node(s) to the parent" do
230
- @sample.property_values_append(
231
- :parent_select => [:person, {:first_name=>"Tim", :family_name=>"Berners-Lee"}] ,
232
- :child_index => :first,
233
- :template => [:person, :affiliation],
234
- :values => ["my new value", "another new value"]
235
- )
236
- end
237
-
238
- it "should accept parent_select and template [property_reference, lookup_opts] as argument arrays for generators/lookups" do
239
- # this appends two affiliation nodes into the first person node whose name is Tim Berners-Lee
240
- expected_result = '<ns3:name type="personal">
241
- <ns3:namePart type="family">Berners-Lee</ns3:namePart>
242
- <ns3:namePart type="given">Tim</ns3:namePart>
243
- <ns3:role>
244
- <ns3:roleTerm type="text" authority="marcrelator">creator</ns3:roleTerm>
245
- <ns3:roleTerm type="code" authority="marcrelator">cre</ns3:roleTerm>
246
- </ns3:role>
247
- <ns3:affiliation>my new value</ns3:affiliation><ns3:affiliation>another new value</ns3:affiliation></ns3:name>'
248
-
249
- @sample.property_values_append(
250
- :parent_select => [:person, {:first_name=>"Tim", :family_name=>"Berners-Lee"}] ,
251
- :child_index => :first,
252
- :template => [:person, :affiliation],
253
- :values => ["my new value", "another new value"]
254
- ).to_xml.should == expected_result
255
-
256
- @sample.lookup(:person, {:first_name=>"Tim", :family_name=>"Berners-Lee"}).first.to_xml.should == expected_result
257
- end
258
-
259
- it "should accept symbols as arguments for generators/lookups" do
260
- # this appends a role of "my role" into the third "person" node in the document
261
- @sample.property_values_append(
262
- :parent_select => :person ,
263
- :child_index => 3,
264
- :template => :role,
265
- :values => "my role"
266
- ).to_xml.should #== expected_result
267
- @sample.lookup(:person)[3].search("./ns3:role[3]").first.text.should == "my role"
268
- end
269
-
270
- it "should accept parent_select as an (xpath) string and template as a (template) string" do
271
- # this uses the provided template to add a node into the first node resulting from the xpath '//oxns:name[@type="personal"]'
272
- expected_result = "<ns3:name type=\"personal\">\n <ns3:namePart type=\"family\">Berners-Lee</ns3:namePart>\n <ns3:namePart type=\"given\">Tim</ns3:namePart>\n <ns3:role>\n <ns3:roleTerm type=\"text\" authority=\"marcrelator\">creator</ns3:roleTerm>\n <ns3:roleTerm type=\"code\" authority=\"marcrelator\">cre</ns3:roleTerm>\n </ns3:role>\n <ns3:role type=\"code\" authority=\"marcrelator\"><ns3:roleTerm>creator</ns3:roleTerm></ns3:role></ns3:name>"
273
-
274
- @sample.ng_xml.xpath('//oxns:name[@type="personal" and position()=1]/oxns:role', @sample.ox_namespaces).length.should == 1
275
-
276
- @sample.property_values_append(
277
- :parent_select =>'//oxns:name[@type="personal"]',
278
- :child_index => 0,
279
- :template => 'xml.role { xml.roleTerm( \'#{builder_new_value}\', :type=>\'code\', :authority=>\'marcrelator\') }',
280
- :values => "founder"
281
- )
282
-
283
- @sample.ng_xml.xpath('//oxns:name[@type="personal" and position()=1]/oxns:role', @sample.ox_namespaces).length.should == 2
284
- @sample.ng_xml.xpath('//oxns:name[@type="personal" and position()=1]/oxns:role[last()]/oxns:roleTerm', @sample.ox_namespaces).first.text.should == "founder"
285
-
286
- # @sample.lookup(:person).first.to_xml.should == expected_result
287
- end
288
-
289
- it "should support more complex mixing & matching" do
290
- pending "not working because builder_template is not returning the correct template (returns builder for role instead of roleTerm)"
291
- @sample.ng_xml.xpath('//oxns:name[@type="personal"][2]/oxns:role[1]/oxns:roleTerm', @sample.ox_namespaces).length.should == 2
292
- @sample.property_values_append(
293
- :parent_select =>'//oxns:name[@type="personal"][2]/oxns:role',
294
- :child_index => 0,
295
- :template => [ :person, :role, :text, {:attributes=>{"authority"=>"marcrelator"}} ],
296
- :values => "foo"
297
- )
298
-
299
- @sample.ng_xml.xpath('//oxns:name[@type="personal"][2]/oxns:role[1]/oxns:roleTerm', @sample.ox_namespaces).length.should == 3
300
- @sample.retrieve({:person=>1},:role)[0].search("./oxns:roleTerm[@type=\"text\" and @authority=\"marcrelator\"]", @sample.ox_namespaces).first.text.should == "foo"
301
- end
302
-
303
- it "should raise exception if no node corresponds to the provided :parent_select and :child_index"
304
-
305
- end
306
-
307
- describe ".property_value_update" do
308
-
309
- it "should accept an xpath as :parent_select" do
310
- sample_xpath = '//oxns:name[@type="personal"][4]/oxns:role/oxns:roleTerm[@type="text"]'
311
- @sample.property_value_update(sample_xpath,1,"artist")
312
-
313
- # @sample.property_value_update(
314
- # :parent_select =>sample_xpath,
315
- # :child_index => 1,
316
- # :value => "donor"
317
- # )
318
-
319
- @sample.ng_xml.xpath(sample_xpath, @sample.ox_namespaces)[1].text.should == "artist"
320
- end
321
-
322
- it "if :select is provided, should update the first node provided by that xpath statement" do
323
- sample_xpath = '//oxns:name[@type="personal"][1]/oxns:namePart[@type="given"]'
324
- @sample.property_value_update(sample_xpath,0,"Timmeh")
325
- @sample.ng_xml.xpath(sample_xpath, @sample.ox_namespaces).first.text.should == "Timmeh"
326
- end
327
-
328
- it "should replace the existing node if you pass a template and values" do
329
- pending
330
- @sample.property_value_update(
331
- :parent_select =>'//oxns:name[@type="personal"]',
332
- :child_index => 1,
333
- :template => [ :person, :role, {:attributes=>{"type"=>"code", "authority"=>"marcrelator"}} ],
334
- :value => "foo"
335
- )
336
- 1.should == 2
337
- end
338
- end
339
-
340
- describe ".property_value_delete" do
341
- it "should accept an xpath query as :select option" do
342
- generic_xpath = '//oxns:name[@type="personal" and position()=4]/oxns:role'
343
- specific_xpath = '//oxns:name[@type="personal" and position()=4]/oxns:role[oxns:roleTerm="visionary"]'
344
- select_xpath = '//oxns:name[@type="personal" and position()=4]/oxns:role[last()]'
345
-
346
- # Check that we're starting with 2 roles
347
- # Check that the specific node we want to delete exists
348
- @sample.lookup(generic_xpath).length.should == 2
349
- @sample.lookup(specific_xpath).length.should == 1
350
-
351
- @sample.property_value_delete(
352
- :select =>select_xpath
353
- )
354
- # Check that we're finishing with 1 role
355
- @sample.lookup(generic_xpath).length.should == 1
356
- # Check that the specific node we want to delete no longer exists
357
- @sample.lookup(specific_xpath).length.should == 0
358
- end
359
- it "should accept :parent_select, :parent_index and :child_index options instead of a :select" do
360
-
361
- generic_xpath = '//oxns:name[@type="personal" and position()=4]/oxns:role/oxns:roleTerm'
362
- specific_xpath = '//oxns:name[@type="personal" and position()=4]/oxns:role[oxns:roleTerm="visionary"]'
363
-
364
- # Check that we're starting with 2 roles
365
- # Check that the specific node we want to delete exists
366
- @sample.lookup(generic_xpath).length.should == 4
367
- @sample.lookup(specific_xpath).length.should == 1
368
-
369
- # this is attempting to delete the last child (in this case roleTerm) from the 3rd role in the document.
370
- @sample.property_value_delete(
371
- :parent_select => [:person, :role],
372
- :parent_index => 3,
373
- :child_index => :last
374
- )
375
-
376
- # Check that we're finishing with 1 role
377
- @sample.lookup(generic_xpath).length.should == 3
378
- # Check that the specific node we want to delete no longer exists
379
- @sample.lookup(specific_xpath).length.should == 1
380
- end
381
- it "should work if only :parent_select and :child_index are provided" do
382
- generic_xpath = '//oxns:name[@type="personal"]/oxns:role'
383
- # specific_xpath = '//oxns:name[@type="personal"]/oxns:role'
384
-
385
- # Check that we're starting with 2 roles
386
- # Check that the specific node we want to delete exists
387
- @sample.lookup(generic_xpath).length.should == 4
388
- # @sample.lookup(specific_xpath).length.should == 1
389
-
390
- @sample.property_value_delete(
391
- :parent_select => [:person, :role],
392
- :child_index => 3
393
- )
394
- # Check that we're finishing with 1 role
395
- @sample.lookup(generic_xpath).length.should == 3
396
- end
397
- end
398
-
399
- end