evergreen_holdings 0.3.1 → 0.4.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 (3) hide show
  1. checksums.yaml +5 -5
  2. data/lib/evergreen_holdings.rb +196 -198
  3. metadata +32 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: da13869aee1d6030dc730f20f662d3bbae682f1b
4
- data.tar.gz: efbf034638ed3b6b301934de474f1dc1365bcfcb
2
+ SHA256:
3
+ metadata.gz: e5800a7a145695ef115c882d45a1ba4264ea8f97888d7d305b7fdbbda4085b84
4
+ data.tar.gz: 0eaf07e5c8bb021fd79fcee3ec8584beff6b1842d097de72b7285614e2866368
5
5
  SHA512:
6
- metadata.gz: 8a874195ffa5f2c7b0a202cecf66121d487d8eca4f60cf8ba0536f258040cc9a58d50dda5d6b4f62d6dcb17ce93a46654cdc3e3b0b6b81d0f0ca16872839ef6b
7
- data.tar.gz: 9557150bed33a4e14d189e1ee2cd0e8f6048ca44d63cd289bb10e32547e315ed7b2a5c2ad8efc73d346b1179dca1d5d52686a951e06c6e66ee6c62f443b98138
6
+ metadata.gz: 14af7152bf4201748e500b1821152cc0331413e6b4e7df8ede03983b180bfbe3e32f9d368714b8bf7d5f9a015003500b32fcfce5a98e757b98c40ced3813166e
7
+ data.tar.gz: e4e82b9fe288ae589cad6089d34464421a5f0ffb698abbaa1ae2d41e55a9f1b6cbd2477ba545e0fc7bbc897828f3bce8fc3262a9e79872c16d3c6e20fa23c881
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'net/http'
2
4
  require 'json'
3
5
  require 'evergreen_holdings/errors'
@@ -7,229 +9,225 @@ require 'open-uri'
7
9
  OSRF_PATH = '/osrf-gateway-v1'
8
10
 
9
11
  module EvergreenHoldings
10
- class Connection
11
- attr_reader :org_units
12
- # Create a new object with the evergreen_domain
13
- # specified, e.g. http://libcat.linnbenton.edu
14
- #
15
- # Usage: `conn = EvergreenHoldings::Connection.new 'http://gapines.org'`
16
- def initialize evergreen_domain
17
- @evergreen_domain = evergreen_domain
18
- @gateway = URI evergreen_domain+OSRF_PATH
19
- fetch_idl_order
20
- unless fetch_statuses
21
- raise CouldNotConnectToEvergreenError
22
- end
23
- fetch_ou_tree
12
+ class Connection
13
+ attr_reader :org_units
14
+ # Create a new object with the evergreen_domain
15
+ # specified, e.g. http://libcat.linnbenton.edu
16
+ #
17
+ # Usage: `conn = EvergreenHoldings::Connection.new 'http://gapines.org'`
18
+ def initialize(evergreen_domain)
19
+ @evergreen_domain = evergreen_domain
20
+ @gateway = URI evergreen_domain + OSRF_PATH
21
+ @acpl_cache = {}
22
+ fetch_idl_order
23
+ raise CouldNotConnectToEvergreenError unless fetch_statuses
24
+
25
+ fetch_ou_tree
26
+ end
27
+
28
+ # Fetch holdings data from the Evergreen server
29
+ # Returns a Status object
30
+ #
31
+ # Usage: `stat = conn.get_holdings 23405`
32
+ # If you just want holdings at a specific org_unit: `my_connection.get_holdings 23405, org_unit: 5`
33
+ def get_holdings(tcn, options = {})
34
+ if options.key?(:org_unit)
35
+ if options[:descendants]
36
+ params = "format=json&input_format=json&service=open-ils.cat&method=open-ils.cat.asset.copy_tree.retrieve&param=auth_token_not_needed_for_this_call&param=#{tcn}"
37
+ @org_units[options[:org_unit]][:descendants]&.each do |ou|
38
+ params << + "&param=#{ou}"
39
+ end
40
+ else
41
+ params = "format=json&input_format=json&service=open-ils.cat&method=open-ils.cat.asset.copy_tree.retrieve&param=auth_token_not_needed_for_this_call&param=#{tcn}&param=#{options[:org_unit]}"
24
42
  end
43
+ else
44
+ params = "format=json&input_format=json&service=open-ils.cat&method=open-ils.cat.asset.copy_tree.global.retrieve&param=auth_token_not_needed_for_this_call&param=#{tcn}"
45
+ end
46
+ @gateway.query = params
25
47
 
26
- # Fetch holdings data from the Evergreen server
27
- # Returns a Status object
28
- #
29
- # Usage: `stat = conn.get_holdings 23405`
30
- # If you just want holdings at a specific org_unit: `my_connection.get_holdings 23405, org_unit: 5`
31
- def get_holdings tcn, options = {}
32
- if options.key?(:org_unit)
33
- if options[:descendants]
34
- params = "format=json&input_format=json&service=open-ils.cat&method=open-ils.cat.asset.copy_tree.retrieve&param=auth_token_not_needed_for_this_call&param=#{tcn}"
35
- if @org_units[options[:org_unit]][:descendants]
36
- @org_units[options[:org_unit]][:descendants].each do |ou|
37
- params << + "&param=#{ou}"
38
- end
39
- end
40
- else
41
- params = "format=json&input_format=json&service=open-ils.cat&method=open-ils.cat.asset.copy_tree.retrieve&param=auth_token_not_needed_for_this_call&param=#{tcn}&param=#{options[:org_unit]}"
42
- end
43
- else
44
- params = "format=json&input_format=json&service=open-ils.cat&method=open-ils.cat.asset.copy_tree.global.retrieve&param=auth_token_not_needed_for_this_call&param=#{tcn}"
45
- end
46
- @gateway.query = params
48
+ res = send_query
49
+ return Status.new res.body, @idl_order, self if res
50
+ end
47
51
 
48
- res = send_query
49
- return Status.new res.body, @idl_order, self if res
50
- end
52
+ # Given an ID, returns a human-readable name
53
+ def location_name(id)
54
+ @acpl_cache.fetch(id) { |id| fetch_new_acpl(id) || id }
55
+ end
51
56
 
52
- # Given an ID, returns a human-readable name
53
- def location_name id
54
- params = "format=json&input_format=json&service=open-ils.circ&method=open-ils.circ.copy_location.retrieve&param=#{id}"
55
- @gateway.query = params
56
- res = send_query
57
- if res
58
- data = JSON.parse(res.body)['payload'][0]
59
- unless data.key? 'stacktrace'
60
- return data['__p'][@idl_order[:acpl]['name']]
61
- end
62
- end
63
- return id
64
- end
57
+ def status_name(id)
58
+ @possible_item_statuses[id]
59
+ end
65
60
 
66
- def status_name id
67
- return @possible_item_statuses[id]
61
+ def ou_name(id)
62
+ @org_units[id][:name]
68
63
  end
69
64
 
70
- def ou_name id
71
- return @org_units[id][:name]
72
- end
65
+ private
73
66
 
74
- private
75
-
76
- def add_ou_descendants id, parent
77
- (@org_units[parent][:descendants] ||= []) << id
78
- if @org_units[parent][:parent]
79
- add_ou_descendants id, @org_units[parent][:parent]
80
- end
81
- end
82
-
83
- def take_info_from_ou_tree o
84
- id = o[@idl_order[:aou]['id']]
85
- @org_units[id] = {}
86
- @org_units[id][:name] = o[@idl_order[:aou]['name']]
87
- if o[@idl_order[:aou]['parent_ou']]
88
- @org_units[id][:parent] = o[@idl_order[:aou]['parent_ou']]
89
- add_ou_descendants id, o[@idl_order[:aou]['parent_ou']]
90
- end
91
- o[@idl_order[:aou]['children']].each do |p|
92
- take_info_from_ou_tree p['__p']
93
- end
94
- end
67
+ def add_ou_descendants(id, parent)
68
+ (@org_units[parent][:descendants] ||= []) << id
69
+ add_ou_descendants id, @org_units[parent][:parent] if @org_units[parent][:parent]
70
+ end
95
71
 
72
+ def take_info_from_ou_tree(o)
73
+ id = o[@idl_order[:aou]['id']]
74
+ @org_units[id] = {}
75
+ @org_units[id][:name] = o[@idl_order[:aou]['name']]
76
+ if o[@idl_order[:aou]['parent_ou']]
77
+ @org_units[id][:parent] = o[@idl_order[:aou]['parent_ou']]
78
+ add_ou_descendants id, o[@idl_order[:aou]['parent_ou']]
79
+ end
80
+ o[@idl_order[:aou]['children']].each do |p|
81
+ take_info_from_ou_tree p['__p']
82
+ end
83
+ end
96
84
 
97
- def send_query
98
- begin
99
- res = Net::HTTP.get_response(@gateway)
100
- rescue Errno::ECONNREFUSED, Net::ReadTimeout
101
- return nil
102
- end
103
- return res if res.is_a?(Net::HTTPSuccess)
104
- return nil
105
- end
85
+ # Given the ID of a shelving location, this method
86
+ # finds the name of the location, caches it, and
87
+ # returns it
88
+ def fetch_new_acpl(id)
89
+ params = "format=json&input_format=json&service=open-ils.circ&method=open-ils.circ.copy_location.retrieve&param=#{id}"
90
+ @gateway.query = params
91
+ res = send_query
92
+ if res
93
+ data = JSON.parse(res.body)['payload'][0]
94
+ name = data['__p'][@idl_order[:acpl]['name']] unless data.key? 'stacktrace'
95
+ @acpl_cache[id] = name
96
+ return name if name
97
+ end
98
+ false
99
+ end
106
100
 
107
- def fetch_idl_order
108
- @idl_order = {}
101
+ def send_query
102
+ begin
103
+ res = Net::HTTP.get_response(@gateway)
104
+ rescue Errno::ECONNREFUSED, Net::ReadTimeout
105
+ return nil
106
+ end
107
+ return res if res.is_a?(Net::HTTPSuccess)
109
108
 
110
- idl = Nokogiri::XML(open(@evergreen_domain + '/reports/fm_IDL.xml'))
109
+ nil
110
+ end
111
111
 
112
- [:acn, :acp, :acpl, :aou, :ccs, :circ].each do |idl_class|
113
- i = 0
114
- @idl_order[idl_class] = {}
115
- fields = idl.xpath("//idl:class[@id='#{idl_class}']/idl:fields/idl:field", 'idl' => 'http://opensrf.org/spec/IDL/base/v1')
116
- fields.each do |field|
117
- @idl_order[idl_class][field['name']] = i
118
- i = i + 1
119
- end
120
- end
121
- end
112
+ def fetch_idl_order
113
+ @idl_order = {}
122
114
 
123
- def fetch_statuses
124
- @possible_item_statuses = []
125
- params = 'format=json&input_format=json&service=open-ils.search&method=open-ils.search.config.copy_status.retrieve.all'
126
- @gateway.query = params
127
- res = send_query
128
- if res
129
- stats = JSON.parse(res.body)['payload'][0]
130
- stats.each do |stat|
131
- @possible_item_statuses[stat['__p'][@idl_order[:ccs]['id']]] = stat['__p'][@idl_order[:ccs]['name']]
132
- end
133
- return true if stats.size > 0
134
- end
135
- return false
136
- end
115
+ idl = Nokogiri::XML(open(@evergreen_domain + '/reports/fm_IDL.xml'))
137
116
 
138
- def fetch_ou_tree
139
- @org_units = {}
140
- params = 'format=json&input_format=json&service=open-ils.actor&method=open-ils.actor.org_tree.retrieve'
141
- @gateway.query = params
142
- res = send_query
143
- if res
144
- raw_orgs = JSON.parse(res.body)['payload'][0]['__p']
145
- take_info_from_ou_tree raw_orgs
146
- return true if @org_units.size > 0
147
- end
148
- return false
117
+ %i[acn acp acpl aou ccs circ].each do |idl_class|
118
+ i = 0
119
+ @idl_order[idl_class] = {}
120
+ fields = idl.xpath("//idl:class[@id='#{idl_class}']/idl:fields/idl:field", 'idl' => 'http://opensrf.org/spec/IDL/base/v1')
121
+ fields.each do |field|
122
+ @idl_order[idl_class][field['name']] = i
123
+ i += 1
149
124
  end
150
-
125
+ end
151
126
  end
152
127
 
153
- # Status objects represent all the holdings attached to a specific tcn
154
- class Status
155
- attr_reader :copies, :libraries
156
- def initialize json_data, idl_order, connection = nil
157
- @idl_order = idl_order
158
- @connection = connection
159
- @raw_data = JSON.parse(json_data)['payload'][0]
160
- extract_copies
161
- substitute_values_for_ids unless @connection.nil?
162
- @available_copies = []
163
- @next_copy_available = 'a date'
128
+ def fetch_statuses
129
+ @possible_item_statuses = []
130
+ params = 'format=json&input_format=json&service=open-ils.search&method=open-ils.search.config.copy_status.retrieve.all'
131
+ @gateway.query = params
132
+ res = send_query
133
+ if res
134
+ stats = JSON.parse(res.body)['payload'][0]
135
+ stats.each do |stat|
136
+ @possible_item_statuses[stat['__p'][@idl_order[:ccs]['id']]] = stat['__p'][@idl_order[:ccs]['name']]
164
137
  end
138
+ return true unless stats.empty?
139
+ end
140
+ false
141
+ end
165
142
 
166
- # Determines if any copies are available for your patrons
167
- def any_copies_available?
168
- @copies.each do |copy|
169
- return true if 0 == copy.status
170
- return true if 'Available' == copy.status
171
- end
172
- return false
173
- end
143
+ def fetch_ou_tree
144
+ @org_units = {}
145
+ params = 'format=json&input_format=json&service=open-ils.actor&method=open-ils.actor.org_tree.retrieve'
146
+ @gateway.query = params
147
+ res = send_query
148
+ if res
149
+ raw_orgs = JSON.parse(res.body)['payload'][0]['__p']
150
+ take_info_from_ou_tree raw_orgs
151
+ return true unless @org_units.empty?
152
+ end
153
+ false
154
+ end
155
+ end
156
+
157
+ # Status objects represent all the holdings attached to a specific tcn
158
+ class Status
159
+ attr_reader :copies, :libraries
160
+ def initialize(json_data, idl_order, connection = nil)
161
+ @idl_order = idl_order
162
+ @connection = connection
163
+ @raw_data = JSON.parse(json_data)['payload'][0]
164
+ extract_copies
165
+ substitute_values_for_ids unless @connection.nil?
166
+ @available_copies = []
167
+ @next_copy_available = 'a date'
168
+ end
174
169
 
175
- private
176
-
177
- # Look through @raw_data and find the copies
178
- def extract_copies
179
- @copies = Array.new
180
- @raw_data.each do |vol|
181
- if vol['__p'][0].size > 0
182
- vol['__p'][0].each do |item|
183
- i = 0
184
- item_info = {
185
- barcode: item['__p'][@idl_order[:acp]['barcode']],
186
- call_number: vol['__p'][@idl_order[:acn]['label']],
187
- location: item['__p'][@idl_order[:acp]['location']],
188
- status: item['__p'][@idl_order[:acp]['status']],
189
- owning_lib: item['__p'][@idl_order[:acp]['circ_lib']],
190
- }
191
- unless item['__p'][@idl_order[:acp]['circulations']].is_a? Array
192
- @copies.push Item.new item_info
193
- else
194
- begin
195
- item_info[:due_date] = item['__p'][@idl_order[:acp]['circulations']][0]['__p'][@idl_order[:circ]['due_date']]
196
- rescue
197
- end
198
- @copies.push Item.new item_info
199
- end
200
- end
201
- end
202
- end
203
- end
170
+ # Determines if any copies are available for your patrons
171
+ def any_copies_available?
172
+ @copies.each do |copy|
173
+ return true if copy.status.zero?
174
+ return true if copy.status == 'Available'
175
+ end
176
+ false
177
+ end
204
178
 
205
- def substitute_values_for_ids
206
- @libraries = @connection.org_units.clone
207
- @libraries.each { |key, lib| lib[:copies] = Array.new }
208
- @copies.each do |copy|
209
- if copy.location.is_a? Numeric
210
- copy.location = @connection.location_name copy.location
211
- end
212
- if copy.status.is_a? Numeric
213
- copy.status = @connection.status_name copy.status
214
- end
215
- if copy.owning_lib.is_a? Numeric
216
- ou_id = copy.owning_lib
217
- copy.owning_lib = @connection.ou_name copy.owning_lib
218
- @libraries[ou_id][:copies].push copy
219
- end
179
+ private
180
+
181
+ # Look through @raw_data and find the copies
182
+ def extract_copies
183
+ @copies = []
184
+ @raw_data.each do |vol|
185
+ next if vol['__p'][0].empty?
186
+
187
+ vol['__p'][0].each do |item|
188
+ item_info = {
189
+ barcode: item['__p'][@idl_order[:acp]['barcode']],
190
+ call_number: vol['__p'][@idl_order[:acn]['label']],
191
+ location: item['__p'][@idl_order[:acp]['location']],
192
+ status: item['__p'][@idl_order[:acp]['status']],
193
+ owning_lib: item['__p'][@idl_order[:acp]['circ_lib']]
194
+ }
195
+ if item['__p'][@idl_order[:acp]['circulations']].is_a? Array
196
+ begin
197
+ item_info[:due_date] = item['__p'][@idl_order[:acp]['circulations']][0]['__p'][@idl_order[:circ]['due_date']]
198
+ rescue StandardError
199
+ end
200
+ @copies.push Item.new item_info
201
+ else
202
+ @copies.push Item.new item_info
220
203
  end
221
204
  end
222
-
205
+ end
223
206
  end
224
207
 
225
- # A physical copy of an item
226
- class Item
227
- attr_accessor :location, :status, :owning_lib
228
- attr_reader :barcode, :call_number, :due_date
229
- def initialize data = {}
230
- data.each do |k,v|
231
- instance_variable_set("@#{k}", v) unless v.nil?
232
- end
233
- end
208
+ def substitute_values_for_ids
209
+ @libraries = @connection.org_units.clone
210
+ @libraries.each { |_key, lib| lib[:copies] = [] }
211
+ @copies.each do |copy|
212
+ copy.location = @connection.location_name copy.location if copy.location.is_a? Numeric
213
+ copy.status = @connection.status_name copy.status if copy.status.is_a? Numeric
214
+ next unless copy.owning_lib.is_a? Numeric
215
+
216
+ ou_id = copy.owning_lib
217
+ copy.owning_lib = @connection.ou_name copy.owning_lib
218
+ @libraries[ou_id][:copies].push copy
219
+ end
220
+ end
221
+ end
222
+
223
+ # A physical copy of an item
224
+ class Item
225
+ attr_accessor :location, :status, :owning_lib
226
+ attr_reader :barcode, :call_number, :due_date
227
+ def initialize(data = {})
228
+ data.each do |k, v|
229
+ instance_variable_set("@#{k}", v) unless v.nil?
230
+ end
234
231
  end
232
+ end
235
233
  end
metadata CHANGED
@@ -1,22 +1,22 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: evergreen_holdings
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jane Sandberg
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
  date: 2019-12-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: nokogiri
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
18
  version: '1.11'
19
+ name: nokogiri
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
@@ -25,33 +25,53 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.11'
27
27
  - !ruby/object:Gem::Dependency
28
- name: minitest
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
30
  - - "~>"
32
31
  - !ruby/object:Gem::Version
33
- version: 5.0.0
32
+ version: 0.7.0
33
+ name: coveralls
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 5.0.0
40
+ version: 0.7.0
41
41
  - !ruby/object:Gem::Dependency
42
- name: coveralls
43
42
  requirement: !ruby/object:Gem::Requirement
44
43
  requirements:
45
44
  - - "~>"
46
45
  - !ruby/object:Gem::Version
47
- version: 0.7.0
46
+ version: 5.0.0
47
+ name: minitest
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.7.0
54
+ version: 5.0.0
55
+ - !ruby/object:Gem::Dependency
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">"
59
+ - !ruby/object:Gem::Version
60
+ version: 1.0.0
61
+ - - "<"
62
+ - !ruby/object:Gem::Version
63
+ version: '2'
64
+ name: rubocop
65
+ type: :development
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">"
70
+ - !ruby/object:Gem::Version
71
+ version: 1.0.0
72
+ - - "<"
73
+ - !ruby/object:Gem::Version
74
+ version: '2'
55
75
  description: Access holdings information from Evergreen ILS
56
76
  email: sandbej@linnbenton.edu
57
77
  executables: []
@@ -65,7 +85,7 @@ homepage: https://github.com/sandbergja/evergreen_holdings_gem
65
85
  licenses:
66
86
  - MIT
67
87
  metadata: {}
68
- post_install_message:
88
+ post_install_message:
69
89
  rdoc_options: []
70
90
  require_paths:
71
91
  - lib
@@ -80,9 +100,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
100
  - !ruby/object:Gem::Version
81
101
  version: '0'
82
102
  requirements: []
83
- rubyforge_project:
84
- rubygems_version: 2.6.13
85
- signing_key:
103
+ rubygems_version: 3.0.6
104
+ signing_key:
86
105
  specification_version: 4
87
106
  summary: A ruby gem for getting information about copy availability from Evergreen
88
107
  ILS