om 0.1.10 → 1.0.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.
@@ -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