The Bibliography class models a BibTeX bibliography; typically, it corresponds to a `.bib' file.
Defines a new accessor that selects elements by type.
# 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
Creates a new bibliography.
# 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
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)
# 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
Parses the given string and returns a corresponding Bibliography instance.
# 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
# File lib/bibtex/bibliography.rb, line 516 def <=>(other) other.respond_to?(:to_a) ? to_a <=> other.to_a : nil end
Returns an element or a list of elements according to the given index, range, or query. Contrary to the #query this method does not yield to a block for additional refinement of the query.
# File lib/bibtex/bibliography.rb, line 223 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
Adds a new element, or a list of new elements to the bibliography. Returns the Bibliography for chainability.
# File lib/bibtex/bibliography.rb, line 120 def add(*arguments) Element.parse(arguments.flatten, @options).each do |element| data << element.added_to_bibliography(self) end self end
Converts all enties using the given filter(s). If an optional block is given the block is used as a condition (the block will be called with each entry). @see BibTeX::Entry#convert!
# File lib/bibtex/bibliography.rb, line 172 def convert(*filters) filters = filters.flatten.map { |f| Filters.resolve!(f) } entries.each_value do |entry| entry.convert!(*filters) if !block_given? || yield(entry) end self end
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.
# File lib/bibtex/bibliography.rb, line 189 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
# File lib/bibtex/bibliography.rb, line 538 def duplicates? !select_duplicates_by.empty? end
# File lib/bibtex/bibliography.rb, line 148 def each if block_given? data.each(&Proc.new) self else to_enum end end
# File lib/bibtex/bibliography.rb, line 502 def each_entry if block_given? q('@entry').each(&Proc.new) else q('@entry').to_enum end end
Returns true if there are object which could not be parsed.
# File lib/bibtex/bibliography.rb, line 249 def errors? !errors.empty? end
Extends the initials for the given names. Returns the Bibliography.
# File lib/bibtex/bibliography.rb, line 302 def extend_initials(*arguments) arguments.each do |with_first, for_last| names.each do |name| name.extend_initials(with_first, for_last) end end self end
This method combines all names in the bibliography that look identical when using initials as first names and then tries to extend the first names for all names in each group to the longest available form. Returns the bibliography.
If your bibliography contains the names 'Poe, Edgar A.', 'Poe, E.A.', and 'Poe, E. A.' calling this method would convert all three names to 'Poe, Edgar A.'.
# File lib/bibtex/bibliography.rb, line 320 def extend_initials! groups = Hash.new do |h,k| h[k] = { :prototype => nil, :names => [] } end # group names together names.each do |name| group = groups[name.sort_order(:initials => true).downcase] group[:names] << name if group[:prototype].nil? || group[:prototype].first.to_s.length < name.first.to_s.length group[:prototype] = name end end # extend all names in group to prototype groups.each_value do |group| group[:names].each do |name| name.set(group[:prototype]) end end self end
# File lib/bibtex/bibliography.rb, line 510 def find_by_type(*types, &block) q(types.flatten.compact.map { |t| "@#{t}" }.join(', '), &block) end
# File lib/bibtex/bibliography.rb, line 370 def group_by(*arguments, &block) groups = Hash.new { |h,k| h[k] = [] } entries.values.each do |e| groups[e.digest(arguments, &block)] << e end groups end
# 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) } other.each do |element| add element.dup end self end
# File lib/bibtex/bibliography.rb, line 399 def inspect "#<#{self.class} data=[#{length}]>" end
# File lib/bibtex/bibliography.rb, line 284 def join(filter = '') q(filter, &:join) self end
Returns a list of the names of all authors, editors and translators in the Bibliography.
# File lib/bibtex/bibliography.rb, line 260 def names map(&:names).flatten end
# File lib/bibtex/bibliography.rb, line 163 def parse_months entries.each_value { |e| e.parse_month } self end
# File lib/bibtex/bibliography.rb, line 158 def parse_names entries.each_value { |e| e.parse_names } self end
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) }
# File lib/bibtex/bibliography.rb, line 482 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
# File lib/bibtex/bibliography.rb, line 291 def rename(*arguments, &block) q('@entry') { |e| e.rename(*arguments, &block) } self end
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.
# File lib/bibtex/bibliography.rb, line 277 def replace(filter = '') q(filter) { |e| e.replace(@strings.values) } self end
Saves the bibliography to the current path.
# File lib/bibtex/bibliography.rb, line 132 def save(options = {}) save_to(@path, options) end
Saves the bibliography to a file at the given path. Returns the bibliography.
# File lib/bibtex/bibliography.rb, line 137 def save_to(path, options = {}) options[:quotes] ||= %w({ }) File.open(path, 'w:UTF-8') do |f| f.write(to_s(options)) end self end
# File lib/bibtex/bibliography.rb, line 520 def select_duplicates_by(*arguments) arguments = [:year, :title] if arguments.empty? block = Proc.new if block_given? group_by(*arguments) { |digest, entry| # 1.8 compatibility # digest = digest[0] if digest.is_a?(Array) digest.gsub(/\s+/, '').downcase digest = block.call(digest, entry) unless block.nil? digest }.values.select { |d| d.length > 1 } end
# File lib/bibtex/bibliography.rb, line 385 def sort(*arguments, &block) dup.sort!(*arguments, &block) end
# File lib/bibtex/bibliography.rb, line 380 def sort!(*arguments, &block) data.sort!(*arguments, &block) self end
# File lib/bibtex/bibliography.rb, line 389 def sort_by!(*arguments, &block) data.sort_by!(*arguments, &block) self end
# File lib/bibtex/bibliography.rb, line 403 def to_a(options = {}) map { |o| o.to_hash(options) } end
Returns a CiteProc JSON representation of the bibliography. Only BibTeX enrties are exported.
# File lib/bibtex/bibliography.rb, line 423 def to_citeproc(options = {}) q('@entry').map { |o| o.to_citeproc(options) } end
Returns a Ruby hash representation of the bibliography.
# File lib/bibtex/bibliography.rb, line 408 def to_hash(options = {}) { :bibliography => map { |o| o.to_hash(options) } } end
Returns a JSON representation of the bibliography.
# File lib/bibtex/bibliography.rb, line 418 def to_json(options = {}) ::JSON.dump(to_a(options)) end
Returns an RDF::Graph representation of the bibliography. The graph can be serialized using any of the RDF serializer plugins.
# File lib/bibtex/bibliography.rb, line 446 def to_rdf(options = {}) if defined?(::RDF) RDFConverter.convert(self) else BibTeX.log.error 'Please `gem install rdf` for RDF support.' end end
Returns a string representation of the bibliography.
# File lib/bibtex/bibliography.rb, line 395 def to_s(options = {}) map { |o| o.to_s(options) }.join end
Returns a REXML::Document representation of the bibliography using the BibTeXML format.
# File lib/bibtex/bibliography.rb, line 429 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
Returns a YAML representation of the bibliography.
# File lib/bibtex/bibliography.rb, line 413 def to_yaml(options = {}) to_a(options).to_yaml end
Sets all fields matching the passed-in pattern to the supplied value. If a block is given, each matching entry will be passed to the block instead. Returns the bibliography.
# File lib/bibtex/bibliography.rb, line 352 def unify(field, pattern, value = nil) pattern = Regexp.new(pattern) unless pattern.is_a?(Regexp) block = if block_given? Proc.new else Proc.new { |e| e[field] = value } end each_entry do |entry| if entry.field?(field) && entry[field].to_s =~ pattern block.call(entry) end end self end
Experimental! Returns a new Bibliography with all duplicates removed.
# File lib/bibtex/bibliography.rb, line 576 def uniq(*arguments, &block) dup.uniq! end
Removes duplicate entries from the Bibliography.
All arguments given will be used to calculate a digest for each entry. If a block is given, it will be be passed the computed digest as well as each entry; the block must then yield the final digest that will be used to compute duplicates.
This method will always retain the first entry and will discard subsequent duplicates on the basis of each entry's digest.
@see BibTeX::Entry#digest @see @duplicates_by
# File lib/bibtex/bibliography.rb, line 563 def uniq!(*arguments, &block) select_duplicates_by(*arguments, &block).each do |dupes| dupes.shift dupes.each do |dupe| self.remove dupe end end self end
Returns true if the Bibliography
contains no errors and only
valid BibTeX objects (meta content is
ignored).
# File lib/bibtex/bibliography.rb, line 255 def valid? !errors? && entries.values.all?(&:valid?) end
# File lib/bibtex/bibliography.rb, line 582 def query_handler(selector) case selector.to_s when /first|distinct|detect/ :detect when /none|reject|not/ :reject else :select end end