bibtex-ruby 2.0.12 → 2.1.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.

data/Rakefile CHANGED
@@ -1,21 +1,24 @@
1
- # -*- ruby -*-
2
- lib = File.expand_path('../lib/', __FILE__)
3
- $:.unshift lib unless $:.include?(lib)
1
+ # encoding: utf-8
2
+
3
+ require 'bundler'
4
+ begin
5
+ Bundler.setup
6
+ rescue Bundler::BundlerError => e
7
+ $stderr.puts e.message
8
+ $stderr.puts "Run `bundle install` to install missing gems"
9
+ exit e.status_code
10
+ end
11
+
12
+ $:.unshift(File.join(File.dirname(__FILE__), './lib'))
13
+
4
14
 
5
15
  require 'rake/clean'
6
16
  require 'rake/testtask'
7
17
 
8
- require 'rdoc/task'
9
-
10
18
  require 'bibtex/version'
11
19
 
12
- RDoc::Task.new(:rdoc => ['clean','racc']) do |rd|
13
- rd.main = 'README.md'
14
- rd.title = "BibTeX-Ruby Documentation"
15
- rd.rdoc_files.include('README.md',"lib/**/*.rb")
16
- rd.rdoc_dir = "doc/html"
17
- rd.options << '--webcvs=http://github.com/inukshuk/bibtex-ruby/tree/master/'
18
- end
20
+ require 'yard'
21
+ YARD::Rake::YardocTask.new
19
22
 
20
23
  Rake::TestTask.new(:test_task) do |t|
21
24
  t.libs << 'lib' << 'test'
@@ -31,12 +34,12 @@ begin
31
34
  rescue LoadError
32
35
  desc 'Cucumber rake task not available'
33
36
  task :features do
34
- abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin'
37
+ abort 'Cucumber rake task is not available. Please install cucumber as a gem or plugin'
35
38
  end
36
39
  end
37
40
 
38
41
 
39
- task :default => ['racc']
42
+ task :default => [:test, :features]
40
43
 
41
44
  desc 'Generates the BibTeX parser'
42
45
  task :racc => ['lib/bibtex/parser.rb','lib/bibtex/name_parser.rb']
@@ -54,6 +57,18 @@ file 'lib/bibtex/name_parser.rb' => ['lib/bibtex/names.y'] do
54
57
  sh 'bundle exec racc -o lib/bibtex/name_parser.rb lib/bibtex/names.y'
55
58
  end
56
59
 
60
+ desc 'Run an IRB session with BibTeX-Ruby loaded'
61
+ task :console, [:script] do |t,args|
62
+ ARGV.clear
63
+
64
+ require 'irb'
65
+ require 'bibtex'
66
+
67
+ IRB.conf[:SCRIPT] = args.script
68
+ IRB.start
69
+ end
70
+
71
+
57
72
  desc 'Runs the benchmarks (and plots the results)'
58
73
  task :benchmark => ['racc'] do
59
74
  require File.expand_path('../test/benchmark.rb', __FILE__)
@@ -69,7 +84,9 @@ end
69
84
  desc 'Updates the Manifest file'
70
85
  task :manifest => ['clean', 'racc'] do
71
86
  m = File.open('Manifest', 'w')
72
- m.print FileList['**/*'].reject{ |f| f.end_with?('rbc') }.join("\n")
87
+ m.print FileList['**/*'].reject{ |f|
88
+ f.start_with?('coverage') || f.end_with?('rbc')
89
+ }.join("\n")
73
90
  m.close
74
91
  end
75
92
 
@@ -89,7 +106,4 @@ CLEAN.include('lib/bibtex/parser.rb')
89
106
  CLEAN.include('lib/bibtex/parser.output')
90
107
  CLEAN.include('lib/bibtex/name_parser.rb')
91
108
  CLEAN.include('lib/bibtex/name_parser.output')
92
- CLEAN.include('doc/html')
93
109
  CLEAN.include('*.gem')
94
-
95
- # vim: syntax=ruby
data/bibtex-ruby.gemspec CHANGED
@@ -9,12 +9,12 @@ Gem::Specification.new do |s|
9
9
  s.version = BibTeX::Version::STRING.dup
10
10
  s.platform = Gem::Platform::RUBY
11
11
  s.authors = ['Sylvester Keil']
12
- s.email = ['http://sylvester.keil.or.at']
12
+ s.email = ['sylvester@keil.or.at']
13
13
  s.homepage = 'http://inukshuk.github.com/bibtex-ruby'
14
14
  s.license = 'GPL-3'
15
15
 
16
16
  s.summary = 'A BibTeX parser, converter and API for Ruby.'
17
- s.description = <<-END_DESCRIPTION
17
+ s.description = <<-END_DESCRIPTION.gsub(/^\s+/, '')
18
18
  BibTeX-Ruby is the Rubyist's swiss-army-knife for all things BibTeX. It
19
19
  includes a parser for all common BibTeX objects (@string, @preamble,
20
20
  @comment and regular entries) and a sophisticated name parser that
@@ -28,18 +28,12 @@ Gem::Specification.new do |s|
28
28
  s.add_runtime_dependency('latex-decode', ['>=0.0.6'])
29
29
  s.add_runtime_dependency('multi_json', ['~>1.3'])
30
30
 
31
- s.add_development_dependency('rake', ['~>0.9'])
32
- s.add_development_dependency('racc', ['~>1.4'])
33
- s.add_development_dependency('rdoc', ['~>3.9'])
34
-
35
31
  s.files = File.open('Manifest').readlines.map(&:chomp)
36
32
  s.test_files = Dir.glob('test/**/test*.rb')
37
33
  s.executables = []
38
34
  s.require_path = 'lib'
39
35
 
40
- s.rdoc_options = %w{--line-numbers --inline-source --title "BibTeX-Ruby\ Documentation" --main README.md --webcvs=http://github.com/inukshuk/bibtex-ruby/tree/master/}
41
- s.extra_rdoc_files = %w{README.md}
42
-
36
+ s.has_rdoc = 'yard'
43
37
  end
44
38
 
45
39
  # vim: syntax=ruby
@@ -59,4 +59,42 @@ Feature: Searching in BibTeX bibliographies
59
59
  Then there should be exactly 3 matches
60
60
  When I search for "@*[year=2007]"
61
61
  Then there should be exactly 1 match
62
-
62
+
63
+ @query
64
+ Scenario: Find entries using compound queries
65
+ Given the bibliography:
66
+ """
67
+ @book{pickaxe,
68
+ Address = {Raleigh, North Carolina},
69
+ Author = {Thomas, Dave, and Fowler, Chad, and Hunt, Andy},
70
+ Date-Added = {2010-08-05 09:54:07 +0200},
71
+ Date-Modified = {2010-08-05 10:07:01 +0200},
72
+ Keywords = {ruby},
73
+ Publisher = {The Pragmatic Bookshelf},
74
+ Series = {The Facets of Ruby},
75
+ Title = {Programming Ruby 1.9: The Pragmatic Programmer's Guide},
76
+ Year = {2009}
77
+ }
78
+ @article{a1,
79
+ Title = {An Article},
80
+ Keywords = {@book}
81
+ }
82
+ @book{dragon,
83
+ Address = {Boston},
84
+ Author = {Aho, Alfred V., and Lam, Monica S., and Ullman, Jeffrey D.},
85
+ Booktitle = {Compilers: Principles, Techniques, and Tools},
86
+ Date-Added = {2010-08-05 09:57:15 +0200},
87
+ Date-Modified = {2010-08-05 10:06:32 +0200},
88
+ Edition = {second},
89
+ Keywords = {compiler, lex, yacc},
90
+ Publisher = {Addison Wesley},
91
+ Title = {Compilers: Principles, Techniques, and Tools},
92
+ Year = {2007}
93
+ }
94
+ """
95
+ When I search for "@*[keywords = @book || edition = second]"
96
+ Then there should be exactly 2 matches
97
+ When I search for "@*[keywords = @book && edition = second]"
98
+ Then there should be exactly 0 matches
99
+ When I search for "@*[keywords = @book && title ~= Article]"
100
+ Then there should be exactly 1 match
@@ -1,6 +1,18 @@
1
+ begin
2
+ if RUBY_VERSION > '1.8'
3
+ require 'debugger'
4
+ require 'simplecov'
5
+ else
6
+ require 'ruby-debug'
7
+ Debugger.start
8
+ end
9
+ rescue LoadError
10
+ # ignore
11
+ end
12
+
1
13
  require 'bibtex'
2
14
  require 'minitest/unit'
3
15
 
4
16
  World do
5
17
  extend MiniTest::Assertions
6
- end
18
+ end
data/lib/bibtex.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  #--
2
2
  # BibTeX-Ruby
3
- # Copyright (C) 2010-2011 Sylvester Keil <sylvester.keil.or.at>
3
+ # Copyright (C) 2010-2012 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
@@ -56,10 +56,13 @@ end
56
56
  # Debugger.start
57
57
 
58
58
  require 'bibtex/extensions'
59
- require 'bibtex/compatibility'
59
+
60
60
  require 'bibtex/value'
61
61
  require 'bibtex/filters'
62
62
  require 'bibtex/name_parser'
63
+
64
+ require 'bibtex/compatibility'
65
+
63
66
  require 'bibtex/names'
64
67
  require 'bibtex/replaceable'
65
68
  require 'bibtex/elements'
@@ -1,6 +1,6 @@
1
1
  #--
2
2
  # BibTeX-Ruby
3
- # Copyright (C) 2010-2011 Sylvester Keil <sylvester.keil.or.at>
3
+ # Copyright (C) 2010-2012 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
@@ -1,3 +1,4 @@
1
+ # coding: utf-8
1
2
 
2
3
  unless Symbol.include?(Comparable)
3
4
  class Symbol
@@ -7,4 +8,11 @@ unless Symbol.include?(Comparable)
7
8
  to_s <=> other.to_s
8
9
  end
9
10
  end
10
- end
11
+ end
12
+
13
+ if RUBY_VERSION < '1.9'
14
+ $KCODE = 'u'
15
+ require 'jcode'
16
+
17
+ BibTeX::NameParser.patterns[:upper] = /[[:upper:]ÄÖÜ][^\t\r\n\s\{\}\d\\,]*/o
18
+ end
@@ -1,17 +1,17 @@
1
1
  #--
2
2
  # BibTeX-Ruby
3
- # Copyright (C) 2010-2011 Sylvester Keil <sylvester.keil.or.at>
4
- #
3
+ # Copyright (C) 2010-2012 Sylvester Keil <sylvester.keil.or.at>
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
7
7
  # the Free Software Foundation, either version 3 of the License, or
8
8
  # (at your option) any later version.
9
- #
9
+ #
10
10
  # This program is distributed in the hope that it will be useful,
11
11
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
12
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
13
  # GNU General Public License for more details.
14
- #
14
+ #
15
15
  # You should have received a copy of the GNU General Public License
16
16
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
17
  #++
@@ -23,10 +23,10 @@ module BibTeX
23
23
  #
24
24
  class Element
25
25
  include Comparable
26
-
26
+
27
27
  attr_writer :id
28
28
  attr_reader :bibliography
29
-
29
+
30
30
  # Returns an array of BibTeX elements.
31
31
  def self.parse(input, options = {})
32
32
  case input
@@ -45,7 +45,7 @@ module BibTeX
45
45
  raise ArgumentError, "failed to parse Element from #{input.inspect}"
46
46
  end
47
47
  end
48
-
48
+
49
49
  # Returns a string containing the object's content.
50
50
  def content(options = {}); ''; end
51
51
 
@@ -54,33 +54,33 @@ module BibTeX
54
54
 
55
55
  # Invokes BibTeX string joining on this element.
56
56
  def join; self; end
57
-
57
+
58
58
  # Returns the element's id.
59
59
  def id; @id ||= object_id.to_s; end
60
-
60
+
61
61
  # Returns the BibTeX type (if applicable) or the normalized class name.
62
62
  def type
63
63
  self.class.name.split(/::/).last.gsub(/([[:lower:]])([[:upper:]])/) { "#{$1}_#{$2}" }.downcase.intern
64
64
  end
65
-
65
+
66
66
  # Returns a list of names for that Element. All Elements except Entries return an empty list.
67
67
  def names
68
68
  []
69
69
  end
70
-
70
+
71
71
  def has_type?(type)
72
72
  self.type == type.intern || defined?(type) == 'constant' && is_a?(type)
73
73
  end
74
-
75
- [:entry, :book, :article, :collection, :string, :preamble, :comment]. each do |type|
74
+
75
+ [:entry, :book, :article, :collection, :string, :preamble, :comment].each do |type|
76
76
  method_id = "#{type}?"
77
77
  define_method(method_id) { has_type?(type) } unless method_defined?(method_id)
78
78
  end
79
-
79
+
80
80
  # Returns true if the element matches the given query.
81
81
  def matches?(query)
82
82
  return true if query.nil? || query.respond_to?(:empty?) && query.empty?
83
-
83
+
84
84
  case query
85
85
  when Symbol
86
86
  query.to_s == id.to_s
@@ -88,63 +88,61 @@ module BibTeX
88
88
  query == self
89
89
  when Regexp
90
90
  to_s.match(query)
91
+ when /^\/(.+)\/$/
92
+ to_s.match(Regexp.new($1))
91
93
  when /@(\*|\w+)(?:\[([^\]]*)\])?/
92
94
  query.scan(/@(\*|\w+)(?:\[([^\]]*)\])?/).any? do |type, condition|
93
- has_type?(type) && ( condition.nil? || meets?(condition.split(/,\s*/)) )
95
+ if has_type?(type)
96
+ if condition.nil? || condition.empty?
97
+ true
98
+ else
99
+ condition.to_s.split(/\s*\|\|\s*/).any? do |conditions|
100
+ meets_all? conditions.split(/\s*(?:,|&&)\s*/)
101
+ end
102
+ end
103
+ end
94
104
  end
95
- when /^\/(.+)\/$/
96
- to_s.match(Regexp.new($1))
97
105
  else
98
106
  id.to_s == query
99
- end
107
+ end
100
108
  end
101
-
109
+
102
110
  alias === matches?
103
111
  alias match? matches?
104
-
105
- # Returns true if the element meets all of the given conditions.
106
- def meets?(*conditions)
107
- conditions.flatten.all? do |condition|
108
- property, operator, value = condition.split(/\s*([!~\/\^<>]?=)\s*/)
109
-
110
- if property.nil?
111
- true
112
- else
113
- case operator
114
- when '!=', '/='
115
- !respond_to?(property) || send(property).to_s != value
116
- when '^='
117
- respond_to?(property) && send(property).to_s.match("^#{value}")
118
- when '~='
119
- respond_to?(property) && send(property).to_s.match(value)
120
- when '<='
121
- respond_to?(property) && send(property).to_i <= value.to_i
122
- when '>='
123
- respond_to?(property) && send(property).to_i >= value.to_i
124
- else
125
- respond_to?(property) && send(property).to_s == value
126
- end
127
- end
112
+
113
+ def meets_all?(*conditions)
114
+ meets? conditions.flatten, :all?
115
+ end
116
+ alias meet_all? meets_all?
117
+
118
+ def meets_any?(*conditions)
119
+ meets? conditions.flatten, :any?
120
+ end
121
+ alias meet_any? meets_any?
122
+
123
+ # Returns true if the element meets all or any of the given conditions.
124
+ def meets?(conditions, op = :all?)
125
+ conditions.send(op) do |condition|
126
+ meets_condition? condition
128
127
  end
129
128
  end
130
-
131
129
  alias meet? meets?
132
-
130
+
133
131
  alias to_s content
134
-
132
+
135
133
  def to_hash(options = {})
136
134
  { type => content }
137
135
  end
138
-
136
+
139
137
  def to_yaml(options = {})
140
138
  require 'yaml'
141
139
  to_hash.to_yaml
142
140
  end
143
-
141
+
144
142
  def to_json(options = {})
145
143
  MultiJson.dump(to_hash(options))
146
144
  end
147
-
145
+
148
146
  def to_xml(options = {})
149
147
  require 'rexml/document'
150
148
  xml = REXML::Element.new(type)
@@ -158,25 +156,52 @@ module BibTeX
158
156
  @bibliography = bibliography
159
157
  self
160
158
  end
161
-
159
+
162
160
  # Called when the element was removed from a bibliography.
163
161
  def removed_from_bibliography(bibliography)
164
162
  @bibliography = nil
165
163
  self
166
164
  end
167
-
165
+
168
166
  def <=>(other)
169
167
  return nil unless other.respond_to? :type and other.respond_to? :to_s
170
168
  [type, to_s] <=> [other.type, other.to_s]
171
169
  end
172
-
170
+
173
171
  # Returns the Element as a nicely formatted string.
174
172
  def inspect
175
173
  "#<#{self.class} #{content.gsub(/\n/, ' ')}>"
176
174
  end
175
+
176
+ private
177
+
178
+ def meets_condition?(condition)
179
+ property, operator, value = condition.split(/\s*([!~\/\^<>]?=)\s*/)
180
+
181
+ if property.nil?
182
+ true
183
+ else
184
+ actual = respond_to?(property) ? send(property) : nil
185
+
186
+ case operator
187
+ when '!=', '/='
188
+ actual.nil? || actual.to_s != value
189
+ when '^='
190
+ !actual.nil? && actual.to_s.match("^#{value}")
191
+ when '~='
192
+ !actual.nil? && actual.to_s.match(value)
193
+ when '<='
194
+ !actual.nil? && actual.to_i <= value.to_i
195
+ when '>='
196
+ !actual.nil? && actual.to_i >= value.to_i
197
+ else
198
+ !actual.nil? && actual.to_s == value
199
+ end
200
+ end
201
+ end
177
202
  end
178
203
 
179
-
204
+
180
205
  #
181
206
  # Represents a @string object.
182
207
  #
@@ -187,9 +212,9 @@ module BibTeX
187
212
  # @string and @preamble objects, as well as in field values
188
213
  # of regular entries.
189
214
  #
190
- class String < Element
215
+ class String < Element
191
216
  include Replaceable
192
-
217
+
193
218
  attr_reader :key
194
219
 
195
220
  # Creates a new instance.
@@ -201,7 +226,7 @@ module BibTeX
201
226
  # Sets the string's key (i.e., the symbol identifying the constant).
202
227
  def key=(key)
203
228
  raise(ArgumentError, "keys must be convertible to Symbol; was: #{type.class.name}.") unless type.respond_to?(:to_sym)
204
-
229
+
205
230
  unless bibliography.nil?
206
231
  bibliography.strings.delete(@key)
207
232
  bibliography.strings[key.to_sym] = self
@@ -214,7 +239,7 @@ module BibTeX
214
239
  def [](key)
215
240
  @key == key ? @value : nil
216
241
  end
217
-
242
+
218
243
 
219
244
  # Called when the element was added to a bibliography.
220
245
  def added_to_bibliography(bibliography)
@@ -222,7 +247,7 @@ module BibTeX
222
247
  bibliography.strings[@key] = self
223
248
  self
224
249
  end
225
-
250
+
226
251
  # Called when the element was removed from a bibliography.
227
252
  def removed_from_bibliography(bibliography)
228
253
  super
@@ -239,23 +264,23 @@ module BibTeX
239
264
  def to_s(options = {})
240
265
  "@string{ #{content} }"
241
266
  end
242
-
267
+
243
268
  def to_hash(options = {})
244
269
  { :string => { @key => @value.to_s(:quotes => '"') } }
245
270
  end
246
-
271
+
247
272
  def to_xml(options = {})
248
273
  require 'rexml/document'
249
-
274
+
250
275
  xml = REXML::Element.new(:string)
251
-
276
+
252
277
  k, v = REXML::Element.new(:key), REXML::Element.new(:value)
253
278
  k.text = key.to_s
254
279
  v.text = value.to_s(:quotes => '"')
255
-
280
+
256
281
  xml.add_elements(k)
257
282
  xml.add_elements(v)
258
-
283
+
259
284
  xml
260
285
  end
261
286
  end
@@ -273,7 +298,7 @@ module BibTeX
273
298
  def initialize(value = '')
274
299
  @value = Value.new(value)
275
300
  end
276
-
301
+
277
302
  # Returns a string representation of the @preamble's content.
278
303
  def content
279
304
  @value.to_s(:quotes => '"')
@@ -288,7 +313,7 @@ module BibTeX
288
313
  # Represents a @comment object.
289
314
  class Comment < Element
290
315
  attr_accessor :content
291
-
316
+
292
317
  def initialize(content = '')
293
318
  @content = content
294
319
  end
@@ -300,7 +325,7 @@ module BibTeX
300
325
 
301
326
  # Represents text in a `.bib' file, but outside of an
302
327
  # actual BibTeX object; typically, such text is treated
303
- # as a comment and is ignored by the parser.
328
+ # as a comment and is ignored by the parser.
304
329
  # BibTeX-Ruby offers this class to allows for
305
330
  # post-processing of this type of `meta' content. If you
306
331
  # want the parser to include +MetaComment+ objects, you
@@ -308,7 +333,7 @@ module BibTeX
308
333
  # option.
309
334
  class MetaContent < Element
310
335
  attr_accessor :content
311
-
336
+
312
337
  def initialize(content = '')
313
338
  @content = content
314
339
  end