voyager_api 0.1.2 → 0.2.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.
data/Gemfile CHANGED
@@ -1,7 +1,8 @@
1
1
  source "http://rubygems.org"
2
2
  # Add dependencies required to use your gem here.
3
3
  # Example:
4
- # gem "activesupport", ">= 2.3.5"
4
+ gem "activesupport"
5
+ gem 'i18n'
5
6
 
6
7
  gem "httpclient"
7
8
  gem "nokogiri"
data/Gemfile.lock CHANGED
@@ -1,6 +1,8 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
+ activesupport (3.1.0)
5
+ multi_json (~> 1.0)
4
6
  git (1.2.5)
5
7
  growl (1.0.3)
6
8
  guard (0.6.3)
@@ -8,6 +10,7 @@ GEM
8
10
  guard-minitest (0.4.0)
9
11
  guard (~> 0.4)
10
12
  httpclient (2.2.1)
13
+ i18n (0.6.0)
11
14
  jeweler (1.6.4)
12
15
  bundler (~> 1.0)
13
16
  git (>= 1.2.5)
@@ -16,6 +19,7 @@ GEM
16
19
  minitest (2.5.1)
17
20
  mocha (0.10.0)
18
21
  metaclass (~> 0.0.1)
22
+ multi_json (1.0.3)
19
23
  nokogiri (1.5.0)
20
24
  rake (0.9.2)
21
25
  rb-fsevent (0.4.3.1)
@@ -26,10 +30,12 @@ PLATFORMS
26
30
  ruby
27
31
 
28
32
  DEPENDENCIES
33
+ activesupport
29
34
  bundler (~> 1.0.0)
30
35
  growl
31
36
  guard-minitest
32
37
  httpclient
38
+ i18n
33
39
  jeweler (~> 1.6.4)
34
40
  minitest
35
41
  mocha
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.2.0
@@ -0,0 +1,172 @@
1
+ 1n:
2
+ short_message: Available
3
+ long_message: Not checked out
4
+ 1r:
5
+ short_message: 'Available (Requests: %REQS)'
6
+ long_message: 'Not checked out (Requests: %REQS)'
7
+ 2n:
8
+ short_message: 'Checked out, due %DATE'
9
+ long_message: 'Checked out, due %DATE - Recall, or try Borrow Direct or ILL.'
10
+ services:
11
+ - recall_hold
12
+ - borrow_direct
13
+ - ill
14
+ 2r:
15
+ short_message: 'Checked out, due %DATE (Requests: %REQS)'
16
+ long_message: 'Checked out, due %DATE (Requests: %REQS). Try Borrow Direct or ILL.'
17
+ services:
18
+ - borrow_direct
19
+ - ill
20
+ 3n:
21
+ short_message: 'Checked out, due %DATE'
22
+ long_message: 'Checked out, due %DATE - Recall, or try Borrow Direct or ILL.'
23
+ services:
24
+ - recall_hold
25
+ - borrow_direct
26
+ - ill
27
+ 3r:
28
+ short_message: 'Checked out, due %DATE (Requests: %REQS)'
29
+ long_message: 'Checked out, due %DATE (Requests: %REQS). Try Borrow Direct or ILL.'
30
+ services:
31
+ - borrow_direct
32
+ - ill
33
+ 4n:
34
+ short_message: 'Overdue as of %DATE'
35
+ long_message: 'Overdue as of %DATE - Recall, or try Borrow Direct.'
36
+ services:
37
+ - recall_hold
38
+ - borrow_direct
39
+ 4r:
40
+ short_message: 'Overdue as of %DATE (Requests: %REQS)'
41
+ long_message: 'Overdue as of %DATE (Requests: %REQS). Try Borrow Direct or ILL.'
42
+ services:
43
+ - borrow_direct
44
+ - ill
45
+ 5n:
46
+ short_message: 'Requests: %REQS'
47
+ long_message: 'Requests: %REQS'
48
+ 5r:
49
+ short_message: 'Checked out, due %DATE (Requests: %REQS)'
50
+ long_message: 'Checked out, due %DATE (Requests: %REQS). Try Borrow Direct or ILL.'
51
+ services:
52
+ - borrow_direct
53
+ - ill
54
+ 6n:
55
+ short_message: 'Requests: %REQS'
56
+ long_message: 'Requests: %REQS'
57
+ 6r:
58
+ short_message: 'Checked out, due %DATE (Requests: %REQS)'
59
+ long_message: 'Checked out, due %DATE (Requests: %REQS). Try Borrow Direct or ILL.'
60
+ services:
61
+ - borrow_direct
62
+ - ill
63
+ 7n:
64
+ short_message: 'On hold at %LOC'
65
+ long_message: 'On hold at %LOC. Try Borrow Direct or ILL.'
66
+ services:
67
+ - borrow_direct
68
+ - ill
69
+ 7r:
70
+ short_message: 'On hold at %LOC (Requests: %REQS)'
71
+ long_message: 'On hold at %LOC (Requests: %REQS). Try Borrow Direct or ILL.'
72
+ services:
73
+ - borrow_direct
74
+ - ill
75
+ 8n:
76
+ short_message: 'In transit %DATE'
77
+ long_message: 'In transit %DATE. Place a hold request.'
78
+ services:
79
+ - recall_hold
80
+ 8r:
81
+ short_message: 'In transit %DATE (Requests: %REQS)'
82
+ long_message: 'In transit %DATE (Requests: %REQS). Try Borrow Direct or ILL.'
83
+ services:
84
+ - borrow_direct
85
+ - ill
86
+ 9n:
87
+ short_message: 'In transit to %LOC %DATE'
88
+ long_message: 'In transit to %LOC %DATE. Place a hold request.'
89
+ services:
90
+ - recall_hold
91
+ 9r:
92
+ short_message: 'In transit to %LOC %DATE (Requests: %REQS)'
93
+ long_message: 'In transit to %LOC %DATE (Requests: %REQS). Try Borrow Direct.'
94
+ services:
95
+ - borrow_direct
96
+ 10n:
97
+ short_message: 'In transit to %LOC %DATE. Place a hold request.'
98
+ long_message: 'In transit to %LOC %DATE. Place a hold request.'
99
+ services:
100
+ - recall_hold
101
+ 10r:
102
+ short_message: 'In transit to %LOC %DATE (Requests: %REQS)'
103
+ long_message: 'In transit to %LOC %DATE (Requests: %REQS). Try Borrow Direct.'
104
+ services:
105
+ - borrow_direct
106
+ 11n:
107
+ short_message: 'Returned %DATE'
108
+ long_message: 'Returned %DATE'
109
+ 11r:
110
+ short_message: 'Returned %DATE (Requests: %REQS)'
111
+ long_message: 'Returned %DATE (Requests: %REQS). Try Borrow Direct or ILL.'
112
+ services:
113
+ - borrow_direct
114
+ - ill
115
+ 12n:
116
+ short_message: 'Missing %DATE'
117
+ long_message: 'Missing %DATE. Try Borrow Direct or ILL.'
118
+ services:
119
+ - borrow_direct
120
+ - ill
121
+ 12r:
122
+ short_message: 'Missing %DATE (Requests: %REQS)'
123
+ long_message: 'Missing %DATE (Requests: %REQS). Try Borrow Direct or ILL.'
124
+ services:
125
+ - borrow_direct
126
+ - ill
127
+ 13n:
128
+ short_message: 'Unavailable %DATE'
129
+ long_message: 'Unavailable %DATE. Try Borrow Direct or ILL.'
130
+ services:
131
+ - borrow_direct
132
+ - ill
133
+ 13r:
134
+ short_message: 'Unavailable %DATE (Requests: %REQS)'
135
+ long_message: 'Unavailable %DATE (Requests: %REQS). Try Borrow Direct or ILL.'
136
+ services:
137
+ - borrow_direct
138
+ - ill
139
+ 14n:
140
+ short_message: 'Unavailable %DATE'
141
+ long_message: 'Unavailable %DATE. Try Borrow Direct or ILL.'
142
+ services:
143
+ - borrow_direct
144
+ - ill
145
+ 14r:
146
+ short_message: 'Unavailable %DATE (Requests: %REQS)'
147
+ long_message: 'Unavailable %DATE (Requests: %REQS). Try Borrow Direct or ILL.'
148
+ services:
149
+ - borrow_direct
150
+ - ill
151
+ 18n:
152
+ short_message: 'Sent to bindery for 1 month on %DATE'
153
+ long_message: 'Sent to bindery for 1 month on %DATE. Try Borrow Direct or ILL. '
154
+ services:
155
+ - borrow_direct
156
+ - ill
157
+ 18r:
158
+ short_message: 'Sent to bindery for 1 month on %DATE (Requests: %REQS)'
159
+ long_message: 'Sent to bindery for 1 month on %DATE (Requests: %REQS). Try Borrow Direct or ILL.'
160
+ services:
161
+ - borrow_direct
162
+ - ill
163
+ 22n:
164
+ short_message: 'In Process %DATE'
165
+ long_message: 'In Process %DATE. Place an In Process item request.'
166
+ services:
167
+ - in_process
168
+ 22r:
169
+ short_message: 'In Process %DATE (Requests: %REQS)'
170
+ long_message: 'In Process %DATE (Requests: %REQS). Place an In Process item request.'
171
+ services:
172
+ - in_process
@@ -0,0 +1,25 @@
1
+ '0':
2
+ short_message: 'In the Pre-Order Process'
3
+ long_message: 'In the Pre-Order Process. Try Borrow Direct or ILL.'
4
+ services:
5
+ - borrow_direct
6
+ - ill
7
+ '1':
8
+ short_message: 'Received %DATE'
9
+ long_message: 'Received %DATE. Place an In Process item request.'
10
+ services:
11
+ - in_process
12
+ '4':
13
+ short_message: 'Not yet received; claimed %DATE'
14
+ long_message: 'Not yet received; claimed %DATE. Try Borrow Direct or ILL.'
15
+ services:
16
+ - on_order
17
+ - borrow_direct
18
+ - ill
19
+ '8':
20
+ short_message: 'Copy On Order %DATE'
21
+ long_message: 'Copy On Order %DATE. Try Borrow Direct or ILL.'
22
+ services:
23
+ - on_order
24
+ - borrow_direct
25
+ - ill
@@ -18,12 +18,41 @@ module Voyager
18
18
  end
19
19
 
20
20
  # Generate output hash from Record class instances
21
- def to_hash
21
+ def to_hash(options = {})
22
+ options.reverse_merge!(:output_type => :raw, :content_type => :full, :message_type => :long_message)
23
+
24
+ # :output_type --> :raw (default) | :condensed
25
+ #
26
+ # if :output_type == :condensed
27
+ # :content_type --> :brief | :full (default)
28
+ # :brief --> basic elements: currently location_name, call_number, overall location status, services
29
+ # :full --> all elements
30
+ # if :content_type == :full
31
+ # :message_type --> :short_message | :long_message (default)
32
+ #
33
+
34
+ raise ":output_type not defined" unless options[:output_type] == :raw || options[:output_type] == :condensed
35
+ raise ":content_type not defined" unless options[:content_type] == :full || options[:content_type] == :brief
36
+ raise ":message_type not defined" unless options[:message_type] == :long_message || options[:message_type] == :short_message
37
+
22
38
  output = {}
23
- output[:records] = @records.collect do |rec|
24
- rec.to_hash
39
+
40
+ case options[:output_type]
41
+ when :raw
42
+ output[:records] = @records.collect { |rec| rec.to_hash }
43
+ when :condensed
44
+ # convert @records into a holdings hash
45
+ holdings = @records.collect { |rec| rec.to_hash }
46
+ case options[:content_type]
47
+ when :full
48
+ output[:condensed_holdings_full] = condense_holdings(holdings,options)
49
+ when :brief
50
+ output[:condensed_holdings_brief] = condense_holdings(holdings,options)
51
+ end
25
52
  end
53
+
26
54
  output
55
+
27
56
  end
28
57
 
29
58
  private
@@ -44,6 +73,203 @@ module Voyager
44
73
  Record.new(record_node)
45
74
  end
46
75
  end
76
+
77
+ def condense_holdings(holdings,options)
78
+
79
+ # processing varies depending on complexity
80
+ complexity = determine_complexity(holdings)
81
+ process_holdings(holdings,complexity,options)
82
+
83
+ end
84
+
85
+ def determine_complexity(holdings)
86
+
87
+ # holdings are complex if anything other than item_status has a value
88
+
89
+ complexity = :complex
90
+
91
+ holdings.each do |holding|
92
+ if [:summary_holdings, :supplements, :indexes, :notes,
93
+ :reproduction_note, :current_issues, :temp_locations,
94
+ :orders].all? { |key| holding[key].empty?}
95
+ complexity = :simple
96
+ end
97
+ end
98
+
99
+ complexity
100
+
101
+ end
102
+
103
+ def process_holdings(holdings,complexity,options)
104
+
105
+ entries = []
106
+ holdings.each do |holding|
107
+ # test for location and call number
108
+ entry = entries.find { |entry| entry[:location_name] == holding[:location_name] &&
109
+ entry[:call_number] == holding[:call_number] }
110
+
111
+ unless entry
112
+ entry = {
113
+ :location_name => holding[:location_name],
114
+ :call_number => holding[:call_number],
115
+ :status => '',
116
+ :copies => [],
117
+ :services => []
118
+ }
119
+ entry[:copies] << {:items => {}} if complexity == :simple
120
+ entries << entry
121
+ end
122
+
123
+ # for simple holdings put consolidated status information in the first copy
124
+ if complexity == :simple
125
+ item_status = holding[:item_status]
126
+ messages = item_status[:messages]
127
+ messages.each do |message|
128
+ text = message[options[:message_type]]
129
+ if entry[:copies].first[:items].has_key?(text)
130
+ entry[:copies].first[:items][text][:count] += 1
131
+ else
132
+ entry[:copies].first[:items][text] = {
133
+ :status => item_status[:status],
134
+ :count => 1
135
+ }
136
+ end
137
+ end
138
+ # for complex holdings create hash of elements for each copy and add to entry :copies array
139
+ else
140
+ out = {}
141
+ # process status messages
142
+ item_status = holding[:item_status]
143
+ messages = item_status[:messages]
144
+ out[:items] = {}
145
+ messages.each do |message|
146
+ text = message[options[:message_type]]
147
+ if out[:items].has_key?(text)
148
+ out[:items][text][:count] += 1
149
+ else
150
+ out[:items][text] = {
151
+ :status => item_status[:status],
152
+ :count => 1
153
+ }
154
+ end
155
+ end
156
+ # add other elements to :copies array
157
+ [:current_issues, :indexes, :notes, :orders, :reproduction_note, :supplements,
158
+ :summary_holdings, :temp_locations].each { |type| add_holdings_elements(out,holding,type,options[:message_type]) }
159
+
160
+ entry[:copies] << out
161
+
162
+ end
163
+
164
+ entry[:services] << holding[:services]
165
+
166
+ end
167
+
168
+ # get overall status of each location entry
169
+ entries.each { |entry| determine_overall_status(entry) }
170
+
171
+ # condense services list
172
+ entries.each { |entry| entry[:services] = entry[:services].flatten.uniq }
173
+
174
+ output_condensed_holdings(entries,options[:content_type])
175
+
176
+ end
177
+
178
+ def add_holdings_elements(out,holding,type,message_type)
179
+
180
+ case type
181
+ when :current_issues
182
+ out[type] = "Current Issues: " + holding[type].join('; ') unless holding[type].empty?
183
+ when :indexes
184
+ out[type] = "Indexes: " + holding[type].join(' ') unless holding[type].empty?
185
+ when :notes
186
+ out[type] = "Notes: " + holding[type].join(' ') unless holding[type].empty?
187
+ when :orders
188
+ unless holding[type].empty?
189
+ messages = holding[type].each.collect { |message| message[message_type] }
190
+ out[type] = "Order Information: " + messages.join('; ')
191
+ end
192
+ when :reproduction_note
193
+ out[type] = holding[type] unless holding[type].empty?
194
+ when :supplements
195
+ out[type] = "Supplements: " + holding[type].join(' ') unless holding[type].empty?
196
+ when :summary_holdings
197
+ out[type] = "Library has: " + holding[type].join(' ') unless holding[type].empty?
198
+ when :temp_locations
199
+ out[type] = holding[type] unless holding[type].empty?
200
+ else
201
+ end
202
+
203
+ end
204
+
205
+ def determine_overall_status(entry)
206
+
207
+ a = 0 # available
208
+ s = 0 # some available
209
+ n = 0 # not available
210
+
211
+ status = ''
212
+
213
+ entry[:copies].each do |copy|
214
+ copy[:items].each_pair do |message,details|
215
+ a = 1 if details[:status] == 'available'
216
+ s = 2 if details[:status] == 'some_available'
217
+ n = 4 if details[:status] == 'not_available'
218
+ end
219
+ end
220
+
221
+ # | some | not
222
+ # available (1) | available (2) | available (4) total (a+s+n)
223
+ # -----------------------------------------------------------------
224
+ # Y Y Y 7
225
+ # Y Y N 3
226
+ # Y N Y 5
227
+ # Y N N 1
228
+ # N Y Y 6
229
+ # N Y N 2
230
+ # N N Y 4
231
+ # N N N 0
232
+ #
233
+ # :available is returned if all items are available (1).
234
+ # :not_available is returned if everything is unavailable (4).
235
+ # :none is returned if there is no status (0).
236
+ # otherwise :some_available is returned:
237
+ # All status are checked; as long as something is available, even if
238
+ # there are some items check out, :some_available is returned.
239
+ #
240
+
241
+ case a + s + n
242
+ when 0
243
+ status = 'none'
244
+ status = 'online' if entry[:location_name].match(/^Online/)
245
+ when 1
246
+ status = 'available'
247
+ when 4
248
+ status = 'not_available'
249
+ else
250
+ status = 'some_available'
251
+ end
252
+
253
+ entry[:status] = status
254
+
255
+ end
256
+
257
+ def output_condensed_holdings(entries,type)
258
+
259
+ case type
260
+ when :full
261
+ entries
262
+ when :brief
263
+ entries.collect do |entry|
264
+ {:location_name => entry[:location_name],
265
+ :call_number => entry[:call_number],
266
+ :status => entry[:status],
267
+ :services => entry[:services]}
268
+ end
269
+ end
270
+
271
+ end
272
+
47
273
  end
48
274
  end
49
275
  end