blacklight-marc 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.travis.yml +19 -0
- data/Gemfile +15 -0
- data/LICENSE +15 -0
- data/README.md +40 -0
- data/Rakefile +68 -0
- data/app/helpers/blacklight_marc_helper.rb +24 -0
- data/app/views/bookmarks/_endnote.html.erb +3 -0
- data/app/views/bookmarks/_refworks.html.erb +3 -0
- data/app/views/catalog/_marc_view.html.erb +32 -0
- data/app/views/catalog/endnote.endnote.erb +1 -0
- data/app/views/catalog/librarian_view.html.erb +10 -0
- data/blacklight-marc.gemspec +31 -0
- data/config/jetty.yml +4 -0
- data/config/locales/blacklight.en.yml +13 -0
- data/config/locales/blacklight.fr.yml +13 -0
- data/config/routes.rb +17 -0
- data/lib/SolrMarc.jar +0 -0
- data/lib/blacklight/marc.rb +18 -0
- data/lib/blacklight/marc/catalog.rb +20 -0
- data/lib/blacklight/marc/engine.rb +8 -0
- data/lib/blacklight/marc/railtie.rb +17 -0
- data/lib/blacklight/marc/routes.rb +43 -0
- data/lib/blacklight/marc/version.rb +5 -0
- data/lib/blacklight/solr/document/marc.rb +72 -0
- data/lib/blacklight/solr/document/marc_export.rb +587 -0
- data/lib/generators/blacklight_marc/marc_generator.rb +57 -0
- data/lib/generators/blacklight_marc/templates/config/SolrMarc/config-test.properties +37 -0
- data/lib/generators/blacklight_marc/templates/config/SolrMarc/config.properties +37 -0
- data/lib/generators/blacklight_marc/templates/config/SolrMarc/index.properties +97 -0
- data/lib/generators/blacklight_marc/templates/config/SolrMarc/index_scripts/dewey.bsh +47 -0
- data/lib/generators/blacklight_marc/templates/config/SolrMarc/index_scripts/format.bsh +126 -0
- data/lib/generators/blacklight_marc/templates/config/SolrMarc/translation_maps/README_MAPS +1 -0
- data/lib/generators/blacklight_marc/templates/config/SolrMarc/translation_maps/callnumber_map.properties +407 -0
- data/lib/generators/blacklight_marc/templates/config/SolrMarc/translation_maps/composition_era_map.properties +56 -0
- data/lib/generators/blacklight_marc/templates/config/SolrMarc/translation_maps/country_map.properties +379 -0
- data/lib/generators/blacklight_marc/templates/config/SolrMarc/translation_maps/format_map.properties +50 -0
- data/lib/generators/blacklight_marc/templates/config/SolrMarc/translation_maps/instrument_map.properties +101 -0
- data/lib/generators/blacklight_marc/templates/config/SolrMarc/translation_maps/language_map.properties +490 -0
- data/lib/railties/solr_marc.rake +158 -0
- data/spec/controllers/catalog_controller_spec.rb +23 -0
- data/spec/features/librarian_view_spec.rb +13 -0
- data/spec/helpers/blacklight_marc_helper_spec.rb +26 -0
- data/spec/integration/solr_document_spec.rb +59 -0
- data/spec/lib/blacklight_solr_document_marc_spec.rb +89 -0
- data/spec/lib/marc_export_spec.rb +743 -0
- data/spec/lib/tasks/solr_marc_task_spec.rb +60 -0
- data/spec/routing/routes_spec.rb +16 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/test_app_templates/Gemfile.extra +21 -0
- data/spec/test_app_templates/lib/generators/test_app_generator.rb +35 -0
- data/spec/test_app_templates/lib/tasks/blacklight_test_app.rake +14 -0
- data/spec/views/bookmarks/_endnote.html.erb_spec.rb +9 -0
- data/spec/views/bookmarks/_refworks.html.erb_spec.rb +10 -0
- data/test_support/data/test_data.utf8.mrc +1 -0
- metadata +231 -0
@@ -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&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Abook&rfr_id=info%3Asid%2Fblacklight.rubyforge.org%3Agenerator&rft.genre=book&"
|
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'])}&"
|
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'])}&"
|
72
|
+
export_text << "rft.au=#{(author.nil? or author['a'].nil?) ? "" : CGI::escape(author['a'])}&"
|
73
|
+
export_text << "rft.aucorp=#{CGI::escape(corp_author['a']) if corp_author['a']}+#{CGI::escape(corp_author['b']) if corp_author['b']}&" unless corp_author.blank?
|
74
|
+
export_text << "rft.date=#{(publisher_info.nil? or publisher_info['c'].nil?) ? "" : CGI::escape(publisher_info['c'])}&"
|
75
|
+
export_text << "rft.place=#{(publisher_info.nil? or publisher_info['a'].nil?) ? "" : CGI::escape(publisher_info['a'])}&"
|
76
|
+
export_text << "rft.pub=#{(publisher_info.nil? or publisher_info['b'].nil?) ? "" : CGI::escape(publisher_info['b'])}&"
|
77
|
+
export_text << "rft.edition=#{(edition.nil? or edition['a'].nil?) ? "" : CGI::escape(edition['a'])}&"
|
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&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Ajournal&rfr_id=info%3Asid%2Fblacklight.rubyforge.org%3Agenerator&rft.genre=article&"
|
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'])}&"
|
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'])}&"
|
83
|
+
export_text << "rft.aucorp=#{CGI::escape(corp_author['a']) if corp_author['a']}+#{CGI::escape(corp_author['b']) if corp_author['b']}&" unless corp_author.blank?
|
84
|
+
export_text << "rft.date=#{(publisher_info.nil? or publisher_info['c'].nil?) ? "" : CGI::escape(publisher_info['c'])}&"
|
85
|
+
export_text << "rft.issn=#{(issn.nil? or issn['a'].nil?) ? "" : issn['a']}"
|
86
|
+
else
|
87
|
+
export_text << "ctx_ver=Z39.88-2004&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Adc&rfr_id=info%3Asid%2Fblacklight.rubyforge.org%3Agenerator&"
|
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 << "&rft.creator=" + ((author.nil? or author['a'].nil?) ? "" : CGI::escape(author['a']))
|
91
|
+
export_text << "&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 << "&rft.date=" + ((publisher_info.nil? or publisher_info['c'].nil?) ? "" : CGI::escape(publisher_info['c']))
|
93
|
+
export_text << "&rft.place=" + ((publisher_info.nil? or publisher_info['a'].nil?) ? "" : CGI::escape(publisher_info['a']))
|
94
|
+
export_text << "&rft.pub=" + ((publisher_info.nil? or publisher_info['b'].nil?) ? "" : CGI::escape(publisher_info['b']))
|
95
|
+
export_text << "&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(", & " + 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
|