pubgen 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Pubgen
2
2
 
3
- Pubgen is a simple command-line based epub generator. With the simple YAML
4
- file, Pubgen generate the epub file for you.
3
+ Pubgen is a command-line based epub generator. With a simple YAML, Pubgen make
4
+ a epub for you.
5
5
 
6
6
  ## Installation
7
7
 
@@ -14,7 +14,7 @@ $ gem install pubgen
14
14
 
15
15
  ```bash
16
16
  $ pubgen -h
17
- pubgen 0.1.0, a epub generator.
17
+ pubgen, a epub generator. (http://github.com/9beach/pubgen)
18
18
 
19
19
  Usage:
20
20
  pubgen <yaml file> [-o <epub file>] [-v]
@@ -28,15 +28,13 @@ Usage:
28
28
  ## Quick Start
29
29
 
30
30
  Prepare files (documents, images, style sheets, etc.) that make up the
31
- publication. iBooks requires strict xhtml format,
32
- [`tidy -asxhtml`] (http://tidy.sourceforge.net/) will be helpful.
31
+ publication. iBooks requires strict xhtml. [`tidy -asxhtml`]
32
+ (http://tidy.sourceforge.net/) will be helpful.
33
33
 
34
34
  ```bash
35
35
  $ find .
36
36
  .
37
37
  ./contents
38
- ./contents/a-1.html
39
- ./contents/a-2.html
40
38
  ./contents/a.html
41
39
  ./contents/b.html
42
40
  ./images
@@ -46,14 +44,14 @@ $ find .
46
44
  ./images/cover.jpg
47
45
  ./style.css
48
46
  ```
49
- Create the YAML file describing your publication. As a example,
47
+
48
+ Create the utf-8 encoded YAML file describing the publication. As a example,
50
49
  `will_oldham.yml`.
51
50
 
52
51
  ```yaml
53
52
  # METADATA: Publication metadata (title, author, publisher, etc.).
54
53
  #
55
54
  # See http://idpf.org/epub/20/spec/OPF_2.0.1_draft.htm#Section2.2
56
- # -*- encoding: utf-8 -*-
57
55
  metadata:
58
56
  title: "Will Oldham: Wikipedia, the free encyclopedia"
59
57
  creator: Wikipedia
@@ -61,7 +59,7 @@ metadata:
61
59
  language: en
62
60
  subject: American alternative country singers
63
61
  publisher:
64
- contrubuter:
62
+ contributor:
65
63
  description:
66
64
  source: "http://en.wikipedia.org/wiki/Will_Oldham"
67
65
  rights:
@@ -71,19 +69,22 @@ metadata:
71
69
  # publication, such as table of contents, foreword, bibliography, etc.
72
70
  #
73
71
  # See http://idpf.org/epub/20/spec/OPF_2.0.1_draft.htm#Section2.6
72
+ #
73
+ # If you provide cover-image without cover-page, pubgen automatically
74
+ # generate cover-page xhtml, and add it to manifest and spine
74
75
  guide:
75
76
  toc-page:
76
77
  title-page:
77
- # If you provide cover-image without cover-page, pubgen automatically
78
- # generate cover-page xhtml, and add it to manifest and spine
79
- cover-image: images/cover.jpg
80
78
  cover-page:
79
+ cover-image: images/cover.jpg
81
80
 
82
81
  # MANIFEST: A list of files (documents, images, style sheets, etc.) that make
83
82
  # up the publication.
84
83
  #
85
- # All the files in manifest ought to be in the same or sub-directory of yaml.
86
- # Say yaml's path is /book/a.yaml.
84
+ # See http://idpf.org/epub/20/spec/OPF_2.0.1_draft.htm#Section2.3
85
+ #
86
+ # All the file paths in manifest ought to be relative to yaml's path and in the
87
+ # same or sub-directory of yaml. Say yaml's path is /book/a.yaml.
87
88
  # - a/b/c.html # good. in the sub-directory
88
89
  # - d.jpg # good. in the same directory
89
90
  # - ./e.jpg # good. in the same directory
@@ -93,8 +94,6 @@ guide:
93
94
  # - ../book/f.png # bad. although in the same directory
94
95
  manifest:
95
96
  - contents/a.html
96
- - contents/a-1.html
97
- - contents/a-2.html
98
97
  - contents/b.html
99
98
  - images/cover.jpg
100
99
  - images/1.jpg
@@ -103,18 +102,26 @@ manifest:
103
102
  - style.css
104
103
 
105
104
  # SPINE: An arrangement of documents providing a linear reading order.
105
+ #
106
+ # See http://idpf.org/epub/20/spec/OPF_2.0.1_draft.htm#Section2.4
106
107
  spine:
107
108
  - contents/a.html
108
- - contents/a-1.html
109
- - contents/a-2.html
110
109
  - contents/b.html
111
110
 
112
111
  # TOC: Table of contents
112
+ #
113
+ # See http://idpf.org/epub/20/spec/OPF_2.0.1_draft.htm#Section2.4.1
113
114
  toc:
114
- - Music -- contents/a.html: # don't forget colon to indent
115
- - Discography -- contents/a-1.html
116
- - Response -- contents/a-2.html
117
- - Film -- contents/b.html
115
+ # Add a colon suffix to indent
116
+ - 1 Music -- contents/a.html:
117
+ - 1.1 Discography -- contents/a.html#discography:
118
+ - 1.1.1 Studio albums -- contents/a.html#studio_albums
119
+ - 1.2 Response -- contents/a.html#response
120
+ - 2 Film -- contents/b.html:
121
+ - 2.1 Filmography -- contents/b.html#filmography
122
+ - 3 Photography -- contents/b.html#photography
123
+ - 4 References -- contents/b.html#references
124
+ - 5 External links -- contents/b.html#external_links
118
125
  ```
119
126
 
120
127
  Run pubgen.
@@ -123,8 +130,6 @@ Run pubgen.
123
130
  $ pubgen /path/to/will_oldham.yml -v
124
131
  mkdir .pubgen-4f4a210e
125
132
  cp ./contents/a.html .pubgen-4f4a210e/contents
126
- cp ./contents/a-1.html .pubgen-4f4a210e/contents
127
- cp ./contents/a-2.html .pubgen-4f4a210e/contents
128
133
  cp ./contents/b.html .pubgen-4f4a210e/contents
129
134
  cp ./images/cover.jpg .pubgen-4f4a210e/images
130
135
  cp ./images/1.jpg .pubgen-4f4a210e/images
@@ -138,8 +143,10 @@ cat > cover-pubgen.xhtml
138
143
  cat > content.opf
139
144
  cat > toc.ncx
140
145
  zip > pubgen.epub
141
- cd /path/to/pwd
142
- mv .pubgen-4f4a210e /pubgen.epub 'Will Oldham_ Wikipedia, the free encyclopedia.epub'
146
+ cd /path/to/prev_dir
147
+ mv .pubgen-4f4a210e/pubgen.epub 'Will Oldham_ Wikipedia, the free encyclopedia.epub'
143
148
  rm -rf .pubgen-4f4a210e
144
149
  # Successfully generated 'Will Oldham_ Wikipedia, the free encyclopedia.epub'
145
150
  ```
151
+
152
+ Done!
@@ -0,0 +1,10 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ task :default => [:test_units]
5
+ Rake::TestTask.new('test_units') do |t|
6
+ t.libs << %w[lib test]
7
+ t.pattern = 'test/test*.rb'
8
+ t.warning = true
9
+ end
10
+
data/bin/pubgen CHANGED
@@ -1,8 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- PACKAGE = 'pubgen'
4
- VERSION = '0.1.2'
5
-
6
3
  require 'yaml'
7
4
  require 'fileutils'
8
5
  require 'optparse'
@@ -13,11 +10,11 @@ $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
13
10
  require 'pubgen'
14
11
 
15
12
  HELP = <<EOF
16
- #{PACKAGE} #{VERSION}, a epub generator. (http://github.com/9beach/pubgen)
13
+ pubgen #{Pubgen::VERSION}, a epub generator. (http://github.com/9beach/pubgen)
17
14
 
18
15
  Usage:
19
- #{PACKAGE} <yaml file> [-o <epub file>] [-v]
20
- #{PACKAGE} <yaml file> -m
16
+ pubgen <yaml file> [-o <epub file>] [-v]
17
+ pubgen <yaml file> -m
21
18
 
22
19
  EOF
23
20
 
@@ -42,18 +39,18 @@ opts.parse!(ARGV)
42
39
  # check options validity
43
40
  if (options[:meta_file_only] == true && options[:epub_path] != nil)
44
41
  $stderr << <<EOF
45
- #{PACKAGE}: `--meta-file-only' with `--output EPUB_PATH', not allowed
42
+ pubgen: `--meta-file-only' with `--output EPUB_PATH', not allowed
46
43
 
47
- Try `#{PACKAGE} -h' for more informations
44
+ Try `pubgen -h' for more informations
48
45
  EOF
49
46
  exit 1
50
47
  end
51
48
 
52
49
  if ARGV.size != 1
53
50
  $stderr << <<EOF
54
- #{PACKAGE}: specify a yaml file
51
+ pubgen: specify a yaml file
55
52
 
56
- Try `#{PACKAGE} -h' for more informations
53
+ Try `pubgen -h' for more informations
57
54
  EOF
58
55
  exit 1
59
56
  else
@@ -68,7 +65,8 @@ rescue Exception=>e
68
65
  end
69
66
 
70
67
  if yaml['metadata']['title'] == nil
71
- pubgen_err("Failed to find the value of 'title' attribute in: " + options[:yaml_path])
68
+ pubgen_err("Failed to find the value of 'title' attribute in: " +
69
+ options[:yaml_path])
72
70
  exit 1
73
71
  end
74
72
 
@@ -77,20 +75,23 @@ if !options[:meta_file_only] && !options[:epub_path]
77
75
  options[:epub_path] = yaml['metadata']['title'] + ".epub"
78
76
  options[:epub_path].gsub!(/[\/:?]/, "_") # file-system friendly
79
77
  end
80
- # now, options done
78
+ # options done
81
79
 
82
- # just for one line
80
+ # just for one line log
83
81
  def pubgen_log(log, verbose = true)
84
82
  $stdout << log + "\n" if verbose
85
83
  end
86
84
 
87
- # just for one line
88
85
  def pubgen_err(err)
89
86
  $stderr << '# ' + err + "\n"
90
87
  end
91
88
 
92
- yaml['metadata']['creator'] = "#{PACKAGE}-#{VERSION}" if yaml['metadata']['creator'] == nil
93
- yaml['metadata']['contributor'] = "#{PACKAGE}-#{VERSION}" if yaml['metadata']['contributor'] == nil
89
+ if yaml['metadata']['creator'] == nil
90
+ yaml['metadata']['creator'] = "pubgen-#{Pubgen::VERSION}"
91
+ end
92
+ if yaml['metadata']['contributor'] == nil
93
+ yaml['metadata']['contributor'] = "pubgen-#{Pubgen::VERSION}"
94
+ end
94
95
 
95
96
  $tmpdir = ""
96
97
  $pwd_old = Dir.pwd
@@ -98,19 +99,20 @@ $exit_code = 0
98
99
 
99
100
  begin
100
101
  if !options[:meta_file_only]
101
- # we need temporal working directory
102
+ # temporal working directory
102
103
  $tmpdir = ".pubgen-%08x" % Time.now.to_i
103
104
  Dir.mkdir($tmpdir)
104
105
  pubgen_log("mkdir " + $tmpdir, options[:verbose])
105
106
 
106
- # copy all files of manifest to $tmpdir
107
+ # copy all the files of manifest to $tmpdir
107
108
  yaml['manifest'].each do |file|
108
109
  if Pubgen::OPF.valid_manifest_element?(file) == false
109
110
  raise "Invalid manifest (not in sub-directory of yaml file): " + file
110
111
  end
111
112
  target_dir = "#{$tmpdir}/#{File.dirname(file)}"
112
113
  FileUtils.mkdir_p(target_dir)
113
- FileUtils.cp("#{File.dirname(options[:yaml_path])}/#{file}", target_dir, :verbose=>options[:verbose])
114
+ FileUtils.cp("#{File.dirname(options[:yaml_path])}/#{file}",
115
+ target_dir, :verbose=>options[:verbose])
114
116
  end
115
117
 
116
118
  # change pwd
@@ -119,15 +121,16 @@ begin
119
121
  end
120
122
 
121
123
  # generate container.xml
122
- # it's name and path are fixed (META-INF/container.xml)
124
+ # it's path is fixed (META-INF/container.xml)
123
125
  Dir.mkdir('META-INF') if !File::directory?('META-INF')
124
126
  container = File.new('META-INF/container.xml', 'w')
125
127
  container.write(Pubgen::Container.generate)
126
128
  container.close
127
- pubgen_log('cat > META-INF/container.xml', options[:meta_file_only] || options[:verbose])
129
+ pubgen_log('cat > META-INF/container.xml',
130
+ options[:meta_file_only] || options[:verbose])
128
131
 
129
132
  # generate mimetype
130
- # it's name and path are also fixed (./mimetype)
133
+ # it's path is also fixed (./mimetype)
131
134
  mimetype = File.new('mimetype', 'w')
132
135
  mimetype.write('application/epub+zip')
133
136
  mimetype.close
@@ -135,12 +138,13 @@ begin
135
138
 
136
139
  # pubgen automatically generates cover page if cover-image is given without
137
140
  # cover-page
138
- if Pubgen::CoverPage.need_to_generate?(yaml['guide'])
141
+ if yaml['guide']['cover-image'] != nil && yaml['guide']['cover-page'] == nil
139
142
  COVER_PAGE_PATH = 'cover-pubgen.xhtml'
140
143
  cover_page = File.new(COVER_PAGE_PATH, 'w')
141
144
  cover_page.write(Pubgen::CoverPage.generate(yaml['guide']['cover-image']))
142
145
  cover_page.close
143
- pubgen_log("cat > " + COVER_PAGE_PATH, options[:meta_file_only] || options[:verbose])
146
+ pubgen_log("cat > " + COVER_PAGE_PATH,
147
+ options[:meta_file_only] || options[:verbose])
144
148
 
145
149
  # add/set it to manifest, spine, and cover-page
146
150
  yaml['manifest'] << COVER_PAGE_PATH
@@ -149,24 +153,26 @@ begin
149
153
  end
150
154
 
151
155
  # generate uuid
152
- uuid = "%08x" % Time.now.to_i + "-" + [4,4,4,12].map {|l| "%0#{l}x" % rand(1 << l*4) }.join('-')
153
- # require 'uuid'
156
+ uuid = "%08x-" % Time.now.to_i +
157
+ [4,4,4,12].map {|l| "%0#{l}x" % rand(1 << l*4) }.join('-')
154
158
  # uuid = UUID.new.generate
155
159
 
156
- # generate opf file
160
+ # generate .opf file
157
161
  opf = File.new(Pubgen::Container.opf_path, 'w')
158
162
  opf.write(Pubgen::OPF.generate(yaml, uuid))
159
163
  opf.close
160
- pubgen_log("cat > " + Pubgen::Container.opf_path, options[:meta_file_only] || options[:verbose])
161
- # pubgen automatically added ncx file to opf's manifest (but not to yaml[]'s)
164
+ pubgen_log("cat > " + Pubgen::Container.opf_path,
165
+ options[:meta_file_only] || options[:verbose])
166
+ # pubgen automatically added .ncx file to opf's manifest
162
167
 
163
- # generate ncx file
168
+ # generate .ncx file
164
169
  ncx = File.new(Pubgen::OPF.ncx_path, 'w')
165
170
  ncx.write(Pubgen::NCX.generate(yaml['metadata']['title'], yaml['toc'], uuid))
166
171
  ncx.close
167
- pubgen_log("cat > " + Pubgen::OPF.ncx_path, options[:meta_file_only] || options[:verbose])
172
+ pubgen_log("cat > " + Pubgen::OPF.ncx_path,
173
+ options[:meta_file_only] || options[:verbose])
168
174
 
169
- # generate epub
175
+ # make an epub
170
176
  if !options[:meta_file_only]
171
177
  Zip::Archive.open("pubgen.epub", Zip::CREATE | Zip::TRUNC) do |ar|
172
178
  Dir.glob('**/*').each do |path|
@@ -183,7 +189,8 @@ begin
183
189
  Dir.chdir($pwd_old)
184
190
  pubgen_log("cd " + $pwd_old, options[:verbose])
185
191
  FileUtils.mv($tmpdir + "/pubgen.epub", options[:epub_path])
186
- pubgen_log("mv #{$tmpdir} /pubgen.epub '#{options[:epub_path]}'", options[:verbose])
192
+ pubgen_log("mv #{$tmpdir}/pubgen.epub '#{options[:epub_path]}'",
193
+ options[:verbose])
187
194
  end
188
195
  rescue Exception=>e
189
196
  $exit_code = 1
@@ -2,3 +2,4 @@ require 'pubgen/cover_page'
2
2
  require 'pubgen/ncx'
3
3
  require 'pubgen/opf'
4
4
  require 'pubgen/container'
5
+ require 'pubgen/version'
@@ -7,11 +7,11 @@ module Pubgen
7
7
  def self.generate
8
8
  <<EOF
9
9
  <?xml version="1.0"?>
10
- <container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container"
11
- >
10
+ <container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:\
11
+ container">
12
12
  <rootfiles>
13
- <rootfile full-path="#{opf_path}" media-type="application/oebps-package+xml"
14
- />
13
+ <rootfile full-path="#{opf_path}" media-type="application/\
14
+ oebps-package+xml"/>
15
15
  </rootfiles>
16
16
  </container>
17
17
  EOF
@@ -1,9 +1,5 @@
1
1
  module Pubgen
2
2
  module CoverPage
3
- def self.need_to_generate?(guide)
4
- guide['cover-image'] != nil && guide['cover-page'] == nil
5
- end
6
-
7
3
  def self.generate(cover_image)
8
4
  <<EOF
9
5
  <?xml version='1.0' encoding='utf-8'?>
@@ -19,7 +15,9 @@ module Pubgen
19
15
  </head>
20
16
  <body>
21
17
  <div>
22
- <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100%" height="100%" viewBox="0 0 469 616" preserveAspectRatio="xMinYMin">
18
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/\
19
+ 1999/xlink" version="1.1" width="100%" height="100%" viewBox="0 0 469 616" \
20
+ preserveAspectRatio="xMinYMin">
23
21
  <image width="469" height="616" xlink:href="#{cover_image}"/>
24
22
  </svg>
25
23
  </div>
@@ -2,72 +2,68 @@ module Pubgen
2
2
  module NCX
3
3
  def self.generate(title, toc, uuid)
4
4
  # header
5
- toc_xml = TOC_XML_HEADER_FORMAT % [uuid, CGI.escapeHTML(title || '')]
6
- # NavPoint traces indentation, so we need class and instantiation of it
7
- nav_point = NavPointImpl.new
8
- toc.each do |name_and_path|
9
- toc_xml += nav_point.generate(name_and_path)
10
- end
11
- # footer
12
- toc_xml += TOC_XML_FOOTER
13
- end
14
-
15
- # define NavPointImpl class and some constants
16
- # they are all private, only Pubgen.NCX.generate use them
17
- NAVPOINT_XML_HEADER_FORMAT = <<EOF
18
- <navPoint id="d%03d" playOrder="%d">
19
- <navLabel>
20
- <text>%s</text>
21
- </navLabel>
22
- <content src="%s"/>
23
- EOF
24
- NAVPOINT_XML_FOOTER = " </navPoint>\n"
25
- TOC_XML_HEADER_FORMAT = <<EOF
5
+ toc_xml = <<EOF
26
6
  <?xml version='1.0' encoding='utf-8'?>
27
- <ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1" xml:lang="en">
7
+ <ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1" \
8
+ xml:lang="en">
28
9
  <head>
29
- <meta content="%s" name="dtb:uid"/>
10
+ <meta content="#{uuid}" name="dtb:uid"/>
30
11
  <meta content="2" name="dtb:depth"/>
31
12
  <meta content="pubgen" name="dtb:generator"/>
32
13
  <meta content="0" name="dtb:totalPageCount"/>
33
14
  <meta content="0" name="dtb:maxPageNumber"/>
34
15
  </head>
35
16
  <docTitle>
36
- <text>%s</text>
17
+ <text>#{CGI.escapeHTML(title || '')}</text>
37
18
  </docTitle>
38
19
  <navMap>
39
20
  EOF
40
- TOC_XML_FOOTER = " </navMap>\n</ncx>"
21
+ # NavPoint traces indentation, so we need class and instantiation of it
22
+ nav_point = NavPointImpl.new
23
+ toc.each do |name_and_path|
24
+ toc_xml += nav_point.generate(name_and_path)
25
+ end
26
+ # footer
27
+ toc_xml += " </navMap>\n</ncx>"
28
+ end
41
29
 
30
+ # define NavPointImpl class
31
+ # it's private. only Pubgen.NCX.generate use it
42
32
  class NavPointImpl
43
33
  private
44
34
  def generate_impl(name_and_path, depth)
45
- header = NAVPOINT_XML_HEADER_FORMAT
46
- footer = NAVPOINT_XML_FOOTER
47
- @toc_indent_order += 1
35
+ header = <<EOF
36
+ <navPoint id="d%03d" playOrder="%d">
37
+ <navLabel>
38
+ <text>%s</text>
39
+ </navLabel>
40
+ <content src="%s"/>
41
+ EOF
42
+ footer = " </navPoint>\n"
48
43
  if depth
49
44
  depth.times do
50
- header = header.gsub(/^/, ' ')
51
- footer = footer.gsub(/^/, ' ')
45
+ header.gsub!(/^/, ' ')
46
+ footer.gsub!(/^/, ' ')
52
47
  end
53
48
  end
54
49
 
50
+ @play_order += 1
55
51
  navpoint_xml = ''
56
52
  if name_and_path.is_a?(String)
57
53
  if name_and_path.split(" -- ").size != 2
58
54
  raise "Bad toc contents format: " + name_and_path
59
55
  end
60
- navpoint_xml = header % [@toc_indent_order, @toc_indent_order,
61
- CGI.escapeHTML(name_and_path.split(" -- ")[0]),
62
- name_and_path.split(" -- ")[1]]
56
+ navpoint_xml = header % [@play_order, @play_order,
57
+ CGI.escapeHTML(name_and_path.split(" -- ")[0]),
58
+ name_and_path.split(" -- ")[1]]
63
59
  else
64
60
  # if not string, it's hash map with just one element
65
61
  name_and_path.each do |key, value|
66
62
  if key.split(" -- ").size != 2
67
63
  raise "Bad toc contents format: " + key
68
64
  end
69
- navpoint_xml = header % [@toc_indent_order, @toc_indent_order,
70
- CGI.escapeHTML(key.split(" -- ")[0]), key.split(" -- ")[1]]
65
+ navpoint_xml = header % [@play_order, @play_order,
66
+ CGI.escapeHTML(key.split(" -- ")[0]), key.split(" -- ")[1]]
71
67
  value.each do |v|
72
68
  navpoint_xml += generate_impl(v, depth + 1)
73
69
  end
@@ -79,7 +75,7 @@ EOF
79
75
 
80
76
  public
81
77
  def initialize
82
- @toc_indent_order = 0
78
+ @play_order = 0
83
79
  end
84
80
 
85
81
  def generate(name_and_path)
@@ -3,49 +3,32 @@ require 'cgi'
3
3
  module Pubgen
4
4
  module OPF
5
5
  def self.ncx_path
6
- NCX_PATH
6
+ 'toc.ncx'
7
7
  end
8
8
 
9
9
  def self.generate(yaml, uuid)
10
10
  cover_id, manifest_xml, file2id =
11
- OPFImpl.get_cover_id_and_manifest_xml(yaml['guide']['cover-image'],
12
- yaml['manifest'])
11
+ OPFImpl.get_cover_id_and_manifest_xml(yaml['guide']['cover-image'],
12
+ yaml['manifest'])
13
13
  metadata_xml = OPFImpl.get_metadata_xml(yaml['metadata'], uuid, cover_id)
14
14
  spine_xml = OPFImpl.get_spine_xml(yaml['spine'], file2id)
15
15
  guide_xml = OPFImpl.get_guide_xml(yaml['guide'], file2id)
16
- return OPF_XML_HEADER + metadata_xml + manifest_xml + spine_xml +
17
- guide_xml + OPF_XML_FOOTER
16
+
17
+ <<EOF
18
+ <?xml version='1.0' encoding='utf-8'?>
19
+ <package xmlns="http://www.idpf.org/2007/opf" version="2.0" \
20
+ unique-identifier="uuid_id">
21
+ #{metadata_xml}#{manifest_xml}#{spine_xml}#{guide_xml}</package>
22
+ EOF
18
23
  end
19
24
 
25
+ # sub directories and relative paths
20
26
  def self.valid_manifest_element?(e)
21
27
  e[0..2] != "../" && e[0] != "/"
22
28
  end
23
29
 
24
- # define OPFImpl class and some constants
25
- # they are all private, only Pubgen.OPF.generate use them
26
- NCX_PATH = "toc.ncx"
27
- METADATA_FORMAT = <<EOF
28
- <metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
29
- <dc:title>%s</dc:title>
30
- <dc:creator opf:role="aut">%s</dc:creator>
31
- <dc:date>%s</dc:date>
32
- <dc:language>%s</dc:language>
33
- <dc:subject>%s</dc:subject>
34
- <dc:publisher>%s</dc:publisher>
35
- <dc:description>%s</dc:description>
36
- <dc:contributor opf:role="bkp">%s</dc:contributor>
37
- <dc:source>%s</dc:source>
38
- <dc:rights>%s</dc:rights>
39
- <dc:relation>%s</dc:relation>
40
- <dc:identifier id="BookID" opf:scheme="UUID">%s</dc:identifier>%s
41
- </metadata>
42
- EOF
43
- OPF_XML_HEADER = <<EOF
44
- <?xml version='1.0' encoding='utf-8'?>
45
- <package xmlns="http://www.idpf.org/2007/opf" version="2.0" unique-identifier="uuid_id">
46
- EOF
47
- OPF_XML_FOOTER = '</package>'
48
-
30
+ # define OPFImpl class
31
+ # it's private. only Pubgen.OPF.generate use it
49
32
  module OPFImpl
50
33
  def self.guess_media_type(filename)
51
34
  case filename.downcase
@@ -78,10 +61,12 @@ EOF
78
61
 
79
62
  manifest.each do |path|
80
63
  if OPF.valid_manifest_element?(path) == false
81
- raise "One of manifest element (" + path + ") is not in sub-directory of yaml file"
64
+ raise "A manifest file, #{path} is not in sub-directory of " +
65
+ "yaml file"
82
66
  end
83
67
  id = "i%03d" % no
84
- manifest_xml += " <item id=\"#{id}\" href=\"#{path}\" media-type=\"#{guess_media_type(path)}\"/>\n"
68
+ manifest_xml += " <item id=\"#{id}\" href=\"#{path}\" " +
69
+ "media-type=\"#{guess_media_type(path)}\"/>\n"
85
70
  if path == cover_path
86
71
  cover_id = id
87
72
  end
@@ -91,34 +76,45 @@ EOF
91
76
  end
92
77
 
93
78
  if cover_path && cover_id == nil
94
- raise "Can't find cover-image from manifest"
79
+ raise "Failed to find cover-image from manifest"
95
80
  end
96
81
 
97
- manifest_xml += " <item id=\"ncx\" href=\"#{NCX_PATH}\" media-type=\"application/x-dtbncx+xml\"/>\n </manifest>\n"
82
+ manifest_xml += " <item id=\"ncx\" href=\"#{OPF.ncx_path}\" " +
83
+ "media-type=\"application/x-dtbncx+xml\"/>\n </manifest>\n"
98
84
 
99
85
  return cover_id, manifest_xml, file2id
100
86
  end
101
87
 
88
+ def self.cgi_escape(text)
89
+ CGI.escapeHTML(text || '')
90
+ end
91
+
102
92
  def self.get_metadata_xml(metadata, uuid, cover_id)
103
93
  cover_id_xml = ''
104
94
  if cover_id != nil
105
- cover_id_xml = "\n <meta name=\"cover\" content=\"%s\"/>" % cover_id
95
+ cover_id_xml = "\n <meta name=\"cover\" content=\"#{cover_id}\"/>"
106
96
  end
107
- METADATA_FORMAT % [
108
- CGI.escapeHTML(metadata['title'] || ''),
109
- CGI.escapeHTML(metadata['creator'] || ''),
110
- CGI.escapeHTML((metadata['date'].is_a?(Fixnum) ?
111
- metadata['date'].to_s : metadata['date']) || ''),
112
- CGI.escapeHTML(metadata['language'] || ''),
113
- CGI.escapeHTML(metadata['subject'] || ''),
114
- CGI.escapeHTML(metadata['publisher'] || ''),
115
- CGI.escapeHTML(metadata['description'] || ''),
116
- CGI.escapeHTML(metadata['contributor'] || ''),
117
- CGI.escapeHTML(metadata['source'] || ''),
118
- CGI.escapeHTML(metadata['rights'] || ''),
119
- CGI.escapeHTML(metadata['relation'] || ''),
120
- uuid, cover_id_xml
121
- ]
97
+ <<EOF
98
+ <metadata xmlns:dc="http://purl.org/dc/elements/1.1/" \
99
+ xmlns:opf="http://www.idpf.org/2007/opf">
100
+ <dc:title>#{cgi_escape(metadata['title'])}</dc:title>
101
+ <dc:creator opf:role="aut">#{cgi_escape(metadata['creator'])}\
102
+ </dc:creator>
103
+ <dc:date>#{cgi_escape((metadata['date'].is_a?(Fixnum) ? \
104
+ metadata['date'].to_s : metadata['date']))}</dc:date>
105
+ <dc:language>#{cgi_escape(metadata['language'])}</dc:language>
106
+ <dc:subject>#{cgi_escape(metadata['subject'])}</dc:subject>
107
+ <dc:publisher>#{cgi_escape(metadata['publisher'])}</dc:publisher>
108
+ <dc:description>#{cgi_escape(metadata['description'])}</dc:description>
109
+ <dc:contributor opf:role="bkp">#{cgi_escape(metadata['contributor'])}\
110
+ </dc:contributor>
111
+ <dc:source>#{cgi_escape(metadata['source'])}</dc:source>
112
+ <dc:rights>#{cgi_escape(metadata['rights'])}</dc:rights>
113
+ <dc:relation>#{cgi_escape(metadata['relation'])}</dc:relation>
114
+ <dc:identifier id="BookID" opf:scheme="UUID">#{uuid}</dc:identifier>\
115
+ #{cover_id_xml}
116
+ </metadata>
117
+ EOF
122
118
  end
123
119
 
124
120
  def self.get_guide_xml(guide, file2id)
@@ -126,25 +122,28 @@ EOF
126
122
  cover_page = guide['cover-page']
127
123
  if cover_page != nil
128
124
  if file2id[cover_page] == nil
129
- raise "Can't find cover-page from manifest"
125
+ raise "Failed to find cover-page from manifest"
130
126
  else
131
- guide_xml += " <reference href=\"%s\" type=\"cover\" title=\"Cover\"/>\n" % cover_page
127
+ guide_xml += " <reference href=\"#{cover_page}\" " +
128
+ "type=\"cover\" title=\"Cover\"/>\n"
132
129
  end
133
130
  end
134
131
  toc_page = guide['toc-page']
135
132
  if toc_page != nil
136
133
  if file2id[toc_page] == nil
137
- raise "Can't find toc-page from manifest"
134
+ raise "Failed to find toc-page from manifest"
138
135
  else
139
- guide_xml += " <reference href=\"%s\" type=\"toc\" title=\"Table of Contents\"/>\n" % toc_page
136
+ guide_xml += " <reference href=\"#{toc_page}\" type=\"toc\" " +
137
+ "title=\"Table of Contents\"/>\n"
140
138
  end
141
139
  end
142
140
  title_page = guide['title-page']
143
141
  if title_page != nil
144
142
  if file2id[title_page] == nil
145
- raise "Can't find title-page from manifest"
143
+ raise "Failed to find title-page from manifest"
146
144
  else
147
- guide_xml += " <reference href=\"%s\" type=\"title-page\" title=\"Title Page\"/>\n" % toc_page
145
+ guide_xml += " <reference href=\"#{title_page}\" " +
146
+ "type=\"title-page\" title=\"Title Page\"/>\n"
148
147
  end
149
148
  end
150
149
  guide_xml += " </guide>\n"
@@ -156,7 +155,7 @@ EOF
156
155
  if file2id[path] != nil
157
156
  spine_xml += " <itemref idref=\"#{file2id[path]}\"/>\n"
158
157
  else
159
- raise "Can't find spine element `#{path}' from manifest"
158
+ raise "Failed to find spine element `#{path}' from manifest"
160
159
  end
161
160
  end
162
161
  spine_xml += " </spine>\n"
@@ -0,0 +1,3 @@
1
+ module Pubgen
2
+ VERSION = "0.1.3"
3
+ end
@@ -1,8 +1,11 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
+ $:.push File.expand_path("../lib", __FILE__)
4
+ require "pubgen/version"
5
+
3
6
  Gem::Specification.new do |s|
4
7
  s.name = "pubgen"
5
- s.version = "0.1.2"
8
+ s.version = Pubgen::VERSION
6
9
  s.platform = Gem::Platform::RUBY
7
10
  s.author = "9beach"
8
11
  s.email = ["9beach@gmail.com"]
@@ -12,6 +15,6 @@ Gem::Specification.new do |s|
12
15
  s.bindir = 'bin'
13
16
  s.require_paths = ["lib"]
14
17
  s.summary = "command-line based epub generator"
15
- s.description = "Pubgen is a simple command-line based epub generator. With the simple YAML file, Pubgen generate the epub file for you."
18
+ s.description = "Pubgen is a simple command-line based epub generator. With a plain YAML, Pubgen generate the epub for you."
16
19
  s.add_dependency "zipruby"
17
20
  end
@@ -0,0 +1 @@
1
+ require 'pubgen'
@@ -0,0 +1,11 @@
1
+ require 'test/unit'
2
+ require 'yaml'
3
+
4
+ require 'helper'
5
+
6
+ class TestCoverPage < Test::Unit::TestCase
7
+ def test_generate
8
+ xml = Pubgen::CoverPage.generate("test.jpg")
9
+ assert_match(/<image.*"test.jpg"\/>/, xml)
10
+ end
11
+ end
@@ -0,0 +1,90 @@
1
+ require 'test/unit'
2
+ require 'yaml'
3
+
4
+ require 'helper'
5
+
6
+ $test_yaml = <<EOF
7
+ metadata:
8
+ title: "Will Oldham"
9
+ creator: Wikipedia
10
+ date: 2012
11
+ language: en
12
+ subject: American alternative country singers
13
+ publisher: 9beach
14
+ contributor: 9valley
15
+ description: describe here
16
+ source: "http://en.wikipedia.org/wiki/Will_Oldham"
17
+ rights: I've got no right
18
+ relation: bad relation
19
+
20
+ guide:
21
+ toc-page: contents/a.html
22
+ title-page: contents/b.html
23
+ cover-page: contents/c.html
24
+ cover-image: images/cover.jpg
25
+
26
+ manifest:
27
+ - contents/a.html
28
+ - contents/b.html
29
+ - contents/c.html
30
+ - images/cover.jpg
31
+ - images/1.jpg
32
+ - images/2.jpg
33
+ - images/3.jpg
34
+ - style.css
35
+
36
+ spine:
37
+ - contents/a.html
38
+ - contents/b.html
39
+ - contents/c.html
40
+
41
+ toc:
42
+ - 1 Music -- contents/a.html:
43
+ - 1.1 Discography -- contents/a.html#discography:
44
+ - 1.1.1 Studio albums -- contents/a.html#studio_albums
45
+ - 1.2 Response -- contents/a.html#response
46
+ - 2 Film -- contents/b.html:
47
+ - 2.1 Filmography -- contents/b.html#filmography
48
+ - 3 Photography -- contents/b.html#photography
49
+ - 4 References -- contents/b.html#references
50
+ - 5 External links -- contents/c.html
51
+ EOF
52
+
53
+ class TestNCX < Test::Unit::TestCase
54
+ def setup
55
+ $yaml = YAML::load $test_yaml
56
+ end
57
+
58
+ def test_generate
59
+ xml = Pubgen::NCX.generate('English Patient', $yaml['toc'], '1111')
60
+
61
+ assert_match(/<meta content="1111" name="dtb:uid"\/>/, xml)
62
+ assert_match(/^ <navPoint id="d001" playOrder="1">/, xml)
63
+ assert_match(/^ <content src="contents\/a.html"/, xml)
64
+ assert_match(/^ <text>1 Music</, xml)
65
+ assert_match(/^ <navPoint id="d002" playOrder="2">/, xml)
66
+ assert_match(/^ <content src="contents\/a.html#discography"/, xml)
67
+ assert_match(/^ <text>1.1 Discography</, xml)
68
+ assert_match(/^ <navPoint id="d003" playOrder="3">/, xml)
69
+ assert_match(/^ <content src="contents\/a.html#studio_albums"/, xml)
70
+ assert_match(/^ <text>1.1.1 Studio albums</, xml)
71
+ assert_match(/^ <navPoint id="d004" playOrder="4">/, xml)
72
+ assert_match(/^ <content src="contents\/a.html#response"/, xml)
73
+ assert_match(/^ <text>1.2 Response</, xml)
74
+ assert_match(/^ <navPoint id="d005" playOrder="5">/, xml)
75
+ assert_match(/^ <content src="contents\/b.html"/, xml)
76
+ assert_match(/^ <text>2 Film</, xml)
77
+ assert_match(/^ <navPoint id="d006" playOrder="6">/, xml)
78
+ assert_match(/^ <content src="contents\/b.html#filmography"/, xml)
79
+ assert_match(/^ <text>2.1 Filmography</, xml)
80
+ assert_match(/^ <navPoint id="d007" playOrder="7">/, xml)
81
+ assert_match(/^ <content src="contents\/b.html#photography"/, xml)
82
+ assert_match(/^ <text>3 Photography</, xml)
83
+ assert_match(/^ <navPoint id="d008" playOrder="8">/, xml)
84
+ assert_match(/^ <content src="contents\/b.html#references"/, xml)
85
+ assert_match(/^ <text>4 References</, xml)
86
+ assert_match(/^ <navPoint id="d009" playOrder="9">/, xml)
87
+ assert_match(/^ <content src="contents\/c.html"/, xml)
88
+ assert_match(/^ <text>5 External links</, xml)
89
+ end
90
+ end
@@ -0,0 +1,112 @@
1
+ require 'test/unit'
2
+ require 'yaml'
3
+
4
+ require 'helper'
5
+
6
+ $test_yaml = <<EOF
7
+ metadata:
8
+ title: "Will Oldham"
9
+ creator: Wikipedia
10
+ date: 2012
11
+ language: en
12
+ subject: American alternative country singers
13
+ publisher: 9beach
14
+ contributor: 9valley
15
+ description: describe here
16
+ source: "http://en.wikipedia.org/wiki/Will_Oldham"
17
+ rights: I've got no right
18
+ relation: bad relation
19
+
20
+ guide:
21
+ toc-page: contents/a.html
22
+ title-page: contents/b.html
23
+ cover-page: contents/c.html
24
+ cover-image: images/cover.jpg
25
+
26
+ manifest:
27
+ - contents/a.html
28
+ - contents/b.html
29
+ - contents/c.html
30
+ - images/cover.jpg
31
+ - images/1.jpg
32
+ - images/2.jpg
33
+ - images/3.jpg
34
+ - style.css
35
+
36
+ spine:
37
+ - contents/a.html
38
+ - contents/b.html
39
+ - contents/c.html
40
+
41
+ toc:
42
+ - 1 Music -- contents/a.html:
43
+ - 1.1 Discography -- contents/a.html#discography:
44
+ - 1.1.1 Studio albums -- contents/a.html#studio_albums
45
+ - 1.2 Response -- contents/a.html#response
46
+ - 2 Film -- contents/b.html:
47
+ - 2.1 Filmography -- contents/b.html#filmography
48
+ - 3 Photography -- contents/b.html#photography
49
+ - 4 References -- contents/b.html#references
50
+ - 5 External links -- contents/c.html
51
+ EOF
52
+
53
+ class TestOPF < Test::Unit::TestCase
54
+ def setup
55
+ $yaml = YAML::load $test_yaml
56
+ end
57
+
58
+ def test_metadata
59
+ xml = Pubgen::OPF.generate($yaml, 'aaaaaaaa-1111')
60
+ assert_match(/<dc:title>Will Oldham<\/dc:[^>].*>/, xml)
61
+ assert_match(/<dc:creator opf:role="aut">Wikipedia<\/dc:[^>].*>/, xml)
62
+ assert_match(/<dc:date>2012<\/dc:[^>].*>/, xml)
63
+ assert_match(/<dc:language>en<\/dc:[^>].*>/, xml)
64
+ assert_match(/<dc:subject>American alternative country singers<\/dc:[^>].*>/, xml)
65
+ assert_match(/<dc:publisher>9beach<\/dc:[^>].*>/, xml)
66
+ assert_match(/<dc:description>describe here<\/dc:[^>].*>/, xml)
67
+ assert_match(/<dc:source>http:\/\/en.wikipedia.org\/wiki\/Will_Oldham<\/dc:[^>].*>/, xml)
68
+ assert_match(/<dc:rights>I've got no right<\/dc:[^>].*>/, xml)
69
+ assert_match(/<dc:relation>bad relation<\/dc:[^>].*>/, xml)
70
+ assert_match(/<dc:contributor opf:role="bkp">9valley<\/dc:[^>].*>/, xml)
71
+ assert_match(/<dc:identifier id="BookID" opf:scheme="UUID">aaaaaaaa-1111<\/dc:[^>].*>/, xml)
72
+ end
73
+
74
+ def test_guide
75
+ xml = Pubgen::OPF.generate($yaml, 'aaaaaaaa')
76
+
77
+ assert_match(/reference href="contents\/a.html" type="toc"/, xml)
78
+ assert_match(/reference href="contents\/b.html" type="title-page"/, xml)
79
+ assert_match(/reference href="contents\/c.html" type="cover"/, xml)
80
+ assert_match(/<meta name="cover" content/, xml)
81
+
82
+ $yaml['guide']['cover-image'] = nil
83
+ xml = Pubgen::OPF.generate($yaml, 'aaaaaaa')
84
+ assert_no_match(/<meta name="cover" content/, xml)
85
+ end
86
+
87
+ def test_manifest
88
+ xml = Pubgen::OPF.generate($yaml, 'a')
89
+ assert_match(/item id="i001" href="contents\/a.html" media-type="application\/xhtml\+xml"\/>/, xml)
90
+ assert_match(/item id="i002" href="contents\/b.html" media-type="application\/xhtml\+xml"\/>/, xml)
91
+ assert_match(/item id="i003" href="contents\/c.html" media-type="application\/xhtml\+xml"\/>/, xml)
92
+ assert_match(/item id="i004" href="images\/cover.jpg" media-type="image\/jpeg"\/>/, xml)
93
+ assert_match(/item id="i005" href="images\/1.jpg" media-type="image\/jpeg"\/>/, xml)
94
+ assert_match(/item id="i006" href="images\/2.jpg" media-type="image\/jpeg"\/>/, xml)
95
+ assert_match(/item id="i007" href="images\/3.jpg" media-type="image\/jpeg"\/>/, xml)
96
+ assert_match(/item id="i008" href="style.css" media-type="text\/css"\/>/, xml)
97
+ assert_match(/item id="ncx" href="#{Pubgen::OPF.ncx_path}" media-type="application\/x-dtbncx\+xml"\/>/, xml)
98
+ end
99
+
100
+ def test_spine
101
+ xml = Pubgen::OPF.generate($yaml, 'aaaaaaaa-1111')
102
+ assert_match(/<itemref idref="i001"\/>/, xml)
103
+ assert_match(/<itemref idref="i002"\/>/, xml)
104
+ assert_match(/<itemref idref="i003"\/>/, xml)
105
+ assert_no_match(/<itemref idref="i004"\/>/, xml)
106
+ assert_no_match(/<itemref idref="i005"\/>/, xml)
107
+ assert_no_match(/<itemref idref="i006"\/>/, xml)
108
+ assert_no_match(/<itemref idref="i007"\/>/, xml)
109
+ assert_no_match(/<itemref idref="i008"\/>/, xml)
110
+ assert_no_match(/<itemref idref="ncx"\/>/, xml)
111
+ end
112
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pubgen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-26 00:00:00.000000000Z
12
+ date: 2012-02-27 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: zipruby
16
- requirement: &2157391000 !ruby/object:Gem::Requirement
16
+ requirement: &15276980 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,9 +21,9 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2157391000
25
- description: Pubgen is a simple command-line based epub generator. With the simple
26
- YAML file, Pubgen generate the epub file for you.
24
+ version_requirements: *15276980
25
+ description: Pubgen is a simple command-line based epub generator. With a plain YAML,
26
+ Pubgen generate the epub for you.
27
27
  email:
28
28
  - 9beach@gmail.com
29
29
  executables:
@@ -34,13 +34,19 @@ files:
34
34
  - .gitignore
35
35
  - LICENSE
36
36
  - README.md
37
+ - Rakefile
37
38
  - bin/pubgen
38
39
  - lib/pubgen.rb
39
40
  - lib/pubgen/container.rb
40
41
  - lib/pubgen/cover_page.rb
41
42
  - lib/pubgen/ncx.rb
42
43
  - lib/pubgen/opf.rb
44
+ - lib/pubgen/version.rb
43
45
  - pubgen.gemspec
46
+ - test/helper.rb
47
+ - test/test_cover_page.rb
48
+ - test/test_ncx.rb
49
+ - test/test_opf.rb
44
50
  homepage: https://github.com/9beach/pubgen
45
51
  licenses: []
46
52
  post_install_message: