zcc 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +15 -0
- data/Manifest.txt +12 -19
- data/Rakefile +2 -1
- data/bin/zcc +228 -202
- data/examples/zcc.yaml +21 -12
- data/examples/zebra/{register/empty → key/remove_me} +1 -1
- data/examples/zebra/{key/empty → lock/remove_me} +1 -1
- data/examples/zebra/records/0.mrc +1 -0
- data/examples/zebra/{lock/empty → register/remove_me} +1 -1
- data/examples/zebra/tab/marc21.abs +67 -0
- data/examples/zebra/tab/record.abs +1 -0
- data/examples/zebra/zebra.cfg +2 -2
- data/examples/zservers.yaml +869 -0
- data/lib/zcc.rb +8 -0
- data/lib/zcc/ansicolorz.rb +26 -0
- data/lib/zcc/cli_display.rb +461 -0
- data/lib/zcc/query.rb +183 -0
- data/lib/zcc/record.rb +265 -0
- data/lib/zcc/resultset.rb +169 -0
- data/lib/zcc/version.rb +2 -2
- data/lib/zcc/zoomer.rb +16 -2
- data/lib/zcc/zserver.rb +38 -0
- data/website/index.html +1 -1
- data/website/koha.html +18 -10
- data/website/koha.txt +13 -8
- data/website/zcc.html +35 -33
- data/website/zcc.txt +30 -32
- data/website/zebra.html +57 -15
- data/website/zebra.txt +56 -15
- metadata +23 -21
- data/examples/zebra/README +0 -2
- data/examples/zebra/records/examples/0.xml +0 -1
- data/examples/zebra/records/examples/1.xml +0 -1
- data/examples/zebra/records/examples/2.xml +0 -1
- data/examples/zebra/records/examples/3.xml +0 -1
- data/examples/zebra/records/examples/4.xml +0 -1
- data/examples/zebra/records/examples/5.xml +0 -1
- data/examples/zebra/records/examples/6.xml +0 -1
- data/examples/zebra/records/examples/7.xml +0 -1
- data/examples/zebra/records/examples/8.xml +0 -1
- data/examples/zebra/records/examples/9.xml +0 -1
- data/examples/zebra/shadow/empty +0 -1
- data/examples/zebra/tab/kohalis +0 -1
- data/examples/zebra/tmp/empty +0 -1
- data/lib/zcc/marcadditions.rb +0 -221
- data/lib/zcc/pickers.rb +0 -176
data/lib/zcc/query.rb
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
module ZCC
|
2
|
+
|
3
|
+
class Query
|
4
|
+
attr_reader :term, :zservers, :type, :zsearch
|
5
|
+
|
6
|
+
def initialize(term, zservers)
|
7
|
+
self.term = term #=> string of original query post any filtering
|
8
|
+
#puts "term: " + self.term
|
9
|
+
@zservers = []
|
10
|
+
@zservers << zservers #=>array of Zserver objects
|
11
|
+
self.zservers.compact!
|
12
|
+
self.zservers.flatten!
|
13
|
+
#puts self.inspect
|
14
|
+
#puts self.zservers[0].to_s
|
15
|
+
end
|
16
|
+
|
17
|
+
def term=(term)
|
18
|
+
if term =~ /\d+-\d+/
|
19
|
+
@term = lccn_conversion(term)
|
20
|
+
@type = 'lccn'
|
21
|
+
#puts "converted lccn to #{@term}"
|
22
|
+
@zsearch = "@attr 1=9 #{@term}"
|
23
|
+
elsif term =~ /\d+[X||\d]/ and !(term.match( /[a-wyz]/i ))
|
24
|
+
#puts "Searching for ISBN: #{term}"
|
25
|
+
@term = term
|
26
|
+
@type = 'isbn'
|
27
|
+
@zsearch = "@attr 1=7 #{@term}"
|
28
|
+
else ( term[/[a-z]/i] ) #-- This check for a string could be better!
|
29
|
+
#puts "searching for title:#{term}"
|
30
|
+
if term.match(/ :au /)
|
31
|
+
term = term.split(" :au ")
|
32
|
+
puts "Author and title then"
|
33
|
+
@term = term[0]
|
34
|
+
@zsearch = "@and @attr 1=4 \"#{@term}\" @attr 1=1 \"#{term[1]} \"" #was: "@attr 1=4 \"'#{@term}'\""
|
35
|
+
else
|
36
|
+
@term = term
|
37
|
+
@zsearch = "@attr 1=4 \"#{@term}\"" #was: "@attr 1=4 \"'#{@term}'\""
|
38
|
+
end
|
39
|
+
@type = 'title'
|
40
|
+
|
41
|
+
#puts self.term
|
42
|
+
#puts self.type
|
43
|
+
#puts self.zsearch
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
#This is the main search logic of the whole shebang. Aliased as 'search'.
|
49
|
+
#The method on a query object and is passed the number of records from each host to present to the user. Default number of records is 10.
|
50
|
+
#Still need to work on a way to get options in so this might change.
|
51
|
+
#Currently only MARC21 is supported.
|
52
|
+
def zoom(show = 10)
|
53
|
+
result_set = ResultSet.new(self)
|
54
|
+
#puts zservers.inspect
|
55
|
+
search_threads=[]
|
56
|
+
puts zservers.size.to_s + " z-servers in group " + zservers[0].group.to_s
|
57
|
+
z = 0
|
58
|
+
self.zservers.each do |server|
|
59
|
+
z += 1
|
60
|
+
#zservers are made up of...
|
61
|
+
#puts server.to_s
|
62
|
+
search_threads << Thread.new(server, z) do |myserver, myz|
|
63
|
+
begin
|
64
|
+
conn = ZOOM::Connection.new
|
65
|
+
conn.connect(myserver.host, server.port) #do |conn
|
66
|
+
conn.set_option('charset', 'UTF-8')
|
67
|
+
conn.preferred_record_syntax = 'MARC21'
|
68
|
+
conn.database_name = myserver.database
|
69
|
+
puts "#{myz} Searching: #{myserver.to_s} | #{self.zsearch}"
|
70
|
+
rset = conn.search(self.zsearch)
|
71
|
+
say(myz.to_s.headline + " Finished searching: #{myserver.to_s} | rset.size: " + "#{rset.size}".red.bold)
|
72
|
+
rset_recs = rset[0, show]
|
73
|
+
#puts "rset_recs in query.search: "
|
74
|
+
#puts rset_recs
|
75
|
+
i = 0
|
76
|
+
rset_recs.each do |rec|
|
77
|
+
#puts myserver.to_s
|
78
|
+
#puts rec
|
79
|
+
#puts
|
80
|
+
marc_record = ZCC.convert_char(rec)
|
81
|
+
#puts "gets past character conversion"
|
82
|
+
#puts "-------------\n"
|
83
|
+
#puts marc_record
|
84
|
+
#puts "---------------\n"
|
85
|
+
zcc_record = Record.new(marc_record, myserver)
|
86
|
+
result_set.ingest(zcc_record)
|
87
|
+
puts "#{myz} record #{i} from #{myserver}..."
|
88
|
+
i += 1
|
89
|
+
end
|
90
|
+
rescue Exception => e
|
91
|
+
zerror_log("dead thread: " + myserver.to_s + " | " + e)
|
92
|
+
puts "\a#{myz}!!!!!!!! Thread died #{myserver} !!!!!"
|
93
|
+
end
|
94
|
+
#puts "end: #{Thread.list}"
|
95
|
+
#puts "Results processed from: #{myserver.to_s}"
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
search_threads.each{|thread| thread.join}
|
100
|
+
return result_set
|
101
|
+
end
|
102
|
+
|
103
|
+
alias search zoom
|
104
|
+
def zerror_log error
|
105
|
+
File.open("#{File.expand_path("~")}/.zcc/zerror_log", "a+") do |f|
|
106
|
+
f.write error + "\n"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
def convert_char rsetrec
|
114
|
+
rec = MARC::Record.new_from_marc(rsetrec.raw)
|
115
|
+
#puts "initial rec" + rec.to_s
|
116
|
+
ldr9 = rec.leader[9, 1]
|
117
|
+
return_rec = ''
|
118
|
+
#puts "gets to creating dummy record."
|
119
|
+
if ldr9 == ' '
|
120
|
+
#return_rec = MARC::Record.new_from_marc(rsetrec.raw('MARC-8', 'UTF-8')) #This does NOT work
|
121
|
+
return_rec = MARC::XMLReader.new(StringIO.new(rsetrec.xml('MARC-8', 'UTF-8'))).to_a
|
122
|
+
return_rec = return_rec[0]
|
123
|
+
return_rec.leader[9,1] = 'a'
|
124
|
+
#puts "return_rec" + return_rec.to_s
|
125
|
+
elsif ldr9 == 'a'
|
126
|
+
#puts "already unicode"
|
127
|
+
return_rec = rec
|
128
|
+
else
|
129
|
+
raise "Invalid value in leader 9 for MARC21"
|
130
|
+
end
|
131
|
+
return_rec
|
132
|
+
end
|
133
|
+
|
134
|
+
def lccn_conversion lccn
|
135
|
+
split_lccn = lccn.split('-')
|
136
|
+
year_len = split_lccn[0].length
|
137
|
+
serial_len = split_lccn[1].length
|
138
|
+
start_length = year_len + serial_len
|
139
|
+
if year_len == 2
|
140
|
+
final_lccn = lccn.gsub('-', "#{'0' * (8 - start_length)}")
|
141
|
+
elsif year_len == 4
|
142
|
+
final_lccn = lccn.gsub('-', "#{'0' * (10 - start_length)}")
|
143
|
+
end
|
144
|
+
final_lccn
|
145
|
+
end
|
146
|
+
|
147
|
+
#++ compare() is a method to print out a comparison of two MARC records tag by tag (not by subfields).
|
148
|
+
# A match between lines is denoted with a 'm'. If there are differences between the records,
|
149
|
+
# the object that recieves the compare call is denoted with a '+' and the object passed in
|
150
|
+
# parens is denoted with '-'.
|
151
|
+
def compare_marc(orig, rec2)
|
152
|
+
puts "+ = #{orig.zserver.to_s}".bold
|
153
|
+
puts "- = #{rec2.zserver.to_s}".bold
|
154
|
+
orig = orig.marc
|
155
|
+
rec2 = rec2.marc
|
156
|
+
|
157
|
+
for ft in ('000'..'999')
|
158
|
+
fields_original = orig.find_all {|f| f.tag == ft}
|
159
|
+
fields_record2 = rec2.find_all {|f| f.tag == ft}
|
160
|
+
fields_orig = []
|
161
|
+
fields_rec2 = []
|
162
|
+
|
163
|
+
fields_original.each {|f| fields_orig << f.to_s}
|
164
|
+
fields_record2.each {|f| fields_rec2 << f.to_s}
|
165
|
+
|
166
|
+
matches = fields_orig & fields_rec2
|
167
|
+
matches.each { |f| puts "m".bold + " #{f}" } if matches
|
168
|
+
|
169
|
+
fields_orig -= matches
|
170
|
+
fields_orig.each {|f| puts "+".bold + " #{f}"} if fields_orig
|
171
|
+
|
172
|
+
fields_rec2 -= matches
|
173
|
+
fields_rec2.each {|f| puts "-".bold + " #{f}"} if fields_rec2
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def blank_field_prompt(field, subfield)
|
178
|
+
#puts "subfield: #{subfield}"
|
179
|
+
value = ask("\nYour MARC record does not contain #{field}#{subfield}.\nEnter the intended value for #{field}#{subfield} or hit ENTER to leave blank\n#{field}#{subfield} > ")
|
180
|
+
value
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
data/lib/zcc/record.rb
ADDED
@@ -0,0 +1,265 @@
|
|
1
|
+
module ZCC
|
2
|
+
|
3
|
+
class Record
|
4
|
+
attr_accessor :selected, :marc, :authorities, :rank
|
5
|
+
attr_reader :zserver
|
6
|
+
def initialize(marc, zserver, selected = false)
|
7
|
+
@marc = marc
|
8
|
+
@zserver = zserver
|
9
|
+
@selected = selected
|
10
|
+
@rank = 0
|
11
|
+
end
|
12
|
+
|
13
|
+
#def authorities<< (authority)
|
14
|
+
#end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
full_string = "\n---------------RECORD----------------\nzserver: " + zserver.to_s + "\n" + marc.to_s + "---------------RECORD----------------\n"
|
18
|
+
full_string
|
19
|
+
end
|
20
|
+
|
21
|
+
def title
|
22
|
+
self.marc['245']['a']
|
23
|
+
end
|
24
|
+
|
25
|
+
def author
|
26
|
+
end #1XX?
|
27
|
+
|
28
|
+
def extent
|
29
|
+
self.marc['260']['a']
|
30
|
+
end
|
31
|
+
|
32
|
+
def year_260
|
33
|
+
if self.marc['260'] && self.marc['260']['c']
|
34
|
+
date = self.marc['260']['c'].dup
|
35
|
+
date.gsub!('[', '')
|
36
|
+
date.gsub!(']', '')
|
37
|
+
date.gsub!('c','')
|
38
|
+
date
|
39
|
+
else
|
40
|
+
date = '0'
|
41
|
+
date
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def years_fixed
|
46
|
+
end
|
47
|
+
|
48
|
+
def save(format)
|
49
|
+
end #save MARC record to file in proper format (MARC, MARCXML)
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
# linter depends on Perl's MARC::Lint and hence Perl's MARC::Record
|
54
|
+
# Use cpan to install them.
|
55
|
+
def linter
|
56
|
+
rec = self.marc
|
57
|
+
xml_rec = (rec.to_xml).to_s
|
58
|
+
if LINTER == false
|
59
|
+
puts 'You do not have the Perl MARC::Lint module installed or have disabled this feature.'
|
60
|
+
return
|
61
|
+
end
|
62
|
+
contents = `perl "#{File.expand_path("~")}"/.zcc/linter.pl "#{xml_rec}"`
|
63
|
+
if contents.empty?
|
64
|
+
puts "there were no errors detected by the linter."
|
65
|
+
else
|
66
|
+
puts contents
|
67
|
+
end
|
68
|
+
if rec.leader[18,1] == 'a'
|
69
|
+
puts "Leader indicates: AACR"
|
70
|
+
elsif rec.leader[18,1] == 'i'
|
71
|
+
puts "Leader indicates: ISBD"
|
72
|
+
else
|
73
|
+
puts "Leader indicates NOT AACR nor ISBD."
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
#++ The local_script method is for automating changes to the record before saving it. See the main script to turn on this feature. See zoomer.yaml for instructions on creating a script for your purposes.
|
78
|
+
def local_script(script)
|
79
|
+
#print $clear_code
|
80
|
+
record = self.marc
|
81
|
+
|
82
|
+
#--creating my procs for creating fields and appending subfields
|
83
|
+
# these two should probably be moved to methods
|
84
|
+
create_datafield = proc{|record, field, i1, i2| puts "Creating datafield: #{field}"; record.append(MARC::DataField.new(field.to_s, i1.to_s, i2.to_s)); puts "****", record, "***" if $testing;}
|
85
|
+
|
86
|
+
append_subfield = proc{|record, field, subfield, val|
|
87
|
+
field = field.to_s
|
88
|
+
subfield = subfield.to_s
|
89
|
+
value = val.dup
|
90
|
+
value = value.to_s
|
91
|
+
if value.include?('proc ')
|
92
|
+
#I've had problems with this bit but it seems to work now
|
93
|
+
value = value.sub(/^proc /, '')
|
94
|
+
real_value = eval("#{$procs[value]}")
|
95
|
+
next if real_value == nil
|
96
|
+
record[field].append(MARC::Subfield.new(subfield, real_value))
|
97
|
+
elsif
|
98
|
+
record[field].append(MARC::Subfield.new(subfield, value))
|
99
|
+
end
|
100
|
+
}
|
101
|
+
|
102
|
+
script.each do |single_script|
|
103
|
+
puts "--------------------------------------" if $testing
|
104
|
+
puts single_script.join(', ') if $testing
|
105
|
+
op, field, subfield, filler= single_script
|
106
|
+
field = field.to_s
|
107
|
+
subfield = subfield.to_s
|
108
|
+
operation = op.dup
|
109
|
+
if operation.include?('proc ')
|
110
|
+
operation = operation.dup.sub(/^proc /, '')
|
111
|
+
eval("#{$procs[operation]}")
|
112
|
+
elsif operation == 'create-field'
|
113
|
+
create_datafield.call(record, field, subfield, filler)
|
114
|
+
elsif operation == 'append-subfield'
|
115
|
+
append_subfield.call(record, field, subfield, filler)
|
116
|
+
elsif operation == 'prompt'
|
117
|
+
field_data = ask("What do you want to go into the #{field}#{subfield} #{filler}? ")
|
118
|
+
|
119
|
+
next if field_data.empty?
|
120
|
+
m_fields = record.find_all{|x| x.tag == field}
|
121
|
+
if m_fields.empty?
|
122
|
+
puts "m_fields is empty!!"
|
123
|
+
create_datafield.call(record, field, ' ', ' ')
|
124
|
+
m_fields = record.find_all{|x| x.tag == field}
|
125
|
+
end
|
126
|
+
m_fields.each {|field| field.append(MARC::Subfield.new(subfield, field_data))}
|
127
|
+
elsif operation == 'remove'
|
128
|
+
to_remove = record.find_all {|f| f.tag =~ Regexp.new( field.gsub('X','.'))}
|
129
|
+
to_remove.each do |remove|
|
130
|
+
record.fields.delete(remove)
|
131
|
+
end
|
132
|
+
elsif operation == 'sort-tags' ##This doesn't work right now
|
133
|
+
puts "sorting by tag"
|
134
|
+
puts record , "################"
|
135
|
+
record = record.sort_by{| field | field.tag}
|
136
|
+
puts record
|
137
|
+
STDIN.gets
|
138
|
+
else
|
139
|
+
puts "there's nothing for that yet in local_script"
|
140
|
+
end
|
141
|
+
puts record if $testing
|
142
|
+
end
|
143
|
+
|
144
|
+
record
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
|
149
|
+
def edit
|
150
|
+
puts "Subfield Editing"
|
151
|
+
puts "To denote which subfield you want to edit put it in the form of 245a.\nIn the case of repeating fields or subfields you will be prompted\nto choose the one you wish to edit. "
|
152
|
+
continue = true
|
153
|
+
while continue
|
154
|
+
fs = ask("What field and subfield would you like to edit (in form 245a) or quit?\n> "){|q| q.readline = true}
|
155
|
+
if fs == 'q' || fs == 'quit'
|
156
|
+
continue = false
|
157
|
+
next
|
158
|
+
end
|
159
|
+
if !(fs =~/\d\d\d\w/ )
|
160
|
+
puts "That's not a valid value"
|
161
|
+
next
|
162
|
+
end
|
163
|
+
self.change_subfield(fs)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
#edit_subfield is passed to a MARC::Record object and give a subfield
|
168
|
+
def change_subfield(fs)
|
169
|
+
field_subfield = subfield_parse(fs)
|
170
|
+
field = field_subfield[0]
|
171
|
+
subfield = field_subfield[1]
|
172
|
+
|
173
|
+
fields = self.marc.find_all {|f| f.tag == field}
|
174
|
+
subfields = []
|
175
|
+
for field in fields
|
176
|
+
subfields << field.find_all {|s| s.code == subfield}
|
177
|
+
end
|
178
|
+
subfields.flatten!
|
179
|
+
if subfields.length > 1
|
180
|
+
i = 0
|
181
|
+
for subfield in subfields
|
182
|
+
puts "#{i}\t#{subfield}"
|
183
|
+
i += 1
|
184
|
+
end
|
185
|
+
num_to_change = ask("Which subfield do you want to change?"){|q| q.readline = true}
|
186
|
+
subfield_to_change = subfields[num_to_change.to_i]
|
187
|
+
elsif subfields.length == 1
|
188
|
+
subfield_to_change = subfields[0]
|
189
|
+
elsif subfields.empty?
|
190
|
+
puts "No such subfield!"
|
191
|
+
return nil
|
192
|
+
end
|
193
|
+
|
194
|
+
|
195
|
+
puts self.marc; puts
|
196
|
+
|
197
|
+
print "Currently:\t"
|
198
|
+
puts subfield_to_change.value
|
199
|
+
edit = ask("Your edit:\t"){|q| q.readline = true}
|
200
|
+
subfield_to_change.value = edit
|
201
|
+
puts; puts self.marc; puts
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
#subfield_parse method for getting from '245a' to ['245','a']
|
206
|
+
def subfield_parse(combined)
|
207
|
+
field_subfield = []
|
208
|
+
field_subfield << combined[0, 3]
|
209
|
+
field_subfield << combined[3,1]
|
210
|
+
end
|
211
|
+
|
212
|
+
|
213
|
+
|
214
|
+
# To use marc_to_csv it must be passed a csv template in the order of the fields.
|
215
|
+
# See the zoomer.yaml file for instructions on creating a template.
|
216
|
+
# See the main script for turning this feature on.
|
217
|
+
def marc_to_csv(template)
|
218
|
+
values = []
|
219
|
+
template.each do |template|
|
220
|
+
field, subfield, leng = template
|
221
|
+
field = field.to_s
|
222
|
+
subfield = subfield.to_s
|
223
|
+
if field == 'prompt'
|
224
|
+
value = ask("prompt: please enter the #{field} #{subfield}") #--subfield here is a label for the prompt
|
225
|
+
|
226
|
+
value = "\"#{value}\","
|
227
|
+
values << value
|
228
|
+
elsif field.length == 3 and field.match('\d')
|
229
|
+
fields = self.marc.find_all { | f | f.tag =~ Regexp.new( field.gsub('X','.'))}
|
230
|
+
value = ''
|
231
|
+
if fields.empty?
|
232
|
+
#puts "oh, no!"
|
233
|
+
value = blank_field_prompt(field, subfield)
|
234
|
+
#eval(blank_field_prompt)
|
235
|
+
else
|
236
|
+
fields.each do |f|
|
237
|
+
if f[subfield]
|
238
|
+
value += f[subfield] + "|"
|
239
|
+
else
|
240
|
+
value = blank_field_prompt(field, subfield)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
value.sub!(/\|$/, '')
|
245
|
+
value = value[0, leng] if leng
|
246
|
+
#puts "value: #{value}"
|
247
|
+
value = "\"#{value}\","
|
248
|
+
values << value
|
249
|
+
|
250
|
+
else
|
251
|
+
puts "this is not a valid value for marc_to_csv"
|
252
|
+
end
|
253
|
+
end
|
254
|
+
#puts values
|
255
|
+
values[-1].sub!(/\,$/, '')
|
256
|
+
values = values.to_s
|
257
|
+
values += "\n"
|
258
|
+
end
|
259
|
+
|
260
|
+
|
261
|
+
|
262
|
+
|
263
|
+
end
|
264
|
+
|
265
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
module ZCC
|
2
|
+
class ResultSet
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
attr_accessor :query, :sort_by, :index_start, :index_pos, :records, :rank
|
6
|
+
|
7
|
+
#All values of initialize are optional, though you'll want to supply it with a query object if you intend on getting records into your set through a z39.50 search. index_start and index_end will be used for the TUI display.
|
8
|
+
def initialize(query_object=nil, sort_by='title', index_start=0, index_pos=4 )
|
9
|
+
@query = query_object #query object
|
10
|
+
|
11
|
+
@sort_by = sort_by
|
12
|
+
@index_start = index_start
|
13
|
+
@index_pos = index_pos
|
14
|
+
#puts self.sort_by
|
15
|
+
#puts self.index_start
|
16
|
+
@records = []
|
17
|
+
#puts self.records.class
|
18
|
+
end
|
19
|
+
|
20
|
+
#Pretty prints the result set object. Nests pretty printed record objects within.
|
21
|
+
def to_s
|
22
|
+
full_string = "-------RESULT SET--------------\n" + "Result set has #{self.records.size} records."
|
23
|
+
self.records.each do |record|
|
24
|
+
full_string << record.to_s
|
25
|
+
end
|
26
|
+
full_string += "-------RESULT SET--------------\n"
|
27
|
+
end
|
28
|
+
|
29
|
+
# Method to add records only to a result set.
|
30
|
+
def ingest record
|
31
|
+
self.records << record
|
32
|
+
end
|
33
|
+
|
34
|
+
# appends a result set to another.
|
35
|
+
# Replaces the query and sort_by instance variables with the new ones.
|
36
|
+
|
37
|
+
|
38
|
+
#Removes unselected records from the result set. Uses the selected instance variable to check for true or false.
|
39
|
+
def remove_unselected!
|
40
|
+
self.records.each_index do |i|
|
41
|
+
if self.records[i].nil?
|
42
|
+
else
|
43
|
+
self.records[i] = nil unless self.records[i].selected
|
44
|
+
end
|
45
|
+
end
|
46
|
+
self.records.flatten!
|
47
|
+
self.records.compact!
|
48
|
+
self.records.uniq!
|
49
|
+
end
|
50
|
+
|
51
|
+
#Number of records in the result set
|
52
|
+
def size
|
53
|
+
self.records.length
|
54
|
+
end
|
55
|
+
|
56
|
+
alias length size
|
57
|
+
|
58
|
+
#returns number of ZCC::Records with @selected set to true
|
59
|
+
def selected_size
|
60
|
+
selected_records = self.find_all{|record| record.selected unless record == nil}
|
61
|
+
selected_records.length
|
62
|
+
end
|
63
|
+
|
64
|
+
alias selected_length selected_size
|
65
|
+
|
66
|
+
# This allows for Enumerable mixin.
|
67
|
+
def each
|
68
|
+
for record in @records
|
69
|
+
yield record
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def sort_by_title!
|
74
|
+
self.records.compact!
|
75
|
+
self.records.flatten!
|
76
|
+
self.records = self.records.sort_by{|r| r.marc['245']['a']}
|
77
|
+
end
|
78
|
+
|
79
|
+
def sort_by_date!
|
80
|
+
self.remove_nil!
|
81
|
+
self.records = self.records.sort_by{ |r| r.year_260}
|
82
|
+
end
|
83
|
+
|
84
|
+
def sort_by_subfield! sf
|
85
|
+
self.remove_nil!
|
86
|
+
field, subfield = sf[0,3], sf[3,10]
|
87
|
+
subfield = 'a' if subfield == ''
|
88
|
+
nil_subfields = []
|
89
|
+
self.records.each_index do |i|
|
90
|
+
unless self.records[i].marc[field] && self.records[i].marc[field][subfield]
|
91
|
+
nil_subfields << self.records[i]
|
92
|
+
self.records[i] = nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
self.records.compact!
|
96
|
+
begin
|
97
|
+
self.records = self.records.sort_by{ |r| r.marc[field][subfield]}
|
98
|
+
rescue Exception => e
|
99
|
+
puts e
|
100
|
+
say_help("There was an error.\nYour records have not been sorted.")
|
101
|
+
end
|
102
|
+
self.records << nil_subfields
|
103
|
+
self.remove_nil!
|
104
|
+
end
|
105
|
+
|
106
|
+
def sort_by_standard!
|
107
|
+
self.remove_nil!
|
108
|
+
self.records = self.records.sort_by{|r| r.marc.leader[18]}
|
109
|
+
self.records.reverse
|
110
|
+
end
|
111
|
+
|
112
|
+
# Very simple relevancy ranking for title searches
|
113
|
+
def rank_by_relevance!
|
114
|
+
rank = 0
|
115
|
+
#raise NotImplementedError
|
116
|
+
#unless self.query.type == 'title'
|
117
|
+
# raise "Relevancy ranking only works with titles (and not even them yet)"
|
118
|
+
#end
|
119
|
+
self.rank
|
120
|
+
term = self.query.term
|
121
|
+
re_term = Regexp.new("#{term}", true)
|
122
|
+
re_term2 = Regexp.new("\^#{term}", true)
|
123
|
+
self.records.each do |rec|
|
124
|
+
#puts re_term
|
125
|
+
#puts rec.marc['245']['a'] =~ re_term
|
126
|
+
rec.rank += 5 if rec.marc['245']['a'] =~ re_term
|
127
|
+
rec.rank += 10 if rec.marc['245']['a'] =~ re_term2
|
128
|
+
end
|
129
|
+
self.records = self.records.sort_by{|record| record.rank}
|
130
|
+
self.records.reverse!
|
131
|
+
end
|
132
|
+
|
133
|
+
def remove_nil!
|
134
|
+
self.records.compact!
|
135
|
+
self.records.flatten!
|
136
|
+
end
|
137
|
+
|
138
|
+
def hits_per_source
|
139
|
+
end #=> hash{zurl=>[rec, rec],zurl=>[rec, rec]
|
140
|
+
|
141
|
+
def []
|
142
|
+
|
143
|
+
|
144
|
+
end # Record at that position
|
145
|
+
|
146
|
+
def empty?
|
147
|
+
if self.records.size == 0
|
148
|
+
return true
|
149
|
+
elsif self.records.size > 0
|
150
|
+
return false
|
151
|
+
end
|
152
|
+
end #returns true if the @ZCCRecords array is empty or only nil values
|
153
|
+
|
154
|
+
#def find_all
|
155
|
+
#self.find_all {|record| record.selected}
|
156
|
+
#end
|
157
|
+
|
158
|
+
def <<(result_set)
|
159
|
+
#puts record
|
160
|
+
self.records << result_set.records
|
161
|
+
self.query = result_set.query
|
162
|
+
self.sort_by = result_set.sort_by
|
163
|
+
self.records.flatten!
|
164
|
+
#puts self.records.inspect
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
end
|
169
|
+
end
|