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.
Files changed (76) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +14 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +183 -0
  6. data/Rakefile +11 -0
  7. data/bd_metrics/finditem_measure.rb +61 -0
  8. data/bd_metrics/isbn.txt +1088 -0
  9. data/bd_metrics/lccn.txt +1668 -0
  10. data/bd_metrics/oclc.txt +167 -0
  11. data/borrow_direct.gemspec +30 -0
  12. data/lib/borrow_direct/authentication.rb +55 -0
  13. data/lib/borrow_direct/defaults.rb +38 -0
  14. data/lib/borrow_direct/error.rb +17 -0
  15. data/lib/borrow_direct/find_item.rb +149 -0
  16. data/lib/borrow_direct/generate_query.rb +78 -0
  17. data/lib/borrow_direct/request.rb +185 -0
  18. data/lib/borrow_direct/request_item.rb +119 -0
  19. data/lib/borrow_direct/request_query.rb +124 -0
  20. data/lib/borrow_direct/util.rb +18 -0
  21. data/lib/borrow_direct/version.rb +3 -0
  22. data/lib/borrow_direct.rb +19 -0
  23. data/test/authentication_test.rb +79 -0
  24. data/test/find_item_test.rb +159 -0
  25. data/test/generate_query_test.rb +91 -0
  26. data/test/request_item_test.rb +109 -0
  27. data/test/request_query_test.rb +113 -0
  28. data/test/request_test.rb +141 -0
  29. data/test/support/assertions.rb +23 -0
  30. data/test/support/vcr_filter.rb +45 -0
  31. data/test/test_helper.rb +39 -0
  32. data/test/util_test.rb +32 -0
  33. data/test/vcr_cassettes/Authentication/Makes_a_request_succesfully.yml +52 -0
  34. data/test/vcr_cassettes/Authentication/Raises_for_bad_library_symbol.yml +52 -0
  35. data/test/vcr_cassettes/Authentication/Raises_for_bad_patron_barcode.yml +53 -0
  36. data/test/vcr_cassettes/Authentication/get_auth_id/raises_for_a_bad_library_symbol.yml +52 -0
  37. data/test/vcr_cassettes/Authentication/get_auth_id/raises_for_a_bad_patron_barcode.yml +53 -0
  38. data/test/vcr_cassettes/Authentication/get_auth_id/returns_an_auth_id_for_a_good_request.yml +52 -0
  39. data/test/vcr_cassettes/Authentication/raw_request_to_verify_HTTP_api/.yml +52 -0
  40. data/test/vcr_cassettes/FindItem/_find_item_request/finds_a_locally_available_item.yml +49 -0
  41. data/test/vcr_cassettes/FindItem/_find_item_request/finds_a_requestable_item.yml +49 -0
  42. data/test/vcr_cassettes/FindItem/_find_item_request/finds_an_item_that_does_not_exist_in_BD.yml +50 -0
  43. data/test/vcr_cassettes/FindItem/_find_item_request/with_expected_error_PUBFI002/returns_result.yml +40 -0
  44. data/test/vcr_cassettes/FindItem/_find_item_request/works_with_multiple_values.yml +49 -0
  45. data/test/vcr_cassettes/FindItem/find_with_Response/has_an_auth_id.yml +49 -0
  46. data/test/vcr_cassettes/FindItem/find_with_Response/has_nil_auth_id_when_BD_doesn_t_want_to_give_us_one.yml +40 -0
  47. data/test/vcr_cassettes/FindItem/find_with_Response/has_nil_pickup_locations_when_BD_doesn_t_want_to_give_us_them.yml +40 -0
  48. data/test/vcr_cassettes/FindItem/find_with_Response/has_pickup_locations.yml +49 -0
  49. data/test/vcr_cassettes/FindItem/find_with_Response/not_requestable_for_item_that_BD_returns_PUBFI002.yml +40 -0
  50. data/test/vcr_cassettes/FindItem/find_with_Response/not_requestable_for_item_that_does_not_exist_in_BD.yml +50 -0
  51. data/test/vcr_cassettes/FindItem/find_with_Response/not_requestable_for_item_that_no_libraries_will_lend.yml +50 -0
  52. data/test/vcr_cassettes/FindItem/find_with_Response/not_requestable_for_locally_available_item.yml +49 -0
  53. data/test/vcr_cassettes/FindItem/find_with_Response/requestable_for_requestable_item.yml +49 -0
  54. data/test/vcr_cassettes/FindItem/find_with_Response/requestable_with_multiple_items_if_at_least_one_is_requestable.yml +49 -0
  55. data/test/vcr_cassettes/Request/authentication_id/automatically_fetches_one_when_needed.yml +52 -0
  56. data/test/vcr_cassettes/Request/authentication_id/can_refetch_when_instructed.yml +52 -0
  57. data/test/vcr_cassettes/Request/can_make_a_succesful_request.yml +49 -0
  58. data/test/vcr_cassettes/Request/gets_BD_error_info.yml +41 -0
  59. data/test/vcr_cassettes/Request/raises_on_bad_path.yml +53 -0
  60. data/test/vcr_cassettes/Request/raises_on_bad_request_hash.yml +63 -0
  61. data/test/vcr_cassettes/Request/with_expected_errors/still_returns_result.yml +41 -0
  62. data/test/vcr_cassettes/RequestItem/make_request/make_request_for_a_locally_available_item.yml +90 -0
  63. data/test/vcr_cassettes/RequestItem/make_request/make_request_for_a_requestable_item.yml +89 -0
  64. data/test/vcr_cassettes/RequestItem/make_request/make_request_for_an_unrequestable_item.yml +91 -0
  65. data/test/vcr_cassettes/RequestItem/make_request/raises_for_unrequestable.yml +91 -0
  66. data/test/vcr_cassettes/RequestItem/make_request/returns_number_for_succesful_request.yml +89 -0
  67. data/test/vcr_cassettes/RequestItem/make_request/says_no_for_item_that_BD_returns_PUBRI004.yml +89 -0
  68. data/test/vcr_cassettes/RequestItem/raw_requests_an_unrequestable_item.yml +91 -0
  69. data/test/vcr_cassettes/RequestItem/uses_manually_set_auth_id.yml +89 -0
  70. data/test/vcr_cassettes/RequestItem/with_pickup_location_and_requestable_item/still_works.yml +90 -0
  71. data/test/vcr_cassettes/RequestQuery/raw_request_query_request/returns_results.yml +381 -0
  72. data/test/vcr_cassettes/RequestQuery/raw_request_to_verify_the_BD_HTTP_API.yml +381 -0
  73. data/test/vcr_cassettes/RequestQuery/requests/fetches_default_records.yml +384 -0
  74. data/test/vcr_cassettes/RequestQuery/requests/fetches_full_records.yml +481 -0
  75. data/test/vcr_cassettes/top_level_describe/an_inner_describe/.yml +76 -0
  76. 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
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in borrow_direct.gemspec
4
+ gemspec
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
+ [![Build Status](https://travis-ci.org/jrochkind/borrow_direct.svg)](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,11 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'lib'
7
+ t.libs << 'test'
8
+ t.pattern = 'test/**/*_test.rb'
9
+ end
10
+
11
+ task :default => [:test]
@@ -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
+