borrow_direct 0.9.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 +15 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +183 -0
- data/Rakefile +11 -0
- data/bd_metrics/finditem_measure.rb +61 -0
- data/bd_metrics/isbn.txt +1088 -0
- data/bd_metrics/lccn.txt +1668 -0
- data/bd_metrics/oclc.txt +167 -0
- data/borrow_direct.gemspec +30 -0
- data/lib/borrow_direct/authentication.rb +55 -0
- data/lib/borrow_direct/defaults.rb +38 -0
- data/lib/borrow_direct/error.rb +17 -0
- data/lib/borrow_direct/find_item.rb +149 -0
- data/lib/borrow_direct/generate_query.rb +78 -0
- data/lib/borrow_direct/request.rb +185 -0
- data/lib/borrow_direct/request_item.rb +119 -0
- data/lib/borrow_direct/request_query.rb +124 -0
- data/lib/borrow_direct/util.rb +18 -0
- data/lib/borrow_direct/version.rb +3 -0
- data/lib/borrow_direct.rb +19 -0
- data/test/authentication_test.rb +79 -0
- data/test/find_item_test.rb +159 -0
- data/test/generate_query_test.rb +91 -0
- data/test/request_item_test.rb +109 -0
- data/test/request_query_test.rb +113 -0
- data/test/request_test.rb +141 -0
- data/test/support/assertions.rb +23 -0
- data/test/support/vcr_filter.rb +45 -0
- data/test/test_helper.rb +39 -0
- data/test/util_test.rb +32 -0
- data/test/vcr_cassettes/Authentication/Makes_a_request_succesfully.yml +52 -0
- data/test/vcr_cassettes/Authentication/Raises_for_bad_library_symbol.yml +52 -0
- data/test/vcr_cassettes/Authentication/Raises_for_bad_patron_barcode.yml +53 -0
- data/test/vcr_cassettes/Authentication/get_auth_id/raises_for_a_bad_library_symbol.yml +52 -0
- data/test/vcr_cassettes/Authentication/get_auth_id/raises_for_a_bad_patron_barcode.yml +53 -0
- data/test/vcr_cassettes/Authentication/get_auth_id/returns_an_auth_id_for_a_good_request.yml +52 -0
- data/test/vcr_cassettes/Authentication/raw_request_to_verify_HTTP_api/.yml +52 -0
- data/test/vcr_cassettes/FindItem/_find_item_request/finds_a_locally_available_item.yml +49 -0
- data/test/vcr_cassettes/FindItem/_find_item_request/finds_a_requestable_item.yml +49 -0
- data/test/vcr_cassettes/FindItem/_find_item_request/finds_an_item_that_does_not_exist_in_BD.yml +50 -0
- data/test/vcr_cassettes/FindItem/_find_item_request/with_expected_error_PUBFI002/returns_result.yml +40 -0
- data/test/vcr_cassettes/FindItem/_find_item_request/works_with_multiple_values.yml +49 -0
- data/test/vcr_cassettes/FindItem/find_with_Response/has_an_auth_id.yml +49 -0
- data/test/vcr_cassettes/FindItem/find_with_Response/has_nil_auth_id_when_BD_doesn_t_want_to_give_us_one.yml +40 -0
- data/test/vcr_cassettes/FindItem/find_with_Response/has_nil_pickup_locations_when_BD_doesn_t_want_to_give_us_them.yml +40 -0
- data/test/vcr_cassettes/FindItem/find_with_Response/has_pickup_locations.yml +49 -0
- data/test/vcr_cassettes/FindItem/find_with_Response/not_requestable_for_item_that_BD_returns_PUBFI002.yml +40 -0
- data/test/vcr_cassettes/FindItem/find_with_Response/not_requestable_for_item_that_does_not_exist_in_BD.yml +50 -0
- data/test/vcr_cassettes/FindItem/find_with_Response/not_requestable_for_item_that_no_libraries_will_lend.yml +50 -0
- data/test/vcr_cassettes/FindItem/find_with_Response/not_requestable_for_locally_available_item.yml +49 -0
- data/test/vcr_cassettes/FindItem/find_with_Response/requestable_for_requestable_item.yml +49 -0
- data/test/vcr_cassettes/FindItem/find_with_Response/requestable_with_multiple_items_if_at_least_one_is_requestable.yml +49 -0
- data/test/vcr_cassettes/Request/authentication_id/automatically_fetches_one_when_needed.yml +52 -0
- data/test/vcr_cassettes/Request/authentication_id/can_refetch_when_instructed.yml +52 -0
- data/test/vcr_cassettes/Request/can_make_a_succesful_request.yml +49 -0
- data/test/vcr_cassettes/Request/gets_BD_error_info.yml +41 -0
- data/test/vcr_cassettes/Request/raises_on_bad_path.yml +53 -0
- data/test/vcr_cassettes/Request/raises_on_bad_request_hash.yml +63 -0
- data/test/vcr_cassettes/Request/with_expected_errors/still_returns_result.yml +41 -0
- data/test/vcr_cassettes/RequestItem/make_request/make_request_for_a_locally_available_item.yml +90 -0
- data/test/vcr_cassettes/RequestItem/make_request/make_request_for_a_requestable_item.yml +89 -0
- data/test/vcr_cassettes/RequestItem/make_request/make_request_for_an_unrequestable_item.yml +91 -0
- data/test/vcr_cassettes/RequestItem/make_request/raises_for_unrequestable.yml +91 -0
- data/test/vcr_cassettes/RequestItem/make_request/returns_number_for_succesful_request.yml +89 -0
- data/test/vcr_cassettes/RequestItem/make_request/says_no_for_item_that_BD_returns_PUBRI004.yml +89 -0
- data/test/vcr_cassettes/RequestItem/raw_requests_an_unrequestable_item.yml +91 -0
- data/test/vcr_cassettes/RequestItem/uses_manually_set_auth_id.yml +89 -0
- data/test/vcr_cassettes/RequestItem/with_pickup_location_and_requestable_item/still_works.yml +90 -0
- data/test/vcr_cassettes/RequestQuery/raw_request_query_request/returns_results.yml +381 -0
- data/test/vcr_cassettes/RequestQuery/raw_request_to_verify_the_BD_HTTP_API.yml +381 -0
- data/test/vcr_cassettes/RequestQuery/requests/fetches_default_records.yml +384 -0
- data/test/vcr_cassettes/RequestQuery/requests/fetches_full_records.yml +481 -0
- data/test/vcr_cassettes/top_level_describe/an_inner_describe/.yml +76 -0
- metadata +262 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MTNmMzNjZTU2NWY3NzJlMThhZmQ0ODExZTZmN2YwNGE2MzJmMDBhOQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NjUxMGE4MTE5YjY3OTcyYTEzOTkzYmRiN2ExYmFiZGQzY2EwZmJmOA==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
YzBmODM3YzUxODBhMTY1ZmI5MTljZWE5N2Q5ODA3YWMzMGQyZWVjNzcwZDA4
|
10
|
+
NDYzZGZkMDI2ZjYzYjVhNDI2MmYyYzJmOGZkMmYwNDg2NjFlYzFiMzQ2YzRm
|
11
|
+
ZGE3MzE2MzU0MTdmMGFhODQ1NTI2ZTQ1NGZlYjdkMTdmMmFjNmM=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NmZmMzcwZWJiMDEyNGZiZjg2ODYwZjRiYThjNjhhZWNkNmYzNGQ0YTI1MmVm
|
14
|
+
YmUwOTI2MGI0OTYzZjQ1YjgxMjI0Mzk1OTcxY2I1NTc5MWJjN2QyZTJiYjg2
|
15
|
+
Yzk4NGJmNzBhMmJiOTc2YmM1MTVkOGY2YmFiNWY4MzVhY2YyMzg=
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Jonathan Rochkind
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
[](https://travis-ci.org/jrochkind/borrow_direct)
|
2
|
+
|
3
|
+
# BorrowDirect
|
4
|
+
|
5
|
+
EXPERIMENTAL WORK IN PROGRESS, MAY HAVE UNSTABLE API
|
6
|
+
|
7
|
+
Ruby tools for programmatic access to BorrowDirect consortial system, powered by Relais D2D software.
|
8
|
+
|
9
|
+
Using API as well as deep-linking to search results and possibly other stuff.
|
10
|
+
|
11
|
+
May also work with other Relais D2D setups with configuration or changes, no idea.
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
Some configuration at boot, perhaps in a Rails initializer:
|
16
|
+
|
17
|
+
~~~ruby
|
18
|
+
# Uses BD Test system by defualt, if you want to use production system instead
|
19
|
+
BorrowDirect::Defaults.api_base = BorrowDirect::Defaults::PRODUCTION_API_BASE
|
20
|
+
|
21
|
+
# Set a default BD LibrarySymbol for your library
|
22
|
+
BorrowDirect::Defaults.library_symbol = "YOURSYMBOL"
|
23
|
+
|
24
|
+
# If you want to do FindItem requests with a default generic patron
|
25
|
+
# barcode
|
26
|
+
BorrowDirect::Defaults.find_item_patron_barcode = "9999999"
|
27
|
+
|
28
|
+
# BorrowDirect can take an awful long time to respond sometimes.
|
29
|
+
# How long are you willing to wait? (Seconds, default 30)
|
30
|
+
BorrowDirect::Defaults.timeout = 10
|
31
|
+
~~~
|
32
|
+
|
33
|
+
Then you can do things.
|
34
|
+
|
35
|
+
### Find an item's requestability (FindItem api)
|
36
|
+
|
37
|
+
~~~ruby
|
38
|
+
# with default generic patron set in config find_item_patron_barcode
|
39
|
+
response = BorrowDirect::FindItem.new.find?(:isbn => "1212121212")
|
40
|
+
# Returns a BorrowDirect::FindItem::Response
|
41
|
+
response.requestable?
|
42
|
+
response.pickup_locations
|
43
|
+
|
44
|
+
# Or with specific patron, with default library symbol
|
45
|
+
BorrowDirect::FindItem.new(patron_barcode).find(:isbn => "121212").requestable?
|
46
|
+
~~~
|
47
|
+
|
48
|
+
|
49
|
+
### Make a request (RequestItem api)
|
50
|
+
~~~ruby
|
51
|
+
request_number = BorrowDirect::RequestItem.new(patron_barcode).make_request(pickup_location, :isbn => "1212121212")
|
52
|
+
# Will return request number, or nil if couldn't be requested.
|
53
|
+
# Or, use make_request! (with exclamation point) to raise if
|
54
|
+
# can't be requested.
|
55
|
+
~~~
|
56
|
+
|
57
|
+
### Get patron's current requests (RequestQuery api)
|
58
|
+
|
59
|
+
~~~ruby
|
60
|
+
items = BorrowDirect::RequestQuery.new(patron_barcode).requests
|
61
|
+
# Returns an array of BorrowDirect::RequestQuery::Item
|
62
|
+
items.each do |item|
|
63
|
+
item.request_number
|
64
|
+
item.title
|
65
|
+
item.date_submitted # a ruby DateTime
|
66
|
+
item.request_status
|
67
|
+
end
|
68
|
+
|
69
|
+
# Or use a BD 'type' argument
|
70
|
+
BorrowDirect::RequestQuery.new(patron_barcode).requests("open")
|
71
|
+
~~~
|
72
|
+
|
73
|
+
### AuthID's
|
74
|
+
|
75
|
+
For BD api that requires an AuthorizationID (RequestItem and RequestQuery), our ruby
|
76
|
+
API still accepts a barcode. The ruby code will make a separate request to retrieve
|
77
|
+
the AuthorizationID behind the scenes.
|
78
|
+
|
79
|
+
If you already have an AuthorizationID, you can set it to avoid this, but at the moment
|
80
|
+
we have no code to rescue from expired authorization ID's (and if we did, depending on
|
81
|
+
how often they expire, it might be less efficient than simply requesting a new one)
|
82
|
+
|
83
|
+
~~~ruby
|
84
|
+
response = BorrowDirect::FindItem.new(patron_barcode).find(:isbn => isbn)
|
85
|
+
auth_id = response.auth_id
|
86
|
+
|
87
|
+
BorrowDirect::RequestItem.new(patron_barcode).with_auth_id(auth_id).make_request(pickup_location, :isbn => isbn)
|
88
|
+
~~~
|
89
|
+
|
90
|
+
### Generate a query into BorrowDirect
|
91
|
+
|
92
|
+
Sometimes you may want to send the user to specific search results inside the standard BorrowDirect HTML interface. We include a helper class for generating such queries.
|
93
|
+
|
94
|
+
This helper class currently assumes you run a front-end "redirect" script to authenticate your users and send them to BorrowDirect, and depends on that. You will need to ensure your script also takes any`query=X` URL query parameter sent to it, and includes this in the auth redirect to BorrowDirect.
|
95
|
+
|
96
|
+
~~~ruby
|
97
|
+
BorrowDirect::Defaults.html_base_url = "https://university.edu/borrow_direct_auth_redirector"
|
98
|
+
|
99
|
+
# Generate a link to search results:
|
100
|
+
BorrowDirect::GenerateQuery.new.query_url_with(:isbn => "1234435445")
|
101
|
+
|
102
|
+
# Multiple fields can be included, their values will be treated
|
103
|
+
# as phrase searches, and boolean AND'd together. All the fields
|
104
|
+
# from the BorrowDirect "advanced search" are supported
|
105
|
+
BorrowDirect::GenerateQuery.new.query_url_with(
|
106
|
+
:author => "John Smith",
|
107
|
+
:title => "Some Book",
|
108
|
+
:keyword => "stuff",
|
109
|
+
:subject => "medicine",
|
110
|
+
:isbn => "1234435445")
|
111
|
+
~~~
|
112
|
+
|
113
|
+
Sometimes you want to generate a search for a specific known item, and use
|
114
|
+
an ISBN if available, otherwise an author/title search. That is one of our
|
115
|
+
own main use cases for these deep links. The `#best_known_item_query_url_with`
|
116
|
+
method is available to automatically use ISBN if available, otherwise author/title.
|
117
|
+
|
118
|
+
The GenerateQuery class can be enhanced if there is demand; to allow more
|
119
|
+
flexible searches (instead of always phrase searches with boolean AND); to or allow
|
120
|
+
sending barcode directly to BD instead of relying on a local authenticating redirect
|
121
|
+
script.
|
122
|
+
|
123
|
+
|
124
|
+
|
125
|
+
### Errors
|
126
|
+
|
127
|
+
In error conditions, a BorrowDirect::Error may be thrown -- including request timeouts when
|
128
|
+
BD is taking too long to respond. You can set timeout value with default config, or
|
129
|
+
for each api object.
|
130
|
+
|
131
|
+
## Installation
|
132
|
+
|
133
|
+
Add this line to your application's Gemfile:
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
gem 'borrow_direct'
|
137
|
+
```
|
138
|
+
|
139
|
+
And then execute:
|
140
|
+
|
141
|
+
$ bundle
|
142
|
+
|
143
|
+
Or install it yourself as:
|
144
|
+
|
145
|
+
$ gem install borrow_direct
|
146
|
+
|
147
|
+
## Running tests
|
148
|
+
|
149
|
+
Test coverage is with Minitest::Spec -- if more convenient, you can use Minitest::Unit
|
150
|
+
style instead. But we do not use rspec; and we use Minispec assertion style (assert_x) not
|
151
|
+
expectation style please (not x.must_).
|
152
|
+
|
153
|
+
Run tests with
|
154
|
+
*`rake test`
|
155
|
+
* or a specific test file with `ruby -Ilib:test ./test/some_test.rb`
|
156
|
+
|
157
|
+
Tests are recorded with the [VCR](https://github.com/vcr/vcr) gem,
|
158
|
+
so tests can be re-run without actually contacting BorrowDirect server, it uses
|
159
|
+
the recorded transactions.
|
160
|
+
|
161
|
+
To re-run tests with live HTTP connections to BD
|
162
|
+
* delete all or some of the cassettes in `./test/vcr_cassettes`
|
163
|
+
* set shell ENV variables `BD_LIBRARY_SYMBOL` and `BD_PATRON` to values
|
164
|
+
that will be used for testing, and re-recording cassettes
|
165
|
+
* There are some constants at the top of the testing file that identify
|
166
|
+
ISBN's expected to have certain characteristics (like being requestable, or not).
|
167
|
+
If those characteristics are not true for your library, you may need to reset
|
168
|
+
those constants to values that meet expected conditions.
|
169
|
+
|
170
|
+
Your barcode and library symbol credentials are not stored in the VCR cassettes,
|
171
|
+
they are filtered out.
|
172
|
+
|
173
|
+
The tests are run against the BD test system, but the email address associated
|
174
|
+
with the `BD_PATRON` will likely still get multiple emails generated to it as a result
|
175
|
+
of testing.
|
176
|
+
|
177
|
+
## Contributing
|
178
|
+
|
179
|
+
1. Fork it ( https://github.com/[my-github-username]/borrow_direct/fork )
|
180
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
181
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
182
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
183
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# ruby -Ilib:test ./bd_metrics/finditem_measure.rb
|
4
|
+
|
5
|
+
require 'borrow_direct'
|
6
|
+
require 'borrow_direct/find_item'
|
7
|
+
|
8
|
+
key = ARGV[0] || "isbn"
|
9
|
+
sourcefile = ARGV[1] || File.expand_path("../#{key}.txt", __FILE__)
|
10
|
+
|
11
|
+
puts "#{key}: #{sourcefile}"
|
12
|
+
|
13
|
+
identifiers = File.readlines(sourcefile).shuffle
|
14
|
+
|
15
|
+
puts " #{identifiers.count} total input identifiers"
|
16
|
+
|
17
|
+
times = []
|
18
|
+
errors = []
|
19
|
+
finder = BorrowDirect::FindItem.new(ENV["BD_FINDITEM_PATRON"], ENV["BD_LIBRARY_SYMBOL"])
|
20
|
+
|
21
|
+
|
22
|
+
at_exit do
|
23
|
+
puts "\n\nERRORS: "
|
24
|
+
errors.each do |arr|
|
25
|
+
puts arr.inspect
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
i = 0
|
30
|
+
identifiers.each do |id|
|
31
|
+
id = id.chomp
|
32
|
+
i = i + 1
|
33
|
+
|
34
|
+
start = Time.now
|
35
|
+
|
36
|
+
begin
|
37
|
+
finder.find_item_request(key => id)
|
38
|
+
rescue BorrowDirect::Error => e
|
39
|
+
errors << [key, id, e]
|
40
|
+
end
|
41
|
+
elapsed = Time.now - start
|
42
|
+
|
43
|
+
times << elapsed
|
44
|
+
times.sort!
|
45
|
+
|
46
|
+
if i % 10 == 0
|
47
|
+
min = times[0]
|
48
|
+
tenth = times[(times.count / 10) - 1]
|
49
|
+
median = times[(times.count / 2) - 1]
|
50
|
+
seventyfifth = times[(times.count - (times.count / 4)) - 1]
|
51
|
+
ninetieth = times[(times.count - (times.count / 10)) - 1]
|
52
|
+
ninetyninth = times[(times.count - (times.count / 100)) - 1]
|
53
|
+
|
54
|
+
max = times[times.count - 1]
|
55
|
+
|
56
|
+
puts "i==#{i}; min: #{min}; 10th %ile: #{tenth}; median: #{median}; 75th %ile: #{seventyfifth}; 90th %ile: #{ninetieth}; 99th %ile: #{ninetyninth}; max: #{max}"
|
57
|
+
puts " errors: #{errors.count}"
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|