active-fedora 3.1.1 → 3.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CONSOLE_GETTING_STARTED.textile +19 -6
- data/Gemfile.lock +1 -1
- data/History.txt +17 -0
- data/NOKOGIRI_DATASTREAMS.textile +185 -1
- data/lib/active_fedora/model.rb +36 -3
- data/lib/active_fedora/nokogiri_datastream.rb +6 -0
- data/lib/active_fedora/rdf_xml_writer.rb +69 -0
- data/lib/active_fedora/rels_ext_datastream.rb +9 -2
- data/lib/active_fedora/rubydora_connection.rb +8 -4
- data/lib/active_fedora/semantic_node.rb +18 -8
- data/lib/active_fedora/solr_service.rb +1 -12
- data/lib/active_fedora/version.rb +1 -1
- data/lib/tasks/active_fedora_dev.rake +0 -12
- data/spec/integration/model_spec.rb +5 -1
- data/spec/integration/nokogiri_datastream_spec.rb +5 -3
- data/spec/integration/solr_service_spec.rb +3 -0
- data/spec/unit/model_spec.rb +2 -1
- data/spec/unit/nokogiri_datastream_spec.rb +4 -2
- data/spec/unit/rdf_xml_writer.rb +63 -0
- data/spec/unit/rels_ext_datastream_spec.rb +11 -3
- data/spec/unit/rubydora_connection_spec.rb +29 -0
- data/spec/unit/semantic_node_spec.rb +8 -0
- metadata +7 -4
@@ -141,7 +141,15 @@ Use the relationships method to list the object's relationships:
|
|
141
141
|
|
142
142
|
<pre>
|
143
143
|
newthing.relationships
|
144
|
-
=>
|
144
|
+
=> #<RDF::Graph:0x83a53088(<>)>
|
145
|
+
|
146
|
+
newthing.relationships.statements.map(&:inspect)
|
147
|
+
=> ["#<RDF::Statement:0x8371a858(<info:fedora/changeme:30> <info:fedora/fedora-system:def/model#hasModel> <info:fedora/hydra-cModel:DisplaySet> .)>",
|
148
|
+
"#<RDF::Statement:0x8371a6f0(<info:fedora/changeme:30> <info:fedora/fedora-system:def/model#hasModel> <info:fedora/hydra-cModel:CommonMetadata> .)>",
|
149
|
+
"#<RDF::Statement:0x8371a3e4(<info:fedora/changeme:30> <info:fedora/fedora-system:def/relations-external#isMemberOf> <info:fedora/changeme:parentSet> .)>"]
|
150
|
+
|
151
|
+
newthing.relationships(:is_member_of)
|
152
|
+
=> ["info:fedora/changeme:parentSet"]
|
145
153
|
</pre>
|
146
154
|
|
147
155
|
The SpecialThing class definition contains these lines:
|
@@ -174,8 +182,17 @@ Now we'll create another Fedora object (using the default ActiveFedora object mo
|
|
174
182
|
newobj = ActiveFedora::Base.new
|
175
183
|
newobj.add_relationship(:has_derivation, newthing)
|
176
184
|
=> true
|
185
|
+
|
177
186
|
newobj.relationships
|
178
|
-
=>
|
187
|
+
=> #<RDF::Graph:0x83a53088(<>)>
|
188
|
+
|
189
|
+
newobj.relationships.statements.map(&:inspect)
|
190
|
+
=> ["#<RDF::Statement:0x8371a3e4(<info:fedora/changeme:30> <info:fedora/fedora-system:def/relations-external#hasDerivation> <info:fedora/changeme:30> .)>"]
|
191
|
+
|
192
|
+
newobj.relationships(:has_derivation)
|
193
|
+
=> ["info:fedora/changeme:30"]
|
194
|
+
|
195
|
+
|
179
196
|
newobj.save
|
180
197
|
=> ...
|
181
198
|
newobj.pid
|
@@ -256,10 +273,6 @@ newthing.pid
|
|
256
273
|
copy_as_base = ActiveFedora::Base.load_instance("changeme:30")
|
257
274
|
copy_as_base.pid
|
258
275
|
=> "changeme:30"
|
259
|
-
newthing.relationships
|
260
|
-
=> {:self=>{:has_model=>["info:fedora/afmodel:SpecialThing"]}}
|
261
|
-
copy_as_base.relationships
|
262
|
-
=> {:self=>{:has_model=>["info:fedora/afmodel:SpecialThing"]}}
|
263
276
|
newthing.datastreams.keys
|
264
277
|
=> ["DS1", "descMetadata", "Foo1", "minivan", "RELS-EXT", "rightsMetadata", "DC", "extraMetadataForFun"]
|
265
278
|
copy_as_base.datastreams.keys
|
data/Gemfile.lock
CHANGED
data/History.txt
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
3.1.2
|
2
|
+
correctly handling non-default pid_namespace (Benjamin Armintor)
|
3
|
+
info uri support; rdf:type predicate compatibility with Fedora(Benjamin Armintor)
|
4
|
+
more flexibility for initializing Rubydora (Michael B. Klein)
|
5
|
+
NokogiriDatastream and RELS-EXT datastream set mimeType (Justin Coyne)
|
6
|
+
|
7
|
+
|
8
|
+
3.1.1
|
9
|
+
adds support for better handling of literal values in the RELS-EXT datastream.
|
10
|
+
adds support for setting the controlGroup via a parameter to has_metadata.
|
11
|
+
ability to pass a predicate as a parameter to AF::Base#relationships to get a list of the matching targets. This reads a bit better than ids_for_outbound().
|
12
|
+
refactoring to support overriding certain sections (ContentModel) by consumers of active-fedora.
|
13
|
+
|
14
|
+
3.1.0
|
15
|
+
Based on rubydora for fedora interface
|
16
|
+
RDF-xml for the relationships
|
17
|
+
|
1
18
|
3.0.4
|
2
19
|
|
3
20
|
HYDRA-663 -- Passing an empty string to a id setter should clear the belongs to association
|
@@ -106,4 +106,188 @@ After calling add_datastream, then everything will be ready to save to Fedora.
|
|
106
106
|
|
107
107
|
<pre>
|
108
108
|
st.datastreams["descMetadata"].save
|
109
|
-
</pre>
|
109
|
+
</pre>
|
110
|
+
|
111
|
+
h2. (Rails3) Using ActiveModel methods and delegate to treat xml nodes like regular ActiveModel attributes
|
112
|
+
|
113
|
+
h3. Handling most xml fields with delegate method
|
114
|
+
|
115
|
+
Say you want to treat a mods title like a regular ActiveModel attribute so that you can use all of the Rails helpers and methods like form_for.
|
116
|
+
|
117
|
+
The Datastream definition:
|
118
|
+
|
119
|
+
<pre>
|
120
|
+
# app/models/mods_generic_content.rb
|
121
|
+
class ModsGenericContent < ObjectMods
|
122
|
+
|
123
|
+
set_terminology do |t|
|
124
|
+
t.root(:path=>"mods", :xmlns=>"http://www.loc.gov/mods/v3", :schema=>"http://www.loc.gov/standards/mods/v3/mods-3-2.xsd")
|
125
|
+
|
126
|
+
t.title_info(:path=>"titleInfo") {
|
127
|
+
t.main_title(:path=>"title", :label=>"title", :index_as=>[:facetable])
|
128
|
+
}
|
129
|
+
|
130
|
+
# Proxy Terms (delegate can only reference root terms, so you have to create a root term "title" that proxies to the correct spot in the Terminology)
|
131
|
+
t.title(:proxy=>[:title_info, :main_title])
|
132
|
+
end
|
133
|
+
end
|
134
|
+
</pre>
|
135
|
+
|
136
|
+
The Model:
|
137
|
+
|
138
|
+
|
139
|
+
<pre>
|
140
|
+
# app/models/generic_content.rb
|
141
|
+
class GenericContent < ActiveFedora::Base
|
142
|
+
|
143
|
+
include Hydra::ModelMethods
|
144
|
+
has_metadata :name => "descMetadata", :label=>"MODS metadata", :type => ModsGenericContent
|
145
|
+
|
146
|
+
delegate :title, :to=>:descMetadata
|
147
|
+
end
|
148
|
+
</pre>
|
149
|
+
|
150
|
+
Example form:
|
151
|
+
|
152
|
+
|
153
|
+
<pre>
|
154
|
+
# app/views/generic_contents.html.erb
|
155
|
+
<%= form_for @generic_content do |f| %>
|
156
|
+
<dl>
|
157
|
+
<dt class="title">
|
158
|
+
<%= f.label "Title:" %>
|
159
|
+
</dt>
|
160
|
+
<dd class="title">
|
161
|
+
<%= f.text_field :title %>
|
162
|
+
</dd>
|
163
|
+
</dl>
|
164
|
+
<%= f.submit "Save Changes" %>
|
165
|
+
<% end %>
|
166
|
+
</pre>
|
167
|
+
|
168
|
+
The Controller that processes updates:
|
169
|
+
|
170
|
+
<pre>
|
171
|
+
# app/controllers/generic_contents_controller.rb
|
172
|
+
class GenericContentsController < ApplicationController
|
173
|
+
|
174
|
+
# This renders the edit form
|
175
|
+
def edit
|
176
|
+
@generic_content = GenericContent.find(params[:id])
|
177
|
+
end
|
178
|
+
|
179
|
+
# This updates the object based on the info submitted by your form, which puts the Hash of new values into params["generic_content"]
|
180
|
+
def update
|
181
|
+
@generic_content = GenericContent.find(params[:id])
|
182
|
+
@generic_content.update_attributes(params[:generic_content])
|
183
|
+
if @generic_content.save
|
184
|
+
flash[:notice] = "Saved changes to #{@generic_content.title}"
|
185
|
+
else
|
186
|
+
flash[:error] = "Failed to save your changes!"
|
187
|
+
end
|
188
|
+
redirect_to edit_generic_content_path(@generic_content)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
</pre>
|
192
|
+
|
193
|
+
h3. Handling complex xml structures in attributes= method
|
194
|
+
|
195
|
+
This approach complements the usage of the delegate method to handle most xml nodes in your datasreams.
|
196
|
+
|
197
|
+
With this approach, you can still create relatively normal Rails forms while updating complex xml structures (ie. MODS name entries) internally without creating a separate controller & model for those structures.
|
198
|
+
|
199
|
+
Example: You want to create/edit xml like this in a descMetadata datastream that uses the GenericContentXml datatstream definition.
|
200
|
+
|
201
|
+
<pre>
|
202
|
+
<subject>
|
203
|
+
<topic>Subject 1</topic>
|
204
|
+
<catgegory>topic</category>
|
205
|
+
</subject>
|
206
|
+
<subject>
|
207
|
+
<topic>Subject 2</topic>
|
208
|
+
<catgegory>geographic</category>
|
209
|
+
</subject>
|
210
|
+
</pre>
|
211
|
+
|
212
|
+
You have a form that submits parameters like this:
|
213
|
+
|
214
|
+
<pre>
|
215
|
+
{
|
216
|
+
"generic_content" => {
|
217
|
+
"subjects" =>[
|
218
|
+
{
|
219
|
+
"topic" => "Subject 1",
|
220
|
+
"category" => "topic"
|
221
|
+
},{
|
222
|
+
"topic" => "Subject 2",
|
223
|
+
"category" => "geographic"
|
224
|
+
}
|
225
|
+
]
|
226
|
+
}}
|
227
|
+
</pre>
|
228
|
+
|
229
|
+
Here's the test:
|
230
|
+
|
231
|
+
<pre>
|
232
|
+
# spec/models/generic_content_spec.rb
|
233
|
+
describe "attributes=" do
|
234
|
+
before do
|
235
|
+
@node = GenericContent.new
|
236
|
+
@sample_post_params = {
|
237
|
+
"generic_content" => {
|
238
|
+
"subjects" =>[
|
239
|
+
{
|
240
|
+
"topic" => "Subject 1",
|
241
|
+
"category" => "topic"
|
242
|
+
},{
|
243
|
+
"topic" => "Subject 2",
|
244
|
+
"category" => "geographic"
|
245
|
+
}
|
246
|
+
]
|
247
|
+
}}
|
248
|
+
|
249
|
+
end
|
250
|
+
it "with subjects" do
|
251
|
+
@node.attributes = @sample_post_params["generic_content"]
|
252
|
+
@node.descMetadata.subject.length.should == 2
|
253
|
+
@node.descMetadata.subject(0).topic.should == ["Subject 1"]
|
254
|
+
@node.descMetadata.subject(0).category.should == ["topic"]
|
255
|
+
@node.descMetadata.subject(1).topic.should == ["Subject 2"]
|
256
|
+
@node.descMetadata.subject(1).category.should == ["geographic"]
|
257
|
+
end
|
258
|
+
end
|
259
|
+
</pre>
|
260
|
+
|
261
|
+
In the OM terminology of the Datasream definition:
|
262
|
+
|
263
|
+
<pre>
|
264
|
+
# app/models/generic_content_xml.rb
|
265
|
+
...
|
266
|
+
t.subject(:path=>"subject", :attributes=>{:authority=>"UoH"}) {
|
267
|
+
t.topic(:index_as=>[:facetable])
|
268
|
+
t.category
|
269
|
+
}
|
270
|
+
...
|
271
|
+
</pre>
|
272
|
+
|
273
|
+
The Model:
|
274
|
+
|
275
|
+
<pre>
|
276
|
+
# app/models/generic_content.rb
|
277
|
+
class GenericContent < ActiveFedora::Base
|
278
|
+
|
279
|
+
include Hydra::ModelMethods
|
280
|
+
has_metadata :name => "descMetadata", :label=>"generic metadata", :type => GenericContentXml
|
281
|
+
|
282
|
+
def attributes=(properties)
|
283
|
+
if (properties["subjects"])
|
284
|
+
self.descMetadata.subject.nodeset.remove # wipe out existing values
|
285
|
+
properties["subjects"].each_with_index do |subject_hash, index|
|
286
|
+
self.descMetadata.subject(index).topic = subject_hash["topic"]
|
287
|
+
self.descMetadata.subject(index).category = subject_hash["category"]
|
288
|
+
end
|
289
|
+
properties.delete("subjects")
|
290
|
+
end
|
291
|
+
super
|
292
|
+
end
|
293
|
+
</pre>
|
data/lib/active_fedora/model.rb
CHANGED
@@ -8,11 +8,36 @@ module ActiveFedora
|
|
8
8
|
# much in the way ActiveRecord does.
|
9
9
|
module Model
|
10
10
|
extend ActiveFedora::FedoraObject
|
11
|
-
|
11
|
+
DEFAULT_NS = 'afmodel'
|
12
12
|
|
13
13
|
def self.included(klass) # :nodoc:
|
14
14
|
klass.extend(ClassMethods)
|
15
15
|
end
|
16
|
+
|
17
|
+
# Takes a Fedora URI for a cModel, and returns a
|
18
|
+
# corresponding Model if available
|
19
|
+
# This method should reverse ClassMethods#to_class_uri
|
20
|
+
def self.from_class_uri(uri)
|
21
|
+
if match_data = /info:fedora\/([a-zA-z0-9\-_]+):(.+)$/.match(uri)
|
22
|
+
pid_ns = match_data[1]
|
23
|
+
model_value = match_data[2]
|
24
|
+
model_value.gsub!('_', '::')
|
25
|
+
else
|
26
|
+
raise "model URI incorrectly formatted: #{uri}"
|
27
|
+
end
|
28
|
+
if model_value.include?("::")
|
29
|
+
result = eval(model_value)
|
30
|
+
else
|
31
|
+
result = Kernel.const_get(model_value)
|
32
|
+
end
|
33
|
+
unless result.nil?
|
34
|
+
model_ns = (result.respond_to? :pid_namespace) ? result.pid_namespace : DEFAULT_NS
|
35
|
+
if model_ns != pid_ns
|
36
|
+
logger.warn "Model class namespace (#{model_ns}) and uri namespace (#{pid_ns}) do not match!"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
result
|
40
|
+
end
|
16
41
|
|
17
42
|
def add_metadata
|
18
43
|
end
|
@@ -52,7 +77,15 @@ module ActiveFedora
|
|
52
77
|
def load_instance(pid)
|
53
78
|
RubydoraConnection.instance.find_model(pid, self)
|
54
79
|
end
|
55
|
-
|
80
|
+
|
81
|
+
# Returns a suitable uri object for :has_model
|
82
|
+
# Should reverse Model#from_class_uri
|
83
|
+
def to_class_uri
|
84
|
+
ns = (self.respond_to? :pid_namespace) ? self.pid_namespace : Model::DEFAULT_NS
|
85
|
+
pid = self.name.gsub(/::/,'_')
|
86
|
+
"info:fedora/#{ns}:#{pid}"
|
87
|
+
end
|
88
|
+
|
56
89
|
# Takes :all or a pid as arguments
|
57
90
|
# Returns an Array of objects of the Class that +find+ is being
|
58
91
|
# called on
|
@@ -62,7 +95,7 @@ module ActiveFedora
|
|
62
95
|
if args == :all
|
63
96
|
return_multiple = true
|
64
97
|
# escaped_class_name = self.name.gsub(/(:)/, '\\:')
|
65
|
-
escaped_class_uri =
|
98
|
+
escaped_class_uri = SolrService.escape_uri_for_query(self.to_class_uri)
|
66
99
|
# q = "#{ActiveFedora::SolrService.solr_name(:active_fedora_model, :symbol)}:#{escaped_class_name}"
|
67
100
|
q = "#{ActiveFedora::SolrService.solr_name(:has_model, :symbol)}:#{escaped_class_uri}"
|
68
101
|
elsif args.class == String
|
@@ -16,6 +16,12 @@ module ActiveFedora
|
|
16
16
|
alias_method(:om_update_values, :update_values) unless method_defined?(:om_update_values)
|
17
17
|
|
18
18
|
attr_accessor :internal_solr_doc
|
19
|
+
|
20
|
+
before_create :add_mime_type
|
21
|
+
|
22
|
+
def add_mime_type
|
23
|
+
self.mimeType= 'text/xml'
|
24
|
+
end
|
19
25
|
|
20
26
|
# Create an instance of this class based on xml content
|
21
27
|
# @param [String, File, Nokogiri::XML::Node] xml the xml content to build from
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'rdf/rdfxml'
|
3
|
+
require 'rdf'
|
4
|
+
|
5
|
+
module ActiveFedora
|
6
|
+
# This class ensures that the RELS-EXT datastream is always serialized
|
7
|
+
# with an rdf:Description container for the properties
|
8
|
+
# the default behavior for RDF:RDFXML::Writer is to change that element if
|
9
|
+
# an rdf:type assertion is present; this is incompatible with Fedora
|
10
|
+
class RDFXMLWriter < RDF::RDFXML::Writer
|
11
|
+
def subject(subject, parent_node)
|
12
|
+
node = nil
|
13
|
+
|
14
|
+
raise RDF::WriterError, "Illegal use of subject #{subject.inspect}, not supported in RDF/XML" unless subject.resource?
|
15
|
+
|
16
|
+
if !is_done?(subject)
|
17
|
+
subject_done(subject)
|
18
|
+
properties = @graph.properties(subject)
|
19
|
+
add_debug {"subject: #{subject.inspect}, props: #{properties.inspect}"}
|
20
|
+
|
21
|
+
@graph.query(:subject => subject).each do |st|
|
22
|
+
raise RDF::WriterError, "Illegal use of predicate #{st.predicate.inspect}, not supported in RDF/XML" unless st.predicate.uri?
|
23
|
+
end
|
24
|
+
|
25
|
+
prop_list = order_properties(properties)
|
26
|
+
add_debug {"=> property order: #{prop_list.to_sentence}"}
|
27
|
+
|
28
|
+
qname = "rdf:Description"
|
29
|
+
prefixes[:rdf] = RDF.to_uri
|
30
|
+
|
31
|
+
node = Nokogiri::XML::Element.new(qname, parent_node.document)
|
32
|
+
|
33
|
+
if subject.is_a?(RDF::Node)
|
34
|
+
# Only need nodeID if it's referenced elsewhere
|
35
|
+
if ref_count(subject) > (@depth == 0 ? 0 : 1)
|
36
|
+
node["rdf:nodeID"] = subject.id
|
37
|
+
else
|
38
|
+
node.add_child(Nokogiri::XML::Comment.new(node.document, "Serialization for #{subject}")) if RDF::RDFXML::debug?
|
39
|
+
end
|
40
|
+
else
|
41
|
+
node["rdf:about"] = relativize(subject)
|
42
|
+
end
|
43
|
+
|
44
|
+
prop_list.each do |prop|
|
45
|
+
prop_ref = RDF::URI.intern(prop)
|
46
|
+
|
47
|
+
properties[prop].each do |object|
|
48
|
+
raise RDF::WriterError, "Illegal use of object #{object.inspect}, not supported in RDF/XML" unless object.resource? || object.literal?
|
49
|
+
|
50
|
+
@depth += 1
|
51
|
+
predicate(prop_ref, object, node, properties[prop].length == 1)
|
52
|
+
@depth -= 1
|
53
|
+
end
|
54
|
+
end
|
55
|
+
elsif @force_RDF_about.include?(subject)
|
56
|
+
add_debug {"subject: #{subject.inspect}, force about"}
|
57
|
+
node = Nokogiri::XML::Element.new("rdf:Description", parent_node.document)
|
58
|
+
if subject.is_a?(RDF::Node)
|
59
|
+
node["rdf:nodeID"] = subject.id
|
60
|
+
else
|
61
|
+
node["rdf:about"] = relativize(subject)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
@force_RDF_about.delete(subject)
|
65
|
+
|
66
|
+
parent_node.add_child(node) if node
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -3,13 +3,20 @@ require 'solrizer/field_name_mapper'
|
|
3
3
|
require 'uri'
|
4
4
|
require 'rdf/rdfxml'
|
5
5
|
require 'rdf'
|
6
|
+
require 'active_fedora/rdf_xml_writer'
|
6
7
|
|
7
8
|
module ActiveFedora
|
8
9
|
class RelsExtDatastream < Datastream
|
9
10
|
|
10
11
|
include Solrizer::FieldNameMapper
|
11
12
|
attr_accessor :model
|
12
|
-
|
13
|
+
|
14
|
+
before_create :add_mime_type
|
15
|
+
|
16
|
+
def add_mime_type
|
17
|
+
self.mimeType= 'application/rdf+xml'
|
18
|
+
end
|
19
|
+
|
13
20
|
def serialize!
|
14
21
|
self.content = to_rels_ext() if model.relationships_are_dirty
|
15
22
|
model.relationships_are_dirty = false
|
@@ -46,7 +53,7 @@ module ActiveFedora
|
|
46
53
|
# @param [Hash] relationships (optional) @default self.relationships
|
47
54
|
# Note: This method is implemented on SemanticNode instead of RelsExtDatastream because SemanticNode contains the relationships array
|
48
55
|
def to_rels_ext()
|
49
|
-
xml =
|
56
|
+
xml = ActiveFedora::RDFXMLWriter.buffer do |writer|
|
50
57
|
model.relationships.each_statement do |statement|
|
51
58
|
writer << statement
|
52
59
|
end
|
@@ -9,6 +9,7 @@ module ActiveFedora
|
|
9
9
|
attr_accessor :options
|
10
10
|
|
11
11
|
def self.connect(params={})
|
12
|
+
params = params.dup
|
12
13
|
if params.kind_of? String
|
13
14
|
u = URI.parse params
|
14
15
|
params = {}
|
@@ -17,14 +18,17 @@ module ActiveFedora
|
|
17
18
|
params[:url] = "#{u.scheme}://#{u.host}:#{u.port}#{u.path}"
|
18
19
|
end
|
19
20
|
instance = self.instance
|
21
|
+
force = params.delete(:force)
|
20
22
|
instance.options = params
|
21
|
-
instance.connect
|
23
|
+
instance.connect force
|
22
24
|
instance
|
23
25
|
end
|
24
26
|
|
25
|
-
def connect()
|
26
|
-
return unless @connection.nil?
|
27
|
-
|
27
|
+
def connect(force=false)
|
28
|
+
return unless @connection.nil? or force
|
29
|
+
allowable_options = [:url, :user, :password, :timeout, :open_timeout, :ssl_client_cert, :ssl_client_key]
|
30
|
+
client_options = options.reject { |k,v| not allowable_options.include?(k) }
|
31
|
+
@connection = Rubydora.connect client_options
|
28
32
|
end
|
29
33
|
|
30
34
|
def nextid(attrs={})
|
@@ -32,21 +32,31 @@ module ActiveFedora
|
|
32
32
|
# @param uri a string represending the subject
|
33
33
|
# @param predicate a predicate symbol
|
34
34
|
# @param target an object to store
|
35
|
-
def build_statement(uri, predicate, target, literal=
|
35
|
+
def build_statement(uri, predicate, target, literal=false)
|
36
36
|
raise "Not allowed anymore" if uri == :self
|
37
37
|
target = target.internal_uri if target.respond_to? :internal_uri
|
38
38
|
subject = RDF::URI.new(uri) #TODO cache
|
39
|
-
|
39
|
+
unless literal or target.is_a? RDF::Resource
|
40
40
|
begin
|
41
|
-
|
41
|
+
target_uri = (target.is_a? URI) ? target : URI.parse(target)
|
42
|
+
if target_uri.scheme.nil?
|
43
|
+
raise ArgumentError, "Invalid target \"#{target}\". Must have namespace."
|
44
|
+
end
|
45
|
+
if target_uri.to_s =~ /\A[\w\-]+:[\w\-]+\Z/
|
46
|
+
raise ArgumentError, "Invalid target \"#{target}\". Target should be a complete URI, and not a pid."
|
47
|
+
end
|
42
48
|
rescue URI::InvalidURIError
|
43
|
-
literal
|
49
|
+
raise ArgumentError, "Invalid target \"#{target}\". Target must be specified as a literal, or be a valid URI."
|
44
50
|
end
|
45
51
|
end
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
52
|
+
if literal
|
53
|
+
object = RDF::Literal.new(target)
|
54
|
+
elsif target.is_a? RDF::Resource
|
55
|
+
object = target
|
56
|
+
else
|
57
|
+
object = RDF::URI.new(target)
|
58
|
+
end
|
59
|
+
RDF::Statement.new(subject, find_graph_predicate(predicate), object)
|
50
60
|
|
51
61
|
end
|
52
62
|
|
@@ -44,18 +44,7 @@ module ActiveFedora
|
|
44
44
|
|
45
45
|
def self.class_from_solr_document(hit)
|
46
46
|
model_value = hit[solr_name("has_model", :symbol)].first
|
47
|
-
|
48
|
-
model_value = match_data[1]
|
49
|
-
model_value.gsub!('_', '::')
|
50
|
-
else
|
51
|
-
raise "has_model assertion incorrectly formatted: #{model_value}"
|
52
|
-
end
|
53
|
-
|
54
|
-
if model_value.include?("::")
|
55
|
-
eval(model_value)
|
56
|
-
else
|
57
|
-
Kernel.const_get(model_value)
|
58
|
-
end
|
47
|
+
Model.from_class_uri(model_value)
|
59
48
|
end
|
60
49
|
|
61
50
|
# Construct a solr query for a list of pids
|
@@ -69,12 +69,6 @@ namespace :active_fedora do
|
|
69
69
|
t.rcov_opts << ['--exclude', 'spec']
|
70
70
|
end
|
71
71
|
|
72
|
-
desc "Refresh test fixtres"
|
73
|
-
task :refresh_fixtures do
|
74
|
-
Rake::Task["active_fedora:clean_jetty"].invoke
|
75
|
-
Rake::Task["active_fedora:load_fixtures"].invoke
|
76
|
-
end
|
77
|
-
|
78
72
|
task :clean_jetty do
|
79
73
|
Dir.chdir("./jetty")
|
80
74
|
system("git clean -f -d")
|
@@ -83,12 +77,6 @@ namespace :active_fedora do
|
|
83
77
|
end
|
84
78
|
|
85
79
|
task :load_fixtures => :environment do
|
86
|
-
# require 'solrizer'
|
87
|
-
# require 'solrizer-fedora'
|
88
|
-
# require 'spec/samples/models/hydrangea_article'
|
89
|
-
# ENV["FEDORA_HOME"] ||= File.expand_path(File.join(File.dirname(__FILE__),'..','..','jetty','fedora','default'))
|
90
|
-
# retval = `$FEDORA_HOME/client/bin/fedora-ingest-demos.sh localhost 8983 fedoraAdmin fedoraAdmin http`
|
91
|
-
# puts "loaded demo objects #{retval}"
|
92
80
|
ActiveFedora.init unless Thread.current[:repo]
|
93
81
|
|
94
82
|
ENV["pid"] = "hydrangea:fixture_mods_article1"
|
@@ -17,6 +17,9 @@ describe ActiveFedora::Model do
|
|
17
17
|
|
18
18
|
class Basic < ActiveFedora::Base
|
19
19
|
include ActiveFedora::Model
|
20
|
+
def self.pid_namespace
|
21
|
+
"foo"
|
22
|
+
end
|
20
23
|
end
|
21
24
|
|
22
25
|
end
|
@@ -34,9 +37,10 @@ describe ActiveFedora::Model do
|
|
34
37
|
|
35
38
|
describe '#find' do
|
36
39
|
it "should return an array of instances of the calling Class" do
|
37
|
-
pending
|
38
40
|
result = ModelIntegrationSpec::Basic.find(:all)
|
39
41
|
result.should be_instance_of(Array)
|
42
|
+
# this test is meaningless if the array length is zero
|
43
|
+
result.length.should > 0
|
40
44
|
result.each do |obj|
|
41
45
|
obj.class.should == ModelIntegrationSpec::Basic
|
42
46
|
end
|
@@ -21,12 +21,14 @@ describe ActiveFedora::NokogiriDatastream do
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
@pid = "hydrangea:fixture_mods_article1"
|
25
|
-
@test_solr_object = HydrangeaArticle2.load_instance_from_solr(@pid)
|
26
|
-
@test_object = HydrangeaArticle2.load_instance(@pid)
|
27
24
|
end
|
28
25
|
|
29
26
|
describe '.term_values' do
|
27
|
+
before do
|
28
|
+
@pid = "hydrangea:fixture_mods_article1"
|
29
|
+
@test_solr_object = HydrangeaArticle2.load_instance_from_solr(@pid)
|
30
|
+
@test_object = HydrangeaArticle2.load_instance(@pid)
|
31
|
+
end
|
30
32
|
|
31
33
|
it "should return the same values whether getting from solr or Fedora" do
|
32
34
|
@test_solr_object.datastreams["descMetadata"].term_values(:name,:role,:text).should == ["Creator","Contributor","Funder","Host"]
|
@@ -6,6 +6,9 @@ describe ActiveFedora::SolrService do
|
|
6
6
|
describe "#reify_solr_results" do
|
7
7
|
before(:all) do
|
8
8
|
class FooObject < ActiveFedora::Base
|
9
|
+
def self.pid_namespace
|
10
|
+
"foo"
|
11
|
+
end
|
9
12
|
has_metadata :name => "properties", :type => ActiveFedora::MetadataDatastream do |m|
|
10
13
|
m.field "holding_id", :string
|
11
14
|
end
|
data/spec/unit/model_spec.rb
CHANGED
@@ -103,7 +103,8 @@ describe ActiveFedora::Model do
|
|
103
103
|
mock_solr = mock("SolrConnection")
|
104
104
|
mock_result = mock("MockResult")
|
105
105
|
mock_result.expects(:hits).returns([{"id" => "changeme:30"}, {"id" => "changeme:22"}])
|
106
|
-
mock_solr.expects(:query).with('has_model_s:info\\:fedora/afmodel\\:SpecModel\:\:Basic', :rows=>1001).returns(mock_result)
|
106
|
+
#mock_solr.expects(:query).with('has_model_s:info\\:fedora/afmodel\\:SpecModel\:\:Basic', :rows=>1001).returns(mock_result)
|
107
|
+
mock_solr.expects(:query).with('has_model_s:info\\:fedora/afmodel\\:SpecModel_Basic', :rows=>1001).returns(mock_result)
|
107
108
|
ActiveFedora::SolrService.expects(:instance).returns(mock("SolrService", :conn => mock_solr))
|
108
109
|
ActiveFedora::RubydoraConnection.instance.expects(:find_model).with("changeme:30", SpecModel::Basic).returns("Fake Object1")
|
109
110
|
ActiveFedora::RubydoraConnection.instance.expects(:find_model).with("changeme:22", SpecModel::Basic).returns("Fake Object2")
|
@@ -25,7 +25,7 @@ describe ActiveFedora::NokogiriDatastream do
|
|
25
25
|
|
26
26
|
after(:each) do
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
it "should include the Solrizer::XML::TerminologyBasedSolrizer for .to_solr support" do
|
30
30
|
ActiveFedora::NokogiriDatastream.included_modules.should include(Solrizer::XML::TerminologyBasedSolrizer)
|
31
31
|
end
|
@@ -171,10 +171,12 @@ describe ActiveFedora::NokogiriDatastream do
|
|
171
171
|
end
|
172
172
|
it "should persist the product of .to_xml in fedora" do
|
173
173
|
@test_ds.expects(:new?).returns(true).twice
|
174
|
-
@mock_repo.expects(:
|
174
|
+
@mock_repo.expects(:datastream).with(:pid => nil, :dsid => 'descMetadata')
|
175
|
+
@mock_repo.expects(:add_datastream).with(:pid => nil, :dsid => 'descMetadata', :checksumType => 'DISABLED', :versionable => true, :content => 'fake xml', :controlGroup => 'M', :dsState => 'A', :mimeType=>'text/xml')
|
175
176
|
@test_ds.expects(:to_xml).returns("fake xml")
|
176
177
|
@test_ds.serialize!
|
177
178
|
@test_ds.save
|
179
|
+
@test_ds.mimeType.should == 'text/xml'
|
178
180
|
end
|
179
181
|
end
|
180
182
|
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require File.join( File.dirname(__FILE__), "../spec_helper" )
|
2
|
+
require File.join( File.dirname(__FILE__), "../../lib/active_fedora/rdf_xml_writer" )
|
3
|
+
|
4
|
+
describe ActiveFedora::RDFXMLWriter do
|
5
|
+
before(:all) do
|
6
|
+
@rdf_xml = <<-EOS
|
7
|
+
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
|
8
|
+
<rdf:Description rdf:about='info:fedora/test:sample_pid'>
|
9
|
+
<isMemberOf rdf:resource='info:fedora/demo:10' xmlns='info:fedora/fedora-system:def/relations-external#'/>
|
10
|
+
<isPartOf rdf:resource='info:fedora/demo:11' xmlns='info:fedora/fedora-system:def/relations-external#'/>
|
11
|
+
<hasPart rdf:resource='info:fedora/demo:12' xmlns='info:fedora/fedora-system:def/relations-external#'/>
|
12
|
+
<hasModel rdf:resource='info:fedora/afmodel:OtherModel' xmlns='info:fedora/fedora-system:def/model#'/>
|
13
|
+
<hasModel rdf:resource='info:fedora/afmodel:SampleModel' xmlns='info:fedora/fedora-system:def/model#'/>
|
14
|
+
</rdf:Description>
|
15
|
+
</rdf:RDF>
|
16
|
+
EOS
|
17
|
+
|
18
|
+
@rdf_xml_with_type = <<-EOS
|
19
|
+
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
|
20
|
+
<rdf:Description rdf:about='info:fedora/test:sample_pid'>
|
21
|
+
<isMemberOf rdf:resource='demo:10' xmlns='info:fedora/fedora-system:def/relations-external#'/>
|
22
|
+
<type rdf:resource='http://purl.org/dc/dcmitype/Collection' xmlns='http://www.w3.org/1999/02/22-rdf-syntax-ns#' />
|
23
|
+
</rdf:Description>
|
24
|
+
</rdf:RDF>
|
25
|
+
EOS
|
26
|
+
|
27
|
+
end
|
28
|
+
it "should serialize graphs using the rdf:Description element despite the presence of rdf:type statements" do
|
29
|
+
graph = RDF::Graph.new
|
30
|
+
subject = RDF::URI.new "info:fedora/test:sample_pid"
|
31
|
+
graph.insert RDF::Statement.new(subject, ActiveFedora::Base.new.find_graph_predicate(:is_member_of), RDF::URI.new('demo:10'))
|
32
|
+
graph.insert RDF::Statement.new(subject, RDF::URI('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), RDF::URI.new('http://purl.org/dc/dcmitype/Collection'))
|
33
|
+
content = RDF::RDFXML::Writer.buffer do |writer|
|
34
|
+
graph.each_statement do |statement|
|
35
|
+
writer << statement
|
36
|
+
end
|
37
|
+
end
|
38
|
+
EquivalentXml.equivalent?(content, @rdf_xml_with_type).should be_true
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should serialize graphs without rdf:type equivalently to RDF::RDFXML::Writer' do
|
42
|
+
graph = RDF::Graph.new
|
43
|
+
subject = RDF::URI.new "info:fedora/test:sample_pid"
|
44
|
+
graph.insert RDF::Statement.new(subject, ActiveFedora::Base.new.find_graph_predicate(:is_member_of), RDF::URI.new('info:fedora/demo:10'))
|
45
|
+
graph.insert RDF::Statement.new(subject, ActiveFedora::Base.new.find_graph_predicate(:is_part_of), RDF::URI.new('info:fedora/demo:11'))
|
46
|
+
graph.insert RDF::Statement.new(subject, ActiveFedora::Base.new.find_graph_predicate(:has_part), RDF::URI.new('info:fedora/demo:12'))
|
47
|
+
graph.insert RDF::Statement.new(subject, ActiveFedora::Base.new.find_graph_predicate(:has_model), RDF::URI.new("info:fedora/afmodel:OtherModel"))
|
48
|
+
graph.insert RDF::Statement.new(subject, ActiveFedora::Base.new.find_graph_predicate(:has_model), RDF::URI.new("info:fedora/afmodel:SampleModel"))
|
49
|
+
|
50
|
+
local_content = ActiveFedora::RDFXMLWriter.buffer do |writer|
|
51
|
+
graph.each_statement do |statement|
|
52
|
+
writer << statement
|
53
|
+
end
|
54
|
+
end
|
55
|
+
generic_content = RDF::RDFXML::Writer.buffer do |writer|
|
56
|
+
graph.each_statement do |statement|
|
57
|
+
writer << statement
|
58
|
+
end
|
59
|
+
end
|
60
|
+
EquivalentXml.equivalent?(local_content, @rdf_xml).should be_true
|
61
|
+
EquivalentXml.equivalent?(local_content, generic_content).should be_true
|
62
|
+
end
|
63
|
+
end
|
@@ -21,9 +21,17 @@ describe ActiveFedora::RelsExtDatastream do
|
|
21
21
|
mock_inner.stubs(:pid).returns(@pid)
|
22
22
|
@test_ds = ActiveFedora::RelsExtDatastream.new(mock_inner, "RELS-EXT")
|
23
23
|
end
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
|
25
|
+
describe "#save" do
|
26
|
+
before do
|
27
|
+
@mock_repo.expects(:add_datastream).with(:pid => 'test:sample_pid', :dsid => 'RELS-EXT', :checksumType => 'DISABLED', :versionable => true, :content => 'fake xml', :controlGroup => 'M', :dsState => 'A', :mimeType=>'application/rdf+xml')
|
28
|
+
@mock_repo.expects(:datastream).with(:pid => 'test:sample_pid', :dsid => 'RELS-EXT')
|
29
|
+
@test_ds.content = 'fake xml'
|
30
|
+
end
|
31
|
+
it 'should set the mime type' do
|
32
|
+
@test_ds.save
|
33
|
+
@test_ds.mimeType.should == 'application/rdf+xml'
|
34
|
+
end
|
27
35
|
end
|
28
36
|
|
29
37
|
|
@@ -16,6 +16,35 @@ describe ActiveFedora::RubydoraConnection do
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
describe 'connect' do
|
20
|
+
before do
|
21
|
+
@instance = ActiveFedora::RubydoraConnection.instance
|
22
|
+
@reconfig = { :force => true, :url => @instance.connection.client.url }.merge(@instance.connection.client.options)
|
23
|
+
end
|
24
|
+
|
25
|
+
after do
|
26
|
+
ActiveFedora::RubydoraConnection.connect @reconfig
|
27
|
+
end
|
28
|
+
|
29
|
+
it "shouldn't reconnect by default" do
|
30
|
+
client_id = @instance.connection.client.object_id
|
31
|
+
ActiveFedora::RubydoraConnection.connect :timeout => 3600
|
32
|
+
@instance.connection.client.object_id.should == client_id
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should reconnect with force" do
|
36
|
+
client_id = @instance.connection.client.object_id
|
37
|
+
ActiveFedora::RubydoraConnection.connect :force => true
|
38
|
+
@instance.connection.client.object_id.should_not == client_id
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should pass through valid options" do
|
42
|
+
ActiveFedora::RubydoraConnection.connect :timeout => 3600, :fake_option => :missing, :force => true
|
43
|
+
@instance.connection.client.options[:timeout].should == 3600
|
44
|
+
@instance.connection.client.options.has_key?(:fake_option).should be_false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
19
48
|
describe 'find_model' do
|
20
49
|
|
21
50
|
end
|
@@ -26,6 +26,14 @@ describe ActiveFedora::SemanticNode do
|
|
26
26
|
stm = @node.build_statement('info:fedora/spec:9', :is_part_of, 'info:fedora/spec:7')
|
27
27
|
stm.object.to_s.should == "info:fedora/spec:7"
|
28
28
|
end
|
29
|
+
it "should also be happy with non-info URIs" do
|
30
|
+
stm = @node.build_statement('info:fedora/spec:9', :is_annotation_of, 'http://www.w3.org/standards/techs/rdf')
|
31
|
+
stm.object.to_s.should == "http://www.w3.org/standards/techs/rdf"
|
32
|
+
end
|
33
|
+
it "should also be happy with targets that are URI::Generics" do
|
34
|
+
stm = @node.build_statement('info:fedora/spec:9', :is_annotation_of, URI.parse('http://www.w3.org/standards/techs/rdf'))
|
35
|
+
stm.object.to_s.should == "http://www.w3.org/standards/techs/rdf"
|
36
|
+
end
|
29
37
|
end
|
30
38
|
|
31
39
|
describe "with a bunch of objects" do
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active-fedora
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 7
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 3
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 3.1.
|
9
|
+
- 2
|
10
|
+
version: 3.1.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Matt Zumwalt
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2011-11-
|
19
|
+
date: 2011-11-18 00:00:00 -06:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -589,6 +589,7 @@ files:
|
|
589
589
|
- lib/active_fedora/property.rb
|
590
590
|
- lib/active_fedora/qualified_dublin_core_datastream.rb
|
591
591
|
- lib/active_fedora/railtie.rb
|
592
|
+
- lib/active_fedora/rdf_xml_writer.rb
|
592
593
|
- lib/active_fedora/reflection.rb
|
593
594
|
- lib/active_fedora/relationship.rb
|
594
595
|
- lib/active_fedora/relationships_helper.rb
|
@@ -707,6 +708,7 @@ files:
|
|
707
708
|
- spec/unit/nokogiri_datastream_spec.rb
|
708
709
|
- spec/unit/property_spec.rb
|
709
710
|
- spec/unit/qualified_dublin_core_datastream_spec.rb
|
711
|
+
- spec/unit/rdf_xml_writer.rb
|
710
712
|
- spec/unit/relationship_spec.rb
|
711
713
|
- spec/unit/relationships_helper_spec.rb
|
712
714
|
- spec/unit/rels_ext_datastream_spec.rb
|
@@ -843,6 +845,7 @@ test_files:
|
|
843
845
|
- spec/unit/nokogiri_datastream_spec.rb
|
844
846
|
- spec/unit/property_spec.rb
|
845
847
|
- spec/unit/qualified_dublin_core_datastream_spec.rb
|
848
|
+
- spec/unit/rdf_xml_writer.rb
|
846
849
|
- spec/unit/relationship_spec.rb
|
847
850
|
- spec/unit/relationships_helper_spec.rb
|
848
851
|
- spec/unit/rels_ext_datastream_spec.rb
|