sip2-ruby 0.1.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 (45) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +136 -0
  4. data/Rakefile +10 -0
  5. data/bin/json-to-sip2 +109 -0
  6. data/bin/sip2-to-json +81 -0
  7. data/lib/sip2/checksum_encoder.rb +11 -0
  8. data/lib/sip2/field_parser_rules.rb +490 -0
  9. data/lib/sip2/fields.rb +742 -0
  10. data/lib/sip2/message/base_message.rb +135 -0
  11. data/lib/sip2/message/unknown_message.rb +26 -0
  12. data/lib/sip2/message.rb +95 -0
  13. data/lib/sip2/message_parser_rules.rb +122 -0
  14. data/lib/sip2/messages.rb +628 -0
  15. data/lib/sip2/parser.rb +14 -0
  16. data/lib/sip2/parser_atoms.rb +53 -0
  17. data/lib/sip2/transformer.rb +94 -0
  18. data/lib/sip2/types.rb +6 -0
  19. data/lib/sip2/version.rb +3 -0
  20. data/lib/sip2.rb +18 -0
  21. data/sip2-ruby.gemspec +39 -0
  22. data/test/fixture_helper.rb +31 -0
  23. data/test/fixtures/09.sip2 +1 -0
  24. data/test/fixtures/10.sip2 +1 -0
  25. data/test/fixtures/17.sip2 +1 -0
  26. data/test/fixtures/18.sip2 +1 -0
  27. data/test/fixtures/98-with-unexpected.sip2 +1 -0
  28. data/test/fixtures/98.sip2 +1 -0
  29. data/test/fixtures/99-with-unexpected.sip2 +1 -0
  30. data/test/fixtures/99.sip2 +1 -0
  31. data/test/fixtures/XX.sip2 +1 -0
  32. data/test/fixtures/alma/09.sip2 +1 -0
  33. data/test/fixtures/alma/10.sip2 +1 -0
  34. data/test/fixtures/alma/17.sip2 +1 -0
  35. data/test/fixtures/alma/18.sip2 +1 -0
  36. data/test/fixtures/alma/98.sip2 +1 -0
  37. data/test/fixtures/alma/99.sip2 +1 -0
  38. data/test/round_trip_spec.rb +82 -0
  39. data/test/sip2/message_parser_rules_spec.rb +50 -0
  40. data/test/sip2/parser_atoms_spec.rb +354 -0
  41. data/test/sip2/parser_test.rb +11 -0
  42. data/test/sip2_spec.rb +145 -0
  43. data/test/spec_helper.rb +4 -0
  44. data/test/test_helper.rb +4 -0
  45. metadata +190 -0
@@ -0,0 +1,628 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sip2
4
+ MESSAGES = [
5
+ {
6
+ code: "01",
7
+ name: "Block Patron",
8
+ symbol: :block_patron,
9
+ ordered_fields: %i[
10
+ card_retained
11
+ transaction_date
12
+ ],
13
+ required_delimited_fields: %i[
14
+ institution_id
15
+ blocked_card_msg
16
+ patron_identifier
17
+ terminal_password
18
+ ],
19
+ optional_delimited_fields: [],
20
+ },
21
+ {
22
+ code: "09",
23
+ name: "Checkin",
24
+ symbol: :checkin,
25
+ ordered_fields: %i[
26
+ no_block
27
+ transaction_date
28
+ return_date
29
+ ],
30
+ required_delimited_fields: %i[
31
+ current_location
32
+ institution_id
33
+ item_identifier
34
+ terminal_password
35
+ ],
36
+ optional_delimited_fields: %i[
37
+ item_properties
38
+ cancel
39
+ ],
40
+ },
41
+ {
42
+ code: "10",
43
+ name: "Checkin Response",
44
+ symbol: :checkin_response,
45
+ ordered_fields: %i[
46
+ ok
47
+ resensitize
48
+ magnetic_media
49
+ alert
50
+ transaction_date
51
+ ],
52
+ required_delimited_fields: %i[
53
+ institution_id
54
+ item_identifier
55
+ permanent_location
56
+ ],
57
+ optional_delimited_fields: %i[
58
+ title_identifier
59
+ sort_bin
60
+ patron_identifier
61
+ media_type
62
+ item_properties
63
+ screen_message
64
+ print_line
65
+ ],
66
+ },
67
+ {
68
+ code: "11",
69
+ name: "Checkout",
70
+ symbol: :checkout,
71
+ ordered_fields: %i[
72
+ sc_renewal_policy
73
+ no_block
74
+ transaction_date
75
+ nb_due_date
76
+ ],
77
+ required_delimited_fields: %i[
78
+ institution_id
79
+ patron_identifier
80
+ item_identifier
81
+ terminal_password
82
+ ],
83
+ optional_delimited_fields: %i[
84
+ patron_password
85
+ item_properties
86
+ fee_acknowledged
87
+ cancel
88
+ ],
89
+ },
90
+ {
91
+ code: "12",
92
+ name: "Checkout Response",
93
+ symbol: :checkout_response,
94
+ ordered_fields: %i[
95
+ ok
96
+ renewal_ok
97
+ magnetic_media
98
+ desensitize
99
+ transaction_date
100
+ ],
101
+ required_delimited_fields: %i[
102
+ institution_id
103
+ patron_identifier
104
+ item_identifier
105
+ title_identifier
106
+ due_date
107
+ ],
108
+ optional_delimited_fields: %i[
109
+ fee_type
110
+ security_inhibit
111
+ currency_type
112
+ fee_amount
113
+ media_type
114
+ item_properties
115
+ transaction_id
116
+ screen_message
117
+ print_line
118
+ ]
119
+ },
120
+ {
121
+ code: "15",
122
+ name: "Hold",
123
+ symbol: :hold,
124
+ ordered_fields: %i[
125
+ hold_mode
126
+ transaction_date
127
+ ],
128
+ required_delimited_fields: %i[
129
+ institution_id
130
+ patron_identifier
131
+ ],
132
+ optional_delimited_fields: %i[
133
+ expiration_date
134
+ pickup_location
135
+ hold_type
136
+ patron_password
137
+ item_identifier
138
+ title_identifier
139
+ terminal_password
140
+ fee_acknowledged
141
+ ],
142
+ },
143
+ {
144
+ code: "16",
145
+ name: "Hold Response",
146
+ symbol: :hold_response,
147
+ ordered_fields: %i[
148
+ ok
149
+ available
150
+ transaction_date
151
+ ],
152
+ required_delimited_fields: %i[
153
+ institution_id
154
+ patron_identifier
155
+ ],
156
+ optional_delimited_fields: %i[
157
+ expiration_date
158
+ queue_position
159
+ pickup_location
160
+ item_identifier
161
+ title_identifier
162
+ screen_message
163
+ print_line
164
+ ],
165
+ },
166
+ {
167
+ code: "17",
168
+ name: "Item Information",
169
+ symbol: :item_information,
170
+ ordered_fields: %i[
171
+ transaction_date
172
+ ],
173
+ required_delimited_fields: %i[
174
+ institution_id
175
+ item_identifier
176
+ ],
177
+ optional_delimited_fields: %i[
178
+ terminal_password
179
+ ],
180
+ },
181
+ {
182
+ code: "18",
183
+ name: "Item Information Response",
184
+ symbol: :item_information_response,
185
+ ordered_fields: %i[
186
+ circulation_status
187
+ security_marker
188
+ fee_type_ordered
189
+ transaction_date
190
+ ],
191
+ required_delimited_fields: %i[
192
+ item_identifier
193
+ title_identifier
194
+ ],
195
+ optional_delimited_fields: %i[
196
+ hold_queue_length
197
+ due_date
198
+ recall_date
199
+ hold_pickup_date
200
+ owner
201
+ currency_type
202
+ fee_amount
203
+ media_type
204
+ permanent_location
205
+ current_location
206
+ item_properties
207
+ screen_message
208
+ print_line
209
+ ],
210
+ },
211
+ {
212
+ code: "19",
213
+ name: "Item Status Update",
214
+ symbol: :item_status_update,
215
+ ordered_fields: %i[
216
+ transaction_date
217
+ ],
218
+ required_delimited_fields: %i[
219
+ institution_id
220
+ item_identifier
221
+ item_properties
222
+ ],
223
+ optional_delimited_fields: %i[
224
+ terminal_password
225
+ ],
226
+ },
227
+ {
228
+ code: "20",
229
+ name: "Item Status Update Response",
230
+ symbol: :item_status_update_response,
231
+ ordered_fields: %i[
232
+ item_properties_ok
233
+ transaction_date
234
+ ],
235
+ required_delimited_fields: %i[
236
+ item_identifier
237
+ ],
238
+ optional_delimited_fields: %i[
239
+ title_identifier
240
+ item_properties
241
+ screen_message
242
+ print_line
243
+ ],
244
+ },
245
+ {
246
+ code: "23",
247
+ name: "Patron Status Request",
248
+ symbol: :patron_status_request,
249
+ ordered_fields: %i[
250
+ language
251
+ transaction_date
252
+ ],
253
+ required_delimited_fields: %i[
254
+ institution_id
255
+ patron_identifier
256
+ terminal_password
257
+ patron_password
258
+ ],
259
+ optional_delimited_fields: [],
260
+ },
261
+ {
262
+ code: "24",
263
+ name: "Patron Status Response",
264
+ symbol: :patron_status_response,
265
+ ordered_fields: %i[
266
+ patron_status
267
+ language
268
+ transaction_date
269
+ ],
270
+ required_delimited_fields: %i[
271
+ institution_id
272
+ patron_identifier
273
+ personal_name
274
+ ],
275
+ optional_delimited_fields: %i[
276
+ valid_patron
277
+ valid_patron_password
278
+ currency_type
279
+ fee_amount
280
+ screen_message
281
+ print_line
282
+ ],
283
+ },
284
+ {
285
+ code: "25",
286
+ name: "Patron Enable",
287
+ symbol: :patron_enable,
288
+ ordered_fields: %i[
289
+ transaction_date
290
+ ],
291
+ required_delimited_fields: %i[
292
+ institution_id
293
+ patron_identifier
294
+ ],
295
+ optional_delimited_fields: %i[
296
+ terminal_password
297
+ patron_password
298
+ ],
299
+ },
300
+ {
301
+ code: "26",
302
+ name: "Patron Enable Response",
303
+ symbol: :patron_enable_response,
304
+ ordered_fields: %i[
305
+ patron_status
306
+ language
307
+ transaction_date
308
+ ],
309
+ required_delimited_fields: %i[
310
+ institution_id
311
+ patron_identifier
312
+ personal_name
313
+ ],
314
+ optional_delimited_fields: %i[
315
+ valid_patron
316
+ valid_patron_password
317
+ screen_message
318
+ print_line
319
+ ],
320
+ },
321
+ {
322
+ code: "29",
323
+ name: "Renew",
324
+ symbol: :renew,
325
+ ordered_fields: %i[
326
+ third_party_allowed
327
+ no_block
328
+ transaction_date
329
+ nb_due_date
330
+ ],
331
+ required_delimited_fields: %i[
332
+ institution_id
333
+ patron_identifier
334
+ ],
335
+ optional_delimited_fields: %i[
336
+ patron_password
337
+ item_identifier
338
+ title_identifier
339
+ terminal_password
340
+ item_properties
341
+ fee_acknowledged
342
+ ],
343
+ },
344
+ {
345
+ code: "30",
346
+ name: "Renew Response",
347
+ symbol: :renew_response,
348
+ ordered_fields: %i[
349
+ ok
350
+ renewal_ok
351
+ magnetic_media
352
+ desensitize
353
+ transaction_date
354
+ ],
355
+ required_delimited_fields: %i[
356
+ institution_id
357
+ patron_identifier
358
+ item_identifier
359
+ title_identifier
360
+ due_date
361
+ ],
362
+ optional_delimited_fields: %i[
363
+ fee_type
364
+ security_inhibit
365
+ currency_type
366
+ fee_amount
367
+ media_type
368
+ item_properties
369
+ transaction_id
370
+ screen_message
371
+ print_line
372
+ ],
373
+ },
374
+ {
375
+ code: "35",
376
+ name: "End Patron Session",
377
+ symbol: :end_patron_session,
378
+ ordered_fields: %i[
379
+ transaction_date
380
+ ],
381
+ required_delimited_fields: %i[
382
+ institution_id
383
+ patron_identifier
384
+ ],
385
+ optional_delimited_fields: %i[
386
+ terminal_password
387
+ patron_password
388
+ ],
389
+ },
390
+ {
391
+ code: "36",
392
+ name: "End Session Response",
393
+ symbol: :end_session_response,
394
+ ordered_fields: %i[
395
+ end_session
396
+ transaction_date
397
+ ],
398
+ required_delimited_fields: %i[
399
+ institution_id
400
+ patron_identifier
401
+ ],
402
+ optional_delimited_fields: %i[
403
+ screen_message
404
+ print_line
405
+ ],
406
+ },
407
+ {
408
+ code: "37",
409
+ name: "Fee Paid",
410
+ symbol: :fee_paid,
411
+ ordered_fields: %i[
412
+ transaction_date
413
+ fee_type_ordered
414
+ payment_type
415
+ currency_type_ordered
416
+ ],
417
+ required_delimited_fields: %i[
418
+ fee_amount
419
+ institution_id
420
+ patron_identifier
421
+ ],
422
+ optional_delimited_fields: %i[
423
+ terminal_password
424
+ patron_password
425
+ fee_identifier
426
+ transaction_id
427
+ ],
428
+ },
429
+ {
430
+ code: "38",
431
+ name: "Fee Paid Response",
432
+ symbol: :fee_paid_response,
433
+ ordered_fields: %i[
434
+ payment_accepted
435
+ transaction_date
436
+ ],
437
+ required_delimited_fields: %i[
438
+ institution_id
439
+ patron_identifier
440
+ ],
441
+ optional_delimited_fields: %i[
442
+ transaction_id
443
+ screen_message
444
+ print_line
445
+ ],
446
+ },
447
+ {
448
+ code: "63",
449
+ name: "Patron Information",
450
+ symbol: :patron_information,
451
+ ordered_fields: %i[
452
+ language
453
+ transaction_date
454
+ summary
455
+ ],
456
+ required_delimited_fields: %i[
457
+ institution_id
458
+ patron_identifier
459
+ ],
460
+ optional_delimited_fields: %i[
461
+ terminal_password
462
+ patron_password
463
+ start_item
464
+ end_item
465
+ ]
466
+ },
467
+ {
468
+ code: "64",
469
+ name: "Patron Information Response",
470
+ symbol: :patron_information_response,
471
+ ordered_fields: %i[
472
+ patron_status
473
+ language
474
+ transaction_date
475
+ hold_items_count
476
+ overdue_items_count
477
+ charged_items_count
478
+ fine_items_count
479
+ recall_items_count
480
+ unavailable_holds_count
481
+ ],
482
+ required_delimited_fields: %i[
483
+ institution_id
484
+ patron_identifier
485
+ personal_name
486
+ ],
487
+ optional_delimited_fields: %i[
488
+ hold_items_limit
489
+ overdue_items_limit
490
+ charged_items_limit
491
+ valid_patron
492
+ valid_patron_password
493
+ currency_type
494
+ fee_amount
495
+ fee_limit
496
+ items
497
+ home_address
498
+ email_address
499
+ home_phone_number
500
+ screen_message
501
+ print_line
502
+ ]
503
+ },
504
+ {
505
+ code: "65",
506
+ name: "Renew All",
507
+ symbol: :renew_all,
508
+ ordered_fields: %i[
509
+ transaction_date
510
+ ],
511
+ required_delimited_fields: %i[
512
+ institution_id
513
+ patron_identifier
514
+ ],
515
+ optional_delimited_fields: %i[
516
+ patron_password
517
+ terminal_password
518
+ fee_acknowledged
519
+ ],
520
+ },
521
+ {
522
+ code: "66",
523
+ name: "Renew All Response",
524
+ symbol: :renew_all_response,
525
+ ordered_fields: %i[
526
+ ok
527
+ renewed_count
528
+ unrenewed_count
529
+ transaction_date
530
+ ],
531
+ required_delimited_fields: %i[
532
+ institution_id
533
+ ],
534
+ optional_delimited_fields: %i[
535
+ renewed_items
536
+ unrenewed_items
537
+ screen_message
538
+ print_line
539
+ ],
540
+ },
541
+ {
542
+ code: "93",
543
+ name: "Login",
544
+ symbol: :login,
545
+ ordered_fields: %i[
546
+ uid_algorithm
547
+ pwd_algorithm
548
+ ],
549
+ required_delimited_fields: %i[
550
+ login_user_id
551
+ login_password
552
+ ],
553
+ optional_delimited_fields: %i[
554
+ location_code
555
+ ],
556
+ },
557
+ {
558
+ code: "94",
559
+ name: "Login Response",
560
+ symbol: :login_response,
561
+ ordered_fields: %i[
562
+ ok
563
+ ],
564
+ required_delimited_fields: [],
565
+ optional_delimited_fields: [],
566
+ },
567
+ {
568
+ code: "96",
569
+ name: "Request SC Resend",
570
+ symbol: :request_sc_resend,
571
+ ordered_fields: [],
572
+ required_delimited_fields: [],
573
+ optional_delimited_fields: [],
574
+ },
575
+ {
576
+ code: "97",
577
+ name: "Request ACS Resend",
578
+ symbol: :request_acs_resend,
579
+ ordered_fields: [],
580
+ required_delimited_fields: [],
581
+ optional_delimited_fields: [],
582
+ },
583
+ {
584
+ code: "98",
585
+ name: "ACS Status",
586
+ symbol: :acs_status,
587
+ ordered_fields: %i[
588
+ online_status
589
+ checkin_ok
590
+ checkout_ok
591
+ acs_renewal_policy
592
+ status_update_ok
593
+ offline_ok
594
+ timeout_period
595
+ retries_allowed
596
+ date_time_sync
597
+ protocol_version
598
+ ],
599
+ required_delimited_fields: %i[
600
+ institution_id
601
+ supported_messages
602
+ ],
603
+ optional_delimited_fields: %i[
604
+ library_name
605
+ terminal_location
606
+ screen_message
607
+ print_line
608
+ ],
609
+ },
610
+ {
611
+ code: "99",
612
+ name: "SC Status",
613
+ symbol: :sc_status,
614
+ ordered_fields: %i[
615
+ status_code
616
+ max_print_width
617
+ protocol_version
618
+ ],
619
+ required_delimited_fields: [],
620
+ optional_delimited_fields: [],
621
+ },
622
+ ]
623
+
624
+ MESSAGES_BY_CODE = MESSAGES
625
+ .group_by { |m| m[:code] }
626
+ .map { |k,v| [k,v.first] }
627
+ .to_h
628
+ end
@@ -0,0 +1,14 @@
1
+ require 'parslet'
2
+ require 'parslet/convenience'
3
+
4
+ require 'sip2/message_parser_rules'
5
+ require 'sip2/field_parser_rules'
6
+
7
+ module Sip2
8
+ class Parser < Parslet::Parser
9
+ include Sip2::MessageParserRules
10
+
11
+ root(:messages)
12
+
13
+ end
14
+ end
@@ -0,0 +1,53 @@
1
+ require 'parslet'
2
+
3
+ module Sip2
4
+ module ParserAtoms
5
+ include Parslet
6
+
7
+ rule(:digit) { match["0-9"] }
8
+ rule(:natural) { match["1-9"] }
9
+ rule(:zero) { str("0") }
10
+
11
+ rule(:eom) { str("\r") }
12
+ rule(:nullc) { str("\0") }
13
+ rule(:pipe) { str("|") }
14
+ rule(:any_valid) { eom.absent? >> nullc.absent? >> pipe.absent? >> any }
15
+
16
+ rule(:hex_digit) { match["0-9A-F"] }
17
+
18
+ rule(:space) { str(" ") }
19
+ rule(:upper) { match["A-Z"] }
20
+
21
+ rule(:year) { digit.repeat(4,4) }
22
+ rule(:month) { (zero >> natural) | (str("1") >> match["012"] ) }
23
+ rule(:day) { (zero >> natural) | (match["12"] >> digit) | (str("3") >> match["01"]) }
24
+ rule(:zzzz) { (space | upper).repeat(4,4) }
25
+ rule(:hour) { (match["01"] >> digit) | str("2") >> match["0-3"] }
26
+ rule(:minute) { match["0-5"] >> digit }
27
+ rule(:second) { minute }
28
+
29
+ rule(:bool) { match["YN"].as(:bool) }
30
+ rule(:bool_with_space) { match["Y "].as(:bool) }
31
+ rule(:nillable_bool) { match["YNU"].as(:bool) }
32
+ rule(:numerical_bool) { match["01"].as(:bool) }
33
+
34
+ rule(:timestamp) {
35
+ year.as(:int).as(:year) >> month.as(:int).as(:month) >> day.as(:int).as(:day) >>
36
+ zzzz.as(:tz).as(:zone) >>
37
+ hour.as(:int).as(:hour) >> minute.as(:int).as(:minute) >> second.as(:int).as(:second)
38
+ }
39
+
40
+ rule(:any_field_identifier) {
41
+ match["0-9A-Za-z"].repeat(2,2).as(:str)
42
+ }
43
+
44
+ rule(:four_digits_or_blanks) {
45
+ digit.repeat(4,4).as(:int) | space.repeat(4,4).as(:nil)
46
+ }
47
+
48
+ rule(:variable_length_value) {
49
+ (pipe.absent? >> any).repeat(0,255).as(:str) >> pipe
50
+ }
51
+
52
+ end
53
+ end