bibtex-ruby 1.2.1 → 1.3.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/Gemfile +6 -1
- data/Gemfile.lock +48 -5
- data/History.txt +16 -1
- data/Manifest +43 -19
- data/README.md +178 -167
- data/Rakefile +26 -5
- data/auto.watchr +6 -0
- data/bibtex-ruby.gemspec +8 -5
- data/examples/bib2html.rb +28 -18
- data/features/bibtex.feature +96 -0
- data/features/entries.feature +67 -0
- data/features/issues/slash_keys.feature +21 -0
- data/features/names.feature +72 -0
- data/features/preambles.feature +27 -0
- data/features/query.feature +56 -0
- data/features/replacement.feature +68 -0
- data/features/step_definitions/bibtex_steps.rb +74 -0
- data/features/step_definitions/name_steps.rb +13 -0
- data/features/strings.feature +52 -0
- data/features/support/env.rb +7 -0
- data/lib/bibtex.rb +5 -1
- data/lib/bibtex/bibliography.rb +218 -95
- data/lib/bibtex/bibtex.y +18 -15
- data/lib/bibtex/elements.rb +130 -136
- data/lib/bibtex/entry.rb +133 -69
- data/lib/bibtex/extensions.rb +0 -35
- data/lib/bibtex/lexer.rb +9 -9
- data/lib/bibtex/name_parser.output +464 -0
- data/lib/bibtex/name_parser.rb +490 -0
- data/lib/bibtex/names.rb +162 -0
- data/lib/bibtex/names.y +196 -0
- data/lib/bibtex/parser.output +5 -5
- data/lib/bibtex/parser.rb +19 -16
- data/lib/bibtex/replaceable.rb +52 -0
- data/lib/bibtex/utilities.rb +23 -5
- data/lib/bibtex/value.rb +201 -0
- data/lib/bibtex/version.rb +1 -1
- data/test/benchmark.rb +52 -0
- data/test/bibtex/test_bibliography.rb +141 -0
- data/test/bibtex/test_elements.rb +40 -0
- data/test/bibtex/test_entry.rb +99 -0
- data/test/bibtex/test_names.rb +23 -0
- data/test/bibtex/test_parser.rb +79 -0
- data/test/bibtex/test_string.rb +83 -0
- data/test/bibtex/test_utilities.rb +34 -0
- data/test/bibtex/test_value.rb +70 -0
- data/test/{bib/10_bibdesk.bib → fixtures/bibdesk.bib} +1 -1
- data/test/{bib/05_comment.bib → fixtures/comment.bib} +0 -0
- data/test/{bib/08_decoret.bib → fixtures/decoret.bib} +0 -0
- data/test/{bib/00_empty.bib → fixtures/empty.bib} +0 -0
- data/test/{bib/07_entry.bib → fixtures/entry.bib} +0 -0
- data/test/{bib/09_errors.bib → fixtures/errors.bib} +0 -0
- data/test/{bib/01_no_bibtex.bib → fixtures/no_bibtex.bib} +0 -0
- data/test/{bib/06_preamble.bib → fixtures/preamble.bib} +1 -1
- data/test/{bib/11_roundtrip.bib → fixtures/roundtrip.bib} +1 -1
- data/test/helper.rb +17 -2
- data/test/test_bibtex.rb +87 -93
- data/test/test_export.rb +18 -22
- metadata +85 -30
- data/test/bib/02_string.bib +0 -1
- data/test/bib/03_string.bib +0 -25
- data/test/bib/04_string_replacement.bib +0 -16
- data/test/test_comment.rb +0 -21
- data/test/test_entry.rb +0 -98
- data/test/test_preamble.rb +0 -39
- data/test/test_string.rb +0 -97
- data/test/test_utilities.rb +0 -36
data/lib/bibtex/bibtex.y
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#--
|
2
2
|
# BibTeX-Ruby
|
3
|
-
# Copyright (C) 2010 Sylvester Keil <http://sylvester.keil.or.at>
|
3
|
+
# Copyright (C) 2010-2011 Sylvester Keil <http://sylvester.keil.or.at>
|
4
4
|
#
|
5
5
|
# This program is free software: you can redistribute it and/or modify
|
6
6
|
# it under the terms of the GNU General Public License as published by
|
@@ -23,21 +23,21 @@
|
|
23
23
|
|
24
24
|
class BibTeX::Parser
|
25
25
|
|
26
|
-
token AT COMMA COMMENT CONTENT ERROR EQ LBRACE
|
26
|
+
token AT COMMA COMMENT CONTENT ERROR EQ LBRACE META_CONTENT
|
27
27
|
NAME NUMBER PREAMBLE RBRACE SHARP STRING STRING_LITERAL
|
28
28
|
|
29
29
|
expect 0
|
30
30
|
|
31
31
|
rule
|
32
32
|
|
33
|
-
bibliography : /* empty */ { result = Bibliography.new }
|
33
|
+
bibliography : /* empty */ { result = BibTeX::Bibliography.new }
|
34
34
|
| objects { result = val[0] }
|
35
35
|
|
36
|
-
objects : object { result = Bibliography.new << val[0] }
|
36
|
+
objects : object { result = BibTeX::Bibliography.new << val[0] }
|
37
37
|
| objects object { result << val[1] }
|
38
38
|
|
39
39
|
object : AT at_object { result = val[1] }
|
40
|
-
|
|
40
|
+
| META_CONTENT { result = BibTeX::MetaContent.new(val[0]) }
|
41
41
|
| ERROR { result = BibTeX::Error.new(val[0]) }
|
42
42
|
|
43
43
|
at_object : comment { result = val[0] }
|
@@ -89,32 +89,35 @@ require 'bibtex/lexer'
|
|
89
89
|
|
90
90
|
attr_reader :lexer
|
91
91
|
|
92
|
-
def initialize(options={})
|
93
|
-
|
94
|
-
@
|
95
|
-
@lexer = Lexer.new(options)
|
92
|
+
def initialize(options = {})
|
93
|
+
self.options.merge!(options)
|
94
|
+
@lexer = Lexer.new(@options)
|
96
95
|
end
|
97
96
|
|
97
|
+
def options
|
98
|
+
@options ||= { :include => [:errors], :debug => ENV['DEBUG'] == true }
|
99
|
+
end
|
100
|
+
|
98
101
|
def parse(input)
|
99
|
-
@yydebug =
|
102
|
+
@yydebug = debug?
|
100
103
|
|
101
|
-
|
102
|
-
|
104
|
+
@lexer.src = input
|
105
|
+
@lexer.analyse
|
103
106
|
|
104
107
|
do_parse
|
105
108
|
end
|
106
109
|
|
107
110
|
def next_token
|
108
|
-
token =
|
111
|
+
token = @lexer.next_token
|
109
112
|
if token[0] == :ERROR
|
110
|
-
|
113
|
+
include_errors? ? token : next_token
|
111
114
|
else
|
112
115
|
[token[0],token[1][0]]
|
113
116
|
end
|
114
117
|
end
|
115
118
|
|
116
119
|
def debug?
|
117
|
-
@options[:debug] == true
|
120
|
+
@options[:debug] == true
|
118
121
|
end
|
119
122
|
|
120
123
|
def include_errors?
|
data/lib/bibtex/elements.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#--
|
2
2
|
# BibTeX-Ruby
|
3
|
-
# Copyright (C) 2010 Sylvester Keil <sylvester.keil.or.at>
|
3
|
+
# Copyright (C) 2010-2011 Sylvester Keil <sylvester.keil.or.at>
|
4
4
|
#
|
5
5
|
# This program is free software: you can redistribute it and/or modify
|
6
6
|
# it under the terms of the GNU General Public License as published by
|
@@ -24,45 +24,100 @@ module BibTeX
|
|
24
24
|
class Element
|
25
25
|
include Comparable
|
26
26
|
|
27
|
+
attr_writer :id
|
27
28
|
attr_reader :bibliography
|
28
29
|
|
29
30
|
# Returns an array of BibTeX elements.
|
30
|
-
def self.parse(string, options={})
|
31
|
-
BibTeX::Parser.new(options).parse(string).
|
31
|
+
def self.parse(string, options = {})
|
32
|
+
BibTeX::Parser.new(options).parse(string).data
|
32
33
|
end
|
33
34
|
|
34
|
-
def initialize
|
35
|
-
@bibliography = nil
|
36
|
-
end
|
37
|
-
|
38
35
|
# Returns a string containing the object's content.
|
39
|
-
def content
|
40
|
-
|
36
|
+
def content(options = {})
|
37
|
+
''
|
41
38
|
end
|
42
39
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
40
|
+
# Invokes BibTeX string replacement on this element.
|
41
|
+
def replace(*arguments); self; end
|
42
|
+
|
43
|
+
# Invokes BibTeX string joining on this element.
|
44
|
+
def join; self; end
|
45
|
+
|
46
|
+
# Returns the element's id.
|
47
|
+
def id; @id ||= object_id.to_s.intern; end
|
48
|
+
|
49
|
+
# Returns the BibTeX type (if applicable) or the normalized class name.
|
50
|
+
def type
|
51
|
+
self.class.name.split(/::/).last.gsub(/([[:lower:]])([[:upper:]])/) { "#{$1}_#{$2}" }.downcase.intern
|
52
|
+
end
|
53
|
+
|
54
|
+
def has_type?(type)
|
55
|
+
self.type == type.intern || defined?(type) == 'constant' && is_a?(type)
|
56
|
+
end
|
57
|
+
|
58
|
+
[:entry, :book, :article, :collection, :string, :preamble, :comment]. each do |type|
|
59
|
+
method_id = "#{type}?"
|
60
|
+
unless method_defined?(method_id)
|
61
|
+
define_method(method_id) { has_type?(type) }
|
62
|
+
alias_method("is_#{method_id}", method_id)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns true if the element matches the given query.
|
67
|
+
def matches?(query)
|
68
|
+
return true if query.nil? || query.respond_to?(:empty?) && query.empty?
|
69
|
+
|
70
|
+
case query
|
71
|
+
when Element
|
72
|
+
self == query
|
73
|
+
when Symbol
|
74
|
+
id == query
|
75
|
+
when Regexp
|
76
|
+
to_s.match(query)
|
77
|
+
when /^\/(.+)\/$/
|
78
|
+
to_s.match(Regexp.new($1))
|
79
|
+
when /@(\w+)(?:\[([^\]]*)\])?/
|
80
|
+
query.scan(/@(\w+)(?:\[([^\]]*)\])?/).any? do |type, condition|
|
81
|
+
has_type?(type) && ( condition.nil? || meets?(condition.split(/,\s*/)) )
|
82
|
+
end
|
83
|
+
else
|
84
|
+
id == query.to_sym
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
alias :=== :matches?
|
89
|
+
alias :match? :matches?
|
90
|
+
|
91
|
+
# Returns true if the element meets all of the given conditions.
|
92
|
+
def meets?(*conditions)
|
93
|
+
conditions.flatten.all? do |condition|
|
94
|
+
property, value = condition.split(/\s*=\s*/)
|
95
|
+
property.nil? || send(property).to_s == value
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
alias :meet? :meets?
|
100
|
+
|
101
|
+
alias :to_s :content
|
47
102
|
|
48
|
-
def to_hash
|
49
|
-
{
|
103
|
+
def to_hash(options = {})
|
104
|
+
{ type => content }
|
50
105
|
end
|
51
106
|
|
52
|
-
def to_yaml
|
107
|
+
def to_yaml(options = {})
|
53
108
|
require 'yaml'
|
54
|
-
|
109
|
+
to_hash.to_yaml
|
55
110
|
end
|
56
111
|
|
57
|
-
def to_json
|
112
|
+
def to_json(options = {})
|
58
113
|
require 'json'
|
59
|
-
|
114
|
+
to_hash.to_json
|
60
115
|
end
|
61
116
|
|
62
|
-
def to_xml
|
117
|
+
def to_xml(options = {})
|
63
118
|
require 'rexml/document'
|
64
|
-
xml = REXML::Element.new(
|
65
|
-
xml.text =
|
119
|
+
xml = REXML::Element.new(type)
|
120
|
+
xml.text = content
|
66
121
|
xml
|
67
122
|
end
|
68
123
|
|
@@ -79,7 +134,7 @@ module BibTeX
|
|
79
134
|
end
|
80
135
|
|
81
136
|
def <=>(other)
|
82
|
-
|
137
|
+
[type, to_s] <=> [other.type, other.to_s]
|
83
138
|
end
|
84
139
|
|
85
140
|
end
|
@@ -96,105 +151,70 @@ module BibTeX
|
|
96
151
|
# of regular entries.
|
97
152
|
#
|
98
153
|
class String < Element
|
154
|
+
include Replaceable
|
155
|
+
|
99
156
|
attr_reader :key
|
100
157
|
|
101
158
|
# Creates a new instance.
|
102
|
-
def initialize(key=nil,value=nil)
|
103
|
-
|
104
|
-
self
|
159
|
+
def initialize(key = nil, value = nil)
|
160
|
+
@key, @value = key.to_sym, Value.new(value)
|
161
|
+
yield self if block_given?
|
105
162
|
end
|
106
163
|
|
107
|
-
# Sets the string's key (i.e., the
|
164
|
+
# Sets the string's key (i.e., the symbol identifying the constant).
|
108
165
|
def key=(key)
|
109
|
-
|
110
|
-
|
166
|
+
raise(ArgumentError, "keys must be convertible to Symbol; was: #{type.class.name}.") unless type.respond_to?(:to_sym)
|
167
|
+
|
168
|
+
unless @bibliography.nil?
|
169
|
+
@bibliography.strings.delete(@key)
|
170
|
+
@bibliography.strings[key.to_sym] = self
|
171
|
+
end
|
172
|
+
|
173
|
+
@key = key.to_sym
|
111
174
|
end
|
112
175
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
@value = Extensions.string_replacement(value.is_a?(Array) ? value : [value])
|
117
|
-
end
|
118
|
-
|
119
|
-
def value
|
120
|
-
@value.to_s(:quotes => %w(" "))
|
176
|
+
# Retuns the string's value if parameter matches the key; nil otherwise.
|
177
|
+
def [](key)
|
178
|
+
@key == key ? @value : nil
|
121
179
|
end
|
122
180
|
|
123
|
-
# Replaces all constants in this string's value which are defined in +hash+.
|
124
|
-
# Returns the new value (the @string object itself remains unchanged).
|
125
|
-
#
|
126
|
-
# call-seq:
|
127
|
-
# s.to_s
|
128
|
-
# => "@string{ foobar = foo # "bar"}"
|
129
|
-
# s.replace({:foo => 'bar'})
|
130
|
-
# => "\"bar\" # \"bar\""
|
131
|
-
# s.to_s
|
132
|
-
# => "@string{ foobar = foo # "bar"}"
|
133
|
-
def replace(hash)
|
134
|
-
@value.replace_strings(hash)
|
135
|
-
end
|
136
|
-
|
137
|
-
# Replaces all constants in this string's value which are defined in +hsh+.
|
138
|
-
# Returns the new value (the @string object itself is changed as well).
|
139
|
-
#
|
140
|
-
# call-seq:
|
141
|
-
# s.to_s
|
142
|
-
# => "@string{ foobar = foo # "bar"}"
|
143
|
-
# s.replace({:foo => 'bar'})
|
144
|
-
# => ["bar","bar"]
|
145
|
-
# s.to_s
|
146
|
-
# => "@string{ foobar = "bar" # "bar"}"
|
147
|
-
def replace!(hash)
|
148
|
-
@value = @value.replace_strings(hash)
|
149
|
-
@bibliography.strings[@key] = @value unless @bibliography.nil?
|
150
|
-
end
|
151
|
-
|
152
|
-
def join!
|
153
|
-
@value = @value.join_strings
|
154
|
-
@bibliography.strings[@key] = @value unless @bibliography.nil?
|
155
|
-
end
|
156
|
-
|
157
|
-
# Adds either a string constant or literal to the current value. The
|
158
|
-
# values will be concatenated using the `#' symbol.
|
159
|
-
def <<(value)
|
160
|
-
raise(ArgumentError, "BibTeX::String value can contain only instances of Symbol or String; was: #{value.class.name}.") unless [::String,Symbol].map { |k| value.is_a?(k) }.inject { |sum,n| sum || n }
|
161
|
-
@value << value
|
162
|
-
end
|
163
181
|
|
164
182
|
# Called when the element was added to a bibliography.
|
165
183
|
def added_to_bibliography(bibliography)
|
166
|
-
super
|
167
|
-
bibliography.strings[@key] =
|
184
|
+
super
|
185
|
+
bibliography.strings[@key] = self
|
168
186
|
self
|
169
187
|
end
|
170
188
|
|
171
189
|
# Called when the element was removed from a bibliography.
|
172
190
|
def removed_from_bibliography(bibliography)
|
173
|
-
super
|
191
|
+
super
|
174
192
|
bibliography.strings[@key] = nil
|
175
193
|
self
|
176
194
|
end
|
177
195
|
|
178
196
|
# Returns a string representation of the @string's content.
|
179
197
|
def content
|
180
|
-
|
198
|
+
"#@key = #{@value.to_s(:quotes => '"')}"
|
181
199
|
end
|
182
200
|
|
183
201
|
# Returns a string representation of the @string object.
|
184
|
-
def to_s
|
202
|
+
def to_s(options = {})
|
185
203
|
"@string{ #{content} }"
|
186
204
|
end
|
187
205
|
|
188
|
-
def to_hash
|
189
|
-
{
|
206
|
+
def to_hash(options = {})
|
207
|
+
{ :string => { @key => @value.to_s(:quotes => '"') } }
|
190
208
|
end
|
191
209
|
|
192
|
-
def to_xml
|
193
|
-
|
194
|
-
|
195
|
-
|
210
|
+
def to_xml(options = {})
|
211
|
+
require 'rexml/document'
|
212
|
+
|
213
|
+
xml = REXML::Element.new(:string)
|
214
|
+
key = REXML::Element.new(:key)
|
215
|
+
val = REXML::Element.new(:value)
|
196
216
|
key.text = @key.to_s
|
197
|
-
val.text = @value.to_s(:quotes =>
|
217
|
+
val.text = @value.to_s(:quotes => '"')
|
198
218
|
xml
|
199
219
|
end
|
200
220
|
end
|
@@ -206,79 +226,53 @@ module BibTeX
|
|
206
226
|
# a single constant, or a concatenation of string literals and
|
207
227
|
# constants.
|
208
228
|
class Preamble < Element
|
209
|
-
|
210
|
-
# Creates a new instance.
|
211
|
-
def initialize(value=[])
|
212
|
-
self.value = value
|
213
|
-
end
|
214
|
-
|
215
|
-
def value=(value)
|
216
|
-
raise(ArgumentError, "BibTeX::Preamble value must be of type Array, Symbol, or String; was: #{value.class.name}.") unless [Array,::String,Symbol].map { |k| value.is_a?(k) }.inject { |sum,n| sum || n }
|
217
|
-
@value = Extensions.string_replacement(value.is_a?(Array) ? value : [value])
|
218
|
-
end
|
229
|
+
include Replaceable
|
219
230
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
def replace!(hash)
|
225
|
-
@value = @value.replace_strings(hash)
|
231
|
+
# Creates a new instance.
|
232
|
+
def initialize(value = '')
|
233
|
+
@value = Value.new(value)
|
226
234
|
end
|
227
|
-
|
228
|
-
def join!
|
229
|
-
@value = @value.join_strings
|
230
|
-
end
|
231
|
-
|
232
|
-
def value
|
233
|
-
content
|
234
|
-
end
|
235
235
|
|
236
236
|
# Returns a string representation of the @preamble's content.
|
237
237
|
def content
|
238
|
-
@value.to_s(:quotes =>
|
238
|
+
@value.to_s(:quotes => '"')
|
239
239
|
end
|
240
240
|
|
241
241
|
# Returns a string representation of the @preamble object
|
242
|
-
def to_s
|
243
|
-
"@preamble{ #{
|
242
|
+
def to_s(options = {})
|
243
|
+
"@preamble{ #{content} }"
|
244
244
|
end
|
245
|
-
|
246
245
|
end
|
247
246
|
|
248
247
|
# Represents a @comment object.
|
249
248
|
class Comment < Element
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
end
|
254
|
-
|
255
|
-
def content=(content)
|
256
|
-
raise(ArgumentError, "BibTeX::#{self.class.name} content must be of type String; was: #{content.class.name}.") unless content.is_a?(::String)
|
249
|
+
attr_accessor :content
|
250
|
+
|
251
|
+
def initialize(content = '')
|
257
252
|
@content = content
|
258
253
|
end
|
259
254
|
|
260
|
-
def
|
261
|
-
@content
|
255
|
+
def to_s(options = {})
|
256
|
+
"@comment{ #@content }"
|
262
257
|
end
|
263
|
-
|
264
|
-
def to_s
|
265
|
-
['@comment{ ',content,'}'].join
|
266
|
-
end
|
267
|
-
|
268
258
|
end
|
269
259
|
|
270
260
|
# Represents text in a `.bib' file, but outside of an
|
271
261
|
# actual BibTeX object; typically, such text is treated
|
272
262
|
# as a comment and is ignored by the parser.
|
273
263
|
# BibTeX-Ruby offers this class to allows for
|
274
|
-
# post-processing of this type of `meta'
|
264
|
+
# post-processing of this type of `meta' content. If you
|
275
265
|
# want the parser to include +MetaComment+ objects, you
|
276
|
-
# need to add +:
|
266
|
+
# need to add +:meta_content+ to the parser's +:include+
|
277
267
|
# option.
|
278
|
-
class
|
279
|
-
|
280
|
-
|
268
|
+
class MetaContent < Element
|
269
|
+
attr_accessor :content
|
270
|
+
|
271
|
+
def initialize(content = '')
|
272
|
+
@content = content
|
281
273
|
end
|
274
|
+
|
275
|
+
def to_s(options = {}); @content; end
|
282
276
|
end
|
283
277
|
|
284
278
|
end
|