asciibook 0.0.0 → 0.0.1
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 +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
|