Class: Opac

Inherits:
Service show all
Defined in:
app/service_adaptors/opac.rb

Overview

FIXME This service is not working For starters it needs the method service_types_generated()

Constant Summary

Constants inherited from Service

Service::LinkOutFilterTask, Service::StandardTask

Instance Attribute Summary collapse

Attributes inherited from Service

#group, #name, #priority, #request, #service_id, #status, #task, #url

Instance Method Summary collapse

Methods inherited from Service

#credits, #handle_wrapper, #initialize, #link_out_filter, #preempted_by, required_config_params, #service_types_generated, #translate

Constructor Details

This class inherits a constructor from Service

Instance Attribute Details

#display_nameObject (readonly)

Returns the value of attribute display_name


5
6
7
# File 'app/service_adaptors/opac.rb', line 5

def display_name
  @display_name
end

#record_attributesObject (readonly)

Returns the value of attribute record_attributes


5
6
7
# File 'app/service_adaptors/opac.rb', line 5

def record_attributes
  @record_attributes
end

Instance Method Details

#check_holdings(holdings, request) ⇒ Object

The client should be able to return an array of holdings objects


93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'app/service_adaptors/opac.rb', line 93

def check_holdings(holdings, request)      
  return if holdings.empty?
  # These need to moved to services.yml
  electronic_locations = ['INTERNET', 'NETLIBRARY', 'GALILEO']
  holdings.each do | holding | 
    @record_attributes[holding.identifier.to_s][:holdings] = holding
    holding.locations.each do | location |
      next if electronic_locations.index(location.code)
      location.items.each do | item |         
        if request.referent.format == 'journal' and request.referent.["volume"] and @record_attributes[holding.identifier.to_s][:conference] == false
          copy_match = false
          if item.enumeration
            if vol_match = item.enumeration.match(/VOL [A-z0-9\-]*/) 
              vol = vol_match[0]                
              vol.sub!(/^VOL\s*/, '')
               (svol, evol) = vol.split('-')
              if request.referent.["volume"] == svol
                copy_match = true
              elsif evol
                if request.referent.["volume"] == evol
                  copy_match = true
                elsif request.referent.["volume"].to_i > svol.to_i and request.referent.["volume"].to_i < evol.to_i                    
                  copy_match = true
                end
              end
            end
          end
          if copy_match == true
            request.add_service_response(:service=>self,:key=>holding.identifier.to_s,:value_string=>location.name,:value_alt_string=>item.call_number,:value_text=>item.status.to_s, :service_type_value => 'holding')         
            break
          end   	                            		
        else  
          request.add_service_response(:service=>self,:key=>holding.identifier.to_s,:value_string=>location.name,:value_alt_string=>item.call_number,:value_text=>item.status.to_s,:service_type_value=>'holding')
        end  	         			
      end
    end
  end         
end

#collect_record_attributes(client, request) ⇒ Object

The client is expected to respond to results and return an array of MARC records. Override this method (and parse_for_fulltext, collect_subjects, and enhance_referent) if your client does not return MARC.


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'app/service_adaptors/opac.rb', line 47

def collect_record_attributes(client, request) 
  require 'marc'    
  client.results.each do | record |
    MARC::XMLReader.new(StringIO.new(record.to_s)).each do | rec |
      id = nil
      
      # Assumes your local control number to be defined in 001
      rec.find_all { | f| '001' === f.tag}.each do | bibnum |
        id = bibnum.value
        @record_attributes[id] = {}
      end 
      
      # Conferences have their own crazy logic
      if self.is_conference?(rec)
        @record_attributes[id][:conference] = true
      else
        @record_attributes[id][:conference] = false
      end
      self.parse_for_fulltext_links(rec, request)              
      self.enhance_referent(rec, request, client.accuracy)
    end    
  end
end

#enhance_referent(marc, request, accuracy) ⇒ Object

When given a MARC record, this method fills in any missing pieces of the Request.referent. 'accuracy' is a 3 point scale determined by the client, 1 = 'possibly the correct resource', 2 = same resource, but not necessarily the same edition, 3 = exactly the same resource


192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
# File 'app/service_adaptors/opac.rb', line 192

def enhance_referent(marc, request, accuracy)
  return unless accuracy > 2
  
  title_key = case request.referent.format
  when "book" then "btitle"
  when "journal" then "jtitle"
  when "dissertation" then "title"
  end
   = request.referent.
  unless [title_key]
    if request.referent.["title"] && title_key != "title"
      request.referent.enhance_referent(title_key, ["title"])
    else 
      request.referent.enhance_referent(title_key, marc['245'].value)
    end
  end
  unless ["au"]
    if marc['100'] && marc['100']['a']
      request.referent.enhance_referent('au', marc['100']['a'])
    end
  end
  unless ["aucorp"]
    if marc['110'] && marc['110']['a']
      request.referent.enhance_referent('aucorp', marc['110']['a'])
    end      
  end
  return unless accuracy > 3    
  unless ["place"]
    if marc['260'] && marc['260']['a']
      request.referent.enhance_referent('place', marc['260']['a'])
    end       
  end     
  unless ["pub"]
    if marc['260'] && marc['260']['b']
      request.referent.enhance_referent('pub', marc['260']['b'])
    end       
  end  
  unless ["edition"]  
    if marc['250'] && marc['250']['a']
      request.referent.enhance_referent('edition', marc['250']['a'])
    end       
  end 
  unless ["series"]
    if marc['490'] && marc['490']['a']
      request.referent.enhance_referent('series', marc['490']['a'])
    elsif marc['730'] && marc['730']['a']
      request.referent.enhance_referent('series', marc['730']['a'])        
    end        
  end 
  unless ["date"] or request.referent.format == 'journal'
    if marc['260'] && marc['260']['c']
      request.referent.enhance_referent('date', marc['260']['c'])   
    end   
  end 
  unless request.referent.format
    type = self.record_type(marc)
    request.referent.enhance_referent('format', 'book', false) if type == "BKS"
    request.referent.enhance_referent('format', 'journal', false) if type == "SER"
  end    
  unless ["genre"]
    if self.is_conference?(marc)
      if ["atitle"]
        request.referent.enhance_referent('genre', 'proceeding')
      else
        request.referent.enhance_referent('genre', 'conference')
      end
    elsif type = self.nature_of_contents(marc)
      case type
      when "dissertation" then request.referent.enhance_referent('format', 'dissertation', false)            
      when "patent" then request.referent.enhance_referent('format', 'patent', false)
      when "report" then request.referent.enhance_referent('genre', 'report')
      end
    else
      type = self.record_type(marc)
      if type == "BKS"
        request.referent.enhance_referent('format', 'book', false) unless request.referent.format == 'book'
        if ["atitle"]
          request.referent.enhance_referent('genre', 'bookpart')
        else
          request.referent.enhance_referent('genre', 'book')
        end
      elsif type == "SER"
        request.referent.enhance_referent('format', 'journal', false) unless request.referent.format == 'journal'        
        if ["atitle"]
          request.referent.enhance_referent('genre', 'article')
        elsif ["issue"]
          request.referent.enhance_referent('genre', 'issue')
        else
          request.referent.enhance_referent('genre', 'journal')
        end
      end
    end
  end
  
  unless ["isbn"]
    if marc['020'] && marc['020']['a']
      request.referent.enhance_referent('isbn', marc['020']['a'])
    end
  end   
  unless ["issn"]
    if marc['022'] && marc['022']['a']
      request.referent.enhance_referent('issn', marc['022']['a'])
    end    
  end 
  unless ["sici"]
    if marc['024'] && marc['024'].indicator1 == "4"
      request.referent.enhance_referent('sici', marc['024']['a'])      
    end       
  end
  
  unless ["coden"]
    if marc['030'] && marc['030']['a']
      request.referent.enhance_referent('coden', marc['030']['a'])      
    end       
  end    
end

#handle(request) ⇒ Object

The Opac class has a few assumptions

  • You have some sort of bib client to get MARC records from your OPAC

  • This operates independently of holdings data

  • If your client can supply holdings information, you have the methods:

  • init_holdings_client

  • get_holdings

The Opac class should be extended with your local connection client and not called directly.


17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'app/service_adaptors/opac.rb', line 17

def handle(request)
  # It's unlikely that consortial catalogs allow borrowing
  # of journals, but this may need to pushed to a client class
  
  if request.referent.format == 'journal' and @consortial
    return request.dispatched(self, true)
  end  
  @record_attributes = {}
  self.search_bib_data(request)
  if self.respond_to?(:init_holdings_client)
    opac_client = self.init_holdings_client
    opac_client.get_holdings(@record_attributes.keys)  
    self.check_holdings(opac_client.results, request)    
  else
    self.add_link_to_opac(client,request)
  end
  return request.dispatched(self, true)    
end

#is_conference?(marc) ⇒ Boolean

Check the leader to determine if this is defined as a conference or proceeding in the MARC


134
135
136
137
138
139
140
141
142
143
144
145
# File 'app/service_adaptors/opac.rb', line 134

def is_conference?(marc)
  # Check the leader/008 for books and serials
  return true if marc['008'].value[29,1] == '1' && marc.leader[6,1].match(/[at]/) && marc.leader[7,1].match(/[abcdms]/)      
  # Check the leader/008 for scores and recordings
  return true if marc['008'].value[30,2] == 'c' && marc.leader[6,1].match(/[cdij]/) && marc.leader[7,1].match(/[abcdms]/)
  # Loop through the 006s
  marc.find_all {|f| ('006') === f.tag}.each { | fxd_fld |
    return true if fxd_fld.value[12,1] == '1' && fxd_fld.value[0,1].match(/[ats]{1}/)
    return true if fxd_fld.value[13,2]== 'c' && fxd_fld.value[0,1].match(/[cdij]{1}/)
  }      
  return false  
end

#nature_of_contents(marc) ⇒ Object

When given a MARC record, determines if the referent should be defined as a dissertation, report or patent.


311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
# File 'app/service_adaptors/opac.rb', line 311

def nature_of_contents(marc)
  types = {'m'=>'dissertation','t'=>'report','j'=>'patent'}
  idx = nil
  if self.record_type(marc) == 'BKS'
    idx = 24
    len = 4
  elsif self.record_type(marc) == 'SER'
    idx = 25
    len = 3
  end
  if idx
    marc['008'].value[idx,len].split(//).each do | char | 
      return types[char] if types.keys.index(char)
    end
  end
  marc.find_all {|f| ('006') === f.tag}.each do | fxd_fld |
    idx = nil
    if fxd_fld.value[0,1].match(/[at]{1}/)
      idx = 7
      len = 4
    elsif fxd_fld.value[0,1].match('s')
      idx = 8
      len = 3
    end     
    if idx 
      fxd_fld.value[idx,len].split(//).each do | char | 
        return types[char] if types.keys.index(char)
      end
    end  
  end        
  return false      
end

Searches the MARC record for 856 tags, checks to see if they seem to be digital representations and, if so, adds them as fulltext service types


74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'app/service_adaptors/opac.rb', line 74

def parse_for_fulltext_links(marc, request)    
  eight_fifty_sixes = []    
  marc.find_all { | f| '856' === f.tag}.each do | link |
    eight_fifty_sixes << link
  end    
  eight_fifty_sixes.each do | link |
    next if link.indicator2.match(/[28]/)
    next if link['u'].match(/(sfx\.galib\.uga\.edu)|(findit\.library\.gatech\.edu)/)
    label = (link['z']||'Electronic Access')
    request.add_service_response(
      :service=>self,
      :key=>label,
      :value_string=>link['u'],
      :service_type_value => 'fulltext'
      )
  end 
end

#record_type(marc) ⇒ Object

Determines the kind of record referred to in the MARC leader/fixed fields (Book, Serial, Map, etc.)


150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'app/service_adaptors/opac.rb', line 150

def record_type(marc)
  type = marc.leader[6,1]
  blvl = marc.leader[7,1]
  valid_types = ['a','t','g','k','r','o','p','e','f','c','d','i','j','m']
  rec_types = {
    'BKS' => { :type => /[at]{1}/,	:blvl => /[acdm]{1}/ },
    'SER' => { :type => /[a]{1}/,	:blvl => /[bs]{1}/ },
    'VIS' => { :type => /[gkro]{1}/,	:blvl => /[abcdms]{1}/ },
    'MIX' => { :type => /[p]{1}/,	:blvl => /[cd]{1}/ },
    'MAP' => { :type => /[ef]{1}/,	:blvl => /[abcdms]{1}/ },
    'SCO' => { :type => /[cd]{1}/,	:blvl => /[abcdms]{1}/ },
    'REC' => { :type => /[ij]{1}/,	:blvl => /[abcdms]{1}/ },
    'COM' => { :type => /[m]{1}/,	:blvl => /[abcdms]{1}/ }
  } 
  
  rec_types.each_key do | rec_type |
    return rec_type if type.match(rec_types[rec_type][:type]) and blvl.match(rec_types[rec_type][:blvl])
  end 
end

#response_url(service_type, http_params) ⇒ Object

Builds a URL either based on a URL in the value_string or builds a link to the OPAC using the direct_link_arg and the bib ID.


346
347
348
349
350
# File 'app/service_adaptors/opac.rb', line 346

def response_url(service_type, http_params)
  response service_type.service_response
  return CGI.unescapeHTML(response.value_string) if response.value_string.match(/^http(s)?:\/\//)
  return @url+'&'+@direct_link_arg+response.response_key          
end

#search_bib_data(request) ⇒ Object

Searches the bibliographic database


37
38
39
40
41
# File 'app/service_adaptors/opac.rb', line 37

def search_bib_data(request)    
  client = self.init_bib_client
  client.search_by_referent(request.referent)
  self.collect_record_attributes(client, request)    
end

#to_fulltext(response) ⇒ Object

When given a ServiceResponse object as its argument, returns the anchor text and URL


171
172
173
# File 'app/service_adaptors/opac.rb', line 171

def to_fulltext(response)
  return {:display_text=>response.response_key, :url=>response.value_string}
end

#to_holding(response) ⇒ Object

When given a ServiceResponse object as its argument, returns the object as a hash with the keys:

  • :display_text

  • :call_number

  • :status

  • :source_name (which equates to self.display_name)


181
182
183
# File 'app/service_adaptors/opac.rb', line 181

def to_holding(response)
  return {:display_text=>response.value_string,:call_number=>response.value_alt_string,:status=>response.value_text,:source_name=>self.display_name}
end