persie 0.0.1.alpha
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/.gitignore +4 -0
- data/.rspec +3 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +52 -0
- data/Rakefile +85 -0
- data/bin/persie +12 -0
- data/lib/persie/asciidoctor_ext/htmlbook.rb +1120 -0
- data/lib/persie/asciidoctor_ext/sample.rb +54 -0
- data/lib/persie/asciidoctor_ext/spine_item_processor.rb +43 -0
- data/lib/persie/book.rb +60 -0
- data/lib/persie/builder.rb +110 -0
- data/lib/persie/builders/epub.rb +434 -0
- data/lib/persie/builders/mobi.rb +80 -0
- data/lib/persie/builders/pdf.rb +113 -0
- data/lib/persie/builders/site.rb +110 -0
- data/lib/persie/cli.rb +106 -0
- data/lib/persie/dependency.rb +26 -0
- data/lib/persie/generator.rb +68 -0
- data/lib/persie/server.rb +27 -0
- data/lib/persie/ui.rb +27 -0
- data/lib/persie/version.rb +3 -0
- data/lib/persie.rb +32 -0
- data/persie.gemspec +41 -0
- data/spec/build_pdf_command_spec.rb +25 -0
- data/spec/fixtures/a-book/.gitignore +2 -0
- data/spec/fixtures/a-book/Gemfile +3 -0
- data/spec/fixtures/a-book/book.adoc +31 -0
- data/spec/fixtures/a-book/manuscript/chapter1.adoc +5 -0
- data/spec/fixtures/a-book/manuscript/chapter2.adoc +3 -0
- data/spec/fixtures/a-book/manuscript/preface.adoc +6 -0
- data/spec/fixtures/a-book/themes/pdf/pdf.css +1 -0
- data/spec/fixtures/a-book-with-parts/.gitignore +2 -0
- data/spec/fixtures/a-book-with-parts/Gemfile +3 -0
- data/spec/fixtures/a-book-with-parts/book.adoc +39 -0
- data/spec/fixtures/a-book-with-parts/manuscript/chapter1.adoc +4 -0
- data/spec/fixtures/a-book-with-parts/manuscript/chapter2.adoc +4 -0
- data/spec/fixtures/a-book-with-parts/manuscript/chapter3.adoc +3 -0
- data/spec/fixtures/a-book-with-parts/manuscript/chapter4.adoc +3 -0
- data/spec/fixtures/a-book-with-parts/manuscript/part1.adoc +3 -0
- data/spec/fixtures/a-book-with-parts/manuscript/part2.adoc +3 -0
- data/spec/fixtures/a-book-with-parts/manuscript/preface.adoc +4 -0
- data/spec/htmlbook_spec.rb +29 -0
- data/spec/new_command_spec.rb +57 -0
- data/spec/pdf_builder_spec.rb +39 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/version_command_spec.rb +8 -0
- data/templates/Gemfile.txt +3 -0
- data/templates/book.adoc.erb +35 -0
- data/templates/chapter1.adoc +3 -0
- data/templates/chapter2.adoc +3 -0
- data/templates/gitignore.txt +2 -0
- data/templates/preface.adoc +4 -0
- data/workflow.png +0 -0
- metadata +278 -0
@@ -0,0 +1,80 @@
|
|
1
|
+
require_relative '../builder'
|
2
|
+
|
3
|
+
module Persie
|
4
|
+
class Mobi < Builder
|
5
|
+
|
6
|
+
def initialize(book, options = {})
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
# Builds mobi.
|
11
|
+
def build
|
12
|
+
@ui.info '=== Build mobi ' << '=' * 57
|
13
|
+
|
14
|
+
self.check_dependency
|
15
|
+
check_sample
|
16
|
+
self.check_epub
|
17
|
+
self.generate_mobi
|
18
|
+
|
19
|
+
@ui.info END_LINE
|
20
|
+
end
|
21
|
+
|
22
|
+
def check_dependency
|
23
|
+
unless Dependency.kindlegen_installed?
|
24
|
+
@ui.error 'kindlegen not installed, termineted!'
|
25
|
+
@ui.info END_LINE
|
26
|
+
exit 41
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Checks if ePub file generated yet.
|
31
|
+
def check_epub
|
32
|
+
unless File.exist? self.epub_path
|
33
|
+
sample = sample? ? 'sample ' : nil
|
34
|
+
@ui.error "Please generate #{sample}ePub first"
|
35
|
+
@ui.info END_LINE
|
36
|
+
exit 42
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Generates mobi file.
|
41
|
+
def generate_mobi
|
42
|
+
FileUtils.chdir File.dirname(self.epub_path) do
|
43
|
+
@ui.info 'Converting to mobi...'
|
44
|
+
|
45
|
+
system "kindlegen -c2 #{self.epub_path(true)}"
|
46
|
+
|
47
|
+
mobi_file = File.basename(self.mobi_path)
|
48
|
+
if File.exist? mobi_file
|
49
|
+
prepare_directory(self.mobi_path)
|
50
|
+
FileUtils.mv(mobi_file, self.mobi_path)
|
51
|
+
|
52
|
+
@ui.confirm ' mobi file created'
|
53
|
+
@ui.info " Location: #{self.mobi_path(true)}"
|
54
|
+
else
|
55
|
+
@ui.error ' Can not create mobi'
|
56
|
+
@ui.info END_LINE
|
57
|
+
exit 43
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Gets ePub file path.
|
63
|
+
def epub_path(relative=false)
|
64
|
+
name = sample? ? "#{@book.slug}-sample" : @book.slug
|
65
|
+
return "#{name}.epub" if relative
|
66
|
+
|
67
|
+
File.join(@book.builds_dir, 'epub', "#{name}.epub")
|
68
|
+
end
|
69
|
+
|
70
|
+
# Gets mobi file path.
|
71
|
+
def mobi_path(relative = false)
|
72
|
+
name = sample? ? "#{@book.slug}-sample" : @book.slug
|
73
|
+
path = File.join('builds', 'mobi', "#{name}.mobi")
|
74
|
+
return path if relative
|
75
|
+
|
76
|
+
File.join(@book.base_dir, path)
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
require_relative '../builder'
|
4
|
+
|
5
|
+
module Persie
|
6
|
+
class PDF < Builder
|
7
|
+
|
8
|
+
def initialize(book, options = {})
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
# Builds PDF.
|
13
|
+
def build
|
14
|
+
@ui.info '=== Build PDF ' << '=' * 58
|
15
|
+
|
16
|
+
self.check_dependency
|
17
|
+
self.check_sample
|
18
|
+
|
19
|
+
self.convert_to_html
|
20
|
+
self.restart_page_number
|
21
|
+
self.convert_to_pdf
|
22
|
+
|
23
|
+
@ui.info END_LINE
|
24
|
+
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
# Checks dependency.
|
29
|
+
def check_dependency
|
30
|
+
unless Dependency.prince_installed?
|
31
|
+
@ui.error 'Error: PrinceXML not installed'
|
32
|
+
@ui.info END_LINE
|
33
|
+
exit 22
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Gets HTML file path.
|
38
|
+
def html_path(relative = false)
|
39
|
+
name = sample? ? "#{@book.slug}-sample" : @book.slug
|
40
|
+
path = File.join('tmp', 'pdf', "#{name}.html")
|
41
|
+
return path if relative
|
42
|
+
|
43
|
+
File.join(@book.base_dir, path)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Gets PDF file path.
|
47
|
+
def pdf_path(relative = false)
|
48
|
+
name = sample? ? "#{@book.slug}-sample" : @book.slug
|
49
|
+
path = File.join('builds', 'pdf', "#{name}.pdf")
|
50
|
+
return path if relative
|
51
|
+
|
52
|
+
File.join(@book.base_dir, path)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Converts AsciiDoc document to HTML, and writes to a file.
|
56
|
+
def convert_to_html
|
57
|
+
@ui.info 'Converting to HTML...'
|
58
|
+
html = @document.convert
|
59
|
+
prepare_directory(self.html_path)
|
60
|
+
File.write(self.html_path, html)
|
61
|
+
@ui.confirm ' HTMl file created'
|
62
|
+
@ui.info " Location: #{self.html_path(true)}"
|
63
|
+
@ui.info '' # new line
|
64
|
+
end
|
65
|
+
|
66
|
+
# Restart PDF page number.
|
67
|
+
def restart_page_number
|
68
|
+
content = File.read(self.html_path)
|
69
|
+
root = ::Nokogiri::HTML(content)
|
70
|
+
|
71
|
+
# Has parts
|
72
|
+
if (parts = root.css('body > div[data-type="part"]')).size > 0
|
73
|
+
add_class(parts.first, 'restart_page_number')
|
74
|
+
# No parts, but has chapters
|
75
|
+
elsif (chapters = root.css('body > section[data-type="chapter"]')).size > 0
|
76
|
+
add_class(chapters.first, 'restart_page_number')
|
77
|
+
end
|
78
|
+
|
79
|
+
File.write(self.html_path, root.to_xhtml)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Converts HTML to PDF with PrinceXML.
|
83
|
+
def convert_to_pdf
|
84
|
+
@ui.info 'Converting to PDF...'
|
85
|
+
prepare_directory(self.pdf_path)
|
86
|
+
system "prince #{self.html_path} -o #{self.pdf_path}"
|
87
|
+
if $?.to_i == 0
|
88
|
+
@ui.confirm ' PDF file created'
|
89
|
+
@ui.info " Location: #{self.pdf_path(true)}"
|
90
|
+
else
|
91
|
+
@ui.error ' Error: Cannot create PDF with PrinceXML'
|
92
|
+
@ui.info END_LINE
|
93
|
+
exit 23
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def adoc_custom_attributes
|
100
|
+
{
|
101
|
+
'ebook-format' => 'pdf',
|
102
|
+
'outfilesuffix' => '.html'
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
# Add a class to a element.
|
107
|
+
def add_class(el, cls)
|
108
|
+
classes = el['class'].to_s.split(/\s+/)
|
109
|
+
el['class'] = classes.push(cls).uniq.join " "
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'liquid'
|
3
|
+
require_relative '../builder'
|
4
|
+
|
5
|
+
module Persie
|
6
|
+
class Site < Builder
|
7
|
+
|
8
|
+
def initialize(book, options = {})
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
# Builds a website.
|
13
|
+
def build
|
14
|
+
@ui.info '=== Build site ' << '=' * 57
|
15
|
+
|
16
|
+
if @options.multiple?
|
17
|
+
self.build_multiple
|
18
|
+
return nil
|
19
|
+
end
|
20
|
+
|
21
|
+
self.build_single
|
22
|
+
|
23
|
+
@ui.info END_LINE
|
24
|
+
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def build_multiple
|
29
|
+
@ui.warning "Multiple pages\n"
|
30
|
+
|
31
|
+
@ui.warning 'Not Implemented!'
|
32
|
+
end
|
33
|
+
|
34
|
+
# Builds single file website.
|
35
|
+
def build_single
|
36
|
+
@ui.warning "Single page\n"
|
37
|
+
|
38
|
+
html_path = File.join(@book.builds_dir, 'site', 'single' ,'index.html')
|
39
|
+
prepare_directory(html_path)
|
40
|
+
|
41
|
+
html = @document.convert
|
42
|
+
content = render_layout_of('single', assemble_payloads(html))
|
43
|
+
|
44
|
+
if content.nil?
|
45
|
+
File.write(html_path, html)
|
46
|
+
else
|
47
|
+
File.write(html_path, content)
|
48
|
+
end
|
49
|
+
|
50
|
+
if File.exist? html_path
|
51
|
+
@ui.confirm 'Site created'
|
52
|
+
@ui.info "Location: site/single/index.html"
|
53
|
+
else
|
54
|
+
@ui.error 'Cannot create site'
|
55
|
+
@ui.info END_LINE
|
56
|
+
exit 52
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def adoc_custom_attributes
|
63
|
+
{
|
64
|
+
'ebook-format' => 'site',
|
65
|
+
'single-page' => @options.multiple? ? false : true,
|
66
|
+
'outfilesuffix' => '.html'
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
# Assembles payloads for Liquid to render.
|
71
|
+
def assemble_payloads(html)
|
72
|
+
root = ::Nokogiri::HTML(html)
|
73
|
+
body = root.css('body')
|
74
|
+
body.css('> section[data-type="titlepage"]').unlink
|
75
|
+
toc = body.css('> nav[data-type="toc"]')
|
76
|
+
toc.unlink
|
77
|
+
footnotes = body.css('> div.footnotes')
|
78
|
+
footnotes.unlink
|
79
|
+
|
80
|
+
attrs = @document.attributes
|
81
|
+
custom = {
|
82
|
+
'title' => attrs['doctitle'],
|
83
|
+
'toc' => toc.to_xhtml,
|
84
|
+
'content' => body.to_xhtml,
|
85
|
+
'footnotes' => footnotes.to_xhtml,
|
86
|
+
'generator' => "persie ::Persie::VERSION"
|
87
|
+
}
|
88
|
+
|
89
|
+
attrs.merge(custom)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Renders ERb layouts of `single' or `multiple'.
|
93
|
+
def render_layout_of(format, payloads)
|
94
|
+
unless ['single', 'multipe'].include? format
|
95
|
+
@ui.error "ONLY can render layout for `single' or `multiple'"
|
96
|
+
@ui.info END_LINE
|
97
|
+
exit 53
|
98
|
+
end
|
99
|
+
|
100
|
+
# Site templates stored in `themes/site/' folder
|
101
|
+
path = File.join @book.themes_dir, 'site', "#{format}.html.liquid"
|
102
|
+
|
103
|
+
return nil unless File.exist? path
|
104
|
+
|
105
|
+
tpl = ::Liquid::Template.parse File.read(path)
|
106
|
+
tpl.render(payloads)
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
data/lib/persie/cli.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'colorize'
|
3
|
+
|
4
|
+
require_relative 'book'
|
5
|
+
require_relative 'server'
|
6
|
+
require_relative 'version'
|
7
|
+
require_relative 'generator'
|
8
|
+
|
9
|
+
module Persie
|
10
|
+
class Cli < ::Thor
|
11
|
+
|
12
|
+
desc 'check', 'Check dependencies'
|
13
|
+
def check
|
14
|
+
ok = 'installed'.colorize(:green)
|
15
|
+
ng = 'not installed'.colorize(:red)
|
16
|
+
|
17
|
+
output = '=== Check dependencies ' << '=' * 49
|
18
|
+
output << "\n"
|
19
|
+
|
20
|
+
output << 'PrinceXML: '
|
21
|
+
output << (Dependency.prince_installed? ? ok : ng)
|
22
|
+
output << "\n"
|
23
|
+
|
24
|
+
output << 'epubcheck: '
|
25
|
+
output << (Dependency.epubcheck_installed? ? ok : ng)
|
26
|
+
output << "\n"
|
27
|
+
|
28
|
+
output << 'kindlegen: '
|
29
|
+
output << (Dependency.kindlegen_installed? ? ok : ng)
|
30
|
+
output << "\n"
|
31
|
+
|
32
|
+
output << '=' * 72
|
33
|
+
|
34
|
+
$stdout.puts output
|
35
|
+
end
|
36
|
+
|
37
|
+
desc 'new PATH', 'Create a new book'
|
38
|
+
def new(path)
|
39
|
+
g = ::Persie::Generator.new
|
40
|
+
g.destination_root = path
|
41
|
+
g.invoke_all
|
42
|
+
end
|
43
|
+
|
44
|
+
desc 'build FORMAT', 'Build a ebook format, including pdf, epub, mobi and site'
|
45
|
+
method_option :debug, aliases: '-d',
|
46
|
+
type: :boolean,
|
47
|
+
desc: 'Debug mode'
|
48
|
+
method_option :sample, aliases: '-s',
|
49
|
+
type: :boolean,
|
50
|
+
desc: 'Build sample only'
|
51
|
+
method_option :validate, aliases: '-c',
|
52
|
+
type: :boolean,
|
53
|
+
desc: 'Validate epub with epubcheck'
|
54
|
+
method_option :baseurl, type: :string,
|
55
|
+
desc: 'Base url for site'
|
56
|
+
method_option :multiple, aliases: '-m',
|
57
|
+
type: :boolean,
|
58
|
+
desc: 'Chunk site to multiple pages'
|
59
|
+
def build(format)
|
60
|
+
unless valid_book?
|
61
|
+
$stderr.puts 'Not a valid presie project.'.colorize(:red)
|
62
|
+
exit 11
|
63
|
+
end
|
64
|
+
|
65
|
+
book = ::Persie::Book.new root
|
66
|
+
case format
|
67
|
+
when 'pdf'
|
68
|
+
book.build_pdf(options)
|
69
|
+
when 'epub'
|
70
|
+
book.build_epub(options)
|
71
|
+
when 'mobi'
|
72
|
+
book.build_mobi(options)
|
73
|
+
when 'site'
|
74
|
+
book.build_site(options)
|
75
|
+
else
|
76
|
+
$stderr.puts 'Do not support build this formats.'.colorize(:red)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
desc 'preview [FORMAT]', 'Preview site on a local server'
|
81
|
+
def preview(format)
|
82
|
+
unless ['single', 'multiple'].include? format
|
83
|
+
$stderr.puts 'Only supports preview "single" page or "multiple" pages site'.colorize(:red)
|
84
|
+
exit 51
|
85
|
+
end
|
86
|
+
|
87
|
+
Server.start(format)
|
88
|
+
end
|
89
|
+
|
90
|
+
desc 'version', 'Show the persie version'
|
91
|
+
def version
|
92
|
+
$stdout.puts "persie #{VERSION}"
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def root
|
98
|
+
@root ||= Dir.pwd
|
99
|
+
end
|
100
|
+
|
101
|
+
def valid_book?
|
102
|
+
File.exist? File.join(root, 'book.adoc')
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Persie
|
2
|
+
module Dependency
|
3
|
+
|
4
|
+
def self.prince_installed?
|
5
|
+
installed? 'prince'
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.epubcheck_installed?
|
9
|
+
installed? 'epubcheck'
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.kindlegen_installed?
|
13
|
+
installed? 'kindlegen'
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.installed?(cmd)
|
17
|
+
return true if which(cmd)
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
# Finds the executable.
|
22
|
+
def self.which(cmd)
|
23
|
+
system "which #{cmd} > /dev/null 2>&1"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'uuid'
|
3
|
+
|
4
|
+
require 'time'
|
5
|
+
|
6
|
+
module Persie
|
7
|
+
class Generator < ::Thor::Group
|
8
|
+
|
9
|
+
include ::Thor::Actions
|
10
|
+
|
11
|
+
def self.source_root
|
12
|
+
File.join(::Persie::GEM_ROOT, 'templates')
|
13
|
+
end
|
14
|
+
|
15
|
+
def copy_master_file
|
16
|
+
template 'book.adoc.erb', 'book.adoc'
|
17
|
+
end
|
18
|
+
|
19
|
+
def copy_gitignore
|
20
|
+
copy_file 'gitignore.txt', '.gitignore'
|
21
|
+
end
|
22
|
+
|
23
|
+
def copy_gemfile
|
24
|
+
copy_file 'Gemfile.txt', 'Gemfile'
|
25
|
+
end
|
26
|
+
|
27
|
+
def copy_book_files
|
28
|
+
copy_file 'preface.adoc', 'manuscript/preface.adoc'
|
29
|
+
copy_file 'chapter1.adoc', 'manuscript/chapter1.adoc'
|
30
|
+
copy_file 'chapter2.adoc', 'manuscript/chapter2.adoc'
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_theme_dirs
|
34
|
+
empty_directory 'themes/pdf'
|
35
|
+
empty_directory 'themes/epub'
|
36
|
+
empty_directory 'themes/mobi'
|
37
|
+
empty_directory 'themes/site/single'
|
38
|
+
empty_directory 'themes/site/multiple'
|
39
|
+
end
|
40
|
+
|
41
|
+
def create_build_dir
|
42
|
+
empty_directory 'builds'
|
43
|
+
end
|
44
|
+
|
45
|
+
def create_tmp_dir
|
46
|
+
empty_directory 'tmp'
|
47
|
+
end
|
48
|
+
|
49
|
+
def create_images_dir
|
50
|
+
empty_directory 'images'
|
51
|
+
end
|
52
|
+
|
53
|
+
def create_plugins_dir
|
54
|
+
empty_directory 'plugins'
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def uuid
|
60
|
+
UUID.new.generate(:urn)
|
61
|
+
end
|
62
|
+
|
63
|
+
def time_now
|
64
|
+
Time.now.iso8601
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'webrick'
|
2
|
+
|
3
|
+
module Persie
|
4
|
+
module Server
|
5
|
+
|
6
|
+
include WEBrick
|
7
|
+
|
8
|
+
def self.start(dir)
|
9
|
+
destination = File.join(Dir.pwd, 'builds', 'site', dir)
|
10
|
+
|
11
|
+
# recreate NondisclosureName under utf-8 circumstance
|
12
|
+
fh_option = WEBrick::Config::FileHandler
|
13
|
+
fh_option[:NondisclosureName] = ['.ht*','~*']
|
14
|
+
|
15
|
+
s = HTTPServer.new(
|
16
|
+
:Port => 9527,
|
17
|
+
:BindAddress => '0.0.0.0',
|
18
|
+
)
|
19
|
+
|
20
|
+
s.mount('/', HTTPServlet::FileHandler, destination, fh_option)
|
21
|
+
t = Thread.new { s.start }
|
22
|
+
trap("INT") { s.shutdown }
|
23
|
+
t.join()
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
data/lib/persie/ui.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'colorize'
|
2
|
+
|
3
|
+
module Persie
|
4
|
+
class UI
|
5
|
+
|
6
|
+
def initialize(options= {})
|
7
|
+
@test_mode = options.has_key?(:test) && options[:test] === true
|
8
|
+
end
|
9
|
+
|
10
|
+
def info(msg)
|
11
|
+
$stdout.puts msg unless @test_mode
|
12
|
+
end
|
13
|
+
|
14
|
+
def confirm(msg)
|
15
|
+
$stdout.puts msg.colorize(:green) unless @test_mode
|
16
|
+
end
|
17
|
+
|
18
|
+
def error(msg)
|
19
|
+
$stderr.puts msg.colorize(:red) unless @test_mode
|
20
|
+
end
|
21
|
+
|
22
|
+
def warning(msg)
|
23
|
+
$stdout.puts msg.colorize(:yellow) unless @test_mode
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
data/lib/persie.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative 'persie/cli'
|
2
|
+
|
3
|
+
Encoding.default_internal = 'utf-8'
|
4
|
+
Encoding.default_external = 'utf-8'
|
5
|
+
|
6
|
+
module Persie
|
7
|
+
GEM_ROOT = File.expand_path('../../', __FILE__)
|
8
|
+
TEMPLATES_DIR = File.join(GEM_ROOT, 'templates')
|
9
|
+
|
10
|
+
def self.ruby_platform_warning
|
11
|
+
host = RbConfig::CONFIG['host_os']
|
12
|
+
if host =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
13
|
+
$stderr.puts 'Sorry, you cannot use persie on Windows.'
|
14
|
+
exit 1
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.ruby_version_warning
|
19
|
+
if RUBY_VERSION < '1.9.3'
|
20
|
+
$stderr.puts "Your Ruby version(#{RUBY_VERSION}) is NOT supported, please upgrade!"
|
21
|
+
exit 2
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.require_plugins
|
26
|
+
plugins = File.join(Dir.pwd, 'plugins', '*.rb')
|
27
|
+
|
28
|
+
Dir.glob(plugins) do |path|
|
29
|
+
require path
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/persie.gemspec
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
$:.unshift File.expand_path('../lib', __FILE__)
|
2
|
+
|
3
|
+
require 'persie/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.specification_version = 2 if s.respond_to? :specification_version=
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
|
9
|
+
s.name = 'persie'
|
10
|
+
s.version = ::Persie::VERSION
|
11
|
+
s.license = 'MIT'
|
12
|
+
s.date = '2014-06-18'
|
13
|
+
|
14
|
+
s.summary = "电子书制作工具"
|
15
|
+
s.description = "使用 AsciiDoc 编写书籍内容,通过 persie 将其转换成 PDF,ePub 和 Mobi 格式电子书。"
|
16
|
+
|
17
|
+
s.authors = ["Andor Chen"]
|
18
|
+
s.email = 'andor.chen.27@gmail.com'
|
19
|
+
s.homepage = 'https://github.com/AndorChen/persie'
|
20
|
+
|
21
|
+
s.require_paths = %w[lib]
|
22
|
+
s.executables = ["persie"]
|
23
|
+
s.files = `git ls-files`.split($/)
|
24
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
25
|
+
|
26
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
27
|
+
s.extra_rdoc_files = %w[README.md LICENSE]
|
28
|
+
|
29
|
+
s.add_runtime_dependency('thor', '0.19.1')
|
30
|
+
s.add_runtime_dependency('uuid', '2.3.7')
|
31
|
+
s.add_runtime_dependency('rouge', '1.7.1')
|
32
|
+
s.add_runtime_dependency('gepub', '0.6.9.2')
|
33
|
+
s.add_runtime_dependency('liquid', '2.6.1')
|
34
|
+
s.add_runtime_dependency('colorize', '0.7.3')
|
35
|
+
s.add_runtime_dependency('nokogiri', '1.6.3.1')
|
36
|
+
s.add_runtime_dependency('thread_safe', '0.3.4')
|
37
|
+
s.add_runtime_dependency('asciidoctor', '1.5.1')
|
38
|
+
|
39
|
+
s.add_development_dependency('rake', '~> 10.3.2')
|
40
|
+
s.add_development_dependency('rspec', '~> 3.1.0')
|
41
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Cli#build(pdf)' do
|
4
|
+
|
5
|
+
it 'generates a pdf file' do
|
6
|
+
FileUtils.cd(A_BOOK_PATH) do
|
7
|
+
persie_command 'build pdf'
|
8
|
+
path = 'builds/pdf/a-book.pdf'
|
9
|
+
expect(File.exist?(path)).to be true
|
10
|
+
FileUtils.remove_dir('tmp/pdf')
|
11
|
+
FileUtils.remove_dir('builds/pdf')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'generates a sample pdf file' do
|
16
|
+
FileUtils.cd(A_BOOK_PATH) do
|
17
|
+
persie_command 'build pdf -s'
|
18
|
+
path = 'builds/pdf/a-book-sample.pdf'
|
19
|
+
expect(File.exist?(path)).to be true
|
20
|
+
FileUtils.remove_dir('tmp/pdf')
|
21
|
+
FileUtils.remove_dir('builds/pdf')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|