blacklight-marc 5.0.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 (57) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.travis.yml +19 -0
  4. data/Gemfile +15 -0
  5. data/LICENSE +15 -0
  6. data/README.md +40 -0
  7. data/Rakefile +68 -0
  8. data/app/helpers/blacklight_marc_helper.rb +24 -0
  9. data/app/views/bookmarks/_endnote.html.erb +3 -0
  10. data/app/views/bookmarks/_refworks.html.erb +3 -0
  11. data/app/views/catalog/_marc_view.html.erb +32 -0
  12. data/app/views/catalog/endnote.endnote.erb +1 -0
  13. data/app/views/catalog/librarian_view.html.erb +10 -0
  14. data/blacklight-marc.gemspec +31 -0
  15. data/config/jetty.yml +4 -0
  16. data/config/locales/blacklight.en.yml +13 -0
  17. data/config/locales/blacklight.fr.yml +13 -0
  18. data/config/routes.rb +17 -0
  19. data/lib/SolrMarc.jar +0 -0
  20. data/lib/blacklight/marc.rb +18 -0
  21. data/lib/blacklight/marc/catalog.rb +20 -0
  22. data/lib/blacklight/marc/engine.rb +8 -0
  23. data/lib/blacklight/marc/railtie.rb +17 -0
  24. data/lib/blacklight/marc/routes.rb +43 -0
  25. data/lib/blacklight/marc/version.rb +5 -0
  26. data/lib/blacklight/solr/document/marc.rb +72 -0
  27. data/lib/blacklight/solr/document/marc_export.rb +587 -0
  28. data/lib/generators/blacklight_marc/marc_generator.rb +57 -0
  29. data/lib/generators/blacklight_marc/templates/config/SolrMarc/config-test.properties +37 -0
  30. data/lib/generators/blacklight_marc/templates/config/SolrMarc/config.properties +37 -0
  31. data/lib/generators/blacklight_marc/templates/config/SolrMarc/index.properties +97 -0
  32. data/lib/generators/blacklight_marc/templates/config/SolrMarc/index_scripts/dewey.bsh +47 -0
  33. data/lib/generators/blacklight_marc/templates/config/SolrMarc/index_scripts/format.bsh +126 -0
  34. data/lib/generators/blacklight_marc/templates/config/SolrMarc/translation_maps/README_MAPS +1 -0
  35. data/lib/generators/blacklight_marc/templates/config/SolrMarc/translation_maps/callnumber_map.properties +407 -0
  36. data/lib/generators/blacklight_marc/templates/config/SolrMarc/translation_maps/composition_era_map.properties +56 -0
  37. data/lib/generators/blacklight_marc/templates/config/SolrMarc/translation_maps/country_map.properties +379 -0
  38. data/lib/generators/blacklight_marc/templates/config/SolrMarc/translation_maps/format_map.properties +50 -0
  39. data/lib/generators/blacklight_marc/templates/config/SolrMarc/translation_maps/instrument_map.properties +101 -0
  40. data/lib/generators/blacklight_marc/templates/config/SolrMarc/translation_maps/language_map.properties +490 -0
  41. data/lib/railties/solr_marc.rake +158 -0
  42. data/spec/controllers/catalog_controller_spec.rb +23 -0
  43. data/spec/features/librarian_view_spec.rb +13 -0
  44. data/spec/helpers/blacklight_marc_helper_spec.rb +26 -0
  45. data/spec/integration/solr_document_spec.rb +59 -0
  46. data/spec/lib/blacklight_solr_document_marc_spec.rb +89 -0
  47. data/spec/lib/marc_export_spec.rb +743 -0
  48. data/spec/lib/tasks/solr_marc_task_spec.rb +60 -0
  49. data/spec/routing/routes_spec.rb +16 -0
  50. data/spec/spec_helper.rb +27 -0
  51. data/spec/test_app_templates/Gemfile.extra +21 -0
  52. data/spec/test_app_templates/lib/generators/test_app_generator.rb +35 -0
  53. data/spec/test_app_templates/lib/tasks/blacklight_test_app.rake +14 -0
  54. data/spec/views/bookmarks/_endnote.html.erb_spec.rb +9 -0
  55. data/spec/views/bookmarks/_refworks.html.erb_spec.rb +10 -0
  56. data/test_support/data/test_data.utf8.mrc +1 -0
  57. metadata +231 -0
@@ -0,0 +1,5 @@
1
+ module Blacklight
2
+ module Marc
3
+ VERSION = "5.0.0"
4
+ end
5
+ end
@@ -0,0 +1,72 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ # This is a document extension meant to be mixed into a
4
+ # Blacklight::Solr::Document class, such as SolrDocument. It provides support
5
+ # for restoration of MARC data (xml or binary) from a Solr stored field, and
6
+ # then provides various transformations/exports of that Marc via the included
7
+ # Blacklight::Solr::Document::MarcExport module.
8
+ #
9
+ # This extension would normally be registered using
10
+ # Blacklight::Solr::Document#use_extension. eg:
11
+ #
12
+ # SolrDocument.use_extension( Blacklight::Solr::Document::Marc ) { |document| my_logic_for_document_has_marc?( document ) }
13
+ #
14
+ # This extension also expects a :marc_source_field and :marc_format_type to
15
+ # be registered with the hosting classes extension_parameters. In an initializer
16
+ # or other startup code:
17
+ # SolrDocument.extension_paramters[:marc_source_field] = "name_of_solr_stored_field"
18
+ # SolrDocument.extension_parameters[:marc_format_type] = :marc21 # or :marcxml
19
+ require 'marc'
20
+
21
+ module Blacklight::Solr::Document::Marc
22
+
23
+ include Blacklight::Solr::Document::MarcExport # All our export_as stuff based on to_marc.
24
+
25
+ class UnsupportedMarcFormatType < RuntimeError; end
26
+
27
+ def self.extended(document)
28
+ # Register our exportable formats, we inherit these from MarcExport
29
+ Blacklight::Solr::Document::MarcExport.register_export_formats( document )
30
+ end
31
+
32
+ # ruby-marc object
33
+ def to_marc
34
+ @_ruby_marc_obj ||= load_marc
35
+ end
36
+
37
+
38
+ protected
39
+ def marc_source
40
+ @_marc_source ||= fetch(_marc_source_field)
41
+ end
42
+
43
+ def load_marc
44
+ case _marc_format_type.to_s
45
+ when 'marcxml'
46
+ records = MARC::XMLReader.new(StringIO.new( fetch(_marc_source_field) )).to_a
47
+ return records[0]
48
+ when 'marc21'
49
+ return MARC::Record.new_from_marc( fetch(_marc_source_field) )
50
+ else
51
+
52
+ raise UnsupportedMarcFormatType.new("Only marcxml and marc21 are supported, this documents format is #{_marc_format_type} and the current extension parameters are #{self.class.extension_parameters.inspect}")
53
+ end
54
+ end
55
+
56
+
57
+
58
+ def _marc_helper
59
+ @_marc_helper ||= (
60
+ Blacklight::Marc::Document.new fetch(_marc_source_field), _marc_format_type )
61
+ end
62
+
63
+ def _marc_source_field
64
+ self.class.extension_parameters[:marc_source_field]
65
+ end
66
+
67
+ def _marc_format_type
68
+ #TODO: Raise if not present
69
+ self.class.extension_parameters[:marc_format_type]
70
+ end
71
+
72
+ end
@@ -0,0 +1,587 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # -*- coding: utf-8 -*-
3
+ # Written for use with Blacklight::Solr::Document::Marc, but you can use
4
+ # it for your own custom Blacklight document Marc extension too -- just
5
+ # include this module in any document extension (or any other class)
6
+ # that provides a #to_marc returning a ruby-marc object. This module will add
7
+ # in export_as translation methods for a variety of formats.
8
+ module Blacklight::Solr::Document::MarcExport
9
+
10
+ def self.register_export_formats(document)
11
+ document.will_export_as(:xml)
12
+ document.will_export_as(:marc, "application/marc")
13
+ # marcxml content type:
14
+ # http://tools.ietf.org/html/draft-denenberg-mods-etc-media-types-00
15
+ document.will_export_as(:marcxml, "application/marcxml+xml")
16
+ document.will_export_as(:openurl_ctx_kev, "application/x-openurl-ctx-kev")
17
+ document.will_export_as(:refworks_marc_txt, "text/plain")
18
+ document.will_export_as(:endnote, "application/x-endnote-refer")
19
+ end
20
+
21
+
22
+ def export_as_marc
23
+ to_marc.to_marc
24
+ end
25
+
26
+ def export_as_marcxml
27
+ to_marc.to_xml.to_s
28
+ end
29
+ alias_method :export_as_xml, :export_as_marcxml
30
+
31
+
32
+ # TODO This exporting as formatted citation thing should be re-thought
33
+ # redesigned at some point to be more general purpose, but this
34
+ # is in-line with what we had before, but at least now attached
35
+ # to the document extension where it belongs.
36
+ def export_as_apa_citation_txt
37
+ apa_citation( to_marc )
38
+ end
39
+
40
+ def export_as_mla_citation_txt
41
+ mla_citation( to_marc )
42
+ end
43
+
44
+ def export_as_chicago_citation_txt
45
+ chicago_citation( to_marc )
46
+ end
47
+
48
+ # Exports as an OpenURL KEV (key-encoded value) query string.
49
+ # For use to create COinS, among other things. COinS are
50
+ # for Zotero, among other things. TODO: This is wierd and fragile
51
+ # code, it should use ruby OpenURL gem instead to work a lot
52
+ # more sensibly. The "format" argument was in the old marc.marc.to_zotero
53
+ # call, but didn't neccesarily do what it thought it did anyway. Left in
54
+ # for now for backwards compatibilty, but should be replaced by
55
+ # just ruby OpenURL.
56
+ def export_as_openurl_ctx_kev(format = nil)
57
+ title = to_marc.find{|field| field.tag == '245'}
58
+ author = to_marc.find{|field| field.tag == '100'}
59
+ corp_author = to_marc.find{|field| field.tag == '110'}
60
+ publisher_info = to_marc.find{|field| field.tag == '260'}
61
+ edition = to_marc.find{|field| field.tag == '250'}
62
+ isbn = to_marc.find{|field| field.tag == '020'}
63
+ issn = to_marc.find{|field| field.tag == '022'}
64
+ unless format.nil?
65
+ format.is_a?(Array) ? format = format[0].downcase.strip : format = format.downcase.strip
66
+ end
67
+ export_text = ""
68
+ if format == 'book'
69
+ export_text << "ctx_ver=Z39.88-2004&amp;rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Abook&amp;rfr_id=info%3Asid%2Fblacklight.rubyforge.org%3Agenerator&amp;rft.genre=book&amp;"
70
+ export_text << "rft.btitle=#{(title.nil? or title['a'].nil?) ? "" : CGI::escape(title['a'])}+#{(title.nil? or title['b'].nil?) ? "" : CGI::escape(title['b'])}&amp;"
71
+ export_text << "rft.title=#{(title.nil? or title['a'].nil?) ? "" : CGI::escape(title['a'])}+#{(title.nil? or title['b'].nil?) ? "" : CGI::escape(title['b'])}&amp;"
72
+ export_text << "rft.au=#{(author.nil? or author['a'].nil?) ? "" : CGI::escape(author['a'])}&amp;"
73
+ export_text << "rft.aucorp=#{CGI::escape(corp_author['a']) if corp_author['a']}+#{CGI::escape(corp_author['b']) if corp_author['b']}&amp;" unless corp_author.blank?
74
+ export_text << "rft.date=#{(publisher_info.nil? or publisher_info['c'].nil?) ? "" : CGI::escape(publisher_info['c'])}&amp;"
75
+ export_text << "rft.place=#{(publisher_info.nil? or publisher_info['a'].nil?) ? "" : CGI::escape(publisher_info['a'])}&amp;"
76
+ export_text << "rft.pub=#{(publisher_info.nil? or publisher_info['b'].nil?) ? "" : CGI::escape(publisher_info['b'])}&amp;"
77
+ export_text << "rft.edition=#{(edition.nil? or edition['a'].nil?) ? "" : CGI::escape(edition['a'])}&amp;"
78
+ export_text << "rft.isbn=#{(isbn.nil? or isbn['a'].nil?) ? "" : isbn['a']}"
79
+ elsif (format =~ /journal/i) # checking using include because institutions may use formats like Journal or Journal/Magazine
80
+ export_text << "ctx_ver=Z39.88-2004&amp;rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Ajournal&amp;rfr_id=info%3Asid%2Fblacklight.rubyforge.org%3Agenerator&amp;rft.genre=article&amp;"
81
+ export_text << "rft.title=#{(title.nil? or title['a'].nil?) ? "" : CGI::escape(title['a'])}+#{(title.nil? or title['b'].nil?) ? "" : CGI::escape(title['b'])}&amp;"
82
+ export_text << "rft.atitle=#{(title.nil? or title['a'].nil?) ? "" : CGI::escape(title['a'])}+#{(title.nil? or title['b'].nil?) ? "" : CGI::escape(title['b'])}&amp;"
83
+ export_text << "rft.aucorp=#{CGI::escape(corp_author['a']) if corp_author['a']}+#{CGI::escape(corp_author['b']) if corp_author['b']}&amp;" unless corp_author.blank?
84
+ export_text << "rft.date=#{(publisher_info.nil? or publisher_info['c'].nil?) ? "" : CGI::escape(publisher_info['c'])}&amp;"
85
+ export_text << "rft.issn=#{(issn.nil? or issn['a'].nil?) ? "" : issn['a']}"
86
+ else
87
+ export_text << "ctx_ver=Z39.88-2004&amp;rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Adc&amp;rfr_id=info%3Asid%2Fblacklight.rubyforge.org%3Agenerator&amp;"
88
+ export_text << "rft.title=" + ((title.nil? or title['a'].nil?) ? "" : CGI::escape(title['a']))
89
+ export_text << ((title.nil? or title['b'].nil?) ? "" : CGI.escape(" ") + CGI::escape(title['b']))
90
+ export_text << "&amp;rft.creator=" + ((author.nil? or author['a'].nil?) ? "" : CGI::escape(author['a']))
91
+ export_text << "&amp;rft.aucorp=#{CGI::escape(corp_author['a']) if corp_author['a']}+#{CGI::escape(corp_author['b']) if corp_author['b']}" unless corp_author.blank?
92
+ export_text << "&amp;rft.date=" + ((publisher_info.nil? or publisher_info['c'].nil?) ? "" : CGI::escape(publisher_info['c']))
93
+ export_text << "&amp;rft.place=" + ((publisher_info.nil? or publisher_info['a'].nil?) ? "" : CGI::escape(publisher_info['a']))
94
+ export_text << "&amp;rft.pub=" + ((publisher_info.nil? or publisher_info['b'].nil?) ? "" : CGI::escape(publisher_info['b']))
95
+ export_text << "&amp;rft.format=" + (format.nil? ? "" : CGI::escape(format))
96
+ end
97
+ export_text.html_safe unless export_text.blank?
98
+ end
99
+
100
+
101
+ # This format used to be called 'refworks', which wasn't really
102
+ # accurate, sounds more like 'refworks tagged format'. Which this
103
+ # is not, it's instead some weird under-documented Refworks
104
+ # proprietary marc-ish in text/plain format. See
105
+ # http://robotlibrarian.billdueber.com/sending-marcish-data-to-refworks/
106
+ def export_as_refworks_marc_txt
107
+ fields = to_marc.find_all { |f| ('000'..'999') === f.tag }
108
+ text = "LEADER #{to_marc.leader}"
109
+ fields.each do |field|
110
+ unless ["940","999"].include?(field.tag)
111
+ if field.is_a?(MARC::ControlField)
112
+ text << "#{field.tag} #{field.value}\n"
113
+ else
114
+ text << "#{field.tag} "
115
+ text << (field.indicator1 ? field.indicator1 : " ")
116
+ text << (field.indicator2 ? field.indicator2 : " ")
117
+ text << " "
118
+ field.each {|s| s.code == 'a' ? text << "#{s.value}" : text << " |#{s.code}#{s.value}"}
119
+ text << "\n"
120
+ end
121
+ end
122
+ end
123
+
124
+ # As of 11 May 2010, Refworks has a problem with UTF-8 if it's decomposed,
125
+ # it seems to want C form normalization, although RefWorks support
126
+ # couldn't tell me that. -jrochkind
127
+ text = ActiveSupport::Multibyte::Unicode.normalize(text, :c)
128
+
129
+ return text
130
+ end
131
+
132
+ # Endnote Import Format. See the EndNote User Guide at:
133
+ # http://www.endnote.com/support/enx3man-terms-win.asp
134
+ # Chapter 7: Importing Reference Data into EndNote / Creating a Tagged “EndNote Import” File
135
+ #
136
+ # Note: This code is copied from what used to be in the previous version
137
+ # in ApplicationHelper#render_to_endnote. It does NOT produce very good
138
+ # endnote import format; the %0 is likely to be entirely illegal, the
139
+ # rest of the data is barely correct but messy. TODO, a new version of this,
140
+ # or better yet just an export_as_ris instead, which will be more general
141
+ # purpose.
142
+ def export_as_endnote()
143
+ end_note_format = {
144
+ "%A" => "100.a",
145
+ "%C" => "260.a",
146
+ "%D" => "260.c",
147
+ "%E" => "700.a",
148
+ "%I" => "260.b",
149
+ "%J" => "440.a",
150
+ "%@" => "020.a",
151
+ "%_@" => "022.a",
152
+ "%T" => "245.a,245.b",
153
+ "%U" => "856.u",
154
+ "%7" => "250.a"
155
+ }
156
+ marc_obj = to_marc
157
+
158
+ # TODO. This should be rewritten to guess
159
+ # from actual Marc instead, probably.
160
+ format_str = 'Generic'
161
+
162
+ text = ''
163
+ text << "%0 #{ format_str }\n"
164
+ # If there is some reliable way of getting the language of a record we can add it here
165
+ #text << "%G #{record['language'].first}\n"
166
+ end_note_format.each do |key,value|
167
+ values = value.split(",")
168
+ first_value = values[0].split('.')
169
+ if values.length > 1
170
+ second_value = values[1].split('.')
171
+ else
172
+ second_value = []
173
+ end
174
+
175
+ if marc_obj[first_value[0].to_s]
176
+ marc_obj.find_all{|f| (first_value[0].to_s) === f.tag}.each do |field|
177
+ if field[first_value[1]].to_s or field[second_value[1]].to_s
178
+ text << "#{key.gsub('_','')}"
179
+ if field[first_value[1]].to_s
180
+ text << " #{field[first_value[1]].to_s}"
181
+ end
182
+ if field[second_value[1]].to_s
183
+ text << " #{field[second_value[1]].to_s}"
184
+ end
185
+ text << "\n"
186
+ end
187
+ end
188
+ end
189
+ end
190
+ text
191
+ end
192
+
193
+ ## DEPRECATED stuff left in for backwards compatibility, but should
194
+ # be gotten rid of eventually.
195
+
196
+ def to_zotero(format)
197
+ warn("[DEPRECATION] Simply call document.export_as_openurl_kev to get an openURL kev context object suitable for including in a COinS; then have view code make the span for the COinS. ")
198
+ "<span class=\"Z3988\" title=\"#{export_as_openurl_kev(format)}\"></span>"
199
+ end
200
+
201
+ def to_apa
202
+ warn("[DEPRECATION] Call document.export_as_apa_citation instead.")
203
+ export_as_apa_citation
204
+ end
205
+
206
+ def to_mla
207
+ warn("[DEPRECATION] Call document.export_as_mla_citation instead.")
208
+ end
209
+
210
+
211
+
212
+ protected
213
+
214
+ # Main method for defining chicago style citation. If we don't end up converting to using a citation formatting service
215
+ # we should make this receive a semantic document and not MARC so we can use this with other formats.
216
+ def chicago_citation(marc)
217
+ authors = get_all_authors(marc)
218
+ author_text = ""
219
+ unless authors[:primary_authors].blank?
220
+ if authors[:primary_authors].length > 10
221
+ authors[:primary_authors].each_with_index do |author,index|
222
+ if index < 7
223
+ if index == 0
224
+ author_text << "#{author}"
225
+ if author.ends_with?(",")
226
+ author_text << " "
227
+ else
228
+ author_text << ", "
229
+ end
230
+ else
231
+ author_text << "#{name_reverse(author)}, "
232
+ end
233
+ end
234
+ end
235
+ author_text << " et al."
236
+ elsif authors[:primary_authors].length > 1
237
+ authors[:primary_authors].each_with_index do |author,index|
238
+ if index == 0
239
+ author_text << "#{author}"
240
+ if author.ends_with?(",")
241
+ author_text << " "
242
+ else
243
+ author_text << ", "
244
+ end
245
+ elsif index + 1 == authors[:primary_authors].length
246
+ author_text << "and #{name_reverse(author)}."
247
+ else
248
+ author_text << "#{name_reverse(author)}, "
249
+ end
250
+ end
251
+ else
252
+ author_text << authors[:primary_authors].first
253
+ end
254
+ else
255
+ temp_authors = []
256
+ authors[:translators].each do |translator|
257
+ temp_authors << [translator, "trans."]
258
+ end
259
+ authors[:editors].each do |editor|
260
+ temp_authors << [editor, "ed."]
261
+ end
262
+ authors[:compilers].each do |compiler|
263
+ temp_authors << [compiler, "comp."]
264
+ end
265
+
266
+ unless temp_authors.blank?
267
+ if temp_authors.length > 10
268
+ temp_authors.each_with_index do |author,index|
269
+ if index < 7
270
+ author_text << "#{author.first} #{author.last} "
271
+ end
272
+ end
273
+ author_text << " et al."
274
+ elsif temp_authors.length > 1
275
+ temp_authors.each_with_index do |author,index|
276
+ if index == 0
277
+ author_text << "#{author.first} #{author.last}, "
278
+ elsif index + 1 == temp_authors.length
279
+ author_text << "and #{name_reverse(author.first)} #{author.last}"
280
+ else
281
+ author_text << "#{name_reverse(author.first)} #{author.last}, "
282
+ end
283
+ end
284
+ else
285
+ author_text << "#{temp_authors.first.first} #{temp_authors.first.last}"
286
+ end
287
+ end
288
+ end
289
+ title = ""
290
+ additional_title = ""
291
+ section_title = ""
292
+ if marc["245"] and (marc["245"]["a"] or marc["245"]["b"])
293
+ title << citation_title(clean_end_punctuation(marc["245"]["a"]).strip) if marc["245"]["a"]
294
+ title << ": #{citation_title(clean_end_punctuation(marc["245"]["b"]).strip)}" if marc["245"]["b"]
295
+ end
296
+ if marc["245"] and (marc["245"]["n"] or marc["245"]["p"])
297
+ section_title << citation_title(clean_end_punctuation(marc["245"]["n"])) if marc["245"]["n"]
298
+ if marc["245"]["p"]
299
+ section_title << ", <i>#{citation_title(clean_end_punctuation(marc["245"]["p"]))}.</i>"
300
+ elsif marc["245"]["n"]
301
+ section_title << "."
302
+ end
303
+ end
304
+
305
+ if !authors[:primary_authors].blank? and (!authors[:translators].blank? or !authors[:editors].blank? or !authors[:compilers].blank?)
306
+ additional_title << "Translated by #{authors[:translators].collect{|name| name_reverse(name)}.join(" and ")}. " unless authors[:translators].blank?
307
+ additional_title << "Edited by #{authors[:editors].collect{|name| name_reverse(name)}.join(" and ")}. " unless authors[:editors].blank?
308
+ additional_title << "Compiled by #{authors[:compilers].collect{|name| name_reverse(name)}.join(" and ")}. " unless authors[:compilers].blank?
309
+ end
310
+
311
+ edition = ""
312
+ edition << setup_edition(marc) unless setup_edition(marc).nil?
313
+
314
+ pub_info = ""
315
+ if marc["260"] and (marc["260"]["a"] or marc["260"]["b"])
316
+ pub_info << clean_end_punctuation(marc["260"]["a"]).strip if marc["260"]["a"]
317
+ pub_info << ": #{clean_end_punctuation(marc["260"]["b"]).strip}" if marc["260"]["b"]
318
+ pub_info << ", #{setup_pub_date(marc)}" if marc["260"]["c"]
319
+ elsif marc["502"] and marc["502"]["a"] # MARC 502 is the Dissertation Note. This holds the correct pub info for these types of records.
320
+ pub_info << marc["502"]["a"]
321
+ elsif marc["502"] and (marc["502"]["b"] or marc["502"]["c"] or marc["502"]["d"]) #sometimes the dissertation note is encoded in pieces in the $b $c and $d sub fields instead of lumped into the $a
322
+ pub_info << "#{marc["502"]["b"]}, #{marc["502"]["c"]}, #{clean_end_punctuation(marc["502"]["d"])}"
323
+ end
324
+
325
+ citation = ""
326
+ citation << "#{author_text} " unless author_text.blank?
327
+ citation << "<i>#{title}.</i> " unless title.blank?
328
+ citation << "#{section_title} " unless section_title.blank?
329
+ citation << "#{additional_title} " unless additional_title.blank?
330
+ citation << "#{edition} " unless edition.blank?
331
+ citation << "#{pub_info}." unless pub_info.blank?
332
+ citation
333
+ end
334
+
335
+
336
+
337
+ def mla_citation(record)
338
+ text = ''
339
+ authors_final = []
340
+
341
+ #setup formatted author list
342
+ authors = get_author_list(record)
343
+
344
+ if authors.length < 4
345
+ authors.each do |l|
346
+ if l == authors.first #first
347
+ authors_final.push(l)
348
+ elsif l == authors.last #last
349
+ authors_final.push(", and " + name_reverse(l) + ".")
350
+ else #all others
351
+ authors_final.push(", " + name_reverse(l))
352
+ end
353
+ end
354
+ text += authors_final.join
355
+ unless text.blank?
356
+ if text[-1,1] != "."
357
+ text += ". "
358
+ else
359
+ text += " "
360
+ end
361
+ end
362
+ else
363
+ text += authors.first + ", et al. "
364
+ end
365
+ # setup title
366
+ title = setup_title_info(record)
367
+ if !title.nil?
368
+ text += "<i>" + mla_citation_title(title) + "</i> "
369
+ end
370
+
371
+ # Edition
372
+ edition_data = setup_edition(record)
373
+ text += edition_data + " " unless edition_data.nil?
374
+
375
+ # Publication
376
+ text += setup_pub_info(record) + ", " unless setup_pub_info(record).nil?
377
+
378
+ # Get Pub Date
379
+ text += setup_pub_date(record) unless setup_pub_date(record).nil?
380
+ if text[-1,1] != "."
381
+ text += "." unless text.nil? or text.blank?
382
+ end
383
+ text
384
+ end
385
+
386
+ def apa_citation(record)
387
+ text = ''
388
+ authors_list = []
389
+ authors_list_final = []
390
+
391
+ #setup formatted author list
392
+ authors = get_author_list(record)
393
+ authors.each do |l|
394
+ authors_list.push(abbreviate_name(l)) unless l.blank?
395
+ end
396
+ authors_list.each do |l|
397
+ if l == authors_list.first #first
398
+ authors_list_final.push(l.strip)
399
+ elsif l == authors_list.last #last
400
+ authors_list_final.push(", &amp; " + l.strip)
401
+ else #all others
402
+ authors_list_final.push(", " + l.strip)
403
+ end
404
+ end
405
+ text += authors_list_final.join
406
+ unless text.blank?
407
+ if text[-1,1] != "."
408
+ text += ". "
409
+ else
410
+ text += " "
411
+ end
412
+ end
413
+ # Get Pub Date
414
+ text += "(" + setup_pub_date(record) + "). " unless setup_pub_date(record).nil?
415
+
416
+ # setup title info
417
+ title = setup_title_info(record)
418
+ text += "<i>" + title + "</i> " unless title.nil?
419
+
420
+ # Edition
421
+ edition_data = setup_edition(record)
422
+ text += edition_data + " " unless edition_data.nil?
423
+
424
+ # Publisher info
425
+ text += setup_pub_info(record) unless setup_pub_info(record).nil?
426
+ unless text.blank?
427
+ if text[-1,1] != "."
428
+ text += "."
429
+ end
430
+ end
431
+ text
432
+ end
433
+ def setup_pub_date(record)
434
+ if !record.find{|f| f.tag == '260'}.nil?
435
+ pub_date = record.find{|f| f.tag == '260'}
436
+ if pub_date.find{|s| s.code == 'c'}
437
+ date_value = pub_date.find{|s| s.code == 'c'}.value.gsub(/[^0-9|n\.d\.]/, "")[0,4] unless pub_date.find{|s| s.code == 'c'}.value.gsub(/[^0-9|n\.d\.]/, "")[0,4].blank?
438
+ end
439
+ return nil if date_value.nil?
440
+ end
441
+ clean_end_punctuation(date_value) if date_value
442
+ end
443
+ def setup_pub_info(record)
444
+ text = ''
445
+ pub_info_field = record.find{|f| f.tag == '260'}
446
+ if !pub_info_field.nil?
447
+ a_pub_info = pub_info_field.find{|s| s.code == 'a'}
448
+ b_pub_info = pub_info_field.find{|s| s.code == 'b'}
449
+ a_pub_info = clean_end_punctuation(a_pub_info.value.strip) unless a_pub_info.nil?
450
+ b_pub_info = b_pub_info.value.strip unless b_pub_info.nil?
451
+ text += a_pub_info.strip unless a_pub_info.nil?
452
+ if !a_pub_info.nil? and !b_pub_info.nil?
453
+ text += ": "
454
+ end
455
+ text += b_pub_info.strip unless b_pub_info.nil?
456
+ end
457
+ return nil if text.strip.blank?
458
+ clean_end_punctuation(text.strip)
459
+ end
460
+
461
+ def mla_citation_title(text)
462
+ no_upcase = ["a","an","and","but","by","for","it","of","the","to","with"]
463
+ new_text = []
464
+ word_parts = text.split(" ")
465
+ word_parts.each do |w|
466
+ if !no_upcase.include? w
467
+ new_text.push(w.capitalize)
468
+ else
469
+ new_text.push(w)
470
+ end
471
+ end
472
+ new_text.join(" ")
473
+ end
474
+
475
+ # This will replace the mla_citation_title method with a better understanding of how MLA and Chicago citation titles are formatted.
476
+ # This method will take in a string and capitalize all of the non-prepositions.
477
+ def citation_title(title_text)
478
+ prepositions = ["a","about","across","an","and","before","but","by","for","it","of","the","to","with","without"]
479
+ new_text = []
480
+ title_text.split(" ").each_with_index do |word,index|
481
+ if (index == 0 and word != word.upcase) or (word.length > 1 and word != word.upcase and !prepositions.include?(word))
482
+ # the split("-") will handle the capitalization of hyphenated words
483
+ new_text << word.split("-").map!{|w| w.capitalize }.join("-")
484
+ else
485
+ new_text << word
486
+ end
487
+ end
488
+ new_text.join(" ")
489
+ end
490
+
491
+ def setup_title_info(record)
492
+ text = ''
493
+ title_info_field = record.find{|f| f.tag == '245'}
494
+ if !title_info_field.nil?
495
+ a_title_info = title_info_field.find{|s| s.code == 'a'}
496
+ b_title_info = title_info_field.find{|s| s.code == 'b'}
497
+ a_title_info = clean_end_punctuation(a_title_info.value.strip) unless a_title_info.nil?
498
+ b_title_info = clean_end_punctuation(b_title_info.value.strip) unless b_title_info.nil?
499
+ text += a_title_info unless a_title_info.nil?
500
+ if !a_title_info.nil? and !b_title_info.nil?
501
+ text += ": "
502
+ end
503
+ text += b_title_info unless b_title_info.nil?
504
+ end
505
+
506
+ return nil if text.strip.blank?
507
+ clean_end_punctuation(text.strip) + "."
508
+
509
+ end
510
+
511
+ def clean_end_punctuation(text)
512
+ if [".",",",":",";","/"].include? text[-1,1]
513
+ return text[0,text.length-1]
514
+ end
515
+ text
516
+ end
517
+
518
+ def setup_edition(record)
519
+ edition_field = record.find{|f| f.tag == '250'}
520
+ edition_code = edition_field.find{|s| s.code == 'a'} unless edition_field.nil?
521
+ edition_data = edition_code.value unless edition_code.nil?
522
+ if edition_data.nil? or edition_data == '1st ed.'
523
+ return nil
524
+ else
525
+ return edition_data
526
+ end
527
+ end
528
+
529
+ def get_author_list(record)
530
+ author_list = []
531
+ authors_primary = record.find{|f| f.tag == '100'}
532
+ author_primary = authors_primary.find{|s| s.code == 'a'}.value unless authors_primary.nil? rescue ''
533
+ author_list.push(clean_end_punctuation(author_primary)) unless author_primary.nil?
534
+ authors_secondary = record.find_all{|f| ('700') === f.tag}
535
+ if !authors_secondary.nil?
536
+ authors_secondary.each do |l|
537
+ author_list.push(clean_end_punctuation(l.find{|s| s.code == 'a'}.value)) unless l.find{|s| s.code == 'a'}.value.nil?
538
+ end
539
+ end
540
+
541
+ author_list.uniq!
542
+ author_list
543
+ end
544
+
545
+ # This is a replacement method for the get_author_list method. This new method will break authors out into primary authors, translators, editors, and compilers
546
+ def get_all_authors(record)
547
+ translator_code = "trl"; editor_code = "edt"; compiler_code = "com"
548
+ primary_authors = []; translators = []; editors = []; compilers = []
549
+ record.find_all{|f| f.tag === "100" }.each do |field|
550
+ primary_authors << field["a"] if field["a"]
551
+ end
552
+ record.find_all{|f| f.tag === "700" }.each do |field|
553
+ if field["a"]
554
+ relators = []
555
+ relators << clean_end_punctuation(field["e"]) if field["e"]
556
+ relators << clean_end_punctuation(field["4"]) if field["4"]
557
+ if relators.include?(translator_code)
558
+ translators << field["a"]
559
+ elsif relators.include?(editor_code)
560
+ editors << field["a"]
561
+ elsif relators.include?(compiler_code)
562
+ compilers << field["a"]
563
+ else
564
+ primary_authors << field["a"]
565
+ end
566
+ end
567
+ end
568
+ {:primary_authors => primary_authors, :translators => translators, :editors => editors, :compilers => compilers}
569
+ end
570
+
571
+ def abbreviate_name(name)
572
+ name_parts = name.split(", ")
573
+ first_name_parts = name_parts.last.split(" ")
574
+ temp_name = name_parts.first + ", " + first_name_parts.first[0,1] + "."
575
+ first_name_parts.shift
576
+ temp_name += " " + first_name_parts.join(" ") unless first_name_parts.empty?
577
+ temp_name
578
+ end
579
+
580
+ def name_reverse(name)
581
+ name = clean_end_punctuation(name)
582
+ return name unless name =~ /,/
583
+ temp_name = name.split(", ")
584
+ return temp_name.last + " " + temp_name.first
585
+ end
586
+
587
+ end