om 1.0.2 → 1.1.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.
- data/History.textile +14 -0
- data/VERSION +1 -1
- data/lib/om/samples/mods_article.rb +6 -2
- data/lib/om/xml.rb +0 -9
- data/lib/om/xml/node_generator.rb +7 -0
- data/lib/om/xml/term.rb +3 -0
- data/lib/om/xml/term_value_operators.rb +8 -2
- data/lib/om/xml/term_xpath_generator.rb +58 -29
- data/om.gemspec +2 -14
- data/spec/fixtures/mods_articles/hydrangea_article1.xml +3 -0
- data/spec/unit/document_spec.rb +5 -1
- data/spec/unit/term_value_operators_spec.rb +13 -2
- data/spec/unit/term_xpath_generator_spec.rb +11 -1
- data/spec/unit/terminology_spec.rb +6 -1
- data/spec/unit/xml_spec.rb +0 -3
- metadata +3 -15
- data/lib/om/xml/accessors.rb +0 -217
- data/lib/om/xml/generator.rb +0 -26
- data/lib/om/xml/properties.rb +0 -396
- data/lib/om/xml/property_value_operators.rb +0 -160
- data/spec/unit/accessors_spec.rb +0 -216
- data/spec/unit/generator_spec.rb +0 -67
- data/spec/unit/properties_spec.rb +0 -315
- data/spec/unit/property_value_operators_spec.rb +0 -399
@@ -1,160 +0,0 @@
|
|
1
|
-
require "open-uri"
|
2
|
-
require "logger"
|
3
|
-
|
4
|
-
class OM::XML::ParentNodeNotFoundError < RuntimeError; end
|
5
|
-
module OM::XML::PropertyValueOperators
|
6
|
-
|
7
|
-
def property_values(*lookup_args)
|
8
|
-
result = []
|
9
|
-
retrieve(*lookup_args).each {|node| result << node.text }
|
10
|
-
return result
|
11
|
-
end
|
12
|
-
|
13
|
-
#
|
14
|
-
# example properties values hash: {[{":person"=>"0"}, "role", "text"]=>{"0"=>"role1", "1"=>"role2", "2"=>"role3"}, [{:person=>1}, :family_name]=>"Andronicus", [{"person"=>"1"},:given_name]=>["Titus"],[{:person=>1},:role,:text]=>["otherrole1","otherrole2"] }
|
15
|
-
def update_properties(params={})
|
16
|
-
# remove any fields from params that this datastream doesn't recognize
|
17
|
-
params.delete_if do |field_key,new_values|
|
18
|
-
if field_key.kind_of?(String)
|
19
|
-
true
|
20
|
-
else
|
21
|
-
self.class.accessor_xpath(*OM.destringify(field_key) ).nil?
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
result = params.dup
|
26
|
-
|
27
|
-
params.each_pair do |property_pointer,new_values|
|
28
|
-
pointer = OM.destringify(property_pointer)
|
29
|
-
template = OM.pointers_to_flat_array(pointer,false)
|
30
|
-
hn = self.class.accessor_hierarchical_name(*pointer)
|
31
|
-
|
32
|
-
case new_values
|
33
|
-
when Hash
|
34
|
-
when Array
|
35
|
-
nv = new_values.dup
|
36
|
-
new_values = {}
|
37
|
-
nv.each {|v| new_values[nv.index(v).to_s] = v}
|
38
|
-
else
|
39
|
-
new_values = {"0"=>new_values}
|
40
|
-
end
|
41
|
-
|
42
|
-
result.delete(property_pointer)
|
43
|
-
result[hn] = new_values.dup
|
44
|
-
|
45
|
-
current_values = property_values(*pointer)
|
46
|
-
new_values.delete_if do |y,z|
|
47
|
-
if current_values[y.to_i]==z and y.to_i > -1
|
48
|
-
true
|
49
|
-
else
|
50
|
-
false
|
51
|
-
end
|
52
|
-
end
|
53
|
-
xpath = self.class.accessor_xpath(*pointer)
|
54
|
-
parent_pointer = pointer.dup
|
55
|
-
parent_pointer.pop
|
56
|
-
parent_xpath = self.class.accessor_xpath(*parent_pointer)
|
57
|
-
new_values.each do |y,z|
|
58
|
-
if retrieve(*pointer)[y.to_i].nil? || y.to_i == -1
|
59
|
-
result[hn].delete(y)
|
60
|
-
property_values_append(:parent_select=>parent_xpath,:child_index=>0,:template=>template,:values=>z)
|
61
|
-
new_array_index = retrieve(*pointer).length - 1
|
62
|
-
result[hn][new_array_index.to_s] = z
|
63
|
-
else
|
64
|
-
property_value_update(xpath, y.to_i, z)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
# current_values.delete_if {|x| x == :delete || x == "" || x == nil}
|
68
|
-
# instance_eval("#{field_accessor_method}=(current_values)") #write it back to the ds
|
69
|
-
# result[field_name].delete("-1")
|
70
|
-
end
|
71
|
-
return result
|
72
|
-
end
|
73
|
-
|
74
|
-
def property_values_append(opts={})
|
75
|
-
parent_select = Array( opts[:parent_select] )
|
76
|
-
child_index = opts[:child_index]
|
77
|
-
template = opts[:template]
|
78
|
-
new_values = Array( opts[:values] )
|
79
|
-
|
80
|
-
# If template is a string, use it as the template, otherwise use it as arguments to builder_template
|
81
|
-
unless template.instance_of?(String)
|
82
|
-
template_args = Array(template)
|
83
|
-
if template_args.last.kind_of?(Hash)
|
84
|
-
template_opts = template_args.delete_at(template_args.length - 1)
|
85
|
-
else
|
86
|
-
template_opts = {}
|
87
|
-
end
|
88
|
-
template = self.class.builder_template( template_args, template_opts )
|
89
|
-
end
|
90
|
-
|
91
|
-
parent_nodeset = lookup(parent_select[0], parent_select[1])
|
92
|
-
parent_node = node_from_set(parent_nodeset, child_index)
|
93
|
-
|
94
|
-
if parent_node.nil?
|
95
|
-
raise OM::XML::ParentNodeNotFoundError, "Failed to find a parent node to insert values into based on :parent_select #{parent_select.inspect} with :child_index #{child_index.inspect}"
|
96
|
-
end
|
97
|
-
|
98
|
-
builder = Nokogiri::XML::Builder.with(parent_node) do |xml|
|
99
|
-
new_values.each do |builder_new_value|
|
100
|
-
builder_arg = eval('"'+ template + '"') # this inserts builder_new_value into the builder template
|
101
|
-
eval(builder_arg)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
# Nokogiri::XML::Node.new(builder.to_xml, foo)
|
106
|
-
|
107
|
-
return parent_node
|
108
|
-
|
109
|
-
end
|
110
|
-
|
111
|
-
def property_value_update(node_select,child_index,new_value,opts={})
|
112
|
-
# template = opts.fetch(:template,nil)
|
113
|
-
node = lookup(node_select, nil)[child_index]
|
114
|
-
node.content = new_value
|
115
|
-
end
|
116
|
-
|
117
|
-
# def property_value_set(property_ref, query_opts, node_index, new_value)
|
118
|
-
# end
|
119
|
-
|
120
|
-
def property_value_delete(opts={})
|
121
|
-
parent_select = Array( opts[:parent_select] )
|
122
|
-
parent_index = opts[:parent_index]
|
123
|
-
child_index = opts[:child_index]
|
124
|
-
xpath_select = opts[:select]
|
125
|
-
|
126
|
-
if !xpath_select.nil?
|
127
|
-
node = lookup(xpath_select, nil).first
|
128
|
-
else
|
129
|
-
parent_nodeset = lookup(parent_select, parent_select)
|
130
|
-
# parent_nodeset = lookup(parent_select[0])
|
131
|
-
|
132
|
-
if parent_index.nil?
|
133
|
-
node = node_from_set(parent_nodeset, child_index)
|
134
|
-
else
|
135
|
-
parent = node_from_set(parent_nodeset, parent_index)
|
136
|
-
# this next line is a hack around the fact that element_children() sometimes doesn't work.
|
137
|
-
node = node_from_set(parent.xpath("*"), child_index)
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
node.remove
|
142
|
-
end
|
143
|
-
|
144
|
-
|
145
|
-
# Allows you to provide an array index _or_ a symbol representing the function to call on the nodeset in order to retrieve the node.
|
146
|
-
def node_from_set(nodeset, index)
|
147
|
-
if index.kind_of?(Integer)
|
148
|
-
node = nodeset[index]
|
149
|
-
elsif index.kind_of?(Symbol) && nodeset.respond_to?(index)
|
150
|
-
node = nodeset.send(index)
|
151
|
-
else
|
152
|
-
raise "Could not retrieve node using index #{index}."
|
153
|
-
end
|
154
|
-
|
155
|
-
return node
|
156
|
-
end
|
157
|
-
|
158
|
-
private :node_from_set
|
159
|
-
|
160
|
-
end
|
data/spec/unit/accessors_spec.rb
DELETED
@@ -1,216 +0,0 @@
|
|
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
|
-
@sample.stubs(:ox_namespaces).returns("oxns"=>"http://www.loc.gov/mods/v3")
|
64
|
-
end
|
65
|
-
|
66
|
-
describe '#accessor' do
|
67
|
-
it "should populate the .accessors hash" do
|
68
|
-
AccessorTest.accessors[:abstract][:relative_xpath].should == "oxns:abstract"
|
69
|
-
AccessorTest.accessors[:journal][:relative_xpath].should == 'oxns:relatedItem[@type="host"]'
|
70
|
-
AccessorTest.accessors[:journal][:children][:issue][:relative_xpath].should == "oxns:part"
|
71
|
-
AccessorTest.accessors[:journal][:children][:issue][:children][:end_page][:relative_xpath].should == 'oxns:extent[@unit="pages"]/oxns:end'
|
72
|
-
|
73
|
-
AccessorTest.accessors[:person][:children][:role][:children][:text][:relative_xpath].should == 'oxns:roleTerm[@type="text"]'
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
describe ".retrieve" do
|
78
|
-
it "should use Nokogiri to retrieve a NodeSet corresponding to the combination of accessor keys and array/nodeset indexes" do
|
79
|
-
@sample.retrieve( :person ).length.should == 2
|
80
|
-
|
81
|
-
@sample.retrieve( {:person=>1} ).first.should == @sample.ng_xml.xpath('//oxns:name[@type="personal"][2]', "oxns"=>"http://www.loc.gov/mods/v3").first
|
82
|
-
@sample.retrieve( {:person=>1}, :first_name ).class.should == Nokogiri::XML::NodeSet
|
83
|
-
@sample.retrieve( {:person=>1}, :first_name ).first.text.should == "Siddartha"
|
84
|
-
end
|
85
|
-
|
86
|
-
it "should support accessors whose relative_xpath is a lookup array instead of an xpath string" do
|
87
|
-
# pending "this only impacts scenarios where we want to display & edit"
|
88
|
-
AccessorTest.accessors[:title_info][:children][:language][:relative_xpath].should == {:attribute=>"lang"}
|
89
|
-
# @sample.retrieve( :title, 1 ).first.text.should == "Artikkelin otsikko Hydrangea artiklan 1"
|
90
|
-
@sample.retrieve( {:title_info=>1}, :language ).first.text.should == "finnish"
|
91
|
-
end
|
92
|
-
|
93
|
-
it "should support xpath queries as the pointer" do
|
94
|
-
@sample.retrieve('//oxns:name[@type="personal"][1]/oxns:namePart[1]').first.text.should == "FAMILY NAME"
|
95
|
-
end
|
96
|
-
|
97
|
-
it "should return nil if the xpath fails to generate" do
|
98
|
-
@sample.retrieve( {:foo=>20}, :bar ).should == nil
|
99
|
-
end
|
100
|
-
|
101
|
-
end
|
102
|
-
|
103
|
-
describe "generated accessor methods" do
|
104
|
-
it "should mix accessor methods into nodesets so you can use regular array syntax to access stuff" do
|
105
|
-
pending "This is tempting, but somewhat difficult to implement and potentially slow at runtime. Might never be worth it?"
|
106
|
-
@sample.persons.length.should == 2
|
107
|
-
@sample.persons[1].first_name.text.should == "Siddartha"
|
108
|
-
@sample.persons.last.roles.length.should == 1
|
109
|
-
@sample.persons.last.roles[0].text.should == "teacher"
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
describe "#accessor_info" do
|
114
|
-
it "should return the xpath given in the call to #accessor" do
|
115
|
-
AccessorTest.accessor_info( :abstract ).should == AccessorTest.accessors[:abstract]
|
116
|
-
end
|
117
|
-
it "should return the xpath given in the call to #accessor" do
|
118
|
-
AccessorTest.accessor_info( :abstract ).should == AccessorTest.accessors[:abstract]
|
119
|
-
end
|
120
|
-
it "should dig into the accessors hash as far as you want, ignoring index values" do
|
121
|
-
AccessorTest.accessor_info( *[{:conference=>0}, {:role=>1}, :text] ).should == AccessorTest.accessors[:conference][:children][:role][:children][:text]
|
122
|
-
AccessorTest.accessor_info( {:conference=>0}, {:role=>1}, :text ).should == AccessorTest.accessors[:conference][:children][:role][:children][:text]
|
123
|
-
|
124
|
-
AccessorTest.accessor_info( :conference, :role, :text ).should == AccessorTest.accessors[:conference][:children][:role][:children][:text]
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
describe "#accessor_xpath" do
|
129
|
-
it "should return the xpath given in the call to #accessor" do
|
130
|
-
AccessorTest.accessor_xpath( :abstract ).should == '//oxns:abstract'
|
131
|
-
end
|
132
|
-
# Note: Ruby array indexes begin from 0. In xpath queries (which start from 1 instead of 0), this will be translated accordingly.
|
133
|
-
it "should prepend the xpath for any parent nodes, inserting calls to xpath array lookup where necessary" do
|
134
|
-
AccessorTest.accessor_xpath( {:conference=>0}, {:role=>1}, :text ).should == '//oxns:name[@type="conference"][1]/oxns:role[2]/oxns:roleTerm[@type="text"]'
|
135
|
-
end
|
136
|
-
it "should support xpath queries as argument" do
|
137
|
-
AccessorTest.accessor_xpath('//oxns:name[@type="personal"][1]/oxns:namePart').should == '//oxns:name[@type="personal"][1]/oxns:namePart'
|
138
|
-
end
|
139
|
-
it "should return nil if no accessor_info is available" do
|
140
|
-
AccessorTest.accessor_xpath( :sample_undeclared_accessor ).should == nil
|
141
|
-
end
|
142
|
-
it "should be idempotent" do
|
143
|
-
AccessorTest.accessor_xpath( *[{:title_info=>2}, :main_title] ).should == "//oxns:titleInfo[3]/oxns:title"
|
144
|
-
AccessorTest.accessor_xpath( *[{:title_info=>2}, :main_title] ).should == "//oxns:titleInfo[3]/oxns:title"
|
145
|
-
AccessorTest.accessor_xpath( *[{:title_info=>2}, :main_title] ).should == "//oxns:titleInfo[3]/oxns:title"
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
describe "#accessor_constrained_xpath" do
|
150
|
-
it 'should append contains("#{constraint_value}") to query' do
|
151
|
-
# @sample.class.accessor_constrained_xpath_template([:journal, :issn]).should == '//oxns:relatedItem[@type="host"]/oxns:identifier[@type="issn" and contains("#{constraint_value}")]'
|
152
|
-
@sample.class.accessor_constrained_xpath([:journal, :issn], "123-456-ABC").should == '//oxns:relatedItem[@type="host"]/oxns:identifier[@type="issn" and contains(., "123-456-ABC")]'
|
153
|
-
@sample.class.accessor_constrained_xpath([:journal, :title], "My Journal Title").should == '//oxns:relatedItem[@type="host"]/oxns:titleInfo/oxns:title[contains(., "My Journal Title")]'
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
describe "#accessor_generic_name" do
|
158
|
-
it "should generate a generic accessor name based on an array of pointers" do
|
159
|
-
AccessorTest.accessor_generic_name( {:conference=>0}, {:role=>1}, :text ).should == "conference_role_text"
|
160
|
-
AccessorTest.accessor_generic_name( *[{:conference=>0}, {:role=>1}, :text] ).should == "conference_role_text"
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
describe "#accessor_hierarchical_name" do
|
165
|
-
it "should generate a specific accessor name based on an array of pointers and indexes" do
|
166
|
-
AccessorTest.accessor_hierarchical_name( {:conference=>0}, {:role=>1}, :text ).should == "conference_0_role_1_text"
|
167
|
-
AccessorTest.accessor_hierarchical_name( *[{:conference=>0}, {:role=>1}, :text] ).should == "conference_0_role_1_text"
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
describe '#generate_accessors_from_properties' do
|
172
|
-
before(:each) do
|
173
|
-
class AccessorTest2
|
174
|
-
include OM::XML::Accessors
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
it "should generate accessors from the properties hash" do
|
179
|
-
sample_properties_hash = {:abstract=>{:xpath_relative=>"oxns:abstract", :path=>"abstract", :xpath_constrained=>"//oxns:abstract[contains(\\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:abstract", :ref=>:abstract, :convenience_methods=>{}}, :topic_tag=>{:xpath_relative=>"oxns:subject", :path=>"subject", :xpath_constrained=>"//oxns:subject[contains(oxns:topic, \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:subject", :ref=>:topic_tag, :default_content_path=>"topic", :convenience_methods=>{}}, :title_info=>{:xpath_relative=>"oxns:titleInfo", :path=>"titleInfo", :xpath_constrained=>"//oxns:titleInfo[contains(\\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:titleInfo", :ref=>:title_info, :convenience_methods=>{:main_title=>{:xpath_relative=>"oxns:title", :path=>"title", :xpath_constrained=>"//oxns:titleInfo[contains(oxns:title, \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:titleInfo/oxns:title"}, :language=>{:xpath_relative=>"@lang", :path=>{:attribute=>"lang"}, :xpath_constrained=>"//oxns:titleInfo[contains(@lang, \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:titleInfo/@lang"}}}, :person=>{:xpath_relative=>"oxns:name[@type=\"personal\"]", :path=>"name", :xpath_constrained=>"//oxns:name[@type=\\\"personal\\\" and contains(oxns:namePart, \\\"\#{constraint_value}\\\")]", :attributes=>{:type=>"personal"}, :xpath=>"//oxns:name[@type=\"personal\"]", :ref=>:person, :default_content_path=>"namePart", :subelements=>["namePart", "displayForm", "affiliation", :role, "description"], :convenience_methods=>{:first_name=>{:xpath_relative=>"oxns:namePart[@type=\"given\"]", :path=>"namePart", :attributes=>{:type=>"given"}, :xpath_constrained=>"//oxns:name[@type=\\\"personal\\\" and contains(oxns:namePart[@type=\\\"given\\\"], \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:name[@type=\"personal\"]/oxns:namePart[@type=\"given\"]"}, :affiliation=>{:xpath_relative=>"oxns:affiliation", :path=>"affiliation", :xpath_constrained=>"//oxns:name[@type=\\\"personal\\\" and contains(oxns:affiliation, \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:name[@type=\"personal\"]/oxns:affiliation"}, :terms_of_address=>{:xpath_relative=>"oxns:namePart[@type=\"termsOfAddress\"]", :path=>"namePart", :attributes=>{:type=>"termsOfAddress"}, :xpath_constrained=>"//oxns:name[@type=\\\"personal\\\" and contains(oxns:namePart[@type=\\\"termsOfAddress\\\"], \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:name[@type=\"personal\"]/oxns:namePart[@type=\"termsOfAddress\"]"}, :namePart=>{:xpath_relative=>"oxns:namePart", :path=>"namePart", :xpath_constrained=>"//oxns:name[@type=\\\"personal\\\" and contains(oxns:namePart, \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:name[@type=\"personal\"]/oxns:namePart"}, :displayForm=>{:xpath_relative=>"oxns:displayForm", :path=>"displayForm", :xpath_constrained=>"//oxns:name[@type=\\\"personal\\\" and contains(oxns:displayForm, \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:name[@type=\"personal\"]/oxns:displayForm"}, :role=>{:xpath_relative=>"oxns:role", :path=>"role", :xpath_constrained=>"//oxns:name[@type=\\\"personal\\\" and contains(oxns:role, \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:name[@type=\"personal\"]/oxns:role", :ref=>:role, :convenience_methods=>{:text=>{:xpath_relative=>"oxns:roleTerm[@type=\"text\"]", :path=>"roleTerm", :attributes=>{:type=>"text"}, :xpath_constrained=>"//oxns:role[contains(oxns:roleTerm[@type=\\\"text\\\"], \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:role/oxns:roleTerm[@type=\"text\"]"}, :code=>{:xpath_relative=>"oxns:roleTerm[@type=\"code\"]", :path=>"roleTerm", :attributes=>{:type=>"code"}, :xpath_constrained=>"//oxns:role[contains(oxns:roleTerm[@type=\\\"code\\\"], \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:role/oxns:roleTerm[@type=\"code\"]"}}, :parents=>[:name_]}, :date=>{:xpath_relative=>"oxns:namePart[@type=\"date\"]", :path=>"namePart", :attributes=>{:type=>"date"}, :xpath_constrained=>"//oxns:name[@type=\\\"personal\\\" and contains(oxns:namePart[@type=\\\"date\\\"], \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:name[@type=\"personal\"]/oxns:namePart[@type=\"date\"]"}, :family_name=>{:xpath_relative=>"oxns:namePart[@type=\"family\"]", :path=>"namePart", :attributes=>{:type=>"family"}, :xpath_constrained=>"//oxns:name[@type=\\\"personal\\\" and contains(oxns:namePart[@type=\\\"family\\\"], \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:name[@type=\"personal\"]/oxns:namePart[@type=\"family\"]"}, :description=>{:xpath_relative=>"oxns:description", :path=>"description", :xpath_constrained=>"//oxns:name[@type=\\\"personal\\\" and contains(oxns:description, \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:name[@type=\"personal\"]/oxns:description"}}, :variant_of=>:name_}, :name_=>{:xpath_relative=>"oxns:name", :path=>"name", :xpath_constrained=>"//oxns:name[contains(oxns:namePart, \\\"\#{constraint_value}\\\")]", :attributes=>[:xlink, :lang, "xml:lang", :script, :transliteration, {:type=>["personal", "enumerated", "corporate"]}], :xpath=>"//oxns:name", :ref=>:name_, :default_content_path=>"namePart", :subelements=>["namePart", "displayForm", "affiliation", :role, "description"], :convenience_methods=>{:affiliation=>{:xpath_relative=>"oxns:affiliation", :path=>"affiliation", :xpath_constrained=>"//oxns:name[contains(oxns:affiliation, \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:name/oxns:affiliation"}, :first_name=>{:xpath_relative=>"oxns:namePart[@type=\"given\"]", :path=>"namePart", :xpath_constrained=>"//oxns:name[contains(oxns:namePart[@type=\\\"given\\\"], \\\"\#{constraint_value}\\\")]", :attributes=>{:type=>"given"}, :xpath=>"//oxns:name/oxns:namePart[@type=\"given\"]"}, :terms_of_address=>{:xpath_relative=>"oxns:namePart[@type=\"termsOfAddress\"]", :path=>"namePart", :xpath_constrained=>"//oxns:name[contains(oxns:namePart[@type=\\\"termsOfAddress\\\"], \\\"\#{constraint_value}\\\")]", :attributes=>{:type=>"termsOfAddress"}, :xpath=>"//oxns:name/oxns:namePart[@type=\"termsOfAddress\"]"}, :displayForm=>{:xpath_relative=>"oxns:displayForm", :path=>"displayForm", :xpath_constrained=>"//oxns:name[contains(oxns:displayForm, \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:name/oxns:displayForm"}, :namePart=>{:xpath_relative=>"oxns:namePart", :path=>"namePart", :xpath_constrained=>"//oxns:name[contains(oxns:namePart, \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:name/oxns:namePart"}, :role=>{:xpath_relative=>"oxns:role", :path=>"role", :xpath_constrained=>"//oxns:name[contains(oxns:role, \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:name/oxns:role", :ref=>:role, :convenience_methods=>{:text=>{:xpath_relative=>"oxns:roleTerm[@type=\"text\"]", :path=>"roleTerm", :attributes=>{:type=>"text"}, :xpath_constrained=>"//oxns:role[contains(oxns:roleTerm[@type=\\\"text\\\"], \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:role/oxns:roleTerm[@type=\"text\"]"}, :code=>{:xpath_relative=>"oxns:roleTerm[@type=\"code\"]", :path=>"roleTerm", :attributes=>{:type=>"code"}, :xpath_constrained=>"//oxns:role[contains(oxns:roleTerm[@type=\\\"code\\\"], \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:role/oxns:roleTerm[@type=\"code\"]"}}, :parents=>[:name_]}, :description=>{:xpath_relative=>"oxns:description", :path=>"description", :xpath_constrained=>"//oxns:name[contains(oxns:description, \\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:name/oxns:description"}, :family_name=>{:xpath_relative=>"oxns:namePart[@type=\"family\"]", :path=>"namePart", :xpath_constrained=>"//oxns:name[contains(oxns:namePart[@type=\\\"family\\\"], \\\"\#{constraint_value}\\\")]", :attributes=>{:type=>"family"}, :xpath=>"//oxns:name/oxns:namePart[@type=\"family\"]"}, :date=>{:xpath_relative=>"oxns:namePart[@type=\"date\"]", :path=>"namePart", :xpath_constrained=>"//oxns:name[contains(oxns:namePart[@type=\\\"date\\\"], \\\"\#{constraint_value}\\\")]", :attributes=>{:type=>"date"}, :xpath=>"//oxns:name/oxns:namePart[@type=\"date\"]"}}}, :role=>{:xpath_relative=>"oxns:role", :path=>"role", :xpath_constrained=>"//oxns:role[contains(\\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:role", :ref=>:role, :convenience_methods=>{:text=>{:xpath_relative=>"oxns:roleTerm[@type=\"text\"]", :path=>"roleTerm", :xpath_constrained=>"//oxns:role[contains(oxns:roleTerm[@type=\\\"text\\\"], \\\"\#{constraint_value}\\\")]", :attributes=>{:type=>"text"}, :xpath=>"//oxns:role/oxns:roleTerm[@type=\"text\"]"}, :code=>{:xpath_relative=>"oxns:roleTerm[@type=\"code\"]", :path=>"roleTerm", :xpath_constrained=>"//oxns:role[contains(oxns:roleTerm[@type=\\\"code\\\"], \\\"\#{constraint_value}\\\")]", :attributes=>{:type=>"code"}, :xpath=>"//oxns:role/oxns:roleTerm[@type=\"code\"]"}}, :parents=>[:name_]}, :unresolved=>{}, :mods=>{:xpath_relative=>"oxns:mods", :schema=>"http://www.loc.gov/standards/mods/v3/mods-3-2.xsd", :path=>"mods", :xpath_constrained=>"//oxns:mods[contains(\\\"\#{constraint_value}\\\")]", :attributes=>["id", "version"], :xpath=>"//oxns:mods", :ref=>:mods, :convenience_methods=>{}}}
|
180
|
-
AccessorTest2.stubs(:properties).returns(sample_properties_hash)
|
181
|
-
AccessorTest2.accessors.should be_nil
|
182
|
-
AccessorTest2.generate_accessors_from_properties.should_not be_nil
|
183
|
-
[:mods, :name_, :person, [:person,:first_name],[:person, :role], [:person, :role, :text] ].each do |pointer|
|
184
|
-
puts pointer
|
185
|
-
ai = AccessorTest2.accessor_info(*pointer)
|
186
|
-
ai.should_not be_nil
|
187
|
-
ai[:relative_xpath].should_not be_nil
|
188
|
-
end
|
189
|
-
AccessorTest2.accessor_info(*[:title_info, :language])[:relative_xpath].should == "@lang"
|
190
|
-
end
|
191
|
-
|
192
|
-
end
|
193
|
-
|
194
|
-
# describe ".accessor_xpath (instance method)" do
|
195
|
-
# it "should delegate to the class method" do
|
196
|
-
# AccessorTest.expects(:accessor_xpath).with( [:conference, conference_index, :text_role] )
|
197
|
-
# @sample.accessor_xpath( [:conference, conference_index, :role] )
|
198
|
-
# end
|
199
|
-
# end
|
200
|
-
#
|
201
|
-
# describe "generated catchall xpaths" do
|
202
|
-
# it "should return an xpath query that will catch all nodes corresponding to the specified accessor" do
|
203
|
-
# AccessorTest.journal_issue_end_page_xpath.should == 'oxns:relatedItem[@type="host"]/oxns:part/oxns:extent[@unit="pages"]/oxns:end'
|
204
|
-
# end
|
205
|
-
# it "should rely on #catchall_xpath" do
|
206
|
-
# AccessorTest.expects(:catchall_xpath).with(:journal, :issue, :end_page)
|
207
|
-
# AccessorTest.journal_issue_end_page_xpath
|
208
|
-
# end
|
209
|
-
# end
|
210
|
-
#
|
211
|
-
# describe ".catchall_xpath" do
|
212
|
-
# it "should return an xpath query that will catch all nodes corresponding to the specified accessor" do
|
213
|
-
# AccessorTest.catchall_xpath(:journal, :issue, :end_page).should == 'oxns:relatedItem[@type="host"]/oxns:part/oxns:extent[@unit="pages"]/oxns:end'
|
214
|
-
# end
|
215
|
-
# end
|
216
|
-
end
|
data/spec/unit/generator_spec.rb
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
-
require "om"
|
3
|
-
|
4
|
-
describe "OM::XML::Generator" do
|
5
|
-
|
6
|
-
before(:all) do
|
7
|
-
#ModsHelpers.name_("Beethoven, Ludwig van", :date=>"1770-1827", :role=>"creator")
|
8
|
-
class GeneratorTest
|
9
|
-
|
10
|
-
include OM::XML::Container
|
11
|
-
include OM::XML::Properties
|
12
|
-
include OM::XML::Generator
|
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
|
-
property :person, :variant_of=>:name_, :attributes=>{:type=>"personal"}
|
34
|
-
property :role, :path=>"role",
|
35
|
-
:parents=>[:name_],
|
36
|
-
:attributes=>[ { "type"=>["text", "code"] } , "authority"],
|
37
|
-
:default_content_path => "roleTerm"
|
38
|
-
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
before(:each) do
|
44
|
-
@sample = GeneratorTest.from_xml( fixture( File.join("test_dummy_mods.xml") ) )
|
45
|
-
end
|
46
|
-
|
47
|
-
after(:all) do
|
48
|
-
Object.send(:remove_const, :GeneratorTest)
|
49
|
-
end
|
50
|
-
|
51
|
-
describe '#generate' do
|
52
|
-
it "should use the corresponding builder template(s) to generate the node" do
|
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 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
|
-
|
61
|
-
end
|
62
|
-
it "should return Nokogiri Documents" do
|
63
|
-
GeneratorTest.generate(:mods, "foo").class.should == Nokogiri::XML::Document
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
end
|
@@ -1,315 +0,0 @@
|
|
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
|
-
|
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
|
-
property :title_info, :path=>"titleInfo",
|
23
|
-
:convenience_methods => {
|
24
|
-
:main_title => {:path=>"title"},
|
25
|
-
:language => {:path=>{:attribute=>"lang"}},
|
26
|
-
}
|
27
|
-
|
28
|
-
property :name_, :path=>"name",
|
29
|
-
:attributes=>[:xlink, :lang, "xml:lang", :script, :transliteration, {:type=>["personal", "enumerated", "corporate"]} ],
|
30
|
-
:subelements=>["namePart", "displayForm", "affiliation", :role, "description"],
|
31
|
-
:default_content_path => "namePart",
|
32
|
-
:convenience_methods => {
|
33
|
-
:date => {:path=>"namePart", :attributes=>{:type=>"date"}},
|
34
|
-
:family_name => {:path=>"namePart", :attributes=>{:type=>"family"}},
|
35
|
-
:given_name => {:path=>"namePart", :attributes=>{:type=>"given"}},
|
36
|
-
:terms_of_address => {:path=>"namePart", :attributes=>{:type=>"termsOfAddress"}}
|
37
|
-
}
|
38
|
-
|
39
|
-
property :person, :variant_of=>:name_, :attributes=>{:type=>"personal"}
|
40
|
-
|
41
|
-
property :role, :path=>"role",
|
42
|
-
:parents=>[:name_],
|
43
|
-
:attributes=>[ { "type"=>["text", "code"] } , "authority"],
|
44
|
-
:default_content_path => "roleTerm"
|
45
|
-
|
46
|
-
property :journal, :path=>'relatedItem', :attributes=>{:type=>"host"},
|
47
|
-
:subelements=>[:title_info, :origin_info, :issue],
|
48
|
-
:convenience_methods => {
|
49
|
-
:issn => {:path=>"identifier", :attributes=>{:type=>"issn"}},
|
50
|
-
}
|
51
|
-
|
52
|
-
property :issue, :path=>'part',
|
53
|
-
:subelements=>[:start_page, :end_page, :volume],
|
54
|
-
:convenience_methods => {
|
55
|
-
# :volume => {:path=>"detail", :attributes=>{:type=>"volume"}},
|
56
|
-
:level => {:path=>"detail", :attributes=>{:type=>"number"}, :default_content_path=>"number"},
|
57
|
-
# Hack to support provisional spot for start & end page (nesting was too deep for this version of OM)
|
58
|
-
:citation_start_page => {:path=>"pages", :attributes=>{:type=>"start"}},
|
59
|
-
:citation_end_page => {:path=>"pages", :attributes=>{:type=>"end"}},
|
60
|
-
:foo => {:path=>"foo", :attributes=>{:type=>"ness"}},
|
61
|
-
:publication_date => {:path=>"date"}
|
62
|
-
}
|
63
|
-
|
64
|
-
property :volume, :path=>"detail", :attributes=>{:type=>"volume"}, :subelements=>"number"
|
65
|
-
|
66
|
-
property :start_page, :path=>"extent", :attributes=>{:unit=>"pages"}, :default_content_path => "start"
|
67
|
-
property :end_page, :path=>"extent", :attributes=>{:unit=>"pages"}, :default_content_path => "end"
|
68
|
-
end
|
69
|
-
|
70
|
-
class FakeOtherOx < Nokogiri::XML::Document
|
71
|
-
|
72
|
-
include OM::XML::Properties
|
73
|
-
# extend OX::ClassMethods
|
74
|
-
|
75
|
-
root_property :other, "other", "http://www.foo.com"
|
76
|
-
|
77
|
-
end
|
78
|
-
|
79
|
-
end
|
80
|
-
|
81
|
-
before(:each) do
|
82
|
-
@fixturemods = FakeOxMods.from_xml( fixture( File.join("CBF_MODS", "ARS0025_016.xml") ) )
|
83
|
-
end
|
84
|
-
|
85
|
-
after(:all) do
|
86
|
-
Object.send(:remove_const, :FakeOxMods)
|
87
|
-
end
|
88
|
-
|
89
|
-
describe "#new" do
|
90
|
-
it "should set up namespaces" do
|
91
|
-
@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"}
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
describe "#root_property" do
|
96
|
-
it "should initialize root_property class attributes without attributes bleeding over to other OX classes" do
|
97
|
-
FakeOxMods.root_property_ref.should == :mods
|
98
|
-
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"}
|
99
|
-
FakeOxMods.ox_namespaces.should == {"oxns"=>"http://www.loc.gov/mods/v3"}
|
100
|
-
|
101
|
-
FakeOtherOx.root_property_ref.should == :other
|
102
|
-
FakeOtherOx.root_config.should == {:namespace=>"http://www.foo.com", :path=>"other", :ref=>:other}
|
103
|
-
end
|
104
|
-
it "should add a corresponding entry into the properties hash" do
|
105
|
-
FakeOxMods.property_info_for(FakeOxMods.root_property_ref).should == {:schema=>"http://www.loc.gov/standards/mods/v3/mods-3-2.xsd", :xpath_relative=>"oxns:mods", :path=>"mods", :xpath_constrained=>"//oxns:mods[contains(\\\"\#{constraint_value}\\\")]", :xpath=>"//oxns:mods", :ref=>:mods, :convenience_methods=>{}, :attributes=>["id", "version"]}
|
106
|
-
FakeOxMods.builder_template(FakeOxMods.root_property_ref).should == "xml.mods( '\#{builder_new_value}' )"
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
describe "#property" do
|
111
|
-
|
112
|
-
it "fails gracefully if you try to look up nodes for an undefined property" do
|
113
|
-
@fixturemods.lookup(:nobody_home).should == []
|
114
|
-
end
|
115
|
-
|
116
|
-
it "constructs xpath queries for finding properties" do
|
117
|
-
FakeOxMods.properties[:name_][:xpath].should == '//oxns:name'
|
118
|
-
FakeOxMods.properties[:name_][:xpath_relative].should == 'oxns:name'
|
119
|
-
|
120
|
-
FakeOxMods.properties[:person][:xpath].should == '//oxns:name[@type="personal"]'
|
121
|
-
FakeOxMods.properties[:person][:xpath_relative].should == 'oxns:name[@type="personal"]'
|
122
|
-
end
|
123
|
-
|
124
|
-
it "constructs templates for value-driven searches" do
|
125
|
-
FakeOxMods.properties[:name_][:xpath_constrained].should == '//oxns:name[contains(oxns:namePart, "#{constraint_value}")]'.gsub('"', '\"')
|
126
|
-
FakeOxMods.properties[:person][:xpath_constrained].should == '//oxns:name[@type="personal" and contains(oxns:namePart, "#{constraint_value}")]'.gsub('"', '\"')
|
127
|
-
|
128
|
-
# Example of how you could use these templates:
|
129
|
-
constraint_value = "SAMPLE CONSTRAINT VALUE"
|
130
|
-
constrained_query = eval( '"' + FakeOxMods.properties[:person][:xpath_constrained] + '"' )
|
131
|
-
constrained_query.should == '//oxns:name[@type="personal" and contains(oxns:namePart, "SAMPLE CONSTRAINT VALUE")]'
|
132
|
-
end
|
133
|
-
|
134
|
-
it "constructs xpath queries & templates for convenience methods" do
|
135
|
-
FakeOxMods.properties[:name_][:convenience_methods][:date][:xpath].should == '//oxns:name/oxns:namePart[@type="date"]'
|
136
|
-
FakeOxMods.properties[:name_][:convenience_methods][:date][:xpath_relative].should == 'oxns:namePart[@type="date"]'
|
137
|
-
FakeOxMods.properties[:name_][:convenience_methods][:date][:xpath_constrained].should == '//oxns:name[contains(oxns:namePart[@type="date"], "#{constraint_value}")]'.gsub('"', '\"')
|
138
|
-
|
139
|
-
FakeOxMods.properties[:person][:convenience_methods][:date][:xpath].should == '//oxns:name[@type="personal"]/oxns:namePart[@type="date"]'
|
140
|
-
FakeOxMods.properties[:person][:convenience_methods][:date][:xpath_relative].should == 'oxns:namePart[@type="date"]'
|
141
|
-
FakeOxMods.properties[:person][:convenience_methods][:date][:xpath_constrained].should == '//oxns:name[@type="personal" and contains(oxns:namePart[@type="date"], "#{constraint_value}")]'.gsub('"', '\"')
|
142
|
-
|
143
|
-
end
|
144
|
-
|
145
|
-
it "constructs xpath queries & templates for subelements too" do
|
146
|
-
FakeOxMods.properties[:person][:convenience_methods][:displayForm][:xpath].should == '//oxns:name[@type="personal"]/oxns:displayForm'
|
147
|
-
FakeOxMods.properties[:person][:convenience_methods][:displayForm][:xpath_relative].should == 'oxns:displayForm'
|
148
|
-
FakeOxMods.properties[:person][:convenience_methods][:displayForm][:xpath_constrained].should == '//oxns:name[@type="personal" and contains(oxns:displayForm, "#{constraint_value}")]'.gsub('"', '\"')
|
149
|
-
end
|
150
|
-
|
151
|
-
it "supports subelements that are specified as separate properties" do
|
152
|
-
FakeOxMods.properties[:name_][:convenience_methods][:role][:xpath].should == '//oxns:name/oxns:role'
|
153
|
-
FakeOxMods.properties[:name_][:convenience_methods][:role][:xpath_relative].should == 'oxns:role'
|
154
|
-
FakeOxMods.properties[:name_][:convenience_methods][:role][:xpath_constrained].should == '//oxns:name[contains(oxns:role/oxns:roleTerm, "#{constraint_value}")]'.gsub('"', '\"')
|
155
|
-
end
|
156
|
-
|
157
|
-
it "supports treating attributes as properties" do
|
158
|
-
FakeOxMods.properties[:title_info][:convenience_methods][:language][:xpath].should == '//oxns:titleInfo/@lang'
|
159
|
-
FakeOxMods.properties[:title_info][:convenience_methods][:language][:xpath_relative].should == '@lang'
|
160
|
-
FakeOxMods.properties[:title_info][:convenience_methods][:language][:xpath_constrained].should == '//oxns:titleInfo[contains(@lang, "#{constraint_value}")]'.gsub('"', '\"')
|
161
|
-
end
|
162
|
-
|
163
|
-
it "should support deep nesting of properties" do
|
164
|
-
pending "requires property method to be recursive"
|
165
|
-
|
166
|
-
FakeOxMods.properties[:journal][:convenience_methods][:issue][:convenience_methods][:volume].should == {:xpath_constrained=>"//oxns:part[contains(oxns:detail[@type=\\\"volume\\\"], \\\"\#{constraint_value}\\\")]", :path=>"detail", :attributes=>{:type=>"volume"}, :xpath=>"//oxns:part/oxns:detail[@type=\"volume\"]", :xpath_relative=>"oxns:detail[@type=\"volume\"]"}
|
167
|
-
prop_info = FakeOxMods.property_info_for([:journal, :issue, :volume])
|
168
|
-
prop_info[:xpath_constrained].should == "//oxns:part[contains(oxns:detail[@type=\\\"volume\\\"], \\\"\#{constraint_value}\\\")]"
|
169
|
-
prop_info[:xpath].should == "//oxns:part/oxns:detail[@type=\"volume\"]"
|
170
|
-
prop_info[:xpath_relative].should == "oxns:detail[@type=\"volume\"]"
|
171
|
-
end
|
172
|
-
|
173
|
-
it "should support even deeper nesting of properties" do
|
174
|
-
pending "requires property method to be recursive"
|
175
|
-
|
176
|
-
FakeOxMods.properties[:journal][:convenience_methods][:issue][:convenience_methods][:start_page].should == {:xpath_constrained=>"//oxns:part[contains(oxns:detail[@type=\\\"volume\\\"], \\\"\#{constraint_value}\\\")]", :path=>"detail", :attributes=>{:type=>"volume"}, :xpath=>"//oxns:part/oxns:detail[@type=\"volume\"]", :xpath_relative=>"oxns:detail[@type=\"volume\"]"}
|
177
|
-
FakeOxMods.property_info_for([:journal, :issue, :end_page]).should == ""
|
178
|
-
end
|
179
|
-
|
180
|
-
it "should not overwrite default property info when adding a variant property" do
|
181
|
-
FakeOxMods.properties[:name_].should_not equal(FakeOxMods.properties[:person])
|
182
|
-
FakeOxMods.properties[:name_][:convenience_methods].should_not equal(FakeOxMods.properties[:person][:convenience_methods])
|
183
|
-
|
184
|
-
FakeOxMods.properties[:name_][:xpath].should_not == FakeOxMods.properties[:person][:xpath]
|
185
|
-
FakeOxMods.properties[:name_][:convenience_methods][:date][:xpath_constrained].should_not == FakeOxMods.properties[:person][:convenience_methods][:date][:xpath_constrained]
|
186
|
-
end
|
187
|
-
|
188
|
-
end
|
189
|
-
|
190
|
-
describe ".lookup" do
|
191
|
-
|
192
|
-
it "uses the generated xpath queries" do
|
193
|
-
@fixturemods.ng_xml.expects(:xpath).with('//oxns:name[@type="personal"]', @fixturemods.ox_namespaces)
|
194
|
-
@fixturemods.lookup(:person)
|
195
|
-
|
196
|
-
@fixturemods.ng_xml.expects(:xpath).with('//oxns:name[@type="personal" and contains(oxns:namePart, "Beethoven, Ludwig van")]', @fixturemods.ox_namespaces)
|
197
|
-
@fixturemods.lookup(:person, "Beethoven, Ludwig van")
|
198
|
-
|
199
|
-
@fixturemods.ng_xml.expects(:xpath).with('//oxns:name[@type="personal" and contains(oxns:namePart[@type="date"], "2010")]', @fixturemods.ox_namespaces)
|
200
|
-
@fixturemods.lookup(:person, :date=>"2010")
|
201
|
-
|
202
|
-
@fixturemods.ng_xml.expects(:xpath).with('//oxns:name[@type="personal" and contains(oxns:role/oxns:roleTerm, "donor")]', @fixturemods.ox_namespaces)
|
203
|
-
@fixturemods.lookup(:person, :role=>"donor")
|
204
|
-
|
205
|
-
#
|
206
|
-
# This is the way we want to move towards... (currently implementing part of this in accessor_constrained_xpath)
|
207
|
-
# @fixturemods.ng_xml.expects(:xpath).with('//oxns:relatedItem/oxns:identifier[@type=\'issn\'] and contains("123-ABC-44567")]', @fixturemods.ox_namespaces)
|
208
|
-
# @fixturemods.lookup([:journal, :issn], "123-ABC-44567")
|
209
|
-
|
210
|
-
end
|
211
|
-
|
212
|
-
end
|
213
|
-
|
214
|
-
describe ".xpath_query_for" do
|
215
|
-
|
216
|
-
it "retrieves the generated xpath query to match your desires" do
|
217
|
-
@fixturemods.xpath_query_for(:person).should == '//oxns:name[@type="personal"]'
|
218
|
-
|
219
|
-
@fixturemods.xpath_query_for(:person, "Beethoven, Ludwig van").should == '//oxns:name[@type="personal" and contains(oxns:namePart, "Beethoven, Ludwig van")]'
|
220
|
-
|
221
|
-
@fixturemods.xpath_query_for(:person, :date=>"2010").should == '//oxns:name[@type="personal" and contains(oxns:namePart[@type="date"], "2010")]'
|
222
|
-
|
223
|
-
@fixturemods.xpath_query_for(:person, :role=>"donor").should == '//oxns:name[@type="personal" and contains(oxns:role/oxns:roleTerm, "donor")]'
|
224
|
-
|
225
|
-
@fixturemods.xpath_query_for([:person,:date]).should == '//oxns:name[@type="personal"]/oxns:namePart[@type="date"]'
|
226
|
-
|
227
|
-
@fixturemods.xpath_query_for([:person,:date], "2010").should == '//oxns:name[@type="personal" and contains(oxns:namePart[@type="date"], "2010")]'
|
228
|
-
end
|
229
|
-
|
230
|
-
it "parrots any strings back to you (in case you already have an xpath query)" do
|
231
|
-
@fixturemods.xpath_query_for('//oxns:name[@type="personal"]/oxns:namePart[@type="date"]').should == '//oxns:name[@type="personal"]/oxns:namePart[@type="date"]'
|
232
|
-
end
|
233
|
-
|
234
|
-
end
|
235
|
-
|
236
|
-
describe "#generate_xpath" do
|
237
|
-
it "should generate an xpath query from the options in the provided hash and should support generating xpaths with constraint values" do
|
238
|
-
opts1 = {:path=>"name", :default_content_path=>"namePart"}
|
239
|
-
opts2 = {:path=>"originInfo"}
|
240
|
-
opts3 = {:path=>["name", "namePart"]}
|
241
|
-
FakeOxMods.generate_xpath( opts1 ).should == '//oxns:name'
|
242
|
-
FakeOxMods.generate_xpath( opts1, :constraints=>:default ).should == '//oxns:name[contains(oxns:namePart, "#{constraint_value}")]'
|
243
|
-
FakeOxMods.generate_xpath( opts2, :constraints=>:default ).should == '//oxns:originInfo[contains("#{constraint_value}")]'
|
244
|
-
|
245
|
-
FakeOxMods.generate_xpath( opts1, :variations=>{:attributes=>{:type=>"personal"}} ).should == '//oxns:name[@type="personal"]'
|
246
|
-
FakeOxMods.generate_xpath( opts1, :variations=>{:attributes=>{:type=>"personal"}}, :constraints=>:default ).should == '//oxns:name[@type="personal" and contains(oxns:namePart, "#{constraint_value}")]'
|
247
|
-
|
248
|
-
FakeOxMods.generate_xpath( opts1, :constraints=>{:path=>"namePart", :attributes=>{:type=>"date"}} ).should == '//oxns:name[contains(oxns:namePart[@type="date"], "#{constraint_value}")]'
|
249
|
-
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}")]'
|
250
|
-
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}")]'
|
251
|
-
|
252
|
-
FakeOxMods.generate_xpath(opts1, :variations=>{:attributes=>{:type=>"personal"}, :subelement_path=>"displayForm" } ).should == '//oxns:name[@type="personal"]/oxns:displayForm'
|
253
|
-
FakeOxMods.generate_xpath(opts1, :variations=>{:attributes=>{:type=>"personal"}}, :constraints=>{:path=>"displayForm"} ).should == '//oxns:name[@type="personal" and contains(oxns:displayForm, "#{constraint_value}")]'
|
254
|
-
FakeOxMods.generate_xpath(opts1, :variations=>{:attributes=>{:type=>"personal"}, :subelement_path=>["role", "roleTerm"] } ).should == '//oxns:name[@type="personal"]/oxns:role/oxns:roleTerm'
|
255
|
-
|
256
|
-
FakeOxMods.generate_xpath( opts3, :variations=>{:attributes=>{:type=>"date"}} ).should == '//oxns:name/oxns:namePart[@type="date"]'
|
257
|
-
FakeOxMods.generate_xpath( opts3, :variations=>{:attributes=>{:type=>"date"}}, :constraints=>:default ).should == '//oxns:name/oxns:namePart[@type="date" and contains("#{constraint_value}")]'
|
258
|
-
|
259
|
-
FakeOxMods.generate_xpath( {:path=>["relatedItem", "identifier"]}, :variations=>{:attributes=>{:type=>"issn"}}, :constraints=>:default ).should == '//oxns:relatedItem/oxns:identifier[@type="issn" and contains("#{constraint_value}")]'
|
260
|
-
|
261
|
-
end
|
262
|
-
|
263
|
-
|
264
|
-
it "should support relative paths" do
|
265
|
-
relative_opts = {:path=>"namePart"}
|
266
|
-
FakeOxMods.generate_xpath( relative_opts, :variations=>{:attributes=>{:type=>"date"}}, :relative=>true).should == 'oxns:namePart[@type="date"]'
|
267
|
-
end
|
268
|
-
|
269
|
-
it "should work with real properties hashes" do
|
270
|
-
FakeOxMods.generate_xpath(FakeOxMods.properties[:person], :variations=>FakeOxMods.properties[:person]).should == "//oxns:name[@type=\"personal\"]"
|
271
|
-
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}")]'
|
272
|
-
date_hash = FakeOxMods.properties[:person][:convenience_methods][:date]
|
273
|
-
FakeOxMods.generate_xpath( date_hash, :variations=>date_hash, :relative=>true ).should == 'oxns:namePart[@type="date"]'
|
274
|
-
end
|
275
|
-
|
276
|
-
it "should support custom templates" do
|
277
|
-
opts = {:path=>"name", :default_content_path=>"namePart"}
|
278
|
-
FakeOxMods.generate_xpath( opts, :template=>'/#{prefix}:sampleNode/#{prefix}:#{path}[contains(#{default_content_path}, \":::constraint_value:::\")]' ).should == '/oxns:sampleNode/oxns:name[contains(namePart, "#{constraint_value}")]'
|
279
|
-
end
|
280
|
-
end
|
281
|
-
|
282
|
-
describe "#builder_template" do
|
283
|
-
|
284
|
-
it "should generate a template call for passing into the builder block (assumes 'xml' as the argument for the block)" do
|
285
|
-
FakeOxMods.builder_template([:person,:date]).should == 'xml.namePart( \'#{builder_new_value}\', :type=>\'date\' )'
|
286
|
-
FakeOxMods.builder_template([:name_,:affiliation]).should == 'xml.affiliation( \'#{builder_new_value}\' )'
|
287
|
-
|
288
|
-
simple_role_builder_template = 'xml.role( :type=>\'text\' ) { xml.roleTerm( \'#{builder_new_value}\' ) }'
|
289
|
-
FakeOxMods.builder_template([:role]).should == simple_role_builder_template
|
290
|
-
FakeOxMods.builder_template([:person,:role]).should == simple_role_builder_template
|
291
|
-
|
292
|
-
marcrelator_role_builder_template = 'xml.role( :type=>\'code\', :authority=>\'marcrelator\' ) { xml.roleTerm( \'#{builder_new_value}\' ) }'
|
293
|
-
FakeOxMods.builder_template([:role], {:attributes=>{"type"=>"code", "authority"=>"marcrelator"}} ).should == marcrelator_role_builder_template
|
294
|
-
FakeOxMods.builder_template([:person,:role], {:attributes=>{"type"=>"code", "authority"=>"marcrelator"}} ).should == marcrelator_role_builder_template
|
295
|
-
end
|
296
|
-
|
297
|
-
it "should work with deeply nested properties" do
|
298
|
-
FakeOxMods.builder_template([:issue, :volume]).should == "xml.detail( '\#{builder_new_value}', :type=>'volume' )"
|
299
|
-
FakeOxMods.builder_template([:volume, :number]).should == "xml.number( '\#{builder_new_value}' )"
|
300
|
-
FakeOxMods.builder_template([:journal, :issue, :level]).should == "xml.detail( :type=>'number' ) { xml.number( '\#{builder_new_value}' ) }"
|
301
|
-
FakeOxMods.builder_template([:journal, :issue, :volume]).should == "xml.detail( '\#{builder_new_value}', :type=>'volume' )"
|
302
|
-
FakeOxMods.builder_template([:journal, :issue, :volume, :number]).should == "xml.number( '\#{builder_new_value}' )"
|
303
|
-
FakeOxMods.builder_template([:journal, :issue, :start_page]).should == "xml.extent( :unit=>'pages' ) { xml.start( '\#{builder_new_value}' ) }"
|
304
|
-
end
|
305
|
-
|
306
|
-
end
|
307
|
-
|
308
|
-
describe "#applicable_attributes" do
|
309
|
-
it "returns a Hash where all of the values are strings" do
|
310
|
-
FakeOxMods.send(:applicable_attributes, {:type=>"date"} ).should == {:type=>"date"}
|
311
|
-
FakeOxMods.send(:applicable_attributes, ["authority", {:type=>["text","code"]}] ).should == {:type=>"text"}
|
312
|
-
end
|
313
|
-
end
|
314
|
-
|
315
|
-
end
|