bibtex-ruby 2.1.2 → 2.2.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.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