Class: BibTeX::Entry
- Extended by:
- Forwardable
- Includes:
- Enumerable
- Defined in:
- lib/bibtex/entry.rb
Overview
Represents a regular BibTeX entry.
Constant Summary collapse
- REQUIRED_FIELDS =
Defines the required fields of the standard entry types
Hash.new([]).merge({ :article => [:author,:title,:journal,:year], :book => [[:author,:editor],:title,:publisher,:year], :booklet => [:title], :conference => [:author,:title,:booktitle,:year], :inbook => [[:author,:editor],:title,[:chapter,:pages],:publisher,:year], :incollection => [:author,:title,:booktitle,:publisher,:year], :inproceedings => [:author,:title,:booktitle,:year], :manual => [:title], :mastersthesis => [:author,:title,:school,:year], :misc => [], :phdthesis => [:author,:title,:school,:year], :proceedings => [:title,:year], :techreport => [:author,:title,:institution,:year], :unpublished => [:author,:title,:note] }).freeze
- FIELD_ALIASES =
Defines the default fallbacks for values defined in cross-references
{ :booktitle => :title, # :editor => :author }.freeze
- NAME_FIELDS =
[:author,:editor,:translator].freeze
- DATE_FIELDS =
[:year,:month].freeze
- MONTHS =
[:jan,:feb,:mar,:apr,:may,:jun,:jul,:aug,:sep,:oct,:nov,:dec].freeze
- MONTHS_FILTER =
Hash.new do |h,k| case k.to_s.strip when /^(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)/i h[k] = Value.new(k.to_s[0,3].downcase.to_sym) when /^\d\d?$/ h[k] = Value.new(MONTHS[k.to_i - 1] || k) else h[k] = Value.new(k) end end
- CSL_FILTER =
Hash.new {|h,k|k}.merge(Hash[*%w{ date issued isbn ISBN booktitle container-title journal container-title series collection-title address publisher-place pages page number issue url URL doi DOI year issued }.map(&:intern)]).freeze
- CSL_FIELDS =
%w{ abstract annote archive archive_location archive-place authority call-number chapter-number citation-label citation-number collection-title container-title DOI edition event event-place first-reference-note-number genre ISBN issue jurisdiction keyword locator medium note number number-of-pages number-of-volumes original-publisher original-publisher-place original-title page page-first publisher publisher-place references section status title URL version volume year-suffix accessed container event-date issued original-date author editor translator recipient interviewer publisher composer original-publisher original-author container-author collection-editor }.map(&:intern).freeze
- CSL_TYPES =
Hash.new {|h,k|k}.merge(Hash[*%w{ booklet pamphlet conference paper-conference inbook chapter incollection chapter inproceedings paper-conference manual book mastersthesis thesis misc article phdthesis thesis proceedings paper-conference techreport report unpublished manuscript article article-journal }.map(&:intern)]).freeze
Instance Attribute Summary collapse
-
#fields ⇒ Object
readonly
Returns the value of attribute fields.
-
#type ⇒ Object
Returns the value of attribute type.
Attributes inherited from Element
Instance Method Summary collapse
- #<=>(other) ⇒ Object
-
#[](name) ⇒ Object
(also: #get)
Returns the value of the field with the given name.
-
#[]=(name, value) ⇒ Object
Adds a new field (name-value pair) to the entry.
-
#add(*arguments) ⇒ Object
(also: #<<)
Adds a new field (name-value pair) or multiple fields to the entry.
-
#added_to_bibliography(bibliography) ⇒ Object
Called when the element was added to a bibliography.
-
#aliases ⇒ Object
Returns the Entry’s field name aliases.
-
#children ⇒ Object
(also: #cross_referenced_by)
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.
-
#content(options = {}) ⇒ Object
Returns a string of all the entry’s fields.
-
#convert(filter) ⇒ Object
Returns a duplicate entry with all values converted using the filter.
-
#convert!(filter) ⇒ Object
In-place variant of @see #convert.
-
#delete(name) ⇒ Object
Removes the field with a given name from the entry.
-
#each ⇒ Object
(also: #each_pair)
call-seq: entry.each { |key, value| block } -> entry entry.each_pair { |key, value| block } -> entry entry.each -> an_enumerator entry.each_pair -> an_enumerator.
- #fetch(name, default = nil) ⇒ Object
-
#field_names(filter = [], include_inherited = true) ⇒ Object
Returns a sorted list of the Entry’s field names.
- #generate_hash(filter = []) ⇒ Object
-
#has_children? ⇒ Boolean
(also: #cross_referenced?)
Returns true if the entry is cross-referenced by another entry in the Bibliography.
- #has_field?(name) ⇒ Boolean (also: #field?)
-
#has_parent? ⇒ Boolean
(also: #has_cross_reference?)
Returns true if the Entry has a valid cross-reference in the Bibliography.
- #has_type?(type) ⇒ Boolean (also: #type?)
-
#inherited_fields ⇒ Object
Returns a sorted list of all field names referenced by this Entry’s cross-reference.
- #inherits?(name) ⇒ Boolean
-
#initialize(attributes = {}) {|_self| ... } ⇒ Entry
constructor
Creates a new instance.
- #initialize_copy(other) ⇒ Object
- #issued ⇒ Object (also: #citeproc_date)
- #join ⇒ Object
- #key ⇒ Object (also: #id)
-
#key=(key) ⇒ Object
(also: #id=)
Sets the Entry’s key.
- #method_missing(name, *args, &block) ⇒ Object
- #month=(month) ⇒ Object
-
#names ⇒ Object
Returns a list of all names (authors, editors, translators).
-
#parent ⇒ Object
(also: #cross_reference)
Returns the cross-referenced Entry from the Bibliography or nil if this Entry does define a cross-reference.
-
#parent_missing? ⇒ Boolean
(also: #cross_reference_missing?)
Returns true if the Entry cross-references an Entry which is not registered in the current Bibliography.
- #parse_month ⇒ Object (also: #parse_months)
-
#parse_names ⇒ Object
Parses all name values of the entry.
-
#provide(name) ⇒ Object
Returns the field value referenced by the passed-in name.
-
#provides?(name) ⇒ Boolean
Returns true if the Entry has a field (or alias) for the passed-in name.
-
#register(key) ⇒ Object
Registers this Entry in the associated Bibliographies entries hash.
-
#registered? ⇒ Boolean
Returns true if the Entry is currently registered with the associated Bibliography.
-
#removed_from_bibliography(bibliography) ⇒ Object
Called when the element was removed from a bibliography.
-
#rename(*arguments) ⇒ Object
(also: #rename_fields)
Returns a copy of the Entry with all the field names renamed.
-
#rename!(*arguments) ⇒ Object
(also: #rename_fields!)
Renames the given field names unless a field with the new name already exists.
- #replace(*arguments) ⇒ Object
- #respond_to?(method) ⇒ Boolean
-
#save_inherited_fields ⇒ Object
If the Entry has a cross-reference, copies all referenced all inherited values from the parent.
- #to_citeproc(options = {}) ⇒ Object
- #to_hash(options = {}) ⇒ Object
-
#to_s(options = {}) ⇒ Object
Returns a string representation of the entry.
- #to_xml(options = {}) ⇒ Object
-
#valid? ⇒ Boolean
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.
Methods inherited from Element
#inspect, #matches?, #meets?, parse, #to_json, #to_yaml
Constructor Details
#initialize(attributes = {}) {|_self| ... } ⇒ Entry
Creates a new instance. If a hash is given, the entry is populated accordingly.
116 117 118 119 120 121 122 123 124 125 |
# File 'lib/bibtex/entry.rb', line 116 def initialize(attributes = {}) @fields = {} self.type = attributes.delete(:type) if attributes.has_key?(:type) self.key = attributes.delete(:key) if attributes.has_key?(:key) add(attributes) yield self if block_given? end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args, &block) ⇒ Object
271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
# File 'lib/bibtex/entry.rb', line 271 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 |
Instance Attribute Details
#fields ⇒ Object (readonly)
Returns the value of attribute fields.
111 112 113 |
# File 'lib/bibtex/entry.rb', line 111 def fields @fields end |
#type ⇒ Object
Returns the value of attribute type.
111 112 113 |
# File 'lib/bibtex/entry.rb', line 111 def type @type end |
Instance Method Details
#<=>(other) ⇒ Object
577 578 579 |
# File 'lib/bibtex/entry.rb', line 577 def <=>(other) type != other.type ? type <=> other.type : key != other.key ? key <=> other.key : to_s <=> other.to_s end |
#[](name) ⇒ Object Also known as: get
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.
314 315 316 |
# File 'lib/bibtex/entry.rb', line 314 def [](name) fields[name.to_sym] || parent && parent.provide(name) end |
#[]=(name, value) ⇒ Object
Adds a new field (name-value pair) to the entry. Returns the new value.
326 327 328 |
# File 'lib/bibtex/entry.rb', line 326 def []=(name, value) add(name.to_sym, value) end |
#add(*arguments) ⇒ Object Also known as: <<
Adds a new field (name-value pair) or multiple fields to the entry. Returns the entry for chainability.
call-seq: add(:author, “Edgar A. Poe”) add(:author, “Edgar A. Poe”, :title, “The Raven”) add([:author, “Edgar A. Poe”, :title, “The Raven”]) add(:author => “Edgar A. Poe”, :title => “The Raven”)
338 339 340 341 342 343 344 |
# File 'lib/bibtex/entry.rb', line 338 def add(*arguments) Hash[*arguments.flatten].each_pair do |name, value| fields[name.to_sym] = Value.new(value) end self end |
#added_to_bibliography(bibliography) ⇒ Object
Called when the element was added to a bibliography.
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 |
# File 'lib/bibtex/entry.rb', line 367 def added_to_bibliography(bibliography) super @key = register(key) [:parse_names, :parse_months].each do |parser| send(parser) if bibliography.[parser] end if bibliography..has_key?(:filter) convert!(bibliography.[:filter]) end self end |
#aliases ⇒ Object
Returns the Entry’s field name aliases.
159 160 161 |
# File 'lib/bibtex/entry.rb', line 159 def aliases @aliases ||= FIELD_ALIASES.dup end |
#children ⇒ Object Also known as: cross_referenced_by
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.
488 489 490 |
# File 'lib/bibtex/entry.rb', line 488 def children bibliography && bibliography.q("@entry[crossref=#{key}]") or [] end |
#content(options = {}) ⇒ Object
Returns a string of all the entry’s fields.
496 497 498 |
# File 'lib/bibtex/entry.rb', line 496 def content( = {}) fields.map { |k,v| "#{k} = #{ fields[k].to_s() }" }.join(",\n") end |
#convert(filter) ⇒ Object
Returns a duplicate entry with all values converted using the filter. 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).
567 568 569 |
# File 'lib/bibtex/entry.rb', line 567 def convert(filter) block_given? ? dup.convert!(filter, &Proc.new) : dup.convert!(filter) end |
#convert!(filter) ⇒ Object
In-place variant of @see #convert
572 573 574 575 |
# File 'lib/bibtex/entry.rb', line 572 def convert!(filter) fields.each_pair { |k,v| !block_given? || yield(k,v) ? v.convert!(filter) : v } self end |
#delete(name) ⇒ Object
Removes the field with a given name from the entry. Returns the value of the deleted field; nil if the field was not set.
350 351 352 |
# File 'lib/bibtex/entry.rb', line 350 def delete(name) fields.delete(name.to_sym) end |
#each ⇒ Object Also known as: each_pair
call-seq:
entry.each { |key, value| block } -> entry
entry.each_pair { |key, value| block } -> entry
entry.each -> an_enumerator
entry.each_pair -> 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.
146 147 148 149 150 151 152 153 |
# File 'lib/bibtex/entry.rb', line 146 def each if block_given? fields.each(&Proc.new) self else to_enum end end |
#fetch(name, default = nil) ⇒ Object
320 321 322 |
# File 'lib/bibtex/entry.rb', line 320 def fetch(name, default = nil) get(name) || block_given? ? yield(name) : default end |
#field_names(filter = [], include_inherited = true) ⇒ Object
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.
244 245 246 247 248 249 250 251 252 253 254 255 256 257 |
# File 'lib/bibtex/entry.rb', line 244 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 |
#generate_hash(filter = []) ⇒ Object
362 363 364 |
# File 'lib/bibtex/entry.rb', line 362 def generate_hash(filter = []) Digest::MD5.hexdigest(field_names(filter).map { |k| [k, fields[k]] }.flatten.join) end |
#has_children? ⇒ Boolean Also known as: cross_referenced?
Returns true if the entry is cross-referenced by another entry in the Bibliography.
479 480 481 |
# File 'lib/bibtex/entry.rb', line 479 def has_children? !children.empty? end |
#has_field?(name) ⇒ Boolean Also known as: field?
201 202 203 |
# File 'lib/bibtex/entry.rb', line 201 def has_field?(name) name.respond_to?(:to_sym) ? fields.has_key?(name.to_sym) : false end |
#has_parent? ⇒ Boolean Also known as: has_cross_reference?
Returns true if the Entry has a valid cross-reference in the Bibliography.
454 455 456 |
# File 'lib/bibtex/entry.rb', line 454 def has_parent? !parent.nil? end |
#has_type?(type) ⇒ Boolean Also known as: type?
194 195 196 |
# File 'lib/bibtex/entry.rb', line 194 def has_type?(type) type.to_s.match(/^(?:entry|\*)$/i) || @type == type.to_sym || super end |
#inherited_fields ⇒ Object
Returns a sorted list of all field names referenced by this Entry’s cross-reference.
260 261 262 263 264 265 266 267 268 |
# File 'lib/bibtex/entry.rb', line 260 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 |
#inherits?(name) ⇒ Boolean
207 208 209 |
# File 'lib/bibtex/entry.rb', line 207 def inherits?(name) !has_field(name) && has_parent? && parent.provides?(name) end |
#initialize_copy(other) ⇒ Object
127 128 129 130 131 132 133 134 |
# File 'lib/bibtex/entry.rb', line 127 def initialize_copy (other) @fields = {} self.type = other.type self.key = other.key add(other.fields) end |
#issued ⇒ Object Also known as: citeproc_date
529 530 531 532 533 534 |
# File 'lib/bibtex/entry.rb', line 529 def issued m = MONTHS.find_index(fields[:month].to_s.intern) m = m + 1 unless m.nil? Hash['date-parts', [[fields[:year],m].compact.map(&:to_i)]] end |
#join ⇒ Object
415 416 417 418 |
# File 'lib/bibtex/entry.rb', line 415 def join fields.values.each(&:join) self end |
#key ⇒ Object Also known as: id
182 183 184 |
# File 'lib/bibtex/entry.rb', line 182 def key @key ||= default_key end |
#key=(key) ⇒ Object Also known as: id=
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.
169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/bibtex/entry.rb', line 169 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.}" end |
#month=(month) ⇒ Object
420 421 422 |
# File 'lib/bibtex/entry.rb', line 420 def month=(month) fields[:month] = MONTHS_FILTER[month] end |
#names ⇒ Object
Returns a list of all names (authors, editors, translators).
448 449 450 |
# File 'lib/bibtex/entry.rb', line 448 def names NAME_FIELDS.map { |k| has_field?(k) ? @fields[k].tokens : nil }.flatten.compact end |
#parent ⇒ Object Also known as: cross_reference
Returns the cross-referenced Entry from the Bibliography or nil if this Entry does define a cross-reference.
470 471 472 |
# File 'lib/bibtex/entry.rb', line 470 def parent bibliography && bibliography[fields[:crossref]] end |
#parent_missing? ⇒ Boolean Also known as: cross_reference_missing?
Returns true if the Entry cross-references an Entry which is not registered in the current Bibliography.
462 463 464 |
# File 'lib/bibtex/entry.rb', line 462 def parent_missing? has_field?(:crossref) && !has_parent? end |
#parse_month ⇒ Object Also known as: parse_months
424 425 426 427 |
# File 'lib/bibtex/entry.rb', line 424 def parse_month fields[:month] = MONTHS_FILTER[fields[:month]] if has_field?(:month) self end |
#parse_names ⇒ Object
Parses all name values of the entry. Tries to replace and join the value prior to parsing.
434 435 436 437 438 439 440 441 442 443 444 445 |
# File 'lib/bibtex/entry.rb', line 434 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) ⇒ Object
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.
220 221 222 223 224 |
# File 'lib/bibtex/entry.rb', line 220 def provide(name) return nil unless name.respond_to?(:to_sym) name = name.to_sym fields[name] || fields[aliases[name]] end |
#provides?(name) ⇒ Boolean
Returns true if the Entry has a field (or alias) for the passed-in name.
212 213 214 215 |
# File 'lib/bibtex/entry.rb', line 212 def provides?(name) return nil unless name.respond_to?(:to_sym) has_field?(name) || has_field?(aliases[name.to_sym]) end |
#register(key) ⇒ Object
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.
400 401 402 403 404 405 406 407 |
# File 'lib/bibtex/entry.rb', line 400 def register(key) return nil if bibliography.nil? k = key.dup k.succ! while bibliography.has_key?(k) bibliography.entries[k] = self k end |
#registered? ⇒ Boolean
Returns true if the Entry is currently registered with the associated Bibliography.
391 392 393 |
# File 'lib/bibtex/entry.rb', line 391 def registered? !!(bibliography && bibliography.entries[key].equal?(self)) end |
#removed_from_bibliography(bibliography) ⇒ Object
Called when the element was removed from a bibliography.
384 385 386 387 388 |
# File 'lib/bibtex/entry.rb', line 384 def removed_from_bibliography(bibliography) super bibliography.entries.delete(key) self end |
#rename(*arguments) ⇒ Object Also known as: rename_fields
Returns a copy of the Entry with all the field names renamed.
292 293 294 |
# File 'lib/bibtex/entry.rb', line 292 def rename(*arguments) dup.rename!(*arguments) end |
#rename!(*arguments) ⇒ Object Also known as: rename_fields!
Renames the given field names unless a field with the new name already exists.
298 299 300 301 302 303 304 305 306 |
# File 'lib/bibtex/entry.rb', line 298 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 |
#replace(*arguments) ⇒ Object
409 410 411 412 413 |
# File 'lib/bibtex/entry.rb', line 409 def replace(*arguments) arguments = bibliography.q('@string') if arguments.empty? fields.values.each { |v| v.replace(*arguments) } self end |
#respond_to?(method) ⇒ Boolean
286 287 288 289 |
# File 'lib/bibtex/entry.rb', line 286 def respond_to?(method) provides?(method.to_sym) || method.to_s.match(/=$/) || method =~ /^(?:convert|from)_([a-z]+)(!)?$/ || (has_parent? && parent.respond_to?(method)) || super end |
#save_inherited_fields ⇒ Object
If the Entry has a cross-reference, copies all referenced all inherited values from the parent.
Returns the Entry.
230 231 232 233 234 235 236 |
# 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_citeproc(options = {}) ⇒ Object
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 |
# File 'lib/bibtex/entry.rb', line 513 def to_citeproc( = {}) [:quotes] ||= [] parse_names parse_month hash = { 'id' => key.to_s, 'type' => CSL_TYPES[type].to_s } each_pair do |k,v| hash[CSL_FILTER[k].to_s] = v.to_citeproc() unless DATE_FIELDS.include?(k) end hash['issued'] = citeproc_date hash end |
#to_hash(options = {}) ⇒ Object
506 507 508 509 510 511 |
# File 'lib/bibtex/entry.rb', line 506 def to_hash( = {}) [:quotes] ||= %w({ }) hash = { :key => key, :type => type } each_pair { |k,v| hash[k] = v.to_s() } hash end |
#to_s(options = {}) ⇒ Object
Returns a string representation of the entry.
501 502 503 504 |
# File 'lib/bibtex/entry.rb', line 501 def to_s( = {}) [:quotes] ||= %w({ }) ["@#{type}{#{key},", content().gsub(/^/,' '), "}\n"].join("\n") end |
#to_xml(options = {}) ⇒ Object
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 |
# File 'lib/bibtex/entry.rb', line 538 def to_xml( = {}) require 'rexml/document' xml = REXML::Element.new('bibtex:entry') xml.attributes['id'] = key entry = REXML::Element.new("bibtex:#{type}") fields.each do |key, value| field = REXML::Element.new("bibtex:#{key}") if [:extended] && value.name? value.each { |n| entry.add_element(n.to_xml) } else field.text = value.to_s() end entry.add_element(field) end xml.add_element(entry) xml end |
#valid? ⇒ Boolean
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.
356 357 358 359 360 |
# File 'lib/bibtex/entry.rb', line 356 def valid? REQUIRED_FIELDS[@type].all? do |f| f.is_a?(Array) ? !(f & fields.keys).empty? : !fields[f].nil? end end |