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.
- checksums.yaml +5 -5
- data/lib/evergreen_holdings.rb +196 -198
- metadata +32 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e5800a7a145695ef115c882d45a1ba4264ea8f97888d7d305b7fdbbda4085b84
|
4
|
+
data.tar.gz: 0eaf07e5c8bb021fd79fcee3ec8584beff6b1842d097de72b7285614e2866368
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14af7152bf4201748e500b1821152cc0331413e6b4e7df8ede03983b180bfbe3e32f9d368714b8bf7d5f9a015003500b32fcfce5a98e757b98c40ced3813166e
|
7
|
+
data.tar.gz: e4e82b9fe288ae589cad6089d34464421a5f0ffb698abbaa1ae2d41e55a9f1b6cbd2477ba545e0fc7bbc897828f3bce8fc3262a9e79872c16d3c6e20fa23c881
|
data/lib/evergreen_holdings.rb
CHANGED
@@ -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
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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¶m=auth_token_not_needed_for_this_call¶m=#{tcn}"
|
37
|
+
@org_units[options[:org_unit]][:descendants]&.each do |ou|
|
38
|
+
params << + "¶m=#{ou}"
|
39
|
+
end
|
40
|
+
else
|
41
|
+
params = "format=json&input_format=json&service=open-ils.cat&method=open-ils.cat.asset.copy_tree.retrieve¶m=auth_token_not_needed_for_this_call¶m=#{tcn}¶m=#{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¶m=auth_token_not_needed_for_this_call¶m=#{tcn}"
|
45
|
+
end
|
46
|
+
@gateway.query = params
|
25
47
|
|
26
|
-
|
27
|
-
|
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¶m=auth_token_not_needed_for_this_call¶m=#{tcn}"
|
35
|
-
if @org_units[options[:org_unit]][:descendants]
|
36
|
-
@org_units[options[:org_unit]][:descendants].each do |ou|
|
37
|
-
params << + "¶m=#{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¶m=auth_token_not_needed_for_this_call¶m=#{tcn}¶m=#{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¶m=auth_token_not_needed_for_this_call¶m=#{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
|
-
|
49
|
-
|
50
|
-
|
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
|
-
|
53
|
-
|
54
|
-
|
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
|
-
|
67
|
-
|
61
|
+
def ou_name(id)
|
62
|
+
@org_units[id][:name]
|
68
63
|
end
|
69
64
|
|
70
|
-
|
71
|
-
return @org_units[id][:name]
|
72
|
-
end
|
65
|
+
private
|
73
66
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
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¶m=#{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
|
-
|
108
|
-
|
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
|
-
|
109
|
+
nil
|
110
|
+
end
|
111
111
|
|
112
|
-
|
113
|
-
|
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
|
-
|
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
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
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
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
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
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
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
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
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
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
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
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
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.
|
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:
|
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:
|
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.
|
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.
|
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
|
-
|
84
|
-
|
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
|