oai 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/oai/client.rb +1 -2
- data/lib/oai/client/record.rb +2 -1
- data/lib/oai/client/response.rb +11 -16
- data/lib/oai/harvester.rb +1 -0
- data/lib/oai/harvester/harvest.rb +1 -1
- data/lib/oai/provider.rb +6 -1
- data/lib/oai/provider/model.rb +7 -1
- data/lib/oai/provider/model/activerecord_wrapper.rb +18 -2
- data/lib/oai/provider/response/get_record.rb +2 -1
- data/lib/oai/provider/response/identify.rb +12 -0
- data/lib/oai/provider/response/list_records.rb +1 -0
- data/lib/oai/provider/response/record_response.rb +15 -0
- data/test/client/tc_get_record.rb +2 -0
- data/test/provider/models.rb +9 -0
- data/test/provider/tc_provider.rb +7 -0
- data/test/provider/test_helper.rb +10 -1
- metadata +36 -4
data/lib/oai/client.rb
CHANGED
@@ -206,8 +206,7 @@ module OAI
|
|
206
206
|
case @parser
|
207
207
|
when 'libxml'
|
208
208
|
begin
|
209
|
-
parser = XML::Parser.
|
210
|
-
parser.string = xml
|
209
|
+
parser = XML::Parser.string()
|
211
210
|
return parser.parse
|
212
211
|
rescue XML::Parser::ParseError => e
|
213
212
|
raise OAI::Exception, 'response not well formed XML: '+e, caller
|
data/lib/oai/client/record.rb
CHANGED
@@ -10,11 +10,12 @@ module OAI
|
|
10
10
|
|
11
11
|
class Record
|
12
12
|
include OAI::XPath
|
13
|
-
attr_accessor :header, :metadata
|
13
|
+
attr_accessor :header, :metadata, :about
|
14
14
|
|
15
15
|
def initialize(element)
|
16
16
|
@header = OAI::Header.new xpath_first(element, './/header')
|
17
17
|
@metadata = xpath_first(element, './/metadata')
|
18
|
+
@about = xpath_first(element, './/about')
|
18
19
|
end
|
19
20
|
|
20
21
|
# a convenience method which digs into the header status attribute
|
data/lib/oai/client/response.rb
CHANGED
@@ -2,22 +2,17 @@ module OAI
|
|
2
2
|
|
3
3
|
# An OAI::Response contains entries and a resumption token. If a resumption token is present,
|
4
4
|
# then you must use it to fetch the rest of the entries for your query. For example:
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
# end
|
17
|
-
# rescue OAI::Exception => e
|
18
|
-
# puts 'No records to process'
|
19
|
-
# end
|
20
|
-
# puts "Done processing #{i} records"
|
5
|
+
# # List all records in a given set
|
6
|
+
# client = OAI::Client.new 'http://my-oai-provider.example.com/oai'
|
7
|
+
# response = client.list_records :set => 'my_set_name'
|
8
|
+
# while response.entries.count > 0
|
9
|
+
# response.entries.each { |entry|
|
10
|
+
# puts entry.header.identifier
|
11
|
+
# }
|
12
|
+
# token = response.resumption_token
|
13
|
+
# # Note: You do not need to pass the options hash again, just the verb and the resumption token
|
14
|
+
# response = client.list_records :resumption_token => token if token
|
15
|
+
# end
|
21
16
|
|
22
17
|
class Response
|
23
18
|
include OAI::XPath
|
data/lib/oai/harvester.rb
CHANGED
@@ -72,7 +72,7 @@ module OAI
|
|
72
72
|
|
73
73
|
file = Tempfile.new('oai_data')
|
74
74
|
gz = Zlib::GzipWriter.new(file)
|
75
|
-
gz << "<?
|
75
|
+
gz << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
|
76
76
|
gz << "<records>"
|
77
77
|
begin
|
78
78
|
response = client.list_records(options)
|
data/lib/oai/provider.rb
CHANGED
@@ -55,6 +55,7 @@ end
|
|
55
55
|
# repository_url 'http://localhost/provider'
|
56
56
|
# record_prefix 'oai:localhost'
|
57
57
|
# admin_email 'root@localhost'
|
58
|
+
# sample_identifier 'oai:pubmedcentral.gov:13900'
|
58
59
|
# source_model MyModel.new
|
59
60
|
# end
|
60
61
|
#
|
@@ -97,6 +98,7 @@ end
|
|
97
98
|
# record_prefix 'oai:blog'
|
98
99
|
# admin_email 'root@localhost'
|
99
100
|
# source_model OAI::Provider::ActiveRecordWrapper.new(Post)
|
101
|
+
# sample_identifier 'oai:pubmedcentral.gov:13900'
|
100
102
|
# end
|
101
103
|
#
|
102
104
|
# Create a custom controller:
|
@@ -184,7 +186,7 @@ module OAI::Provider
|
|
184
186
|
|
185
187
|
class << self
|
186
188
|
attr_reader :formats
|
187
|
-
attr_accessor :name, :url, :prefix, :email, :delete_support, :granularity, :model
|
189
|
+
attr_accessor :name, :url, :prefix, :email, :delete_support, :granularity, :model, :identifier, :description
|
188
190
|
|
189
191
|
def register_format(format)
|
190
192
|
@formats ||= {}
|
@@ -218,6 +220,8 @@ module OAI::Provider
|
|
218
220
|
alias_method :deletion_support, :delete_support=
|
219
221
|
alias_method :update_granularity, :granularity=
|
220
222
|
alias_method :source_model, :model=
|
223
|
+
alias_method :sample_id, :identifier=
|
224
|
+
alias_method :extra_description, :description=
|
221
225
|
|
222
226
|
end
|
223
227
|
|
@@ -228,6 +232,7 @@ module OAI::Provider
|
|
228
232
|
Base.admin_email 'nobody@localhost'
|
229
233
|
Base.deletion_support OAI::Const::Delete::TRANSIENT
|
230
234
|
Base.update_granularity OAI::Const::Granularity::HIGH
|
235
|
+
Base.sample_id '13900'
|
231
236
|
|
232
237
|
Base.register_format(OAI::Provider::Metadata::DublinCore.instance)
|
233
238
|
|
data/lib/oai/provider/model.rb
CHANGED
@@ -17,6 +17,8 @@ module OAI::Provider
|
|
17
17
|
# available_formats - if overridden, individual records should return an
|
18
18
|
# array of prefixes for all formats in which that record is available,
|
19
19
|
# if other than ["oai_dc"]
|
20
|
+
# about - if overridden, should return a String or Array of XML Strings to
|
21
|
+
# insert into the OAI Record <about> chunks.
|
20
22
|
#
|
21
23
|
# == Resumption Tokens
|
22
24
|
#
|
@@ -68,7 +70,11 @@ module OAI::Provider
|
|
68
70
|
def deleted?
|
69
71
|
false
|
70
72
|
end
|
71
|
-
|
73
|
+
|
74
|
+
# can return a String or Array of XML Strings add as OAI Record <about> chunks.
|
75
|
+
def about record
|
76
|
+
nil
|
77
|
+
end
|
72
78
|
end
|
73
79
|
|
74
80
|
end
|
@@ -24,7 +24,7 @@ module OAI::Provider
|
|
24
24
|
)
|
25
25
|
end
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
def earliest
|
29
29
|
model.find(:first,
|
30
30
|
:order => "#{timestamp_field} asc").send(timestamp_field)
|
@@ -65,6 +65,22 @@ module OAI::Provider
|
|
65
65
|
false
|
66
66
|
end
|
67
67
|
|
68
|
+
def respond_to?(m, *args)
|
69
|
+
if m =~ /^map_/
|
70
|
+
model.respond_to?(m, *args)
|
71
|
+
else
|
72
|
+
super
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def method_missing(m, *args, &block)
|
77
|
+
if m =~ /^map_/
|
78
|
+
model.send(m, *args, &block)
|
79
|
+
else
|
80
|
+
super
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
68
84
|
protected
|
69
85
|
|
70
86
|
# Request the next set in this sequence.
|
@@ -120,7 +136,7 @@ module OAI::Provider
|
|
120
136
|
sql << "#{timestamp_field} >= ?" << "#{timestamp_field} <= ?"
|
121
137
|
sql << "set = ?" if opts[:set]
|
122
138
|
esc_values = [sql.join(" AND ")]
|
123
|
-
esc_values << Time.parse(opts[:from]).localtime << Time.parse(opts[:until]).localtime #-- OAI 2.0 hack - UTC fix from record_responce
|
139
|
+
esc_values << Time.parse(opts[:from].to_s).localtime << Time.parse(opts[:until].to_s).localtime.to_s #-- OAI 2.0 hack - UTC fix from record_responce
|
124
140
|
esc_values << opts[:set] if opts[:set]
|
125
141
|
|
126
142
|
return esc_values
|
@@ -16,7 +16,19 @@ module OAI::Provider::Response
|
|
16
16
|
r.earliestDatestamp Time.parse(provider.model.earliest.to_s).utc.xmlschema
|
17
17
|
r.deletedRecord provider.delete_support.to_s
|
18
18
|
r.granularity provider.granularity
|
19
|
+
r.description do
|
20
|
+
r.tag! 'oai-identifier', 'xmlns' => 'http://www.openarchives.org/OAI/2.0/oai-identifier', 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xsi:schemaLocation' => 'http://www.openarchives.org/OAI/2.0/oai-identifier http://www.openarchives.org/OAI/2.0/oai-identifier.xsd' do
|
21
|
+
r.scheme 'oai'
|
22
|
+
r.repositoryIdentifier provider.prefix.gsub(/oai:/, '')
|
23
|
+
r.delimiter ':'
|
24
|
+
r.sampleIdentifier "#{provider.prefix}:#{provider.identifier}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
if provider.description
|
28
|
+
r.target! << provider.description
|
29
|
+
end
|
19
30
|
end
|
31
|
+
|
20
32
|
end
|
21
33
|
end
|
22
34
|
|
@@ -26,6 +26,21 @@ module OAI::Provider::Response
|
|
26
26
|
@builder.target! << provider.format(requested_format).encode(provider.model, record)
|
27
27
|
end
|
28
28
|
end
|
29
|
+
|
30
|
+
# about - core routine for delivering about records
|
31
|
+
#
|
32
|
+
def about_for(record)
|
33
|
+
return unless provider.model.respond_to? :about
|
34
|
+
|
35
|
+
about = provider.model.about(record)
|
36
|
+
return if about.nil?
|
37
|
+
|
38
|
+
Array(about).each do |a|
|
39
|
+
@builder.about do
|
40
|
+
@builder.target! << a
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
29
44
|
|
30
45
|
private
|
31
46
|
|
@@ -9,6 +9,7 @@ class GetRecordTest < Test::Unit::TestCase
|
|
9
9
|
assert_kind_of OAI::Record, response.record
|
10
10
|
assert_kind_of REXML::Element, response.record.metadata
|
11
11
|
assert_kind_of OAI::Header, response.record.header
|
12
|
+
assert_kind_of REXML::Element, response.record.about
|
12
13
|
|
13
14
|
# minimal check that the header is working
|
14
15
|
assert_equal 'oai:test/3',
|
@@ -16,6 +17,7 @@ class GetRecordTest < Test::Unit::TestCase
|
|
16
17
|
|
17
18
|
# minimal check that the metadata is working
|
18
19
|
#assert 'en', response.record.metadata.elements['.//dc:language'].text
|
20
|
+
assert_equal 'Ruby OAI test data', response.record.about.elements['.//dc:publisher'].text
|
19
21
|
end
|
20
22
|
|
21
23
|
def test_missing_identifier
|
data/test/provider/models.rb
CHANGED
@@ -231,5 +231,14 @@ class ComplexModel < TestModel
|
|
231
231
|
generate_records(250, Time.parse("December 25 2005"), [set_four, set_three_four])
|
232
232
|
end
|
233
233
|
|
234
|
+
def about record
|
235
|
+
<<-eos
|
236
|
+
<oai_dc:dc
|
237
|
+
xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/"
|
238
|
+
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
239
|
+
<dc:publisher>Ruby OAI test data</dc:publisher>
|
240
|
+
</oai_dc:dc>
|
241
|
+
eos
|
242
|
+
end
|
234
243
|
end
|
235
244
|
|
@@ -5,6 +5,13 @@ class OaiTest < Test::Unit::TestCase
|
|
5
5
|
def setup
|
6
6
|
@mapped_provider = MappedProvider.new
|
7
7
|
@big_provider = BigProvider.new
|
8
|
+
@described_provider = DescribedProvider.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_additional_description
|
12
|
+
doc = REXML::Document.new(@described_provider.identify)
|
13
|
+
assert_equal "oai:test:13900", doc.elements['OAI-PMH/Identify/description/oai-identifier/sampleIdentifier'].text
|
14
|
+
assert_not_nil doc.elements['OAI-PMH/Identify/my_custom_xml']
|
8
15
|
end
|
9
16
|
|
10
17
|
def test_list_identifiers_for_correct_xml
|
@@ -33,4 +33,13 @@ class ComplexProvider < Provider::Base
|
|
33
33
|
repository_url 'http://localhost'
|
34
34
|
record_prefix 'oai:test'
|
35
35
|
source_model ComplexModel.new(100)
|
36
|
-
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class DescribedProvider < Provider::Base
|
39
|
+
repository_name 'Described PRovider'
|
40
|
+
repository_url 'http://localhost'
|
41
|
+
record_prefix 'oai:test'
|
42
|
+
source_model SimpleModel.new
|
43
|
+
sample_id '13900'
|
44
|
+
extra_description "<my_custom_xml />"
|
45
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oai
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire: oai
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-07-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: builder
|
@@ -75,6 +75,38 @@ dependencies:
|
|
75
75
|
- - ! '>='
|
76
76
|
- !ruby/object:Gem::Version
|
77
77
|
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: activerecord
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: sqlite3
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
78
110
|
- !ruby/object:Gem::Dependency
|
79
111
|
name: rdoc
|
80
112
|
requirement: !ruby/object:Gem::Requirement
|
@@ -195,7 +227,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
195
227
|
version: '0'
|
196
228
|
segments:
|
197
229
|
- 0
|
198
|
-
hash:
|
230
|
+
hash: 1810922164571931912
|
199
231
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
200
232
|
none: false
|
201
233
|
requirements:
|
@@ -204,7 +236,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
204
236
|
version: '0'
|
205
237
|
segments:
|
206
238
|
- 0
|
207
|
-
hash:
|
239
|
+
hash: 1810922164571931912
|
208
240
|
requirements: []
|
209
241
|
rubyforge_project:
|
210
242
|
rubygems_version: 1.8.24
|