berkeley_library-util 0.2.0 → 0.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3f343b3b9dc12a94f77d0a672e3d61f90ccb637f4217238b9a5b7358d658c860
4
- data.tar.gz: 94ce31eb5eeb374fda410f3b984ce26ca4e070635415b2aa8afa38c33a9ceefa
3
+ metadata.gz: 95474321e18bf12390800d829d0fd62e043e5d5e3a17a75df968944698a10328
4
+ data.tar.gz: 98d7b23d5be9bb910b707f53bafa517b51994f9e2fab5b963342027f54c26e84
5
5
  SHA512:
6
- metadata.gz: 25a2f1d770068ed5d54e70c359dc574958c2438f872ae466c07c9dbf9dfd8c4c033aca4cbadec1f45c8cb886ba5cdf3b626e1ab5131d3bebba94325975dc70b3
7
- data.tar.gz: 22607a4573f7f85cdbde5dcb997d7b3b5fc0480262faad923ac3b01bcc6cca0c301c4746eeb9195ff8054b6b00ac56a030a0c566348278086b48603172c1823b
6
+ metadata.gz: 835494737587ecf7b19aa9b88d1ba500f3919c830f6b3dbae1a45d10c42e0cc5520c6f401bcc678cdc2feae4e747caedaf8960804bbc98ecd2981b7157cc0ec1
7
+ data.tar.gz: 770fb93344dc72807d6bfed3d8d1c70e811546bd8698b4bb627dba0206a763b17f0d34f44bf30368837d4a2b7daf64e598d7917b626ee70f978f5095cb8afcdd
data/.gitignore CHANGED
@@ -35,6 +35,7 @@ Gemfile.lock
35
35
  /test/tmp/
36
36
  /test/version_tmp/
37
37
  /tmp/
38
+ /vendor
38
39
 
39
40
  # Used by dotenv library to load environment variables.
40
41
  # .env
@@ -218,7 +219,8 @@ flycheck_*.el
218
219
  .LSOverride
219
220
 
220
221
  # Icon must end with two \r
221
- Icon
222
+ Icon
223
+
222
224
 
223
225
  # Thumbnails
224
226
  ._*
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- ~> 3.3
1
+ 3.3
data/CHANGES.md CHANGED
@@ -1,3 +1,10 @@
1
+ # 0.3.0 (2026-02-04)
2
+
3
+ - Add `URIs::HeadCheck`, an OkComputer check that performs a HEAD request
4
+ to verify the availability of a URL, with optional basic authentication.
5
+ - updates Requester to support timeouts values passed to RestClient
6
+ - Bumping to 0.3.0 to reflect changes to `Requester` and the addition of `URIs::HeadCheck`.
7
+
1
8
  # 0.2.0 (2025-07-24)
2
9
 
3
10
  - Update to support Ruby 3.3+.
@@ -28,6 +28,7 @@ Gem::Specification.new do |spec|
28
28
  spec.add_development_dependency 'ci_reporter_rspec', '~> 1.0'
29
29
  spec.add_development_dependency 'colorize', '~> 1.0'
30
30
  spec.add_development_dependency 'dotenv', '~> 2.7'
31
+ spec.add_development_dependency 'okcomputer', '~> 1.19'
31
32
  spec.add_development_dependency 'rake', '~> 13.0'
32
33
  spec.add_development_dependency 'rspec', '~> 3.10'
33
34
  spec.add_development_dependency 'rubocop', '~> 1.78.0'
@@ -63,8 +63,8 @@ module BerkeleyLibrary
63
63
  # @yieldparam target [Object] the value to compare against
64
64
  # @return [Array<Integer>, nil] the indices in `in_array` of each value in `for_array`,
65
65
  # or `nil` if not all values could be found
66
- def find_indices(for_array:, in_array:, &block)
67
- return find_indices_matching(for_array, in_array, &block) if block_given?
66
+ def find_indices(for_array:, in_array:, &)
67
+ return find_indices_matching(for_array, in_array, &) if block_given?
68
68
 
69
69
  find_all_indices(for_array, in_array)
70
70
  end
@@ -89,10 +89,10 @@ module BerkeleyLibrary
89
89
  # @param in_array [Array] the array to search
90
90
  # @param start_index [Integer] the index to start with
91
91
  # @return [Enumerator] a new enumerator
92
- def find_index(*args, in_array:, start_index: 0, &block)
92
+ def find_index(*args, in_array:, start_index: 0, &)
93
93
  raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 0..1" if args.size > 1
94
94
  return Enumerator.new { |y| find_index(in_array: in_array, start_index: start_index, &y) } if args.empty? && !block_given?
95
- return unless (relative_index = in_array[start_index..].find_index(*args, &block))
95
+ return unless (relative_index = in_array[start_index..].find_index(*args, &))
96
96
 
97
97
  relative_index + start_index
98
98
  end
@@ -2,12 +2,12 @@ module BerkeleyLibrary
2
2
  module Util
3
3
  class ModuleInfo
4
4
  NAME = 'berkeley_library-util'.freeze
5
- AUTHORS = ['David Moles', 'maría a. matienzo'].freeze
6
- AUTHOR_EMAILS = ['dmoles@berkeley.edu', 'matienzo@berkeley.edu'].freeze
5
+ AUTHORS = ['David Moles', 'maría a. matienzo', 'Jason Raitz'].freeze
6
+ AUTHOR_EMAILS = ['dmoles@berkeley.edu', 'matienzo@berkeley.edu', 'raitz@berkeley.edu'].freeze
7
7
  SUMMARY = 'Miscellaneous Ruby utilities for the UC Berkeley Library'.freeze
8
8
  DESCRIPTION = 'A collection of miscellaneous Ruby routines for the UC Berkeley Library.'.freeze
9
9
  LICENSE = 'MIT'.freeze
10
- VERSION = '0.2.0'.freeze
10
+ VERSION = '0.3.0'.freeze
11
11
  HOMEPAGE = 'https://github.com/BerkeleyLibrary/util'.freeze
12
12
  end
13
13
  end
@@ -0,0 +1,27 @@
1
+ require 'berkeley_library/util/uris'
2
+
3
+ module BerkeleyLibrary
4
+ module Util
5
+ # :nocov:
6
+ if defined?(::OkComputer)
7
+ class HeadCheck < ::OkComputer::HttpCheck
8
+
9
+ def perform_request
10
+ headers = {}
11
+ if basic_auth_options.any?
12
+ user, password = basic_auth_options
13
+ headers['Authorization'] = "Basic #{Base64.strict_encode64("#{user}:#{password}")}"
14
+ end
15
+
16
+ options = { headers: headers, log: false }
17
+ options[:timeout] = request_timeout.to_i if request_timeout
18
+
19
+ URIs.head_response(url, **options)
20
+ rescue StandardError => e
21
+ raise OkComputer::HttpCheck::ConnectionFailed, e
22
+ end
23
+ end
24
+ end
25
+ # :nocov:
26
+ end
27
+ end
@@ -13,9 +13,11 @@ module BerkeleyLibrary
13
13
  # @param log [Boolean] whether to log each request URL and response code
14
14
  # @param max_retries [Integer] the maximum number of times to retry after a 429 or 503 with Retry-After
15
15
  # @param max_retry_delay [Integer] the maximum retry delay (in seconds) to accept in a Retry-After header
16
+ # @param timeout [Integer] the request timeout in seconds (RestClient will use this to set both open and read timeouts)
16
17
  # @raise [RestClient::Exception] in the event of an unsuccessful request.
17
- def get(uri, params: {}, headers: {}, log: true, max_retries: MAX_RETRIES, max_retry_delay: MAX_RETRY_DELAY_SECONDS)
18
- resp = make_request(:get, uri, params, headers, log, max_retries, max_retry_delay)
18
+ def get(uri, params: {}, headers: {}, log: true, max_retries: MAX_RETRIES, max_retry_delay: MAX_RETRY_DELAY_SECONDS,
19
+ timeout: DEFAULT_TIMEOUT_SECONDS)
20
+ resp = make_request(:get, uri, params, headers, log, max_retries, max_retry_delay, timeout)
19
21
  resp.body
20
22
  end
21
23
 
@@ -28,8 +30,10 @@ module BerkeleyLibrary
28
30
  # @param headers [Hash] the request headers.
29
31
  # @param log [Boolean] whether to log each request URL and response code
30
32
  # @return [Integer] the response code as an integer.
31
- def head(uri, params: {}, headers: {}, log: true, max_retries: MAX_RETRIES, max_retry_delay: MAX_RETRY_DELAY_SECONDS)
32
- head_response(uri, params: params, headers: headers, log: log, max_retries: max_retries, max_retry_delay: max_retry_delay).code
33
+ def head(uri, params: {}, headers: {}, log: true, max_retries: MAX_RETRIES, max_retry_delay: MAX_RETRY_DELAY_SECONDS,
34
+ timeout: DEFAULT_TIMEOUT_SECONDS)
35
+ head_response(uri, params: params, headers: headers, log: log, max_retries: max_retries, max_retry_delay: max_retry_delay,
36
+ timeout: timeout).code
33
37
  end
34
38
 
35
39
  # Performs a GET request and returns the response, even in the event of
@@ -40,8 +44,9 @@ module BerkeleyLibrary
40
44
  # @param headers [Hash] the request headers.
41
45
  # @param log [Boolean] whether to log each request URL and response code
42
46
  # @return [RestClient::Response] the response
43
- def get_response(uri, params: {}, headers: {}, log: true, max_retries: MAX_RETRIES, max_retry_delay: MAX_RETRY_DELAY_SECONDS)
44
- make_request(:get, uri, params, headers, log, max_retries, max_retry_delay)
47
+ def get_response(uri, params: {}, headers: {}, log: true, max_retries: MAX_RETRIES, max_retry_delay: MAX_RETRY_DELAY_SECONDS,
48
+ timeout: DEFAULT_TIMEOUT_SECONDS)
49
+ make_request(:get, uri, params, headers, log, max_retries, max_retry_delay, timeout)
45
50
  rescue RestClient::Exception => e
46
51
  e.response
47
52
  end
@@ -54,15 +59,18 @@ module BerkeleyLibrary
54
59
  # @param headers [Hash] the request headers.
55
60
  # @param log [Boolean] whether to log each request URL and response code
56
61
  # @return [RestClient::Response] the response
57
- def head_response(uri, params: {}, headers: {}, log: true, max_retries: MAX_RETRIES, max_retry_delay: MAX_RETRY_DELAY_SECONDS)
58
- make_request(:head, uri, params, headers, log, max_retries, max_retry_delay)
62
+ def head_response(uri, params: {}, headers: {}, log: true, max_retries: MAX_RETRIES, max_retry_delay: MAX_RETRY_DELAY_SECONDS,
63
+ timeout: DEFAULT_TIMEOUT_SECONDS)
64
+ make_request(:head, uri, params, headers, log, max_retries, max_retry_delay, timeout)
59
65
  rescue RestClient::Exception => e
60
- e.response
66
+ return e.response if e.response
67
+
68
+ raise
61
69
  end
62
70
 
63
71
  private
64
72
 
65
- def make_request(method, url, params, headers, log, max_retries, max_retry_delay)
73
+ def make_request(method, url, params, headers, log, max_retries, max_retry_delay, timeout)
66
74
  Requester.new(
67
75
  method,
68
76
  url,
@@ -70,7 +78,8 @@ module BerkeleyLibrary
70
78
  headers: headers,
71
79
  log: log,
72
80
  max_retries: max_retries,
73
- max_retry_delay: max_retry_delay
81
+ max_retry_delay: max_retry_delay,
82
+ timeout: timeout
74
83
  ).make_request
75
84
  end
76
85
 
@@ -20,11 +20,12 @@ module BerkeleyLibrary
20
20
  RETRY_STATUSES = [429, 503].freeze
21
21
  MAX_RETRY_DELAY_SECONDS = 10
22
22
  MAX_RETRIES = 3
23
+ DEFAULT_TIMEOUT_SECONDS = 10
23
24
 
24
25
  # ------------------------------------------------------------
25
26
  # Attributes
26
27
 
27
- attr_reader :method, :url_str, :headers, :log, :max_retries, :max_retry_delay
28
+ attr_reader :method, :url_str, :headers, :log, :max_retries, :max_retry_delay, :timeout
28
29
 
29
30
  # ------------------------------------------------------------
30
31
  # Initializer
@@ -38,9 +39,11 @@ module BerkeleyLibrary
38
39
  # @param log [Boolean] whether to log each request URL and response code
39
40
  # @param max_retries [Integer] the maximum number of times to retry after a 429 or 503 with Retry-After
40
41
  # @param max_retry_delay [Integer] the maximum retry delay (in seconds) to accept in a Retry-After header
42
+ # @param timeout [Integer] the request timeout in seconds (RestClient will use this to set both open and read timeouts)
41
43
  # @raise URI::InvalidURIError if the specified URL is invalid
42
44
  # rubocop:disable Metrics/ParameterLists
43
- def initialize(method, url, params: {}, headers: {}, log: true, max_retries: MAX_RETRIES, max_retry_delay: MAX_RETRY_DELAY_SECONDS)
45
+ def initialize(method, url, params: {}, headers: {}, log: true, max_retries: MAX_RETRIES, max_retry_delay: MAX_RETRY_DELAY_SECONDS,
46
+ timeout: DEFAULT_TIMEOUT_SECONDS)
44
47
  raise ArgumentError, "#{method} not supported" unless SUPPORTED_METHODS.include?(method)
45
48
  raise ArgumentError, 'url cannot be nil' unless (uri = Validator.uri_or_nil(url))
46
49
 
@@ -50,6 +53,7 @@ module BerkeleyLibrary
50
53
  @log = log
51
54
  @max_retries = max_retries
52
55
  @max_retry_delay = max_retry_delay
56
+ @timeout = timeout
53
57
  end
54
58
 
55
59
  # rubocop:enable Metrics/ParameterLists
@@ -73,7 +77,7 @@ module BerkeleyLibrary
73
77
  private
74
78
 
75
79
  def log_response(response)
76
- return unless log
80
+ return unless log && response&.code
77
81
 
78
82
  logger.info("#{method.to_s.upcase} #{url_str} returned #{response.code}")
79
83
  end
@@ -90,6 +94,8 @@ module BerkeleyLibrary
90
94
 
91
95
  def execute_request(retries_remaining = max_retries)
92
96
  try_execute_request
97
+ rescue RestClient::Exceptions::Timeout
98
+ raise
93
99
  rescue RestClient::Exception => e
94
100
  response = e.response
95
101
  raise unless (retry_delay = retry_delay_from(response))
@@ -99,7 +105,7 @@ module BerkeleyLibrary
99
105
  end
100
106
 
101
107
  def try_execute_request
102
- RestClient::Request.execute(method: method, url: url_str, headers: headers).tap do |response|
108
+ RestClient::Request.execute(method: method, url: url_str, headers: headers, timeout: timeout).tap do |response|
103
109
  # Not all failed RestClient requests throw exceptions
104
110
  raise(exception_for(response)) unless response.code == 200
105
111
  end
@@ -34,8 +34,8 @@ module BerkeleyLibrary
34
34
  # @param log [Boolean] whether to log each request URL and response code
35
35
  # @return [String] the body as a string.
36
36
  # @raise [RestClient::Exception] in the event of an unsuccessful request.
37
- def get(uri, params: {}, headers: {}, log: true)
38
- Requester.get(uri, params: params, headers: headers, log: log)
37
+ def get(uri, params: {}, headers: {}, log: true, timeout: Requester::DEFAULT_TIMEOUT_SECONDS)
38
+ Requester.get(uri, params: params, headers: headers, log: log, timeout: timeout)
39
39
  end
40
40
 
41
41
  # Performs a HEAD request and returns the response status as an integer.
@@ -47,8 +47,8 @@ module BerkeleyLibrary
47
47
  # @param headers [Hash] the request headers.
48
48
  # @param log [Boolean] whether to log each request URL and response code
49
49
  # @return [Integer] the response code as an integer.
50
- def head(uri, params: {}, headers: {}, log: true)
51
- Requester.head(uri, params: params, headers: headers, log: log)
50
+ def head(uri, params: {}, headers: {}, log: true, timeout: Requester::DEFAULT_TIMEOUT_SECONDS)
51
+ Requester.head(uri, params: params, headers: headers, log: log, timeout: timeout)
52
52
  end
53
53
 
54
54
  # Performs a GET request and returns the response, even in the event of
@@ -59,8 +59,8 @@ module BerkeleyLibrary
59
59
  # @param headers [Hash] the request headers.
60
60
  # @param log [Boolean] whether to log each request URL and response code
61
61
  # @return [RestClient::Response] the response
62
- def get_response(uri, params: {}, headers: {}, log: true)
63
- Requester.get_response(uri, params: params, headers: headers, log: log)
62
+ def get_response(uri, params: {}, headers: {}, log: true, timeout: Requester::DEFAULT_TIMEOUT_SECONDS)
63
+ Requester.get_response(uri, params: params, headers: headers, log: log, timeout: timeout)
64
64
  end
65
65
 
66
66
  # Performs a HEAD request and returns the response, even in the event of
@@ -71,8 +71,8 @@ module BerkeleyLibrary
71
71
  # @param headers [Hash] the request headers.
72
72
  # @param log [Boolean] whether to log each request URL and response code
73
73
  # @return [RestClient::Response] the response
74
- def head_response(uri, params: {}, headers: {}, log: true)
75
- Requester.head_response(uri, params: params, headers: headers, log: log)
74
+ def head_response(uri, params: {}, headers: {}, log: true, timeout: Requester::DEFAULT_TIMEOUT_SECONDS)
75
+ Requester.head_response(uri, params: params, headers: headers, log: log, timeout: timeout)
76
76
  end
77
77
 
78
78
  # Returns the specified URL as a URI, or `nil` if the URL is `nil`.
@@ -1 +1 @@
1
- Dir.glob(File.expand_path('util/*.rb', __dir__)).sort.each(&method(:require))
1
+ Dir.glob(File.expand_path('util/*.rb', __dir__)).each(&method(:require))
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+ require 'okcomputer'
3
+ require 'berkeley_library/util/uris/head_check'
4
+ require 'base64'
5
+
6
+ module BerkeleyLibrary
7
+ module Util
8
+ RSpec.describe HeadCheck do
9
+ let(:url) { 'http://example.com' }
10
+ let(:check) { described_class.new(url) }
11
+ let(:mock_response) { instance_double(RestClient::Response) }
12
+
13
+ before do
14
+ allow(BerkeleyLibrary::Util::URIs).to receive(:head_response).and_return(mock_response)
15
+ end
16
+
17
+ describe '#perform_request' do
18
+ context 'without basic auth' do
19
+ it 'does not add Authorization header' do
20
+ check.perform_request
21
+ expect(BerkeleyLibrary::Util::URIs).not_to have_received(:head_response).with(anything, hash_including('Authorization' => anything), anything)
22
+ end
23
+
24
+ it 'calls URIs.head_response with the correct URL' do
25
+ check.perform_request
26
+ expect(BerkeleyLibrary::Util::URIs).to have_received(:head_response).with(URI(url), headers: {}, log: false, timeout: 5)
27
+ end
28
+ end
29
+
30
+ context 'with basic auth' do
31
+ let(:user) { 'user' }
32
+ let(:password) { 'pass' }
33
+
34
+ # Stub the configuration on the instance directly
35
+ before do
36
+ allow(check).to receive(:basic_auth_options).and_return([user, password])
37
+ end
38
+
39
+ it 'adds the Authorization header' do
40
+ expected_headers = { 'Authorization' => "Basic #{Base64.strict_encode64("#{user}:#{password}")}" }
41
+
42
+ check.perform_request
43
+ expect(BerkeleyLibrary::Util::URIs).to have_received(:head_response).with(URI(url), headers: expected_headers, log: false, timeout: 5)
44
+ end
45
+ end
46
+
47
+ context 'when URIs.head_response raises an error' do
48
+ let(:error_message) { 'Something went wrong' }
49
+
50
+ before do
51
+ allow(BerkeleyLibrary::Util::URIs).to receive(:head_response).and_raise(StandardError, error_message)
52
+ end
53
+
54
+ it 'raises an OkComputer::HttpCheck::ConnectionFailed error' do
55
+ expect { check.perform_request }.to raise_error(OkComputer::HttpCheck::ConnectionFailed, error_message)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -305,6 +305,13 @@ module BerkeleyLibrary
305
305
  requester = Requester.new(:get, url)
306
306
  expect { requester.make_request }.to raise_error(RestClient::ServiceUnavailable)
307
307
  end
308
+
309
+ it "raises #{RestClient::Exceptions::Timeout} when the request times out" do
310
+ url = 'http://example.edu/timeout'
311
+ stub_request(:get, url).to_raise(RestClient::Exceptions::Timeout)
312
+
313
+ expect { Requester.get(url, timeout: 10) }.to raise_error(RestClient::Exceptions::Timeout)
314
+ end
308
315
  end
309
316
  end
310
317
  end
@@ -374,6 +381,13 @@ module BerkeleyLibrary
374
381
  end
375
382
  end
376
383
 
384
+ it "raises #{RestClient::Exceptions::Timeout} when the request times out" do
385
+ url = 'http://example.edu/timeout'
386
+ stub_request(:head, url).to_raise(RestClient::Exceptions::Timeout)
387
+
388
+ expect { Requester.head(url, timeout: 10) }.to raise_error(RestClient::Exceptions::Timeout)
389
+ end
390
+
377
391
  it 'handles redirects' do
378
392
  url1 = 'https://example.org/'
379
393
  url2 = 'https://example.edu/'
metadata CHANGED
@@ -1,15 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: berkeley_library-util
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Moles
8
8
  - maría a. matienzo
9
+ - Jason Raitz
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2025-07-24 00:00:00.000000000 Z
13
+ date: 2026-02-04 00:00:00.000000000 Z
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
16
  name: berkeley_library-logging
@@ -95,6 +96,20 @@ dependencies:
95
96
  - - "~>"
96
97
  - !ruby/object:Gem::Version
97
98
  version: '2.7'
99
+ - !ruby/object:Gem::Dependency
100
+ name: okcomputer
101
+ requirement: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - "~>"
104
+ - !ruby/object:Gem::Version
105
+ version: '1.19'
106
+ type: :development
107
+ prerelease: false
108
+ version_requirements: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - "~>"
111
+ - !ruby/object:Gem::Version
112
+ version: '1.19'
98
113
  - !ruby/object:Gem::Dependency
99
114
  name: rake
100
115
  requirement: !ruby/object:Gem::Requirement
@@ -211,6 +226,7 @@ description: A collection of miscellaneous Ruby routines for the UC Berkeley Lib
211
226
  email:
212
227
  - dmoles@berkeley.edu
213
228
  - matienzo@berkeley.edu
229
+ - raitz@berkeley.edu
214
230
  executables: []
215
231
  extensions: []
216
232
  extra_rdoc_files: []
@@ -248,6 +264,7 @@ files:
248
264
  - lib/berkeley_library/util/uris.rb
249
265
  - lib/berkeley_library/util/uris/appender.rb
250
266
  - lib/berkeley_library/util/uris/exceptions.rb
267
+ - lib/berkeley_library/util/uris/head_check.rb
251
268
  - lib/berkeley_library/util/uris/requester.rb
252
269
  - lib/berkeley_library/util/uris/requester/class_methods.rb
253
270
  - lib/berkeley_library/util/uris/validator.rb
@@ -263,6 +280,7 @@ files:
263
280
  - spec/berkeley_library/util/stringios_spec.rb
264
281
  - spec/berkeley_library/util/strings_spec.rb
265
282
  - spec/berkeley_library/util/times_spec.rb
283
+ - spec/berkeley_library/util/uris/head_check_spec.rb
266
284
  - spec/berkeley_library/util/uris/requester_spec.rb
267
285
  - spec/berkeley_library/util/uris/validator_spec.rb
268
286
  - spec/berkeley_library/util/uris_spec.rb