asciidoctor-bibliography 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.codeclimate.yml +5 -0
- data/.gitignore +8 -2
- data/.hound.yml +3 -0
- data/.oss-guides.rubocop.yml +1076 -0
- data/.rubocop.yml +4 -10
- data/.travis.yml +2 -1
- data/Gemfile +1 -1
- data/README.adoc +224 -24
- data/Rakefile +2 -2
- data/asciidoctor-bibliography.gemspec +23 -23
- data/lib/asciidoctor-bibliography.rb +2 -2
- data/lib/asciidoctor-bibliography/asciidoctor.rb +4 -4
- data/lib/asciidoctor-bibliography/asciidoctor/bibliographer_preprocessor.rb +9 -56
- data/lib/asciidoctor-bibliography/bibliographer.rb +6 -7
- data/lib/asciidoctor-bibliography/citation.rb +56 -53
- data/lib/asciidoctor-bibliography/citation_item.rb +19 -10
- data/lib/asciidoctor-bibliography/database.rb +18 -6
- data/lib/asciidoctor-bibliography/databases/bibtex.rb +10 -10
- data/lib/asciidoctor-bibliography/errors.rb +16 -0
- data/lib/asciidoctor-bibliography/formatters/csl.rb +13 -2
- data/lib/asciidoctor-bibliography/formatters/tex.rb +42 -44
- data/lib/asciidoctor-bibliography/helpers.rb +9 -9
- data/lib/asciidoctor-bibliography/index.rb +17 -13
- data/lib/asciidoctor-bibliography/options.rb +97 -0
- data/lib/asciidoctor-bibliography/version.rb +1 -1
- data/samples/latex_macros_in_bibtex/sample.adoc +1 -1
- data/samples/standard/sample-default.adoc +3 -3
- data/samples/standard/sample-default.html +9 -8
- data/samples/standard/sample-din.adoc +1 -1
- data/samples/standard/sample-din.html +4 -3
- data/samples/standard/sample-ieee.adoc +1 -1
- data/samples/standard/sample-ieee.html +4 -3
- data/samples/tex/sample-authoryear.adoc +7 -17
- data/samples/tex/sample-authoryear.html +10 -32
- data/samples/tex/sample-numbers.adoc +7 -18
- data/samples/tex/sample-numbers.html +7 -29
- data/samples/tex/{sample-ordering.adoc → sample-sort.adoc} +6 -4
- data/spec/citation_item_spec.rb +67 -19
- data/spec/database_spec.rb +21 -16
- data/spec/helpers_spec.rb +46 -44
- data/spec/options_spec.rb +43 -0
- data/spec/spec_helper.rb +53 -55
- metadata +9 -7
- data/lib/asciidoctor-bibliography/exceptions.rb +0 -5
- data/samples/tex/sample-din.adoc +0 -74
- data/samples/tex/sample-din.html +0 -556
- data/samples/tex/sample-ordering.html +0 -467
@@ -24,19 +24,18 @@ module AsciidoctorBibliography
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def sort
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
27
|
+
return unless options["order"] == "alphabetical"
|
28
|
+
@occurring_keys = @occurring_keys.sort_by do |target|
|
29
|
+
first_author_family_name(target)
|
31
30
|
end
|
32
31
|
end
|
33
32
|
|
34
33
|
private
|
35
34
|
|
36
35
|
def first_author_family_name(key)
|
37
|
-
authors = database.
|
38
|
-
return
|
39
|
-
authors.map { |h| h[
|
36
|
+
authors = database.find_entry_by_id(key)["author"]
|
37
|
+
return "" if authors.nil?
|
38
|
+
authors.map { |h| h["family"] }.compact.first # TODO: is the first also alphabetically the first?
|
40
39
|
end
|
41
40
|
end
|
42
41
|
end
|
@@ -1,12 +1,13 @@
|
|
1
|
-
require
|
2
|
-
require_relative
|
3
|
-
require_relative
|
4
|
-
require_relative
|
1
|
+
require "securerandom"
|
2
|
+
require_relative "formatters/csl"
|
3
|
+
require_relative "formatters/tex"
|
4
|
+
require_relative "citation_item"
|
5
5
|
|
6
6
|
module AsciidoctorBibliography
|
7
7
|
class Citation
|
8
|
-
|
9
|
-
|
8
|
+
MACRO_NAME_REGEXP = Formatters::TeX::MACROS.keys.concat(%w[cite fullcite]).
|
9
|
+
map { |s| Regexp.escape s }.join("|").freeze
|
10
|
+
REGEXP = /\\?(#{MACRO_NAME_REGEXP}):(?:(\S*?)?\[(|.*?[^\\])\])(?:\+(\S*?)?\[(|.*?[^\\])\])*/
|
10
11
|
REF_ATTRIBUTES = %i[chapter page section clause].freeze
|
11
12
|
|
12
13
|
attr_reader :macro, :citation_items
|
@@ -25,70 +26,72 @@ module AsciidoctorBibliography
|
|
25
26
|
end
|
26
27
|
|
27
28
|
def render(bibliographer)
|
28
|
-
|
29
|
+
case macro
|
30
|
+
when "cite"
|
29
31
|
render_citation_with_csl(bibliographer)
|
30
|
-
|
32
|
+
when "fullcite"
|
31
33
|
render_fullcite_with_csl(bibliographer)
|
32
|
-
|
33
|
-
formatter = Formatters::TeX.new(bibliographer.options
|
34
|
+
when *Formatters::TeX::MACROS.keys
|
35
|
+
formatter = Formatters::TeX.new(bibliographer.options.tex_style)
|
34
36
|
formatter.import bibliographer.database
|
35
|
-
formatter.render
|
37
|
+
formatter.render bibliographer, self
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
39
|
-
def
|
40
|
-
formatter = Formatters::CSL.new(bibliographer.options
|
41
|
+
def render_fullcite_with_csl(bibliographer)
|
42
|
+
formatter = Formatters::CSL.new(bibliographer.options.style)
|
43
|
+
prepare_fullcite_item bibliographer, formatter
|
44
|
+
formatted_citation = formatter.render(:bibliography, id: citation_items.first.key).join
|
45
|
+
formatted_citation = Helpers.html_to_asciidoc formatted_citation
|
46
|
+
# We prepend an empty interpolation to avoid interferences w/ standard syntax (e.g. block role is "\n[foo]")
|
47
|
+
"{empty}" + formatted_citation
|
48
|
+
end
|
41
49
|
|
42
|
-
|
43
|
-
formatter.import
|
44
|
-
|
45
|
-
items = formatter.data.map(&:cite)
|
46
|
-
items.each { |item| prepare_citation_item item, hyperlink: bibliographer.options['hyperlinks'] == 'true' }
|
50
|
+
def prepare_fullcite_item(bibliographer, formatter)
|
51
|
+
formatter.import([bibliographer.database.find_entry_by_id(citation_items.first.key)])
|
52
|
+
end
|
47
53
|
|
54
|
+
def render_citation_with_csl(bibliographer)
|
55
|
+
formatter = Formatters::CSL.new(bibliographer.options.style)
|
56
|
+
items = prepare_items bibliographer, formatter
|
48
57
|
formatted_citation = formatter.engine.renderer.render(items, formatter.engine.style.citation)
|
58
|
+
escape_brackets_inside_xref! formatted_citation
|
49
59
|
# We prepend an empty interpolation to avoid interferences w/ standard syntax (e.g. block role is "\n[foo]")
|
50
|
-
|
51
|
-
# We escape closing square brackets inside the xref label.
|
52
|
-
['[', Regexp.last_match[:xref_label].gsub(']', '\]'), ']'].join
|
53
|
-
end
|
60
|
+
"{empty}" + formatted_citation
|
54
61
|
end
|
55
62
|
|
56
|
-
def
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
.merge('locator': cite.locators.any? ? ' ' : nil)
|
61
|
-
# TODO: why is 'locator' necessary to display locators? (and not just in the item, later)
|
63
|
+
def escape_brackets_inside_xref!(string)
|
64
|
+
string.gsub!(/{{{(?<xref_label>.*?)}}}/) do
|
65
|
+
["[", Regexp.last_match[:xref_label].gsub("]", '\]'), "]"].join
|
66
|
+
end
|
62
67
|
end
|
63
68
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
end
|
70
|
-
# Assign locator
|
71
|
-
locator = citation_items.find { |cite| cite.key == item.id }.locators.first
|
72
|
-
item.label, item.locator = locator unless locator.nil?
|
73
|
-
# TODO: suppress_author and only_author options?
|
69
|
+
def prepare_items(bibliographer, formatter)
|
70
|
+
cites_with_local_attributes = citation_items.map { |cite| prepare_metadata bibliographer, cite }
|
71
|
+
formatter.import cites_with_local_attributes
|
72
|
+
formatter.sort(mode: :citation)
|
73
|
+
formatter.data.map(&:cite).each { |item| prepare_item bibliographer.options, item }
|
74
74
|
end
|
75
75
|
|
76
|
-
def
|
77
|
-
|
76
|
+
def prepare_metadata(bibliographer, cite)
|
77
|
+
bibliographer.database.find_entry_by_id(cite.key).
|
78
|
+
merge('citation-number': bibliographer.appearance_index_of(cite.key)).
|
79
|
+
merge('citation-label': cite.key). # TODO: smart label generators
|
80
|
+
merge('locator': cite.locator.nil? ? nil : " ")
|
81
|
+
# TODO: why is a non blank 'locator' necessary to display locators set at a later stage?
|
82
|
+
end
|
78
83
|
|
79
|
-
|
80
|
-
|
84
|
+
def prepare_item(options, item)
|
85
|
+
# TODO: hyperlink, suppress_author and only_author options
|
86
|
+
ci = citation_items.detect { |c| c.key == item.id }
|
87
|
+
wrap_item item, ci.prefix, ci.suffix
|
88
|
+
wrap_item item, "xref:#{xref_id(item.id)}{{{", "}}}" if options.hyperlinks?
|
89
|
+
item.label, item.locator = ci.locator
|
90
|
+
end
|
81
91
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
end
|
86
|
-
# TODO: as is, citation items other than the first are simply ignored.
|
87
|
-
database_entry = bibliographer.database.find { |e| e['id'] == citation_items.first.key }
|
88
|
-
database_entry.merge!(mergeable_attributes)
|
89
|
-
formatter.import([database_entry])
|
90
|
-
'{empty}' + Helpers.html_to_asciidoc(formatter.render(:bibliography, id: citation_items.first.key).join)
|
91
|
-
# '{empty}' + Helpers.html_to_asciidoc(formatter.render(:citation, id: citation_items.first.key))
|
92
|
+
def wrap_item(item, prefix, suffix)
|
93
|
+
item.prefix = prefix.to_s + item.prefix.to_s
|
94
|
+
item.suffix = item.suffix.to_s + suffix.to_s
|
92
95
|
end
|
93
96
|
|
94
97
|
def uuid
|
@@ -96,7 +99,7 @@ module AsciidoctorBibliography
|
|
96
99
|
end
|
97
100
|
|
98
101
|
def xref_id(key)
|
99
|
-
[
|
102
|
+
["bibliography", key].compact.join("-")
|
100
103
|
end
|
101
104
|
|
102
105
|
def xref(key, label)
|
@@ -1,26 +1,35 @@
|
|
1
|
-
require
|
1
|
+
require "asciidoctor/attribute_list"
|
2
2
|
|
3
3
|
module AsciidoctorBibliography
|
4
4
|
class CitationItem
|
5
|
+
LOCATORS = CiteProc::CitationItem.labels.map(&:to_s).push("locator").freeze
|
6
|
+
|
5
7
|
attr_accessor :key, :target, :positional_attributes, :named_attributes, :locators
|
6
8
|
|
7
9
|
def initialize
|
8
10
|
yield self if block_given?
|
9
11
|
end
|
10
12
|
|
13
|
+
def prefix
|
14
|
+
named_attributes["prefix"]
|
15
|
+
end
|
16
|
+
|
17
|
+
def suffix
|
18
|
+
named_attributes["suffix"]
|
19
|
+
end
|
20
|
+
|
11
21
|
def locators
|
12
|
-
|
13
|
-
|
14
|
-
|
22
|
+
named_attributes.select { |key, _| LOCATORS.include? key }
|
23
|
+
end
|
24
|
+
|
25
|
+
def locator
|
26
|
+
locators.first
|
15
27
|
end
|
16
28
|
|
17
29
|
def parse_attribute_list(string)
|
18
|
-
parsed_attributes =
|
19
|
-
|
20
|
-
|
21
|
-
.values.map { |a| Hash[a] }
|
22
|
-
self.positional_attributes = parsed_attributes.first.values
|
23
|
-
self.named_attributes = parsed_attributes.last
|
30
|
+
parsed_attributes = ::Asciidoctor::AttributeList.new(string).parse
|
31
|
+
self.named_attributes = parsed_attributes.reject { |key, _| key.is_a? Integer }
|
32
|
+
self.positional_attributes = parsed_attributes.select { |key, _| key.is_a? Integer }.values
|
24
33
|
self.key = positional_attributes.shift
|
25
34
|
end
|
26
35
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require_relative
|
2
|
-
require_relative
|
1
|
+
require_relative "databases/bibtex"
|
2
|
+
require_relative "errors"
|
3
3
|
|
4
4
|
module AsciidoctorBibliography
|
5
5
|
# This is an array of citeproc entries.
|
@@ -14,13 +14,25 @@ module AsciidoctorBibliography
|
|
14
14
|
concat Database.load(filename)
|
15
15
|
end
|
16
16
|
|
17
|
+
def find_entry_by_id(id)
|
18
|
+
result = detect { |entry| entry["id"] == id }
|
19
|
+
if result.nil?
|
20
|
+
message = "No entry with id '#{id}' was found in the bibliographic database."
|
21
|
+
raise Errors::Database::IdNotFound, message
|
22
|
+
end
|
23
|
+
result
|
24
|
+
end
|
25
|
+
|
17
26
|
def self.load(filename)
|
18
|
-
|
27
|
+
filepath = File.expand_path filename
|
28
|
+
raise Errors::Database::FileNotFound, filepath unless File.exist?(filepath)
|
29
|
+
|
30
|
+
fileext = File.extname filepath
|
31
|
+
case fileext
|
19
32
|
when *Databases::BibTeX::EXTENSIONS
|
20
|
-
Databases::BibTeX.load
|
33
|
+
Databases::BibTeX.load filepath
|
21
34
|
else
|
22
|
-
raise
|
23
|
-
'Bibliographic database format not supported.'
|
35
|
+
raise Errors::Database::UnsupportedFormat, fileext
|
24
36
|
end
|
25
37
|
end
|
26
38
|
end
|
@@ -1,12 +1,12 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
1
|
+
require "bibtex"
|
2
|
+
require "bibtex/filters"
|
3
|
+
require "latex/decode/base"
|
4
|
+
require "latex/decode/maths"
|
5
|
+
require "latex/decode/accents"
|
6
|
+
require "latex/decode/diacritics"
|
7
|
+
require "latex/decode/punctuation"
|
8
|
+
require "latex/decode/symbols"
|
9
|
+
require "latex/decode/greek"
|
10
10
|
|
11
11
|
module AsciidoctorBibliography
|
12
12
|
module Databases
|
@@ -33,7 +33,7 @@ module AsciidoctorBibliography
|
|
33
33
|
LaTeX::Decode::Symbols.decode!(text)
|
34
34
|
LaTeX::Decode::Greek.decode!(text)
|
35
35
|
text.gsub!(/\\url\{(.+?)\}/, ' \\1 ')
|
36
|
-
text.gsub!(/\\\w+(?=\s+\w)/,
|
36
|
+
text.gsub!(/\\\w+(?=\s+\w)/, "")
|
37
37
|
text.gsub!(/\\\w+(?:\[.+?\])?\s*\{(.+?)\}/, '\\1')
|
38
38
|
LaTeX::Decode::Base.strip_braces(text)
|
39
39
|
LaTeX.normalize_C(text)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module AsciidoctorBibliography
|
2
|
+
module Errors
|
3
|
+
class Error < StandardError; end
|
4
|
+
|
5
|
+
module Options
|
6
|
+
class Missing < Error; end
|
7
|
+
class Invalid < Error; end
|
8
|
+
end
|
9
|
+
|
10
|
+
module Database
|
11
|
+
class UnsupportedFormat < Error; end
|
12
|
+
class FileNotFound < Error; end
|
13
|
+
class IdNotFound < Error; end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "citeproc"
|
2
|
+
require "csl/styles"
|
3
|
+
require "yaml"
|
3
4
|
|
4
5
|
module AsciidoctorBibliography
|
5
6
|
module Formatters
|
@@ -8,6 +9,16 @@ module AsciidoctorBibliography
|
|
8
9
|
super style: style, format: :html
|
9
10
|
end
|
10
11
|
|
12
|
+
def replace_bibliography_sort(array)
|
13
|
+
new_keys = array.map(&::CSL::Style::Sort::Key.method(:new))
|
14
|
+
new_sort = ::CSL::Style::Sort.new.add_children(*new_keys)
|
15
|
+
|
16
|
+
bibliography = engine.style.find_child("bibliography")
|
17
|
+
bibliography.find_child("sort")&.unlink
|
18
|
+
|
19
|
+
bibliography.add_child new_sort
|
20
|
+
end
|
21
|
+
|
11
22
|
def sort(mode:)
|
12
23
|
# Valid modes are :citation and :bibliography
|
13
24
|
engine.sort! data, engine.style.send(mode).sort_keys if engine.style.send(mode).sort?
|
@@ -3,20 +3,19 @@ module AsciidoctorBibliography
|
|
3
3
|
# This formatter emulates the behaviour of traditional Bib(La)TeX/NatBib citations.
|
4
4
|
class TeX
|
5
5
|
MACROS = {
|
6
|
-
# NOTE: cite
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
'citeyearpar' => { type: :years_only, bracketed: true }
|
6
|
+
# NOTE: \citet is equivalent to \cite, so we reserve the latter for CSL styling.
|
7
|
+
"citet" => { type: :textual, bracketed: true, authors: :abbreviated },
|
8
|
+
"citet*" => { type: :textual, bracketed: true, authors: :full },
|
9
|
+
"citealt" => { type: :textual, bracketed: false, authors: :abbreviated },
|
10
|
+
"citealt*" => { type: :textual, bracketed: false, authors: :full },
|
11
|
+
"citep" => { type: :parenthetical, bracketed: true, authors: :abbreviated },
|
12
|
+
"citep*" => { type: :parenthetical, bracketed: true, authors: :full },
|
13
|
+
"citealp" => { type: :parenthetical, bracketed: false, authors: :abbreviated },
|
14
|
+
"citealp*" => { type: :parenthetical, bracketed: false, authors: :full },
|
15
|
+
"citeauthor" => { type: :authors_only, bracketed: false, authors: :abbreviated },
|
16
|
+
"citeauthor*" => { type: :authors_only, bracketed: false, authors: :full },
|
17
|
+
"citeyear" => { type: :years_only, bracketed: false },
|
18
|
+
"citeyearpar" => { type: :years_only, bracketed: true },
|
20
19
|
}.freeze
|
21
20
|
|
22
21
|
attr_accessor :opening_bracket,
|
@@ -27,10 +26,10 @@ module AsciidoctorBibliography
|
|
27
26
|
:years_separator
|
28
27
|
|
29
28
|
def initialize(format)
|
30
|
-
if format ==
|
31
|
-
bibpunct =
|
32
|
-
elsif format ==
|
33
|
-
bibpunct =
|
29
|
+
if format == "numbers"
|
30
|
+
bibpunct = "{[}{]}{,}{n}{,}{,}"
|
31
|
+
elsif format == "authoryear"
|
32
|
+
bibpunct = "{(}{)}{;}{a}{,}{,}"
|
34
33
|
else
|
35
34
|
raise StandardError, "Unknown TeX citation format: #{format}"
|
36
35
|
end
|
@@ -50,56 +49,55 @@ module AsciidoctorBibliography
|
|
50
49
|
macro_options = MACROS[citation.macro]
|
51
50
|
output = []
|
52
51
|
case macro_options[:type]
|
53
|
-
when :full
|
54
52
|
# NOTE: deliberately repetitive to improve redability.
|
55
53
|
when :textual
|
56
54
|
citation.citation_items.each do |cite|
|
57
55
|
authors = authors(macro_options[:authors], cite)
|
58
|
-
year = if @style ==
|
56
|
+
year = if @style == "n"
|
59
57
|
bibliographer.appearance_index_of(cite.key)
|
60
58
|
else
|
61
59
|
year(cite)
|
62
60
|
end
|
63
|
-
cetera = Helpers.join_nonempty([year].concat(extra(cite)), @years_separator +
|
61
|
+
cetera = Helpers.join_nonempty([year].concat(extra(cite)), @years_separator + " ")
|
64
62
|
cetera = bracket(cetera) if macro_options[:bracketed]
|
65
|
-
label = Helpers.join_nonempty([authors, cetera],
|
63
|
+
label = Helpers.join_nonempty([authors, cetera], " ")
|
66
64
|
output << citation.xref(cite.key, label)
|
67
65
|
end
|
68
|
-
output = output.join(@cites_separator +
|
66
|
+
output = output.join(@cites_separator + " ")
|
69
67
|
when :parenthetical
|
70
68
|
citation.citation_items.each do |cite|
|
71
|
-
if @style ==
|
69
|
+
if @style == "n"
|
72
70
|
authors = nil
|
73
71
|
year = bibliographer.appearance_index_of(cite.key)
|
74
72
|
else
|
75
73
|
authors = authors(macro_options[:authors], cite)
|
76
74
|
year = year(cite)
|
77
75
|
end
|
78
|
-
cetera = Helpers.join_nonempty([year].concat(extra(cite)), @years_separator +
|
79
|
-
label = Helpers.join_nonempty([authors, cetera], @author_year_separator +
|
76
|
+
cetera = Helpers.join_nonempty([year].concat(extra(cite)), @years_separator + " ")
|
77
|
+
label = Helpers.join_nonempty([authors, cetera], @author_year_separator + " ")
|
80
78
|
output << citation.xref(cite.key, label)
|
81
79
|
end
|
82
|
-
output = output.join(@cites_separator +
|
80
|
+
output = output.join(@cites_separator + " ")
|
83
81
|
output = bracket(output) if macro_options[:bracketed]
|
84
82
|
when :authors_only
|
85
83
|
citation.citation_items.each do |cite|
|
86
84
|
authors = authors(macro_options[:authors], cite)
|
87
85
|
year = nil
|
88
|
-
cetera = Helpers.join_nonempty([year].concat(extra(cite)), @years_separator +
|
89
|
-
label = Helpers.join_nonempty([authors, cetera], @author_year_separator +
|
86
|
+
cetera = Helpers.join_nonempty([year].concat(extra(cite)), @years_separator + " ")
|
87
|
+
label = Helpers.join_nonempty([authors, cetera], @author_year_separator + " ")
|
90
88
|
output << citation.xref(cite.key, label)
|
91
89
|
end
|
92
|
-
output = output.join(@cites_separator +
|
90
|
+
output = output.join(@cites_separator + " ")
|
93
91
|
output = bracket(output) if macro_options[:bracketed]
|
94
92
|
when :years_only
|
95
93
|
citation.citation_items.each do |cite|
|
96
94
|
authors = nil
|
97
95
|
year = year(cite)
|
98
|
-
cetera = Helpers.join_nonempty([year].concat(extra(cite)), @years_separator +
|
99
|
-
label = Helpers.join_nonempty([authors, cetera], @author_year_separator +
|
96
|
+
cetera = Helpers.join_nonempty([year].concat(extra(cite)), @years_separator + " ")
|
97
|
+
label = Helpers.join_nonempty([authors, cetera], @author_year_separator + " ")
|
100
98
|
output << citation.xref(cite.key, label)
|
101
99
|
end
|
102
|
-
output = output.join(@cites_separator +
|
100
|
+
output = output.join(@cites_separator + " ")
|
103
101
|
output = bracket(output) if macro_options[:bracketed]
|
104
102
|
else
|
105
103
|
raise StandardError, "Unknown TeX citation macro type: #{macro_options[:type]}"
|
@@ -115,24 +113,24 @@ module AsciidoctorBibliography
|
|
115
113
|
end
|
116
114
|
|
117
115
|
def find_entry(key)
|
118
|
-
entry = @database.
|
116
|
+
entry = @database.detect { |h| h["id"] == key }
|
119
117
|
raise StandardError, "Can't find entry: #{key}" if entry.nil?
|
120
118
|
entry
|
121
119
|
end
|
122
120
|
|
123
121
|
def year(cite)
|
124
122
|
entry = find_entry(cite.key)
|
125
|
-
issued = entry[
|
123
|
+
issued = entry["issued"]
|
126
124
|
|
127
125
|
if issued.nil?
|
128
|
-
|
129
|
-
return
|
126
|
+
warn "asciidoctor-bibliography: citation (#{cite.key}) has no 'issued' information"
|
127
|
+
return ""
|
130
128
|
end
|
131
129
|
|
132
|
-
date_parts = issued[
|
133
|
-
return
|
130
|
+
date_parts = issued["date-parts"]
|
131
|
+
return "" if date_parts.nil?
|
134
132
|
|
135
|
-
return
|
133
|
+
return "" if date_parts.first.nil?
|
136
134
|
date_parts.first.first
|
137
135
|
end
|
138
136
|
|
@@ -168,20 +166,20 @@ module AsciidoctorBibliography
|
|
168
166
|
|
169
167
|
def authors_list(cite)
|
170
168
|
entry = find_entry(cite.key)
|
171
|
-
authors = entry[
|
169
|
+
authors = entry["author"]
|
172
170
|
return [] if authors.nil?
|
173
|
-
authors.map { |h| h[
|
171
|
+
authors.map { |h| h["family"] }.compact
|
174
172
|
end
|
175
173
|
|
176
174
|
def authors_abbreviated(cite)
|
177
175
|
authors = authors_list(cite)
|
178
|
-
return
|
176
|
+
return "" if authors.empty?
|
179
177
|
authors.length > 1 ? "#{authors.first} et al." : authors.first
|
180
178
|
end
|
181
179
|
|
182
180
|
def authors_full(cite)
|
183
181
|
authors = authors_list(cite)
|
184
|
-
return
|
182
|
+
return "" if authors.empty?
|
185
183
|
Helpers.to_sentence authors
|
186
184
|
end
|
187
185
|
end
|