jekyll-printing-press 1.0.0rc1
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 +7 -0
- data/LICENSE +21 -0
- data/README.md +222 -0
- data/lib/jekyll/converters/markdown/pandoc.rb +47 -0
- data/lib/jekyll/pandoc/configuration.rb +120 -0
- data/lib/jekyll/pandoc/document.rb +202 -0
- data/lib/jekyll/pandoc/documents/bound.rb +58 -0
- data/lib/jekyll/pandoc/documents/imposed.rb +61 -0
- data/lib/jekyll/pandoc/documents/multiple.rb +76 -0
- data/lib/jekyll/pandoc/generator.rb +94 -0
- data/lib/jekyll/pandoc/generators/binder.rb +45 -0
- data/lib/jekyll/pandoc/generators/category.rb +32 -0
- data/lib/jekyll/pandoc/generators/imposition.rb +45 -0
- data/lib/jekyll/pandoc/generators/multiple.rb +62 -0
- data/lib/jekyll/pandoc/generators/posts.rb +54 -0
- data/lib/jekyll/pandoc/generators/site.rb +32 -0
- data/lib/jekyll/pandoc/paru_helper.rb +24 -0
- data/lib/jekyll/pandoc/printing.latex.liquid +10 -0
- data/lib/jekyll/pandoc/printing.rb +167 -0
- data/lib/jekyll/pandoc/renderer.rb +62 -0
- data/lib/jekyll/pandoc/renderers/binder.rb +32 -0
- data/lib/jekyll/pandoc/renderers/imposition.rb +82 -0
- data/lib/jekyll/pandoc/utils.rb +95 -0
- data/lib/jekyll-pandoc-multiple-formats.rb +16 -0
- metadata +311 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
require_relative '../document'
|
5
|
+
require_relative '../renderers/imposition'
|
6
|
+
|
7
|
+
module Jekyll
|
8
|
+
module Pandoc
|
9
|
+
module Documents
|
10
|
+
# An imposed document is a PDF with pages arranged for printing
|
11
|
+
# and folding.
|
12
|
+
class Imposed < Jekyll::Pandoc::Document
|
13
|
+
# Do nothing, content is not read, but Jekyll expects a String
|
14
|
+
#
|
15
|
+
# @return [nil]
|
16
|
+
def read_content(**)
|
17
|
+
self.content = ''
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
# Adds relations to source documents
|
22
|
+
#
|
23
|
+
# @return [nil]
|
24
|
+
def read_post_data
|
25
|
+
if data.key? 'uuid'
|
26
|
+
require 'securerandom'
|
27
|
+
data['uuid'] = SecureRandom.uuid
|
28
|
+
end
|
29
|
+
|
30
|
+
source_document.source_document.data['imposed'] =
|
31
|
+
source_document.data['imposed'] = self
|
32
|
+
|
33
|
+
source_document.source_document.data['formats'] << self
|
34
|
+
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
|
38
|
+
# Imposition
|
39
|
+
#
|
40
|
+
# @return [Jekyll::Pandoc::Renderers::Imposition]
|
41
|
+
def renderer
|
42
|
+
@renderer ||= Jekyll::Pandoc::Renderers::Imposition.new(site, self)
|
43
|
+
end
|
44
|
+
|
45
|
+
# The file is always binary
|
46
|
+
#
|
47
|
+
# @return [TrueClass]
|
48
|
+
def binary?
|
49
|
+
true
|
50
|
+
end
|
51
|
+
|
52
|
+
# PDFs can't be rendered with Liquid
|
53
|
+
#
|
54
|
+
# @return [FalseClass]
|
55
|
+
def render_with_liquid?
|
56
|
+
false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
require 'jekyll/utils'
|
5
|
+
require_relative '../document'
|
6
|
+
require_relative '../utils'
|
7
|
+
|
8
|
+
module Jekyll
|
9
|
+
module Pandoc
|
10
|
+
module Documents
|
11
|
+
# A document composed of several documents
|
12
|
+
class Multiple < Jekyll::Pandoc::Document
|
13
|
+
# Documents group
|
14
|
+
#
|
15
|
+
# @return [Array]
|
16
|
+
attr_reader :source_documents
|
17
|
+
|
18
|
+
# @param path [String]
|
19
|
+
# @param relations [Hash]
|
20
|
+
def initialize(path, relations = {})
|
21
|
+
@source_documents = relations[:source_documents]
|
22
|
+
relations[:source_document] = self
|
23
|
+
super
|
24
|
+
|
25
|
+
Jekyll::Utils.deep_merge_hashes!(data, relations[:data])
|
26
|
+
end
|
27
|
+
|
28
|
+
# Data must be provided externally
|
29
|
+
#
|
30
|
+
# @return [Hash]
|
31
|
+
def data
|
32
|
+
@data ||= { 'multiple' => true }
|
33
|
+
end
|
34
|
+
|
35
|
+
# The content is a concatenated string of source_documents
|
36
|
+
# content with their titles.
|
37
|
+
#
|
38
|
+
# The ID is attached to a title so you can map IDs to metadata
|
39
|
+
# on a Pandoc filter later.
|
40
|
+
#
|
41
|
+
# @return [nil]
|
42
|
+
def read_content(**)
|
43
|
+
self.content = source_documents.map do |doc|
|
44
|
+
["\n\n# #{doc['title']} {##{extract_id(doc)} data-chapter-title=true}", doc.content]
|
45
|
+
end.flatten.join("\n\n")
|
46
|
+
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
|
50
|
+
# Generates a data hash from source documents so they can be
|
51
|
+
# accessed later as Pandoc metadata. For instance, to generate
|
52
|
+
# authors per chapter.
|
53
|
+
#
|
54
|
+
# @return [nil]
|
55
|
+
def read_post_data
|
56
|
+
data['uuid'] ||= SecureRandom.uuid
|
57
|
+
|
58
|
+
source_documents.each do |doc|
|
59
|
+
data[extract_id(doc)] = Jekyll::Pandoc::Utils.sanitize_data doc.data
|
60
|
+
end
|
61
|
+
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
# Extracts an ID from a document
|
68
|
+
#
|
69
|
+
# @return [String]
|
70
|
+
def extract_id(document)
|
71
|
+
document['uuid'] || document.id.tr('/', '-').sub(/\A-/, '')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Pandoc
|
5
|
+
# Generates all Pandoc documents and adds them to the site. The
|
6
|
+
# documents are not written, just prepared for later rendering and
|
7
|
+
# writing following Jekyll's process.
|
8
|
+
#
|
9
|
+
# @see Jekyll::Site#generate
|
10
|
+
# @see Jekyll::Generator
|
11
|
+
class Generator < ::Jekyll::Generator
|
12
|
+
safe true
|
13
|
+
priority :highest
|
14
|
+
|
15
|
+
# Site
|
16
|
+
#
|
17
|
+
# @return [Jekyll::Site]
|
18
|
+
attr_reader :site
|
19
|
+
|
20
|
+
# Pandoc collections
|
21
|
+
#
|
22
|
+
# @return [Hash]
|
23
|
+
attr_reader :collections
|
24
|
+
|
25
|
+
# Generate documents for every format.
|
26
|
+
#
|
27
|
+
# @return [nil]
|
28
|
+
def generate(site)
|
29
|
+
@site = site
|
30
|
+
@collections = {}
|
31
|
+
|
32
|
+
return unless generate?
|
33
|
+
|
34
|
+
setup
|
35
|
+
generate_documents!
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# Do nothing for now
|
41
|
+
def setup; end
|
42
|
+
|
43
|
+
# Source documents. Every generator know how to fetch its own
|
44
|
+
# documents.
|
45
|
+
#
|
46
|
+
# @return [Array]
|
47
|
+
def source_documents
|
48
|
+
raise NotImplementedError
|
49
|
+
end
|
50
|
+
|
51
|
+
# This method knows how to collect documents, and generate
|
52
|
+
# collections and Pandoc documents.
|
53
|
+
#
|
54
|
+
# @return [nil]
|
55
|
+
def generate_documents!
|
56
|
+
raise NotImplementedError
|
57
|
+
end
|
58
|
+
|
59
|
+
# @return [Hash]
|
60
|
+
def config
|
61
|
+
site.config['pandoc']
|
62
|
+
end
|
63
|
+
|
64
|
+
# Jekyll runs every Jekyll::Generator descendant, but we don't
|
65
|
+
# want to run this one, just use it as a template.
|
66
|
+
#
|
67
|
+
# @return [Boolean]
|
68
|
+
def generate?
|
69
|
+
self.class != Jekyll::Pandoc::Generator
|
70
|
+
end
|
71
|
+
|
72
|
+
# Creates or finds a collection by a label, performs basic
|
73
|
+
# configuration and brings everything else from site
|
74
|
+
# configuration.
|
75
|
+
#
|
76
|
+
# @param label [String]
|
77
|
+
# @return [Hash]
|
78
|
+
def collection_for(label)
|
79
|
+
site.collections[label] ||=
|
80
|
+
Jekyll::Collection.new(site, label).tap do |col|
|
81
|
+
# Allow to configure the collection
|
82
|
+
# @see https://jekyllrb.com/docs/collections/
|
83
|
+
col.metadata['output'] = true unless col.metadata.key? 'output'
|
84
|
+
# Follow the same permalink structure unless otherwise
|
85
|
+
# specified.
|
86
|
+
unless site.config.dig('collections', label, 'permalink')
|
87
|
+
col.metadata['permalink'] =
|
88
|
+
site.posts.url_template
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../generator'
|
4
|
+
require_relative '../documents/bound'
|
5
|
+
|
6
|
+
module Jekyll
|
7
|
+
module Pandoc
|
8
|
+
module Generators
|
9
|
+
# Generates a ready for print PDF for use in a binding machine.
|
10
|
+
class Binder < Jekyll::Pandoc::Generator
|
11
|
+
priority :high
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
# Only generate if the site asks for imposition
|
16
|
+
#
|
17
|
+
# @return [Boolean]
|
18
|
+
def generate?
|
19
|
+
site.config.dig('pandoc', 'printing', 'formats')&.include? 'binder'
|
20
|
+
end
|
21
|
+
|
22
|
+
# Only PDFs are imposed
|
23
|
+
#
|
24
|
+
# @return [Array]
|
25
|
+
def source_documents
|
26
|
+
@source_documents ||= site.collections['pdf'].docs
|
27
|
+
end
|
28
|
+
|
29
|
+
# Generate a {Jekyll::Pandoc::Documents::Bound} per document
|
30
|
+
#
|
31
|
+
# @return [nil]
|
32
|
+
def generate_documents!
|
33
|
+
source_documents.each do |document|
|
34
|
+
collection_for('bound').tap do |col|
|
35
|
+
col.docs << Jekyll::Pandoc::Documents::Bound.new(document.path, site: site, collection: col,
|
36
|
+
source_document: document).tap(&:read)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../generator'
|
4
|
+
require_relative 'multiple'
|
5
|
+
|
6
|
+
module Jekyll
|
7
|
+
module Pandoc
|
8
|
+
module Generators
|
9
|
+
class Category < Jekyll::Pandoc::Generator
|
10
|
+
include Multiple
|
11
|
+
|
12
|
+
priority :high
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
# Group posts by categories
|
17
|
+
#
|
18
|
+
# @return [String]
|
19
|
+
def generator_type
|
20
|
+
@generator_type ||= 'categories'
|
21
|
+
end
|
22
|
+
|
23
|
+
# Groups documents by category
|
24
|
+
#
|
25
|
+
# @return [Array]
|
26
|
+
def source_documents
|
27
|
+
@source_documents ||= site.categories.to_a
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../generator'
|
4
|
+
require_relative '../documents/imposed'
|
5
|
+
|
6
|
+
module Jekyll
|
7
|
+
module Pandoc
|
8
|
+
module Generators
|
9
|
+
# Generates a ready for print PDF by creating 4-pages sheets.
|
10
|
+
class Imposition < Jekyll::Pandoc::Generator
|
11
|
+
priority :high
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
# Only generate if the site asks for imposition
|
16
|
+
#
|
17
|
+
# @return [Boolean]
|
18
|
+
def generate?
|
19
|
+
site.config.dig('pandoc', 'printing', 'formats')&.include? 'imposition'
|
20
|
+
end
|
21
|
+
|
22
|
+
# Only PDFs are imposed
|
23
|
+
#
|
24
|
+
# @return [Array]
|
25
|
+
def source_documents
|
26
|
+
@source_documents ||= site.collections['pdf'].docs
|
27
|
+
end
|
28
|
+
|
29
|
+
# Generate a {Jekyll::Pandoc::Documents::Imposed} per document
|
30
|
+
#
|
31
|
+
# @return [nil]
|
32
|
+
def generate_documents!
|
33
|
+
source_documents.each do |document|
|
34
|
+
collection_for('imposed').tap do |col|
|
35
|
+
col.docs << Jekyll::Pandoc::Documents::Imposed.new(document.path, site: site, collection: col,
|
36
|
+
source_document: document).tap(&:read)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tempfile'
|
4
|
+
require 'jekyll/utils'
|
5
|
+
require_relative '../documents/multiple'
|
6
|
+
|
7
|
+
module Jekyll
|
8
|
+
module Pandoc
|
9
|
+
module Generators
|
10
|
+
# Mixin for multiple-file generators
|
11
|
+
module Multiple
|
12
|
+
private
|
13
|
+
|
14
|
+
# Generator type
|
15
|
+
#
|
16
|
+
# @return [String]
|
17
|
+
def generator_type
|
18
|
+
raise NotImplementedError
|
19
|
+
end
|
20
|
+
|
21
|
+
# Must return an Array of grouped documents (an Array of Arrays)
|
22
|
+
#
|
23
|
+
# @return [Array]
|
24
|
+
def source_documents
|
25
|
+
raise NotImplementedError
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return [Boolean]
|
29
|
+
def generate?
|
30
|
+
config['documents']&.include? generator_type
|
31
|
+
end
|
32
|
+
|
33
|
+
# Generates a temporary file on site source per each document
|
34
|
+
# group and passes data as a relation.
|
35
|
+
#
|
36
|
+
# @return [nil]
|
37
|
+
def generate_documents!
|
38
|
+
source_documents.each do |(title, documents)|
|
39
|
+
config.available_formats.each do |format|
|
40
|
+
next if format == :html5
|
41
|
+
|
42
|
+
data = {
|
43
|
+
'title' => title,
|
44
|
+
'slug' => Jekyll::Utils.slugify(title, mode: 'pretty'),
|
45
|
+
'data' => Time.now
|
46
|
+
}
|
47
|
+
label = format.to_s
|
48
|
+
file = Tempfile.new([data['slug'], '.markdown'], site.source)
|
49
|
+
|
50
|
+
collection_for(label).tap do |col|
|
51
|
+
col.docs << Jekyll::Pandoc::Documents::Multiple.new(file.path, site: site, collection: col,
|
52
|
+
source_documents: documents, data: data).tap(&:read)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../document'
|
4
|
+
require_relative '../generator'
|
5
|
+
|
6
|
+
module Jekyll
|
7
|
+
module Pandoc
|
8
|
+
class Generator
|
9
|
+
# Generates Pandoc documents from Jekyll posts collection. Each
|
10
|
+
# format is a collection.
|
11
|
+
class Posts < Generator
|
12
|
+
priority :highest
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
# Only generate if aggregating posts is enabled
|
17
|
+
#
|
18
|
+
# @return [Boolean]
|
19
|
+
def generate?
|
20
|
+
config['documents']&.include? 'posts'
|
21
|
+
end
|
22
|
+
|
23
|
+
# Documents to generate from
|
24
|
+
#
|
25
|
+
# @return [Array]
|
26
|
+
def source_documents
|
27
|
+
@source_documents ||= site.posts.docs.reject(&:asset_file?)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Generate a Pandoc document for each format and adds it to
|
31
|
+
# a collection.
|
32
|
+
#
|
33
|
+
# HTML5 is already generated by
|
34
|
+
# {Jekyll::Converters::Markdown::Pandoc}
|
35
|
+
#
|
36
|
+
# @return [nil]
|
37
|
+
def generate_documents!
|
38
|
+
source_documents.each do |document|
|
39
|
+
config.available_formats.each do |format|
|
40
|
+
next if format == :html5
|
41
|
+
|
42
|
+
collection_for(format.to_s).tap do |col|
|
43
|
+
col.docs << Document.new(document.path, site: site, collection: col,
|
44
|
+
source_document: document).tap(&:read)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../generator'
|
4
|
+
require_relative 'multiple'
|
5
|
+
|
6
|
+
module Jekyll
|
7
|
+
module Pandoc
|
8
|
+
module Generators
|
9
|
+
class Site < Jekyll::Pandoc::Generator
|
10
|
+
include Multiple
|
11
|
+
|
12
|
+
priority :high
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
# All posts
|
17
|
+
#
|
18
|
+
# @return [String]
|
19
|
+
def generator_type
|
20
|
+
@generator_type ||= 'site'
|
21
|
+
end
|
22
|
+
|
23
|
+
# All posts
|
24
|
+
#
|
25
|
+
# @return [Array]
|
26
|
+
def source_documents
|
27
|
+
@source_documents ||= [ [ site.config['title'], site.posts.docs.reject(&:asset_file?) ] ]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'paru/pandoc'
|
4
|
+
|
5
|
+
module Jekyll
|
6
|
+
module Pandoc
|
7
|
+
# Creates a Paru::Pandoc with options from configuration
|
8
|
+
module ParuHelper
|
9
|
+
extend self
|
10
|
+
|
11
|
+
# Returns a Paru::Pandoc with options set
|
12
|
+
#
|
13
|
+
# @param options [Hash]
|
14
|
+
# @return [Paru::Pandoc]
|
15
|
+
def from(options)
|
16
|
+
Paru::Pandoc.new.tap do |paru|
|
17
|
+
options.each do |option, value|
|
18
|
+
paru.send option, value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
\documentclass[{{ sheetsize }},10pt]{article}
|
2
|
+
|
3
|
+
\usepackage{pgfpages}
|
4
|
+
\usepackage{pdfpages}
|
5
|
+
|
6
|
+
\pgfpagesuselayout{ {{- nup }} on 1}[{{ sheetsize }},{{ options }}]
|
7
|
+
|
8
|
+
\begin{document}
|
9
|
+
\includepdf[pages={ {{- pages | join: ',' -}} }]{ {{- path -}} }
|
10
|
+
\end{document}
|