om 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,14 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'om'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+ require 'ruby-debug'
7
+
8
+ Spec::Runner.configure do |config|
9
+ config.mock_with :mocha
10
+ end
11
+
12
+ def fixture(file)
13
+ File.new(File.join(File.dirname(__FILE__), 'fixtures', file))
14
+ end
@@ -0,0 +1,156 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require "nokogiri"
3
+ require "om"
4
+
5
+ describe "OM::XML::Accessors" do
6
+
7
+ before(:all) do
8
+ class AccessorTest
9
+
10
+ include OM::XML::Container
11
+ include OM::XML::Accessors
12
+ #accessor :title, :relative_xpath=>[:titleInfo, :title]}}
13
+
14
+ accessor :title_info, :relative_xpath=>'oxns:titleInfo', :children=>[
15
+ {:main_title=>{:relative_xpath=>'oxns:title'}},
16
+ {:language =>{:relative_xpath=>{:attribute=>"lang"} }}
17
+ ] # this allows you to access the language attribute as if it was a regular child accessor
18
+ accessor :abstract
19
+ accessor :topic_tag, :relative_xpath=>'oxns:subject/oxns:topic'
20
+ accessor :person, :relative_xpath=>'oxns:name[@type="personal"]', :children=>[
21
+ {:last_name=>{:relative_xpath=>'oxns:namePart[@type="family"]'}},
22
+ {:first_name=>{:relative_xpath=>'oxns:namePart[@type="given"]'}},
23
+ {:institution=>{:relative_xpath=>'oxns:affiliation'}},
24
+ {:role=>{:children=>[
25
+ {:text=>{:relative_xpath=>'oxns:roleTerm[@type="text"]'}},
26
+ {:code=>{:relative_xpath=>'oxns:roleTerm[@type="code"]'}}
27
+ ]}}
28
+ ]
29
+ accessor :organization, :relative_xpath=>'oxns:name[@type="institutional"]', :children=>[
30
+ {:role=>{:children=>[
31
+ {:text=>{:relative_xpath=>'oxns:roleTerm[@type="text"]'}},
32
+ {:code=>{:relative_xpath=>'oxns:roleTerm[@type="code"]'}}
33
+ ]}}
34
+ ]
35
+ accessor :conference, :relative_xpath=>'oxns:name[@type="conference"]', :children=>[
36
+ {:role=>{:children=>[
37
+ {:text=>{:relative_xpath=>'oxns:roleTerm[@type="text"]'}},
38
+ {:code=>{:relative_xpath=>'oxns:roleTerm[@type="code"]'}}
39
+ ]}}
40
+ ]
41
+ accessor :journal, :relative_xpath=>'oxns:relatedItem[@type="host"]', :children=>[
42
+ # allows for children that are hashes...
43
+ # this allows for more robust handling of nested values (in generating views and when generating solr field names)
44
+ {:title=>{:relative_xpath=>'oxns:titleInfo/oxns:title'}},
45
+ {:publisher=>{:relative_xpath=>'oxns:originInfo/oxns:publisher'}},
46
+ {:issn=>{:relative_xpath=>'oxns:identifier[@type="issn"]'}},
47
+ {:date_issued=>{:relative_xpath=>'oxns:originInfo/oxns:dateIssued'}},
48
+ {:issue => {:relative_xpath=>"oxns:part", :children=>[
49
+ {:volume=>{:relative_xpath=>'oxns:detail[@type="volume"]'}},
50
+ {:level=>{:relative_xpath=>'oxns:detail[@type="level"]'}},
51
+ {:start_page=>{:relative_xpath=>'oxns:extent[@unit="pages"]/oxns:start'}},
52
+ {:end_page=>{:relative_xpath=>'oxns:extent[@unit="pages"]/oxns:end'}},
53
+ {:publication_date=>{:relative_xpath=>'oxns:date'}}
54
+ ]}}
55
+ ]
56
+ end
57
+
58
+ end
59
+
60
+ before(:each) do
61
+ article_xml = fixture( File.join("mods_articles", "hydrangea_article1.xml") )
62
+ @sample = AccessorTest.from_xml(article_xml)
63
+ end
64
+
65
+ describe '#accessor' do
66
+ it "should populate the .accessors hash" do
67
+ AccessorTest.accessors[:abstract][:relative_xpath].should == "oxns:abstract"
68
+ AccessorTest.accessors[:journal][:relative_xpath].should == 'oxns:relatedItem[@type="host"]'
69
+ AccessorTest.accessors[:journal][:children][:issue][:relative_xpath].should == "oxns:part"
70
+ AccessorTest.accessors[:journal][:children][:issue][:children][:end_page][:relative_xpath].should == 'oxns:extent[@unit="pages"]/oxns:end'
71
+
72
+ AccessorTest.accessors[:person][:children][:role][:children][:text][:relative_xpath].should == 'oxns:roleTerm[@type="text"]'
73
+ end
74
+ end
75
+
76
+ describe ".retrieve" do
77
+ it "should use Nokogiri to retrieve a NodeSet corresponding to the combination of accessor keys and array/nodeset indexes" do
78
+ @sample.retrieve( :person ).length.should == 2
79
+
80
+ @sample.retrieve( :person, 1 ).first.should == @sample.ng_xml.xpath('//oxns:name[@type="personal" and position()=2]', "oxns"=>"http://www.loc.gov/mods/v3").first
81
+ @sample.retrieve( :person, 1, :first_name ).class.should == Nokogiri::XML::NodeSet
82
+ @sample.retrieve( :person, 1, :first_name ).first.text.should == "Siddartha"
83
+ end
84
+
85
+ it "should support accessors whose relative_xpath is a lookup array instead of an xpath string" do
86
+ # pending "this only impacts scenarios where we want to display & edit"
87
+ AccessorTest.accessors[:title_info][:children][:language][:relative_xpath].should == {:attribute=>"lang"}
88
+ # @sample.retrieve( :title, 1 ).first.text.should == "Artikkelin otsikko Hydrangea artiklan 1"
89
+ @sample.retrieve( :title_info, 1, :language ).first.text.should == "finnish"
90
+ end
91
+
92
+ end
93
+
94
+ describe ".retrieve_at" do
95
+ it "should return the first node in the resulting set (uses Nokogiri xpath_at)" do
96
+ pending "might be able to make this implicit in the last value of call to .retrieve"
97
+ @sample.retrieve_at(:person, 1, :first_name).text.should == "Siddartha"
98
+ @sample.retrieve_at(:person, 1, :first_name).should == @sample.retrieve( :person, 1, :first_name).first
99
+ end
100
+ end
101
+
102
+ describe "generated accessor methods" do
103
+ it "should mix accessor methods into nodesets so you can use regular array syntax to access stuff" do
104
+ pending "This is tempting, but somewhat difficult to implement and potentially slow at runtime. Might never be worth it?"
105
+ @sample.persons.length.should == 2
106
+ @sample.persons[1].first_name.text.should == "Siddartha"
107
+ @sample.persons.last.roles.length.should == 1
108
+ @sample.persons.last.roles[0].text.should == "teacher"
109
+ end
110
+ end
111
+
112
+ describe "#accessor_info" do
113
+ it "should return the xpath given in the call to #accessor" do
114
+ AccessorTest.accessor_info( :abstract ).should == AccessorTest.accessors[:abstract]
115
+ end
116
+ it "should return the xpath given in the call to #accessor" do
117
+ AccessorTest.accessor_info( :abstract ).should == AccessorTest.accessors[:abstract]
118
+ end
119
+ it "should dig into the accessors hash as far as you want, ignoring index values" do
120
+ AccessorTest.accessor_info( :conference, 0, :role, 1, :text ).should == AccessorTest.accessors[:conference][:children][:role][:children][:text]
121
+ AccessorTest.accessor_info( :conference, :role, :text ).should == AccessorTest.accessors[:conference][:children][:role][:children][:text]
122
+ end
123
+ end
124
+
125
+ describe "#accessor_xpath" do
126
+ it "should return the xpath given in the call to #accessor" do
127
+ AccessorTest.accessor_xpath( :abstract ).should == '//oxns:abstract'
128
+ end
129
+ # Note: Ruby array indexes begin from 0. In xpath queries (which start from 1 instead of 0), this will be translated accordingly.
130
+ it "should prepend the xpath for any parent nodes, inserting calls to xpath:position() function where necessary" do
131
+ AccessorTest.accessor_xpath( :conference, 0, :role, 1, :text ).should == '//oxns:name[@type="conference" and position()=1]/oxns:role[position()=2]/oxns:roleTerm[@type="text"]'
132
+ end
133
+ end
134
+ # describe ".accessor_xpath (instance method)" do
135
+ # it "should delegate to the class method" do
136
+ # AccessorTest.expects(:accessor_xpath).with( [:conference, conference_index, :text_role] )
137
+ # @sample.accessor_xpath( [:conference, conference_index, :role] )
138
+ # end
139
+ # end
140
+ #
141
+ # describe "generated catchall xpaths" do
142
+ # it "should return an xpath query that will catch all nodes corresponding to the specified accessor" do
143
+ # AccessorTest.journal_issue_end_page_xpath.should == 'oxns:relatedItem[@type="host"]/oxns:part/oxns:extent[@unit="pages"]/oxns:end'
144
+ # end
145
+ # it "should rely on #catchall_xpath" do
146
+ # AccessorTest.expects(:catchall_xpath).with(:journal, :issue, :end_page)
147
+ # AccessorTest.journal_issue_end_page_xpath
148
+ # end
149
+ # end
150
+ #
151
+ # describe ".catchall_xpath" do
152
+ # it "should return an xpath query that will catch all nodes corresponding to the specified accessor" do
153
+ # AccessorTest.catchall_xpath(:journal, :issue, :end_page).should == 'oxns:relatedItem[@type="host"]/oxns:part/oxns:extent[@unit="pages"]/oxns:end'
154
+ # end
155
+ # end
156
+ end
@@ -0,0 +1,60 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require "nokogiri"
3
+ require "om"
4
+
5
+ describe "OM::XML::Container" do
6
+
7
+ before(:all) do
8
+ class ContainerTest
9
+ include OM::XML::Container
10
+ end
11
+ end
12
+
13
+ before(:each) do
14
+ @container = ContainerTest.from_xml("<foo><bar>1</bar></foo>")
15
+ end
16
+
17
+ it "should automatically include the other modules" do
18
+ pending
19
+ ContainerTest.included_modules.should include(OM::XML::Accessor)
20
+ ContainerTest.included_modules.should include(OM::XML::Schema)
21
+ end
22
+
23
+ it "should add .ng_xml accessor" do
24
+ @container.should respond_to(:ng_xml)
25
+ @container.should respond_to(:ng_xml=)
26
+ end
27
+
28
+ describe "new" do
29
+ it "should populate ng_xml with an instance of Nokogiri::XML::Document" do
30
+ @container.ng_xml.class.should == Nokogiri::XML::Document
31
+ end
32
+ end
33
+
34
+ describe "#from_xml" do
35
+ it "should accept a String, parse it and store it in .ng_xml" do
36
+ Nokogiri::XML::Document.expects(:parse).returns("parsed xml")
37
+ container1 = ContainerTest.from_xml("<foo><bar>1</bar></foo>")
38
+ container1.ng_xml.should == "parsed xml"
39
+ end
40
+ it "should accept a File, parse it and store it in .ng_xml" do
41
+ file = fixture(File.join("mods_articles", "hydrangea_article1.xml"))
42
+ Nokogiri::XML::Document.expects(:parse).returns("parsed xml")
43
+ container1 = ContainerTest.from_xml(file)
44
+ container1.ng_xml.should == "parsed xml"
45
+ end
46
+ it "should accept Nokogiri nodes as input and leave them as-is" do
47
+ parsed_xml = Nokogiri::XML::Document.parse("<foo><bar>1</bar></foo>")
48
+ container1 = ContainerTest.from_xml(parsed_xml)
49
+ container1.ng_xml.should == parsed_xml
50
+ end
51
+ end
52
+
53
+ describe ".to_xml" do
54
+ it "should call .ng_xml.to_xml" do
55
+ @container.ng_xml.expects(:to_xml).returns("ng xml")
56
+ @container.to_xml.should == "ng xml"
57
+ end
58
+ end
59
+
60
+ end
@@ -0,0 +1,247 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require "om"
3
+
4
+ describe "OM::XML::Properties" do
5
+
6
+ before(:all) do
7
+ #ModsHelpers.name_("Beethoven, Ludwig van", :date=>"1770-1827", :role=>"creator")
8
+ class FakeOxMods
9
+
10
+ include OM::XML::Container
11
+ include OM::XML::Properties
12
+
13
+ # Could add support for multiple root declarations.
14
+ # For now, assume that any modsCollections have already been broken up and fed in as individual mods documents
15
+ # root :mods_collection, :path=>"modsCollection",
16
+ # :attributes=>[],
17
+ # :subelements => :mods
18
+
19
+ 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"
20
+
21
+
22
+ property :name_, :path=>"name",
23
+ :attributes=>[:xlink, :lang, "xml:lang", :script, :transliteration, {:type=>["personal", "enumerated", "corporate"]} ],
24
+ :subelements=>["namePart", "displayForm", "affiliation", :role, "description"],
25
+ :default_content_path => "namePart",
26
+ :convenience_methods => {
27
+ :date => {:path=>"namePart", :attributes=>{:type=>"date"}},
28
+ :family_name => {:path=>"namePart", :attributes=>{:type=>"family"}},
29
+ :given_name => {:path=>"namePart", :attributes=>{:type=>"given"}},
30
+ :terms_of_address => {:path=>"namePart", :attributes=>{:type=>"termsOfAddress"}}
31
+ }
32
+
33
+ property :person, :variant_of=>:name_, :attributes=>{:type=>"personal"}
34
+
35
+ property :role, :path=>"role",
36
+ :parents=>[:name_],
37
+ :attributes=>[ { "type"=>["text", "code"] } , "authority"],
38
+ :default_content_path => "roleTerm"
39
+
40
+
41
+ end
42
+
43
+ class FakeOtherOx < Nokogiri::XML::Document
44
+
45
+ include OM::XML::Properties
46
+ # extend OX::ClassMethods
47
+
48
+ root_property :other, "other", "http://www.foo.com"
49
+
50
+ end
51
+
52
+ end
53
+
54
+ before(:each) do
55
+ @fixturemods = FakeOxMods.from_xml( fixture( File.join("CBF_MODS", "ARS0025_016.xml") ) )
56
+ end
57
+
58
+ after(:all) do
59
+ Object.send(:remove_const, :FakeOxMods)
60
+ end
61
+
62
+ describe "#new" do
63
+ it "should set up namespaces" do
64
+ @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"}
65
+ end
66
+ end
67
+
68
+ describe "#root_property" do
69
+ it "should initialize root_property class attributes without attributes bleeding over to other OX classes" do
70
+ FakeOxMods.root_property_ref.should == :mods
71
+ FakeOxMods.root_config.should == {:ref=>:mods, :path=>"mods", :namespace=>"http://www.loc.gov/mods/v3", :attributes=>["id", "version"], :schema=>"http://www.loc.gov/standards/mods/v3/mods-3-2.xsd"}
72
+ FakeOxMods.ox_namespaces.should == {"oxns"=>"http://www.loc.gov/mods/v3"}
73
+
74
+ FakeOtherOx.root_property_ref.should == :other
75
+ FakeOtherOx.root_config.should == {:namespace=>"http://www.foo.com", :path=>"other", :ref=>:other}
76
+ end
77
+ end
78
+
79
+ describe "#property" do
80
+
81
+ it "fails gracefully if you try to look up nodes for an undefined property" do
82
+ @fixturemods.lookup(:nobody_home).should == []
83
+ end
84
+
85
+ it "constructs xpath queries for finding properties" do
86
+ FakeOxMods.properties[:name_][:xpath].should == '//oxns:name'
87
+ FakeOxMods.properties[:name_][:xpath_relative].should == 'oxns:name'
88
+
89
+ FakeOxMods.properties[:person][:xpath].should == '//oxns:name[@type="personal"]'
90
+ FakeOxMods.properties[:person][:xpath_relative].should == 'oxns:name[@type="personal"]'
91
+ end
92
+
93
+ it "constructs templates for value-driven searches" do
94
+ FakeOxMods.properties[:name_][:xpath_constrained].should == '//oxns:name[contains(oxns:namePart, "#{constraint_value}")]'.gsub('"', '\"')
95
+ FakeOxMods.properties[:person][:xpath_constrained].should == '//oxns:name[@type="personal" and contains(oxns:namePart, "#{constraint_value}")]'.gsub('"', '\"')
96
+
97
+ # Example of how you could use these templates:
98
+ constraint_value = "SAMPLE CONSTRAINT VALUE"
99
+ constrained_query = eval( '"' + FakeOxMods.properties[:person][:xpath_constrained] + '"' )
100
+ constrained_query.should == '//oxns:name[@type="personal" and contains(oxns:namePart, "SAMPLE CONSTRAINT VALUE")]'
101
+ end
102
+
103
+ it "constructs xpath queries & templates for convenience methods" do
104
+ FakeOxMods.properties[:name_][:convenience_methods][:date][:xpath].should == '//oxns:name/oxns:namePart[@type="date"]'
105
+ FakeOxMods.properties[:name_][:convenience_methods][:date][:xpath_relative].should == 'oxns:namePart[@type="date"]'
106
+ FakeOxMods.properties[:name_][:convenience_methods][:date][:xpath_constrained].should == '//oxns:name[contains(oxns:namePart[@type="date"], "#{constraint_value}")]'.gsub('"', '\"')
107
+
108
+ FakeOxMods.properties[:person][:convenience_methods][:date][:xpath].should == '//oxns:name[@type="personal"]/oxns:namePart[@type="date"]'
109
+ FakeOxMods.properties[:person][:convenience_methods][:date][:xpath_relative].should == 'oxns:namePart[@type="date"]'
110
+ FakeOxMods.properties[:person][:convenience_methods][:date][:xpath_constrained].should == '//oxns:name[@type="personal" and contains(oxns:namePart[@type="date"], "#{constraint_value}")]'.gsub('"', '\"')
111
+
112
+ end
113
+
114
+ it "constructs xpath queries & templates for subelements too" do
115
+ FakeOxMods.properties[:person][:convenience_methods][:displayForm][:xpath].should == '//oxns:name[@type="personal"]/oxns:displayForm'
116
+ FakeOxMods.properties[:person][:convenience_methods][:displayForm][:xpath_relative].should == 'oxns:displayForm'
117
+ FakeOxMods.properties[:person][:convenience_methods][:displayForm][:xpath_constrained].should == '//oxns:name[@type="personal" and contains(oxns:displayForm, "#{constraint_value}")]'.gsub('"', '\"')
118
+ end
119
+
120
+ it "supports subelements that are specified as separate properties" do
121
+ FakeOxMods.properties[:name_][:convenience_methods][:role][:xpath].should == '//oxns:name/oxns:role'
122
+ FakeOxMods.properties[:name_][:convenience_methods][:role][:xpath_relative].should == 'oxns:role'
123
+ FakeOxMods.properties[:name_][:convenience_methods][:role][:xpath_constrained].should == '//oxns:name[contains(oxns:role/oxns:roleTerm, "#{constraint_value}")]'.gsub('"', '\"')
124
+ end
125
+
126
+ it "should not overwrite default property info when adding a variant property" do
127
+ FakeOxMods.properties[:name_].should_not equal(FakeOxMods.properties[:person])
128
+ FakeOxMods.properties[:name_][:convenience_methods].should_not equal(FakeOxMods.properties[:person][:convenience_methods])
129
+
130
+ FakeOxMods.properties[:name_][:xpath].should_not == FakeOxMods.properties[:person][:xpath]
131
+ FakeOxMods.properties[:name_][:convenience_methods][:date][:xpath_constrained].should_not == FakeOxMods.properties[:person][:convenience_methods][:date][:xpath_constrained]
132
+ end
133
+
134
+ end
135
+
136
+ describe ".lookup" do
137
+
138
+ it "uses the generated xpath queries" do
139
+ @fixturemods.ng_xml.expects(:xpath).with('//oxns:name[@type="personal"]', @fixturemods.ox_namespaces)
140
+ @fixturemods.lookup(:person)
141
+
142
+ @fixturemods.ng_xml.expects(:xpath).with('//oxns:name[@type="personal" and contains(oxns:namePart, "Beethoven, Ludwig van")]', @fixturemods.ox_namespaces)
143
+ @fixturemods.lookup(:person, "Beethoven, Ludwig van")
144
+
145
+ @fixturemods.ng_xml.expects(:xpath).with('//oxns:name[@type="personal" and contains(oxns:namePart[@type="date"], "2010")]', @fixturemods.ox_namespaces)
146
+ @fixturemods.lookup(:person, :date=>"2010")
147
+
148
+ @fixturemods.ng_xml.expects(:xpath).with('//oxns:name[@type="personal" and contains(oxns:role/oxns:roleTerm, "donor")]', @fixturemods.ox_namespaces)
149
+ @fixturemods.lookup(:person, :role=>"donor")
150
+
151
+ # @fixturemods.expects(:xpath).with('//oxns:name[@type="personal"]/oxns:namePart[@type="date"]', @fixturemods.ox_namespaces)
152
+ # @fixturemods.lookup([:person,:date])
153
+
154
+ # @fixturemods.expects(:xpath).with('//oxns:name[contains(oxns:namePart[@type="date"], "2010")]', @fixturemods.ox_namespaces)
155
+ # @fixturemods.lookup([:person,:date], "2010")
156
+ end
157
+
158
+ end
159
+
160
+ describe ".xpath_query_for" do
161
+
162
+ it "retrieves the generated xpath query to match your desires" do
163
+ @fixturemods.xpath_query_for(:person).should == '//oxns:name[@type="personal"]'
164
+
165
+ @fixturemods.xpath_query_for(:person, "Beethoven, Ludwig van").should == '//oxns:name[@type="personal" and contains(oxns:namePart, "Beethoven, Ludwig van")]'
166
+
167
+ @fixturemods.xpath_query_for(:person, :date=>"2010").should == '//oxns:name[@type="personal" and contains(oxns:namePart[@type="date"], "2010")]'
168
+
169
+ @fixturemods.xpath_query_for(:person, :role=>"donor").should == '//oxns:name[@type="personal" and contains(oxns:role/oxns:roleTerm, "donor")]'
170
+
171
+ @fixturemods.xpath_query_for([:person,:date]).should == '//oxns:name[@type="personal"]/oxns:namePart[@type="date"]'
172
+
173
+ @fixturemods.xpath_query_for([:person,:date], "2010").should == '//oxns:name[@type="personal" and contains(oxns:namePart[@type="date"], "2010")]'
174
+ end
175
+
176
+ it "parrots any strings back to you (in case you already have an xpath query)" do
177
+ @fixturemods.xpath_query_for('//oxns:name[@type="personal"]/oxns:namePart[@type="date"]').should == '//oxns:name[@type="personal"]/oxns:namePart[@type="date"]'
178
+ end
179
+
180
+ end
181
+
182
+ describe "#generate_xpath" do
183
+ it "should generate an xpath query from the options in the provided hash and should support generating xpaths with constraint values" do
184
+ opts1 = {:path=>"name", :default_content_path=>"namePart"}
185
+ opts2 = {:path=>"originInfo"}
186
+ opts3 = {:path=>["name", "namePart"]}
187
+ FakeOxMods.generate_xpath( opts1 ).should == '//oxns:name'
188
+ FakeOxMods.generate_xpath( opts1, :constraints=>:default ).should == '//oxns:name[contains(oxns:namePart, "#{constraint_value}")]'
189
+ FakeOxMods.generate_xpath( opts2, :constraints=>:default ).should == '//oxns:originInfo[contains("#{constraint_value}")]'
190
+
191
+ FakeOxMods.generate_xpath( opts1, :variations=>{:attributes=>{:type=>"personal"}} ).should == '//oxns:name[@type="personal"]'
192
+ FakeOxMods.generate_xpath( opts1, :variations=>{:attributes=>{:type=>"personal"}}, :constraints=>:default ).should == '//oxns:name[@type="personal" and contains(oxns:namePart, "#{constraint_value}")]'
193
+
194
+ FakeOxMods.generate_xpath( opts1, :constraints=>{:path=>"namePart", :attributes=>{:type=>"date"}} ).should == '//oxns:name[contains(oxns:namePart[@type="date"], "#{constraint_value}")]'
195
+ FakeOxMods.generate_xpath( opts1, :constraints=>{:path=>"namePart", :attributes=>{:type=>"date"}}, :variations=>{:attributes=>{:type=>"personal"}} ).should == '//oxns:name[@type="personal" and contains(oxns:namePart[@type="date"], "#{constraint_value}")]'
196
+ FakeOxMods.generate_xpath(FakeOxMods.properties[:person], :variations=>{:attributes=>{:type=>"personal"}}, :constraints=>{:path=>"role", :default_content_path=>"roleTerm"}, :subelement_of=>":person").should == '//oxns:name[@type="personal" and contains(oxns:role/oxns:roleTerm, "#{constraint_value}")]'
197
+
198
+ FakeOxMods.generate_xpath(opts1, :variations=>{:attributes=>{:type=>"personal"}, :subelement_path=>"displayForm" } ).should == '//oxns:name[@type="personal"]/oxns:displayForm'
199
+ FakeOxMods.generate_xpath(opts1, :variations=>{:attributes=>{:type=>"personal"}}, :constraints=>{:path=>"displayForm"} ).should == '//oxns:name[@type="personal" and contains(oxns:displayForm, "#{constraint_value}")]'
200
+ FakeOxMods.generate_xpath(opts1, :variations=>{:attributes=>{:type=>"personal"}, :subelement_path=>["role", "roleTerm"] } ).should == '//oxns:name[@type="personal"]/oxns:role/oxns:roleTerm'
201
+
202
+ FakeOxMods.generate_xpath( opts3, :variations=>{:attributes=>{:type=>"date"}} ).should == '//oxns:name/oxns:namePart[@type="date"]'
203
+ end
204
+
205
+ it "should support relative paths" do
206
+ relative_opts = {:path=>"namePart"}
207
+ FakeOxMods.generate_xpath( relative_opts, :variations=>{:attributes=>{:type=>"date"}}, :relative=>true).should == 'oxns:namePart[@type="date"]'
208
+ end
209
+
210
+ it "should work with real properties hashes" do
211
+ FakeOxMods.generate_xpath(FakeOxMods.properties[:person], :variations=>FakeOxMods.properties[:person]).should == "//oxns:name[@type=\"personal\"]"
212
+ FakeOxMods.generate_xpath(FakeOxMods.properties[:person], :variations=>FakeOxMods.properties[:person], :constraints=>{:path=>"role", :default_content_path=>"roleTerm"}, :subelement_of=>":person").should == '//oxns:name[@type="personal" and contains(oxns:role/oxns:roleTerm, "#{constraint_value}")]'
213
+ date_hash = FakeOxMods.properties[:person][:convenience_methods][:date]
214
+ FakeOxMods.generate_xpath( date_hash, :variations=>date_hash, :relative=>true ).should == 'oxns:namePart[@type="date"]'
215
+ end
216
+
217
+ it "should support custom templates" do
218
+ opts = {:path=>"name", :default_content_path=>"namePart"}
219
+ FakeOxMods.generate_xpath( opts, :template=>'/#{prefix}:sampleNode/#{prefix}:#{path}[contains(#{default_content_path}, \":::constraint_value:::\")]' ).should == '/oxns:sampleNode/oxns:name[contains(namePart, "#{constraint_value}")]'
220
+ end
221
+ end
222
+
223
+ describe "#builder_template" do
224
+
225
+ it "should generate a template call for passing into the builder block (assumes 'xml' as the argument for the block)" do
226
+ FakeOxMods.builder_template([:person,:date]).should == 'xml.namePart( \'#{builder_new_value}\', :type=>\'date\' )'
227
+ FakeOxMods.builder_template([:name_,:affiliation]).should == 'xml.affiliation( \'#{builder_new_value}\' )'
228
+
229
+ simple_role_builder_template = 'xml.role( :type=>\'text\' ) { xml.roleTerm( \'#{builder_new_value}\' ) }'
230
+ FakeOxMods.builder_template([:role]).should == simple_role_builder_template
231
+ FakeOxMods.builder_template([:person,:role]).should == simple_role_builder_template
232
+
233
+ marcrelator_role_builder_template = 'xml.role( :type=>\'code\', :authority=>\'marcrelator\' ) { xml.roleTerm( \'#{builder_new_value}\' ) }'
234
+ FakeOxMods.builder_template([:role], {:attributes=>{"type"=>"code", "authority"=>"marcrelator"}} ).should == marcrelator_role_builder_template
235
+ FakeOxMods.builder_template([:person,:role], {:attributes=>{"type"=>"code", "authority"=>"marcrelator"}} ).should == marcrelator_role_builder_template
236
+ end
237
+
238
+ end
239
+
240
+ describe "#applicable_attributes" do
241
+ it "returns a Hash where all of the values are strings" do
242
+ FakeOxMods.send(:applicable_attributes, {:type=>"date"} ).should == {:type=>"date"}
243
+ FakeOxMods.send(:applicable_attributes, ["authority", {:type=>["text","code"]}] ).should == {:type=>"text"}
244
+ end
245
+ end
246
+
247
+ end