jekyll-printing-press 1.0.0rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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}