Represents a regular BibTeX entry.
Defines the default fallbacks for values defined in cross-references
Defines the required fields of the standard entry types
Creates a new instance. If a hash is given, the entry is populated accordingly.
# File lib/bibtex/entry.rb, line 73 def initialize(attributes = {}) @fields = {} @key = nil self.type = attributes.delete(:bibtex_type) if attributes.has_key?(:bibtex_type) self.key = attributes.delete(:bibtex_key) if attributes.has_key?(:bibtex_key) add(attributes) yield self if block_given? end
# File lib/bibtex/entry.rb, line 627 def <=>(other) type != other.type ? type <=> other.type : key != other.key ? key <=> other.key : to_s <=> other.to_s end
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 346 def [](name) fields[name.to_sym] || parent && parent.provide(name) end
Adds a new field (name-value pair) to the entry. Returns the new value.
# File lib/bibtex/entry.rb, line 358 def []=(name, value) add(name.to_sym, value) end
Adds a new field (name-value pair) or multiple fields to the entry. Returns the entry for chainability.
# File lib/bibtex/entry.rb, line 371 def add(*arguments) Hash[*arguments.flatten].each_pair do |name, value| fields[name.to_sym] = Value.create(value) end self end
Called when the element was added to a bibliography.
# File lib/bibtex/entry.rb, line 434 def added_to_bibliography(bibliography) super @key = register(key) [:parse_names, :parse_months].each do |parser| send(parser) if bibliography.options[parser] end if bibliography.options.has_key?(:filter) [*bibliography.options[:filter]].each do |filter| convert!(filter) end end self end
Returns the Entry's field name aliases.
# File lib/bibtex/entry.rb, line 173 def aliases @aliases ||= FIELD_ALIASES.dup end
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 576 def children bibliography && bibliography.q("@entry[crossref=#{key}]") or [] end
Returns true if this entry is published inside a book, collection or journal
# File lib/bibtex/entry.rb, line 595 def contained? has_field?(:container, :journal) || has_field?(:booktitle) && get(:booktitle) != get(:title) end
# File lib/bibtex/entry.rb, line 582 def container_title get(:booktitle) || get(:journal) || get(:container) end
Returns a string of all the entry's fields.
# File lib/bibtex/entry.rb, line 633 def content(options = {}) fields.map { |k,v| "#{k} = #{ fields[k].to_s(options) }" }.join(",\n") end
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 612 def convert(*filters) block_given? ? dup.convert!(*filters, &Proc.new) : dup.convert!(*filters) end
In-place variant of @see convert
# File lib/bibtex/entry.rb, line 617 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
# File lib/bibtex/entry.rb, line 516 def date get(:date) || get(:year) end
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 383 def delete(name) fields.delete(name.to_sym) end
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 408 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
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 160 def each if block_given? fields.each(&Proc.new) self else to_enum end end
# File lib/bibtex/entry.rb, line 352 def fetch(name, default = nil) get(name) || (block_given? ? yield(name) : default) end
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 275 def field_names(filter = [], include_inherited = true) names = fields.keys if include_inherited && has_parent? names.concat(inherited_fields) end unless filter.empty? names = names & filter.map(&:to_sym) end names.sort! names end
Returns true if the entry is cross-referenced by another entry in the Bibliography.
# File lib/bibtex/entry.rb, line 567 def has_children? !children.empty? end
# File lib/bibtex/entry.rb, line 219 def has_field?(*names) names.flatten.any? do |name| name.respond_to?(:to_sym) ? fields.has_key?(name.to_sym) : false end end
Returns true if the Entry has a valid cross-reference in the Bibliography.
# File lib/bibtex/entry.rb, line 542 def has_parent? !parent.nil? end
# File lib/bibtex/entry.rb, line 212 def has_type?(type) type.to_s.match(/^(?:entry|\*)$/) || @type == type.to_sym || super end
# File lib/bibtex/entry.rb, line 420 def identifier case when provides?(:doi) "info:doi/#{get(:doi)}" when provides?(:isbn) "urn:isbn:#{get(:isbn)}" when provides?(:issn) "urn:issn:#{get(:issn)}" else "urn:bibtex:#{key}" end end
Returns a sorted list of all field names referenced by this Entry's cross-reference.
# File lib/bibtex/entry.rb, line 291 def inherited_fields return [] unless has_parent? names = parent.fields.keys - fields.keys names.concat(parent.aliases.reject { |k,v| !parent.has_field?(v) }.keys) names.sort! names end
# File lib/bibtex/entry.rb, line 227 def inherits?(*names) names.flatten.any? do |name| !has_field(name) && has_parent? && parent.provides?(name) end end
# File lib/bibtex/entry.rb, line 85 def initialize_copy(other) @fields = {} self.type = other.type self.key = other.key add(other.fields) end
# File lib/bibtex/entry.rb, line 484 def join fields.values.each(&:join) self end
# File lib/bibtex/entry.rb, line 196 def key if @key.nil? || @key.empty? @key = default_key else @key end end
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 183 def key=(key) key = key.to_s if registered? bibliography.entries.delete(@key) key = register(key) end @key = key rescue => e raise BibTeXError, "failed to set key to #{key.inspect}: #{e.message}" end
# File lib/bibtex/entry.rb, line 94 def merge(other, filter = field_names) dup.merge!(other, filter) end
# File lib/bibtex/entry.rb, line 98 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
# File lib/bibtex/entry.rb, line 302 def method_missing(name, *args, &block) case when fields.has_key?(name) fields[name] when name.to_s =~ /^(.+)=$/ send(:add, $1.to_sym, args[0]) when name =~ /^(?:convert|from)_([a-z]+)(!)?$/ $2 ? convert!($1, &block) : convert($1, &block) when has_parent? && parent.provides?(name) parent.provide(name) else super end end
# File lib/bibtex/entry.rb, line 489 def month=(month) fields[:month] = month ensure parse_month end
# File lib/bibtex/entry.rb, line 495 def month_numeric return unless has_field?(:month) return unless (num = MONTHS.index fields[:month].to_sym) num.succ end
Returns a list of all names (authors, editors, translators).
# File lib/bibtex/entry.rb, line 536 def names NAME_FIELDS.map { |k| has_field?(k) ? @fields[k].tokens : nil }.flatten.compact end
# File lib/bibtex/entry.rb, line 586 def pages_from fetch(:pages, '').split(/\D+/)[0] end
# File lib/bibtex/entry.rb, line 590 def pages_to fetch(:pages, '').split(/\D+/)[-1] end
Returns the cross-referenced Entry from the Bibliography or nil if this Entry does define a cross-reference.
# File lib/bibtex/entry.rb, line 558 def parent bibliography && bibliography[fields[:crossref]] end
Returns true if the Entry cross-references an Entry which is not registered in the current Bibliography.
# File lib/bibtex/entry.rb, line 550 def parent_missing? has_field?(:crossref) && !has_parent? end
# File lib/bibtex/entry.rb, line 502 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
Parses all name values of the entry. Tries to replace and join the value prior to parsing.
# File lib/bibtex/entry.rb, line 522 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
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 251 def provide(name) return nil unless name.respond_to?(:to_sym) name = name.to_sym fields[name] || fields[aliases[name]] end
Returns true if the Entry has a field (or alias) for any of the passed-in names.
# File lib/bibtex/entry.rb, line 234 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
# File lib/bibtex/entry.rb, line 244 def provides_or_inherits?(*names) provides?(names) || inherits?(names) end
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 469 def register(key) return nil if bibliography.nil? k = key.dup k.succ! while bibliography.has_key?(k) bibliography.entries[k] = self k end
Returns true if the Entry is currently registered with the associated Bibliography.
# File lib/bibtex/entry.rb, line 460 def registered? !!(bibliography && bibliography.entries[key].equal?(self)) end
Called when the element was removed from a bibliography.
# File lib/bibtex/entry.rb, line 453 def removed_from_bibliography(bibliography) super bibliography.entries.delete(key) self end
Returns a copy of the Entry with all the field names renamed.
# File lib/bibtex/entry.rb, line 324 def rename(*arguments) dup.rename!(*arguments) end
Renames the given field names unless a field with the new name already exists.
# File lib/bibtex/entry.rb, line 330 def rename!(*arguments) Hash[*arguments.flatten].each_pair do |from,to| if fields.has_key?(from) && !fields.has_key?(to) fields[to] = fields[from] fields.delete(from) end end self end
# File lib/bibtex/entry.rb, line 478 def replace(*arguments) arguments = bibliography.q('@string') if arguments.empty? fields.values.each { |v| v.replace(*arguments) } self end
# File lib/bibtex/entry.rb, line 317 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
# File lib/bibtex/entry.rb, line 650 def to_citeproc(options = {}) CiteProcConverter.convert(self, options) end
# File lib/bibtex/entry.rb, line 643 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
Returns a RDF::Graph representation of the entry using the BIBO ontology.
# File lib/bibtex/entry.rb, line 659 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 entry.
# File lib/bibtex/entry.rb, line 638 def to_s(options = {}) options[:quotes] ||= %w({ }) ["@#{type}{#{key},", content(options).gsub(/^/,' '), "}\n"].join("\n") end
# File lib/bibtex/entry.rb, line 654 def to_xml(options = {}) BibTeXMLConverter.convert(self, options) end
Sets the type of the entry.
# File lib/bibtex/entry.rb, line 208 def type=(type) @type = type.to_sym end
# File lib/bibtex/entry.rb, line 113 def update(fields) fields.each do |name, value| add name, value end self end
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 389 def valid? REQUIRED_FIELDS[type].all? do |f| f.is_a?(Array) ? !(f & fields.keys).empty? : !fields[f].nil? end end
Returns an array containing the values associated with the given keys.
# File lib/bibtex/entry.rb, line 601 def values_at(*arguments) arguments.map do |key| get key end end
# File lib/bibtex/entry.rb, line 669 def year return fields[:year] if has_field?(:year) return unless has_field?(:date) fields[:date].to_s[/\d{4}/] end
Returns a default key for this entry.
# File lib/bibtex/entry.rb, line 679 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