docbook_xsl_wrapper 0.0.5 → 0.1.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.
- data/README.md +5 -7
- data/bin/docbook_xsl_wrapper +1 -1
- data/lib/docbook_xsl_wrapper/epub.rb +111 -104
- data/lib/docbook_xsl_wrapper/options.rb +16 -16
- data/lib/docbook_xsl_wrapper/version.rb +1 -1
- data/spec/docbook_xsl_wrapper/options_spec.rb +14 -5
- metadata +2 -2
data/README.md
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
# DocBook XSL Wrapper
|
2
2
|
|
3
|
-
|
4
|
-
this as an Alpha release._
|
3
|
+
_Please consider this as an Alpha release._
|
5
4
|
|
6
5
|
The DocBook XSL stylesheets are very powerful and provide an easy way to output
|
7
6
|
your DocBook XML documents into a usable format such as EPUB and PDF. This GEM
|
8
7
|
hopes to make using these stylesheets even easier.
|
9
8
|
|
10
|
-
At present the wrapper will only convert DocBook to
|
9
|
+
At present the wrapper will only convert DocBook to EPUB2 and EPUB3 and is
|
11
10
|
intended to be run from the command-line - future versions will have more
|
12
11
|
functionality (see Future Improvements).
|
13
12
|
|
@@ -17,7 +16,7 @@ The original Ruby script can be found at: http://docbook.sourceforge.net/release
|
|
17
16
|
## Requirements
|
18
17
|
|
19
18
|
* DocBook
|
20
|
-
* DocBook XSL (~> v1.78.
|
19
|
+
* DocBook XSL (~> v1.78.1)
|
21
20
|
* xsltproc
|
22
21
|
|
23
22
|
### NOTE
|
@@ -31,10 +30,10 @@ needed fixing before everything worked correctly.
|
|
31
30
|
|
32
31
|
The catalog file ($XML_CATALOG_FILES) needed updating;
|
33
32
|
|
34
|
-
1. Add an entry to your 1.78.
|
33
|
+
1. Add an entry to your 1.78.1 path.
|
35
34
|
2. Remove older XSL entries (e.g. 1.76.0 & 1.77.0).
|
36
35
|
|
37
|
-
_Please make sure that xsltproc uses the *1.78.
|
36
|
+
_Please make sure that xsltproc uses the *1.78.1* stylesheets as default_
|
38
37
|
|
39
38
|
|
40
39
|
## Installation
|
@@ -49,7 +48,6 @@ _Please make sure that xsltproc uses the *1.78.0* stylesheets as default_
|
|
49
48
|
|
50
49
|
* Better design so it can be used from within other GEMs, as part of a larger tool-chain.
|
51
50
|
* Test that the GEM also works on Linux.
|
52
|
-
* EPUB3 output
|
53
51
|
* Other output formats (e.g. PDF)
|
54
52
|
|
55
53
|
## Contributing
|
data/bin/docbook_xsl_wrapper
CHANGED
@@ -8,64 +8,58 @@ module DocbookXslWrapper
|
|
8
8
|
|
9
9
|
def initialize(options)
|
10
10
|
@options = options
|
11
|
-
|
11
|
+
|
12
|
+
case options.format
|
13
|
+
when 'epub3'
|
14
|
+
xsl = File.join('epub3', 'chunk.xsl')
|
15
|
+
else
|
16
|
+
xsl = File.join('epub', 'docbook.xsl')
|
17
|
+
end
|
18
|
+
official_docbook_xsl = File.join('http://docbook.sourceforge.net/release/xsl/current', xsl)
|
19
|
+
|
20
|
+
@options.stylesheet = official_docbook_xsl unless options.stylesheet
|
12
21
|
end
|
13
22
|
|
14
|
-
def
|
15
|
-
|
16
|
-
|
23
|
+
def create
|
24
|
+
begin
|
25
|
+
render_to_epub
|
26
|
+
bundle_epub
|
27
|
+
ensure
|
28
|
+
FileUtils.remove_entry_secure @collapsed_docbook_file
|
29
|
+
end
|
17
30
|
end
|
18
31
|
|
19
32
|
private
|
20
33
|
|
21
34
|
def render_to_epub
|
22
|
-
@collapsed_docbook_file = collapse_docbook
|
35
|
+
@collapsed_docbook_file = collapse_docbook
|
23
36
|
|
24
37
|
# Double-quote stylesheet & file to help Windows cmd.exe
|
25
|
-
db2epub_cmd = %Q(cd "#{options.destination}" && xsltproc #{xsl_parser_options} "#{options.
|
38
|
+
db2epub_cmd = %Q(cd "#{options.destination}" && xsltproc #{xsl_parser_options} "#{options.stylesheet}" "#{@collapsed_docbook_file}")
|
26
39
|
STDERR.puts db2epub_cmd if options.debug
|
27
40
|
success = system(db2epub_cmd)
|
28
41
|
raise "Could not render as .epub to #{options.output} (#{db2epub_cmd})" unless success
|
29
42
|
end
|
30
43
|
|
31
44
|
def xsl_parser_options
|
32
|
-
chunk_quietly
|
33
|
-
|
34
|
-
|
35
|
-
co_ext = "--stringparam callout.graphics.extension #{options.callout_ext}"
|
36
|
-
html_stylesheet = "--stringparam html.stylesheet #{File.basename(options.css)}" if options.css
|
37
|
-
base = "--stringparam base.dir #{oebps_path}/"
|
45
|
+
chunk_quietly = "--stringparam chunk.quietly 1" if options.verbose == false
|
46
|
+
css = "--stringparam html.stylesheet #{File.basename(options.css)}/" if options.css
|
47
|
+
base = "--stringparam base.dir #{oebps_path}/"
|
38
48
|
unless options.fonts.empty?
|
39
49
|
fonts = options.fonts.map {|f| File.basename(f)}.join(',')
|
40
50
|
font = "--stringparam epub.embedded.fonts \"#{fonts}\""
|
41
51
|
end
|
42
|
-
meta = "--stringparam epub.metainf.dir #{
|
52
|
+
meta = "--stringparam epub.metainf.dir #{meta_inf_directory}/"
|
43
53
|
oebps = "--stringparam epub.oebps.dir #{oebps_directory}/"
|
44
|
-
[chunk_quietly,
|
45
|
-
co_path,
|
46
|
-
co_limit,
|
47
|
-
co_ext,
|
48
|
-
base,
|
49
|
-
font,
|
50
|
-
meta,
|
51
|
-
oebps,
|
52
|
-
html_stylesheet,
|
53
|
-
].join(" ")
|
54
|
-
end
|
55
54
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
# Double-quote stylesheet & file to help Windows cmd.exe
|
65
|
-
zip_cmd = %Q(cd "#{options.destination}" && zip #{quiet} -X -r "#{File.expand_path(options.output)}" "#{mimetype_filename}" "#{meta_inf_directory}" "#{oebps_directory}")
|
66
|
-
puts zip_cmd if options.debug
|
67
|
-
success = system(zip_cmd)
|
68
|
-
raise "Could not bundle into .epub file to #{options.output}" unless success
|
55
|
+
[
|
56
|
+
chunk_quietly,
|
57
|
+
base,
|
58
|
+
font,
|
59
|
+
meta,
|
60
|
+
oebps,
|
61
|
+
css,
|
62
|
+
].join(" ")
|
69
63
|
end
|
70
64
|
|
71
65
|
def collapse_docbook
|
@@ -84,91 +78,108 @@ module DocbookXslWrapper
|
|
84
78
|
xinclude_success = system(xinclude_collapse_command)
|
85
79
|
raise "Could not collapse XIncludes in #{options.docbook}" unless xinclude_success
|
86
80
|
|
87
|
-
|
81
|
+
collapsed_file
|
82
|
+
end
|
83
|
+
|
84
|
+
def bundle_epub
|
85
|
+
quiet = options.verbose ? "" : "-q"
|
86
|
+
mimetype_filename = write_mimetype
|
87
|
+
images = copy_images
|
88
|
+
csses = copy_css
|
89
|
+
fonts = copy_fonts
|
90
|
+
callouts = copy_callouts
|
91
|
+
# zip -X -r ../book.epub mimetype META-INF OEBPS
|
92
|
+
# Double-quote stylesheet & file to help Windows cmd.exe
|
93
|
+
zip_cmd = %Q(cd "#{options.destination}" && zip #{quiet} -X -r "#{File.expand_path(options.output)}" "#{mimetype_filename}" "#{meta_inf_directory}" "#{oebps_directory}")
|
94
|
+
puts zip_cmd if options.debug
|
95
|
+
success = system(zip_cmd)
|
96
|
+
raise "Could not bundle into .epub file to #{options.output}" unless success
|
97
|
+
end
|
98
|
+
|
99
|
+
def write_mimetype
|
100
|
+
filename = File.join(options.destination, "mimetype")
|
101
|
+
File.open(filename, "w") {|f| f.print "application/epub+zip"}
|
102
|
+
File.basename(filename)
|
88
103
|
end
|
89
104
|
|
90
105
|
def copy_callouts
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
106
|
+
return unless has_callouts?
|
107
|
+
|
108
|
+
images = Array.new
|
109
|
+
calloutglob = "#{options.callout_full_path}/*#{options.callout_ext}"
|
110
|
+
Dir.glob(calloutglob).each do |image|
|
111
|
+
new_filename = File.join(oebps_path, options.callout_path, File.basename(image))
|
112
|
+
|
113
|
+
# TODO: What to rescue for these two?
|
114
|
+
FileUtils.mkdir_p(File.dirname(new_filename))
|
115
|
+
FileUtils.cp(image, new_filename)
|
116
|
+
images << image
|
102
117
|
end
|
103
|
-
|
118
|
+
images
|
119
|
+
end
|
120
|
+
|
121
|
+
# Returns true if the document has code callouts
|
122
|
+
def has_callouts?
|
123
|
+
parser = REXML::Parsers::PullParser.new(File.new(@collapsed_docbook_file))
|
124
|
+
while parser.has_next?
|
125
|
+
element = parser.pull
|
126
|
+
return true if element.start_element? and (element[0] == "calloutlist" or element[0] == "co")
|
127
|
+
end
|
128
|
+
false
|
104
129
|
end
|
105
130
|
|
106
131
|
def copy_fonts
|
107
|
-
|
108
|
-
options.fonts.each {|
|
109
|
-
|
110
|
-
FileUtils.cp(
|
111
|
-
|
132
|
+
fonts = Array.new
|
133
|
+
options.fonts.each {|font|
|
134
|
+
new_filename = File.join(oebps_path, File.basename(font))
|
135
|
+
FileUtils.cp(font, new_filename)
|
136
|
+
fonts << font
|
112
137
|
}
|
113
|
-
|
138
|
+
fonts
|
114
139
|
end
|
115
140
|
|
116
|
-
def
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
141
|
+
def copy_css
|
142
|
+
return unless options.css
|
143
|
+
|
144
|
+
filename = File.join(oebps_path, File.basename(options.css))
|
145
|
+
FileUtils.cp(options.css, filename)
|
121
146
|
end
|
122
147
|
|
123
148
|
def copy_images
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
if img =~ /\.(svg|png|gif|jpe?g|xml)/i
|
130
|
-
img_new_filename = File.join(oebps_path, img)
|
131
|
-
img_full = File.join(File.expand_path(File.dirname(options.docbook)), img)
|
132
|
-
|
133
|
-
# TODO: What to rescue for these two?
|
134
|
-
FileUtils.mkdir_p(File.dirname(img_new_filename))
|
135
|
-
puts(img_full + ": " + img_new_filename) if options.debug
|
136
|
-
FileUtils.cp(img_full, img_new_filename)
|
137
|
-
new_images << img_full
|
138
|
-
end
|
139
|
-
}
|
140
|
-
return new_images
|
149
|
+
images = Array.new
|
150
|
+
xml_image_references.each do |image|
|
151
|
+
images << copy_image(image)
|
152
|
+
end
|
153
|
+
images
|
141
154
|
end
|
142
155
|
|
143
|
-
def
|
144
|
-
|
145
|
-
File.
|
146
|
-
|
156
|
+
def copy_image(image)
|
157
|
+
source_file = File.join(File.expand_path(File.dirname(options.docbook)), image)
|
158
|
+
destination_file = File.join(oebps_path, image)
|
159
|
+
|
160
|
+
FileUtils.mkdir_p(File.dirname(destination_file))
|
161
|
+
|
162
|
+
puts "Copying image: #{source_file} to #{destination_file}" if options.debug
|
163
|
+
FileUtils.cp(source_file, destination_file)
|
164
|
+
|
165
|
+
destination_file
|
147
166
|
end
|
148
167
|
|
149
|
-
|
150
|
-
def get_image_refs
|
168
|
+
def xml_image_references
|
151
169
|
parser = REXML::Parsers::PullParser.new(File.new(@collapsed_docbook_file))
|
152
|
-
|
170
|
+
references = Array.new
|
153
171
|
while parser.has_next?
|
154
|
-
|
155
|
-
|
156
|
-
image_refs << el[1]['fileref']
|
157
|
-
end
|
172
|
+
element = parser.pull
|
173
|
+
references << element[1]['fileref'] if is_valid_image_reference?(element)
|
158
174
|
end
|
159
|
-
|
175
|
+
references.uniq
|
160
176
|
end
|
161
177
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
if el.start_element? and (el[0] == "calloutlist" or el[0] == "co")
|
168
|
-
return true
|
169
|
-
end
|
170
|
-
end
|
171
|
-
return false
|
178
|
+
def is_valid_image_reference?(element)
|
179
|
+
return false unless element.start_element?
|
180
|
+
return false unless element[0] == 'graphic' or element[0] == 'imagedata'
|
181
|
+
return true if element[1]['fileref'].match(/\.(jpe?g|png|gif|svg|xml)\Z/i)
|
182
|
+
false
|
172
183
|
end
|
173
184
|
|
174
185
|
def oebps_directory
|
@@ -183,9 +194,5 @@ module DocbookXslWrapper
|
|
183
194
|
'META-INF'
|
184
195
|
end
|
185
196
|
|
186
|
-
def meta_inf_path
|
187
|
-
@meta_inf_path ||= File.join(options.destination, meta_inf_directory)
|
188
|
-
end
|
189
|
-
|
190
197
|
end
|
191
198
|
end
|
@@ -6,16 +6,11 @@ module DocbookXslWrapper
|
|
6
6
|
|
7
7
|
def self.parse(args)
|
8
8
|
options = OpenStruct.new
|
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
9
|
|
15
10
|
options.css = nil
|
16
|
-
options.
|
11
|
+
options.stylesheet = nil
|
17
12
|
options.fonts = []
|
18
|
-
options.
|
13
|
+
options.format = 'epub'
|
19
14
|
options.debug = false
|
20
15
|
options.verbose = false
|
21
16
|
options.docbook = nil
|
@@ -33,20 +28,25 @@ module DocbookXslWrapper
|
|
33
28
|
opts.separator "Specific options:"
|
34
29
|
|
35
30
|
|
36
|
-
opts.on("-c", "--css [FILE]", "
|
37
|
-
options.css = css
|
31
|
+
opts.on("-c", "--css [FILE]", "Custom CSS for generated HTML") do |css|
|
32
|
+
options.css = File.expand_path(css)
|
38
33
|
end
|
39
34
|
|
40
|
-
opts.on("-s", "--stylesheet [XSL FILE]", "
|
41
|
-
options.
|
35
|
+
opts.on("-s", "--stylesheet [XSL FILE]", "Custom XSL layer (imports epub/docbook.xsl, overrides --type)") do |xsl|
|
36
|
+
options.stylesheet = File.expand_path(xsl)
|
42
37
|
end
|
43
38
|
|
44
|
-
opts.on("-f", "--font [OTF FILE]", "
|
45
|
-
options.fonts << otf
|
39
|
+
opts.on("-f", "--font [OTF FILE]", "OpenType Font file for inclusion in the EPUB") do |otf|
|
40
|
+
options.fonts << File.expand_path(otf)
|
46
41
|
end
|
47
42
|
|
48
|
-
opts.on("-o", "--output [OUTPUT FILE]", "
|
49
|
-
options.output = output
|
43
|
+
opts.on("-o", "--output [OUTPUT FILE]", "Filename for the generated document") do |output|
|
44
|
+
options.output = File.expand_path(output)
|
45
|
+
end
|
46
|
+
|
47
|
+
opts.on("-t", "--type [BOOK TYPE]", "eBook type (format) that you wish to output: epub, epub3", /\Aepub[23]?\z/i) do |format|
|
48
|
+
format = format.downcase if format
|
49
|
+
options.format = "#{format}"
|
50
50
|
end
|
51
51
|
|
52
52
|
opts.separator ""
|
@@ -79,7 +79,7 @@ module DocbookXslWrapper
|
|
79
79
|
args = ['-h'] if args.empty?
|
80
80
|
opts.parse!(args)
|
81
81
|
|
82
|
-
options.docbook = args.first
|
82
|
+
options.docbook = File.expand_path(args.first)
|
83
83
|
unless options.docbook
|
84
84
|
puts "No DocBook XML file(s) specified"
|
85
85
|
exit
|
@@ -9,12 +9,14 @@ module DocbookXslWrapper
|
|
9
9
|
options.css.should be nil
|
10
10
|
options.customization.should be nil
|
11
11
|
options.fonts.should eql []
|
12
|
+
options.format.should eq 'epub'
|
13
|
+
options.output.should match /etext\.epub\z/
|
12
14
|
options.debug.should be false
|
13
15
|
options.verbose.should be false
|
14
16
|
end
|
15
17
|
it "should assign docbook with the XML file path" do
|
16
18
|
options = Options.parse(['etext.xml'])
|
17
|
-
options.docbook.should
|
19
|
+
options.docbook.should match /etext\.xml\z/
|
18
20
|
end
|
19
21
|
it "should set the EPUB output filename from the XML filename" do
|
20
22
|
options = Options.parse(['/path/to/etext.xml'])
|
@@ -40,19 +42,20 @@ module DocbookXslWrapper
|
|
40
42
|
context "when css option used" do
|
41
43
|
it "should assign value to .css" do
|
42
44
|
options = Options.parse(['--css', 'stylesheet.css', 'etext.xml'])
|
43
|
-
options.css.should
|
45
|
+
options.css.should match /stylesheet\.css\z/
|
44
46
|
end
|
45
47
|
end
|
46
48
|
context "when customization stylsheet given option" do
|
47
|
-
it "should set .
|
49
|
+
it "should set .stylesheet with the value" do
|
48
50
|
options = Options.parse(['--stylesheet', 'some.xsl', 'etext.xml'])
|
49
|
-
options.
|
51
|
+
options.stylesheet.should match /some\.xsl\z/
|
50
52
|
end
|
51
53
|
end
|
52
54
|
context "when fonts option" do
|
53
55
|
it "should sets fonts with the OTF files" do
|
54
56
|
options = Options.parse(['--font', 'one.otf', '--font', 'two.otf', 'etext.xml'])
|
55
|
-
options.fonts.should
|
57
|
+
options.fonts[0].should match /one\.otf\z/
|
58
|
+
options.fonts[1].should match /two\.otf\z/
|
56
59
|
end
|
57
60
|
end
|
58
61
|
context "when output file given" do
|
@@ -61,6 +64,12 @@ module DocbookXslWrapper
|
|
61
64
|
options.output.should eq '/path/to/new.epub'
|
62
65
|
end
|
63
66
|
end
|
67
|
+
context "when output ebook format is given" do
|
68
|
+
it "should assign format with the given book format" do
|
69
|
+
options = Options.parse(['--type', 'ePub3', 'etext.xml'])
|
70
|
+
options.format.should eq 'epub3'
|
71
|
+
end
|
72
|
+
end
|
64
73
|
end
|
65
74
|
|
66
75
|
end
|
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.
|
4
|
+
version: 0.1.1
|
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-03-
|
12
|
+
date: 2013-03-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|