eeepub3 0.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e37fdd0df050b43117eb43439f4f2dba67cc9f96
4
+ data.tar.gz: 7e5a05e05a17afbdcd72c3c3a6ed2269c16c51d9
5
+ SHA512:
6
+ metadata.gz: e1587a96ace135f869eb4494d2c087e5dac8aedf7977140fa1bfe54469e12a3eb3bede7e099823ec7875d60a52d48c6f7af6527d1b859d421c9cb494135f0c97
7
+ data.tar.gz: 43d500fe967d569fbba17c71712eb6dfed33119cb6ca6dffd03c61808b939574659e7ab59d9e6ff07bd10eee880f318e5e179ee44087c8d8f39f12bb1438c5b9
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in eeepub.gemspec
4
+ gemspec
data/LICENSE ADDED
File without changes
@@ -0,0 +1,4 @@
1
+ eeepub3
2
+ =======
3
+
4
+ EPUB3 tools
@@ -0,0 +1,22 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ begin
5
+ require 'rspec/core/rake_task'
6
+ RSpec::Core::RakeTask.new do |t|
7
+ t.rspec_opts = ['--color']
8
+ end
9
+ rescue LoadError => e
10
+ puts "RSpec not installed"
11
+ end
12
+
13
+ task :default => :spec
14
+
15
+ begin
16
+ require 'yard'
17
+ YARD::Rake::YardocTask.new
18
+ rescue LoadError
19
+ task :yardoc do
20
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "eeepub3"
5
+ s.version = "0.0.1"
6
+ s.platform = Gem::Platform::RUBY
7
+ s.authors = ["bubaz"]
8
+ s.email = ["s.bubovich@gmail.com"]
9
+ s.homepage = "http://github.com/bubaz/eeepub3"
10
+ s.summary = %q{ePub generator}
11
+ s.description = %q{EeePub is a Ruby ePub generator.}
12
+
13
+ s.files = `git ls-files`.split("\n")
14
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
+ s.require_paths = ["lib"]
17
+
18
+ s.add_dependency "builder"
19
+ s.add_dependency "rubyzip"
20
+ s.add_development_dependency "rspec"
21
+ s.add_development_dependency "nokogiri"
22
+ s.add_development_dependency "rr"
23
+ s.add_development_dependency "simplecov"
24
+ end
@@ -0,0 +1,15 @@
1
+ require 'eeepub/container_item'
2
+ require 'eeepub/opf'
3
+ require 'eeepub/ocf'
4
+ require 'eeepub/ncx'
5
+ require 'eeepub/maker'
6
+ require 'eeepub/easy'
7
+
8
+ module EeePub
9
+ # Make ePub
10
+ #
11
+ # @param [Proc] block the block for initialize EeePub::Maker
12
+ def self.make(&block)
13
+ EeePub::Maker.new(&block)
14
+ end
15
+ end
@@ -0,0 +1,116 @@
1
+ require 'builder'
2
+
3
+ module EeePub
4
+ # Abstract base class for container item of ePub. Provides some helper methods.
5
+ #
6
+ # @abstract
7
+ class ContainerItem
8
+ class << self
9
+
10
+ private
11
+
12
+ # Set default value to attribute
13
+ #
14
+ # @param [Symbol] name the attribute name
15
+ # @param [Object] default the default value
16
+ def default_value(name, default)
17
+ instance_variable_name = "@#{name}"
18
+ define_method(name) do
19
+ self.instance_variable_get(instance_variable_name) ||
20
+ self.instance_variable_set(instance_variable_name, default)
21
+ end
22
+ end
23
+
24
+ # Define alias of attribute accessor
25
+ #
26
+ # @param [Symbol] name the attribute name as alias
27
+ # @param [Symbol] name the attribute name as source
28
+ def attr_alias(name, src)
29
+ alias_method name, src
30
+ alias_method :"#{name}=", :"#{src}="
31
+ end
32
+ end
33
+
34
+ # @param [Hash<Symbol, Object>] values the hash of symbols and objects for attributes
35
+ def initialize(values)
36
+ set_values(values)
37
+ end
38
+
39
+ # Set values for attributes
40
+ #
41
+ # @param [Hash<Symbol, Object>] values the hash of symbols and objects for attributes
42
+ def set_values(values)
43
+ values.each do |k, v|
44
+ self.send(:"#{k}=", v)
45
+ end
46
+ end
47
+
48
+ # Convert to xml of container item
49
+ #
50
+ # @return [String] the xml of container item
51
+ def to_xml
52
+ out = ""
53
+ builder = Builder::XmlMarkup.new(:target => out, :indent => 2)
54
+ builder.instruct!
55
+ build_xml(builder)
56
+ out
57
+ end
58
+
59
+ # Save as container item
60
+ #
61
+ # @param [String] filepath the file path for container item
62
+ def save(filepath)
63
+ File.open(filepath, 'w') do |file|
64
+ file << self.to_xml
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ # Guess media type from file name
71
+ #
72
+ # @param [String] filename the file name
73
+ # @return [String] the media-type
74
+ def guess_media_type(filename)
75
+ ext = File.extname(filename)
76
+ mimes = {
77
+ '.png' => 'image/png',
78
+ '.js' => 'application/x-javascript',
79
+ '.html' => 'application/xhtml+xml',
80
+ '.jpeg' => 'image/jpeg',
81
+ '.jpg' => 'image/jpeg',
82
+ '.gif' => 'image/gif',
83
+ '.svg' => 'image/svg+xml',
84
+ '.ncx' => 'application/x-dtbncx+xml',
85
+ '.css' => 'text/css',
86
+ '.less' => 'text/plain', #explicit not text/css because of validation failure
87
+ '.mp4' => 'video/mp4',
88
+ '.mp3' => 'audio/mpeg',
89
+ '.webm' => 'video/webm',
90
+ '.woff' => 'application/font-woff',
91
+ '.otf' => 'application/vnd.ms-opentype',
92
+ '.ttf' => 'application/vnd.ms-opentype',
93
+ '.eot' => 'application/vnd.ms-opentype',
94
+ '.db' =>'application/octet-stream', #explicit,
95
+ '.nes'=>'text/plain; charset=x-user-defined', #explicit
96
+ '.txt'=>'text/plain'
97
+ }
98
+
99
+ mimes[ext] || 'application/octet-stream'
100
+
101
+ end
102
+
103
+ # Convert options for xml attributes
104
+ #
105
+ # @param [Hash<Symbol, Object>] hash the hash of symbols and objects for xml attributes
106
+ # @return [Hash<String, Object>] the options for xml attributes
107
+ def convert_to_xml_attributes(hash)
108
+ result = {}
109
+ hash.each do |k, v|
110
+ key = k.to_s.gsub('_', '-').to_sym
111
+ result[key] = v
112
+ end
113
+ result
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,100 @@
1
+ require 'tmpdir'
2
+ require 'fileutils'
3
+
4
+ module EeePub
5
+ # The class to make ePub more easily
6
+ #
7
+ # @example
8
+ # epub = EeePub::Easy.new do
9
+ # title 'sample'
10
+ # creator 'jugyo'
11
+ # identifier 'http://example.com/book/foo', :scheme => 'URL'
12
+ # uid 'http://example.com/book/foo'
13
+ # end
14
+ #
15
+ # epub.sections << ['1. foo', <<HTML]
16
+ # <?xml version="1.0" encoding="UTF-8"?>
17
+ # <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
18
+ # <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja">
19
+ # <head>
20
+ # <title>foo</title>
21
+ # </head>
22
+ # <body>
23
+ # <p>
24
+ # foo foo foo foo foo foo
25
+ # </p>
26
+ # </body>
27
+ # </html>
28
+ # HTML
29
+ #
30
+ # epub.assets << 'image.png'
31
+ #
32
+ # epub.save('sample.epub')
33
+ class Easy < EeePub::Maker
34
+ attr_reader :sections, :assets
35
+
36
+ # @param [Proc] block the block for initialize
37
+ def initialize(&block)
38
+ @sections = []
39
+ @assets = []
40
+ super
41
+ end
42
+
43
+ # Save as ePub file
44
+ #
45
+ # @param [String] filename the ePub file name to save
46
+ def save(filename)
47
+ Dir.mktmpdir do |dir|
48
+ prepare(dir)
49
+
50
+ NCX.new(
51
+ :uid => @uid,
52
+ :title => @titles[0],
53
+ :nav => @nav
54
+ ).save(File.join(dir, @ncx_file))
55
+
56
+ OPF.new(
57
+ :title => @titles,
58
+ :identifier => @identifiers,
59
+ :creator => @creators,
60
+ :publisher => @publishers,
61
+ :date => @dates,
62
+ :language => @languages,
63
+ :subject => @subjects,
64
+ :description => @descriptions,
65
+ :rights => @rightss,
66
+ :relation => @relations,
67
+ :manifest => @files.map{|i| File.basename(i)},
68
+ :ncx => @ncx_file
69
+ ).save(File.join(dir, @opf_file))
70
+
71
+ OCF.new(
72
+ :dir => dir,
73
+ :container => @opf_file
74
+ ).save(filename)
75
+ end
76
+ end
77
+
78
+ private
79
+
80
+ def prepare(dir)
81
+ filenames = []
82
+ sections.each_with_index do |section, index|
83
+ filename = File.join(dir, "section_#{index}.html")
84
+ File.open(filename, 'w') { |file| file.write section[1] }
85
+ filenames << filename
86
+ end
87
+
88
+ assets.each do |file|
89
+ FileUtils.cp(file, dir)
90
+ end
91
+
92
+ files(filenames + assets)
93
+ nav(
94
+ [sections, filenames].transpose.map do |section, filename|
95
+ {:label => section[0], :content => File.basename(filename)}
96
+ end
97
+ )
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,156 @@
1
+ require 'tmpdir'
2
+ require 'fileutils'
3
+
4
+ module EeePub
5
+ # The class to make ePub easily
6
+ #
7
+ # Note on unique identifiers:
8
+ #
9
+ # At least one 'identifier' must be the unique identifer represented by the name
10
+ # given to 'uid' and set via the hash option :id => {name}. The default name for
11
+ # uid is 'BookId' and doesn't need to be specified explicitly. If no identifier is
12
+ # marked as the unique identifier, the first one give will be chosen.
13
+ #
14
+ # @example
15
+ # epub = EeePub.make do
16
+ # title 'sample'
17
+ # creator 'jugyo'
18
+ # publisher 'jugyo.org'
19
+ # date '2010-05-06'
20
+ # uid 'BookId'
21
+ # identifier 'http://example.com/book/foo', :scheme => 'URL', :id => 'BookId'
22
+ #
23
+ # files ['/path/to/foo.html', '/path/to/bar.html']
24
+ # nav [
25
+ # {:label => '1. foo', :content => 'foo.html', :nav => [
26
+ # {:label => '1.1 foo-1', :content => 'foo.html#foo-1'}
27
+ # ]},
28
+ # {:label => '1. bar', :content => 'bar.html'}
29
+ # ]
30
+ # end
31
+ # epub.save('sample.epub')
32
+ class Maker
33
+ [
34
+ :title,
35
+ :creator,
36
+ :publisher,
37
+ :date,
38
+ :language,
39
+ :subject,
40
+ :description,
41
+ :rights,
42
+ :relation
43
+ ].each do |name|
44
+ class_eval <<-DELIM
45
+ def #{name}(value)
46
+ @#{name}s ||= []
47
+ @#{name}s << value
48
+ end
49
+ DELIM
50
+ end
51
+
52
+ [
53
+ :uid,
54
+ :files,
55
+ :nav,
56
+ :cover,
57
+ :ncx_file,
58
+ :opf_file,
59
+ :guide
60
+ ].each do |name|
61
+ define_method(name) do |arg|
62
+ instance_variable_set("@#{name}", arg)
63
+ end
64
+ end
65
+
66
+ def identifier(id, options)
67
+ @identifiers ||= []
68
+ @identifiers << {:value => id, :scheme => options[:scheme], :id => options[:id]}
69
+ end
70
+
71
+ # @param [Proc] block the block for initialize
72
+ def initialize(&block)
73
+ @files ||= []
74
+ @nav ||= []
75
+ @ncx_file ||= 'toc.ncx'
76
+ @opf_file ||= 'content.opf'
77
+
78
+ instance_eval(&block) if block_given?
79
+ end
80
+
81
+ # Save as ePub file
82
+ #
83
+ # @param [String] filename the ePub file name to save
84
+ def save(filename)
85
+ create_epub.save(filename)
86
+ end
87
+
88
+ # instead of saving to file, output the file contents.
89
+ # important for serving on-the-fly doc creation from
90
+ # web interface where we don't want to allow file system
91
+ # writes (Heroku, et al.)
92
+ def render
93
+ create_epub.render
94
+ end
95
+
96
+ private
97
+
98
+ def create_epub
99
+ @uid ||= 'BookId'
100
+ unique_identifier = @identifiers.select{ |i| i[:id] == @uid }.first
101
+ unless unique_identifier
102
+ unique_identifier = @identifiers.first
103
+ unique_identifier[:id] = @uid
104
+ end
105
+ dir = Dir.mktmpdir
106
+ @files.each do |file|
107
+ case file
108
+ when String
109
+ FileUtils.cp(file, dir)
110
+ when Hash
111
+ file_path, dir_path = *file.first
112
+ dest_dir = File.join(dir, dir_path)
113
+ FileUtils.mkdir_p(dest_dir)
114
+ FileUtils.cp(file_path, dest_dir)
115
+ end
116
+ end
117
+
118
+ NCX.new(
119
+ :uid => @identifiers.select{ |i| i[:id] == @uid }.first,
120
+ :title => @titles[0],
121
+ :nav => @nav
122
+ ).save(File.join(dir, @ncx_file))
123
+
124
+ OPF.new(
125
+ :title => @titles,
126
+ :unique_identifier => @uid,
127
+ :identifier => @identifiers,
128
+ :creator => @creators,
129
+ :publisher => @publishers,
130
+ :date => @dates,
131
+ :language => @languages,
132
+ :subject => @subjects,
133
+ :description => @descriptions,
134
+ :rights => @rightss,
135
+ :cover => @cover,
136
+ :relation => @relations,
137
+ :manifest => @files.map{|file|
138
+ case file
139
+ when String
140
+ File.basename(file)
141
+ when Hash
142
+ file_path, dir_path = *file.first
143
+ File.join(dir_path, File.basename(file_path))
144
+ end
145
+ },
146
+ :ncx => @ncx_file,
147
+ :guide => @guide
148
+ ).save(File.join(dir, @opf_file))
149
+
150
+ OCF.new(
151
+ :dir => dir,
152
+ :container => @opf_file
153
+ )
154
+ end
155
+ end
156
+ end