jekyll-pandoc-multiple-formats-jekyll34 0.2.10 → 0.2.12
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/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.md +190 -0
- data/Rakefile +13 -0
- data/bin/imponer +62 -0
- data/jekyll-pandoc-multiple-formats-jekyll34-0.2.11.gem +0 -0
- data/jekyll-pandoc-multiple-formats-jekyll34.gemspec +29 -0
- data/lib/jekyll-pandoc-multiple-formats-jekyll34.rb +37 -0
- data/lib/jekyll-pandoc-multiple-formats-jekyll34/binder.rb +45 -0
- data/lib/jekyll-pandoc-multiple-formats-jekyll34/config.rb +40 -0
- data/lib/jekyll-pandoc-multiple-formats-jekyll34/converter.rb +81 -0
- data/lib/jekyll-pandoc-multiple-formats-jekyll34/generator.rb +110 -0
- data/lib/jekyll-pandoc-multiple-formats-jekyll34/imposition.rb +97 -0
- data/lib/jekyll-pandoc-multiple-formats-jekyll34/pandoc_file.rb +276 -0
- data/lib/jekyll-pandoc-multiple-formats-jekyll34/printer.rb +105 -0
- data/lib/jekyll-pandoc-multiple-formats-jekyll34/unite.rb +70 -0
- data/lib/jekyll-pandoc-multiple-formats-jekyll34/version.rb +3 -0
- data/test/fixtures/test.pdf +0 -0
- data/test/source/_layouts/nil.html +1 -0
- data/test/source/_posts/2014-01-01-test.markdown +10 -0
- data/test/source/_posts/2015-01-01-another_post.markdown +11 -0
- data/test/test_helper.rb +37 -0
- data/test/test_pandoc_file.rb +106 -0
- data/test/test_printer.rb +483 -0
- metadata +38 -6
@@ -0,0 +1,81 @@
|
|
1
|
+
# Copyright (c) 2012-2015 Nicolás Reynolds <fauno@endefensadelsl.org>
|
2
|
+
# 2012-2013 Mauricio Pasquier Juan <mpj@endefensadelsl.org>
|
3
|
+
# 2013 Brian Candler <b.candler@pobox.com>
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
# a copy of this software and associated documentation files (the
|
7
|
+
# "Software"), to deal in the Software without restriction, including
|
8
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
# the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be
|
14
|
+
# included in all copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
# Namespacing and metaprogramming FTW
|
25
|
+
module JekyllPandocMultipleFormats
|
26
|
+
# Determines the correct module where it lives the converter
|
27
|
+
def self.namespace
|
28
|
+
Jekyll::VERSION >= '1.0.0' ? Jekyll::Converters : Jekyll
|
29
|
+
end
|
30
|
+
|
31
|
+
# Determines the correct class name. Jekyll has the converters class kinda
|
32
|
+
# hardcoded
|
33
|
+
def self.class_name
|
34
|
+
Jekyll::VERSION >= '1.0.0' ? 'Markdown' : 'MarkdownConverter'
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.build
|
38
|
+
namespace::const_get(class_name).send :include, ConverterMethods
|
39
|
+
end
|
40
|
+
|
41
|
+
# When included in the correspondant markdown class this module redefines the
|
42
|
+
# three needed Converter instance methods
|
43
|
+
module ConverterMethods
|
44
|
+
def self.included(base)
|
45
|
+
base.class_eval do
|
46
|
+
# Just return html5
|
47
|
+
def convert(content)
|
48
|
+
flags = "#{@config['pandoc']['flags']} #{@config['pandoc']['site_flags']}"
|
49
|
+
|
50
|
+
output = ''
|
51
|
+
Dir::chdir(@config['source']) do
|
52
|
+
Open3::popen3("pandoc -t html5 #{flags}") do |stdin, stdout, stderr, thread|
|
53
|
+
stdin.puts content
|
54
|
+
stdin.close
|
55
|
+
|
56
|
+
output = stdout.read.strip
|
57
|
+
STDERR.print stderr.read
|
58
|
+
|
59
|
+
# Wait for the process to finish
|
60
|
+
thread.value
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
output
|
65
|
+
end
|
66
|
+
|
67
|
+
def matches(ext)
|
68
|
+
rgx = '(' + @config['markdown_ext'].gsub(',','|') +')'
|
69
|
+
ext =~ Regexp.new(rgx, Regexp::IGNORECASE)
|
70
|
+
end
|
71
|
+
|
72
|
+
def output_ext(ext)
|
73
|
+
'.html'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Conjures the metamagic
|
81
|
+
JekyllPandocMultipleFormats.build
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# Copyright (c) 2012-2015 Nicolás Reynolds <fauno@endefensadelsl.org>
|
2
|
+
# 2012-2013 Mauricio Pasquier Juan <mpj@endefensadelsl.org>
|
3
|
+
# 2013 Brian Candler <b.candler@pobox.com>
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
# a copy of this software and associated documentation files (the
|
7
|
+
# "Software"), to deal in the Software without restriction, including
|
8
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
# the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be
|
14
|
+
# included in all copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
module Jekyll
|
25
|
+
|
26
|
+
class PandocGenerator < Generator
|
27
|
+
safe true
|
28
|
+
|
29
|
+
attr_accessor :site, :config
|
30
|
+
|
31
|
+
def generate(site)
|
32
|
+
@site ||= site
|
33
|
+
@config ||= JekyllPandocMultipleFormats::Config.new(@site.config['pandoc'])
|
34
|
+
|
35
|
+
return if @config.skip?
|
36
|
+
|
37
|
+
# we create a single array of files
|
38
|
+
@pandoc_files = []
|
39
|
+
|
40
|
+
@config.outputs.each_pair do |output, extra_flags|
|
41
|
+
@site.posts.docs.each do |post|
|
42
|
+
|
43
|
+
pandoc_file = PandocFile.new(@site, output, post)
|
44
|
+
next unless pandoc_file.write
|
45
|
+
|
46
|
+
@site.keep_files << pandoc_file.relative_path
|
47
|
+
@pandoc_files << pandoc_file
|
48
|
+
end
|
49
|
+
|
50
|
+
@site.post_attr_hash('categories').each_pair do |title, posts|
|
51
|
+
posts.sort!
|
52
|
+
pandoc_file = PandocFile.new(@site, output, posts, title)
|
53
|
+
|
54
|
+
if @site.keep_files.include? pandoc_file.relative_path
|
55
|
+
puts "#{pandoc_file.relative_path} is a category file AND a post file"
|
56
|
+
puts 'change the category name to fix this'
|
57
|
+
next
|
58
|
+
end
|
59
|
+
|
60
|
+
next unless pandoc_file.write
|
61
|
+
|
62
|
+
@site.keep_files << pandoc_file.relative_path
|
63
|
+
@pandoc_files << pandoc_file
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
@pandoc_files.each do |pandoc_file|
|
68
|
+
# If output is PDF, we also create the imposed PDF
|
69
|
+
if pandoc_file.pdf?
|
70
|
+
|
71
|
+
if @config.imposition?
|
72
|
+
|
73
|
+
imposed_file = JekyllPandocMultipleFormats::Imposition
|
74
|
+
.new(pandoc_file.path, pandoc_file.papersize,
|
75
|
+
pandoc_file.sheetsize, pandoc_file.signature)
|
76
|
+
|
77
|
+
imposed_file.write
|
78
|
+
@site.keep_files << imposed_file.relative_path(@site.dest)
|
79
|
+
end
|
80
|
+
|
81
|
+
# If output is PDF, we also create the imposed PDF
|
82
|
+
if @config.binder?
|
83
|
+
|
84
|
+
binder_file = JekyllPandocMultipleFormats::Binder
|
85
|
+
.new(pandoc_file.path, pandoc_file.papersize,
|
86
|
+
pandoc_file.sheetsize)
|
87
|
+
|
88
|
+
binder_file.write
|
89
|
+
@site.keep_files << binder_file.relative_path(@site.dest)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Add covers to PDFs after building ready for print files
|
93
|
+
if pandoc_file.has_cover?
|
94
|
+
# Generate the cover
|
95
|
+
next unless pandoc_file.pdf_cover!
|
96
|
+
united_output = pandoc_file.path.gsub(/\.pdf\Z/, '-cover.pdf')
|
97
|
+
united_file = JekyllPandocMultipleFormats::Unite
|
98
|
+
.new(united_output, [pandoc_file.pdf_cover,pandoc_file.path])
|
99
|
+
|
100
|
+
if united_file.write
|
101
|
+
# Replace the original file with the one with cover
|
102
|
+
FileUtils.rm_f(pandoc_file.path)
|
103
|
+
FileUtils.mv(united_output, pandoc_file.path)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# Copyright (c) 2012-2015 Nicolás Reynolds <fauno@endefensadelsl.org>
|
2
|
+
# 2012-2013 Mauricio Pasquier Juan <mpj@endefensadelsl.org>
|
3
|
+
# 2013 Brian Candler <b.candler@pobox.com>
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
# a copy of this software and associated documentation files (the
|
7
|
+
# "Software"), to deal in the Software without restriction, including
|
8
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
# the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be
|
14
|
+
# included in all copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
module JekyllPandocMultipleFormats
|
25
|
+
class Imposition < Printer
|
26
|
+
|
27
|
+
attr_accessor :rounded_pages, :blank_pages, :signature
|
28
|
+
|
29
|
+
def initialize(file, papersize = nil, sheetsize = nil, signature = nil, extra_options = nil)
|
30
|
+
super(file, papersize, sheetsize, extra_options)
|
31
|
+
@output_file = file.gsub(/\.pdf\Z/, '-imposed.pdf')
|
32
|
+
# Total pages must be modulo 4
|
33
|
+
@rounded_pages = round_to_nearest(@pages, 4)
|
34
|
+
@blank_pages = @rounded_pages - @pages
|
35
|
+
# If we don't use a signature, make a single fold
|
36
|
+
@signature = signature || @rounded_pages
|
37
|
+
# Also if we specified 0
|
38
|
+
@signature = @rounded_pages if signature == 0
|
39
|
+
|
40
|
+
render_template
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_nup
|
45
|
+
# 14 pages example:
|
46
|
+
# [ {}, 1, 2, {}, 14, 3, 4, 13, 12, 5, 6, 11, 10, 7, 8, 9 ]
|
47
|
+
#
|
48
|
+
# * Add {} to missing pages
|
49
|
+
# [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, {}, {}]
|
50
|
+
# * Take first half [ 1, 2, 3, 4, 5, 6, 7, 8 ]
|
51
|
+
# * Reverse second half [ {}, {}, 14, 13, 12, 11, 10, 9 ]
|
52
|
+
# * Intercalate the first half into the second half by two
|
53
|
+
# elements
|
54
|
+
# [ {}, 1, 2, {}, 14, 3, 4, 13, 12, 5, 6, 11, 10, 7, 8, 9 ]
|
55
|
+
#
|
56
|
+
# An array of numbered pages padded with blank pages ('{}')
|
57
|
+
#
|
58
|
+
# [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 ] + [ '{}', '{}' ]
|
59
|
+
padded = @pages.times.map{|i|i+1} + Array.new(@blank_pages, '{}')
|
60
|
+
|
61
|
+
# If we have a signature, we have to split in groups up to the
|
62
|
+
# amount of pages per signature, and then continue with the rest
|
63
|
+
#
|
64
|
+
# If we have no signature, we assume it's equal to the total
|
65
|
+
# amount of pages, so you only have one fold
|
66
|
+
signed = padded.each_slice(@signature).to_a
|
67
|
+
folds = []
|
68
|
+
signed.each do |fold|
|
69
|
+
#
|
70
|
+
# Split in halves
|
71
|
+
# [ [ 1, 2, 3, 4, 5, 6, 7, 8 ],
|
72
|
+
# [ 9, 10, 11, 12, 13, 14, '{}', '{}' ] ]
|
73
|
+
halved = fold.each_slice(fold.size / 2).to_a
|
74
|
+
# Add a nil as last page. When we reverse it and intercalate by
|
75
|
+
# two pages, we'll have [nil, last_page] instead of
|
76
|
+
# [last_page,second_to_last_page]
|
77
|
+
#
|
78
|
+
# [ [ 1, 2, 3, 4, 5, 6, 7, 8 ],
|
79
|
+
# [ 9, 10, 11, 12, 13, 14, '{}', '{}', nil ] ]
|
80
|
+
halved.last << nil
|
81
|
+
# Reverse the second half and intercalate by two pages into the
|
82
|
+
# first one. Then remove nil elements and flatten the array.
|
83
|
+
#
|
84
|
+
# [ [ 1, 2, 3, 4, 5, 6, 7, 8 ],
|
85
|
+
# [ nil, '{}', '{}', 14, 13, 12, 11, 10 ] ]
|
86
|
+
#
|
87
|
+
# [ {}, 1, 2, {}, 14, 3, 4, 13, 12, 5, 6, 11, 10, 7, 8, 9 ]
|
88
|
+
folds << halved.last.reverse.each_slice(2).zip(halved.first.each_slice(2).to_a).flatten.compact
|
89
|
+
end
|
90
|
+
|
91
|
+
# Create the matrix of pages (N-Up) per fold
|
92
|
+
#
|
93
|
+
# ["{}", 1, "{}", 1, 2, "{}", 2, "{}", 14, 3, 14, 3, 4, 13, 4, 13, 12, 5, 12, 5, 6, 11, 6, 11, 10, 7, 10, 7, 8, 9, 8, 9]
|
94
|
+
folds.map { |o| o.each_slice(2).map{ |i| a=[]; (@nup/2).times { a = a+i }; a }}.flatten
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,276 @@
|
|
1
|
+
# Copyright (c) 2012-2015 Nicolás Reynolds <fauno@endefensadelsl.org>
|
2
|
+
# 2012-2013 Mauricio Pasquier Juan <mpj@endefensadelsl.org>
|
3
|
+
# 2013 Brian Candler <b.candler@pobox.com>
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
# a copy of this software and associated documentation files (the
|
7
|
+
# "Software"), to deal in the Software without restriction, including
|
8
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
# the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be
|
14
|
+
# included in all copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
module Jekyll
|
25
|
+
class PandocFile
|
26
|
+
include Convertible
|
27
|
+
|
28
|
+
|
29
|
+
attr_reader :format, :site, :config, :flags, :posts, :slug, :title, :url
|
30
|
+
attr_reader :papersize, :sheetsize, :signature
|
31
|
+
|
32
|
+
def initialize(site, format, posts, title = nil)
|
33
|
+
@site = site
|
34
|
+
@config = JekyllPandocMultipleFormats::Config.new(@site.config['pandoc']).config
|
35
|
+
@format = format
|
36
|
+
@flags = []
|
37
|
+
|
38
|
+
if posts.is_a? Array
|
39
|
+
@posts = posts
|
40
|
+
|
41
|
+
raise ArgumentError.new "'title' argument is required for multipost file" unless title
|
42
|
+
|
43
|
+
@title = title
|
44
|
+
else
|
45
|
+
@posts = [posts]
|
46
|
+
@title = posts.data['title'] unless title
|
47
|
+
end
|
48
|
+
|
49
|
+
@slug = Utils.slugify(title)
|
50
|
+
end
|
51
|
+
|
52
|
+
def path
|
53
|
+
# path is full destination path with all elements of permalink
|
54
|
+
path = @site.in_dest_dir(relative_path)
|
55
|
+
end
|
56
|
+
|
57
|
+
def relative_path
|
58
|
+
path = URL.unescape_path(url)
|
59
|
+
path.gsub! /^\//, ''
|
60
|
+
|
61
|
+
# but if the post is going to be index.html, use slug + format
|
62
|
+
# (ie /year/month/slug/slug.pdf)
|
63
|
+
if url.end_with? '/'
|
64
|
+
path = File.join(path, @slug)
|
65
|
+
path << '.'
|
66
|
+
path << @format
|
67
|
+
end
|
68
|
+
|
69
|
+
path
|
70
|
+
end
|
71
|
+
|
72
|
+
# if it's just one article, the url is the same except it's not html
|
73
|
+
# otherwise we use the permalink template with some placeholder
|
74
|
+
def url
|
75
|
+
@url = if single_post?
|
76
|
+
single_post.url.gsub(/\.html$/, ".#{@format}")
|
77
|
+
else
|
78
|
+
URL.new({
|
79
|
+
template: @config['bundle_permalink'],
|
80
|
+
placeholders: url_placeholders,
|
81
|
+
permalink: nil }).to_s
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def url_placeholders
|
86
|
+
{ output_ext: @format,
|
87
|
+
slug: @slug,
|
88
|
+
title: @title }
|
89
|
+
end
|
90
|
+
|
91
|
+
# adds post metadata as yaml metadata
|
92
|
+
def yaml_metadata
|
93
|
+
if single_post?
|
94
|
+
|
95
|
+
# if we were to merge config to data, the default options would
|
96
|
+
# take precedence
|
97
|
+
data = Jekyll::Utils.deep_merge_hashes @config, single_post.data
|
98
|
+
single_post.merge_data! data
|
99
|
+
|
100
|
+
|
101
|
+
# we extract the excerpt because it serializes as an object and
|
102
|
+
# breaks pandoc
|
103
|
+
metadata = single_post.data.reject{ |k| k == 'excerpt' }
|
104
|
+
|
105
|
+
if @config['date_format']
|
106
|
+
metadata['date'] = metadata['date'].strftime(@config['date_format'])
|
107
|
+
else
|
108
|
+
metadata.delete('date')
|
109
|
+
end
|
110
|
+
else
|
111
|
+
# we have to use this fugly syntax because jekyll doesn't do
|
112
|
+
# symbols
|
113
|
+
metadata = {
|
114
|
+
'date' => @config['date_format'] ? Date.today.strftime(@config['date_format']) : nil,
|
115
|
+
'title' => @title,
|
116
|
+
'author' => nil,
|
117
|
+
'papersize' => papersize,
|
118
|
+
'sheetsize' => sheetsize,
|
119
|
+
'signature' => signature
|
120
|
+
}
|
121
|
+
end
|
122
|
+
|
123
|
+
# fix page sizes, pandoc uses 'A4' while printer.rb uses
|
124
|
+
# 'a4paper'
|
125
|
+
%w[papersize sheetsize].each do |size|
|
126
|
+
metadata[size] = fix_size metadata[size]
|
127
|
+
end
|
128
|
+
|
129
|
+
metadata.to_yaml << "\n---\n"
|
130
|
+
end
|
131
|
+
|
132
|
+
def content
|
133
|
+
if single_post?
|
134
|
+
single_post.content
|
135
|
+
else
|
136
|
+
header_re = /^(#+.*\n*|.*\n[=-]+\n*)\Z/
|
137
|
+
bib_title = ""
|
138
|
+
@posts.map do |post|
|
139
|
+
bib_title = post.content.match(header_re).to_s if bib_title.empty?
|
140
|
+
# remove bibliography titles
|
141
|
+
# since pandoc does it's own bibliography output, it recommends
|
142
|
+
# leaving an empty chapter title to mark it as such
|
143
|
+
post.content.gsub(header_re, '')
|
144
|
+
# we add the first bibliography title we can find in the end
|
145
|
+
end.join("\n\n\n") << bib_title
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def write
|
150
|
+
FileUtils.mkdir_p(File.dirname(path))
|
151
|
+
# Remove the file before creating it
|
152
|
+
FileUtils.rm_f(path)
|
153
|
+
# Move to the source dir since everything will be relative to that
|
154
|
+
Dir::chdir(@site.config['source']) do
|
155
|
+
# Do the stuff
|
156
|
+
Open3::popen3(command) do |stdin, stdout, stderr, thread|
|
157
|
+
stdin.puts yaml_metadata
|
158
|
+
stdin.puts content
|
159
|
+
stdin.close
|
160
|
+
STDERR.print stderr.read
|
161
|
+
|
162
|
+
# Wait for the process to finish
|
163
|
+
thread.value
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
File.exists?(path)
|
168
|
+
end
|
169
|
+
|
170
|
+
# Returns a cover, without checking if it exists
|
171
|
+
#
|
172
|
+
# It assumes covers are in PNG format
|
173
|
+
def cover
|
174
|
+
if single_post? && single_post.data['cover']
|
175
|
+
File.join(@site.config['source'], single_post.data['cover'])
|
176
|
+
else
|
177
|
+
File.join(@site.config['source'], @config['covers_dir'], "#{@slug}.png")
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Returns a PDF cover
|
182
|
+
def pdf_cover
|
183
|
+
cover.gsub(/\.[^\.]+\Z/, '.pdf')
|
184
|
+
end
|
185
|
+
|
186
|
+
def pdf_cover!
|
187
|
+
if has_cover? && !File.exists?(pdf_cover)
|
188
|
+
Open3::popen3("convert \"#{cover}\" \"#{pdf_cover}\"") do |stdin, stdout, stderr, thread|
|
189
|
+
STDERR.print stderr.read
|
190
|
+
|
191
|
+
# Wait for the process to finish
|
192
|
+
thread.value
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
File.exists?(pdf_cover)
|
197
|
+
end
|
198
|
+
|
199
|
+
def flags
|
200
|
+
return @flags.join ' ' unless @flags.empty?
|
201
|
+
|
202
|
+
@flags << @config['flags']
|
203
|
+
@flags << @config['outputs'][@format] if @config['outputs'].key?(@format)
|
204
|
+
@flags << '-o'
|
205
|
+
@flags << path
|
206
|
+
|
207
|
+
# Binary formats don't need a -t flag
|
208
|
+
unless binary?
|
209
|
+
@flags << '-t'
|
210
|
+
@flags << @format
|
211
|
+
end
|
212
|
+
|
213
|
+
if epub? && has_cover?
|
214
|
+
@flags << '--epub-cover-image'
|
215
|
+
@flags << cover
|
216
|
+
end
|
217
|
+
|
218
|
+
@flags.join ' '
|
219
|
+
end
|
220
|
+
|
221
|
+
def command
|
222
|
+
'pandoc ' << flags
|
223
|
+
end
|
224
|
+
|
225
|
+
def pdf?
|
226
|
+
@format == 'pdf'
|
227
|
+
end
|
228
|
+
|
229
|
+
def epub?
|
230
|
+
%w[epub epub3].include? @format
|
231
|
+
end
|
232
|
+
|
233
|
+
# These formats are binary files and must use the -o flag
|
234
|
+
def binary?
|
235
|
+
%w[pdf epub epub3 odt docx].include? @format
|
236
|
+
end
|
237
|
+
|
238
|
+
def single_post?
|
239
|
+
@posts.count == 1
|
240
|
+
end
|
241
|
+
|
242
|
+
def has_cover?
|
243
|
+
File.exists? cover
|
244
|
+
end
|
245
|
+
|
246
|
+
def papersize
|
247
|
+
@papersize ||= find_option 'papersize'
|
248
|
+
end
|
249
|
+
|
250
|
+
def sheetsize
|
251
|
+
@sheetsize ||= find_option 'sheetsize'
|
252
|
+
end
|
253
|
+
|
254
|
+
def signature
|
255
|
+
@signature ||= find_option 'signature'
|
256
|
+
end
|
257
|
+
|
258
|
+
private
|
259
|
+
|
260
|
+
def single_post
|
261
|
+
@posts.first
|
262
|
+
end
|
263
|
+
|
264
|
+
def find_option(name)
|
265
|
+
if @posts.any? { |p| p.data.key? name }
|
266
|
+
@posts.select { |p| p.data.key? name }.first.data[name]
|
267
|
+
else
|
268
|
+
@config[name]
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def fix_size(size)
|
273
|
+
size.gsub /paper$/, ''
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|