om 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,245 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require "om"
3
+
4
+ describe "OM::XML::PropertyValueOperators" do
5
+
6
+ before(:all) do
7
+ #ModsHelpers.name_("Beethoven, Ludwig van", :date=>"1770-1827", :role=>"creator")
8
+ class PropertiesValueOperatorsTest
9
+
10
+ include OM::XML::Container
11
+ include OM::XML::Properties
12
+ include OM::XML::PropertyValueOperators
13
+
14
+ # Could add support for multiple root declarations.
15
+ # For now, assume that any modsCollections have already been broken up and fed in as individual mods documents
16
+ # root :mods_collection, :path=>"modsCollection",
17
+ # :attributes=>[],
18
+ # :subelements => :mods
19
+
20
+ 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"
21
+
22
+
23
+ property :name_, :path=>"name",
24
+ :attributes=>[:xlink, :lang, "xml:lang", :script, :transliteration, {:type=>["personal", "enumerated", "corporate"]} ],
25
+ :subelements=>["namePart", "displayForm", "affiliation", :role, "description"],
26
+ :default_content_path => "namePart",
27
+ :convenience_methods => {
28
+ :date => {:path=>"namePart", :attributes=>{:type=>"date"}},
29
+ :family_name => {:path=>"namePart", :attributes=>{:type=>"family"}},
30
+ :given_name => {:path=>"namePart", :attributes=>{:type=>"given"}},
31
+ :terms_of_address => {:path=>"namePart", :attributes=>{:type=>"termsOfAddress"}}
32
+ }
33
+
34
+ property :person, :variant_of=>:name_, :attributes=>{:type=>"personal"}
35
+
36
+ property :role, :path=>"role",
37
+ :parents=>[:name_],
38
+ :attributes=>[ { "type"=>["text", "code"] } , "authority"],
39
+ :default_content_path => "roleTerm"
40
+
41
+
42
+ end
43
+
44
+ end
45
+
46
+ before(:each) do
47
+ @sample = PropertiesValueOperatorsTest.from_xml( fixture( File.join("test_dummy_mods.xml") ) )
48
+ end
49
+
50
+ after(:all) do
51
+ Object.send(:remove_const, :PropertiesValueOperatorsTest)
52
+ end
53
+
54
+ describe ".property_values" do
55
+
56
+ it "should call .lookup and then build an array of values from the returned nodeset (using default_node, etc as nessesary)" do
57
+ lookup_opts = "insert args here"
58
+ mock_node = mock("node")
59
+ mock_node.expects(:text).returns("sample value").times(3)
60
+ mock_nodeset = [mock_node, mock_node, mock_node]
61
+ @sample.expects(:lookup).with(lookup_opts).returns(mock_nodeset)
62
+
63
+ @sample.property_values(lookup_opts).should == ["sample value","sample value","sample value"]
64
+ end
65
+
66
+ end
67
+
68
+ describe ".property_values_append" do
69
+
70
+ it "looks up the parent using :parent_select, uses :child_index to choose the parent node from the result set, uses :template to build the node(s) to be inserted, inserts the :values(s) into the node(s) and adds the node(s) to the parent" do
71
+ @sample.property_values_append(
72
+ :parent_select => [:person, {:given_name=>"Tim", :family_name=>"Berners-Lee"}] ,
73
+ :child_index => :first,
74
+ :template => [:person, :affiliation],
75
+ :values => ["my new value", "another new value"]
76
+ )
77
+ end
78
+
79
+ it "should accept parent_select and template [property_reference, lookup_opts] as argument arrays for generators/lookups" do
80
+ # this appends two affiliation nodes into the first person node whose name is Tim Berners-Lee
81
+ expected_result = '<ns3:name type="personal">
82
+ <ns3:namePart type="family">Berners-Lee</ns3:namePart>
83
+ <ns3:namePart type="given">Tim</ns3:namePart>
84
+ <ns3:role>
85
+ <ns3:roleTerm type="text" authority="marcrelator">creator</ns3:roleTerm>
86
+ <ns3:roleTerm type="code" authority="marcrelator">cre</ns3:roleTerm>
87
+ </ns3:role>
88
+ <ns3:affiliation>my new value</ns3:affiliation><ns3:affiliation>another new value</ns3:affiliation></ns3:name>'
89
+
90
+ @sample.property_values_append(
91
+ :parent_select => [:person, {:given_name=>"Tim", :family_name=>"Berners-Lee"}] ,
92
+ :child_index => :first,
93
+ :template => [:person, :affiliation],
94
+ :values => ["my new value", "another new value"]
95
+ ).to_xml.should == expected_result
96
+
97
+ @sample.lookup(:person, {:given_name=>"Tim", :family_name=>"Berners-Lee"}).first.to_xml.should == expected_result
98
+ end
99
+
100
+ it "should accept symbols as arguments for generators/lookups" do
101
+ # this appends a role of "my role" into the third "person" node in the document
102
+ expected_result = "<ns3:name type=\"personal\">\n <ns3:namePart type=\"family\">Klimt</ns3:namePart>\n <ns3:namePart type=\"given\">Gustav</ns3:namePart>\n <ns3:role>\n <ns3:roleTerm type=\"text\" authority=\"marcrelator\">creator</ns3:roleTerm>\n <ns3:roleTerm type=\"code\" authority=\"marcrelator\">cre</ns3:roleTerm>\n </ns3:role>\n <ns3:role>\n <ns3:roleTerm type=\"text\" authority=\"marcrelator\">visionary</ns3:roleTerm>\n <ns3:roleTerm type=\"code\" authority=\"marcrelator\">vry</ns3:roleTerm>\n </ns3:role>\n <ns3:role type=\"text\"><ns3:roleTerm>my role</ns3:roleTerm></ns3:role></ns3:name>"
103
+
104
+ @sample.property_values_append(
105
+ :parent_select => :person ,
106
+ :child_index => 3,
107
+ :template => :role,
108
+ :values => "my role"
109
+ ).to_xml.should == expected_result
110
+
111
+ @sample.lookup(:person)[3].to_xml.should == expected_result
112
+ end
113
+
114
+ it "should accept parent_select as an (xpath) string and template as a (template) string" do
115
+ # this uses the provided template to add a node into the first node resulting from the xpath '//oxns:name[@type="personal"]'
116
+ expected_result = "<ns3:name type=\"personal\">\n <ns3:namePart type=\"family\">Berners-Lee</ns3:namePart>\n <ns3:namePart type=\"given\">Tim</ns3:namePart>\n <ns3:role>\n <ns3:roleTerm type=\"text\" authority=\"marcrelator\">creator</ns3:roleTerm>\n <ns3:roleTerm type=\"code\" authority=\"marcrelator\">cre</ns3:roleTerm>\n </ns3:role>\n <ns3:role type=\"code\" authority=\"marcrelator\"><ns3:roleTerm>creator</ns3:roleTerm></ns3:role></ns3:name>"
117
+
118
+ @sample.ng_xml.xpath('//oxns:name[@type="personal" and position()=1]/oxns:role', @sample.ox_namespaces).length.should == 1
119
+
120
+ @sample.property_values_append(
121
+ :parent_select =>'//oxns:name[@type="personal"]',
122
+ :child_index => 0,
123
+ :template => 'xml.role { xml.roleTerm( \'#{builder_new_value}\', :type=>\'code\', :authority=>\'marcrelator\') }',
124
+ :values => "founder"
125
+ )
126
+
127
+ @sample.ng_xml.xpath('//oxns:name[@type="personal" and position()=1]/oxns:role', @sample.ox_namespaces).length.should == 2
128
+ @sample.ng_xml.xpath('//oxns:name[@type="personal" and position()=1]/oxns:role[last()]/oxns:roleTerm', @sample.ox_namespaces).first.text.should == "founder"
129
+
130
+ # @sample.lookup(:person).first.to_xml.should == expected_result
131
+ end
132
+
133
+ it "should support more complex mixing & matching" do
134
+ expected_result = "<ns3:name type=\"personal\">\n <ns3:namePart type=\"family\">Jobs</ns3:namePart>\n <ns3:namePart type=\"given\">Steve</ns3:namePart>\n <ns3:namePart type=\"date\">2004</ns3:namePart>\n <ns3:role>\n <ns3:roleTerm type=\"text\" authority=\"marcrelator\">creator</ns3:roleTerm>\n <ns3:roleTerm type=\"code\" authority=\"marcrelator\">cre</ns3:roleTerm>\n </ns3:role>\n <ns3:role type=\"code\" authority=\"marcrelator\"><ns3:roleTerm>foo</ns3:roleTerm></ns3:role></ns3:name>"
135
+
136
+ @sample.ng_xml.xpath('//oxns:name[@type="personal" and position()=2]/oxns:role', @sample.ox_namespaces).length.should == 1
137
+
138
+ @sample.property_values_append(
139
+ :parent_select =>'//oxns:name[@type="personal"]',
140
+ :child_index => 1,
141
+ :template => [ :person, :role, {:attributes=>{"type"=>"code", "authority"=>"marcrelator"}} ],
142
+ :values => "foo"
143
+ )
144
+
145
+ @sample.ng_xml.xpath('//oxns:name[@type="personal" and position()=2]/oxns:role', @sample.ox_namespaces).length.should == 2
146
+ @sample.lookup(:person)[1].search("./oxns:role[last()]/oxns:roleTerm", @sample.ox_namespaces).first.text.should == "foo"
147
+ end
148
+
149
+ it "should raise exception if no node corresponds to the provided :parent_select and :child_index"
150
+
151
+ end
152
+
153
+ describe ".property_value_update" do
154
+
155
+ it "should accept an xpath as :parent_select" do
156
+ sample_xpath = '//oxns:name[@type="personal"]/oxns:role/oxns:roleTerm[@type="text"]'
157
+ @sample.property_value_update(
158
+ :parent_select =>sample_xpath,
159
+ :child_index => 1,
160
+ :value => "donor"
161
+ )
162
+ @sample.ng_xml.xpath(sample_xpath, @sample.ox_namespaces)[1].text.should == "donor"
163
+ end
164
+
165
+ it "if :select is provided, should update the first node provided by that xpath statement" do
166
+ sample_xpath = '//oxns:name[@type="personal" and position()=1]/oxns:namePart[@type="given"]'
167
+ @sample.property_value_update(
168
+ :select =>sample_xpath,
169
+ :value => "Timmeh"
170
+ )
171
+ @sample.ng_xml.xpath(sample_xpath, @sample.ox_namespaces).first.text.should == "Timmeh"
172
+ end
173
+
174
+ it "should replace the existing node if you pass a template and values" do
175
+ pending
176
+ @sample.property_value_update(
177
+ :parent_select =>'//oxns:name[@type="personal"]',
178
+ :child_index => 1,
179
+ :template => [ :person, :role, {:attributes=>{"type"=>"code", "authority"=>"marcrelator"}} ],
180
+ :value => "foo"
181
+ )
182
+ 1.should == 2
183
+ end
184
+ end
185
+
186
+ describe ".property_value_delete" do
187
+ it "should accept an xpath query as :select option" do
188
+ generic_xpath = '//oxns:name[@type="personal" and position()=4]/oxns:role'
189
+ specific_xpath = '//oxns:name[@type="personal" and position()=4]/oxns:role[oxns:roleTerm="visionary"]'
190
+ select_xpath = '//oxns:name[@type="personal" and position()=4]/oxns:role[last()]'
191
+
192
+ # Check that we're starting with 2 roles
193
+ # Check that the specific node we want to delete exists
194
+ @sample.lookup(generic_xpath).length.should == 2
195
+ @sample.lookup(specific_xpath).length.should == 1
196
+
197
+ @sample.property_value_delete(
198
+ :select =>select_xpath
199
+ )
200
+ # Check that we're finishing with 1 role
201
+ @sample.lookup(generic_xpath).length.should == 1
202
+ # Check that the specific node we want to delete no longer exists
203
+ @sample.lookup(specific_xpath).length.should == 0
204
+ end
205
+ it "should accept :parent_select, :parent_index and :child_index options instead of a :select" do
206
+
207
+ generic_xpath = '//oxns:name[@type="personal" and position()=4]/oxns:role/oxns:roleTerm'
208
+ specific_xpath = '//oxns:name[@type="personal" and position()=4]/oxns:role[oxns:roleTerm="visionary"]'
209
+
210
+ # Check that we're starting with 2 roles
211
+ # Check that the specific node we want to delete exists
212
+ @sample.lookup(generic_xpath).length.should == 4
213
+ @sample.lookup(specific_xpath).length.should == 1
214
+
215
+ # this is attempting to delete the last child (in this case roleTerm) from the 3rd role in the document.
216
+ @sample.property_value_delete(
217
+ :parent_select => [:person, :role],
218
+ :parent_index => 3,
219
+ :child_index => :last
220
+ )
221
+
222
+ # Check that we're finishing with 1 role
223
+ @sample.lookup(generic_xpath).length.should == 3
224
+ # Check that the specific node we want to delete no longer exists
225
+ @sample.lookup(specific_xpath).length.should == 1
226
+ end
227
+ it "should work if only :parent_select and :child_index are provided" do
228
+ generic_xpath = '//oxns:name[@type="personal"]/oxns:role'
229
+ # specific_xpath = '//oxns:name[@type="personal"]/oxns:role'
230
+
231
+ # Check that we're starting with 2 roles
232
+ # Check that the specific node we want to delete exists
233
+ @sample.lookup(generic_xpath).length.should == 4
234
+ # @sample.lookup(specific_xpath).length.should == 1
235
+
236
+ @sample.property_value_delete(
237
+ :parent_select => [:person, :role],
238
+ :child_index => 3
239
+ )
240
+ # Check that we're finishing with 1 role
241
+ @sample.lookup(generic_xpath).length.should == 3
242
+ end
243
+ end
244
+
245
+ end
@@ -0,0 +1,78 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require "nokogiri"
3
+ require "om"
4
+
5
+ describe "OM::XML::Validation" do
6
+
7
+ before(:all) do
8
+ class ValidationTest
9
+ include OM::XML::Container
10
+ include OM::XML::Validation
11
+ self.schema_url = "http://www.loc.gov/standards/mods/v3/mods-3-2.xsd"
12
+ end
13
+ end
14
+
15
+ before(:each) do
16
+ @sample = ValidationTest.from_xml("<foo><bar>1</bar></foo>")
17
+ end
18
+
19
+ ## Validation Support
20
+ # Some of these tests fail when you don't have an internet connection because the mods schema includes other xsd schemas by URL reference.
21
+
22
+ describe '#schema_url' do
23
+ it "should allow you to set the schema url" do
24
+ ValidationTest.schema_url.should == "http://www.loc.gov/standards/mods/v3/mods-3-2.xsd"
25
+ end
26
+ end
27
+
28
+ describe "#schema" do
29
+ it "should return an instance of Nokogiri::XML::Schema loaded from the schema url -- fails if no internet connection" do
30
+ ValidationTest.schema.should be_kind_of Nokogiri::XML::Schema
31
+ end
32
+ end
33
+
34
+ describe "#validate" do
35
+ it "should validate the provided document against the schema provided in class definition -- fails if no internet connection" do
36
+ ValidationTest.schema.expects(:validate).with(@sample).returns([])
37
+ ValidationTest.validate(@sample)
38
+ end
39
+ end
40
+
41
+ describe ".validate" do
42
+ it "should rely on class validate method" do
43
+ ValidationTest.expects(:validate).with(@sample)
44
+ @sample.validate
45
+ end
46
+ end
47
+
48
+ describe "#schema_file" do
49
+ before(:all) do
50
+ ValidationTest.schema_file = nil
51
+ end
52
+
53
+ after(:all) do
54
+ ValidationTest.schema_file = fixture("mods-3-2.xsd")
55
+ end
56
+
57
+ it "should lazy load the schema file from the @schema_url" do
58
+ ValidationTest.instance_variable_get(:@schema_file).should be_nil
59
+ ValidationTest.expects(:file_from_url).with(ValidationTest.schema_url).returns("fake file").once
60
+ ValidationTest.schema_file
61
+ ValidationTest.instance_variable_get(:@schema_file).should == "fake file"
62
+ ValidationTest.schema_file.should == "fake file"
63
+ end
64
+ end
65
+
66
+ describe "#file_from_url" do
67
+ it "should retrieve a file from the provided url over HTTP" do
68
+ ValidationTest.send(:file_from_url, "http://google.com")
69
+ end
70
+ it "should raise an error if the url is invalid" do
71
+ lambda {ValidationTest.send(:file_from_url, "")}.should raise_error(RuntimeError, "Could not retrieve file from . Error: No such file or directory - ")
72
+ lambda {ValidationTest.send(:file_from_url, "foo")}.should raise_error(RuntimeError, "Could not retrieve file from foo. Error: No such file or directory - foo")
73
+ end
74
+ it "should raise an error if file retrieval fails" do
75
+ lambda {ValidationTest.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")
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,21 @@
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 XMLTest
9
+ include OM::XML
10
+ end
11
+ end
12
+
13
+
14
+ it "should automatically include the other modules" do
15
+ XMLTest.included_modules.should include(OM::XML::Container)
16
+ XMLTest.included_modules.should include(OM::XML::Accessors)
17
+ XMLTest.included_modules.should include(OM::XML::Validation)
18
+ XMLTest.included_modules.should include(OM::XML::Properties)
19
+ XMLTest.included_modules.should include(OM::XML::PropertyValueOperators)
20
+ end
21
+ end
metadata ADDED
@@ -0,0 +1,174 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: om
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Matt Zumwalt
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-06-20 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: nokogiri
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: facets
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: rspec
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 13
58
+ segments:
59
+ - 1
60
+ - 2
61
+ - 9
62
+ version: 1.2.9
63
+ type: :development
64
+ version_requirements: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ name: mocha
67
+ prerelease: false
68
+ requirement: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: 43
74
+ segments:
75
+ - 0
76
+ - 9
77
+ - 8
78
+ version: 0.9.8
79
+ type: :development
80
+ version_requirements: *id004
81
+ - !ruby/object:Gem::Dependency
82
+ name: ruby-debug
83
+ prerelease: false
84
+ requirement: &id005 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ hash: 3
90
+ segments:
91
+ - 0
92
+ version: "0"
93
+ type: :development
94
+ version_requirements: *id005
95
+ description: "OM (Opinionated Metadata): A library to help you tame sprawling XML schemas like MODS. Wraps Nokogiri documents in objects with miscellaneous helper methods for doing things like retrieve generated xpath queries or look up properties based on a simplified DSL"
96
+ email: matt.zumwalt@yourmediashelf.com
97
+ executables: []
98
+
99
+ extensions: []
100
+
101
+ extra_rdoc_files:
102
+ - LICENSE
103
+ - README.rdoc
104
+ files:
105
+ - .document
106
+ - .gitignore
107
+ - History.textile
108
+ - LICENSE
109
+ - README.rdoc
110
+ - Rakefile
111
+ - VERSION
112
+ - lib/om.rb
113
+ - lib/om/xml.rb
114
+ - lib/om/xml/accessors.rb
115
+ - lib/om/xml/container.rb
116
+ - lib/om/xml/properties.rb
117
+ - lib/om/xml/property_value_operators.rb
118
+ - lib/om/xml/validation.rb
119
+ - om.gemspec
120
+ - spec/fixtures/CBF_MODS/ARS0025_016.xml
121
+ - spec/fixtures/RUBRIC_mods_article_template.xml
122
+ - spec/fixtures/mods-3-2.xsd
123
+ - spec/fixtures/mods_articles/hydrangea_article1.xml
124
+ - spec/fixtures/test_dummy_mods.xml
125
+ - spec/spec.opts
126
+ - spec/spec_helper.rb
127
+ - spec/unit/accessors_spec.rb
128
+ - spec/unit/container_spec.rb
129
+ - spec/unit/properties_spec.rb
130
+ - spec/unit/property_value_operators_spec.rb
131
+ - spec/unit/validation_spec.rb
132
+ - spec/unit/xml_spec.rb
133
+ has_rdoc: true
134
+ homepage: http://github.com/mediashelf/om
135
+ licenses: []
136
+
137
+ post_install_message:
138
+ rdoc_options:
139
+ - --charset=UTF-8
140
+ require_paths:
141
+ - lib
142
+ required_ruby_version: !ruby/object:Gem::Requirement
143
+ none: false
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ hash: 3
148
+ segments:
149
+ - 0
150
+ version: "0"
151
+ required_rubygems_version: !ruby/object:Gem::Requirement
152
+ none: false
153
+ requirements:
154
+ - - ">="
155
+ - !ruby/object:Gem::Version
156
+ hash: 3
157
+ segments:
158
+ - 0
159
+ version: "0"
160
+ requirements: []
161
+
162
+ rubyforge_project:
163
+ rubygems_version: 1.3.7
164
+ signing_key:
165
+ specification_version: 3
166
+ summary: "OM (Opinionated Metadata): A library to help you tame sprawling XML schemas like MODS."
167
+ test_files:
168
+ - spec/spec_helper.rb
169
+ - spec/unit/accessors_spec.rb
170
+ - spec/unit/container_spec.rb
171
+ - spec/unit/properties_spec.rb
172
+ - spec/unit/property_value_operators_spec.rb
173
+ - spec/unit/validation_spec.rb
174
+ - spec/unit/xml_spec.rb