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:



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

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



398
399
400
# File 'lib/bibtex/bibliography.rb', line 398

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:



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

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.



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

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!



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

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.



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

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)


417
418
419
# File 'lib/bibtex/bibliography.rb', line 417

def duplicates?
  !select_duplicates_by?.empty?
end

#eachObject



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

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)


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

def errors?
  !errors.empty?
end

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



392
393
394
# File 'lib/bibtex/bibliography.rb', line 392

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

#initialize_copy(other) ⇒ Object



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

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



299
300
301
# File 'lib/bibtex/bibliography.rb', line 299

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

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



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

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

#namesObject

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



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

def names
  map(&:names).flatten
end

#parse_monthsObject



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

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

#parse_namesObject



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

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) }


372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
# File 'lib/bibtex/bibliography.rb', line 372

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



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

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



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

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

#save(options = {}) ⇒ Object

Saves the bibliography to the current path.



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

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.



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

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



406
407
408
409
410
411
412
413
# File 'lib/bibtex/bibliography.rb', line 406

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



289
290
291
292
# File 'lib/bibtex/bibliography.rb', line 289

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

#to_a(options = {}) ⇒ Object



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

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.



323
324
325
# File 'lib/bibtex/bibliography.rb', line 323

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.



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

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

#to_json(options = {}) ⇒ Object

Returns a JSON representation of the bibliography.



318
319
320
# File 'lib/bibtex/bibliography.rb', line 318

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

#to_s(options = {}) ⇒ Object

Returns a string representation of the bibliography.



295
296
297
# File 'lib/bibtex/bibliography.rb', line 295

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.



329
330
331
332
333
334
335
336
337
338
339
340
341
342
# File 'lib/bibtex/bibliography.rb', line 329

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.



313
314
315
# File 'lib/bibtex/bibliography.rb', line 313

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)


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

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