voyager 0.0.1

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.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in voyager.gemspec
4
+ gemspec
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,17 @@
1
+ # ActiveRecord
2
+ require 'active_record'
3
+ require 'voyager/activerecord/base'
4
+ require 'voyager/activerecord/bib/text'
5
+ require 'voyager/activerecord/bib/item'
6
+ require 'voyager/activerecord/circ/transaction'
7
+ require 'voyager/activerecord/item'
8
+ require 'voyager/activerecord/item/barcode'
9
+
10
+ # SIP Client
11
+ require 'socket'
12
+ require 'voyager/sip/basic_client'
13
+ require 'voyager/sip/client'
14
+
15
+ module Voyager
16
+ # Your code goes here...
17
+ end
@@ -0,0 +1,6 @@
1
+ module Voyager
2
+ module AR
3
+ class Base < ActiveRecord::Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,12 @@
1
+ module Voyager
2
+ module AR
3
+ module Bib
4
+ class Item < Voyager::AR::Base
5
+ set_table_name 'bib_item'
6
+ set_primary_key 'bib_id'
7
+
8
+ has_one :bib_text, :foreign_key => :bib_id, :class_name => 'Voyager::AR::Bib::Text'
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ module Voyager
2
+ module AR
3
+ module Bib
4
+ class Text < Voyager::AR::Base
5
+ set_table_name 'bib_text'
6
+ set_primary_key 'bib_id'
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ module Voyager
2
+ module AR
3
+ module Circ
4
+ class Transaction < Voyager::AR::Base
5
+ # ActiveRecord Configuration
6
+ set_table_name 'circ_transactions'
7
+ set_primary_key 'circ_transactions_id'
8
+
9
+ # AR Associations
10
+ belongs_to :item, :class_name => 'Voyager::AR::Item'
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ module Voyager
2
+ module AR
3
+ class Item < Voyager::AR::Base
4
+ # ActiveRecord Configuration
5
+ set_table_name 'item'
6
+ set_primary_key 'item_id'
7
+
8
+ # Associations
9
+ has_one :barcode, :foreign_key => 'item_id', :class_name => 'Voyager::AR::Item::Barcode'
10
+ has_one :circ_transaction, :class_name => 'Voyager::AR::Circ::Transaction'
11
+
12
+ has_one :bib_text, :through => :bib_item, :class_name => 'Voyager::AR::Bib::Text'
13
+ has_one :bib_item, :foreign_key => 'item_id', :class_name => 'Voyager::AR::Bib::Item'
14
+
15
+ # Class Methods
16
+ def charged?
17
+ circ_transaction.nil? ? false : true
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,12 @@
1
+ module Voyager
2
+ module AR
3
+ class Item
4
+ class Barcode < Voyager::AR::Base
5
+ set_table_name 'item_barcode'
6
+ set_primary_key 'item_id'
7
+
8
+ belongs_to :item, :class_name => 'Voyager::AR::Item'
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,60 @@
1
+ require 'socket'
2
+
3
+ # Rudimentary SIP Client
4
+
5
+ module Voyager
6
+ module SIP
7
+ module BasicSipClient
8
+ VERBOSE = true
9
+ TIMESTAMP_FORMAT = "%Y%m%d %H%M%S"
10
+ @socket
11
+
12
+ def initialize(host, port)
13
+ Rails::logger.info "SIPClient: Connecting with #{host}:#{port}" if VERBOSE
14
+ @socket = TCPSocket::new(host, port)
15
+
16
+ if block_given?
17
+ begin
18
+ yield self
19
+ ensure
20
+ # When given a socket, we automatically close connection
21
+ close
22
+ end
23
+ end
24
+ end
25
+
26
+ def send(msg)
27
+ Rails::logger.info "SIPClient: Sending #{msg}" if VERBOSE
28
+ @socket.write("#{msg.strip}\r")
29
+
30
+ # If a block is given, yield the response
31
+ if block_given?
32
+ yield recv
33
+ end
34
+ end
35
+
36
+ def recv
37
+ msg = ""
38
+ until msg =~ /\r/
39
+ result = IO::select([@socket], nil, nil)
40
+
41
+ for inp in result[0]
42
+ msg << @socket.recv(300);
43
+ end
44
+ end
45
+
46
+ Rails::logger.info "SIPClient: Recieved #{msg.strip}" if VERBOSE
47
+ msg
48
+ end
49
+
50
+ def close
51
+ Rails::logger.info "SIPClient: Connection closed." if VERBOSE
52
+ @socket.close
53
+ end
54
+
55
+ def timestamp
56
+ Time.now.strftime(TIMESTAMP_FORMAT)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,134 @@
1
+ module Voyager
2
+ module SIP
3
+ class Client
4
+ include BasicSipClient
5
+ #--
6
+ # Sends a Login Message
7
+ #
8
+ # Example login request:
9
+ # 9300CNusername|COpassword|CPCIRC|
10
+ # Example login response:
11
+ # 941
12
+ #++
13
+ def login(username, password, location)
14
+ msg = "9300CN#{username}|CO#{password}|CP#{location}|\r"
15
+
16
+ send(msg) do |response|
17
+ response = parse_login(response)
18
+
19
+ raise "Invalid login: #{response[:raw]}" unless response[:ok] == '1'
20
+
21
+ if block_given?
22
+ yield response
23
+ end
24
+
25
+ response
26
+ end
27
+ end
28
+
29
+ def parse_login(msg)
30
+ match = msg.match(/^94(0|1)\r$/)
31
+ if match
32
+ {:raw => msg,
33
+ :id => 94,
34
+ :ok => match[1]}
35
+ end
36
+ end
37
+
38
+ #--
39
+ # Sends a Create Bib Message
40
+ #
41
+ # Example create bib request:
42
+ # 8120100813 133505AO|MFSelfchk|AJThe transformation of learning : / *77087*|AB77087|AC|^M
43
+ # Example create bib response:
44
+ # 821MJ633124|MA630995|AFCreate Bib successful.|^M
45
+ #++
46
+ def create_bib(operator, title, barcode)
47
+ msg = "81#{self.timestamp}|AO|MF#{operator}|AJ#{title}|AB#{barcode}|AC|"
48
+
49
+ send(msg) do |response|
50
+ response = parse_create_bib(response)
51
+
52
+ # Bib/MFHD/Item create failed
53
+ raise "Bib/MFHD/Item create failed: #{response['raw']}" if response[:ok] == '0'
54
+
55
+ # Bib was created, but not the item
56
+ #
57
+ # This is possible if we have a duplicate barcode, however we
58
+ # check for that. Possible race condition, though unlikely.
59
+ #
60
+ # Store the bib_id for troubleshooting
61
+ raise "Duplicate barcode. A bib exists without an item and should be deleted: #{response['raw']}" if response[:item_id].empty?
62
+
63
+
64
+ if block_given?
65
+ yield response
66
+ end
67
+
68
+ response
69
+ end
70
+ end
71
+
72
+ def parse_create_bib(msg)
73
+ # 821MJ640267|MA818432|AFCreate Bib successful.|
74
+ # [2] - OK? 1:yes, 0:no
75
+ # MJ - Item number
76
+ # MA - Bib number
77
+ # AF - Print screen
78
+ match = msg.match(/^82(.)MJ(.*)\|MA(.*)\|AF(.*)\|\r$/)
79
+ if match
80
+ {:raw => msg,
81
+ :id => 82,
82
+ :ok => match[1],
83
+ :item_id => match[2],
84
+ :bib_id => match[3],
85
+ :print_msg => match[4]
86
+ }
87
+ end
88
+ end
89
+
90
+ def item_status(item_identifier)
91
+ msg = "17#{self.timestamp}|AO|AB#{item_identifier}|AC|"
92
+
93
+ send(msg) do |response|
94
+ response = parse_item_status(response)
95
+
96
+ if block_given?
97
+ yield response
98
+ end
99
+
100
+ response
101
+ end
102
+ end
103
+
104
+ def parse_item_status(msg)
105
+ # 1803000120110408 150732CF0|AH|CJ|AB96917|AJBokml - Test for Nostos *96917*|BGHealey_Library|AQCirculation Desk|AFItem Info retrieved successfully.|
106
+ match = msg.match(/^18([0-9]{2})([0-9]{2})([0-9]{2})(.{18})(.*)\r$/)
107
+ # 1 - Circulation Status
108
+ # 2 - Security Marker
109
+ # 3 - Fee Type
110
+ # 4 - Transaction Date
111
+ # 5 - Variable Fields
112
+ var_fields = msg.scan(/([A-Z]{2})([^|]*)\|/)
113
+ if match
114
+ r = {:raw => msg,
115
+ :id => 18,
116
+ :circ_status => match[1],
117
+ :security_marker => match[2],
118
+ :fee_type => match[3],
119
+ :transaction_date => match[4],
120
+ }
121
+ var_fields.each do |field|
122
+ r[field.first.to_sym] = field.last
123
+ end
124
+ r
125
+ end
126
+ end
127
+
128
+ # Utilities
129
+ def timestamp
130
+ Time.now.strftime("%Y%m%d %H%M%S")
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,3 @@
1
+ module Voyager
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "voyager/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "voyager"
7
+ s.version = Voyager::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Brice Stacey"]
10
+ s.email = ["bricestacey@gmail.com"]
11
+ s.homepage = "https://github.com/bricestacey/voyager"
12
+ s.summary = %q{ActiveRecord bindings for Voyager ILS}
13
+ s.description = %q{ActiveRecord bindings for Voyager ILS}
14
+
15
+ s.rubyforge_project = "voyager"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency('activerecord')
23
+ s.add_dependency('activerecord-oracle_enhanced-adapter')
24
+ s.add_dependency('ruby-oci8')
25
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: voyager
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Brice Stacey
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-04-15 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activerecord
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ type: :runtime
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: activerecord-oracle_enhanced-adapter
28
+ prerelease: false
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: "0"
35
+ type: :runtime
36
+ version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
38
+ name: ruby-oci8
39
+ prerelease: false
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ type: :runtime
47
+ version_requirements: *id003
48
+ description: ActiveRecord bindings for Voyager ILS
49
+ email:
50
+ - bricestacey@gmail.com
51
+ executables: []
52
+
53
+ extensions: []
54
+
55
+ extra_rdoc_files: []
56
+
57
+ files:
58
+ - .gitignore
59
+ - Gemfile
60
+ - Rakefile
61
+ - lib/voyager.rb
62
+ - lib/voyager/activerecord/base.rb
63
+ - lib/voyager/activerecord/bib/item.rb
64
+ - lib/voyager/activerecord/bib/text.rb
65
+ - lib/voyager/activerecord/circ/transaction.rb
66
+ - lib/voyager/activerecord/item.rb
67
+ - lib/voyager/activerecord/item/barcode.rb
68
+ - lib/voyager/sip/basic_client.rb
69
+ - lib/voyager/sip/client.rb
70
+ - lib/voyager/version.rb
71
+ - voyager.gemspec
72
+ homepage: https://github.com/bricestacey/voyager
73
+ licenses: []
74
+
75
+ post_install_message:
76
+ rdoc_options: []
77
+
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: "0"
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: "0"
92
+ requirements: []
93
+
94
+ rubyforge_project: voyager
95
+ rubygems_version: 1.7.2
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: ActiveRecord bindings for Voyager ILS
99
+ test_files: []
100
+