opinionated-xml 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,77 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{opinionated-xml}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Matt Zumwalt"]
12
+ s.date = %q{2010-05-16}
13
+ s.description = %q{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
+ s.email = %q{matt.zumwalt@yourmediashelf.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "History.textile",
23
+ "LICENSE",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "lib/opinionated-xml.rb",
28
+ "lib/opinionated-xml/ox.rb",
29
+ "lib/opinionated-xml/ox_property_values_helper.rb",
30
+ "opinionated-xml.gemspec",
31
+ "spec/fixtures/CBF_MODS/ARS0025_016.xml",
32
+ "spec/fixtures/mods-3-2.xsd",
33
+ "spec/fixtures/test_dummy_mods.xml",
34
+ "spec/helpers/ox_property_values_helper_spec.rb",
35
+ "spec/spec.opts",
36
+ "spec/spec_helper.rb",
37
+ "spec/unit/opinionated-xml_spec.rb",
38
+ "spec/unit/ox_integration_spec.rb"
39
+ ]
40
+ s.homepage = %q{http://github.com/mediashelf/opinionated-xml}
41
+ s.rdoc_options = ["--charset=UTF-8"]
42
+ s.require_paths = ["lib"]
43
+ s.rubygems_version = %q{1.3.6}
44
+ s.summary = %q{A library to help you tame sprawling XML schemas like MODS.}
45
+ s.test_files = [
46
+ "spec/helpers/ox_property_values_helper_spec.rb",
47
+ "spec/spec_helper.rb",
48
+ "spec/unit/opinionated-xml_spec.rb",
49
+ "spec/unit/ox_integration_spec.rb"
50
+ ]
51
+
52
+ if s.respond_to? :specification_version then
53
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
54
+ s.specification_version = 3
55
+
56
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
57
+ s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
58
+ s.add_runtime_dependency(%q<facets>, [">= 0"])
59
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
60
+ s.add_development_dependency(%q<mocha>, [">= 0.9.8"])
61
+ s.add_development_dependency(%q<ruby-debug>, [">= 0"])
62
+ else
63
+ s.add_dependency(%q<nokogiri>, [">= 0"])
64
+ s.add_dependency(%q<facets>, [">= 0"])
65
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
66
+ s.add_dependency(%q<mocha>, [">= 0.9.8"])
67
+ s.add_dependency(%q<ruby-debug>, [">= 0"])
68
+ end
69
+ else
70
+ s.add_dependency(%q<nokogiri>, [">= 0"])
71
+ s.add_dependency(%q<facets>, [">= 0"])
72
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
73
+ s.add_dependency(%q<mocha>, [">= 0.9.8"])
74
+ s.add_dependency(%q<ruby-debug>, [">= 0"])
75
+ end
76
+ end
77
+
@@ -0,0 +1,94 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2
+ <ns3:mods xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns3="http://www.loc.gov/mods/v3" xmlns:ns2="http://www.w3.org/1999/xlink">
3
+ <ns3:titleInfo>
4
+ <ns3:title>Brandenburg concerto no. 1 in F major</ns3:title>
5
+ </ns3:titleInfo>
6
+ <ns3:language>
7
+ <ns3:languageTerm type="code" authority="iso639-2b">No_linguistic_content</ns3:languageTerm>
8
+ <ns3:languageTerm type="text">No linguistic content</ns3:languageTerm>
9
+ </ns3:language>
10
+ <ns3:typeOfResource>sound recording-musical</ns3:typeOfResource>
11
+ <ns3:originInfo>
12
+ <ns3:dateCreated>07/23/1962</ns3:dateCreated>
13
+ </ns3:originInfo>
14
+ <ns3:name type="personal" authority="ingest">
15
+ <ns3:role>
16
+ <ns3:roleTerm type="text" authority="marcrelator">creator</ns3:roleTerm>
17
+ <ns3:roleTerm type="code" authority="marcrelator">cre</ns3:roleTerm>
18
+ </ns3:role>
19
+ <ns3:namePart type="family">Bach, Johann Sebastian, 1685-1750</ns3:namePart>
20
+ <ns3:displayForm>Bach, Johann Sebastian, 1685-1750</ns3:displayForm>
21
+ </ns3:name>
22
+ <ns3:name type="personal" authority="ingest">
23
+ <ns3:role>
24
+ <ns3:roleTerm type="text" authority="marcrelator">creator</ns3:roleTerm>
25
+ <ns3:roleTerm type="code" authority="marcrelator">cre</ns3:roleTerm>
26
+ </ns3:role>
27
+ <ns3:namePart type="family">Bergstone, Fred</ns3:namePart>
28
+ <ns3:displayForm>Bergstone, Fred</ns3:displayForm>
29
+ </ns3:name>
30
+ <ns3:name type="personal" authority="ingest">
31
+ <ns3:role>
32
+ <ns3:roleTerm type="text" authority="marcrelator">creator</ns3:roleTerm>
33
+ <ns3:roleTerm type="code" authority="marcrelator">cre</ns3:roleTerm>
34
+ </ns3:role>
35
+ <ns3:namePart type="family">Dust\u00E9, Raymond</ns3:namePart>
36
+ <ns3:displayForm>Dust\u00E9, Raymond</ns3:displayForm>
37
+ </ns3:name>
38
+ <ns3:name type="personal" authority="ingest">
39
+ <ns3:role>
40
+ <ns3:roleTerm type="text" authority="marcrelator">creator</ns3:roleTerm>
41
+ <ns3:roleTerm type="code" authority="marcrelator">cre</ns3:roleTerm>
42
+ </ns3:role>
43
+ <ns3:namePart type="family">Kates, Philip</ns3:namePart>
44
+ <ns3:displayForm>Kates, Philip</ns3:displayForm>
45
+ </ns3:name>
46
+ <ns3:name type="personal" authority="ingest">
47
+ <ns3:role>
48
+ <ns3:roleTerm type="text" authority="marcrelator">creator</ns3:roleTerm>
49
+ <ns3:roleTerm type="code" authority="marcrelator">cre</ns3:roleTerm>
50
+ </ns3:role>
51
+ <ns3:namePart type="family">Price, Charles Gower, 1939-</ns3:namePart>
52
+ <ns3:displayForm>Price, Charles Gower, 1939-</ns3:displayForm>
53
+ </ns3:name>
54
+ <ns3:name type="personal" authority="ingest">
55
+ <ns3:role>
56
+ <ns3:roleTerm type="text" authority="marcrelator">creator</ns3:roleTerm>
57
+ <ns3:roleTerm type="code" authority="marcrelator">cre</ns3:roleTerm>
58
+ </ns3:role>
59
+ <ns3:namePart type="family">Taylor, Ross, arranger</ns3:namePart>
60
+ <ns3:displayForm>Taylor, Ross, arranger</ns3:displayForm>
61
+ </ns3:name>
62
+ <ns3:name type="personal" authority="ingest">
63
+ <ns3:role>
64
+ <ns3:roleTerm type="text" authority="marcrelator">creator</ns3:roleTerm>
65
+ <ns3:roleTerm type="code" authority="marcrelator">cre</ns3:roleTerm>
66
+ </ns3:role>
67
+ <ns3:namePart type="family">Waller, Rosemary</ns3:namePart>
68
+ <ns3:displayForm>Waller, Rosemary</ns3:displayForm>
69
+ </ns3:name>
70
+ <ns3:subject authority="lcsh">
71
+ <ns3:topic>Concerti grossi</ns3:topic>
72
+ </ns3:subject>
73
+ <ns3:note displayLabel="Uniform title">Bach, Johann Sebastian, 1685-1750. Brandenburgische Konzerte. Nr. 1
74
+
75
+ </ns3:note>
76
+ <ns3:physicalDescription>
77
+ <ns3:note displayLabel="General Physical Description note">1 7 in. open reel audio tape</ns3:note>
78
+ </ns3:physicalDescription>
79
+ <ns3:relatedItem type="host">
80
+ <ns3:titleInfo>
81
+ <ns3:title>Carmel Bach Festival Tape Collection</ns3:title>
82
+ </ns3:titleInfo>
83
+ <ns3:originInfo>
84
+ <ns3:dateCreated>1962-1982</ns3:dateCreated>
85
+ <ns3:dateCreated point="start">1962</ns3:dateCreated>
86
+ <ns3:dateCreated point="end">1982</ns3:dateCreated>
87
+ </ns3:originInfo>
88
+ <ns3:identifier type="local">ARS.0025</ns3:identifier>
89
+ </ns3:relatedItem>
90
+ <ns3:note displayLabel="Digital object made available by ">Archive of Recorded Sound, Braun Music Center, 541 Lasuen Mall, Stanford University, Stanford, California, 94305-3076, USA, (http://library.stanford.edu/depts/ars)</ns3:note>
91
+ <ns3:identifier displayLabel="Audio-Streaming">ARS0025_016_a_sl.mp3</ns3:identifier>
92
+ <ns3:identifier displayLabel="Audio-Service">ARS0025_016_a_sh.wav</ns3:identifier>
93
+ <ns3:identifier displayLabel="Audio-Master">ARS0025_016_a_pm.wav</ns3:identifier>
94
+ </ns3:mods>
@@ -0,0 +1 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
  Tentative plan for 4.0 is to make it an element instead of an attribute,
1
3
  and wrap <url> and <urlNote> together. Can't do that in 3.2
2
4
  because it would not be compatible with 3.1.
3
5
  but had not been explicitly typed, are now typed.
4
6
  http://www.loc.gov/standards/xlink.xsd.
5
7
  (It was previously http://www.loc.gov/standards/mods/xlink.xsd.
6
8
  The schema now resides in both places so that earlier versions
7
9
  will not be affected, but it is now intended that the new copy
8
10
  be referenced, outside of the mods directory,
9
11
  so that other projects, e.g. mets, may reference it.)
10
12
  (1) a single MODS record:
11
13
  record definintion, and also relatedItem.
12
14
  Difference is that mods requires at least one element
13
15
  and relatedItem does not.
14
- ->
15
- ->
16
16
 
17
17
  ********** titleInfoType definition **********
18
18
  -->
19
19
  ********** nameType definition **********
20
- ->
21
- ->
22
- ->
23
20
  </xsd:documentation>
24
- ->
25
21
  -->
26
- ->
27
22
  ********** originInfoType definition **********
28
- ->
29
- ->
30
- ->
31
23
  -->
32
24
  -->
33
25
  -->
34
26
  -->
35
27
  -->
36
28
  ********** subjectType definition **********
37
- ->
38
- ->
39
- ->
40
- ->
41
- ->
42
- ->
43
29
  -->
44
30
 
45
31
  -->
46
32
  -->
47
- ->
48
- ->
49
- ->
50
- ->
51
- ->
52
- ->
53
- ->
54
33
  ********** language attribute group definition **********
55
- ->
56
34
  ********** definition of codeOrText type used by type attribute
57
35
  for elements that distinguish code from text **********
58
36
  -->
59
37
  ********** definition of placeAuthority type used by authority attribute
60
38
  for placeType and geographic **********
61
39
  -->
62
40
  ********** definition of nameTypeAttribute used by name attribute
63
41
  "type" **********
64
42
  -->
@@ -0,0 +1,19 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2
+ <ns3:mods xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns3="http://www.loc.gov/mods/v3" xmlns:ns2="http://www.w3.org/1999/xlink">
3
+ <ns3:name type="personal">
4
+ <ns3:namePart type="family">Berners-Lee</ns3:namePart>
5
+ <ns3:namePart type="given">Tim</ns3:namePart>
6
+ </ns3:name>
7
+ <ns3:name type="personal">
8
+ <ns3:namePart type="family">Jobs</ns3:namePart>
9
+ <ns3:namePart type="given">Steve</ns3:namePart>
10
+ </ns3:name>
11
+ <ns3:name type="personal">
12
+ <ns3:namePart type="family">Wozniak</ns3:namePart>
13
+ <ns3:namePart type="given">The Woz</ns3:namePart>
14
+ </ns3:name>
15
+ <ns3:name type="personal">
16
+ <ns3:namePart type="family">Klimt</ns3:namePart>
17
+ <ns3:namePart type="given">Gustav</ns3:namePart>
18
+ </ns3:name>
19
+ </ns3:mods>
@@ -0,0 +1,55 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ class FakePVHClass
4
+ include OX::PropertyValuesHelper
5
+ end
6
+
7
+ def helper
8
+ @fake_includer
9
+ end
10
+
11
+ describe "OX::PropertyValuesHelper" do
12
+
13
+ before(:all) do
14
+ @fake_includer = FakePVHClass.new
15
+ end
16
+
17
+ describe ".property_values" do
18
+
19
+ it "should call .lookup and then build an array of values from the returned nodeset (using default_node, etc as nessesary)" do
20
+ lookup_opts = "insert args here"
21
+ mock_node = mock("node")
22
+ mock_node.expects(:text).returns("sample value").times(3)
23
+ mock_nodeset = [mock_node, mock_node, mock_node]
24
+ helper.expects(:lookup).with(lookup_opts).returns(mock_nodeset)
25
+
26
+ helper.property_values(lookup_opts).should == ["sample value","sample value","sample value"]
27
+ end
28
+
29
+ end
30
+
31
+ describe ".property_values_append" do
32
+
33
+ # see ../unit/ox_integration_spec.rb
34
+
35
+ end
36
+
37
+ describe ".property_value_set" do
38
+
39
+ it "should " do
40
+ pending "in progress..."
41
+ @fixturemods.property_value_set('//oxns:name[@type="personal"]',1,"foo")
42
+ @fixturemods.property_value_set([ [:person,:role], "donor"], 5, "special donor")
43
+ end
44
+
45
+ it "could support alternative notation" do
46
+ pending "this would be for the sake of consistency with the method signature of property_values_append"
47
+ # @fixturemods.property_value_set(
48
+ # :node_select =>'//oxns:name[@type="personal"]',
49
+ # :node_index => 1,
50
+ # :values => "foo"
51
+ # ).to_xml.should == expected_result
52
+ end
53
+ end
54
+
55
+ end
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 'opinionated-xml'
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,300 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "OpinionatedXml" do
4
+
5
+ before(:all) do
6
+ #ModsHelpers.name_("Beethoven, Ludwig van", :date=>"1770-1827", :role=>"creator")
7
+ class FakeOxMods < Nokogiri::XML::Document
8
+
9
+ include OX
10
+
11
+ # Could add support for multiple root declarations.
12
+ # For now, assume that any modsCollections have already been broken up and fed in as individual mods documents
13
+ # root :mods_collection, :path=>"modsCollection",
14
+ # :attributes=>[],
15
+ # :subelements => :mods
16
+
17
+ 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"
18
+
19
+
20
+ property :name_, :path=>"name",
21
+ :attributes=>[:xlink, :lang, "xml:lang", :script, :transliteration, {:type=>["personal", "enumerated", "corporate"]} ],
22
+ :subelements=>["namePart", "displayForm", "affiliation", :role, "description"],
23
+ :default_content_path => "namePart",
24
+ :convenience_methods => {
25
+ :date => {:path=>"namePart", :attributes=>{:type=>"date"}},
26
+ :family_name => {:path=>"namePart", :attributes=>{:type=>"family"}},
27
+ :given_name => {:path=>"namePart", :attributes=>{:type=>"given"}},
28
+ :terms_of_address => {:path=>"namePart", :attributes=>{:type=>"termsOfAddress"}}
29
+ }
30
+
31
+ property :person, :variant_of=>:name_, :attributes=>{:type=>"personal"}
32
+
33
+ property :role, :path=>"role",
34
+ :parents=>[:name_],
35
+ :attributes=>[ { "type"=>["text", "code"] } , "authority"],
36
+ :default_content_path => "roleTerm"
37
+
38
+
39
+ end
40
+
41
+ class FakeOtherOx < Nokogiri::XML::Document
42
+
43
+ include OX
44
+ extend OX::ClassMethods
45
+
46
+ root_property :other, "other", "http://www.foo.com"
47
+
48
+ end
49
+
50
+ end
51
+
52
+ before(:each) do
53
+ @fixturemods = FakeOxMods.parse( fixture( File.join("CBF_MODS", "ARS0025_016.xml") ) )
54
+ end
55
+
56
+ after(:all) do
57
+ Object.send(:remove_const, :FakeOxMods)
58
+ end
59
+
60
+ describe "#new" do
61
+ it "should set up namespaces" do
62
+ @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"}
63
+ end
64
+ end
65
+
66
+ describe "#root_property" do
67
+ it "should initialize root_property class attributes without attributes bleeding over to other OX classes" do
68
+ FakeOxMods.root_property_ref.should == :mods
69
+ 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"}
70
+ FakeOxMods.ox_namespaces.should == {"oxns"=>"http://www.loc.gov/mods/v3"}
71
+ FakeOxMods.schema_url.should == "http://www.loc.gov/standards/mods/v3/mods-3-2.xsd"
72
+
73
+ FakeOtherOx.root_property_ref.should == :other
74
+ FakeOtherOx.root_config.should == {:namespace=>"http://www.foo.com", :path=>"other", :ref=>:other}
75
+ end
76
+ end
77
+
78
+ describe "#property" do
79
+
80
+ it "fails gracefully if you try to look up nodes for an undefined property" do
81
+ @fixturemods.lookup(:nobody_home).should == []
82
+ end
83
+
84
+ it "constructs xpath queries for finding properties" do
85
+ FakeOxMods.properties[:name_][:xpath].should == '//oxns:name'
86
+ FakeOxMods.properties[:name_][:xpath_relative].should == 'oxns:name'
87
+
88
+ FakeOxMods.properties[:person][:xpath].should == '//oxns:name[@type="personal"]'
89
+ FakeOxMods.properties[:person][:xpath_relative].should == 'oxns:name[@type="personal"]'
90
+ end
91
+
92
+ it "constructs templates for value-driven searches" do
93
+ FakeOxMods.properties[:name_][:xpath_constrained].should == '//oxns:name[contains(oxns:namePart, "#{constraint_value}")]'.gsub('"', '\"')
94
+ FakeOxMods.properties[:person][:xpath_constrained].should == '//oxns:name[@type="personal" and contains(oxns:namePart, "#{constraint_value}")]'.gsub('"', '\"')
95
+
96
+ # Example of how you could use these templates:
97
+ constraint_value = "SAMPLE CONSTRAINT VALUE"
98
+ constrained_query = eval( '"' + FakeOxMods.properties[:person][:xpath_constrained] + '"' )
99
+ constrained_query.should == '//oxns:name[@type="personal" and contains(oxns:namePart, "SAMPLE CONSTRAINT VALUE")]'
100
+ end
101
+
102
+ it "constructs xpath queries & templates for convenience methods" do
103
+ FakeOxMods.properties[:name_][:convenience_methods][:date][:xpath].should == '//oxns:name/oxns:namePart[@type="date"]'
104
+ FakeOxMods.properties[:name_][:convenience_methods][:date][:xpath_relative].should == 'oxns:namePart[@type="date"]'
105
+ FakeOxMods.properties[:name_][:convenience_methods][:date][:xpath_constrained].should == '//oxns:name[contains(oxns:namePart[@type="date"], "#{constraint_value}")]'.gsub('"', '\"')
106
+
107
+ FakeOxMods.properties[:person][:convenience_methods][:date][:xpath].should == '//oxns:name[@type="personal"]/oxns:namePart[@type="date"]'
108
+ FakeOxMods.properties[:person][:convenience_methods][:date][:xpath_relative].should == 'oxns:namePart[@type="date"]'
109
+ FakeOxMods.properties[:person][:convenience_methods][:date][:xpath_constrained].should == '//oxns:name[@type="personal" and contains(oxns:namePart[@type="date"], "#{constraint_value}")]'.gsub('"', '\"')
110
+
111
+ end
112
+
113
+ it "constructs xpath queries & templates for subelements too" do
114
+ FakeOxMods.properties[:person][:convenience_methods][:displayForm][:xpath].should == '//oxns:name[@type="personal"]/oxns:displayForm'
115
+ FakeOxMods.properties[:person][:convenience_methods][:displayForm][:xpath_relative].should == 'oxns:displayForm'
116
+ FakeOxMods.properties[:person][:convenience_methods][:displayForm][:xpath_constrained].should == '//oxns:name[@type="personal" and contains(oxns:displayForm, "#{constraint_value}")]'.gsub('"', '\"')
117
+ end
118
+
119
+ it "supports subelements that are specified as separate properties" do
120
+ FakeOxMods.properties[:name_][:convenience_methods][:role][:xpath].should == '//oxns:name/oxns:role'
121
+ FakeOxMods.properties[:name_][:convenience_methods][:role][:xpath_relative].should == 'oxns:role'
122
+ FakeOxMods.properties[:name_][:convenience_methods][:role][:xpath_constrained].should == '//oxns:name[contains(oxns:role/oxns:roleTerm, "#{constraint_value}")]'.gsub('"', '\"')
123
+ end
124
+
125
+ it "should not overwrite default property info when adding a variant property" do
126
+ FakeOxMods.properties[:name_].should_not equal(FakeOxMods.properties[:person])
127
+ FakeOxMods.properties[:name_][:convenience_methods].should_not equal(FakeOxMods.properties[:person][:convenience_methods])
128
+
129
+ FakeOxMods.properties[:name_][:xpath].should_not == FakeOxMods.properties[:person][:xpath]
130
+ FakeOxMods.properties[:name_][:convenience_methods][:date][:xpath_constrained].should_not == FakeOxMods.properties[:person][:convenience_methods][:date][:xpath_constrained]
131
+ end
132
+
133
+ end
134
+
135
+ describe ".lookup" do
136
+
137
+ it "uses the generated xpath queries" do
138
+ @fixturemods.expects(:xpath).with('//oxns:name[@type="personal"]', @fixturemods.ox_namespaces)
139
+ @fixturemods.lookup(:person)
140
+
141
+ @fixturemods.expects(:xpath).with('//oxns:name[@type="personal" and contains(oxns:namePart, "Beethoven, Ludwig van")]', @fixturemods.ox_namespaces)
142
+ @fixturemods.lookup(:person, "Beethoven, Ludwig van")
143
+
144
+ @fixturemods.expects(:xpath).with('//oxns:name[@type="personal" and contains(oxns:namePart[@type="date"], "2010")]', @fixturemods.ox_namespaces)
145
+ @fixturemods.lookup(:person, :date=>"2010")
146
+
147
+ @fixturemods.expects(:xpath).with('//oxns:name[@type="personal" and contains(oxns:role/oxns:roleTerm, "donor")]', @fixturemods.ox_namespaces)
148
+ @fixturemods.lookup(:person, :role=>"donor")
149
+
150
+ # @fixturemods.expects(:xpath).with('//oxns:name[@type="personal"]/oxns:namePart[@type="date"]', @fixturemods.ox_namespaces)
151
+ # @fixturemods.lookup([:person,:date])
152
+
153
+ # @fixturemods.expects(:xpath).with('//oxns:name[contains(oxns:namePart[@type="date"], "2010")]', @fixturemods.ox_namespaces)
154
+ # @fixturemods.lookup([:person,:date], "2010")
155
+ end
156
+
157
+ end
158
+
159
+ describe ".xpath_query_for" do
160
+
161
+ it "retrieves the generated xpath query to match your desires" do
162
+ @fixturemods.xpath_query_for(:person).should == '//oxns:name[@type="personal"]'
163
+
164
+ @fixturemods.xpath_query_for(:person, "Beethoven, Ludwig van").should == '//oxns:name[@type="personal" and contains(oxns:namePart, "Beethoven, Ludwig van")]'
165
+
166
+ @fixturemods.xpath_query_for(:person, :date=>"2010").should == '//oxns:name[@type="personal" and contains(oxns:namePart[@type="date"], "2010")]'
167
+
168
+ @fixturemods.xpath_query_for(:person, :role=>"donor").should == '//oxns:name[@type="personal" and contains(oxns:role/oxns:roleTerm, "donor")]'
169
+
170
+ @fixturemods.xpath_query_for([:person,:date]).should == '//oxns:name[@type="personal"]/oxns:namePart[@type="date"]'
171
+
172
+ @fixturemods.xpath_query_for([:person,:date], "2010").should == '//oxns:name[@type="personal" and contains(oxns:namePart[@type="date"], "2010")]'
173
+ end
174
+
175
+ it "parrots any strings back to you (in case you already have an xpath query)" do
176
+ @fixturemods.xpath_query_for('//oxns:name[@type="personal"]/oxns:namePart[@type="date"]').should == '//oxns:name[@type="personal"]/oxns:namePart[@type="date"]'
177
+ end
178
+
179
+ end
180
+
181
+ describe "#generate_xpath" do
182
+ it "should generate an xpath query from the options in the provided hash and should support generating xpaths with constraint values" do
183
+ opts1 = {:path=>"name", :default_content_path=>"namePart"}
184
+ opts2 = {:path=>"originInfo"}
185
+ opts3 = {:path=>["name", "namePart"]}
186
+ FakeOxMods.generate_xpath( opts1 ).should == '//oxns:name'
187
+ FakeOxMods.generate_xpath( opts1, :constraints=>:default ).should == '//oxns:name[contains(oxns:namePart, "#{constraint_value}")]'
188
+ FakeOxMods.generate_xpath( opts2, :constraints=>:default ).should == '//oxns:originInfo[contains("#{constraint_value}")]'
189
+
190
+ FakeOxMods.generate_xpath( opts1, :variations=>{:attributes=>{:type=>"personal"}} ).should == '//oxns:name[@type="personal"]'
191
+ FakeOxMods.generate_xpath( opts1, :variations=>{:attributes=>{:type=>"personal"}}, :constraints=>:default ).should == '//oxns:name[@type="personal" and contains(oxns:namePart, "#{constraint_value}")]'
192
+
193
+ FakeOxMods.generate_xpath( opts1, :constraints=>{:path=>"namePart", :attributes=>{:type=>"date"}} ).should == '//oxns:name[contains(oxns:namePart[@type="date"], "#{constraint_value}")]'
194
+ 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}")]'
195
+ 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}")]'
196
+
197
+ FakeOxMods.generate_xpath(opts1, :variations=>{:attributes=>{:type=>"personal"}, :subelement_path=>"displayForm" } ).should == '//oxns:name[@type="personal"]/oxns:displayForm'
198
+ FakeOxMods.generate_xpath(opts1, :variations=>{:attributes=>{:type=>"personal"}}, :constraints=>{:path=>"displayForm"} ).should == '//oxns:name[@type="personal" and contains(oxns:displayForm, "#{constraint_value}")]'
199
+ FakeOxMods.generate_xpath(opts1, :variations=>{:attributes=>{:type=>"personal"}, :subelement_path=>["role", "roleTerm"] } ).should == '//oxns:name[@type="personal"]/oxns:role/oxns:roleTerm'
200
+
201
+ FakeOxMods.generate_xpath( opts3, :variations=>{:attributes=>{:type=>"date"}} ).should == '//oxns:name/oxns:namePart[@type="date"]'
202
+ end
203
+
204
+ it "should support relative paths" do
205
+ relative_opts = {:path=>"namePart"}
206
+ FakeOxMods.generate_xpath( relative_opts, :variations=>{:attributes=>{:type=>"date"}}, :relative=>true).should == 'oxns:namePart[@type="date"]'
207
+ end
208
+
209
+ it "should work with real properties hashes" do
210
+ FakeOxMods.generate_xpath(FakeOxMods.properties[:person], :variations=>FakeOxMods.properties[:person]).should == "//oxns:name[@type=\"personal\"]"
211
+ 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}")]'
212
+ date_hash = FakeOxMods.properties[:person][:convenience_methods][:date]
213
+ FakeOxMods.generate_xpath( date_hash, :variations=>date_hash, :relative=>true ).should == 'oxns:namePart[@type="date"]'
214
+ end
215
+
216
+ it "should support custom templates" do
217
+ opts = {:path=>"name", :default_content_path=>"namePart"}
218
+ FakeOxMods.generate_xpath( opts, :template=>'/#{prefix}:sampleNode/#{prefix}:#{path}[contains(#{default_content_path}, \":::constraint_value:::\")]' ).should == '/oxns:sampleNode/oxns:name[contains(namePart, "#{constraint_value}")]'
219
+ end
220
+ end
221
+
222
+ describe "#builder_template" do
223
+
224
+ it "should generate a template call for passing into the builder block (assumes 'xml' as the argument for the block)" do
225
+ FakeOxMods.builder_template([:person,:date]).should == 'xml.namePart( \'#{builder_new_value}\', :type=>\'date\' )'
226
+ FakeOxMods.builder_template([:name_,:affiliation]).should == 'xml.affiliation( \'#{builder_new_value}\' )'
227
+
228
+ simple_role_builder_template = 'xml.role( :type=>\'text\' ) { xml.roleTerm( \'#{builder_new_value}\' ) }'
229
+ FakeOxMods.builder_template([:role]).should == simple_role_builder_template
230
+ FakeOxMods.builder_template([:person,:role]).should == simple_role_builder_template
231
+
232
+ marcrelator_role_builder_template = 'xml.role( :type=>\'code\', :authority=>\'marcrelator\' ) { xml.roleTerm( \'#{builder_new_value}\' ) }'
233
+ FakeOxMods.builder_template([:role], {:attributes=>{"type"=>"code", "authority"=>"marcrelator"}} ).should == marcrelator_role_builder_template
234
+ FakeOxMods.builder_template([:person,:role], {:attributes=>{"type"=>"code", "authority"=>"marcrelator"}} ).should == marcrelator_role_builder_template
235
+ end
236
+
237
+ end
238
+
239
+ describe "#applicable_attributes" do
240
+ it "returns a Hash where all of the values are strings" do
241
+ FakeOxMods.send(:applicable_attributes, {:type=>"date"} ).should == {:type=>"date"}
242
+ FakeOxMods.send(:applicable_attributes, ["authority", {:type=>["text","code"]}] ).should == {:type=>"text"}
243
+ end
244
+ end
245
+
246
+ ## Validation Support
247
+ # Some of these tests fail when you don't have an internet connection because the mods schema includes other xsd schemas by URL reference.
248
+
249
+ describe "#schema" do
250
+ it "should return an instance of Nokogiri::XML::Schema loaded from the schema url -- fails if no internet connection" do
251
+ FakeOxMods.schema.should be_kind_of Nokogiri::XML::Schema
252
+ end
253
+ end
254
+
255
+ describe "#validate" do
256
+ it "should validate the provided document against the schema provided in class definition -- fails if no internet connection" do
257
+ FakeOxMods.schema.expects(:validate).with(@fixturemods).returns([])
258
+ FakeOxMods.validate(@fixturemods)
259
+ end
260
+ end
261
+
262
+ describe ".validate" do
263
+ it "should rely on class validate method" do
264
+ FakeOxMods.expects(:validate).with(@fixturemods)
265
+ @fixturemods.validate
266
+ end
267
+ end
268
+
269
+ describe "#schema_file" do
270
+ before(:all) do
271
+ FakeOxMods.schema_file = nil
272
+ end
273
+
274
+ after(:all) do
275
+ FakeOxMods.schema_file = fixture("mods-3-2.xsd")
276
+ end
277
+
278
+ it "should lazy load the schema file from the @schema_url" do
279
+ FakeOxMods.instance_variable_get(:@schema_file).should be_nil
280
+ FakeOxMods.expects(:file_from_url).with(FakeOxMods.schema_url).returns("fake file").once
281
+ FakeOxMods.schema_file
282
+ FakeOxMods.instance_variable_get(:@schema_file).should == "fake file"
283
+ FakeOxMods.schema_file.should == "fake file"
284
+ end
285
+ end
286
+
287
+ describe "#file_from_url" do
288
+ it "should retrieve a file from the provided url over HTTP" do
289
+ FakeOxMods.send(:file_from_url, "http://google.com")
290
+ end
291
+ it "should raise an error if the url is invalid" do
292
+ lambda {FakeOxMods.send(:file_from_url, "")}.should raise_error(RuntimeError, "Could not retrieve file from . Error: No such file or directory - ")
293
+ lambda {FakeOxMods.send(:file_from_url, "foo")}.should raise_error(RuntimeError, "Could not retrieve file from foo. Error: No such file or directory - foo")
294
+ end
295
+ it "should raise an error if file retrieval fails" do
296
+ lambda {FakeOxMods.send(:file_from_url, "http://fedora-commons.org/nonexistent_file")}.should raise_error(RuntimeError, "Could not retrieve file from http://fedora-commons.org/nonexistent_file. Error: 404 Not Found")
297
+ end
298
+ end
299
+
300
+ end