asciidoctor-bibliography 0.0.1.dev
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +50 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +41 -0
- data/LICENSE.txt +21 -0
- data/README.adoc +101 -0
- data/SYNTAX.adoc +117 -0
- data/asciidoctor-bibliography.gemspec +37 -0
- data/deprecated/asciidoctor-bibliography/asciidoctor/bibliographer_postprocessor.rb +23 -0
- data/deprecated/asciidoctor-bibliography/asciidoctor/bibliography_block_macro.rb +77 -0
- data/deprecated/asciidoctor-bibliography/asciidoctor/citation_processor.rb +144 -0
- data/deprecated/asciidoctor-bibliography/asciidoctor/cite_inline_macro.rb +30 -0
- data/deprecated/asciidoctor-bibliography/citationdata.rb +23 -0
- data/deprecated/asciidoctor-bibliography/citations.rb +45 -0
- data/deprecated/asciidoctor-bibliography/citationutils.rb +67 -0
- data/deprecated/asciidoctor-bibliography/extensions.rb +64 -0
- data/deprecated/asciidoctor-bibliography/filehandlers.rb +32 -0
- data/deprecated/asciidoctor-bibliography/index.rb +31 -0
- data/deprecated/asciidoctor-bibliography/processor.rb +208 -0
- data/deprecated/asciidoctor-bibliography/processorutils.rb +34 -0
- data/deprecated/asciidoctor-bibliography/styles.rb +27 -0
- data/lib/asciidoctor-bibliography.rb +3 -0
- data/lib/asciidoctor-bibliography/asciidoctor.rb +17 -0
- data/lib/asciidoctor-bibliography/asciidoctor/bibliographer_preprocessor.rb +68 -0
- data/lib/asciidoctor-bibliography/bibliographer.rb +31 -0
- data/lib/asciidoctor-bibliography/citation.rb +73 -0
- data/lib/asciidoctor-bibliography/database.rb +20 -0
- data/lib/asciidoctor-bibliography/databases/bibtex.rb +43 -0
- data/lib/asciidoctor-bibliography/formatters/csl.rb +12 -0
- data/lib/asciidoctor-bibliography/formatters/tex.rb +164 -0
- data/lib/asciidoctor-bibliography/helpers.rb +40 -0
- data/lib/asciidoctor-bibliography/index.rb +43 -0
- data/lib/asciidoctor-bibliography/version.rb +3 -0
- data/samples/.byebug_history +245 -0
- data/samples/biblio.bib +31 -0
- data/samples/latex_macros_in_bibtex/reference.bib +16 -0
- data/samples/latex_macros_in_bibtex/sample.adoc +13 -0
- data/samples/sample-authoryear.adoc +72 -0
- data/samples/sample-authoryear.html +550 -0
- data/samples/sample-numbers.adoc +72 -0
- data/samples/sample-numbers.html +550 -0
- metadata +187 -0
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'asciidoctor'
|
2
|
+
require 'asciidoctor/extensions'
|
3
|
+
require 'asciidoctor/reader'
|
4
|
+
require 'asciidoctor/parser'
|
5
|
+
# require 'bibtex/filters'
|
6
|
+
# require 'latex/decode/base'
|
7
|
+
# require 'latex/decode/maths'
|
8
|
+
# require 'latex/decode/accents'
|
9
|
+
# require 'latex/decode/diacritics'
|
10
|
+
# require 'latex/decode/punctuation'
|
11
|
+
# require 'latex/decode/symbols'
|
12
|
+
# require 'latex/decode/greek'
|
13
|
+
# require_relative 'styles'
|
14
|
+
# require_relative 'filehandlers'
|
15
|
+
|
16
|
+
module AsciidoctorBibliography
|
17
|
+
module Asciidoctor
|
18
|
+
|
19
|
+
# This filter extends the original latex filter in bibtex-ruby to handle
|
20
|
+
# unknown latex macros more gracefully. We could have used latex-decode
|
21
|
+
# gem together with our custom replacement rules, but latex-decode eats up
|
22
|
+
# all braces after it finishes all decoding. So we hack over the
|
23
|
+
# LaTeX.decode function and insert our rules before `strip_braces`.
|
24
|
+
# class LatexFilter < ::BibTeX::Filter
|
25
|
+
# def apply(value)
|
26
|
+
# text = value.to_s
|
27
|
+
# LaTeX::Decode::Base.normalize(text)
|
28
|
+
# LaTeX::Decode::Maths.decode!(text)
|
29
|
+
# LaTeX::Decode::Accents.decode!(text)
|
30
|
+
# LaTeX::Decode::Diacritics.decode!(text)
|
31
|
+
# LaTeX::Decode::Punctuation.decode!(text)
|
32
|
+
# LaTeX::Decode::Symbols.decode!(text)
|
33
|
+
# LaTeX::Decode::Greek.decode!(text)
|
34
|
+
# text.gsub!(/\\url\{(.+?)\}/, " \\1 ")
|
35
|
+
# text.gsub!(/\\\w+(?=\s+\w)/, "")
|
36
|
+
# text.gsub!(/\\\w+(?:\[.+?\])?\s*\{(.+?)\}/, "\\1")
|
37
|
+
# LaTeX::Decode::Base.strip_braces(text)
|
38
|
+
# LaTeX.normalize_C(text)
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
|
42
|
+
# This processor scans the document, generates a list of citations,
|
43
|
+
# replace each citation with correct text and the reference block macro
|
44
|
+
# placeholder with the final reference list. It relys on the block macro
|
45
|
+
# processor to generate the place holder.
|
46
|
+
class CitationProcessor < ::Asciidoctor::Extensions::Treeprocessor
|
47
|
+
|
48
|
+
def process document
|
49
|
+
puts self
|
50
|
+
# byebug
|
51
|
+
# bibtex_file = (document.attr 'bibtex-file').to_s
|
52
|
+
# bibtex_style = ((document.attr 'bibtex-style') || 'ieee').to_s
|
53
|
+
# bibtex_order = ((document.attr 'bibtex-order') || 'appearance').to_sym
|
54
|
+
# bibtex_format = ((document.attr 'bibtex-format') || 'asciidoc').to_sym
|
55
|
+
|
56
|
+
# if bibtex_file.empty?
|
57
|
+
# bibtex_file = AsciidoctorBibliography::FileHandlers.find_bibliography "."
|
58
|
+
# end
|
59
|
+
# if bibtex_file.empty?
|
60
|
+
# bibtex_file = AsciidoctorBibliography::FileHandlers.find_bibliography "#{ENV['HOME']}/Documents"
|
61
|
+
# end
|
62
|
+
# if bibtex_file.empty?
|
63
|
+
# puts "Error: bibtex-file is not set and automatic search failed"
|
64
|
+
# exit
|
65
|
+
# end
|
66
|
+
|
67
|
+
# bibtex = BibTeX.open bibtex_file, :filter => [LatexFilter]
|
68
|
+
# processor = Processor.new bibtex, true, bibtex_style, bibtex_order == :appearance, bibtex_format
|
69
|
+
|
70
|
+
# prose_blocks = document.find_by {|b| b.content_model == :simple or b.context == :list_item}
|
71
|
+
# prose_blocks.each do |block|
|
72
|
+
# if block.context == :list_item
|
73
|
+
# line = block.instance_variable_get :@text
|
74
|
+
# processor.citations.add_from_line line
|
75
|
+
# else
|
76
|
+
# block.lines.each do |line|
|
77
|
+
# processor.citations.add_from_line line
|
78
|
+
# end
|
79
|
+
# end
|
80
|
+
# end
|
81
|
+
|
82
|
+
# prose_blocks.each do |block|
|
83
|
+
# if block.context == :list_item
|
84
|
+
# line = block.instance_variable_get :@text
|
85
|
+
# processor.citations.retrieve_citations(line).each do |citation|
|
86
|
+
# line.gsub!(citation.original, processor.complete_citation(citation))
|
87
|
+
# end
|
88
|
+
# block.instance_variable_set :@text, line
|
89
|
+
# else
|
90
|
+
# block.lines.each do |line|
|
91
|
+
# processor.citations.retrieve_citations(line).each do |citation|
|
92
|
+
# line.gsub!(citation.original, processor.complete_citation(citation))
|
93
|
+
# end
|
94
|
+
# end
|
95
|
+
# end
|
96
|
+
# end
|
97
|
+
|
98
|
+
# references_asciidoc = []
|
99
|
+
# if bibtex_format == :latex
|
100
|
+
# references_asciidoc << %(+++\\bibliography{#{bibtex_file}}{}+++)
|
101
|
+
# references_asciidoc << %(+++\\bibliographystyle{#{bibtex_style}}+++)
|
102
|
+
# else
|
103
|
+
# processor.cites.each do |ref|
|
104
|
+
# references_asciidoc << processor.get_reference(ref)
|
105
|
+
# references_asciidoc << ''
|
106
|
+
# end
|
107
|
+
# end
|
108
|
+
|
109
|
+
# biblio_blocks = document.find_by do |b|
|
110
|
+
# # for fast search (since most searches shall fail)
|
111
|
+
# b.content_model == :simple and b.lines.size == 1 \
|
112
|
+
# and b.lines[0] == BibliographyBlockMacroPlaceholder
|
113
|
+
# end
|
114
|
+
# biblio_blocks.each do |block|
|
115
|
+
# block_index = block.parent.blocks.index do |b|
|
116
|
+
# b == block
|
117
|
+
# end
|
118
|
+
# reference_blocks = parse_asciidoc block.parent, references_asciidoc
|
119
|
+
# reference_blocks.reverse.each do |b|
|
120
|
+
# block.parent.blocks.insert block_index, b
|
121
|
+
# end
|
122
|
+
# block.parent.blocks.delete_at block_index + reference_blocks.size
|
123
|
+
# end
|
124
|
+
|
125
|
+
# nil
|
126
|
+
end
|
127
|
+
|
128
|
+
# This is an adapted version of Asciidoctor::Extension::parse_content,
|
129
|
+
# where resultant blocks are returned as a list instead of attached to
|
130
|
+
# the parent.
|
131
|
+
def parse_asciidoc parent, content, attributes = {}
|
132
|
+
result = []
|
133
|
+
reader = ::Asciidoctor::Reader.new content
|
134
|
+
while reader.has_more_lines?
|
135
|
+
block = ::Asciidoctor::Parser.next_block reader, parent, attributes
|
136
|
+
result << block if block
|
137
|
+
end
|
138
|
+
result
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'asciidoctor'
|
2
|
+
require 'asciidoctor/extensions'
|
3
|
+
|
4
|
+
require 'securerandom'
|
5
|
+
|
6
|
+
module AsciidoctorBibliography
|
7
|
+
module Asciidoctor
|
8
|
+
|
9
|
+
class CiteInlineMacro < ::Asciidoctor::Extensions::InlineMacroProcessor
|
10
|
+
use_dsl
|
11
|
+
|
12
|
+
named :cite
|
13
|
+
# name_positional_attributes 'volnum'
|
14
|
+
|
15
|
+
def process parent, target, attrs
|
16
|
+
puts self
|
17
|
+
|
18
|
+
citation = AsciidoctorBibliography::Citation.new parent, target, attrs, SecureRandom.uuid
|
19
|
+
parent.document.bibliographer.citations << citation
|
20
|
+
|
21
|
+
# text = target # TODO: typeset
|
22
|
+
# target = "#bibliography-#{target}"
|
23
|
+
# parent.document.register :links, target
|
24
|
+
# (create_anchor parent, text, type: :link, target: target).render
|
25
|
+
|
26
|
+
citation.placeholder
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# citationdata class
|
2
|
+
#
|
3
|
+
# Copyright (c) Peter Lane, 2013.
|
4
|
+
# Released under Open Works License, 0.9.2
|
5
|
+
|
6
|
+
module AsciidoctorBibliography
|
7
|
+
# Class to hold information about a citation in text:
|
8
|
+
# the text forming the citation, its type, pretext, and enclosed cites
|
9
|
+
class CitationData
|
10
|
+
attr_reader :original, :type, :pretext, :cites
|
11
|
+
|
12
|
+
def initialize original, type, pretext, cites
|
13
|
+
@original = original
|
14
|
+
@type = type
|
15
|
+
@pretext = if pretext.nil?
|
16
|
+
''
|
17
|
+
else
|
18
|
+
pretext
|
19
|
+
end
|
20
|
+
@cites = cites
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
#
|
2
|
+
# Class to hold and manage citations
|
3
|
+
#
|
4
|
+
# Copyright (c) Peter Lane, 2013.
|
5
|
+
# Released under Open Works License, 0.9.2
|
6
|
+
|
7
|
+
module AsciidoctorBibliography
|
8
|
+
# Class to store list of citations used in document
|
9
|
+
class Citations
|
10
|
+
include CitationUtils
|
11
|
+
|
12
|
+
attr_reader :cites_used
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@cites_used = []
|
16
|
+
end
|
17
|
+
|
18
|
+
# Given a line of text, extract any citations and include new citation references in current list
|
19
|
+
def add_from_line line
|
20
|
+
retrieve_citations(line).each do |citation|
|
21
|
+
@cites_used += citation.cites.collect {|cite| cite.ref}
|
22
|
+
end
|
23
|
+
@cites_used.uniq! {|item| item.to_s} # only keep each reference once
|
24
|
+
end
|
25
|
+
|
26
|
+
# Return a list of citation references in document, sorted into order
|
27
|
+
def sorted_cites biblio
|
28
|
+
@cites_used.sort_by do |ref|
|
29
|
+
bibitem = biblio[ref]
|
30
|
+
|
31
|
+
unless bibitem.nil?
|
32
|
+
# extract the reference, and uppercase.
|
33
|
+
# Remove { } from grouped names for sorting.
|
34
|
+
author = bibitem.author
|
35
|
+
if author.nil?
|
36
|
+
author = bibitem.editor
|
37
|
+
end
|
38
|
+
author_chicago(author).collect {|s| s.upcase.gsub("{","").gsub("}","")} + [bibitem.year]
|
39
|
+
else
|
40
|
+
[ref]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# Utility functions for citations class
|
2
|
+
#
|
3
|
+
# Copyright (c) Peter Lane, 2013.
|
4
|
+
# Released under Open Works License, 0.9.2
|
5
|
+
|
6
|
+
module AsciidoctorBibliography
|
7
|
+
# Some utility functions used in Citations class
|
8
|
+
module CitationUtils
|
9
|
+
|
10
|
+
# Given a line, return a list of CitationData instances
|
11
|
+
# containing information on each set of citation information
|
12
|
+
def retrieve_citations line
|
13
|
+
result = []
|
14
|
+
md = CITATION_FULL.match line
|
15
|
+
while md
|
16
|
+
data = CitationData.new md[0], md[1], nil, []
|
17
|
+
cm = CITATION_KEY.match md[2]
|
18
|
+
while cm
|
19
|
+
pages = nil
|
20
|
+
if cm[2]
|
21
|
+
pages = cm[2][1...-1]
|
22
|
+
end
|
23
|
+
data.cites << Citation.new(cm[1], pages)
|
24
|
+
# look for next ref within citation
|
25
|
+
cm = CITATION_KEY.match cm.post_match
|
26
|
+
end
|
27
|
+
result << data
|
28
|
+
# look for next citation on line
|
29
|
+
md = CITATION_FULL.match md.post_match
|
30
|
+
end
|
31
|
+
|
32
|
+
return result
|
33
|
+
end
|
34
|
+
|
35
|
+
# arrange author string, flag for order of surname/initials
|
36
|
+
def arrange_authors authors, surname_first
|
37
|
+
return [] if authors.nil?
|
38
|
+
authors.split(/\band\b/).collect do |name|
|
39
|
+
if name.include?(", ")
|
40
|
+
parts = name.strip.rpartition(", ")
|
41
|
+
if surname_first
|
42
|
+
"#{parts.first}, #{parts.third}"
|
43
|
+
else
|
44
|
+
"#{parts.third} #{parts.first}"
|
45
|
+
end
|
46
|
+
else
|
47
|
+
name
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Arrange given author string into Chicago format
|
53
|
+
def author_chicago authors
|
54
|
+
arrange_authors authors, true
|
55
|
+
end
|
56
|
+
|
57
|
+
# matches a citation key, such as 'Dan2012(99-100)'
|
58
|
+
CITATION_KEY = /([^\s,()\[\]]+)(\(\d+(-\d+)*\))?/
|
59
|
+
# matches a citation type
|
60
|
+
CITATION_TYPE = /cite|citenp|fullcite/
|
61
|
+
# matches a citation list
|
62
|
+
CITATION_LIST_TAIL = /(\s*,\s*#{CITATION_KEY})*/
|
63
|
+
CITATION_LIST = /(?:#{CITATION_KEY}#{CITATION_LIST_TAIL})/
|
64
|
+
# matches the whole citation
|
65
|
+
CITATION_FULL = /(#{CITATION_TYPE}):\[(#{CITATION_LIST})\]/
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# Some extension and helper methods.
|
2
|
+
#
|
3
|
+
# Copyright (c) Peter Lane, 2012-13.
|
4
|
+
# Released under Open Works License, 0.9.2
|
5
|
+
|
6
|
+
module AsciidoctorBibliographyArrayExtensions
|
7
|
+
|
8
|
+
# Retrieve the third item of an array
|
9
|
+
# Note: no checks for validity
|
10
|
+
def third
|
11
|
+
self[2]
|
12
|
+
end
|
13
|
+
|
14
|
+
# Join items in array using commas and 'and' on last item
|
15
|
+
def comma_and_join
|
16
|
+
if size < 2
|
17
|
+
return self.join("")
|
18
|
+
end
|
19
|
+
result = ""
|
20
|
+
self.each_with_index do |item, index|
|
21
|
+
if index.zero?
|
22
|
+
result << item
|
23
|
+
elsif index == size-1
|
24
|
+
result << " and #{item}"
|
25
|
+
else
|
26
|
+
result << ", #{item}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
return result
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# monkey patch the extension methods to Array
|
35
|
+
class Array
|
36
|
+
include AsciidoctorBibliographyArrayExtensions
|
37
|
+
end
|
38
|
+
|
39
|
+
# Converts html output produced by citeproc to asciidoc markup
|
40
|
+
module StringHtmlToAsciiDoc
|
41
|
+
def html_to_asciidoc
|
42
|
+
r = self.gsub(/<\/?i>/, '_')
|
43
|
+
r = r.gsub(/<\/?b>/, '*')
|
44
|
+
r = r.gsub(/<\/?span.*?>/, '')
|
45
|
+
r = r.gsub(/\{|\}/, '')
|
46
|
+
r
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Provides a check that a string is in integer
|
51
|
+
# Taken from:
|
52
|
+
# http://stackoverflow.com/questions/1235863/test-if-a-string-is-basically-an-integer-in-quotes-using-ruby
|
53
|
+
module IntegerCheck
|
54
|
+
def is_i?
|
55
|
+
!!(self =~ /^[-+]?[0-9]+$/)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# monkey patch the extension methods into String
|
60
|
+
class String
|
61
|
+
include StringHtmlToAsciiDoc
|
62
|
+
include IntegerCheck
|
63
|
+
end
|
64
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#
|
2
|
+
# filehandlers.rb
|
3
|
+
# Contains top-level file utility methods
|
4
|
+
#
|
5
|
+
|
6
|
+
module AsciidoctorBibliography
|
7
|
+
|
8
|
+
module FileHandlers
|
9
|
+
# Locate a bibliography file to read in given dir
|
10
|
+
def FileHandlers.find_bibliography dir
|
11
|
+
begin
|
12
|
+
candidates = Dir.glob("#{dir}/*.bib")
|
13
|
+
if candidates.empty?
|
14
|
+
return ""
|
15
|
+
else
|
16
|
+
return candidates.first
|
17
|
+
end
|
18
|
+
rescue # catch all errors, and return empty string
|
19
|
+
return ""
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Add '-ref' before the extension of a filename
|
24
|
+
def FileHandlers.add_ref filename
|
25
|
+
file_dir = File.dirname(File.expand_path(filename))
|
26
|
+
file_base = File.basename(filename, ".*")
|
27
|
+
file_ext = File.extname(filename)
|
28
|
+
return "#{file_dir}#{File::SEPARATOR}#{file_base}-ref#{file_ext}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module AsciidoctorBibliography
|
2
|
+
class Index
|
3
|
+
attr_reader :parent, :target, :attrs, :uuid
|
4
|
+
|
5
|
+
def initialize(parent, target, attrs, uuid)
|
6
|
+
@parent = parent
|
7
|
+
@target = target
|
8
|
+
@attrs = attrs
|
9
|
+
@uuid = uuid
|
10
|
+
end
|
11
|
+
|
12
|
+
def placeholder
|
13
|
+
"{#{uuid}}"
|
14
|
+
end
|
15
|
+
|
16
|
+
# attr_reader :ref, :pages
|
17
|
+
|
18
|
+
# def initialize ref, pages
|
19
|
+
# @ref = ref
|
20
|
+
# @pages = pages
|
21
|
+
# # clean up pages
|
22
|
+
# @pages = '' unless @pages
|
23
|
+
# @pages.gsub!("--","-")
|
24
|
+
# end
|
25
|
+
|
26
|
+
# def to_s
|
27
|
+
# "#{@ref}:#{@pages}"
|
28
|
+
# end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|