class AsciidoctorBibliography::Citation

Constants

MACRO_NAME_REGEXP
MACRO_PARAMETERS_REGEXP
MISSING_ID_MARK
REF_ATTRIBUTES
REGEXP
TEX_MACROS

Attributes

citation_items[R]
macro[R]

Public Class Methods

new(macro, *target_and_attributes_list_pairs) click to toggle source
# File lib/asciidoctor-bibliography/citation.rb, line 38
def initialize(macro, *target_and_attributes_list_pairs)
  @uuid = SecureRandom.uuid
  @macro = macro
  @citation_items = []
  target_and_attributes_list_pairs.each do |target, attribute_list|
    @citation_items << CitationItem.new do |cite|
      cite.target = target.to_s.empty? ? "default" : target
      cite.parse_attribute_list attribute_list
    end
  end
  # rubocop:enable Performance/HashEachMethods
end

Public Instance Methods

any_missing_id?(bibliographer) click to toggle source
# File lib/asciidoctor-bibliography/citation.rb, line 56
def any_missing_id?(bibliographer)
  # NOTE: do not use :any? since it ignores nil
  not missing_ids(bibliographer).empty?
end
interpolate_formatted_citation!(formatted_citation) click to toggle source
# File lib/asciidoctor-bibliography/citation.rb, line 120
def interpolate_formatted_citation!(formatted_citation)
  citation_items.each do |citation_item|
    key = Regexp.escape citation_item.key
    formatted_citation.gsub!(/___#{key}___(?<citation>.*?)___\/#{key}___/) do
      # NOTE: this handles custom citation text (slight overkill but easy to extend)
      # NOTE: escaping ] is necessary to safely nest macros (e.g. citing in a footnote)
      (citation_item.text || "{cite}").
        sub("{cite}", escape_square_brackets(Regexp.last_match[:citation]))
    end
  end
end
missing_ids(bibliographer) click to toggle source
# File lib/asciidoctor-bibliography/citation.rb, line 51
def missing_ids(bibliographer)
  m_ids = (@citation_items.map(&:key) - bibliographer.database.map { |entry| entry["id"] })
  m_ids.map! { |id| id.nil? ? "" : id }
end
prepare_fullcite_item(bibliographer, formatter) click to toggle source
# File lib/asciidoctor-bibliography/citation.rb, line 108
def prepare_fullcite_item(bibliographer, formatter)
  formatter.import([bibliographer.database.find_entry_by_id(citation_items.first.key)])
end
prepare_item(options, item, affix: true) click to toggle source
# File lib/asciidoctor-bibliography/citation.rb, line 151
def prepare_item(options, item, affix: true)
  # TODO: hyperlink, suppress_author and only_author options
  ci = citation_items.detect { |c| c.key == item.id }
  wrap_item item, ci.prefix, ci.suffix if affix
  id = xref_id "bibliography", ci.target, item.id
  wrap_item item, "___#{item.id}___", "___/#{item.id}___"
  wrap_item item, "<<#{id},", ">>" if options.hyperlinks?
  item.label, item.locator = ci.locator
end
prepare_items(bibliographer, formatter, tex: false) click to toggle source
# File lib/asciidoctor-bibliography/citation.rb, line 132
def prepare_items(bibliographer, formatter, tex: false)
  # NOTE: when we're using our custom TeX CSL styles prefix/suffix are used as
  #   variables for metadata instead of as parameters for citations.
  cites_with_local_attributes = citation_items.map { |cite| prepare_metadata bibliographer, cite, affix: tex }
  formatter.import cites_with_local_attributes
  formatter.force_sort!(mode: :citation)
  formatter.data.map(&:cite).each { |item| prepare_item bibliographer.options, item, affix: !tex }
end
prepare_metadata(bibliographer, cite, affix: false) click to toggle source
# File lib/asciidoctor-bibliography/citation.rb, line 141
def prepare_metadata(bibliographer, cite, affix: false)
  bibliographer.database.find_entry_by_id(cite.key).
    merge 'citation-number': bibliographer.appearance_index_of(cite.target, cite.key),
          'citation-label': cite.key, # TODO: smart label generators
          'locator': cite.locator.nil? ? nil : " ",
          'prefix': affix ? cite.prefix : nil,
          'suffix': affix ? cite.suffix : nil
  # TODO: why is a non blank 'locator' necessary to display locators set at a later stage?
end
render(bibliographer) click to toggle source
# File lib/asciidoctor-bibliography/citation.rb, line 61
def render(bibliographer)
  # NOTE: If there is any blank key we must render the entire (possibly composite)
  # NOTE: citation as missing, as we don't have that kind of control over CSL styles.
  if any_missing_id?(bibliographer)
    warn "Warning: I didn't find a database entry for #{missing_ids(bibliographer)}."
    # TODO: It would be cool to have the title attribute show the missing keys
    # TODO: as a popup above *??* but it does not work on inline quoted text.
    return MISSING_ID_MARK
  end

  formatted_citation = render_with_csl(bibliographer)
  wrap_up_citation citation: formatted_citation, bibliographer: bibliographer
end
render_citation_with_csl(bibliographer, style: bibliographer.options.style, tex: false) click to toggle source
# File lib/asciidoctor-bibliography/citation.rb, line 112
def render_citation_with_csl(bibliographer, style: bibliographer.options.style, tex: false)
  formatter = Formatter.new(style, locale: bibliographer.options.locale)
  items = prepare_items bibliographer, formatter, tex: tex
  formatted_citation = formatter.engine.renderer.render(items, formatter.engine.style.citation)
  interpolate_formatted_citation! formatted_citation
  formatted_citation
end
render_fullcite_with_csl(bibliographer) click to toggle source
# File lib/asciidoctor-bibliography/citation.rb, line 102
def render_fullcite_with_csl(bibliographer)
  formatter = Formatter.new(bibliographer.options.style, locale: bibliographer.options.locale)
  prepare_fullcite_item bibliographer, formatter
  formatter.render(:bibliography, id: citation_items.first.key).join
end
render_texmacro_with_csl(bibliographer) click to toggle source
# File lib/asciidoctor-bibliography/citation.rb, line 96
def render_texmacro_with_csl(bibliographer)
  filename = ["tex", macro.tr("*", "s"), bibliographer.options.tex_style].join("-")
  filepath = File.join AsciidoctorBibliography.root, "lib/csl/styles", filename
  render_citation_with_csl(bibliographer, style: filepath, tex: true)
end
render_with_csl(bibliographer) click to toggle source
# File lib/asciidoctor-bibliography/citation.rb, line 75
def render_with_csl(bibliographer)
  case macro
  when "cite"
    render_citation_with_csl(bibliographer)
  when "fullcite"
    render_fullcite_with_csl(bibliographer)
  when "nocite"
    ""
  when *TEX_MACROS
    render_texmacro_with_csl(bibliographer)
  end
end
uuid() click to toggle source
# File lib/asciidoctor-bibliography/citation.rb, line 166
def uuid
  ":#{@uuid}:"
end
wrap_item(item, prefix, suffix) click to toggle source
# File lib/asciidoctor-bibliography/citation.rb, line 161
def wrap_item(item, prefix, suffix)
  item.prefix = prefix.to_s + item.prefix.to_s
  item.suffix = item.suffix.to_s + suffix.to_s
end
wrap_up_citation(citation:, bibliographer:) click to toggle source
# File lib/asciidoctor-bibliography/citation.rb, line 88
def wrap_up_citation(citation:, bibliographer:)
  text = citation.dup
  # TODO: handle hyperlinks here, maybe?
  text = ["+++", text, "+++"].join if bibliographer.options.passthrough?(:citation)
  text.prepend "{empty}" if bibliographer.options.prepend_empty?(:citation)
  text
end
xref_id(*fragments) click to toggle source
# File lib/asciidoctor-bibliography/citation.rb, line 170
def xref_id(*fragments)
  fragments.compact.join("-")
end

Private Instance Methods

escape_square_brackets(string) click to toggle source
# File lib/asciidoctor-bibliography/citation.rb, line 176
def escape_square_brackets(string)
  string.gsub("[", "&lsqb;").gsub("]", "&rsqb;")
end