active-fedora 7.0.0.rc1 → 7.0.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/active_fedora/attributes.rb +15 -20
- data/lib/active_fedora/datastream.rb +9 -4
- data/lib/active_fedora/datastream_attribute.rb +33 -38
- data/lib/active_fedora/datastream_hash.rb +2 -2
- data/lib/active_fedora/datastreams.rb +43 -31
- data/lib/active_fedora/datastreams/nokogiri_datastreams.rb +146 -0
- data/lib/active_fedora/digital_object.rb +2 -2
- data/lib/active_fedora/indexing.rb +1 -1
- data/lib/active_fedora/nom_datastream.rb +7 -23
- data/lib/active_fedora/om_datastream.rb +3 -130
- data/lib/active_fedora/rdf_datastream.rb +4 -0
- data/lib/active_fedora/rdf_node.rb +1 -0
- data/lib/active_fedora/rdf_object.rb +1 -7
- data/lib/active_fedora/relation.rb +0 -29
- data/lib/active_fedora/relation/query_methods.rb +36 -0
- data/lib/active_fedora/simple_datastream.rb +1 -0
- data/lib/active_fedora/version.rb +1 -1
- data/spec/integration/base_spec.rb +2 -1
- data/spec/integration/om_datastream_spec.rb +2 -2
- data/spec/integration/scoped_query_spec.rb +13 -0
- data/spec/samples/hydra-mods_article_datastream.rb +1 -1
- data/spec/unit/datastream_spec.rb +0 -41
- data/spec/unit/datastreams_spec.rb +3 -3
- data/spec/unit/om_datastream_spec.rb +4 -1
- metadata +44 -43
@@ -4,10 +4,10 @@ module ActiveFedora
|
|
4
4
|
attr_accessor :original_class
|
5
5
|
|
6
6
|
module DatastreamBootstrap
|
7
|
-
def datastream_object_for dsid, ds_spec=nil
|
7
|
+
def datastream_object_for dsid, options={}, ds_spec=nil
|
8
8
|
# ds_spec is nil when called from Rubydora for existing datastreams, so it should not be autocreated
|
9
9
|
ds_spec ||= (original_class.ds_specs[dsid] || {}).merge(:autocreate=>false)
|
10
|
-
ds = ds_spec.fetch(:type, ActiveFedora::Datastream).new(self, dsid)
|
10
|
+
ds = ds_spec.fetch(:type, ActiveFedora::Datastream).new(self, dsid, options)
|
11
11
|
attributes = {}
|
12
12
|
attributes[:asOfDateTime] ||= asOfDateTime if self.respond_to? :asOfDateTime
|
13
13
|
attributes[:dsLabel] = ds_spec[:label] if ds_spec[:label].present?
|
@@ -2,6 +2,9 @@ require "nom"
|
|
2
2
|
|
3
3
|
module ActiveFedora
|
4
4
|
class NomDatastream < Datastream
|
5
|
+
|
6
|
+
include Datastreams::NokogiriDatastreams
|
7
|
+
|
5
8
|
def self.set_terminology(options = {}, &block)
|
6
9
|
@terminology_options = options || {}
|
7
10
|
@terminology = block
|
@@ -29,35 +32,16 @@ module ActiveFedora
|
|
29
32
|
ds
|
30
33
|
end
|
31
34
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
xml.nom!
|
37
|
-
xml
|
38
|
-
end
|
35
|
+
def self.decorate_ng_xml(xml)
|
36
|
+
xml.set_terminology terminology_options, &terminology
|
37
|
+
xml.nom!
|
38
|
+
xml
|
39
39
|
end
|
40
40
|
|
41
|
-
def ng_xml= ng_xml
|
42
|
-
@ng_xml = ng_xml
|
43
|
-
@ng_xml.set_terminology self.class.terminology_options, &self.class.terminology
|
44
|
-
content_will_change!
|
45
|
-
@ng_xml
|
46
|
-
end
|
47
|
-
|
48
41
|
def serialize!
|
49
42
|
self.content = @ng_xml.to_s if @ng_xml
|
50
43
|
end
|
51
44
|
|
52
|
-
def content
|
53
|
-
@content || super
|
54
|
-
end
|
55
|
-
|
56
|
-
def content=(content)
|
57
|
-
super
|
58
|
-
@ng_xml = nil
|
59
|
-
end
|
60
|
-
|
61
45
|
def to_solr
|
62
46
|
solr_doc = {}
|
63
47
|
|
@@ -12,7 +12,8 @@ module ActiveFedora
|
|
12
12
|
|
13
13
|
include OM::XML::Document
|
14
14
|
include OM::XML::TerminologyBasedSolrizer # this adds support for calling .to_solr
|
15
|
-
|
15
|
+
include Datastreams::NokogiriDatastreams
|
16
|
+
|
16
17
|
alias_method(:om_term_values, :term_values) unless method_defined?(:om_term_values)
|
17
18
|
alias_method(:om_update_values, :update_values) unless method_defined?(:om_update_values)
|
18
19
|
|
@@ -22,136 +23,12 @@ module ActiveFedora
|
|
22
23
|
super.merge(:controlGroup => 'M', :mimeType => 'text/xml')
|
23
24
|
end
|
24
25
|
|
25
|
-
# Create an instance of this class based on xml content
|
26
|
-
# @param [String, File, Nokogiri::XML::Node] xml the xml content to build from
|
27
|
-
# @param [ActiveFedora::OmDatastream] tmpl the Datastream object that you are building @default a new instance of this class
|
28
|
-
# Careful! If you call this from a constructor, be sure to provide something 'ie. self' as the @tmpl. Otherwise, you will get an infinite loop!
|
29
|
-
def self.from_xml(xml, tmpl=nil)
|
30
|
-
tmpl = self.new if tmpl.nil? ## This path is used only for unit testing (e.g. MarpaDCDatastream.from_xml(fixture("data.xml")) )
|
31
|
-
|
32
|
-
if !xml.present?
|
33
|
-
tmpl.ng_xml = self.xml_template
|
34
|
-
elsif xml.kind_of? Nokogiri::XML::Node || xml.kind_of?(Nokogiri::XML::Document)
|
35
|
-
tmpl.ng_xml = xml
|
36
|
-
else
|
37
|
-
tmpl.ng_xml = Nokogiri::XML::Document.parse(xml)
|
38
|
-
end
|
39
|
-
|
40
|
-
tmpl.ng_xml_doesnt_change!
|
41
|
-
|
42
|
-
return tmpl
|
43
|
-
end
|
44
|
-
|
45
|
-
def self.xml_template
|
46
|
-
Nokogiri::XML::Document.parse("<xml/>")
|
47
|
-
end
|
48
|
-
|
49
|
-
def ng_xml
|
50
|
-
@ng_xml ||= begin
|
51
|
-
if new?
|
52
|
-
## Load up the template
|
53
|
-
self.class.xml_template
|
54
|
-
else
|
55
|
-
Nokogiri::XML::Document.parse(datastream_content)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def ng_xml=(new_xml)
|
61
|
-
# before we set ng_xml, we load the datastream so we know if the new value differs.
|
62
|
-
local_or_remote_content(true)
|
63
|
-
|
64
|
-
case new_xml
|
65
|
-
when Nokogiri::XML::Document
|
66
|
-
self.content=new_xml.to_xml
|
67
|
-
when Nokogiri::XML::Node
|
68
|
-
## Cast a fragment to a document
|
69
|
-
self.content=new_xml.to_s
|
70
|
-
when String
|
71
|
-
self.content=new_xml
|
72
|
-
else
|
73
|
-
raise TypeError, "You passed a #{new_xml.class} into the ng_xml of the #{self.dsid} datastream. OmDatastream.ng_xml= only accepts Nokogiri::XML::Document, Nokogiri::XML::Element, Nokogiri::XML::Node, or raw XML (String) as inputs."
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
# don't want content eagerly loaded by proxy, so implementing methods that would be implemented by define_attribute_methods
|
78
|
-
def ng_xml_will_change!
|
79
|
-
changed_attributes['ng_xml'] = nil
|
80
|
-
end
|
81
|
-
|
82
|
-
def ng_xml_doesnt_change!
|
83
|
-
changed_attributes.delete('ng_xml')
|
84
|
-
end
|
85
|
-
|
86
|
-
# don't want content eagerly loaded by proxy, so implementing methods that would be implemented by define_attribute_methods
|
87
|
-
def ng_xml_changed?
|
88
|
-
changed_attributes.has_key? 'ng_xml'
|
89
|
-
end
|
90
|
-
|
91
26
|
# Indicates that this datastream has metadata content.
|
92
27
|
# @return true
|
93
28
|
def metadata?
|
94
29
|
true
|
95
30
|
end
|
96
31
|
|
97
|
-
def local_or_remote_content(ensure_fetch = true)
|
98
|
-
@content = to_xml if ng_xml_changed? || autocreate?
|
99
|
-
super
|
100
|
-
end
|
101
|
-
|
102
|
-
def autocreate?
|
103
|
-
changed_attributes.has_key? :profile
|
104
|
-
end
|
105
|
-
|
106
|
-
def datastream_content
|
107
|
-
@datastream_content ||= Nokogiri::XML(super).to_xml {|config| config.no_declaration}.strip
|
108
|
-
end
|
109
|
-
|
110
|
-
def content=(new_content)
|
111
|
-
if inline?
|
112
|
-
# inline datastreams may be transformed by fedora 3, so we test for equivalence instead of equality
|
113
|
-
if !EquivalentXml.equivalent?(datastream_content, new_content)
|
114
|
-
ng_xml_will_change!
|
115
|
-
@ng_xml = Nokogiri::XML::Document.parse(new_content)
|
116
|
-
super(@ng_xml.to_s)
|
117
|
-
end
|
118
|
-
else
|
119
|
-
if datastream_content != new_content
|
120
|
-
ng_xml_will_change!
|
121
|
-
@ng_xml = Nokogiri::XML::Document.parse(new_content)
|
122
|
-
super(@ng_xml.to_s)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
def content_changed?
|
128
|
-
return false if !xml_loaded
|
129
|
-
super
|
130
|
-
end
|
131
|
-
|
132
|
-
def to_xml(xml = nil)
|
133
|
-
xml = self.ng_xml if xml.nil?
|
134
|
-
ng_xml = self.ng_xml
|
135
|
-
if ng_xml.respond_to?(:root) && ng_xml.root.nil? && self.class.respond_to?(:root_property_ref) && !self.class.root_property_ref.nil?
|
136
|
-
ng_xml = self.class.generate(self.class.root_property_ref, "")
|
137
|
-
if xml.root.nil?
|
138
|
-
xml = ng_xml
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
unless xml == ng_xml || ng_xml.root.nil?
|
143
|
-
if xml.kind_of?(Nokogiri::XML::Document)
|
144
|
-
xml.root.add_child(ng_xml.root)
|
145
|
-
elsif xml.kind_of?(Nokogiri::XML::Node)
|
146
|
-
xml.add_child(ng_xml.root)
|
147
|
-
else
|
148
|
-
raise "You can only pass instances of Nokogiri::XML::Node into this method. You passed in #{xml}"
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
return xml.to_xml {|config| config.no_declaration}.strip
|
153
|
-
end
|
154
|
-
|
155
32
|
# ** Experimental **
|
156
33
|
#
|
157
34
|
# This method is called by ActiveFedora::Base.load_instance_from_solr
|
@@ -172,7 +49,7 @@ module ActiveFedora
|
|
172
49
|
# value returned by the +prefix+ method.
|
173
50
|
def to_solr(solr_doc = {})
|
174
51
|
prefix = self.prefix
|
175
|
-
super.each_with_object({}) { |(key, value), new| new[[prefix,key].join] = value }
|
52
|
+
solr_doc.merge super({}).each_with_object({}) { |(key, value), new| new[[prefix,key].join] = value }
|
176
53
|
end
|
177
54
|
|
178
55
|
|
@@ -422,9 +299,5 @@ module ActiveFedora
|
|
422
299
|
end
|
423
300
|
end
|
424
301
|
|
425
|
-
def xml_loaded
|
426
|
-
instance_variable_defined? :@ng_xml
|
427
|
-
end
|
428
|
-
|
429
302
|
end
|
430
303
|
end
|
@@ -7,13 +7,7 @@ module ActiveFedora
|
|
7
7
|
attr_reader :rdf_subject, :graph
|
8
8
|
end
|
9
9
|
|
10
|
-
def graph
|
11
|
-
@graph ||= RDF::Graph.new
|
12
|
-
@graph
|
13
|
-
end
|
14
|
-
|
15
|
-
|
16
|
-
def initialize(graph, subject=nil)
|
10
|
+
def initialize(graph = RDF::Graph.new, subject=nil)
|
17
11
|
subject ||= RDF::Node.new
|
18
12
|
@graph = graph
|
19
13
|
@rdf_subject = subject
|
@@ -50,35 +50,6 @@ module ActiveFedora
|
|
50
50
|
self
|
51
51
|
end
|
52
52
|
|
53
|
-
# Limits the returned records to those that match the provided search conditions
|
54
|
-
#
|
55
|
-
# @option [Hash] opts a hash of solr conditions
|
56
|
-
#
|
57
|
-
# @example
|
58
|
-
# Person.where(name_t: 'Mario', occupation_s: 'Plumber')
|
59
|
-
# => [#<Person @id="foo:123" @name='Mario'>, #<Person @id="foo:125" @name='Mario'>, ...]
|
60
|
-
def where(opts)
|
61
|
-
return self if opts.blank?
|
62
|
-
relation = clone
|
63
|
-
relation.where_values = opts
|
64
|
-
relation
|
65
|
-
end
|
66
|
-
|
67
|
-
# Order the returned records by the field and direction provided
|
68
|
-
#
|
69
|
-
# @option [Array<String>] args a list of fields and directions to sort by
|
70
|
-
#
|
71
|
-
# @example
|
72
|
-
# Person.where(occupation_s: 'Plumber').order('name_t desc', 'color_t asc')
|
73
|
-
# => [#<Person @id="foo:123" @name='Luigi'>, #<Person @id="foo:125" @name='Mario'>, ...]
|
74
|
-
def order(*args)
|
75
|
-
return self if args.blank?
|
76
|
-
|
77
|
-
relation = clone
|
78
|
-
relation.order_values += args.flatten
|
79
|
-
relation
|
80
|
-
end
|
81
|
-
|
82
53
|
def to_a
|
83
54
|
return @records if loaded?
|
84
55
|
args = @klass == ActiveFedora::Base ? {:cast=>true} : {}
|
@@ -37,6 +37,42 @@ module ActiveFedora
|
|
37
37
|
@values[:limit] = value
|
38
38
|
end
|
39
39
|
|
40
|
+
# Limits the returned records to those that match the provided search conditions
|
41
|
+
#
|
42
|
+
# @option [Hash] opts a hash of solr conditions
|
43
|
+
#
|
44
|
+
# @example
|
45
|
+
# Person.where(name_t: 'Mario', occupation_s: 'Plumber')
|
46
|
+
# => [#<Person @id="foo:123" @name='Mario'>, #<Person @id="foo:125" @name='Mario'>, ...]
|
47
|
+
def where(values)
|
48
|
+
spawn.where!(values)
|
49
|
+
end
|
50
|
+
|
51
|
+
def where!(values)
|
52
|
+
if values.is_a?(String)
|
53
|
+
self.where_values = values
|
54
|
+
else
|
55
|
+
self.where_values = self.where_values.merge(values)
|
56
|
+
end
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
# Order the returned records by the field and direction provided
|
61
|
+
#
|
62
|
+
# @option [Array<String>] args a list of fields and directions to sort by
|
63
|
+
#
|
64
|
+
# @example
|
65
|
+
# Person.where(occupation_s: 'Plumber').order('name_t desc', 'color_t asc')
|
66
|
+
# => [#<Person @id="foo:123" @name='Luigi'>, #<Person @id="foo:125" @name='Mario'>, ...]
|
67
|
+
def order(*args)
|
68
|
+
spawn.order!(args)
|
69
|
+
end
|
70
|
+
|
71
|
+
def order!(*args)
|
72
|
+
self.order_values += args.flatten
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
40
76
|
# Limits the number of returned records to the value specified
|
41
77
|
#
|
42
78
|
# @option [Integer] value the number of records to return
|
@@ -21,7 +21,8 @@ describe "A base object with metadata" do
|
|
21
21
|
obj.foo.should_not be_new
|
22
22
|
obj.foo.person.should == ['bob']
|
23
23
|
person_field = ActiveFedora::SolrService.solr_name('person', type: :string)
|
24
|
-
ActiveFedora::SolrService.query("{!raw f=id}#{@obj.pid}", :fl=>"id #{person_field}").first
|
24
|
+
solr_result = ActiveFedora::SolrService.query("{!raw f=id}#{@obj.pid}", :fl=>"id #{person_field}").first
|
25
|
+
expect(solr_result).to eq("id"=>@obj.pid, person_field =>['bob'])
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
@@ -7,7 +7,7 @@ describe ActiveFedora::OmDatastream do
|
|
7
7
|
before(:all) do
|
8
8
|
class ModsArticle3 < ActiveFedora::Base
|
9
9
|
# Uses the Hydra MODS Article profile for tracking most of the descriptive metadata
|
10
|
-
has_metadata
|
10
|
+
has_metadata "descMetadata", type: Hydra::ModsArticleDatastream, control_group: 'X', autocreate: true
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
@@ -56,7 +56,7 @@ describe ActiveFedora::OmDatastream do
|
|
56
56
|
before(:all) do
|
57
57
|
class ModsArticle2 < ActiveFedora::Base
|
58
58
|
# Uses the Hydra MODS Article profile for tracking most of the descriptive metadata
|
59
|
-
has_metadata
|
59
|
+
has_metadata "descMetadata", type: Hydra::ModsArticleDatastream, autocreate: true
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -81,6 +81,10 @@ describe "scoped queries" do
|
|
81
81
|
ModelIntegrationSpec::Basic.where(ActiveFedora::SolrService.solr_name('bar', type: :string) => 'Peanuts').order(ActiveFedora::SolrService.solr_name('foo', :sortable) + ' asc').limit(1).should == [test_instance2]
|
82
82
|
end
|
83
83
|
|
84
|
+
it "should chain where queries" do
|
85
|
+
ModelIntegrationSpec::Basic.where(ActiveFedora::SolrService.solr_name('bar', type: :string) => 'Peanuts').where(ActiveFedora::SolrService.solr_name('foo', type: :string) => 'bar').where_values.should == {ActiveFedora::SolrService.solr_name('bar', type: :string) => 'Peanuts', ActiveFedora::SolrService.solr_name('foo', type: :string) => 'bar'}
|
86
|
+
end
|
87
|
+
|
84
88
|
it "should chain count" do
|
85
89
|
ModelIntegrationSpec::Basic.where(ActiveFedora::SolrService.solr_name('bar', type: :string) => 'Peanuts').count.should == 2
|
86
90
|
end
|
@@ -90,6 +94,15 @@ describe "scoped queries" do
|
|
90
94
|
expect {relation.first}.not_to change {relation.to_a.size}
|
91
95
|
end
|
92
96
|
|
97
|
+
it "calling where should not affect the relation's ability to get all results later" do
|
98
|
+
relation = ModelIntegrationSpec::Basic.where(ActiveFedora::SolrService.solr_name('bar', type: :string) => 'Peanuts')
|
99
|
+
expect {relation.where(ActiveFedora::SolrService.solr_name('foo', type: :string) => 'bar')}.not_to change {relation.to_a.size}
|
100
|
+
end
|
101
|
+
|
102
|
+
it "calling order should not affect the original order of the relation later" do
|
103
|
+
relation = ModelIntegrationSpec::Basic.order(ActiveFedora::SolrService.solr_name('foo', :sortable) + ' asc')
|
104
|
+
expect {relation.order(ActiveFedora::SolrService.solr_name('foo', :sortable) + ' desc')}.not_to change {relation.to_a}
|
105
|
+
end
|
93
106
|
end
|
94
107
|
|
95
108
|
describe "when one of the objects in solr isn't in fedora" do
|
@@ -506,7 +506,7 @@ module Hydra
|
|
506
506
|
end
|
507
507
|
|
508
508
|
def to_solr(solr_doc=Hash.new)
|
509
|
-
super(solr_doc)
|
509
|
+
solr_doc = super(solr_doc)
|
510
510
|
|
511
511
|
::Solrizer::Extractor.insert_solr_field_value(solr_doc, Solrizer.default_field_mapper.solr_name('object_type', :facetable), "Article")
|
512
512
|
::Solrizer::Extractor.insert_solr_field_value(solr_doc, Solrizer.default_field_mapper.solr_name('mods_journal_title_info', :facetable), "Unknown") if solr_doc["mods_journal_title_info_facet"].nil?
|
@@ -19,47 +19,6 @@ describe ActiveFedora::Datastream do
|
|
19
19
|
@test_datastream.inspect.should match /#<ActiveFedora::Datastream @pid=\"\" @dsid=\"abcd\" @controlGroup=\"M\" changed=\"true\" @mimeType=\"\" >/
|
20
20
|
end
|
21
21
|
|
22
|
-
describe '#validate_content_present' do
|
23
|
-
before :each do
|
24
|
-
@test_datastream.content = nil
|
25
|
-
@test_datastream.dsLocation = nil
|
26
|
-
end
|
27
|
-
|
28
|
-
it "should expect content on an Inline (X) datastream" do
|
29
|
-
@test_datastream.controlGroup = 'X'
|
30
|
-
@test_datastream.dsLocation = "http://example.com/test/content/abcd"
|
31
|
-
@test_datastream.validate_content_present.should be_false
|
32
|
-
@test_datastream.content = "<foo><xmlelement/></foo>"
|
33
|
-
@test_datastream.validate_content_present.should be_true
|
34
|
-
end
|
35
|
-
|
36
|
-
it "should expect content on a Managed (M) datastream" do
|
37
|
-
@test_datastream.controlGroup = 'M'
|
38
|
-
@test_datastream.dsLocation = "http://example.com/test/content/abcd"
|
39
|
-
@test_datastream.validate_content_present.should be_false
|
40
|
-
@test_datastream.content = "<foo><xmlelement/></foo>"
|
41
|
-
@test_datastream.validate_content_present.should be_true
|
42
|
-
@test_datastream.should_not be_external
|
43
|
-
end
|
44
|
-
|
45
|
-
it "should expect a dsLocation on an External (E) datastream" do
|
46
|
-
@test_datastream.controlGroup = 'E'
|
47
|
-
@test_datastream.content = "<foo><xmlelement/></foo>"
|
48
|
-
@test_datastream.validate_content_present.should be_false
|
49
|
-
@test_datastream.dsLocation = "http://example.com/test/content/abcd"
|
50
|
-
@test_datastream.validate_content_present.should be_true
|
51
|
-
@test_datastream.should be_external
|
52
|
-
end
|
53
|
-
|
54
|
-
it "should expect a dsLocation on a Redirect (R) datastream" do
|
55
|
-
@test_datastream.controlGroup = 'R'
|
56
|
-
@test_datastream.content = "<foo><xmlelement/></foo>"
|
57
|
-
@test_datastream.validate_content_present.should be_false
|
58
|
-
@test_datastream.dsLocation = "http://example.com/test/content/abcd"
|
59
|
-
@test_datastream.validate_content_present.should be_true
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
22
|
it "should have mimeType accessors" do
|
64
23
|
ds1 = ActiveFedora::Datastream.new
|
65
24
|
ds1.mimeType = "text/foo"
|