class BibTeX::Entry

Represents a regular BibTeX entry.

Constants

DATE_FIELDS
FIELD_ALIASES

Defines the default fallbacks for values defined in cross-references

MONTHS
MONTHS_FILTER
NAME_FIELDS
REQUIRED_FIELDS

Defines the required fields of the standard entry types

Attributes

fields[R]
type[R]

Public Class Methods

new(attributes = {}) { |self| ... } click to toggle source

Creates a new instance. If a hash is given, the entry is populated accordingly.

# File lib/bibtex/entry.rb, line 72
def initialize(attributes = {})
  @fields = {}
  @key = nil

  self.type = attributes.delete(:bibtex_type) if attributes.key?(:bibtex_type)
  self.key = attributes.delete(:bibtex_key) if attributes.key?(:bibtex_key)

  add(attributes)

  yield self if block_given?
end

Public Instance Methods

<<
Alias for: add
<=>(other) click to toggle source
# File lib/bibtex/entry.rb, line 587
def <=>(other)
  type != other.type ? type <=> other.type : key != other.key ? key <=> other.key : to_s <=> other.to_s
end
[](name) click to toggle source

Returns the value of the field with the given name. If the value is not defined and the entry has cross-reference, returns the cross-referenced value instead.

# File lib/bibtex/entry.rb, line 309
def [](name)
  fields[name.to_sym] || parent&.provide(name)
end
Also aliased as: get
[]=(name, value) click to toggle source

Adds a new field (name-value pair) to the entry. Returns the new value.

# File lib/bibtex/entry.rb, line 321
def []=(name, value)
  add(name.to_sym, value)
end
add(:author, "Edgar A. Poe") click to toggle source
add(:author, "Edgar A. Poe", :title, "The Raven")
add([:author, "Edgar A. Poe", :title, "The Raven"])
add(:author => "Edgar A. Poe", :title → "The Raven")
add(:author => Names.new(Name.new(:first => 'Edgar A.', :last → 'Poe')))

Adds a new field (name-value pair) or multiple fields to the entry. Returns the entry for chainability.

# File lib/bibtex/entry.rb, line 334
def add(*arguments)
  Hash[*arguments.flatten].each_pair do |name, value|
    fields[name.to_sym] = Value.create(value)
  end

  self
end
Also aliased as: <<
added_to_bibliography(bibliography) click to toggle source

Called when the element was added to a bibliography.

Calls superclass method BibTeX::Element#added_to_bibliography
# File lib/bibtex/entry.rb, line 396
def added_to_bibliography(bibliography)
  super

  @key = register(key)

  %i[parse_names parse_months].each do |parser|
    send(parser) if bibliography.options[parser]
  end

  if bibliography.options.key?(:filter)
    [*bibliography.options[:filter]].each do |filter|
      convert!(filter)
    end
  end

  self
end
aliases() click to toggle source

Returns the Entry’s field name aliases.

# File lib/bibtex/entry.rb, line 142
def aliases
  @aliases ||= FIELD_ALIASES.dup
end
children() click to toggle source

Returns a list of all entries in the Bibliography containing a cross-reference to this entry or [] if there are no references to this entry.

# File lib/bibtex/entry.rb, line 536
def children
  bibliography&.q("@entry[crossref=#{key}]") || []
end
Also aliased as: cross_referenced_by
contained?() click to toggle source

Returns true if this entry is published inside a book, collection or journal

# File lib/bibtex/entry.rb, line 555
def contained?
  has_field?(:container, :journal) ||
    has_field?(:booktitle) && get(:booktitle) != get(:title)
end
container_title() click to toggle source
# File lib/bibtex/entry.rb, line 542
def container_title
  get(:booktitle) || get(:journal) || get(:container)
end
content(options = {}) click to toggle source

Returns a string of all the entry’s fields.

# File lib/bibtex/entry.rb, line 592
def content(options = {})
  fields.map { |k, _v| "#{k} = #{fields[k].to_s(options)}" }.join(",\n")
end
convert(*filters, &block) click to toggle source

Returns a duplicate entry with all values converted using the filter(s). If an optional block is given, only those values will be converted where the block returns true (the block will be called with each key-value pair).

@see convert!

# File lib/bibtex/entry.rb, line 572
def convert(*filters, &block)
  block_given? ? dup.convert!(*filters, &block) : dup.convert!(*filters)
end
convert!(*filters) { |k, v| ... } click to toggle source

In-place variant of @see convert

# File lib/bibtex/entry.rb, line 577
def convert!(*filters)
  filters = filters.flatten.map { |f| Filters.resolve!(f) }

  fields.each_pair do |k, v|
    !block_given? || yield(k, v) ? v.convert!(*filters) : v
  end

  self
end
cross_reference()
Alias for: parent
cross_reference_missing?()
Alias for: parent_missing?
cross_referenced?()
Alias for: has_children?
cross_referenced_by()
Alias for: children
date() click to toggle source
# File lib/bibtex/entry.rb, line 478
def date
  get(:date) || get(:year)
end
delete(name) click to toggle source

Removes the field with a given name from the entry. Returns the value of the deleted field; nil if the field was not set.

# File lib/bibtex/entry.rb, line 346
def delete(name)
  fields.delete(name.to_sym)
end
digest(filter = []) { |digest, self| ... } click to toggle source

Creates the entry’s digest based on the passed-in filters.

The digest contains the type and all key-value pairs based on the passed in filter.

If a block is given, the computed digest will be passed to the block for post-processing (the entry itself will be passed as the second parameter).

@see field_names

@param [<Symbol>] the field names to use @return [String] the digest string

# File lib/bibtex/entry.rb, line 371
def digest(filter = [])
  names = field_names(filter)
  digest = type.to_s

  names.zip(values_at(*names)).each do |key, value|
    digest << "|#{key}:#{value}"
  end

  digest = yield(digest, self) if block_given?
  digest
end
each { |key, value| block } → entry click to toggle source
each → an_enumerator

Calls block once for each key in entry, passing the key-value pair as parameters.

If no block is given, an enumerator is returned instead.

# File lib/bibtex/entry.rb, line 130
def each(&block)
  if block_given?
    fields.each(&block)
    self
  else
    to_enum
  end
end
Also aliased as: each_pair
each_pair { |key, value| block } → entry
each_pair → an_enumerator
Alias for: each
fetch(name, default = nil) { |name| ... } click to toggle source
# File lib/bibtex/entry.rb, line 315
def fetch(name, default = nil)
  get(name) || (block_given? ? yield(name) : default)
end
field?(*names)
Alias for: has_field?
field_names(filter = [], include_inherited = true) click to toggle source

Returns a sorted list of the Entry’s field names. If a filter is passed as argument, returns all field names that are also defined by the filter. If the filter is empty, returns all field names.

If the second optional argument is true (default) and the Entry contains a cross-reference, the list will include all inherited fields.

# File lib/bibtex/entry.rb, line 244
def field_names(filter = [], include_inherited = true)
  names = fields.keys

  names.concat(inherited_fields) if include_inherited && has_parent?

  names &= filter.map(&:to_sym) unless filter.empty?

  names.sort!
  names
end
get(name)
Alias for: []
has_children?() click to toggle source

Returns true if the entry is cross-referenced by another entry in the Bibliography.

# File lib/bibtex/entry.rb, line 527
def has_children?
  !children.empty?
end
Also aliased as: cross_referenced?
has_cross_reference?()
Alias for: has_parent?
has_field?(*names) click to toggle source
# File lib/bibtex/entry.rb, line 187
def has_field?(*names)
  names.flatten.any? do |name|
    name.respond_to?(:to_sym) ? fields.key?(name.to_sym) : false
  end
end
Also aliased as: field?
has_parent?() click to toggle source

Returns true if the Entry has a valid cross-reference in the Bibliography.

# File lib/bibtex/entry.rb, line 503
def has_parent?
  !parent.nil?
end
Also aliased as: has_cross_reference?
has_type?(type) click to toggle source
Calls superclass method BibTeX::Element#has_type?
# File lib/bibtex/entry.rb, line 181
def has_type?(type)
  type.to_s.match(/^(?:entry|\*)$/i) || @type.casecmp?(type.to_sym) || super
end
Also aliased as: type?
id()
Alias for: key
id=(key)
Alias for: key=
identifier() click to toggle source
# File lib/bibtex/entry.rb, line 383
def identifier
  if provides?(:doi)
    "info:doi/#{get(:doi)}"
  elsif provides?(:isbn)
    "urn:isbn:#{get(:isbn)}"
  elsif provides?(:issn)
    "urn:issn:#{get(:issn)}"
  else
    "urn:bibtex:#{key}"
  end
end
inherited_fields() click to toggle source

Returns a sorted list of all field names referenced by this Entry’s cross-reference.

# File lib/bibtex/entry.rb, line 256
def inherited_fields
  return [] unless has_parent?

  names = parent.fields.keys - fields.keys
  names.concat(parent.aliases.select { |_k, v| parent.has_field?(v) }.keys)
  names.sort!

  names
end
inherits?(*names) click to toggle source
# File lib/bibtex/entry.rb, line 195
def inherits?(*names)
  names.flatten.any? do |name|
    !has_field(name) && has_parent? && parent.provides?(name)
  end
end
initialize_copy(other) click to toggle source
# File lib/bibtex/entry.rb, line 84
def initialize_copy(other)
  @fields = {}

  self.type = other.type
  self.key = other.key

  add(other.fields)
end
join() click to toggle source
# File lib/bibtex/entry.rb, line 446
def join
  fields.values.each(&:join)
  self
end
key() click to toggle source
# File lib/bibtex/entry.rb, line 165
def key
  if @key.nil? || @key.empty?
    @key = default_key
  else
    @key
  end
end
Also aliased as: id
key=(key) click to toggle source

Sets the Entry’s key. If the Entry is currently registered with a Bibliography, re-registers the Entry with the new key; note that this may change the key value if another Entry is already regsitered with the same key.

Returns the new key.

# File lib/bibtex/entry.rb, line 152
def key=(key)
  key = key.to_s

  if registered?
    bibliography.entries.delete(@key)
    key = register(key)
  end

  @key = key
rescue StandardError => e
  raise BibTeXError, "failed to set key to #{key.inspect}: #{e.message}"
end
Also aliased as: id=
merge(other, filter = field_names) click to toggle source
# File lib/bibtex/entry.rb, line 93
def merge(other, filter = field_names)
  dup.merge!(other, filter)
end
merge!(other, filter = field_names) click to toggle source
# File lib/bibtex/entry.rb, line 97
def merge!(other, filter = field_names)
  raise InvalidArgument, "failed to merge entries: type mismatch: #{type} #{other.type}" unless
    type == other.type

  other.each do |name, value|
    if has_field?(name)
      get(name).merge!(value) if filter.include?(name)
    else
      add name, value.dup
    end
  end

  self
end
method_missing(name, *args, &block) click to toggle source
Calls superclass method
# File lib/bibtex/entry.rb, line 266
def method_missing(name, *args, &block)
  if fields.key?(name)
    fields[name]
  elsif name.to_s =~ /^(.+)=$/
    send(:add, Regexp.last_match(1).to_sym, args[0])
  elsif name =~ /^(?:convert|from)_([a-z]+)(!)?$/
    Regexp.last_match(2) ? convert!(Regexp.last_match(1), &block) : convert(Regexp.last_match(1), &block)
  elsif has_parent? && parent.provides?(name)
    parent.provide(name)
  else
    super
  end
end
month=(month) click to toggle source
# File lib/bibtex/entry.rb, line 451
def month=(month)
  fields[:month] = month
ensure
  parse_month
end
month_numeric() click to toggle source
# File lib/bibtex/entry.rb, line 457
def month_numeric
  return unless has_field?(:month)
  return unless (num = MONTHS.index fields[:month].to_sym)

  num.succ
end
names() click to toggle source

Returns a list of all names (authors, editors, translators).

# File lib/bibtex/entry.rb, line 498
def names
  NAME_FIELDS.map { |k| has_field?(k) ? @fields[k].tokens : nil }.flatten.compact
end
pages_from() click to toggle source
# File lib/bibtex/entry.rb, line 546
def pages_from
  fetch(:pages, '').split(/\D+/)[0]
end
pages_to() click to toggle source
# File lib/bibtex/entry.rb, line 550
def pages_to
  fetch(:pages, '').split(/\D+/)[-1]
end
parent() click to toggle source

Returns the cross-referenced Entry from the Bibliography or nil if this Entry does define a cross-reference.

# File lib/bibtex/entry.rb, line 519
def parent
  bibliography && bibliography[fields[:crossref]]
end
Also aliased as: cross_reference
parent_missing?() click to toggle source

Returns true if the Entry cross-references an Entry which is not registered in the current Bibliography.

# File lib/bibtex/entry.rb, line 511
def parent_missing?
  has_field?(:crossref) && !has_parent?
end
Also aliased as: cross_reference_missing?
parse_month() click to toggle source
# File lib/bibtex/entry.rb, line 464
def parse_month
  fields.delete(:month_numeric)
  return unless has_field?(:month)

  fields[:month] = MONTHS_FILTER[fields[:month]]

  numeric = MONTHS.index(fields[:month].to_sym)
  fields[:month_numeric] = Value.new(numeric.succ) if numeric

  self
end
Also aliased as: parse_months
parse_months()
Alias for: parse_month
parse_names() click to toggle source

Parses all name values of the entry. Tries to replace and join the value prior to parsing.

# File lib/bibtex/entry.rb, line 484
def parse_names
  strings = bibliography ? bibliography.strings.values : []

  NAME_FIELDS.each do |key|
    if name = fields[key]
      name = name.dup.replace(strings).join.to_name
      fields[key] = name unless name.nil?
    end
  end

  self
end
provide(name) click to toggle source

Returns the field value referenced by the passed-in name. For example, this will return the ‘title’ value for ‘booktitle’ if a corresponding alias is defined.

# File lib/bibtex/entry.rb, line 219
def provide(name)
  return nil unless name.respond_to?(:to_sym)

  name = name.to_sym
  fields[name] || fields[aliases[name]]
end
provides?(*names) click to toggle source

Returns true if the Entry has a field (or alias) for any of the passed-in names.

# File lib/bibtex/entry.rb, line 202
def provides?(*names)
  names.flatten.any? do |name|
    if name.respond_to?(:to_sym)
      has_field?(name) || has_field?(aliases[name.to_sym])
    else
      false
    end
  end
end
provides_or_inherits?(*names) click to toggle source
# File lib/bibtex/entry.rb, line 212
def provides_or_inherits?(*names)
  provides?(names) || inherits?(names)
end
register(key) click to toggle source

Registers this Entry in the associated Bibliographies entries hash. This method may change the Entry’s key, if another entry is already registered with the current key.

Returns the key or nil if the Entry is not associated with a Bibliography.

# File lib/bibtex/entry.rb, line 431
def register(key)
  return nil if bibliography.nil?

  k = key.dup
  k.succ! while bibliography.key?(k)
  bibliography.entries[k] = self
  k
end
registered?() click to toggle source

Returns true if the Entry is currently registered with the associated Bibliography.

# File lib/bibtex/entry.rb, line 422
def registered?
  !!(bibliography && bibliography.entries[key].equal?(self))
end
removed_from_bibliography(bibliography) click to toggle source

Called when the element was removed from a bibliography.

# File lib/bibtex/entry.rb, line 415
def removed_from_bibliography(bibliography)
  super
  bibliography.entries.delete(key)
  self
end
rename(*arguments) click to toggle source

Returns a copy of the Entry with all the field names renamed.

# File lib/bibtex/entry.rb, line 287
def rename(*arguments)
  dup.rename!(*arguments)
end
Also aliased as: rename_fields
rename!(*arguments) click to toggle source

Renames the given field names unless a field with the new name already exists.

# File lib/bibtex/entry.rb, line 293
def rename!(*arguments)
  Hash[*arguments.flatten].each_pair do |from, to|
    if fields.key?(from) && !fields.key?(to)
      fields[to] = fields[from]
      fields.delete(from)
    end
  end
  self
end
Also aliased as: rename_fields!
rename_fields(*arguments)
Alias for: rename
rename_fields!(*arguments)
Alias for: rename!
replace(*arguments) click to toggle source
# File lib/bibtex/entry.rb, line 440
def replace(*arguments)
  arguments = bibliography.q('@string') if arguments.empty?
  fields.values.each { |v| v.replace(*arguments) }
  self
end
respond_to?(method, include_all = false) click to toggle source
Calls superclass method
# File lib/bibtex/entry.rb, line 280
def respond_to?(method, include_all = false)
  provides?(method.to_sym) || method.to_s.match(/=$/) ||
    method =~ /^(?:convert|from)_([a-z]+)(!)?$/ ||
    (has_parent? && parent.respond_to?(method, include_all)) || super
end
save_inherited_fields() click to toggle source

If the Entry has a cross-reference, copies all referenced all inherited values from the parent.

Returns the Entry.

# File lib/bibtex/entry.rb, line 230
def save_inherited_fields
  inherited_fields.each do |name|
    fields[name] = parent.provide(name)
  end

  self
end
to_bibo(_options = {})
Alias for: to_rdf
to_citeproc(options = {}) click to toggle source
# File lib/bibtex/entry.rb, line 609
def to_citeproc(options = {})
  CiteProcConverter.convert(self, options)
end
to_hash(options = {}) click to toggle source
# File lib/bibtex/entry.rb, line 602
def to_hash(options = {})
  options[:quotes] ||= %w[{ }]
  hash = { bibtex_key: key, bibtex_type: type }
  each_pair { |k, v| hash[k] = v.to_s(options) }
  hash
end
to_rdf(_options = {}) click to toggle source

Returns a RDF::Graph representation of the entry using the BIBO ontology.

# File lib/bibtex/entry.rb, line 618
def to_rdf(_options = {})
  if defined?(::RDF)
    RDFConverter.convert(self)
  else
    BibTeX.log.error 'Please `gem install rdf` for RDF support.'
  end
end
Also aliased as: to_bibo
to_s(options = {}) click to toggle source

Returns a string representation of the entry.

# File lib/bibtex/entry.rb, line 597
def to_s(options = {})
  options[:quotes] ||= %w[{ }]
  ["@#{type}{#{key},", content(options).gsub(/^/, '  '), "}\n"].join("\n")
end
to_xml(options = {}) click to toggle source
# File lib/bibtex/entry.rb, line 613
def to_xml(options = {})
  BibTeXMLConverter.convert(self, options)
end
type=(type) click to toggle source

Sets the type of the entry.

# File lib/bibtex/entry.rb, line 177
def type=(type)
  @type = type.to_sym
end
type?(type)
Alias for: has_type?
update(fields) click to toggle source
# File lib/bibtex/entry.rb, line 112
def update(fields)
  fields.each do |name, value|
    add name, value
  end

  self
end
valid?() click to toggle source

Returns false if the entry is one of the standard entry types and does not have definitions of all the required fields for that type.

# File lib/bibtex/entry.rb, line 352
def valid?
  REQUIRED_FIELDS[type].all? do |f|
    f.is_a?(Array) ? !(f & fields.keys).empty? : !fields[f].nil?
  end
end
values_at(*arguments) click to toggle source

Returns an array containing the values associated with the given keys.

# File lib/bibtex/entry.rb, line 561
def values_at(*arguments)
  arguments.map do |key|
    get key
  end
end
year() click to toggle source
# File lib/bibtex/entry.rb, line 628
def year
  return fields[:year] if has_field?(:year)
  return unless has_field?(:date)

  fields[:date].to_s[/\d{4}/]
end

Private Instance Methods

default_key() click to toggle source

Returns a default key for this entry.

# File lib/bibtex/entry.rb, line 676
def default_key
  k = names[0]
  k = k.respond_to?(:family) ? k.family : k.to_s
  k = BibTeX.transliterate(k).gsub(/["']/, '')
  k = k[/[A-Za-z-]+/] || 'unknown'
  k << (year.to_s[/\d+/] || '-')
  k << 'a'
  k.downcase!
  k
end