bibtex-ruby 1.3.12 → 2.0.0pre1
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/Gemfile +7 -0
- data/Gemfile.lock +12 -13
- data/Manifest +1 -1
- data/README.md +114 -22
- data/bibtex-ruby.gemspec +13 -7
- data/features/issues/crossref.feature +62 -0
- data/features/names.feature +1 -1
- data/features/step_definitions/bibtex_steps.rb +2 -2
- data/lib/bibtex.rb +3 -1
- data/lib/bibtex/bibliography.rb +84 -32
- data/lib/bibtex/elements.rb +49 -30
- data/lib/bibtex/entry.rb +243 -72
- data/lib/bibtex/error.rb +11 -2
- data/lib/bibtex/lexer.rb +8 -8
- data/lib/bibtex/names.rb +29 -4
- data/lib/bibtex/value.rb +9 -9
- data/lib/bibtex/version.rb +1 -1
- data/lib/bibtex/version.rbc +2 -2
- data/test/bibtex/test_bibliography.rb +59 -31
- data/test/bibtex/test_elements.rb +31 -7
- data/test/bibtex/test_entry.rb +220 -41
- data/test/bibtex/test_filters.rb +6 -6
- data/test/bibtex/test_lexer.rb +1 -1
- data/test/bibtex/test_name_parser.rb +4 -4
- data/test/bibtex/test_names.rb +5 -5
- data/test/bibtex/test_parser.rb +23 -23
- data/test/bibtex/test_string.rb +6 -6
- data/test/bibtex/test_value.rb +32 -32
- data/test/helper.rb +0 -1
- data/test/test_bibtex.rb +5 -6
- data/test/test_export.rb +2 -3
- metadata +32 -72
- data/profile.png +0 -0
data/Gemfile
CHANGED
@@ -7,6 +7,13 @@ group :debug do
|
|
7
7
|
gem 'rbx-trepanning', :platforms => [:rbx]
|
8
8
|
end
|
9
9
|
|
10
|
+
group :test do
|
11
|
+
gem 'minitest', :platforms => [:ruby_18, :jruby, :rbx]
|
12
|
+
gem 'mynyml-redgreen', ['~>0.7']
|
13
|
+
gem 'autowatchr', ['~>0.1']
|
14
|
+
gem 'cucumber', ['~>1.0']
|
15
|
+
end
|
16
|
+
|
10
17
|
group :profile do
|
11
18
|
gem 'ruby-prof', ['~>0.10']
|
12
19
|
gem 'gnuplot', ['~>2.3']
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
bibtex-ruby (
|
4
|
+
bibtex-ruby (2.0.0pre1)
|
5
5
|
latex-decode (>= 0.0.3)
|
6
|
+
multi_json (~> 1.0)
|
6
7
|
|
7
8
|
GEM
|
8
9
|
remote: http://rubygems.org/
|
@@ -12,29 +13,28 @@ GEM
|
|
12
13
|
watchr
|
13
14
|
builder (3.0.0)
|
14
15
|
columnize (0.3.4)
|
15
|
-
cucumber (0.
|
16
|
+
cucumber (1.0.2)
|
16
17
|
builder (>= 2.1.2)
|
17
18
|
diff-lcs (>= 1.1.2)
|
18
|
-
gherkin (~> 2.4.
|
19
|
+
gherkin (~> 2.4.5)
|
19
20
|
json (>= 1.4.6)
|
20
21
|
term-ansicolor (>= 1.0.5)
|
21
22
|
diff-lcs (1.1.2)
|
22
|
-
gherkin (2.4.
|
23
|
+
gherkin (2.4.18)
|
23
24
|
json (>= 1.4.6)
|
24
|
-
gherkin (2.4.
|
25
|
+
gherkin (2.4.18-java)
|
25
26
|
json (>= 1.4.6)
|
26
27
|
gnuplot (2.3.6)
|
27
|
-
json (1.5.
|
28
|
-
json (1.5.
|
28
|
+
json (1.5.4)
|
29
|
+
json (1.5.4-java)
|
29
30
|
latex-decode (0.0.3)
|
30
31
|
unicode (>= 0.4)
|
31
32
|
linecache (0.46)
|
32
33
|
rbx-require-relative (> 0.0.4)
|
33
34
|
linecache19 (0.5.12)
|
34
35
|
ruby_core_source (>= 0.1.4)
|
35
|
-
|
36
|
-
|
37
|
-
minitest (2.1.0)
|
36
|
+
minitest (2.3.1)
|
37
|
+
multi_json (1.0.3)
|
38
38
|
mynyml-redgreen (0.7.1)
|
39
39
|
term-ansicolor (>= 1.0.4)
|
40
40
|
racc (1.4.6)
|
@@ -75,10 +75,9 @@ PLATFORMS
|
|
75
75
|
DEPENDENCIES
|
76
76
|
autowatchr (~> 0.1)
|
77
77
|
bibtex-ruby!
|
78
|
-
cucumber (~> 0
|
78
|
+
cucumber (~> 1.0)
|
79
79
|
gnuplot (~> 2.3)
|
80
|
-
|
81
|
-
mini_shoulda (~> 0.3)
|
80
|
+
minitest
|
82
81
|
mynyml-redgreen (~> 0.7)
|
83
82
|
racc (~> 1.4)
|
84
83
|
rake (~> 0.9)
|
data/Manifest
CHANGED
@@ -17,6 +17,7 @@ features/bibtex.feature
|
|
17
17
|
features/entries.feature
|
18
18
|
features/issues
|
19
19
|
features/issues/braced_strings.feature
|
20
|
+
features/issues/crossref.feature
|
20
21
|
features/issues/latex_filter.feature
|
21
22
|
features/issues/number_keys.feature
|
22
23
|
features/issues/parse_months.feature
|
@@ -75,7 +76,6 @@ lib/bibtex/version.rb
|
|
75
76
|
lib/bibtex/version.rbc
|
76
77
|
lib/bibtex.rb
|
77
78
|
lib/bibtex.rbc
|
78
|
-
profile.png
|
79
79
|
test
|
80
80
|
test/benchmark.rb
|
81
81
|
test/bibtex
|
data/README.md
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
BibTeX-Ruby
|
2
2
|
===========
|
3
3
|
|
4
|
-
BibTeX-Ruby is
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
4
|
+
BibTeX-Ruby is the Rubyist's swiss-army-knife for all things BibTeX. It
|
5
|
+
includes a parser for all common BibTeX objects (@string, @preamble,
|
6
|
+
@comment and regular entries) and a sophisticated name parser that
|
7
|
+
tokenizes correctly formatted names; BibTeX-Ruby recognizes BibTeX string
|
8
|
+
replacements, joins values containing multiple strings or variables,
|
9
|
+
supports cross-references, and decodes common LaTeX formatting
|
10
|
+
instructions to unicode; if you are in a hurry, it also allows for easy
|
11
|
+
export/conversion to formats such as YAML, JSON, CiteProc, and XML (BibTeXML).
|
12
|
+
|
13
|
+
For a list of projects using BibTeX-Ruby, see
|
14
|
+
[the project wiki](https://github.com/inukshuk/bibtex-ruby/wiki/Projects-Using-BibTeX-Ruby).
|
12
15
|
|
13
16
|
|
14
17
|
Quickstart
|
@@ -19,9 +22,9 @@ Quickstart
|
|
19
22
|
>> require 'bibtex'
|
20
23
|
=> true
|
21
24
|
>> b = BibTeX.open('./ruby.bib')
|
22
|
-
>> b[
|
25
|
+
>> b['pickaxe']
|
23
26
|
=> "2009"
|
24
|
-
>> b[
|
27
|
+
>> b['pickaxe'].title
|
25
28
|
=> "Programming Ruby 1.9: The Pragmatic Programmer's Guide"
|
26
29
|
>> b[:pickaxe].author.length
|
27
30
|
=> 3
|
@@ -39,7 +42,8 @@ Quickstart
|
|
39
42
|
BibTeX-Ruby helps you convert your bibliography to JSON, XML, or YAML;
|
40
43
|
alternatively, you can export to the JSON format used by
|
41
44
|
[CSL](http://citationstyles.org) processors and render the bibliography in
|
42
|
-
many styles
|
45
|
+
one of [many different styles](https://github.com/citation-style-language/styles)
|
46
|
+
([previews](http://www.zotero.org/styles/)):
|
43
47
|
|
44
48
|
>> require 'citeproc' # requires the citeproc-ruby gem
|
45
49
|
=> true
|
@@ -80,10 +84,9 @@ Requirements
|
|
80
84
|
|
81
85
|
* The parser generator [racc](http://i.loveruby.net/en/projects/racc/) is
|
82
86
|
required to generate the BibTeX parser and the name parser.
|
83
|
-
* The **json** gem is required on older Ruby versions for JSON export.
|
84
87
|
|
85
|
-
The
|
86
|
-
been confirmed to work with REE
|
88
|
+
The BibTeX-Ruby gem has been tested on Ruby versions 1.8.7 and 1.9.2; it has
|
89
|
+
been confirmed to work with REE, JRuby, and Rubinius;
|
87
90
|
however, there have been some [issues](https://github.com/inukshuk/bibtex-ruby/issues)
|
88
91
|
with MacRuby implementations.
|
89
92
|
|
@@ -139,6 +142,27 @@ Instead of parsing strings you can also create BibTeX elements directly in Ruby:
|
|
139
142
|
> book.key = :mybook
|
140
143
|
> bib << book
|
141
144
|
|
145
|
+
### Cross References
|
146
|
+
|
147
|
+
From version 2.0, BibTeX-Ruby correctly resolves entry cross-references, which are commonly used for entries with type `inbook`, `incollection`, and `inproceedings`. When an entry has a valid citation key in field `crossref`, BibTeX-Ruby will return any fields inherited from the parent entry:
|
148
|
+
|
149
|
+
> b = BibTeX.parse <<-END
|
150
|
+
@inbook{fraassen_1989b,
|
151
|
+
Crossref = {fraassen_1989},
|
152
|
+
Pages = {40-64},
|
153
|
+
Title = {Ideal Science: David Lewis's Account of Laws},
|
154
|
+
}
|
155
|
+
|
156
|
+
@book{fraassen_1989,
|
157
|
+
Address = {Oxford},
|
158
|
+
Author = {Bas C. van Fraassen},
|
159
|
+
Publisher = {Oxford University Press},
|
160
|
+
Title = {Laws and Symmetry},
|
161
|
+
Year = 1989
|
162
|
+
}
|
163
|
+
END
|
164
|
+
> b['fraassen_1989b'].booktitle
|
165
|
+
=> <"Laws and Symmetry">
|
142
166
|
|
143
167
|
### Queries
|
144
168
|
|
@@ -274,21 +298,22 @@ Conditional conversions are also supported:
|
|
274
298
|
>> faust1 = '@book{faust1, title = {Faust: Der Trag\"odie Erster Teil}}'
|
275
299
|
>> faust2 = '@book{faust2, title = {Faust: Der Trag\"odie Zweiter Teil}}'
|
276
300
|
>> p BibTeX.parse(faust1 + faust2).convert(:latex) { |e| e.key == :faust2 }.to_s
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
301
|
+
@book{faust1,
|
302
|
+
title = {Faust: Der Trag\"odie Erster Teil}
|
303
|
+
}
|
304
|
+
@book{faust2,
|
305
|
+
title = {Faust: Der Tragödie Zweiter Teil}
|
306
|
+
}
|
283
307
|
|
284
308
|
If you need to express a condition on the basis of individual fields, use the
|
285
309
|
conversion methods of BibTeX::Entry with a block instead (the block will be
|
286
310
|
passed the key and value of each field prior to conversion).
|
287
311
|
|
288
|
-
###
|
312
|
+
### Exports
|
289
313
|
|
290
314
|
Furthermore, BibTeX-Ruby allows you to export your bibliography for processing
|
291
315
|
by other tools. Currently supported formats include YAML, JSON, and XML.
|
316
|
+
|
292
317
|
Of course, you can also export your bibliography back to BibTeX; if you include
|
293
318
|
`:meta_content', your export should be identical to the original '.bib' file,
|
294
319
|
except for whitespace, blank lines and letter case (BibTeX-Ruby will downcase
|
@@ -300,6 +325,52 @@ BibTeX to YAML converter:
|
|
300
325
|
|
301
326
|
>> BibTeX.open('example.bib').to_yaml
|
302
327
|
|
328
|
+
Starting with version 2.0, BibTeX-Ruby's `#to_xml` exports your bibliography
|
329
|
+
to the [BibTeXML](http//bibtexml.sf.net/) format. By passing the option
|
330
|
+
`:extended => true` you can make use of the BibTeXML's extended format which
|
331
|
+
will return individual person elements and name tokens (provided you have
|
332
|
+
successfully parsed the names of your bibliography).
|
333
|
+
|
334
|
+
> BibTeX.parse(<<-END).to_xml(:extended => true).write($stdout, 2)
|
335
|
+
" @book{pickaxe,
|
336
|
+
" Address = {Raleigh, North Carolina},
|
337
|
+
" Author = {Thomas, Dave, and Fowler, Chad, and Hunt, Andy},
|
338
|
+
" Publisher = {The Pragmatic Bookshelf},
|
339
|
+
" Title = {Programming Ruby 1.9: The Pragmatic Programmer's Guide},
|
340
|
+
" Year = {2009}
|
341
|
+
" }
|
342
|
+
" END
|
343
|
+
|
344
|
+
This example parse a BibTeX entry, formats it as extended BibTeXML,
|
345
|
+
and writes the following XML to standard out:
|
346
|
+
|
347
|
+
<?xml version='1.0' encoding='UTF-8'?>
|
348
|
+
<bibtex:file xmlns:bibtex='http://bibtexml.sf.net/'>
|
349
|
+
<bibtex:entry id='pickaxe'>
|
350
|
+
<bibtex:book>
|
351
|
+
<bibtex:address>Raleigh, North Carolina</bibtex:address>
|
352
|
+
<bibtex:person>
|
353
|
+
<bibtex:first>Dave</bibtex:first>
|
354
|
+
<bibtex:last>Thomas</bibtex:last>
|
355
|
+
</bibtex:person>
|
356
|
+
<bibtex:person>
|
357
|
+
<bibtex:first>Chad</bibtex:first>
|
358
|
+
<bibtex:last>Fowler</bibtex:last>
|
359
|
+
</bibtex:person>
|
360
|
+
<bibtex:person>
|
361
|
+
<bibtex:first>Andy</bibtex:first>
|
362
|
+
<bibtex:last>Hunt</bibtex:last>
|
363
|
+
</bibtex:person>
|
364
|
+
<bibtex:author/>
|
365
|
+
<bibtex:publisher>The Pragmatic Bookshelf</bibtex:publisher>
|
366
|
+
<bibtex:title>
|
367
|
+
Programming Ruby 1.9: The Pragmatic Programmer's Guide
|
368
|
+
</bibtex:title>
|
369
|
+
<bibtex:year>2009</bibtex:year>
|
370
|
+
</bibtex:book>
|
371
|
+
</bibtex:entry>
|
372
|
+
</bibtex:file>
|
373
|
+
|
303
374
|
Look at the 'examples' directory for more elaborate examples of a BibTeX to YAML
|
304
375
|
and a BibTeX to HTML converter using **#to_citeproc** to format a bibliography
|
305
376
|
using [CSL](http://citationstyles.org/).
|
@@ -345,20 +416,41 @@ quotes; therefore you can simply add the :quotes option with an empty string:
|
|
345
416
|
:title=>"Programming Ruby 1.9: The Pragmatic Programmer's Guide",
|
346
417
|
:year=>"2009"}]
|
347
418
|
|
419
|
+
|
348
420
|
The Parser
|
349
421
|
----------
|
350
422
|
|
351
423
|
The BibTeX-Ruby parser is generated using the awesome
|
352
424
|
[racc](http://i.loveruby.net/en/projects/racc/) parser generator. You can take
|
353
|
-
look at the grammar
|
425
|
+
look at the LALR grammar in the file
|
354
426
|
[lib/bibtex/bibtex.y](https://github.com/inukshuk/bibtex-ruby/blob/master/lib/bibtex/bibtex.y).
|
355
427
|
|
356
428
|
For more information about the BibTeX format and the parser's idiosyncrasies
|
357
429
|
[refer to the project wiki](https://github.com/inukshuk/bibtex-ruby/wiki/The-BibTeX-Format).
|
358
430
|
|
431
|
+
Contributing
|
432
|
+
------------
|
433
|
+
|
434
|
+
The BibTeX-Ruby source code is
|
435
|
+
[hosted on GitHub](http://github.com/inukshuk/bibtex-ruby/).
|
436
|
+
You can check out a copy of the latest code using Git:
|
437
|
+
|
438
|
+
$ git clone https://github.com/inukshuk/bibtex-ruby.git
|
439
|
+
|
440
|
+
If you've found a bug or have a question, please open an issue on the
|
441
|
+
[BibTeX-Ruby issue tracker](http://github.com/inukshuk/bibtex-ruby/issues).
|
442
|
+
Or, for extra credit, clone the BibTeX-Ruby repository, write a failing
|
443
|
+
example, or cucumber feature, fix the bug and submit a pull request (for
|
444
|
+
useful examples, take a look at the cucumber features in the
|
445
|
+
[features/issues/](https://github.com/inukshuk/bibtex-ruby/blob/master/features/issues)
|
446
|
+
directory).
|
447
|
+
|
359
448
|
|
360
449
|
Credits
|
361
450
|
-------
|
362
451
|
|
363
452
|
The BibTeX-Ruby package was written by [Sylvester Keil](http://sylvester.keil.or.at/);
|
364
453
|
kudos and thanks to all [contributors](https://github.com/inukshuk/bibtex-ruby/contributors)!
|
454
|
+
|
455
|
+
BibTeX-Ruby is distributed under the terms and conditions of the GPL. See
|
456
|
+
LICENSE for details.
|
data/bibtex-ruby.gemspec
CHANGED
@@ -11,19 +11,25 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.authors = ['Sylvester Keil']
|
12
12
|
s.email = ['http://sylvester.keil.or.at']
|
13
13
|
s.homepage = 'http://inukshuk.github.com/bibtex-ruby'
|
14
|
-
s.summary = 'A BibTeX parser and converter written in Ruby.'
|
15
|
-
s.description = 'A (fairly complete) BibTeX library and parser written in Ruby. Includes a name parser and supports regular BibTeX entries, @comments, string replacement via @string. Allows for easy export/conversion to formats such as YAML, JSON, and XML.'
|
16
14
|
s.license = 'GPL-3'
|
17
15
|
|
16
|
+
s.summary = 'A BibTeX parser, converter and API for Ruby.'
|
17
|
+
s.description = <<-END_DESCRIPTION
|
18
|
+
BibTeX-Ruby is the Rubyist's swiss-army-knife for all things BibTeX. It
|
19
|
+
includes a parser for all common BibTeX objects (@string, @preamble,
|
20
|
+
@comment and regular entries) and a sophisticated name parser that
|
21
|
+
tokenizes correctly formatted names; BibTeX-Ruby recognizes BibTeX string
|
22
|
+
replacements, joins values containing multiple strings or variables,
|
23
|
+
supports cross-references, and decodes common LaTeX formatting
|
24
|
+
instructions to unicode; if you are in a hurry, it also allows for easy
|
25
|
+
export/conversion to formats such as YAML, JSON, CSL, and XML (BibTeXML).
|
26
|
+
END_DESCRIPTION
|
27
|
+
|
18
28
|
s.add_runtime_dependency('latex-decode', ['>=0.0.3'])
|
29
|
+
s.add_runtime_dependency('multi_json', ['~>1.0'])
|
19
30
|
|
20
31
|
s.add_development_dependency('rake', ['~>0.9'])
|
21
32
|
s.add_development_dependency('racc', ['~>1.4'])
|
22
|
-
s.add_development_dependency('mini_shoulda', ['~>0.3'])
|
23
|
-
s.add_development_dependency('mynyml-redgreen', ['~>0.7'])
|
24
|
-
s.add_development_dependency('autowatchr', ['~>0.1'])
|
25
|
-
s.add_development_dependency('cucumber', ['~>0.10'])
|
26
|
-
s.add_development_dependency('json', ['~>1.5'])
|
27
33
|
s.add_development_dependency('rdoc', ['~>3.9'])
|
28
34
|
|
29
35
|
s.files = File.open('Manifest').readlines.map(&:chomp)
|
@@ -0,0 +1,62 @@
|
|
1
|
+
Feature: Parse BibTeX cross-references
|
2
|
+
As a hacker who works with bibliographies
|
3
|
+
I want to be able to parse BibTeX files with cross-referenced entries
|
4
|
+
|
5
|
+
@wip
|
6
|
+
Scenario: A BibTeX file with six entries and three cross-references
|
7
|
+
When I parse the following file:
|
8
|
+
"""
|
9
|
+
@book{zimmerman_2004,
|
10
|
+
Address = {Oxford},
|
11
|
+
Author = {Dean W. Zimmerman},
|
12
|
+
Editor = {Dean W. Zimmerman},
|
13
|
+
Keywords = {Metaphysics},
|
14
|
+
Publisher = {Oxford University Press},
|
15
|
+
Title = {Oxford Studies in Metaphysics},
|
16
|
+
Volume = {1},
|
17
|
+
Year = {2004}
|
18
|
+
}
|
19
|
+
|
20
|
+
@incollection{hall_2004b,
|
21
|
+
Author = {Ned Hall},
|
22
|
+
Crossref = {zimmerman_2004},
|
23
|
+
Keywords = {Causation},
|
24
|
+
Pages = {255-299},
|
25
|
+
Title = {The Intrinsic Character of Causation}
|
26
|
+
}
|
27
|
+
|
28
|
+
@proceedings{weingartner_1989,
|
29
|
+
Address = {Vienna},
|
30
|
+
Editor = {Paul Weingartner and Gerhard Schurz},
|
31
|
+
Keywords = {Anthology},
|
32
|
+
Publisher = {Verlag H{\"o}lder-Pichter Tempsky},
|
33
|
+
Title = {Philosophy of the Natural Sciences: Proceedings of the 13th International Wittgenstein Symposium},
|
34
|
+
Year = {1989}}
|
35
|
+
|
36
|
+
@inproceedings{cartwright_1989a,
|
37
|
+
Author = {Nancy Cartwright},
|
38
|
+
Crossref = {weingartner_1989},
|
39
|
+
Keywords = {Causation; Quantum Mechanics},
|
40
|
+
Pages = {120-127},
|
41
|
+
Title = {Quantum Causes: The Lesson of the Bell Inequalities}}
|
42
|
+
|
43
|
+
@inbook{fraassen_1989b,
|
44
|
+
Crossref = {fraassen_1989},
|
45
|
+
Pages = {40-64},
|
46
|
+
Title = {Ideal Science: David Lewis's Account of Laws},
|
47
|
+
Url = {http://dx.doi.org/10.1093/0198248601.003.0003}
|
48
|
+
}
|
49
|
+
|
50
|
+
@book{fraassen_1989,
|
51
|
+
Address = {Oxford},
|
52
|
+
Author = {Bas C. van Fraassen},
|
53
|
+
Keywords = {Laws; Lewis},
|
54
|
+
Publisher = {Oxford University Press},
|
55
|
+
Title = {Laws and Symmetry},
|
56
|
+
Url = {http://dx.doi.org/10.1093/0198248601.001.0001},
|
57
|
+
Year = 1989
|
58
|
+
}
|
59
|
+
"""
|
60
|
+
Then the entry with key "fraassen_1989b" should have a field "Booktitle" with the value "Laws and Symmetry"
|
61
|
+
And the entry with key "hall_2004b" should have a field "Editor" with the value "Zimmerman, Dean W."
|
62
|
+
And the entry with key "cartwright_1989a" should have a field "Year" with the value "1989"
|
data/features/names.feature
CHANGED
@@ -61,7 +61,7 @@ end
|
|
61
61
|
|
62
62
|
Then /^my bibliography should contain an entry with (?:key|id) "([^"]*)" and a?n? (\w+) value of "([^"]*)"$/ do |key,field,value|
|
63
63
|
refute_nil @bibliography[key.to_s]
|
64
|
-
assert_equal value, @bibliography[key.to_s][field].to_s
|
64
|
+
assert_equal value, @bibliography[key.to_s][field.downcase.to_sym].to_s
|
65
65
|
end
|
66
66
|
|
67
67
|
|
@@ -91,5 +91,5 @@ Then /^the string "([^"]*)" should be "([^"]*)"$/ do |key, value|
|
|
91
91
|
end
|
92
92
|
|
93
93
|
Then /^the entry with key "([^"]*)" should have a field "([^"]*)" with the value "([^"]*)"$/ do |key, field, value|
|
94
|
-
assert_equal value, @bibliography[key
|
94
|
+
assert_equal value, @bibliography[key][field.downcase.to_sym].to_s
|
95
95
|
end
|
data/lib/bibtex.rb
CHANGED
@@ -19,11 +19,13 @@
|
|
19
19
|
$:.unshift(File.dirname(__FILE__)) unless
|
20
20
|
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
21
21
|
|
22
|
-
require '
|
22
|
+
require 'digest/md5'
|
23
23
|
|
24
24
|
require 'bibtex/version'
|
25
25
|
require 'logger'
|
26
26
|
|
27
|
+
require 'multi_json'
|
28
|
+
|
27
29
|
# = BibTeX
|
28
30
|
#
|
29
31
|
# This module encompasses a parser for BibTeX files and
|
data/lib/bibtex/bibliography.rb
CHANGED
@@ -31,10 +31,12 @@ module BibTeX
|
|
31
31
|
include Enumerable
|
32
32
|
include Comparable
|
33
33
|
|
34
|
-
|
34
|
+
@defaults = { :parse_names => true, :parse_months => true }.freeze
|
35
35
|
|
36
36
|
class << self
|
37
37
|
|
38
|
+
attr_reader :defaults
|
39
|
+
|
38
40
|
# Opens and parses the `.bib' file at the given +path+. Returns
|
39
41
|
# a new Bibliography instance corresponding to the file, or, if a block
|
40
42
|
# is given, yields the instance to the block, ensuring that the file
|
@@ -50,7 +52,8 @@ module BibTeX
|
|
50
52
|
# -:filter: convert all entries using the sepcified filter (not set by default)
|
51
53
|
#
|
52
54
|
def open(path, options = {})
|
53
|
-
b = parse(Kernel.open(path).read, options)
|
55
|
+
b = parse(Kernel.open(path, 'r:UTF-8').read, options)
|
56
|
+
b.path = path
|
54
57
|
return b unless block_given?
|
55
58
|
|
56
59
|
begin
|
@@ -61,13 +64,16 @@ module BibTeX
|
|
61
64
|
end
|
62
65
|
|
63
66
|
# Parses the given string and returns a corresponding Bibliography instance.
|
64
|
-
def parse(
|
65
|
-
|
67
|
+
def parse(input, options = {})
|
68
|
+
case input
|
69
|
+
when Array, Hash, Element
|
70
|
+
Bibliography.new(options).add(input)
|
71
|
+
else
|
72
|
+
Parser.new(options).parse(input) || Bibliography.new(options)
|
73
|
+
end
|
66
74
|
end
|
67
75
|
|
68
|
-
#
|
69
76
|
# Defines a new accessor that selects elements by type.
|
70
|
-
#
|
71
77
|
def attr_by_type(*arguments)
|
72
78
|
arguments.each do |type|
|
73
79
|
method_id = "#{type}s"
|
@@ -77,19 +83,21 @@ module BibTeX
|
|
77
83
|
end
|
78
84
|
|
79
85
|
attr_accessor :path
|
86
|
+
|
80
87
|
attr_reader :data, :strings, :entries, :errors, :options
|
81
88
|
|
82
|
-
attr_by_type :article, :book, :journal, :collection, :preamble, :comment,
|
89
|
+
attr_by_type :article, :book, :journal, :collection, :preamble, :comment,
|
90
|
+
:meta_content
|
83
91
|
|
84
|
-
def_delegators :@data, :length, :size, :each, :empty
|
85
|
-
|
92
|
+
def_delegators :@data, :length, :size, :each, :empty?, :last
|
93
|
+
def_delegators :@entries, :has_key?
|
86
94
|
|
87
|
-
|
95
|
+
|
88
96
|
# Creates a new bibliography.
|
89
|
-
#
|
90
97
|
def initialize(options = {})
|
91
|
-
@options =
|
92
|
-
@data, @strings
|
98
|
+
@options = Bibliography.defaults.merge(options)
|
99
|
+
@data, @strings = [], {}
|
100
|
+
@entries = Hash.new { |h,k| h.fetch(k.to_s, nil) }
|
93
101
|
|
94
102
|
yield self if block_given?
|
95
103
|
end
|
@@ -97,9 +105,8 @@ module BibTeX
|
|
97
105
|
# Adds a new element, or a list of new elements to the bibliography.
|
98
106
|
# Returns the Bibliography for chainability.
|
99
107
|
def add(*arguments)
|
100
|
-
arguments.flatten.each do |element|
|
101
|
-
|
102
|
-
@data << element.added_to_bibliography(self)
|
108
|
+
Element.parse(arguments.flatten).each do |element|
|
109
|
+
data << element.added_to_bibliography(self)
|
103
110
|
end
|
104
111
|
self
|
105
112
|
end
|
@@ -107,6 +114,7 @@ module BibTeX
|
|
107
114
|
alias << add
|
108
115
|
alias push add
|
109
116
|
|
117
|
+
|
110
118
|
# Saves the bibliography to the current path.
|
111
119
|
def save(options = {})
|
112
120
|
save_to(@path, options)
|
@@ -115,19 +123,21 @@ module BibTeX
|
|
115
123
|
# Saves the bibliography to a file at the given path. Returns the bibliography.
|
116
124
|
def save_to(path, options = {})
|
117
125
|
options[:quotes] ||= %w({ })
|
118
|
-
File.open(path,
|
126
|
+
File.open(path, 'w:UTF-8') { |f| f.write(to_s(options)) }
|
119
127
|
self
|
120
128
|
end
|
121
129
|
|
130
|
+
|
122
131
|
def parse_names
|
123
132
|
@entries.each_value { |e| e.parse_names }
|
124
133
|
self
|
125
134
|
end
|
126
|
-
|
135
|
+
|
127
136
|
def parse_months
|
128
137
|
@entries.each_value { |e| e.parse_month }
|
129
138
|
self
|
130
139
|
end
|
140
|
+
|
131
141
|
|
132
142
|
# Converts all enties using the given filter. If an optional block is given
|
133
143
|
# the block is used as a condition (the block will be called with each
|
@@ -137,7 +147,7 @@ module BibTeX
|
|
137
147
|
self
|
138
148
|
end
|
139
149
|
|
140
|
-
|
150
|
+
|
141
151
|
# Deletes an object, or a list of objects from the bibliography.
|
142
152
|
# If a list of objects is to be deleted, you can either supply the list
|
143
153
|
# of objects or use a query or block to define the list.
|
@@ -169,7 +179,7 @@ module BibTeX
|
|
169
179
|
# >> bib[:key]
|
170
180
|
# => Returns the first entry with key 'key' or nil
|
171
181
|
# >> bib['key']
|
172
|
-
# =>
|
182
|
+
# => Same as above
|
173
183
|
# >> bib['@article']
|
174
184
|
# => Returns all entries of type 'article' or []
|
175
185
|
# >> bib['@preamble']
|
@@ -183,10 +193,21 @@ module BibTeX
|
|
183
193
|
raise(ArgumentError, "wrong number of arguments (#{arguments.length} for 1..2)") unless arguments.length.between?(1,2)
|
184
194
|
|
185
195
|
case
|
186
|
-
when
|
187
|
-
|
188
|
-
|
189
|
-
|
196
|
+
when arguments[0].is_a?(Numeric) || arguments[0].is_a?(Range)
|
197
|
+
data[*arguments]
|
198
|
+
when arguments.length == 1
|
199
|
+
case
|
200
|
+
when arguments[0].nil?
|
201
|
+
nil
|
202
|
+
when arguments[0].respond_to?(:empty?) && arguments[0].empty?
|
203
|
+
nil
|
204
|
+
when arguments[0].is_a?(Symbol)
|
205
|
+
entries[arguments[0]]
|
206
|
+
when arguments[0].respond_to?(:start_with?) && !arguments[0].start_with?('@')
|
207
|
+
entries[arguments[0]]
|
208
|
+
else
|
209
|
+
query(*arguments)
|
210
|
+
end
|
190
211
|
else
|
191
212
|
query(*arguments)
|
192
213
|
end
|
@@ -208,6 +229,11 @@ module BibTeX
|
|
208
229
|
!errors? && @entries.values.all?(&:valid?)
|
209
230
|
end
|
210
231
|
|
232
|
+
# Returns a list of the names of all authors, editors and translators in the Bibliography.
|
233
|
+
def names
|
234
|
+
map(&:names).flatten
|
235
|
+
end
|
236
|
+
|
211
237
|
# Replaces all string symbols which are defined in the bibliography.
|
212
238
|
#
|
213
239
|
# By default symbols in @string, @preamble and entries are replaced; this
|
@@ -266,7 +292,7 @@ module BibTeX
|
|
266
292
|
|
267
293
|
# Returns a JSON representation of the bibliography.
|
268
294
|
def to_json(options = {})
|
269
|
-
to_a(options)
|
295
|
+
MultiJson.encode(to_a(options))
|
270
296
|
end
|
271
297
|
|
272
298
|
# Returns a CiteProc JSON representation of the bibliography. Only BibTeX enrties are exported.
|
@@ -274,15 +300,20 @@ module BibTeX
|
|
274
300
|
q('@entry').map { |o| o.to_citeproc(options) }
|
275
301
|
end
|
276
302
|
|
277
|
-
# Returns
|
278
|
-
|
303
|
+
# Returns a REXML::Document representation of the bibliography using the
|
304
|
+
# BibTeXML format.
|
305
|
+
def to_xml(options = {})
|
279
306
|
require 'rexml/document'
|
280
307
|
|
281
|
-
xml =
|
308
|
+
xml = REXML::Document.new
|
282
309
|
xml << REXML::XMLDecl.new('1.0','UTF-8')
|
283
|
-
|
284
|
-
|
285
|
-
|
310
|
+
|
311
|
+
root = REXML::Element.new('bibtex:file')
|
312
|
+
root.add_namespace('bibtex', 'http://bibtexml.sf.net/')
|
313
|
+
|
314
|
+
each { |e| root.add_element(e.to_xml(options)) }
|
315
|
+
|
316
|
+
xml.add_element(root)
|
286
317
|
xml
|
287
318
|
end
|
288
319
|
|
@@ -307,7 +338,8 @@ module BibTeX
|
|
307
338
|
raise(ArgumentError, "wrong number of arguments (#{arguments.length} for 0..2)") unless arguments.length.between?(0,2)
|
308
339
|
|
309
340
|
q, selector = arguments.reverse
|
310
|
-
filter = block ? Proc.new { |e| e.match?(q) && block.call(e) } :
|
341
|
+
filter = block ? Proc.new { |e| e.match?(q) && block.call(e) } :
|
342
|
+
Proc.new { |e| e.match?(q) }
|
311
343
|
|
312
344
|
send(query_handler(selector), &filter)
|
313
345
|
end
|
@@ -324,6 +356,26 @@ module BibTeX
|
|
324
356
|
other.respond_to?(:to_a) ? to_a <=> other.to_a : nil
|
325
357
|
end
|
326
358
|
|
359
|
+
# TODO this should be faster than select_duplicates_by
|
360
|
+
# def detect_duplicates_by(*arguments)
|
361
|
+
# end
|
362
|
+
|
363
|
+
def select_duplicates_by(*arguments)
|
364
|
+
d, fs = Hash.new([]), arguments.flatten.map(&:to_sym)
|
365
|
+
q('@entry') do |e|
|
366
|
+
d[e.generate_hash(fs)] << e
|
367
|
+
end
|
368
|
+
|
369
|
+
d.values.dup
|
370
|
+
end
|
371
|
+
|
372
|
+
alias duplicates select_duplicates_by
|
373
|
+
|
374
|
+
def duplicates?
|
375
|
+
!select_duplicates_by?.empty?
|
376
|
+
end
|
377
|
+
|
378
|
+
|
327
379
|
private
|
328
380
|
|
329
381
|
def query_handler(selector)
|