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 CHANGED
@@ -206,8 +206,7 @@ module OAI
206
206
  case @parser
207
207
  when 'libxml'
208
208
  begin
209
- parser = XML::Parser.new()
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
@@ -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
@@ -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
- # # List all records
6
- # i = 1
7
- # begin
8
- # response = client.list_records
9
- # while response.entries.size > 0
10
- # response.entries.each { |entry|
11
- # puts "<b>#{i}</b> #{entry.header.identifier}<br/>"
12
- # i +=1
13
- # }
14
- # token = response.resumption_token
15
- # response = client.list_records :resumption_token => token if token
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
@@ -1,3 +1,4 @@
1
+ require 'time'
1
2
  require 'zlib'
2
3
  require 'net/smtp'
3
4
  require 'yaml'
@@ -72,7 +72,7 @@ module OAI
72
72
 
73
73
  file = Tempfile.new('oai_data')
74
74
  gz = Zlib::GzipWriter.new(file)
75
- gz << "<? xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
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
 
@@ -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
@@ -14,6 +14,7 @@ module OAI::Provider::Response
14
14
  r.record do
15
15
  header_for record
16
16
  data_for record unless deleted?(record)
17
+ about_for record unless deleted?(record)
17
18
  end
18
19
  end
19
20
  end
@@ -23,4 +24,4 @@ module OAI::Provider::Response
23
24
 
24
25
  end
25
26
 
26
-
27
+
@@ -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
 
@@ -15,6 +15,7 @@ module OAI::Provider::Response
15
15
  r.record do
16
16
  header_for rec
17
17
  data_for rec unless deleted?(rec)
18
+ about_for rec unless deleted?(rec)
18
19
  end
19
20
  end
20
21
 
@@ -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
@@ -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.1.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-06-01 00:00:00.000000000 Z
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: -1260822851612593558
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: -1260822851612593558
239
+ hash: 1810922164571931912
208
240
  requirements: []
209
241
  rubyforge_project:
210
242
  rubygems_version: 1.8.24