bibtex-ruby 2.1.2 → 2.2.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/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bibtex-ruby (2.1.2)
4
+ bibtex-ruby (2.2.0)
5
5
  latex-decode (>= 0.0.6)
6
6
  multi_json (~> 1.3)
7
7
 
data/History.txt CHANGED
@@ -1,3 +1,9 @@
1
+ 2.2.0 / 2012-12-02
2
+ ==================
3
+
4
+ * Adds duplicate detection
5
+ * Adds Entry merge support
6
+
1
7
  2.1.1 / 2012-11-02
2
8
  ==================
3
9
 
@@ -1,17 +1,17 @@
1
1
  #--
2
2
  # BibTeX-Ruby
3
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
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
  #++
@@ -24,16 +24,16 @@ module BibTeX
24
24
  #
25
25
  class Bibliography
26
26
  extend Forwardable
27
-
27
+
28
28
  include Enumerable
29
29
  include Comparable
30
-
30
+
31
31
  @defaults = { :parse_names => true, :parse_months => true }.freeze
32
-
33
- class << self
32
+
33
+ class << self
34
34
 
35
35
  attr_reader :defaults
36
-
36
+
37
37
  # Opens and parses the `.bib' file at the given +path+. Returns
38
38
  # a new Bibliography instance corresponding to the file, or, if a block
39
39
  # is given, yields the instance to the block, ensuring that the file
@@ -71,7 +71,7 @@ module BibTeX
71
71
  raise ArgumentError, "failed to parse #{input.inspect}"
72
72
  end
73
73
  end
74
-
74
+
75
75
  # Defines a new accessor that selects elements by type.
76
76
  def attr_by_type(*arguments)
77
77
  arguments.each do |type|
@@ -80,17 +80,17 @@ module BibTeX
80
80
  end
81
81
  end
82
82
  end
83
-
83
+
84
84
  attr_accessor :path
85
85
 
86
86
  attr_reader :data, :strings, :entries, :errors, :options
87
87
 
88
88
  attr_by_type :article, :book, :journal, :collection, :preamble,
89
89
  :comment, :meta_content
90
-
90
+
91
91
  def_delegators :@data, :length, :size, :empty?
92
92
  def_delegators :@entries, :key?, :has_key?, :values_at
93
-
93
+
94
94
  alias entries_at values_at
95
95
 
96
96
  # Creates a new bibliography.
@@ -101,7 +101,7 @@ module BibTeX
101
101
 
102
102
  yield self if block_given?
103
103
  end
104
-
104
+
105
105
  def initialize_copy(other)
106
106
  @options = other.options.dup
107
107
  @errors = other.errors.dup
@@ -109,7 +109,7 @@ module BibTeX
109
109
  @entries = Hash.new { |h,k| h.fetch(k.to_s, nil) }
110
110
  add(other.data)
111
111
  end
112
-
112
+
113
113
  # Adds a new element, or a list of new elements to the bibliography.
114
114
  # Returns the Bibliography for chainability.
115
115
  def add(*arguments)
@@ -118,16 +118,16 @@ module BibTeX
118
118
  end
119
119
  self
120
120
  end
121
-
121
+
122
122
  alias << add
123
123
  alias push add
124
-
124
+
125
125
 
126
126
  # Saves the bibliography to the current path.
127
127
  def save(options = {})
128
128
  save_to(@path, options)
129
129
  end
130
-
130
+
131
131
  # Saves the bibliography to a file at the given path. Returns the bibliography.
132
132
  def save_to(path, options = {})
133
133
  options[:quotes] ||= %w({ })
@@ -135,7 +135,7 @@ module BibTeX
135
135
  File.open(path, 'w:UTF-8') do |f|
136
136
  f.write(to_s(options))
137
137
  end
138
-
138
+
139
139
  self
140
140
  end
141
141
 
@@ -148,7 +148,7 @@ module BibTeX
148
148
  to_enum
149
149
  end
150
150
  end
151
-
151
+
152
152
 
153
153
  def parse_names
154
154
  entries.each_value { |e| e.parse_names }
@@ -160,7 +160,7 @@ module BibTeX
160
160
  self
161
161
  end
162
162
 
163
-
163
+
164
164
  # Converts all enties using the given filter. If an optional block is given
165
165
  # the block is used as a condition (the block will be called with each
166
166
  # entry). @see Entry#convert!
@@ -168,10 +168,10 @@ module BibTeX
168
168
  entries.each_value do |entry|
169
169
  entry.convert!(filter) if !block_given? || yield(entry)
170
170
  end
171
-
171
+
172
172
  self
173
173
  end
174
-
174
+
175
175
 
176
176
  # Deletes an object, or a list of objects from the bibliography.
177
177
  # If a list of objects is to be deleted, you can either supply the list
@@ -184,7 +184,7 @@ module BibTeX
184
184
  @data = @data - objects
185
185
  objects.length == 1 ? objects[0] : objects
186
186
  end
187
-
187
+
188
188
  alias remove delete
189
189
  alias rm delete
190
190
 
@@ -218,7 +218,7 @@ module BibTeX
218
218
 
219
219
  case
220
220
  when arguments[0].is_a?(Numeric) || arguments[0].is_a?(Range)
221
- data[*arguments]
221
+ data[*arguments]
222
222
  when arguments.length == 1
223
223
  case
224
224
  when arguments[0].nil?
@@ -248,12 +248,12 @@ module BibTeX
248
248
  def valid?
249
249
  !errors? && entries.values.all?(&:valid?)
250
250
  end
251
-
251
+
252
252
  # Returns a list of the names of all authors, editors and translators in the Bibliography.
253
253
  def names
254
254
  map(&:names).flatten
255
255
  end
256
-
256
+
257
257
  # Replaces all string symbols which are defined in the bibliography.
258
258
  #
259
259
  # By default symbols in @string, @preamble and entries are replaced; this
@@ -271,21 +271,21 @@ module BibTeX
271
271
  q(filter) { |e| e.replace(@strings.values) }
272
272
  self
273
273
  end
274
-
274
+
275
275
  alias :replace_strings :replace
276
276
 
277
277
  def join(filter = '')
278
278
  q(filter, &:join)
279
279
  self
280
280
  end
281
-
281
+
282
282
  alias join_strings join
283
283
 
284
284
  def rename(*arguments, &block)
285
285
  q('@entry') { |e| e.rename(*arguments, &block) }
286
286
  self
287
287
  end
288
-
288
+
289
289
  # call-seq:
290
290
  # b.extend_initials(['Edgar Allen', 'Poe'], ['Nathaniel', 'Hawthorne'])
291
291
  # #=> Extends the initials in names like 'E.A. Poe' or 'Hawethorne, N.'
@@ -298,10 +298,10 @@ module BibTeX
298
298
  name.extend_initials(with_first, for_last)
299
299
  end
300
300
  end
301
-
301
+
302
302
  self
303
303
  end
304
-
304
+
305
305
  # This method combines all names in the bibliography that look identical
306
306
  # when using initials as first names and then tries to extend the first
307
307
  # names for all names in each group to the longest available form.
@@ -314,24 +314,24 @@ module BibTeX
314
314
  groups = Hash.new do |h,k|
315
315
  h[k] = { :prototype => nil, :names => [] }
316
316
  end
317
-
317
+
318
318
  # group names together
319
319
  names.each do |name|
320
320
  group = groups[name.sort_order(:initials => true).gsub(/\s+/, '').downcase]
321
321
  group[:names] << name
322
-
322
+
323
323
  if group[:prototype].nil? || group[:prototype].first.to_s.length < name.first.to_s.length
324
324
  group[:prototype] = name
325
325
  end
326
326
  end
327
-
327
+
328
328
  # extend all names in group to prototype
329
329
  groups.each_value do |group|
330
330
  group[:names].each do |name|
331
331
  name.set(group[:prototype])
332
332
  end
333
333
  end
334
-
334
+
335
335
  self
336
336
  end
337
337
 
@@ -350,21 +350,31 @@ module BibTeX
350
350
  else
351
351
  Proc.new { |e| e[field] = value }
352
352
  end
353
-
353
+
354
354
  each_entry do |entry|
355
355
  if entry.field?(field) && entry[field].to_s =~ pattern
356
356
  block.call(entry)
357
357
  end
358
358
  end
359
-
359
+
360
360
  self
361
361
  end
362
-
362
+
363
+ def group_by(*arguments, &block)
364
+ groups = Hash.new { |h,k| h[k] = [] }
365
+
366
+ entries.values.each do |e|
367
+ groups[e.digest(arguments, &block)] << e
368
+ end
369
+
370
+ groups
371
+ end
372
+
363
373
  def sort(*arguments, &block)
364
374
  data.sort(*arguments, &block)
365
375
  self
366
376
  end
367
-
377
+
368
378
  # Returns a string representation of the bibliography.
369
379
  def to_s(options = {})
370
380
  map { |o| o.to_s(options) }.join
@@ -373,42 +383,42 @@ module BibTeX
373
383
  def inspect
374
384
  "#<#{self.class} data=[#{length}]>"
375
385
  end
376
-
386
+
377
387
  def to_a(options = {})
378
388
  map { |o| o.to_hash(options) }
379
389
  end
380
-
390
+
381
391
  # Returns a Ruby hash representation of the bibliography.
382
392
  def to_hash(options = {})
383
393
  { :bibliography => map { |o| o.to_hash(options) } }
384
394
  end
385
-
395
+
386
396
  # Returns a YAML representation of the bibliography.
387
397
  def to_yaml(options = {})
388
398
  to_a(options).to_yaml
389
399
  end
390
-
400
+
391
401
  # Returns a JSON representation of the bibliography.
392
402
  def to_json(options = {})
393
403
  MultiJson.dump(to_a(options))
394
404
  end
395
-
405
+
396
406
  # Returns a CiteProc JSON representation of the bibliography. Only BibTeX enrties are exported.
397
407
  def to_citeproc(options = {})
398
408
  q('@entry').map { |o| o.to_citeproc(options) }
399
409
  end
400
-
410
+
401
411
  # Returns a REXML::Document representation of the bibliography using the
402
412
  # BibTeXML format.
403
413
  def to_xml(options = {})
404
414
  require 'rexml/document'
405
-
415
+
406
416
  xml = REXML::Document.new
407
417
  xml << REXML::XMLDecl.new('1.0','UTF-8')
408
418
 
409
419
  root = REXML::Element.new('bibtex:file')
410
420
  root.add_namespace('bibtex', 'http://bibtexml.sf.net/')
411
-
421
+
412
422
  each { |e| root.add_element(e.to_xml(options)) if e.is_a?(Entry) }
413
423
 
414
424
  xml.add_element(root)
@@ -419,18 +429,18 @@ module BibTeX
419
429
  # can be serialized using any of the RDF serializer plugins.
420
430
  def to_rdf(options = {})
421
431
  require 'rdf'
422
-
432
+
423
433
  graph = RDF::Graph.new
424
434
 
425
435
  q('@entry').each do |entry|
426
436
  graph << entry.to_rdf(options)
427
437
  end
428
-
438
+
429
439
  graph
430
440
  rescue LoadError
431
441
  BibTeX.log.error "Please gem install rdf for RDF support."
432
442
  end
433
-
443
+
434
444
  # call-seq:
435
445
  # bib.query() #=> returns all elements
436
446
  # bib.query('@book') #=> returns all books
@@ -470,15 +480,15 @@ module BibTeX
470
480
  else
471
481
  raise ArgumentError, "wrong number of arguments (#{arguments.length} for 0..2)"
472
482
  end
473
-
483
+
474
484
  filter = block ? Proc.new { |e| e.match?(q) && block.call(e) } :
475
485
  Proc.new { |e| e.match?(q) }
476
486
 
477
487
  send(query_handler(selector), &filter)
478
488
  end
479
-
489
+
480
490
  alias q query
481
-
491
+
482
492
  def each_entry
483
493
  if block_given?
484
494
  q('@entry').each(&Proc.new)
@@ -486,39 +496,34 @@ module BibTeX
486
496
  q('@entry').to_enum
487
497
  end
488
498
  end
489
-
499
+
490
500
  def find_by_type(*types, &block)
491
501
  q(types.flatten.compact.map { |t| "@#{t}" }.join(', '), &block)
492
502
  end
493
-
503
+
494
504
  alias find_by_types find_by_type
495
505
 
496
506
  def <=>(other)
497
507
  other.respond_to?(:to_a) ? to_a <=> other.to_a : nil
498
508
  end
499
-
500
- # TODO this should be faster than select_duplicates_by
501
- # def detect_duplicates_by(*arguments)
502
- # end
503
509
 
504
510
  def select_duplicates_by(*arguments)
505
- d, fs = Hash.new([]), arguments.flatten.map(&:to_sym)
506
- q('@entry') do |e|
507
- d[e.generate_hash(fs)] << e
508
- end
509
-
510
- d.values.dup
511
+ arguments = [:year, :title] if arguments.empty?
512
+
513
+ group_by(*arguments) { |digest|
514
+ digest.gsub(/\s+/, '').downcase
515
+ }.values.select { |d| d.length > 1 }
511
516
  end
512
-
517
+
513
518
  alias duplicates select_duplicates_by
514
-
519
+
515
520
  def duplicates?
516
521
  !select_duplicates_by?.empty?
517
522
  end
518
-
519
-
523
+
524
+
520
525
  private
521
-
526
+
522
527
  def query_handler(selector)
523
528
  case selector.to_s
524
529
  when /first|distinct|detect/i
@@ -529,6 +534,6 @@ module BibTeX
529
534
  :select
530
535
  end
531
536
  end
532
-
537
+
533
538
  end
534
539
  end
@@ -47,8 +47,19 @@ module BibTeX
47
47
  end
48
48
 
49
49
  # Returns a string containing the object's content.
50
- def content(options = {}); ''; end
50
+ def content(options = {})
51
+ ''
52
+ end
51
53
 
54
+ # Returns a string containing the object's content.
55
+ def values_at(*arguments)
56
+ []
57
+ end
58
+
59
+ def digest(*arguments)
60
+ [type, content].join('|')
61
+ end
62
+
52
63
  # Invokes BibTeX string replacement on this element.
53
64
  def replace(*arguments); self; end
54
65