bibtex-ruby 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bibtex-ruby might be problematic. Click here for more details.

Files changed (67) hide show
  1. data/Gemfile +6 -1
  2. data/Gemfile.lock +48 -5
  3. data/History.txt +16 -1
  4. data/Manifest +43 -19
  5. data/README.md +178 -167
  6. data/Rakefile +26 -5
  7. data/auto.watchr +6 -0
  8. data/bibtex-ruby.gemspec +8 -5
  9. data/examples/bib2html.rb +28 -18
  10. data/features/bibtex.feature +96 -0
  11. data/features/entries.feature +67 -0
  12. data/features/issues/slash_keys.feature +21 -0
  13. data/features/names.feature +72 -0
  14. data/features/preambles.feature +27 -0
  15. data/features/query.feature +56 -0
  16. data/features/replacement.feature +68 -0
  17. data/features/step_definitions/bibtex_steps.rb +74 -0
  18. data/features/step_definitions/name_steps.rb +13 -0
  19. data/features/strings.feature +52 -0
  20. data/features/support/env.rb +7 -0
  21. data/lib/bibtex.rb +5 -1
  22. data/lib/bibtex/bibliography.rb +218 -95
  23. data/lib/bibtex/bibtex.y +18 -15
  24. data/lib/bibtex/elements.rb +130 -136
  25. data/lib/bibtex/entry.rb +133 -69
  26. data/lib/bibtex/extensions.rb +0 -35
  27. data/lib/bibtex/lexer.rb +9 -9
  28. data/lib/bibtex/name_parser.output +464 -0
  29. data/lib/bibtex/name_parser.rb +490 -0
  30. data/lib/bibtex/names.rb +162 -0
  31. data/lib/bibtex/names.y +196 -0
  32. data/lib/bibtex/parser.output +5 -5
  33. data/lib/bibtex/parser.rb +19 -16
  34. data/lib/bibtex/replaceable.rb +52 -0
  35. data/lib/bibtex/utilities.rb +23 -5
  36. data/lib/bibtex/value.rb +201 -0
  37. data/lib/bibtex/version.rb +1 -1
  38. data/test/benchmark.rb +52 -0
  39. data/test/bibtex/test_bibliography.rb +141 -0
  40. data/test/bibtex/test_elements.rb +40 -0
  41. data/test/bibtex/test_entry.rb +99 -0
  42. data/test/bibtex/test_names.rb +23 -0
  43. data/test/bibtex/test_parser.rb +79 -0
  44. data/test/bibtex/test_string.rb +83 -0
  45. data/test/bibtex/test_utilities.rb +34 -0
  46. data/test/bibtex/test_value.rb +70 -0
  47. data/test/{bib/10_bibdesk.bib → fixtures/bibdesk.bib} +1 -1
  48. data/test/{bib/05_comment.bib → fixtures/comment.bib} +0 -0
  49. data/test/{bib/08_decoret.bib → fixtures/decoret.bib} +0 -0
  50. data/test/{bib/00_empty.bib → fixtures/empty.bib} +0 -0
  51. data/test/{bib/07_entry.bib → fixtures/entry.bib} +0 -0
  52. data/test/{bib/09_errors.bib → fixtures/errors.bib} +0 -0
  53. data/test/{bib/01_no_bibtex.bib → fixtures/no_bibtex.bib} +0 -0
  54. data/test/{bib/06_preamble.bib → fixtures/preamble.bib} +1 -1
  55. data/test/{bib/11_roundtrip.bib → fixtures/roundtrip.bib} +1 -1
  56. data/test/helper.rb +17 -2
  57. data/test/test_bibtex.rb +87 -93
  58. data/test/test_export.rb +18 -22
  59. metadata +85 -30
  60. data/test/bib/02_string.bib +0 -1
  61. data/test/bib/03_string.bib +0 -25
  62. data/test/bib/04_string_replacement.bib +0 -16
  63. data/test/test_comment.rb +0 -21
  64. data/test/test_entry.rb +0 -98
  65. data/test/test_preamble.rb +0 -39
  66. data/test/test_string.rb +0 -97
  67. data/test/test_utilities.rb +0 -36
@@ -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 META_COMMENT
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
- | META_COMMENT { result = BibTeX::MetaComment.new(val[0]) }
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
- @options = options
94
- @options[:include] ||= [:errors]
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 = self.debug?
102
+ @yydebug = debug?
100
103
 
101
- self.lexer.src = input
102
- self.lexer.analyse
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 = self.lexer.next_token
111
+ token = @lexer.next_token
109
112
  if token[0] == :ERROR
110
- self.include_errors? ? token : next_token
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 || ENV['DEBUG'] == true
120
+ @options[:debug] == true
118
121
  end
119
122
 
120
123
  def include_errors?
@@ -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).to_a
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
- # Returns a string representation of the object.
44
- def to_s
45
- self.content
46
- end
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
- { self.class.name.downcase => content }
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
- self.to_hash.to_yaml
109
+ to_hash.to_yaml
55
110
  end
56
111
 
57
- def to_json
112
+ def to_json(options = {})
58
113
  require 'json'
59
- self.to_hash.to_json
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(self.class.name.downcase)
65
- xml.text = self.content
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
- (type_comparison = self.class.name <=> other.class.name) == 0 ? self.to_s <=> other.to_s : type_comparison
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
- self.key = key.to_sym unless key.nil?
104
- self.value = value unless value.nil?
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 name of the constant)
164
+ # Sets the string's key (i.e., the symbol identifying the constant).
108
165
  def key=(key)
109
- raise(ArgumentError, "BibTeX::String key must be of type Symbol; was: #{key.class.name}.") unless key.is_a?(Symbol)
110
- @key = key
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
- # Sets the string's value (i.e., the string literal defined by the constant)
114
- def value=(value)
115
- raise(ArgumentError, "BibTeX::String 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 }
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(bibliography)
167
- bibliography.strings[@key] = @value
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(bibliography)
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
- [@key.to_s, value].join(' = ')
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
- { 'string' => { @key.to_s => @value.to_s(:quotes => %w(" ")) } }
206
+ def to_hash(options = {})
207
+ { :string => { @key => @value.to_s(:quotes => '"') } }
190
208
  end
191
209
 
192
- def to_xml
193
- xml = REXML::Element.new('string')
194
- key = REXML::Element.new('key')
195
- val = REXML::Element.new('value')
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 => %w(" "))
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
- def replace(hash)
221
- @value.replace_strings(hash)
222
- end
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 => %w(" "))
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{ #{ content } }"
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
- def initialize(content='')
252
- self.content = content
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 content
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' comment. If you
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 +:meta_comments+ to the parser's +:include+
266
+ # need to add +:meta_content+ to the parser's +:include+
277
267
  # option.
278
- class MetaComment < Comment
279
- def to_s
280
- @content
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