blacklight_marc 0.0.2 → 0.0.3
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.
- checksums.yaml +4 -4
- data/blacklight_marc.gemspec +3 -0
- data/lib/blacklight/solr/document/marc.rb +71 -0
- data/lib/blacklight/solr/document/marc_export.rb +602 -0
- data/lib/blacklight_marc/version.rb +1 -1
- data/lib/blacklight_marc.rb +5 -0
- metadata +23 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 24c6e3dc1f7daff18432642867d570b2ffb4a6f5
|
4
|
+
data.tar.gz: 1f8bc8a88cb1e29c5605b9de140612c38d1d3588
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4625cf4d1a6a15db370f2c5fafcaa0b8d0a369d3a87bf009c4d46917af7d5539d5367d117a1c97cbeb35a977553d4c60519ecbca51b1114b97c5fe1a1334321a
|
7
|
+
data.tar.gz: 26ffce0d381dd7dd4cd1d5bf3b7dd772962d4257cbe4acef266853b9eb17b44af356c42376fa1842f79e3d459a6537bce26e5584202ca3a5a814787bc82ebd54
|
data/blacklight_marc.gemspec
CHANGED
@@ -21,4 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.3"
|
22
22
|
spec.add_development_dependency "rake"
|
23
23
|
spec.add_dependency "railties", ">= 3.2.6", "< 5"
|
24
|
+
# Let's allow future versions of marc, count on
|
25
|
+
# them to be backwards compat until 1.1
|
26
|
+
spec.add_dependency "marc", ">= 0.4.3", "< 1.1" # Marc record parser.
|
24
27
|
end
|
@@ -0,0 +1,71 @@
|
|
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
|
+
module Blacklight::Solr::Document::Marc
|
21
|
+
|
22
|
+
include Blacklight::Solr::Document::MarcExport # All our export_as stuff based on to_marc.
|
23
|
+
|
24
|
+
class UnsupportedMarcFormatType < RuntimeError; end
|
25
|
+
|
26
|
+
def self.extended(document)
|
27
|
+
# Register our exportable formats, we inherit these from MarcExport
|
28
|
+
Blacklight::Solr::Document::MarcExport.register_export_formats( document )
|
29
|
+
end
|
30
|
+
|
31
|
+
# ruby-marc object
|
32
|
+
def to_marc
|
33
|
+
@_ruby_marc_obj ||= load_marc
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
protected
|
38
|
+
def marc_source
|
39
|
+
@_marc_source ||= fetch(_marc_source_field)
|
40
|
+
end
|
41
|
+
|
42
|
+
def load_marc
|
43
|
+
case _marc_format_type.to_s
|
44
|
+
when 'marcxml'
|
45
|
+
records = MARC::XMLReader.new(StringIO.new( fetch(_marc_source_field) )).to_a
|
46
|
+
return records[0]
|
47
|
+
when 'marc21'
|
48
|
+
return MARC::Record.new_from_marc( fetch(_marc_source_field) )
|
49
|
+
else
|
50
|
+
|
51
|
+
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}")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
def _marc_helper
|
58
|
+
@_marc_helper ||= (
|
59
|
+
Blacklight::Marc::Document.new fetch(_marc_source_field), _marc_format_type )
|
60
|
+
end
|
61
|
+
|
62
|
+
def _marc_source_field
|
63
|
+
self.class.extension_parameters[:marc_source_field]
|
64
|
+
end
|
65
|
+
|
66
|
+
def _marc_format_type
|
67
|
+
#TODO: Raise if not present
|
68
|
+
self.class.extension_parameters[:marc_format_type]
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,602 @@
|
|
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
|
+
# plugin/gem weirdness means we do need to manually require
|
108
|
+
# here.
|
109
|
+
# As of 11 May 2010, Refworks has a problem with UTF-8 if it's decomposed,
|
110
|
+
# it seems to want C form normalization, although RefWorks support
|
111
|
+
# couldn't tell me that. -jrochkind
|
112
|
+
# DHF: moved this require a little lower in the method.
|
113
|
+
# require 'unicode'
|
114
|
+
|
115
|
+
fields = to_marc.find_all { |f| ('000'..'999') === f.tag }
|
116
|
+
text = "LEADER #{to_marc.leader}"
|
117
|
+
fields.each do |field|
|
118
|
+
unless ["940","999"].include?(field.tag)
|
119
|
+
if field.is_a?(MARC::ControlField)
|
120
|
+
text << "#{field.tag} #{field.value}\n"
|
121
|
+
else
|
122
|
+
text << "#{field.tag} "
|
123
|
+
text << (field.indicator1 ? field.indicator1 : " ")
|
124
|
+
text << (field.indicator2 ? field.indicator2 : " ")
|
125
|
+
text << " "
|
126
|
+
field.each {|s| s.code == 'a' ? text << "#{s.value}" : text << " |#{s.code}#{s.value}"}
|
127
|
+
text << "\n"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
if Blacklight.jruby?
|
133
|
+
require 'java'
|
134
|
+
java_import java.text.Normalizer
|
135
|
+
Normalizer.normalize(text, Normalizer::Form::NFC).to_s
|
136
|
+
else
|
137
|
+
begin
|
138
|
+
require 'unicode'
|
139
|
+
Unicode.normalize_C(text)
|
140
|
+
rescue LoadError
|
141
|
+
Blacklight.logger.warn "Unable to load unicode library in #export_as_refworks_marc_txt; skipping unicode normalization"
|
142
|
+
text
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Endnote Import Format. See the EndNote User Guide at:
|
148
|
+
# http://www.endnote.com/support/enx3man-terms-win.asp
|
149
|
+
# Chapter 7: Importing Reference Data into EndNote / Creating a Tagged “EndNote Import” File
|
150
|
+
#
|
151
|
+
# Note: This code is copied from what used to be in the previous version
|
152
|
+
# in ApplicationHelper#render_to_endnote. It does NOT produce very good
|
153
|
+
# endnote import format; the %0 is likely to be entirely illegal, the
|
154
|
+
# rest of the data is barely correct but messy. TODO, a new version of this,
|
155
|
+
# or better yet just an export_as_ris instead, which will be more general
|
156
|
+
# purpose.
|
157
|
+
def export_as_endnote()
|
158
|
+
end_note_format = {
|
159
|
+
"%A" => "100.a",
|
160
|
+
"%C" => "260.a",
|
161
|
+
"%D" => "260.c",
|
162
|
+
"%E" => "700.a",
|
163
|
+
"%I" => "260.b",
|
164
|
+
"%J" => "440.a",
|
165
|
+
"%@" => "020.a",
|
166
|
+
"%_@" => "022.a",
|
167
|
+
"%T" => "245.a,245.b",
|
168
|
+
"%U" => "856.u",
|
169
|
+
"%7" => "250.a"
|
170
|
+
}
|
171
|
+
marc_obj = to_marc
|
172
|
+
|
173
|
+
# TODO. This should be rewritten to guess
|
174
|
+
# from actual Marc instead, probably.
|
175
|
+
format_str = 'Generic'
|
176
|
+
|
177
|
+
text = ''
|
178
|
+
text << "%0 #{ format_str }\n"
|
179
|
+
# If there is some reliable way of getting the language of a record we can add it here
|
180
|
+
#text << "%G #{record['language'].first}\n"
|
181
|
+
end_note_format.each do |key,value|
|
182
|
+
values = value.split(",")
|
183
|
+
first_value = values[0].split('.')
|
184
|
+
if values.length > 1
|
185
|
+
second_value = values[1].split('.')
|
186
|
+
else
|
187
|
+
second_value = []
|
188
|
+
end
|
189
|
+
|
190
|
+
if marc_obj[first_value[0].to_s]
|
191
|
+
marc_obj.find_all{|f| (first_value[0].to_s) === f.tag}.each do |field|
|
192
|
+
if field[first_value[1]].to_s or field[second_value[1]].to_s
|
193
|
+
text << "#{key.gsub('_','')}"
|
194
|
+
if field[first_value[1]].to_s
|
195
|
+
text << " #{field[first_value[1]].to_s}"
|
196
|
+
end
|
197
|
+
if field[second_value[1]].to_s
|
198
|
+
text << " #{field[second_value[1]].to_s}"
|
199
|
+
end
|
200
|
+
text << "\n"
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
text
|
206
|
+
end
|
207
|
+
|
208
|
+
## DEPRECATED stuff left in for backwards compatibility, but should
|
209
|
+
# be gotten rid of eventually.
|
210
|
+
|
211
|
+
def to_zotero(format)
|
212
|
+
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. ")
|
213
|
+
"<span class=\"Z3988\" title=\"#{export_as_openurl_kev(format)}\"></span>"
|
214
|
+
end
|
215
|
+
|
216
|
+
def to_apa
|
217
|
+
warn("[DEPRECATION] Call document.export_as_apa_citation instead.")
|
218
|
+
export_as_apa_citation
|
219
|
+
end
|
220
|
+
|
221
|
+
def to_mla
|
222
|
+
warn("[DEPRECATION] Call document.export_as_mla_citation instead.")
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
|
227
|
+
protected
|
228
|
+
|
229
|
+
# Main method for defining chicago style citation. If we don't end up converting to using a citation formatting service
|
230
|
+
# we should make this receive a semantic document and not MARC so we can use this with other formats.
|
231
|
+
def chicago_citation(marc)
|
232
|
+
authors = get_all_authors(marc)
|
233
|
+
author_text = ""
|
234
|
+
unless authors[:primary_authors].blank?
|
235
|
+
if authors[:primary_authors].length > 10
|
236
|
+
authors[:primary_authors].each_with_index do |author,index|
|
237
|
+
if index < 7
|
238
|
+
if index == 0
|
239
|
+
author_text << "#{author}"
|
240
|
+
if author.ends_with?(",")
|
241
|
+
author_text << " "
|
242
|
+
else
|
243
|
+
author_text << ", "
|
244
|
+
end
|
245
|
+
else
|
246
|
+
author_text << "#{name_reverse(author)}, "
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
author_text << " et al."
|
251
|
+
elsif authors[:primary_authors].length > 1
|
252
|
+
authors[:primary_authors].each_with_index do |author,index|
|
253
|
+
if index == 0
|
254
|
+
author_text << "#{author}"
|
255
|
+
if author.ends_with?(",")
|
256
|
+
author_text << " "
|
257
|
+
else
|
258
|
+
author_text << ", "
|
259
|
+
end
|
260
|
+
elsif index + 1 == authors[:primary_authors].length
|
261
|
+
author_text << "and #{name_reverse(author)}."
|
262
|
+
else
|
263
|
+
author_text << "#{name_reverse(author)}, "
|
264
|
+
end
|
265
|
+
end
|
266
|
+
else
|
267
|
+
author_text << authors[:primary_authors].first
|
268
|
+
end
|
269
|
+
else
|
270
|
+
temp_authors = []
|
271
|
+
authors[:translators].each do |translator|
|
272
|
+
temp_authors << [translator, "trans."]
|
273
|
+
end
|
274
|
+
authors[:editors].each do |editor|
|
275
|
+
temp_authors << [editor, "ed."]
|
276
|
+
end
|
277
|
+
authors[:compilers].each do |compiler|
|
278
|
+
temp_authors << [compiler, "comp."]
|
279
|
+
end
|
280
|
+
|
281
|
+
unless temp_authors.blank?
|
282
|
+
if temp_authors.length > 10
|
283
|
+
temp_authors.each_with_index do |author,index|
|
284
|
+
if index < 7
|
285
|
+
author_text << "#{author.first} #{author.last} "
|
286
|
+
end
|
287
|
+
end
|
288
|
+
author_text << " et al."
|
289
|
+
elsif temp_authors.length > 1
|
290
|
+
temp_authors.each_with_index do |author,index|
|
291
|
+
if index == 0
|
292
|
+
author_text << "#{author.first} #{author.last}, "
|
293
|
+
elsif index + 1 == temp_authors.length
|
294
|
+
author_text << "and #{name_reverse(author.first)} #{author.last}"
|
295
|
+
else
|
296
|
+
author_text << "#{name_reverse(author.first)} #{author.last}, "
|
297
|
+
end
|
298
|
+
end
|
299
|
+
else
|
300
|
+
author_text << "#{temp_authors.first.first} #{temp_authors.first.last}"
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
title = ""
|
305
|
+
additional_title = ""
|
306
|
+
section_title = ""
|
307
|
+
if marc["245"] and (marc["245"]["a"] or marc["245"]["b"])
|
308
|
+
title << citation_title(clean_end_punctuation(marc["245"]["a"]).strip) if marc["245"]["a"]
|
309
|
+
title << ": #{citation_title(clean_end_punctuation(marc["245"]["b"]).strip)}" if marc["245"]["b"]
|
310
|
+
end
|
311
|
+
if marc["245"] and (marc["245"]["n"] or marc["245"]["p"])
|
312
|
+
section_title << citation_title(clean_end_punctuation(marc["245"]["n"])) if marc["245"]["n"]
|
313
|
+
if marc["245"]["p"]
|
314
|
+
section_title << ", <i>#{citation_title(clean_end_punctuation(marc["245"]["p"]))}.</i>"
|
315
|
+
elsif marc["245"]["n"]
|
316
|
+
section_title << "."
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
if !authors[:primary_authors].blank? and (!authors[:translators].blank? or !authors[:editors].blank? or !authors[:compilers].blank?)
|
321
|
+
additional_title << "Translated by #{authors[:translators].collect{|name| name_reverse(name)}.join(" and ")}. " unless authors[:translators].blank?
|
322
|
+
additional_title << "Edited by #{authors[:editors].collect{|name| name_reverse(name)}.join(" and ")}. " unless authors[:editors].blank?
|
323
|
+
additional_title << "Compiled by #{authors[:compilers].collect{|name| name_reverse(name)}.join(" and ")}. " unless authors[:compilers].blank?
|
324
|
+
end
|
325
|
+
|
326
|
+
edition = ""
|
327
|
+
edition << setup_edition(marc) unless setup_edition(marc).nil?
|
328
|
+
|
329
|
+
pub_info = ""
|
330
|
+
if marc["260"] and (marc["260"]["a"] or marc["260"]["b"])
|
331
|
+
pub_info << clean_end_punctuation(marc["260"]["a"]).strip if marc["260"]["a"]
|
332
|
+
pub_info << ": #{clean_end_punctuation(marc["260"]["b"]).strip}" if marc["260"]["b"]
|
333
|
+
pub_info << ", #{setup_pub_date(marc)}" if marc["260"]["c"]
|
334
|
+
elsif marc["502"] and marc["502"]["a"] # MARC 502 is the Dissertation Note. This holds the correct pub info for these types of records.
|
335
|
+
pub_info << marc["502"]["a"]
|
336
|
+
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
|
337
|
+
pub_info << "#{marc["502"]["b"]}, #{marc["502"]["c"]}, #{clean_end_punctuation(marc["502"]["d"])}"
|
338
|
+
end
|
339
|
+
|
340
|
+
citation = ""
|
341
|
+
citation << "#{author_text} " unless author_text.blank?
|
342
|
+
citation << "<i>#{title}.</i> " unless title.blank?
|
343
|
+
citation << "#{section_title} " unless section_title.blank?
|
344
|
+
citation << "#{additional_title} " unless additional_title.blank?
|
345
|
+
citation << "#{edition} " unless edition.blank?
|
346
|
+
citation << "#{pub_info}." unless pub_info.blank?
|
347
|
+
citation
|
348
|
+
end
|
349
|
+
|
350
|
+
|
351
|
+
|
352
|
+
def mla_citation(record)
|
353
|
+
text = ''
|
354
|
+
authors_final = []
|
355
|
+
|
356
|
+
#setup formatted author list
|
357
|
+
authors = get_author_list(record)
|
358
|
+
|
359
|
+
if authors.length < 4
|
360
|
+
authors.each do |l|
|
361
|
+
if l == authors.first #first
|
362
|
+
authors_final.push(l)
|
363
|
+
elsif l == authors.last #last
|
364
|
+
authors_final.push(", and " + name_reverse(l) + ".")
|
365
|
+
else #all others
|
366
|
+
authors_final.push(", " + name_reverse(l))
|
367
|
+
end
|
368
|
+
end
|
369
|
+
text += authors_final.join
|
370
|
+
unless text.blank?
|
371
|
+
if text[-1,1] != "."
|
372
|
+
text += ". "
|
373
|
+
else
|
374
|
+
text += " "
|
375
|
+
end
|
376
|
+
end
|
377
|
+
else
|
378
|
+
text += authors.first + ", et al. "
|
379
|
+
end
|
380
|
+
# setup title
|
381
|
+
title = setup_title_info(record)
|
382
|
+
if !title.nil?
|
383
|
+
text += "<i>" + mla_citation_title(title) + "</i> "
|
384
|
+
end
|
385
|
+
|
386
|
+
# Edition
|
387
|
+
edition_data = setup_edition(record)
|
388
|
+
text += edition_data + " " unless edition_data.nil?
|
389
|
+
|
390
|
+
# Publication
|
391
|
+
text += setup_pub_info(record) + ", " unless setup_pub_info(record).nil?
|
392
|
+
|
393
|
+
# Get Pub Date
|
394
|
+
text += setup_pub_date(record) unless setup_pub_date(record).nil?
|
395
|
+
if text[-1,1] != "."
|
396
|
+
text += "." unless text.nil? or text.blank?
|
397
|
+
end
|
398
|
+
text
|
399
|
+
end
|
400
|
+
|
401
|
+
def apa_citation(record)
|
402
|
+
text = ''
|
403
|
+
authors_list = []
|
404
|
+
authors_list_final = []
|
405
|
+
|
406
|
+
#setup formatted author list
|
407
|
+
authors = get_author_list(record)
|
408
|
+
authors.each do |l|
|
409
|
+
authors_list.push(abbreviate_name(l)) unless l.blank?
|
410
|
+
end
|
411
|
+
authors_list.each do |l|
|
412
|
+
if l == authors_list.first #first
|
413
|
+
authors_list_final.push(l.strip)
|
414
|
+
elsif l == authors_list.last #last
|
415
|
+
authors_list_final.push(", & " + l.strip)
|
416
|
+
else #all others
|
417
|
+
authors_list_final.push(", " + l.strip)
|
418
|
+
end
|
419
|
+
end
|
420
|
+
text += authors_list_final.join
|
421
|
+
unless text.blank?
|
422
|
+
if text[-1,1] != "."
|
423
|
+
text += ". "
|
424
|
+
else
|
425
|
+
text += " "
|
426
|
+
end
|
427
|
+
end
|
428
|
+
# Get Pub Date
|
429
|
+
text += "(" + setup_pub_date(record) + "). " unless setup_pub_date(record).nil?
|
430
|
+
|
431
|
+
# setup title info
|
432
|
+
title = setup_title_info(record)
|
433
|
+
text += "<i>" + title + "</i> " unless title.nil?
|
434
|
+
|
435
|
+
# Edition
|
436
|
+
edition_data = setup_edition(record)
|
437
|
+
text += edition_data + " " unless edition_data.nil?
|
438
|
+
|
439
|
+
# Publisher info
|
440
|
+
text += setup_pub_info(record) unless setup_pub_info(record).nil?
|
441
|
+
unless text.blank?
|
442
|
+
if text[-1,1] != "."
|
443
|
+
text += "."
|
444
|
+
end
|
445
|
+
end
|
446
|
+
text
|
447
|
+
end
|
448
|
+
def setup_pub_date(record)
|
449
|
+
if !record.find{|f| f.tag == '260'}.nil?
|
450
|
+
pub_date = record.find{|f| f.tag == '260'}
|
451
|
+
if pub_date.find{|s| s.code == 'c'}
|
452
|
+
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?
|
453
|
+
end
|
454
|
+
return nil if date_value.nil?
|
455
|
+
end
|
456
|
+
clean_end_punctuation(date_value) if date_value
|
457
|
+
end
|
458
|
+
def setup_pub_info(record)
|
459
|
+
text = ''
|
460
|
+
pub_info_field = record.find{|f| f.tag == '260'}
|
461
|
+
if !pub_info_field.nil?
|
462
|
+
a_pub_info = pub_info_field.find{|s| s.code == 'a'}
|
463
|
+
b_pub_info = pub_info_field.find{|s| s.code == 'b'}
|
464
|
+
a_pub_info = clean_end_punctuation(a_pub_info.value.strip) unless a_pub_info.nil?
|
465
|
+
b_pub_info = b_pub_info.value.strip unless b_pub_info.nil?
|
466
|
+
text += a_pub_info.strip unless a_pub_info.nil?
|
467
|
+
if !a_pub_info.nil? and !b_pub_info.nil?
|
468
|
+
text += ": "
|
469
|
+
end
|
470
|
+
text += b_pub_info.strip unless b_pub_info.nil?
|
471
|
+
end
|
472
|
+
return nil if text.strip.blank?
|
473
|
+
clean_end_punctuation(text.strip)
|
474
|
+
end
|
475
|
+
|
476
|
+
def mla_citation_title(text)
|
477
|
+
no_upcase = ["a","an","and","but","by","for","it","of","the","to","with"]
|
478
|
+
new_text = []
|
479
|
+
word_parts = text.split(" ")
|
480
|
+
word_parts.each do |w|
|
481
|
+
if !no_upcase.include? w
|
482
|
+
new_text.push(w.capitalize)
|
483
|
+
else
|
484
|
+
new_text.push(w)
|
485
|
+
end
|
486
|
+
end
|
487
|
+
new_text.join(" ")
|
488
|
+
end
|
489
|
+
|
490
|
+
# This will replace the mla_citation_title method with a better understanding of how MLA and Chicago citation titles are formatted.
|
491
|
+
# This method will take in a string and capitalize all of the non-prepositions.
|
492
|
+
def citation_title(title_text)
|
493
|
+
prepositions = ["a","about","across","an","and","before","but","by","for","it","of","the","to","with","without"]
|
494
|
+
new_text = []
|
495
|
+
title_text.split(" ").each_with_index do |word,index|
|
496
|
+
if (index == 0 and word != word.upcase) or (word.length > 1 and word != word.upcase and !prepositions.include?(word))
|
497
|
+
# the split("-") will handle the capitalization of hyphenated words
|
498
|
+
new_text << word.split("-").map!{|w| w.capitalize }.join("-")
|
499
|
+
else
|
500
|
+
new_text << word
|
501
|
+
end
|
502
|
+
end
|
503
|
+
new_text.join(" ")
|
504
|
+
end
|
505
|
+
|
506
|
+
def setup_title_info(record)
|
507
|
+
text = ''
|
508
|
+
title_info_field = record.find{|f| f.tag == '245'}
|
509
|
+
if !title_info_field.nil?
|
510
|
+
a_title_info = title_info_field.find{|s| s.code == 'a'}
|
511
|
+
b_title_info = title_info_field.find{|s| s.code == 'b'}
|
512
|
+
a_title_info = clean_end_punctuation(a_title_info.value.strip) unless a_title_info.nil?
|
513
|
+
b_title_info = clean_end_punctuation(b_title_info.value.strip) unless b_title_info.nil?
|
514
|
+
text += a_title_info unless a_title_info.nil?
|
515
|
+
if !a_title_info.nil? and !b_title_info.nil?
|
516
|
+
text += ": "
|
517
|
+
end
|
518
|
+
text += b_title_info unless b_title_info.nil?
|
519
|
+
end
|
520
|
+
|
521
|
+
return nil if text.strip.blank?
|
522
|
+
clean_end_punctuation(text.strip) + "."
|
523
|
+
|
524
|
+
end
|
525
|
+
|
526
|
+
def clean_end_punctuation(text)
|
527
|
+
if [".",",",":",";","/"].include? text[-1,1]
|
528
|
+
return text[0,text.length-1]
|
529
|
+
end
|
530
|
+
text
|
531
|
+
end
|
532
|
+
|
533
|
+
def setup_edition(record)
|
534
|
+
edition_field = record.find{|f| f.tag == '250'}
|
535
|
+
edition_code = edition_field.find{|s| s.code == 'a'} unless edition_field.nil?
|
536
|
+
edition_data = edition_code.value unless edition_code.nil?
|
537
|
+
if edition_data.nil? or edition_data == '1st ed.'
|
538
|
+
return nil
|
539
|
+
else
|
540
|
+
return edition_data
|
541
|
+
end
|
542
|
+
end
|
543
|
+
|
544
|
+
def get_author_list(record)
|
545
|
+
author_list = []
|
546
|
+
authors_primary = record.find{|f| f.tag == '100'}
|
547
|
+
author_primary = authors_primary.find{|s| s.code == 'a'}.value unless authors_primary.nil? rescue ''
|
548
|
+
author_list.push(clean_end_punctuation(author_primary)) unless author_primary.nil?
|
549
|
+
authors_secondary = record.find_all{|f| ('700') === f.tag}
|
550
|
+
if !authors_secondary.nil?
|
551
|
+
authors_secondary.each do |l|
|
552
|
+
author_list.push(clean_end_punctuation(l.find{|s| s.code == 'a'}.value)) unless l.find{|s| s.code == 'a'}.value.nil?
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
author_list.uniq!
|
557
|
+
author_list
|
558
|
+
end
|
559
|
+
|
560
|
+
# 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
|
561
|
+
def get_all_authors(record)
|
562
|
+
translator_code = "trl"; editor_code = "edt"; compiler_code = "com"
|
563
|
+
primary_authors = []; translators = []; editors = []; compilers = []
|
564
|
+
record.find_all{|f| f.tag === "100" }.each do |field|
|
565
|
+
primary_authors << field["a"] if field["a"]
|
566
|
+
end
|
567
|
+
record.find_all{|f| f.tag === "700" }.each do |field|
|
568
|
+
if field["a"]
|
569
|
+
relators = []
|
570
|
+
relators << clean_end_punctuation(field["e"]) if field["e"]
|
571
|
+
relators << clean_end_punctuation(field["4"]) if field["4"]
|
572
|
+
if relators.include?(translator_code)
|
573
|
+
translators << field["a"]
|
574
|
+
elsif relators.include?(editor_code)
|
575
|
+
editors << field["a"]
|
576
|
+
elsif relators.include?(compiler_code)
|
577
|
+
compilers << field["a"]
|
578
|
+
else
|
579
|
+
primary_authors << field["a"]
|
580
|
+
end
|
581
|
+
end
|
582
|
+
end
|
583
|
+
{:primary_authors => primary_authors, :translators => translators, :editors => editors, :compilers => compilers}
|
584
|
+
end
|
585
|
+
|
586
|
+
def abbreviate_name(name)
|
587
|
+
name_parts = name.split(", ")
|
588
|
+
first_name_parts = name_parts.last.split(" ")
|
589
|
+
temp_name = name_parts.first + ", " + first_name_parts.first[0,1] + "."
|
590
|
+
first_name_parts.shift
|
591
|
+
temp_name += " " + first_name_parts.join(" ") unless first_name_parts.empty?
|
592
|
+
temp_name
|
593
|
+
end
|
594
|
+
|
595
|
+
def name_reverse(name)
|
596
|
+
name = clean_end_punctuation(name)
|
597
|
+
return name unless name =~ /,/
|
598
|
+
temp_name = name.split(", ")
|
599
|
+
return temp_name.last + " " + temp_name.first
|
600
|
+
end
|
601
|
+
|
602
|
+
end
|
data/lib/blacklight_marc.rb
CHANGED
@@ -5,5 +5,10 @@ module BlacklightMarc
|
|
5
5
|
rake_tasks do
|
6
6
|
load "railties/solr_marc.rake"
|
7
7
|
end
|
8
|
+
|
9
|
+
initializer "blacklight MARC" do
|
10
|
+
Blacklight::Solr::Document.autoload :Marc, 'blacklight/solr/document/marc'
|
11
|
+
Blacklight::Solr::Document.autoload :MarcExport, 'blacklight/solr/document/marc_export'
|
12
|
+
end
|
8
13
|
end
|
9
14
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blacklight_marc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Coyne
|
@@ -58,6 +58,26 @@ dependencies:
|
|
58
58
|
- - <
|
59
59
|
- !ruby/object:Gem::Version
|
60
60
|
version: '5'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: marc
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 0.4.3
|
68
|
+
- - <
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '1.1'
|
71
|
+
type: :runtime
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 0.4.3
|
78
|
+
- - <
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '1.1'
|
61
81
|
description: SolrMarc support for Blacklight
|
62
82
|
email:
|
63
83
|
- justin@curationexperts.com
|
@@ -72,6 +92,8 @@ files:
|
|
72
92
|
- Rakefile
|
73
93
|
- blacklight_marc.gemspec
|
74
94
|
- lib/SolrMarc.jar
|
95
|
+
- lib/blacklight/solr/document/marc.rb
|
96
|
+
- lib/blacklight/solr/document/marc_export.rb
|
75
97
|
- lib/blacklight_marc.rb
|
76
98
|
- lib/blacklight_marc/version.rb
|
77
99
|
- lib/generators/blacklight_marc/marc_generator.rb
|