om 1.6.1 → 1.7.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +31 -19
- data/History.textile +3 -0
- data/devel/notes.txt +12 -0
- data/lib/om.rb +2 -0
- data/lib/om/version.rb +1 -1
- data/lib/om/xml/container.rb +7 -6
- data/lib/om/xml/document.rb +47 -31
- data/lib/om/xml/dynamic_node.rb +36 -6
- data/lib/om/xml/named_term_proxy.rb +9 -2
- data/lib/om/xml/term.rb +22 -1
- data/lib/om/xml/term_value_operators.rb +8 -1
- data/lib/om/xml/validation.rb +2 -5
- data/om.gemspec +3 -0
- data/spec/integration/serialization_spec.rb +53 -0
- data/spec/unit/container_spec.rb +21 -17
- data/spec/unit/dynamic_node_spec.rb +4 -1
- data/spec/unit/nokogiri_sanity_spec.rb +3 -0
- data/spec/unit/term_spec.rb +205 -166
- data/spec/unit/term_value_operators_spec.rb +21 -1
- data/spec/unit/terminology_builder_spec.rb +3 -1
- data/spec/unit/terminology_spec.rb +9 -3
- metadata +57 -6
@@ -122,6 +122,7 @@ module OM::XML::TermValueOperators
|
|
122
122
|
# @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.
|
123
123
|
# @return [Nokogiri::XML::Node] the parent_node with new chldren inserted into it
|
124
124
|
def insert_from_template(parent_node, new_values, template)
|
125
|
+
ng_xml_will_change!
|
125
126
|
# If template is a string, use it as the template, otherwise use it as arguments to xml_builder_template
|
126
127
|
unless template.instance_of?(String)
|
127
128
|
template_args = Array(template)
|
@@ -202,20 +203,26 @@ module OM::XML::TermValueOperators
|
|
202
203
|
end
|
203
204
|
|
204
205
|
def term_value_update(node_select,node_index,new_value,opts={})
|
206
|
+
ng_xml_will_change!
|
205
207
|
# template = opts.fetch(:template,nil)
|
206
208
|
|
207
209
|
node = find_by_terms_and_value(*node_select)[node_index]
|
208
|
-
if
|
210
|
+
if delete_on_update?(node, new_value)
|
209
211
|
node.remove
|
210
212
|
else
|
211
213
|
node.content = new_value
|
212
214
|
end
|
213
215
|
end
|
216
|
+
|
217
|
+
def delete_on_update?(node, new_value)
|
218
|
+
new_value == "" || new_value == :delete
|
219
|
+
end
|
214
220
|
|
215
221
|
# def term_value_set(term_ref, query_opts, node_index, new_value)
|
216
222
|
# end
|
217
223
|
|
218
224
|
def term_value_delete(opts={})
|
225
|
+
ng_xml_will_change!
|
219
226
|
parent_select = Array( opts[:parent_select] )
|
220
227
|
parent_index = opts[:parent_index]
|
221
228
|
child_index = opts[:child_index]
|
data/lib/om/xml/validation.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
module OM::XML::Validation
|
2
|
+
extend ActiveSupport::Concern
|
2
3
|
|
3
4
|
# Class Methods -- These methods will be available on classes that include this Module
|
4
5
|
|
@@ -52,12 +53,8 @@ module OM::XML::Validation
|
|
52
53
|
|
53
54
|
# Instance Methods -- These methods will be available on instances of classes that include this module
|
54
55
|
|
55
|
-
def self.included(klass)
|
56
|
-
klass.extend(ClassMethods)
|
57
|
-
end
|
58
|
-
|
59
56
|
def validate
|
60
57
|
self.class.validate(self)
|
61
58
|
end
|
62
59
|
|
63
|
-
end
|
60
|
+
end
|
data/om.gemspec
CHANGED
@@ -12,10 +12,13 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.summary = %q{OM (Opinionated Metadata): A library to help you tame sprawling XML schemas like MODS.}
|
13
13
|
s.description = %q{OM (Opinionated Metadata): A library to help you tame sprawling XML schemas like MODS. Wraps Nokogiri documents in objects with miscellaneous helper methods for doing things like retrieve generated xpath queries or look up properties based on a simplified DSL}
|
14
14
|
|
15
|
+
s.add_dependency 'activesupport'
|
16
|
+
s.add_dependency 'activemodel'
|
15
17
|
s.add_dependency('nokogiri', ">= 1.4.2")
|
16
18
|
s.add_dependency('mediashelf-loggable')
|
17
19
|
s.add_development_dependency "rspec", "~> 2.0"
|
18
20
|
s.add_development_dependency "rake"
|
21
|
+
s.add_development_dependency "awesome_print"
|
19
22
|
s.add_development_dependency "mocha", ">= 0.9.8"
|
20
23
|
s.add_development_dependency "equivalent-xml", ">= 0.2.4"
|
21
24
|
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "element values" do
|
4
|
+
before(:all) do
|
5
|
+
class ElementValueTerminology
|
6
|
+
include OM::XML::Document
|
7
|
+
|
8
|
+
set_terminology do |t|
|
9
|
+
t.root(:path => "outer", :xmlns => nil)
|
10
|
+
t.my_date(:type=>:date)
|
11
|
+
t.my_int(:type=>:integer)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
subject do
|
17
|
+
ElementValueTerminology.from_xml <<-EOF
|
18
|
+
<outer outerId="hypatia:outer" type="outer type">
|
19
|
+
<my_date>2012-10-30</my_date>
|
20
|
+
<my_int>7</my_int>
|
21
|
+
</outer>
|
22
|
+
EOF
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "Reading from xml" do
|
26
|
+
it "should handle date" do
|
27
|
+
subject.my_date.should == [Date.parse('2012-10-30')]
|
28
|
+
end
|
29
|
+
it "should handle ints" do
|
30
|
+
subject.my_int.should == [7]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
describe "Writing to xml" do
|
34
|
+
it "should handle date" do
|
35
|
+
subject.my_date = [Date.parse('2012-09-22')]
|
36
|
+
subject.to_xml.should be_equivalent_to '<?xml version="1.0"?>
|
37
|
+
<outer outerId="hypatia:outer" type="outer type">
|
38
|
+
<my_date>2012-09-22</my_date>
|
39
|
+
<my_int>7</my_int>
|
40
|
+
</outer>'
|
41
|
+
end
|
42
|
+
it "should handle ints" do
|
43
|
+
subject.my_int = [9]
|
44
|
+
subject.to_xml.should be_equivalent_to '<?xml version="1.0"?>
|
45
|
+
<outer outerId="hypatia:outer" type="outer type">
|
46
|
+
<my_date>2012-10-30</my_date>
|
47
|
+
<my_int>9</my_int>
|
48
|
+
</outer>'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
data/spec/unit/container_spec.rb
CHANGED
@@ -8,21 +8,25 @@ describe "OM::XML::Container" do
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
subject {
|
12
|
+
ContainerTest.from_xml("<foo><bar>1</bar></foo>")
|
13
|
+
}
|
14
|
+
|
15
15
|
it "should add .ng_xml accessor" do
|
16
|
-
|
17
|
-
|
16
|
+
subject.should respond_to(:ng_xml)
|
17
|
+
subject.should respond_to(:ng_xml=)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should initialize" do
|
21
|
+
ContainerTest.new.ng_xml.should be_a_kind_of Nokogiri::XML::Document
|
18
22
|
end
|
19
23
|
|
20
24
|
describe "new" do
|
21
25
|
it "should populate ng_xml with an instance of Nokogiri::XML::Document" do
|
22
|
-
|
26
|
+
subject.ng_xml.class.should == Nokogiri::XML::Document
|
23
27
|
end
|
24
28
|
end
|
25
|
-
|
29
|
+
|
26
30
|
describe "#from_xml" do
|
27
31
|
it "should accept a String, parse it and store it in .ng_xml" do
|
28
32
|
Nokogiri::XML::Document.expects(:parse).returns("parsed xml")
|
@@ -44,20 +48,20 @@ describe "OM::XML::Container" do
|
|
44
48
|
|
45
49
|
describe ".to_xml" do
|
46
50
|
it "should call .ng_xml.to_xml" do
|
47
|
-
|
48
|
-
|
51
|
+
subject.ng_xml.expects(:to_xml).returns("ng xml")
|
52
|
+
subject.to_xml.should == "ng xml"
|
49
53
|
end
|
50
54
|
|
51
55
|
it 'should accept an optional Nokogiri::XML Document as an argument and insert its fields into that (mocked test)' do
|
52
56
|
doc = Nokogiri::XML::Document.parse("<test_xml/>")
|
53
57
|
mock_new_node = mock("new node")
|
54
|
-
doc.root.expects(:add_child).with(
|
55
|
-
result =
|
58
|
+
doc.root.expects(:add_child).with(subject.ng_xml.root).returns(mock_new_node)
|
59
|
+
result = subject.to_xml(doc)
|
56
60
|
end
|
57
61
|
|
58
62
|
it 'should accept an optional Nokogiri::XML Document as an argument and insert its fields into that (functional test)' do
|
59
63
|
doc = Nokogiri::XML::Document.parse("<test_xml/>")
|
60
|
-
|
64
|
+
subject.to_xml(doc).should == "<?xml version=\"1.0\"?>\n<test_xml>\n <foo>\n <bar>1</bar>\n </foo>\n</test_xml>\n"
|
61
65
|
end
|
62
66
|
|
63
67
|
it 'should add to root of Nokogiri::XML::Documents, but add directly to the elements if a Nokogiri::XML::Node is passed in' do
|
@@ -66,10 +70,10 @@ describe "OM::XML::Container" do
|
|
66
70
|
|
67
71
|
doc = Nokogiri::XML::Document.parse("<test_document/>")
|
68
72
|
el = Nokogiri::XML::Node.new("test_element", Nokogiri::XML::Document.new)
|
69
|
-
doc.root.expects(:add_child).with(
|
70
|
-
el.expects(:add_child).with(
|
71
|
-
|
72
|
-
|
73
|
+
doc.root.expects(:add_child).with(subject.ng_xml.root).returns(mock_new_node)
|
74
|
+
el.expects(:add_child).with(subject.ng_xml.root).returns(mock_new_node)
|
75
|
+
subject.to_xml(doc).should
|
76
|
+
subject.to_xml(el)
|
73
77
|
end
|
74
78
|
end
|
75
79
|
|
@@ -132,11 +132,14 @@ describe "OM::XML::DynamicNode" do
|
|
132
132
|
end
|
133
133
|
|
134
134
|
it "should append nodes at the specified index if possible, setting dirty to true if the object responds to dirty" do
|
135
|
+
# backwards-compatible stuff..
|
135
136
|
@article.stubs(:respond_to?).with(:dirty=).returns(true)
|
136
|
-
@article.expects(:dirty=).with(true).
|
137
|
+
@article.expects(:dirty=).with(true).at_least(2)
|
138
|
+
|
137
139
|
@article.journal.title_info = ["all", "for", "the"]
|
138
140
|
@article.journal.title_info(3, 'glory')
|
139
141
|
@article.term_values(:journal, :title_info).should == ["all", "for", "the", "glory"]
|
142
|
+
@article.should be_changed
|
140
143
|
end
|
141
144
|
|
142
145
|
end
|
@@ -28,6 +28,7 @@ describe "OM::XML::TermValueOperators" do
|
|
28
28
|
test_args = {[{:person=>0}, :first_name]=>{"0"=>"Replacement FirstName"}}
|
29
29
|
@article.update_values(test_args)
|
30
30
|
@article.term_values({:person=>0}, :first_name).should == ["Replacement FirstName"]
|
31
|
+
@article.should be_changed
|
31
32
|
end
|
32
33
|
|
33
34
|
it "should update the xml according to the find_by_terms_and_values in the given hash" do
|
@@ -39,6 +40,7 @@ describe "OM::XML::TermValueOperators" do
|
|
39
40
|
terms_update_hash = {[{":person"=>"0"}, "affiliation"]=>{"0"=>"affiliation1", "1"=>"affiliation2", "2"=>"affiliation3"}, [{:person=>1}, :last_name]=>"Andronicus", [{"person"=>"1"},:first_name]=>["Titus"],[{:person=>1},:role]=>["otherrole1","otherrole2"] }
|
40
41
|
result = @article.update_values(terms_update_hash)
|
41
42
|
result.should == {"person_0_affiliation"=>{"0"=>"affiliation1", "1"=>"affiliation2", "2"=>"affiliation3"}, "person_1_last_name"=>{"0"=>"Andronicus"},"person_1_first_name"=>{"0"=>"Titus"}, "person_1_role"=>{"0"=>"otherrole1","1"=>"otherrole2"}}
|
43
|
+
@article.should be_changed
|
42
44
|
end
|
43
45
|
|
44
46
|
it "should work when you re-run the command" do
|
@@ -66,6 +68,7 @@ describe "OM::XML::TermValueOperators" do
|
|
66
68
|
terms_update_hash = {[{":person"=>"0"}, "affiliation"]=>{"0"=>"affiliation1", "1"=>"affiliation2", "2"=>"affiliation3"}, [{:person=>1}, :last_name]=>"Andronicus", [{"person"=>"1"},:first_name]=>["Titus"],[{:person=>1},:role]=>["otherrole1","otherrole2"] }
|
67
69
|
result = @article.update_values(terms_update_hash)
|
68
70
|
result.should == {"person_0_affiliation"=>{"0"=>"affiliation1", "1"=>"affiliation2", "2"=>"affiliation3"}, "person_1_last_name"=>{"0"=>"Andronicus"},"person_1_first_name"=>{"0"=>"Titus"}, "person_1_role"=>{"0"=>"otherrole1","1"=>"otherrole2"}}
|
71
|
+
@article.should be_changed
|
69
72
|
end
|
70
73
|
end
|
71
74
|
|
data/spec/unit/term_spec.rb
CHANGED
@@ -1,204 +1,243 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
@
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
3
|
+
describe OM::XML::Term do
|
4
|
+
describe "without a type" do
|
5
|
+
subject { OM::XML::Term.new(:test_term) }
|
6
|
+
its (:type) { should == :string }
|
7
|
+
end
|
8
|
+
describe "when type is specified" do
|
9
|
+
subject { OM::XML::Term.new(:test_term, :type=>:date)}
|
10
|
+
its (:type) { should == :date }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "a big test" do
|
14
|
+
before(:each) do
|
15
|
+
@test_name_part = OM::XML::Term.new(:namePart, {}).generate_xpath_queries!
|
16
|
+
@test_volume = OM::XML::Term.new(:volume, :path=>"detail", :attributes=>{:type=>"volume"}, :default_content_path=>"number")
|
17
|
+
@test_date = OM::XML::Term.new(:namePart, :attributes=>{:type=> "date"})
|
18
|
+
@test_person = OM::XML::Term.new(:namePart, :attributes=>{:type=> :none})
|
19
|
+
@test_affiliation = OM::XML::Term.new(:affiliation)
|
20
|
+
@test_role_code = OM::XML::Term.new(:roleTerm, :attributes=>{:type=>"code"})
|
21
|
+
@test_type = OM::XML::Term.new(:class)
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#new' do
|
25
|
+
it "should set path from mapper name if no path is provided" do
|
26
|
+
@test_name_part.path.should == "namePart"
|
27
|
+
end
|
28
|
+
it "should populate the xpath values if no options are provided" do
|
29
|
+
local_mapping = OM::XML::Term.new(:namePart)
|
30
|
+
local_mapping.xpath_relative.should be_nil
|
31
|
+
local_mapping.xpath.should be_nil
|
32
|
+
local_mapping.xpath_constrained.should be_nil
|
33
|
+
end
|
24
34
|
end
|
25
|
-
end
|
26
35
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
36
|
+
describe 'inner_xml' do
|
37
|
+
it "should be a kind of Nokogiri::XML::Node" do
|
38
|
+
pending
|
39
|
+
@test_mapping.inner_xml.should be_kind_of(Nokogiri::XML::Node)
|
40
|
+
end
|
31
41
|
end
|
32
|
-
end
|
33
42
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
+
describe '#from_node' do
|
44
|
+
it "should create a mapper from a nokogiri node" do
|
45
|
+
pending "probably should do this in the Builder"
|
46
|
+
ng_builder = Nokogiri::XML::Builder.new do |xml|
|
47
|
+
xml.mapper(:name=>"person", :path=>"name") {
|
48
|
+
xml.attribute(:name=>"type", :value=>"personal")
|
49
|
+
xml.mapper(:name=>"first_name", :path=>"namePart") {
|
50
|
+
xml.attribute(:name=>"type", :value=>"given")
|
51
|
+
xml.attribute(:name=>"another_attribute", :value=>"myval")
|
52
|
+
}
|
43
53
|
}
|
44
|
-
|
54
|
+
end
|
55
|
+
# node = Nokogiri::XML::Document.parse( '<mapper name="first_name" path="namePart"><attribute name="type" value="given"/><attribute name="another_attribute" value="myval"/></mapper>' ).root
|
56
|
+
node = ng_builder.doc.root
|
57
|
+
mapper = OM::XML::Term.from_node(node)
|
58
|
+
mapper.name.should == :person
|
59
|
+
mapper.path.should == "name"
|
60
|
+
mapper.attributes.should == {:type=>"personal"}
|
61
|
+
mapper.internal_xml.should == node
|
62
|
+
|
63
|
+
child = mapper.children[:first_name]
|
64
|
+
|
65
|
+
child.name.should == :first_name
|
66
|
+
child.path.should == "namePart"
|
67
|
+
child.attributes.should == {:type=>"given", :another_attribute=>"myval"}
|
68
|
+
child.internal_xml.should == node.xpath("./mapper").first
|
45
69
|
end
|
46
|
-
# node = Nokogiri::XML::Document.parse( '<mapper name="first_name" path="namePart"><attribute name="type" value="given"/><attribute name="another_attribute" value="myval"/></mapper>' ).root
|
47
|
-
node = ng_builder.doc.root
|
48
|
-
mapper = OM::XML::Term.from_node(node)
|
49
|
-
mapper.name.should == :person
|
50
|
-
mapper.path.should == "name"
|
51
|
-
mapper.attributes.should == {:type=>"personal"}
|
52
|
-
mapper.internal_xml.should == node
|
53
|
-
|
54
|
-
child = mapper.children[:first_name]
|
55
|
-
|
56
|
-
child.name.should == :first_name
|
57
|
-
child.path.should == "namePart"
|
58
|
-
child.attributes.should == {:type=>"given", :another_attribute=>"myval"}
|
59
|
-
child.internal_xml.should == node.xpath("./mapper").first
|
60
70
|
end
|
61
|
-
end
|
62
71
|
|
63
|
-
|
64
|
-
|
65
|
-
|
72
|
+
describe ".label" do
|
73
|
+
it "should default to the mapper name with underscores converted to spaces"
|
74
|
+
end
|
66
75
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
76
|
+
describe ".retrieve_term" do
|
77
|
+
it "should crawl down into mapper children to find the desired term" do
|
78
|
+
mock_role = mock("mapper", :children =>{:text=>"the target"})
|
79
|
+
mock_conference = mock("mapper", :children =>{:role=>mock_role})
|
80
|
+
@test_name_part.expects(:children).returns({:conference=>mock_conference})
|
81
|
+
@test_name_part.retrieve_term(:conference, :role, :text).should == "the target"
|
82
|
+
end
|
83
|
+
it "should return an empty hash if no term can be found" do
|
84
|
+
@test_name_part.retrieve_term(:journal, :issue, :end_page).should == nil
|
85
|
+
end
|
73
86
|
end
|
74
|
-
|
75
|
-
|
87
|
+
|
88
|
+
describe 'inner_xml' do
|
89
|
+
it "should be a kind of Nokogiri::XML::Node" do
|
90
|
+
pending
|
91
|
+
@test_name_part.inner_xml.should be_kind_of(Nokogiri::XML::Node)
|
92
|
+
end
|
76
93
|
end
|
77
|
-
end
|
78
94
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
95
|
+
describe "getters/setters" do
|
96
|
+
it "should set the corresponding .settings value and return the current value" do
|
97
|
+
# :index_as is a special case
|
98
|
+
[:path, :required, :data_type, :variant_of, :path, :attributes, :default_content_path, :namespace_prefix].each do |method_name|
|
99
|
+
@test_name_part.send(method_name.to_s+"=", "#{method_name.to_s}foo").should == "#{method_name.to_s}foo"
|
100
|
+
@test_name_part.send(method_name).should == "#{method_name.to_s}foo"
|
101
|
+
end
|
102
|
+
end
|
83
103
|
end
|
84
|
-
end
|
85
104
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
105
|
+
describe "OM terminology should accept a symbol as a value to :index_as" do
|
106
|
+
subject {
|
107
|
+
class TestTerminology
|
108
|
+
include OM::XML::Document
|
109
|
+
|
110
|
+
set_terminology do |t|
|
111
|
+
t.as_array :index_as => [:not_searchable]
|
112
|
+
t.as_symbol :index_as => :not_searchable
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
TestTerminology
|
117
|
+
}
|
118
|
+
|
119
|
+
it "should accept an array as an :index_as value" do
|
120
|
+
subject.terminology.terms[:as_array].index_as.should be_a_kind_of(Array)
|
121
|
+
subject.terminology.terms[:as_array].index_as.should == [:not_searchable]
|
122
|
+
end
|
123
|
+
it "should accept a plain symbol as a value to :index_as" do
|
124
|
+
subject.terminology.terms[:as_symbol].index_as.should be_a_kind_of(Array)
|
125
|
+
subject.terminology.terms[:as_symbol].index_as.should == [:not_searchable]
|
91
126
|
end
|
92
127
|
end
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
@test_volume.should respond_to :terminology=
|
97
|
-
end
|
98
|
-
describe ".ancestors" do
|
99
|
-
it "should return an array of Terms that are the ancestors of the current object, ordered from the top/root of the hierarchy" do
|
100
|
-
@test_volume.set_parent(@test_name_part)
|
101
|
-
@test_volume.ancestors.should == [@test_name_part]
|
128
|
+
it "should have a .terminology attribute accessor" do
|
129
|
+
@test_volume.should respond_to :terminology
|
130
|
+
@test_volume.should respond_to :terminology=
|
102
131
|
end
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
@test_name_part.parent.should == "ancestor3"
|
132
|
+
describe ".ancestors" do
|
133
|
+
it "should return an array of Terms that are the ancestors of the current object, ordered from the top/root of the hierarchy" do
|
134
|
+
@test_volume.set_parent(@test_name_part)
|
135
|
+
@test_volume.ancestors.should == [@test_name_part]
|
136
|
+
end
|
109
137
|
end
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
138
|
+
describe ".parent" do
|
139
|
+
it "should retrieve the immediate parent of the given object from the ancestors array" do
|
140
|
+
# @test_name_part.expects(:ancestors).returns(["ancestor1","ancestor2","ancestor3"])
|
141
|
+
@test_name_part.ancestors = ["ancestor1","ancestor2","ancestor3"]
|
142
|
+
@test_name_part.parent.should == "ancestor3"
|
143
|
+
end
|
115
144
|
end
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
145
|
+
describe ".children" do
|
146
|
+
it "should return a hash of Terms that are the children of the current object, indexed by name" do
|
147
|
+
@test_volume.add_child(@test_name_part)
|
148
|
+
@test_volume.children[@test_name_part.name].should == @test_name_part
|
149
|
+
end
|
121
150
|
end
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
@test_volume.children[@test_name_part.name].should == @test_name_part
|
151
|
+
describe ".retrieve_child" do
|
152
|
+
it "should fetch the child identified by the given name" do
|
153
|
+
@test_volume.add_child(@test_name_part)
|
154
|
+
@test_volume.retrieve_child(@test_name_part.name).should == @test_volume.children[@test_name_part.name]
|
155
|
+
end
|
128
156
|
end
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
157
|
+
describe ".set_parent" do
|
158
|
+
it "should insert the mapper into the given parent" do
|
159
|
+
@test_name_part.set_parent(@test_volume)
|
160
|
+
@test_name_part.ancestors.should include(@test_volume)
|
161
|
+
@test_volume.children[@test_name_part.name].should == @test_name_part
|
162
|
+
end
|
135
163
|
end
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
164
|
+
describe ".add_child" do
|
165
|
+
it "should insert the given mapper into the current mappers children" do
|
166
|
+
@test_volume.add_child(@test_name_part)
|
167
|
+
@test_volume.children[@test_name_part.name].should == @test_name_part
|
168
|
+
@test_name_part.ancestors.should include(@test_volume)
|
169
|
+
end
|
141
170
|
end
|
142
|
-
it "should regenerate the xpath values" do
|
143
|
-
@test_volume.xpath_relative.should be_nil
|
144
|
-
@test_volume.xpath.should be_nil
|
145
|
-
@test_volume.xpath_constrained.should be_nil
|
146
171
|
|
147
|
-
|
172
|
+
describe "generate_xpath_queries!" do
|
173
|
+
it "should return the current object" do
|
174
|
+
@test_name_part.generate_xpath_queries!.should == @test_name_part
|
175
|
+
end
|
176
|
+
it "should regenerate the xpath values" do
|
177
|
+
@test_volume.xpath_relative.should be_nil
|
178
|
+
@test_volume.xpath.should be_nil
|
179
|
+
@test_volume.xpath_constrained.should be_nil
|
148
180
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
181
|
+
@test_volume.generate_xpath_queries!.should == @test_volume
|
182
|
+
|
183
|
+
@test_volume.xpath_relative.should == 'detail[@type="volume"]'
|
184
|
+
@test_volume.xpath.should == '//detail[@type="volume"]'
|
185
|
+
@test_volume.xpath_constrained.should == '//detail[@type="volume" and contains(number, "#{constraint_value}")]'.gsub('"', '\"')
|
186
|
+
end
|
187
|
+
it "should trigger update on any child objects" do
|
188
|
+
mock_child = mock("child term")
|
189
|
+
mock_child.expects(:generate_xpath_queries!).times(3)
|
190
|
+
@test_name_part.expects(:children).returns({1=>mock_child, 2=>mock_child, 3=>mock_child})
|
191
|
+
@test_name_part.generate_xpath_queries!
|
192
|
+
end
|
158
193
|
end
|
159
|
-
end
|
160
194
|
|
161
|
-
|
195
|
+
describe "#xml_builder_template" do
|
162
196
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
it "should accept extra options" do
|
169
|
-
marcrelator_role_xml_builder_template = 'xml.roleTerm( \'#{builder_new_value}\', \'type\'=>\'code\', \'authority\'=>\'marcrelator\' )'
|
170
|
-
@test_role_code.xml_builder_template(:attributes=>{"authority"=>"marcrelator"}).should == marcrelator_role_xml_builder_template
|
171
|
-
end
|
197
|
+
it "should generate a template call for passing into the builder block (assumes 'xml' as the argument for the block)" do
|
198
|
+
@test_date.xml_builder_template.should == 'xml.namePart( \'#{builder_new_value}\', \'type\'=>\'date\' )'
|
199
|
+
@test_person.xml_builder_template.should == 'xml.namePart( \'#{builder_new_value}\' )'
|
200
|
+
@test_affiliation.xml_builder_template.should == 'xml.affiliation( \'#{builder_new_value}\' )'
|
201
|
+
end
|
172
202
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
203
|
+
it "should accept extra options" do
|
204
|
+
# Expected marcrelator_role_xml_builder_template.
|
205
|
+
# Include both version to handle either ordering of the hash -- a band-aid hack to fix failing test.
|
206
|
+
e1 = %q{xml.roleTerm( '#{builder_new_value}', 'type'=>'code', 'authority'=>'marcrelator' )}
|
207
|
+
e2 = %q{xml.roleTerm( '#{builder_new_value}', 'authority'=>'marcrelator', 'type'=>'code' )}
|
208
|
+
got = @test_role_code.xml_builder_template(:attributes=>{"authority"=>"marcrelator"})
|
209
|
+
[e1, e2].should include(got)
|
210
|
+
end
|
179
211
|
|
180
|
-
|
181
|
-
|
182
|
-
|
212
|
+
it "should work for namespaced nodes" do
|
213
|
+
@ical_date = OM::XML::Term.new(:ical_date, :path=>"ical:date")
|
214
|
+
@ical_date.xml_builder_template.should == "xml[\'ical\'].date( '\#{builder_new_value}' )"
|
215
|
+
@ical_date = OM::XML::Term.new(:ical_date, :path=>"date", :namespace_prefix=>"ical")
|
216
|
+
@ical_date.xml_builder_template.should == "xml[\'ical\'].date( '\#{builder_new_value}' )"
|
217
|
+
end
|
183
218
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
end
|
219
|
+
it "should work for nodes with default_content_path" do
|
220
|
+
@test_volume.xml_builder_template.should == "xml.detail( \'type\'=>'volume' ) { xml.number( '\#{builder_new_value}' ) }"
|
221
|
+
end
|
188
222
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
223
|
+
it "should support terms that are attributes" do
|
224
|
+
@type_attribute_term = OM::XML::Term.new(:type_attribute, :path=>{:attribute=>:type})
|
225
|
+
@type_attribute_term.xml_builder_template.should == "xml.@type( '\#{builder_new_value}' )"
|
226
|
+
end
|
193
227
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
228
|
+
it "should support terms with namespaced attributes" do
|
229
|
+
@french_title = OM::XML::Term.new(:french_title, :path=>"title", :attributes=>{"xml:lang"=>"fre"})
|
230
|
+
@french_title.xml_builder_template.should == "xml.title( '\#{builder_new_value}', 'xml:lang'=>'fre' )"
|
231
|
+
end
|
232
|
+
|
233
|
+
it "should support terms that are namespaced attributes" do
|
234
|
+
@xml_lang_attribute_term = OM::XML::Term.new(:xml_lang_attribute, :path=>{:attribute=>"xml:lang"})
|
235
|
+
@xml_lang_attribute_term.xml_builder_template.should == "xml.@xml:lang( '\#{builder_new_value}' )"
|
236
|
+
end
|
237
|
+
|
238
|
+
it "should generate a template call for passing into the builder block (assumes 'xml' as the argument for the block) for terms that share a name with an existing method on the builder" do
|
239
|
+
@test_type.xml_builder_template.should == 'xml.class_( \'#{builder_new_value}\' )'
|
240
|
+
end
|
201
241
|
end
|
202
242
|
end
|
203
|
-
|
204
243
|
end
|