om 0.1.10 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,141 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require "om"
3
+
4
+ describe "OM::XML::Document" do
5
+
6
+ before(:all) do
7
+ #ModsHelpers.name_("Beethoven, Ludwig van", :date=>"1770-1827", :role=>"creator")
8
+ class DocumentTest
9
+
10
+ include OM::XML::Document
11
+
12
+ # Could add support for multiple root declarations.
13
+ # For now, assume that any modsCollections have already been broken up and fed in as individual mods documents
14
+ # root :mods_collection, :path=>"modsCollection",
15
+ # :attributes=>[],
16
+ # :subelements => :mods
17
+
18
+ set_terminology do |t|
19
+ t.root(:path=>"mods", :xmlns=>"http://www.loc.gov/mods/v3", :schema=>"http://www.loc.gov/standards/mods/v3/mods-3-2.xsd")
20
+
21
+ t.title_info(:path=>"titleInfo") {
22
+ t.main_title(:path=>"title", :label=>"title")
23
+ t.language(:path=>{:attribute=>"lang"})
24
+ }
25
+ # This is a mods:name. The underscore is purely to avoid namespace conflicts.
26
+ t.name_ {
27
+ # this is a namepart
28
+ t.namePart(:index_as=>[:searchable, :displayable, :facetable, :sortable], :required=>:true, :type=>:string, :label=>"generic name")
29
+ # affiliations are great
30
+ t.affiliation
31
+ t.displayForm
32
+ t.role(:ref=>[:role])
33
+ t.description
34
+ t.date(:path=>"namePart", :attributes=>{:type=>"date"})
35
+ t.last_name(:path=>"namePart", :attributes=>{:type=>"family"})
36
+ t.first_name(:path=>"namePart", :attributes=>{:type=>"given"}, :label=>"first name")
37
+ t.terms_of_address(:path=>"namePart", :attributes=>{:type=>"termsOfAddress"})
38
+ }
39
+ # lookup :person, :first_name
40
+ t.person(:ref=>:name, :attributes=>{:type=>"personal"})
41
+
42
+ t.role {
43
+ t.text(:path=>"roleTerm",:attributes=>{:type=>"text"})
44
+ t.code(:path=>"roleTerm",:attributes=>{:type=>"code"})
45
+ }
46
+ t.journal(:path=>'relatedItem', :attributes=>{:type=>"host"}) {
47
+ t.title_info
48
+ t.origin_info(:path=>"originInfo")
49
+ t.issn(:path=>"identifier", :attributes=>{:type=>"issn"})
50
+ t.issue(:ref=>:issue)
51
+ }
52
+ t.issue(:path=>"part") {
53
+ t.volume(:path=>"detail", :attributes=>{:type=>"volume"}, :default_content_path=>"number")
54
+ t.level(:path=>"detail", :attributes=>{:type=>"number"}, :default_content_path=>"number")
55
+ t.start_page(:path=>"pages", :attributes=>{:type=>"start"})
56
+ t.end_page(:path=>"pages", :attributes=>{:type=>"end"})
57
+ # t.start_page(:path=>"extent", :attributes=>{:unit=>"pages"}, :default_content_path => "start")
58
+ # t.end_page(:path=>"extent", :attributes=>{:unit=>"pages"}, :default_content_path => "end")
59
+ t.publication_date(:path=>"date")
60
+ }
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+
67
+ before(:each) do
68
+ @fixturemods = DocumentTest.from_xml( fixture( File.join("CBF_MODS", "ARS0025_016.xml") ) )
69
+ article_xml = fixture( File.join("mods_articles", "hydrangea_article1.xml") )
70
+ @mods_article = DocumentTest.from_xml(article_xml)
71
+ end
72
+
73
+ after(:all) do
74
+ Object.send(:remove_const, :DocumentTest)
75
+ end
76
+
77
+ describe ".ox_namespaces" do
78
+ it "should merge terminology namespaces with document namespaces" do
79
+ @fixturemods.ox_namespaces.should == {"oxns"=>"http://www.loc.gov/mods/v3", "xmlns:ns2"=>"http://www.w3.org/1999/xlink", "xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance", "xmlns:ns3"=>"http://www.loc.gov/mods/v3", "xmlns"=>"http://www.loc.gov/mods/v3"}
80
+ end
81
+ end
82
+
83
+
84
+ describe ".find_by_terms_and_value" do
85
+ it "should fail gracefully if you try to look up nodes for an undefined property" do
86
+ pending "better to get an informative error?"
87
+ @fixturemods.find_by_terms_and_value(:nobody_home).should == []
88
+ end
89
+ it "should use Nokogiri to retrieve a NodeSet corresponding to the term pointers" do
90
+ @mods_article.find_by_terms_and_value( :person ).length.should == 2
91
+ end
92
+
93
+ it "should allow you to search by term pointer" do
94
+ @fixturemods.ng_xml.expects(:xpath).with('//oxns:name[@type="personal"]', @fixturemods.ox_namespaces)
95
+ @fixturemods.find_by_terms_and_value(:person)
96
+ end
97
+ it "should allow you to constrain your searches" do
98
+ @fixturemods.ng_xml.expects(:xpath).with('//oxns:name[@type="personal" and contains(., "Beethoven, Ludwig van")]', @fixturemods.ox_namespaces)
99
+ @fixturemods.find_by_terms_and_value(:person, "Beethoven, Ludwig van")
100
+ end
101
+ it "should allow you to use complex constraints" do
102
+ @fixturemods.ng_xml.expects(:xpath).with('//oxns:name[@type="personal"]/oxns:namePart[@type="date" and contains(., "2010")]', @fixturemods.ox_namespaces)
103
+ @fixturemods.find_by_terms_and_value(:person, :date=>"2010")
104
+
105
+ @fixturemods.ng_xml.expects(:xpath).with('//oxns:name[@type="personal"]/oxns:role[contains(., "donor")]', @fixturemods.ox_namespaces)
106
+ @fixturemods.find_by_terms_and_value(:person, :role=>"donor")
107
+ end
108
+ end
109
+ describe ".find_by_terms" do
110
+ it "should use Nokogiri to retrieve a NodeSet corresponding to the combination of term pointers and array/nodeset indexes" do
111
+ @mods_article.find_by_terms( :person ).length.should == 2
112
+ @mods_article.find_by_terms( {:person=>1} ).first.should == @mods_article.ng_xml.xpath('//oxns:name[@type="personal"][2]', "oxns"=>"http://www.loc.gov/mods/v3").first
113
+ @mods_article.find_by_terms( {:person=>1}, :first_name ).class.should == Nokogiri::XML::NodeSet
114
+ @mods_article.find_by_terms( {:person=>1}, :first_name ).first.text.should == "Siddartha"
115
+ end
116
+ it "should support accessors whose relative_xpath is a lookup array instead of an xpath string" do
117
+ # pending "this only impacts scenarios where we want to display & edit"
118
+ DocumentTest.terminology.retrieve_term(:title_info, :language).path.should == {:attribute=>"lang"}
119
+ # @sample.retrieve( :title, 1 ).first.text.should == "Artikkelin otsikko Hydrangea artiklan 1"
120
+ @mods_article.find_by_terms( {:title_info=>1}, :language ).first.text.should == "finnish"
121
+ end
122
+
123
+ it "should support xpath queries as the pointer" do
124
+ @mods_article.find_by_terms('//oxns:name[@type="personal"][1]/oxns:namePart[1]').first.text.should == "FAMILY NAME"
125
+ end
126
+
127
+ it "should return nil if the xpath fails to generate" do
128
+ pending "Can't decide if it's better to return nil or raise an error. Choosing informative errors for now."
129
+ @mods_article.find_by_terms( {:foo=>20}, :bar ).should == nil
130
+ end
131
+
132
+ it "should support terms that point to attributes instead of nodes" do
133
+ @mods_article.find_by_terms( {:title_info=>1}, :language ).first.text.should == "finnish"
134
+ end
135
+
136
+ it "should support xpath queries as the pointer" do
137
+ @mods_article.find_by_terms('//oxns:name[@type="personal"][1]/oxns:namePart[1]').first.text.should == "FAMILY NAME"
138
+ end
139
+ end
140
+
141
+ end
@@ -51,7 +51,13 @@ describe "OM::XML::Generator" do
51
51
  describe '#generate' do
52
52
  it "should use the corresponding builder template(s) to generate the node" do
53
53
  GeneratorTest.generate(:mods, "foo").root.to_xml.should == "<mods>foo</mods>"
54
- GeneratorTest.generate([:person,:role], "creator", {:attributes=>{"type"=>"code", "authority"=>"marcrelator"}}).root.to_xml.should == "<role type=\"code\" authority=\"marcrelator\">\n <roleTerm>creator</roleTerm>\n</role>"
54
+ # GeneratorTest.generate([:person,:role], "creator", {:attributes=>{"type"=>"code", "authority"=>"marcrelator"}}).root.to_xml.should == "<role authority=\"marcrelator\" type=\"code\">\n <roleTerm>creator</roleTerm>\n</role>"
55
+ generated_node = GeneratorTest.generate([:person,:role], "creator", {:attributes=>{"type"=>"code", "authority"=>"marcrelator"}})
56
+ # generated_node.should have_node 'role[@authority="marcrelator"][@type="code"]' do
57
+ # with_node "roleTerm", "creator"
58
+ # end
59
+ generated_node.xpath('./role[@authority="marcrelator"][@type="code"]').xpath("./roleTerm").text.should == "creator"
60
+
55
61
  end
56
62
  it "should return Nokogiri Documents" do
57
63
  GeneratorTest.generate(:mods, "foo").class.should == Nokogiri::XML::Document
@@ -0,0 +1,39 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require "om"
3
+
4
+ describe "OM::XML::NamedTermProxy" do
5
+
6
+ before(:all) do
7
+
8
+ @test_terminology_builder = OM::XML::Terminology::Builder.new do |t|
9
+ t.parent {
10
+ t.foo {
11
+ t.bar
12
+ }
13
+ t.my_proxy(:proxy=>[:foo, :bar])
14
+ }
15
+ t.adoptive_parent(:ref=>[:parent], :attributes=>{:type=>"adoptive"})
16
+ end
17
+
18
+ @test_terminology = @test_terminology_builder.build
19
+ @test_proxy = @test_terminology.retrieve_term(:parent, :my_proxy)
20
+ @proxied_term = @test_terminology.retrieve_term(:parent, :foo, :bar)
21
+ @adoptive_parent = @test_terminology.retrieve_term(:adoptive_parent)
22
+ end
23
+
24
+ it "should proxy all extra methods to the proxied object" do
25
+ [:xpath, :xpath_relative, :xml_builder_template].each do |method|
26
+ @proxied_term.expects(method)
27
+ @test_proxy.send(method)
28
+ end
29
+ end
30
+ it "should proxy the term specified by the builder" do
31
+ @test_proxy.proxied_term.should == @test_terminology.retrieve_term(:parent, :foo, :bar)
32
+ @test_proxy.xpath.should == "//oxns:parent/oxns:foo/oxns:bar"
33
+ end
34
+ it "should search relative to the parent term when finding the term to proxy" do
35
+ proxy2 = @test_terminology.retrieve_term(:adoptive_parent, :my_proxy)
36
+ proxy2.proxied_term.should == @test_terminology.retrieve_term(:adoptive_parent, :foo, :bar)
37
+ proxy2.xpath.should == '//oxns:parent[@type="adoptive"]/oxns:foo/oxns:bar'
38
+ end
39
+ end
@@ -0,0 +1,27 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require "om"
3
+
4
+ describe "OM::XML::NodeGenerator" do
5
+
6
+
7
+ before(:each) do
8
+ @test_mods_term = OM::XML::Term.new(:mods)
9
+ @test_volume_term = OM::XML::Term.new(:volume, :path=>"detail", :attributes=>{:type=>"volume"}, :default_content_path=>"number")
10
+ end
11
+
12
+ describe '#generate' do
13
+ it "should use the corresponding builder template(s) to generate the node" do
14
+ OM::XML::NodeGenerator.generate(@test_mods_term, "foo").root.to_xml.should == "<mods>foo</mods>"
15
+ generated_node = OM::XML::NodeGenerator.generate(@test_volume_term, "108", {:attributes=>{"extraAttr"=>"my value"}})
16
+ generated_node.xpath('./detail[@type="volume"][@extraAttr="my value"]').xpath("./number").text.should == "108"
17
+ # Would be great if we wrote a have_node custom rspec matcher...
18
+ # generated_node.should have_node 'role[@authority="marcrelator"][@type="code"]' do
19
+ # with_node "roleTerm", "creator"
20
+ # end
21
+ end
22
+ it "should return Nokogiri Documents" do
23
+ OM::XML::NodeGenerator.generate(@test_mods_term, "foo").class.should == Nokogiri::XML::Document
24
+ end
25
+ end
26
+
27
+ end
@@ -312,4 +312,4 @@ describe "OM::XML::Properties" do
312
312
  end
313
313
  end
314
314
 
315
- end
315
+ end
@@ -0,0 +1,195 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require "om"
3
+
4
+ describe "OM::XML::Term::Builder" do
5
+
6
+ before(:each) do
7
+ @test_terminology_builder = OM::XML::Terminology::Builder.new do |t|
8
+ t.fruit_trees {
9
+ t.citrus(:attributes=>{"citric_acid"=>"true"}, :index_as=>[:facetable]) {
10
+ t.randomness
11
+ }
12
+ t.stone_fruit(:path=>"prunus", :attributes=>{:genus=>"Prunus"})
13
+ t.peach(:ref=>[:fruit_trees, :stone_fruit], :attributes=>{:subgenus=>"Amygdalus", :species=>"Prunus persica"})
14
+ t.nectarine(:ref=>[:fruit_trees, :peach], :attributes=>{:cultivar=>"nectarine"})
15
+ t.almond(:ref=>[:fruit_trees, :peach], :attributes=>{:species=>"Prunus dulcis"})
16
+ }
17
+ t.coconut(:ref=>:pineapple)
18
+ t.banana(:ref=>:coconut)
19
+ t.pineapple(:ref=>:banana)
20
+ end
21
+
22
+ @citrus = @test_terminology_builder.retrieve_term_builder(:fruit_trees, :citrus)
23
+ @stone_fruit = @test_terminology_builder.retrieve_term_builder(:fruit_trees, :stone_fruit)
24
+ @peach = @test_terminology_builder.retrieve_term_builder(:fruit_trees, :peach)
25
+ @nectarine = @test_terminology_builder.retrieve_term_builder(:fruit_trees, :nectarine)
26
+ @almond = @test_terminology_builder.retrieve_term_builder(:fruit_trees, :almond)
27
+ @pineapple = @test_terminology_builder.retrieve_term_builder(:pineapple)
28
+ end
29
+
30
+ before(:each) do
31
+ @test_builder = OM::XML::Term::Builder.new("term1")
32
+ @test_builder_2 = OM::XML::Term::Builder.new("term2")
33
+ end
34
+
35
+ describe '#new' do
36
+ it "should set terminology_builder attribute if provided" do
37
+ mock_terminology_builder = mock("TerminologyBuilder")
38
+ OM::XML::Term::Builder.new("term1", mock_terminology_builder).terminology_builder.should == mock_terminology_builder
39
+ end
40
+ end
41
+
42
+ describe "configuration methods" do
43
+ it "should set the corresponding .settings value return the mapping object" do
44
+ [:path, :index_as, :required, :data_type, :variant_of, :path, :attributes, :default_content_path].each do |method_name|
45
+ @test_builder.send(method_name, "#{method_name.to_s}foo").should == @test_builder
46
+ @test_builder.settings[method_name].should == "#{method_name.to_s}foo"
47
+ end
48
+ end
49
+ it "should be chainable" do
50
+ test_builder = OM::XML::Term::Builder.new("chainableTerm").index_as(:facetable, :searchable, :sortable, :displayable).required(true).data_type(:text)
51
+ resulting_settings = test_builder.settings
52
+ resulting_settings[:index_as].should == [:facetable, :searchable, :sortable, :displayable]
53
+ resulting_settings[:required].should == true
54
+ resulting_settings[:data_type].should == :text
55
+ end
56
+ end
57
+
58
+ describe "settings" do
59
+ describe "defaults" do
60
+ it "should be set" do
61
+ @test_builder.settings[:required].should == false
62
+ @test_builder.settings[:data_type].should == :string
63
+ @test_builder.settings[:variant_of].should be_nil
64
+ @test_builder.settings[:attributes].should be_nil
65
+ @test_builder.settings[:default_content_path].should be_nil
66
+ end
67
+ end
68
+ end
69
+
70
+ describe ".add_child" do
71
+ it "should insert the given Term Builder into the current Term Builder's children" do
72
+ @test_builder.add_child(@test_builder_2)
73
+ @test_builder.children[@test_builder_2.name].should == @test_builder_2
74
+ @test_builder.ancestors.should include(@test_builder_2)
75
+ end
76
+ end
77
+ describe ".retrieve_child" do
78
+ it "should fetch the child identified by the given name" do
79
+ @test_builder.add_child(@test_builder_2)
80
+ @test_builder.retrieve_child(@test_builder_2.name).should == @test_builder.children[@test_builder_2.name]
81
+ end
82
+ end
83
+ describe ".children" do
84
+ it "should return a hash of Term Builders that are the children of the current object, indexed by name" do
85
+ @test_builder.add_child(@test_builder_2)
86
+ @test_builder.children[@test_builder_2.name].should == @test_builder_2
87
+ end
88
+ end
89
+
90
+ describe ".build" do
91
+ it "should build a Term with the given settings and generate its xpath values" do
92
+ test_builder = OM::XML::Term::Builder.new("requiredTextFacet").index_as([:facetable, :searchable, :sortable, :displayable]).required(true).data_type(:text)
93
+ result = test_builder.build
94
+ result.should be_instance_of OM::XML::Term
95
+ result.index_as.should == [:facetable, :searchable, :sortable, :displayable]
96
+ result.required.should == true
97
+ result.data_type.should == :text
98
+
99
+ result.xpath.should == OM::XML::TermXpathGenerator.generate_absolute_xpath(result)
100
+ result.xpath_constrained.should == OM::XML::TermXpathGenerator.generate_constrained_xpath(result)
101
+ result.xpath_relative.should == OM::XML::TermXpathGenerator.generate_relative_xpath(result)
102
+ end
103
+ it "should create proxy terms if :proxy is set" do
104
+ test_builder = OM::XML::Term::Builder.new("my_proxy").proxy([:foo, :bar])
105
+ result = test_builder.build
106
+ result.should be_kind_of OM::XML::NamedTermProxy
107
+ end
108
+ it "should set path to match name if it is empty" do
109
+ @test_builder.settings[:path].should be_nil
110
+ @test_builder.build.path.should == @test_builder.name.to_s
111
+ end
112
+ it "should work recursively, calling .build on any of its children" do
113
+ OM::XML::Term.any_instance.stubs(:generate_xpath_queries!)
114
+ built_child1 = OM::XML::Term.new("child1")
115
+ built_child2 = OM::XML::Term.new("child2")
116
+
117
+ mock1 = mock("Builder1", :build => built_child1 )
118
+ mock2 = mock("Builder2", :build => built_child2 )
119
+ mock1.stubs(:name).returns("child1")
120
+ mock2.stubs(:name).returns("child2")
121
+
122
+ @test_builder.children = {:mock1=>mock1, :mock2=>mock2}
123
+ result = @test_builder.build
124
+ result.children[:child1].should == built_child1
125
+ result.children[:child2].should == built_child2
126
+ result.children.length.should == 2
127
+ end
128
+ end
129
+
130
+ describe ".lookup_refs" do
131
+ it "should return an empty array if no refs are declared" do
132
+ @test_builder.lookup_refs.should == []
133
+ end
134
+ it "should should look up the referenced TermBuilder from the terminology_builder" do
135
+ @peach.lookup_refs.should == [@stone_fruit]
136
+ end
137
+ it "should support recursive refs" do
138
+ @almond.lookup_refs.should == [@peach, @stone_fruit]
139
+ end
140
+ it "should raise an error if the TermBuilder does not have a reference to a terminology builder" do
141
+ lambda { OM::XML::Term::Builder.new("referrer").ref("bongos").lookup_refs }.should raise_error(StandardError,"Cannot perform lookup_ref for the referrer builder. It doesn't have a reference to any terminology builder")
142
+ end
143
+ it "should raise an error if the referece points to a nonexistent term builder" do
144
+ tb = OM::XML::Term::Builder.new("mork",@test_terminology_builder).ref(:characters, :aliens)
145
+ lambda { tb.lookup_refs }.should raise_error(OM::XML::Terminology::BadPointerError,"#{tb.name} refers to a Term Builder that doesn't exist. The bad pointer is [:characters, :aliens]")
146
+ end
147
+ it "should raise an error with informative error when given circular references" do
148
+ lambda { @pineapple.lookup_refs }.should raise_error(OM::XML::Terminology::CircularReferenceError,"Circular reference in Terminology: :pineapple => :banana => :coconut => :pineapple")
149
+ end
150
+ end
151
+
152
+ describe ".resolve_refs!" do
153
+ it "should do nothing if settings don't include a :ref" do
154
+ settings_pre = @test_builder.settings
155
+ children_pre = @test_builder.children
156
+
157
+ @test_builder.resolve_refs!
158
+ @test_builder.settings.should == settings_pre
159
+ @test_builder.children.should == children_pre
160
+ end
161
+ it "should should look up the referenced TermBuilder, use its settings and duplicate its children without changing the name" do
162
+ term_builder = OM::XML::Term::Builder.new("orange",@test_terminology_builder).ref(:fruit_trees, :citrus)
163
+ term_builder.resolve_refs!
164
+ # Make sure children and settings were copied
165
+ term_builder.settings.should == @citrus.settings.merge(:path=>"citrus")
166
+ term_builder.children.should == @citrus.children
167
+
168
+ # Make sure name and parent of both the term_builder and its target were left alone
169
+ term_builder.name.should == :orange
170
+ @citrus.name.should == :citrus
171
+ end
172
+ it "should set path based on the ref's path if set" do
173
+ [@peach,@almond].each { |x| x.resolve_refs! }
174
+ @peach.settings[:path].should == "prunus"
175
+ @almond.settings[:path].should == "prunus"
176
+ end
177
+ it "should set path based on the first ref's name if no path is set" do
178
+ orange_builder = OM::XML::Term::Builder.new("orange",@test_terminology_builder).ref(:fruit_trees, :citrus)
179
+ orange_builder.resolve_refs!
180
+ orange_builder.settings[:path].should == "citrus"
181
+ end
182
+ # It should not be a problem if multiple TermBuilders refer to the same child TermBuilder since the parent-child relationship is set up after calling TermBuilder.build
183
+ it "should result in clean trees of Terms after building"
184
+
185
+ it "should preserve any extra settings specific to this builder (for variant terms)" do
186
+ tb = OM::XML::Term::Builder.new("orange",@test_terminology_builder).ref(:fruit_trees, :citrus).attributes(:color=>"orange").required(true)
187
+ tb.resolve_refs!
188
+ tb.settings.should == {:path=>"citrus", :attributes=>{"citric_acid"=>"true", :color=>"orange"}, :required=>true, :data_type=>:string, :index_as=>[:facetable]}
189
+ end
190
+ it "should aggregate all settings from refs, combining them with a cascading approach" do
191
+ @almond.resolve_refs!
192
+ @almond.settings[:attributes].should == {:genus=>"Prunus",:subgenus=>"Amygdalus", :species=>"Prunus dulcis"}
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,180 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require "om"
3
+
4
+ describe "OM::XML::Term" do
5
+
6
+ before(:each) do
7
+ @test_name_part = OM::XML::Term.new(:namePart, {}).generate_xpath_queries!
8
+ @test_volume = OM::XML::Term.new(:volume, :path=>"detail", :attributes=>{:type=>"volume"}, :default_content_path=>"number")
9
+ @test_date = OM::XML::Term.new(:namePart, :attributes=>{:type=> "date"})
10
+ @test_affiliation = OM::XML::Term.new(:affiliation)
11
+ @test_role_code = OM::XML::Term.new(:roleTerm, :attributes=>{:type=>"code"})
12
+ end
13
+
14
+ describe '#new' do
15
+ it "should set default values" do
16
+ @test_name_part.namespace_prefix.should == "oxns"
17
+ end
18
+ it "should set path from mapper name if no path is provided" do
19
+ @test_name_part.path.should == "namePart"
20
+ end
21
+ it "should populate the xpath values if no options are provided" do
22
+ local_mapping = OM::XML::Term.new(:namePart)
23
+ local_mapping.xpath_relative.should be_nil
24
+ local_mapping.xpath.should be_nil
25
+ local_mapping.xpath_constrained.should be_nil
26
+ end
27
+ end
28
+
29
+ describe 'inner_xml' do
30
+ it "should be a kind of Nokogiri::XML::Node" do
31
+ pending
32
+ @test_mapping.inner_xml.should be_kind_of(Nokogiri::XML::Node)
33
+ end
34
+ end
35
+
36
+ describe '#from_node' do
37
+ it "should create a mapper from a nokogiri node" do
38
+ pending "probably should do this in the Builder"
39
+ ng_builder = Nokogiri::XML::Builder.new do |xml|
40
+ xml.mapper(:name=>"person", :path=>"name") {
41
+ xml.attribute(:name=>"type", :value=>"personal")
42
+ xml.mapper(:name=>"first_name", :path=>"namePart") {
43
+ xml.attribute(:name=>"type", :value=>"given")
44
+ xml.attribute(:name=>"another_attribute", :value=>"myval")
45
+ }
46
+ }
47
+ end
48
+ # node = Nokogiri::XML::Document.parse( '<mapper name="first_name" path="namePart"><attribute name="type" value="given"/><attribute name="another_attribute" value="myval"/></mapper>' ).root
49
+ node = ng_builder.doc.root
50
+ mapper = OM::XML::Term.from_node(node)
51
+ mapper.name.should == :person
52
+ mapper.path.should == "name"
53
+ mapper.attributes.should == {:type=>"personal"}
54
+ mapper.internal_xml.should == node
55
+
56
+ child = mapper.children[:first_name]
57
+
58
+ child.name.should == :first_name
59
+ child.path.should == "namePart"
60
+ child.attributes.should == {:type=>"given", :another_attribute=>"myval"}
61
+ child.internal_xml.should == node.xpath("./mapper").first
62
+ end
63
+ end
64
+
65
+ describe ".label" do
66
+ it "should default to the mapper name with underscores converted to spaces"
67
+ end
68
+
69
+ describe ".retrieve_term" do
70
+ it "should crawl down into mapper children to find the desired term" do
71
+ mock_role = mock("mapper", :children =>{:text=>"the target"})
72
+ mock_conference = mock("mapper", :children =>{:role=>mock_role})
73
+ @test_name_part.expects(:children).returns({:conference=>mock_conference})
74
+ @test_name_part.retrieve_term(:conference, :role, :text).should == "the target"
75
+ end
76
+ it "should return an empty hash if no term can be found" do
77
+ @test_name_part.retrieve_term(:journal, :issue, :end_page).should == nil
78
+ end
79
+ end
80
+
81
+ describe 'inner_xml' do
82
+ it "should be a kind of Nokogiri::XML::Node" do
83
+ pending
84
+ @test_name_part.inner_xml.should be_kind_of(Nokogiri::XML::Node)
85
+ end
86
+ end
87
+
88
+ describe "getters/setters" do
89
+ it "should set the corresponding .settings value and return the current value" do
90
+ [:path, :index_as, :required, :data_type, :variant_of, :path, :attributes, :default_content_path, :namespace_prefix].each do |method_name|
91
+ @test_name_part.send(method_name.to_s+"=", "#{method_name.to_s}foo").should == "#{method_name.to_s}foo"
92
+ @test_name_part.send(method_name).should == "#{method_name.to_s}foo"
93
+ end
94
+ end
95
+ end
96
+ it "should have a .terminology attribute accessor" do
97
+ @test_volume.should respond_to :terminology
98
+ @test_volume.should respond_to :terminology=
99
+ end
100
+ describe ".ancestors" do
101
+ it "should return an array of Terms that are the ancestors of the current object, ordered from the top/root of the hierarchy" do
102
+ @test_volume.set_parent(@test_name_part)
103
+ @test_volume.ancestors.should == [@test_name_part]
104
+ end
105
+ end
106
+ describe ".parent" do
107
+ it "should retrieve the immediate parent of the given object from the ancestors array" do
108
+ # @test_name_part.expects(:ancestors).returns(["ancestor1","ancestor2","ancestor3"])
109
+ @test_name_part.ancestors = ["ancestor1","ancestor2","ancestor3"]
110
+ @test_name_part.parent.should == "ancestor3"
111
+ end
112
+ end
113
+ describe ".children" do
114
+ it "should return a hash of Terms that are the children of the current object, indexed by name" do
115
+ @test_volume.add_child(@test_name_part)
116
+ @test_volume.children[@test_name_part.name].should == @test_name_part
117
+ end
118
+ end
119
+ describe ".retrieve_child" do
120
+ it "should fetch the child identified by the given name" do
121
+ @test_volume.add_child(@test_name_part)
122
+ @test_volume.retrieve_child(@test_name_part.name).should == @test_volume.children[@test_name_part.name]
123
+ end
124
+ end
125
+ describe ".set_parent" do
126
+ it "should insert the mapper into the given parent" do
127
+ @test_name_part.set_parent(@test_volume)
128
+ @test_name_part.ancestors.should include(@test_volume)
129
+ @test_volume.children[@test_name_part.name].should == @test_name_part
130
+ end
131
+ end
132
+ describe ".add_child" do
133
+ it "should insert the given mapper into the current mappers children" do
134
+ @test_volume.add_child(@test_name_part)
135
+ @test_volume.children[@test_name_part.name].should == @test_name_part
136
+ @test_name_part.ancestors.should include(@test_volume)
137
+ end
138
+ end
139
+
140
+ describe "generate_xpath_queries!" do
141
+ it "should return the current object" do
142
+ @test_name_part.generate_xpath_queries!.should == @test_name_part
143
+ end
144
+ it "should regenerate the xpath values" do
145
+ @test_volume.xpath_relative.should be_nil
146
+ @test_volume.xpath.should be_nil
147
+ @test_volume.xpath_constrained.should be_nil
148
+
149
+ @test_volume.generate_xpath_queries!.should == @test_volume
150
+
151
+ @test_volume.xpath_relative.should == 'oxns:detail[@type="volume"]'
152
+ @test_volume.xpath.should == '//oxns:detail[@type="volume"]'
153
+ @test_volume.xpath_constrained.should == '//oxns:detail[@type="volume" and contains(oxns:number, "#{constraint_value}")]'.gsub('"', '\"')
154
+ end
155
+ it "should trigger update on any child objects" do
156
+ mock_child = mock("child term")
157
+ mock_child.expects(:generate_xpath_queries!).times(3)
158
+ @test_name_part.expects(:children).returns({1=>mock_child, 2=>mock_child, 3=>mock_child})
159
+ @test_name_part.generate_xpath_queries!
160
+ end
161
+ end
162
+
163
+ describe "#xml_builder_template" do
164
+
165
+ it "should generate a template call for passing into the builder block (assumes 'xml' as the argument for the block)" do
166
+ @test_date.xml_builder_template.should == 'xml.namePart( \'#{builder_new_value}\', :type=>\'date\' )'
167
+ @test_affiliation.xml_builder_template.should == 'xml.affiliation( \'#{builder_new_value}\' )'
168
+ end
169
+ it "should accept extra options" do
170
+ marcrelator_role_xml_builder_template = 'xml.roleTerm( \'#{builder_new_value}\', :type=>\'code\', :authority=>\'marcrelator\' )'
171
+ @test_role_code.xml_builder_template(:attributes=>{"authority"=>"marcrelator"}).should == marcrelator_role_xml_builder_template
172
+ end
173
+
174
+ it "should work for nodes with default_content_path" do
175
+ @test_volume.xml_builder_template.should == "xml.detail( :type=>'volume' ) { xml.number( '\#{builder_new_value}' ) }"
176
+ end
177
+
178
+ end
179
+
180
+ end