asciibook 0.0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.adoc +122 -0
- data/book_template/asciibook.yml +5 -0
- data/book_template/book.adoc +3 -0
- data/exe/asciibook +7 -0
- data/lib/asciibook.rb +19 -1
- data/lib/asciibook/asciidoctor_ext/abstract_node.rb +5 -0
- data/lib/asciibook/book.rb +153 -0
- data/lib/asciibook/builders/base_builder.rb +24 -0
- data/lib/asciibook/builders/epub_builder.rb +84 -0
- data/lib/asciibook/builders/html_builder.rb +45 -0
- data/lib/asciibook/builders/mobi_builder.rb +21 -0
- data/lib/asciibook/builders/pdf_builder.rb +154 -0
- data/lib/asciibook/command.rb +85 -0
- data/lib/asciibook/converter.rb +303 -0
- data/lib/asciibook/page.rb +30 -0
- data/lib/asciibook/version.rb +1 -1
- data/templates/admonition.html +4 -0
- data/templates/audio.html +7 -0
- data/templates/colist.html +7 -0
- data/templates/dlist.html +12 -0
- data/templates/document.html +29 -0
- data/templates/embedded.html +20 -0
- data/templates/example.html +4 -0
- data/templates/footnotes.html +7 -0
- data/templates/image.html +11 -0
- data/templates/index.html +40 -0
- data/templates/inline_anchor.html +12 -0
- data/templates/inline_callout.html +1 -0
- data/templates/inline_footnote.html +1 -0
- data/templates/inline_image.html +3 -0
- data/templates/inline_indexterm.html +5 -0
- data/templates/inline_quoted.html +24 -0
- data/templates/listing.html +4 -0
- data/templates/literal.html +1 -0
- data/templates/olist.html +8 -0
- data/templates/page_break.html +1 -0
- data/templates/paragraph.html +1 -0
- data/templates/pass.html +1 -0
- data/templates/preamble.html +3 -0
- data/templates/quote.html +9 -0
- data/templates/section.html +4 -0
- data/templates/sidebar.html +6 -0
- data/templates/stem.html +9 -0
- data/templates/table.html +41 -0
- data/templates/thematic_break.html +1 -0
- data/templates/ulist.html +8 -0
- data/templates/verse.html +9 -0
- data/templates/video.html +10 -0
- data/theme/epub/epub.css +6 -0
- data/theme/epub/layout.html +14 -0
- data/theme/html/html.css +190 -0
- data/theme/html/html.js +29 -0
- data/theme/html/layout.html +91 -0
- data/theme/mobi/layout.html +13 -0
- data/theme/mobi/mobi.css +2 -0
- data/theme/pdf/config.yml +6 -0
- data/theme/pdf/footer.html +11 -0
- data/theme/pdf/header.html +3 -0
- data/theme/pdf/layout.html +14 -0
- data/theme/pdf/pdf.css +3 -0
- data/theme/pdf/toc.xsl +81 -0
- data/theme/share/default.css +174 -0
- data/theme/share/highlight.css +216 -0
- data/theme/share/normalize.css +349 -0
- metadata +119 -21
- data/.gitignore +0 -9
- data/.travis.yml +0 -4
- data/Gemfile +0 -4
- data/README.md +0 -41
- data/Rakefile +0 -10
- data/asciibook.gemspec +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f5860141a3903d0f2939ec985c5b81bbdd5b3cf14771e65daa16136c1c02bb9f
|
4
|
+
data.tar.gz: a89d6248fd14e1088037e5a15e7174f5a43ba8508b6168e4a3b2addf63e4b3e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ff6a611b748a2cf9e1ee49ea99ed385fd75d10a3db42615a9ee0804d92b642b996ffdc808c497c596723f56bd1965181fabb6d71e8597714c4c093f08c56fe0
|
7
|
+
data.tar.gz: b7f63c4c369a50afbc01c0b6981f13a82f87b15003353f459cc38c79bc1c5d4a47b5216a1cf68f4b9362767a5780eea9b4c25c923fa6b3aadbf6e0f2d859b668
|
data/README.adoc
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
= Asciibook
|
2
|
+
:toc:
|
3
|
+
|
4
|
+
Asciibook is an Ebook generator for converting AsciiDoc to HTML, PDF, EPUB and MOBI.
|
5
|
+
|
6
|
+
== Installation
|
7
|
+
|
8
|
+
If you are familiar with Ruby, you can use <<manual-installation>>.
|
9
|
+
|
10
|
+
If your are familiar with Docker, you can use <<docker-installation>>.
|
11
|
+
|
12
|
+
[[manual-installation]]
|
13
|
+
=== Manual installation
|
14
|
+
|
15
|
+
Install by rubygems:
|
16
|
+
|
17
|
+
[source, console]
|
18
|
+
----
|
19
|
+
$ gem install asciibook
|
20
|
+
----
|
21
|
+
|
22
|
+
For PDF generate, download and install wkhtmltopdf in https://wkhtmltopdf.org/downloads.html .
|
23
|
+
|
24
|
+
For Mobi generate, download and install kindlegen in https://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211 .
|
25
|
+
|
26
|
+
|
27
|
+
[[docker-installation]]
|
28
|
+
=== Docker Installation
|
29
|
+
|
30
|
+
Pull docker image:
|
31
|
+
|
32
|
+
[source, consle]
|
33
|
+
----
|
34
|
+
$ docker pull asciibook/asciibook
|
35
|
+
----
|
36
|
+
|
37
|
+
Then use asciibook CLI in this way:
|
38
|
+
|
39
|
+
[source, console]
|
40
|
+
----
|
41
|
+
$ docker run -v $(pwd):/asciibook asciibook/asciibook asciibook build mybook.adoc
|
42
|
+
----
|
43
|
+
|
44
|
+
Or enter the container environment to avoid repeating lengthy commands:
|
45
|
+
|
46
|
+
[source, console]
|
47
|
+
----
|
48
|
+
$ docker run -v $(pwd):/asciibook asciibook/asciibook bash
|
49
|
+
/asciibook $ asciibook build mybook.adoc
|
50
|
+
----
|
51
|
+
|
52
|
+
== Usage
|
53
|
+
|
54
|
+
For a existing AsciiDoc file, run this command to build all format books:
|
55
|
+
|
56
|
+
[source, console]
|
57
|
+
----
|
58
|
+
$ ascibook build mybook.adoc
|
59
|
+
----
|
60
|
+
|
61
|
+
Generated books will put in `build` directory.
|
62
|
+
|
63
|
+
Or generate only partial format:
|
64
|
+
|
65
|
+
[source, console]
|
66
|
+
----
|
67
|
+
$ asciibook build mybook.adoc --format html
|
68
|
+
$ asciibook build mybook.adoc --format pdf,mobi
|
69
|
+
----
|
70
|
+
|
71
|
+
If you don't want to enter the parameters repeatedly, you can create a configuration file for the document:
|
72
|
+
|
73
|
+
[source, console]
|
74
|
+
----
|
75
|
+
$ asciibook init mybook.adoc
|
76
|
+
----
|
77
|
+
|
78
|
+
It will create a config file `asciibook.yml` in the same directory, edit config for your need, then use this command to build next time:
|
79
|
+
|
80
|
+
[source, console]
|
81
|
+
----
|
82
|
+
$ asciibook build
|
83
|
+
----
|
84
|
+
|
85
|
+
Use this command to create a empty AsciiDoc and config file:
|
86
|
+
|
87
|
+
[source, console]
|
88
|
+
----
|
89
|
+
$ asciibook new mybook
|
90
|
+
----
|
91
|
+
|
92
|
+
== Development
|
93
|
+
|
94
|
+
Clone this repo:
|
95
|
+
|
96
|
+
[source, console]
|
97
|
+
----
|
98
|
+
$ git clone https://github.com/asciibook/asciibook.git
|
99
|
+
$ cd asciibook
|
100
|
+
----
|
101
|
+
|
102
|
+
Star dev environment with docker:
|
103
|
+
|
104
|
+
[source, console]
|
105
|
+
----
|
106
|
+
$ docker-compose run console
|
107
|
+
----
|
108
|
+
|
109
|
+
Run test:
|
110
|
+
|
111
|
+
[source, console]
|
112
|
+
----
|
113
|
+
/asciibook # rake test
|
114
|
+
----
|
115
|
+
|
116
|
+
== Contributing
|
117
|
+
|
118
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/asciibook/asciibook.
|
119
|
+
|
120
|
+
== License
|
121
|
+
|
122
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/exe/asciibook
ADDED
data/lib/asciibook.rb
CHANGED
@@ -1,5 +1,23 @@
|
|
1
|
+
require "asciidoctor"
|
2
|
+
require "rexml/document"
|
3
|
+
require "nokogiri"
|
4
|
+
require "fileutils"
|
5
|
+
require "liquid"
|
6
|
+
require "logger"
|
7
|
+
require 'yaml'
|
8
|
+
require "gepub"
|
9
|
+
require "rouge"
|
10
|
+
|
1
11
|
require "asciibook/version"
|
12
|
+
require "asciibook/asciidoctor_ext/abstract_node"
|
13
|
+
require "asciibook/converter"
|
14
|
+
require "asciibook/book"
|
15
|
+
require "asciibook/page"
|
16
|
+
require "asciibook/builders/base_builder"
|
17
|
+
require "asciibook/builders/html_builder"
|
18
|
+
require "asciibook/builders/pdf_builder"
|
19
|
+
require "asciibook/builders/epub_builder"
|
20
|
+
require "asciibook/builders/mobi_builder"
|
2
21
|
|
3
22
|
module Asciibook
|
4
|
-
# Your code goes here...
|
5
23
|
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
module Asciibook
|
2
|
+
class Book
|
3
|
+
attr_reader :data, :options, :doc, :pages, :basename, :base_dir, :dest_dir, :theme_dir, :template_dir
|
4
|
+
|
5
|
+
def initialize(data, options = {})
|
6
|
+
@data = data
|
7
|
+
@options = options
|
8
|
+
@basename = options[:basename] || 'output'
|
9
|
+
@base_dir = options[:base_dir] || '.'
|
10
|
+
@dest_dir = options[:dest_dir] || File.join(@base_dir, 'build')
|
11
|
+
@theme_dir = options[:theme_dir] || File.expand_path('../../../theme', __FILE__)
|
12
|
+
@formats = options[:formats] || %w(html pdf epub mobi)
|
13
|
+
@template_dir = options[:template_dir]
|
14
|
+
|
15
|
+
@page_level = @options[:page_level] || 1
|
16
|
+
|
17
|
+
@logger = @options[:logger] || Logger.new(STDERR, level: :warn)
|
18
|
+
|
19
|
+
@exclude_patterns = ["build/**/*"]
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.load_file(path, options = {})
|
23
|
+
options.merge!(
|
24
|
+
basename: File.basename(path, '.*'),
|
25
|
+
base_dir: File.dirname(path)
|
26
|
+
)
|
27
|
+
|
28
|
+
if File.exist?(path)
|
29
|
+
new(File.open(path, 'r:utf-8').read, options)
|
30
|
+
else
|
31
|
+
raise "File not exists #{path}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def process
|
36
|
+
@doc = Asciidoctor.load(@data, base_dir: @base_dir, backend: 'asciibook', logger: @logger, safe: :unsafe, template_dirs: [@template_dir].compact)
|
37
|
+
@toc = nil
|
38
|
+
process_pages
|
39
|
+
end
|
40
|
+
|
41
|
+
def title
|
42
|
+
doc.attributes['doctitle']
|
43
|
+
end
|
44
|
+
|
45
|
+
def cover_image_path
|
46
|
+
doc.attributes['cover-image']
|
47
|
+
end
|
48
|
+
|
49
|
+
def toc
|
50
|
+
@toc ||= outline(doc)
|
51
|
+
end
|
52
|
+
|
53
|
+
def outline(node)
|
54
|
+
data = []
|
55
|
+
node.sections.each do |section|
|
56
|
+
section_data = {
|
57
|
+
'title' => section.xreftext,
|
58
|
+
'path' => section.page ? section.page.path : "#{find_page_node(section).page.path}##{section.id}"
|
59
|
+
}
|
60
|
+
if section.sections.count > 0 and section.level < (doc.attributes['toclevels'] || 2).to_i
|
61
|
+
section_data['items'] = outline(section)
|
62
|
+
end
|
63
|
+
data << section_data
|
64
|
+
end
|
65
|
+
data
|
66
|
+
end
|
67
|
+
|
68
|
+
def find_page_node(node)
|
69
|
+
page_node = node
|
70
|
+
|
71
|
+
until page_node.page or page_node.parent.nil?
|
72
|
+
page_node = page_node.parent
|
73
|
+
end
|
74
|
+
|
75
|
+
page_node
|
76
|
+
end
|
77
|
+
|
78
|
+
def to_hash
|
79
|
+
{
|
80
|
+
'title' => doc.attributes['doctitle'],
|
81
|
+
'attributes' => doc.attributes,
|
82
|
+
'toc' => toc
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
def build
|
87
|
+
if @formats.include?('html')
|
88
|
+
Builders::HtmlBuilder.new(self).build
|
89
|
+
end
|
90
|
+
|
91
|
+
if @formats.include?('pdf')
|
92
|
+
Builders::PdfBuilder.new(self).build
|
93
|
+
end
|
94
|
+
|
95
|
+
if @formats.include?('epub')
|
96
|
+
Builders::EpubBuilder.new(self).build
|
97
|
+
end
|
98
|
+
|
99
|
+
if @formats.include?('mobi')
|
100
|
+
Builders::MobiBuilder.new(self).build
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def process_pages
|
105
|
+
@pages = []
|
106
|
+
|
107
|
+
append_page('index.html', doc)
|
108
|
+
|
109
|
+
if @page_level > 0
|
110
|
+
doc.sections.each do |section|
|
111
|
+
process_page(section)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def process_page(node)
|
117
|
+
append_page("#{node.id}.html", node)
|
118
|
+
|
119
|
+
if node.level < @page_level
|
120
|
+
node.sections.each do |section|
|
121
|
+
process_page(section)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def append_page(path, node)
|
127
|
+
if @pages.map(&:path).include?(path)
|
128
|
+
@logger.warn("Page path already in use: #{path}")
|
129
|
+
end
|
130
|
+
|
131
|
+
page = Page.new(
|
132
|
+
path: path,
|
133
|
+
node: node
|
134
|
+
)
|
135
|
+
|
136
|
+
if last_page = @pages.last
|
137
|
+
page.prev_page = last_page
|
138
|
+
last_page.next_page = page
|
139
|
+
end
|
140
|
+
|
141
|
+
node.page = page
|
142
|
+
@pages << page
|
143
|
+
end
|
144
|
+
|
145
|
+
def assets
|
146
|
+
Dir.glob('**/*.{jpg,png,gif,mp3,mp4,ogg,wav}', File::FNM_CASEFOLD, base: @base_dir).reject do |path|
|
147
|
+
@exclude_patterns.any? do |pattern|
|
148
|
+
File.fnmatch?(pattern, path)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Asciibook
|
2
|
+
module Builders
|
3
|
+
class BaseBuilder
|
4
|
+
def initialize(book)
|
5
|
+
@book = book
|
6
|
+
@theme_share_dir = File.join(@book.theme_dir, 'share')
|
7
|
+
|
8
|
+
# reset book doc
|
9
|
+
@book.process
|
10
|
+
end
|
11
|
+
|
12
|
+
def build
|
13
|
+
raise NotImplementedError
|
14
|
+
end
|
15
|
+
|
16
|
+
def copy_file(path, src_dir, dest_dir)
|
17
|
+
src_path = File.join(src_dir, path)
|
18
|
+
dest_path = File.join(dest_dir, path)
|
19
|
+
FileUtils.mkdir_p File.dirname(dest_path)
|
20
|
+
FileUtils.cp src_path, dest_path
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Asciibook
|
2
|
+
module Builders
|
3
|
+
class EpubBuilder < BaseBuilder
|
4
|
+
def initialize(book)
|
5
|
+
super
|
6
|
+
@dest_dir = File.join(@book.dest_dir, 'epub')
|
7
|
+
@theme_dir = File.join(@book.theme_dir, 'epub')
|
8
|
+
end
|
9
|
+
|
10
|
+
def build
|
11
|
+
FileUtils.mkdir_p @dest_dir
|
12
|
+
|
13
|
+
layout = Liquid::Template.parse(File.read(File.join(@theme_dir, 'layout.html')))
|
14
|
+
|
15
|
+
# Satisfy epub specifications
|
16
|
+
@book.pages.each do |page|
|
17
|
+
page.path = page.path.gsub(/.html$/, '.xhtml')
|
18
|
+
end
|
19
|
+
|
20
|
+
epub = GEPUB::Book.new do |book|
|
21
|
+
book.title = @book.title
|
22
|
+
book.identifier = @book.doc.attributes['identifier'] || 'undefined'
|
23
|
+
book.language = @book.doc.attributes['language'] || 'en'
|
24
|
+
|
25
|
+
id_pool = GEPUB::Package::IDPool.new
|
26
|
+
|
27
|
+
@book.assets.each do |path|
|
28
|
+
book.add_item path, content: File.open(File.join(@book.base_dir, path)), id: id_pool.generate_key(prefix: 'asset_')
|
29
|
+
end
|
30
|
+
|
31
|
+
if @book.cover_image_path
|
32
|
+
book.add_item(@book.cover_image_path, content: File.open(File.join(@book.base_dir, @book.cover_image_path)), id: 'cover_image').cover_image
|
33
|
+
end
|
34
|
+
|
35
|
+
Dir.glob('**/*.{jpb,png,gif,svg,css,js}', File::FNM_CASEFOLD, base: @theme_share_dir).each do |path|
|
36
|
+
book.add_item path, content: File.open(File.join(@theme_share_dir, path)), id: id_pool.generate_key(prefix: 'theme_asset_')
|
37
|
+
end
|
38
|
+
|
39
|
+
Dir.glob('**/*.{jpb,png,gif,svg,css,js}', File::FNM_CASEFOLD, base: @theme_dir).each do |path|
|
40
|
+
book.add_item path, content: File.open(File.join(@theme_dir, path)), id: id_pool.generate_key(prefix: 'theme_asset_')
|
41
|
+
end
|
42
|
+
|
43
|
+
book.ordered do
|
44
|
+
@book.pages.each do |page|
|
45
|
+
html = layout.render(
|
46
|
+
'book' => @book.to_hash,
|
47
|
+
'page' => page.to_hash
|
48
|
+
)
|
49
|
+
book.add_item page.path, content: StringIO.new(html), id: id_pool.generate_key(prefix: 'page_')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
book.add_tocdata tocdata
|
54
|
+
end
|
55
|
+
|
56
|
+
epub.generate_epub(File.join(@dest_dir, "#{@book.basename}.epub"))
|
57
|
+
|
58
|
+
# restore page path
|
59
|
+
@book.pages.each do |page|
|
60
|
+
page.path = page.path.gsub(/.xhtml$/, '.html')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def tocdata
|
65
|
+
outline(@book.doc, 1)
|
66
|
+
end
|
67
|
+
|
68
|
+
def outline(node, level)
|
69
|
+
data = []
|
70
|
+
node.sections.each do |section|
|
71
|
+
data << {
|
72
|
+
text: section.xreftext,
|
73
|
+
link: section.page ? section.page.path : "#{@book.find_page_node(section).page.path}##{section.id}",
|
74
|
+
level: level
|
75
|
+
}
|
76
|
+
if section.sections.count > 0 and section.level < (@book.doc.attributes['toclevels'] || 2).to_i
|
77
|
+
data.concat outline(section, level + 1)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
data
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|