docbook_xsl_wrapper 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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
 
@@ -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.docbooks.each {|docbook_file|
13
- dir = File.expand_path(File.join(Dir.tmpdir, ".epubtmp#{Time.now.to_f.to_s}"))
14
- FileUtils.mkdir_p(dir)
15
- e = DocbookXslWrapper::Epub.new(docbook_file, dir, options.css, options.customization, options.fonts)
16
-
17
- if options.output
18
- epub_file = options.output
19
- else
20
- epub_file = File.join(File.dirname(docbook_file), File.basename(docbook_file, ".xml") + ".epub")
21
- end
22
- puts "Rendering DocBook file #{docbook_file} to #{epub_file}" if options.verbose
23
- e.render_to_file(epub_file)
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
@@ -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
- DOCBOOK_URI = "http://docbook.sourceforge.net/release/xsl/current"
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
- unless File.exist?(@docbook_file)
39
- raise ArgumentError.new("File #{@docbook_file} does not exist")
40
- end
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(output_file, verbose=false)
44
- render_to_epub(output_file, verbose)
45
- bundle_epub(output_file, verbose)
46
- cleanup_files(@to_delete)
14
+ def render_to_file
15
+ render_to_epub
16
+ bundle_epub
47
17
  end
48
18
 
49
- def self.invalid?(file)
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
- private
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
- callout_path = "--stringparam callout.graphics.path #{CALLOUT_PATH}/"
68
- callout_limit = "--stringparam callout.graphics.number.limit #{CALLOUT_LIMIT}"
69
- callout_ext = "--stringparam callout.graphics.extension #{CALLOUT_EXT}"
70
- html_stylesheet = "--stringparam html.stylesheet #{File.basename(@css_file)}" if @css_file
71
- base = "--stringparam base.dir #{OEBPS_DIR}/"
72
- unless @embedded_fonts.empty?
73
- embedded_fonts = @embedded_fonts.map {|f| File.basename(f)}.join(',')
74
- font = "--stringparam epub.embedded.fonts \"#{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 #{META_DIR}/"
77
- oebps = "--stringparam epub.oebps.dir #{OEBPS_DIR}/"
78
- options = [chunk_quietly,
79
- callout_path,
80
- callout_limit,
81
- callout_ext,
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 "#{@output_dir}" && #{XSLT_PROCESSOR} #{options} "#{@stylesheet}" "#{@collapsed_docbook_file}")
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 #{output_file} (#{db2epub_cmd})" unless success
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(output_file, verbose)
98
-
99
- quiet = verbose ? "" : "-q"
53
+ def bundle_epub
54
+ quiet = options.verbose ? "" : "-q"
100
55
  mimetype_filename = write_mimetype()
101
- meta = File.basename(@meta_dir)
102
- oebps = File.basename(@oebps_dir)
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 "#{@output_dir}" && #{ZIPPER} #{quiet} -X -r "#{File.expand_path(output_file)}" "#{mimetype_filename}" "#{meta}" "#{oebps}")
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 #{output_file}" unless success
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(@docbook_file)),
121
- '.collapsed.' + File.basename(@docbook_file))
122
- entity_collapse_command = %Q(xmllint --loaddtd --noent -o "#{collapsed_file}" "#{@docbook_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 #{@docbook_file}" unless entity_success
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 #{@docbook_file}" unless xinclude_success
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 = "#{CALLOUT_FULL_PATH}/*#{CALLOUT_EXT}"
92
+ calloutglob = "#{options.callout_full_path}/*#{options.callout_ext}"
138
93
  Dir.glob(calloutglob).each {|img|
139
- img_new_filename = File.join(@oebps_dir, CALLOUT_PATH, File.basename(img))
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
- @embedded_fonts.each {|font_file|
154
- font_new_filename = File.join(@oebps_dir, File.basename(font_file))
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 @css_file
163
- css_new_filename = File.join(@oebps_dir, File.basename(@css_file))
164
- FileUtils.cp(@css_file, css_new_filename)
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(@oebps_dir, img)
176
- img_full = File.join(File.expand_path(File.dirname(@docbook_file)), img)
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(@output_dir, "mimetype")
191
- File.open(mimetype_filename, "w") {|f| f.print MIMETYPE}
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.css = nil
10
- options.customization = nil
11
- options.fonts = []
12
- options.output = nil
13
- options.debug = false
14
- options.verbose = false
15
- options.docbooks = []
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 customization layer (imports epub/docbook.xsl).") do |xsl|
35
- options.customization = xsl
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.docbooks = args
77
- if options.docbooks.empty?
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
@@ -1,3 +1,3 @@
1
1
  module DocbookXslWrapper
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  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 put the XML file in the docbooks array" do
15
+ it "should assign docbook with the XML file path" do
17
16
  options = Options.parse(['etext.xml'])
18
- options.docbooks.should eql ['etext.xml']
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 .customiztion with the value" do
47
+ it "should set .custom_xsl with the value" do
45
48
  options = Options.parse(['--stylesheet', 'some.xsl', 'etext.xml'])
46
- options.customization.should eq 'some.xsl'
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.3
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-27 00:00:00.000000000 Z
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: []