oai 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +1 -1
- data/Rakefile +1 -3
- data/lib/oai/client.rb +27 -27
- data/lib/oai/harvester.rb +1 -0
- data/lib/oai/harvester/shell.rb +2 -2
- data/lib/oai/provider.rb +4 -4
- data/lib/oai/provider/metadata_format.rb +46 -4
- data/lib/oai/provider/model/activerecord_caching_wrapper.rb +0 -1
- data/lib/oai/provider/model/activerecord_wrapper.rb +2 -2
- data/lib/oai/provider/response.rb +4 -6
- data/lib/oai/provider/response/identify.rb +5 -3
- data/lib/oai/xpath.rb +1 -1
- data/test/activerecord_provider/database/oaipmhtest +0 -0
- data/test/activerecord_provider/helpers/set_provider.rb +1 -1
- data/test/activerecord_provider/tc_ar_provider.rb +31 -24
- data/test/activerecord_provider/tc_ar_sets_provider.rb +12 -6
- data/test/activerecord_provider/tc_caching_paging_provider.rb +22 -21
- data/test/activerecord_provider/tc_simple_paging_provider.rb +23 -22
- data/test/client/tc_exception.rb +3 -3
- data/test/client/tc_list_records.rb +1 -0
- data/test/client/tc_low_resolution_dates.rb +14 -0
- data/test/client/tc_utf8_escaping.rb +11 -0
- data/test/client/tc_xpath.rb +2 -5
- data/test/provider/models.rb +16 -16
- data/test/provider/tc_exceptions.rb +4 -3
- data/test/provider/tc_functional_tokens.rb +2 -2
- data/test/provider/tc_provider.rb +7 -7
- metadata +35 -51
data/README
CHANGED
data/Rakefile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
RUBY_OAI_VERSION = '0.0.
|
1
|
+
RUBY_OAI_VERSION = '0.0.7'
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'rake'
|
@@ -25,8 +25,6 @@ spec = Gem::Specification.new do |s|
|
|
25
25
|
s.bindir = 'bin'
|
26
26
|
s.executables = 'oai'
|
27
27
|
|
28
|
-
s.add_dependency('activesupport', '>=1.3.1')
|
29
|
-
s.add_dependency('chronic', '>=0.0.3')
|
30
28
|
s.add_dependency('builder', '>=2.0.0')
|
31
29
|
|
32
30
|
s.files = %w(README Rakefile) +
|
data/lib/oai/client.rb
CHANGED
@@ -155,7 +155,7 @@ module OAI
|
|
155
155
|
def do_request(verb, opts = nil)
|
156
156
|
# fire off the request and return appropriate DOM object
|
157
157
|
uri = build_uri(verb, opts)
|
158
|
-
xml = get(uri)
|
158
|
+
xml = strip_invalid_utf_8_chars(get(uri))
|
159
159
|
if @parser == 'libxml'
|
160
160
|
# remove default namespace for oai-pmh since libxml
|
161
161
|
# isn't able to use our xpaths to get at them
|
@@ -176,15 +176,16 @@ module OAI
|
|
176
176
|
|
177
177
|
def encode(value)
|
178
178
|
return CGI.escape(value) unless value.respond_to?(:strftime)
|
179
|
-
if value.
|
180
|
-
value.
|
179
|
+
if value.kind_of?(DateTime)
|
180
|
+
Time.parse(value.asctime).utc.xmlschema
|
181
|
+
elsif value.kind_of?(Time)
|
182
|
+
value.utc.xmlschema
|
181
183
|
else # Assume something date like
|
182
184
|
value.strftime('%Y-%m-%d')
|
183
185
|
end
|
184
186
|
end
|
185
187
|
|
186
188
|
def load_document(xml)
|
187
|
-
retried = false
|
188
189
|
case @parser
|
189
190
|
when 'libxml'
|
190
191
|
begin
|
@@ -192,28 +193,13 @@ module OAI
|
|
192
193
|
parser.string = xml
|
193
194
|
return parser.parse
|
194
195
|
rescue XML::Parser::ParseError => e
|
195
|
-
|
196
|
-
raise OAI::Exception, 'response not well formed XML: '+e, caller
|
197
|
-
end
|
198
|
-
ic = Iconv.new('UTF-8//IGNORE', 'UTF-8')
|
199
|
-
xml2 = ic.iconv(xml << ' ')[0..-2]
|
200
|
-
puts "equal? #{xml == xml2}"
|
201
|
-
retried = true
|
202
|
-
retry
|
196
|
+
raise OAI::Exception, 'response not well formed XML: '+e, caller
|
203
197
|
end
|
204
198
|
when 'rexml'
|
205
199
|
begin
|
206
200
|
return REXML::Document.new(xml)
|
207
201
|
rescue REXML::ParseException => e
|
208
|
-
|
209
|
-
puts xml
|
210
|
-
raise OAI::Exception, 'response not well formed XML: '+e, caller
|
211
|
-
end
|
212
|
-
puts "RETRYING"
|
213
|
-
ic = Iconv.new('UTF-8//IGNORE', 'UTF-8')
|
214
|
-
xml = ic.iconv(xml << ' ')[0..-2]
|
215
|
-
retried = true
|
216
|
-
retry
|
202
|
+
raise OAI::Exception, 'response not well formed XML: '+e.message, caller
|
217
203
|
end
|
218
204
|
end
|
219
205
|
end
|
@@ -288,13 +274,27 @@ module OAI
|
|
288
274
|
def parse_date(value)
|
289
275
|
return value if value.respond_to?(:strftime)
|
290
276
|
|
291
|
-
#
|
292
|
-
#
|
293
|
-
|
294
|
-
raise OAI::ArgumentError.new
|
295
|
-
|
296
|
-
dt.utc
|
277
|
+
Date.parse(value) # This will raise an exception for badly formatted dates
|
278
|
+
Time.parse(value).utc # Sadly, this will not
|
279
|
+
rescue
|
280
|
+
raise OAI::ArgumentError.new
|
297
281
|
end
|
298
282
|
|
283
|
+
# Strip out invalid UTF-8 characters. Regex from the W3C, inverted.
|
284
|
+
# http://www.w3.org/International/questions/qa-forms-utf-8.en.php
|
285
|
+
#
|
286
|
+
# Regex is from WebCollab:
|
287
|
+
# http://webcollab.sourceforge.net/unicode.html
|
288
|
+
def strip_invalid_utf_8_chars(xml)
|
289
|
+
simple_bytes = xml.gsub(/[\x00-\x08\x10\x0B\x0C\x0E-\x19\x7F]
|
290
|
+
| [\x00-\x7F][\x80-\xBF]+
|
291
|
+
| ([\xC0\xC1]|[\xF0-\xFF])[\x80-\xBF]*
|
292
|
+
| [\xC2-\xDF]((?![\x80-\xBF])|[\x80-\xBF]{2,})
|
293
|
+
| [\xE0-\xEF](([\x80-\xBF](?![\x80-\xBF]))
|
294
|
+
| (?![\x80-\xBF]{2})|[\x80-\xBF]{3,})/x, '?')
|
295
|
+
simple_bytes.gsub(/\xE0[\x80-\x9F][\x80-\xBF]
|
296
|
+
| \xED[\xA0-\xBF][\x80-\xBF]/,'?')
|
297
|
+
end
|
298
|
+
|
299
299
|
end
|
300
300
|
end
|
data/lib/oai/harvester.rb
CHANGED
data/lib/oai/harvester/shell.rb
CHANGED
data/lib/oai/provider.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
require '
|
1
|
+
require 'rexml/document'
|
2
|
+
require 'singleton'
|
2
3
|
require 'builder'
|
3
|
-
require 'chronic'
|
4
4
|
|
5
5
|
if not defined?(OAI::Const::VERBS)
|
6
6
|
require 'oai/exception'
|
@@ -266,8 +266,8 @@ module OAI::Provider
|
|
266
266
|
Response::GetRecord.new(self.class, options).to_xml
|
267
267
|
end
|
268
268
|
|
269
|
-
# xml_response = process_verb('ListRecords', :from => 'October',
|
270
|
-
# :until => 'November')
|
269
|
+
# xml_response = process_verb('ListRecords', :from => 'October 1, 2005',
|
270
|
+
# :until => 'November 1, 2005')
|
271
271
|
#
|
272
272
|
# If you are implementing a web interface using process_request is the
|
273
273
|
# preferred way.
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
1
3
|
module OAI::Provider::Metadata
|
2
4
|
# == Metadata Base Class
|
3
5
|
#
|
@@ -54,10 +56,9 @@ module OAI::Provider::Metadata
|
|
54
56
|
def value_for(field, record, map)
|
55
57
|
method = map[field] ? map[field].to_s : field.to_s
|
56
58
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
elsif methods.include?(method)
|
59
|
+
if record.respond_to?(pluralize(method))
|
60
|
+
record.send pluralize(method)
|
61
|
+
elsif record.respond_to?(method)
|
61
62
|
record.send method
|
62
63
|
else
|
63
64
|
[]
|
@@ -68,6 +69,47 @@ module OAI::Provider::Metadata
|
|
68
69
|
def header_specification
|
69
70
|
raise NotImplementedError.new
|
70
71
|
end
|
72
|
+
|
73
|
+
# Shamelessly lifted form ActiveSupport. Thanks Rails community!
|
74
|
+
def pluralize(word)
|
75
|
+
# Use ActiveSupports pluralization if it's available.
|
76
|
+
return word.pluralize if word.respond_to?(:pluralize)
|
77
|
+
|
78
|
+
# Otherwise use our own simple pluralization rules.
|
79
|
+
result = word.to_s.dup
|
80
|
+
|
81
|
+
# Uncountable words
|
82
|
+
return result if %w(equipment information rice money species series fish sheep).include?(result)
|
83
|
+
|
84
|
+
# Irregular words
|
85
|
+
{ 'person' => 'people', 'man' => 'men', 'child' => 'children', 'sex' => 'sexes',
|
86
|
+
'move' => 'moves', 'cow' => 'kine' }.each { |k,v| return v if word == k }
|
87
|
+
|
88
|
+
rules.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
|
89
|
+
result
|
90
|
+
end
|
91
|
+
|
92
|
+
def rules
|
93
|
+
[
|
94
|
+
[/$/, 's'],
|
95
|
+
[/s$/i, 's'],
|
96
|
+
[/(ax|test)is$/i, '\1es'],
|
97
|
+
[/(octop|vir)us$/i, '\1i'],
|
98
|
+
[/(alias|status)$/i, '\1es'],
|
99
|
+
[/(bu)s$/i, '\1ses'],
|
100
|
+
[/(buffal|tomat)o$/i, '\1oes'],
|
101
|
+
[/([ti])um$/i, '\1a'],
|
102
|
+
[/sis$/i, 'ses'],
|
103
|
+
[/(?:([^f])fe|([lr])f)$/i, '\1\2ves'],
|
104
|
+
[/(hive)$/i, '\1s'],
|
105
|
+
[/([^aeiouy]|qu)y$/i, '\1ies'],
|
106
|
+
[/(x|ch|ss|sh)$/i, '\1es'],
|
107
|
+
[/(matr|vert|ind)(?:ix|ex)$/i, '\1ices'],
|
108
|
+
[/([m|l])ouse$/i, '\1ice'],
|
109
|
+
[/^(ox)$/i, '\1en'],
|
110
|
+
[/(quiz)$/i, '\1zes']
|
111
|
+
]
|
112
|
+
end
|
71
113
|
|
72
114
|
end
|
73
115
|
|
@@ -20,8 +20,8 @@ module OAI::Provider
|
|
20
20
|
@limit = options.delete(:limit)
|
21
21
|
|
22
22
|
unless options.empty?
|
23
|
-
raise
|
24
|
-
"Unsupported options [#{options.join(', ')}]"
|
23
|
+
raise ArgumentError.new(
|
24
|
+
"Unsupported options [#{options.keys.join(', ')}]"
|
25
25
|
)
|
26
26
|
end
|
27
27
|
end
|
@@ -94,12 +94,10 @@ module OAI
|
|
94
94
|
def parse_date(value)
|
95
95
|
return value if value.respond_to?(:strftime)
|
96
96
|
|
97
|
-
#
|
98
|
-
#
|
99
|
-
|
100
|
-
raise OAI::ArgumentError.new
|
101
|
-
|
102
|
-
dt.utc
|
97
|
+
Date.parse(value) # This will raise an exception for badly formatted dates
|
98
|
+
Time.parse(value).utc # Sadly, this will not
|
99
|
+
rescue
|
100
|
+
raise OAI::ArgumentError.new
|
103
101
|
end
|
104
102
|
|
105
103
|
def internalize(hash = {})
|
@@ -8,9 +8,11 @@ module OAI::Provider::Response
|
|
8
8
|
r.repositoryName provider.name
|
9
9
|
r.baseURL provider.url
|
10
10
|
r.protocolVersion 2.0
|
11
|
-
provider.email.each
|
12
|
-
r.adminEmail address
|
13
|
-
|
11
|
+
if provider.email and provider.email.respond_to?(:each)
|
12
|
+
provider.email.each { |address| r.adminEmail address }
|
13
|
+
else
|
14
|
+
r.adminEmail provider.email.to_s
|
15
|
+
end
|
14
16
|
r.earliestDatestamp provider.model.earliest
|
15
17
|
r.deletedRecord provider.delete_support.to_s
|
16
18
|
r.granularity provider.granularity
|
data/lib/oai/xpath.rb
CHANGED
Binary file
|
@@ -32,5 +32,5 @@ class ARSetProvider < OAI::Provider::Base
|
|
32
32
|
repository_name 'ActiveRecord Set Based Provider'
|
33
33
|
repository_url 'http://localhost'
|
34
34
|
record_prefix = 'oai:test'
|
35
|
-
source_model SetModel.new(DCField)
|
35
|
+
source_model SetModel.new(DCField, :timestamp_field => 'date')
|
36
36
|
end
|
@@ -13,7 +13,8 @@ class ActiveRecordProviderTest < Test::Unit::TestCase
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def test_metadata_formats_for_record
|
16
|
-
|
16
|
+
record_id = DCField.find(:first).id
|
17
|
+
assert_nothing_raised { REXML::Document.new(@provider.list_metadata_formats(:identifier => "oai:test/#{record_id}")) }
|
17
18
|
doc = REXML::Document.new(@provider.list_metadata_formats)
|
18
19
|
assert doc.elements['/OAI-PMH/ListMetadataFormats/metadataFormat/metadataPrefix'].text == 'oai_dc'
|
19
20
|
end
|
@@ -31,25 +32,29 @@ class ActiveRecordProviderTest < Test::Unit::TestCase
|
|
31
32
|
end
|
32
33
|
|
33
34
|
def test_get_record
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
record_id = DCField.find(:first).id
|
36
|
+
assert_nothing_raised { REXML::Document.new(@provider.get_record(:identifier => "oai:test/#{record_id}")) }
|
37
|
+
doc = REXML::Document.new(@provider.get_record(:identifier => "#{record_id}"))
|
38
|
+
assert_equal "oai:test/#{record_id}", doc.elements['OAI-PMH/GetRecord/record/header/identifier'].text
|
37
39
|
end
|
38
40
|
|
39
41
|
def test_deleted
|
40
|
-
DCField.
|
41
|
-
|
42
|
-
|
42
|
+
record = DCField.find(:first)
|
43
|
+
record.deleted = true;
|
44
|
+
record.save
|
45
|
+
doc = REXML::Document.new(@provider.get_record(:identifier => "oai:test/#{record.id}"))
|
46
|
+
assert_equal "oai:test/#{record.id}", doc.elements['OAI-PMH/GetRecord/record/header/identifier'].text
|
43
47
|
assert_equal 'deleted', doc.elements['OAI-PMH/GetRecord/record/header'].attributes["status"]
|
44
48
|
end
|
45
49
|
|
46
50
|
def test_from
|
47
|
-
DCField.
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
+
first_id = DCField.find(:first, :order => "id asc").id
|
52
|
+
DCField.update_all(['updated_at = ?', Time.parse("January 1 2005")],
|
53
|
+
"id < #{first_id + 90}")
|
54
|
+
DCField.update_all(['updated_at = ?', Time.parse("June 1 2005")],
|
55
|
+
"id < #{first_id + 10}")
|
51
56
|
|
52
|
-
from_param =
|
57
|
+
from_param = Time.parse("January 1 2006")
|
53
58
|
|
54
59
|
doc = REXML::Document.new(
|
55
60
|
@provider.list_records(:from => from_param)
|
@@ -58,31 +63,33 @@ class ActiveRecordProviderTest < Test::Unit::TestCase
|
|
58
63
|
doc.elements['OAI-PMH/ListRecords'].size
|
59
64
|
|
60
65
|
doc = REXML::Document.new(
|
61
|
-
@provider.list_records(:from =>
|
66
|
+
@provider.list_records(:from => Time.parse("May 30 2005"))
|
62
67
|
)
|
63
68
|
assert_equal 20, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
64
69
|
end
|
65
70
|
|
66
71
|
def test_until
|
67
|
-
DCField.
|
68
|
-
|
72
|
+
first_id = DCField.find(:first, :order => "id asc").id
|
73
|
+
DCField.update_all(['updated_at = ?', Time.parse("June 1 2005")],
|
74
|
+
"id < #{first_id + 10}")
|
69
75
|
|
70
76
|
doc = REXML::Document.new(
|
71
|
-
@provider.list_records(:until =>
|
77
|
+
@provider.list_records(:until => Time.parse("June 1 2005"))
|
72
78
|
)
|
73
|
-
assert_equal
|
79
|
+
assert_equal 10, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
74
80
|
end
|
75
81
|
|
76
82
|
def test_from_and_until
|
77
|
-
DCField.
|
78
|
-
DCField.update_all(['updated_at = ?',
|
79
|
-
|
80
|
-
|
81
|
-
|
83
|
+
first_id = DCField.find(:first, :order => "id asc").id
|
84
|
+
DCField.update_all(['updated_at = ?', Time.parse("June 1 2005")])
|
85
|
+
DCField.update_all(['updated_at = ?', Time.parse("June 15 2005")],
|
86
|
+
"id < #{first_id + 50}")
|
87
|
+
DCField.update_all(['updated_at = ?', Time.parse("June 30 2005")],
|
88
|
+
"id < #{first_id + 10}")
|
82
89
|
|
83
90
|
doc = REXML::Document.new(
|
84
|
-
@provider.list_records(:from =>
|
85
|
-
:until =>
|
91
|
+
@provider.list_records(:from => Time.parse("June 3 2005"),
|
92
|
+
:until => Time.parse("June 16 2005"))
|
86
93
|
)
|
87
94
|
assert_equal 40, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
88
95
|
end
|
@@ -25,7 +25,8 @@ class ActiveRecordSetProviderTest < Test::Unit::TestCase
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def test_record_with_multiple_sets
|
28
|
-
|
28
|
+
record = DCSet.find(:first, :conditions => "spec = 'C'").dc_fields.first
|
29
|
+
assert_equal 2, record.sets.size
|
29
30
|
end
|
30
31
|
|
31
32
|
def setup
|
@@ -43,24 +44,29 @@ class ActiveRecordSetProviderTest < Test::Unit::TestCase
|
|
43
44
|
def define_sets
|
44
45
|
set_a = DCSet.create(:name => "Set A", :spec => "A")
|
45
46
|
set_b = DCSet.create(:name => "Set B", :spec => "B")
|
46
|
-
set_c = DCSet.create(:name => "Set
|
47
|
+
set_c = DCSet.create(:name => "Set C", :spec => "C")
|
47
48
|
set_ab = DCSet.create(:name => "Set A:B", :spec => "A:B")
|
48
49
|
|
49
|
-
|
50
|
+
next_id = 0
|
51
|
+
DCField.find(:all, :limit => 10, :order => "id asc").each do |record|
|
50
52
|
set_a.dc_fields << record
|
53
|
+
next_id = record.id
|
51
54
|
end
|
52
55
|
|
53
|
-
DCField.find(
|
56
|
+
DCField.find(:all, :limit => 10, :order => "id asc", :conditions => "id > #{next_id}").each do |record|
|
54
57
|
set_b.dc_fields << record
|
58
|
+
next_id = record.id
|
55
59
|
end
|
56
60
|
|
57
|
-
DCField.find(
|
61
|
+
DCField.find(:all, :limit => 10, :order => "id asc", :conditions => "id > #{next_id}").each do |record|
|
58
62
|
set_ab.dc_fields << record
|
63
|
+
next_id = record.id
|
59
64
|
end
|
60
65
|
|
61
|
-
DCField.find(
|
66
|
+
DCField.find(:all, :limit => 10, :order => "id asc", :conditions => "id > #{next_id}").each do |record|
|
62
67
|
set_a.dc_fields << record
|
63
68
|
set_c.dc_fields << record
|
69
|
+
next_id = record.id
|
64
70
|
end
|
65
71
|
end
|
66
72
|
end
|
@@ -5,40 +5,41 @@ class CachingPagingProviderTest < Test::Unit::TestCase
|
|
5
5
|
|
6
6
|
def test_full_harvest
|
7
7
|
doc = Document.new(@provider.list_records)
|
8
|
-
assert_not_nil doc.elements["/OAI-PMH/resumptionToken"]
|
9
|
-
assert_equal
|
10
|
-
token = doc.elements["/OAI-PMH/resumptionToken"].text
|
8
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
9
|
+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].size
|
10
|
+
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
11
11
|
doc = Document.new(@provider.list_records(:resumption_token => token))
|
12
|
-
assert_not_nil doc.elements["/OAI-PMH/resumptionToken"]
|
13
|
-
token = doc.elements["/OAI-PMH/resumptionToken"].text
|
14
|
-
assert_equal
|
12
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
13
|
+
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
14
|
+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].size
|
15
15
|
doc = Document.new(@provider.list_records(:resumption_token => token))
|
16
|
-
assert_not_nil doc.elements["/OAI-PMH/resumptionToken"]
|
17
|
-
token = doc.elements["/OAI-PMH/resumptionToken"].text
|
18
|
-
assert_equal
|
16
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
17
|
+
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
18
|
+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].size
|
19
19
|
doc = Document.new(@provider.list_records(:resumption_token => token))
|
20
|
-
assert_nil doc.elements["/OAI-PMH/resumptionToken"]
|
20
|
+
assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
21
21
|
assert_equal 25, doc.elements["/OAI-PMH/ListRecords"].size
|
22
22
|
end
|
23
23
|
|
24
24
|
def test_from_and_until
|
25
|
-
DCField.
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
first_id = DCField.find(:first, :order => "id asc").id
|
26
|
+
DCField.update_all(['updated_at = ?', Time.parse("September 15 2005")],
|
27
|
+
"id <= #{first_id + 25}")
|
28
|
+
DCField.update_all(['updated_at = ?', Time.parse("November 1 2005")],
|
29
|
+
"id < #{first_id + 50} and id > #{first_id + 25}")
|
30
|
+
|
30
31
|
# Should return 50 records broken into 2 groups of 25.
|
31
32
|
doc = Document.new(
|
32
33
|
@provider.list_records(
|
33
|
-
:from =>
|
34
|
-
:until =>
|
34
|
+
:from => Time.parse("September 1 2005"),
|
35
|
+
:until => Time.parse("November 30 2005"))
|
35
36
|
)
|
36
|
-
assert_equal
|
37
|
-
token = doc.elements["/OAI-PMH/resumptionToken"].text
|
38
|
-
assert_not_nil doc.elements["/OAI-PMH/resumptionToken"]
|
37
|
+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].size
|
38
|
+
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
39
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
39
40
|
doc = Document.new(@provider.list_records(:resumption_token => token))
|
40
41
|
assert_equal 25, doc.elements["/OAI-PMH/ListRecords"].size
|
41
|
-
assert_nil doc.elements["/OAI-PMH/resumptionToken"]
|
42
|
+
assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
42
43
|
end
|
43
44
|
|
44
45
|
def setup
|
@@ -5,42 +5,43 @@ class SimpleResumptionProviderTest < Test::Unit::TestCase
|
|
5
5
|
|
6
6
|
def test_full_harvest
|
7
7
|
doc = Document.new(@provider.list_records)
|
8
|
-
assert_not_nil doc.elements["/OAI-PMH/resumptionToken"]
|
9
|
-
assert_equal
|
10
|
-
token = doc.elements["/OAI-PMH/resumptionToken"].text
|
8
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
9
|
+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
10
|
+
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
11
11
|
doc = Document.new(@provider.list_records(:resumption_token => token))
|
12
|
-
assert_not_nil doc.elements["/OAI-PMH/resumptionToken"]
|
13
|
-
token = doc.elements["/OAI-PMH/resumptionToken"].text
|
14
|
-
assert_equal
|
12
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
13
|
+
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
14
|
+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
15
15
|
doc = Document.new(@provider.list_records(:resumption_token => token))
|
16
|
-
assert_not_nil doc.elements["/OAI-PMH/resumptionToken"]
|
17
|
-
token = doc.elements["/OAI-PMH/resumptionToken"].text
|
18
|
-
assert_equal
|
16
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
17
|
+
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
18
|
+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
19
19
|
doc = Document.new(@provider.list_records(:resumption_token => token))
|
20
|
-
assert_nil doc.elements["/OAI-PMH/resumptionToken"]
|
20
|
+
assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
21
21
|
assert_equal 25, doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
22
22
|
end
|
23
23
|
|
24
24
|
def test_from_and_until
|
25
|
-
DCField.
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
first_id = DCField.find(:first, :order => "id asc").id
|
26
|
+
DCField.update_all(['updated_at = ?', Time.parse("September 15 2005")],
|
27
|
+
"id < #{first_id + 25}")
|
28
|
+
DCField.update_all(['updated_at = ?', Time.parse("November 1 2005")],
|
29
|
+
"id <= #{first_id + 50} and id > #{first_id + 25}")
|
29
30
|
|
30
|
-
total = DCField.count(:id, :conditions => ["updated_at >= ? AND updated_at <= ?",
|
31
|
+
total = DCField.count(:id, :conditions => ["updated_at >= ? AND updated_at <= ?", Time.parse("September 1 2005"), Time.parse("November 30 2005")])
|
31
32
|
|
32
33
|
# Should return 50 records broken into 2 groups of 25.
|
33
34
|
doc = Document.new(
|
34
35
|
@provider.list_records(
|
35
|
-
:from =>
|
36
|
-
:until =>
|
36
|
+
:from => Time.parse("September 1 2005"),
|
37
|
+
:until => Time.parse("November 30 2005"))
|
37
38
|
)
|
38
|
-
assert_equal
|
39
|
-
assert_not_nil doc.elements["/OAI-PMH/resumptionToken"]
|
40
|
-
token = doc.elements["/OAI-PMH/resumptionToken"].text
|
39
|
+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
40
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
41
|
+
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
41
42
|
doc = Document.new(@provider.list_records(:resumption_token => token))
|
42
|
-
assert_equal
|
43
|
-
assert_nil doc.elements["/OAI-PMH/resumptionToken"]
|
43
|
+
assert_equal 25, doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
44
|
+
assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
44
45
|
end
|
45
46
|
|
46
47
|
def setup
|
data/test/client/tc_exception.rb
CHANGED
@@ -2,9 +2,9 @@ require 'test_helper'
|
|
2
2
|
|
3
3
|
class ExceptionTest < Test::Unit::TestCase
|
4
4
|
|
5
|
-
def
|
6
|
-
client = OAI::Client.new 'http://www.
|
7
|
-
assert_raises(
|
5
|
+
def test_not_found
|
6
|
+
client = OAI::Client.new 'http://www.google.com'
|
7
|
+
assert_raises(ArgumentError) { client.identify }
|
8
8
|
end
|
9
9
|
|
10
10
|
def test_xml_error
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class LowResolutionDatesTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_low_res_date_parsing
|
6
|
+
client = OAI::Client.new 'http://caltechcstr.library.caltech.edu/perl/oai2'
|
7
|
+
|
8
|
+
date = Date.new 2003, 1, 1
|
9
|
+
|
10
|
+
# get a list of identifier headers
|
11
|
+
assert_nothing_raised { client.list_identifiers :from => date }
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class UTF8Test < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_escaping_invalid_utf_8_characters
|
6
|
+
client = OAI::Client.new 'http://localhost:3333/oai' #, :parser => 'libxml'
|
7
|
+
invalid_utf_8 = [2, 3, 4, 104, 5, 101, 6, 108, 66897, 108, 66535, 111, 1114112, 33, 55234123, 33].pack("U*")
|
8
|
+
assert_equal("hello!!", client.send(:strip_invalid_utf_8_chars, invalid_utf_8).gsub(/\?/, ''))
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
data/test/client/tc_xpath.rb
CHANGED
@@ -13,7 +13,7 @@ class XpathTest < Test::Unit::TestCase
|
|
13
13
|
def test_libxml
|
14
14
|
begin
|
15
15
|
require 'xml/libxml'
|
16
|
-
rescue
|
16
|
+
rescue LoadError
|
17
17
|
# libxml not available so nothing to test!
|
18
18
|
return
|
19
19
|
end
|
@@ -23,7 +23,4 @@ class XpathTest < Test::Unit::TestCase
|
|
23
23
|
assert_equal xpath(doc, './/foobar'), nil
|
24
24
|
end
|
25
25
|
|
26
|
-
end
|
27
|
-
|
28
|
-
__END__
|
29
|
-
|
26
|
+
end
|
data/test/provider/models.rb
CHANGED
@@ -143,9 +143,9 @@ class SimpleModel < TestModel
|
|
143
143
|
set_two.spec = "A:B"
|
144
144
|
set_two.description = "This is test set two."
|
145
145
|
|
146
|
-
generate_records(5,
|
147
|
-
generate_records(1,
|
148
|
-
generate_records(4,
|
146
|
+
generate_records(5, Time.parse("2002-10-5"), set_one)
|
147
|
+
generate_records(1, Time.parse("2002-11-5"), [set_two], true)
|
148
|
+
generate_records(4, Time.parse("2002-11-5"), [set_two])
|
149
149
|
end
|
150
150
|
|
151
151
|
end
|
@@ -154,11 +154,11 @@ class BigModel < TestModel
|
|
154
154
|
|
155
155
|
def initialize(limit = nil)
|
156
156
|
super(limit)
|
157
|
-
generate_records(100,
|
158
|
-
generate_records(100,
|
159
|
-
generate_records(100,
|
160
|
-
generate_records(100,
|
161
|
-
generate_records(100,
|
157
|
+
generate_records(100, Time.parse("October 2 2000"))
|
158
|
+
generate_records(100, Time.parse("November 2 2000"))
|
159
|
+
generate_records(100, Time.parse("December 2 2000"))
|
160
|
+
generate_records(100, Time.parse("January 2 2001"))
|
161
|
+
generate_records(100, Time.parse("February 2 2001"))
|
162
162
|
end
|
163
163
|
|
164
164
|
end
|
@@ -172,7 +172,7 @@ class MappedModel < TestModel
|
|
172
172
|
set_one.spec = "A"
|
173
173
|
set_one.description = "This is test set one."
|
174
174
|
|
175
|
-
generate_records(5,
|
175
|
+
generate_records(5, Time.parse("dec 1 2006"), set_one)
|
176
176
|
end
|
177
177
|
|
178
178
|
def map_oai_dc
|
@@ -216,14 +216,14 @@ class ComplexModel < TestModel
|
|
216
216
|
set_three_four.spec = "Three:Four"
|
217
217
|
set_three_four.description = "This is combination set of Three and Four."
|
218
218
|
|
219
|
-
generate_records(250,
|
220
|
-
generate_records(50,
|
221
|
-
generate_records(50,
|
222
|
-
generate_records(250,
|
219
|
+
generate_records(250, Time.parse("May 2 1998"), [set_one, set_one_two])
|
220
|
+
generate_records(50, Time.parse("June 2 1998"), [set_one, set_one_two], true)
|
221
|
+
generate_records(50, Time.parse("October 10 1998"), [set_three, set_three_four], true)
|
222
|
+
generate_records(250, Time.parse("July 2 2002"), [set_two, set_one_two])
|
223
223
|
|
224
|
-
generate_records(250,
|
225
|
-
generate_records(50,
|
226
|
-
generate_records(250,
|
224
|
+
generate_records(250, Time.parse("September 15 2004"), [set_three, set_three_four])
|
225
|
+
generate_records(50, Time.parse("October 10 2004"), [set_three, set_three_four], true)
|
226
|
+
generate_records(250, Time.parse("December 25 2005"), [set_four, set_three_four])
|
227
227
|
end
|
228
228
|
|
229
229
|
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class ProviderExceptions < Test::Unit::TestCase
|
4
|
-
|
4
|
+
include Singleton
|
5
|
+
|
5
6
|
def setup
|
6
7
|
@provider = ComplexProvider.new
|
7
8
|
end
|
@@ -51,8 +52,8 @@ class ProviderExceptions < Test::Unit::TestCase
|
|
51
52
|
|
52
53
|
def test_no_records_match_dates_that_are_out_of_range
|
53
54
|
assert_raise(OAI::NoMatchException) do
|
54
|
-
@provider.list_records(:from =>
|
55
|
-
:until =>
|
55
|
+
@provider.list_records(:from => Time.parse("November 2 2000"),
|
56
|
+
:until => Time.parse("November 1 2000"))
|
56
57
|
end
|
57
58
|
end
|
58
59
|
|
@@ -23,8 +23,8 @@ class ResumptionTokenFunctionalTest < Test::Unit::TestCase
|
|
23
23
|
assert_nothing_raised { Document.new(@provider.list_records) }
|
24
24
|
doc = Document.new(
|
25
25
|
@provider.list_records(
|
26
|
-
:from =>
|
27
|
-
:until =>
|
26
|
+
:from => Time.parse("September 1 2004"),
|
27
|
+
:until => Time.parse("November 30 2004"))
|
28
28
|
)
|
29
29
|
assert_equal 101, doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
30
30
|
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
@@ -33,12 +33,12 @@ class OaiTest < Test::Unit::TestCase
|
|
33
33
|
def test_from
|
34
34
|
assert_nothing_raised { REXML::Document.new(@big_provider.list_records) }
|
35
35
|
doc = REXML::Document.new(
|
36
|
-
@big_provider.list_records(:from =>
|
36
|
+
@big_provider.list_records(:from => Time.parse("February 1 2001"))
|
37
37
|
)
|
38
38
|
assert_equal 100, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
39
39
|
|
40
40
|
doc = REXML::Document.new(
|
41
|
-
@big_provider.list_records(:from =>
|
41
|
+
@big_provider.list_records(:from => Time.parse("January 1 2001"))
|
42
42
|
)
|
43
43
|
assert_equal 200, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
44
44
|
end
|
@@ -46,7 +46,7 @@ class OaiTest < Test::Unit::TestCase
|
|
46
46
|
def test_until
|
47
47
|
assert_nothing_raised { REXML::Document.new(@big_provider.list_records) }
|
48
48
|
doc = REXML::Document.new(
|
49
|
-
@big_provider.list_records(:until =>
|
49
|
+
@big_provider.list_records(:until => Time.parse("November 1 2000"))
|
50
50
|
)
|
51
51
|
assert_equal 100, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
52
52
|
end
|
@@ -54,14 +54,14 @@ class OaiTest < Test::Unit::TestCase
|
|
54
54
|
def test_from_and_until
|
55
55
|
assert_nothing_raised { REXML::Document.new(@big_provider.list_records) }
|
56
56
|
doc = REXML::Document.new(
|
57
|
-
@big_provider.list_records(:from =>
|
58
|
-
:until =>
|
57
|
+
@big_provider.list_records(:from => Time.parse("November 1 2000"),
|
58
|
+
:until => Time.parse("November 30 2000"))
|
59
59
|
)
|
60
60
|
assert_equal 100, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
61
61
|
|
62
62
|
doc = REXML::Document.new(
|
63
|
-
@big_provider.list_records(:from =>
|
64
|
-
:until =>
|
63
|
+
@big_provider.list_records(:from => Time.parse("December 1 2000"),
|
64
|
+
:until => Time.parse("December 31 2000"))
|
65
65
|
)
|
66
66
|
assert_equal 100, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
67
67
|
end
|
metadata
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.
|
2
|
+
rubygems_version: 0.9.4
|
3
3
|
specification_version: 1
|
4
4
|
name: oai
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.0.
|
7
|
-
date:
|
6
|
+
version: 0.0.7
|
7
|
+
date: 2008-01-14 00:00:00 -05:00
|
8
8
|
summary: A ruby library for working with the Open Archive Initiative Protocol for Metadata Harvesting (OAI-PMH)
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -33,30 +33,30 @@ files:
|
|
33
33
|
- Rakefile
|
34
34
|
- bin/oai
|
35
35
|
- test/activerecord_provider
|
36
|
-
- test/client
|
37
|
-
- test/provider
|
38
|
-
- test/test.xml
|
39
36
|
- test/activerecord_provider/config
|
40
|
-
- test/activerecord_provider/database
|
41
|
-
- test/activerecord_provider/fixtures
|
42
|
-
- test/activerecord_provider/helpers
|
43
|
-
- test/activerecord_provider/models
|
44
|
-
- test/activerecord_provider/tc_ar_provider.rb
|
45
|
-
- test/activerecord_provider/tc_ar_sets_provider.rb
|
46
|
-
- test/activerecord_provider/tc_caching_paging_provider.rb
|
47
|
-
- test/activerecord_provider/tc_simple_paging_provider.rb
|
48
|
-
- test/activerecord_provider/test_helper.rb
|
49
37
|
- test/activerecord_provider/config/connection.rb
|
50
38
|
- test/activerecord_provider/config/database.yml
|
39
|
+
- test/activerecord_provider/database
|
51
40
|
- test/activerecord_provider/database/ar_migration.rb
|
52
41
|
- test/activerecord_provider/database/oaipmhtest
|
42
|
+
- test/activerecord_provider/fixtures
|
53
43
|
- test/activerecord_provider/fixtures/dc.yml
|
44
|
+
- test/activerecord_provider/helpers
|
54
45
|
- test/activerecord_provider/helpers/providers.rb
|
55
46
|
- test/activerecord_provider/helpers/set_provider.rb
|
47
|
+
- test/activerecord_provider/models
|
56
48
|
- test/activerecord_provider/models/dc_field.rb
|
57
49
|
- test/activerecord_provider/models/dc_set.rb
|
58
50
|
- test/activerecord_provider/models/oai_token.rb
|
51
|
+
- test/activerecord_provider/tc_ar_provider.rb
|
52
|
+
- test/activerecord_provider/tc_ar_sets_provider.rb
|
53
|
+
- test/activerecord_provider/tc_caching_paging_provider.rb
|
54
|
+
- test/activerecord_provider/tc_simple_paging_provider.rb
|
55
|
+
- test/activerecord_provider/test_helper.rb
|
56
|
+
- test/client
|
59
57
|
- test/client/helpers
|
58
|
+
- test/client/helpers/provider.rb
|
59
|
+
- test/client/helpers/test_wrapper.rb
|
60
60
|
- test/client/tc_exception.rb
|
61
61
|
- test/client/tc_get_record.rb
|
62
62
|
- test/client/tc_identify.rb
|
@@ -65,10 +65,11 @@ files:
|
|
65
65
|
- test/client/tc_list_metadata_formats.rb
|
66
66
|
- test/client/tc_list_records.rb
|
67
67
|
- test/client/tc_list_sets.rb
|
68
|
+
- test/client/tc_low_resolution_dates.rb
|
69
|
+
- test/client/tc_utf8_escaping.rb
|
68
70
|
- test/client/tc_xpath.rb
|
69
71
|
- test/client/test_helper.rb
|
70
|
-
- test/
|
71
|
-
- test/client/helpers/test_wrapper.rb
|
72
|
+
- test/provider
|
72
73
|
- test/provider/models.rb
|
73
74
|
- test/provider/tc_exceptions.rb
|
74
75
|
- test/provider/tc_functional_tokens.rb
|
@@ -76,19 +77,9 @@ files:
|
|
76
77
|
- test/provider/tc_resumption_tokens.rb
|
77
78
|
- test/provider/tc_simple_provider.rb
|
78
79
|
- test/provider/test_helper.rb
|
80
|
+
- test/test.xml
|
79
81
|
- lib/oai
|
80
|
-
- lib/oai.rb
|
81
|
-
- lib/test.rb
|
82
82
|
- lib/oai/client
|
83
|
-
- lib/oai/client.rb
|
84
|
-
- lib/oai/constants.rb
|
85
|
-
- lib/oai/exception.rb
|
86
|
-
- lib/oai/harvester
|
87
|
-
- lib/oai/harvester.rb
|
88
|
-
- lib/oai/provider
|
89
|
-
- lib/oai/provider.rb
|
90
|
-
- lib/oai/set.rb
|
91
|
-
- lib/oai/xpath.rb
|
92
83
|
- lib/oai/client/get_record.rb
|
93
84
|
- lib/oai/client/header.rb
|
94
85
|
- lib/oai/client/identify.rb
|
@@ -99,23 +90,27 @@ files:
|
|
99
90
|
- lib/oai/client/metadata_format.rb
|
100
91
|
- lib/oai/client/record.rb
|
101
92
|
- lib/oai/client/response.rb
|
93
|
+
- lib/oai/client.rb
|
94
|
+
- lib/oai/constants.rb
|
95
|
+
- lib/oai/exception.rb
|
96
|
+
- lib/oai/harvester
|
102
97
|
- lib/oai/harvester/config.rb
|
103
98
|
- lib/oai/harvester/harvest.rb
|
104
99
|
- lib/oai/harvester/logging.rb
|
105
100
|
- lib/oai/harvester/mailer.rb
|
106
101
|
- lib/oai/harvester/shell.rb
|
102
|
+
- lib/oai/harvester.rb
|
103
|
+
- lib/oai/provider
|
107
104
|
- lib/oai/provider/extensions
|
108
105
|
- lib/oai/provider/metadata_format
|
106
|
+
- lib/oai/provider/metadata_format/oai_dc.rb
|
109
107
|
- lib/oai/provider/metadata_format.rb
|
110
108
|
- lib/oai/provider/model
|
109
|
+
- lib/oai/provider/model/activerecord_caching_wrapper.rb
|
110
|
+
- lib/oai/provider/model/activerecord_wrapper.rb
|
111
111
|
- lib/oai/provider/model.rb
|
112
112
|
- lib/oai/provider/partial_result.rb
|
113
113
|
- lib/oai/provider/response
|
114
|
-
- lib/oai/provider/response.rb
|
115
|
-
- lib/oai/provider/resumption_token.rb
|
116
|
-
- lib/oai/provider/metadata_format/oai_dc.rb
|
117
|
-
- lib/oai/provider/model/activerecord_caching_wrapper.rb
|
118
|
-
- lib/oai/provider/model/activerecord_wrapper.rb
|
119
114
|
- lib/oai/provider/response/error.rb
|
120
115
|
- lib/oai/provider/response/get_record.rb
|
121
116
|
- lib/oai/provider/response/identify.rb
|
@@ -124,6 +119,13 @@ files:
|
|
124
119
|
- lib/oai/provider/response/list_records.rb
|
125
120
|
- lib/oai/provider/response/list_sets.rb
|
126
121
|
- lib/oai/provider/response/record_response.rb
|
122
|
+
- lib/oai/provider/response.rb
|
123
|
+
- lib/oai/provider/resumption_token.rb
|
124
|
+
- lib/oai/provider.rb
|
125
|
+
- lib/oai/set.rb
|
126
|
+
- lib/oai/xpath.rb
|
127
|
+
- lib/oai.rb
|
128
|
+
- lib/test.rb
|
127
129
|
- examples/models/file_model.rb
|
128
130
|
- examples/providers/dublin_core.rb
|
129
131
|
test_files: []
|
@@ -139,24 +141,6 @@ extensions: []
|
|
139
141
|
requirements: []
|
140
142
|
|
141
143
|
dependencies:
|
142
|
-
- !ruby/object:Gem::Dependency
|
143
|
-
name: activesupport
|
144
|
-
version_requirement:
|
145
|
-
version_requirements: !ruby/object:Gem::Version::Requirement
|
146
|
-
requirements:
|
147
|
-
- - ">="
|
148
|
-
- !ruby/object:Gem::Version
|
149
|
-
version: 1.3.1
|
150
|
-
version:
|
151
|
-
- !ruby/object:Gem::Dependency
|
152
|
-
name: chronic
|
153
|
-
version_requirement:
|
154
|
-
version_requirements: !ruby/object:Gem::Version::Requirement
|
155
|
-
requirements:
|
156
|
-
- - ">="
|
157
|
-
- !ruby/object:Gem::Version
|
158
|
-
version: 0.0.3
|
159
|
-
version:
|
160
144
|
- !ruby/object:Gem::Dependency
|
161
145
|
name: builder
|
162
146
|
version_requirement:
|