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 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: []