bibtex-ruby 1.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.
Potentially problematic release.
This version of bibtex-ruby might be problematic. Click here for more details.
- data.tar.gz.sig +0 -0
- data/History.txt +3 -0
- data/LICENSE +621 -0
- data/Manifest +34 -0
- data/README.rdoc +152 -0
- data/Rakefile +54 -0
- data/bibtex-ruby.gemspec +36 -0
- data/examples/bib2html.rb +28 -0
- data/examples/markdown.bib +39 -0
- data/lib/bibtex.rb +51 -0
- data/lib/bibtex/bibliography.rb +175 -0
- data/lib/bibtex/bibtex.y +129 -0
- data/lib/bibtex/elements.rb +262 -0
- data/lib/bibtex/entry.rb +154 -0
- data/lib/bibtex/error.rb +37 -0
- data/lib/bibtex/lexer.rb +328 -0
- data/lib/bibtex/parser.output +578 -0
- data/lib/bibtex/parser.rb +467 -0
- data/lib/bibtex/string_replacement.rb +43 -0
- data/lib/extensions/core.rb +35 -0
- data/test/bib/00_empty.bib +0 -0
- data/test/bib/01_no_bibtex.bib +9 -0
- data/test/bib/02_string.bib +1 -0
- data/test/bib/03_string.bib +26 -0
- data/test/bib/04_string_replacement.bib +16 -0
- data/test/bib/05_comment.bib +15 -0
- data/test/bib/06_preamble.bib +12 -0
- data/test/bib/07_entry.bib +20 -0
- data/test/bib/08_decoret.bib +83 -0
- data/test/bib/09_errors.bib +67 -0
- data/test/bib/10_bibdesk.bib +47 -0
- data/test/test_bibtex.rb +58 -0
- data/test/test_comment.rb +24 -0
- data/test/test_entry.rb +35 -0
- data/test/test_preamble.rb +24 -0
- data/test/test_string.rb +77 -0
- metadata +155 -0
- metadata.gz.sig +0 -0
data/lib/bibtex/bibtex.y
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
#--
|
2
|
+
# BibTeX-Ruby
|
3
|
+
# Copyright (C) 2010 Sylvester Keil <http://sylvester.keil.or.at>
|
4
|
+
#
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
#++
|
18
|
+
#
|
19
|
+
# A BibTeX grammar for the parser generator +racc+
|
20
|
+
#
|
21
|
+
|
22
|
+
# -*- racc -*-
|
23
|
+
|
24
|
+
class BibTeX::Parser
|
25
|
+
|
26
|
+
token AT COMMA COMMENT CONTENT ERROR EQ LBRACE META_COMMENT
|
27
|
+
NAME NUMBER PREAMBLE RBRACE SHARP STRING STRING_LITERAL
|
28
|
+
|
29
|
+
expect 0
|
30
|
+
|
31
|
+
rule
|
32
|
+
|
33
|
+
bibliography : /* empty */ { result = Bibliography.new }
|
34
|
+
| objects { result = val[0] }
|
35
|
+
|
36
|
+
objects : object { result = Bibliography.new << val[0] }
|
37
|
+
| objects object { result << val[1] }
|
38
|
+
|
39
|
+
object : AT at_object { result = val[1] }
|
40
|
+
| META_COMMENT { result = BibTeX::MetaComment.new(val[0]) }
|
41
|
+
| ERROR { result = BibTeX::Error.new(val[0]) }
|
42
|
+
|
43
|
+
at_object : comment { result = val[0] }
|
44
|
+
| string { result = val[0] }
|
45
|
+
| preamble { result = val[0] }
|
46
|
+
| entry { result = val[0] }
|
47
|
+
|
48
|
+
comment : COMMENT LBRACE content RBRACE { result = BibTeX::Comment.new(val[2]) }
|
49
|
+
|
50
|
+
content : /* empty */ { result = '' }
|
51
|
+
| CONTENT { result = val[0] }
|
52
|
+
|
53
|
+
preamble : PREAMBLE LBRACE string_value RBRACE { result = BibTeX::Preamble.new(val[2]) }
|
54
|
+
|
55
|
+
string : STRING LBRACE string_assignment RBRACE { result = BibTeX::String.new(val[2][0],val[2][1]); }
|
56
|
+
|
57
|
+
string_assignment : NAME EQ string_value { result = [val[0].downcase.to_sym, val[2]] }
|
58
|
+
|
59
|
+
string_value : string_literal { result = [val[0]] }
|
60
|
+
| string_value SHARP string_literal { result << val[2] }
|
61
|
+
|
62
|
+
string_literal : NAME { result = val[0].downcase.to_sym }
|
63
|
+
| STRING_LITERAL { result = val[0] }
|
64
|
+
|
65
|
+
entry : entry_head assignments RBRACE { result = val[0] << val[1] }
|
66
|
+
| entry_head assignments COMMA RBRACE { result = val[0] << val[1] }
|
67
|
+
| entry_head RBRACE { result = val[0] }
|
68
|
+
|
69
|
+
entry_head : NAME LBRACE key COMMA { result = BibTeX::Entry.new(val[0].downcase.to_sym,val[2]) }
|
70
|
+
|
71
|
+
key : NAME { result = val[0] }
|
72
|
+
| NUMBER { result = val[0] }
|
73
|
+
|
74
|
+
assignments : assignment { result = val[0] }
|
75
|
+
| assignments COMMA assignment { result.merge!(val[2]) }
|
76
|
+
|
77
|
+
assignment : NAME EQ value { result = { val[0].downcase.to_sym => val[2] } }
|
78
|
+
|
79
|
+
value : string_value { result = val[0] }
|
80
|
+
| NUMBER { result = val[0] }
|
81
|
+
| LBRACE content RBRACE { result = val[1] }
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
---- header
|
86
|
+
require 'bibtex/lexer'
|
87
|
+
|
88
|
+
---- inner
|
89
|
+
|
90
|
+
attr_reader :lexer
|
91
|
+
|
92
|
+
def initialize(options={})
|
93
|
+
@options = options
|
94
|
+
@options[:include] ||= [:errors]
|
95
|
+
@lexer = Lexer.new(options)
|
96
|
+
end
|
97
|
+
|
98
|
+
def parse(input)
|
99
|
+
@yydebug = self.debug?
|
100
|
+
|
101
|
+
self.lexer.src = input
|
102
|
+
self.lexer.analyse
|
103
|
+
|
104
|
+
do_parse
|
105
|
+
end
|
106
|
+
|
107
|
+
def next_token
|
108
|
+
token = self.lexer.next_token
|
109
|
+
if token[0] == :ERROR
|
110
|
+
self.include_errors? ? token : next_token
|
111
|
+
else
|
112
|
+
[token[0],token[1][0]]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def debug?
|
117
|
+
@options[:debug] == true || ENV['DEBUG'] == true
|
118
|
+
end
|
119
|
+
|
120
|
+
def include_errors?
|
121
|
+
@options[:include].include?(:errors)
|
122
|
+
end
|
123
|
+
|
124
|
+
def on_error(tid, val, vstack)
|
125
|
+
#raise(ParseError, "Failed to parse BibTeX on value %s (%s) %s" % [val.inspect, token_to_str(tid) || '?', vstack.inspect])
|
126
|
+
Log.error("Failed to parse BibTeX on value %s (%s) %s" % [val.inspect, token_to_str(tid) || '?', vstack.inspect])
|
127
|
+
end
|
128
|
+
|
129
|
+
# -*- racc -*-
|
@@ -0,0 +1,262 @@
|
|
1
|
+
#--
|
2
|
+
# BibTeX-Ruby
|
3
|
+
# Copyright (C) 2010 Sylvester Keil <sylvester.keil.or.at>
|
4
|
+
#
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
#++
|
18
|
+
|
19
|
+
require 'json'
|
20
|
+
require 'rexml/document'
|
21
|
+
require 'yaml'
|
22
|
+
|
23
|
+
module BibTeX
|
24
|
+
|
25
|
+
#
|
26
|
+
# The base class for BibTeX objects.
|
27
|
+
#
|
28
|
+
class Element
|
29
|
+
|
30
|
+
attr_reader :bibliography
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
@bibliography = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns a string containing the object's content.
|
37
|
+
def content
|
38
|
+
""
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns a string representation of the object.
|
42
|
+
def to_s
|
43
|
+
self.content
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_hash
|
47
|
+
{ self.class.name.downcase => content }
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_yaml
|
51
|
+
self.to_hash.to_yaml
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_json
|
55
|
+
self.to_hash.to_json
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_xml
|
59
|
+
xml = REXML::Element.new(self.class.name.downcase)
|
60
|
+
xml.text = self.content
|
61
|
+
xml
|
62
|
+
end
|
63
|
+
|
64
|
+
# Called when the element was added to a bibliography.
|
65
|
+
def added_to_bibliography(bibliography)
|
66
|
+
@bibliography = bibliography
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
# Called when the element was removed from a bibliography.
|
71
|
+
def removed_from_bibliography(bibliography)
|
72
|
+
@bibliography = nil
|
73
|
+
self
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
#
|
79
|
+
# Represents a @string object.
|
80
|
+
#
|
81
|
+
# In BibTeX @string objects contain a single string constant
|
82
|
+
# assignment. For example, @string{ foo = "bar" } defines the
|
83
|
+
# constant `foo'; this constant can be used (using BibTeX's
|
84
|
+
# string concatenation syntax) in susbsequent
|
85
|
+
# @string and @preamble objects, as well as in field values
|
86
|
+
# of regular entries.
|
87
|
+
#
|
88
|
+
class String < Element
|
89
|
+
attr_reader :key, :value
|
90
|
+
|
91
|
+
# Creates a new instance.
|
92
|
+
def initialize(key=nil,value=nil)
|
93
|
+
self.key = key.to_sym unless key.nil?
|
94
|
+
self.value = value unless value.nil?
|
95
|
+
end
|
96
|
+
|
97
|
+
# Sets the string's key (i.e., the name of the constant)
|
98
|
+
def key=(key)
|
99
|
+
raise(ArgumentError, "BibTeX::String key must be of type Symbol; was: #{key.class.name}.") unless key.kind_of?(Symbol)
|
100
|
+
@key = key
|
101
|
+
end
|
102
|
+
|
103
|
+
# Sets the string's value (i.e., the string literal defined by the constant)
|
104
|
+
def value=(value)
|
105
|
+
raise(ArgumentError, "BibTeX::String value must be of type Array, Symbol, or String; was: #{value.class.name}.") unless [Array,::String,Symbol].map { |k| value.kind_of?(k) }.inject { |sum,n| sum || n }
|
106
|
+
@value = value.kind_of?(Array) ? value : [value]
|
107
|
+
end
|
108
|
+
|
109
|
+
# Replaces all constants in this string's value which are defined in +hsh+.
|
110
|
+
# Returns the new value (the @string object itself remains unchanged).
|
111
|
+
#
|
112
|
+
# call-seq:
|
113
|
+
# s.to_s
|
114
|
+
# => "@string{ foobar = foo # "bar"}"
|
115
|
+
# s.replace({:foo => 'foo'})
|
116
|
+
# => ["foo","bar"]
|
117
|
+
# s.to_s
|
118
|
+
# => "@string{ foobar = foo # "bar"}"
|
119
|
+
def replace(hsh)
|
120
|
+
StringReplacement.replace(@value,hsh)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Replaces all constants in this string's value which are defined in +hsh+.
|
124
|
+
# Returns the new value (the @string object itself is changed as well).
|
125
|
+
#
|
126
|
+
# call-seq:
|
127
|
+
# s.to_s
|
128
|
+
# => "@string{ foobar = foo # "bar"}"
|
129
|
+
# s.replace({:foo => 'foo'})
|
130
|
+
# => ["foo","bar"]
|
131
|
+
# s.to_s
|
132
|
+
# => "@string{ foobar = "foo" # "bar"}"
|
133
|
+
def replace!(hsh)
|
134
|
+
@value = replace(hsh)
|
135
|
+
@bibliography.strings[@key] = value unless @bibliography.nil?
|
136
|
+
end
|
137
|
+
|
138
|
+
# Adds either a string constant or literal to the current value. The
|
139
|
+
# values will be concatenated using the `#' symbol.
|
140
|
+
def <<(value)
|
141
|
+
raise(ArgumentError, "BibTeX::String value can contain only instances of Symbol or String; was: #{value.class.name}.") unless [::String,Symbol].map { |k| value.kind_of?(k) }.inject { |sum,n| sum || n }
|
142
|
+
@value << value
|
143
|
+
end
|
144
|
+
|
145
|
+
# Called when the element was added to a bibliography.
|
146
|
+
def added_to_bibliography(bibliography)
|
147
|
+
super(bibliography)
|
148
|
+
bibliography.strings[@key] = @value
|
149
|
+
self
|
150
|
+
end
|
151
|
+
|
152
|
+
# Called when the element was removed from a bibliography.
|
153
|
+
def removed_from_bibliography(bibliography)
|
154
|
+
super(bibliography)
|
155
|
+
bibliography.strings[@key] = nil
|
156
|
+
self
|
157
|
+
end
|
158
|
+
|
159
|
+
# Returns a string representation of the @string's content.
|
160
|
+
def content
|
161
|
+
[@key.to_s,' = ',StringReplacement.to_s(@value)].join
|
162
|
+
end
|
163
|
+
|
164
|
+
# Returns a string representation of the @string object.
|
165
|
+
def to_s
|
166
|
+
['@string{ ',content,'}'].join
|
167
|
+
end
|
168
|
+
|
169
|
+
def to_hash
|
170
|
+
{ 'string' => { @key.to_s => StringReplacement.to_s(@value) } }
|
171
|
+
end
|
172
|
+
|
173
|
+
def to_xml
|
174
|
+
xml = REXML::Element.new('string')
|
175
|
+
key = REXML::Element.new('key')
|
176
|
+
val = REXML::Element.new('value')
|
177
|
+
key.text = @key.to_s
|
178
|
+
val.text = @value.to_s
|
179
|
+
xml
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
#
|
184
|
+
# Represents a @preamble object.
|
185
|
+
#
|
186
|
+
# In BibTeX an @preamble object contains a single string literal,
|
187
|
+
# a single constant, or a concatenation of string literals and
|
188
|
+
# constants.
|
189
|
+
class Preamble < Element
|
190
|
+
attr_reader :value
|
191
|
+
|
192
|
+
# Creates a new instance.
|
193
|
+
def initialize(value=[])
|
194
|
+
self.value = value
|
195
|
+
end
|
196
|
+
|
197
|
+
def value=(value)
|
198
|
+
raise(ArgumentError, "BibTeX::Preamble value must be of type Array, Symbol, or String; was: #{value.class.name}.") unless [Array,::String,Symbol].map { |k| value.kind_of?(k) }.inject { |sum,n| sum || n }
|
199
|
+
@value = value.kind_of?(Array) ? value : [value]
|
200
|
+
end
|
201
|
+
|
202
|
+
def replace(hsh)
|
203
|
+
StringReplacement.replace(@value,hsh)
|
204
|
+
end
|
205
|
+
|
206
|
+
def replace!(hsh)
|
207
|
+
@value = replace(hsh)
|
208
|
+
@bibliography.strings[@key] = @value unless @bibliography.nil?
|
209
|
+
end
|
210
|
+
|
211
|
+
# Returns a string representation of the @preamble's content.
|
212
|
+
def content
|
213
|
+
StringReplacement.to_s(@value)
|
214
|
+
end
|
215
|
+
|
216
|
+
# Returns a string representation of the @preamble object
|
217
|
+
def to_s
|
218
|
+
['@preamble{ ',content,'}'].join
|
219
|
+
end
|
220
|
+
|
221
|
+
def to_hash
|
222
|
+
{ 'preamble' => StringReplacement.to_s(@value) }
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
# Represents a @comment object.
|
227
|
+
class Comment < Element
|
228
|
+
|
229
|
+
def initialize(content='')
|
230
|
+
self.content = content
|
231
|
+
end
|
232
|
+
|
233
|
+
def content=(content)
|
234
|
+
raise(ArgumentError, "BibTeX::#{self.class.name} content must be of type String; was: #{content.class.name}.") unless content.kind_of?(::String)
|
235
|
+
@content = content
|
236
|
+
end
|
237
|
+
|
238
|
+
def content
|
239
|
+
@content
|
240
|
+
end
|
241
|
+
|
242
|
+
def to_s
|
243
|
+
['@comment{ ',content,'}'].join
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
247
|
+
|
248
|
+
# Represents text in a `.bib' file, but outside of an
|
249
|
+
# actual BibTeX object; typically, such text is treated
|
250
|
+
# as a comment and is ignored by the parser.
|
251
|
+
# BibTeX-Ruby offers this class to allows for
|
252
|
+
# post-processing of this type of `meta' comment. If you
|
253
|
+
# want the parser to include +MetaComment+ objects, you
|
254
|
+
# need to add +:meta_comments+ to the parser's +:include+
|
255
|
+
# option.
|
256
|
+
class MetaComment < Comment
|
257
|
+
def to_s
|
258
|
+
@content
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
end
|
data/lib/bibtex/entry.rb
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
#--
|
2
|
+
# BibTeX-Ruby
|
3
|
+
# Copyright (C) 2010 Sylvester Keil <sylvester.keil.or.at>
|
4
|
+
#
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
#++
|
18
|
+
|
19
|
+
module BibTeX
|
20
|
+
#
|
21
|
+
# Represents a regular BibTeX entry.
|
22
|
+
#
|
23
|
+
class Entry < Element
|
24
|
+
attr_reader :key, :type, :fields
|
25
|
+
|
26
|
+
# Hash containing the required fields of the standard entry types
|
27
|
+
@@RequiredFields = Hash.new([])
|
28
|
+
@@RequiredFields.merge!({
|
29
|
+
:article => [:author,:title,:journal,:year],
|
30
|
+
:book => [[:author,:editor],:title,:publisher,:year],
|
31
|
+
:booklet => [:title],
|
32
|
+
:conference => [:author,:title,:booktitle,:year],
|
33
|
+
:inbook => [[:author,:editor],:title,[:chapter,:pages],:publisher,:year],
|
34
|
+
:incollection => [:author,:title,:booktitle,:publisher,:year],
|
35
|
+
:inproceedings => [:author,:title,:booktitle,:year],
|
36
|
+
:manual => [:title],
|
37
|
+
:mastersthesis => [:author,:title,:school,:year],
|
38
|
+
:misc => [],
|
39
|
+
:phdthesis => [:author,:title,:school,:year],
|
40
|
+
:proceedings => [:title,:year],
|
41
|
+
:techreport => [:author,:title,:institution,:year],
|
42
|
+
:unpublished => [:author,:title,:note]
|
43
|
+
})
|
44
|
+
|
45
|
+
# Creates a new instance of a given +type+ (e.g., :article, :book, etc.)
|
46
|
+
# identified by a +key+.
|
47
|
+
def initialize(type=nil, key=nil)
|
48
|
+
self.key = key.to_s unless key.nil?
|
49
|
+
self.type = type.to_sym unless type.nil?
|
50
|
+
@fields = {}
|
51
|
+
end
|
52
|
+
|
53
|
+
# Sets the key of the entry
|
54
|
+
def key=(key)
|
55
|
+
raise(ArgumentError, "BibTeX::Entry key must be of type String; was: #{key.class.name}.") unless key.kind_of?(::String)
|
56
|
+
@key = key
|
57
|
+
end
|
58
|
+
|
59
|
+
# Sets the type of the entry.
|
60
|
+
def type=(type)
|
61
|
+
raise(ArgumentError, "BibTeX::Entry type must be of type Symbol; was: #{type.class.name}.") unless type.kind_of?(Symbol)
|
62
|
+
@type = type
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns the value of the field with the given name.
|
66
|
+
def [](name)
|
67
|
+
@fields[name.to_sym]
|
68
|
+
end
|
69
|
+
|
70
|
+
# Adds a new field (name-value pair) to the entry.
|
71
|
+
# Returns the new value.
|
72
|
+
def []=(name,value)
|
73
|
+
add(name,value)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Adds a new field (name-value pair) to the entry.
|
77
|
+
# Returns the new value.
|
78
|
+
def add(name,value)
|
79
|
+
raise(ArgumentError, "BibTeX::Entry field name must be of type Symbol; was: #{name.class.name}.") unless name.kind_of?(Symbol)
|
80
|
+
raise(ArgumentError, "BibTeX::Entry field value must be of type Array, Symbol, or String; was: #{value.class.name}.") unless [Array,::String,Symbol].map { |k| value.kind_of?(k) }.inject { |sum,n| sum || n }
|
81
|
+
@fields[name] = value.kind_of?(Array) ? value : [value]
|
82
|
+
end
|
83
|
+
|
84
|
+
# Removes the field with a given name from the entry.
|
85
|
+
# Returns the value of the deleted field; nil if the field was not set.
|
86
|
+
def delete(name)
|
87
|
+
@fields.delete(name.to_sym)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Adds all the fields contained in a given hash to the entry.
|
91
|
+
def <<(fields)
|
92
|
+
raise(ArgumentError, "BibTeX::Entry fields must be of type Hash; was: #{fields.class.name}.") unless fields.kind_of?(Hash)
|
93
|
+
fields.each { |n,v| add(n,v) }
|
94
|
+
self
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns true if the entry currently contains no field.
|
98
|
+
def empty?
|
99
|
+
@fields.empty?
|
100
|
+
end
|
101
|
+
|
102
|
+
# Returns false if the entry is one of the standard entry types and does not have
|
103
|
+
# definitions of all the required fields for that type.
|
104
|
+
def valid?
|
105
|
+
!@@RequiredFields[@type].map { |f|
|
106
|
+
f.kind_of?(Array) ? !(f & @fields.keys).empty? : !@fields[f].nil?
|
107
|
+
}.include?(false)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Called when the element was added to a bibliography.
|
111
|
+
def added_to_bibliography(bibliography)
|
112
|
+
super(bibliography)
|
113
|
+
bibliography.entries[@key] = self
|
114
|
+
self
|
115
|
+
end
|
116
|
+
|
117
|
+
# Called when the element was removed from a bibliography.
|
118
|
+
def removed_from_bibliography(bibliography)
|
119
|
+
super(bibliography)
|
120
|
+
bibliography.entries[@key] = nil
|
121
|
+
self
|
122
|
+
end
|
123
|
+
|
124
|
+
# Replaces all constants in this entry's field values which are defined in +hsh+.
|
125
|
+
def replace!(hsh)
|
126
|
+
@fields.keys.each { |k| @fields[k] = StringReplacement.replace(@fields[k],hsh) }
|
127
|
+
end
|
128
|
+
|
129
|
+
# Returns a string of all the entry's fields.
|
130
|
+
def content
|
131
|
+
@fields.keys.map { |k| "#{k} = #{StringReplacement.to_s(@fields[k], :delimiter => ['{','}'])}" }.join(",\n")
|
132
|
+
end
|
133
|
+
|
134
|
+
# Returns a string representation of the entry.
|
135
|
+
def to_s
|
136
|
+
["@#{type}{#{key},",content.gsub(/^/,' '),"}\n"].join("\n")
|
137
|
+
end
|
138
|
+
|
139
|
+
def to_hash
|
140
|
+
{ @type.to_s => @fields.keys.map { |k| { k.to_s => StringReplacement.to_s(@fields[k], :delimiter => ['{','}']) } }.inject({ 'key' => @key }) { |sum,n| sum.merge(n) } }.to_yaml
|
141
|
+
end
|
142
|
+
|
143
|
+
def to_xml
|
144
|
+
xml = REXML::Element.new(@type.to_s)
|
145
|
+
xml.attributes['key'] = @key
|
146
|
+
@fields.each do |k,v|
|
147
|
+
e = REXML::Element.new(k.to_s)
|
148
|
+
e.text = StringReplacement.to_s(v, :delimiter => ['',''])
|
149
|
+
xml.add_element(e)
|
150
|
+
end
|
151
|
+
xml
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|