umlaut 3.0.0alpha1

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 (293) hide show
  1. data/LICENSE +7 -0
  2. data/README.md +49 -0
  3. data/Rakefile +37 -0
  4. data/app/assets/images/error.gif +0 -0
  5. data/app/assets/images/export_bg_bot.gif +0 -0
  6. data/app/assets/images/export_bg_mid.gif +0 -0
  7. data/app/assets/images/export_bg_top.gif +0 -0
  8. data/app/assets/images/famfamfam/book_open.png +0 -0
  9. data/app/assets/images/famfamfam/cross.png +0 -0
  10. data/app/assets/images/famfamfam/page_sound.gif +0 -0
  11. data/app/assets/images/famfamfam/page_text.gif +0 -0
  12. data/app/assets/images/famfamfam/page_up.gif +0 -0
  13. data/app/assets/images/famfamfam/page_white.png +0 -0
  14. data/app/assets/images/famfamfam/readme.html +1495 -0
  15. data/app/assets/images/famfamfam/tiny_cross.png +0 -0
  16. data/app/assets/images/frame_remove.gif +0 -0
  17. data/app/assets/images/ico_go.gif +0 -0
  18. data/app/assets/images/jhu_findit.gif +0 -0
  19. data/app/assets/images/list_closed.png +0 -0
  20. data/app/assets/images/list_open.png +0 -0
  21. data/app/assets/images/more_info.gif +0 -0
  22. data/app/assets/images/rails.png +0 -0
  23. data/app/assets/images/request.gif +0 -0
  24. data/app/assets/images/spinner.gif +0 -0
  25. data/app/assets/javascripts/umlaut/ajax_windows.js +35 -0
  26. data/app/assets/javascripts/umlaut/ensure_window_size.js.erb +34 -0
  27. data/app/assets/javascripts/umlaut/expand_contract_toggle.js +25 -0
  28. data/app/assets/javascripts/umlaut/search_autocomplete.js +46 -0
  29. data/app/assets/javascripts/umlaut/simple_visible_toggle.js +8 -0
  30. data/app/assets/javascripts/umlaut/update_html.js +152 -0
  31. data/app/assets/javascripts/umlaut.js +17 -0
  32. data/app/assets/stylesheets/umlaut.css +857 -0
  33. data/app/controllers/application_controller.rb +14 -0
  34. data/app/controllers/export_email_controller.rb +123 -0
  35. data/app/controllers/js_helper_controller.rb +10 -0
  36. data/app/controllers/link_router_controller.rb +87 -0
  37. data/app/controllers/open_search_controller.rb +9 -0
  38. data/app/controllers/resolve_controller.rb +288 -0
  39. data/app/controllers/resource_controller.rb +83 -0
  40. data/app/controllers/search_controller.rb +328 -0
  41. data/app/controllers/search_methods/sfx3.rb +148 -0
  42. data/app/controllers/search_methods/sfx4.rb +257 -0
  43. data/app/controllers/search_methods/sfx_api.rb +47 -0
  44. data/app/controllers/store_controller.rb +64 -0
  45. data/app/controllers/umlaut/controller_behavior.rb +20 -0
  46. data/app/controllers/umlaut/controller_logic.rb +96 -0
  47. data/app/controllers/umlaut/error_handling.rb +48 -0
  48. data/app/controllers/umlaut_controller.rb +112 -0
  49. data/app/helpers/application_helper.rb +4 -0
  50. data/app/helpers/emailer_helper.rb +43 -0
  51. data/app/helpers/export_email_helper.rb +34 -0
  52. data/app/helpers/open_search_helper.rb +7 -0
  53. data/app/helpers/resolve_helper.rb +225 -0
  54. data/app/helpers/search_helper.rb +50 -0
  55. data/app/helpers/umlaut/footer_helper.rb +64 -0
  56. data/app/helpers/umlaut/helper.rb +62 -0
  57. data/app/helpers/umlaut/html_head_helper.rb +37 -0
  58. data/app/helpers/umlaut/url_generation.rb +77 -0
  59. data/app/mailers/emailer.rb +48 -0
  60. data/app/models/clickthrough.rb +2 -0
  61. data/app/models/collection.rb +259 -0
  62. data/app/models/crossref_lookup.rb +2 -0
  63. data/app/models/dispatched_service.rb +58 -0
  64. data/app/models/permalink.rb +29 -0
  65. data/app/models/referent.rb +473 -0
  66. data/app/models/referent_value.rb +14 -0
  67. data/app/models/request.rb +449 -0
  68. data/app/models/service_response.rb +179 -0
  69. data/app/models/service_store.rb +59 -0
  70. data/app/models/service_type_value.rb +58 -0
  71. data/app/models/service_wave.rb +150 -0
  72. data/app/models/sfx_db/az_additional_title.rb +11 -0
  73. data/app/models/sfx_db/az_letter_group.rb +11 -0
  74. data/app/models/sfx_db/az_title.rb +38 -0
  75. data/app/models/sfx_db/az_title_v2.rb +34 -0
  76. data/app/models/sfx_db/isbn.rb +12 -0
  77. data/app/models/sfx_db/issn.rb +12 -0
  78. data/app/models/sfx_db/object.rb +35 -0
  79. data/app/models/sfx_db/object_portfolio.rb +6 -0
  80. data/app/models/sfx_db/publisher.rb +10 -0
  81. data/app/models/sfx_db/sfx_db_base.rb +54 -0
  82. data/app/models/sfx_db/target.rb +9 -0
  83. data/app/models/sfx_db/target_service.rb +10 -0
  84. data/app/models/sfx_db/title.rb +10 -0
  85. data/app/models/sfx_db.rb +10 -0
  86. data/app/models/sfx_url.rb +35 -0
  87. data/app/views/emailer/citation.text.erb +28 -0
  88. data/app/views/emailer/short_citation.text.erb +8 -0
  89. data/app/views/export_email/_email.html.erb +25 -0
  90. data/app/views/export_email/_send_email.html.erb +3 -0
  91. data/app/views/export_email/_send_txt.html.erb +3 -0
  92. data/app/views/export_email/_txt.html.erb +62 -0
  93. data/app/views/export_email/email.html.erb +3 -0
  94. data/app/views/export_email/send_email.html.erb +1 -0
  95. data/app/views/export_email/send_txt.html.erb +1 -0
  96. data/app/views/export_email/txt.html.erb +3 -0
  97. data/app/views/js_helper/loader.erb.js +13 -0
  98. data/app/views/layouts/umlaut.html.erb +52 -0
  99. data/app/views/open_search/index.html.erb +9 -0
  100. data/app/views/resolve/_api_in_progress.xml.erb +21 -0
  101. data/app/views/resolve/_background_progress.html.erb +51 -0
  102. data/app/views/resolve/_background_updater.html.erb +38 -0
  103. data/app/views/resolve/_citation.html.erb +87 -0
  104. data/app/views/resolve/_coins.html.erb +1 -0
  105. data/app/views/resolve/_compact_citation.html.erb +33 -0
  106. data/app/views/resolve/_cover_image.html.erb +35 -0
  107. data/app/views/resolve/_fulltext.html.erb +55 -0
  108. data/app/views/resolve/_help.html.erb +17 -0
  109. data/app/views/resolve/_holding.html.erb +91 -0
  110. data/app/views/resolve/_related_items.html.erb +35 -0
  111. data/app/views/resolve/_search_inside.html.erb +62 -0
  112. data/app/views/resolve/_section_display.html.erb +49 -0
  113. data/app/views/resolve/_service_errors.html.erb +29 -0
  114. data/app/views/resolve/_standard_response_item.html.erb +89 -0
  115. data/app/views/resolve/api.xml.builder +72 -0
  116. data/app/views/resolve/background_status.html.erb +26 -0
  117. data/app/views/resolve/index.html.erb +73 -0
  118. data/app/views/resolve/partial_html_sections.xml.erb +30 -0
  119. data/app/views/search/_a_to_z.html.erb +6 -0
  120. data/app/views/search/_citation.html.erb +94 -0
  121. data/app/views/search/_pager.html.erb +60 -0
  122. data/app/views/search/books.html.erb +103 -0
  123. data/app/views/search/journal_search.html.erb +90 -0
  124. data/app/views/search/journals.html.erb +167 -0
  125. data/app/views/search/opensearch_description.rxml +10 -0
  126. data/app/views/testing/index.html.erb +1 -0
  127. data/app/views/umlaut/README +5 -0
  128. data/app/views/umlaut/error.html.erb +45 -0
  129. data/db/migrate/01_umlaut_init.rb +113 -0
  130. data/db/orig_fixed_data/service_type_values.yml +120 -0
  131. data/db/seeds.rb +7 -0
  132. data/lib/CronTab.rb +192 -0
  133. data/lib/aws_product_sign.rb +146 -0
  134. data/lib/exlibris/aleph/patron.rb +64 -0
  135. data/lib/exlibris/aleph/record.rb +54 -0
  136. data/lib/exlibris/aleph/rest_api.rb +29 -0
  137. data/lib/exlibris/primo/holding.rb +192 -0
  138. data/lib/exlibris/primo/rsrc.rb +17 -0
  139. data/lib/exlibris/primo/searcher.rb +276 -0
  140. data/lib/exlibris/primo/source/aleph.rb +46 -0
  141. data/lib/exlibris/primo/source/distribution/nyu_aleph.rb +323 -0
  142. data/lib/exlibris/primo/toc.rb +17 -0
  143. data/lib/exlibris/primo_ws.rb +140 -0
  144. data/lib/generators/templates/umlaut_services.yml +237 -0
  145. data/lib/generators/umlaut/asset_hooks_generator.rb +44 -0
  146. data/lib/generators/umlaut/install_generator.rb +110 -0
  147. data/lib/hip3/bib.rb +291 -0
  148. data/lib/hip3/bib_searcher.rb +302 -0
  149. data/lib/hip3/custom_field_lookup.rb +44 -0
  150. data/lib/hip3/holding.rb +50 -0
  151. data/lib/hip3/item.rb +65 -0
  152. data/lib/hip3/receipt.rb +7 -0
  153. data/lib/hip3/serial_copy.rb +82 -0
  154. data/lib/holding.rb +32 -0
  155. data/lib/marc_helper.rb +254 -0
  156. data/lib/metadata_helper.rb +312 -0
  157. data/lib/opensearch_feed.rb +398 -0
  158. data/lib/opensearch_query.rb +98 -0
  159. data/lib/referent_filter.rb +16 -0
  160. data/lib/referent_filters/dissertation_catch.rb +45 -0
  161. data/lib/section_renderer.rb +503 -0
  162. data/lib/service.rb +336 -0
  163. data/lib/service_adaptors/ajax_export.rb +37 -0
  164. data/lib/service_adaptors/amazon.rb +412 -0
  165. data/lib/service_adaptors/blacklight.rb +327 -0
  166. data/lib/service_adaptors/book_finder.rb +40 -0
  167. data/lib/service_adaptors/bx.rb +51 -0
  168. data/lib/service_adaptors/cover_thing.rb +73 -0
  169. data/lib/service_adaptors/elsevier_cover.rb +57 -0
  170. data/lib/service_adaptors/email_export.rb +10 -0
  171. data/lib/service_adaptors/ezproxy.rb +171 -0
  172. data/lib/service_adaptors/google_book_search.rb +442 -0
  173. data/lib/service_adaptors/gpo.rb +124 -0
  174. data/lib/service_adaptors/hathi_trust.rb +308 -0
  175. data/lib/service_adaptors/hip3_service.rb +150 -0
  176. data/lib/service_adaptors/hip_holding_search.rb +237 -0
  177. data/lib/service_adaptors/internet_archive.rb +488 -0
  178. data/lib/service_adaptors/isbn_db.rb +86 -0
  179. data/lib/service_adaptors/isi.rb +258 -0
  180. data/lib/service_adaptors/jcr.rb +146 -0
  181. data/lib/service_adaptors/opac.rb +351 -0
  182. data/lib/service_adaptors/open_library.rb +316 -0
  183. data/lib/service_adaptors/open_library_cover.rb +73 -0
  184. data/lib/service_adaptors/primo_service.rb +392 -0
  185. data/lib/service_adaptors/primo_source.rb +78 -0
  186. data/lib/service_adaptors/pubmed.rb +133 -0
  187. data/lib/service_adaptors/request_to_fixture.rb +68 -0
  188. data/lib/service_adaptors/scopus.rb +295 -0
  189. data/lib/service_adaptors/sfx-new.rb +557 -0
  190. data/lib/service_adaptors/sfx.rb +566 -0
  191. data/lib/service_adaptors/sfx_backchannel_record.rb +69 -0
  192. data/lib/service_adaptors/txt_holding_export.rb +32 -0
  193. data/lib/service_adaptors/ulrichs_cover.rb +57 -0
  194. data/lib/service_adaptors/ulrichs_link.rb +47 -0
  195. data/lib/service_adaptors/worldcat.rb +116 -0
  196. data/lib/service_adaptors/worldcat_identities.rb +591 -0
  197. data/lib/tasks/umlaut.rake +134 -0
  198. data/lib/umlaut/default_configuration.rb +5 -0
  199. data/lib/umlaut/routes.rb +136 -0
  200. data/lib/umlaut/version.rb +3 -0
  201. data/lib/umlaut.rb +37 -0
  202. data/lib/umlaut_configurable.rb +343 -0
  203. data/lib/umlaut_http.rb +100 -0
  204. data/lib/xml_schema_helper.rb +109 -0
  205. data/test/dummy/Rakefile +7 -0
  206. data/test/dummy/app/assets/javascripts/application.js +13 -0
  207. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  208. data/test/dummy/app/controllers/application_controller.rb +3 -0
  209. data/test/dummy/app/controllers/umlaut_controller.rb +112 -0
  210. data/test/dummy/app/helpers/application_helper.rb +2 -0
  211. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  212. data/test/dummy/config/application.rb +45 -0
  213. data/test/dummy/config/boot.rb +10 -0
  214. data/test/dummy/config/database-jhu.yml +44 -0
  215. data/test/dummy/config/database.yml +25 -0
  216. data/test/dummy/config/environment.rb +5 -0
  217. data/test/dummy/config/environments/development.rb +34 -0
  218. data/test/dummy/config/environments/production.rb +60 -0
  219. data/test/dummy/config/environments/test.rb +39 -0
  220. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  221. data/test/dummy/config/initializers/inflections.rb +10 -0
  222. data/test/dummy/config/initializers/mime_types.rb +5 -0
  223. data/test/dummy/config/initializers/secret_token.rb +7 -0
  224. data/test/dummy/config/initializers/session_store.rb +8 -0
  225. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  226. data/test/dummy/config/locales/en.yml +5 -0
  227. data/test/dummy/config/routes.rb +61 -0
  228. data/test/dummy/config/umlaut_services.yml +237 -0
  229. data/test/dummy/config.ru +4 -0
  230. data/test/dummy/db/migrate/20111228211210_umlaut_init.rb +113 -0
  231. data/test/dummy/db/schema.rb +124 -0
  232. data/test/dummy/log/development.log +12981 -0
  233. data/test/dummy/log/production.log +0 -0
  234. data/test/dummy/public/404.html +26 -0
  235. data/test/dummy/public/422.html +26 -0
  236. data/test/dummy/public/500.html +26 -0
  237. data/test/dummy/public/favicon.ico +0 -0
  238. data/test/dummy/script/rails +6 -0
  239. data/test/dummy/tmp/cache/assets/C5F/340/sprockets%2F99692920160b7a279b86a80415b79db7 +0 -0
  240. data/test/dummy/tmp/cache/assets/C70/4D0/sprockets%2F034ad2036e623081bd352800786dfe80 +0 -0
  241. data/test/dummy/tmp/cache/assets/C73/920/sprockets%2Fd371318f22900492fd180f17c5e2a504 +9268 -0
  242. data/test/dummy/tmp/cache/assets/C80/980/sprockets%2Fc94807409c1523d43e18d25f35d93c41 +0 -0
  243. data/test/dummy/tmp/cache/assets/C8F/780/sprockets%2Fe47e28558116fb5f8038754e60d1961d +11769 -0
  244. data/test/dummy/tmp/cache/assets/CAA/EB0/sprockets%2F1d179210e8b76f1ea63c802688a015e4 +9271 -0
  245. data/test/dummy/tmp/cache/assets/CBB/9C0/sprockets%2F706f28923fb754cad04b9107c89986a1 +0 -0
  246. data/test/dummy/tmp/cache/assets/CBF/B60/sprockets%2F08ca89671549936265dcb673bf02e36f +0 -0
  247. data/test/dummy/tmp/cache/assets/CC9/9F0/sprockets%2F306166316e2cafd13c15e62b51a2339d +0 -0
  248. data/test/dummy/tmp/cache/assets/CF6/F20/sprockets%2F5b2ffa1103079dfd555197838f87a99f +0 -0
  249. data/test/dummy/tmp/cache/assets/CF7/2B0/sprockets%2F25a7c73655bd3598173b39d9f98bcd46 +862 -0
  250. data/test/dummy/tmp/cache/assets/CFE/080/sprockets%2F37fe9f4255baddbd549a659914929398 +0 -0
  251. data/test/dummy/tmp/cache/assets/D22/060/sprockets%2F9aec77b768e91a802d284271c58e2f7e +21357 -0
  252. data/test/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
  253. data/test/dummy/tmp/cache/assets/D33/6D0/sprockets%2F500129c57f1146e556ec3aacd6cd38c1 +0 -0
  254. data/test/dummy/tmp/cache/assets/D33/FD0/sprockets%2F2ba0b4e6334a77b923e5f770381bb2bf +0 -0
  255. data/test/dummy/tmp/cache/assets/D42/C20/sprockets%2Fbcf14e437b1582bf93b77670acf8e090 +21353 -0
  256. data/test/dummy/tmp/cache/assets/D50/A30/sprockets%2F7d8b294ac433db5d056538f8cf7c66b9 +0 -0
  257. data/test/dummy/tmp/cache/assets/D54/ED0/sprockets%2F71c9fa01091d432b131da3bb73faf3d4 +872 -0
  258. data/test/dummy/tmp/cache/assets/D65/590/sprockets%2Fc1bb92fc3406a126b7dd302edc96d629 +0 -0
  259. data/test/dummy/tmp/cache/assets/D71/6B0/sprockets%2Fde558b71b494cf09b1bf055c8dff0353 +0 -0
  260. data/test/dummy/tmp/cache/assets/D72/610/sprockets%2Fa8c708eeb30ef93de34d755d4f45d023 +859 -0
  261. data/test/dummy/tmp/cache/assets/D76/AD0/sprockets%2Fe2158cde93188cf5ab6457bc6d6602ec +0 -0
  262. data/test/dummy/tmp/cache/assets/D7A/E40/sprockets%2F9622ffcc499a57627cd1bb18fe31b8e4 +11772 -0
  263. data/test/dummy/tmp/cache/assets/D84/210/sprockets%2Fabd0103ccec2b428ac62c94e4c40b384 +0 -0
  264. data/test/dummy/tmp/cache/assets/D9B/770/sprockets%2F8aacf02eb7dbb0949704b28f27b87e0b +0 -0
  265. data/test/dummy/tmp/cache/assets/DA6/A80/sprockets%2F92e26d8e58d5bcc8b8f6c25d1b05b9c1 +0 -0
  266. data/test/dummy/tmp/cache/assets/DE8/790/sprockets%2Fd1333bde2b9aafcc712d11dd09ab35d8 +0 -0
  267. data/test/dummy/tmp/cache/assets/DF7/F30/sprockets%2F7bc16c4109b17fabe29f8ddbbf732d1c +374 -0
  268. data/test/dummy/tmp/cache/assets/E03/570/sprockets%2F493bdc0ac14cd4f57fdfe4253f992bde +0 -0
  269. data/test/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
  270. data/test/dummy/tmp/cache/assets/E0B/4B0/sprockets%2F7988df51a61c81ce6ede4a2d4c8cce4f +377 -0
  271. data/test/dummy/tmp/cache/assets/E5F/960/sprockets%2Fdc007b6cad5c7ef08e33ec28cfff0ef6 +0 -0
  272. data/test/fixtures/dispatched_services.yml +5 -0
  273. data/test/fixtures/permalinks.yml +5 -0
  274. data/test/fixtures/referent_values.yml +1734 -0
  275. data/test/fixtures/referents.yml +156 -0
  276. data/test/fixtures/requests.yml +284 -0
  277. data/test/fixtures/service_responses.yml +5 -0
  278. data/test/fixtures/sfx_urls.yml +4 -0
  279. data/test/performance/browsing_test.rb +9 -0
  280. data/test/test_helper.rb +10 -0
  281. data/test/umlaut_test.rb +7 -0
  282. data/test/unit/aleph_patron_test.rb +39 -0
  283. data/test/unit/aleph_record_benchmarks.rb +28 -0
  284. data/test/unit/aleph_record_test.rb +30 -0
  285. data/test/unit/aws_product_sign_test.rb +93 -0
  286. data/test/unit/collection_test.rb +76 -0
  287. data/test/unit/google_book_search_test.rb +101 -0
  288. data/test/unit/primo_searcher_test.rb +403 -0
  289. data/test/unit/primo_service_test.rb +939 -0
  290. data/test/unit/primo_ws_test.rb +131 -0
  291. data/test/unit/service_response_test.rb +9 -0
  292. data/test/unit/service_test.rb +33 -0
  293. metadata +580 -0
@@ -0,0 +1,302 @@
1
+ #!/usr/bin/ruby
2
+
3
+
4
+ require 'net/http'
5
+ require 'nokogiri'
6
+
7
+ # Hip3 Module has been written for JHU's HIP3 installation. It may not work
8
+ # quite right with other installations, I'm almost certain it needs to be
9
+ # abstracted and parameterized better to be more generic.
10
+ module Hip3
11
+
12
+
13
+ # If multiple search criteria are supplied, will 'or' them all to find
14
+ # bibs matching ANY criteria.
15
+ # keywords should be an array, and will be 'and'ed
16
+ # Searches using the HIP3 xml 'interface', which means it may be sensitive to
17
+ # HIP display changes that change XML.
18
+ # It finds BibNums, and creates Hip3Bib
19
+ # objects based on that bibNum. Doesn't take any other info but Bib num from
20
+ # the actual search response, but it could, and pre-load the bib object.
21
+ class BibSearcher
22
+ ISSN_KW_INDEX = '.IS'
23
+ ISBN_KW_INDEX = '.IB'
24
+
25
+ GEN_KW_INDEX = '.GW'
26
+ TITLE_KW_INDEX = '.TW'
27
+ SERIAL_TITLE_KW_INDEX = '.ST'
28
+ AUTHOR_KW_INDEX = '.AW'
29
+
30
+ BIBNUM_INDEX = 'BIB'
31
+
32
+ SUDOC_KW_INDEX = '.SD'
33
+
34
+ attr_accessor :httpSession
35
+ attr_accessor :hip_base_url_str, :hip_base_url
36
+ attr_reader :issn, :isbn # writers provided concretely
37
+ attr_accessor :sudoc, :bibnum
38
+ attr_reader :keywords
39
+
40
+ # You can pass in a Net::HTTP, if you'd for instance like to keep
41
+ # open a persistent connection. You are advised to use our special
42
+ # Hip3::HTTPSession, for it's error handling. Or better yet, just
43
+ # leave second argument empty, and we'll create one for you.
44
+ def initialize(arg_base_path, arg_http_session=nil)
45
+ self.hip_base_url_str = arg_base_path
46
+ self.hip_base_url = URI::parse(self.hip_base_url_str);
47
+
48
+
49
+ self.httpSession = arg_http_session
50
+ if self.httpSession.nil?
51
+ self.httpSession = Hip3::HTTPSession.create(self.hip_base_url.host() )
52
+ end
53
+
54
+ self.keywords = []
55
+
56
+ end
57
+
58
+
59
+
60
+ # Method checks for basic well-formedness (doesn't actually check
61
+ # checksum), and adds hyphen if neccesary, because our HIP needs
62
+ # it to search. Bah!
63
+ def issn=(argIssn)
64
+ if (argIssn.nil? || argIssn.empty?)
65
+ @issn = nil
66
+ return
67
+ end
68
+
69
+ # first remove hyphen to normalize
70
+ argIssn.gsub!('-', '')
71
+ # now check for basic well-formedness
72
+ unless argIssn =~ /\d{7}(\d|X)/
73
+ raise ArgumentError.new("Malformed issn: #{argIssn}")
74
+ end
75
+ #now put the hyphen back, sadly
76
+ @issn = argIssn.slice(0..3) + '-' + argIssn.slice(4..7)
77
+ end
78
+
79
+ def isbn=(arg_isbn)
80
+ if ( arg_isbn.nil? || arg_isbn.empty? )
81
+ @isbn = nil
82
+ end
83
+
84
+ @isbn = arg_isbn
85
+ end
86
+
87
+ # Yet another way to specify search criteria.
88
+ # Hash, where the key is the name of a HIP keyword Index (use
89
+ # constants in this class if possible), and the value is an array of
90
+ # keywords. Everything is "anded" together.
91
+ def search_hash=(hash)
92
+ @search_hash = hash
93
+ end
94
+
95
+ def keywords=(arg_kw)
96
+ set_keywords(arg_kw)
97
+ end
98
+
99
+ def set_keywords(arg_kw, args={})
100
+
101
+ arg_kw = [] if arg_kw.nil?
102
+ args[:index] = :general unless args[:index]
103
+
104
+ @keywords = arg_kw
105
+
106
+
107
+
108
+ if (args[:index] == :title)
109
+ @keyword_index = TITLE_KW_INDEX
110
+ elsif (args[:index] == :serial_title)
111
+ @keyword_index = SERIAL_TITLE_KW_INDEX
112
+ else
113
+ @keyword_index = GEN_KW_INDEX
114
+ end
115
+ end
116
+
117
+ # Returns the URL starting from / that specifies the search criteria to
118
+ # HIP.
119
+ def searchPath(args = {})
120
+ args[:xml] = true if args[:xml].nil?
121
+
122
+ path = self.hip_base_url.path() + '?' "menu=search&aspect=power&npp=30&ipp=20&spp=20&profile=general&ri=2"
123
+
124
+ criteria = Array.new
125
+
126
+ # Need to do search_hash first, to make sure bibnum and isbn search
127
+ # come LAST, for HIP.
128
+ unless ( @search_hash.blank?)
129
+ manual_criteria = []
130
+ @search_hash.each_pair do |index, kws|
131
+ manual_criteria << kws.collect do |kw|
132
+ kw = '"' + kw + '"' unless [BIBNUM_INDEX, ISSN_KW_INDEX, ISBN_KW_INDEX, AUTHOR_KW_INDEX].include?(index)
133
+ "&index=#{index}&term=#{URI.escape(kw)}"
134
+ end
135
+ end
136
+ path << manual_criteria.join("&oper=and") << "&oper=or"
137
+ end
138
+
139
+
140
+ criteria<< "&index=#{SUDOC_KW_INDEX}&term=#{URI.escape('"' + self.sudoc + '"' )}" unless sudoc.nil?
141
+ criteria << "&index=#{ISSN_KW_INDEX}&term=#{URI.escape(self.issn)}" unless issn.nil?
142
+ # For some reason ISBN must be LAST in order, and bibnum must be right before, or HIP doesn't like it.
143
+ criteria << "&index=#{BIBNUM_INDEX}&term=#{URI.escape(self.bibnum)}" unless bibnum.blank?
144
+ # Go figure. I hate you, HIP.
145
+ criteria << "&index=#{ISBN_KW_INDEX}&term=#{URI.escape(self.isbn)}" unless isbn.nil?
146
+
147
+ criteria << keyword_url_args
148
+ path << criteria.join("&oper=or")
149
+
150
+
151
+
152
+
153
+ path << "&x=0&y=0&aspect=power"
154
+ path << "&GetXML=1" if args[:xml]
155
+
156
+ return path
157
+
158
+ end
159
+
160
+ def keyword_url_args
161
+ args =
162
+ self.keywords.collect { |k| "&index=#{@keyword_index}&term=#{CGI.escape('"' + k + '"')}" }
163
+
164
+ return args.join("&oper=and") || ""
165
+ end
166
+
167
+ # returns the numbef of hits--does not cache anything, calling
168
+ # this method will cause a trip to the db, and calling search
169
+ # will cause another one.
170
+ def count
171
+ return [] if insufficient_query
172
+
173
+ httpResp = httpSession.get( searchPath, nil )
174
+ reDoc = Nokogiri::XML( httpResp.body )
175
+
176
+ # Confusingly, sometimes
177
+ # this gives us a search results page, and sometimes it gives us
178
+ # a single bib
179
+
180
+ # single bib?
181
+ if reDoc.at('searchresponse/fullnonmarc/searchresults/results/row/key')
182
+ return 1
183
+ end
184
+
185
+ # Multiple, get the count
186
+ hits = reDoc.at('searchresponse/yoursearch/hits')
187
+ return hits ? hits.inner_text.to_s.to_i : 0
188
+ end
189
+
190
+ # Returns an array of bib objects.
191
+ def search
192
+ return [] if insufficient_query
193
+ httpResp = httpSession.get(searchPath(), nil )
194
+
195
+
196
+ bib_xml = Nokogiri::XML( httpResp.body )
197
+ # Confusingly, sometimes
198
+ # this gives us a search results page, and sometimes it gives us
199
+ # a single bib
200
+
201
+ # single bib?
202
+ if ( bibNum = bib_xml.at('searchresponse/fullnonmarc/searchresults/results/row/key'))
203
+ # Single bib
204
+ #return [Hip3::Bib.new( httpSession, bibNum.text, reDoc)]
205
+ return [Hip3::Bib.new( bibNum.inner_text, self.hip_base_url,
206
+ :http_session => httpSession,
207
+ :bib_xml_doc => bib_xml
208
+ )]
209
+ end
210
+
211
+
212
+ # Multi-response
213
+ # Get Bib #s and titles for each result.
214
+
215
+ bib_summaries = bib_xml.search('searchresponse/summary/searchresults/results/row');
216
+
217
+ return bib_summaries.collect do |bib_xml|
218
+ next unless bib_xml.at('key')
219
+
220
+ # Find a title from the summary xml
221
+ title_el = bib_xml.at('TITLE/data/text')
222
+ title = title_el ? title_el.inner_text : nil
223
+ # remove possible author on there, after a '/' char. That's how HIP rolls.
224
+ title.sub!(/\/.*$/, '')
225
+
226
+ Hip3::Bib.new(bib_xml.at('key').inner_text, self.hip_base_url, :http_session => httpSession, :title => title )
227
+ end
228
+ end
229
+
230
+ def insufficient_query
231
+ # Have to have some search criteria to search
232
+ return (self.issn.nil? && self.isbn.nil? && self.sudoc.blank? && self.bibnum.blank? && self.keywords.blank? && @search_hash.blank?)
233
+ end
234
+
235
+ def search_url
236
+ return self.hip_base_url_str + '?' + self.searchPath(:xml => false )
237
+ end
238
+
239
+ end
240
+
241
+
242
+ class HTTPSession < Net::HTTP
243
+ @@timeout = 5
244
+
245
+ def HTTPSession.create(a_host, a_port = 80)
246
+ http = HTTPSession.new(a_host, a_port)
247
+ http.read_timeout = @@timeout
248
+ http.open_timeout = @@timeout
249
+ return http
250
+ end
251
+
252
+
253
+ def get(path, headers=nil, &block)
254
+ limit = 6
255
+ tries = 0
256
+ response = nil
257
+
258
+ while (response == nil || response.kind_of?(Net::HTTPRedirection) && tries < limit)
259
+ # follow redirects
260
+ if response.kind_of?( Net::HTTPRedirection )
261
+ response = Net::HTTP.get_response(URI.parse(response['location']))
262
+ else
263
+ response = super(path, headers, block)
264
+ end
265
+ tries = tries + 1
266
+ end
267
+
268
+
269
+ #This method raises if not 2xx response status.
270
+ #No idea why such a method is called 'value'
271
+ response.value
272
+
273
+ return response
274
+ end
275
+
276
+ # Does a get whether or not the connection is already open,
277
+ # if it wasn't already open, will make sure to leave it closed again.
278
+ def self.safe_get(httpObj, path, headers=nil)
279
+ if httpObj.started?
280
+ return httpObj.get(path, headers)
281
+ else
282
+ # With a block, will close the connection when we're done.
283
+ return httpObj.start { |h| h.get(path, headers) }
284
+ end
285
+ end
286
+
287
+ end
288
+
289
+
290
+
291
+ end
292
+
293
+
294
+
295
+
296
+
297
+
298
+
299
+
300
+
301
+
302
+
@@ -0,0 +1,44 @@
1
+ module Hip3
2
+
3
+ # Certain fields we add to the Item/Copy/Bib display are in the XML, but they
4
+ # are only findable by name of the field header as configured in HIP
5
+ # admin, and then only by seeing what index in a list that header is,
6
+ # and then finding the corresponding indexed value! This object
7
+ # does that work for us, and caches it's calcuations while it's at it.
8
+ # One of these objects has it's own rexml doc representing a particular
9
+ # bib with item info, because the answer may be different for different bibs!
10
+ class CustomFieldLookup
11
+ attr_accessor :header_list
12
+
13
+ def initialize(a_header_list)
14
+ self.header_list = a_header_list
15
+
16
+ end
17
+
18
+
19
+ def index_for(label)
20
+ return header_list.index(label)
21
+ end
22
+
23
+ # list can be either an array of strings, or a rexml element
24
+ # representing a <row> element for this item. In either case,
25
+ # we lookup the index i of label in our original header list,
26
+ # and then return the text value of element i in the list arg.
27
+ def text_value_for(list, label )
28
+ i = index_for(label)
29
+ return nil if i.nil?
30
+
31
+ if ( list.kind_of?(Hpricot::Node) )
32
+ # Assume they passed in a HIP 'row' element, turn it
33
+ # into a nice array of strings. Can't figure out how
34
+ # to test if it really is a 'row' element!
35
+ list = list.search('/cell/data/text').collect {|e| e.inner_text}
36
+ end
37
+
38
+ return list.at( i )
39
+
40
+ end
41
+
42
+
43
+ end
44
+ end
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/ruby
2
+
3
+
4
+
5
+ module Hip3
6
+ # abstract superclass for copies and items (both serial and mono). Both a Copy
7
+ # and an Item are Holdings.
8
+ # coverage_str only applies to copies and serial items, not mono items, but
9
+ # we put it here anyway, it'll just be nil for mono items.
10
+ class Holding
11
+ attr_accessor :id, :location_str, :collection_str, :call_no, :copy_str, :status_str, :coverage_str, :notes
12
+ # Holdings sometimes use the bib to lazy load more stuff.
13
+ attr_accessor :bib
14
+
15
+ # If input is nil, returns nil, else returns input.inner_text
16
+ def textValue(el)
17
+ return ( el == nil ? nil : el.inner_text)
18
+ end
19
+
20
+ # Return an array of holding strings, possibly empty, possibly single-valued.
21
+ # over-ridden by SerialCopy to give you an array, since SerialCopies have
22
+ # multiple holdings strings.
23
+ def coverage_str_to_a
24
+ return coverage_str.nil? ? [] : [coverage_str]
25
+ end
26
+
27
+ # Some items are dummy/placeholder items which don't really represent
28
+ # an item, and shouldn't be shown. Having trouble figuring out what
29
+ # our 'business rules' for that are, so this is a messy guess.
30
+ def dummy?
31
+ #Mostly trying to rule out the weird internet holdings
32
+ #that tell us nothing--url is already in the bib.
33
+ return ( collection_str == "Internet" ||
34
+ collection_str == "Internet Resource" ||
35
+ collection_str == "Welch Online Journals" ||
36
+ collection_str == "Welch Online Journal" ||
37
+ collection_str == "Gibson-Electronic Journals & Indexes" ||
38
+ collection_str == "Gibson - Electronic Journals")
39
+
40
+ #return (( (call_no == "World Wide Web" || call_no.blank?) &&
41
+ # ( collection_str == "Internet" || collection_str == "Welch Online Journals" || collection_str == "Welch Online Journal")) ||
42
+ # (collection_str == "Gibson-Electronic Journals & Indexes" && call_no="Online journal"))
43
+
44
+ end
45
+ end
46
+
47
+
48
+
49
+
50
+ end
data/lib/hip3/item.rb ADDED
@@ -0,0 +1,65 @@
1
+ module Hip3
2
+ # We're going to try using this for serial items and mono items. Only difference is
3
+ # that serial items have a relationship to a SerialCopy, stored in :copy attribute.
4
+ # Item objects need to be initialized with reXML object representing
5
+ # the item element.
6
+ class Item < Holding
7
+ # Labels set up in HIP admin item display to expose these data of interest.
8
+ @@Field_labels = { :rmst => 'hide_rmst', :barcode => 'hide_barcode', :copy_id => 'hide_CopyNum'}
9
+
10
+ # Item-specific attributes
11
+ attr_accessor :avail_date_str, :rmst_str, :barcode, :copy_id
12
+ attr_accessor :copy
13
+
14
+ # Item is not lazily loadable--you need to give it
15
+ # all three arguments to create it, you need to have the
16
+ # XML in hand. We could certainly provide a different
17
+ # way than XML to init values, but we haven't.
18
+ def initialize(item_row_element, arg_bib)
19
+ @bib = arg_bib
20
+ loadFromItemRowElement(item_row_element)
21
+ end
22
+
23
+ def loadFromItemRowElement( el )
24
+
25
+ @id = textValue(el.at('/key'));
26
+
27
+ # Pull out the values built into HIP automatically. They have weird
28
+ # XML elements, but I think I've appropriately identified them,
29
+ # even though it doesn't look like it.Actually, no, those aren't
30
+ # reliable, I don't understand what they are. We'll just pull
31
+ # everything from the HIP display.
32
+
33
+ #@copy_str = textValue(el.elements['MIDSPINE/data/text'])
34
+ @copy_str = @bib.item_field_lookup.text_value_for(el, "Copy")
35
+ @collection_str = @bib.item_field_lookup.text_value_for(el, "Collection")
36
+
37
+ #Maybe. Not sure where else to get this.
38
+ @location_str = textValue(el.at('/LOCALLOCATION/data/text'))
39
+
40
+ #@call_no = textValue(el.elements['COPYNUMBER/data/text'])
41
+ @call_no = @bib.item_field_lookup.text_value_for(el, "Call No.")
42
+
43
+ @status_str = @bib.item_field_lookup.text_value_for(el, "Status")
44
+
45
+ # Not sure about this one.
46
+ @avail_date_str = textValue(el.at('/AVAILABILITYDATE/data/text'))
47
+
48
+ # Pull out the values we had to configure in Copy display
49
+ @rmst_str = @bib.item_field_lookup.text_value_for(el, @@Field_labels[:rmst])
50
+ @barcode = @bib.item_field_lookup.text_value_for(el, @@Field_labels[:barcode])
51
+ @copy_id = @bib.item_field_lookup.text_value_for(el, @@Field_labels[:copy_id])
52
+
53
+ # Attach this thing to the proper Copy object, in both directions.
54
+ # We have the Bib do it for us, since the Bib has a list of Copies.
55
+ # Since we've set our @copy_id, the Bib can find out what it needs to.
56
+ @bib.register_item( self)
57
+ end
58
+
59
+ def hasSerialCopy
60
+ return ! self.copy.nil?
61
+ end
62
+
63
+
64
+ end
65
+ end