berkeley_library-alma 0.0.5 → 0.0.6

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: '0805d8fb305dd644ede89efb0c71845c479df3cc8b69334bbfc4e747312c229d'
4
- data.tar.gz: 80b1576c6dc7d5bbfd5bd5a0a53985167c4c3929668d505dae92ffcac196988e
3
+ metadata.gz: ab227f94abea9d1275bceb4ed361cf2d75021ae7d9cf49283e6139404e9e327f
4
+ data.tar.gz: 2370efa8b2bc2b72e6e506cf38271a74ee8a785cbebf7f42b19e49bf84b4a6da
5
5
  SHA512:
6
- metadata.gz: 879cb4ef386caa8543bf883ac3b62888c4ca810ef431562618ad456c9d560ee81f6dada5b9ae850ca15523cd6f58d5487919c3e782c817313deaff346912c257
7
- data.tar.gz: b10240d0571733f28f90ab099da879647cdd670da05c5af5aa396f0fcd8c9ae026d2ec9b4c1246764a6b919bc594c665ff0096140b400cb2626af893bdcd3b21
6
+ metadata.gz: 438181aea5e19163ca57dd7c5c9086fd6d324ac5bb6e05fd33917cc70327ca5682e1f07a9ffc5280104207562f6fdda4443070bdc8ba3163b519ba70f96f2558
7
+ data.tar.gz: dc9cafbf0b36ee0ac1875d8cc89b0b4a10bdccd37456f67004e0c3abb0097fde7b8d5da31c946ab1eb4f300dd1f14ad5dcaf550ca697aef0de4f8b6d81521bdb
data/.idea/alma.iml CHANGED
@@ -12,15 +12,15 @@
12
12
  </content>
13
13
  <orderEntry type="jdk" jdkName="RVM: ruby-2.7.5" jdkType="RUBY_SDK" />
14
14
  <orderEntry type="sourceFolder" forTests="false" />
15
- <orderEntry type="library" scope="PROVIDED" name="actionpack (v6.1.4.6, RVM: ruby-2.7.5) [gem]" level="application" />
16
- <orderEntry type="library" scope="PROVIDED" name="actionview (v6.1.4.6, RVM: ruby-2.7.5) [gem]" level="application" />
17
- <orderEntry type="library" scope="PROVIDED" name="activesupport (v6.1.4.6, RVM: ruby-2.7.5) [gem]" level="application" />
15
+ <orderEntry type="library" scope="PROVIDED" name="actionpack (v7.0.2.4, RVM: ruby-2.7.5) [gem]" level="application" />
16
+ <orderEntry type="library" scope="PROVIDED" name="actionview (v7.0.2.4, RVM: ruby-2.7.5) [gem]" level="application" />
17
+ <orderEntry type="library" scope="PROVIDED" name="activesupport (v7.0.2.4, RVM: ruby-2.7.5) [gem]" level="application" />
18
18
  <orderEntry type="library" scope="PROVIDED" name="addressable (v2.8.0, RVM: ruby-2.7.5) [gem]" level="application" />
19
19
  <orderEntry type="library" scope="PROVIDED" name="amazing_print (v1.4.0, RVM: ruby-2.7.5) [gem]" level="application" />
20
20
  <orderEntry type="library" scope="PROVIDED" name="ast (v2.4.2, RVM: ruby-2.7.5) [gem]" level="application" />
21
- <orderEntry type="library" scope="PROVIDED" name="berkeley_library-logging (v0.2.5, RVM: ruby-2.7.5) [gem]" level="application" />
21
+ <orderEntry type="library" scope="PROVIDED" name="berkeley_library-logging (v0.2.6, RVM: ruby-2.7.5) [gem]" level="application" />
22
22
  <orderEntry type="library" scope="PROVIDED" name="berkeley_library-marc (v0.3.1, RVM: ruby-2.7.5) [gem]" level="application" />
23
- <orderEntry type="library" scope="PROVIDED" name="berkeley_library-util (v0.1.1, RVM: ruby-2.7.5) [gem]" level="application" />
23
+ <orderEntry type="library" scope="PROVIDED" name="berkeley_library-util (v0.1.2, RVM: ruby-2.7.5) [gem]" level="application" />
24
24
  <orderEntry type="library" scope="PROVIDED" name="builder (v3.2.4, RVM: ruby-2.7.5) [gem]" level="application" />
25
25
  <orderEntry type="library" scope="PROVIDED" name="bundle-audit (v0.1.0, RVM: ruby-2.7.5) [gem]" level="application" />
26
26
  <orderEntry type="library" scope="PROVIDED" name="bundler (v2.1.4, RVM: ruby-2.7.5) [gem]" level="application" />
@@ -28,7 +28,7 @@
28
28
  <orderEntry type="library" scope="PROVIDED" name="ci_reporter (v2.0.0, RVM: ruby-2.7.5) [gem]" level="application" />
29
29
  <orderEntry type="library" scope="PROVIDED" name="ci_reporter_rspec (v1.0.0, RVM: ruby-2.7.5) [gem]" level="application" />
30
30
  <orderEntry type="library" scope="PROVIDED" name="colorize (v0.8.1, RVM: ruby-2.7.5) [gem]" level="application" />
31
- <orderEntry type="library" scope="PROVIDED" name="concurrent-ruby (v1.1.9, RVM: ruby-2.7.5) [gem]" level="application" />
31
+ <orderEntry type="library" scope="PROVIDED" name="concurrent-ruby (v1.1.10, RVM: ruby-2.7.5) [gem]" level="application" />
32
32
  <orderEntry type="library" scope="PROVIDED" name="crack (v0.4.5, RVM: ruby-2.7.5) [gem]" level="application" />
33
33
  <orderEntry type="library" scope="PROVIDED" name="crass (v1.0.6, RVM: ruby-2.7.5) [gem]" level="application" />
34
34
  <orderEntry type="library" scope="PROVIDED" name="diff-lcs (v1.5.0, RVM: ruby-2.7.5) [gem]" level="application" />
@@ -39,16 +39,16 @@
39
39
  <orderEntry type="library" scope="PROVIDED" name="http-accept (v1.7.0, RVM: ruby-2.7.5) [gem]" level="application" />
40
40
  <orderEntry type="library" scope="PROVIDED" name="http-cookie (v1.0.4, RVM: ruby-2.7.5) [gem]" level="application" />
41
41
  <orderEntry type="library" scope="PROVIDED" name="i18n (v1.10.0, RVM: ruby-2.7.5) [gem]" level="application" />
42
- <orderEntry type="library" scope="PROVIDED" name="lograge (v0.11.2, RVM: ruby-2.7.5) [gem]" level="application" />
43
- <orderEntry type="library" scope="PROVIDED" name="loofah (v2.14.0, RVM: ruby-2.7.5) [gem]" level="application" />
42
+ <orderEntry type="library" scope="PROVIDED" name="lograge (v0.12.0, RVM: ruby-2.7.5) [gem]" level="application" />
43
+ <orderEntry type="library" scope="PROVIDED" name="loofah (v2.17.0, RVM: ruby-2.7.5) [gem]" level="application" />
44
44
  <orderEntry type="library" scope="PROVIDED" name="marc (v1.1.1, RVM: ruby-2.7.5) [gem]" level="application" />
45
45
  <orderEntry type="library" scope="PROVIDED" name="method_source (v1.0.0, RVM: ruby-2.7.5) [gem]" level="application" />
46
46
  <orderEntry type="library" scope="PROVIDED" name="mime-types (v3.4.1, RVM: ruby-2.7.5) [gem]" level="application" />
47
47
  <orderEntry type="library" scope="PROVIDED" name="mime-types-data (v3.2022.0105, RVM: ruby-2.7.5) [gem]" level="application" />
48
- <orderEntry type="library" scope="PROVIDED" name="mini_portile2 (v2.7.1, RVM: ruby-2.7.5) [gem]" level="application" />
48
+ <orderEntry type="library" scope="PROVIDED" name="mini_portile2 (v2.8.0, RVM: ruby-2.7.5) [gem]" level="application" />
49
49
  <orderEntry type="library" scope="PROVIDED" name="minitest (v5.15.0, RVM: ruby-2.7.5) [gem]" level="application" />
50
50
  <orderEntry type="library" scope="PROVIDED" name="netrc (v0.11.0, RVM: ruby-2.7.5) [gem]" level="application" />
51
- <orderEntry type="library" scope="PROVIDED" name="nokogiri (v1.13.1, RVM: ruby-2.7.5) [gem]" level="application" />
51
+ <orderEntry type="library" scope="PROVIDED" name="nokogiri (v1.13.5, RVM: ruby-2.7.5) [gem]" level="application" />
52
52
  <orderEntry type="library" scope="PROVIDED" name="oj (v3.13.11, RVM: ruby-2.7.5) [gem]" level="application" />
53
53
  <orderEntry type="library" scope="PROVIDED" name="ougai (v1.9.1, RVM: ruby-2.7.5) [gem]" level="application" />
54
54
  <orderEntry type="library" scope="PROVIDED" name="parallel (v1.21.0, RVM: ruby-2.7.5) [gem]" level="application" />
@@ -60,7 +60,7 @@
60
60
  <orderEntry type="library" scope="PROVIDED" name="rack-test (v1.1.0, RVM: ruby-2.7.5) [gem]" level="application" />
61
61
  <orderEntry type="library" scope="PROVIDED" name="rails-dom-testing (v2.0.3, RVM: ruby-2.7.5) [gem]" level="application" />
62
62
  <orderEntry type="library" scope="PROVIDED" name="rails-html-sanitizer (v1.4.2, RVM: ruby-2.7.5) [gem]" level="application" />
63
- <orderEntry type="library" scope="PROVIDED" name="railties (v6.1.4.6, RVM: ruby-2.7.5) [gem]" level="application" />
63
+ <orderEntry type="library" scope="PROVIDED" name="railties (v7.0.2.4, RVM: ruby-2.7.5) [gem]" level="application" />
64
64
  <orderEntry type="library" scope="PROVIDED" name="rainbow (v3.1.1, RVM: ruby-2.7.5) [gem]" level="application" />
65
65
  <orderEntry type="library" scope="PROVIDED" name="rake (v13.0.6, RVM: ruby-2.7.5) [gem]" level="application" />
66
66
  <orderEntry type="library" scope="PROVIDED" name="regexp_parser (v2.2.0, RVM: ruby-2.7.5) [gem]" level="application" />
@@ -87,7 +87,7 @@
87
87
  <orderEntry type="library" scope="PROVIDED" name="typesafe_enum (v0.3.0, RVM: ruby-2.7.5) [gem]" level="application" />
88
88
  <orderEntry type="library" scope="PROVIDED" name="tzinfo (v2.0.4, RVM: ruby-2.7.5) [gem]" level="application" />
89
89
  <orderEntry type="library" scope="PROVIDED" name="unf (v0.1.4, RVM: ruby-2.7.5) [gem]" level="application" />
90
- <orderEntry type="library" scope="PROVIDED" name="unf_ext (v0.0.8, RVM: ruby-2.7.5) [gem]" level="application" />
90
+ <orderEntry type="library" scope="PROVIDED" name="unf_ext (v0.0.8.1, RVM: ruby-2.7.5) [gem]" level="application" />
91
91
  <orderEntry type="library" scope="PROVIDED" name="unicode-display_width (v2.1.0, RVM: ruby-2.7.5) [gem]" level="application" />
92
92
  <orderEntry type="library" scope="PROVIDED" name="webmock (v3.14.0, RVM: ruby-2.7.5) [gem]" level="application" />
93
93
  <orderEntry type="library" scope="PROVIDED" name="webrick (v1.7.0, RVM: ruby-2.7.5) [gem]" level="application" />
@@ -109,7 +109,7 @@
109
109
  </RakeTaskImpl>
110
110
  <RakeTaskImpl description="Run all specs in spec directory, with coverage" fullCommand="coverage" id="coverage" />
111
111
  <RakeTaskImpl description="Run tests, check test coverage, check code style, check for vulnerabilities, build gem" fullCommand="default" id="default" />
112
- <RakeTaskImpl description="Build berkeley_library-alma.gemspec as berkeley_library-alma-0.0.3.gem" fullCommand="gem" id="gem" />
112
+ <RakeTaskImpl description="Build berkeley_library-alma.gemspec as berkeley_library-alma-0.0.5.gem" fullCommand="gem" id="gem" />
113
113
  <RakeTaskImpl description="Run RuboCop with auto-correct, and output results to console" fullCommand="ra" id="ra" />
114
114
  <RakeTaskImpl description="Run rubocop with HTML output" fullCommand="rubocop" id="rubocop" />
115
115
  <RakeTaskImpl id="rubocop">
@@ -7,6 +7,7 @@
7
7
  <inspection_tool class="GoUnusedGlobalVariable" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
8
8
  <inspection_tool class="GoUnusedVariable" enabled="true" level="WARNING" enabled_by_default="true" />
9
9
  <inspection_tool class="GrazieInspection" enabled="false" level="TYPO" enabled_by_default="false" />
10
+ <inspection_tool class="HttpUrlsUsage" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
10
11
  <inspection_tool class="LanguageDetectionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
11
12
  <inspection_tool class="Rubocop" enabled="false" level="WARNING" enabled_by_default="false" />
12
13
  <inspection_tool class="RubyCaseWithoutElseBlockInspection" enabled="false" level="WARNING" enabled_by_default="false" />
@@ -15,6 +16,7 @@
15
16
  </inspection_tool>
16
17
  <inspection_tool class="RubyNilAnalysis" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
17
18
  <inspection_tool class="RubyStringKeysInHashInspection" enabled="true" level="INFORMATION" enabled_by_default="true" />
19
+ <inspection_tool class="RubyTooManyInstanceVariablesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
18
20
  <inspection_tool class="RubyUnnecessaryReturnStatement" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
19
21
  <inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
20
22
  <option name="processCode" value="true" />
data/CHANGES.md CHANGED
@@ -1,3 +1,7 @@
1
+ # 0.0.6 (5 May 2022)
2
+
3
+ - `SRU#get_marc_records` now supports paginated results.
4
+
1
5
  # 0.0.5 (4 May 2022)
2
6
 
3
7
  - extracts `SRU` module for performing SRU queries.
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
24
24
 
25
25
  spec.add_dependency 'berkeley_library-logging', '~> 0.2'
26
26
  spec.add_dependency 'berkeley_library-marc', '~> 0.3.1'
27
- spec.add_dependency 'berkeley_library-util', '~> 0.1', '>= 0.1.1'
27
+ spec.add_dependency 'berkeley_library-util', '~> 0.1', '>= 0.1.2'
28
28
  spec.add_dependency 'nokogiri', '~> 1.12'
29
29
 
30
30
  spec.add_development_dependency 'bundle-audit', '~> 0.1'
@@ -7,7 +7,7 @@ module BerkeleyLibrary
7
7
  SUMMARY = 'Alma/Primo utilities for the UC Berkeley Library'.freeze
8
8
  DESCRIPTION = 'A gem providing Alma/Primo-related utility code for the UC Berkeley Library'.freeze
9
9
  LICENSE = 'MIT'.freeze
10
- VERSION = '0.0.5'.freeze
10
+ VERSION = '0.0.6'.freeze
11
11
  HOMEPAGE = 'https://github.com/BerkeleyLibrary/alma'.freeze
12
12
  end
13
13
  end
@@ -60,12 +60,8 @@ module BerkeleyLibrary
60
60
  # @return [MARC::Record, nil] the MARC record
61
61
  # rubocop:disable Naming/AccessorMethodName
62
62
  def get_marc_record
63
- unless (marc_reader = SRU.marc_records_for(sru_query_value))
64
- logger.warn("GET #{marc_uri} did not return a MARC record")
65
- return nil
66
- end
67
-
68
- logger.warn("GET #{marc_uri} did not return a MARC record") unless (marc_record = marc_reader.first)
63
+ records = SRU.marc_records_for(sru_query_value)
64
+ logger.warn("GET #{marc_uri} did not return a MARC record") unless (marc_record = records.first)
69
65
  marc_record
70
66
  end
71
67
  # rubocop:enable Naming/AccessorMethodName
@@ -0,0 +1,102 @@
1
+ require 'uri'
2
+ require 'berkeley_library/util/uris'
3
+ require 'berkeley_library/alma/config'
4
+ require 'berkeley_library/alma/constants'
5
+ require 'berkeley_library/alma/record_id'
6
+ require 'berkeley_library/alma/sru/xml_reader'
7
+
8
+ module BerkeleyLibrary
9
+ module Alma
10
+ module SRU
11
+ include BerkeleyLibrary::Logging
12
+ include Constants
13
+
14
+ class << self
15
+ include SRU
16
+ end
17
+
18
+ # Given a list of record IDs, returns the MARC records for each ID (if found).
19
+ # Note that the order of the records is not guaranteed.
20
+ #
21
+ # @param record_ids [Array<String, RecordId>] the record IDs to look up
22
+ # @param freeze [Boolean] whether to freeze the records
23
+ # @return [Enumerator::Lazy<MARC::Record>] the records
24
+ def get_marc_records(*record_ids, freeze: false)
25
+ # noinspection RubyMismatchedReturnType
26
+ parsed_ids = record_ids.filter_map { |id| RecordId.parse(id) }
27
+ raise ArgumentError, "Argument #{record_ids.inspect} contain no valid record IDs" if parsed_ids.empty?
28
+
29
+ sru_query_value = parsed_ids.map(&:sru_query_value).join(' or ')
30
+ SRU.marc_records_for(sru_query_value, freeze: freeze)
31
+ end
32
+
33
+ # Returns a URI for retrieving records for the specified query
34
+ # via SRU. Requires {Config#alma_sru_base_uri} to be set.
35
+ #
36
+ # @return [URI] the MARC URI
37
+ def sru_query_uri(sru_query_value)
38
+ query_string = URI.encode_www_form(
39
+ 'version' => '1.2',
40
+ 'operation' => 'searchRetrieve',
41
+ 'query' => sru_query_value
42
+ )
43
+
44
+ Util::URIs.append(Config.alma_sru_base_uri, '?', query_string)
45
+ end
46
+
47
+ # Makes an SRU query for the specified query value and returns the query response
48
+ # as a string.
49
+ #
50
+ # @param query_value [String] the value of the SRU query parameter
51
+ # @return [String, nil] the SRU query response body, or nil in the event of an error.
52
+ def make_sru_query(query_value)
53
+ uri = sru_query_uri(query_value)
54
+ do_get(uri)
55
+ end
56
+
57
+ # Makes an SRU query for the specified query value and returns the query response
58
+ # as MARC records.
59
+ #
60
+ # @param query_value [String] the value of the SRU query parameter
61
+ # @param freeze [Boolean] whether to freeze the records
62
+ # @return [Enumerator::Lazy<MARC::Record>] the records
63
+ def marc_records_for(query_value, freeze: false)
64
+ Enumerator.new do |y|
65
+ uri = sru_query_uri(query_value)
66
+ perform_query(uri, freeze: freeze) { |rec| y << rec }
67
+ end.lazy
68
+ end
69
+
70
+ private
71
+
72
+ def perform_query(query_uri, start_record: nil, freeze: false, &block)
73
+ full_query_uri = full_query_uri_for(query_uri, start_record)
74
+ next_start_record = perform_single_query(full_query_uri, freeze, &block)
75
+ return unless next_start_record
76
+
77
+ perform_query(query_uri, start_record: next_start_record, freeze: freeze, &block)
78
+ end
79
+
80
+ def full_query_uri_for(query_uri, start_record)
81
+ return query_uri unless start_record
82
+
83
+ BerkeleyLibrary::Util::URIs.append(query_uri, "&startRecord=#{start_record}")
84
+ end
85
+
86
+ def perform_single_query(query_uri, freeze, &block)
87
+ return unless (xml = do_get(query_uri))
88
+
89
+ xml_reader = XMLReader.read(xml, freeze: freeze)
90
+ xml_reader.each(&block)
91
+ xml_reader.next_record_position
92
+ end
93
+
94
+ def do_get(uri)
95
+ Util::URIs.get(uri, headers: { user_agent: DEFAULT_USER_AGENT })
96
+ rescue RestClient::Exception => e
97
+ logger.warn("GET #{uri} failed", e)
98
+ nil
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,148 @@
1
+ require 'nokogiri'
2
+ require 'marc/xml_parsers'
3
+ require 'berkeley_library/util/files'
4
+
5
+ module BerkeleyLibrary
6
+ module Alma
7
+ module SRU
8
+ # A customized XML reader for reading MARC records from SRU search results.
9
+ class XMLReader
10
+ include Enumerable
11
+ include ::MARC::NokogiriReader
12
+ include BerkeleyLibrary::Util::Files
13
+
14
+ # ############################################################
15
+ # Constants
16
+
17
+ NS_SRW = 'http://www.loc.gov/zing/srw/'.freeze
18
+ NS_MARC = 'http://www.loc.gov/MARC21/slim'.freeze
19
+
20
+ # ############################################################
21
+ # Attributes
22
+
23
+ # @return [Integer, nil] the record identifier of the most recently parsed record, if any
24
+ attr_reader :last_record_id
25
+
26
+ # @return [Integer, nil] the record position of the most recently parsed record, if any
27
+ attr_reader :last_record_position
28
+
29
+ # @return [Integer, nil] the next record position, if present
30
+ attr_reader :next_record_position
31
+
32
+ # Returns the total number of records, based on the `<numberOfRecords/>` tag
33
+ # returned in the SRU response.
34
+ #
35
+ # Note that the total is not guaranteed to be present, and if present,
36
+ # may not be present unless at least some records have been parsed.
37
+ #
38
+ # @return [Integer, nil] the total number of records, or `nil` if the total has not been read yet
39
+ def num_records
40
+ @num_records&.to_i
41
+ end
42
+
43
+ # Returns the number of records yielded.
44
+ #
45
+ # @return [Integer] the number of records yielded.
46
+ def records_yielded
47
+ @records_yielded ||= 0
48
+ end
49
+
50
+ # ############################################################
51
+ # Initializer
52
+
53
+ def initialize(source, freeze: false)
54
+ @handle = ensure_io(source)
55
+ @freeze = freeze
56
+ init
57
+ end
58
+
59
+ class << self
60
+ # Reads MARC records from an XML datasource given either as an XML string, a file path,
61
+ # or as an IO object.
62
+ #
63
+ # @param source [String, Pathname, IO] an XML string, the path to a file, or an IO to read from directly
64
+ # @param freeze [Boolean] whether to freeze each record after reading
65
+ def read(source, freeze: false)
66
+ new(source, freeze: freeze)
67
+ end
68
+ end
69
+
70
+ # ############################################################
71
+ # MARC::GenericPullParser overrides
72
+
73
+ def yield_record
74
+ @record[:record].tap do |record|
75
+ record.freeze if @freeze
76
+ end
77
+
78
+ super
79
+ ensure
80
+ increment_records_yielded!
81
+ end
82
+
83
+ # ############################################################
84
+ # Nokogiri::XML::SAX::Document overrides
85
+
86
+ # @see Nokogiri::XML::Sax::Document#start_element_namespace
87
+ # rubocop:disable Metrics/ParameterLists
88
+ def start_element_namespace(name, attrs = [], prefix = nil, uri = nil, ns = [])
89
+ super
90
+
91
+ @current_element_ns = uri
92
+ @current_element_name = name
93
+ end
94
+ # rubocop:enable Metrics/ParameterLists
95
+
96
+ # @see Nokogiri::XML::Sax::Document#end_element_namespace
97
+ def end_element_namespace(name, prefix = nil, uri = nil)
98
+ # Delay yielding record till we reach the end of the outer SRU <record/>
99
+ # element (not the inner MARC <record/> element), so we can record the
100
+ # values of <recordIdentifier> and <recordPosition/>
101
+ if name.downcase == 'record'
102
+ yield_record if uri == NS_SRW
103
+ elsif uri == NS_MARC
104
+ super
105
+ end
106
+
107
+ @current_element_name = nil
108
+ end
109
+
110
+ # @see Nokogiri::XML::Sax::Document#characters
111
+ # rubocop:disable Metrics/MethodLength
112
+ def characters(string)
113
+ return super unless NS_SRW == @current_element_ns
114
+ return unless (name = @current_element_name)
115
+
116
+ case name
117
+ when 'numberOfRecords'
118
+ @num_records = string
119
+ when 'recordIdentifier'
120
+ @last_record_id = string
121
+ when 'recordPosition'
122
+ @last_record_position = string.to_i
123
+ when 'nextRecordPosition'
124
+ @next_record_position = string.to_i
125
+ end
126
+ end
127
+ # rubocop:enable Metrics/MethodLength
128
+
129
+ # ############################################################
130
+ # Private
131
+
132
+ private
133
+
134
+ def ensure_io(file)
135
+ return file if reader_like?(file)
136
+ return File.new(file) if file_exists?(file)
137
+ return StringIO.new(file) if file =~ /^\s*</x
138
+
139
+ raise ArgumentError, "Don't know how to read XML from #{file.inspect}: not an IO, file path, or XML text"
140
+ end
141
+
142
+ def increment_records_yielded!
143
+ @records_yielded = records_yielded + 1
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
@@ -1,79 +1 @@
1
- require 'uri'
2
- require 'berkeley_library/alma/config'
3
- require 'berkeley_library/alma/constants'
4
- require 'berkeley_library/alma/record_id'
5
- require 'berkeley_library/util/uris'
6
-
7
- module BerkeleyLibrary
8
- module Alma
9
- module SRU
10
- include BerkeleyLibrary::Logging
11
- include Constants
12
-
13
- class << self
14
- include SRU
15
- end
16
-
17
- # Given a list of record IDs, returns the MARC records for each ID (if found).
18
- #
19
- # @param record_ids [Array<String, RecordId>] the record IDs to look up
20
- # @return [MARC::XMLReader, nil] a reader for the MARC records, or nil if
21
- # the records could not be read
22
- def get_marc_records(*record_ids)
23
- # noinspection RubyMismatchedReturnType
24
- parsed_ids = record_ids.filter_map { |id| RecordId.parse(id) }
25
- raise ArgumentError, "Argument #{record_ids.inspect} contain no valid record IDs" if parsed_ids.empty?
26
-
27
- sru_query_value = parsed_ids.map(&:sru_query_value).join(' or ')
28
- SRU.marc_records_for(sru_query_value)
29
- end
30
-
31
- # Returns a URI for retrieving records for the specified query
32
- # via SRU. Requires {Config#alma_sru_base_uri} to be set.
33
- #
34
- # @return [URI] the MARC URI
35
- def sru_query_uri(sru_query_value)
36
- query_string = URI.encode_www_form(
37
- 'version' => '1.2',
38
- 'operation' => 'searchRetrieve',
39
- 'query' => sru_query_value
40
- )
41
-
42
- Util::URIs.append(Config.alma_sru_base_uri, '?', query_string)
43
- end
44
-
45
- # Makes an SRU query for the specified query value and returns the query response
46
- # as a string.
47
- #
48
- # @param query_value [String] the value of the SRU query parameter
49
- # @return [String, nil] the SRU query response body, or nil in the event of an error.
50
- def make_sru_query(query_value)
51
- uri = sru_query_uri(query_value)
52
- do_get(uri)
53
- end
54
-
55
- # Makes an SRU query for the specified query value and returns the query response
56
- # as MARC records.
57
- #
58
- # @param query_value [String] the value of the SRU query parameter
59
- # @return [MARC::XMLReader, nil] a reader for the MARC records, or nil if
60
- # the records could not be read
61
- def marc_records_for(query_value)
62
- return unless (xml = make_sru_query(query_value))
63
-
64
- input = StringIO.new(xml.scrub)
65
- MARC::XMLReader.new(input, parser: 'nokogiri')
66
- end
67
-
68
- private
69
-
70
- def do_get(uri)
71
- # TODO: can we get the XML as an IO rather than as a string?
72
- Util::URIs.get(uri, headers: { user_agent: DEFAULT_USER_AGENT })
73
- rescue RestClient::Exception => e
74
- logger.warn("GET #{uri} failed", e)
75
- nil
76
- end
77
- end
78
- end
79
- end
1
+ Dir.glob(File.expand_path('sru/*.rb', __dir__)).sort.each(&method(:require))