alexandria-zoom 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/ChangeLog +178 -0
- data/LICENSE +504 -0
- data/README.md +94 -0
- data/ext/zoom/extconf.rb +19 -0
- data/ext/zoom/rbzoom.c +34 -0
- data/ext/zoom/rbzoom.h +68 -0
- data/ext/zoom/rbzoomconnection.c +346 -0
- data/ext/zoom/rbzoomoptions.c +121 -0
- data/ext/zoom/rbzoompackage.c +200 -0
- data/ext/zoom/rbzoomquery.c +125 -0
- data/ext/zoom/rbzoomrecord.c +192 -0
- data/ext/zoom/rbzoomresultset.c +268 -0
- data/sample/hello.rb +8 -0
- data/sample/needle.rb +125 -0
- metadata +146 -0
@@ -0,0 +1,268 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (C) 2005 Laurent Sansonetti <lrz@chopine.be>
|
3
|
+
*
|
4
|
+
* This library is free software; you can redistribute it and/or
|
5
|
+
* modify it under the terms of the GNU Lesser General Public
|
6
|
+
* License as published by the Free Software Foundation; either
|
7
|
+
* version 2.1 of the License, or (at your option) any later version.
|
8
|
+
*
|
9
|
+
* This library is distributed in the hope that it will be useful,
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
* Lesser General Public License for more details.
|
13
|
+
*
|
14
|
+
* You should have received a copy of the GNU Lesser General Public
|
15
|
+
* License along with this library; if not, write to the Free Software
|
16
|
+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
17
|
+
*/
|
18
|
+
|
19
|
+
#include "rbzoom.h"
|
20
|
+
|
21
|
+
#ifdef MAKING_RDOC_HAPPY
|
22
|
+
mZoom = rb_define_module("ZOOM");
|
23
|
+
#endif
|
24
|
+
|
25
|
+
/* Class: ZOOM::ResultSet
|
26
|
+
* The result set object is a container for records returned from a target.
|
27
|
+
*/
|
28
|
+
static VALUE cZoomResultSet;
|
29
|
+
|
30
|
+
VALUE
|
31
|
+
rbz_resultset_make (ZOOM_resultset resultset)
|
32
|
+
{
|
33
|
+
return resultset != NULL
|
34
|
+
? Data_Wrap_Struct (cZoomResultSet,
|
35
|
+
NULL,
|
36
|
+
ZOOM_resultset_destroy,
|
37
|
+
resultset)
|
38
|
+
: Qnil;
|
39
|
+
}
|
40
|
+
|
41
|
+
static ZOOM_resultset
|
42
|
+
rbz_resultset_get (VALUE obj)
|
43
|
+
{
|
44
|
+
ZOOM_resultset resultset;
|
45
|
+
|
46
|
+
Data_Get_Struct (obj, struct ZOOM_resultset_p, resultset);
|
47
|
+
assert (resultset != NULL);
|
48
|
+
|
49
|
+
return resultset;
|
50
|
+
}
|
51
|
+
|
52
|
+
/*
|
53
|
+
* call-seq:
|
54
|
+
* set_option(key, value)
|
55
|
+
*
|
56
|
+
* key: the name of the option, as a string.
|
57
|
+
*
|
58
|
+
* value: the value of this option (as a string, integer or boolean).
|
59
|
+
*
|
60
|
+
* Sets an option on the result set.
|
61
|
+
*
|
62
|
+
* Returns: self.
|
63
|
+
*/
|
64
|
+
static VALUE
|
65
|
+
rbz_resultset_set_option (VALUE self, VALUE key, VALUE val)
|
66
|
+
{
|
67
|
+
ZOOM_resultset_option_set (rbz_resultset_get (self),
|
68
|
+
RVAL2CSTR (key),
|
69
|
+
RVAL2CSTR (rb_obj_as_string (val)));
|
70
|
+
|
71
|
+
return self;
|
72
|
+
}
|
73
|
+
|
74
|
+
/*
|
75
|
+
* call-seq:
|
76
|
+
* get_option(key)
|
77
|
+
*
|
78
|
+
* key: the name of the option, as a string.
|
79
|
+
*
|
80
|
+
* Gets the value of a result set's option.
|
81
|
+
*
|
82
|
+
* Returns: the value of the given option, as a string, integer or boolean.
|
83
|
+
*/
|
84
|
+
static VALUE
|
85
|
+
rbz_resultset_get_option (VALUE self, VALUE key)
|
86
|
+
{
|
87
|
+
const char *value;
|
88
|
+
|
89
|
+
value = ZOOM_resultset_option_get (rbz_resultset_get (self),
|
90
|
+
RVAL2CSTR (key));
|
91
|
+
|
92
|
+
return zoom_option_value_to_ruby_value (value);
|
93
|
+
}
|
94
|
+
|
95
|
+
/*
|
96
|
+
* Returns: the number of hits.
|
97
|
+
*/
|
98
|
+
static VALUE
|
99
|
+
rbz_resultset_size (VALUE self)
|
100
|
+
{
|
101
|
+
return INT2NUM (ZOOM_resultset_size (rbz_resultset_get (self)));
|
102
|
+
}
|
103
|
+
|
104
|
+
/*
|
105
|
+
* call-seq:
|
106
|
+
* [](key)
|
107
|
+
*
|
108
|
+
* key: either an integer, a range or an interval of 2 integers.
|
109
|
+
*
|
110
|
+
* Retrieves one or many records from the result set, according to the given
|
111
|
+
* key.
|
112
|
+
*
|
113
|
+
* # Gets the first record.
|
114
|
+
* rset[0]
|
115
|
+
* # Gets the first, second and third records.
|
116
|
+
* rset[1..3]
|
117
|
+
* # Gets three records starting from the second one.
|
118
|
+
* rset[2, 3]
|
119
|
+
*
|
120
|
+
* Returns: one or many references to ZOOM::Record objects.
|
121
|
+
*/
|
122
|
+
static VALUE
|
123
|
+
rbz_resultset_index (int argc, VALUE *argv, VALUE self)
|
124
|
+
{
|
125
|
+
ZOOM_record *records;
|
126
|
+
ZOOM_record record;
|
127
|
+
VALUE ary;
|
128
|
+
size_t begin;
|
129
|
+
size_t count;
|
130
|
+
size_t i;
|
131
|
+
|
132
|
+
if (argc == 1) {
|
133
|
+
VALUE arg = argv [0];
|
134
|
+
|
135
|
+
if (TYPE (arg) == T_FIXNUM || TYPE (arg) == T_BIGNUM) {
|
136
|
+
record = ZOOM_resultset_record (rbz_resultset_get (self),
|
137
|
+
NUM2LONG (arg));
|
138
|
+
return record != NULL
|
139
|
+
? rbz_record_make (ZOOM_record_clone (record))
|
140
|
+
: Qnil;
|
141
|
+
}
|
142
|
+
|
143
|
+
if (CLASS_OF (arg) == rb_cRange) {
|
144
|
+
begin = NUM2LONG (rb_funcall (arg, rb_intern ("begin"), 0));
|
145
|
+
count = NUM2LONG (rb_funcall (arg, rb_intern ("end"), 0));
|
146
|
+
count -= begin;
|
147
|
+
}
|
148
|
+
else
|
149
|
+
rb_raise (rb_eArgError,
|
150
|
+
"Invalid argument of type %s (not Numeric or Range)",
|
151
|
+
rb_class2name (CLASS_OF (arg)));
|
152
|
+
}
|
153
|
+
else {
|
154
|
+
VALUE rb_begin;
|
155
|
+
VALUE rb_count;
|
156
|
+
|
157
|
+
rb_scan_args (argc, argv, "2", &rb_begin, &rb_count);
|
158
|
+
|
159
|
+
begin = NUM2LONG (rb_begin);
|
160
|
+
count = NUM2LONG (rb_count);
|
161
|
+
}
|
162
|
+
|
163
|
+
ary = rb_ary_new ();
|
164
|
+
if (count == 0)
|
165
|
+
return ary;
|
166
|
+
|
167
|
+
/* Allocate array */
|
168
|
+
records = ALLOC_N (ZOOM_record, count);
|
169
|
+
|
170
|
+
/* Download records in batches */
|
171
|
+
ZOOM_resultset_records (rbz_resultset_get (self), records, begin, count);
|
172
|
+
|
173
|
+
/* Test the first record in the set. If null, then fall back. If valid,
|
174
|
+
* generate the ruby array.
|
175
|
+
*/
|
176
|
+
|
177
|
+
if (records[0]!=NULL) {
|
178
|
+
for (i = 0; i < count; i++)
|
179
|
+
|
180
|
+
/* We don't want any null records -- if there is on in the resultset,
|
181
|
+
* ignore it.
|
182
|
+
*/
|
183
|
+
|
184
|
+
if (records[i]!=NULL)
|
185
|
+
rb_ary_push (ary, rbz_record_make (ZOOM_record_clone (records [i])));
|
186
|
+
} else {
|
187
|
+
/* This is our fallback function
|
188
|
+
* It exists for those anomalies where the server
|
189
|
+
* will not respect the batch request and will return just
|
190
|
+
* a null array (per change request 36 where Laurent Sansonetti notes
|
191
|
+
* Retrieves the record one by one using ZOOM_resultset_record instead
|
192
|
+
* of getting them all in once with ZOOM_resultset_records (for a strange
|
193
|
+
* reason sometimes the resultset was not empty but ZOOM_resultset_records
|
194
|
+
* used to return empty records).
|
195
|
+
*/
|
196
|
+
|
197
|
+
for (i = 0; i < count; i++) {
|
198
|
+
record = ZOOM_resultset_record (rbz_resultset_get (self),
|
199
|
+
begin + i);
|
200
|
+
/* Ignore null records */
|
201
|
+
if (record != NULL)
|
202
|
+
rb_ary_push (ary, rbz_record_make (ZOOM_record_clone (record)));
|
203
|
+
}
|
204
|
+
}
|
205
|
+
|
206
|
+
return ary;
|
207
|
+
}
|
208
|
+
|
209
|
+
/*
|
210
|
+
* Lists the records inside the result set.
|
211
|
+
*
|
212
|
+
* Returns: an array of ZOOM::Record objects.
|
213
|
+
*/
|
214
|
+
static VALUE
|
215
|
+
rbz_resultset_records (VALUE self)
|
216
|
+
{
|
217
|
+
VALUE argv [2];
|
218
|
+
|
219
|
+
argv [0] = INT2FIX (0);
|
220
|
+
argv [1] = rbz_resultset_size (self);
|
221
|
+
|
222
|
+
return rbz_resultset_index (2, argv, self);
|
223
|
+
}
|
224
|
+
|
225
|
+
/*
|
226
|
+
* call-seq:
|
227
|
+
* each_record { |record| ... }
|
228
|
+
*
|
229
|
+
* Parses the records inside the result set and call the given block for each
|
230
|
+
* record, passing a reference to a ZOOM::Record object as parameter.
|
231
|
+
*
|
232
|
+
* Returns: self.
|
233
|
+
*/
|
234
|
+
static VALUE
|
235
|
+
rbz_resultset_each_record (VALUE self)
|
236
|
+
{
|
237
|
+
rb_ary_each (rbz_resultset_records (self));
|
238
|
+
return self;
|
239
|
+
}
|
240
|
+
|
241
|
+
void
|
242
|
+
Init_zoom_resultset (VALUE mZoom)
|
243
|
+
{
|
244
|
+
VALUE c;
|
245
|
+
|
246
|
+
c = rb_define_class_under (mZoom, "ResultSet", rb_cObject);
|
247
|
+
rb_undef_alloc_func(c);
|
248
|
+
|
249
|
+
rb_undef_method (CLASS_OF (c), "new");
|
250
|
+
rb_define_method (c, "set_option", rbz_resultset_set_option, 2);
|
251
|
+
rb_define_method (c, "get_option", rbz_resultset_get_option, 1);
|
252
|
+
|
253
|
+
define_zoom_option (c, "start");
|
254
|
+
define_zoom_option (c, "count");
|
255
|
+
define_zoom_option (c, "presentChunk");
|
256
|
+
define_zoom_option (c, "elementSetName");
|
257
|
+
define_zoom_option (c, "preferredRecordSyntax");
|
258
|
+
define_zoom_option (c, "schema");
|
259
|
+
define_zoom_option (c, "setname");
|
260
|
+
|
261
|
+
rb_define_method (c, "size", rbz_resultset_size, 0);
|
262
|
+
rb_define_alias (c, "length", "size");
|
263
|
+
rb_define_method (c, "records", rbz_resultset_records, 0);
|
264
|
+
rb_define_method (c, "each_record", rbz_resultset_each_record, 0);
|
265
|
+
rb_define_method (c, "[]", rbz_resultset_index, -1);
|
266
|
+
|
267
|
+
cZoomResultSet = c;
|
268
|
+
}
|
data/sample/hello.rb
ADDED
data/sample/needle.rb
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
#
|
3
|
+
# Given a list of ISBNs and Z39.50 servers, try to get a MARC record
|
4
|
+
# for each book. The servers listed here seem to be the best
|
5
|
+
# worldwide. If an ISBN cannot be found then we use the xisbn service
|
6
|
+
# to try different editions.
|
7
|
+
#
|
8
|
+
# TODO: If more then one record is found, pick the longest one.
|
9
|
+
#
|
10
|
+
# By Devin Bayer - Summer 2006 - Public Domain
|
11
|
+
#
|
12
|
+
#
|
13
|
+
require 'rubygems'
|
14
|
+
require 'zoom'
|
15
|
+
require 'net/http'
|
16
|
+
Net::HTTP.version_1_2
|
17
|
+
require 'rexml/document'
|
18
|
+
|
19
|
+
servers_source = [
|
20
|
+
# Server, Username, Password
|
21
|
+
[ 'z3950.loc.gov:7090/Voyager' ], # Library of Congress
|
22
|
+
[ 'amicus.nlc-bnc.ca/ANY', 'USERNAME', 'PASSWORD' ], # Canada
|
23
|
+
[ 'catnyp.nypl.org:210/INNOPAC' ], # New York Public
|
24
|
+
[ 'z3950.copac.ac.uk:2100/COPAC' ], # United Kingdom
|
25
|
+
[ 'z3950.btj.se:210/BURK' ], # Sweden
|
26
|
+
[ '195.249.206.204:210/Default' ], # DenMark
|
27
|
+
[ 'library.ox.ac.uk:210/ADVANCE' ], # Oxford
|
28
|
+
[ '216.16.224.199:210/INNOPAC' ], # Cambridge
|
29
|
+
[ 'prodorbis.library.yale.edu:7090/Voyager' ], # Yale
|
30
|
+
[ 'zsrv.library.northwestern.edu:11090/Voyager' ]] # NorthWestern University
|
31
|
+
|
32
|
+
#########################################
|
33
|
+
# Connect to each server
|
34
|
+
#########################################
|
35
|
+
@servers = Array.new
|
36
|
+
|
37
|
+
servers_source.each do |array|
|
38
|
+
tries = 0
|
39
|
+
$stderr.puts 'INFO: connecting to ' + array[0]
|
40
|
+
begin
|
41
|
+
con = ZOOM::Connection.new()
|
42
|
+
con.preferred_record_syntax = 'MARC21'
|
43
|
+
con.element_set_name = 'F'
|
44
|
+
if array[1] then
|
45
|
+
con.user = array[1]
|
46
|
+
con.password = array[2]
|
47
|
+
end
|
48
|
+
con.connect(array[0])
|
49
|
+
@servers << con
|
50
|
+
rescue RuntimeError
|
51
|
+
$stderr.puts 'ERROR: connecting to ' + array[0] + ': ' + $!
|
52
|
+
tries += 1
|
53
|
+
retry if tries < 3
|
54
|
+
$stderr.puts 'WARNING: giving up on ' + array[0]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
#################################
|
59
|
+
# search for ISBN on each server
|
60
|
+
# return true if found
|
61
|
+
#################################
|
62
|
+
def search(isbn)
|
63
|
+
@servers.each do |con|
|
64
|
+
begin
|
65
|
+
rset = con.search("@attr 1=7 #{isbn}")
|
66
|
+
if rset.size > 0 and rset[0].to_s.chomp.length > 1 then
|
67
|
+
$stderr.puts con.host + ': ' + isbn + ': ' +
|
68
|
+
rset.size.to_s + ' records'
|
69
|
+
puts rset[0].raw('marc8')
|
70
|
+
return true
|
71
|
+
end
|
72
|
+
rescue RuntimeError
|
73
|
+
$stderr.puts 'WARNING: ' + con.host + ': ' +
|
74
|
+
isbn + ': ' + $!
|
75
|
+
end
|
76
|
+
end
|
77
|
+
return false
|
78
|
+
end
|
79
|
+
|
80
|
+
#########################################
|
81
|
+
# Lookup each ISBN
|
82
|
+
#########################################
|
83
|
+
failed_isbns = Array.new
|
84
|
+
|
85
|
+
xisbn = Net::HTTP.new('labs.oclc.org')
|
86
|
+
|
87
|
+
File.open('isbns').each_line do |isbn|
|
88
|
+
isbn = isbn.chomp.upcase
|
89
|
+
next if isbn.length < 1
|
90
|
+
if not search(isbn) then
|
91
|
+
tries = 0
|
92
|
+
# Try alternate editions
|
93
|
+
begin
|
94
|
+
xisbn.start if not xisbn.started?
|
95
|
+
xml = xisbn.get("/xisbn/#{isbn}").body
|
96
|
+
rescue SocketError, Errno::ECONNRESET, Errno::EPIPE, EOFError, Timeout::Error
|
97
|
+
xisbn.finish if xisbn.started?
|
98
|
+
if tries < 3 then
|
99
|
+
tries += 1
|
100
|
+
retry
|
101
|
+
else
|
102
|
+
$stderr.puts "ERROR: xisbn failure: " + $!
|
103
|
+
end
|
104
|
+
end
|
105
|
+
found = false
|
106
|
+
REXML::Document.new(xml).root.each_element do |elem|
|
107
|
+
alt = elem.texts.to_s.chomp.upcase
|
108
|
+
next if alt == isbn
|
109
|
+
if search(alt) then
|
110
|
+
$stderr.puts "INFO: alternate for #{isbn}: #{alt}"
|
111
|
+
found = true
|
112
|
+
break
|
113
|
+
end
|
114
|
+
end
|
115
|
+
if not found then
|
116
|
+
$stderr.puts "INFO: isbn #{isbn} not found"
|
117
|
+
failed_isbns << isbn
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
if failed_isbns.size > 0 then
|
123
|
+
$stderr.puts "ISBN's not found:"
|
124
|
+
failed_isbns.each { |isbn| $stderr.puts isbn }
|
125
|
+
end
|
metadata
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: alexandria-zoom
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.6.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matijs van Zuijlen
|
8
|
+
- Laurent Sansonetti
|
9
|
+
- Ed Summers
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2023-04-28 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: pkg-config
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - "~>"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.5.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - "~>"
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: 1.5.1
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: rake
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - "~>"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '13.0'
|
36
|
+
type: :development
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '13.0'
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: rake-compiler
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '1.2'
|
50
|
+
type: :development
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - "~>"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '1.2'
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: rake-manifest
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - "~>"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 0.2.0
|
64
|
+
type: :development
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - "~>"
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 0.2.0
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: rubocop
|
73
|
+
requirement: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - "~>"
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '1.41'
|
78
|
+
type: :development
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - "~>"
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '1.41'
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: test-unit
|
87
|
+
requirement: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - "~>"
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '3.3'
|
92
|
+
type: :development
|
93
|
+
prerelease: false
|
94
|
+
version_requirements: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - "~>"
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '3.3'
|
99
|
+
description:
|
100
|
+
email:
|
101
|
+
executables: []
|
102
|
+
extensions:
|
103
|
+
- ext/zoom/extconf.rb
|
104
|
+
extra_rdoc_files: []
|
105
|
+
files:
|
106
|
+
- ChangeLog
|
107
|
+
- LICENSE
|
108
|
+
- README.md
|
109
|
+
- ext/zoom/extconf.rb
|
110
|
+
- ext/zoom/rbzoom.c
|
111
|
+
- ext/zoom/rbzoom.h
|
112
|
+
- ext/zoom/rbzoomconnection.c
|
113
|
+
- ext/zoom/rbzoomoptions.c
|
114
|
+
- ext/zoom/rbzoompackage.c
|
115
|
+
- ext/zoom/rbzoomquery.c
|
116
|
+
- ext/zoom/rbzoomrecord.c
|
117
|
+
- ext/zoom/rbzoomresultset.c
|
118
|
+
- sample/hello.rb
|
119
|
+
- sample/needle.rb
|
120
|
+
homepage: https://github.com/mvz/alexandria-zoom
|
121
|
+
licenses:
|
122
|
+
- LGPL-2.1
|
123
|
+
metadata:
|
124
|
+
rubygems_mfa_required: 'true'
|
125
|
+
post_install_message:
|
126
|
+
rdoc_options: []
|
127
|
+
require_paths:
|
128
|
+
- lib
|
129
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 2.7.0
|
134
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
requirements: []
|
140
|
+
rubygems_version: 3.4.12
|
141
|
+
signing_key:
|
142
|
+
specification_version: 4
|
143
|
+
summary: Ruby/ZOOM provides a Ruby binding to the Z39.50 Object-Orientation Model
|
144
|
+
(ZOOM), an abstract object-oriented programming interface to a subset of the services
|
145
|
+
specified by the Z39.50 standard, also known as the international standard ISO 23950.
|
146
|
+
test_files: []
|