bibtex-ruby 3.0.1 → 3.1.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.
Potentially problematic release.
This version of bibtex-ruby might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Gemfile +29 -17
- data/History.txt +5 -0
- data/Manifest +8 -0
- data/README.md +33 -31
- data/bibtex-ruby.gemspec +2 -3
- data/features/issues/non_ascii_default_keys.feature +3 -3
- data/features/support/env.rb +12 -10
- data/lib/bibtex.rb +14 -4
- data/lib/bibtex/bibliography.rb +10 -12
- data/lib/bibtex/bibliography/rdf_converter.rb +27 -0
- data/lib/bibtex/compatibility.rb +1 -1
- data/lib/bibtex/elements.rb +2 -2
- data/lib/bibtex/entry.rb +9 -233
- data/lib/bibtex/entry/bibtexml_converter.rb +44 -0
- data/lib/bibtex/entry/citeproc_converter.rb +110 -0
- data/lib/bibtex/entry/rdf_converter.rb +543 -0
- data/lib/bibtex/lexer.rb +1 -1
- data/lib/bibtex/names.rb +2 -2
- data/lib/bibtex/value.rb +1 -1
- data/lib/bibtex/version.rb +7 -7
- data/test/bibtex/entry/test_rdf_converter.rb +317 -0
- data/test/bibtex/test_bibliography.rb +1 -1
- data/test/bibtex/test_entry.rb +2 -1
- data/test/bibtex/test_names.rb +1 -1
- data/test/bibtex/test_utilities.rb +8 -8
- data/test/helper.rb +16 -8
- data/test/test_bibtex.rb +1 -1
- data/test/test_export.rb +5 -5
- metadata +20 -28
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
|
3
|
+
class BibTeX::Entry::BibTeXMLConverter
|
4
|
+
def self.convert(bibtex, options = {})
|
5
|
+
new(bibtex, options).convert!
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(bibtex, options = {})
|
9
|
+
@bibtex = bibtex
|
10
|
+
@options = options
|
11
|
+
end
|
12
|
+
|
13
|
+
def convert!
|
14
|
+
xml = REXML::Element.new('bibtex:entry')
|
15
|
+
xml.attributes['id'] = bibtex.key
|
16
|
+
|
17
|
+
fields
|
18
|
+
|
19
|
+
xml.add_element(entry)
|
20
|
+
xml
|
21
|
+
end
|
22
|
+
|
23
|
+
def fields
|
24
|
+
bibtex.fields.each do |key, value|
|
25
|
+
field = REXML::Element.new("bibtex:#{key}")
|
26
|
+
|
27
|
+
if options[:extended] && value.name?
|
28
|
+
value.each { |n| entry.add_element(n.to_xml) }
|
29
|
+
else
|
30
|
+
field.text = value.to_s(options)
|
31
|
+
end
|
32
|
+
|
33
|
+
entry.add_element(field)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_reader :bibtex, :options
|
40
|
+
|
41
|
+
def entry
|
42
|
+
@entry ||= REXML::Element.new("bibtex:#{bibtex.type}")
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
class BibTeX::Entry::CiteProcConverter
|
2
|
+
CSL_FILTER = Hash.new { |h, k| k }.merge(Hash[*%w{
|
3
|
+
date issued
|
4
|
+
isbn ISBN
|
5
|
+
booktitle container-title
|
6
|
+
journal container-title
|
7
|
+
series collection-title
|
8
|
+
address publisher-place
|
9
|
+
pages page
|
10
|
+
number issue
|
11
|
+
url URL
|
12
|
+
doi DOI
|
13
|
+
year issued
|
14
|
+
type genre
|
15
|
+
}.map(&:intern)]).freeze
|
16
|
+
|
17
|
+
CSL_FIELDS = %w{
|
18
|
+
abstract annote archive archive_location archive-place
|
19
|
+
authority call-number chapter-number citation-label citation-number
|
20
|
+
collection-title container-title DOI edition event event-place
|
21
|
+
first-reference-note-number genre ISBN issue jurisdiction keyword locator
|
22
|
+
medium note number number-of-pages number-of-volumes original-publisher
|
23
|
+
original-publisher-place original-title page page-first publisher
|
24
|
+
publisher-place references section status title URL version volume
|
25
|
+
year-suffix accessed container event-date issued original-date
|
26
|
+
author editor translator recipient interviewer publisher composer
|
27
|
+
original-publisher original-author container-author collection-editor
|
28
|
+
}.map(&:intern).freeze
|
29
|
+
|
30
|
+
CSL_TYPES = Hash.new { |h, k| k }.merge(Hash[*%w{
|
31
|
+
booklet pamphlet
|
32
|
+
conference paper-conference
|
33
|
+
inbook chapter
|
34
|
+
incollection chapter
|
35
|
+
inproceedings paper-conference
|
36
|
+
manual book
|
37
|
+
mastersthesis thesis
|
38
|
+
misc article
|
39
|
+
phdthesis thesis
|
40
|
+
proceedings paper-conference
|
41
|
+
techreport report
|
42
|
+
unpublished manuscript
|
43
|
+
article article-journal
|
44
|
+
}.map(&:intern)]).freeze
|
45
|
+
|
46
|
+
def self.convert(bibtex, options = {})
|
47
|
+
new(bibtex, options).convert!
|
48
|
+
end
|
49
|
+
|
50
|
+
def initialize(bibtex, options = {})
|
51
|
+
@bibtex = bibtex
|
52
|
+
@options = { quotes: [] }.merge(options)
|
53
|
+
end
|
54
|
+
|
55
|
+
def convert!
|
56
|
+
bibtex.parse_names
|
57
|
+
bibtex.parse_month
|
58
|
+
|
59
|
+
bibtex.each_pair do |key, value|
|
60
|
+
hash[CSL_FILTER[key].to_s] = value.to_citeproc(options) unless BibTeX::Entry::DATE_FIELDS.include?(key)
|
61
|
+
end
|
62
|
+
|
63
|
+
methods = self.class.instance_methods(false) - [:convert!]
|
64
|
+
methods.each { |m| send(m) }
|
65
|
+
|
66
|
+
hash
|
67
|
+
end
|
68
|
+
|
69
|
+
def date
|
70
|
+
return unless bibtex.field?(:year)
|
71
|
+
|
72
|
+
case bibtex[:year].to_s
|
73
|
+
when /^\d+$/
|
74
|
+
parts = [bibtex[:year].to_s]
|
75
|
+
|
76
|
+
if bibtex.field?(:month)
|
77
|
+
parts.push BibTeX::Entry::MONTHS.find_index(bibtex[:month].to_s.intern)
|
78
|
+
parts[1] = parts[1] + 1 unless parts[1].nil?
|
79
|
+
end
|
80
|
+
|
81
|
+
hash['issued'] = { 'date-parts' => [parts.compact.map(&:to_i)] }
|
82
|
+
else
|
83
|
+
hash['issued'] = { 'literal' => bibtex[:year].to_s }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def key
|
88
|
+
hash['id'] = bibtex.key.to_s
|
89
|
+
end
|
90
|
+
|
91
|
+
def type
|
92
|
+
hash['type'] = CSL_TYPES[bibtex.type].to_s
|
93
|
+
|
94
|
+
return if hash.key?('genre')
|
95
|
+
case bibtex.type
|
96
|
+
when :mastersthesis
|
97
|
+
hash['genre'] = "Master's thesis"
|
98
|
+
when :phdthesis
|
99
|
+
hash['genre'] = 'PhD thesis'
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
attr_reader :bibtex, :options
|
106
|
+
|
107
|
+
def hash
|
108
|
+
@hash ||= {}
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,543 @@
|
|
1
|
+
require 'uri/common'
|
2
|
+
|
3
|
+
class BibTeX::Entry::RDFConverter
|
4
|
+
DEFAULT_REMOVE_FROM_FALLBACK = %w(
|
5
|
+
date-modified
|
6
|
+
bdsk-file-1
|
7
|
+
bdsk-file-2
|
8
|
+
bdsk-file-3
|
9
|
+
).map(&:intern).freeze
|
10
|
+
|
11
|
+
BIBO_TYPES = Hash[*%w{
|
12
|
+
article Article
|
13
|
+
book Book
|
14
|
+
booklet Book
|
15
|
+
collection Collection
|
16
|
+
conference AcademicArticle
|
17
|
+
inbook BookSection
|
18
|
+
incollection BookSection
|
19
|
+
inproceedings AcademicArticle
|
20
|
+
journal Journal
|
21
|
+
manual Manual
|
22
|
+
mastersthesis Thesis
|
23
|
+
online Website
|
24
|
+
patent Patent
|
25
|
+
periodical Periodical
|
26
|
+
phdthesis Thesis
|
27
|
+
proceedings Proceedings
|
28
|
+
standard Standard
|
29
|
+
techreport Report
|
30
|
+
thesis Thesis
|
31
|
+
unpublished Manuscript
|
32
|
+
}.map(&:intern)].freeze
|
33
|
+
|
34
|
+
# converts a BibTeX entry to RDF
|
35
|
+
# @return [RDF::Graph] the RDF graph of this entry
|
36
|
+
def self.convert(bibtex, graph = RDF::Graph.new, agent = {})
|
37
|
+
new(bibtex, graph, agent).convert!
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param [BibTeX::Entry] the entry to convert
|
41
|
+
def initialize(bibtex, graph = RDF::Graph.new, agent = {})
|
42
|
+
@bibtex = bibtex
|
43
|
+
@graph = graph
|
44
|
+
@agent = agent
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [RDF::Graph] the RDF graph of this entry
|
48
|
+
def convert!
|
49
|
+
bibtex.parse_names
|
50
|
+
bibtex.parse_month
|
51
|
+
|
52
|
+
unless uri_in_graph?(entry)
|
53
|
+
methods = self.class.instance_methods(false) - [:convert!]
|
54
|
+
methods.each { |m| send(m) }
|
55
|
+
run_fallback
|
56
|
+
end
|
57
|
+
|
58
|
+
graph
|
59
|
+
end
|
60
|
+
|
61
|
+
def abstract
|
62
|
+
return unless bibtex.field?(:abstract)
|
63
|
+
remove_from_fallback(:abstract)
|
64
|
+
|
65
|
+
graph << [entry, RDF::DC.abstract, bibtex[:abstract].to_s]
|
66
|
+
graph << [entry, bibo[:abstract], bibtex[:abstract].to_s]
|
67
|
+
end
|
68
|
+
|
69
|
+
def author
|
70
|
+
return unless bibtex.field?(:author)
|
71
|
+
remove_from_fallback(:author)
|
72
|
+
|
73
|
+
seq = RDF::Node.new
|
74
|
+
|
75
|
+
graph << [seq, RDF.type, RDF[:Seq]]
|
76
|
+
graph << [entry, bibo[:authorList], seq]
|
77
|
+
|
78
|
+
bibtex[:author].each do |name|
|
79
|
+
node = agent(name) { create_agent(name, :Person) }
|
80
|
+
|
81
|
+
graph << [entry, RDF::DC.creator, node]
|
82
|
+
graph << [seq, RDF.li, node]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def booktitle
|
87
|
+
return unless bibtex.field?(:booktitle)
|
88
|
+
remove_from_fallback(:booktitle)
|
89
|
+
return if bibtex.has_parent? &&
|
90
|
+
bibtex.parent[:title] == bibtex[:booktitle]
|
91
|
+
return if bibtex.has_parent? &&
|
92
|
+
bibtex.parent[:booktitle] == bibtex[:booktitle]
|
93
|
+
return if bibtex.has_parent? &&
|
94
|
+
bibtex.parent[:isbn] == bibtex[:isbn]
|
95
|
+
return if bibtex[:title] == bibtex[:booktitle]
|
96
|
+
|
97
|
+
series = RDF::Node.new
|
98
|
+
graph << [series, RDF.type, bibo[:Document]]
|
99
|
+
graph << [series, RDF::DC.title, bibtex[:booktitle].to_s]
|
100
|
+
|
101
|
+
graph << [entry, RDF::DC.isPartOf, series]
|
102
|
+
end
|
103
|
+
|
104
|
+
def chapter
|
105
|
+
return unless bibtex.field?(:chapter)
|
106
|
+
remove_from_fallback(:chapter)
|
107
|
+
|
108
|
+
graph << [entry, bibo[:chapter], bibtex[:chapter].to_s]
|
109
|
+
end
|
110
|
+
|
111
|
+
def children
|
112
|
+
return unless bibtex.has_children?
|
113
|
+
|
114
|
+
bibtex.children.each do |child|
|
115
|
+
child_id = RDF::URI.new(child.identifier)
|
116
|
+
BibTeX::Entry::RDFConverter.new(child, graph, agent).convert! unless uri_in_graph?(child_id)
|
117
|
+
graph << [entry, RDF::DC.hasPart, child_id]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def copyright
|
122
|
+
return unless bibtex.field?(:copyright)
|
123
|
+
remove_from_fallback(:copyright)
|
124
|
+
|
125
|
+
graph << [entry, RDF::DC.rightsHolder, bibtex[:copyright].to_s]
|
126
|
+
end
|
127
|
+
|
128
|
+
def date_added
|
129
|
+
return unless bibtex.field?(:'date-added')
|
130
|
+
remove_from_fallback(:'date-added')
|
131
|
+
|
132
|
+
graph << [entry, RDF::DC.created, bibtex[:'date-added'].to_s]
|
133
|
+
end
|
134
|
+
|
135
|
+
def doi
|
136
|
+
return unless bibtex.field?(:doi)
|
137
|
+
remove_from_fallback(:doi)
|
138
|
+
|
139
|
+
graph << [entry, bibo[:doi], bibtex[:doi].to_s]
|
140
|
+
graph << [entry, RDF::DC.identifier, "doi:#{bibtex[:doi].to_s}"]
|
141
|
+
end
|
142
|
+
|
143
|
+
def edition
|
144
|
+
return unless bibtex.field?(:edition)
|
145
|
+
remove_from_fallback(:edition)
|
146
|
+
|
147
|
+
graph << [entry, bibo[:edition], bibtex[:edition].to_s]
|
148
|
+
end
|
149
|
+
|
150
|
+
def editor
|
151
|
+
return unless bibtex.field?(:editor)
|
152
|
+
remove_from_fallback(:editor)
|
153
|
+
|
154
|
+
seq = RDF::Node.new
|
155
|
+
|
156
|
+
graph << [seq, RDF.type, RDF[:Seq]]
|
157
|
+
graph << [entry, bibo[:editorList], seq]
|
158
|
+
|
159
|
+
bibtex[:editor].each do |name|
|
160
|
+
node = agent(name) { create_agent(name, :Person) }
|
161
|
+
|
162
|
+
graph << [entry, bibo.name, node]
|
163
|
+
graph << [seq, RDF.li, node]
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def fallback_default
|
168
|
+
remove_from_fallback(*DEFAULT_REMOVE_FROM_FALLBACK)
|
169
|
+
end
|
170
|
+
|
171
|
+
def howpublished
|
172
|
+
return unless bibtex.field?(:howpublished)
|
173
|
+
return unless bibtex[:howpublished] =~ /^#{URI.regexp}$/
|
174
|
+
remove_from_fallback(:howpublished)
|
175
|
+
|
176
|
+
graph << [entry, RDF::DC.URI, bibtex[:howpublished].to_s]
|
177
|
+
graph << [entry, bibo[:uri], bibtex[:howpublished].to_s]
|
178
|
+
end
|
179
|
+
|
180
|
+
def institution
|
181
|
+
return unless bibtex.field?(:institution)
|
182
|
+
remove_from_fallback(:institution)
|
183
|
+
|
184
|
+
org = agent(bibtex[:institution].to_s) { create_agent(bibtex[:institution].to_s, :Organization) }
|
185
|
+
|
186
|
+
graph << [entry, RDF::DC.contributor, org]
|
187
|
+
end
|
188
|
+
|
189
|
+
def isbn
|
190
|
+
return unless bibtex.field?(:isbn)
|
191
|
+
remove_from_fallback(:isbn)
|
192
|
+
|
193
|
+
graph << [entry, bibo[:isbn], bibtex[:isbn].to_s]
|
194
|
+
|
195
|
+
if bibtex.contained?
|
196
|
+
graph << [entry, RDF::DC.isPartOf, "urn:isbn:#{bibtex[:isbn].to_s}"]
|
197
|
+
else
|
198
|
+
graph << [entry, RDF::DC.identifier, "urn:isbn:#{bibtex[:isbn].to_s}"]
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def issn
|
203
|
+
return unless bibtex.field?(:issn)
|
204
|
+
remove_from_fallback(:issn)
|
205
|
+
|
206
|
+
graph << [entry, bibo[:issn], bibtex[:issn].to_s]
|
207
|
+
if bibtex.contained?
|
208
|
+
graph << [entry, RDF::DC.isPartOf, "urn:issn:#{bibtex[:issn].to_s}"]
|
209
|
+
else
|
210
|
+
graph << [entry, RDF::DC.identifier, "urn:issn:#{bibtex[:issn].to_s}"]
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def journal_dc_source
|
215
|
+
return unless bibtex.field?(:journal)
|
216
|
+
remove_from_fallback(:journal)
|
217
|
+
|
218
|
+
source = []
|
219
|
+
source << bibtex[:journal].to_s
|
220
|
+
source << "Vol. #{bibtex[:volume].to_s}" if bibtex.field?(:volume)
|
221
|
+
source << "No. #{bibtex[:number].to_s}" if bibtex.field?(:number)
|
222
|
+
pagination = bibtex[:pagination] || 'pp.'
|
223
|
+
source << "#{pagination.to_s} #{bibtex[:pages].to_s}" if bibtex.field?(:pages)
|
224
|
+
graph << [entry, RDF::DC.source, source.join(', ')]
|
225
|
+
end
|
226
|
+
|
227
|
+
def journal_dc_part_of
|
228
|
+
return unless bibtex.field?(:journal)
|
229
|
+
return if bibtex.has_parent? && bibtex.parent[:title] == bibtex[:journal]
|
230
|
+
return if bibtex.has_parent? && bibtex.parent[:issn] == bibtex[:issn]
|
231
|
+
|
232
|
+
journal = RDF::Node.new
|
233
|
+
graph << [journal, RDF.type, bibo[:Journal]]
|
234
|
+
graph << [journal, RDF::DC.title, bibtex[:journal].to_s]
|
235
|
+
|
236
|
+
graph << [entry, RDF::DC.isPartOf, journal]
|
237
|
+
end
|
238
|
+
|
239
|
+
def key
|
240
|
+
graph << [entry, RDF::DC.identifier, "urn:bibtex:#{bibtex.key}"]
|
241
|
+
end
|
242
|
+
|
243
|
+
def keywords
|
244
|
+
return unless bibtex.field?(:keywords)
|
245
|
+
remove_from_fallback(:keywords)
|
246
|
+
|
247
|
+
bibtex[:keywords].to_s.split(/\s*,\s*/).each do |keyword|
|
248
|
+
graph << [entry, RDF::DC.subject, keyword]
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def language
|
253
|
+
return unless bibtex.field?(:language)
|
254
|
+
remove_from_fallback(:language)
|
255
|
+
|
256
|
+
bibtex[:language] = 'german' if bibtex[:language] == 'ngerman'
|
257
|
+
|
258
|
+
graph << [entry, RDF::DC.language, bibtex[:language].to_s]
|
259
|
+
end
|
260
|
+
|
261
|
+
def location
|
262
|
+
return unless bibtex.field?(:location)
|
263
|
+
remove_from_fallback(:location)
|
264
|
+
|
265
|
+
graph << [entry, RDF::DC.Location, bibtex[:location].to_s]
|
266
|
+
if [:proceedings, :inproceedings, :conference].include?(bibtex.type)
|
267
|
+
event = RDF::Vocabulary.new('http://purl.org/NET/c4dm/event.owl')
|
268
|
+
graph << [entry, event[:place], org]
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def lccn
|
273
|
+
return unless bibtex.field?(:lccn)
|
274
|
+
remove_from_fallback(:lccn)
|
275
|
+
|
276
|
+
graph << [entry, bibo[:lccn], bibtex[:lccn].to_s]
|
277
|
+
end
|
278
|
+
|
279
|
+
def note
|
280
|
+
return unless bibtex.field?(:note)
|
281
|
+
remove_from_fallback(:note)
|
282
|
+
|
283
|
+
pub = RDF::Node.new
|
284
|
+
graph << [pub, RDF.type, bibo[:Note]]
|
285
|
+
graph << [pub, bibo[:content], bibtex[:note]]
|
286
|
+
|
287
|
+
graph << [entry, bibo[:annotates], pub]
|
288
|
+
end
|
289
|
+
|
290
|
+
def number
|
291
|
+
return unless bibtex.field?(:number)
|
292
|
+
remove_from_fallback(:number)
|
293
|
+
|
294
|
+
case bibtex.type
|
295
|
+
when :techreport || :manual || :unpublished
|
296
|
+
graph << [entry, bibo[:number], bibtex[:number].to_s]
|
297
|
+
else
|
298
|
+
graph << [entry, bibo[:issue], bibtex[:number].to_s]
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
def organization
|
303
|
+
return unless bibtex.field?(:organization)
|
304
|
+
remove_from_fallback(:organization)
|
305
|
+
|
306
|
+
org = agent(bibtex[:organization].to_s) { create_agent(bibtex[:organization].to_s, :Organization) }
|
307
|
+
|
308
|
+
graph << [entry, RDF::DC.contributor, org]
|
309
|
+
graph << [entry, bibo[:organizer], org] if [:proceedings, :inproceedings, :conference].include?(bibtex.type)
|
310
|
+
end
|
311
|
+
|
312
|
+
def pages
|
313
|
+
return unless bibtex.field?(:pages)
|
314
|
+
remove_from_fallback(:pages)
|
315
|
+
|
316
|
+
if bibtex[:pages].to_s =~ /^\s*(\d+)\s*-+\s*(\d+)\s*$/
|
317
|
+
graph << [entry, bibo[:pageStart], Regexp.last_match[1]]
|
318
|
+
graph << [entry, bibo[:pageEnd], Regexp.last_match[2]]
|
319
|
+
else
|
320
|
+
graph << [entry, bibo[:pages], bibtex[:pages].to_s]
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
def pagetotal
|
325
|
+
return unless bibtex.field?(:pagetotal)
|
326
|
+
remove_from_fallback(:pagetotal)
|
327
|
+
|
328
|
+
graph << [entry, bibo[:numPages], bibtex[:pagetotal].to_s]
|
329
|
+
end
|
330
|
+
|
331
|
+
def parent
|
332
|
+
return unless bibtex.has_parent?
|
333
|
+
remove_from_fallback(:crossref)
|
334
|
+
|
335
|
+
parent_id = RDF::URI.new(bibtex.parent.identifier)
|
336
|
+
BibTeX::Entry::RDFConverter.new(bibtex.parent, graph, agent).convert! unless uri_in_graph?(parent_id)
|
337
|
+
graph << [entry, RDF::DC.isPartOf, parent_id]
|
338
|
+
end
|
339
|
+
|
340
|
+
def publisher
|
341
|
+
return unless bibtex.field?(:publisher) || bibtex.field?(:organization) || bibtex.field?(:school)
|
342
|
+
remove_from_fallback(:publisher, :address)
|
343
|
+
|
344
|
+
org =
|
345
|
+
case
|
346
|
+
when bibtex.field?(:publisher)
|
347
|
+
agent(bibtex[:publisher].to_s) { create_agent(bibtex[:publisher].to_s, :Organization) }
|
348
|
+
when bibtex.field?(:organization)
|
349
|
+
agent(bibtex[:organization].to_s) { create_agent(bibtex[:organization].to_s, :Organization) }
|
350
|
+
when bibtex.field?(:school)
|
351
|
+
agent(bibtex[:school].to_s) { create_agent(bibtex[:school].to_s, :Organization) }
|
352
|
+
end
|
353
|
+
|
354
|
+
if bibtex.field?(:address)
|
355
|
+
address = RDF::Vocabulary.new('http://schemas.talis.com/2005/address/schema#')
|
356
|
+
graph << [org, address[:localityName], bibtex[:address]]
|
357
|
+
end
|
358
|
+
|
359
|
+
graph << [entry, RDF::DC.publisher, org]
|
360
|
+
graph << [entry, bibo[:publisher], org]
|
361
|
+
end
|
362
|
+
|
363
|
+
def school
|
364
|
+
return unless bibtex.field?(:school)
|
365
|
+
remove_from_fallback(:school)
|
366
|
+
|
367
|
+
org = agent(bibtex[:school].to_s) { create_agent(bibtex[:school].to_s, :Organization) }
|
368
|
+
|
369
|
+
graph << [entry, RDF::DC.contributor, org]
|
370
|
+
end
|
371
|
+
|
372
|
+
def series
|
373
|
+
return unless bibtex.field?(:series)
|
374
|
+
remove_from_fallback(:series)
|
375
|
+
return if bibtex.has_parent? && bibtex.parent[:title] == bibtex[:series]
|
376
|
+
return if bibtex.has_parent? && bibtex.parent[:series] == bibtex[:series]
|
377
|
+
return if bibtex.has_parent? && bibtex.parent[:issn] == bibtex[:issn]
|
378
|
+
|
379
|
+
series = RDF::Node.new
|
380
|
+
graph << [series, RDF.type, bibo[:MultiVolumeBook]]
|
381
|
+
graph << [series, RDF::DC.title, bibtex[:series].to_s]
|
382
|
+
|
383
|
+
graph << [entry, RDF::DC.isPartOf, series]
|
384
|
+
end
|
385
|
+
|
386
|
+
def thesis_degree
|
387
|
+
return unless bibo_class == :Thesis
|
388
|
+
|
389
|
+
degree =
|
390
|
+
case bibtex.type
|
391
|
+
# ms = masters degree in science
|
392
|
+
# Only ma and ms available. We simply chose one.
|
393
|
+
when :mastersthesis then bibo['degrees/ms']
|
394
|
+
when :phdthesis then bibo['degrees/phd']
|
395
|
+
end
|
396
|
+
|
397
|
+
degree =
|
398
|
+
case bibtex[:type]
|
399
|
+
when 'mathesis' then bibo['degrees/ma']
|
400
|
+
when 'phdthesis' then bibo['degrees/phd']
|
401
|
+
when /Bachelor['s]{0,2} Thesis/i then "Bachelor's Thesis"
|
402
|
+
when /Diplomarbeit/i then bibo['degrees/ms']
|
403
|
+
when /Magisterarbeit/i then bibo['degrees/ma']
|
404
|
+
else degree
|
405
|
+
end
|
406
|
+
|
407
|
+
graph << [entry, bibo[:degree], degree] unless degree.nil?
|
408
|
+
end
|
409
|
+
|
410
|
+
def title
|
411
|
+
return unless bibtex.field?(:title)
|
412
|
+
remove_from_fallback(:title)
|
413
|
+
|
414
|
+
title = [bibtex[:title].to_s, bibtex[:subtitle].to_s].join(': ')
|
415
|
+
graph << [entry, RDF::DC.title, title]
|
416
|
+
graph << [entry, bibo[:shortTitle], bibtex[:title].to_s] if bibtex.field?(:subtitle)
|
417
|
+
end
|
418
|
+
|
419
|
+
def translator
|
420
|
+
return unless bibtex.field?(:translator)
|
421
|
+
remove_from_fallback(:translator)
|
422
|
+
|
423
|
+
node = agent(bibtex[:translator].to_s) do
|
424
|
+
create_agent(bibtex[:translator].to_s, :Person)
|
425
|
+
end
|
426
|
+
|
427
|
+
graph << [entry, RDF::DC.contributor, node]
|
428
|
+
graph << [entry, bibo[:translator], node]
|
429
|
+
end
|
430
|
+
|
431
|
+
def type
|
432
|
+
graph << [entry, RDF.type, bibo_class]
|
433
|
+
|
434
|
+
case bibtex.type
|
435
|
+
when :proceedings, :journal
|
436
|
+
graph << [entry, RDF::DC.type, 'Collection']
|
437
|
+
else
|
438
|
+
graph << [entry, RDF::DC.type, 'Text']
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
def url
|
443
|
+
return unless bibtex.field?(:url)
|
444
|
+
remove_from_fallback(:url)
|
445
|
+
|
446
|
+
graph << [entry, RDF::DC.URI, bibtex[:url].to_s]
|
447
|
+
graph << [entry, bibo[:uri], bibtex[:url].to_s]
|
448
|
+
end
|
449
|
+
|
450
|
+
def volume
|
451
|
+
return unless bibtex.field?(:volume)
|
452
|
+
remove_from_fallback(:volume)
|
453
|
+
|
454
|
+
graph << [entry, bibo[:volume], bibtex[:volume].to_s]
|
455
|
+
end
|
456
|
+
|
457
|
+
def volumes
|
458
|
+
return unless bibtex.field?(:volumes)
|
459
|
+
remove_from_fallback(:volumes)
|
460
|
+
|
461
|
+
graph << [entry, bibo[:numVolumes], bibtex[:volumes].to_s]
|
462
|
+
end
|
463
|
+
|
464
|
+
def year
|
465
|
+
return unless bibtex.field?(:year)
|
466
|
+
remove_from_fallback(:year, :month)
|
467
|
+
|
468
|
+
year = bibtex[:year].to_s
|
469
|
+
if bibtex.field?(:month)
|
470
|
+
month = BibTeX::Entry::MONTHS.find_index(bibtex[:month].to_s.intern)
|
471
|
+
month += 1 unless month.nil?
|
472
|
+
end
|
473
|
+
date = [year, month].join('-')
|
474
|
+
|
475
|
+
graph << [entry, RDF::DC.issued, date]
|
476
|
+
end
|
477
|
+
|
478
|
+
private
|
479
|
+
|
480
|
+
attr_reader :bibtex, :graph
|
481
|
+
|
482
|
+
def bibo
|
483
|
+
@bibo ||= RDF::Vocabulary.new('http://purl.org/ontology/bibo/')
|
484
|
+
end
|
485
|
+
|
486
|
+
def bibo_class
|
487
|
+
BIBO_TYPES[bibtex[:type]] || BIBO_TYPES[bibtex.type] || :Document
|
488
|
+
end
|
489
|
+
|
490
|
+
def entry
|
491
|
+
@entry ||= RDF::URI.new(bibtex.identifier)
|
492
|
+
end
|
493
|
+
|
494
|
+
def agent(key = nil, &block)
|
495
|
+
if key.nil?
|
496
|
+
@agent
|
497
|
+
else
|
498
|
+
key = key.respond_to?(:to_hash) ? key.to_hash : key
|
499
|
+
@agent[key] ||= yield
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
def create_agent(name, type)
|
504
|
+
node = RDF::Node.new
|
505
|
+
|
506
|
+
graph << [node, RDF.type, RDF::FOAF[type]]
|
507
|
+
graph << [node, RDF::FOAF.name, name.to_s]
|
508
|
+
|
509
|
+
if name.is_a?(BibTeX::Name)
|
510
|
+
[:given, :family, :prefix, :suffix].each do |part|
|
511
|
+
value = name.send(part)
|
512
|
+
graph << [node, bibo["#{part}Name"], value.to_s] unless value.nil?
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
node
|
517
|
+
end
|
518
|
+
|
519
|
+
def uri_in_graph?(uri)
|
520
|
+
solutions = RDF::Query.execute(graph) do
|
521
|
+
pattern [uri, nil, nil]
|
522
|
+
end
|
523
|
+
|
524
|
+
solutions.size > 0
|
525
|
+
end
|
526
|
+
|
527
|
+
def fallback
|
528
|
+
@fallback ||= bibtex.fields.keys
|
529
|
+
end
|
530
|
+
|
531
|
+
def remove_from_fallback(*fields)
|
532
|
+
fields.each { |field| fallback.delete(field) }
|
533
|
+
end
|
534
|
+
|
535
|
+
def run_fallback
|
536
|
+
return if fallback.empty?
|
537
|
+
|
538
|
+
ml = RDF::Vocabulary.new('http://bibtexml.sf.net/')
|
539
|
+
fallback.each do |field|
|
540
|
+
graph << [entry, ml[field], bibtex[field]]
|
541
|
+
end
|
542
|
+
end
|
543
|
+
end
|