Skip to content

Commit 0b5e851

Browse files
committed
Adding :full and ResumptionWrapper, to allow seamless use of resumption tokens.
1 parent 1354522 commit 0b5e851

File tree

9 files changed

+123
-22
lines changed

9 files changed

+123
-22
lines changed

lib/oai/client.rb

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
require 'oai/client/record'
1919
require 'oai/client/identify'
2020
require 'oai/client/get_record'
21+
require 'oai/client/resumable'
2122
require 'oai/client/list_identifiers'
2223
require 'oai/client/list_metadata_formats'
2324
require 'oai/client/list_records'
@@ -118,30 +119,30 @@ def initialize(base_url, options={})
118119
# parser then you will get an XML::Node object instead.
119120

120121
def identify
121-
return OAI::IdentifyResponse.new(do_request('Identify'))
122+
OAI::IdentifyResponse.new(do_request('Identify'))
122123
end
123124

124125
# Equivalent to a ListMetadataFormats request. A ListMetadataFormatsResponse
125126
# object is returned to you.
126127

127128
def list_metadata_formats(opts={})
128-
return OAI::ListMetadataFormatsResponse.new(do_request('ListMetadataFormats', opts))
129+
OAI::ListMetadataFormatsResponse.new(do_request('ListMetadataFormats', opts))
129130
end
130131

131132
# Equivalent to a ListIdentifiers request. Pass in :from, :until arguments
132133
# as Date or DateTime objects as appropriate depending on the granularity
133134
# supported by the server.
134135

135136
def list_identifiers(opts={})
136-
return OAI::ListIdentifiersResponse.new(do_request('ListIdentifiers', opts))
137+
do_resumable(OAI::ListIdentifiersResponse, 'ListIdentifiers', opts)
137138
end
138139

139140
# Equivalent to a GetRecord request. You must supply an identifier
140141
# argument. You should get back a OAI::GetRecordResponse object
141142
# which you can extract a OAI::Record object from.
142143

143144
def get_record(opts={})
144-
return OAI::GetRecordResponse.new(do_request('GetRecord', opts))
145+
OAI::GetRecordResponse.new(do_request('GetRecord', opts))
145146
end
146147

147148
# Equivalent to the ListRecords request. A ListRecordsResponse
@@ -152,7 +153,7 @@ def get_record(opts={})
152153
# end
153154

154155
def list_records(opts={})
155-
return OAI::ListRecordsResponse.new(do_request('ListRecords', opts))
156+
do_resumable(OAI::ListRecordsResponse, 'ListRecords', opts)
156157
end
157158

158159
# Equivalent to the ListSets request. A ListSetsResponse object
@@ -164,7 +165,7 @@ def list_records(opts={})
164165
# end
165166

166167
def list_sets(opts={})
167-
return OAI::ListSetsResponse.new(do_request('ListSets', opts))
168+
do_resumable(OAI::ListSetsResponse, 'ListSets', opts)
168169
end
169170

170171
private
@@ -183,6 +184,13 @@ def do_request(verb, opts = nil)
183184
return load_document(xml)
184185
end
185186

187+
def do_resumable(responseClass, verb, opts)
188+
responseClass.new(do_request(verb, opts)) do |response|
189+
responseClass.new \
190+
do_request(verb, :resumption_token => response.resumption_token)
191+
end
192+
end
193+
186194
def build_uri(verb, opts)
187195
opts = validate_options(verb, opts)
188196
uri = @base.clone

lib/oai/client/list_identifiers.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module OAI
22
class ListIdentifiersResponse < Response
33
include Enumerable
4+
include OAI::Resumable
45
include OAI::XPath
56

67
def each

lib/oai/client/list_records.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ module OAI
77
# end
88
#
99
# you'll need to handle resumption tokens
10-
10+
1111
class ListRecordsResponse < Response
12-
include OAI::XPath
1312
include Enumerable
13+
include OAI::Resumable
14+
include OAI::XPath
1415

1516
def each
1617
for record_element in xpath_all(@doc, './/ListRecords/record')

lib/oai/client/list_sets.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ module OAI
55
# for set in client.list_sets
66
# puts set
77
# end
8-
8+
99
class ListSetsResponse < Response
10-
include OAI::XPath
1110
include Enumerable
11+
include OAI::Resumable
12+
include OAI::XPath
1213

1314
def each
1415
for set_element in xpath_all(@doc, './/set')

lib/oai/client/response.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module OAI
22

3-
# An OAI::Response contains entries and a resumption token. If a resumption token is present,
3+
# An OAI::Response contains entries and a resumption token. If a resumption token is present,
44
# then you must use it to fetch the rest of the entries for your query. For example:
55
# # List all records in a given set
66
# client = OAI::Client.new 'http://my-oai-provider.example.com/oai'
@@ -16,11 +16,12 @@ module OAI
1616

1717
class Response
1818
include OAI::XPath
19-
attr_reader :doc, :resumption_token
19+
attr_reader :doc, :resumption_token, :resumption_block
2020

21-
def initialize(doc)
21+
def initialize(doc, &resumption_block)
2222
@doc = doc
2323
@resumption_token = xpath(doc, './/resumptionToken')
24+
@resumption_block = resumption_block
2425

2526
# throw an exception if there was an error
2627
error = xpath_first(doc, './/error')

lib/oai/client/resumable.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
module OAI
2+
module Resumable
3+
4+
class ResumptionWrapper
5+
include Enumerable
6+
7+
def initialize(response)
8+
@response = response
9+
@resumption_block = response.resumption_block
10+
end
11+
12+
def each(&block)
13+
yield_from_response &block
14+
while resumable?
15+
@response = @resumption_block.call @response
16+
yield_from_response &block
17+
end
18+
end
19+
20+
private
21+
22+
def yield_from_response(&block)
23+
@response.each do |obj|
24+
block.call(obj)
25+
end
26+
end
27+
28+
def resumable?
29+
@response.resumption_token and not @response.resumption_token.empty?
30+
end
31+
32+
end
33+
34+
def full
35+
if @resumption_block.nil?
36+
raise NotImplementedError.new("Resumption block not provided")
37+
end
38+
ResumptionWrapper.new(self)
39+
end
40+
41+
end
42+
end

test/client/tc_list_identifiers.rb

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
class ListIdentifiersTest < Test::Unit::TestCase
44

55
def test_list_with_resumption_token
6-
client = OAI::Client.new 'http://localhost:3333/oai'
6+
client = OAI::Client.new 'http://localhost:3333/oai'
77

88
# get a list of identifier headers
9-
response = client.list_identifiers :metadata_prefix => 'oai_dc'
9+
response = client.list_identifiers :metadata_prefix => 'oai_dc'
1010
assert_kind_of OAI::ListIdentifiersResponse, response
1111
assert_kind_of OAI::Response, response
1212
assert response.entries.size > 0
@@ -27,6 +27,25 @@ def test_list_with_resumption_token
2727
assert_not_equal response.entries[0].identifier, first_identifier
2828
end
2929

30+
def test_list_full
31+
client = OAI::Client.new 'http://localhost:3333/oai'
32+
33+
# get a list of identifier headers
34+
response = client.list_identifiers :metadata_prefix => 'oai_dc'
35+
assert_kind_of OAI::ListIdentifiersResponse, response
36+
assert_kind_of OAI::Response, response
37+
assert response.respond_to?(:full), "Should expose :full"
38+
39+
# Check that it runs through the pages
40+
assert_equal 1150, response.full.count
41+
response.full.each do |header|
42+
assert_kind_of OAI::Header, header
43+
assert header.identifier
44+
assert header.datestamp
45+
assert header.set_spec
46+
end
47+
end
48+
3049
def test_list_with_date_range
3150
client = OAI::Client.new 'http://localhost:3333/oai'
3251
from_date = Date.new(1998,1,1)
@@ -48,5 +67,5 @@ def test_invalid_argument
4867
client = OAI::Client.new 'http://localhost:3333/oai'
4968
assert_raise(OAI::ArgumentException) {client.list_identifiers :foo => 'bar'}
5069
end
51-
70+
5271
end

test/client/tc_list_records.rb

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
11
require 'test_helper'
22

3-
class GetRecordsTest < Test::Unit::TestCase
3+
class ListRecordsTest < Test::Unit::TestCase
44

5-
def test_get_records
5+
def test_list
66
client = OAI::Client.new 'http://localhost:3333/oai'
7-
response = client.list_records
7+
response = client.list_records
88
assert_kind_of OAI::ListRecordsResponse, response
99
assert response.entries.size > 0
1010
assert_kind_of OAI::Record, response.entries[0]
1111
end
12-
12+
13+
def test_list_full
14+
client = OAI::Client.new 'http://localhost:3333/oai'
15+
16+
response = client.list_records
17+
assert_kind_of OAI::ListRecordsResponse, response
18+
19+
# Check that it runs through the pages
20+
assert_equal 1150, response.full.count
21+
response.full.each do |record|
22+
assert_kind_of OAI::Record, record
23+
end
24+
end
25+
1326
end

test/client/tc_list_sets.rb

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,27 @@ def test_list
88
assert_kind_of OAI::ListSetsResponse, response
99
assert response.entries.size > 0
1010
assert_kind_of OAI::Set, response.entries[0]
11-
11+
1212
# test iterator
1313
for set in response
1414
assert_kind_of OAI::Set, set
1515
end
1616
end
17-
17+
18+
def test_list_full
19+
client = OAI::Client.new 'http://localhost:3333/oai'
20+
21+
response = client.list_sets
22+
assert_kind_of OAI::ListSetsResponse, response
23+
assert_kind_of OAI::Response, response
24+
assert response.respond_to?(:full), "Should expose :full"
25+
26+
# This won't page, but it should work anyway
27+
assert_equal 6, response.full.count
28+
response.full.each do |set|
29+
assert_kind_of OAI::Set, set
30+
end
31+
end
32+
1833
end
1934

0 commit comments

Comments
 (0)