docbook_xsl_wrapper 0.0.3 → 0.0.4
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.
- data/README.md +2 -0
- data/bin/docbook_xsl_wrapper +15 -14
- data/docbook_xsl_wrapper.gemspec +0 -1
- data/lib/docbook_xsl_wrapper/epub.rb +61 -107
- data/lib/docbook_xsl_wrapper/options.rb +24 -11
- data/lib/docbook_xsl_wrapper/version.rb +1 -1
- data/spec/docbook_xsl_wrapper/options_spec.rb +8 -5
- metadata +3 -3
data/README.md
CHANGED
@@ -11,6 +11,8 @@ At present the wrapper will only convert DocBook to EPUB 2 and is
|
|
11
11
|
intended to be run from the command-line - future versions will have more
|
12
12
|
functionality (see Future Improvements).
|
13
13
|
|
14
|
+
The original Ruby script can be found at: http://docbook.sourceforge.net/release/xsl/1.78.0/epub/bin/
|
15
|
+
|
14
16
|
|
15
17
|
## Requirements
|
16
18
|
|
data/bin/docbook_xsl_wrapper
CHANGED
@@ -2,23 +2,24 @@
|
|
2
2
|
|
3
3
|
$LOAD_PATH << File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
4
|
|
5
|
-
require 'fileutils'
|
6
5
|
require 'tmpdir'
|
7
6
|
require 'docbook_xsl_wrapper'
|
8
7
|
|
9
8
|
|
10
9
|
options = DocbookXslWrapper::Options.parse(ARGV)
|
11
10
|
|
12
|
-
options.
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
11
|
+
unless File.exist?(options.docbook)
|
12
|
+
raise ArgumentError.new("File #{options.docbook} does not exist")
|
13
|
+
end
|
14
|
+
|
15
|
+
tmp_dir = Dir.mktmpdir
|
16
|
+
options.destination = tmp_dir
|
17
|
+
|
18
|
+
begin
|
19
|
+
puts "Rendering DocBook file #{options.docbook} to #{options.output}" if options.verbose
|
20
|
+
|
21
|
+
epub = DocbookXslWrapper::Epub.new(options)
|
22
|
+
epub.render_to_file
|
23
|
+
ensure
|
24
|
+
FileUtils.remove_entry_secure tmp_dir
|
25
|
+
end
|
data/docbook_xsl_wrapper.gemspec
CHANGED
@@ -8,7 +8,6 @@ Gem::Specification.new do |gem|
|
|
8
8
|
gem.email = ["m@mikecook.co.uk"]
|
9
9
|
gem.summary = %q{Wrapper for the DocBook XSL stylesheets for easy XML to EPUB}
|
10
10
|
gem.description = %q{DocBook XSL Wrapper let's you easily convert DocBook XML to EPUB using the official DocBook XSL stylesheets.}
|
11
|
-
gem.homepage = ""
|
12
11
|
|
13
12
|
gem.platform = Gem::Platform::RUBY
|
14
13
|
gem.files = `git ls-files`.split($\)
|
@@ -4,81 +4,39 @@ require 'rexml/parsers/pullparser'
|
|
4
4
|
module DocbookXslWrapper
|
5
5
|
|
6
6
|
class Epub
|
7
|
-
|
8
|
-
CHECKER = "epubcheck"
|
9
|
-
STYLESHEET = File.join(DOCBOOK_URI, "epub", "docbook.xsl")
|
10
|
-
CALLOUT_PATH = File.join('images', 'callouts')
|
11
|
-
CALLOUT_FULL_PATH = File.join(DOCBOOK_URI, CALLOUT_PATH)
|
12
|
-
CALLOUT_LIMIT = 15
|
13
|
-
CALLOUT_EXT = ".png"
|
14
|
-
XSLT_PROCESSOR = "xsltproc"
|
15
|
-
OUTPUT_DIR = ".epubtmp#{Time.now.to_f.to_s}"
|
16
|
-
MIMETYPE = "application/epub+zip"
|
17
|
-
META_DIR = "META-INF"
|
18
|
-
OEBPS_DIR = "OEBPS"
|
19
|
-
ZIPPER = "zip"
|
20
|
-
|
21
|
-
attr_reader :output_dir
|
22
|
-
|
23
|
-
def initialize(docbook_file, output_dir=OUTPUT_DIR, css_file=nil, customization_layer=nil, embedded_fonts=[])
|
24
|
-
@docbook_file = docbook_file
|
25
|
-
@output_dir = output_dir
|
26
|
-
@meta_dir = File.join(@output_dir, META_DIR)
|
27
|
-
@oebps_dir = File.join(@output_dir, OEBPS_DIR)
|
28
|
-
@css_file = css_file ? File.expand_path(css_file) : css_file
|
29
|
-
@embedded_fonts = embedded_fonts
|
30
|
-
@to_delete = []
|
31
|
-
|
32
|
-
if customization_layer
|
33
|
-
@stylesheet = File.expand_path(customization_layer)
|
34
|
-
else
|
35
|
-
@stylesheet = STYLESHEET
|
36
|
-
end
|
7
|
+
attr_reader :options
|
37
8
|
|
38
|
-
|
39
|
-
|
40
|
-
|
9
|
+
def initialize(options)
|
10
|
+
@options = options
|
11
|
+
@options.custom_xsl = File.join(options.docbook_xsl_root, 'epub', 'docbook.xsl') unless options.custom_xsl
|
41
12
|
end
|
42
13
|
|
43
|
-
def render_to_file
|
44
|
-
render_to_epub
|
45
|
-
bundle_epub
|
46
|
-
cleanup_files(@to_delete)
|
14
|
+
def render_to_file
|
15
|
+
render_to_epub
|
16
|
+
bundle_epub
|
47
17
|
end
|
48
18
|
|
49
|
-
|
50
|
-
# Obnoxiously, we can't just check for a non-zero output...
|
51
|
-
cmd = %Q(#{CHECKER} "#{file}")
|
52
|
-
output = `#{cmd} 2>&1`
|
53
|
-
|
54
|
-
if $?.to_i == 0
|
55
|
-
return false
|
56
|
-
else
|
57
|
-
STDERR.puts output if $DEBUG
|
58
|
-
return output
|
59
|
-
end
|
60
|
-
end
|
19
|
+
private
|
61
20
|
|
62
|
-
|
63
|
-
def render_to_epub(output_file, verbose)
|
21
|
+
def render_to_epub
|
64
22
|
@collapsed_docbook_file = collapse_docbook()
|
65
23
|
|
66
|
-
chunk_quietly = "--stringparam chunk.quietly " + (verbose ? '0' : '1')
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
html_stylesheet = "--stringparam html.stylesheet #{File.basename(
|
71
|
-
base = "--stringparam base.dir #{
|
72
|
-
unless
|
73
|
-
|
74
|
-
font = "--stringparam epub.embedded.fonts \"#{
|
24
|
+
chunk_quietly = "--stringparam chunk.quietly " + (options.verbose ? '0' : '1')
|
25
|
+
co_path = "--stringparam callout.graphics.path #{options.callout_path}/"
|
26
|
+
co_limit = "--stringparam callout.graphics.number.limit #{options.callout_limit}"
|
27
|
+
co_ext = "--stringparam callout.graphics.extension #{options.callout_ext}"
|
28
|
+
html_stylesheet = "--stringparam html.stylesheet #{File.basename(options.css)}" if options.css
|
29
|
+
base = "--stringparam base.dir #{oebps_directory}/"
|
30
|
+
unless options.fonts.empty?
|
31
|
+
fonts = options.fonts.map {|f| File.basename(f)}.join(',')
|
32
|
+
font = "--stringparam epub.embedded.fonts \"#{fonts}\""
|
75
33
|
end
|
76
|
-
meta = "--stringparam epub.metainf.dir #{
|
77
|
-
oebps = "--stringparam epub.oebps.dir #{
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
34
|
+
meta = "--stringparam epub.metainf.dir #{meta_inf_directory}/"
|
35
|
+
oebps = "--stringparam epub.oebps.dir #{oebps_directory}/"
|
36
|
+
parser_opts = [chunk_quietly,
|
37
|
+
co_path,
|
38
|
+
co_limit,
|
39
|
+
co_ext,
|
82
40
|
base,
|
83
41
|
font,
|
84
42
|
meta,
|
@@ -86,62 +44,58 @@ module DocbookXslWrapper
|
|
86
44
|
html_stylesheet,
|
87
45
|
].join(" ")
|
88
46
|
# Double-quote stylesheet & file to help Windows cmd.exe
|
89
|
-
db2epub_cmd = %Q(cd "#{
|
47
|
+
db2epub_cmd = %Q(cd "#{options.destination}" && xsltproc #{parser_opts} "#{options.custom_xsl}" "#{@collapsed_docbook_file}")
|
90
48
|
STDERR.puts db2epub_cmd if $DEBUG
|
91
49
|
success = system(db2epub_cmd)
|
92
|
-
raise "Could not render as .epub to #{
|
93
|
-
@to_delete << Dir["#{@meta_dir}/*"]
|
94
|
-
@to_delete << Dir["#{@oebps_dir}/*"]
|
50
|
+
raise "Could not render as .epub to #{options.output} (#{db2epub_cmd})" unless success
|
95
51
|
end
|
96
52
|
|
97
|
-
def bundle_epub
|
98
|
-
|
99
|
-
quiet = verbose ? "" : "-q"
|
53
|
+
def bundle_epub
|
54
|
+
quiet = options.verbose ? "" : "-q"
|
100
55
|
mimetype_filename = write_mimetype()
|
101
|
-
meta = File.basename(
|
102
|
-
oebps = File.basename(
|
56
|
+
meta = File.basename(meta_inf_directory)
|
57
|
+
oebps = File.basename(oebps_directory)
|
103
58
|
images = copy_images()
|
104
59
|
csses = copy_csses()
|
105
60
|
fonts = copy_fonts()
|
106
61
|
callouts = copy_callouts()
|
107
62
|
# zip -X -r ../book.epub mimetype META-INF OEBPS
|
108
63
|
# Double-quote stylesheet & file to help Windows cmd.exe
|
109
|
-
zip_cmd = %Q(cd "#{
|
64
|
+
zip_cmd = %Q(cd "#{options.destination}" && zip #{quiet} -X -r "#{File.expand_path(options.output)}" "#{mimetype_filename}" "#{meta}" "#{oebps}")
|
110
65
|
puts zip_cmd if $DEBUG
|
111
66
|
success = system(zip_cmd)
|
112
|
-
raise "Could not bundle into .epub file to #{
|
67
|
+
raise "Could not bundle into .epub file to #{options.output}" unless success
|
113
68
|
end
|
114
69
|
|
115
|
-
# Input must be collapsed because REXML couldn't find figures in files that
|
116
|
-
# were XIncluded or added by ENTITY
|
117
|
-
# http://sourceforge.net/tracker/?func=detail&aid=2750442&group_id=21935&atid=373747
|
118
70
|
def collapse_docbook
|
71
|
+
# Input must be collapsed because REXML couldn't find figures in files that
|
72
|
+
# were XIncluded or added by ENTITY
|
73
|
+
# http://sourceforge.net/tracker/?func=detail&aid=2750442&group_id=21935&atid=373747
|
74
|
+
|
119
75
|
# Double-quote stylesheet & file to help Windows cmd.exe
|
120
|
-
collapsed_file = File.join(File.expand_path(File.dirname(
|
121
|
-
'.collapsed.' + File.basename(
|
122
|
-
entity_collapse_command = %Q(xmllint --loaddtd --noent -o "#{collapsed_file}" "#{
|
76
|
+
collapsed_file = File.join(File.expand_path(File.dirname(options.docbook)),
|
77
|
+
'.collapsed.' + File.basename(options.docbook))
|
78
|
+
entity_collapse_command = %Q(xmllint --loaddtd --noent -o "#{collapsed_file}" "#{options.docbook}")
|
123
79
|
entity_success = system(entity_collapse_command)
|
124
|
-
raise "Could not collapse named entites in #{
|
80
|
+
raise "Could not collapse named entites in #{options.docbook}" unless entity_success
|
125
81
|
|
126
82
|
xinclude_collapse_command = %Q(xmllint --xinclude -o "#{collapsed_file}" "#{collapsed_file}")
|
127
83
|
xinclude_success = system(xinclude_collapse_command)
|
128
|
-
raise "Could not collapse XIncludes in #{
|
84
|
+
raise "Could not collapse XIncludes in #{options.docbook}" unless xinclude_success
|
129
85
|
|
130
|
-
@to_delete << collapsed_file
|
131
86
|
return collapsed_file
|
132
87
|
end
|
133
88
|
|
134
89
|
def copy_callouts
|
135
90
|
new_callout_images = []
|
136
91
|
if has_callouts?
|
137
|
-
calloutglob = "#{
|
92
|
+
calloutglob = "#{options.callout_full_path}/*#{options.callout_ext}"
|
138
93
|
Dir.glob(calloutglob).each {|img|
|
139
|
-
img_new_filename = File.join(
|
94
|
+
img_new_filename = File.join(oebps_directory, options.callout_path, File.basename(img))
|
140
95
|
|
141
96
|
# TODO: What to rescue for these two?
|
142
97
|
FileUtils.mkdir_p(File.dirname(img_new_filename))
|
143
98
|
FileUtils.cp(img, img_new_filename)
|
144
|
-
@to_delete << img_new_filename
|
145
99
|
new_callout_images << img
|
146
100
|
}
|
147
101
|
end
|
@@ -150,8 +104,8 @@ module DocbookXslWrapper
|
|
150
104
|
|
151
105
|
def copy_fonts
|
152
106
|
new_fonts = []
|
153
|
-
|
154
|
-
font_new_filename = File.join(
|
107
|
+
options.fonts.each {|font_file|
|
108
|
+
font_new_filename = File.join(oebps_directory, File.basename(font_file))
|
155
109
|
FileUtils.cp(font_file, font_new_filename)
|
156
110
|
new_fonts << font_file
|
157
111
|
}
|
@@ -159,9 +113,9 @@ module DocbookXslWrapper
|
|
159
113
|
end
|
160
114
|
|
161
115
|
def copy_csses
|
162
|
-
if
|
163
|
-
css_new_filename = File.join(
|
164
|
-
FileUtils.cp(
|
116
|
+
if options.css
|
117
|
+
css_new_filename = File.join(oebps_directory, File.basename(options.css))
|
118
|
+
FileUtils.cp(options.css, css_new_filename)
|
165
119
|
end
|
166
120
|
end
|
167
121
|
|
@@ -172,14 +126,13 @@ module DocbookXslWrapper
|
|
172
126
|
# TODO: It'd be cooler if we had a filetype lookup rather than just
|
173
127
|
# extension
|
174
128
|
if img =~ /\.(svg|png|gif|jpe?g|xml)/i
|
175
|
-
img_new_filename = File.join(
|
176
|
-
img_full = File.join(File.expand_path(File.dirname(
|
129
|
+
img_new_filename = File.join(oebps_directory, img)
|
130
|
+
img_full = File.join(File.expand_path(File.dirname(options.docbook)), img)
|
177
131
|
|
178
132
|
# TODO: What to rescue for these two?
|
179
133
|
FileUtils.mkdir_p(File.dirname(img_new_filename))
|
180
134
|
puts(img_full + ": " + img_new_filename) if $DEBUG
|
181
135
|
FileUtils.cp(img_full, img_new_filename)
|
182
|
-
@to_delete << img_new_filename
|
183
136
|
new_images << img_full
|
184
137
|
end
|
185
138
|
}
|
@@ -187,19 +140,11 @@ module DocbookXslWrapper
|
|
187
140
|
end
|
188
141
|
|
189
142
|
def write_mimetype
|
190
|
-
mimetype_filename = File.join(
|
191
|
-
File.open(mimetype_filename, "w") {|f| f.print
|
192
|
-
@to_delete << mimetype_filename
|
143
|
+
mimetype_filename = File.join(options.destination, "mimetype")
|
144
|
+
File.open(mimetype_filename, "w") {|f| f.print "application/epub+zip"}
|
193
145
|
return File.basename(mimetype_filename)
|
194
146
|
end
|
195
147
|
|
196
|
-
def cleanup_files(file_list)
|
197
|
-
file_list.flatten.each {|f|
|
198
|
-
# Yikes
|
199
|
-
FileUtils.rm_r(f, :force => true )
|
200
|
-
}
|
201
|
-
end
|
202
|
-
|
203
148
|
# Returns an Array of all of the (image) @filerefs in a document
|
204
149
|
def get_image_refs
|
205
150
|
parser = REXML::Parsers::PullParser.new(File.new(@collapsed_docbook_file))
|
@@ -224,5 +169,14 @@ module DocbookXslWrapper
|
|
224
169
|
end
|
225
170
|
return false
|
226
171
|
end
|
172
|
+
|
173
|
+
def oebps_directory
|
174
|
+
@oebps_directory ||= File.join(options.destination, 'OEBPS')
|
175
|
+
end
|
176
|
+
|
177
|
+
def meta_inf_directory
|
178
|
+
@meta_inf_directory ||= File.join(options.destination, 'META-INF')
|
179
|
+
end
|
180
|
+
|
227
181
|
end
|
228
182
|
end
|
@@ -6,13 +6,19 @@ module DocbookXslWrapper
|
|
6
6
|
|
7
7
|
def self.parse(args)
|
8
8
|
options = OpenStruct.new
|
9
|
-
options.
|
10
|
-
options.
|
11
|
-
options.
|
12
|
-
options.
|
13
|
-
options.
|
14
|
-
|
15
|
-
options.
|
9
|
+
options.docbook_xsl_root = 'http://docbook.sourceforge.net/release/xsl/current'
|
10
|
+
options.callout_path = File.join('images', 'callouts')
|
11
|
+
options.callout_full_path = File.join(options.docbook_xsl_root, options.callout_path)
|
12
|
+
options.callout_limit = 15
|
13
|
+
options.callout_ext = '.png'
|
14
|
+
|
15
|
+
options.css = nil
|
16
|
+
options.custom_xsl = nil
|
17
|
+
options.fonts = []
|
18
|
+
options.output = nil
|
19
|
+
options.debug = false
|
20
|
+
options.verbose = false
|
21
|
+
options.docbook = nil
|
16
22
|
|
17
23
|
opts = OptionParser.new do |opts|
|
18
24
|
opts.banner = "Usage: #{opts.program_name} [OPTIONS] [DocBook Files]"
|
@@ -31,8 +37,8 @@ module DocbookXslWrapper
|
|
31
37
|
options.css = css
|
32
38
|
end
|
33
39
|
|
34
|
-
opts.on("-s", "--stylesheet [XSL FILE]", "Use XSL FILE as a
|
35
|
-
options.
|
40
|
+
opts.on("-s", "--stylesheet [XSL FILE]", "Use XSL FILE as a custom_xsl layer (imports epub/docbook.xsl).") do |xsl|
|
41
|
+
options.custom_xsl = xsl
|
36
42
|
end
|
37
43
|
|
38
44
|
opts.on("-f", "--font [OTF FILE]", "Embed OTF FILE in .epub.") do |otf|
|
@@ -73,14 +79,21 @@ module DocbookXslWrapper
|
|
73
79
|
args = ['-h'] if args.empty?
|
74
80
|
opts.parse!(args)
|
75
81
|
|
76
|
-
options.
|
77
|
-
|
82
|
+
options.docbook = args.first
|
83
|
+
unless options.docbook
|
78
84
|
puts "No DocBook XML file(s) specified"
|
79
85
|
exit
|
80
86
|
end
|
87
|
+
options.output = epub_filename_from_given_filename(options.docbook) unless options.output
|
81
88
|
|
82
89
|
options
|
83
90
|
end
|
84
91
|
|
92
|
+
private
|
93
|
+
|
94
|
+
def self.epub_filename_from_given_filename(filename)
|
95
|
+
File.join(File.dirname(filename), File.basename(filename, File.extname(filename)) + ".epub")
|
96
|
+
end
|
97
|
+
|
85
98
|
end
|
86
99
|
end
|
@@ -9,13 +9,16 @@ module DocbookXslWrapper
|
|
9
9
|
options.css.should be nil
|
10
10
|
options.customization.should be nil
|
11
11
|
options.fonts.should eql []
|
12
|
-
options.output.should be nil
|
13
12
|
options.debug.should be false
|
14
13
|
options.verbose.should be false
|
15
14
|
end
|
16
|
-
it "should
|
15
|
+
it "should assign docbook with the XML file path" do
|
17
16
|
options = Options.parse(['etext.xml'])
|
18
|
-
options.
|
17
|
+
options.docbook.should eql 'etext.xml'
|
18
|
+
end
|
19
|
+
it "should set the EPUB output filename from the XML filename" do
|
20
|
+
options = Options.parse(['/path/to/etext.xml'])
|
21
|
+
options.output.should eql '/path/to/etext.epub'
|
19
22
|
end
|
20
23
|
|
21
24
|
context "when verbose option" do
|
@@ -41,9 +44,9 @@ module DocbookXslWrapper
|
|
41
44
|
end
|
42
45
|
end
|
43
46
|
context "when customization stylsheet given option" do
|
44
|
-
it "should set .
|
47
|
+
it "should set .custom_xsl with the value" do
|
45
48
|
options = Options.parse(['--stylesheet', 'some.xsl', 'etext.xml'])
|
46
|
-
options.
|
49
|
+
options.custom_xsl.should eq 'some.xsl'
|
47
50
|
end
|
48
51
|
end
|
49
52
|
context "when fonts option" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: docbook_xsl_wrapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02
|
12
|
+
date: 2013-03-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -52,7 +52,7 @@ files:
|
|
52
52
|
- spec/docbook_xsl_wrapper/options_spec.rb
|
53
53
|
- spec/spec_helper.rb
|
54
54
|
- xslt/obfuscate.xsl
|
55
|
-
homepage:
|
55
|
+
homepage:
|
56
56
|
licenses: []
|
57
57
|
post_install_message:
|
58
58
|
rdoc_options: []
|