Class: BibTeX::Bibliography

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Comparable, Enumerable
Defined in:
lib/bibtex/bibliography.rb

Overview

The Bibliography class models a BibTeX bibliography; typically, it corresponds to a ‘.bib’ file.

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) {|_self| ... } ⇒ Bibliography

Creates a new bibliography.

Yields:

  • (_self)

Yield Parameters:



97
98
99
100
101
102
103
# File 'lib/bibtex/bibliography.rb', line 97

def initialize(options = {})
  @options = Bibliography.defaults.merge(options)
  @data, @strings, @errors = [], {}, []
  @entries = Hash.new { |h,k| h.fetch(k.to_s, nil) }

  yield self if block_given?
end

Class Attribute Details

.defaultsObject (readonly)

Returns the value of attribute defaults.



35
36
37
# File 'lib/bibtex/bibliography.rb', line 35

def defaults
  @defaults
end

Instance Attribute Details

#dataObject (readonly)

Returns the value of attribute data.



86
87
88
# File 'lib/bibtex/bibliography.rb', line 86

def data
  @data
end

#entriesObject (readonly)

Returns the value of attribute entries.



86
87
88
# File 'lib/bibtex/bibliography.rb', line 86

def entries
  @entries
end

#errorsObject (readonly)

Returns the value of attribute errors.



86
87
88
# File 'lib/bibtex/bibliography.rb', line 86

def errors
  @errors
end

#optionsObject (readonly)

Returns the value of attribute options.



86
87
88
# File 'lib/bibtex/bibliography.rb', line 86

def options
  @options
end

#pathObject

Returns the value of attribute path.



84
85
86
# File 'lib/bibtex/bibliography.rb', line 84

def path
  @path
end

#stringsObject (readonly)

Returns the value of attribute strings.



86
87
88
# File 'lib/bibtex/bibliography.rb', line 86

def strings
  @strings
end

Class Method Details

.attr_by_type(*arguments) ⇒ Object

Defines a new accessor that selects elements by type.



76
77
78
79
80
81
# File 'lib/bibtex/bibliography.rb', line 76

def attr_by_type(*arguments)
  arguments.each do |type|
    method_id = "#{type}s"
    define_method(method_id) { find_by_type(type) } unless respond_to?(method_id)
  end
end

.open(path, options = {}) ⇒ Object

Opens and parses the ‘.bib’ file at the given path. Returns a new Bibliography instance corresponding to the file, or, if a block is given, yields the instance to the block, ensuring that the file is saved after the block’s execution (use the :out option if you want to specify a save path other than the path from where the file is loaded).

The options argument is passed on to BibTeX::Parser.new. Additional option parameters are:

-:parse_names: set to false to disable automatic name parsing -:parse_months: set to false to disable automatic month conversion -:filter: convert all entries using the sepcified filter (not set by default)



51
52
53
54
55
56
57
58
59
60
61
# File 'lib/bibtex/bibliography.rb', line 51

def open(path, options = {})
  b = parse(Kernel.open(path, 'r:UTF-8').read, options)
  b.path = path
  return b unless block_given?

  begin
    yield b
  ensure
    b.save_to(options[:out] || path)
  end
end

.parse(input, options = {}) ⇒ Object

Parses the given string and returns a corresponding Bibliography instance.



64
65
66
67
68
69
70
71
72
73
# File 'lib/bibtex/bibliography.rb', line 64

def parse(input, options = {})
  case input
  when Array, Hash, Element
    Bibliography.new(options).add(input)
  when ::String
    Parser.new(options).parse(input) || Bibliography.new(options)
  else
    raise ArgumentError, "failed to parse #{input.inspect}"
  end
end

Instance Method Details

#<=>(other) ⇒ Object



426
427
428
# File 'lib/bibtex/bibliography.rb', line 426

def <=>(other)
  other.respond_to?(:to_a) ? to_a <=> other.to_a : nil
end

#[](*arguments) ⇒ Object

call-seq: >> bib

> Returns the last element of the Bibliography or nil

>> bib

> Returns the second and third elements or nil

>> bib >> Same as above >> bib

> Returns the first entry with key ‘key’ or nil

>> bib

> Same as above

>> bib

> Returns all entries of type ‘article’ or []

>> bib

> Returns all preamble objects (this is the same as Bibliography#preambles) or []

>> bib

> Returns all objects that match ‘ruby’ anywhere or []

>> bib[‘@book’]

> Returns all books whose keywords attribute equals ‘ruby’ or []

Returns an element or a list of elements according to the given index, range, or query. Contrary to the Bibliography#query this method does not yield to a block for additional refinement of the query.

Raises:



216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/bibtex/bibliography.rb', line 216

def [](*arguments)
  raise(ArgumentError, "wrong number of arguments (#{arguments.length} for 1..2)") unless arguments.length.between?(1,2)

  case
  when arguments[0].is_a?(Numeric) || arguments[0].is_a?(Range)
    data[*arguments] 
  when arguments.length == 1
    case
    when arguments[0].nil?
      nil
    when arguments[0].respond_to?(:empty?) && arguments[0].empty?
      nil
    when arguments[0].is_a?(Symbol)
      entries[arguments[0]]
    when arguments[0].respond_to?(:start_with?) && !arguments[0].start_with?('@')
      entries[arguments[0]]
    else
      query(*arguments)
    end
  else
    query(*arguments)
  end
end

#add(*arguments) ⇒ Object Also known as: <<, push

Adds a new element, or a list of new elements to the bibliography. Returns the Bibliography for chainability.



115
116
117
118
119
120
# File 'lib/bibtex/bibliography.rb', line 115

def add(*arguments)
  Element.parse(arguments.flatten).each do |element|
    data << element.added_to_bibliography(self)
  end
  self
end

#convert(filter) ⇒ Object

Converts all enties using the given filter. If an optional block is given the block is used as a condition (the block will be called with each entry). @see Entry#convert!



167
168
169
170
171
172
173
# File 'lib/bibtex/bibliography.rb', line 167

def convert (filter)
  entries.each_value do |entry|
    entry.convert!(filter) if !block_given? || yield(entry)
  end
  
  self
end

#delete(*arguments, &block) ⇒ Object Also known as: remove, rm

Deletes an object, or a list of objects from the bibliography. If a list of objects is to be deleted, you can either supply the list of objects or use a query or block to define the list.

Returns the object (or the list of objects) that were deleted; nil if the object was not part of the bibliography.



182
183
184
185
186
# File 'lib/bibtex/bibliography.rb', line 182

def delete(*arguments, &block)
  objects = q(*arguments, &block).map { |o| o.removed_from_bibliography(self) }
  @data = @data - objects
  objects.length == 1 ? objects[0] : objects
end

#duplicates?Boolean

Returns:

  • (Boolean)


445
446
447
# File 'lib/bibtex/bibliography.rb', line 445

def duplicates?
  !select_duplicates_by?.empty?
end

#eachObject



143
144
145
146
147
148
149
150
# File 'lib/bibtex/bibliography.rb', line 143

def each
  if block_given?
    data.each(&Proc.new)
    self
  else
    to_enum
  end
end

#errors?Boolean

Returns true if there are object which could not be parsed.

Returns:

  • (Boolean)


242
243
244
# File 'lib/bibtex/bibliography.rb', line 242

def errors?
  !errors.empty?
end

#extend_initials(*arguments) ⇒ Object

call-seq:

b.extend_initials(['Edgar Allen', 'Poe'], ['Nathaniel', 'Hawthorne'])
#=> Extends the initials in names like 'E.A. Poe' or 'Hawethorne, N.'
    in the bibliography.


293
294
295
296
297
298
299
# File 'lib/bibtex/bibliography.rb', line 293

def extend_initials(*arguments)
  arguments.each do |with_first, for_last|
    names.each do |name|
      name.extend_initials(with_first, for_last)
    end
  end
end

#find_by_type(*types, &block) ⇒ Object Also known as: find_by_types



420
421
422
# File 'lib/bibtex/bibliography.rb', line 420

def find_by_type(*types, &block)
  q(types.flatten.compact.map { |t| "@#{t}" }.join(', '), &block)
end

#initialize_copy(other) ⇒ Object



105
106
107
108
109
110
111
# File 'lib/bibtex/bibliography.rb', line 105

def initialize_copy(other)
  @options = other.options.dup
  @errors = other.errors.dup
  @data, @strings = [], {}
  @entries = Hash.new { |h,k| h.fetch(k.to_s, nil) }
  add(other.data)
end

#inspectObject



311
312
313
# File 'lib/bibtex/bibliography.rb', line 311

def inspect
  "#<#{self.class} data=[#{length}]>"
end

#join(filter = '') ⇒ Object Also known as: join_strings



277
278
279
280
# File 'lib/bibtex/bibliography.rb', line 277

def join(filter = '')
  q(filter, &:join)
  self
end

#namesObject

Returns a list of the names of all authors, editors and translators in the Bibliography.



253
254
255
# File 'lib/bibtex/bibliography.rb', line 253

def names
  map(&:names).flatten
end

#parse_monthsObject



158
159
160
161
# File 'lib/bibtex/bibliography.rb', line 158

def parse_months
  entries.each_value { |e| e.parse_month }
  self
end

#parse_namesObject



153
154
155
156
# File 'lib/bibtex/bibliography.rb', line 153

def parse_names
  entries.each_value { |e| e.parse_names }
  self
end

#query(*arguments, &block) ⇒ Object Also known as: q

call-seq:

bib.query()          #=> returns all elements
bib.query('@book')   #=> returns all books
bib.query('@entry')  #=> returns all entries (books, articles etc.)
bib.query('@*')      #=> same as above
bib.query(:first, '@book, @article')
  #=> returns the first book or article or nil
bib.query('@book[year=2011], @article)
  #=> returns all books published in 2011 and all articles
bib.query('@book, @article) { |o| o.year == '2011' }
  #=> returns all books and articles published in 2011
bib.query('@book[year=2011], @article[year=2011])
  #=> same as above without using a block

Returns objects in the Bibliography which match the given selector and, optionally, the conditions specified in the given block.

Queries offer syntactic sugar for common enumerator invocations:

>> bib.query(:all, '@book')
=> same as bib.select { |b| b.has_type?(:book) }
>> bib.query('@book')
=> same as above
>> bib.query(:first, '@book')
=> same as bib.detect { |b| b.has_type?(:book) }
>> bib.query(:none, '@book')
=> same as bib.reject { |b| b.has_type?(:book) }


400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
# File 'lib/bibtex/bibliography.rb', line 400

def query(*arguments, &block)
  case arguments.length
  when 0
    selector, q = :all, nil
  when 1
    selector, q = :all, arguments[0]
  when 2
    selector, q = arguments
  else
    raise ArgumentError, "wrong number of arguments (#{arguments.length} for 0..2)"
  end
  
  filter = block ? Proc.new { |e| e.match?(q) && block.call(e) } :
    Proc.new { |e| e.match?(q) }

  send(query_handler(selector), &filter)
end

#rename(*arguments, &block) ⇒ Object



284
285
286
287
# File 'lib/bibtex/bibliography.rb', line 284

def rename(*arguments, &block)
  q('@entry') { |e| e.rename(*arguments, &block) }
  self
end

#replace(filter = '') ⇒ Object Also known as: replace_strings

Replaces all string symbols which are defined in the bibliography.

By default symbols in @string, @preamble and entries are replaced; this behaviour can be changed using the optional query parameter.

Note that strings are replaced in the order in which they occur in the bibliography.

call-seq: bib.replace #=> replaces all symbols bib.replace(‘@string, @preamble’) #=> replaces only symbols in @string and @preamble objects



270
271
272
273
# File 'lib/bibtex/bibliography.rb', line 270

def replace(filter = '')
  q(filter) { |e| e.replace(@strings.values) }
  self
end

#save(options = {}) ⇒ Object

Saves the bibliography to the current path.



127
128
129
# File 'lib/bibtex/bibliography.rb', line 127

def save(options = {})
  save_to(@path, options)
end

#save_to(path, options = {}) ⇒ Object

Saves the bibliography to a file at the given path. Returns the bibliography.



132
133
134
135
136
137
138
139
140
# File 'lib/bibtex/bibliography.rb', line 132

def save_to(path, options = {})
  options[:quotes] ||= %w({ })

  File.open(path, 'w:UTF-8') do |f|
    f.write(to_s(options))
  end
  
  self
end

#select_duplicates_by(*arguments) ⇒ Object Also known as: duplicates

TODO this should be faster than select_duplicates_by def detect_duplicates_by(*arguments) end



434
435
436
437
438
439
440
441
# File 'lib/bibtex/bibliography.rb', line 434

def select_duplicates_by(*arguments)
  d, fs = Hash.new([]), arguments.flatten.map(&:to_sym)
  q('@entry') do |e|
    d[e.generate_hash(fs)] << e
  end
  
  d.values.dup
end

#sort(*arguments, &block) ⇒ Object



301
302
303
304
# File 'lib/bibtex/bibliography.rb', line 301

def sort(*arguments, &block)
  data.sort(*arguments, &block)
  self
end

#to_a(options = {}) ⇒ Object



315
316
317
# File 'lib/bibtex/bibliography.rb', line 315

def to_a(options = {})
  map { |o| o.to_hash(options) }
end

#to_citeproc(options = {}) ⇒ Object

Returns a CiteProc JSON representation of the bibliography. Only BibTeX enrties are exported.



335
336
337
# File 'lib/bibtex/bibliography.rb', line 335

def to_citeproc(options = {})
  q('@entry').map { |o| o.to_citeproc(options) }
end

#to_hash(options = {}) ⇒ Object

Returns a Ruby hash representation of the bibliography.



320
321
322
# File 'lib/bibtex/bibliography.rb', line 320

def to_hash(options = {})
  { :bibliography => map { |o| o.to_hash(options) } }
end

#to_json(options = {}) ⇒ Object

Returns a JSON representation of the bibliography.



330
331
332
# File 'lib/bibtex/bibliography.rb', line 330

def to_json(options = {})
  MultiJson.dump(to_a(options))
end

#to_rdf(options = {}) ⇒ Object

Returns an RDF::Graph representation of the bibliography. The graph can be serialized using any of the RDF serializer plugins.



358
359
360
361
362
363
364
365
366
367
368
369
370
# File 'lib/bibtex/bibliography.rb', line 358

def to_rdf(options = {})
  require 'rdf'
  
  graph = RDF::Graph.new

  q('@entry').each do |entry|
    graph << entry.to_rdf(options)
  end
  
  graph
rescue LoadError
  BibTeX.log.error "Please gem install rdf for RDF support."
end

#to_s(options = {}) ⇒ Object

Returns a string representation of the bibliography.



307
308
309
# File 'lib/bibtex/bibliography.rb', line 307

def to_s(options = {})
  map { |o| o.to_s(options) }.join
end

#to_xml(options = {}) ⇒ Object

Returns a REXML::Document representation of the bibliography using the BibTeXML format.



341
342
343
344
345
346
347
348
349
350
351
352
353
354
# File 'lib/bibtex/bibliography.rb', line 341

def to_xml(options = {})
  require 'rexml/document'
  
  xml =  REXML::Document.new
  xml << REXML::XMLDecl.new('1.0','UTF-8')

  root = REXML::Element.new('bibtex:file')
  root.add_namespace('bibtex', 'http://bibtexml.sf.net/')
  
  each { |e| root.add_element(e.to_xml(options)) if e.is_a?(Entry) }

  xml.add_element(root)
  xml
end

#to_yaml(options = {}) ⇒ Object

Returns a YAML representation of the bibliography.



325
326
327
# File 'lib/bibtex/bibliography.rb', line 325

def to_yaml(options = {})
  to_a(options).to_yaml
end

#valid?Boolean

Returns true if the Bibliography contains no errors and only valid BibTeX objects (meta content is ignored).

Returns:

  • (Boolean)


248
249
250
# File 'lib/bibtex/bibliography.rb', line 248

def valid?
  !errors? && entries.values.all?(&:valid?)
end